diff --git a/build.js b/build.js index f1e2a7166..d8175a31e 100755 --- a/build.js +++ b/build.js @@ -67,7 +67,7 @@ 'bind': ['isFunction'], 'bindAll': ['bind', 'isFunction'], 'chain': ['mixin'], - 'clone': ['extend', 'forIn', 'forOwn', 'isArguments', 'isFunction'], + 'clone': ['extend', 'forOwn', 'isArguments', 'isPlainObject'], 'compact': [], 'compose': [], 'contains': [], @@ -109,6 +109,7 @@ 'isNull': [], 'isNumber': [], 'isObject': [], + 'isPlainObject': ['forIn', 'isArguments', 'isFunction'], 'isRegExp': [], 'isString': [], 'isUndefined': [], @@ -119,7 +120,7 @@ 'map': ['identity'], 'max': [], 'memoize': [], - 'merge': ['isArguments', 'isArray', 'forIn'], + 'merge': ['isArray', 'isPlainObject'], 'min': [], 'mixin': ['forEach', 'functions'], 'noConflict': [], @@ -236,6 +237,7 @@ var underscoreMethods = _.without.apply(_, [allMethods].concat([ 'forIn', 'forOwn', + 'isPlainObject', 'lateBind', 'merge', 'partial' @@ -251,6 +253,42 @@ /*--------------------------------------------------------------------------*/ + /** + * Creates a debug and minified build, executing the `callback` for each. + * The `callback` is invoked with 2 arguments; (filepath, source) + * + * @param {Array} options The options array. + * @param {Function} callback The function called per build. + */ + function buildTemplate(templatePattern, templateSettings) { + var directory = path.dirname(templatePattern); + + var pattern = RegExp( + path.basename(templatePattern) + .replace(/[.+?^=!:${}()|[\]\/\\]/g, '\\$&') + .replace(/\*/g, '.*?') + '$' + ); + + var source = [ + ';(function() {', + ' var templates = _.templates || (_.templates = {});' + ]; + + fs.readdirSync(directory).forEach(function(filename) { + var filepath = path.join(directory, filename); + if (pattern.test(filename)) { + var text = fs.readFileSync(filepath, 'utf8'), + precompiled = getFunctionSource(_.template(text, null, templateSettings)), + prop = filename.replace(/\..*$/, ''); + + source.push(' templates["' + prop + '"] = ' + precompiled + ';'); + } + }); + + source.push('}());'); + return source.join('\n'); + } + /** * Removes unnecessary comments, whitespace, and pseudo private properties. * @@ -294,9 +332,10 @@ ' 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. “!function(window,undefined){%output%}(this)”)', + ' (e.g. `lodash iife="!function(window,undefined){%output%}(this)"`)', + '', ' lodash template=... The file path pattern used for matching template files to compile', - ' (e.g. `lodash template=path/to/templates/*.tmpl`)', + ' (e.g. `lodash template=./*.jst`)', '', ' All arguments, except `legacy` with `csp` or `mobile`, may be combined.', ' Unless specified by `-o` or `--output`, all files created are saved to the current working directory.', @@ -304,7 +343,9 @@ ' Options:', '', ' -c, --stdout Write output to standard output', + ' -d, --debug Write only the debug output', ' -h, --help Display help information', + ' -m, --minify Write only the minified output', ' -o, --output Write output to a given path/filename', ' -s, --silent Skip status updates normally logged to the console', ' -V, --version Output current version of Lo-Dash', @@ -734,7 +775,7 @@ * Creates a debug and minified build, executing the `callback` for each. * The `callback` is invoked with 2 arguments; (filepath, source) * - * @param {Array} options The options array. + * @param {Array} options The build options array. * @param {Function} callback The function called per build. */ function build(options, callback) { @@ -746,7 +787,7 @@ // used to report invalid command-line arguments var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) { if (/^(?:-o|--output)$/.test(options[index - 1]) || - /^(?:category|exclude|exports|iife|include|minus|plus|template)=.*$/.test(value)) { + /^(?:category|exclude|exports|iife|include|minus|plus|settings|template)=.*$/.test(value)) { return true; } return [ @@ -757,7 +798,9 @@ 'strict', 'underscore', '-c', '--stdout', + '-d', '--debug', '-h', '--help', + '-m', '--minify', '-o', '--output', '-s', '--silent', '-V', '--version' @@ -798,7 +841,8 @@ // used to specify a custom IIFE to wrap Lo-Dash var iife = options.reduce(function(result, value) { - return result || (result = value.match(/iife=(.*)/)) && result[1]; + var match = value.match(/iife=(.*)/); + return match ? match[1] : result; }, null); // flag used to specify a Backbone build @@ -807,12 +851,18 @@ // flag used to specify a Content Security Policy build var isCSP = options.indexOf('csp') > -1 || options.indexOf('CSP') > -1; + // flag used to specify only creating the debug build + var isDebug = options.indexOf('-d') > -1 || options.indexOf('--debug') > -1; + // flag used to specify a legacy build var isLegacy = options.indexOf('legacy') > -1; // flag used to specify an Underscore build var isUnderscore = options.indexOf('underscore') > -1; + // flag used to specify only creating the minified build + var isMinify = !isDebug && options.indexOf('-m') > -1 || options.indexOf('--minify')> -1; + // flag used to specify a mobile build var isMobile = !isLegacy && (isCSP || isUnderscore || options.indexOf('mobile') > -1); @@ -836,9 +886,32 @@ // used to specify the output path for builds var outputPath = options.reduce(function(result, value, index) { - return result || (/^(?:-o|--output)$/.test(value) ? options[index + 1] : result); + if (/-o|--output/.test(value)) { + result = options[index + 1]; + result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result)); + } + return result; }, ''); + // used to match external template files to pre-compile + var templatePattern = options.reduce(function(result, value) { + var match = value.match(/template=(.+)$/); + return match + ? path.join(fs.realpathSync(path.dirname(match[1])), path.basename(match[1])) + : result; + }, ''); + + // used when pre-compiling template files + var templateSettings = options.reduce(function(result, value) { + var match = value.match(/settings=(.+)$/); + return match + ? JSON.parse(match[1]) + : result; + }, _.clone(_.templateSettings)); + + // flag used to specify a template build + var isTemplate = !!templatePattern; + // the lodash.js source var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8'); @@ -847,65 +920,68 @@ /*------------------------------------------------------------------------*/ - // collections of method names - var buildMethods; + // names of methods to include in the build + var buildMethods = !isTemplate && (function() { + var result; - var minusMethods = options.reduce(function(result, value) { - return /exclude|minus/.test(value) - ? _.union(result, optionToMethodsArray(source, value)) - : result; - }, []); - - var plusMethods = options.reduce(function(result, value) { - return /plus/.test(value) - ? _.union(result, optionToMethodsArray(source, value)) - : result; - }, []); - - // add method names explicitly - options.some(function(value) { - return /include/.test(value) && - (buildMethods = getDependencies(optionToMethodsArray(source, value))); - }); - - // add method names required by Backbone and Underscore builds - if (isBackbone && !buildMethods) { - buildMethods = getDependencies(backboneDependencies); - } - if (isUnderscore && !buildMethods) { - buildMethods = getDependencies(underscoreMethods); - } - - // add method names by category - options.some(function(value) { - if (!/category/.test(value)) { - return false; - } - // resolve method names belonging to each category (case-insensitive) - var methodNames = optionToArray(value).reduce(function(result, category) { - var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1); - return result.concat(getMethodsByCategory(source, capitalized)); + var minusMethods = options.reduce(function(accumulator, value) { + return /exclude|minus/.test(value) + ? _.union(accumulator, optionToMethodsArray(source, value)) + : accumulator; }, []); - return (buildMethods = _.union(buildMethods || [], getDependencies(methodNames))); - }); + var plusMethods = options.reduce(function(accumulator, value) { + return /plus/.test(value) + ? _.union(accumulator, optionToMethodsArray(source, value)) + : accumulator; + }, []); - // init `buildMethods` if it hasn't been inited - if (!buildMethods) { - buildMethods = allMethods.slice(); - } + // add method names explicitly + options.some(function(value) { + return /include/.test(value) && + (result = getDependencies(optionToMethodsArray(source, value))); + }); - if (plusMethods.length) { - buildMethods = _.union(buildMethods, getDependencies(plusMethods)); - } - if (minusMethods.length) { - buildMethods = _.without.apply(_, [buildMethods].concat(minusMethods, getDependants(buildMethods))); - } + // add method names required by Backbone and Underscore builds + if (isBackbone && !result) { + result = getDependencies(backboneDependencies); + } + if (isUnderscore && !result) { + result = getDependencies(underscoreMethods); + } + + // add method names by category + options.some(function(value) { + if (!/category/.test(value)) { + return false; + } + // resolve method names belonging to each category (case-insensitive) + var methodNames = optionToArray(value).reduce(function(accumulator, category) { + var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1); + return accumulator.concat(getMethodsByCategory(source, capitalized)); + }, []); + + return (result = _.union(result || [], getDependencies(methodNames))); + }); + + // init `result` if it hasn't been inited + if (!result) { + result = allMethods.slice(); + } + + if (plusMethods.length) { + result = _.union(result, getDependencies(plusMethods)); + } + if (minusMethods.length) { + result = _.without.apply(_, [result].concat(minusMethods, getDependants(result))); + } + return result; + }()); /*------------------------------------------------------------------------*/ // load customized Lo-Dash module - var lodash = (function() { + var lodash = !isTemplate && (function() { var context = vm.createContext({ 'clearTimeout': clearTimeout, 'setTimeout': setTimeout @@ -980,156 +1056,191 @@ /*------------------------------------------------------------------------*/ - // simplify template snippets by removing unnecessary brackets - source = source.replace( - RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *([,\\n])", 'g'), "$1'$2" - ); + if (isTemplate) { + source = buildTemplate(templatePattern, templateSettings); + } + else { + // simplify template snippets by removing unnecessary brackets + source = source.replace( + RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *([,\\n])", 'g'), "$1'$2" + ); - source = source.replace( - RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+" - ); + source = source.replace( + RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+" + ); - // remove methods from the build - allMethods.forEach(function(otherName) { - if (!_.contains(buildMethods, otherName)) { - source = removeFunction(source, otherName); + // remove methods from the build + allMethods.forEach(function(otherName) { + if (!_.contains(buildMethods, otherName)) { + source = removeFunction(source, otherName); + } + }); + + // remove `isArguments` fallback before `isArguments` is transformed by + // other parts of the build process + if (isRemoved(source, 'isArguments')) { + source = removeIsArgumentsFallback(source); } - }); - // remove `isArguments` fallback before `isArguments` is transformed by - // other parts of the build process - if (isRemoved(source, 'isArguments')) { - source = removeIsArgumentsFallback(source); + /*----------------------------------------------------------------------*/ + + if (isLegacy) { + _.each(['isBindFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'], function(varName) { + source = removeVar(source, varName); + }); + + _.each(['bind', 'isArray'], function(methodName) { + var snippet = matchFunction(source, methodName), + modified = snippet; + + // remove native `Function#bind` branch in `_.bind` + if (methodName == 'bind') { + modified = modified.replace(/(?:\s*\/\/.*)*\s*return isBindFast[^:]+:\s*/, 'return '); + } + // remove native `Array.isArray` branch in `_.isArray` + else { + modified = modified.replace(/nativeIsArray * \|\|/, ''); + } + source = source.replace(snippet, modified); + }); + + // replace `_.keys` with `shimKeys` + if (!isRemoved(source, 'keys')) { + source = source.replace( + matchFunction(source, 'keys').replace(/[\s\S]+?var keys *=/, ''), + matchFunction(source, 'shimKeys').replace(/[\s\S]+?var shimKeys *=/, '') + ); + + source = removeFunction(source, 'shimKeys'); + } + // replace `_.isArguments` with fallback + if (!isRemoved(source, 'isArguments')) { + source = source.replace( + matchFunction(source, 'isArguments').replace(/[\s\S]+?function isArguments/, ''), + getIsArgumentsFallback(source).match(/isArguments *= *function([\s\S]+?) *};/)[1] + ' }\n' + ); + + source = removeIsArgumentsFallback(source); + } + + source = removeVar(source, 'reNative'); + source = removeFromCreateIterator(source, 'nativeKeys'); + } + + if (isMobile) { + // inline all functions defined with `createIterator` + _.functions(lodash).forEach(function(methodName) { + // match `methodName` with pseudo private `_` prefixes removed to allow matching `shimKeys` + var reFunc = RegExp('(\\bvar ' + methodName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n'); + + // skip if not defined with `createIterator` + if (!reFunc.test(source)) { + return; + } + // extract, format, and inject the compiled function's source code + source = source.replace(reFunc, '$1' + getFunctionSource(lodash[methodName]) + ';\n'); + }); + + // replace `callee` in `_.merge` with `merge` + source = source.replace(matchFunction(source, 'merge'), function(match) { + return match.replace(/\bcallee\b/g, 'merge'); + }); + + if (isUnderscore) { + (function() { + // replace `isArguments` and its fallback + var snippet = matchFunction(source, 'isArguments') + .replace(/function isArguments/, 'lodash.isArguments = function'); + + source = removeFunction(source, 'isArguments'); + + source = source.replace(getIsArgumentsFallback(source), function(match) { + return snippet + '\n' + match + .replace(/\bisArguments\b/g, 'lodash.$&') + .replace(/\bnoArgsClass\b/g, '!lodash.isArguments(arguments)'); + }); + }()); + } + else { + source = removeIsArgumentsFallback(source); + } + + // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment + source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, ''); + + // remove `iteratesOwnLast` from `isPlainObject` + source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, ''); + + // remove JScript [[DontEnum]] fix from `_.isEqual` + source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, ''); + + // remove `hasObjectSpliceBug` fix from the mutator Array functions mixin + source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, ''); + + // remove `noArraySliceOnStrings` from `_.toArray` + source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1'); + + // remove `noCharByIndex` from `_.reduceRight` + source = source.replace(/}\s*else if *\(noCharByIndex[^}]+/, ''); + + source = removeVar(source, 'extendIteratorOptions'); + source = removeVar(source, 'iteratorTemplate'); + source = removeVar(source, 'noArraySliceOnStrings'); + source = removeVar(source, 'noCharByIndex'); + source = removeNoArgsClass(source); + source = removeNoNodeClass(source); + } + else { + // inline `iteratorTemplate` template + source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() { + var snippet = getFunctionSource(lodash._iteratorTemplate); + + // prepend data object references to property names to avoid having to + // use a with-statement + iteratorOptions.forEach(function(property) { + snippet = snippet.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property); + }); + + // remove unnecessary code + snippet = snippet + .replace(/var __t.+/, "var __p = '';") + .replace(/function print[^}]+}/, '') + .replace(/'(?:\\n|\s)+'/g, "''") + .replace(/__p *\+= *' *';/g, '') + .replace(/(__p *\+= *)' *' *\+/g, '$1') + .replace(/(\{) *;|; *(\})/g, '$1$2') + .replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '$1'); + + // remove the with-statement + snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1'); + + // minor cleanup + snippet = snippet + .replace(/obj *\|\| *\(obj *= *\{}\);/, '') + .replace(/var __p = '';\s*__p \+=/, 'var __p ='); + + // remove comments, including sourceURLs + snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, ''); + + return '$1' + snippet + ';\n'; + }())); + } } /*------------------------------------------------------------------------*/ - if (isLegacy) { - _.each(['isBindFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'], function(varName) { - source = removeVar(source, varName); - }); + // customize Lo-Dash's IIFE + (function() { + if (typeof iife == 'string') { + var token = '%output%', + index = iife.indexOf(token); - _.each(['bind', 'isArray'], function(methodName) { - var snippet = matchFunction(source, methodName), - modified = snippet; - - // remove native `Function#bind` branch in `_.bind` - if (methodName == 'bind') { - modified = modified.replace(/(?:\s*\/\/.*)*\s*return isBindFast[^:]+:\s*/, 'return '); - } - // remove native `Array.isArray` branch in `_.isArray` - else { - modified = modified.replace(/nativeIsArray * \|\|/, ''); - } - source = source.replace(snippet, modified); - }); - - // replace `_.keys` with `shimKeys` - if (!isRemoved(source, 'keys')) { - source = source.replace( - matchFunction(source, 'keys').replace(/[\s\S]+?var keys *=/, ''), - matchFunction(source, 'shimKeys').replace(/[\s\S]+?var shimKeys *=/, '') - ); - - source = removeFunction(source, 'shimKeys'); + source = source.match(/\/\*![\s\S]+?\*\/\n/) + + iife.slice(0, index) + + source.replace(/^[^(]+?\(function[^{]+?{|}\(this\)\)[;\s]*$/g, '') + + iife.slice(index + token.length); } - // replace `_.isArguments` with fallback - if (!isRemoved(source, 'isArguments')) { - source = source.replace( - matchFunction(source, 'isArguments').replace(/[\s\S]+?function isArguments/, ''), - getIsArgumentsFallback(source).match(/isArguments *= *function([\s\S]+?) *};/)[1] + ' }\n' - ); - - source = removeIsArgumentsFallback(source); - } - - source = removeVar(source, 'reNative'); - source = removeFromCreateIterator(source, 'nativeKeys'); - } - - if (isMobile) { - // inline all functions defined with `createIterator` - _.functions(lodash).forEach(function(methodName) { - // match `methodName` with pseudo private `_` prefixes removed to allow matching `shimKeys` - var reFunc = RegExp('(\\bvar ' + methodName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n'); - - // skip if not defined with `createIterator` - if (!reFunc.test(source)) { - return; - } - // extract, format, and inject the compiled function's source code - source = source.replace(reFunc, '$1' + getFunctionSource(lodash[methodName]) + ';\n'); - }); - - // replace `callee` in `_.merge` with `merge` - source = source.replace(matchFunction(source, 'merge'), function(match) { - return match.replace(/\bcallee\b/g, 'merge'); - }); - - if (!isUnderscore) { - source = removeIsArgumentsFallback(source); - } - - // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment - source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, ''); - - // remove `iteratesOwnLast` from `isPlainObject` - source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, ''); - - // remove JScript [[DontEnum]] fix from `_.isEqual` - source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, ''); - - // remove `hasObjectSpliceBug` fix from the mutator Array functions mixin - source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, ''); - - // remove `noArraySliceOnStrings` from `_.toArray` - source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1'); - - // remove `noCharByIndex` from `_.reduceRight` - source = source.replace(/}\s*else if *\(noCharByIndex[^}]+/, ''); - - source = removeVar(source, 'extendIteratorOptions'); - source = removeVar(source, 'iteratorTemplate'); - source = removeVar(source, 'noArraySliceOnStrings'); - source = removeVar(source, 'noCharByIndex'); - source = removeNoArgsClass(source); - source = removeNoNodeClass(source); - } - else { - // inline `iteratorTemplate` template - source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() { - var snippet = getFunctionSource(lodash._iteratorTemplate); - - // prepend data object references to property names to avoid having to - // use a with-statement - iteratorOptions.forEach(function(property) { - snippet = snippet.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property); - }); - - // remove unnecessary code - snippet = snippet - .replace(/var __t.+/, "var __p = '';") - .replace(/function print[^}]+}/, '') - .replace(/'(?:\\n|\s)+'/g, "''") - .replace(/__p *\+= *' *';/g, '') - .replace(/(__p *\+= *)' *' *\+/g, '$1') - .replace(/(\{) *;|; *(\})/g, '$1$2') - .replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '$1'); - - // remove the with-statement - snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1'); - - // minor cleanup - snippet = snippet - .replace(/obj *\|\| *\(obj *= *\{}\);/, '') - .replace(/var __p = '';\s*__p \+=/, 'var __p ='); - - // remove comments, including sourceURLs - snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, ''); - - return '$1' + snippet + ';\n'; - }())); - } + }()); /*------------------------------------------------------------------------*/ @@ -1156,106 +1267,87 @@ /*------------------------------------------------------------------------*/ - // customize Lo-Dash's IIFE - (function() { - if (typeof iife == 'string') { - var token = '%output%', - index = iife.indexOf(token); - - source = source.match(/\/\*![\s\S]+?\*\/\n/) + - iife.slice(0, index) + - source.replace(/^[^(]+?\(function[^{]+?{|}\(this\)\)[;\s]*$/g, '') + - iife.slice(index + token.length); + if (isTemplate) { + debugSource = source; + } + else { + // modify/remove references to removed methods/variables + if (isRemoved(source, 'isArguments')) { + source = replaceVar(source, 'noArgsClass', 'false'); + } + if (isRemoved(source, 'isFunction')) { + source = removeIsFunctionFallback(source); + } + if (isRemoved(source, 'mixin')) { + // remove `LoDash` constructor + source = removeFunction(source, 'LoDash'); + // remove `LoDash` calls + source = source.replace(/(?:new +LoDash(?!\()|(?:new +)?LoDash\([^)]*\));?/g, ''); + // remove `LoDash.prototype` additions + source = source.replace(/(?:\s*\/\/.*)*\s*LoDash.prototype *=[\s\S]+?\/\*-+\*\//, ''); + // remove `hasObjectSpliceBug` assignment + source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasObjectSpliceBug;|.+?hasObjectSpliceBug *=.+/g, ''); } - }()); - /*------------------------------------------------------------------------*/ + // remove pseudo private properties + source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n'); - // modify/remove references to removed methods/variables - if (isRemoved(source, 'isArguments')) { - source = replaceVar(source, 'noArgsClass', 'false'); - } - if (isRemoved(source, 'isFunction')) { - source = removeIsFunctionFallback(source); - } - if (isRemoved(source, 'mixin')) { - // remove `LoDash` constructor - source = removeFunction(source, 'LoDash'); - // remove `LoDash` calls - source = source.replace(/(?:new +LoDash(?!\()|(?:new +)?LoDash\([^)]*\));?/g, ''); - // remove `LoDash.prototype` additions - source = source.replace(/(?:\s*\/\/.*)*\s*LoDash.prototype *=[\s\S]+?\/\*-+\*\//, ''); - // remove `hasObjectSpliceBug` assignment - source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasObjectSpliceBug;|.+?hasObjectSpliceBug *=.+/g, ''); - } + // assign debug source before further modifications that rely on the minifier + // to remove unused variables and other dead code + debugSource = source; - // remove pseudo private properties - source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n'); - - // assign debug source before further modifications that rely on the minifier - // to remove unused variables and other dead code - debugSource = source; - - // remove associated functions, variables, and code snippets that the minifier may miss - if (isRemoved(source, 'clone')) { - source = removeVar(source, 'cloneableClasses'); + // remove associated functions, variables, and code snippets that the minifier may miss + if (isRemoved(source, 'clone')) { + source = removeVar(source, 'cloneableClasses'); + } + if (isRemoved(source, 'isArray')) { + source = removeVar(source, 'nativeIsArray'); + } + if (isRemoved(source, 'keys')) { + source = removeFunction(source, 'shimKeys'); + } + if (isRemoved(source, 'template')) { + // remove `templateSettings` assignment + source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, ''); + } + if (isRemoved(source, 'toArray')) { + source = removeVar(source, 'noArraySliceOnStrings'); + } + if (isRemoved(source, 'clone', 'isArguments', 'isEmpty', 'isEqual')) { + source = removeNoArgsClass(source); + } + if (isRemoved(source, 'isEqual', 'isPlainObject')) { + source = removeNoNodeClass(source); + } + if ((source.match(/\bcreateIterator\b/g) || []).length < 2) { + source = removeFunction(source, 'createIterator'); + source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var noArgsEnum;|.+?noArgsEnum *=.+/g, ''); + } + if (isRemoved(source, 'createIterator', 'bind')) { + source = removeVar(source, 'isBindFast'); + source = removeVar(source, 'isStrictFast'); + source = removeVar(source, 'nativeBind'); + } + if (isRemoved(source, 'createIterator', 'bind', 'isArray', 'keys')) { + source = removeVar(source, 'reNative'); + } + if (isRemoved(source, 'createIterator', 'isEmpty', 'isEqual')) { + source = removeVar(source, 'arrayLikeClasses'); + } + if (isRemoved(source, 'createIterator', 'isEqual')) { + source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug;|.+?hasDontEnumBug *=.+/g, ''); + } + if (isRemoved(source, 'createIterator', 'isPlainObject')) { + source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, ''); + } + if (isRemoved(source, 'createIterator', 'keys')) { + source = removeVar(source, 'nativeKeys'); + } + if (!source.match(/var (?:hasDontEnumBug|hasObjectSpliceBug|iteratesOwnLast|noArgsEnum)\b/g)) { + // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, and `noArgsEnum` assignment + source = source.replace(/ *\(function\(\) *{[\s\S]+?}\(1\)\);/, ''); + } } - if (isRemoved(source, 'isArray')) { - source = removeVar(source, 'nativeIsArray'); - } - if (isRemoved(source, 'keys')) { - source = removeFunction(source, 'shimKeys'); - } - if (isRemoved(source, 'template')) { - // remove `templateSettings` assignment - source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, ''); - } - if (isRemoved(source, 'toArray')) { - source = removeVar(source, 'noArraySliceOnStrings'); - } - if (isUnderscore - ? isRemoved(source, 'merge') - : isRemoved(source, 'clone', 'merge') - ) { - source = removeFunction(source, 'isPlainObject'); - } - if (isRemoved(source, 'clone', 'isArguments', 'isEmpty', 'isEqual')) { - source = removeNoArgsClass(source); - } - if (isRemoved(source, 'isEqual', 'isPlainObject')) { - source = removeNoNodeClass(source); - } - if ((source.match(/\bcreateIterator\b/g) || []).length < 2) { - source = removeFunction(source, 'createIterator'); - source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var noArgsEnum;|.+?noArgsEnum *=.+/g, ''); - } - if (isRemoved(source, 'createIterator', 'bind')) { - source = removeVar(source, 'isBindFast'); - source = removeVar(source, 'isStrictFast'); - source = removeVar(source, 'nativeBind'); - } - if (isRemoved(source, 'createIterator', 'bind', 'isArray', 'keys')) { - source = removeVar(source, 'reNative'); - } - if (isRemoved(source, 'createIterator', 'isEmpty', 'isEqual')) { - source = removeVar(source, 'arrayLikeClasses'); - } - if (isRemoved(source, 'createIterator', 'isEqual')) { - source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug;|.+?hasDontEnumBug *=.+/g, ''); - } - if (isRemoved(source, 'createIterator', 'isPlainObject')) { - source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, ''); - } - if (isRemoved(source, 'createIterator', 'keys')) { - source = removeVar(source, 'nativeKeys'); - } - if (!source.match(/var (?:hasDontEnumBug|hasObjectSpliceBug|iteratesOwnLast|noArgsEnum)\b/g)) { - // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, and `noArgsEnum` assignment - source = source.replace(/ *\(function\(\) *{[\s\S]+?}\(1\)\);/, ''); - } - - debugSource = cleanupSource(debugSource); - source = cleanupSource(source); /*------------------------------------------------------------------------*/ @@ -1265,35 +1357,43 @@ !_.isEqual(exportsOptions, exportsAll); // used to name temporary files created in `dist/` - var workingName = 'lodash' + (isCustom ? '.custom' : '') + '.min'; + var workingName = 'lodash' + (isTemplate ? '.template' : isCustom ? '.custom' : ''); // restore `dependencyMap` dependencyMap = dependencyBackup; // output debug build - if (isCustom && !outputPath && !isStdOut) { - callback(debugSource, path.join(cwd, 'lodash.custom.js')); + if (!isMinify && (isCustom || isTemplate)) { + if (isDebug && isStdOut) { + stdout.write(debugSource); + callback(debugSource); + } else if (!isStdOut) { + callback(debugSource, (isDebug && outputPath) || path.join(cwd, workingName + '.js')); + } } // begin the minification process - minify(source, { - 'silent': isSilent, - 'workingName': workingName, - 'onComplete': function(source) { - // correct overly aggressive Closure Compiler minification - source = source.replace(/prototype\s*=\s*{\s*valueOf\s*:\s*1\s*}/, 'prototype={valueOf:1,y:1}'); + if (!isDebug) { + workingName += '.min'; + minify(source, { + 'silent': isSilent, + 'workingName': workingName, + 'onComplete': function(source) { + // correct overly aggressive Closure Compiler minification + source = source.replace(/prototype\s*=\s*{\s*valueOf\s*:\s*1\s*}/, 'prototype={valueOf:1,y:1}'); - // inject "use strict" directive - if (isStrict) { - source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2'); + // inject "use strict" directive + if (isStrict) { + source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2'); + } + if (isStdOut) { + stdout.write(source); + callback(source); + } else { + callback(source, outputPath || path.join(cwd, workingName + '.js')); + } } - if (isStdOut) { - stdout.write(source); - callback(source); - } else { - callback(source, outputPath || path.join(cwd, workingName + '.js')); - } - } - }); + }); + } } /*--------------------------------------------------------------------------*/ diff --git a/build/pre-compile.js b/build/pre-compile.js index 7b2c582ed..4037e1fd2 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -175,6 +175,7 @@ 'isNull', 'isNumber', 'isObject', + 'isPlainObject', 'isRegExp', 'isString', 'isUndefined', @@ -217,6 +218,7 @@ 'take', 'tap', 'template', + 'templates', 'templateSettings', 'throttle', 'times', diff --git a/test/index.html b/test/index.html index 3b75bb9e2..278db46d8 100644 --- a/test/index.html +++ b/test/index.html @@ -62,7 +62,7 @@ } }, ['lodash', 'shimmed', 'underscore'], function(lodash, shimmed, underscore) { - if (lodash.noConflict) { + if (lodash && lodash.noConflict) { lodashModule = lodash.noConflict(); lodashModule.moduleName = 'lodash'; } @@ -70,7 +70,7 @@ shimmedModule = shimmed.noConflict(); shimmedModule.moduleName = 'shimmed'; } - if (underscore.noConflict) { + if (underscore && underscore.noConflict) { underscoreModule = underscore.noConflict(); underscoreModule.moduleName = 'underscore'; } diff --git a/test/test-build.js b/test/test-build.js index 1b54c5947..d35fcb737 100644 --- a/test/test-build.js +++ b/test/test-build.js @@ -165,6 +165,7 @@ 'isNull', 'isNumber', 'isObject', + 'isPlainObject', 'isRegExp', 'isString', 'isUndefined', @@ -238,19 +239,12 @@ /** List of methods used by Underscore */ var underscoreMethods = _.without.apply(_, [allMethods].concat([ - 'countBy', 'forIn', 'forOwn', - 'invert', + 'isPlainObject', 'lateBind', 'merge', - 'object', - 'omit', - 'pairs', - 'partial', - 'random', - 'unescape', - 'where' + 'partial' ])); /*--------------------------------------------------------------------------*/ @@ -654,7 +648,7 @@ asyncTest('`lodash ' + command +'`', function() { build(['-s'].concat(command.split(' ')), function(source, filepath) { - equal(filepath, 'a.js', command); + equal(path.basename(filepath), 'a.js', command); start(); }); }); @@ -670,7 +664,7 @@ var start = _.once(QUnit.start); asyncTest('`lodash ' + command +'`', function() { - build([command, 'exports=', 'include='], function(source, filepath) { + build([command, 'exports=', 'include='], function(source) { equal(source, ''); equal(arguments.length, 1); start(); diff --git a/vendor/underscore/underscore-min.js b/vendor/underscore/underscore-min.js index 6596e3d3a..eecb3bd01 100644 --- a/vendor/underscore/underscore-min.js +++ b/vendor/underscore/underscore-min.js @@ -12,4 +12,4 @@ // Oliver Steele's Functional, and John Resig's Micro-Templating. // For all details and documentation: // http://documentcloud.github.com/underscore -(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=r.unshift,l=i.toString,c=i.hasOwnProperty,h=r.forEach,p=r.map,d=r.reduce,v=r.reduceRight,m=r.filter,g=r.every,y=r.some,b=r.indexOf,w=r.lastIndexOf,E=Array.isArray,S=Object.keys,x=s.bind,T=function(e){if(e instanceof T)return e;if(!(this instanceof T))return new T(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=T),exports._=T):e._=T,T.VERSION="1.3.3";var N=T.each=T.forEach=function(e,t,r){if(e==null)return;if(h&&e.forEach===h)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i2;e==null&&(e=[]);if(!C&&d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){C&&(s=C.keys[s],o=C.list),i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=T.toArray(e).reverse();r&&!i&&(t=T.bind(t,r)),C={keys:T.keys(e).reverse(),list:e};var o=i?T.reduce(s,t,n,r):T.reduce(s,t);return C=null,o},T.find=T.detect=function(e,t,n){var r;return k(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return e==null?r:m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return e==null?r:(N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return e==null?i:g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var k=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return e==null?i:y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return e==null?n:b&&e.indexOf===b?e.indexOf(t)!=-1:(n=k(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;or||n===void 0)return 1;if(n>>1;n.call(r,e[u])=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var _=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=_(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&_(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return _(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r":">",'"':""","'":"'","/":"/"}};D.unescape=T.invert(D.escape);var P={escape:new RegExp("["+T.keys(D.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(D.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(P[e],function(t){return D[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),I.call(this,n.apply(T,e))}})};var H=0;T.uniqueId=function(e){var t=H++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var B=/(.)^/,j={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},F=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||B).source,(n.interpolate||B).source,(n.evaluate||B).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(F,function(e){return"\\"+j[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var I=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],I.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return I.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file +(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=r.unshift,l=i.toString,c=i.hasOwnProperty,h=r.forEach,p=r.map,d=r.reduce,v=r.reduceRight,m=r.filter,g=r.every,y=r.some,b=r.indexOf,w=r.lastIndexOf,E=Array.isArray,S=Object.keys,x=s.bind,T=function(e){if(e instanceof T)return e;if(!(this instanceof T))return new T(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=T),exports._=T):e._=T,T.VERSION="1.3.3";var N=T.each=T.forEach=function(e,t,r){if(e==null)return;if(h&&e.forEach===h)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i2;e==null&&(e=[]);if(d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=T.keys(e);s=o.length}N(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.find=T.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return e==null?r:m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return e==null?r:(N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return e==null?i:g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return e==null?i:y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return e==null?n:b&&e.indexOf===b?e.indexOf(t)!=-1:(n=C(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;or||n===void 0)return 1;if(n>>1;n.call(r,e[u])=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return M(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r":">",'"':""","'":"'","/":"/"}};_.unescape=T.invert(_.escape);var D={escape:new RegExp("["+T.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(_.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(T,e))}})};var P=0;T.uniqueId=function(e){var t=P++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(j,function(e){return"\\"+B[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var F=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file diff --git a/vendor/underscore/underscore.js b/vendor/underscore/underscore.js index 1ac8de132..023ff7eee 100644 --- a/vendor/underscore/underscore.js +++ b/vendor/underscore/underscore.js @@ -105,23 +105,16 @@ return results; }; - // Internal data flag for performing `reduceRight`. - var right = null; - // **Reduce** builds up a single result from a list of values, aka `inject`, // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if (obj == null) obj = []; - if (!right && nativeReduce && obj.reduce === nativeReduce) { + if (nativeReduce && obj.reduce === nativeReduce) { if (context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } each(obj, function(value, index, list) { - if (right) { - index = right.keys[index]; - list = right.list; - } if (!initial) { memo = value; initial = true; @@ -142,12 +135,22 @@ if (context) iterator = _.bind(iterator, context); return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } - var values = _.toArray(obj).reverse(); - if (context && !initial) iterator = _.bind(iterator, context); - right = {keys: _.keys(obj).reverse(), list: obj}; - var result = initial ? _.reduce(values, iterator, memo, context) : _.reduce(values, iterator); - right = null; - return result; + var length = obj.length; + if (length !== +length) { + var keys = _.keys(obj); + length = keys.length; + } + each(obj, function(value, index, list) { + index = keys ? keys[--length] : --length; + if (!initial) { + memo = obj[index]; + initial = true; + } else { + memo = iterator.call(context, memo, obj[index], index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; }; // Return the first value which passes a truth test. Aliased as `detect`.