mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-31 15:27:50 +00:00
4484 lines
158 KiB
JavaScript
4484 lines
158 KiB
JavaScript
#!/usr/bin/env node
|
|
;(function() {
|
|
'use strict';
|
|
|
|
/** Load Node.js modules */
|
|
var vm = require('vm');
|
|
|
|
/** Load other modules */
|
|
var _ = require('./lodash.js'),
|
|
minify = require('./build/minify.js'),
|
|
util = require('./build/util.js');
|
|
|
|
/** Module shortcuts */
|
|
var fs = util.fs,
|
|
path = util.path;
|
|
|
|
/** The current working directory */
|
|
var cwd = process.cwd();
|
|
|
|
/** Used for array and object method references */
|
|
var arrayRef = Array.prototype,
|
|
objectRef = Object.prototype;
|
|
|
|
/** Native method shortcuts */
|
|
var hasOwnProperty = objectRef.hasOwnProperty,
|
|
push = arrayRef.push,
|
|
slice = arrayRef.slice;
|
|
|
|
/** Memoize regexp creation */
|
|
var RegExp = (function() {
|
|
var cache = {};
|
|
return function(pattern, flags) {
|
|
if (flags && /g/.test(flags)) {
|
|
return global.RegExp(pattern, flags);
|
|
}
|
|
var key = '/' + pattern + '/' + (flags || '');
|
|
return cache[key] || (cache[key] = global.RegExp(pattern, flags));
|
|
};
|
|
}());
|
|
|
|
/** Used to create regexes that may detect multi-line comment blocks */
|
|
var multilineComment = '(?:\\n */\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n';
|
|
|
|
/** Used to detect the Node.js executable in command-line arguments */
|
|
var reNode = RegExp('(?:^|' + path.sepEscaped + ')node(?:\\.exe)?$', 'i');
|
|
|
|
/** Shortcut to the `stdout` object */
|
|
var stdout = process.stdout;
|
|
|
|
/** Used to associate aliases with their real names */
|
|
var aliasToRealMap = {
|
|
'all': 'every',
|
|
'any': 'some',
|
|
'collect': 'map',
|
|
'detect': 'find',
|
|
'drop': 'rest',
|
|
'each': 'forEach',
|
|
'extend': 'assign',
|
|
'findWhere': 'find',
|
|
'foldl': 'reduce',
|
|
'foldr': 'reduceRight',
|
|
'head': 'first',
|
|
'include': 'contains',
|
|
'inject': 'reduce',
|
|
'methods': 'functions',
|
|
'object': 'zipObject',
|
|
'select': 'filter',
|
|
'tail': 'rest',
|
|
'take': 'first',
|
|
'unique': 'uniq',
|
|
'unzip': 'zip',
|
|
'value': 'wrapperValueOf'
|
|
};
|
|
|
|
/** Used to associate real names with their aliases */
|
|
var realToAliasMap = {
|
|
'assign': ['extend'],
|
|
'contains': ['include'],
|
|
'every': ['all'],
|
|
'filter': ['select'],
|
|
'find': ['detect', 'findWhere'],
|
|
'first': ['head', 'take'],
|
|
'forEach': ['each'],
|
|
'functions': ['methods'],
|
|
'map': ['collect'],
|
|
'reduce': ['foldl', 'inject'],
|
|
'reduceRight': ['foldr'],
|
|
'rest': ['drop', 'tail'],
|
|
'some': ['any'],
|
|
'uniq': ['unique'],
|
|
'wrapperValueOf': ['value'],
|
|
'zip': ['unzip'],
|
|
'zipObject': ['object']
|
|
};
|
|
|
|
/** Used to track function dependencies */
|
|
var funcDependencyMap = {
|
|
// properties
|
|
'templateSettings': ['escape'],
|
|
|
|
// variables
|
|
'defaultsIteratorOptions': ['keys'],
|
|
'eachIteratorOptions': ['keys'],
|
|
'htmlUnescapes': ['invert'],
|
|
'reEscapedHtml': ['keys'],
|
|
'reUnescapedHtml': ['keys'],
|
|
|
|
// public functions
|
|
'after': ['isFunction'],
|
|
'assign': ['createIterator'],
|
|
'at': ['baseFlatten', 'isString'],
|
|
'bind': ['createBound'],
|
|
'bindAll': ['baseFlatten', 'bind', 'functions'],
|
|
'bindKey': ['createBound'],
|
|
'chain': ['lodashWrapper'],
|
|
'clone': ['baseClone', 'baseCreateCallback'],
|
|
'cloneDeep': ['baseClone', 'baseCreateCallback'],
|
|
'compact': [],
|
|
'compose': ['isFunction'],
|
|
'contains': ['baseEach', 'getIndexOf', 'isString'],
|
|
'countBy': ['createAggregator'],
|
|
'createCallback': ['baseCreateCallback', 'baseIsEqual', 'isObject', 'keys'],
|
|
'curry': ['createBound'],
|
|
'debounce': ['isFunction', 'isObject'],
|
|
'defaults': ['createIterator'],
|
|
'defer': ['isFunction'],
|
|
'delay': ['isFunction'],
|
|
'difference': ['baseFlatten', 'cacheIndexOf', 'createCache', 'getIndexOf', 'releaseObject'],
|
|
'escape': ['escapeHtmlChar', 'keys'],
|
|
'every': ['baseEach', 'createCallback', 'isArray'],
|
|
'filter': ['baseEach', 'createCallback', 'isArray'],
|
|
'find': ['baseEach', 'createCallback', 'isArray'],
|
|
'findIndex': ['createCallback'],
|
|
'findLastIndex': ['createCallback'],
|
|
'findKey': ['createCallback', 'forOwn'],
|
|
'findLast': ['createCallback', 'forEachRight'],
|
|
'findLastKey': ['createCallback', 'forOwnRight'],
|
|
'first': ['createCallback', 'slice'],
|
|
'flatten': ['baseFlatten', 'map'],
|
|
'forEach': ['baseCreateCallback', 'baseEach', 'isArray'],
|
|
'forEachRight': ['baseCreateCallback', 'forEach', 'isString', 'keys'],
|
|
'forIn': ['createIterator'],
|
|
'forInRight': ['baseCreateCallback', 'forIn'],
|
|
'forOwn': ['createIterator'],
|
|
'forOwnRight': ['baseCreateCallback', 'keys'],
|
|
'functions': ['forIn', 'isFunction'],
|
|
'groupBy': ['createAggregator'],
|
|
'has': [],
|
|
'identity': [],
|
|
'indexBy': ['createAggregator'],
|
|
'indexOf': ['baseIndexOf', 'sortedIndex'],
|
|
'initial': ['createCallback', 'slice'],
|
|
'intersection': ['cacheIndexOf', 'createCache', 'getArray', 'getIndexOf', 'releaseArray', 'releaseObject'],
|
|
'invert': ['keys'],
|
|
'invoke': ['forEach'],
|
|
'isArguments': [],
|
|
'isArray': [],
|
|
'isBoolean': [],
|
|
'isDate': [],
|
|
'isElement': [],
|
|
'isEmpty': ['forOwn', 'isArguments', 'isFunction'],
|
|
'isEqual': ['baseCreateCallback', 'baseIsEqual'],
|
|
'isFinite': [],
|
|
'isFunction': [],
|
|
'isNaN': ['isNumber'],
|
|
'isNull': [],
|
|
'isNumber': [],
|
|
'isObject': [],
|
|
'isPlainObject': ['isArguments', 'shimIsPlainObject'],
|
|
'isRegExp': [],
|
|
'isString': [],
|
|
'isUndefined': [],
|
|
'keys': ['isArguments', 'isObject', 'shimKeys'],
|
|
'last': ['createCallback', 'slice'],
|
|
'lastIndexOf': [],
|
|
'lodash': ['isArray', 'lodashWrapper'],
|
|
'map': ['baseEach', 'createCallback', 'isArray'],
|
|
'max': ['baseEach', 'charAtCallback', 'createCallback', 'isArray', 'isString'],
|
|
'memoize': ['isFunction'],
|
|
'merge': ['baseCreateCallback', 'baseMerge', 'getArray', 'isObject', 'releaseArray'],
|
|
'min': ['baseEach', 'charAtCallback', 'createCallback', 'isArray', 'isString'],
|
|
'mixin': ['forEach', 'functions', 'isFunction', 'lodash'],
|
|
'noConflict': [],
|
|
'omit': ['baseFlatten', 'createCallback', 'forIn', 'getIndexOf'],
|
|
'once': ['isFunction'],
|
|
'pairs': ['keys'],
|
|
'parseInt': ['isString'],
|
|
'partial': ['createBound'],
|
|
'partialRight': ['createBound'],
|
|
'pick': ['baseFlatten', 'createCallback', 'forIn', 'isObject'],
|
|
'pluck': ['map'],
|
|
'pull': [],
|
|
'random': [],
|
|
'range': [],
|
|
'reduce': ['baseCreateCallback', 'baseEach', 'isArray'],
|
|
'reduceRight': ['baseCreateCallback', 'forEachRight'],
|
|
'reject': ['createCallback', 'filter'],
|
|
'remove': ['createCallback'],
|
|
'rest': ['createCallback', 'slice'],
|
|
'result': ['isFunction'],
|
|
'runInContext': ['defaults', 'pick'],
|
|
'shuffle': ['forEach'],
|
|
'size': ['keys'],
|
|
'some': ['baseEach', 'createCallback', 'isArray'],
|
|
'sortBy': ['compareAscending', 'createCallback', 'forEach', 'getObject', 'releaseObject'],
|
|
'sortedIndex': ['createCallback', 'identity'],
|
|
'tap': [],
|
|
'template': ['defaults', 'escape', 'escapeStringChar', 'keys', 'values'],
|
|
'throttle': ['debounce', 'getObject', 'isFunction', 'isObject', 'releaseObject'],
|
|
'times': ['baseCreateCallback'],
|
|
'toArray': ['isString', 'slice', 'values'],
|
|
'transform': ['baseCreateCallback', 'baseEach', 'createObject', 'forOwn', 'isArray'],
|
|
'unescape': ['keys', 'unescapeHtmlChar'],
|
|
'union': ['baseFlatten', 'baseUniq'],
|
|
'uniq': ['baseUniq', 'createCallback'],
|
|
'uniqueId': [],
|
|
'values': ['keys'],
|
|
'where': ['filter'],
|
|
'without': ['difference'],
|
|
'wrap': ['isFunction'],
|
|
'wrapperChain': [],
|
|
'wrapperToString': [],
|
|
'wrapperValueOf': [],
|
|
'zip': ['max', 'pluck'],
|
|
'zipObject': [],
|
|
|
|
// private functions
|
|
'baseClone': ['assign', 'baseEach', 'forOwn', 'getArray', 'isArray', 'isObject', 'isNode', 'releaseArray', 'slice'],
|
|
'baseCreateCallback': ['bind', 'identity', 'setBindData'],
|
|
'baseEach': ['createIterator'],
|
|
'baseFlatten': ['isArguments', 'isArray'],
|
|
'baseIndexOf': [],
|
|
'baseIsEqual': ['forIn', 'getArray', 'isArguments', 'isFunction', 'isNode', 'releaseArray'],
|
|
'baseMerge': ['forEach', 'forOwn', 'isArray', 'isPlainObject'],
|
|
'baseUniq': ['cacheIndexOf', 'createCache', 'getArray', 'getIndexOf', 'releaseArray', 'releaseObject'],
|
|
'cacheIndexOf': ['baseIndexOf'],
|
|
'cachePush': [],
|
|
'charAtCallback': [],
|
|
'compareAscending': [],
|
|
'createAggregator': ['createCallback', 'forEach'],
|
|
'createBound': ['createObject', 'isFunction', 'isObject', 'setBindData'],
|
|
'createCache': ['cachePush', 'getObject', 'releaseObject'],
|
|
'createIterator': ['baseCreateCallback', 'getObject', 'isArguments', 'isArray', 'isString', 'iteratorTemplate', 'releaseObject'],
|
|
'createObject': [ 'isObject', 'noop'],
|
|
'escapeHtmlChar': [],
|
|
'escapeStringChar': [],
|
|
'getArray': [],
|
|
'getIndexOf': ['baseIndexOf', 'indexOf'],
|
|
'getObject': [],
|
|
'isNode': [],
|
|
'iteratorTemplate': [],
|
|
'lodashWrapper': [],
|
|
'noop': [],
|
|
'releaseArray': [],
|
|
'releaseObject': [],
|
|
'setBindData': ['getObject', 'noop', 'releaseObject'],
|
|
'shimIsPlainObject': ['forIn', 'isArguments', 'isFunction', 'isNode'],
|
|
'shimKeys': ['createIterator'],
|
|
'slice': [],
|
|
'unescapeHtmlChar': [],
|
|
|
|
// used by the `backbone` and `underscore` builds
|
|
'findWhere': ['where']
|
|
};
|
|
|
|
/** Used to track Lo-Dash property dependencies of identifiers */
|
|
var propDependencyMap = {
|
|
'at': ['support'],
|
|
'baseClone': ['support'],
|
|
'baseIsEqual': ['support'],
|
|
'bind': ['support'],
|
|
'createBound': ['support'],
|
|
'forEachRight': ['support'],
|
|
'isArguments': ['support'],
|
|
'isEmpty': ['support'],
|
|
'isPlainObject': ['support'],
|
|
'iteratorTemplate': ['support'],
|
|
'keys': ['support'],
|
|
'shimIsPlainObject': ['support'],
|
|
'template': ['templateSettings'],
|
|
'toArray': ['support']
|
|
};
|
|
|
|
/** Used to track variable dependencies of identifiers */
|
|
var varDependencyMap = {
|
|
'assign': ['defaultsIteratorOptions'],
|
|
'baseEach': ['eachIteratorOptions'],
|
|
'baseIsEqual': ['objectTypes'],
|
|
'baseUniq': ['largeArraySize'],
|
|
'bind': ['reNative'],
|
|
'cacheIndexOf': ['keyPrefix'],
|
|
'cachePush': ['keyPrefix'],
|
|
'createIterator': ['indicatorObject', 'objectTypes'],
|
|
'createBound': ['reNative'],
|
|
'createObject': ['reNative'],
|
|
'defaults': ['defaultsIteratorOptions'],
|
|
'defer': ['objectTypes', 'reNative'],
|
|
'difference': ['largeArraySize'],
|
|
'escape': ['reUnescapedHtml'],
|
|
'escapeHtmlChar': ['htmlEscapes'],
|
|
'forIn': ['eachIteratorOptions', 'forOwnIteratorOptions'],
|
|
'forOwn': ['eachIteratorOptions', 'forOwnIteratorOptions'],
|
|
'forOwnIteratorOptions': ['eachIteratorOptions'],
|
|
'getArray': ['arrayPool'],
|
|
'getObject': ['objectPool'],
|
|
'htmlUnescapes': ['htmlEscapes'],
|
|
'intersection': ['largeArraySize'],
|
|
'isArray': ['reNative'],
|
|
'isObject': ['objectTypes'],
|
|
'isPlainObject': ['reNative'],
|
|
'isRegExp': ['objectTypes'],
|
|
'keys': ['reNative'],
|
|
'memoize': ['keyPrefix'],
|
|
'reEscapedHtml': ['htmlUnescapes'],
|
|
'releaseArray': ['arrayPool', 'maxPoolSize'],
|
|
'releaseObject': ['maxPoolSize', 'objectPool'],
|
|
'reUnescapedHtml': ['htmlEscapes'],
|
|
'setBindData': ['reNative'],
|
|
'support': ['reNative'],
|
|
'template': ['reInterpolate'],
|
|
'templateSettings': ['reInterpolate'],
|
|
'unescape': ['reEscapedHtml'],
|
|
'unescapeHtmlChar': ['htmlUnescapes']
|
|
};
|
|
|
|
/** Used to track the category of identifiers */
|
|
var categoryMap = {
|
|
'Arrays': [
|
|
'compact',
|
|
'difference',
|
|
'findIndex',
|
|
'findLastIndex',
|
|
'first',
|
|
'flatten',
|
|
'indexOf',
|
|
'initial',
|
|
'intersection',
|
|
'last',
|
|
'lastIndexOf',
|
|
'pull',
|
|
'range',
|
|
'remove',
|
|
'rest',
|
|
'sortedIndex',
|
|
'union',
|
|
'uniq',
|
|
'without',
|
|
'zip',
|
|
'zipObject'
|
|
],
|
|
'Chaining': [
|
|
'chain',
|
|
'lodash',
|
|
'tap',
|
|
'wrapperChain',
|
|
'wrapperToString',
|
|
'wrapperValueOf'
|
|
],
|
|
'Collections': [
|
|
'at',
|
|
'contains',
|
|
'countBy',
|
|
'every',
|
|
'filter',
|
|
'find',
|
|
'findLast',
|
|
'findWhere',
|
|
'forEach',
|
|
'forEachRight',
|
|
'groupBy',
|
|
'indexBy',
|
|
'invoke',
|
|
'map',
|
|
'max',
|
|
'min',
|
|
'pluck',
|
|
'reduce',
|
|
'reduceRight',
|
|
'reject',
|
|
'shuffle',
|
|
'size',
|
|
'some',
|
|
'sortBy',
|
|
'toArray',
|
|
'where'
|
|
],
|
|
'Functions': [
|
|
'after',
|
|
'bind',
|
|
'bindAll',
|
|
'bindKey',
|
|
'createCallback',
|
|
'compose',
|
|
'curry',
|
|
'debounce',
|
|
'defer',
|
|
'delay',
|
|
'memoize',
|
|
'once',
|
|
'partial',
|
|
'partialRight',
|
|
'throttle',
|
|
'wrap'
|
|
],
|
|
'Objects': [
|
|
'assign',
|
|
'clone',
|
|
'cloneDeep',
|
|
'defaults',
|
|
'findKey',
|
|
'findLastKey',
|
|
'forIn',
|
|
'forInRight',
|
|
'forOwn',
|
|
'forOwnRight',
|
|
'functions',
|
|
'has',
|
|
'invert',
|
|
'isArguments',
|
|
'isArray',
|
|
'isBoolean',
|
|
'isDate',
|
|
'isElement',
|
|
'isEmpty',
|
|
'isEqual',
|
|
'isFinite',
|
|
'isFunction',
|
|
'isNaN',
|
|
'isNull',
|
|
'isNumber',
|
|
'isObject',
|
|
'isPlainObject',
|
|
'isRegExp',
|
|
'isString',
|
|
'isUndefined',
|
|
'keys',
|
|
'merge',
|
|
'omit',
|
|
'pairs',
|
|
'pick',
|
|
'transform',
|
|
'values'
|
|
],
|
|
'Utilities': [
|
|
'escape',
|
|
'identity',
|
|
'mixin',
|
|
'noConflict',
|
|
'parseInt',
|
|
'random',
|
|
'result',
|
|
'runInContext',
|
|
'template',
|
|
'templateSettings',
|
|
'times',
|
|
'unescape',
|
|
'uniqueId'
|
|
]
|
|
};
|
|
|
|
/** List of Backbone's Lo-Dash dependencies */
|
|
var backboneDependencies = [
|
|
'bind',
|
|
'bindAll',
|
|
'chain',
|
|
'clone',
|
|
'contains',
|
|
'countBy',
|
|
'defaults',
|
|
'escape',
|
|
'every',
|
|
'extend',
|
|
'filter',
|
|
'find',
|
|
'first',
|
|
'forEach',
|
|
'groupBy',
|
|
'has',
|
|
'indexOf',
|
|
'initial',
|
|
'invert',
|
|
'invoke',
|
|
'isArray',
|
|
'isEmpty',
|
|
'isEqual',
|
|
'isFunction',
|
|
'isObject',
|
|
'isRegExp',
|
|
'isString',
|
|
'keys',
|
|
'last',
|
|
'lastIndexOf',
|
|
'lodash',
|
|
'map',
|
|
'max',
|
|
'min',
|
|
'mixin',
|
|
'omit',
|
|
'once',
|
|
'pairs',
|
|
'pick',
|
|
'reduce',
|
|
'reduceRight',
|
|
'reject',
|
|
'rest',
|
|
'result',
|
|
'shuffle',
|
|
'size',
|
|
'some',
|
|
'sortBy',
|
|
'sortedIndex',
|
|
'toArray',
|
|
'uniqueId',
|
|
'value',
|
|
'values',
|
|
'without',
|
|
'wrapperChain',
|
|
'wrapperValueOf'
|
|
];
|
|
|
|
/** List of all function categories */
|
|
var allCategories = _.keys(categoryMap);
|
|
|
|
/** List of all the ways to export the `lodash` function */
|
|
var allExports = [
|
|
'amd',
|
|
'commonjs',
|
|
'global',
|
|
'node'
|
|
];
|
|
|
|
/** List of variables with complex assignments */
|
|
var complexVars = [
|
|
'cloneableClasses',
|
|
'contextProps',
|
|
'ctorByClass',
|
|
'freeGlobal',
|
|
'nonEnumProps',
|
|
'shadowedProps',
|
|
'support',
|
|
'whitespace'
|
|
];
|
|
|
|
/** Used to inline `iteratorTemplate` */
|
|
var iteratorOptions = [
|
|
'args',
|
|
'array',
|
|
'bottom',
|
|
'firstArg',
|
|
'init',
|
|
'keys',
|
|
'loop',
|
|
'shadowedProps',
|
|
'support',
|
|
'top',
|
|
'useHas'
|
|
];
|
|
|
|
/** List of Lo-Dash only functions */
|
|
var lodashOnlyFuncs = [
|
|
'at',
|
|
'bindKey',
|
|
'cloneDeep',
|
|
'createCallback',
|
|
'curry',
|
|
'findIndex',
|
|
'findKey',
|
|
'findLast',
|
|
'findLastIndex',
|
|
'findLastKey',
|
|
'forEachRight',
|
|
'forIn',
|
|
'forInRight',
|
|
'forOwn',
|
|
'forOwnRight',
|
|
'indexBy',
|
|
'isPlainObject',
|
|
'merge',
|
|
'parseInt',
|
|
'partialRight',
|
|
'pull',
|
|
'remove',
|
|
'runInContext',
|
|
'transform',
|
|
'wrapperToString'
|
|
];
|
|
|
|
/** List of private functions */
|
|
var privateFuncs = [
|
|
'baseClone',
|
|
'baseCreateCallback',
|
|
'baseEach',
|
|
'baseFlatten',
|
|
'baseIndexOf',
|
|
'baseIsEqual',
|
|
'baseMerge',
|
|
'baseUniq',
|
|
'cacheIndexOf',
|
|
'cachePush',
|
|
'charAtCallback',
|
|
'compareAscending',
|
|
'createBound',
|
|
'createCache',
|
|
'createIterator',
|
|
'escapeHtmlChar',
|
|
'escapeStringChar',
|
|
'getArray',
|
|
'getObject',
|
|
'isNode',
|
|
'iteratorTemplate',
|
|
'lodashWrapper',
|
|
'noop',
|
|
'releaseArray',
|
|
'releaseObject',
|
|
'setBindData',
|
|
'shimIsPlainObject',
|
|
'shimKeys',
|
|
'slice',
|
|
'unescapeHtmlChar'
|
|
];
|
|
|
|
/** List of all property dependencies */
|
|
var propDependencies = _.uniq(_.transform(propDependencyMap, function(result, propNames) {
|
|
push.apply(result, propNames);
|
|
}, []));
|
|
|
|
/** List of all variable dependencies */
|
|
var varDependencies = _.uniq(_.transform(varDependencyMap, function(result, varNames) {
|
|
push.apply(result, varNames);
|
|
}, []));
|
|
|
|
/** List of all functions */
|
|
var allFuncs = _.difference(_.keys(funcDependencyMap), propDependencies, varDependencies).filter(function(key) {
|
|
var type = typeof _[key];
|
|
return type == 'function' || type == 'undefined';
|
|
});
|
|
|
|
/** List of Lo-Dash functions */
|
|
var lodashFuncs = _.difference(allFuncs, privateFuncs, ['findWhere']);
|
|
|
|
/** List of Underscore functions */
|
|
var underscoreFuncs = _.difference(allFuncs, lodashOnlyFuncs, privateFuncs);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Adds build `commands` to the copyright/license header of the `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {Array} [commands=[]] An array of commands.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function addCommandsToHeader(source, commands) {
|
|
return source.replace(/(\/\**\n)( \*)( *@license[\s*]+)( *Lo-Dash [\w.-]+)(.*)/, function() {
|
|
// remove `node path/to/build.js` from `commands`
|
|
if (reNode.test(commands[0])) {
|
|
commands.splice(0, 2);
|
|
}
|
|
// add quotes to commands with spaces or equals signs
|
|
commands = _.map(commands, function(command) {
|
|
var separator = command.match(/[= ]/);
|
|
if (separator) {
|
|
separator = separator[0];
|
|
var pair = command.split(separator);
|
|
command = pair[0] + separator + '"' + pair[1] + '"';
|
|
}
|
|
// escape newlines, carriage returns, multi-line comment end tokens
|
|
command = command
|
|
.replace(/\n/g, '\\n')
|
|
.replace(/\r/g, '\\r')
|
|
.replace(/\*\//g, '*\\/');
|
|
|
|
return command;
|
|
});
|
|
// add build commands to copyright/license header
|
|
var parts = slice.call(arguments, 1);
|
|
return (
|
|
parts[0] +
|
|
parts[1] +
|
|
parts[2] + parts[3] + ' (Custom Build)' + parts[4] + '\n' +
|
|
parts[1] + ' Build: `lodash ' + commands.join(' ') + '`'
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Adds support for Underscore style chaining to the `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {Boolean} [isModularize=false] A flag to specify a modularize build
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function addUnderscoreChaining(source, isModularize) {
|
|
// remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments
|
|
source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, '');
|
|
|
|
// remove `lodash.prototype` batch method assignments
|
|
source = source.replace(/(?:\s*\/\/.*)*\n( *)forOwn\(lodash,[\s\S]+?\n\1}.+/g, '');
|
|
|
|
// replace `_.mixin`
|
|
if (!isModularize) {
|
|
source = replaceFunction(source, 'mixin', [
|
|
'function mixin(object) {',
|
|
' forEach(functions(object), function(methodName) {',
|
|
' var func = lodash[methodName] = object[methodName];',
|
|
'',
|
|
' lodash.prototype[methodName] = function() {',
|
|
' var args = [this.__wrapped__];',
|
|
' push.apply(args, arguments);',
|
|
'',
|
|
' var result = func.apply(lodash, args);',
|
|
' if (this.__chain__) {',
|
|
' result = new lodashWrapper(result);',
|
|
' result.__chain__ = true;',
|
|
' }',
|
|
' return result;',
|
|
' };',
|
|
' });',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
else {
|
|
source = replaceFunction(source, 'mixin', [
|
|
'function mixin(object, source) {',
|
|
' var ctor = object,',
|
|
' isFunc = !source || isFunction(ctor);',
|
|
'',
|
|
' if (!source) {',
|
|
' ctor = lodashWrapper;',
|
|
' source = object;',
|
|
' object = lodash;',
|
|
' }',
|
|
' forEach(functions(source), function(methodName) {',
|
|
' var func = object[methodName] = source[methodName];',
|
|
' if (isFunc) {',
|
|
' ctor.prototype[methodName] = function() {',
|
|
' var args = [this.__wrapped__];',
|
|
' push.apply(args, arguments);',
|
|
'',
|
|
' var result = func.apply(object, args);',
|
|
' if (this.__chain__) {',
|
|
' result = new ctor(result);',
|
|
' result.__chain__ = true;',
|
|
' }',
|
|
' return result;',
|
|
' };',
|
|
' }',
|
|
' });',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace wrapper `Array` method assignments
|
|
source = source.replace(/^(?:(?: *\/\/.*\n)*(?: *if *\(.+\n)?( *)(baseEach|forEach)\(\['[\s\S]+?\n\1}\);(?:\n *})?\n+)+/m, function(match, indent, methodName) {
|
|
return indent + [
|
|
'// add `Array` mutator functions to the wrapper',
|
|
methodName + "(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {",
|
|
' var func = arrayRef[methodName];',
|
|
' lodash.prototype[methodName] = function() {',
|
|
' var value = this.__wrapped__;',
|
|
' func.apply(value, arguments);',
|
|
'',
|
|
' // avoid array-like object bugs with `Array#shift` and `Array#splice`',
|
|
' // in Firefox < 10 and IE < 9',
|
|
' if (!support.spliceObjects && value.length === 0) {',
|
|
' delete value[0];',
|
|
' }',
|
|
' return this;',
|
|
' };',
|
|
'});',
|
|
'',
|
|
'// add `Array` accessor functions to the wrapper',
|
|
methodName + "(['concat', 'join', 'slice'], function(methodName) {",
|
|
' var func = arrayRef[methodName];',
|
|
' lodash.prototype[methodName] = function() {',
|
|
' var value = this.__wrapped__,',
|
|
' result = func.apply(value, arguments);',
|
|
'',
|
|
' if (this.__chain__) {',
|
|
' result = new lodashWrapper(result);',
|
|
' result.__chain__ = true;',
|
|
' }',
|
|
' return result;',
|
|
' };',
|
|
'});',
|
|
''
|
|
].join('\n' + indent);
|
|
});
|
|
|
|
// move `mixin(lodash)`
|
|
source = source.replace(getMethodAssignments(source), function(match) {
|
|
// remove `mixin(lodash)`
|
|
match = match.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\).+/, '');
|
|
|
|
// insert `mixin(lodash)` before `_.VERSION`
|
|
return match.replace(/(?:\n *\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n( *)lodash\.VERSION/, function(match, indent) {
|
|
return [
|
|
'',
|
|
'// add functions to `lodash.prototype`',
|
|
'mixin(lodash);',
|
|
match
|
|
].join('\n' + indent);
|
|
});
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Creates modules based on the provided build state.
|
|
*
|
|
* @private
|
|
* @param {Object} state The build state object.
|
|
*/
|
|
function buildModule(state) {
|
|
var buildFuncs = state.buildFuncs,
|
|
funcDepMap = state.funcDepMap,
|
|
includeProps = state.includeProps,
|
|
includeVars = state.includeVars,
|
|
isAMD = state.isAMD,
|
|
isBackbone = state.isBackbone,
|
|
isCommonJS = state.isCommonJS,
|
|
isCSP = state.isCSP,
|
|
isGlobal = state.isGlobal,
|
|
isLegacy = state.isLegacy,
|
|
isMapped = state.isMapped,
|
|
isMobile = state.isMobile,
|
|
isModern = state.isModern,
|
|
isNode = state.isNode,
|
|
isStdOut = state.isStdOut,
|
|
isStrict = state.isStrict,
|
|
isUnderscore = state.isUnderscore,
|
|
outputPath = state.outputPath,
|
|
propDepMap = state.propDepMap,
|
|
varDepMap = state.varDepMap;
|
|
|
|
var empty = [],
|
|
identifiers = _.pull(buildFuncs.concat(includeProps, includeVars), 'lodash'),
|
|
sep = '/';
|
|
|
|
var categories = _.uniq(_.compact(identifiers.map(function(identifier) {
|
|
return getCategory(identifier, funcDepMap);
|
|
}))).sort();
|
|
|
|
var topLevel = {
|
|
'lodash': true,
|
|
'support': true
|
|
};
|
|
|
|
var getDepPath = function(dep, fromPath) {
|
|
var toPath = getPath(dep),
|
|
relative = path.relative(fromPath || '', toPath).replace(RegExp(path.sepEscaped, 'g'), sep);
|
|
|
|
if (relative.charAt(0) != '.') {
|
|
relative = '.' + (relative ? sep + relative : '');
|
|
}
|
|
return relative + sep + dep;
|
|
};
|
|
|
|
var getDepPaths = function(dependencies, fromPath) {
|
|
return dependencies.map(function(dep) {
|
|
return getDepPath(dep, fromPath);
|
|
});
|
|
};
|
|
|
|
var getPath = function(identifier) {
|
|
return topLevel[identifier]
|
|
? ''
|
|
: (getCategory(identifier, funcDepMap) || 'internals').toLowerCase() + sep;
|
|
};
|
|
|
|
// prepare state
|
|
state.plusFuncs = state.minusFuncs = empty;
|
|
state.isAMD = state.isCommonJS = state.isGlobal = state.isNode = false;
|
|
|
|
// provide a destination if one isn't given
|
|
if (!outputPath) {
|
|
outputPath = '.' + path.sep + 'modularize';
|
|
}
|
|
// create modules for each identifier
|
|
identifiers.forEach(function(identifier) {
|
|
var modulePath = getPath(identifier),
|
|
iife = [];
|
|
|
|
var deps = getDependencies(identifier, funcDepMap, true)
|
|
.concat(propDepMap[identifier] || arrayRef)
|
|
.concat(varDepMap[identifier] || arrayRef)
|
|
.sort();
|
|
|
|
var depArgs = deps.join(', '),
|
|
depPaths = '[' + (deps.length ? "'" + getDepPaths(deps, modulePath).join("', '") + "'" : '') + '], ';
|
|
|
|
if (isAMD) {
|
|
iife.push(
|
|
'define(' + depPaths + 'function(' + depArgs + ') {',
|
|
'%output%',
|
|
' return ' + identifier + ';',
|
|
'});'
|
|
);
|
|
}
|
|
state.buildFuncs = state.includeFuncs = state.includeProps = state.includeVars = empty;
|
|
state.iife = iife.join('\n');
|
|
state.outputPath = path.join(outputPath, modulePath + identifier + '.js');
|
|
|
|
var include = [identifier];
|
|
if (_.contains(includeProps, identifier)) {
|
|
state.includeProps = include;
|
|
}
|
|
else if (_.contains(includeVars, identifier)) {
|
|
state.includeVars = include;
|
|
}
|
|
else {
|
|
state.buildFuncs = state.includeFuncs = include;
|
|
}
|
|
build(state);
|
|
});
|
|
|
|
// create lodash module
|
|
(function() {
|
|
var categoryDeps = _.invoke(categories, 'toLowerCase'),
|
|
identifier = 'lodash',
|
|
modulePath = getPath(identifier);
|
|
|
|
var deps = getDependencies(identifier, funcDepMap, true)
|
|
.concat(propDepMap[identifier] || arrayRef)
|
|
.concat(varDepMap[identifier] || arrayRef)
|
|
.sort();
|
|
|
|
var categoryDepPaths = categoryDeps.map(function(dep) { return './' + dep; }),
|
|
depArgs = categoryDeps.concat(deps).join(', '),
|
|
depPaths = categoryDepPaths.concat(getDepPaths(deps, modulePath)),
|
|
iife = [];
|
|
|
|
depPaths = '[' + (depPaths.length ? "'" + depPaths.join("', '") + "'" : '') + '], ';
|
|
|
|
if (isAMD) {
|
|
iife.push(
|
|
'define(' + depPaths + 'function(' + depArgs + ') {',
|
|
'%output%',
|
|
' return lodash;',
|
|
'});'
|
|
);
|
|
}
|
|
state.iife = iife.join('\n');
|
|
state.buildFuncs = state.includeFuncs = [identifier];
|
|
state.includeProps = state.includeVars = empty;
|
|
state.outputPath = path.join(outputPath, identifier + '.js');
|
|
|
|
build(state, function(data) {
|
|
var source = data.source;
|
|
|
|
// add category namespaces to each lodash function assignment
|
|
source = source.replace(/(lodash(?:\.prototype)?\.\w+\s*=\s*)(\w+)/g, function(match, prelude, identifier) {
|
|
return prelude + getCategory(identifier, funcDepMap).toLowerCase() + '.' + identifier;
|
|
});
|
|
|
|
if (_.contains(identifiers, 'mixin')) {
|
|
source = source.replace(/^ *lodashWrapper\.prototype\s*=[^;]+;\n/m, function(match) {
|
|
return match + [
|
|
'',
|
|
' // wrap `_.mixin` so it works when provided only one argument',
|
|
' mixin = (function(fn) {',
|
|
' return function(object, source) {',
|
|
' if (!source) {',
|
|
' source = object;',
|
|
' object = lodash;',
|
|
' }',
|
|
' return fn(object, source);',
|
|
' };',
|
|
' }(mixin));',
|
|
''
|
|
].join('\n');
|
|
});
|
|
}
|
|
|
|
source = source.replace(/^ *return lodash;$/m, function(match) {
|
|
var prelude = '';
|
|
if (_.contains(identifiers, 'support')) {
|
|
prelude += ' lodash.support = support;\n';
|
|
}
|
|
if (_.contains(identifiers, 'templateSettings')) {
|
|
prelude += ' (lodash.templateSettings = utilities.templateSettings).imports._ = lodash;\n';
|
|
}
|
|
return prelude + match;
|
|
});
|
|
|
|
data.source = source;
|
|
defaultBuildCallback(data);
|
|
});
|
|
}());
|
|
|
|
// clear state
|
|
state.buildFuncs = state.includeFuncs = state.includeProps = state.includeVars = empty;
|
|
|
|
// create category modules
|
|
categories.forEach(function(category) {
|
|
var deps = _.intersection(categoryMap[category], identifiers).sort(),
|
|
depArgs = deps.join(', '),
|
|
depPaths = "['" + getDepPaths(deps).join("', '") + "'], ",
|
|
iife = [];
|
|
|
|
if (isAMD) {
|
|
iife.push(
|
|
'define(' + depPaths + 'function(' + depArgs + ') {',
|
|
'%output%',
|
|
' return {',
|
|
deps.map(function(dep) { return " '" + dep + "': " + dep; }).join(',\n'),
|
|
' };',
|
|
'});'
|
|
);
|
|
}
|
|
state.iife = iife.join('\n');
|
|
state.outputPath = path.join(outputPath, category.toLowerCase() + '.js');
|
|
build(state);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Compiles template files matched by the given file path `pattern` into a
|
|
* single source, extending `_.templates` with precompiled templates named after
|
|
* each template file's basename.
|
|
*
|
|
* @private
|
|
* @param {String} [pattern='<cwd>/*.jst'] The file path pattern.
|
|
* @param {Object} options The template options object.
|
|
* @returns {String} Returns the compiled source.
|
|
*/
|
|
function buildTemplate(pattern, options) {
|
|
pattern || (pattern = path.join(cwd, '*.jst'));
|
|
|
|
var directory = fs.realpathSync(path.dirname(pattern));
|
|
|
|
var source = [
|
|
';(function(window) {',
|
|
' var undefined;',
|
|
'',
|
|
' var objectTypes = {',
|
|
" 'function': true,",
|
|
" 'object': true",
|
|
' };',
|
|
'',
|
|
" var freeExports = objectTypes[typeof exports] && typeof require == 'function' && exports;",
|
|
'',
|
|
" var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module;",
|
|
'',
|
|
" var freeGlobal = objectTypes[typeof global] && global;",
|
|
' if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {',
|
|
' window = freeGlobal;',
|
|
' }',
|
|
'',
|
|
' var templates = {},',
|
|
' _ = window._;',
|
|
''
|
|
];
|
|
|
|
// convert to a regexp
|
|
pattern = RegExp(
|
|
path.basename(pattern)
|
|
.replace(/[.+?^=!:${}()|[\]\/\\]/g, '\\$&')
|
|
.replace(/\*/g, '.*?') + '$'
|
|
);
|
|
|
|
fs.readdirSync(directory).forEach(function(filename) {
|
|
if (!pattern.test(filename)) {
|
|
return;
|
|
}
|
|
var filePath = path.join(directory, filename),
|
|
text = fs.readFileSync(filePath, 'utf8'),
|
|
precompiled = cleanupCompiled(getFunctionSource(_.template(text, null, options), 2)),
|
|
prop = filename.replace(/\..*$/, '');
|
|
|
|
source.push(" templates['" + prop.replace(/['\n\r\t]/g, '\\$&') + "'] = " + precompiled + ';', '');
|
|
});
|
|
|
|
source.push(
|
|
" if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {",
|
|
" define(['" + options.moduleId + "'], function(lodash) {",
|
|
' _ = lodash;',
|
|
' lodash.templates = lodash.extend(lodash.templates || {}, templates);',
|
|
' });',
|
|
" } else if (freeExports && !freeExports.nodeType) {",
|
|
" _ = require('" + options.moduleId + "');",
|
|
" if (freeModule) {",
|
|
' (freeModule.exports = templates).templates = templates;',
|
|
' } else {',
|
|
' freeExports.templates = templates;',
|
|
' }',
|
|
' } else if (_) {',
|
|
' _.templates = _.extend(_.templates || {}, templates);',
|
|
' }',
|
|
'}(this));'
|
|
);
|
|
|
|
return source.join('\n');
|
|
}
|
|
|
|
/**
|
|
* Capitalizes a given string.
|
|
*
|
|
* @private
|
|
* @param {String} string The string to capitalize.
|
|
* @returns {String} Returns the capitalized string.
|
|
*/
|
|
function capitalize(string) {
|
|
return string[0].toUpperCase() + string.slice(1);
|
|
}
|
|
|
|
/**
|
|
* Removes unnecessary semicolons and whitespace from compiled code.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function cleanupCompiled(source) {
|
|
return source
|
|
.replace(/\b(function) *(\()/g, '$1$2')
|
|
.replace(/([{}]) *;/g, '$1');
|
|
}
|
|
|
|
/**
|
|
* Removes unnecessary comments, and whitespace.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function cleanupSource(source) {
|
|
return source
|
|
// consolidate consecutive horizontal rule comment separators
|
|
.replace(/(?:\s*\/\*-+\*\/\s*){2,}/g, function(separators) {
|
|
return separators.match(/^\s*/)[0] + separators.slice(separators.lastIndexOf('/*'));
|
|
})
|
|
// remove unneeded single line comments
|
|
.replace(/(\{\s*)?(\n *\/\/.*)(\s*\})/g, function(match, prelude, comment, postlude) {
|
|
return (!prelude && postlude) ? postlude : match;
|
|
})
|
|
// remove unneeded horizontal rule comment separators
|
|
.replace(/(\{\n)\s*\/\*-+\*\/\n|^ *\/\*-+\*\/\n(\s*\})/gm, '$1$2')
|
|
// remove lines with just spaces and semicolons
|
|
.replace(/^ *;\n/gm, '')
|
|
// remove trailing spaces from lines
|
|
.replace(/ *$/gm, '')
|
|
// consolidate multiple newlines
|
|
.replace(/\n{3,}/g, '\n\n')
|
|
// add trailing newline
|
|
.trim() + '\n'
|
|
}
|
|
|
|
/**
|
|
* The default callback used for `build` invocations.
|
|
*
|
|
* @private
|
|
* @param {Object} data The data for the given build.
|
|
* gzip - The gzipped output of the built source
|
|
* outputPath - The path where the built source is to be written
|
|
* source - The built source output
|
|
* sourceMap - The source map output
|
|
*/
|
|
function defaultBuildCallback(data) {
|
|
var outputPath = data.outputPath,
|
|
sourceMap = data.sourceMap;
|
|
|
|
if (outputPath) {
|
|
fs.writeFileSync(outputPath, data.source, 'utf8');
|
|
if (sourceMap) {
|
|
fs.writeFileSync(path.join(path.dirname(outputPath), path.basename(outputPath, '.js') + '.map'), sourceMap, 'utf8');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Writes the help message to standard output.
|
|
*
|
|
* @private
|
|
*/
|
|
function displayHelp() {
|
|
console.log([
|
|
'',
|
|
' Commands:',
|
|
'',
|
|
' lodash backbone Build with only functions required by Backbone',
|
|
' lodash legacy Build tailored for older environments without ES5 support',
|
|
' lodash mobile Build without function compilation and bug fixes for old browsers',
|
|
' lodash modern Build tailored for newer environments with ES5 support',
|
|
' lodash strict Build with `_.assign`, `_.bindAll`, & `_.defaults` in strict mode',
|
|
' lodash underscore Build tailored for projects already using Underscore',
|
|
'',
|
|
' lodash modularize Splits Lo-Dash into modules',
|
|
'',
|
|
' lodash include=... Comma separated function/category names to include in the build',
|
|
' lodash minus=... Comma separated function/category names to remove from the build',
|
|
' lodash plus=... Comma separated function/category names to add to the build',
|
|
' lodash category=... Comma separated categories of functions to include in the build (case-insensitive)',
|
|
' (i.e. “arrays”, “chaining”, “collections”, “functions”, “objects”, and “utilities”)',
|
|
' lodash exports=... Comma separated names of ways to export the `lodash` function',
|
|
' (i.e. “amd”, “commonjs”, “global”, “node”, and “none”)',
|
|
' lodash iife=... Code to replace the immediately-invoked function expression that wraps Lo-Dash',
|
|
' (e.g. `lodash iife="!function(window){%output%}(this)"`)',
|
|
'',
|
|
' lodash template=... File path pattern used to match template files to precompile',
|
|
' (e.g. `lodash template=./*.jst`)',
|
|
' lodash settings=... Template settings used when precompiling templates',
|
|
' (e.g. `lodash settings="{interpolate:/{{([\\s\\S]+?)}}/g}"`)',
|
|
' lodash moduleId=... The AMD module ID, which defaults to “lodash”, for precompiled templates',
|
|
'',
|
|
' All commands, except `backbone`, `csp`, `legacy`, `mobile`, `modern`, and `underscore`, may be combined.',
|
|
' Unless specified by `-o` or `--output`, all files created are saved to the current working directory.',
|
|
'',
|
|
' Options:',
|
|
'',
|
|
' -c, --stdout Write output to standard output',
|
|
' -d, --debug Write only the non-minified development output',
|
|
' -h, --help Display help information',
|
|
' -m, --minify Write only the minified production output',
|
|
' -o, --output Write output to a given path/filename',
|
|
' -p, --source-map Generate a source map for the minified output, using an optional source map URL',
|
|
' -s, --silent Skip status updates normally logged to the console',
|
|
' -V, --version Output current version of Lo-Dash',
|
|
''
|
|
].join('\n'));
|
|
}
|
|
|
|
/**
|
|
* Gets the aliases associated with a given function name.
|
|
*
|
|
* @private
|
|
* @param {String} funcName The name of the function to get aliases for.
|
|
* @param {Object} [depMap] The dependency map used to validate aliases.
|
|
* @returns {Array} Returns an array of aliases.
|
|
*/
|
|
function getAliases(funcName, depMap) {
|
|
var aliases = hasOwnProperty.call(realToAliasMap, funcName) && realToAliasMap[funcName];
|
|
depMap || (depMap = funcDependencyMap);
|
|
return _.reject(aliases, function(funcName) {
|
|
return hasOwnProperty.call(depMap, funcName);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gets the category of the given `identifier`.
|
|
*
|
|
* @private
|
|
* @param {String} identifier The identifier to query.
|
|
* @param {Object} [depMap] The dependency map used to resolve the identifier.
|
|
* @returns {String} Returns the identifier's category.
|
|
*/
|
|
function getCategory(identifier, depMap) {
|
|
identifier = getRealName(identifier, depMap);
|
|
return _.findKey(categoryMap, function(identifiers) {
|
|
return _.contains(identifiers, identifier);
|
|
}) || '';
|
|
}
|
|
|
|
/**
|
|
* Gets the `createObject` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the fork.
|
|
*/
|
|
function getCreateObjectFork(source) {
|
|
var result = source.match(/(?:\s*\/\/.*)*\n( *)if *\((?:!nativeCreate)[\s\S]+?\n *};\n\1}/);
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Gets the `_.defer` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the fork.
|
|
*/
|
|
function getDeferFork(source) {
|
|
var result = source.match(/(?:\s*\/\/.*)*\n( *)if *\(isV8 *&& *freeModule[\s\S]+?\n\1}/);
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Gets an array of depenants for the given function name(s).
|
|
*
|
|
* @private
|
|
* @param {String} funcName A function name or array of function names.
|
|
* @param {Object} [depMap] The dependency map used to look up dependants.
|
|
* @param- {Array} [stackA=[]] Internally used track queried function names.
|
|
* @returns {Array} Returns an array of function dependants.
|
|
*/
|
|
function getDependants(funcName, depMap, stack) {
|
|
var funcNames = _.isArray(funcName) ? funcName : [funcName];
|
|
depMap || (depMap = funcDependencyMap);
|
|
stack || (stack = []);
|
|
|
|
// iterate over the dependency map, adding names of functions that have `funcName` as a dependency
|
|
return _.uniq(_.transform(depMap, function(result, deps, otherName) {
|
|
if (!_.contains(stack, otherName) && _.some(funcNames, function(funcName) {
|
|
return _.contains(deps, funcName);
|
|
})) {
|
|
stack.push(otherName);
|
|
result.push(otherName);
|
|
push.apply(result, getDependants(otherName, depMap, stack));
|
|
}
|
|
}, []));
|
|
}
|
|
|
|
/**
|
|
* Gets an array of dependencies for a given function name. If an array of
|
|
* dependencies is provided, it will return an array containing the given
|
|
* dependencies plus any additional detected sub-dependencies.
|
|
*
|
|
* @private
|
|
* @param {Array|String} funcName A function name or array of dependencies to query.
|
|
* @param {Object} [depMap] The dependency map used to look up dependants.
|
|
* @param {Boolean} [isShallow=false] A flag to indicate getting only the immediate dependencies.
|
|
* @param- {Array} [stackA=[]] Internally used track queried function names.
|
|
* @returns {Array} Returns an array of function dependencies.
|
|
*/
|
|
function getDependencies(funcName, depMap, isShallow, stack) {
|
|
// juggle arguments
|
|
if (typeof depMap != 'object' && typeof isShallow != 'boolean') {
|
|
isShallow = depMap;
|
|
depMap = null;
|
|
}
|
|
// allow working with ES5 Array methods
|
|
if (typeof isShallow != 'boolean' && isShallow != null) {
|
|
isShallow = false;
|
|
stack = null;
|
|
}
|
|
depMap || (depMap = funcDependencyMap);
|
|
|
|
var deps = _.isArray(funcName)
|
|
? funcName
|
|
: (hasOwnProperty.call(depMap, funcName) && depMap[funcName]);
|
|
|
|
if (!deps || !deps.length) {
|
|
return [];
|
|
}
|
|
if (isShallow) {
|
|
return deps.slice();
|
|
}
|
|
stack || (stack = []);
|
|
|
|
// recursively accumulate the dependencies of the `funcName` function, and
|
|
// the dependencies of its dependencies, and so on
|
|
return _.uniq(_.transform(deps, function(result, otherName) {
|
|
if (!_.contains(stack, otherName)) {
|
|
stack.push(otherName);
|
|
push.apply(result, getDependencies(otherName, depMap, isShallow, stack).concat(otherName));
|
|
}
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Gets the formatted source of the given function.
|
|
*
|
|
* @private
|
|
* @param {Function} func The function to process.
|
|
* @param {Number|String} [indent=0] The level to indent.
|
|
* @returns {String} Returns the formatted source.
|
|
*/
|
|
function getFunctionSource(func, indent) {
|
|
var source = func.source || (func + '');
|
|
|
|
indent || (indent = '');
|
|
if (typeof indent == 'number') {
|
|
indent = Array(indent + 1).join(' ');
|
|
}
|
|
// format leading whitespace
|
|
return source.replace(/\n(?:.*)/g, function(match, index) {
|
|
match = match.slice(1);
|
|
return (
|
|
'\n' + indent +
|
|
(match == '}' && !_.contains(source, '}', index + 2) ? '' : ' ')
|
|
) + match;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gets the indent of the given function.
|
|
*
|
|
* @private
|
|
* @param {Function} func The function to process.
|
|
* @returns {String} Returns the indent.
|
|
*/
|
|
function getIndent(func) {
|
|
return /^ *(?=\S)/m.exec(func.source || func)[0];
|
|
}
|
|
|
|
/**
|
|
* Gets the `_.isArguments` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the fork.
|
|
*/
|
|
function getIsArgumentsFork(source) {
|
|
var result = source.match(/(?:\s*\/\/.*)*\n( *)if *\((?:!support\.argsClass|!isArguments)[\s\S]+?\n *};\n\1}/);
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Gets the `_.isArray` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the fork.
|
|
*/
|
|
function getIsArrayFork(source) {
|
|
return matchFunction(source, 'isArray')
|
|
.replace(/^[\s\S]+?=\s*nativeIsArray\b/, '')
|
|
.replace(/[;\s]+$/, '');
|
|
}
|
|
|
|
/**
|
|
* Gets the `_.isFunction` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the fork.
|
|
*/
|
|
function getIsFunctionFork(source) {
|
|
var result = source.match(/(?:\s*\/\/.*)*\n( *)if *\(isFunction\(\/x\/[\s\S]+?\n *};\n\1}/);
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Gets the Lo-Dash method assignments snippet from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the method assignments snippet.
|
|
*/
|
|
function getMethodAssignments(source) {
|
|
var result = source.match(/\n\n(?:\s*\/\/.*)*\s*lodash\.\w+\s*=[\s\S]+lodash\.\w+\s=.+/);
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Gets the names of identifiers in `source` that belong to the given `category`.
|
|
*
|
|
* @private
|
|
* @param {String} category The category to filter by.
|
|
* @returns {Array} Returns a new array of names.
|
|
*/
|
|
function getNamesByCategory(category) {
|
|
return categoryMap[category] || [];
|
|
}
|
|
|
|
/**
|
|
* Gets the real name, not alias, of a given function name.
|
|
*
|
|
* @private
|
|
* @param {String} funcName The name of the function to resolve.
|
|
* @param {Object} [depMap] The dependency map used to validate the real name.
|
|
* @returns {String} Returns the real function name.
|
|
*/
|
|
function getRealName(funcName, depMap) {
|
|
return (
|
|
!hasOwnProperty.call(depMap || funcDependencyMap, funcName) &&
|
|
hasOwnProperty.call(aliasToRealMap, funcName) &&
|
|
aliasToRealMap[funcName]
|
|
) || funcName;
|
|
}
|
|
|
|
/**
|
|
* Gets the `setBindData` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the fork.
|
|
*/
|
|
function getSetBindDataFork(source) {
|
|
var result = matchFunction(source, 'setBindData').match(/!defineProperty[^:]+:\s*/);
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Creates a sorted array of all variables defined outside of Lo-Dash functions.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {Boolean} [isShallow=false] A flag to indicate looking for varaibles one closure deep.
|
|
* @returns {Array} Returns a new array of variable names.
|
|
*/
|
|
function getVars(source, isShallow) {
|
|
var indentA = isShallow ? ' {2}' : ' {2,4}',
|
|
indentB = isShallow ? ' {6}' : ' {6,8}';
|
|
|
|
var result = _.reduce([
|
|
// match a varaible at the start of a declaration list
|
|
indentA + 'var (\\w+) *=.+?,\\n(?= *\\w+ *=)',
|
|
// match a variable declaration in a declaration list
|
|
indentB + '(\\w+) *=.+?[,;]\\n',
|
|
// match a variable that is not part of a declaration list
|
|
'(' + indentA + ')var (\\w+) *(?:|= *(?:.+?(?:&&\\n[^;]+)?|(?:\\w+\\(|[{[(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n'
|
|
], function(result, reSource) {
|
|
source = source.replace(RegExp('^' + reSource, 'gm'), function(match, indent, varName) {
|
|
if (typeof varName == 'number') {
|
|
varName = indent;
|
|
}
|
|
result.push(varName);
|
|
return '';
|
|
});
|
|
return result;
|
|
}, []);
|
|
|
|
// remove duplicates and function names
|
|
return _.difference(_.uniq(result), allFuncs).sort();
|
|
}
|
|
|
|
/**
|
|
* Determines if a variable, of the given `varName`, is used in `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} varName The name of the variable.
|
|
* @param {Boolean} [isShallow=false] A flag to indicate looking for varaibles one closure deep.
|
|
* @returns {Boolean} Returns `true` if the variable is used, else `false`.
|
|
*/
|
|
function isVarUsed(source, varName, isShallow) {
|
|
var match = matchVar(source, varName, isShallow);
|
|
if (!match) {
|
|
return false;
|
|
}
|
|
// remove the variable assignment from the source
|
|
source = source.replace(match, '');
|
|
return RegExp('[^\\w"\'.]' + varName + '\\b').test(source);
|
|
}
|
|
|
|
/**
|
|
* Searches `source` for a `funcName` function declaration, expression, or
|
|
* assignment and returns the matched snippet.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @param {String} funcName The name of the function to match.
|
|
* @param {Boolean} [leadingComments] A flag to indicate including leading comments.
|
|
* @returns {String} Returns the matched function snippet.
|
|
*/
|
|
function matchFunction(source, funcName, leadingComments) {
|
|
var result = _.reduce([
|
|
// match variable declarations using `createAggregator`, `createIterator` and `template`
|
|
'( *)var ' + funcName + ' *=.*?(?:create[A-Z][a-z]+|template)\\((?:.+|[\\s\\S]+?\\n\\3}?)\\);\\n',
|
|
// match a function declaration
|
|
'( *)function ' + funcName + '\\b[\\s\\S]+?\\n\\3}\\n',
|
|
// match a variable declaration with function expression
|
|
'( *)var ' + funcName + ' *=.*?function\\(.+?\{\\n[\\s\\S]+?\\n\\3}(?:\\(\\)\\))?;\\n',
|
|
// match a simple variable declaration
|
|
' *var ' + funcName + ' *=.+?;\\n'
|
|
], function(result, reSource) {
|
|
return result || (result = source.match(RegExp(
|
|
'(' + multilineComment + ')' +
|
|
'(' + reSource + ')'
|
|
))) && result.slice(1, 3);
|
|
}, null);
|
|
|
|
return result && (
|
|
/@type +Function\b/.test(result[0]) ||
|
|
/(?:function(?:\s+\w+)?\b|create[A-Z][a-z]+|template)\(/.test(result[1]))
|
|
? (leadingComments ? result[0] : '') + result[1]
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Searches `source` for a Lo-Dash property, of the given `propName`, and
|
|
* returns the matched snippet.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @param {String} propName The name of the property to match.
|
|
* @param {Boolean} [leadingComments] A flag to indicate including leading comments.
|
|
* @returns {String} Returns the matched property snippet.
|
|
*/
|
|
function matchProp(source, propName, leadingComments) {
|
|
var result = source.match(RegExp(
|
|
(leadingComments ? multilineComment : '\\n') +
|
|
'(?: {2,4}var ' + propName + '\\b.+|(?: *|.*?=\\s*)lodash\\._?' + propName + '\\s*)=[\\s\\S]+?' +
|
|
'(?:\\(function[\\s\\S]+?\\([^)]*\\)\\);\\n(?=\\n)|' +
|
|
'[;}]\\n(?=\\n(?!\\s*\\(func)))'
|
|
));
|
|
|
|
return result ? result[0] : '';
|
|
}
|
|
|
|
/**
|
|
* Searches `source` for a `varName` variable assignment and returns
|
|
* the matched snippet.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @param {String} varName The name of the variable to match.
|
|
* @param {Boolean} [isShallow=false] A flag to indicate looking for varaibles one closure deep.
|
|
* @returns {String} Returns the matched variable snippet.
|
|
*/
|
|
function matchVar(source, varName, isShallow) {
|
|
var indentA = isShallow ? ' {2}' : ' {2,4}',
|
|
indentB = isShallow ? ' {6}' : ' {6,8}';
|
|
|
|
var reSources = [
|
|
// match a varaible at the start of a declaration list
|
|
indentA + 'var ' + varName + ' *=.+?,\\n(?= *\\w+ *=)',
|
|
// match a variable declaration in a declaration list
|
|
indentB + varName + ' *=.+?[,;]\\n',
|
|
// match a variable that is not part of a declaration list
|
|
'(' + indentA + ')var ' + varName + ' *(?:|= *(?:.+?(?:&&\\n[^;]+)?|(?:\\w+\\(|[{[(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n'
|
|
];
|
|
|
|
// match complex variable assignments
|
|
if (varName != 'freeGlobal' && _.contains(complexVars, varName)) {
|
|
reSources = [
|
|
indentA + 'var ' + varName + ' *=[\\s\\S]+?' +
|
|
'(?:\\(function[\\s\\S]+?\\([^)]*\\)\\);\\n(?=\\n)|' +
|
|
'[;}]\\n(?=\\n(?!\\s*\\(func)))'
|
|
];
|
|
}
|
|
return _.reduce(reSources, function(result, reSource) {
|
|
return result || (result = source.match(RegExp(
|
|
'^' + reSource
|
|
, 'm'))) && result[0];
|
|
}, null) || '';
|
|
}
|
|
|
|
/**
|
|
* Converts a comma separated options string into an array.
|
|
*
|
|
* @private
|
|
* @param {String} value The option to convert.
|
|
* @returns {Array} Returns the new converted array.
|
|
*/
|
|
function optionToArray(value) {
|
|
return _.compact(_.isArray(value)
|
|
? value
|
|
: value.match(/\w+=(.*)$/)[1].split(/, */)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Converts a comma separated options string into an array of function names.
|
|
*
|
|
* @private
|
|
* @param {String} value The option to convert.
|
|
* @param {Object} [depMap] The dependency map used to resolve real names.
|
|
* @returns {Array} Returns the new converted array.
|
|
*/
|
|
function optionToMethodsArray(value, depMap) {
|
|
depMap || (depMap = funcDependencyMap);
|
|
return optionToArray(value).map(function(identifier) {
|
|
// convert aliases to real function names
|
|
return getRealName(identifier, depMap);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes support for Lo-Dash wrapper chaining in `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeChaining(source) {
|
|
source = removeSpliceObjectsFix(source);
|
|
|
|
// remove `_.mixin` call
|
|
source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\).+/, '');
|
|
|
|
// remove all `lodash.prototype` additions
|
|
source = source
|
|
.replace(/(?:\s*\/\/.*)*\n( *)forOwn\(lodash,[\s\S]+?\n\1}.+/g, '')
|
|
.replace(/(?:\s*\/\/.*)*\n( *)(?:baseEach|forEach)\(\['[\s\S]+?\n\1}.+/g, '')
|
|
.replace(/(?:\s*\/\/.*)*\n *lodash\.prototype\.[\s\S]+?;/g, '');
|
|
|
|
// replace `lodash` with a simpler version
|
|
source = replaceFunction(source, 'lodash', [
|
|
'function lodash() {',
|
|
' // no operation performed',
|
|
'}'
|
|
].join('\n'));
|
|
|
|
// replace `lodashWrapper` with `lodash` in `_.mixin`
|
|
source = source.replace(matchFunction(source, 'mixin'), function(match) {
|
|
return match.replace(/\blodashWrapper\b/, 'lodash');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all comments from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeComments(source) {
|
|
return source.replace(/^ *(?:\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/|\/\/.+)\n/gm, '');
|
|
}
|
|
|
|
/**
|
|
* Removes the `createObject` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeCreateObjectFork(source) {
|
|
return source.replace(getCreateObjectFork(source), '');
|
|
}
|
|
|
|
/**
|
|
* Removes the `_.defer` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeDeferFork(source) {
|
|
return source.replace(getDeferFork(source), '');
|
|
}
|
|
|
|
/**
|
|
* Removes ES5 specific optimizations from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeEsOptimization(source) {
|
|
// remove `__bindData__` logic and `setBindData` function calls from `createBound`
|
|
source = source.replace(matchFunction(source, 'createBound'), function(match) {
|
|
return match
|
|
.replace(/(?:\s*\/\/.*)*\n( *)var bindData *=[\s\S]+?\n\1}/, '')
|
|
.replace(/(?:\s*\/\/.*)*\n.+bindData *= *nativeSlice.+/, '')
|
|
.replace(/(?:\s*\/\/.*)*\n.+?setBindData.+/, '');
|
|
});
|
|
|
|
// remove `__bindData__` logic and `setBindData` function calls from `baseCreateCallback`
|
|
source = source.replace(matchFunction(source, 'baseCreateCallback'), function(match) {
|
|
return match
|
|
.replace(/(?:\s*\/\/.*)*\n( *)var bindData *=[\s\S]+?\n\1}/, '')
|
|
.replace(/(?:\s*\/\/.*)*\n( *)if *\(bindData[\s\S]+?\n\1}/, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all references to `identifier` from `createIterator` in `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} identifier The name of the variable or property to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeFromCreateIterator(source, identifier) {
|
|
var snippet = matchFunction(source, 'createIterator');
|
|
if (!snippet) {
|
|
return source;
|
|
}
|
|
// remove data object property assignment
|
|
var modified = snippet.replace(RegExp("^(?: *\\/\\/.*\\n)* *(\\w+)\\." + identifier + " *= *(.+\\n+)", 'm'), function(match, object, postlude) {
|
|
return RegExp('\\b' + object + '\\.').test(postlude) ? postlude : '\n';
|
|
});
|
|
|
|
source = source.replace(snippet, function() {
|
|
return modified;
|
|
});
|
|
|
|
// clip to the `factory` assignment
|
|
snippet = modified.match(/Function\([\s\S]+$/)[0];
|
|
|
|
// remove `factory` arguments
|
|
source = source.replace(snippet, function(match) {
|
|
return match
|
|
.replace(RegExp("[^\\n(,']*?\\b" + identifier + "\\b[^\\n),']*(?:, *)?", 'g'), ' ')
|
|
.replace(/, *(?=',)/, '')
|
|
.replace(/,(?=\s*\))/, '');
|
|
});
|
|
|
|
return removeFromGetObject(source, identifier);
|
|
}
|
|
|
|
/**
|
|
* Removes all references to `identifier` from `getObject` in `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} identifier The name of the property to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeFromGetObject(source, identifier) {
|
|
return source.replace(matchFunction(source, 'getObject'), function(match) {
|
|
// remove object property assignments
|
|
return match
|
|
.replace(RegExp("^(?: *\\/\\/.*\\n)* *'" + identifier + "':.+\\n+", 'm'), '')
|
|
.replace(/,(?=\s*})/, '');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes all references to `identifier` from `releaseObject` in `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} identifier The name of the property to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeFromReleaseObject(source, identifier) {
|
|
return source.replace(matchFunction(source, 'releaseObject'), function(match) {
|
|
// remove object property assignments
|
|
return match.replace(RegExp("(?:(^ *)| *)(\\w+)\\." + identifier + " *= *(.+\\n+)", 'm'), function(match, indent, object, postlude) {
|
|
return (indent || '') + RegExp('\\b' + object + '\\.').test(postlude) ? postlude : '';
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes the `funcName` function declaration, expression, or assignment and
|
|
* associated code from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} funcName The name of the function to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeFunction(source, funcName) {
|
|
var snippet;
|
|
|
|
// defer to specialized removal functions
|
|
if (funcName == 'runInContext') {
|
|
return removeRunInContext(source, funcName);
|
|
}
|
|
// remove function
|
|
if ((snippet = matchFunction(source, funcName, true))) {
|
|
source = source.replace(snippet, '');
|
|
}
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all references to `getIndexOf` from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeGetIndexOf(source) {
|
|
source = removeFunction(source, 'getIndexOf');
|
|
|
|
// replace all `getIndexOf` calls with `baseIndexOf`
|
|
_.each(['baseUniq', 'contains', 'difference', 'intersection', 'omit'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/\bgetIndexOf\(\)/g, 'baseIndexOf');
|
|
});
|
|
});
|
|
|
|
// simplify `isLarge` assignments
|
|
_.each(['baseUniq', 'difference'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/\b(largeArraySize).+?baseIndexOf\b/g, '$1');
|
|
});
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes the `_.isArguments` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeIsArgumentsFork(source) {
|
|
return source.replace(getIsArgumentsFork(source), '');
|
|
}
|
|
|
|
/**
|
|
* Removes the `_.isArray` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeIsArrayFork(source) {
|
|
return source.replace(getIsArrayFork(source), '');
|
|
}
|
|
|
|
/**
|
|
* Removes the `_.isFunction` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeIsFunctionFork(source) {
|
|
return source.replace(getIsFunctionFork(source), '');
|
|
}
|
|
|
|
/**
|
|
* Removes the `Object.keys` object iteration optimization from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeKeysOptimization(source) {
|
|
source = removeFromCreateIterator(source, 'keys');
|
|
|
|
// remove "keys" iterator options
|
|
_.each(['defaultsIteratorOptions', 'eachIteratorOptions'], function(varName) {
|
|
source = source.replace(matchVar(source, varName), function(match) {
|
|
return match
|
|
.replace(/^ *'keys':.+\n+/m, '')
|
|
.replace(/,(?=\s*})/, '');
|
|
});
|
|
});
|
|
|
|
// remove optimized branch in `iteratorTemplate`
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match.replace(/^(?: *\/\/.*\n)* *["']( *)<% *if *\(useHas *&& *keys[\s\S]+?["']\1<% *} *else *{ *%>.+\n([\s\S]+?) *["']\1<% *} *%>.+/m, "'\\n' +\n$2");
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
|
|
/**
|
|
* Removes all Lo-Dash assignments from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeAssignments(source) {
|
|
source = removeMethodAssignments(source);
|
|
|
|
// remove intermediate assignments
|
|
source = source.replace(/(=\s*)lodash\.\w+\s*=\s*/g, '$1');
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes the Lo-Dash method assignments snippet from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeMethodAssignments(source) {
|
|
return source.replace(getMethodAssignments(source), '');
|
|
}
|
|
|
|
/**
|
|
* Removes a Lo-Dash property, of the given `propName`, from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} propName The name of the property to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeProp(source, propName) {
|
|
return source.replace(matchProp(source, propName, true), '');
|
|
}
|
|
|
|
/**
|
|
* Removes all pseudo private Lo-Dash properties from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removePseudoPrivates(source) {
|
|
return source.replace(/^(?: *\/\/.*\s*)* *lodash\._\w+ *=[\s\S]+?;\n/gm, '');
|
|
}
|
|
|
|
/**
|
|
* Removes all `runInContext` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeRunInContext(source) {
|
|
// replace reference in `reThis` assignment
|
|
source = source.replace(/\btest\(runInContext\)/, 'test(function() { return this; })');
|
|
|
|
// remove assignment
|
|
source = source.replace(/^(?: *\/\/.*\s*)* *lodash\.runInContext *=[\s\S]+?;\n/m, '');
|
|
|
|
// remove function scaffolding, leaving most of its content
|
|
source = source.replace(matchFunction(source, 'runInContext', true), function(match) {
|
|
return match
|
|
.replace(/^[\s\S]+?function runInContext[\s\S]+?context *= *context.+| *return lodash[\s\S]+$/g, '')
|
|
.replace(/^ {4}/gm, ' ');
|
|
});
|
|
|
|
// cleanup adjusted source
|
|
source = source
|
|
.replace(/\bcontext\b/g, 'window')
|
|
.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var Array *=[\s\S]+?;\n/, '')
|
|
.replace(/(return *|= *)_([;)])/g, '$1lodash$2')
|
|
.replace(/^(?: *\/\/.*\s*)* *var _ *= *runInContext\b.+\n+/m, '');
|
|
|
|
// remove local timer variables
|
|
source = removeVar(source, 'clearTimeout');
|
|
source = removeVar(source, 'setImmediate');
|
|
source = removeVar(source, 'setTimeout');
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes the `setBindData` fork from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSetBindDataFork(source) {
|
|
return source = source.replace(matchFunction(source, 'isArray'), function(match) {
|
|
return match.replace(getSetBindDataFork(source), '');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes the `support.spliceObjects` fix from the `Array` function mixins
|
|
* snippet of `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSpliceObjectsFix(source) {
|
|
return source.replace(/(?:\s*\/\/.*)*\n( *)if *\(!support\.spliceObjects[\s\S]+?(?:\{\s*}|\n\1})/, '');
|
|
}
|
|
|
|
/**
|
|
* Removes all strings from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeStrings(source) {
|
|
return source.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, '');
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.argsClass` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportArgsClass(source) {
|
|
source = removeSupportProp(source, 'argsClass');
|
|
|
|
// replace `support.argsClass` in the `_.isArguments` fork
|
|
source = source.replace(getIsArgumentsFork(source), function(match) {
|
|
return match.replace(/!support\.argsClass/g, '!isArguments(arguments)');
|
|
});
|
|
|
|
// remove `support.argsClass` from `_.isEmpty`
|
|
source = source.replace(matchFunction(source, 'isEmpty'), function(match) {
|
|
return match.replace(/\s*\(support\.argsClass\s*\?([^:]+):.+?\)\)/g, '$1');
|
|
});
|
|
|
|
// remove `support.argsClass` from `_.isPlainObject`
|
|
_.each(['shimIsPlainObject', 'isPlainObject'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/\s*\|\|\s*\(!support\.argsClass[\s\S]+?\)\)/, '');
|
|
});
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.argsObject` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportArgsObject(source) {
|
|
source = removeSupportProp(source, 'argsObject');
|
|
|
|
// remove `argsAreObjects` from `baseIsEqual`
|
|
source = source.replace(matchFunction(source, 'baseIsEqual'), function(match) {
|
|
return match.replace(/!support.\argsObject[^:]+:\s*/g, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.enumErrorProps` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportEnumErrorProps(source) {
|
|
source = removeSupportProp(source, 'enumErrorProps');
|
|
|
|
// remove `support.enumErrorProps` from `iteratorTemplate`
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match
|
|
.replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumErrorProps *(?:&&|\))(.+?}["']|[\s\S]+?<% *} *(?:%>|["'])).+/g, '')
|
|
.replace(/support\.enumErrorProps\s*\|\|\s*/g, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.enumPrototypes` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportEnumPrototypes(source) {
|
|
source = removeSupportProp(source, 'enumPrototypes');
|
|
|
|
// remove `support.enumPrototypes` from `_.keys`
|
|
source = source.replace(matchFunction(source, 'keys'), function(match) {
|
|
return match
|
|
.replace(/\(support\.enumPrototypes[^)]+\)(?:\s*\|\|\s*)?/, '')
|
|
.replace(/\s*if *\(\s*\)[^}]+}/, '');
|
|
});
|
|
|
|
// remove `support.enumPrototypes` from `iteratorTemplate`
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match
|
|
.replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumPrototypes *(?:&&|\))(.+?}["']|[\s\S]+?<% *} *(?:%>|["'])).+/g, '')
|
|
.replace(/support\.enumPrototypes\s*\|\|\s*/g, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.nodeClass` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportNodeClass(source) {
|
|
source = removeSupportProp(source, 'nodeClass');
|
|
|
|
// remove `support.nodeClass` from `baseClone` and `shimIsPlainObject`
|
|
_.each(['baseClone', 'shimIsPlainObject'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, '');
|
|
});
|
|
});
|
|
|
|
// remove `support.nodeClass` from `baseIsEqual`
|
|
source = source.replace(matchFunction(source, 'baseIsEqual'), function(match) {
|
|
return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)\)/, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.nonEnumArgs` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportNonEnumArgs(source) {
|
|
source = removeSupportProp(source, 'nonEnumArgs');
|
|
|
|
// remove `support.nonEnumArgs` from `_.keys`
|
|
source = source.replace(matchFunction(source, 'keys'), function(match) {
|
|
return match
|
|
.replace(/(?:\s*\|\|\s*)?\(support\.nonEnumArgs[\s\S]+?\)\)/, '')
|
|
.replace(/\s*if *\(\s*\)[^}]+}/, '');
|
|
});
|
|
|
|
// remove `nonEnumArgs` from `iteratorTemplate`
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match
|
|
.replace(/(?: *\/\/.*\n)*( *["'] *)<% *} *else *if *\(support\.nonEnumArgs[\s\S]+?(\1<% *} *%>.+)/, '$2')
|
|
.replace(/\s*\|\|\s*support\.nonEnumArgs/, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.nonEnumShadows` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportNonEnumShadows(source) {
|
|
source = removeFromCreateIterator(source, 'nonEnumProps');
|
|
source = removeFromCreateIterator(source, 'shadowedProps');
|
|
source = removeSupportProp(source, 'nonEnumShadows');
|
|
|
|
// remove `support.nonEnumShadows` from `iteratorTemplate`
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(support\.nonEnumShadows[\s\S]+?["']\1<% *} *%>.+/, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.ownLast` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportOwnLast(source) {
|
|
source = removeSupportProp(source, 'ownLast');
|
|
|
|
// remove `support.ownLast` from `shimIsPlainObject`
|
|
source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) {
|
|
return match.replace(/(?:\s*\/\/.*)*\n( *)if *\(support\.ownLast[\s\S]+?\n\1}/, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.spliceObjects` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportSpliceObjects(source) {
|
|
source = removeSupportProp(source, 'spliceObjects');
|
|
source = removeSpliceObjectsFix(source);
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes all `support.unindexedChars` references from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportUnindexedChars(source) {
|
|
source = removeSupportProp(source, 'unindexedChars');
|
|
|
|
// remove `support.unindexedChars` from `_.at`
|
|
source = source.replace(matchFunction(source, 'at'), function(match) {
|
|
return match.replace(/^ *if *\(support\.unindexedChars[^}]+}\n+/m, '');
|
|
});
|
|
|
|
// remove `support.unindexedChars` from `_.forEachRight`
|
|
source = source.replace(matchFunction(source, 'forEachRight'), function(match) {
|
|
return match.replace(/}\s*else if *\(support\.unindexedChars[^}]+/, '');
|
|
});
|
|
|
|
// remove `support.unindexedChars` from `_.toArray`
|
|
source = source.replace(matchFunction(source, 'toArray'), function(match) {
|
|
return match.replace(/(return\b).+?support\.unindexedChars[^:]+:\s*/, '$1 ');
|
|
});
|
|
|
|
// remove `support.unindexedChars` from `iteratorTemplate`
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match
|
|
.replace(/'if *\(<%= *array *%>[^']*/, '$&\\n')
|
|
.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(support\.unindexedChars[\s\S]+?["']\1<% *} *%>.+/, '');
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Removes a given property from the `support` object in `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} varName The name of the `support` property to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeSupportProp(source, propName) {
|
|
return source.replace(matchProp(source, 'support'), function(match) {
|
|
return match.replace(RegExp(
|
|
multilineComment +
|
|
// match a `try` block
|
|
'(?: *try\\b.+\\n)?' +
|
|
// match the `support` property assignment
|
|
' *support\\.' + propName + ' *=.+\\n' +
|
|
// match `catch` block
|
|
'(?:( *).+?catch\\b[\\s\\S]+?\\n\\1}\\n)?'
|
|
), '');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes a variable, of the given `varName`, from `source`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} varName The name of the variable to remove.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function removeVar(source, varName) {
|
|
// simplify complex variable assignments
|
|
if (_.contains(complexVars, varName)) {
|
|
source = source.replace(RegExp(
|
|
'^( *var ' + varName + ') *=[\\s\\S]+?' +
|
|
'(?:\\(function[\\s\\S]+?\\([^)]*\\)\\);(?=\\n\\n)|' +
|
|
'[;}](?=\\n\\n(?!\\s*\\(func)))'
|
|
, 'm'), '$1 = null;')
|
|
}
|
|
|
|
_.some([
|
|
function() {
|
|
return removeFunction(source, varName);
|
|
},
|
|
function() {
|
|
// remove a varaible at the start of a declaration list
|
|
return source.replace(RegExp('(var +)' + varName + ' *=.+?,\\n *'), '$1');
|
|
},
|
|
function() {
|
|
// remove a variable declaration in a declaration list
|
|
return source.replace(RegExp(
|
|
'( *(?:var +)?\\w+ *=.+?),\\n *' + varName + ' *=.+?([,;])(?=\\n)'
|
|
), '$1$2');
|
|
},
|
|
function() {
|
|
// remove a variable that is not part of a declaration list
|
|
return source.replace(RegExp(
|
|
multilineComment +
|
|
'( *)var ' + varName + ' *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{[(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n'
|
|
), '');
|
|
}
|
|
], function(func) {
|
|
var result = func();
|
|
if (result !== source) {
|
|
source = result;
|
|
return true;
|
|
}
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Replaces the `funcName` function body in `source` with `funcValue`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} varName The name of the function to replace.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function replaceFunction(source, funcName, funcValue) {
|
|
var snippet = matchFunction(source, funcName);
|
|
if (!snippet) {
|
|
return source;
|
|
}
|
|
source = source.replace(snippet, function() {
|
|
return funcValue
|
|
.replace(RegExp('^' + getIndent(funcValue), 'gm'), getIndent(snippet))
|
|
.trimRight() + '\n';
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/**
|
|
* Replaces the `support` object `propName` property value in `source` with `propValue`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {String} varName The name of the `support` property to replace.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function replaceSupportProp(source, propName, propValue) {
|
|
return source.replace(RegExp(
|
|
// match a `try` block
|
|
'(?: *try\\b.+\\n)?' +
|
|
// match the `support` property assignment
|
|
'( *support\\.' + propName + ' *=).+\\n' +
|
|
// match `catch` block
|
|
'(?:( *).+?catch\\b[\\s\\S]+?\\n\\2}\\n)?'
|
|
), function(match, left) {
|
|
return left + ' ' + propValue + ';\n';
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Replaces the `varName` variable declaration value in `source` with `varValue`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to inspect.
|
|
* @param {String} varName The name of the variable to replace.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function replaceVar(source, varName, varValue) {
|
|
// replace a variable that's not part of a declaration list
|
|
var result = source.replace(RegExp(
|
|
'(( *)var ' + varName + ' *=)' +
|
|
'(?:.+?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\2.+?;)\\n'
|
|
), function(match, left) {
|
|
return left + ' ' + varValue + ';\n';
|
|
});
|
|
|
|
if (source == result) {
|
|
// replace a varaible at the start or middle of a declaration list
|
|
result = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), function(match, left) {
|
|
return left + ' ' + varValue + ',';
|
|
});
|
|
}
|
|
if (source == result) {
|
|
// replace a variable at the end of a variable declaration list
|
|
result = source.replace(RegExp('(,\\s*' + varName + ' *=).+?;'), function(match, left) {
|
|
return left + ' ' + varValue + ';';
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Hard-codes the `strict` template option value for `iteratorTemplate`.
|
|
*
|
|
* @private
|
|
* @param {String} source The source to process.
|
|
* @param {Boolean} value The value to set.
|
|
* @returns {String} Returns the modified source.
|
|
*/
|
|
function setUseStrictOption(source, value) {
|
|
// inject or remove the "use strict" directive
|
|
source = source.replace(/^([\s\S]*?function[^{]+{)(?:\s*'use strict';)?/, '$1' + (value ? "\n 'use strict';" : ''));
|
|
|
|
// replace `strict` branch in `iteratorTemplate` with hard-coded option
|
|
source = source.replace(matchFunction(source, 'iteratorTemplate'), function(match) {
|
|
return match.replace(/(template\()(?:\s*"'use strict.+)?/, '$1' + (value ? '\n "\'use strict\';\\n" +' : ''));
|
|
});
|
|
|
|
return source;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a debug and/or minified build, executing the `callback` for each.
|
|
* The `callback` is invoked with one argument; (data).
|
|
*
|
|
* Note: For a list of commands see `displayHelp()` or run `lodash --help`.
|
|
*
|
|
* @param {Array|Object} [options=[]] An array of build commands or the state object.
|
|
* @param {Function} [callback=defaultBuildCallback] The function called or per build.
|
|
*/
|
|
function build(options, callback) {
|
|
options || (options = []);
|
|
callback || (callback = defaultBuildCallback);
|
|
|
|
// the debug version of `source`
|
|
var debugSource;
|
|
|
|
// used to specify the output path for builds
|
|
var outputPath;
|
|
|
|
// used to specify the source map URL
|
|
var sourceMapURL;
|
|
|
|
// use to pre-populate the build state
|
|
var state = _.isObject(options) && !_.isArray(options) && options;
|
|
|
|
// used to capture warnings for invalid command-line arguments
|
|
var warnings = [];
|
|
|
|
var isExcluded = function() {
|
|
return _.every(arguments, function(funcName) {
|
|
return !_.contains(buildFuncs, funcName);
|
|
});
|
|
};
|
|
|
|
var isLodash = function(funcName) {
|
|
funcName = getRealName(funcName);
|
|
if (_.contains(lodashOnlyFuncs, funcName) || /^(?:assign|zipObject)$/.test(funcName)) {
|
|
var funcNames = _.difference(_.union(includeFuncs, plusFuncs), minusFuncs);
|
|
return _.contains(funcNames, funcName);
|
|
}
|
|
funcNames = _.difference(plusFuncs, minusFuncs);
|
|
return _.contains(funcNames, funcName);
|
|
};
|
|
|
|
if (state) {
|
|
var buildFuncs = state.buildFuncs,
|
|
filePath = state.filePath,
|
|
funcDepMap = state.funcDepMap,
|
|
iife = state.iife,
|
|
includeFuncs = state.includeFuncs,
|
|
includeProps = state.includeProps,
|
|
includeVars = state.includeVars,
|
|
isAMD = state.isAMD,
|
|
isBackbone = state.isBackbone,
|
|
isCommonJS = state.isCommonJS,
|
|
isCSP = state.isCSP,
|
|
isDebug = true,
|
|
isGlobal = state.isGlobal,
|
|
isIIFE = state.isIIFE,
|
|
isLegacy = state.isLegacy,
|
|
isMapped = state.isMapped,
|
|
isMobile = state.isMobile,
|
|
isModern = state.isModern,
|
|
isNode = state.isNode,
|
|
isNoDep = true,
|
|
isStdOut = state.isStdOut,
|
|
isSilent = true,
|
|
isStrict = state.isStrict,
|
|
isUnderscore = state.isUnderscore,
|
|
minusFuncs = state.minusFuncs,
|
|
options = state.options,
|
|
outputPath = state.outputPath,
|
|
plusFuncs = state.plusFuncs,
|
|
propDepMap = state.propDepMap,
|
|
source = state.source,
|
|
varDepMap = state.varDepMap;
|
|
}
|
|
else {
|
|
// display help message
|
|
if (_.find(options, function(arg) {
|
|
return /^(?:-h|--help)$/.test(arg);
|
|
})) {
|
|
displayHelp();
|
|
return;
|
|
}
|
|
|
|
// display `lodash.VERSION`
|
|
if (_.find(options, function(arg) {
|
|
return /^(?:-V|--version)$/.test(arg);
|
|
})) {
|
|
console.log(_.VERSION);
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// clone dependencies to modify
|
|
var funcDepMap = _.cloneDeep(funcDependencyMap),
|
|
propDepMap = _.cloneDeep(propDependencyMap),
|
|
varDepMap = _.cloneDeep(varDependencyMap);
|
|
|
|
// the path to the source file
|
|
var filePath = path.join(__dirname, 'lodash.js');
|
|
|
|
// used to specify a custom IIFE to wrap Lo-Dash
|
|
var iife = options.reduce(function(result, value) {
|
|
var match = value.match(/^iife=([\s\S]*)$/);
|
|
return match ? match[1] : result;
|
|
}, null);
|
|
|
|
// flag to specify a Backbone build
|
|
var isBackbone = _.contains(options, 'backbone');
|
|
|
|
// flag to specify a Content Security Policy build
|
|
var isCSP = _.contains(options, 'csp') || _.contains(options, 'CSP');
|
|
|
|
// flag to specify only creating the debug build
|
|
var isDebug = _.contains(options, '-d') || _.contains(options, '--debug');
|
|
|
|
// flag to indicate that a custom IIFE was specified
|
|
var isIIFE = typeof iife == 'string';
|
|
|
|
// flag to specify creating a source map for the minified source
|
|
var isMapped = _.contains(options, '-p') || _.contains(options, '--source-map');
|
|
|
|
// flag to specify only creating the minified build
|
|
var isMinify = _.contains(options, '-m') || _.contains(options, '--minify');
|
|
|
|
// flag to specify a mobile build
|
|
var isMobile = _.contains(options, 'mobile');
|
|
|
|
// flag to specify a modern build
|
|
var isModern = isCSP || isMobile || _.contains(options, 'modern');
|
|
|
|
// flag to specify a modularize build
|
|
var isModularize = _.contains(options, 'modularize');
|
|
|
|
// flag to specify a no-dependency build
|
|
var isNoDep = _.contains(options, '-n') || _.contains(options, '--no-dep');
|
|
|
|
// flag to specify writing output to standard output
|
|
var isStdOut = _.contains(options, '-c') || _.contains(options, '--stdout');
|
|
|
|
// flag to specify skipping status updates normally logged to the console
|
|
var isSilent = isStdOut || _.contains(options, '-s') || _.contains(options, '--silent');
|
|
|
|
// flag to specify `_.assign`, `_.bindAll`, and `_.defaults` are
|
|
// constructed using the "use strict" directive
|
|
var isStrict = _.contains(options, 'strict');
|
|
|
|
// flag to specify an Underscore build
|
|
var isUnderscore = isBackbone || _.contains(options, 'underscore');
|
|
|
|
// flag to specify a legacy build
|
|
var isLegacy = !(isModern || isUnderscore) && _.contains(options, 'legacy');
|
|
|
|
// used to specify the ways to export the `lodash` function
|
|
var exportsOptions = options.reduce(function(result, value) {
|
|
return /^exports=.*$/.test(value) ? optionToArray(value).sort() : result;
|
|
}, isUnderscore
|
|
? ['commonjs', 'global', 'node']
|
|
: allExports.slice()
|
|
);
|
|
|
|
// used to specify the AMD module ID of Lo-Dash used by precompiled templates
|
|
var moduleId = options.reduce(function(result, value) {
|
|
var match = value.match(/^moduleId=(.*)$/);
|
|
return match ? match[1] : result;
|
|
}, 'lodash');
|
|
|
|
// used to match external template files to precompile
|
|
var templatePattern = options.reduce(function(result, value) {
|
|
var match = value.match(/^template=(.+)$/);
|
|
return match
|
|
? match[1]
|
|
: result;
|
|
}, '');
|
|
|
|
// used as the template settings for precompiled templates
|
|
var templateSettings = options.reduce(function(result, value) {
|
|
var match = value.match(/^settings=(.+)$/);
|
|
return match
|
|
? _.assign(result, Function('return {' + match[1].replace(/^{|}$/g, '') + '}')())
|
|
: result;
|
|
}, _.assign(_.clone(_.templateSettings), {
|
|
'moduleId': moduleId
|
|
}));
|
|
|
|
// flags to specify export options
|
|
var isAMD = _.contains(exportsOptions, 'amd'),
|
|
isCommonJS = _.contains(exportsOptions, 'commonjs'),
|
|
isGlobal = _.contains(exportsOptions, 'global'),
|
|
isNode = _.contains(exportsOptions, 'node');
|
|
|
|
// flag to specify a template build
|
|
var isTemplate = !!templatePattern;
|
|
|
|
// the lodash.js source
|
|
var source = fs.readFileSync(filePath, 'utf8');
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// delete the `_.findWhere` dependency map to enable its alias mapping
|
|
if (!isUnderscore || isLodash('findWhere')) {
|
|
delete funcDepMap.findWhere;
|
|
}
|
|
|
|
// categories of functions to include in the build
|
|
var categoryOptions = options.reduce(function(accumulator, value) {
|
|
if (/^category=.+$/.test(value)) {
|
|
var array = optionToArray(value);
|
|
accumulator = _.union(array.map(function(category) {
|
|
return capitalize(category.toLowerCase());
|
|
}));
|
|
}
|
|
return accumulator;
|
|
}, []);
|
|
|
|
// functions to include in the build
|
|
var includeFuncs = options.reduce(function(accumulator, value) {
|
|
return /^include=.*$/.test(value)
|
|
? _.union(accumulator, optionToMethodsArray(value, funcDepMap))
|
|
: accumulator;
|
|
}, categoryOptions.slice());
|
|
|
|
// properties to include in the build
|
|
var includeProps = _.intersection(includeFuncs, propDependencies);
|
|
|
|
// variables to include in the build
|
|
var includeVars = _.intersection(includeFuncs, varDependencies);
|
|
|
|
// functions to remove from the build
|
|
var minusFuncs = options.reduce(function(accumulator, value) {
|
|
return /^(?:exclude|minus)=.*$/.test(value)
|
|
? _.union(accumulator, optionToMethodsArray(value, funcDepMap))
|
|
: accumulator;
|
|
}, []);
|
|
|
|
// functions to add to the build
|
|
var plusFuncs = options.reduce(function(accumulator, value) {
|
|
return /^plus=.*$/.test(value)
|
|
? _.union(accumulator, optionToMethodsArray(value, funcDepMap))
|
|
: accumulator;
|
|
}, []);
|
|
|
|
// expand categories to function names
|
|
_.each([includeFuncs, minusFuncs, plusFuncs], function(funcNames) {
|
|
var categories = _.intersection(funcNames, allCategories);
|
|
|
|
categories.forEach(function(category) {
|
|
var otherFuncs = getNamesByCategory(category).filter(function(key) {
|
|
var type = typeof _[key];
|
|
return type == 'function' || type == 'undefined';
|
|
});
|
|
|
|
// limit function names to those available for specific builds
|
|
if (isBackbone) {
|
|
otherFuncs = _.intersection(otherFuncs, backboneDependencies);
|
|
} else if (isUnderscore) {
|
|
otherFuncs = _.intersection(otherFuncs, underscoreFuncs);
|
|
}
|
|
push.apply(funcNames, otherFuncs);
|
|
});
|
|
});
|
|
|
|
// remove categories from function names
|
|
includeFuncs = _.difference(includeFuncs, allCategories, includeProps, includeVars);
|
|
minusFuncs = _.difference(minusFuncs, allCategories);
|
|
plusFuncs = _.difference(plusFuncs, allCategories);
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// used to detect invalid command-line arguments
|
|
var invalidArgs = _.reject(options.slice(reNode.test(options[0]) ? 2 : 0), function(value, index, options) {
|
|
if (/^(?:-o|--output)$/.test(options[index - 1]) ||
|
|
/^(?:category|exclude|exports|iife|include|moduleId|minus|plus|settings|template)=[\s\S]*$/.test(value)) {
|
|
return true;
|
|
}
|
|
var result = _.contains([
|
|
'backbone',
|
|
'csp',
|
|
'legacy',
|
|
'mobile',
|
|
'modern',
|
|
'modularize',
|
|
'strict',
|
|
'underscore',
|
|
'-c', '--stdout',
|
|
'-d', '--debug',
|
|
'-h', '--help',
|
|
'-m', '--minify',
|
|
'-n', '--no-dep',
|
|
'-o', '--output',
|
|
'-p', '--source-map',
|
|
'-s', '--silent',
|
|
'-V', '--version'
|
|
], value);
|
|
|
|
if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) {
|
|
result = true;
|
|
sourceMapURL = value;
|
|
}
|
|
return result;
|
|
});
|
|
|
|
// report invalid command and option arguments
|
|
if (invalidArgs.length) {
|
|
warnings.push('Invalid argument' + (invalidArgs.length > 1 ? 's' : '') + ' passed: ' + invalidArgs.join(', '));
|
|
}
|
|
// report invalid command combinations
|
|
invalidArgs = _.intersection(options, ['backbone', 'csp', 'legacy', 'mobile', 'modern', 'underscore']);
|
|
|
|
if (isTemplate) {
|
|
invalidArgs.push('template');
|
|
}
|
|
if (invalidArgs.length > 1) {
|
|
warnings.push('The `' + invalidArgs.slice(0, -1).join('`, `') + '`' + (invalidArgs.length > 2 ? ',' : '') + ' and `' + invalidArgs.slice(-1) + '` commands may not be combined.');
|
|
}
|
|
// report invalid command entries
|
|
_.forOwn({
|
|
'category': {
|
|
'entries': categoryOptions,
|
|
'validEntries': allCategories
|
|
},
|
|
'exports': {
|
|
'entries': exportsOptions,
|
|
'validEntries': allExports
|
|
},
|
|
'include': {
|
|
'entries': includeFuncs,
|
|
'validEntries': allFuncs
|
|
},
|
|
'minus': {
|
|
'entries': minusFuncs,
|
|
'validEntries': allFuncs
|
|
},
|
|
'plus': {
|
|
'entries': plusFuncs,
|
|
'validEntries': allFuncs
|
|
}
|
|
}, function(data, commandName) {
|
|
invalidArgs = _.difference(data.entries, data.validEntries, ['none']);
|
|
if (invalidArgs.length) {
|
|
warnings.push('Invalid `' + commandName + '` entr' + (invalidArgs.length > 1 ? 'ies' : 'y') + ' passed: ' + invalidArgs.join(', '));
|
|
}
|
|
});
|
|
|
|
if (warnings.length) {
|
|
console.log([''].concat(
|
|
warnings,
|
|
'For more information type: lodash --help'
|
|
).join('\n'));
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// names of functions to include in the build
|
|
var buildFuncs = !isTemplate && (function() {
|
|
var result;
|
|
|
|
// update dependencies
|
|
if (isLegacy) {
|
|
_.pull(propDepMap.createBound, 'support');
|
|
|
|
funcDepMap.isPlainObject = funcDepMap.shimIsPlainObject.slice();
|
|
funcDepMap.keys = funcDepMap.shimKeys.slice();
|
|
|
|
_.forOwn(varDepMap, function(deps) {
|
|
_.pull(deps, 'reNative');
|
|
});
|
|
}
|
|
if (isModularize) {
|
|
funcDepMap.lodash.push('support', 'baseEach', 'forOwn', 'mixin');
|
|
_.pull(funcDepMap.mixin, 'lodash');
|
|
}
|
|
else {
|
|
funcDepMap.chain.push('wrapperChain');
|
|
funcDepMap.wrapperValueOf.push('baseEach', 'chain', 'forOwn', 'mixin', 'wrapperChain', 'wrapperToString');
|
|
|
|
_.each(['lodashWrapper', 'tap', 'wrapperChain', 'wrapperToString'], function(funcName) {
|
|
funcDepMap[funcName].push('wrapperValueOf');
|
|
});
|
|
}
|
|
if (isMobile) {
|
|
_.each(['assign', 'defaults'], function(funcName) {
|
|
_.pull(funcDepMap[funcName], 'keys');
|
|
});
|
|
}
|
|
if (isLegacy || isMobile || isUnderscore) {
|
|
_.each(['baseCreateCallback', 'createBound'], function(funcName) {
|
|
_.pull(funcDepMap[funcName], 'setBindData');
|
|
});
|
|
}
|
|
if (!isModularize && _.contains(plusFuncs, 'chain') == !isUnderscore) {
|
|
_.pull(funcDepMap.mixin, 'isFunction');
|
|
}
|
|
if (isUnderscore) {
|
|
if (!isLodash('baseClone') && !isLodash('clone') && !isLodash('cloneDeep')) {
|
|
_.pull(funcDepMap.clone, 'baseClone').push('assign', 'isArray', 'isObject');
|
|
}
|
|
if (!isLodash('baseIsEqual') && !isLodash('isEqual')) {
|
|
_.pull(funcDepMap.baseIsEqual, 'isArguments');
|
|
}
|
|
if (!isLodash('chain')) {
|
|
_.pull(funcDepMap.wrapperValueOf, 'wrapperToString');
|
|
}
|
|
if (!isLodash('contains')) {
|
|
_.pull(funcDepMap.contains, 'isString');
|
|
}
|
|
if (!isLodash('flatten')) {
|
|
_.pull(funcDepMap.flatten, 'map');
|
|
}
|
|
if (!isLodash('isEmpty')) {
|
|
funcDepMap.isEmpty = ['isArray', 'isString'];
|
|
}
|
|
if (!isLodash('lodash')) {
|
|
_.pull(funcDepMap.lodash, 'isArray');
|
|
}
|
|
if (!isLodash('pick')){
|
|
_.pull(funcDepMap.pick, 'forIn', 'isObject');
|
|
}
|
|
if (!isLodash('template')) {
|
|
_.pull(funcDepMap.template, 'keys', 'values');
|
|
}
|
|
if (!isLodash('toArray')) {
|
|
funcDepMap.toArray.push('isArray', 'map');
|
|
}
|
|
if (!isLodash('findWhere') || !isLodash('where')) {
|
|
_.pull(funcDepMap.createCallback, 'baseIsEqual');
|
|
funcDepMap.where.push('find', 'isEmpty');
|
|
}
|
|
// unexpose "exit early" feature from functions
|
|
if (!isLodash('forEach') && !isLodash('forEachRight') &&
|
|
!isLodash('forIn') && !isLodash('forInRight') &&
|
|
!isLodash('forOwn') && !isLodash('forOwnRight')) {
|
|
_.each(['baseEach', 'forEach', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(funcName) {
|
|
(varDepMap[funcName] || (varDepMap[funcName] = [])).push('indicatorObject');
|
|
});
|
|
|
|
// modify functions that use `_.forEach` to use the private `indicatorObject`
|
|
_.each(['findLast', 'forEachRight', 'transform'], function(funcName) {
|
|
(varDepMap[funcName] || (varDepMap[funcName] = [])).push('indicatorObject');
|
|
});
|
|
|
|
// modify functions that use `_.forIn` to use the private `indicatorObject`
|
|
_.each(['baseIsEqual', 'shimIsPlainObject'], function(funcName) {
|
|
(varDepMap[funcName] || (varDepMap[funcName] = [])).push('indicatorObject');
|
|
});
|
|
|
|
// modify functions that use `_.forOwn` to use the private `indicatorObject`
|
|
_.each(['contains', 'every', 'find', 'findKey', 'some'], function(funcName) {
|
|
(varDepMap[funcName] || (varDepMap[funcName] = [])).push('indicatorObject');
|
|
});
|
|
|
|
// modify functions that use `_.forOwnRight` to use the private `indicatorObject`
|
|
(varDepMap.findLastKey || (varDepMap.findLastKey = [])).push('indicatorObject');
|
|
}
|
|
|
|
_.each(['baseUniq', 'difference', 'intersection'], function(funcName) {
|
|
if (funcName == 'baseUniq'
|
|
? (!isLodash('baseUniq') && !isLodash('uniq'))
|
|
: !isLodash(funcName)
|
|
) {
|
|
_.pull(funcDepMap[funcName], 'cacheIndexOf', 'createCache').push('getIndexOf');
|
|
}
|
|
});
|
|
|
|
_.each(['isEqual', 'omit', 'pick'], function(funcName) {
|
|
if (funcName == 'isEqual'
|
|
? (!isLodash('baseIsEqual') && !isLodash('isEqual'))
|
|
: !isLodash(funcName)
|
|
) {
|
|
_.pull(funcDepMap[funcName], 'baseCreateCallback', 'createCallback');
|
|
}
|
|
});
|
|
|
|
_.forOwn(funcDepMap, function(deps, funcName) {
|
|
if (_.every(getDependants(funcName, funcDepMap).concat(funcName), function(otherName) {
|
|
return !isLodash(otherName);
|
|
})) {
|
|
deps = funcDepMap[funcName];
|
|
if (_.contains(deps, 'charAtCallback')) {
|
|
_.pull(deps, 'charAtCallback', 'isArray', 'isString');
|
|
}
|
|
if (_.contains(deps, 'slice')) {
|
|
_.pull(deps, 'slice');
|
|
}
|
|
}
|
|
});
|
|
|
|
_.forOwn(varDepMap, function(deps, funcName) {
|
|
if (!isLodash(funcName)) {
|
|
_.pull(deps, 'arrayPool', 'largeArraySize', 'maxPoolSize', 'objectPool');
|
|
}
|
|
});
|
|
}
|
|
if (isModern || isUnderscore) {
|
|
_.each(['assign', 'baseEach', 'defaults', 'forIn', 'forOwn', 'shimKeys'], function(funcName) {
|
|
if (!(isUnderscore && isLodash(funcName))) {
|
|
var deps = _.pull(funcDepMap[funcName], 'createIterator');
|
|
_.pull(varDepMap[funcName] || (varDepMap[funcName] = []), 'defaultsIteratorOptions', 'eachIteratorOptions', 'forOwnIteratorOptions').push('objectTypes');
|
|
|
|
if (funcName != 'baseEach') {
|
|
deps.push('isArguments');
|
|
}
|
|
if (funcName != 'defaults' && funcName != 'shimKeys') {
|
|
deps.push('baseCreateCallback');
|
|
}
|
|
if (funcName != 'forIn' && funcName != 'shimKeys') {
|
|
deps.push('keys');
|
|
}
|
|
}
|
|
});
|
|
|
|
_.forOwn(propDepMap, function(deps, funcName) {
|
|
if (funcName != 'createBound' &&
|
|
!(isMobile && funcName == 'keys') &&
|
|
!(isUnderscore && isLodash(funcName))) {
|
|
_.pull(deps, 'support');
|
|
}
|
|
});
|
|
|
|
_.forOwn(funcDepMap, function(deps, funcName) {
|
|
if (_.contains(deps, 'isNode')) {
|
|
_.pull(deps, 'isNode');
|
|
}
|
|
if (_.contains(deps, 'toString') && funcName != 'contains' && funcName != 'parseInt') {
|
|
_.pull(deps, 'isString');
|
|
}
|
|
});
|
|
|
|
if (isUnderscore) {
|
|
_.forOwn(funcDepMap, function(deps, funcName) {
|
|
if (_.every(getDependants(funcName, funcDepMap).concat(funcName), function(otherName) {
|
|
return !isLodash(otherName);
|
|
})) {
|
|
deps = funcDepMap[funcName];
|
|
if (_.contains(deps, 'releaseArray')) {
|
|
_.pull(deps, 'getArray', 'releaseArray');
|
|
}
|
|
if (_.contains(deps, 'releaseObject')) {
|
|
_.pull(deps, 'getObject', 'releaseObject');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (!isMobile) {
|
|
_.pull(funcDepMap.setBindData, 'noop');
|
|
|
|
_.each(['baseClone', 'lodash', 'transform', 'wrapperValueOf'], function(funcName) {
|
|
_.pull(funcDepMap[funcName], 'baseEach').push('forEach');
|
|
});
|
|
|
|
_.each(['contains', 'every', 'filter', 'find', 'forEach', 'map', 'max', 'min', 'reduce', 'some'], function(funcName) {
|
|
_.pull(funcDepMap[funcName], 'baseEach').push('forOwn');
|
|
});
|
|
|
|
_.each(['every', 'find', 'filter', 'forEach', 'forIn', 'forOwn', 'map', 'reduce', 'shimKeys'], function(funcName) {
|
|
if (!(isUnderscore && isLodash(funcName))) {
|
|
_.pull(funcDepMap[funcName], 'isArray');
|
|
}
|
|
});
|
|
|
|
_.each(['max', 'min'], function(funcName) {
|
|
if (!(isUnderscore && isLodash(funcName))) {
|
|
funcDepMap[funcName].push('forEach');
|
|
}
|
|
});
|
|
|
|
_.forOwn(funcDepMap, function(deps, funcName) {
|
|
if (funcName != 'baseFlatten' && _.contains(deps, 'isArguments') &&
|
|
!(isUnderscore && isLodash(funcName))) {
|
|
_.pull(deps, 'isArguments');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
if (isModularize) {
|
|
_.forOwn(funcDepMap, function(deps, funcName) {
|
|
if (_.contains(deps, 'getIndexOf')) {
|
|
_.pull(deps, 'getIndexOf').push('baseIndexOf');
|
|
}
|
|
});
|
|
}
|
|
// add function names explicitly
|
|
if (includeFuncs.length) {
|
|
result = includeFuncs;
|
|
}
|
|
// add default function names
|
|
if (!includeProps.length && !includeVars.length) {
|
|
if (isBackbone && !result) {
|
|
result = backboneDependencies;
|
|
}
|
|
else if (isUnderscore && !result) {
|
|
result = underscoreFuncs;
|
|
}
|
|
if (!result) {
|
|
result = lodashFuncs.slice();
|
|
}
|
|
}
|
|
// remove special "none" entry
|
|
if (result == 'none') {
|
|
result = [];
|
|
} else {
|
|
_.pull(result, 'none');
|
|
}
|
|
// add and subtract function names
|
|
if (plusFuncs.length) {
|
|
result = _.union(result, plusFuncs);
|
|
}
|
|
if (minusFuncs.length) {
|
|
result = _.difference(result, minusFuncs.concat(getDependants(minusFuncs, funcDepMap)));
|
|
}
|
|
if (isModularize) {
|
|
_.pull(result, 'runInContext');
|
|
}
|
|
return getDependencies(result, funcDepMap);
|
|
}());
|
|
|
|
// add properties, variables, and their function dependencies to include in the build
|
|
(function() {
|
|
function expand(result, depMap, funcNames, stack) {
|
|
stack || (stack = []);
|
|
return _.uniq(_.reduce(funcNames || depMap, function(result, identifiers, funcName) {
|
|
// juggle arguments
|
|
if (funcNames) {
|
|
funcName = identifiers;
|
|
identifiers = depMap[funcName] || [];
|
|
}
|
|
if (!_.contains(stack, funcName) && (funcNames || _.contains(buildFuncs, funcName))) {
|
|
var deps = _.uniq(_.transform(identifiers, function(deps, identifier) {
|
|
push.apply(deps, getDependencies(identifier, funcDepMap));
|
|
}));
|
|
|
|
stack.push(funcName);
|
|
push.apply(result, identifiers);
|
|
|
|
buildFuncs = _.union(buildFuncs, deps);
|
|
result = expand(result, depMap, deps, stack);
|
|
}
|
|
return result;
|
|
}, result));
|
|
}
|
|
|
|
includeProps = expand(includeProps, propDepMap);
|
|
includeVars = expand(includeVars, varDepMap);
|
|
}());
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// load customized Lo-Dash module
|
|
var lodash = !isTemplate && (function() {
|
|
source = setUseStrictOption(source, isStrict);
|
|
|
|
if (isLegacy) {
|
|
source = removeSupportProp(source, 'fastBind');
|
|
source = replaceSupportProp(source, 'argsClass', 'false');
|
|
|
|
// remove native `Function#bind` branch in `_.bind`
|
|
source = source.replace(matchFunction(source, 'createBound'), function(match) {
|
|
return match.replace(/(?:\s*\/\/.*)*\n( *)if *\([^{]+?nativeBind[\s\S]+?\n\1else *\{([\s\S]+?)\n\1}/, function(match, indent, snippet) {
|
|
return snippet
|
|
.replace(/^ /gm, '')
|
|
.replace(/^( *)bound(?= *=)/m, '$1var bound');
|
|
});
|
|
});
|
|
|
|
// remove native `Array.isArray` branch in `_.isArray`
|
|
source = source.replace(matchFunction(source, 'isArray'), function(match) {
|
|
return match.replace(/\bnativeIsArray\s*\|\|\s*/, '');
|
|
});
|
|
|
|
// replace `createObject` and `_.isArguments` with their forks
|
|
_.forOwn({
|
|
'createObject': [getCreateObjectFork, removeCreateObjectFork],
|
|
'isArguments': [getIsArgumentsFork, removeIsArgumentsFork]
|
|
},
|
|
function(funcs, funcName) {
|
|
var getFork = funcs[0],
|
|
removeFork = funcs[1];
|
|
|
|
source = source.replace(matchFunction(source, funcName).replace(RegExp('[\\s\\S]+?function ' + funcName), ''), function() {
|
|
var snippet = getFork(source),
|
|
body = snippet.match(RegExp(funcName + ' *= *function([\\s\\S]+?\\n *});'))[1],
|
|
indent = getIndent(snippet);
|
|
|
|
return body.replace(RegExp('^' + indent, 'gm'), indent.slice(0, -2)) + '\n';
|
|
});
|
|
|
|
source = removeFork(source);
|
|
});
|
|
|
|
// replace `_.isPlainObject` with `shimIsPlainObject`
|
|
source = source.replace(
|
|
matchFunction(source, 'isPlainObject').replace(/^ *var isPlainObject *= */m, ''),
|
|
matchFunction(source, 'shimIsPlainObject').replace(/^ *function shimIsPlainObject/m, 'function').replace(/\s*$/, ';\n')
|
|
);
|
|
|
|
// replace `_.keys` with `shimKeys`
|
|
source = source.replace(
|
|
matchFunction(source, 'keys').replace(/^ *var keys.*= */m, ''),
|
|
matchFunction(source, 'shimKeys').replace(/^ *var shimKeys *= */m, '')
|
|
);
|
|
}
|
|
if (isModern) {
|
|
source = removeIsArgumentsFork(source);
|
|
source = removeSetBindDataFork(source);
|
|
source = removeSupportSpliceObjects(source);
|
|
|
|
if (isMobile) {
|
|
source = replaceSupportProp(source, 'enumPrototypes', 'true');
|
|
source = replaceSupportProp(source, 'nonEnumArgs', 'true');
|
|
}
|
|
else {
|
|
source = removeIsArrayFork(source);
|
|
source = removeIsFunctionFork(source);
|
|
source = removeCreateObjectFork(source);
|
|
|
|
// remove Adobe JS engine fix from `compareAscending`
|
|
source = source.replace(matchFunction(source, 'compareAscending'), function(match) {
|
|
return match.replace(/(?: *\/\/.*\n)*( *return ai[^:]+:).+/, '$1 1;');
|
|
});
|
|
|
|
// remove `shimIsPlainObject` from `_.isPlainObject`
|
|
source = source.replace(matchFunction(source, 'isPlainObject'), function(match) {
|
|
return match.replace(/!getPrototypeOf[^:]+:\s*/, '');
|
|
});
|
|
}
|
|
}
|
|
if (!isModern || isMobile) {
|
|
source = removeEsOptimization(source);
|
|
}
|
|
if (isLegacy || isMobile || isUnderscore) {
|
|
if (isMobile || (!isLodash('assign') && !isLodash('defaults') && !isLodash('forIn') && !isLodash('forOwn'))) {
|
|
source = removeKeysOptimization(source);
|
|
}
|
|
if (!isLodash('defer')) {
|
|
source = removeDeferFork(source);
|
|
}
|
|
}
|
|
if (isModern || isUnderscore) {
|
|
source = removeSupportArgsClass(source);
|
|
source = removeSupportArgsObject(source);
|
|
source = removeSupportNonEnumShadows(source);
|
|
source = removeSupportOwnLast(source);
|
|
source = removeSupportUnindexedChars(source);
|
|
source = removeSupportNodeClass(source);
|
|
|
|
if (!isMobile) {
|
|
source = removeSupportEnumErrorProps(source);
|
|
source = removeSupportEnumPrototypes(source);
|
|
source = removeSupportNonEnumArgs(source);
|
|
|
|
// replace `_.forEach`
|
|
source = replaceFunction(source, 'forEach', [
|
|
'function forEach(collection, callback, thisArg) {',
|
|
' var index = -1,',
|
|
' length = collection ? collection.length : 0;',
|
|
'',
|
|
" callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);",
|
|
" if (typeof length == 'number') {",
|
|
' while (++index < length) {',
|
|
' if (callback(collection[index], index, collection) === false) {',
|
|
' break;',
|
|
' }',
|
|
' }',
|
|
' } else {',
|
|
' baseEach(collection, callback);',
|
|
' }',
|
|
' return collection;',
|
|
'}',
|
|
].join('\n'));
|
|
|
|
// replace `_.isRegExp`
|
|
if (!isUnderscore || (isUnderscore && isLodash('isRegExp'))) {
|
|
source = replaceFunction(source, 'isRegExp', [
|
|
'function isRegExp(value) {',
|
|
" return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;",
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
|
|
// replace `_.map`
|
|
source = replaceFunction(source, 'map', [
|
|
'function map(collection, callback, thisArg) {',
|
|
' var index = -1,',
|
|
' length = collection ? collection.length : 0;',
|
|
'',
|
|
' callback = lodash.createCallback(callback, thisArg, 3);',
|
|
" if (typeof length == 'number') {",
|
|
' var result = Array(length);',
|
|
' while (++index < length) {',
|
|
' result[index] = callback(collection[index], index, collection);',
|
|
' }',
|
|
' } else {',
|
|
' result = [];',
|
|
' baseEach(collection, function(value, key, collection) {',
|
|
' result[++index] = callback(value, key, collection);',
|
|
' });',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
|
|
// replace `_.pluck`
|
|
source = replaceFunction(source, 'pluck', [
|
|
'function pluck(collection, property) {',
|
|
' var index = -1,',
|
|
' length = collection ? collection.length : 0;',
|
|
'',
|
|
" if (typeof length == 'number') {",
|
|
' var result = Array(length);',
|
|
' while (++index < length) {',
|
|
' result[index] = collection[index][property];',
|
|
' }',
|
|
' }',
|
|
' return result || map(collection, property);',
|
|
'}'
|
|
].join('\n'));
|
|
|
|
// replace `isArray(collection)` checks in "Collections" functions with simpler type checks
|
|
_.each(['every', 'filter', 'find', 'max', 'min', 'reduce', 'some'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
if (funcName == 'reduce') {
|
|
match = match.replace(/^( *)var noaccum\b/m, '$1if (!collection) return accumulator;\n$&');
|
|
}
|
|
else if (/^(?:max|min)$/.test(funcName)) {
|
|
match = match.replace(/\bbaseEach\(/, 'forEach(');
|
|
if (!isUnderscore || isLodash(funcName)) {
|
|
return match;
|
|
}
|
|
}
|
|
return match.replace(/^(( *)if *\(.*?\bisArray\([^\)]+\).*?\) *\{\n)(( *)var index[^;]+.+\n+)/m, function(snippet, statement, indent, vars) {
|
|
vars = vars
|
|
.replace(/\b(length *=)[^;=]+/, '$1 collection' + (funcName == 'reduce' ? '.length' : ' ? collection.length : 0'))
|
|
.replace(RegExp('^ ' + indent, 'gm'), indent);
|
|
|
|
return vars + statement.replace(/\bisArray\([^\)]+\)/, "typeof length == 'number'");
|
|
});
|
|
});
|
|
});
|
|
|
|
// replace `array` property value of `eachIteratorOptions` with `false`
|
|
source = source.replace(/^( *)var eachIteratorOptions *= *[\s\S]+?\n\1};\n/m, function(match) {
|
|
return match.replace(/(^ *'array':)[^,]+/m, '$1 false');
|
|
});
|
|
}
|
|
}
|
|
if (isUnderscore) {
|
|
// replace `lodash`
|
|
source = replaceFunction(source, 'lodash', [
|
|
'function lodash(value) {',
|
|
' return (value instanceof lodash)',
|
|
' ? value',
|
|
' : new lodashWrapper(value);',
|
|
'}'
|
|
].join('\n'));
|
|
|
|
// replace `_.assign`
|
|
if (!isLodash('assign')) {
|
|
source = replaceFunction(source, 'assign', [
|
|
'function assign(object) {',
|
|
' if (!object) {',
|
|
' return object;',
|
|
' }',
|
|
' for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {',
|
|
' var iterable = arguments[argsIndex];',
|
|
' if (iterable) {',
|
|
' for (var key in iterable) {',
|
|
' object[key] = iterable[key];',
|
|
' }',
|
|
' }',
|
|
' }',
|
|
' return object;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.clone`
|
|
if (!isLodash('baseClone') && !isLodash('clone') && !isLodash('cloneDeep')) {
|
|
source = replaceFunction(source, 'clone', [
|
|
'function clone(value) {',
|
|
' return isObject(value)',
|
|
' ? (isArray(value) ? slice(value) : assign({}, value))',
|
|
' : value;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.contains`
|
|
if (!isLodash('contains')) {
|
|
source = replaceFunction(source, 'contains', [
|
|
'function contains(collection, target) {',
|
|
' var indexOf = getIndexOf(),',
|
|
' length = collection ? collection.length : 0,',
|
|
' result = false;',
|
|
" if (length && typeof length == 'number') {",
|
|
' result = indexOf(collection, target) > -1;',
|
|
' } else {',
|
|
' baseEach(collection, function(value) {',
|
|
' return !(result = value === target);',
|
|
' });',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.defaults`
|
|
if (!isLodash('defaults')) {
|
|
source = replaceFunction(source, 'defaults', [
|
|
'function defaults(object) {',
|
|
' if (!object) {',
|
|
' return object;',
|
|
' }',
|
|
' for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {',
|
|
' var iterable = arguments[argsIndex];',
|
|
' if (iterable) {',
|
|
' for (var key in iterable) {',
|
|
" if (typeof object[key] == 'undefined') {",
|
|
' object[key] = iterable[key];',
|
|
' }',
|
|
' }',
|
|
' }',
|
|
' }',
|
|
' return object;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.difference`
|
|
if (!isLodash('difference')) {
|
|
source = replaceFunction(source, 'difference', [
|
|
'function difference(array) {',
|
|
' var index = -1,',
|
|
' indexOf = getIndexOf(),',
|
|
' length = array.length,',
|
|
' flattened = baseFlatten(arguments, true, true, 1),',
|
|
' result = [];',
|
|
'',
|
|
' while (++index < length) {',
|
|
' var value = array[index];',
|
|
' if (indexOf(flattened, value) < 0) {',
|
|
' result.push(value);',
|
|
' }',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// add Underscore's `_.findWhere`
|
|
if (!isLodash('findWhere') && !isLodash('where')) {
|
|
source = source.replace(matchFunction(source, 'find'), function(match) {
|
|
var indent = getIndent(match);
|
|
return match && (match + [
|
|
'',
|
|
'/**',
|
|
' * Examines each element in a `collection`, returning the first that',
|
|
' * has the given `properties`. When checking `properties`, this method',
|
|
' * performs a deep comparison between values to determine if they are',
|
|
' * equivalent to each other.',
|
|
' *',
|
|
' * @static',
|
|
' * @memberOf _',
|
|
' * @category Collections',
|
|
' * @param {Array|Object|String} collection The collection to iterate over.',
|
|
' * @param {Object} properties The object of property values to filter by.',
|
|
' * @returns {Mixed} Returns the found element, else `undefined`.',
|
|
' * @example',
|
|
' *',
|
|
' * var food = [',
|
|
" * { 'name': 'apple', 'organic': false, 'type': 'fruit' },",
|
|
" * { 'name': 'banana', 'organic': true, 'type': 'fruit' },",
|
|
" * { 'name': 'beet', 'organic': false, 'type': 'vegetable' }",
|
|
' * ];',
|
|
' *',
|
|
" * _.findWhere(food, { 'type': 'vegetable' });",
|
|
" * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }",
|
|
' */',
|
|
'function findWhere(object, properties) {',
|
|
' return where(object, properties, true);',
|
|
'}',
|
|
''
|
|
].join('\n' + indent));
|
|
});
|
|
|
|
// replace alias assignment
|
|
source = source.replace(getMethodAssignments(source), function(match) {
|
|
return match.replace(/^( *lodash.findWhere *= *).+/m, '$1findWhere;');
|
|
});
|
|
}
|
|
// replace `_.flatten`
|
|
if (!isLodash('flatten')) {
|
|
source = replaceFunction(source, 'flatten', [
|
|
'function flatten(array, isShallow) {',
|
|
' return baseFlatten(array, isShallow);',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.intersection`
|
|
if (!isLodash('intersection')) {
|
|
source = replaceFunction(source, 'intersection', [
|
|
'function intersection(array) {',
|
|
' var args = arguments,',
|
|
' argsLength = args.length,',
|
|
' index = -1,',
|
|
' indexOf = getIndexOf(),',
|
|
' length = array ? array.length : 0,',
|
|
' result = [];',
|
|
'',
|
|
' outer:',
|
|
' while (++index < length) {',
|
|
' var value = array[index];',
|
|
' if (indexOf(result, value) < 0) {',
|
|
' var argsIndex = argsLength;',
|
|
' while (--argsIndex) {',
|
|
' if (indexOf(args[argsIndex], value) < 0) {',
|
|
' continue outer;',
|
|
' }',
|
|
' }',
|
|
' result.push(value);',
|
|
' }',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.isEmpty`
|
|
if (!isLodash('isEmpty')) {
|
|
source = replaceFunction(source, 'isEmpty', [
|
|
'function isEmpty(value) {',
|
|
' if (!value) {',
|
|
' return true;',
|
|
' }',
|
|
' if (isArray(value) || isString(value)) {',
|
|
' return !value.length;',
|
|
' }',
|
|
' for (var key in value) {',
|
|
' if (hasOwnProperty.call(value, key)) {',
|
|
' return false;',
|
|
' }',
|
|
' }',
|
|
' return true;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.isEqual`
|
|
if (!isLodash('baseIsEqual') && !isLodash('isEqual')) {
|
|
source = replaceFunction(source, 'isEqual', [
|
|
'function isEqual(a, b) {',
|
|
' return baseIsEqual(a, b);',
|
|
'}'
|
|
].join('\n'));
|
|
|
|
source = replaceFunction(source, 'baseIsEqual', [
|
|
'function baseIsEqual(a, b, stackA, stackB) {',
|
|
' if (a === b) {',
|
|
' return a !== 0 || (1 / a == 1 / b);',
|
|
' }',
|
|
' var type = typeof a,',
|
|
' otherType = typeof b;',
|
|
'',
|
|
' if (a === a &&',
|
|
" !(a && objectTypes[type]) &&",
|
|
" !(b && objectTypes[otherType])) {",
|
|
' return false;',
|
|
' }',
|
|
' if (a == null || b == null) {',
|
|
' return a === b;',
|
|
' }',
|
|
' var className = toString.call(a),',
|
|
' otherClass = toString.call(b);',
|
|
'',
|
|
' if (className != otherClass) {',
|
|
' return false;',
|
|
' }',
|
|
' switch (className) {',
|
|
' case boolClass:',
|
|
' case dateClass:',
|
|
' return +a == +b;',
|
|
'',
|
|
' case numberClass:',
|
|
' return a != +a',
|
|
' ? b != +b',
|
|
' : (a == 0 ? (1 / a == 1 / b) : a == +b);',
|
|
'',
|
|
' case regexpClass:',
|
|
' case stringClass:',
|
|
' return a == String(b);',
|
|
' }',
|
|
' var isArr = className == arrayClass;',
|
|
' if (!isArr) {',
|
|
" if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) {",
|
|
' return baseIsEqual(a.__wrapped__ || a, b.__wrapped__ || b, stackA, stackB);',
|
|
' }',
|
|
' if (className != objectClass) {',
|
|
' return false;',
|
|
' }',
|
|
' var ctorA = a.constructor,',
|
|
' ctorB = b.constructor;',
|
|
'',
|
|
' if (ctorA != ctorB && !(',
|
|
' isFunction(ctorA) && ctorA instanceof ctorA &&',
|
|
' isFunction(ctorB) && ctorB instanceof ctorB',
|
|
' )) {',
|
|
' return false;',
|
|
' }',
|
|
' }',
|
|
' stackA || (stackA = []);',
|
|
' stackB || (stackB = []);',
|
|
'',
|
|
' var length = stackA.length;',
|
|
' while (length--) {',
|
|
' if (stackA[length] == a) {',
|
|
' return stackB[length] == b;',
|
|
' }',
|
|
' }',
|
|
' var result = true,',
|
|
' size = 0;',
|
|
'',
|
|
' stackA.push(a);',
|
|
' stackB.push(b);',
|
|
'',
|
|
' if (isArr) {',
|
|
' size = b.length;',
|
|
' result = size == a.length;',
|
|
'',
|
|
' if (result) {',
|
|
' while (size--) {',
|
|
' if (!(result = baseIsEqual(a[size], b[size], stackA, stackB))) {',
|
|
' break;',
|
|
' }',
|
|
' }',
|
|
' }',
|
|
' return result;',
|
|
' }',
|
|
' forIn(b, function(value, key, b) {',
|
|
' if (hasOwnProperty.call(b, key)) {',
|
|
' size++;',
|
|
' return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, stackA, stackB));',
|
|
' }',
|
|
' });',
|
|
'',
|
|
' if (result) {',
|
|
' forIn(a, function(value, key, a) {',
|
|
' if (hasOwnProperty.call(a, key)) {',
|
|
' return (result = --size > -1);',
|
|
' }',
|
|
' });',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.memoize`
|
|
if (!isLodash('memoize')) {
|
|
source = replaceFunction(source, 'memoize', [
|
|
'function memoize(func, resolver) {',
|
|
' var cache = {};',
|
|
' return function() {',
|
|
' var key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]);',
|
|
' return hasOwnProperty.call(cache, key)',
|
|
' ? cache[key]',
|
|
' : (cache[key] = func.apply(this, arguments));',
|
|
' };',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.omit`
|
|
if (!isLodash('omit')) {
|
|
source = replaceFunction(source, 'omit', [
|
|
'function omit(object) {',
|
|
' var indexOf = getIndexOf(),',
|
|
' props = baseFlatten(arguments, true, false, 1),',
|
|
' result = {};',
|
|
'',
|
|
' forIn(object, function(value, key) {',
|
|
' if (indexOf(props, key) < 0) {',
|
|
' result[key] = value;',
|
|
' }',
|
|
' });',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.pick`
|
|
if (!isLodash('pick')) {
|
|
source = replaceFunction(source, 'pick', [
|
|
'function pick(object) {',
|
|
' var index = -1,',
|
|
' props = baseFlatten(arguments, true, false, 1),',
|
|
' length = props.length,',
|
|
' result = {};',
|
|
'',
|
|
' while (++index < length) {',
|
|
' var prop = props[index];',
|
|
' if (prop in object) {',
|
|
' result[prop] = object[prop];',
|
|
' }',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.result`
|
|
if (!isLodash('result')) {
|
|
source = replaceFunction(source, 'result', [
|
|
'function result(object, property) {',
|
|
' var value = object ? object[property] : undefined;',
|
|
' return isFunction(value) ? object[property]() : value;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.sortBy`
|
|
if (!isLodash('sortBy')) {
|
|
source = replaceFunction(source, 'sortBy', [
|
|
'function sortBy(collection, callback, thisArg) {',
|
|
' var index = -1,',
|
|
' length = collection ? collection.length : 0,',
|
|
" result = Array(typeof length == 'number' ? length : 0);",
|
|
'',
|
|
' callback = lodash.createCallback(callback, thisArg, 3);',
|
|
' forEach(collection, function(value, key, collection) {',
|
|
' result[++index] = {',
|
|
" 'criteria': callback(value, key, collection),",
|
|
" 'index': index,",
|
|
" 'value': value",
|
|
' };',
|
|
' });',
|
|
'',
|
|
' length = result.length;',
|
|
' result.sort(compareAscending);',
|
|
' while (length--) {',
|
|
' result[length] = result[length].value;',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.template`
|
|
if (!isLodash('template')) {
|
|
source = replaceFunction(source, 'template', [
|
|
'function template(text, data, options) {',
|
|
' var _ = lodash,',
|
|
' settings = _.templateSettings;',
|
|
'',
|
|
" text || (text = '');",
|
|
' options = iteratorTemplate ? defaults({}, options, settings) : settings;',
|
|
'',
|
|
' var index = 0,',
|
|
' source = "__p += \'",',
|
|
' variable = options.variable;',
|
|
'',
|
|
' var reDelimiters = RegExp(',
|
|
" (options.escape || reNoMatch).source + '|' +",
|
|
" (options.interpolate || reNoMatch).source + '|' +",
|
|
" (options.evaluate || reNoMatch).source + '|$'",
|
|
" , 'g');",
|
|
'',
|
|
' text.replace(reDelimiters, function(match, escapeValue, interpolateValue, evaluateValue, offset) {',
|
|
' source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);',
|
|
' if (escapeValue) {',
|
|
' source += "\' +\\n_.escape(" + escapeValue + ") +\\n\'";',
|
|
' }',
|
|
' if (evaluateValue) {',
|
|
' source += "\';\\n" + evaluateValue + ";\\n__p += \'";',
|
|
' }',
|
|
' if (interpolateValue) {',
|
|
' source += "\' +\\n((__t = (" + interpolateValue + ")) == null ? \'\' : __t) +\\n\'";',
|
|
' }',
|
|
' index = offset + match.length;',
|
|
' return match;',
|
|
' });',
|
|
'',
|
|
' source += "\';\\n";',
|
|
' if (!variable) {',
|
|
" variable = 'obj';",
|
|
" source = 'with (' + variable + ' || {}) {\\n' + source + '\\n}\\n';",
|
|
' }',
|
|
" source = 'function(' + variable + ') {\\n' +",
|
|
' "var __t, __p = \'\', __j = Array.prototype.join;\\n" +',
|
|
' "function print() { __p += __j.call(arguments, \'\') }\\n" +',
|
|
' source +',
|
|
" 'return __p\\n}';",
|
|
'',
|
|
' try {',
|
|
" var result = Function('_', 'return ' + source)(_);",
|
|
' } catch(e) {',
|
|
' e.source = source;',
|
|
' throw e;',
|
|
' }',
|
|
' if (data) {',
|
|
' return result(data);',
|
|
' }',
|
|
' result.source = source;',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.throttle`
|
|
if (!isLodash('throttle')) {
|
|
source = replaceFunction(source, 'throttle', [
|
|
'function throttle(func, wait, options) {',
|
|
' var leading = true,',
|
|
' trailing = true;',
|
|
'',
|
|
' if (options === false) {',
|
|
' leading = false;',
|
|
' } else if (isObject(options)) {',
|
|
" leading = 'leading' in options ? options.leading : leading;",
|
|
" trailing = 'trailing' in options ? options.trailing : trailing;",
|
|
' }',
|
|
' options = {};',
|
|
' options.leading = leading;',
|
|
' options.maxWait = wait;',
|
|
' options.trailing = trailing;',
|
|
'',
|
|
' return debounce(func, wait, options);',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.times`
|
|
if (!isLodash('times')) {
|
|
source = replaceFunction(source, 'times', [
|
|
'function times(n, callback, thisArg) {',
|
|
' var index = -1,',
|
|
' result = Array(n > -1 ? n : 0);',
|
|
'',
|
|
' while (++index < n) {',
|
|
' result[index] = callback.call(thisArg, index);',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.toArray`
|
|
if (!isLodash('toArray')) {
|
|
source = replaceFunction(source, 'toArray', [
|
|
'function toArray(collection) {',
|
|
' if (isArray(collection)) {',
|
|
' return slice(collection);',
|
|
' }',
|
|
" if (collection && typeof collection.length == 'number') {",
|
|
' return map(collection);',
|
|
' }',
|
|
' return values(collection);',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `baseUniq`
|
|
if (!isLodash('baseUniq') && !isLodash('uniq')) {
|
|
source = replaceFunction(source, 'baseUniq', [
|
|
'function baseUniq(array, isSorted, callback) {',
|
|
' var index = -1,',
|
|
' indexOf = getIndexOf(),',
|
|
' length = array ? array.length : 0,',
|
|
' result = [],',
|
|
' seen = callback ? [] : result;',
|
|
'',
|
|
' while (++index < length) {',
|
|
' var value = array[index],',
|
|
' computed = callback ? callback(value, index, array) : value;',
|
|
'',
|
|
' if (isSorted',
|
|
' ? !index || seen[seen.length - 1] !== computed',
|
|
' : indexOf(seen, computed) < 0',
|
|
' ) {',
|
|
' if (callback) {',
|
|
' seen.push(computed);',
|
|
' }',
|
|
' result.push(value);',
|
|
' }',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.uniqueId`
|
|
if (!isLodash('uniqueId')) {
|
|
source = replaceFunction(source, 'uniqueId', [
|
|
'function uniqueId(prefix) {',
|
|
" var id = ++idCounter + '';",
|
|
' return prefix ? prefix + id : id;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `_.where`
|
|
if (!isLodash('where')) {
|
|
source = replaceFunction(source, 'where', [
|
|
'function where(collection, properties, first) {',
|
|
' return (first && isEmpty(properties))',
|
|
' ? undefined',
|
|
' : (first ? find : filter)(collection, properties);',
|
|
'}'
|
|
].join('\n'));
|
|
|
|
// simplify `_.createCallback`
|
|
source = source.replace(matchFunction(source, 'createCallback'), function(match) {
|
|
return match
|
|
// remove unnecessary fast path
|
|
.replace(/^(( *)var props *=.+?),[\s\S]+?\n\2}/m, '$1;')
|
|
// remove `baseIsEqual` use
|
|
.replace(/=.+?\bbaseIsEqual\((.+?), *(.+?),.+?\)/, '= $1 === $2');
|
|
});
|
|
}
|
|
// replace `_.zip`
|
|
if(!isLodash('zip')) {
|
|
source = replaceFunction(source, 'zip', [
|
|
'function zip() {',
|
|
' var index = -1,',
|
|
" length = max(pluck(arguments, 'length')),",
|
|
' result = Array(length < 0 ? 0 : length);',
|
|
'',
|
|
' while (++index < length) {',
|
|
' result[index] = pluck(arguments, index);',
|
|
' }',
|
|
' return result;',
|
|
'}'
|
|
].join('\n'));
|
|
}
|
|
// replace `htmlEscapes` entries with hex entities
|
|
if (!isLodash('escape')) {
|
|
source = source.replace(matchVar(source, 'htmlEscapes'), function(match) {
|
|
return match
|
|
.replace('#39', '#x27')
|
|
.replace(/(\n *)}/, ",$1 '/': '/'$1}");
|
|
});
|
|
}
|
|
// remove support for a `step` of `0` in `_.range`
|
|
if (!isLodash('range')) {
|
|
source = source.replace(matchFunction(source, 'range'), function(match) {
|
|
return match
|
|
.replace(/typeof *step[^:]+:/, '')
|
|
.replace(/\(step.*\|\|.+?\)/, 'step')
|
|
});
|
|
}
|
|
if (!isModularize) {
|
|
// remove `_.templateSettings.imports assignment
|
|
source = source.replace(/,[^']*'imports':[^}]+}/, '');
|
|
|
|
// replace complex lodash wrapper checks with simpler ones
|
|
source = source.replace(matchFunction(source, 'baseIsEqual'), function(match) {
|
|
return match.replace(/hasOwnProperty\.call\((\w+), *'__wrapped__'\)/g, '$1 instanceof lodash')
|
|
});
|
|
}
|
|
// replace `slice` with `nativeSlice.call`
|
|
_.each(['clone', 'first', 'initial', 'last', 'rest', 'toArray'], function(funcName) {
|
|
if (funcName == 'clone'
|
|
? (!isLodash('baseClone') && !isLodash('clone') && !isLodash('cloneDeep'))
|
|
: !isLodash(funcName)
|
|
) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/([^\w.])slice\(/g, '$1nativeSlice.call(');
|
|
});
|
|
}
|
|
});
|
|
|
|
// remove conditional `charCodeCallback` use from `_.max` and `_.min`
|
|
_.each(['max', 'min'], function(funcName) {
|
|
if (!isLodash(funcName)) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/=.+?callback *&& *isString[^:]+:\s*/g, '= ');
|
|
});
|
|
}
|
|
});
|
|
}
|
|
// add Underscore's chaining functions
|
|
if (_.contains(plusFuncs, 'chain') == !isUnderscore) {
|
|
source = addUnderscoreChaining(source, isModularize);
|
|
}
|
|
// replace `baseEach` references with `forEach` and `forOwn`
|
|
if (isUnderscore || (isModern && !isMobile)) {
|
|
// replace `baseEach` with `_.forOwn` in "Collections" functions
|
|
source = source.replace(/\bbaseEach(?=\(collection)/g, 'forOwn');
|
|
|
|
// replace `baseEach` with `_.forEach` in the rest of the functions
|
|
source = source.replace(/(\?\s*)baseEach(?=\s*:)/g, '$1forEach');
|
|
|
|
// replace `baseEach` with `_.forEach` in the function assignment snippet
|
|
source = source.replace(/\bbaseEach(?=\(\[')/g, 'forEach');
|
|
}
|
|
|
|
var context = vm.createContext({
|
|
'clearTimeout': clearTimeout,
|
|
'console': console,
|
|
'setTimeout': setTimeout
|
|
});
|
|
|
|
vm.runInContext(source, context);
|
|
return context._;
|
|
}());
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
if (isTemplate) {
|
|
source = buildTemplate(templatePattern, templateSettings);
|
|
}
|
|
else {
|
|
source = removeFromCreateIterator(source, 'support');
|
|
source = removePseudoPrivates(source);
|
|
|
|
// inline `iteratorTemplate` template
|
|
source = replaceFunction(source, 'iteratorTemplate', (function() {
|
|
var snippet = cleanupCompiled(getFunctionSource(lodash._iteratorTemplate));
|
|
|
|
// prepend data object references to property names to avoid having to
|
|
// use a with-statement
|
|
iteratorOptions.forEach(function(prop) {
|
|
if (prop !== 'support') {
|
|
snippet = snippet.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|([^.])\\b' + prop + '\\b', 'g'), function(match, quote, prelude) {
|
|
return quote ? match : (prelude + 'obj.' + prop);
|
|
});
|
|
}
|
|
});
|
|
|
|
// remove unnecessary code
|
|
snippet = snippet
|
|
.replace(/var __t.+/, "var __p = '';")
|
|
.replace(/function print[^}]+}/, '')
|
|
.replace(/'(?:\\n|\s)+'/g, "''")
|
|
.replace(/__p *\+= *' *';/g, '')
|
|
.replace(/\s*\+\s*'';/g, ';')
|
|
.replace(/(__p *\+= *)' *' *\+/g, '$1')
|
|
.replace(/\(\(__t *= *\( *([\s\S]+?) *\)\) *== *null *\? *'' *: *__t\)/g, '($1)');
|
|
|
|
// remove the with-statement
|
|
snippet = snippet.replace(/^ *with *\(.+?\) *{\n/m, '\n').replace(/}([^}]*}[^}]*$)/, '$1');
|
|
|
|
// minor cleanup
|
|
snippet = snippet
|
|
.replace(/obj\s*\|\|\s*\(obj *= *{}\);/, '')
|
|
.replace(/var __p = '';\s*__p \+=/, 'var __p =');
|
|
|
|
// remove comments, including sourceURLs
|
|
snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, '');
|
|
|
|
// replace `iteratorTemplate` assignment
|
|
snippet = 'var iteratorTemplate = ' + snippet + ';\n';
|
|
|
|
return snippet;
|
|
}()));
|
|
|
|
// remove `iteratorTemplate` dependency checks from `_.template`
|
|
source = source.replace(matchFunction(source, 'template'), function(match) {
|
|
return match
|
|
.replace(/iteratorTemplate *&& */g, '')
|
|
.replace(/iteratorTemplate\s*\?\s*([^:]+?)\s*:[^,;]+/g, '$1');
|
|
});
|
|
|
|
if (isModern || isUnderscore) {
|
|
iteratorOptions.forEach(function(prop) {
|
|
if (prop != 'array') {
|
|
source = removeFromGetObject(source, prop);
|
|
}
|
|
});
|
|
|
|
// inline all functions defined with `createIterator`
|
|
_.functions(lodash).forEach(function(funcName) {
|
|
if (!(isUnderscore && isLodash(funcName))) {
|
|
// strip leading underscores to match pseudo private functions
|
|
var reFunc = RegExp('^( *)(var ' + funcName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n', 'm');
|
|
if (reFunc.test(source)) {
|
|
// extract, format, and inject the compiled function's source code
|
|
source = source.replace(reFunc, function(match, indent, left) {
|
|
return (indent + left) +
|
|
cleanupCompiled(getFunctionSource(lodash[funcName], indent)) + ';\n';
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
if (isUnderscore) {
|
|
// replace `lodash.createCallback` references with `createCallback`
|
|
if (!isLodash('createCallback')) {
|
|
source = source.replace(/\blodash\.(createCallback\()\b/g, '$1');
|
|
}
|
|
// unexpose "exit early" feature from functions
|
|
if (!isLodash('forEach') && !isLodash('forEachRight') &&
|
|
!isLodash('forIn') && !isLodash('forInRight') &&
|
|
!isLodash('forOwn') && !isLodash('forOwnRight')) {
|
|
_.each(['baseEach', 'forEach', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/=== *false\)/g, '=== indicatorObject)');
|
|
});
|
|
});
|
|
|
|
_.each(['forEachRight', 'transform'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/return callback[^)]+\)/, '$& === false && indicatorObject');
|
|
});
|
|
});
|
|
|
|
_.each(['baseIsEqual', 'every'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/\(result *= *(.+?)\);/g, '!(result = $1) && indicatorObject;');
|
|
});
|
|
});
|
|
|
|
_.each(['find', 'findKey', 'findLast', 'findLastKey', 'shimIsPlainObject'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/return false/, 'return indicatorObject');
|
|
});
|
|
});
|
|
|
|
_.each(['contains', 'some'], function(funcName) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/!\(result *= *(.+?)\);/, '(result = $1) && indicatorObject;');
|
|
});
|
|
});
|
|
}
|
|
// remove chainability
|
|
_.each(['baseEach', 'forEach', 'forEachRight'], function(funcName) {
|
|
if (funcName == 'baseEach' || !isLodash(funcName)) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match.replace(/\n *return .+?([}\s]+)$/, '$1');
|
|
});
|
|
}
|
|
});
|
|
|
|
// remove `thisArg` from unexposed `forEachRight`, `forIn` and `forOwn`
|
|
_.each(['forEachRight', 'forIn', 'forOwn'], function(funcName) {
|
|
if (!isLodash(funcName)) {
|
|
source = source.replace(matchFunction(source, funcName), function(match) {
|
|
return match
|
|
.replace(/(callback), *thisArg/g, '$1')
|
|
.replace(/^ *callback *=.+\n/m, '');
|
|
});
|
|
}
|
|
});
|
|
|
|
// remove `_.assign`, `_.forEachRight`, `_.forIn`, `_.forOwn`, `_.isPlainObject`, `_.unzip`, and `_.zipObject` assignments
|
|
source = source.replace(getMethodAssignments(source), function(match) {
|
|
return _.reduce(['assign', 'createCallback', 'forEachRight', 'forIn', 'forOwn', 'isPlainObject', 'unzip', 'zipObject'], function(result, funcName) {
|
|
return isLodash(funcName)
|
|
? result
|
|
: result.replace(RegExp('^(?: *//.*\\s*)* *lodash\\.' + funcName + ' *=[\\s\\S]+?;\\n', 'm'), '');
|
|
}, match);
|
|
});
|
|
}
|
|
}
|
|
if (isModularize) {
|
|
source = removeGetIndexOf(source);
|
|
|
|
// replace the `lodash.templateSettings` property assignment with a variable assignment
|
|
source = source.replace(/\b(lodash\.)(?=templateSettings *=)/, 'var ');
|
|
|
|
// remove the `lodash` namespace from properties
|
|
source = source.replace(/\blodash\.(?!com|prototype)(\w+)\b(?!\s*=)/g, '$1');
|
|
|
|
// remove all horizontal rule comment separators
|
|
source = source.replace(/^ *\/\*-+\*\/\n/gm, '');
|
|
|
|
// remove `lodash` branch in `_.mixin`
|
|
source = source.replace(matchFunction(source, 'mixin'), function(match) {
|
|
return match.replace(/(?: *\/\/.*\n)*( *)if *\(!source[\s\S]+?\n\1}/, '');
|
|
});
|
|
|
|
// replace `lodash` use in `_.templateSettings.imports`
|
|
source = source.replace(matchProp(source, 'templateSettings'), function(match) {
|
|
return match.replace(/(:\s*)lodash\b/, "$1{ 'escape': escape }");
|
|
});
|
|
|
|
source = source.replace(matchFunction(source, 'template'), function(match) {
|
|
if (isUnderscore) {
|
|
// assign `_` via `template.imports`
|
|
return match.replace(/_ *= *lodash\b/, '$&.templateSettings.imports._');
|
|
}
|
|
return match
|
|
// assign `settings` via `template.imports`
|
|
.replace(/= *templateSettings(?=[,;])/, '$&.imports._.templateSettings')
|
|
// remove debug sourceURL use in `_.template`
|
|
.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, '');
|
|
});
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// customize Lo-Dash's export bootstrap
|
|
if (!isAMD || isModularize) {
|
|
source = source.replace(/(?: *\/\/.*\n)*( *)if *\(typeof +define[\s\S]+?else /, '$1');
|
|
}
|
|
if (!isNode || isModularize) {
|
|
source = removeVar(source, 'freeGlobal');
|
|
source = source.replace(/(?: *\/\/.*\n)*( *)if *\(freeModule[\s\S]+?else *{([\s\S]+?\n)\1}\n+/, '$1$2');
|
|
}
|
|
if (!isCommonJS || isModularize) {
|
|
source = source.replace(/(?: *\/\/.*\n)*(?:( *)(})? *else *{)?\s*freeExports\.\w+ *=[\s\S]+?(?:\n\1})?\n+/, '$1$2\n');
|
|
}
|
|
if (!isGlobal || isModularize) {
|
|
source = source.replace(/(?: *\/\/.*\n)*(?:( *)(})? *else(?: *if *\(_\))? *{)?(?:\s*\/\/.*)*\s*(?:window\._|_\.templates) *=[\s\S]+?(?:\n\1})?\n+/g, '$1$2\n');
|
|
}
|
|
// remove `if (freeExports) {...}` if it's empty
|
|
if (isAMD && isGlobal && !isModularize) {
|
|
source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports.*?\) *{\s*}\n+/, '');
|
|
} else {
|
|
source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports.*?\) *{\s*}(?:\s*else *{([\s\S]+?) *})?\n+/, '$1\n');
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
// exit early to create modules
|
|
if (isModularize) {
|
|
buildModule({
|
|
'buildFuncs': buildFuncs,
|
|
'filePath': filePath,
|
|
'funcDepMap': funcDepMap,
|
|
'includeFuncs': includeFuncs,
|
|
'includeProps': includeProps,
|
|
'includeVars': includeVars,
|
|
'isAMD': isAMD,
|
|
'isBackbone': isBackbone,
|
|
'isCommonJS': isCommonJS,
|
|
'isCSP': isCSP,
|
|
'isDebug': true,
|
|
'isGlobal': isGlobal,
|
|
'isIIFE': true,
|
|
'isLegacy': isLegacy,
|
|
'isMapped': isMapped,
|
|
'isMobile': isMobile,
|
|
'isModern': isModern,
|
|
'isNode': isNode,
|
|
'isStdOut': isStdOut,
|
|
'isStrict': isStrict,
|
|
'isUnderscore': isUnderscore,
|
|
'minusFuncs': minusFuncs,
|
|
'options': options,
|
|
'outputPath': outputPath,
|
|
'plusFuncs': plusFuncs,
|
|
'propDepMap': propDepMap,
|
|
'source': source,
|
|
'varDepMap': varDepMap
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
// customize Lo-Dash's IIFE
|
|
if (isIIFE) {
|
|
source = (function() {
|
|
var token = '%output%',
|
|
header = source.match(/^\/\**[\s\S]+?\*\/\n/),
|
|
index = iife.indexOf(token);
|
|
|
|
return header + (index < 0
|
|
? iife
|
|
: iife.slice(0, index).replace(/\n+$/, '') +
|
|
source.replace(/^[\s\S]+?\(function[^{]+{\n|\s*}\(this\)\)[;\s]*$/g, '\n') +
|
|
iife.slice(index + token.length).replace(/^\n+/, '')
|
|
);
|
|
}());
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
// modify/remove references to removed functions/variables
|
|
if (!isTemplate) {
|
|
if (isExcluded(isNoDep ? 'lodash' : 'lodashWrapper')) {
|
|
// remove `lodashWrapper.prototype` assignment
|
|
source = source.replace(/(?:\s*\/\/.*)*\n *lodashWrapper\.prototype *=.+/, '');
|
|
}
|
|
if (isExcluded(isNoDep ? 'lodash' : 'mixin')) {
|
|
// remove `_.mixin` call
|
|
source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\).+/, '');
|
|
}
|
|
if (isExcluded(isNoDep ? 'lodash' : 'wrapperValueOf')) {
|
|
source = removeChaining(source);
|
|
}
|
|
if (!isNoDep) {
|
|
if (isExcluded('bind')) {
|
|
source = removeSupportProp(source, 'fastBind');
|
|
}
|
|
if (isExcluded('clone', 'isEqual', 'isPlainObject')) {
|
|
source = removeSupportNodeClass(source);
|
|
}
|
|
if (isExcluded('createIterator')) {
|
|
source = removeSupportNonEnumShadows(source);
|
|
}
|
|
if (isExcluded('isArguments')) {
|
|
source = replaceSupportProp(source, 'argsClass', 'true');
|
|
}
|
|
if (isExcluded('isArguments', 'isEmpty')) {
|
|
source = removeSupportArgsClass(source);
|
|
}
|
|
if (isExcluded('isPlainObject')) {
|
|
source = removeSupportOwnLast(source);
|
|
}
|
|
if (isExcluded('keys')) {
|
|
source = removeKeysOptimization(source);
|
|
source = removeSupportNonEnumArgs(source);
|
|
}
|
|
if (isExcluded('lodashWrapper')) {
|
|
source = removeChaining(source);
|
|
}
|
|
if (isExcluded('throttle')) {
|
|
_.each(['leading', 'maxWait', 'trailing'], function(prop) {
|
|
source = removeFromGetObject(source, prop);
|
|
});
|
|
}
|
|
if (!/\.(?:enumErrorProps|nonEnumShadows) *=/.test(source)) {
|
|
source = removeFromCreateIterator(source, 'errorClass');
|
|
source = removeFromCreateIterator(source, 'errorProto');
|
|
|
|
// remove 'Error' from the `contextProps` array
|
|
source = source.replace(/^ *var contextProps *=[\s\S]+?;/m, function(match) {
|
|
return match
|
|
.replace(/'Error',? */, '')
|
|
.replace(/,(?=\s*])/, '');
|
|
});
|
|
}
|
|
_.each([removeFromGetObject, removeFromReleaseObject], function(func) {
|
|
if (isExcluded('setBindData')) {
|
|
source = func(source, 'configurable');
|
|
source = func(source, 'enumerable');
|
|
source = func(source, 'writable');
|
|
}
|
|
if (isExcluded('sortBy')) {
|
|
source = func(source, 'criteria');
|
|
source = func(source, 'index');
|
|
source = func(source, 'value');
|
|
}
|
|
});
|
|
}
|
|
|
|
// remove functions from the build
|
|
allFuncs.forEach(function(funcName) {
|
|
if (!_.contains(buildFuncs, funcName) &&
|
|
!(funcName == 'findWhere' && !isUnderscore) &&
|
|
!(funcName == 'lodash' && !isNoDep)) {
|
|
source = removeFunction(source, funcName);
|
|
if (!isNoDep) {
|
|
source = removeFromCreateIterator(source, funcName);
|
|
source = source.replace(RegExp('^(?: *//.*\\s*)* *lodash(?:\\.prototype)?\\.\\w+ *= *' + funcName + ';\\n', 'gm'), '');
|
|
}
|
|
}
|
|
});
|
|
|
|
// remove forks of removed functions
|
|
_.forOwn({
|
|
'createObject': removeCreateObjectFork,
|
|
'defer': removeDeferFork,
|
|
'isArguments': removeIsArgumentsFork,
|
|
'isArray': removeIsArrayFork,
|
|
'isFunction': removeIsFunctionFork
|
|
},
|
|
function(removeFork, funcName) {
|
|
if (isExcluded(funcName)) {
|
|
source = removeFork(source);
|
|
}
|
|
});
|
|
|
|
// remove unneeded property dependencies
|
|
_.each(propDependencies, function(propName) {
|
|
if (!_.contains(includeProps, propName)) {
|
|
source = removeProp(source, propName);
|
|
}
|
|
});
|
|
|
|
// remove code used to resolve unneeded `support` properties
|
|
source = source.replace(matchProp(source, 'support'), function(match) {
|
|
return match.replace(/^ *\(function[\s\S]+?\n(( *)var ctor *=[\s\S]+?(?:\n *for.+)+\n)([\s\S]+?)}\(1\)\);\n/m, function(match, setup, indent, body) {
|
|
var modified = setup;
|
|
|
|
if (!/\.spliceObjects *=(?! *(?:false|true))/.test(body)) {
|
|
modified = modified.replace(/^ *object *=.+\n/m, '');
|
|
}
|
|
if (!/\.enumPrototypes *=(?! *(?:false|true))/.test(body) &&
|
|
!/\.nonEnumShadows *=(?! *(?:false|true))/.test(body) &&
|
|
!/\.ownLast *=(?! *(?:false|true))/.test(body)) {
|
|
modified = modified
|
|
.replace(/\bctor *=.+\s+/, '')
|
|
.replace(/^ *ctor\.prototype.+\s+.+\n/m, '')
|
|
.replace(/(?:,\n)? *props *=[^;=]+/, '')
|
|
.replace(/^ *for *\((?=prop)/, '$&var ')
|
|
}
|
|
if (!/\.nonEnumArgs *=(?! *(?:false|true))/.test(body)) {
|
|
modified = modified.replace(/^ *for *\(.+? arguments.+\n/m, '');
|
|
}
|
|
// cleanup the empty var statement
|
|
modified = modified.replace(/^ *var;\n/m, '');
|
|
|
|
// if no setup then remove IIFE
|
|
return /^\s*$/.test(modified)
|
|
? body.replace(RegExp('^' + indent, 'gm'), indent.slice(0, -2))
|
|
: match.replace(setup, modified);
|
|
});
|
|
});
|
|
|
|
// remove unused variables
|
|
(function() {
|
|
var isShallow = isExcluded('runInContext'),
|
|
useMap = {},
|
|
snippet = removeStrings(removeComments(source)),
|
|
varNames = getVars(snippet, isShallow);
|
|
|
|
while (varNames.length) {
|
|
varNames = _.sortBy(varNames, function(varName) {
|
|
var result = _.contains(includeVars, varName) || isVarUsed(snippet, varName, isShallow);
|
|
useMap[varName] = result;
|
|
return result;
|
|
});
|
|
|
|
if (useMap[varNames[0]]) {
|
|
varNames.shift();
|
|
}
|
|
else {
|
|
while (varNames.length && !useMap[varNames[0]]) {
|
|
snippet = removeVar(snippet, varNames[0]);
|
|
source = removeVar(source, varNames[0]);
|
|
varNames.shift();
|
|
}
|
|
}
|
|
}
|
|
}());
|
|
|
|
if (isNoDep) {
|
|
if (isExcluded('lodash')) {
|
|
source = removeAssignments(source);
|
|
}
|
|
// remove unneeded variable dependencies
|
|
_.each(varDependencies, function(varName) {
|
|
if (!_.contains(includeVars, varName)) {
|
|
source = removeVar(source, varName);
|
|
}
|
|
});
|
|
}
|
|
else if (isUnderscore) {
|
|
// unexpose `lodash.support`
|
|
if (!isLodash('support')) {
|
|
source = source.replace(/\blodash\.support *= */, '');
|
|
}
|
|
}
|
|
}
|
|
if (_.size(source.match(/\bfreeModule\b/g)) < 2) {
|
|
source = removeVar(source, 'freeModule');
|
|
}
|
|
if (_.size(source.match(/\bfreeExports\b/g)) < 2) {
|
|
source = removeVar(source, 'freeExports');
|
|
}
|
|
|
|
debugSource = cleanupSource(source);
|
|
source = debugSource;
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
// resolve `outputPath` and create directories if needed
|
|
if (!outputPath) {
|
|
outputPath = options.reduce(function(result, value, index) {
|
|
if (/^(?:-o|--output)$/.test(value)) {
|
|
result = options[index + 1];
|
|
var dirname = path.dirname(result);
|
|
fs.mkdirpSync(dirname);
|
|
result = path.join(fs.realpathSync(dirname), path.basename(result));
|
|
}
|
|
return result;
|
|
}, '');
|
|
} else {
|
|
fs.mkdirpSync(path.dirname(outputPath));
|
|
}
|
|
|
|
// flag to track if `outputPath` has been used by `callback`
|
|
var outputUsed = false;
|
|
|
|
// flag to specify creating a custom build
|
|
var isCustom = !isNoDep && (
|
|
isLegacy || isMapped || isModern || isStrict || isUnderscore || outputPath ||
|
|
/(?:category|exclude|exports|iife|include|minus|plus)=.*$/.test(options) ||
|
|
!_.isEqual(exportsOptions, allExports)
|
|
);
|
|
|
|
// used as the basename of the output path
|
|
var basename = outputPath
|
|
? path.basename(outputPath, '.js')
|
|
: 'lodash' + (isTemplate ? '.template' : isCustom ? '.custom' : '');
|
|
|
|
// output debug build
|
|
if (!isMinify && (isCustom || isDebug || isTemplate)) {
|
|
if (isCustom) {
|
|
debugSource = addCommandsToHeader(debugSource, options);
|
|
}
|
|
if (isDebug && isStdOut) {
|
|
stdout.write(debugSource);
|
|
callback({
|
|
'source': debugSource
|
|
});
|
|
}
|
|
else if (!isStdOut) {
|
|
filePath = outputPath || path.join(cwd, basename + '.js');
|
|
outputUsed = true;
|
|
callback({
|
|
'source': debugSource,
|
|
'outputPath': filePath
|
|
});
|
|
}
|
|
}
|
|
// begin the minification process
|
|
if (!isDebug) {
|
|
if (outputPath && outputUsed) {
|
|
outputPath = path.join(path.dirname(outputPath), path.basename(outputPath, '.js') + '.min.js');
|
|
} else if (!outputPath) {
|
|
outputPath = path.join(cwd, basename + '.min.js');
|
|
}
|
|
minify(source, {
|
|
'filePath': filePath,
|
|
'isMapped': isMapped,
|
|
'isSilent': isSilent,
|
|
'isTemplate': isTemplate,
|
|
'modes': isIIFE && ['simple', 'hybrid'],
|
|
'outputPath': outputPath,
|
|
'sourceMapURL': sourceMapURL,
|
|
'onComplete': function(data) {
|
|
if (isCustom) {
|
|
data.source = addCommandsToHeader(data.source, options);
|
|
}
|
|
if (isStdOut) {
|
|
delete data.outputPath;
|
|
stdout.write(data.source);
|
|
}
|
|
callback(data);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// expose `build`
|
|
if (module != require.main) {
|
|
module.exports = build;
|
|
}
|
|
else {
|
|
// or invoked directly
|
|
build(process.argv);
|
|
}
|
|
}());
|