_createHybrid.js
 1  var composeArgs = require('./_composeArgs'),
 2      composeArgsRight = require('./_composeArgsRight'),
 3      countHolders = require('./_countHolders'),
 4      createCtor = require('./_createCtor'),
 5      createRecurry = require('./_createRecurry'),
 6      getHolder = require('./_getHolder'),
 7      reorder = require('./_reorder'),
 8      replaceHolders = require('./_replaceHolders'),
 9      root = require('./_root');
10  
11  /** Used to compose bitmasks for function metadata. */
12  var WRAP_BIND_FLAG = 1,
13      WRAP_BIND_KEY_FLAG = 2,
14      WRAP_CURRY_FLAG = 8,
15      WRAP_CURRY_RIGHT_FLAG = 16,
16      WRAP_ARY_FLAG = 128,
17      WRAP_FLIP_FLAG = 512;
18  
19  /**
20   * Creates a function that wraps `func` to invoke it with optional `this`
21   * binding of `thisArg`, partial application, and currying.
22   *
23   * @private
24   * @param {Function|string} func The function or method name to wrap.
25   * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
26   * @param {*} [thisArg] The `this` binding of `func`.
27   * @param {Array} [partials] The arguments to prepend to those provided to
28   *  the new function.
29   * @param {Array} [holders] The `partials` placeholder indexes.
30   * @param {Array} [partialsRight] The arguments to append to those provided
31   *  to the new function.
32   * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
33   * @param {Array} [argPos] The argument positions of the new function.
34   * @param {number} [ary] The arity cap of `func`.
35   * @param {number} [arity] The arity of `func`.
36   * @returns {Function} Returns the new wrapped function.
37   */
38  function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
39    var isAry = bitmask & WRAP_ARY_FLAG,
40        isBind = bitmask & WRAP_BIND_FLAG,
41        isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
42        isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
43        isFlip = bitmask & WRAP_FLIP_FLAG,
44        Ctor = isBindKey ? undefined : createCtor(func);
45  
46    function wrapper() {
47      var length = arguments.length,
48          args = Array(length),
49          index = length;
50  
51      while (index--) {
52        args[index] = arguments[index];
53      }
54      if (isCurried) {
55        var placeholder = getHolder(wrapper),
56            holdersCount = countHolders(args, placeholder);
57      }
58      if (partials) {
59        args = composeArgs(args, partials, holders, isCurried);
60      }
61      if (partialsRight) {
62        args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
63      }
64      length -= holdersCount;
65      if (isCurried && length < arity) {
66        var newHolders = replaceHolders(args, placeholder);
67        return createRecurry(
68          func, bitmask, createHybrid, wrapper.placeholder, thisArg,
69          args, newHolders, argPos, ary, arity - length
70        );
71      }
72      var thisBinding = isBind ? thisArg : this,
73          fn = isBindKey ? thisBinding[func] : func;
74  
75      length = args.length;
76      if (argPos) {
77        args = reorder(args, argPos);
78      } else if (isFlip && length > 1) {
79        args.reverse();
80      }
81      if (isAry && ary < length) {
82        args.length = ary;
83      }
84      if (this && this !== root && this instanceof wrapper) {
85        fn = Ctor || createCtor(fn);
86      }
87      return fn.apply(thisBinding, args);
88    }
89    return wrapper;
90  }
91  
92  module.exports = createHybrid;