30d3706ce65d9d34e382fe3cfc14669583a1f11c
[motion.git] / public / bower_components / lodash / fp / _baseConvert.js
1 var mapping = require('./_mapping'),
2     mutateMap = mapping.mutate,
3     placeholder = {};
4
5 /**
6  * The base implementation of `convert` which accepts a `util` object of methods
7  * required to perform conversions.
8  *
9  * @param {Object} util The util object.
10  * @param {string} name The name of the function to wrap.
11  * @param {Function} func The function to wrap.
12  * @param {Object} [options] The options object.
13  * @param {boolean} [options.cap=true] Specify capping iteratee arguments.
14  * @param {boolean} [options.curry=true] Specify currying.
15  * @param {boolean} [options.fixed=true] Specify fixed arity.
16  * @param {boolean} [options.immutable=true] Specify immutable operations.
17  * @param {boolean} [options.rearg=true] Specify rearranging arguments.
18  * @returns {Function|Object} Returns the converted function or object.
19  */
20 function baseConvert(util, name, func, options) {
21   var setPlaceholder,
22       isLib = typeof name == 'function',
23       isObj = name === Object(name);
24
25   if (isObj) {
26     options = func;
27     func = name;
28     name = undefined;
29   }
30   if (func == null) {
31     throw new TypeError;
32   }
33   options || (options = {});
34
35   var config = {
36     'cap': 'cap' in options ? options.cap : true,
37     'curry': 'curry' in options ? options.curry : true,
38     'fixed': 'fixed' in options ? options.fixed : true,
39     'immutable': 'immutable' in options ? options.immutable : true,
40     'rearg': 'rearg' in options ? options.rearg : true
41   };
42
43   var forceRearg = ('rearg' in options) && options.rearg;
44
45   var helpers = isLib ? func : {
46     'ary': util.ary,
47     'clone': util.clone,
48     'curry': util.curry,
49     'forEach': util.forEach,
50     'isArray': util.isArray,
51     'isFunction': util.isFunction,
52     'iteratee': util.iteratee,
53     'keys': util.keys,
54     'rearg': util.rearg,
55     'spread': util.spread,
56     'toPath': util.toPath
57   };
58
59   var ary = helpers.ary,
60       clone = helpers.clone,
61       curry = helpers.curry,
62       each = helpers.forEach,
63       isArray = helpers.isArray,
64       isFunction = helpers.isFunction,
65       keys = helpers.keys,
66       rearg = helpers.rearg,
67       spread = helpers.spread,
68       toPath = helpers.toPath;
69
70   var aryMethodKeys = keys(mapping.aryMethod);
71
72   var baseArity = function(func, n) {
73     return n == 2
74       ? function(a, b) { return func.apply(undefined, arguments); }
75       : function(a) { return func.apply(undefined, arguments); };
76   };
77
78   var baseAry = function(func, n) {
79     return n == 2
80       ? function(a, b) { return func(a, b); }
81       : function(a) { return func(a); };
82   };
83
84   var cloneArray = function(array) {
85     var length = array ? array.length : 0,
86         result = Array(length);
87
88     while (length--) {
89       result[length] = array[length];
90     }
91     return result;
92   };
93
94   var cloneByPath = function(object, path) {
95     path = toPath(path);
96
97     var index = -1,
98         length = path.length,
99         result = clone(Object(object)),
100         nested = result;
101
102     while (nested != null && ++index < length) {
103       var key = path[index],
104           value = nested[key];
105
106       if (value != null) {
107         nested[key] = clone(Object(value));
108       }
109       nested = nested[key];
110     }
111     return result;
112   };
113
114   var createCloner = function(func) {
115     return function(object) {
116       return func({}, object);
117     };
118   };
119
120   var immutWrap = function(func, cloner) {
121     return function() {
122       var length = arguments.length;
123       if (!length) {
124         return result;
125       }
126       var args = Array(length);
127       while (length--) {
128         args[length] = arguments[length];
129       }
130       var result = args[0] = cloner.apply(undefined, args);
131       func.apply(undefined, args);
132       return result;
133     };
134   };
135
136   var iterateeAry = function(func, n) {
137     return overArg(func, function(func) {
138       return typeof func == 'function' ? baseAry(func, n) : func;
139     });
140   };
141
142   var iterateeRearg = function(func, indexes) {
143     return overArg(func, function(func) {
144       var n = indexes.length;
145       return baseArity(rearg(baseAry(func, n), indexes), n);
146     });
147   };
148
149   var overArg = function(func, iteratee, retArg) {
150     return function() {
151       var length = arguments.length;
152       if (!length) {
153         return func();
154       }
155       var args = Array(length);
156       while (length--) {
157         args[length] = arguments[length];
158       }
159       var index = config.rearg ? 0 : (length - 1);
160       args[index] = iteratee(args[index]);
161       return func.apply(undefined, args);
162     };
163   };
164
165   var wrappers = {
166     'castArray': function(castArray) {
167       return function() {
168         var value = arguments[0];
169         return isArray(value)
170           ? castArray(cloneArray(value))
171           : castArray.apply(undefined, arguments);
172       };
173     },
174     'iteratee': function(iteratee) {
175       return function() {
176         var func = arguments[0],
177             arity = arguments[1],
178             result = iteratee(func, arity),
179             length = result.length;
180
181         if (config.cap && typeof arity == 'number') {
182           arity = arity > 2 ? (arity - 2) : 1;
183           return (length && length <= arity) ? result : baseAry(result, arity);
184         }
185         return result;
186       };
187     },
188     'mixin': function(mixin) {
189       return function(source) {
190         var func = this;
191         if (!isFunction(func)) {
192           return mixin(func, Object(source));
193         }
194         var methods = [],
195             methodNames = [];
196
197         each(keys(source), function(key) {
198           var value = source[key];
199           if (isFunction(value)) {
200             methodNames.push(key);
201             methods.push(func.prototype[key]);
202           }
203         });
204
205         mixin(func, Object(source));
206
207         each(methodNames, function(methodName, index) {
208           var method = methods[index];
209           if (isFunction(method)) {
210             func.prototype[methodName] = method;
211           } else {
212             delete func.prototype[methodName];
213           }
214         });
215         return func;
216       };
217     },
218     'runInContext': function(runInContext) {
219       return function(context) {
220         return baseConvert(util, runInContext(context), options);
221       };
222     }
223   };
224
225   var wrap = function(name, func) {
226     name = mapping.aliasToReal[name] || name;
227     var wrapper = wrappers[name];
228     if (wrapper) {
229       return wrapper(func);
230     }
231     var wrapped = func;
232     if (config.immutable) {
233       if (mutateMap.array[name]) {
234         wrapped = immutWrap(func, cloneArray);
235       }
236       else if (mutateMap.object[name]) {
237         wrapped = immutWrap(func, createCloner(func));
238       }
239       else if (mutateMap.set[name]) {
240         wrapped = immutWrap(func, cloneByPath);
241       }
242     }
243     var result;
244     each(aryMethodKeys, function(aryKey) {
245       each(mapping.aryMethod[aryKey], function(otherName) {
246         if (name == otherName) {
247           var aryN = !isLib && mapping.iterateeAry[name],
248               reargIndexes = mapping.iterateeRearg[name],
249               spreadStart = mapping.methodSpread[name];
250
251           result = wrapped;
252           if (config.fixed) {
253             result = spreadStart === undefined
254               ? ary(result, aryKey)
255               : spread(result, spreadStart);
256           }
257           if (config.rearg && aryKey > 1 && (forceRearg || !mapping.skipRearg[name])) {
258             result = rearg(result, mapping.methodRearg[name] || mapping.aryRearg[aryKey]);
259           }
260           if (config.cap) {
261             if (reargIndexes) {
262               result = iterateeRearg(result, reargIndexes);
263             } else if (aryN) {
264               result = iterateeAry(result, aryN);
265             }
266           }
267           if (config.curry && aryKey > 1) {
268             result = curry(result, aryKey);
269           }
270           return false;
271         }
272       });
273       return !result;
274     });
275
276     result || (result = wrapped);
277     if (mapping.placeholder[name]) {
278       setPlaceholder = true;
279       func.placeholder = result.placeholder = placeholder;
280     }
281     return result;
282   };
283
284   if (!isObj) {
285     return wrap(name, func);
286   }
287   var _ = func;
288
289   // Iterate over methods for the current ary cap.
290   var pairs = [];
291   each(aryMethodKeys, function(aryKey) {
292     each(mapping.aryMethod[aryKey], function(key) {
293       var func = _[mapping.remap[key] || key];
294       if (func) {
295         pairs.push([key, wrap(key, func)]);
296       }
297     });
298   });
299
300   // Assign to `_` leaving `_.prototype` unchanged to allow chaining.
301   each(pairs, function(pair) {
302     _[pair[0]] = pair[1];
303   });
304
305   if (setPlaceholder) {
306     _.placeholder = placeholder;
307   }
308   // Wrap the lodash method and its aliases.
309   each(keys(_), function(key) {
310     each(mapping.realToAlias[key] || [], function(alias) {
311       _[alias] = _[key];
312     });
313   });
314
315   return _;
316 }
317
318 module.exports = baseConvert;