Initial commit
[yaffs-website] / node_modules / sass-graph / node_modules / lodash / fp / _baseConvert.js
1 var mapping = require('./_mapping'),
2     fallbackHolder = require('./placeholder');
3
4 /** Built-in value reference. */
5 var push = Array.prototype.push;
6
7 /**
8  * Creates a function, with an arity of `n`, that invokes `func` with the
9  * arguments it receives.
10  *
11  * @private
12  * @param {Function} func The function to wrap.
13  * @param {number} n The arity of the new function.
14  * @returns {Function} Returns the new function.
15  */
16 function baseArity(func, n) {
17   return n == 2
18     ? function(a, b) { return func.apply(undefined, arguments); }
19     : function(a) { return func.apply(undefined, arguments); };
20 }
21
22 /**
23  * Creates a function that invokes `func`, with up to `n` arguments, ignoring
24  * any additional arguments.
25  *
26  * @private
27  * @param {Function} func The function to cap arguments for.
28  * @param {number} n The arity cap.
29  * @returns {Function} Returns the new function.
30  */
31 function baseAry(func, n) {
32   return n == 2
33     ? function(a, b) { return func(a, b); }
34     : function(a) { return func(a); };
35 }
36
37 /**
38  * Creates a clone of `array`.
39  *
40  * @private
41  * @param {Array} array The array to clone.
42  * @returns {Array} Returns the cloned array.
43  */
44 function cloneArray(array) {
45   var length = array ? array.length : 0,
46       result = Array(length);
47
48   while (length--) {
49     result[length] = array[length];
50   }
51   return result;
52 }
53
54 /**
55  * Creates a function that clones a given object using the assignment `func`.
56  *
57  * @private
58  * @param {Function} func The assignment function.
59  * @returns {Function} Returns the new cloner function.
60  */
61 function createCloner(func) {
62   return function(object) {
63     return func({}, object);
64   };
65 }
66
67 /**
68  * A specialized version of `_.spread` which flattens the spread array into
69  * the arguments of the invoked `func`.
70  *
71  * @private
72  * @param {Function} func The function to spread arguments over.
73  * @param {number} start The start position of the spread.
74  * @returns {Function} Returns the new function.
75  */
76 function flatSpread(func, start) {
77   return function() {
78     var length = arguments.length,
79         lastIndex = length - 1,
80         args = Array(length);
81
82     while (length--) {
83       args[length] = arguments[length];
84     }
85     var array = args[start],
86         otherArgs = args.slice(0, start);
87
88     if (array) {
89       push.apply(otherArgs, array);
90     }
91     if (start != lastIndex) {
92       push.apply(otherArgs, args.slice(start + 1));
93     }
94     return func.apply(this, otherArgs);
95   };
96 }
97
98 /**
99  * Creates a function that wraps `func` and uses `cloner` to clone the first
100  * argument it receives.
101  *
102  * @private
103  * @param {Function} func The function to wrap.
104  * @param {Function} cloner The function to clone arguments.
105  * @returns {Function} Returns the new immutable function.
106  */
107 function wrapImmutable(func, cloner) {
108   return function() {
109     var length = arguments.length;
110     if (!length) {
111       return;
112     }
113     var args = Array(length);
114     while (length--) {
115       args[length] = arguments[length];
116     }
117     var result = args[0] = cloner.apply(undefined, args);
118     func.apply(undefined, args);
119     return result;
120   };
121 }
122
123 /**
124  * The base implementation of `convert` which accepts a `util` object of methods
125  * required to perform conversions.
126  *
127  * @param {Object} util The util object.
128  * @param {string} name The name of the function to convert.
129  * @param {Function} func The function to convert.
130  * @param {Object} [options] The options object.
131  * @param {boolean} [options.cap=true] Specify capping iteratee arguments.
132  * @param {boolean} [options.curry=true] Specify currying.
133  * @param {boolean} [options.fixed=true] Specify fixed arity.
134  * @param {boolean} [options.immutable=true] Specify immutable operations.
135  * @param {boolean} [options.rearg=true] Specify rearranging arguments.
136  * @returns {Function|Object} Returns the converted function or object.
137  */
138 function baseConvert(util, name, func, options) {
139   var setPlaceholder,
140       isLib = typeof name == 'function',
141       isObj = name === Object(name);
142
143   if (isObj) {
144     options = func;
145     func = name;
146     name = undefined;
147   }
148   if (func == null) {
149     throw new TypeError;
150   }
151   options || (options = {});
152
153   var config = {
154     'cap': 'cap' in options ? options.cap : true,
155     'curry': 'curry' in options ? options.curry : true,
156     'fixed': 'fixed' in options ? options.fixed : true,
157     'immutable': 'immutable' in options ? options.immutable : true,
158     'rearg': 'rearg' in options ? options.rearg : true
159   };
160
161   var forceCurry = ('curry' in options) && options.curry,
162       forceFixed = ('fixed' in options) && options.fixed,
163       forceRearg = ('rearg' in options) && options.rearg,
164       placeholder = isLib ? func : fallbackHolder,
165       pristine = isLib ? func.runInContext() : undefined;
166
167   var helpers = isLib ? func : {
168     'ary': util.ary,
169     'assign': util.assign,
170     'clone': util.clone,
171     'curry': util.curry,
172     'forEach': util.forEach,
173     'isArray': util.isArray,
174     'isFunction': util.isFunction,
175     'iteratee': util.iteratee,
176     'keys': util.keys,
177     'rearg': util.rearg,
178     'toInteger': util.toInteger,
179     'toPath': util.toPath
180   };
181
182   var ary = helpers.ary,
183       assign = helpers.assign,
184       clone = helpers.clone,
185       curry = helpers.curry,
186       each = helpers.forEach,
187       isArray = helpers.isArray,
188       isFunction = helpers.isFunction,
189       keys = helpers.keys,
190       rearg = helpers.rearg,
191       toInteger = helpers.toInteger,
192       toPath = helpers.toPath;
193
194   var aryMethodKeys = keys(mapping.aryMethod);
195
196   var wrappers = {
197     'castArray': function(castArray) {
198       return function() {
199         var value = arguments[0];
200         return isArray(value)
201           ? castArray(cloneArray(value))
202           : castArray.apply(undefined, arguments);
203       };
204     },
205     'iteratee': function(iteratee) {
206       return function() {
207         var func = arguments[0],
208             arity = arguments[1],
209             result = iteratee(func, arity),
210             length = result.length;
211
212         if (config.cap && typeof arity == 'number') {
213           arity = arity > 2 ? (arity - 2) : 1;
214           return (length && length <= arity) ? result : baseAry(result, arity);
215         }
216         return result;
217       };
218     },
219     'mixin': function(mixin) {
220       return function(source) {
221         var func = this;
222         if (!isFunction(func)) {
223           return mixin(func, Object(source));
224         }
225         var pairs = [];
226         each(keys(source), function(key) {
227           if (isFunction(source[key])) {
228             pairs.push([key, func.prototype[key]]);
229           }
230         });
231
232         mixin(func, Object(source));
233
234         each(pairs, function(pair) {
235           var value = pair[1];
236           if (isFunction(value)) {
237             func.prototype[pair[0]] = value;
238           } else {
239             delete func.prototype[pair[0]];
240           }
241         });
242         return func;
243       };
244     },
245     'nthArg': function(nthArg) {
246       return function(n) {
247         var arity = n < 0 ? 1 : (toInteger(n) + 1);
248         return curry(nthArg(n), arity);
249       };
250     },
251     'rearg': function(rearg) {
252       return function(func, indexes) {
253         var arity = indexes ? indexes.length : 0;
254         return curry(rearg(func, indexes), arity);
255       };
256     },
257     'runInContext': function(runInContext) {
258       return function(context) {
259         return baseConvert(util, runInContext(context), options);
260       };
261     }
262   };
263
264   /*--------------------------------------------------------------------------*/
265
266   /**
267    * Casts `func` to a function with an arity capped iteratee if needed.
268    *
269    * @private
270    * @param {string} name The name of the function to inspect.
271    * @param {Function} func The function to inspect.
272    * @returns {Function} Returns the cast function.
273    */
274   function castCap(name, func) {
275     if (config.cap) {
276       var indexes = mapping.iterateeRearg[name];
277       if (indexes) {
278         return iterateeRearg(func, indexes);
279       }
280       var n = !isLib && mapping.iterateeAry[name];
281       if (n) {
282         return iterateeAry(func, n);
283       }
284     }
285     return func;
286   }
287
288   /**
289    * Casts `func` to a curried function if needed.
290    *
291    * @private
292    * @param {string} name The name of the function to inspect.
293    * @param {Function} func The function to inspect.
294    * @param {number} n The arity of `func`.
295    * @returns {Function} Returns the cast function.
296    */
297   function castCurry(name, func, n) {
298     return (forceCurry || (config.curry && n > 1))
299       ? curry(func, n)
300       : func;
301   }
302
303   /**
304    * Casts `func` to a fixed arity function if needed.
305    *
306    * @private
307    * @param {string} name The name of the function to inspect.
308    * @param {Function} func The function to inspect.
309    * @param {number} n The arity cap.
310    * @returns {Function} Returns the cast function.
311    */
312   function castFixed(name, func, n) {
313     if (config.fixed && (forceFixed || !mapping.skipFixed[name])) {
314       var data = mapping.methodSpread[name],
315           start = data && data.start;
316
317       return start  === undefined ? ary(func, n) : flatSpread(func, start);
318     }
319     return func;
320   }
321
322   /**
323    * Casts `func` to an rearged function if needed.
324    *
325    * @private
326    * @param {string} name The name of the function to inspect.
327    * @param {Function} func The function to inspect.
328    * @param {number} n The arity of `func`.
329    * @returns {Function} Returns the cast function.
330    */
331   function castRearg(name, func, n) {
332     return (config.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name]))
333       ? rearg(func, mapping.methodRearg[name] || mapping.aryRearg[n])
334       : func;
335   }
336
337   /**
338    * Creates a clone of `object` by `path`.
339    *
340    * @private
341    * @param {Object} object The object to clone.
342    * @param {Array|string} path The path to clone by.
343    * @returns {Object} Returns the cloned object.
344    */
345   function cloneByPath(object, path) {
346     path = toPath(path);
347
348     var index = -1,
349         length = path.length,
350         lastIndex = length - 1,
351         result = clone(Object(object)),
352         nested = result;
353
354     while (nested != null && ++index < length) {
355       var key = path[index],
356           value = nested[key];
357
358       if (value != null) {
359         nested[path[index]] = clone(index == lastIndex ? value : Object(value));
360       }
361       nested = nested[key];
362     }
363     return result;
364   }
365
366   /**
367    * Converts `lodash` to an immutable auto-curried iteratee-first data-last
368    * version with conversion `options` applied.
369    *
370    * @param {Object} [options] The options object. See `baseConvert` for more details.
371    * @returns {Function} Returns the converted `lodash`.
372    */
373   function convertLib(options) {
374     return _.runInContext.convert(options)(undefined);
375   }
376
377   /**
378    * Create a converter function for `func` of `name`.
379    *
380    * @param {string} name The name of the function to convert.
381    * @param {Function} func The function to convert.
382    * @returns {Function} Returns the new converter function.
383    */
384   function createConverter(name, func) {
385     var realName = mapping.aliasToReal[name] || name,
386         methodName = mapping.remap[realName] || realName,
387         oldOptions = options;
388
389     return function(options) {
390       var newUtil = isLib ? pristine : helpers,
391           newFunc = isLib ? pristine[methodName] : func,
392           newOptions = assign(assign({}, oldOptions), options);
393
394       return baseConvert(newUtil, realName, newFunc, newOptions);
395     };
396   }
397
398   /**
399    * Creates a function that wraps `func` to invoke its iteratee, with up to `n`
400    * arguments, ignoring any additional arguments.
401    *
402    * @private
403    * @param {Function} func The function to cap iteratee arguments for.
404    * @param {number} n The arity cap.
405    * @returns {Function} Returns the new function.
406    */
407   function iterateeAry(func, n) {
408     return overArg(func, function(func) {
409       return typeof func == 'function' ? baseAry(func, n) : func;
410     });
411   }
412
413   /**
414    * Creates a function that wraps `func` to invoke its iteratee with arguments
415    * arranged according to the specified `indexes` where the argument value at
416    * the first index is provided as the first argument, the argument value at
417    * the second index is provided as the second argument, and so on.
418    *
419    * @private
420    * @param {Function} func The function to rearrange iteratee arguments for.
421    * @param {number[]} indexes The arranged argument indexes.
422    * @returns {Function} Returns the new function.
423    */
424   function iterateeRearg(func, indexes) {
425     return overArg(func, function(func) {
426       var n = indexes.length;
427       return baseArity(rearg(baseAry(func, n), indexes), n);
428     });
429   }
430
431   /**
432    * Creates a function that invokes `func` with its first argument transformed.
433    *
434    * @private
435    * @param {Function} func The function to wrap.
436    * @param {Function} transform The argument transform.
437    * @returns {Function} Returns the new function.
438    */
439   function overArg(func, transform) {
440     return function() {
441       var length = arguments.length;
442       if (!length) {
443         return func();
444       }
445       var args = Array(length);
446       while (length--) {
447         args[length] = arguments[length];
448       }
449       var index = config.rearg ? 0 : (length - 1);
450       args[index] = transform(args[index]);
451       return func.apply(undefined, args);
452     };
453   }
454
455   /**
456    * Creates a function that wraps `func` and applys the conversions
457    * rules by `name`.
458    *
459    * @private
460    * @param {string} name The name of the function to wrap.
461    * @param {Function} func The function to wrap.
462    * @returns {Function} Returns the converted function.
463    */
464   function wrap(name, func) {
465     var result,
466         realName = mapping.aliasToReal[name] || name,
467         wrapped = func,
468         wrapper = wrappers[realName];
469
470     if (wrapper) {
471       wrapped = wrapper(func);
472     }
473     else if (config.immutable) {
474       if (mapping.mutate.array[realName]) {
475         wrapped = wrapImmutable(func, cloneArray);
476       }
477       else if (mapping.mutate.object[realName]) {
478         wrapped = wrapImmutable(func, createCloner(func));
479       }
480       else if (mapping.mutate.set[realName]) {
481         wrapped = wrapImmutable(func, cloneByPath);
482       }
483     }
484     each(aryMethodKeys, function(aryKey) {
485       each(mapping.aryMethod[aryKey], function(otherName) {
486         if (realName == otherName) {
487           var data = mapping.methodSpread[realName],
488               afterRearg = data && data.afterRearg;
489
490           result = afterRearg
491             ? castFixed(realName, castRearg(realName, wrapped, aryKey), aryKey)
492             : castRearg(realName, castFixed(realName, wrapped, aryKey), aryKey);
493
494           result = castCap(realName, result);
495           result = castCurry(realName, result, aryKey);
496           return false;
497         }
498       });
499       return !result;
500     });
501
502     result || (result = wrapped);
503     if (result == func) {
504       result = forceCurry ? curry(result, 1) : function() {
505         return func.apply(this, arguments);
506       };
507     }
508     result.convert = createConverter(realName, func);
509     if (mapping.placeholder[realName]) {
510       setPlaceholder = true;
511       result.placeholder = func.placeholder = placeholder;
512     }
513     return result;
514   }
515
516   /*--------------------------------------------------------------------------*/
517
518   if (!isObj) {
519     return wrap(name, func);
520   }
521   var _ = func;
522
523   // Convert methods by ary cap.
524   var pairs = [];
525   each(aryMethodKeys, function(aryKey) {
526     each(mapping.aryMethod[aryKey], function(key) {
527       var func = _[mapping.remap[key] || key];
528       if (func) {
529         pairs.push([key, wrap(key, func)]);
530       }
531     });
532   });
533
534   // Convert remaining methods.
535   each(keys(_), function(key) {
536     var func = _[key];
537     if (typeof func == 'function') {
538       var length = pairs.length;
539       while (length--) {
540         if (pairs[length][0] == key) {
541           return;
542         }
543       }
544       func.convert = createConverter(key, func);
545       pairs.push([key, func]);
546     }
547   });
548
549   // Assign to `_` leaving `_.prototype` unchanged to allow chaining.
550   each(pairs, function(pair) {
551     _[pair[0]] = pair[1];
552   });
553
554   _.convert = convertLib;
555   if (setPlaceholder) {
556     _.placeholder = placeholder;
557   }
558   // Assign aliases.
559   each(keys(_), function(key) {
560     each(mapping.realToAlias[key] || [], function(alias) {
561       _[alias] = _[key];
562     });
563   });
564
565   return _;
566 }
567
568 module.exports = baseConvert;