Source: lib/function.js

/**
 * @module darkFns/function
 */

import {
  defAssign
} from './array'

import {
  isUnDef, isFn
} from './assert'

/**
 * concat functions
 * @method
 * @param { ...function } ...fns variable length parameters
 * @return { function } return a new function formed by the combination of multiple functions
 * @example
 * function a () {
 *  console.log(1)
 * }
 * function b () {
 *  console.log(2)
 * }
 * var fn = concatFn(a, b)
 * fn() // => 1, 2
 */
export function concatFn () {
  var _fns = [].slice.call(arguments)
  return function () {
    return _fns.map(fn => {
      return fn.apply(this, arguments)
    })
  }
}

/**
 * function currying
 * @method
 * @example
 * function add (a, b) {
 *  return a + b
 * }
 * var fn = curry(1)
 * fn(2) // => 3
 * @param { function } fn the function to be fixed paramters
 * @param { ...* } ...args variable length parameters
 * @return { function } return a new function with fixed parameters
 */
export function curry (fn) {
  var _args = [].slice.call(arguments, 1)
  return function () {
    return fn.apply(this, _args.concat([].slice.call(arguments)))
  }
}

/**
 * generating a function to assign indefinite arguments
 * @method
 * @example
 * const fn = indefiniteArgs({
 *  base: [0, 1] // default arguments
 *  args: [
 *    // if recieves zero parameter
 *    // the undefined is the same as `args => args`
 *    undefined,
 *    // if recieves one parameter
 *    // args is an array copy from arguments, 
 *    // the result of this function is the result of defAssign(base, [undefined].concat(args))
 *    args => [undefined].concat(args),
 *    // if recieves two parameter,
 *    // the result of this function is the result of defAssign(base, [0, 1])
 *    [0, 1]
 *  ]
 * })
 * let [arg0, arg1] = fn() // arg0: 0, arg1: 1
 * let [arg0, arg1] = fn(1) // arg0: 0, arg1: 1
 * let [arg0, arg1, arg2] = fn(0, 0, 0) // arg0: 0, arg1: 1, arg2: undefined
 * let [arg0, arg1, arg2, arg3] = fn(1, 2, 3, 4) // arg0: 0, arg1: 1, arg2: 2, arg3: 3, arg4: 4
 * 
 * // is equal to:
 * const { defAssign } = require('dark-fns').array
 * 
 * function fn () {
 *  let base = [0, 1]
 *  if (len === 1) {
 *    return defAssign(base, [undefined].concat(args))
 *  } else if (len === 2) {
 *    return defAssign(base, [0, 1])
 *  } 
 *  // the `args.undefined` of conf
 *  else {
 *    return defAssign(base, [0, 1])
 *  }
 * }
 * 
 * @param { object } conf
 * @return { function }
 */
export function indefiniteArgs (conf) {
  let _baseArgs = conf.base
  let _argsConf = conf.args
  return function () {
    let len = arguments.length
    let conf = _argsConf[len]
    let arr = isUnDef(conf) ?
      [].slice.call(arguments) :
      (
        isFn(conf) ?
        conf([].slice.call(arguments)) :
        conf
      )
    return defAssign(_baseArgs, arr)
  }
}


export default {
  concatFn,
  curry,
  indefiniteArgs
}