eb3a71f29867d9238f32021b2465c286c619dbd7
[yaffs-website] / createHybridWrapper.js
1 var composeArgs = require('./composeArgs'),
2     composeArgsRight = require('./composeArgsRight'),
3     createCtorWrapper = require('./createCtorWrapper'),
4     createRecurryWrapper = require('./createRecurryWrapper'),
5     reorder = require('./reorder'),
6     replaceHolders = require('./replaceHolders');
7
8 /** Used to compose bitmasks for wrapper metadata. */
9 var BIND_FLAG = 1,
10     BIND_KEY_FLAG = 2,
11     CURRY_FLAG = 8,
12     CURRY_RIGHT_FLAG = 16,
13     ARY_FLAG = 128,
14     FLIP_FLAG = 512;
15
16 /**
17  * Creates a function that wraps `func` to invoke it with optional `this`
18  * binding of `thisArg`, partial application, and currying.
19  *
20  * @private
21  * @param {Function|string} func The function or method name to wrap.
22  * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper` for more details.
23  * @param {*} [thisArg] The `this` binding of `func`.
24  * @param {Array} [partials] The arguments to prepend to those provided to the new function.
25  * @param {Array} [holders] The `partials` placeholder indexes.
26  * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
27  * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
28  * @param {Array} [argPos] The argument positions of the new function.
29  * @param {number} [ary] The arity cap of `func`.
30  * @param {number} [arity] The arity of `func`.
31  * @returns {Function} Returns the new wrapped function.
32  */
33 function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
34   var isAry = bitmask & ARY_FLAG,
35       isBind = bitmask & BIND_FLAG,
36       isBindKey = bitmask & BIND_KEY_FLAG,
37       isCurry = bitmask & CURRY_FLAG,
38       isCurryRight = bitmask & CURRY_RIGHT_FLAG,
39       isFlip = bitmask & FLIP_FLAG,
40       Ctor = isBindKey ? undefined : createCtorWrapper(func);
41
42   function wrapper() {
43     var length = arguments.length,
44         index = length,
45         args = Array(length);
46
47     while (index--) {
48       args[index] = arguments[index];
49     }
50     if (partials) {
51       args = composeArgs(args, partials, holders);
52     }
53     if (partialsRight) {
54       args = composeArgsRight(args, partialsRight, holdersRight);
55     }
56     if (isCurry || isCurryRight) {
57       var placeholder = wrapper.placeholder,
58           argsHolders = replaceHolders(args, placeholder);
59
60       length -= argsHolders.length;
61       if (length < arity) {
62         return createRecurryWrapper(func, bitmask, createHybridWrapper, placeholder, thisArg, args, argsHolders, argPos, ary, arity - length);
63       }
64     }
65     var thisBinding = isBind ? thisArg : this,
66         fn = isBindKey ? thisBinding[func] : func;
67
68     if (argPos) {
69       args = reorder(args, argPos);
70     } else if (isFlip && args.length > 1) {
71       args.reverse();
72     }
73     if (isAry && ary < args.length) {
74       args.length = ary;
75     }
76     if (this && this !== global && this instanceof wrapper) {
77       fn = Ctor || createCtorWrapper(fn);
78     }
79     return fn.apply(thisBinding, args);
80   }
81   return wrapper;
82 }
83
84 module.exports = createHybridWrapper;