From 8f9c4cd21732a50fdc6d9416a054e3d4ce39fc14 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 27 Aug 2013 23:28:45 -0700 Subject: [PATCH] Remove build from this repo to move to lodash-cli. Former-commit-id: 0f9e802dd744a97494a10537442a28aae40dc72a --- .gitignore | 2 - .jamignore | 1 - .travis.yml | 3 - bower.json | 2 - build.js | 4563 ----------------------------------------- build/minify.js | 793 ------- build/post-compile.js | 117 -- build/pre-compile.js | 461 ----- build/util.js | 98 - component.json | 2 +- package.json | 15 +- test/run-test.sh | 4 - test/template/a.jst | 3 - test/template/b.jst | 1 - test/template/c.jst | 1 - test/template/d.tpl | 1 - test/test-build.js | 1837 ----------------- 17 files changed, 9 insertions(+), 7895 deletions(-) delete mode 100644 build.js delete mode 100755 build/minify.js delete mode 100644 build/post-compile.js delete mode 100644 build/pre-compile.js delete mode 100755 build/util.js delete mode 100644 test/template/a.jst delete mode 100644 test/template/b.jst delete mode 100644 test/template/c.jst delete mode 100644 test/template/d.tpl delete mode 100644 test/test-build.js diff --git a/.gitignore b/.gitignore index 22f40633b..be1249018 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,3 @@ *.map modularize node_modules -vendor/closure-compiler -vendor/uglifyjs diff --git a/.jamignore b/.jamignore index 436f690da..a05e65d52 100644 --- a/.jamignore +++ b/.jamignore @@ -11,7 +11,6 @@ lodash.js index.js bower.json component.json -build doc modularize node_modules diff --git a/.travis.yml b/.travis.yml index 4f5316657..5b7c16b3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,15 +8,12 @@ env: - TEST_COMMAND="phantomjs ./test/test.js ../dist/lodash.compat.min.js" - TEST_COMMAND="node ./test/test.js ../dist/lodash.js" - TEST_COMMAND="node ./test/test.js ../dist/lodash.min.js" - - TEST_COMMAND="node ./test/test-build.js --time-limit 48m" git: depth: 1 branches: only: - master before_script: - - "tar -xzvf vendor/closure-compiler.tar.gz -C vendor" - - "tar -xzvf vendor/uglifyjs.tar.gz -C vendor" - "npm install -g istanbul" script: $TEST_COMMAND diff --git a/bower.json b/bower.json index f82de6d01..85aca7264 100644 --- a/bower.json +++ b/bower.json @@ -11,11 +11,9 @@ "*.map", "*.md", "*.txt", - "build.js", "index.js", "component.json", "package.json", - "build", "doc", "node_modules", "perf", diff --git a/build.js b/build.js deleted file mode 100644 index 758e64f27..000000000 --- a/build.js +++ /dev/null @@ -1,4563 +0,0 @@ -#!/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', - 'eachRight': 'forEachRight', - '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'], - 'forEachRight': ['eachRight'], - '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', 'createBound', 'functions'], - 'bindKey': ['createBound'], - 'chain': ['lodashWrapper'], - 'clone': ['baseClone', 'baseCreateCallback'], - 'cloneDeep': ['baseClone', 'baseCreateCallback'], - 'compact': [], - 'compose': ['isFunction'], - 'contains': ['baseEach', 'getIndexOf', 'isArray', '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', 'baseEach', 'isArray', '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'], - 'sample': ['isArray', 'random', 'shuffle', 'toArray'], - 'shuffle': ['forEach', 'random'], - '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': ['baseEach', 'createCallback', 'isArray'], - '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'], - 'debounce': ['reNative'], - 'defaults': ['defaultsIteratorOptions'], - 'defer': ['objectTypes', 'reNative', 'root'], - 'difference': ['largeArraySize'], - 'escape': ['reUnescapedHtml'], - 'escapeHtmlChar': ['htmlEscapes'], - 'forIn': ['eachIteratorOptions', 'forOwnIteratorOptions'], - 'forOwn': ['eachIteratorOptions', 'forOwnIteratorOptions'], - 'forOwnIteratorOptions': ['eachIteratorOptions'], - 'getArray': ['arrayPool'], - 'getObject': ['objectPool'], - 'htmlUnescapes': ['htmlEscapes'], - 'intersection': ['largeArraySize'], - 'isArray': ['reNative'], - 'isFinite': ['root'], - 'isObject': ['objectTypes'], - 'isPlainObject': ['reNative'], - 'isRegExp': ['objectTypes'], - 'keys': ['reNative'], - 'memoize': ['keyPrefix'], - 'parseInt': ['root'], - 'reEscapedHtml': ['htmlUnescapes'], - 'releaseArray': ['arrayPool', 'maxPoolSize'], - 'releaseObject': ['maxPoolSize', 'objectPool'], - 'reUnescapedHtml': ['htmlEscapes'], - 'root': ['objectTypes'], - 'setBindData': ['reNative'], - 'support': ['reNative', 'root'], - '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', - 'sample', - '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', - 'npm' - ]; - - /** List of variables with complex assignments */ - var complexVars = [ - 'cloneableClasses', - 'contextProps', - 'ctorByClass', - 'defineProperty', - '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', - 'sample', - '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, - isNpm = state.isNpm, - 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 depPaths = getDepPaths(deps, modulePath); - - if (isAMD) { - iife.push( - 'define([' + (depPaths.length ? "'" + depPaths.join("', '") + "'" : '') + '], function(' + deps.join(', ') + ') {', - '%output%', - ' return ' + identifier + ';', - '});' - ); - } - else if (isNode) { - if (isNpm) { - depPaths = deps.map(function(dep) { return 'lodash.' + dep; }); - } - iife.push( - _.reduce(depPaths, function(result, path, index) { - return result + (result ? ',\n ' : ' var ') + deps[index] + " = require('" + path + "')"; - }, '') + ';', - '%output%', - 'module.exports = ' + 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, function(data) { - var source = data.source; - if (isNode) { - source = source.replace(/^ /gm, ''); - } - data.source = source; - defaultBuildCallback(data); - }); - }); - - // 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 = []; - - if (isAMD) { - iife.push( - 'define([' + (depPaths.length ? "'" + depPaths.join("', '") + "'" : '') + '], function(' + depArgs + ') {', - '%output%', - ' return lodash;', - '});' - ); - } - else if (isNode) { - if (isNpm) { - deps = _.union(deps, _.transform(categories, function(result, category) { - push.apply(result, _.intersection(categoryMap[category], identifiers)); - })) - .sort(); - - depPaths = deps.map(function(dep) { return 'lodash.' + dep; }); - } else { - deps = categoryDeps.concat(deps); - } - - iife.push( - _.reduce(depPaths, function(result, path, index) { - return result + (result ? ',\n ' : ' var ') + deps[index] + " = require('" + path + "')"; - }, '') + ';', - '%output%', - 'module.exports = ' + identifier + ';' - ); - } - - 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 - if (!isNpm) { - 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 +|module\.exports\s*=\s*)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; - }); - - if (isNode) { - source = source.replace(/^ /gm, ''); - } - data.source = source; - defaultBuildCallback(data); - }); - }()); - - // clear state - state.buildFuncs = state.includeFuncs = state.includeProps = state.includeVars = empty; - - // create category modules - if (!isNpm) { - categories.forEach(function(category) { - var deps = _.intersection(categoryMap[category], identifiers).sort(), - depPaths = getDepPaths(deps), - iife = []; - - if (isAMD) { - iife.push( - "define(['" + depPaths.join("', '") + "'], function(" + deps.join(', ') + ') {', - '%output%', - ' return {', - deps.map(function(dep) { return " '" + dep + "': " + dep; }).join(',\n'), - ' };', - '});' - ); - } - else if (isNode) { - iife.push( - '%output%', - 'module.exports = {', - depPaths.map(function(path, index) { return " '" + deps[index] + "': require('" + path + "')"; }).join(',\n'), - '};' - ); - } - state.iife = iife.join('\n'); - state.outputPath = path.join(outputPath, category.toLowerCase() + '.js'); - build(state); - }); - } - } - - /** - * Compiles template files based on the provided build state using the single - * source, extending `_.templates` with precompiled templates named after - * each template file's basename. - * - * @private - * @param {Object} state The build state object. - * @returns {string} Returns the compiled source. - */ - function buildTemplate(state) { - var pattern = state.templatePattern, - settings = state.templateSettings, - moduleId = settings.moduleId; - - pattern || (pattern = path.join(cwd, '*.jst')); - - var directory = fs.realpathSync(path.dirname(pattern)); - - var source = [ - ';(function(root) {', - ' 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)) {', - ' root = freeGlobal;', - ' }', - '', - ' var templates = {},', - ' _ = root._;', - '' - ]; - - // 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, settings), 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(['" + moduleId + "'], function(lodash) {", - ' _ = lodash;', - ' lodash.templates = lodash.extend(lodash.templates || {}, templates);', - ' });', - " } else if (freeExports && !freeExports.nodeType) {", - " _ = require('" + 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(){%output%}()"`)', - '', - ' 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 {string|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(?!\\s*=)').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/i.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) { - source = removeSupportProp(source, 'funcNames'); - - // 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.+?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, 'root') - .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 `_.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 = (function() { - var result = options.reduce(function(result, value) { - return /^exports=.*$/.test(value) ? optionToArray(value).sort() : result; - }, isModularize - ? [] - : (isUnderscore ? ['commonjs', 'global', 'node'] : _.without(allExports, 'npm')) - ); - return isModularize ? _.first(result, 1) : result; - }()); - - // 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'), - isNpm = _.contains(exportsOptions, 'npm'), - isNode = isNpm || _.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) { - _.forOwn(varDepMap, function(deps, funcName) { - _.pull(deps, 'root'); - }); - - funcDepMap.lodash.push('support', 'baseEach', 'forOwn', 'mixin'); - _.pull(funcDepMap.mixin, 'lodash'); - delete varDepMap.root; - } - 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, 'isArray', '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', 'createAggregator', 'every', 'filter', 'find', 'forEach', 'forEachRight', '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 `createBound` - 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 = removeIsFunctionFork(source); - source = removeCreateObjectFork(source); - - // replace `+new Date` with `Date.now` use in `_.debounce - source = source.replace(matchFunction(source, 'debounce'), function(match) { - return match.replace(/\+?new Date\b/g, 'now()'); - }); - - // remove `shimIsPlainObject` from `_.isPlainObject` - source = source.replace(matchFunction(source, 'isPlainObject'), function(match) { - return match.replace(/!getPrototypeOf[^:]+:\s*/, ''); - }); - } - } - if (isLegacy || isMobile || isUnderscore) { - source = removeEsOptimization(source); - 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 `_.forEachRight` - source = replaceFunction(source, 'forEachRight', [ - 'function forEachRight(collection, callback, thisArg) {', - ' var length = collection ? collection.length : 0;', - " callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);", - " if (typeof length == 'number') {", - ' while (length--) {', - ' if (callback(collection[length], length, collection) === false) {', - ' break;', - ' }', - ' }', - ' } else {', - ' var props = keys(collection);', - ' length = props.length;', - ' baseEach(collection, function(value, key, collection) {', - ' key = props ? props[--length] : --length;', - ' return callback(collection[key], key, collection);', - ' });', - ' }', - ' 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(['createAggregator', '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` and `_.where` - 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 {*} 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 `_.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 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 `_.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 `_.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 `_.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': templatePattern, - 'templateSettings': 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, ''); - }); - } - }); - - // unexpose methods - source = source.replace(getMethodAssignments(source), function(match) { - return _.reduce(['assign', 'createCallback', 'eachRight', '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/, '$1templateSettings.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, ''); - }); - - // replace `root` with the appropriate global object for the specified `exports` option - if (isAMD || isNode) { - source = source.replace(/\bcontext(?=\.)/g, isAMD ? 'window' : 'global'); - } - source = removeRunInContext(source); - } - } - - /*----------------------------------------------------------------------*/ - - // 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*(?:root\._|_\.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, - 'isNpm': isNpm, - 'isStdOut': isStdOut, - 'isStrict': isStrict, - 'isUnderscore': isUnderscore, - 'minusFuncs': minusFuncs, - 'options': options, - 'outputPath': outputPath, - 'plusFuncs': plusFuncs, - 'propDepMap': propDepMap, - 'source': source, - 'varDepMap': varDepMap - }); - return; - } - } - - /*------------------------------------------------------------------------*/ - - // 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 = _.difference(getVars(snippet, isShallow), includeProps); - - 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 (!useMap.root) { - source = removeVar(source, 'freeGlobal'); - } - }()); - - 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'); - } - - /*------------------------------------------------------------------------*/ - - // 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) + - source.replace(/^[\s\S]+?\(function[^{]+{\n+|\s*}\.call\(this\)\)[;\s]*$/g, '\n') + - iife.slice(index + token.length) - ); - }()); - } - - /*------------------------------------------------------------------------*/ - - 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, ['amd', 'commonjs', 'global', 'node']) - ); - - // 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); - } -}()); diff --git a/build/minify.js b/build/minify.js deleted file mode 100755 index 245a6dfe9..000000000 --- a/build/minify.js +++ /dev/null @@ -1,793 +0,0 @@ -#!/usr/bin/env node -;(function() { - 'use strict'; - - /** Load Node.js modules */ - var cp = require('child_process'), - https = require('https'), - zlib = require('zlib'); - - /** Load other modules */ - var _ = require('../lodash.js'), - preprocess = require('./pre-compile.js'), - postprocess = require('./post-compile.js'), - tar = require('../vendor/tar/tar.js'), - util = require('./util.js'); - - /** Module shortcuts */ - var fs = util.fs, - path = util.path; - - /** The Git object ID of `closure-compiler.tar.gz` */ - var closureId = '9fd5d61c1b706e7505aeb5187941c2c5497e5fd8'; - - /** The Git object ID of `uglifyjs.tar.gz` */ - var uglifyId = '7de2795a3af58d1b293e3b0e83cdbc994f4941dc'; - - /** The path of the directory that is the base of the repository */ - var basePath = fs.realpathSync(path.join(__dirname, '..')); - - /** The path of the `vendor` directory */ - var vendorPath = path.join(basePath, 'vendor'); - - /** The path to the Closure Compiler `.jar` */ - var closurePath = path.join(vendorPath, 'closure-compiler', 'compiler.jar'); - - /** The path to the UglifyJS module */ - var uglifyPath = path.join(vendorPath, 'uglifyjs', 'tools', 'node.js'); - - /** The Closure Compiler command-line options */ - var closureOptions = ['--warning_level=QUIET']; - - /** The media type for raw blob data */ - var mediaType = 'application/vnd.github.v3.raw'; - - /** Used to detect the Node.js executable in command-line arguments */ - var reNode = RegExp('(?:^|' + path.sepEscaped + ')node(?:\\.exe)?$', 'i'); - - /** Used to reference parts of the blob href */ - var location = (function() { - var host = 'api.github.com', - origin = 'https://api.github.com', - pathname = '/repos/bestiejs/lodash/git/blobs'; - - return { - 'host': host, - 'href': origin + pathname, - 'origin': origin, - 'pathname': pathname - }; - }()); - - /** The Closure Compiler optimization modes */ - var optimizationModes = { - 'simple': 'SIMPLE_OPTIMIZATIONS', - 'advanced': 'ADVANCED_OPTIMIZATIONS' - }; - - /*--------------------------------------------------------------------------*/ - - /** - * Minifies a given Lo-Dash `source` and invokes the `options.onComplete` - * callback when finished. The `onComplete` callback is invoked with one - * argument; (outputSource). - * - * @param {string|string[]} [source=''] The source to minify or array of commands. - * -o, --output - Write output to a given path/filename. - * -s, --silent - Skip status updates normally logged to the console. - * -t, --template - Applies template specific minifier options. - * - * @param {Object} [options={}] The options object. - * @param {string} [options.outputPath] Write output to a given path/filename. - * @param {boolean} [options.isSilent] Skip status updates normally logged to the console. - * @param {boolean} [options.isTemplate] Applies template specific minifier options. - * @param {Function} [options.onComplete] The function called once minification has finished. - */ - function minify(source, options) { - // used to specify the source map URL - var sourceMapURL; - - // used to specify the default minifer modes - var modes = ['simple', 'advanced', 'hybrid']; - - source || (source = ''); - options || (options = {}); - - // juggle arguments - if (Array.isArray(source)) { - // convert commands to an options object - options = source; - - // used to report 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]) || - /^modes=.*$/.test(value)) { - return true; - } - var result = [ - '-o', '--output', - '-p', '--source-map', - '-s', '--silent', - '-t', '--template' - ].indexOf(value) > -1; - - if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) { - result = true; - sourceMapURL = value; - } - return result; - }); - - // report invalid arguments - if (invalidArgs.length) { - console.log( - '\n' + - 'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') + - ' passed: ' + invalidArgs.join(', ') - ); - return; - } - var filePath = options[options.length - 1], - isMapped = _.contains(options, '-p') || _.contains(options, '--source-map'), - isSilent = _.contains(options, '-s') || _.contains(options, '--silent'), - isTemplate = _.contains(options, '-t') || _.contains(options, '--template'), - outputPath = path.join(path.dirname(filePath), path.basename(filePath, '.js') + '.min.js'); - - modes = options.reduce(function(result, value) { - var match = value.match(/modes=(.*)$/); - return match ? match[1].split(/, */) : result; - }, modes); - - 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; - }, outputPath); - - options = { - 'filePath': filePath, - 'isMapped': isMapped, - 'isSilent': isSilent, - 'isTemplate': isTemplate, - 'modes': modes, - 'outputPath': outputPath, - 'sourceMapURL': sourceMapURL - }; - - source = fs.readFileSync(filePath, 'utf8'); - } - - modes = options.modes || modes; - if (options.isMapped) { - modes = modes.filter(function(mode) { - return mode != 'hybrid'; - }); - } - if (options.isTemplate) { - modes = modes.filter(function(mode) { - return mode != 'advanced'; - }); - } - options.modes = modes; - - // fetch the Closure Compiler - getDependency({ - 'id': 'closure-compiler', - 'hashId': closureId, - 'path': vendorPath, - 'title': 'the Closure Compiler', - 'onComplete': function(exception) { - var error = exception; - - // fetch UglifyJS - getDependency({ - 'id': 'uglifyjs', - 'hashId': uglifyId, - 'title': 'UglifyJS', - 'path': vendorPath, - 'onComplete': function(exception) { - error || (error = exception); - if (!error) { - new Minify(source, options); - } - } - }); - } - }); - } - - /** - * The Minify constructor used to keep state of each `minify` invocation. - * - * @private - * @constructor - * @param {string} source The source to minify. - * @param {Object} options The options object. - * outputPath - Write output to a given path/filename. - * isSilent - Skip status updates normally logged to the console. - * isTemplate - Applies template specific minifier options. - * onComplete - The function called once minification has finished. - */ - function Minify(source, options) { - // juggle arguments - if (typeof source == 'object' && source) { - options = source || options; - source = options.source || ''; - } - this.compiled = { 'simple': {}, 'advanced': {} }; - this.hybrid = { 'simple': {}, 'advanced': {} }; - this.uglified = {}; - - this.filePath = options.filePath; - this.isMapped = !!options.isMapped; - this.isSilent = !!options.isSilent; - this.isTemplate = !!options.isTemplate; - this.outputPath = options.outputPath; - this.sourceMapURL = options.sourceMapURL; - - var modes = this.modes = options.modes; - source = this.source = preprocess(source, options); - - this.onComplete = options.onComplete || function(data) { - var outputPath = this.outputPath, - sourceMap = data.sourceMap; - - fs.writeFileSync(outputPath, data.source, 'utf8'); - if (sourceMap) { - fs.writeFileSync(getMapPath(outputPath), sourceMap, 'utf8'); - } - }; - - // begin the minification process - if (_.contains(modes, 'simple')) { - closureCompile.call(this, source, 'simple', onClosureSimpleCompile.bind(this)); - } else if (_.contains(modes, 'advanced')) { - onClosureSimpleGzip.call(this); - } else { - onClosureAdvancedGzip.call(this); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * Fetches a required `.tar.gz` dependency with the given Git object ID from - * the Lo-Dash repo on GitHub. The object ID may be obtained by running - * `git hash-object path/to/dependency.tar.gz`. - * - * @private - * @param {Object} options The options object. - * id - The Git object ID of the `.tar.gz` file. - * onComplete - The function called once the extraction has finished. - * path - The path of the extraction directory. - * title - The dependency's title used in status updates logged to the console. - */ - function getDependency(options) { - options || (options = {}); - - var ran, - destPath = options.path, - hashId = options.hashId, - id = options.id, - onComplete = options.onComplete, - title = options.title; - - // exit early if dependency exists - if (fs.existsSync(path.join(destPath, id))) { - onComplete(); - return; - } - var callback = function(exception) { - if (ran) { - return; - } - if (exception) { - console.error([ - 'There was a problem installing ' + title + '.', - 'Try running the command as root, via `sudo`, or manually install by running:', - '', - "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + hashId + " | tar xvz -C '" + destPath + "'", - '' - ].join('\n')); - } - ran = true; - process.removeListener('uncaughtException', callback); - onComplete(exception); - }; - - console.log('Downloading ' + title + '...'); - process.on('uncaughtException', callback); - - https.get({ - 'host': location.host, - 'path': location.pathname + '/' + hashId, - 'headers': { - // By default, all GitHub blob API endpoints return a JSON document - // containing Base64-encoded blob data. Overriding the `Accept` header - // with the GitHub raw media type returns the blob data directly. - // See http://developer.github.com/v3/media/. - 'Accept': mediaType, - // As of 2013-04-24, the GitHub API mandates the `User-Agent` header - // for all requests. - 'User-Agent': 'Lo-Dash/' + _.VERSION - } - }, function(response) { - var decompressor = zlib.createUnzip(), - parser = new tar.Extract({ 'path': destPath }); - - parser.on('end', callback); - response.pipe(decompressor).pipe(parser); - }); - } - - /** - * Retrieves the Java command-line options used for faster minification by - * the Closure Compiler, invoking the `callback` when finished. Subsequent - * calls will lazily return the previously retrieved options. The `callback` - * is invoked with one argument; (options). - * - * See https://code.google.com/p/closure-compiler/wiki/FAQ#What_are_the_recommended_Java_VM_command-line_options?. - * - * @private - * @param {Function} callback The function called once the options have been retrieved. - */ - function getJavaOptions(callback) { - var result = []; - cp.exec('java -version -client -d32', function(error) { - if (!error && process.platform != 'win32') { - result.push('-client', '-d32'); - } - getJavaOptions = function(callback) { - _.defer(callback, result); - }; - callback(result); - }); - } - - /** - * Resolves the source map path from the given output path. - * - * @private - * @param {string} outputPath The output path. - * @returns {string} Returns the source map path. - */ - function getMapPath(outputPath) { - return path.join(path.dirname(outputPath), path.basename(outputPath, '.js') + '.map'); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Compresses a `source` string using the Closure Compiler. Yields the - * minified result, and any exceptions encountered, to a `callback` function. - * - * @private - * @param {string} source The JavaScript source to minify. - * @param {string} mode The optimization mode. - * @param {Function} callback The function called once the process has completed. - */ - function closureCompile(source, mode, callback) { - var filePath = this.filePath, - isAdvanced = mode == 'advanced', - isMapped = this.isMapped, - isSilent = this.isSilent, - isTemplate = this.isTemplate, - options = closureOptions.slice(), - outputPath = this.outputPath, - mapPath = getMapPath(outputPath), - sourceMapURL = this.sourceMapURL || path.basename(mapPath); - - // remove copyright header to make other modifications easier - var license = (/^(?:\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*/.exec(source) || [''])[0]; - if (license) { - source = source.replace(license, ''); - } - - var hasIIFE = /^;?\(function[^{]+{/.test(source), - isStrict = hasIIFE && /^;?\(function[^{]+{\s*["']use strict["']/.test(source); - - // to avoid stripping the IIFE, convert it to a function call - if (hasIIFE && isAdvanced) { - source = source - .replace(/\(function/, '__iife__$&') - .replace(/\(this\)\)([\s;]*(\n\/\/.+)?)$/, ', this)$1'); - } - - options.push('--compilation_level=' + optimizationModes[mode]); - if (isMapped) { - options.push('--create_source_map=' + mapPath, '--source_map_format=V3'); - } - if (isTemplate) { - options.push('--charset=UTF-8'); - } - - getJavaOptions(function(javaOptions) { - var compiler = cp.spawn('java', javaOptions.concat('-jar', closurePath, options)); - if (!isSilent) { - console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...'); - } - - var error = ''; - compiler.stderr.on('data', function(data) { - error += data; - }); - - var output = ''; - compiler.stdout.on('data', function(data) { - output += data; - }); - - compiler.on('exit', function(status) { - // `status` contains the process exit code - if (status) { - var exception = new Error(error); - exception.status = status; - } - // restore IIFE and move exposed vars inside the IIFE - if (hasIIFE && isAdvanced) { - output = output - .replace(/__iife__\(/, '(') - .replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1') - .replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1'); - } - // inject "use strict" directive - if (isStrict) { - output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";'); - } - // restore copyright header - if (license) { - output = license + output; - } - if (isMapped) { - var mapOutput = fs.readFileSync(mapPath, 'utf8'); - fs.unlinkSync(mapPath); - output = output.replace(/[\s;]*$/, '\n//# sourceMappingURL=' + sourceMapURL); - - mapOutput = JSON.parse(mapOutput); - mapOutput.file = path.basename(outputPath); - mapOutput.sources = [path.basename(filePath)]; - mapOutput = JSON.stringify(mapOutput, null, 2); - } - callback(exception, output, mapOutput); - }); - - // proxy the standard input to the Closure Compiler - compiler.stdin.end(source); - }); - } - - /** - * Compresses a `source` string using UglifyJS. Yields the result to a - * `callback` function. This function is synchronous; the `callback` is used - * for symmetry. - * - * @private - * @param {string} source The JavaScript source to minify. - * @param {string} label The label to log. - * @param {Function} callback The function called once the process has completed. - */ - function uglify(source, label, callback) { - if (!this.isSilent) { - console.log('Compressing ' + path.basename(this.outputPath, '.js') + ' using ' + label + '...'); - } - try { - var uglifyJS = require(uglifyPath); - - // 1. parse - var toplevel = uglifyJS.parse(source); - - // 2. compress - // enable unsafe comparisons - toplevel.figure_out_scope(); - toplevel = toplevel.transform(uglifyJS.Compressor({ - 'comparisons': false, - 'unsafe': true, - 'unsafe_comps': true, - 'warnings': false - })); - - // 3. mangle - // excluding the `define` function exposed by AMD loaders - toplevel.figure_out_scope(); - toplevel.compute_char_frequency(); - toplevel.mangle_names({ - 'except': ['define'] - }); - - // 4. output - // restrict lines to 500 characters for consistency with the Closure Compiler - var stream = uglifyJS.OutputStream({ - 'ascii_only': !this.isTemplate, - 'comments': /^!|@cc_on|@license|@preserve/i, - 'max_line_len': 500, - }); - - toplevel.print(stream); - } - catch(e) { - var exception = e; - } - callback(exception, stream && String(stream)); - } - - /*--------------------------------------------------------------------------*/ - - /** - * The Closure Compiler callback for simple optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {string} result The resulting minified source. - * @param {string} map The source map output. - */ - function onClosureSimpleCompile(exception, result, map) { - if (exception) { - throw exception; - } - result = postprocess(result); - - var simple = this.compiled.simple; - simple.source = result; - simple.sourceMap = map; - zlib.gzip(result, onClosureSimpleGzip.bind(this)); - } - - /** - * The Closure Compiler `gzip` callback for simple optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {Buffer} result The resulting gzipped source. - */ - function onClosureSimpleGzip(exception, result) { - if (exception) { - throw exception; - } - if (result != null) { - if (!this.isSilent) { - console.log('Done. Size: %d bytes.', result.length); - } - this.compiled.simple.gzip = result; - } - // compile the source using advanced optimizations - if (_.contains(this.modes, 'advanced')) { - closureCompile.call(this, this.source, 'advanced', onClosureAdvancedCompile.bind(this)); - } else { - onClosureAdvancedGzip.call(this); - } - } - - /** - * The Closure Compiler callback for advanced optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {string} result The resulting minified source. - * @param {string} map The source map output. - */ - function onClosureAdvancedCompile(exception, result, map) { - if (exception) { - throw exception; - } - result = postprocess(result); - - var advanced = this.compiled.advanced; - advanced.source = result; - advanced.sourceMap = map; - zlib.gzip(result, onClosureAdvancedGzip.bind(this)); - } - - /** - * The Closure Compiler `gzip` callback for advanced optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {Buffer} result The resulting gzipped source. - */ - function onClosureAdvancedGzip(exception, result) { - if (exception) { - throw exception; - } - if (result != null) { - if (!this.isSilent) { - console.log('Done. Size: %d bytes.', result.length); - } - this.compiled.advanced.gzip = result; - } - // minify the source using UglifyJS - if (!this.isMapped) { - uglify.call(this, this.source, 'UglifyJS', onUglify.bind(this)); - } else { - onComplete.call(this); - } - } - - /** - * The UglifyJS callback. - * - * @private - * @param {Object} [exception] The error object. - * @param {string} result The resulting minified source. - */ - function onUglify(exception, result) { - if (exception) { - throw exception; - } - result = postprocess(result); - this.uglified.source = result; - zlib.gzip(result, onUglifyGzip.bind(this)); - } - - /** - * The UglifyJS `gzip` callback. - * - * @private - * @param {Object} [exception] The error object. - * @param {Buffer} result The resulting gzipped source. - */ - function onUglifyGzip(exception, result) { - if (exception) { - throw exception; - } - if (result != null) { - if (!this.isSilent) { - console.log('Done. Size: %d bytes.', result.length); - } - this.uglified.gzip = result; - } - // minify the already Closure Compiler simple optimized source using UglifyJS - var modes = this.modes; - if (_.contains(modes, 'hybrid')) { - if (_.contains(modes, 'simple')) { - uglify.call(this, this.compiled.simple.source, 'hybrid (simple)', onSimpleHybrid.bind(this)); - } else if (_.contains(modes, 'advanced')) { - onSimpleHybridGzip.call(this); - } - } else { - onComplete.call(this); - } - } - - /** - * The hybrid callback for simple optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {string} result The resulting minified source. - */ - function onSimpleHybrid(exception, result) { - if (exception) { - throw exception; - } - result = postprocess(result); - this.hybrid.simple.source = result; - zlib.gzip(result, onSimpleHybridGzip.bind(this)); - } - - /** - * The hybrid `gzip` callback for simple optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {Buffer} result The resulting gzipped source. - */ - function onSimpleHybridGzip(exception, result) { - if (exception) { - throw exception; - } - if (result != null) { - if (!this.isSilent) { - console.log('Done. Size: %d bytes.', result.length); - } - this.hybrid.simple.gzip = result; - } - // minify the already Closure Compiler advance optimized source using UglifyJS - if (_.contains(this.modes, 'advanced')) { - uglify.call(this, this.compiled.advanced.source, 'hybrid (advanced)', onAdvancedHybrid.bind(this)); - } else { - onComplete.call(this); - } - } - - /** - * The hybrid callback for advanced optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {string} result The resulting minified source. - */ - function onAdvancedHybrid(exception, result) { - if (exception) { - throw exception; - } - result = postprocess(result); - this.hybrid.advanced.source = result; - zlib.gzip(result, onAdvancedHybridGzip.bind(this)); - } - - /** - * The hybrid `gzip` callback for advanced optimizations. - * - * @private - * @param {Object} [exception] The error object. - * @param {Buffer} result The resulting gzipped source. - */ - function onAdvancedHybridGzip(exception, result) { - if (exception) { - throw exception; - } - if (result != null) { - if (!this.isSilent) { - console.log('Done. Size: %d bytes.', result.length); - } - this.hybrid.advanced.gzip = result; - } - // finish by choosing the smallest compressed file - onComplete.call(this); - } - - /** - * The callback executed after the source is minified and gzipped. - * - * @private - */ - function onComplete() { - var compiledSimple = this.compiled.simple, - compiledAdvanced = this.compiled.advanced, - uglified = this.uglified, - hybridSimple = this.hybrid.simple, - hybridAdvanced = this.hybrid.advanced; - - var objects = [ - compiledSimple, - compiledAdvanced, - uglified, - hybridSimple, - hybridAdvanced - ]; - - var gzips = objects - .map(function(data) { return data.gzip; }) - .filter(Boolean); - - // select the smallest gzipped file and use its minified counterpart as the - // official minified release (ties go to the Closure Compiler) - var min = gzips.reduce(function(min, gzip) { - var length = gzip.length; - return min > length ? length : min; - }, Infinity); - - // pass the minified source to the "onComplete" callback - objects.some(function(data) { - var gzip = data.gzip; - if (gzip && gzip.length == min) { - data.outputPath = this.outputPath; - this.onComplete(data); - return true; - } - }, this); - } - - /*--------------------------------------------------------------------------*/ - - // expose `minify` - if (module != require.main) { - module.exports = minify; - } - else { - // read the Lo-Dash source file from the first argument if the script - // was invoked directly (e.g. `node minify.js source.js`) and write to - // `.min.js` - (function() { - var options = process.argv; - if (options.length < 3) { - return; - } - minify(options); - }()); - } -}()); diff --git a/build/post-compile.js b/build/post-compile.js deleted file mode 100644 index b33fca174..000000000 --- a/build/post-compile.js +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env node -;(function() { - 'use strict'; - - /** Load Node.js modules */ - var fs = require('fs'), - vm = require('vm'); - - /** The minimal license/copyright template */ - var licenseTemplate = [ - '/**', - ' * @license', - ' * Lo-Dash <%= VERSION %> lodash.com/license | Underscore.js 1.5.1 underscorejs.org/LICENSE', - ' */' - ].join('\n'); - - /*--------------------------------------------------------------------------*/ - - /** - * Post-process a given minified Lo-Dash `source`, preparing it for - * deployment. - * - * @param {string} source The source to process. - * @returns {string} Returns the processed source. - */ - function postprocess(source) { - // correct overly aggressive Closure Compiler advanced optimization - source = source - .replace(/(document[^&]+&&)\s*(?:\w+|!\d)/, '$1!({toString:0}+"")') - .replace(/"\t"/g, '"\\t"') - .replace(/"[^"]*?\\f[^"]*?"/g, - '" \\t\\x0B\\f\\xa0\\ufeff' + - '\\n\\r\\u2028\\u2029' + - '\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000"' - ); - - try { - var context = vm.createContext({}); - vm.runInContext(source, context); - } catch(e) { } - - ['forEach', 'forIn', 'forOwn'].forEach(function(methodName) { - var pairs = /[!=]==\s*([a-zA-Z]+)(?!\()|([a-zA-Z]+)\s*[!=]==/.exec((context._ || {})[methodName]), - varName = pairs && (pairs[1] || pairs[2]), - value = (value = varName && RegExp('\\b' + varName + '\\s*=\\s*!([01])\\b').exec(source)) && !+value[1]; - - if (typeof value == 'boolean') { - // replace vars for `false` and `true` with boolean literals - source = source.replace(RegExp('([!=]==\\s*)' + varName + '\\b(?!\\()|\\b' + varName + '(\\s*[!=]==)', 'g'), function(match, prelude, postlude, at) { - // avoid replacing local variables with the same name - return RegExp('\\b' + varName + '\\s*(?:,|=[^=])').test(source.slice(at - 10, at)) - ? match - : (prelude || '') + value + (postlude || ''); - }); - } - }); - - // replace `!1` and `!0` in expressions with `false` and `true` values - [/([!=]==)\s*!1\b|(.)!1\s*([!=]==)/g, /([!=]==)\s*!0\b|(.)!0\s*([!=]==)/g].forEach(function(regexp, index) { - source = source.replace(regexp, function(match, prelude, chr, postlude) { - return (prelude || chr + (/\w/.test(chr) ? ' ' : '')) + !!index + (postlude || ''); - }); - }); - - // flip `typeof` expressions to help optimize Safari and - // correct the AMD module definition for AMD build optimizers - // (e.g. from `"number" == typeof x` to `typeof x == "number") - source = source.replace(/(\w)?("[^"]+")\s*([!=]=)\s*(typeof(?:\s*\([^)]+\)|\s+[.\w]+(?!\[)))/g, function(match, other, type, equality, expression) { - return (other ? other + ' ' : '') + expression + equality + type; - }); - - // add a space so `define` is detected by the Dojo builder - source = source.replace(/(.)(define\()/, function(match, prelude, define) { - return prelude + (/^\S/.test(prelude) ? ' ' : '') + define; - }); - - // add trailing semicolon - if (source) { - source = source.replace(/[\s;]*?(\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*$/, ';$1'); - } - // exit early if version snippet isn't found - var snippet = /VERSION\s*[=:]\s*([\'"])(.*?)\1/.exec(source); - if (!snippet) { - return source; - } - // remove copyright header - source = source.replace(/^\/\**[\s\S]+?\*\/\n/, ''); - - // add new copyright header - var version = snippet[2]; - source = licenseTemplate.replace('<%= VERSION %>', version) + '\n;' + source; - - return source; - } - - /*--------------------------------------------------------------------------*/ - - // expose `postprocess` - if (module != require.main) { - module.exports = postprocess; - } - else { - // read the Lo-Dash source file from the first argument if the script - // was invoked directly (e.g. `node post-compile.js source.js`) and write to - // the same file - (function() { - var options = process.argv; - if (options.length < 3) { - return; - } - var filePath = options[options.length - 1], - source = fs.readFileSync(filePath, 'utf8'); - - fs.writeFileSync(filePath, postprocess(source), 'utf8'); - }()); - } -}()); diff --git a/build/pre-compile.js b/build/pre-compile.js deleted file mode 100644 index 3f5730213..000000000 --- a/build/pre-compile.js +++ /dev/null @@ -1,461 +0,0 @@ -#!/usr/bin/env node -;(function() { - 'use strict'; - - /** The Node.js filesystem module */ - var fs = require('fs'); - - /** Used to minify variables embedded in compiled strings */ - var compiledVars = [ - 'args', - 'argsIndex', - 'argsLength', - 'baseCreateCallback', - 'callback', - 'className', - 'collection', - 'conditions', - 'ctor', - 'errorClass', - 'errorProto', - 'guard', - 'hasOwnProperty', - 'index', - 'indicatorObject', - 'isArguments', - 'isArray', - 'isProto', - 'isString', - 'iterable', - 'length', - 'keys', - 'lodash', - 'nonEnum', - 'nonEnumProps', - 'object', - 'objectProto', - 'objectTypes', - 'ownIndex', - 'ownProps', - 'result', - 'skipErrorProps', - 'skipProto', - 'source', - 'stringClass', - 'stringProto', - 'thisArg', - 'toString' - ]; - - /** Used to minify `iteratorTemplate` data properties */ - var iteratorOptions = [ - 'args', - 'array', - 'bottom', - 'firstArg', - 'init', - 'keys', - 'loop', - 'shadowedProps', - 'top', - 'useHas' - ]; - - /** Used to minify variables and string values to a single character */ - var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); - minNames.push.apply(minNames, minNames.map(function(value) { - return value + value; - })); - - /** Used to protect the specified properties from getting minified */ - var propWhitelist = [ - 'Array', - 'Boolean', - 'Date', - 'Error', - 'Function', - 'Math', - 'Number', - 'Object', - 'RegExp', - 'String', - 'TypeError', - 'VERSION', - '_', - '__bindData__', - '__chain__', - '__wrapped__', - 'after', - 'all', - 'amd', - 'any', - 'argsClass', - 'argsObject', - 'array', - 'assign', - 'at', - 'attachEvent', - 'bind', - 'bindAll', - 'bindKey', - 'cache', - 'chain', - 'clearTimeout', - 'clone', - 'cloneDeep', - 'collect', - 'compact', - 'compose', - 'configurable', - 'contains', - 'countBy', - 'createCallback', - 'criteria', - 'curry', - 'debounce', - 'defaults', - 'defer', - 'delay', - 'detect', - 'difference', - 'drop', - 'each', - 'enumerable', - 'enumErrorProps', - 'enumPrototypes', - 'environment', - 'escape', - 'evaluate', - 'every', - 'exports', - 'extend', - 'fastBind', - 'fastKeys', - 'filter', - 'find', - 'findIndex', - 'findKey', - 'findLast', - 'findLastIndex', - 'findLastKey', - 'findWhere', - 'first', - 'flatten', - 'foldl', - 'foldr', - 'forEach', - 'forEachRight', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight', - 'function', - 'functions', - 'global', - 'groupBy', - 'has', - 'head', - 'identity', - 'imports', - 'include', - 'index', - 'indexBy', - 'indexOf', - 'initial', - 'inject', - 'interpolate', - 'intersection', - 'invert', - 'invoke', - 'isArguments', - 'isArray', - 'isBoolean', - 'isDate', - 'isElement', - 'isEmpty', - 'isEqual', - 'isEqual', - 'isFinite', - 'isFinite', - 'isFunction', - 'isNaN', - 'isNull', - 'isNumber', - 'isObject', - 'isPlainObject', - 'isRegExp', - 'isString', - 'isUndefined', - 'keys', - 'last', - 'lastIndexOf', - 'leading', - 'map', - 'max', - 'maxWait', - 'memoize', - 'merge', - 'methods', - 'min', - 'mixin', - 'name', - 'noConflict', - 'nodeClass', - 'nonEnumArgs', - 'nonEnumShadows', - 'now', - 'null', - 'number', - 'object', - 'omit', - 'once', - 'ownLast', - 'pairs', - 'parseInt', - 'partial', - 'partialRight', - 'pick', - 'pluck', - 'pull', - 'random', - 'range', - 'reduce', - 'reduceRight', - 'reject', - 'remove', - 'rest', - 'result', - 'runInContext', - 'sample', - 'select', - 'setImmediate', - 'setTimeout', - 'shuffle', - 'size', - 'some', - 'sortBy', - 'sortedIndex', - 'source', - 'spliceObjects', - 'string', - 'support', - 'tail', - 'take', - 'tap', - 'template', - 'templateSettings', - 'throttle', - 'times', - 'toArray', - 'trailing', - 'transform', - 'undefined', - 'unescape', - 'unindexedChars', - 'union', - 'uniq', - 'unique', - 'uniqueId', - 'unzip', - 'value', - 'values', - 'variable', - 'where', - 'window', - 'without', - 'wrap', - 'writable', - 'zip', - 'zipObject' - ]; - - /*--------------------------------------------------------------------------*/ - - /** - * Pre-process a given Lo-Dash `source`, preparing it for minification. - * - * @param {string} [source=''] The source to process. - * @param {Object} [options={}] The options object. - * @returns {string} Returns the processed source. - */ - function preprocess(source, options) { - source || (source = ''); - options || (options = {}); - - // remove unrecognized JSDoc tags so the Closure Compiler won't complain - source = source.replace(/@(?:alias|category)\b.*/g, ''); - - if (options.isTemplate) { - return source; - } - - // remove whitespace from string literals - source = source.replace(/^((?:[ "'\w]+:)? *)"[^"\n\\]*?(?:\\.[^"\n\\]*?)*"|'[^'\n\\]*?(?:\\.[^'\n\\]*?)*'/gm, function(string, left) { - // clip after an object literal property name or leading spaces - if (left) { - string = string.slice(left.length); - } - // avoids removing the '\n' of the `stringEscapes` object - string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) { - return match == false || match == '\\n' ? '' : match; - }); - // unclip - return (left || '') + string; - }); - - // remove whitespace from `_.template` related regexes - source = source.replace(/reEmptyString\w+ *=.+/g, function(match) { - return match.replace(/ |\\n/g, ''); - }); - - // remove newline from double-quoted strings in `_.template` - source = source - .replace('"__p += \'"', '"__p+=\'"') - .replace('"\';\n"', '"\';"') - - // remove debug sourceURL use in `_.template` - source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, ''); - - // minify internal properties - (function() { - var funcNames = [ - 'cacheIndexOf', - 'cachePush', - 'compareAscending', - 'createCache', - 'getObject', - 'releaseObject', - 'sortBy' - ]; - - var props = [ - 'cache', - 'criteria', - 'index', - 'value' - ]; - - // minify other properties used in functions - var snippets = source.match(RegExp('^( *)(?:var|function) +(?:' + funcNames.join('|') + ')\\b[\\s\\S]+?\\n\\1}', 'gm')); - if (!snippets) { - return; - } - snippets.forEach(function(snippet) { - var modified = snippet; - props.forEach(function(prop, index) { - // use minified names different than those chosen for `iteratorOptions` - var minName = minNames[iteratorOptions.length + index], - reBracketProp = RegExp("\\['(" + prop + ")'\\]", 'g'), - reDotProp = RegExp('\\.' + prop + '\\b', 'g'), - rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + prop + "\\2 *:", 'g'); - - modified = modified - .replace(reBracketProp, "['" + minName + "']") - .replace(reDotProp, "['" + minName + "']") - .replace(rePropColon, "$1'" + minName + "':"); - }); - - // replace with modified snippet - source = source.replace(snippet, function() { - return modified; - }); - }); - }()); - - // minify all compilable snippets - var snippets = source.match( - RegExp([ - // match the `iteratorTemplate` - '^( *)var iteratorTemplate\\b[\\s\\S]+?\\n\\1}', - // match methods created by `createIterator` calls - 'createIterator\\((?:{|[a-zA-Z]+)[\\s\\S]*?\\);\\n', - // match variables storing `createIterator` options - '^( *)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\2}', - // match `baseUniq`, `cachePush`, `createCache`, `createIterator`, `getObject`, and `releaseObject` functions - '^( *)(?:var|function) +(?:baseUniq|cachePush|createCache|createIterator|getObject|releaseObject)\\b[\\s\\S]+?\\n\\3}' - ].join('|'), 'gm') - ) || []; - - snippets.forEach(function(snippet, index) { - var isFunc = /\bfunction *[ \w]*\(/.test(snippet), - isIteratorTemplate = /var iteratorTemplate\b/.test(snippet), - modified = snippet; - - // remove unnecessary semicolons in strings - modified = modified.replace(/;(?:}["']|(?:\\n|\s)*["']\s*\+\s*["'](?:\\n|\s)*})/g, function(match) { - return match.slice(1); - }); - - // minify snippet variables / arguments - compiledVars.forEach(function(varName, index) { - var minName = minNames[index]; - - modified = modified.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, function(match) { - return match.replace(RegExp('([^.])\\b' + varName + '\\b', 'g'), '$1' + minName); - }); - - // correct `typeof` string values - if (/^(?:boolean|function|object|number|string|undefined)$/.test(varName)) { - modified = modified.replace(RegExp('(= *)(["\'])' + minName + '\\2|(["\'])' + minName + '\\3( *=)', 'g'), function(match, prelude, preQuote, postQuote, postlude) { - return prelude - ? prelude + preQuote + varName + preQuote - : postQuote + varName + postQuote + postlude; - }); - } - }); - - // minify `createIterator` option property names - iteratorOptions.forEach(function(property, index) { - var minName = minNames[index]; - - // minify iterator option variables - modified = modified.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, function(match, quote) { - return match.replace(RegExp('([^.])\\b' + property + '\\b', 'g'), '$1' + minName) - }); - - // minify iterator option properties, adding brackets so the Closure Compiler won't mung them - modified = modified.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.' + property + '\\b', 'g'), function(match, quote) { - return quote ? match : "['" + minName + "']"; - }); - }); - - // replace with modified snippet - source = source.replace(snippet, function() { - return modified; - }); - }); - - // add brackets to whitelisted properties so the Closure Compiler won't mung them - // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export - source = source.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.(' + propWhitelist.join('|') + ')\\b', 'g'), function(match, quote, prop) { - return quote ? match : "['" + prop + "']"; - }); - - return source; - } - - /*--------------------------------------------------------------------------*/ - - // expose `preprocess` - if (module != require.main) { - module.exports = preprocess; - } - else { - // read the Lo-Dash source file from the first argument if the script - // was invoked directly (e.g. `node pre-compile.js source.js`) and write to - // the same file - (function() { - var options = process.argv; - if (options.length < 3) { - return; - } - var filePath = options[options.length - 1], - isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1, - source = fs.readFileSync(filePath, 'utf8'); - - fs.writeFileSync(filePath, preprocess(source, { - 'isTemplate': isTemplate - }), 'utf8'); - }()); - } -}()); diff --git a/build/util.js b/build/util.js deleted file mode 100755 index ff58cb57a..000000000 --- a/build/util.js +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env node -;(function() { - 'use strict'; - - /** Load Node.js modules */ - var fs = require('fs'), - path = require('path'); - - /** Load other modules */ - var _ = require('../lodash.js'); - - /** Used to indicate if running in Windows */ - var isWindows = process.platform == 'win32'; - - /*--------------------------------------------------------------------------*/ - - /** - * The path separator. - * - * @memberOf util.path - * @type string - */ - var sep = path.sep || (isWindows ? '\\' : '/'); - - /** - * The escaped path separator used for inclusion in RegExp strings. - * - * @memberOf util.path - * @type string - */ - var sepEscaped = sep.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - - /** Used to determine if a path is prefixed with a drive letter, dot, or slash */ - var rePrefixed = RegExp('^(?:' + (isWindows ? '[a-zA-Z]:|' : '') + '\\.?)' + sepEscaped); - - /*--------------------------------------------------------------------------*/ - - /** - * Makes the given `dirname` directory, without throwing errors for existing - * directories and making parent directories as needed. - * - * @memberOf util.fs - * @param {string} dirname The path of the directory. - * @param {number|string} [mode='0777'] The permission mode. - */ - function mkdirpSync(dirname, mode) { - // ensure relative paths are prefixed with `./` - if (!rePrefixed.test(dirname)) { - dirname = '.' + sep + dirname; - } - dirname.split(sep).reduce(function(currPath, segment) { - currPath += sep + segment; - try { - currPath = fs.realpathSync(currPath); - } catch(e) { - fs.mkdirSync(currPath, mode); - } - return currPath; - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * The utility object. - * - * @type Object - */ - var util = { - - /** - * The file system object. - * - * @memberOf util - * @type Object - */ - 'fs': _.defaults(_.cloneDeep(fs), { - 'existsSync': fs.existsSync || path.existsSync, - 'mkdirpSync': mkdirpSync - }), - - /** - * The path object. - * - * @memberOf util - * @type Object - */ - 'path': _.defaults(_.cloneDeep(path), { - 'sep': sep, - 'sepEscaped': sepEscaped - }) - }; - - /*--------------------------------------------------------------------------*/ - - // expose - module.exports = util; -}()); diff --git a/component.json b/component.json index 96c9425e1..9c4cf61fa 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "lodash", "repo": "bestiejs/lodash", "version": "1.3.1", - "description": "A low-level utility library delivering consistency, customization, performance, and extra features.", + "description": "A utility library delivering consistency, customization, performance, and extras.", "license": "MIT", "scripts": [ "index.js", diff --git a/package.json b/package.json index 05fcd3573..464f58ed7 100644 --- a/package.json +++ b/package.json @@ -43,18 +43,21 @@ "type": "git", "url": "https://github.com/bestiejs/lodash.git" }, - "bin": { - "lodash": "./build.js" - }, "engines": [ "node", "rhino" ], "files": [ - "build.js", - "LICENSE.txt", "dist/lodash.js", "dist/lodash.min.js", + "dist/lodash.backbone.js", + "dist/lodash.backbone.min.js", + "dist/lodash.compat.js", + "dist/lodash.compat.min.js", + "dist/lodash.legacy.js", + "dist/lodash.legacy.min.js", + "dist/lodash.mobile.js", + "dist/lodash.mobile.min.js", "dist/lodash.underscore.js", "dist/lodash.underscore.min.js" ], @@ -75,12 +78,10 @@ "*.map", "*.md", "*.txt", - "build.js", "lodash.js", "index.js", "bower.json", "component.json", - "build", "doc", "modularize", "node_modules", diff --git a/test/run-test.sh b/test/run-test.sh index 4f81a6514..70a41bc87 100644 --- a/test/run-test.sh +++ b/test/run-test.sh @@ -9,10 +9,6 @@ done echo "Testing in node..." node test.js ../dist/lodash.js && node test.js ../dist/lodash.min.js -echo "" -echo "Testing build..." -node test-build.js - echo "" echo "Testing in a browser..." open index.html diff --git a/test/template/a.jst b/test/template/a.jst deleted file mode 100644 index cca541d8f..000000000 --- a/test/template/a.jst +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/test/template/b.jst b/test/template/b.jst deleted file mode 100644 index cad081d19..000000000 --- a/test/template/b.jst +++ /dev/null @@ -1 +0,0 @@ -<% print("Hello " + epithet); %>. \ No newline at end of file diff --git a/test/template/c.jst b/test/template/c.jst deleted file mode 100644 index f92679903..000000000 --- a/test/template/c.jst +++ /dev/null @@ -1 +0,0 @@ -Hello ${ name }! \ No newline at end of file diff --git a/test/template/d.tpl b/test/template/d.tpl deleted file mode 100644 index fdb97d1a4..000000000 --- a/test/template/d.tpl +++ /dev/null @@ -1 +0,0 @@ -Hallå {{ name }}! \ No newline at end of file diff --git a/test/test-build.js b/test/test-build.js deleted file mode 100644 index ba81037a1..000000000 --- a/test/test-build.js +++ /dev/null @@ -1,1837 +0,0 @@ -#!/usr/bin/env node -;(function(undefined) { - 'use strict'; - - /** Load Node.js modules */ - var vm = require('vm'); - - /** Load other modules */ - var _ = require('../dist/lodash.js'), - build = require('../build.js'), - minify = require('../build/minify.js'), - util = require('../build/util.js'); - - /** Module shortcuts */ - var fs = util.fs, - path = util.path; - - /** Used to avoid `noglobal` false positives caused by `errno` leaked in Node.js */ - global.errno = true; - - /** The current working directory */ - var cwd = process.cwd(); - - /** Used to prefix relative paths from the current directory */ - var relativePrefix = '.' + path.sep; - - /** The unit testing framework */ - var QUnit = ( - global.addEventListener = Function.prototype, - global.QUnit = require('../vendor/qunit/qunit/qunit.js'), - require('../vendor/qunit-clib/qunit-clib.js').runInContext(global), - delete global.addEventListener, - global.QUnit - ); - - /** Shortcut used to push arrays of values to an array */ - var push = Array.prototype.push; - - /** The time limit for the tests to run (milliseconds) */ - var timeLimit = process.argv.reduce(function(result, value, index) { - if (/--time-limit/.test(value)) { - return parseInt(process.argv[index + 1].replace(/(\d+h)?(\d+m)?(\d+s)?/, function(match, h, m, s) { - return ((parseInt(h) || 0) * 3600000) + - ((parseInt(m) || 0) * 60000) + - ((parseInt(s) || 0) * 1000); - })) || result; - } - return result; - }, 0); - - /** Used to associate aliases with their real names */ - var aliasToRealMap = { - 'all': 'every', - 'any': 'some', - 'collect': 'map', - 'detect': 'find', - 'drop': 'rest', - 'each': 'forEach', - 'extend': 'assign', - 'foldl': 'reduce', - 'foldr': 'reduceRight', - 'head': 'first', - 'include': 'contains', - 'inject': 'reduce', - 'methods': 'functions', - 'object': 'zipObject', - 'select': 'filter', - 'tail': 'rest', - 'take': 'first', - 'unique': 'uniq', - 'unzip': 'zip' - }; - - /** Used to associate real names with their aliases */ - var realToAliasMap = { - 'assign': ['extend'], - 'contains': ['include'], - 'every': ['all'], - 'filter': ['select'], - 'find': ['detect'], - 'first': ['head', 'take'], - 'forEach': ['each'], - 'functions': ['methods'], - 'map': ['collect'], - 'reduce': ['foldl', 'inject'], - 'reduceRight': ['foldr'], - 'rest': ['drop', 'tail'], - 'some': ['any'], - 'uniq': ['unique'], - 'zip': ['unzip'], - 'zipObject': ['object'] - }; - - /** 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', - 'sample', - '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' - ]; - - /** 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', - 'sample', - 'transform' - ]; - - /** List of all functions */ - var allFuncs = _.functions(_).filter(function(funcName) { - return !/^_/.test(funcName); - }); - - /** List of all Lo-Dash functions */ - var lodashFuncs = allFuncs.slice(); - - /** List of Underscore functions */ - var underscoreFuncs = _.difference(allFuncs, lodashOnlyFuncs); - - /*--------------------------------------------------------------------------*/ - - /** - * 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); - } - - /** - * Creates a context object to use with `vm.runInContext`. - * - * @private - * @returns {Object} Returns a new context object. - */ - function createContext() { - return vm.createContext({ - 'clearTimeout': clearTimeout, - 'console': console, - 'setTimeout': setTimeout - }); - } - - /** - * Expands a list of function names to include real and alias names. - * - * @private - * @param {Array} funcNames The array of function names to expand. - * @returns {Array} Returns a new array of expanded function names. - */ - function expandFuncNames(funcNames) { - return funcNames.reduce(function(result, funcName) { - var realName = getRealName(funcName); - push.apply(result, [realName].concat(getAliases(realName))); - return result; - }, []); - } - - /** - * Gets the aliases associated with a given function name. - * - * @private - * @param {string} funcName The name of the function to get aliases for. - * @returns {Array} Returns an array of aliases. - */ - function getAliases(funcName) { - return realToAliasMap[funcName] || []; - } - - /** - * Gets the real name, not alias, of a given function name. - * - * @private - * @param {string} funcName The name of the function to resolve. - * @returns {string} Returns the real name. - */ - function getRealName(funcName) { - return aliasToRealMap[funcName] || funcName; - } - - /** - * Tests if a given method can be called successfully. - * - * @private - * @param {Object} lodash The built Lo-Dash object. - * @param {string} funcName The name of the method to test. - * @param {string} message The unit test message. - */ - function testMethod(lodash, methodName, message) { - var pass = true, - array = [['a', 1], ['b', 2], ['c', 3]], - object = { 'a': 1, 'b': 2, 'c': 3 }, - noop = function() {}, - string = 'abc', - template = '<%= a %>', - func = lodash[methodName]; - - try { - if (_.contains(categoryMap.Arrays, methodName)) { - if (/(?:indexOf|sortedIndex|without)$/i.test(methodName)) { - func(array, string); - } else if (/^(?:difference|intersection|union|uniq|zip)/.test(methodName)) { - func(array, array); - } else if (methodName == 'range') { - func(2, 4); - } else { - func(array); - } - } - else if (_.contains(categoryMap.Chaining, methodName)) { - lodash(array)[methodName](noop); - } - else if (_.contains(categoryMap.Collections, methodName)) { - if (/^(?:count|group|sort)By$/.test(methodName)) { - func(array, noop); - func(array, string); - func(object, noop); - func(object, string); - } - else if (/^(?:size|toArray)$/.test(methodName)) { - func(array); - func(object); - } - else if (methodName == 'at') { - func(array, 0, 2); - func(object, 'a', 'c'); - } - else if (methodName == 'invoke') { - func(array, 'slice'); - func(object, 'toFixed'); - } - else if (methodName == 'findWhere' || methodName == 'where') { - func(array, object); - func(object, object); - } - else { - func(array, noop, object); - func(object, noop, object); - } - } - else if (_.contains(categoryMap.Functions, methodName)) { - if (methodName == 'after') { - func(1, noop); - } else if (methodName == 'bindAll') { - func({ 'noop': noop }); - } else if (methodName == 'bindKey') { - func(lodash, 'identity', array, string); - } else if (/^(?:bind|partial(?:Right)?)$/.test(methodName)) { - func(noop, object, array, string); - } else if (/^(?:compose|memoize|wrap)$/.test(methodName)) { - func(noop, noop); - } else if (/^(?:debounce|throttle)$/.test(methodName)) { - func(noop, 100); - } else { - func(noop); - } - } - else if (_.contains(categoryMap.Objects, methodName)) { - if (methodName == 'clone') { - func(object); - func(object, true); - } - else if (/^(?:defaults|extend|merge)$/.test(methodName)) { - func({}, object); - } else if (/^for(?:In|Own)(?:Right)?$/.test(methodName)) { - func(object, noop); - } else if (/^(?:omit|pick)$/.test(methodName)) { - func(object, 'b'); - } else if (methodName == 'has') { - func(object, string); - } else { - func(object); - } - } - else if (_.contains(categoryMap.Utilities, methodName)) { - if (methodName == 'mixin') { - func({}); - } else if (methodName == 'result') { - func(object, 'b'); - } else if (methodName == 'runInContext') { - func(); - } else if (methodName == 'template') { - func(template, object); - func(template, null, { 'imports': object })(object); - } else if (methodName == 'times') { - func(2, noop, object); - } else { - func(string, object); - } - } - } - catch(e) { - console.log(e); - pass = false; - } - ok(pass, '_.' + methodName + ': ' + message); - } - - /*--------------------------------------------------------------------------*/ - - QUnit.module('build command checks'); - - (function() { - var reHelp = /lodash --help/, - write = process.stdout.write; - - var commands = [ - 'node.EXE build -s modern', - '-s strict underscore' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'` is valid', function() { - var start = _.after(2, _.once(function() { - ok(true, 'should be valid'); - QUnit.start(); - })); - - build(command.split(' '), start); - }); - }); - - commands = [ - 'csp backbone', - 'mobile underscore', - 'modern template=./*.jst' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'` is not valid', function() { - process.stdout.write = _.once(function(string) { - ok(reHelp.test(string)); - process.stdout.write = write; - QUnit.start(); - }); - - build(command.split(' '), function() {}); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('minified AMD snippet'); - - (function() { - asyncTest('r.js build optimizer check', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'exclude='], function(data) { - // uses the same regexp from the r.js build optimizer - var basename = path.basename(data.outputPath, '.js'), - defineHasRegExp = /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g; - - ok(defineHasRegExp.test(data.source), basename); - start(); - }); - }); - - asyncTest('Dojo builder check', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'exclude='], function(data) { - var basename = path.basename(data.outputPath, '.js'), - reSpaceDefine = /\sdefine\(/; - - ok(reSpaceDefine.test(data.source), basename); - start(); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('template builds'); - - (function() { - var templatePath = path.join(__dirname, 'template'); - - var commands = [ - 'template=' + path.join('template', '*.jst'), - 'template=' + relativePrefix + path.join('template', '*.jst'), - 'template=' + path.join(templatePath, '*.jst') - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(function() { - process.chdir(cwd); - QUnit.start(); - })); - - process.chdir(__dirname); - - build(['-s', command], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - var object = { - 'a': { 'people': ['moe', 'larry', 'curly'] }, - 'b': { 'epithet': 'stooge' }, - 'c': { 'name': 'ES6' } - }; - - context._ = _; - vm.runInContext(data.source, context); - - var actual = _.templates.a(object.a); - equal(actual.replace(/[\r\n]+/g, ''), '', basename); - - equal(_.templates.b(object.b), 'Hello stooge.', basename); - equal(_.templates.c(object.c), 'Hello ES6!', basename); - - delete _.templates; - start(); - }); - }); - }); - - commands = [ - '', - 'moduleId=underscore' - ]; - - commands.forEach(function(command) { - var expectedId = /underscore/.test(command) ? 'underscore' : 'lodash'; - - asyncTest('`lodash exports=amd' + (command ? ' ' + command + '`' : '` using the default `moduleId`'), function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'template=' + path.join(templatePath, '*.jst'), 'exports=amd'].concat(command || []), function(data) { - var moduleId, - basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - context.define = function(requires, factory) { - factory(_); - moduleId = requires[0]; - }; - - context.define.amd = {}; - vm.runInContext(data.source, context); - - var templates = _.templates; - equal(moduleId, expectedId, basename); - ok('a' in templates && 'b' in templates && 'c' in templates, basename); - - var actual = templates.a({ 'people': ['moe', 'larry'] }); - equal(actual.replace(/[\r\n]+/g, ''), '', basename); - - delete _.templates; - start(); - }); - }); - - asyncTest('`lodash settings=...' + (command ? ' ' + command : '') + '`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'template=' + path.join(templatePath, '*.tpl'), 'settings={interpolate:/{{([\\s\\S]+?)}}/}'].concat(command || []), function(data) { - var moduleId, - basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - var object = { - 'd': { 'name': 'Mustache' } - }; - - context.define = function(requires, factory) { - factory(_); - moduleId = requires[0]; - }; - - context.define.amd = {}; - vm.runInContext(data.source, context); - - equal(moduleId, expectedId, basename); - equal(_.templates.d(object.d), 'Hallå Mustache!', basename); - delete _.templates; - start(); - }); - }); - }); - - var defaultTemplates = { 'c': function() { return ''; } }; - - var exportsCommands = [ - 'exports=amd', - 'exports=commonjs', - 'exports=global', - 'exports=node', - 'exports=none' - ]; - - exportsCommands.forEach(function(command, index) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'template=' + path.join(templatePath, '*.jst'), command], function(data) { - var templates, - basename = path.basename(data.outputPath, '.js'), - context = createContext(), - source = data.source; - - switch(index) { - case 0: - context.define = function(requires, factory) { factory(_); }; - context.define.amd = {}; - vm.runInContext(source, context); - - templates = _.templates || defaultTemplates; - break; - - case 1: - context.exports = {}; - context.require = function() { return _; }; - vm.runInContext(source, context); - - templates = context.exports.templates || defaultTemplates; - break; - - case 2: - context._ = _; - vm.runInContext(source, context); - - templates = context._.templates || defaultTemplates; - break; - - case 3: - context.exports = {}; - context.require = function() { return _; }; - context.module = { 'exports': context.exports }; - vm.runInContext(source, context); - - templates = context.module.exports || defaultTemplates; - break; - - case 4: - vm.runInContext(source, context); - strictEqual(context._, undefined, basename); - } - if (templates) { - equal(templates.c({ 'name': 'Moe' }), 'Hello Moe!', basename); - } - delete _.templates; - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('independent builds'); - - (function() { - var reCustom = /Custom Build/, - reLicense = /^\/\**\s+\* @license[\s\S]+?\*\/\n/; - - asyncTest('debug only', function() { - var start = _.once(QUnit.start); - build(['-d', '-s'], function(data) { - equal(path.basename(data.outputPath, '.js'), 'lodash'); - start(); - }); - }); - - asyncTest('debug custom', function() { - var start = _.once(QUnit.start); - build(['-d', '-s', 'backbone'], function(data) { - equal(path.basename(data.outputPath, '.js'), 'lodash.custom'); - - var comment = data.source.match(reLicense); - ok(reCustom.test(comment)); - start(); - }); - }); - - asyncTest('minified only', function() { - var start = _.once(QUnit.start); - build(['-m', '-s'], function(data) { - equal(path.basename(data.outputPath, '.js'), 'lodash.min'); - start(); - }); - }); - - asyncTest('minified custom', function() { - var start = _.once(QUnit.start); - build(['-m', '-s', 'backbone'], function(data) { - equal(path.basename(data.outputPath, '.js'), 'lodash.custom.min'); - - var comment = data.source.match(reLicense); - ok(reCustom.test(comment)); - start(); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('csp modifier'); - - (function() { - asyncTest('`lodash csp`', function() { - var sources = []; - - var check = _.after(2, _.once(function() { - ok(_.every(sources, function(source) { - // remove `Function` in `_.template` before testing for additional use - return !/\bFunction\(/.test(source.replace(/= *\w+\(\w+, *['"]return.+?apply[^)]+\)/, '')); - })); - - equal(sources[0], sources[1]); - QUnit.start(); - })); - - var callback = function(data) { - // remove copyright header and append to `sources` - sources.push(data.source.replace(/^\/\**[\s\S]+?\*\/\n/, '')); - check(); - }; - - build(['-s', '-d', 'csp'], callback); - build(['-s', '-d', 'modern'], callback); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('mobile modifier'); - - (function() { - asyncTest('`lodash mobile`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'mobile'], function(data) { - var array = [1, 2, 3], - basename = path.basename(data.outputPath, '.js'), - context = createContext(), - object1 = [{ 'a': 1 }], - object2 = [{ 'b': 2 }], - object3 = [{ 'a': 1, 'b': 2 }], - circular1 = { 'a': 1 }, - circular2 = { 'a': 1 }; - - circular1.b = circular1; - circular2.b = circular2; - - vm.runInContext(data.source, context); - var lodash = context._; - - deepEqual(lodash.merge(object1, object2), object3, basename); - deepEqual(lodash.sortBy([3, 2, 1], _.identity), array, basename); - strictEqual(lodash.isEqual(circular1, circular2), true, basename); - - var actual = lodash.cloneDeep(circular1); - ok(actual != circular1 && actual.b == actual, basename); - start(); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('modern modifier'); - - (function() { - asyncTest('`lodash modern`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'modern'], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - strictEqual(lodash.isPlainObject(Object.create(null)), true, basename); - start(); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('source-map modifier'); - - (function() { - var mapCommands = [ - '-p', - '-p custom.map', - '--source-map', - '--source-map custom.map' - ]; - - var outputCommands = [ - '', - '-o foo.js', - '-m -o bar.js' - ]; - - mapCommands.forEach(function(mapCommand) { - outputCommands.forEach(function(outputCommand) { - asyncTest('`lodash ' + mapCommand + (outputCommand ? ' ' + outputCommand : '') + '`', function() { - var callback = _.once(function(data) { - var basename = path.basename(data.outputPath, '.js'), - sources = /foo.js/.test(outputCommand) ? ['foo.js'] : ['lodash' + (outputCommand.length ? '' : '.custom') + '.js'], - sourceMap = JSON.parse(data.sourceMap), - sourceMapURL = (/\w+(?=\.map$)/.exec(mapCommand) || [basename])[0]; - - ok(RegExp('\\n//# sourceMappingURL=' + sourceMapURL + '.map$').test(data.source), basename); - equal(sourceMap.file, basename + '.js', basename); - deepEqual(sourceMap.sources, sources, basename); - - process.chdir(cwd); - QUnit.start(); - }); - - process.chdir(__dirname); - - outputCommand = outputCommand ? outputCommand.split(' ') : []; - if (!_.contains(outputCommand, '-m')) { - callback = _.after(2, callback); - } - build(['-s'].concat(mapCommand.split(' '), outputCommand), callback); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('strict modifier'); - - (function() { - var object = Object.freeze({ - 'a': _.identity, - 'b': undefined - }); - - var modes = [ - 'non-strict', - 'strict' - ]; - - modes.forEach(function(strictMode, index) { - asyncTest(strictMode + ' should ' + (index ? 'error': 'silently fail') + ' attempting to overwrite read-only properties', function() { - var commands = ['-s', 'include=bindAll,defaults,extend'], - start = _.after(2, _.once(QUnit.start)); - - if (index) { - commands.push('strict'); - } - build(commands, function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - var actual = _.every([ - function() { lodash.bindAll(object); }, - function() { lodash.extend(object, { 'a': 1 }); }, - function() { lodash.defaults(object, { 'b': 2 }); } - ], function(fn) { - var pass = !index; - try { - fn(); - } catch(e) { - pass = !!index; - } - return pass; - }); - - ok(actual, basename); - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('underscore modifier'); - - (function() { - asyncTest('modified methods should work correctly', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'underscore'], function(data) { - var array = [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }], - basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - var object = { - 'fn': lodash.bind(function(foo) { - return foo + this.bar; - }, { 'bar': 1 }, 1) - }; - - equal(object.fn(), 2, '_.bind: ' + basename); - - var actual = lodash.clone('a', function() { - return this.a; - }, { 'a': 'A' }); - - equal(actual, 'a', '_.clone should ignore `callback` and `thisArg`: ' + basename); - strictEqual(lodash.clone(array, true)[0], array[0], '_.clone should ignore `deep`: ' + basename); - - strictEqual(lodash.contains({ 'a': 1, 'b': 2 }, 1), true, '_.contains should work with objects: ' + basename); - strictEqual(lodash.contains([1, 2, 3], 1, 2), true, '_.contains should ignore `fromIndex`: ' + basename); - strictEqual(lodash.every([true, false, true]), false, '_.every: ' + basename); - - function Foo() {} - Foo.prototype = { 'a': 1 }; - - deepEqual(lodash.defaults({}, new Foo), Foo.prototype, '_.defaults should assign inherited `source` properties: ' + basename); - deepEqual(lodash.extend({}, new Foo), Foo.prototype, '_.extend should assign inherited `source` properties: ' + basename); - - var callback = function(a, b) { - actual = this[b]; - }; - - actual = lodash.extend({}, { 'a': 0 }, callback, [2]); - strictEqual(actual.a, 0, '_.extend should ignore `callback` and `thisArg`: ' + basename); - - actual = lodash.find(array, function(value) { - return 'a' in value; - }); - - equal(actual, _.first(array), '_.find: ' + basename); - - var last; - actual = lodash.forEach(array, function(value) { - last = value; - return false; - }); - - equal(last, _.last(array), '_.forEach should not exit early: ' + basename); - equal(actual, undefined, '_.forEach should return `undefined`: ' + basename); - - lodash.forEach([1], callback, [2]); - equal(actual, 2, '_.forEach supports the `thisArg` argument when iterating arrays: ' + basename); - - lodash.forEach({ 'a': 1 }, callback, { 'a': 2 }); - equal(actual, 2, '_.forEach supports the `thisArg` argument when iterating objects: ' + basename); - - array = [{ 'a': [1, 2] }, { 'a': [3] }]; - - actual = lodash.flatten(array, function(value, index) { - return this[index].a; - }, array); - - deepEqual(actual, array, '_.flatten should should ignore `callback` and `thisArg`: ' + basename); - deepEqual(lodash.flatten(array, 'a'), array, '_.flatten should should ignore string `callback` values: ' + basename); - - object = { 'length': 0, 'splice': Array.prototype.splice }; - equal(lodash.isEmpty(object), false, '_.isEmpty should return `false` for jQuery/MooTools DOM query collections: ' + basename); - - object = { 'a': 1, 'b': 2, 'c': 3 }; - equal(lodash.isEqual(object, { 'a': 1, 'b': 0, 'c': 3 }), false, '_.isEqual: ' + basename); - - actual = lodash.isEqual('a', 'b', function(a, b) { - return this[a] == this[b]; - }, { 'a': 1, 'b': 1 }); - - strictEqual(actual, false, '_.isEqual should ignore `callback` and `thisArg`: ' + basename); - - equal(lodash.max('abc'), -Infinity, '_.max should return `-Infinity` for strings: ' + basename); - equal(lodash.min('abc'), Infinity, '_.min should return `Infinity` for strings: ' + basename); - - object = {}; - lodash.mixin(object, { 'a': function(a) { return a[0]; } }); - equal('a' in object, false, '_.mixin should not accept a destination object: ' + basename); - - // avoid issues comparing objects with `deepEqual` - object = { 'a': 1, 'b': 2, 'c': 3 }; - actual = lodash.omit(object, function(value) { return value == 3; }); - deepEqual(_.keys(actual).sort(), ['a', 'b', 'c'], '_.omit should not accept a `callback`: ' + basename); - - actual = lodash.pick(object, function(value) { return value != 3; }); - deepEqual(_.keys(actual), [], '_.pick should not accept a `callback`: ' + basename); - - deepEqual(lodash.range(1, 4, 0), [1, 2, 3], '_.range should not support a `step` of `0`'); - strictEqual(lodash.some([false, true, false]), true, '_.some: ' + basename); - equal(lodash.template('${a}', object), '${a}', '_.template should ignore ES6 delimiters: ' + basename); - equal('support' in lodash, false, '_.support should not exist: ' + basename); - equal('imports' in lodash.templateSettings, false, '_.templateSettings should not have an "imports" property: ' + basename); - strictEqual(lodash.uniqueId(0), '1', '_.uniqueId should ignore a prefix of `0`: ' + basename); - - var collection = [{ 'a': { 'b': 1, 'c': 2 } }]; - deepEqual(lodash.where(collection, { 'a': { 'b': 1 } }), [], '_.where performs shallow comparisons: ' + basename); - - collection = [{ 'a': 1 }, { 'a': 1 }]; - deepEqual(lodash.where(collection, { 'a': 1 }, true), collection[0], '_.where supports a `first` argument: ' + basename); - deepEqual(lodash.where(collection, {}, true), undefined, '_.where should return `undefined` when passed `first` and falsey `properties`: ' + basename); - - deepEqual(lodash.findWhere(collection, { 'a': 1 }), collection[0], '_.findWhere: ' + basename); - strictEqual(lodash.findWhere(collection, {}), undefined, '_.findWhere should return `undefined` for falsey `properties`: ' + basename); - - var expected = [[['moe', 30, true]], [['larry', 40, false]]]; - actual = lodash.zip(lodash.zip(['moe', 'larry'], [30, 40], [true, false])); - deepEqual(actual, expected, '_.zip is unable to correctly consume it\'s output: ' + basename); - - start(); - }); - }); - - asyncTest('should not have AMD support', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'underscore'], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(), - pass = true; - - context.define = function(fn) { - pass = false; - context._ = fn(); - }; - - context.define.amd = {}; - vm.runInContext(data.source, context); - - ok(pass, basename); - start(); - }); - }); - - asyncTest('should not have any Lo-Dash-only methods', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'underscore'], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - _.each(lodashOnlyFuncs.concat('assign'), function(funcName) { - equal(lodash[funcName], undefined, '_.' + funcName + ' should not exist: ' + basename); - }); - - start(); - }); - }); - - asyncTest('`lodash underscore include=partial`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'underscore', 'include=partial'], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - equal(lodash.partial(_.identity, 2)(), 2, '_.partial: ' + basename); - start(); - }); - }); - - var commands = [ - 'plus=clone', - 'plus=cloneDeep' - ]; - - commands.forEach(function(command, index) { - asyncTest('`lodash underscore ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'underscore', command], function(data) { - var array = [{ 'value': 1 }], - basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context, true); - var lodash = context._; - - _.each(index ? ['clone','cloneDeep'] : ['clone'], function(funcName) { - var clone = (funcName == 'clone') - ? lodash.clone(array, true) - : lodash.cloneDeep(array); - - ok(_.isEqual(array, clone), basename); - notEqual(array[0], clone[0], basename); - }); - - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('underscore chaining methods'); - - (function() { - var commands = [ - 'backbone', - 'underscore', - 'modern plus=chain' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s'].concat(command.split(' ')), function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - var array = ['abc']; - ok(lodash.chain(array).first().first() instanceof lodash, '_.chain: ' + basename); - ok(lodash(array).chain().first().first() instanceof lodash, '_#chain: ' + basename); - - var wrapped = lodash(1); - strictEqual(wrapped.identity(), 1, '_(...) wrapped values are not chainable by default: ' + basename); - equal(String(wrapped) === '1', false, '_#toString should not be implemented: ' + basename); - equal(Number(wrapped) === 1 , false, '_#valueOf should not be implemented: ' + basename); - - wrapped.chain(); - ok(wrapped.has('x') instanceof lodash, '_#has returns wrapped values when chaining: ' + basename); - ok(wrapped.join() instanceof lodash, '_#join returns wrapped values when chaining: ' + basename); - - wrapped = lodash([1, 2, 3]); - ok(wrapped.pop() instanceof lodash, '_#pop returns wrapped values: ' + basename); - ok(wrapped.shift() instanceof lodash, '_#shift returns wrapped values: ' + basename); - deepEqual(wrapped.splice(0, 0).value(), [2], '_#splice returns wrapper: ' + basename); - - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('exclude command'); - - (function() { - var commands = [ - 'exclude', - 'minus' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command + '=runInContext`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', command + '=runInContext'], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - - var lodash = context._, - array = [0]; - - var actual = lodash.map(array, function() { - return String(this[0]); - }, array); - - deepEqual(actual, ['0'], basename); - equal('runInContext' in lodash, false, basename); - start(); - }); - }); - - asyncTest('`lodash ' + command + '=value`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', command + '=value'], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - equal(lodash([1]) instanceof lodash, false, basename); - deepEqual(_.keys(lodash.prototype), [], basename); - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('exports command'); - - (function() { - var commands = [ - 'exports=amd', - 'exports=commonjs', - 'exports=global', - 'exports=node', - 'exports=none' - ]; - - commands.forEach(function(command, index) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', command], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(), - pass = false, - source = data.source; - - switch(index) { - case 0: - context.define = function(factory) { - pass = true; - context._ = factory(); - }; - context.define.amd = {}; - vm.runInContext(source, context); - - ok(pass, basename); - ok(_.isFunction(context._), basename); - break; - - case 1: - context.exports = {}; - vm.runInContext(source, context); - - ok(_.isFunction(context.exports._), basename); - strictEqual(context._, undefined, basename); - break; - - case 2: - vm.runInContext(source, context); - ok(_.isFunction(context._), basename); - break; - - case 3: - context.exports = {}; - context.module = { 'exports': context.exports }; - vm.runInContext(source, context); - - ok(_.isFunction(context.module.exports), basename); - strictEqual(context._, undefined, basename); - break; - - case 4: - vm.runInContext(source, context); - strictEqual(context._, undefined, basename); - } - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('iife command'); - - (function() { - var commands = [ - 'iife=this["lodash"]=(function(){%output%;return _}())', - 'iife=define(function(){return (function(){%output%;return _}())});' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', 'exports=none', command], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - context.define = function(func) { - context.lodash = func(); - }; - - try { - vm.runInContext(data.source, context); - } catch(e) { - console.log(e); - } - - var lodash = context.lodash || {}; - ok(_.isString(lodash.VERSION), basename); - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('include command'); - - (function() { - var commands = [ - 'include=mixin', - 'include=mixin,tap', - 'include=mixin,value' - ]; - - commands.forEach(function(command, index) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s', command], function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(), - noop = function() {}; - - vm.runInContext(data.source, context); - var lodash = context._; - - lodash.mixin({ 'x': noop }); - equal(lodash.x, noop, basename); - equal(typeof lodash.prototype.x, 'function', basename); - - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('no-dep option'); - - (function() { - var commands = [ - '-n', - '--no-dep' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash modern include=each ' + command +'`', function() { - var start = _.once(QUnit.start); - - build(['-s', 'modern', 'include=each', command], function(data) { - var basename = path.basename(data.outputPath, '.js'); - strictEqual(/function createCallback\b/.test(data.source), false, basename); - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('output option'); - - (function() { - var nestedPath = path.join(__dirname, 'a', 'b'); - - var commands = [ - '-o a.js', - '--output b.js', - '-o ' + path.join('a', 'b', 'c.js'), - '-o ' + relativePrefix + path.join('a', 'b', 'c.js'), - '-o ' + path.join(nestedPath, 'c.js'), - '-o name_with_keywords_like_category_include_exclude_plus_minus.js' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'`', function() { - var counter = 0, - dirs = _.contains(command, 'c.js'), - expected = /(\w+)(?=\.js$)/.exec(command)[0]; - - var start = _.after(2, _.once(function() { - if (dirs) { - fs.rmdirSync(nestedPath); - fs.rmdirSync(path.dirname(nestedPath)); - } - process.chdir(cwd); - QUnit.start(); - })); - - process.chdir(__dirname); - - build(['-s'].concat(command.split(' ')), function(data) { - var basename = path.basename(data.outputPath, '.js'); - equal(basename, expected + (counter++ ? '.min' : ''), command); - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('stdout option'); - - (function() { - var write = process.stdout.write; - - var commands = [ - '-c', - '-c -d', - '--stdout', - ]; - - commands.forEach(function(command, index) { - asyncTest('`lodash ' + command +'`', function() { - var written, - start = _.once(QUnit.start); - - process.stdout.write = function(string) { - written = string; - }; - - build(['exports=', 'include='].concat(command.split(' ')), function(data) { - strictEqual('outputPath' in data, false); - equal(written, data.source); - equal(arguments.length, 1); - - process.stdout.write = write; - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('underscore builds with lodash methods'); - - (function() { - var funcNames = [ - 'assign', - 'bindKey', - 'clone', - 'contains', - 'defaults', - 'defer', - 'difference', - 'every', - 'filter', - 'find', - 'findIndex', - 'findKey', - 'findLast', - 'findLastIndex', - 'findLastKey', - 'findWhere', - 'first', - 'flatten', - 'forEach', - 'forEachRight', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight', - 'intersection', - 'initial', - 'isEmpty', - 'isEqual', - 'isPlainObject', - 'isRegExp', - 'last', - 'map', - 'max', - 'memoize', - 'min', - 'omit', - 'partial', - 'partialRight', - 'pick', - 'pluck', - 'reduce', - 'reduceRight', - 'result', - 'rest', - 'some', - 'tap', - 'template', - 'throttle', - 'times', - 'toArray', - 'transform', - 'uniq', - 'uniqueId', - 'value', - 'where', - 'zip' - ]; - - var tested = {}; - - function strip(value) { - return String(value) - .replace(/^ *\/\/.*/gm, '') - .replace(/\b(?:basicEach|context|forEach|forOwn)\b/g, '') - .replace(/\blodash\.(createCallback\()\b/g, '$1') - .replace(/[\s;]/g, ''); - } - - funcNames.forEach(function(funcName) { - _.times(2, function(index) { - var command = 'underscore plus=' + funcName, - expected = !(funcName == 'defer' && global.setImmediate); - - if (funcName == 'createCallback') { - expected = !!index; - if (index) { - command += ',where'; - } - } - if (funcName != 'chain' && _.contains(categoryMap.Chaining.concat('mixin'), funcName)) { - expected = funcName == 'tap' || !!index; - if (index) { - command += ',chain'; - } - } - if (_.contains(['contains', 'every', 'find', 'findKey', 'findWhere', 'some', 'transform'], funcName)) { - expected = !!index; - if (index) { - command += ',forOwn'; - } - } - if (funcName == 'findLast') { - expected = !!index; - if (index) { - command += ',forEachRight'; - } - } - if (funcName == 'findLastKey') { - expected = !!index; - if (index) { - command += ',forOwnRight'; - } - } - if (tested[command]) { - return; - } - tested[command] = true; - - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s'].concat(command.split(' ')), function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context, true); - - var lodash = context._, - func = lodash[funcName], - array = [1, 2, 3], - object = { 'a': 1, 'b': 2, 'c': 3 }, - result = []; - - if (/^for(?:Each|In|Own)(?:Right)?$/.test(funcName)) { - func(/^forEach/.test(funcName) ? array : object, function(value) { - result.push(value); - return false; - }); - - equal(result.length, 1, basename); - } - if (!/\.min$/.test(basename)) { - equal(strip(func) === strip(_[funcName]), expected, basename); - } - testMethod(lodash, funcName, basename); - start(); - }); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash build'); - - (function() { - var commands = [ - 'backbone', - 'csp', - 'legacy', - 'mobile', - 'modern', - 'strict', - 'underscore', - 'category=arrays', - 'category=chaining', - 'category=collections', - 'category=functions', - 'category=objects', - 'category=utilities', - 'exclude=union,uniq,zip', - 'include=each,filter,map', - 'include=once plus=bind,Chaining', - 'category=collections,functions', - 'backbone category=utilities minus=first,last', - 'legacy include=defer', - 'mobile strict category=functions exports=amd,global plus=pick,uniq', - 'modern strict include=isArguments,isArray,isFunction,isPlainObject,keys', - 'underscore include=debounce,throttle plus=after minus=throttle' - ] - .concat( - allFuncs.map(function(funcName) { - return 'include=' + funcName; - }) - ); - - var reNonCombinable = /\b(?:backbone|csp|legacy|mobile|modern|underscore)\b/; - - commands.forEach(function(origCommand) { - _.each(['', 'mobile', 'modern', 'underscore'], function(otherCommand) { - var command = (otherCommand + ' ' + origCommand).trim(); - if ((otherCommand && reNonCombinable.test(origCommand)) || - (otherCommand == 'underscore' && /\bcategory\b/.test(origCommand))) { - return; - } - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['--silent'].concat(command.split(' ')), function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(), - isBackbone = /\bbackbone\b/.test(command), - isUnderscore = isBackbone || /\bunderscore\b/.test(command), - exposeAssign = !isUnderscore, - exposeZipObject = !isUnderscore; - - try { - vm.runInContext(data.source, context); - } catch(e) { - console.log(e); - } - // add function names explicitly - if (/\binclude=/.test(command)) { - var funcNames = command.match(/\binclude=(\S*)/)[1].split(/, */); - } - if (/\bcategory=/.test(command)) { - var categories = command.match(/\bcategory=(\S*)/)[1].split(/, */); - funcNames = (funcNames || []).concat(categories.map(function(category) { - return capitalize(category.toLowerCase()); - })); - } - // add function names required by Backbone and Underscore builds - if (/\bbackbone\b/.test(command) && !funcNames) { - funcNames = backboneDependencies.slice(); - } - if (isUnderscore) { - if (funcNames) { - exposeAssign = _.contains(funcNames, 'assign'); - exposeZipObject = _.contains(funcNames, 'zipObject'); - } else { - funcNames = underscoreFuncs.slice(); - } - } - if (!funcNames) { - funcNames = lodashFuncs.slice(); - } - if (/\bplus=/.test(command)) { - var otherNames = command.match(/\bplus=(\S*)/)[1].split(/, */); - funcNames = funcNames.concat(expandFuncNames(otherNames)); - } - if (/\bminus=/.test(command)) { - otherNames = command.match(/\bminus=(\S*)/)[1].split(/, */); - funcNames = _.difference(funcNames, expandFuncNames(otherNames)); - } - if (/\bexclude=/.test(command)) { - otherNames = command.match(/\bexclude=(\S*)/)[1].split(/, */); - funcNames = _.difference(funcNames, expandFuncNames(otherNames)); - } - - // expand categories to function names - funcNames.slice().forEach(function(category) { - var otherNames = _.filter(categoryMap[category], function(key) { - var type = typeof _[key]; - return type == 'function' || type == 'undefined'; - }); - - // limit function names to those available for specific builds - otherNames = _.intersection(otherNames, - isBackbone ? backboneDependencies : - isUnderscore ? underscoreFuncs : - lodashFuncs - ); - - if (otherNames.length) { - _.pull(funcNames, category); - push.apply(funcNames, otherNames); - } - }); - - // expand aliases and remove nonexistent and duplicate function names - funcNames = _.uniq(_.intersection(expandFuncNames(funcNames), allFuncs)); - - if (!exposeAssign) { - _.pull(funcNames, 'assign'); - } - if (!exposeZipObject) { - _.pull(funcNames, 'zipObject'); - } - var lodash = context._ || {}; - funcNames.forEach(function(funcName) { - testMethod(lodash, funcName, basename); - }); - - start(); - }); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - if (timeLimit > 0) { - setTimeout(function() { - process.exit(QUnit.config.stats.bad ? 1 : 0); - }, timeLimit); - } - QUnit.config.noglobals = true; - QUnit.start(); -}());