code: function declare (combinators, prefix) {
    if (arguments.length > 2) throw new ComposerError('Too many arguments in "declare"')
    if (!isObject(combinators)) throw new ComposerError('Invalid argument "combinators" in "declare"', combinators)
    if (prefix !== undefined && typeof prefix !== 'string') throw new ComposerError('Invalid argument "prefix" in "declare"', prefix)
    const composer = {}
    for (let key in combinators) {
      const type = prefix ? prefix + '.' + key : key
      const combinator = combinators[key]
      if (!isObject(combinator) || (combinator.args !== undefined && !Array.isArray(combinator.args))) {
        throw new ComposerError(`Invalid "${type}" combinator specification in "declare"`, combinator)
      }
      for (let arg of combinator.args || []) {
        if (typeof arg.name !== 'string') throw new ComposerError(`Invalid "${type}" combinator specification in "declare"`, combinator)
      }
      composer[key] = function () {
        const composition = { type, '.combinator': () => combinator }
        const skip = (combinator.args && combinator.args.length) || 0
        if (!combinator.components && (arguments.length > skip)) {
          throw new ComposerError(`Too many arguments in "${type}" combinator`)
        }
        for (let i = 0; i < skip; ++i) {
          composition[combinator.args[i].name] = arguments[i]
        }
        if (combinator.components) {
          composition.components = Array.prototype.slice.call(arguments, skip)
        }
        return new Composition(composition)
      }
    }
    return composer
  }
docs: derive combinator methods from combinator table check argument count and map argument positions to argument names delegate to Composition constructor for the rest of the validation