Comparing version 0.7.0 to 0.8.0
1135
build.js
@@ -15,4 +15,10 @@ #!/usr/bin/env node | ||
/** Shortcut to native `Array.prototype` */ | ||
var ArrayProto = Array.prototype; | ||
/** Shortcut used to push arrays of values to an array */ | ||
var push = ArrayProto.push; | ||
/** Shortcut used to convert array-like objects to arrays */ | ||
var slice = [].slice; | ||
var slice = ArrayProto.slice; | ||
@@ -65,7 +71,7 @@ /** Shortcut to the `stdout` object */ | ||
'chain': ['mixin'], | ||
'clone': ['extend', 'forIn', 'forOwn', 'isArguments', 'isFunction'], | ||
'clone': ['extend', 'forOwn', 'isArguments', 'isPlainObject'], | ||
'compact': [], | ||
'compose': [], | ||
'contains': [], | ||
'countBy': [], | ||
'countBy': ['identity'], | ||
'debounce': [], | ||
@@ -80,10 +86,10 @@ 'defaults': ['isArguments'], | ||
'filter': ['identity'], | ||
'find': [], | ||
'find': ['identity'], | ||
'first': [], | ||
'flatten': ['isArray'], | ||
'forEach': [], | ||
'forIn': ['isArguments'], | ||
'forOwn': ['isArguments'], | ||
'forEach': ['identity'], | ||
'forIn': ['identity', 'isArguments'], | ||
'forOwn': ['identity', 'isArguments'], | ||
'functions': ['isArguments', 'isFunction'], | ||
'groupBy': [], | ||
'groupBy': ['identity'], | ||
'has': [], | ||
@@ -109,2 +115,3 @@ 'identity': [], | ||
'isObject': [], | ||
'isPlainObject': ['forIn', 'isArguments', 'isFunction'], | ||
'isRegExp': [], | ||
@@ -116,7 +123,8 @@ 'isString': [], | ||
'lastIndexOf': [], | ||
'lateBind': ['isFunction'], | ||
'map': ['identity'], | ||
'max': [], | ||
'max': ['identity'], | ||
'memoize': [], | ||
'merge': ['isArguments', 'isArray', 'forIn'], | ||
'min': [], | ||
'merge': ['isArray', 'isPlainObject'], | ||
'min': ['identity'], | ||
'mixin': ['forEach', 'functions'], | ||
@@ -128,3 +136,3 @@ 'noConflict': [], | ||
'pairs': [], | ||
'partial': [], | ||
'partial': ['isFunction'], | ||
'pick': [], | ||
@@ -134,4 +142,4 @@ 'pluck': [], | ||
'range': [], | ||
'reduce': [], | ||
'reduceRight': ['keys'], | ||
'reduce': ['identity'], | ||
'reduceRight': ['forEach', 'keys'], | ||
'reject': ['identity'], | ||
@@ -143,4 +151,4 @@ 'rest': [], | ||
'some': ['identity'], | ||
'sortBy': [], | ||
'sortedIndex': ['bind'], | ||
'sortBy': ['identity'], | ||
'sortedIndex': ['identity'], | ||
'tap': ['mixin'], | ||
@@ -170,3 +178,2 @@ 'template': ['escape'], | ||
'bottom', | ||
'exit', | ||
'firstArg', | ||
@@ -217,2 +224,3 @@ 'hasDontEnumBug', | ||
'lastIndexOf', | ||
'lateBind', | ||
'map', | ||
@@ -239,17 +247,11 @@ 'max', | ||
var underscoreMethods = _.without.apply(_, [allMethods].concat([ | ||
'countBy', | ||
'forIn', | ||
'forOwn', | ||
'invert', | ||
'isPlainObject', | ||
'lateBind', | ||
'merge', | ||
'object', | ||
'omit', | ||
'pairs', | ||
'partial', | ||
'random', | ||
'unescape', | ||
'where' | ||
'partial' | ||
])); | ||
/** List of ways to export the `LoDash` function */ | ||
/** List of ways to export the `lodash` function */ | ||
var exportsAll = [ | ||
@@ -265,2 +267,71 @@ 'amd', | ||
/** | ||
* Compiles template files matched by the given file path `pattern` into a | ||
* single source, extending `_.templates` with precompiled templates named after | ||
* each template file's basename. | ||
* | ||
* @private | ||
* @param {String} [pattern='<cwd>/*.jst'] The file path pattern. | ||
* @param {Object} [options=_.templateSettings] The options object. | ||
* @returns {String} Returns the compiled source. | ||
*/ | ||
function buildTemplate(pattern, options) { | ||
pattern || (pattern = path.join(cwd, '*.jst')); | ||
options || (options = _.templateSettings); | ||
var directory = path.dirname(pattern); | ||
var moduleName = 'lodash'; | ||
var source = [ | ||
';(function(window) {', | ||
" var freeExports = typeof exports == 'object' && exports &&", | ||
" (typeof global == 'object' && global && global == global.global && (window = global), exports);", | ||
'', | ||
' var templates = {};', | ||
'', | ||
' var _ = window._;', | ||
'' | ||
]; | ||
// convert to a regexp | ||
pattern = RegExp( | ||
path.basename(pattern) | ||
.replace(/[.+?^=!:${}()|[\]\/\\]/g, '\\$&') | ||
.replace(/\*/g, '.*?') + '$' | ||
); | ||
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, options)), | ||
prop = filename.replace(/\..*$/, ''); | ||
source.push(" templates['" + prop + "'] = " + precompiled + ';'); | ||
} | ||
}); | ||
source.push( | ||
'', | ||
" if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {", | ||
" define(['" + moduleName + "'], function(lodash) {", | ||
' _ = lodash;', | ||
' _.templates = _.extend(_.templates || {}, templates);', | ||
' });', | ||
" } else if (freeExports) {", | ||
" if (typeof module == 'object' && module && module.exports == freeExports) {", | ||
' (module.exports = templates).templates = templates;', | ||
' } else {', | ||
' freeExports.templates = templates;', | ||
' }', | ||
' } else if (_) {', | ||
' _.templates = _.extend(_.templates || {}, templates);', | ||
' }', | ||
'}(this));' | ||
); | ||
return source.join('\n'); | ||
} | ||
/** | ||
* Removes unnecessary comments, whitespace, and pseudo private properties. | ||
@@ -299,19 +370,27 @@ * | ||
' lodash strict Build with `_.bindAll`, `_.defaults`, & `_.extend` in strict mode', | ||
' lodash underscore Build with iteration fixes removed and only Underscore’s API', | ||
' lodash exclude=... Comma separated names of methods to exclude from the build', | ||
' lodash include=... Comma separated names of methods to include in the build', | ||
' lodash category=... Comma separated categories of methods to include in the build', | ||
' lodash underscore Build tailored for projects already using Underscore', | ||
' lodash include=... Comma separated method/category names to include in the build', | ||
' lodash minus=... Comma separated method/category names to remove from those included in the build', | ||
' lodash plus=... Comma separated method/category names to add to those included in the build', | ||
' lodash category=... Comma separated categories of methods 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', | ||
' 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)"`)', | ||
'', | ||
' All arguments, except `exclude` with `include` & `legacy` with `csp`/`mobile`,', | ||
' may be combined.', | ||
' 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}"`)', | ||
'', | ||
' 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.', | ||
'', | ||
' 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', | ||
@@ -407,13 +486,38 @@ ' -s, --silent Skip status updates normally logged to the console', | ||
/** | ||
* Gets the `_.isArguments` fallback snippet from `source`. | ||
* Gets the `_.isArguments` fallback from `source`. | ||
* | ||
* @private | ||
* @param {String} source The source to inspect. | ||
* @returns {String} Returns the `isArguments` fallback snippet. | ||
* @returns {String} Returns the `isArguments` fallback. | ||
*/ | ||
function getIsArgumentsFallback(source) { | ||
return (source.match(/(?:\s*\/\/.*)*\n( +)if *\(noArgsClass[\s\S]+?};\n\1}/) || [''])[0]; | ||
return (source.match(/(?:\s*\/\/.*)*\n( +)if *\(noArgsClass\)[\s\S]+?};\n\1}/) || [''])[0]; | ||
} | ||
/** | ||
* Gets the `_.isFunction` fallback from `source`. | ||
* | ||
* @private | ||
* @param {String} source The source to inspect. | ||
* @returns {String} Returns the `isFunction` fallback. | ||
*/ | ||
function getIsFunctionFallback(source) { | ||
return (source.match(/(?:\s*\/\/.*)*\n( +)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/) || [''])[0]; | ||
} | ||
/** | ||
* Gets the names of methods in `source` belonging to the given `category`. | ||
* | ||
* @private | ||
* @param {String} source The source to inspect. | ||
* @param {String} category The category to filter by. | ||
* @returns {Array} Returns a new array of method names belonging to the given category. | ||
*/ | ||
function getMethodsByCategory(source, category) { | ||
return allMethods.filter(function(methodName) { | ||
return category && RegExp('@category ' + category + '\\b').test(matchFunction(source, methodName)); | ||
}); | ||
} | ||
/** | ||
* Gets the real name, not alias, of a given method name. | ||
@@ -472,2 +576,37 @@ * | ||
/** | ||
* 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 value.match(/\w+=(.*)$/)[1].split(/, */); | ||
} | ||
/** | ||
* Converts a comma separated options string into an array containing | ||
* only real method names. | ||
* | ||
* @private | ||
* @param {String} source The source to inspect. | ||
* @param {String} value The option to convert. | ||
* @returns {Array} Returns the new converted array. | ||
*/ | ||
function optionToMethodsArray(source, value) { | ||
var methodNames = optionToArray(value); | ||
// convert categories to method names | ||
methodNames.forEach(function(category) { | ||
push.apply(methodNames, getMethodsByCategory(source, category)); | ||
}); | ||
// convert aliases to real method names | ||
methodNames = methodNames.map(getRealName); | ||
// remove nonexistent and duplicate method names | ||
return _.uniq(_.intersection(allMethods, methodNames)); | ||
} | ||
/** | ||
* Removes the all references to `refName` from `createIterator` in `source`. | ||
@@ -509,3 +648,3 @@ * | ||
// remove function | ||
source = source.replace(matchFunction(source, funcName), ''); | ||
source = source.replace(snippet, ''); | ||
@@ -545,3 +684,3 @@ // grab the method assignments snippet | ||
function removeIsFunctionFallback(source) { | ||
return source.replace(/(?:\s*\/\/.*)*\n( +)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/, ''); | ||
return source.replace(getIsFunctionFallback(source), ''); | ||
} | ||
@@ -559,3 +698,3 @@ | ||
// remove optimized branch in `iteratorTemplate` | ||
.replace(/(?: *\/\/.*\n)* *'( *)<% *if *\(isKeysFast[\s\S]+?'\1<% *} *else *\{ *%>.+\n([\s\S]+?) *'\1<% *} *%>.+/, '$2') | ||
.replace(/(?: *\/\/.*\n)* *'( *)<% *if *\(isKeysFast[\s\S]+?'\1<% *} *else *\{ *%>.+\n([\s\S]+?) *'\1<% *} *%>.+/, "'\\n' +\n$2") | ||
// remove `isKeysFast` from `beforeLoop.object` of `mapIteratorOptions` | ||
@@ -581,3 +720,3 @@ .replace(/=\s*'\s*\+\s*\(isKeysFast.+/, "= []'") | ||
// remove `noArgsClass` from `_.isEqual` | ||
.replace(/if *\(noArgsClass[^}]+?}\n/, ''); | ||
.replace(/if *\(noArgsClass[^}]+?}\n/, '\n'); | ||
} | ||
@@ -611,2 +750,6 @@ | ||
function removeVar(source, varName) { | ||
// simplify `arrayLikeClasses` and `cloneableClasses` | ||
if (/^(?:arrayLike|cloneable)Classes$/.test(varName)) { | ||
source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?(true;\\n)'), '$1$2'); | ||
} | ||
source = source.replace(RegExp( | ||
@@ -618,3 +761,3 @@ // begin non-capturing group | ||
// match a variable declaration that's not part of a declaration list | ||
'( +)var ' + varName + ' *= *(?:.+?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\1.+?;)\\n|' + | ||
'( +)var ' + varName + ' *= *(?:.+?(?:;|&&\\n[^;]+;)|(?:\\w+\\(|{)[\\s\\S]+?\\n\\1.+?;)\\n|' + | ||
// match a variable in a declaration list | ||
@@ -649,3 +792,3 @@ '\\n +' + varName + ' *=.+?,' + | ||
// replace a variable that's not part of a declaration list | ||
source = source.replace(RegExp( | ||
var result = source.replace(RegExp( | ||
'(( +)var ' + varName + ' *= *)' + | ||
@@ -655,9 +798,11 @@ '(?:.+?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\2.+?;)\\n' | ||
// replace a varaible at the start or middle of a declaration list | ||
source = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), '$1 ' + varValue + ','); | ||
// replace a variable at the end of a variable declaration list | ||
source = source.replace(RegExp('(,\\s*' + varName + ' *=).+?;'), '$1 ' + varValue + ';'); | ||
return source; | ||
if (source == result) { | ||
// replace a varaible at the start or middle of a declaration list | ||
result = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), '$1 ' + varValue + ','); | ||
} | ||
if (source == result) { | ||
// replace a variable at the end of a variable declaration list | ||
result = source.replace(RegExp('(,\\s*' + varName + ' *=).+?;'), '$1 ' + varValue + ';'); | ||
} | ||
return result; | ||
} | ||
@@ -690,5 +835,5 @@ | ||
* Creates a debug and minified build, executing the `callback` for each. | ||
* The `callback` is invoked with 2 arguments; (filepath, source) | ||
* The `callback` is invoked with 2 arguments; (filePath, source) | ||
* | ||
* @param {Array} options The options array. | ||
* @param {Array} [options=[]] An array of commands. | ||
* @param {Function} callback The function called per build. | ||
@@ -705,3 +850,3 @@ */ | ||
if (/^(?:-o|--output)$/.test(options[index - 1]) || | ||
/^(?:category|exclude|exports|iife|include)=.*$/.test(value)) { | ||
/^(?:category|exclude|exports|iife|include|minus|plus|settings|template)=.*$/.test(value)) { | ||
return true; | ||
@@ -717,3 +862,5 @@ } | ||
'-c', '--stdout', | ||
'-d', '--debug', | ||
'-h', '--help', | ||
'-m', '--minify', | ||
'-o', '--output', | ||
@@ -754,6 +901,11 @@ '-s', '--silent', | ||
// collections of method names to exclude or include | ||
var excludeMethods = [], | ||
includeMethods = []; | ||
// backup `dependencyMap` to restore later | ||
var dependencyBackup = _.clone(dependencyMap, true); | ||
// used to specify a custom IIFE to wrap Lo-Dash | ||
var iife = options.reduce(function(result, value) { | ||
var match = value.match(/iife=(.*)/); | ||
return match ? match[1] : result; | ||
}, null); | ||
// flag used to specify a Backbone build | ||
@@ -765,2 +917,5 @@ var isBackbone = options.indexOf('backbone') > -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 | ||
@@ -772,2 +927,5 @@ var isLegacy = options.indexOf('legacy') > -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 | ||
@@ -786,45 +944,108 @@ var isMobile = !isLegacy && (isCSP || isUnderscore || options.indexOf('mobile') > -1); | ||
// flag used to specify if the build should include the "use strict" directive | ||
var useStrict = isStrict || !(isLegacy || isMobile); | ||
// used to specify the ways to export the `lodash` function | ||
var exportsOptions = options.reduce(function(result, value) { | ||
return /exports/.test(value) ? optionToArray(value).sort() : result; | ||
}, isUnderscore | ||
? ['commonjs', 'global', 'node'] | ||
: exportsAll.slice() | ||
); | ||
// used to specify the output path for builds | ||
var outputPath = options.reduce(function(result, value, index) { | ||
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 precompile | ||
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 precompiling template files | ||
var templateSettings = options.reduce(function(result, value) { | ||
var match = value.match(/settings=(.+)$/); | ||
return match | ||
? Function('return {' + match[1].replace(/^{|}$/g, '') + '}')() | ||
: 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'); | ||
// used to specify the ways to export the `LoDash` function | ||
var exportsOptions = options.reduce(function(result, value) { | ||
var match = value.match(/^exports=(.*)$/); | ||
if (!match) { | ||
return result; | ||
} | ||
return match[1].split(/, */).sort(); | ||
}, exportsAll.slice()); | ||
// flag used to specify if the build should include the "use strict" directive | ||
var useStrict = isStrict || !(isLegacy || isMobile); | ||
// used to specify whether filtering is for exclusion or inclusion | ||
var filterType = options.reduce(function(result, value) { | ||
if (result) { | ||
return result; | ||
/*------------------------------------------------------------------------*/ | ||
// names of methods to include in the build | ||
var buildMethods = !isTemplate && (function() { | ||
var result; | ||
var minusMethods = options.reduce(function(accumulator, value) { | ||
return /exclude|minus/.test(value) | ||
? _.union(accumulator, optionToMethodsArray(source, value)) | ||
: accumulator; | ||
}, []); | ||
var plusMethods = options.reduce(function(accumulator, value) { | ||
return /plus/.test(value) | ||
? _.union(accumulator, optionToMethodsArray(source, value)) | ||
: accumulator; | ||
}, []); | ||
// add method names explicitly | ||
options.some(function(value) { | ||
return /include/.test(value) && | ||
(result = getDependencies(optionToMethodsArray(source, value))); | ||
}); | ||
// add method names required by Backbone and Underscore builds | ||
if (isBackbone && !result) { | ||
result = getDependencies(backboneDependencies); | ||
} | ||
var pair = value.match(/^(exclude|include)=(.*)$/); | ||
if (!pair) { | ||
return result; | ||
if (isUnderscore && !result) { | ||
result = getDependencies(underscoreMethods); | ||
} | ||
// remove nonexistent method names | ||
var methodNames = _.intersection(allMethods, pair[2].split(/, */).map(getRealName)); | ||
if (pair[1] == 'exclude') { | ||
excludeMethods = methodNames; | ||
} else { | ||
includeMethods = methodNames; | ||
// 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(); | ||
} | ||
// return `filterType` | ||
return pair[1]; | ||
}, ''); | ||
// 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]; | ||
}, ''); | ||
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({ | ||
@@ -845,3 +1066,3 @@ 'clearTimeout': clearTimeout, | ||
if (isLegacy) { | ||
['isBindFast', 'isKeysFast', 'isStrictFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'].forEach(function(varName) { | ||
_.each(['isBindFast', 'isKeysFast', 'isStrictFast', 'nativeBind', 'nativeGetPrototypeOf', 'nativeIsArray', 'nativeKeys'], function(varName) { | ||
source = replaceVar(source, varName, 'false'); | ||
@@ -854,24 +1075,51 @@ }); | ||
else if (isUnderscore) { | ||
// update dependencies | ||
dependencyMap.clone = ['extend', 'isArray']; | ||
dependencyMap.isEqual = ['isArray', 'isFunction']; | ||
dependencyMap.isEmpty = ['isArray']; | ||
// remove unneeded variables | ||
source = removeVar(source, 'arrayLikeClasses'); | ||
source = removeVar(source, 'cloneableClasses'); | ||
// remove large array optimizations from `cachedContains` | ||
source = source.replace(/( +)function cachedContains[\s\S]+?\n\1}/, [ | ||
' function cachedContains(array, fromIndex) {', | ||
' return function(value) {', | ||
' return indexOf(array, value, fromIndex || 0) > -1;', | ||
' };', | ||
' }' | ||
].join('\n')); | ||
// reduce the number of arguments passed to `cachedContains` from 3 to 2 | ||
source = source.replace(/(cachedContains\(\w+, *\w+), *\w+/g, '$1'); | ||
// replace `arrayLikeClasses` in `_.isEmpty` | ||
source = source.replace(/'if *\(arrayLikeClasses[\s\S]+?' \|\|\\n/, "'if (isArray(value) || className == stringClass ||"); | ||
// replace `arrayLikeClasses` in `_.isEqual` | ||
source = source.replace(/(?: *\/\/.*\n)*( +)var isArr *= *arrayLikeClasses[^}]+}/, '$1var isArr = isArray(a);'); | ||
// remove "exit early" feature from `_.each` | ||
source = source.replace(/( )+var baseIteratorOptions *=[\s\S]+?\n\1.+?;/, function(match) { | ||
return match.replace(/if *\(callback[^']+/, 'callback(value, index, collection)'); | ||
}); | ||
// remove `deep` clone functionality | ||
source = source.replace(/( +)function clone[\s\S]+?\n\1}/, [ | ||
' function clone(value) {', | ||
' if (value == null) {', | ||
' return value;', | ||
' }', | ||
' var isObj = objectTypes[typeof value];', | ||
' if (isObj && value.clone && isFunction(value.clone)) {', | ||
' return value.clone(deep);', | ||
' }', | ||
' if (isObj) {', | ||
' var className = toString.call(value);', | ||
' if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) {', | ||
' return value;', | ||
' }', | ||
' var isArr = className == arrayClass;', | ||
' }', | ||
' return isObj', | ||
' ? (isArr ? slice.call(value) : extend({}, value))', | ||
' : value;', | ||
' return value && objectTypes[typeof value]', | ||
' ? (isArray(value) ? slice.call(value) : extend({}, value))', | ||
' : value', | ||
' }' | ||
].join('\n')); | ||
// remove unused features from `createBound` | ||
if (buildMethods.indexOf('partial') == -1) { | ||
source = source.replace(matchFunction(source, 'createBound'), function(match) { | ||
return match | ||
.replace(/(function createBound\([^{]+{)[\s\S]+?(\n *function bound)/, '$1$2') | ||
.replace(/thisBinding *=[^}]+}/, 'thisBinding = thisArg;\n'); | ||
}); | ||
} | ||
} | ||
@@ -882,5 +1130,2 @@ if (isMobile) { | ||
// remove Opera 10.53-10.60 JIT fixes | ||
source = source.replace(/length *> *-1 *&& *length/g, 'length'); | ||
// remove `prototype` [[Enumerable]] fix from `_.keys` | ||
@@ -891,3 +1136,3 @@ source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(.+?propertyIsEnumerable[\s\S]+?\n\1}/, ''); | ||
source = source | ||
.replace(/(?: *\/\/.*\n)*\s*' *(?:<% *)?if *\(!hasDontEnumBug *(?:&&|\))[\s\S]+?<% *} *(?:%>|').+/g, '') | ||
.replace(/(?: *\/\/.*\n)* *' *(?:<% *)?if *\(!hasDontEnumBug *(?:&&|\))[\s\S]+?<% *} *(?:%>|').+/g, '') | ||
.replace(/!hasDontEnumBug *\|\|/g, ''); | ||
@@ -901,330 +1146,178 @@ } | ||
// customize for Backbone and Underscore builds | ||
if (isUnderscore) { | ||
// don't expose `_.forIn` or `_.forOwn` if `isUnderscore` is `true` unless | ||
// requested by `include` | ||
if (includeMethods.indexOf('forIn') == -1) { | ||
source = source.replace(/ *lodash\.forIn *=.+\n/, ''); | ||
} | ||
if (includeMethods.indexOf('forOwn') == -1) { | ||
source = source.replace(/ *lodash\.forOwn *=.+\n/, ''); | ||
} | ||
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" | ||
); | ||
// include methods required by Backbone and Underscore builds | ||
[ | ||
{ 'flag': isBackbone, 'methodNames': backboneDependencies }, | ||
{ 'flag': isUnderscore, 'methodNames': underscoreMethods } | ||
] | ||
.some(function(data) { | ||
var flag = data.flag, | ||
methodNames = data.methodNames; | ||
source = source.replace( | ||
RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+" | ||
); | ||
if (!flag) { | ||
return false; | ||
} | ||
// add any additional sub-dependencies | ||
methodNames = getDependencies(methodNames); | ||
// remove methods from the build | ||
allMethods.forEach(function(otherName) { | ||
if (!_.contains(buildMethods, otherName)) { | ||
source = removeFunction(source, otherName); | ||
} | ||
}); | ||
if (filterType == 'exclude') { | ||
// remove excluded methods from `methodNames` | ||
includeMethods = _.without.apply(_, [methodNames].concat(excludeMethods)); | ||
// remove `isArguments` fallback before `isArguments` is transformed by | ||
// other parts of the build process | ||
if (isRemoved(source, 'isArguments')) { | ||
source = removeIsArgumentsFallback(source); | ||
} | ||
else if (filterType) { | ||
// merge `methodNames` into `includeMethods` | ||
includeMethods = _.union(includeMethods, methodNames); | ||
} | ||
else { | ||
// include only the `methodNames` | ||
includeMethods = methodNames; | ||
} | ||
filterType = 'include'; | ||
return true; | ||
}); | ||
/*------------------------------------------------------------------------*/ | ||
/*----------------------------------------------------------------------*/ | ||
// include methods by category | ||
options.some(function(value) { | ||
var categories = value.match(/^category=(.*)$/); | ||
if (!categories) { | ||
return false; | ||
} | ||
// resolve method names belonging to each category | ||
var categoryMethods = categories[1].split(/, */).reduce(function(result, category) { | ||
return result.concat(allMethods.filter(function(methodName) { | ||
return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, methodName)); | ||
})); | ||
}, []); | ||
if (isLegacy) { | ||
_.each(['isBindFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'], function(varName) { | ||
source = removeVar(source, varName); | ||
}); | ||
if (filterType == 'exclude') { | ||
// remove excluded methods from `categoryMethods` | ||
includeMethods = _.without.apply(_, [categoryMethods].concat(excludeMethods)); | ||
} | ||
else if (filterType) { | ||
// merge `categoryMethods` into `includeMethods` | ||
includeMethods = _.union(includeMethods, categoryMethods); | ||
} | ||
else { | ||
// include only the `categoryMethods` | ||
includeMethods = categoryMethods; | ||
} | ||
filterType = 'include'; | ||
return true; | ||
}); | ||
_.each(['bind', 'isArray'], function(methodName) { | ||
var snippet = matchFunction(source, methodName), | ||
modified = snippet; | ||
/*------------------------------------------------------------------------*/ | ||
// remove methods from the build | ||
(function() { | ||
// exit early if "exclude" or "include" options aren't specified | ||
if (!filterType) { | ||
return; | ||
} | ||
if (filterType == 'exclude') { | ||
// remove methods that are named in `excludeMethods` and their dependants | ||
excludeMethods.forEach(function(methodName) { | ||
getDependants(methodName).concat(methodName).forEach(function(otherName) { | ||
source = removeFunction(source, otherName); | ||
}); | ||
}); | ||
} | ||
else { | ||
// add dependencies to `includeMethods` | ||
includeMethods = getDependencies(includeMethods); | ||
// remove methods that aren't named in `includeMethods` | ||
allMethods.forEach(function(otherName) { | ||
if (!_.contains(includeMethods, otherName)) { | ||
source = removeFunction(source, otherName); | ||
// 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 *=/, '') | ||
); | ||
// 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'+" | ||
); | ||
// remove `isArguments` fallback before `isArguments` is transformed by | ||
// other parts of the build process | ||
if (isRemoved(source, 'isArguments')) { | ||
source = removeIsArgumentsFallback(source); | ||
} | ||
// DRY out isType functions | ||
(function() { | ||
var iteratorName = _.find(['forEach', 'forOwn'], function(methodName) { | ||
return !isRemoved(source, methodName); | ||
}); | ||
// skip this optimization if there are no iteration methods to use | ||
if (!iteratorName) { | ||
return; | ||
} | ||
var funcNames = [], | ||
objectSnippets = []; | ||
// build replacement code | ||
_.forOwn({ | ||
'Arguments': 'argsClass', | ||
'Date': 'dateClass', | ||
'Number': 'numberClass', | ||
'RegExp': 'regexpClass', | ||
'String': 'stringClass' | ||
}, | ||
function(value, key) { | ||
if (!isUnderscore && key == 'Arguments') { | ||
return; | ||
source = removeFunction(source, 'shimKeys'); | ||
} | ||
var funcName = 'is' + key, | ||
funcCode = matchFunction(source, funcName); | ||
// 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' | ||
); | ||
if (funcCode) { | ||
funcNames.push(funcName); | ||
objectSnippets.push("'" + key + "': " + value); | ||
source = removeIsArgumentsFallback(source); | ||
} | ||
}); | ||
// skip this optimization if there are less than 2 isType functions | ||
if (funcNames.length < 2) { | ||
return; | ||
source = removeVar(source, 'reNative'); | ||
source = removeFromCreateIterator(source, 'nativeKeys'); | ||
} | ||
// remove existing isType functions | ||
funcNames.forEach(function(funcName) { | ||
source = removeFunction(source, funcName); | ||
}); | ||
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'); | ||
// insert new DRY code after the method assignments | ||
var snippet = getMethodAssignments(source); | ||
source = source.replace(snippet, snippet + '\n' + | ||
' // add `_.' + funcNames.join('`, `_.') + '`\n' + | ||
' ' + iteratorName + '({\n ' + objectSnippets.join(',\n ') + '\n }, function(className, key) {\n' + | ||
" lodash['is' + key] = function(value) {\n" + | ||
' return toString.call(value) == className;\n' + | ||
' };\n' + | ||
' });\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 (isLegacy) { | ||
['isBindFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'].forEach(function(varName) { | ||
source = removeVar(source, varName); | ||
}); | ||
if (isUnderscore) { | ||
(function() { | ||
// replace `isArguments` and its fallback | ||
var snippet = matchFunction(source, 'isArguments') | ||
.replace(/function isArguments/, 'lodash.isArguments = function'); | ||
['bind', 'isArray'].forEach(function(methodName) { | ||
var snippet = matchFunction(source, methodName), | ||
modified = snippet; | ||
source = removeFunction(source, 'isArguments'); | ||
// remove native `Function#bind` branch in `_.bind` | ||
if (methodName == 'bind') { | ||
modified = modified.replace(/(?:\s*\/\/.*)*\s*else if *\(isBindFast[^}]+}/, ''); | ||
source = source.replace(getIsArgumentsFallback(source), function(match) { | ||
return snippet + '\n' + match | ||
.replace(/\bisArguments\b/g, 'lodash.$&') | ||
.replace(/\bnoArgsClass\b/g, '!lodash.isArguments(arguments)'); | ||
}); | ||
}()); | ||
} | ||
// remove native `Array.isArray` branch in `_.isArray` | ||
else { | ||
modified = modified.replace(/nativeIsArray * \|\|/, ''); | ||
source = removeIsArgumentsFallback(source); | ||
} | ||
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 *=/, '') | ||
); | ||
// remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment | ||
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, ''); | ||
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' | ||
); | ||
// remove `iteratesOwnLast` from `isPlainObject` | ||
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, ''); | ||
source = removeIsArgumentsFallback(source); | ||
} | ||
// remove JScript [[DontEnum]] fix from `_.isEqual` | ||
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, ''); | ||
source = removeVar(source, 'reNative'); | ||
source = removeFromCreateIterator(source, 'nativeKeys'); | ||
} | ||
// remove `hasObjectSpliceBug` fix from the mutator Array functions mixin | ||
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, ''); | ||
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'); | ||
// remove `noArraySliceOnStrings` from `_.toArray` | ||
source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1'); | ||
// 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'); | ||
}); | ||
// remove `noCharByIndex` from `_.reduceRight` | ||
source = source.replace(/}\s*else if *\(noCharByIndex[^}]+/, ''); | ||
// 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); | ||
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); | ||
// remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment | ||
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, ''); | ||
// 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 `iteratesOwnLast` from `isPlainObject` | ||
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, ''); | ||
// 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 JScript [[DontEnum]] fix from `_.isEqual` | ||
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, ''); | ||
// remove the with-statement | ||
snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1'); | ||
// remove `hasObjectSpliceBug` fix from the mutator Array functions mixin | ||
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, ''); | ||
// minor cleanup | ||
snippet = snippet | ||
.replace(/obj *\|\| *\(obj *= *\{}\);/, '') | ||
.replace(/var __p = '';\s*__p \+=/, 'var __p ='); | ||
// remove `noArraySliceOnStrings` from `_.toArray` | ||
source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1'); | ||
// remove comments, including sourceURLs | ||
snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, ''); | ||
// remove `noCharByIndex` from `_.reduceRight` | ||
source = source.replace(/noCharByIndex *&&[^:]+: *([^;]+)/g, '$1'); | ||
source = removeVar(source, 'extendIteratorOptions'); | ||
source = removeVar(source, 'iteratorTemplate'); | ||
source = removeVar(source, 'noArraySliceOnStrings'); | ||
source = removeVar(source, 'noCharByIndex'); | ||
source = removeNoNodeClass(source); | ||
return '$1' + snippet + ';\n'; | ||
}())); | ||
} | ||
} | ||
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'; | ||
}())); | ||
} | ||
/*------------------------------------------------------------------------*/ | ||
// customize Lo-Dash's export bootstrap | ||
if (exportsOptions.indexOf('amd') == -1) { | ||
source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +define[\s\S]+?else /, '$1'); | ||
} | ||
if (exportsOptions.indexOf('node') == -1) { | ||
source = source.replace(/(?: *\/\/.*\n)* *if *\(typeof +module[\s\S]+?else *{\n([\s\S]+?) *}\n/, '$1'); | ||
} | ||
if (exportsOptions.indexOf('commonjs') == -1) { | ||
source = source.replace(/(?: *\/\/.*\n)*(?:( +)else *{)?\s*freeExports\._ *=.+(\n\1})?\n/, ''); | ||
} | ||
if (exportsOptions.indexOf('global') == -1) { | ||
source = source.replace(/(?:( +)else *{)?(?:\s*\/\/.*)*\s*window\._ *= *lodash.+(\n\1})?\n/g, ''); | ||
} | ||
// remove `if (freeExports) {...}` if it's empty | ||
source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports\) *{\s*}(?:\s*else *{\n([\s\S]+?) *})?/, '$1'); | ||
/*------------------------------------------------------------------------*/ | ||
// customize Lo-Dash's IIFE | ||
(function() { | ||
if (iife) { | ||
if (typeof iife == 'string') { | ||
var token = '%output%', | ||
@@ -1235,3 +1328,3 @@ index = iife.indexOf(token); | ||
iife.slice(0, index) + | ||
source.replace(/^[^(]+?\(function[^{]+?{|}\(this\)\)[;\s]*$/g, '') + | ||
source.replace(/^[\s\S]+?\(function[^{]+?{|}\(this\)\)[;\s]*$/g, '') + | ||
iife.slice(index + token.length); | ||
@@ -1243,125 +1336,169 @@ } | ||
// modify/remove references to removed methods/variables | ||
if (isRemoved(source, 'isArguments')) { | ||
source = replaceVar(source, 'noArgsClass', 'false'); | ||
// customize Lo-Dash's export bootstrap | ||
(function() { | ||
var isAMD = exportsOptions.indexOf('amd') > -1, | ||
isCommonJS = exportsOptions.indexOf('commonjs') > -1, | ||
isGlobal = exportsOptions.indexOf('global') > -1, | ||
isNode = exportsOptions.indexOf('node') > -1; | ||
if (!isAMD) { | ||
source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +define[\s\S]+?else /, '$1'); | ||
} | ||
if (!isNode) { | ||
source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +module[\s\S]+?else *{([\s\S]+?\n)\1}\n/, '$1$2'); | ||
} | ||
if (!isCommonJS) { | ||
source = source.replace(/(?: *\/\/.*\n)*(?:( +)else *{)?\s*freeExports\.\w+ *=[\s\S]+?(?:\n\1})?\n/, ''); | ||
} | ||
if (!isGlobal) { | ||
source = source.replace(/(?:( +)(})? *else(?: *if *\(_\))? *{)?(?:\s*\/\/.*)*\s*(?:window\._|_\.templates) *=[\s\S]+?(?:\n\1})?\n/g, '$1$2\n'); | ||
} | ||
// remove `if (freeExports) {...}` if it's empty | ||
if (isAMD && isGlobal) { | ||
source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports\) *{\s*}\n/, ''); | ||
} else { | ||
source = source.replace(/(?: *\/\/.*\n)* *(?:else )?if *\(freeExports\) *{\s*}(?:\s*else *{([\s\S]+?) *})?\n/, '$1'); | ||
} | ||
if ((source.match(/\bfreeExports\b/g) || []).length < 2) { | ||
source = removeVar(source, 'freeExports'); | ||
} | ||
}()); | ||
/*------------------------------------------------------------------------*/ | ||
if (isTemplate) { | ||
debugSource = source; | ||
} | ||
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, ''); | ||
} | ||
else { | ||
// modify/remove references to removed methods/variables | ||
if (isRemoved(source, 'invert')) { | ||
source = replaceVar(source, 'htmlUnescapes', "{'&':'&','<':'<','>':'>','"':'\"',''':\"'\"}"); | ||
} | ||
if (isRemoved(source, 'isArguments')) { | ||
source = replaceVar(source, 'noArgsClass', 'false'); | ||
} | ||
if (isRemoved(source, 'isFunction')) { | ||
source = removeIsFunctionFallback(source); | ||
} | ||
if (isRemoved(source, 'mixin')) { | ||
// remove `lodash.prototype` additions | ||
source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\)[\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'); | ||
// 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; | ||
// 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 = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var cloneableClasses *=[\s\S]+?true;\n/g, ''); | ||
// 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, 'isPlainObject')) { | ||
source = removeVar(source, 'nativeGetPrototypeOf'); | ||
} | ||
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', 'isPlainObject', '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'); | ||
source = removeKeysOptimization(source); | ||
} | ||
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 = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var arrayLikeClasses *=[\s\S]+?true;\n/g, ''); | ||
} | ||
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); | ||
/*------------------------------------------------------------------------*/ | ||
// used to specify creating a custom build | ||
var isCustom = !_.isEqual(exportsOptions, exportsAll) || filterType || iife || isBackbone || isLegacy || isMobile || isStrict || isUnderscore; | ||
var isCustom = isBackbone || isLegacy || isMobile || isStrict || isUnderscore || | ||
/(?:category|exclude|exports|iife|include|minus|plus)=/.test(options) || | ||
!_.isEqual(exportsOptions, exportsAll); | ||
// 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); | ||
}, ''); | ||
// used as the basename of the output path | ||
var basename = outputPath | ||
? path.basename(outputPath, '.js') | ||
: 'lodash' + (isTemplate ? '.template' : isCustom ? '.custom' : ''); | ||
// used to name temporary files created in `dist/` | ||
var workingName = 'lodash' + (isCustom ? '.custom' : '') + '.min'; | ||
// restore `dependencyMap` | ||
dependencyMap = dependencyBackup; | ||
// output debug build | ||
if (isCustom && !outputPath && !isStdOut) { | ||
callback(debugSource, path.join(cwd, 'lodash.custom.js')); | ||
if (!isMinify && (isCustom || isDebug || isTemplate)) { | ||
if (isDebug && isStdOut) { | ||
stdout.write(debugSource); | ||
callback(debugSource); | ||
} else if (!isStdOut) { | ||
callback(debugSource, (isDebug && outputPath) || path.join(cwd, basename + '.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) { | ||
outputPath || (outputPath = path.join(cwd, basename + '.min.js')); | ||
// inject "use strict" directive | ||
if (isStrict) { | ||
source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2'); | ||
minify(source, { | ||
'isSilent': isSilent, | ||
'isTemplate': isTemplate, | ||
'outputPath': outputPath, | ||
'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'); | ||
} | ||
if (isStdOut) { | ||
stdout.write(source); | ||
callback(source); | ||
} else { | ||
callback(source, outputPath); | ||
} | ||
} | ||
if (isStdOut) { | ||
stdout.write(source); | ||
callback(source); | ||
} else { | ||
callback(source, outputPath || path.join(cwd, workingName + '.js')); | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -1377,6 +1514,6 @@ | ||
// or invoked directly | ||
build(process.argv, function(source, filepath) { | ||
filepath && fs.writeFileSync(filepath, source, 'utf8'); | ||
build(process.argv, function(source, filePath) { | ||
filePath && fs.writeFileSync(filePath, source, 'utf8'); | ||
}); | ||
} | ||
}()); |
@@ -12,3 +12,3 @@ #!/usr/bin/env node | ||
/** The directory that is the base of the repository */ | ||
var basePath = path.join(__dirname, '../'); | ||
var basePath = fs.realpathSync(path.join(__dirname, '..')); | ||
@@ -18,9 +18,6 @@ /** The directory where the Closure Compiler is located */ | ||
/** The distribution directory */ | ||
var distPath = path.join(basePath, 'dist'); | ||
/** Load other modules */ | ||
var preprocess = require(path.join(__dirname, 'pre-compile')), | ||
postprocess = require(path.join(__dirname, 'post-compile')), | ||
uglifyJS = require(path.join(basePath, 'vendor', 'uglifyjs', 'uglify-js')); | ||
var preprocess = require('./pre-compile'), | ||
postprocess = require('./post-compile'), | ||
uglifyJS = require('../vendor/uglifyjs/uglify-js'); | ||
@@ -42,27 +39,34 @@ /** Closure Compiler command-line options */ | ||
* | ||
* @param {Array|String} source The array of command-line arguments or the | ||
* source to minify. | ||
* @param {Object} options The options object containing `onComplete`, | ||
* `silent`, and `workingName`. | ||
* @param {Array|String} [source=''] The source to minify or array of commands. | ||
* @param {Object} [options={}] The options object. | ||
*/ | ||
function minify(source, options) { | ||
source || (source = ''); | ||
options || (options = {}); | ||
// juggle arguments | ||
if (Array.isArray(source)) { | ||
// convert the command-line arguments to an options object | ||
// convert commands to an options object | ||
options = source; | ||
var filePath = options[options.length - 1], | ||
dirPath = path.dirname(filePath), | ||
workingName = path.basename(filePath, '.js') + '.min', | ||
outputPath = path.join(dirPath, workingName + '.js'), | ||
isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1; | ||
isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1, | ||
isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1, | ||
outputPath = path.join(path.dirname(filePath), path.basename(filePath, '.js') + '.min.js'); | ||
source = fs.readFileSync(filePath, 'utf8'); | ||
outputPath = options.reduce(function(result, value, index) { | ||
if (/-o|--output/.test(value)) { | ||
result = options[index + 1]; | ||
result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result)); | ||
} | ||
return result; | ||
}, outputPath); | ||
options = { | ||
'silent': isSilent, | ||
'workingName': workingName, | ||
'onComplete': function(source) { | ||
fs.writeFileSync(outputPath, source, 'utf8'); | ||
} | ||
'isSilent': isSilent, | ||
'isTemplate': isTemplate, | ||
'outputPath': outputPath | ||
}; | ||
source = fs.readFileSync(filePath, 'utf8'); | ||
} | ||
@@ -78,31 +82,24 @@ new Minify(source, options); | ||
* @param {String} source The source to minify. | ||
* @param {Object} options The options object containing `onComplete`, | ||
* `silent`, and `workingName`. | ||
* @param {Object} options The options object. | ||
*/ | ||
function Minify(source, options) { | ||
source || (source = ''); | ||
options || (options = {}); | ||
if (typeof source != 'string') { | ||
// juggle arguments | ||
if (typeof source == 'object' && source) { | ||
options = source || options; | ||
source = options.source || ''; | ||
} | ||
// create the destination directory if it doesn't exist | ||
if (!fs.existsSync(distPath)) { | ||
// avoid errors when called as a npm executable | ||
try { | ||
fs.mkdirSync(distPath); | ||
} catch(e) { } | ||
} | ||
this.compiled = {}; | ||
this.hybrid = {}; | ||
this.uglified = {}; | ||
this.isSilent = !!options.silent; | ||
this.onComplete = options.onComplete || function() {}; | ||
this.workingName = options.workingName || 'temp'; | ||
this.isSilent = !!options.isSilent; | ||
this.isTemplate = !!options.isTemplate; | ||
this.outputPath = options.outputPath; | ||
source = preprocess(source); | ||
source = preprocess(source, options); | ||
this.source = source; | ||
this.onComplete = options.onComplete || function(source) { | ||
fs.writeFileSync(this.outputPath, source, 'utf8'); | ||
}; | ||
// begin the minification process | ||
@@ -124,6 +121,15 @@ closureCompile.call(this, source, onClosureCompile.bind(this)); | ||
function closureCompile(source, message, callback) { | ||
var options = closureOptions.slice(); | ||
// use simple optimizations when minifying template files | ||
if (this.isTemplate) { | ||
options = options.map(function(value) { | ||
return value.replace(/^(compilation_level)=.+$/, '$1=SIMPLE_OPTIMIZATIONS'); | ||
}); | ||
} | ||
// the standard error stream, standard output stream, and Closure Compiler process | ||
var error = '', | ||
output = '', | ||
compiler = spawn('java', ['-jar', closurePath].concat(closureOptions)); | ||
compiler = spawn('java', ['-jar', closurePath].concat(options)); | ||
@@ -138,3 +144,3 @@ // juggle arguments | ||
console.log(message == null | ||
? 'Compressing ' + this.workingName + ' using the Closure Compiler...' | ||
? 'Compressing ' + path.basename(this.outputPath, '.js') + ' using the Closure Compiler...' | ||
: message | ||
@@ -192,3 +198,3 @@ ); | ||
console.log(message == null | ||
? 'Compressing ' + this.workingName + ' using UglifyJS...' | ||
? 'Compressing ' + path.basename(this.outputPath, '.js') + ' using UglifyJS...' | ||
: message | ||
@@ -288,3 +294,3 @@ ); | ||
} | ||
var message = 'Compressing ' + this.workingName + ' using hybrid minification...'; | ||
var message = 'Compressing ' + path.basename(this.outputPath, '.js') + ' using hybrid minification...'; | ||
@@ -343,20 +349,4 @@ // store the gzipped result and report the size | ||
hybrid = this.hybrid, | ||
name = this.workingName, | ||
uglified = this.uglified; | ||
// avoid errors when called as a npm executable | ||
try { | ||
// save the Closure Compiled version to disk | ||
fs.writeFileSync(path.join(distPath, name + '.compiler.js'), compiled.source); | ||
fs.writeFileSync(path.join(distPath, name + '.compiler.js.gz'), compiled.gzip); | ||
// save the Uglified version to disk | ||
fs.writeFileSync(path.join(distPath, name + '.uglify.js'), uglified.source); | ||
fs.writeFileSync(path.join(distPath, name + '.uglify.js.gz'), uglified.gzip); | ||
// save the hybrid minified version to disk | ||
fs.writeFileSync(path.join(distPath, name + '.hybrid.js'), hybrid.source); | ||
fs.writeFileSync(path.join(distPath, name + '.hybrid.js.gz'), hybrid.gzip); | ||
} catch(e) { } | ||
// select the smallest gzipped file and use its minified counterpart as the | ||
@@ -363,0 +353,0 @@ // official minified release (ties go to Closure Compiler) |
@@ -13,6 +13,6 @@ #!/usr/bin/env node | ||
' Lo-Dash @VERSION lodash.com/license\n' + | ||
' Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE\n' + | ||
' Underscore.js 1.4.0 underscorejs.org/LICENSE\n' + | ||
'*/', | ||
'underscore': | ||
'/*! Underscore.js @VERSION github.com/documentcloud/underscore/blob/master/LICENSE */' | ||
'/*! Underscore.js @VERSION underscorejs.org/LICENSE */' | ||
}; | ||
@@ -31,3 +31,3 @@ | ||
// move vars exposed by Closure Compiler into the IIFE | ||
source = source.replace(/^([^(\n]+)\s*(\(function[^)]+\){)/, '$2$1'); | ||
source = source.replace(/^((?:(['"])use strict\2;)?(?:var (?:[a-z]+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^)]+\){)/, '$3$1'); | ||
@@ -61,3 +61,4 @@ // unescape properties (i.e. foo["bar"] => foo.bar) | ||
module.exports = postprocess; | ||
} else { | ||
} | ||
else { | ||
// read the Lo-Dash source file from the first argument if the script | ||
@@ -67,6 +68,12 @@ // was invoked directly (e.g. `node post-compile.js source.js`) and write to | ||
(function() { | ||
var source = fs.readFileSync(process.argv[2], 'utf8'); | ||
fs.writeFileSync(process.argv[2], postprocess(source), 'utf8'); | ||
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'); | ||
}()); | ||
} | ||
}()); |
@@ -15,2 +15,3 @@ #!/usr/bin/env node | ||
'concat', | ||
'createCallback', | ||
'ctor', | ||
@@ -21,3 +22,2 @@ 'hasOwnProperty', | ||
'iteratee', | ||
'iteratorBind', | ||
'length', | ||
@@ -38,2 +38,3 @@ 'nativeKeys', | ||
'toString', | ||
'undefined', | ||
'value', | ||
@@ -50,3 +51,2 @@ | ||
'compareAscending', | ||
'data', | ||
'forIn', | ||
@@ -65,2 +65,3 @@ 'found', | ||
'noaccum', | ||
'noop', | ||
'objectClass', | ||
@@ -72,9 +73,7 @@ 'objectTypes', | ||
'propsLength', | ||
'recursive', | ||
'source', | ||
'sources', | ||
'stackA', | ||
'stackB', | ||
'stackLength', | ||
'target', | ||
'valueProp', | ||
'values' | ||
'target' | ||
]; | ||
@@ -89,3 +88,2 @@ | ||
'bottom', | ||
'exit', | ||
'firstArg', | ||
@@ -116,3 +114,2 @@ 'hasDontEnumBug', | ||
'__chain__', | ||
'__proto__', | ||
'__wrapped__', | ||
@@ -129,3 +126,2 @@ 'after', | ||
'clone', | ||
'clones', | ||
'collect', | ||
@@ -189,2 +185,3 @@ 'compact', | ||
'isObject', | ||
'isPlainObject', | ||
'isRegExp', | ||
@@ -196,2 +193,3 @@ 'isString', | ||
'lastIndexOf', | ||
'lateBind', | ||
'map', | ||
@@ -228,5 +226,2 @@ 'max', | ||
'source', | ||
'sources', | ||
'stackA', | ||
'stackB', | ||
'tail', | ||
@@ -236,2 +231,3 @@ 'take', | ||
'template', | ||
'templates', | ||
'templateSettings', | ||
@@ -265,8 +261,9 @@ 'throttle', | ||
* | ||
* @param {String} source The source to process. | ||
* @param {String} [source=''] The source to process. | ||
* @param {Object} [options={}] The options object. | ||
* @returns {String} Returns the processed source. | ||
*/ | ||
function preprocess(source) { | ||
// remove copyright to add later in post-compile.js | ||
source = source.replace(/\/\*![\s\S]+?\*\//, ''); | ||
function preprocess(source, options) { | ||
source || (source = ''); | ||
options || (options = {}); | ||
@@ -276,2 +273,9 @@ // remove unrecognized JSDoc tags so Closure Compiler won't complain | ||
if (options.isTemplate) { | ||
return source; | ||
} | ||
// remove copyright to add later in post-compile.js | ||
source = source.replace(/\/\*![\s\S]+?\*\//, ''); | ||
// add brackets to whitelisted properties so Closure Compiler won't mung them | ||
@@ -296,3 +300,3 @@ // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export | ||
// avoids removing the '\n' of the `stringEscapes` object | ||
return string.replace(/\[object |delete |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) { | ||
return string.replace(/\[object |delete |else |function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) { | ||
return match == false || match == '\\n' ? '' : match; | ||
@@ -306,3 +310,3 @@ }); | ||
// remove whitespace from `_.template` related regexes | ||
source = source.replace(/(?:reDelimiterCode\w+|reEmptyString\w+|reInsertVariable) *=.+/g, function(match) { | ||
source = source.replace(/(?:reEmptyString\w+|reInsertVariable) *=.+/g, function(match) { | ||
return match.replace(/ |\\n/g, ''); | ||
@@ -323,8 +327,8 @@ }); | ||
// remove debug sourceURL use in `_.template` | ||
source = source.replace(/(?:\s*\/\/.*\n)* *if *\(useSourceURL[^}]+}/, ''); | ||
source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, ''); | ||
// minify internal properties used by 'compareAscending', `_.clone`, `_.isEqual`, `_.merge`, and `_.sortBy` | ||
// minify internal properties used by 'compareAscending', `_.merge`, and `_.sortBy` | ||
(function() { | ||
var properties = ['clones', 'criteria', 'index', 'sources', 'thorough', 'value', 'values'], | ||
snippets = source.match(/( +)(?:function (?:clone|compareAscending|isEqual)|var merge|var sortBy)\b[\s\S]+?\n\1}/g); | ||
var properties = ['criteria', 'index', 'value'], | ||
snippets = source.match(/( +)(?:function compareAscending|var merge|var sortBy)\b[\s\S]+?\n\1}/g); | ||
@@ -464,6 +468,15 @@ if (!snippets) { | ||
(function() { | ||
var source = fs.readFileSync(process.argv[2], 'utf8'); | ||
fs.writeFileSync(process.argv[2], preprocess(source), 'utf8'); | ||
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'); | ||
}()); | ||
} | ||
}()); |
/*! | ||
Lo-Dash 0.7.0 lodash.com/license | ||
Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE | ||
Lo-Dash 0.8.0 lodash.com/license | ||
Underscore.js 1.4.0 underscorejs.org/LICENSE | ||
*/ | ||
;(function(e,t){function s(e){return new o(e)}function o(e){if(e&&e.__wrapped__)return e;this.__wrapped__=e}function u(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||V),s=i?{}:e;if(i)for(var o=t-1;++o<r;)n=e[o]+"",(lt.call(s,n)?s[n]:s[n]=[]).push(e[o]);return function(e){if(i){var n=e+"";return lt.call(s,n)&&-1<k(s[n],e)}return-1<k(s,e,t)}}function a(){for(var e,t,n,s=-1,o=arguments.length,u={e:"",f:"",j:"",q:"",c:{d:""},m:{d:""}};++s<o;)for(t in e=arguments[s],e)n=(n=e[t])==r?"":n,/d|i/.test(t)?("string"==typeof | ||
n&&(n={b:n,l:n}),u.c[t]=n.b||"",u.m[t]=n.l||""):u[t]=n;e=u.a,t=/^[^,]+/.exec(e)[0],n=u.s,u.g=t,u.h=Dt,u.k=zt,u.n=Bt,u.p=st,u.r=u.r!==i,u.s=n==r?Wt:n,u.o==r&&(u.o=It),u.f||(u.f="if(!"+t+")return u");if("d"!=t||!u.c.i)u.c=r;t="",u.s&&(t+="'use strict';"),t+="var i,A,j="+u.g+",u",u.j&&(t+="="+u.j),t+=";"+u.f+";"+u.q+";",u.c&&(t+="var l=j.length;i=-1;",u.m&&(t+="if(l>-1&&l===l>>>0){"),u.o&&(t+="if(z.call(j)==x){j=j.split('')}"),t+=u.c.d+";while(++i<l){A=j[i];"+u.c.i+"}",u.m&&(t+="}"));if(u.m){u.c?t+="else{" | ||
:u.n&&(t+="var l=j.length;i=-1;if(l&&P(j)){while(++i<l){A=j[i+=''];"+u.m.i+"}}else{"),u.h||(t+="var v=typeof j=='function'&&r.call(j,'prototype');");if(u.k&&u.r)t+="var o=-1,p=Y[typeof j]?m(j):[],l=p.length;"+u.m.d+";while(++o<l){i=p[o];",u.h||(t+="if(!(v&&i=='prototype')){"),t+="A=j[i];"+u.m.i+"",u.h||(t+="}");else{t+=u.m.d+";for(i in j){";if(!u.h||u.r)t+="if(",u.h||(t+="!(v&&i=='prototype')"),!u.h&&u.r&&(t+="&&"),u.r&&(t+="g.call(j,i)"),t+="){";t+="A=j[i];"+u.m.i+";";if(!u.h||u.r)t+="}"}t+="}"; | ||
if(u.h){t+="var f=j.constructor;";for(n=0;7>n;n++)t+="i='"+u.p[n]+"';if(","constructor"==u.p[n]&&(t+="!(f&&f.prototype===j)&&"),t+="g.call(j,i)){A=j[i];"+u.m.i+"}"}if(u.c||u.n)t+="}"}return t+=u.e+";return u",Function("D,E,F,I,e,K,g,h,N,P,R,T,U,k,X,Y,m,r,w,x,z","var G=function("+e+"){"+t+"};return G")(Xt,q,_,f,ft,hn,lt,D,k,b,un,w,an,p,Lt,Kt,bt,ht,pt,Ot,dt)}function f(e,n){var r=e.c,i=n.c,e=e.b,n=n.b;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function l(e,t){return at[ | ||
t]}function c(e){return"\\"+Qt[e]}function h(e){return $t[e]}function p(e,t){return function(n,r,i){return e.call(t,n,r,i)}}function d(){}function v(e,t){if(e&&J.test(t))return"<e%-"+t+"%>";var n=at.length;return at[n]="'+__e("+t+")+'",ot+n+ut}function m(e,t,n,i){return i?(e=at.length,at[e]="';"+i+";__p+='",ot+e+ut):t?v(r,t):g(r,n)}function g(e,t){if(e&&J.test(t))return"<e%="+t+"%>";var n=at.length;return at[n]="'+((__t=("+t+"))==null?'':__t)+'",ot+n+ut}function y(e){return Jt[e]}function b(e){return dt | ||
.call(e)==xt}function w(e){return"function"==typeof e}function E(e,t){var n=i;if(!e||"object"!=typeof e||!t&&b(e))return n;var r=e.constructor;return(!qt||"function"==typeof e.toString||"string"!=typeof (e+""))&&(!w(r)||r instanceof r)?Ht?(hn(e,function(e,t,r){return n=!lt.call(r,t),i}),n===i):(hn(e,function(e,t){n=t}),n===i||lt.call(e,n)):n}function S(e,t,s,o){if(e==r)return e;s&&(t=i),o||(o={e:r}),o.t==r&&(o.t=!(!R.clone&&!z.clone&&!W.clone));if(((s=Kt[typeof e])||o.t)&&e.clone&&w(e.clone))return o | ||
.t=r,e.clone(t);if(s){var u=dt.call(e);if(!Vt[u]||jt&&b(e))return e;var a=u==Tt,s=a||(u==Lt?an(e,n):s)}if(!s||!t)return s?a?pt.call(e):cn({},e):e;s=e.constructor;switch(u){case Nt:return new s(e==n);case Ct:return new s(+e);case kt:case Ot:return new s(e);case At:return s(e.source,Z.exec(e))}for(var f=o.a||(o.a=[]),l=o.d||(o.d=[]),u=f.length;u--;)if(l[u]==e)return f[u];var c=a?s(u=e.length):{};f.push(c),l.push(e);if(a)for(a=-1;++a<u;)c[a]=S(e[a],t,r,o);else pn(e,function(e,n){c[n]=S(e,t,r,o)});return c | ||
}function x(e,t,s){if(e==r||t==r)return e===t;s||(s={e:r}),s.t==r&&(s.t=!(!R.isEqual&&!z.isEqual&&!W.isEqual));if(Kt[typeof e]||Kt[typeof t]||s.t){e=e.__wrapped__||e,t=t.__wrapped__||t;if(e.isEqual&&w(e.isEqual))return s.t=r,e.isEqual(t);if(t.isEqual&&w(t.isEqual))return s.t=r,t.isEqual(e)}if(e===t)return 0!==e||1/e==1/t;var o=dt.call(e);if(o!=dt.call(t))return i;switch(o){case Nt:case Ct:return+e==+t;case kt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case At:case Ot:return e==t+""}var u=Xt[o];if(jt&&! | ||
u&&(u=b(e))&&!b(t)||!u&&(o!=Lt||qt&&("function"!=typeof e.toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;for(var a=s.stackA||(s.stackA=[]),f=s.stackB||(s.stackB=[]),o=a.length;o--;)if(a[o]==e)return f[o]==t;var o=-1,l=n,c=0;a.push(e),f.push(t);if(u){c=e.length;if(l=c==t.length)for(;c--&&(l=x(e[c],t[c],s)););return l}u=e.constructor,a=t.constructor;if(u!=a&&(!w(u)||!(u instanceof u&&w(a)&&a instanceof a)))return i;for(var h in e)if(lt.call(e,h)&& | ||
(c++,!lt.call(t,h)||!x(e[h],t[h],s)))return i;for(h in t)if(lt.call(t,h)&&!(c--))return i;if(Dt)for(;7>++o;)if(h=st[o],lt.call(e,h)&&(!lt.call(t,h)||!x(e[h],t[h],s)))return i;return n}function T(e,t,n,r){if(!e)return n;var i=e.length,s=3>arguments.length;r&&(t=p(t,r));if(-1<i&&i===i>>>0){var o=It&&dt.call(e)==Ot?e.split(""):e;for(i&&s&&(n=o[--i]);i--;)n=t(n,o[i],i,e);return n}o=gn(e);for((i=o.length)&&s&&(n=e[o[--i]]);i--;)s=o[i],n=t(n,e[s],s,e);return n}function N(e,t,n){if(e)return t==r||n?e[0] | ||
:pt.call(e,0,t)}function C(e,t){var n=[];if(!e)return n;for(var r,i=-1,s=e.length;++i<s;)r=e[i],un(r)?ct.apply(n,t?r:C(r)):n.push(r);return n}function k(e,t,n){if(!e)return-1;var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=O(e,t),e[r]===t?r:-1;r=(0>n?wt(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function L(e,t,n){var r=-Infinity,i=r;if(!e)return i;var s=-1,o=e.length;if(!t){for(;++s<o;)e[s]>i&&(i=e[s]);return i}for(n&&(t=p(t,n));++s<o;)n=t(e[s],s,e),n>r&&(r=n,i=e[s]);return i} | ||
function A(e,t,n){return e?pt.call(e,t==r||n?1:t):[]}function O(e,t,n,r){if(!e)return 0;var i=0,s=e.length;if(n){r&&(n=_(n,r));for(t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r}else for(;i<s;)r=i+s>>>1,e[r]<t?i=r+1:s=r;return i}function M(e,t,n,r){var s=[];if(!e)return s;var o=-1,u=e.length,a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n?r&&(n=p(n,r)):n=D;++o<u;)if(r=n(e[o],o,e),t?!o||a[a.length-1]!==r:0>k(a,r))a.push(r),s.push(e[o]);return s}function _(e,t){function n(){var o=arguments,u=t;return i|| | ||
(e=t[r]),s.length&&(o=o.length?s.concat(pt.call(o)):s),this instanceof n?(d.prototype=e.prototype,u=new d,(o=e.apply(u,o))&&Kt[typeof o]?o:u):e.apply(u,o)}var r,i=w(e);if(i){if(Ut||vt&&2<arguments.length)return vt.call.apply(vt,arguments)}else r=t,t=e;var s=pt.call(arguments,2);return n}function D(e){return e}function P(e){Ln(dn(e),function(t){var r=s[t]=e[t];o.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&ct.apply(e,arguments),e=r.apply(s,e),this.__chain__&&(e=new o(e | ||
),e.__chain__=n),e}})}var n=!0,r=null,i=!1,H,B,j,F,I="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),q=Array.prototype,R=Boolean.prototype,U=Object.prototype,z=Number.prototype,W=String.prototype,X=0,V=30,$=e._,J=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,K=/&(?:amp|lt|gt|quot|#x27);/g,Q=/\b__p\+='';/g,G=/\b(__p\+=)''\+/g,Y=/(__e\(.*?\)|\b__t\))\+'';/g,Z=/\w*$/,et=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,tt= | ||
RegExp("^"+(U.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),nt=/__token(\d+)__/g,rt=/[&<>"']/g,it=/['\n\r\t\u2028\u2029\\]/g,st="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),ot="__token",ut="__",at=[],ft=q.concat,lt=U.hasOwnProperty,ct=q.push,ht=U.propertyIsEnumerable,pt=q.slice,dt=U.toString,vt=tt.test(vt=pt.bind)&&vt,mt=Math.floor,gt=tt.test(gt=Array.isArray)&>,yt=e.isFinite,bt=tt.test | ||
(bt=Object.keys)&&bt,wt=Math.max,Et=Math.min,St=Math.random,xt="[object Arguments]",Tt="[object Array]",Nt="[object Boolean]",Ct="[object Date]",kt="[object Number]",Lt="[object Object]",At="[object RegExp]",Ot="[object String]",Mt=e.clearTimeout,_t=e.setTimeout,Dt,Pt,Ht,Bt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)Bt=!r;Dt=4>(n+"").length,Ht="x"!=n[0],Pt=(n.splice.call(t,0,1),t[0])})(1);var jt=!b(arguments | ||
),Ft="x"!=pt.call("x")[0],It="xx"!="x"[0]+Object("x")[0];try{var qt=("[object Object]",dt.call(e.document||0)==Lt)}catch(Rt){}var Ut=vt&&/\n|Opera/.test(vt+dt.call(e.opera)),zt=bt&&/^.+$|true/.test(bt+!!e.attachEvent),Wt=!Ut,Xt={};Xt[Nt]=Xt[Ct]=Xt["[object Function]"]=Xt[kt]=Xt[Lt]=Xt[At]=i,Xt[xt]=Xt[Tt]=Xt[Ot]=n;var Vt={};Vt[xt]=Vt["[object Function]"]=i,Vt[Tt]=Vt[Nt]=Vt[Ct]=Vt[kt]=Vt[Lt]=Vt[At]=Vt[Ot]=n;var $t={"&":"&","<":"<",">":">",'"':""","'":"'"},Jt={"&":"&","<":"<" | ||
,">":">",""":'"',"'":"'"},Kt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Qt={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var Gt={a:"d,c,y",j:"d",q:"if(!c)c=h;else if(y)c=k(c,y)",i:"if(c(A,i,d)===false)return u"},Yt={j:"{}",q:"var q;if(typeof c!='function'){var ii=c;c=function(A){return A[ii]}}else if(y)c=k(c,y)" | ||
,i:"q=c(A,i,d);(g.call(u,q)?u[q]++:u[q]=1)"},Zt={j:"true",i:"if(!c(A,i,d))return!u"},en={r:i,s:i,a:"n",j:"n",q:"for(var a=1,b=arguments.length;a<b;a++){if(j=arguments[a]){",i:"u[i]=A",e:"}}"},tn={j:"[]",i:"c(A,i,d)&&u.push(A)"},nn={q:"if(y)c=k(c,y)"},rn={i:{l:Gt.i}},sn={j:"",f:"if(!d)return[]",d:{b:"u=Array(l)",l:"u="+(zt?"Array(l)":"[]")},i:{b:"u[i]=c(A,i,d)",l:"u"+(zt?"[o]=":".push")+"(c(A,i,d))"}},on={r:i,a:"n,c,y",j:"{}",q:"var S=typeof c=='function';if(!S){var t=e.apply(E,arguments)}else if(y)c=k(c,y)" | ||
,i:"if(S?!c(A,i,n):N(t,i)<0)u[i]=A"};jt&&(b=function(e){return!!e&&!!lt.call(e,"callee")});var un=gt||function(e){return dt.call(e)==Tt};w(/x/)&&(w=function(e){return"[object Function]"==dt.call(e)});var an=Kt.__proto__!=U?E:function(e,t){if(!e)return i;var n=e.valueOf,r="function"==typeof n&&(r=n.__proto__)&&r.__proto__;return r?e==r||e.__proto__==r&&(t||!b(e)):E(e)},fn=a({a:"n",j:"[]",i:"u.push(i)"}),ln=a(en,{i:"if(u[i]==null)"+en.i}),cn=a(en),hn=a(Gt,nn,rn,{r:i}),pn=a(Gt,nn,rn),dn=a({r:i,a:"n" | ||
,j:"[]",i:"if(T(A))u.push(i)",e:"u.sort()"}),vn=a({a:"n",j:"{}",i:"u[A]=i"}),mn=a({a:"A",j:"true",q:"var H=z.call(A),l=A.length;if(D[H]"+(jt?"||P(A)":"")+"||(H==X&&l>-1&&l===l>>>0&&T(A.splice)))return!l",i:{l:"return false"}}),gn=bt?function(e){var t=typeof e;return"function"==t&&ht.call(e,"prototype")?fn(e):e&&Kt[t]?bt(e):[]}:fn,yn=a(en,{a:"n,ee,O",q:"var Q,dd=O==U,J=dd?arguments[3]:{g:[],d:[]};for(var a=1,b=dd?2:arguments.length;a<b;a++){if(j=arguments[a]){",i:"if((ee=A)&&((Q=R(ee))||U(ee))){var L=false,jj=J.g,ff=J.d,gg=ff.length;while(gg--)if(L=ff[gg]==ee)break;if(L){u[i]=jj[gg]}else{jj.push(A=(A=u[i])&&Q?(R(A)?A:[]):(U(A)?A:{}));ff.push(ee);u[i]=G(A,ee,U,J)}}else if(ee!=null)u[i]=ee" | ||
}),bn=a(on),wn=a({a:"n",j:"[]",i:"u"+(zt?"[o]=":".push")+"([i,A])"}),En=a(on,{q:"if(typeof c!='function'){var q,t=e.apply(E,arguments),l=t.length;for(i=1;i<l;i++){q=t[i];if(q in n)u[q]=n[q]}}else{if(y)c=k(c,y)",i:"if(c(A,i,n))u[i]=A",e:"}"}),Sn=a({a:"n",j:"[]",i:"u.push(A)"}),xn=a({a:"d,hh",j:"false",o:i,d:{b:"if(z.call(d)==x)return d.indexOf(hh)>-1"},i:"if(A===hh)return true"}),Tn=a(Gt,Yt),Nn=a(Gt,Zt),Cn=a(Gt,tn),kn=a(Gt,nn,{j:"",i:"if(c(A,i,d))return A"}),Ln=a(Gt,nn),An=a(Gt,Yt,{i:"q=c(A,i,d);(g.call(u,q)?u[q]:u[q]=[]).push(A)" | ||
}),On=a(sn,{a:"d,V",q:"var C=w.call(arguments,2),S=typeof V=='function'",i:{b:"u[i]=(S?V:A[V]).apply(A,C)",l:"u"+(zt?"[o]=":".push")+"((S?V:A[V]).apply(A,C))"}}),Mn=a(Gt,sn),_n=a(sn,{a:"d,bb",i:{b:"u[i]=A[bb]",l:"u"+(zt?"[o]=":".push")+"(A[bb])"}}),Dn=a({a:"d,c,B,y",j:"B",q:"var W=arguments.length<3;if(y)c=k(c,y)",d:{b:"if(W)u=j[++i]"},i:{b:"u=c(u,A,i,d)",l:"u=W?(W=false,A):c(u,A,i,d)"}}),Pn=a(Gt,tn,{i:"!"+tn.i}),Hn=a(Gt,Zt,{j:"false",i:Zt.i.replace("!","")}),Bn=a(Gt,Yt,sn,{i:{b:"u[i]={b:c(A,i,d),c:i,f:A}" | ||
,l:"u"+(zt?"[o]=":".push")+"({b:c(A,i,d),c:i,f:A})"},e:"u.sort(I);l=u.length;while(l--)u[l]=u[l].f"}),jn=a(tn,{a:"d,aa",q:"var t=[];K(aa,function(A,q){t.push(q)});var cc=t.length",i:"for(var q,Z=true,s=0;s<cc;s++){q=t[s];if(!(Z=A[q]===aa[q]))break}Z&&u.push(A)"}),Fn=a({r:i,s:i,a:"n",j:"n",q:"var M=arguments,l=M.length;if(l>1){for(var i=1;i<l;i++)u[M[i]]=F(u[M[i]],u);return u}",i:"if(T(u[i]))u[i]=F(u[i],u)"});s.VERSION="0.7.0",s.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply | ||
(this,arguments)}},s.bind=_,s.bindAll=Fn,s.chain=function(e){return e=new o(e),e.__chain__=n,e},s.clone=S,s.compact=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length;++n<r;)e[n]&&t.push(e[n]);return t},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=xn,s.countBy=Tn,s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,Mt | ||
(a),a=_t(i,t),r&&(o=e.apply(u,s)),o}},s.defaults=ln,s.defer=function(e){var n=pt.call(arguments,1);return _t(function(){return e.apply(t,n)},1)},s.delay=function(e,n){var r=pt.call(arguments,2);return _t(function(){return e.apply(t,r)},n)},s.difference=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=ft.apply(t,arguments),i=u(i,r);++n<r;)i(e[n])||t.push(e[n]);return t},s.escape=function(e){return e==r?"":(e+"").replace(rt,h)},s.every=Nn,s.extend=cn,s.filter=Cn,s.find=kn,s.first=N,s.flatten= | ||
C,s.forEach=Ln,s.forIn=hn,s.forOwn=pn,s.functions=dn,s.groupBy=An,s.has=function(e,t){return e?lt.call(e,t):i},s.identity=D,s.indexOf=k,s.initial=function(e,t,n){return e?pt.call(e,0,-(t==r||n?1:t)):[]},s.intersection=function(e){var t=[];if(!e)return t;var n,r=arguments.length,i=[],s=-1,o=e.length;e:for(;++s<o;)if(n=e[s],0>k(t,n)){for(var a=1;a<r;a++)if(!(i[a]||(i[a]=u(arguments[a])))(n))continue e;t.push(n)}return t},s.invert=vn,s.invoke=On,s.isArguments=b,s.isArray=un,s.isBoolean=function(e){return e=== | ||
n||e===i||dt.call(e)==Nt},s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=mn,s.isEqual=x,s.isFinite=function(e){return yt(e)&&dt.call(e)==kt},s.isFunction=w,s.isNaN=function(e){return dt.call(e)==kt&&e!=+e},s.isNull=function(e){return e===r},s.isObject=function(e){return e?Kt[typeof e]:i},s.isUndefined=function(e){return e===t},s.keys=gn,s.last=function(e,t,n){if(e){var i=e.length;return t==r||n?e[i-1]:pt.call(e,-t||i)}},s.lastIndexOf=function(e,t,n){if(!e)return-1;var r=e.length;for( | ||
n&&"number"==typeof n&&(r=(0>n?wt(0,r+n):Et(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.map=Mn,s.max=L,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return lt.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=yn,s.min=function(e,t,n){var r=Infinity,i=r;if(!e)return i;var s=-1,o=e.length;if(!t){for(;++s<o;)e[s]<i&&(i=e[s]);return i}for(n&&(t=p(t,n));++s<o;)n=t(e[s],s,e),n<r&&(r=n,i=e[s]);return i},s.mixin=P,s.noConflict=function(){return e | ||
._=$,this},s.object=function(e,t){if(!e)return{};for(var n=-1,r=e.length,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},s.omit=bn,s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=wn,s.partial=function(e){var t=pt.call(arguments,1),n=t.length;return function(){var r;return r=arguments,r.length&&(t.length=n,ct.apply(t,r)),r=1==t.length?e.call(this,t[0]):e.apply(this,t),t.length=n,r}},s.pick=En,s.pluck=_n,s.random=function(e,t){return e== | ||
r&&t==r?St():(e=+e||0,t==r&&(t=e,e=0),e+mt(St()*((+t||0)-e+1)))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=wt(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=Dn,s.reduceRight=T,s.reject=Pn,s.rest=A,s.result=function(e,t){if(!e)return r;var n=e[t];return w(n)?e[t]():n},s.shuffle=function(e){if(!e)return[];for(var t,n=-1,r=e.length,i=Array(r);++n<r;)t=mt(St()*(n+1)),i[n]=i[t],i[t]=e[n];return i},s.size=function(e){if(!e)return 0;var t=e.length;return-1< | ||
t&&t===t>>>0?t:gn(e).length},s.some=Hn,s.sortBy=Bn,s.sortedIndex=O,s.tap=function(e,t){return t(e),e},s.template=function(e,t,n){n||(n={});var e=e+"",o,u;o=n.escape;var a=n.evaluate,f=n.interpolate,h=s.templateSettings,p=n=n.variable||h.variable;o==r&&(o=h.escape),a==r&&(a=h.evaluate||i),f==r&&(f=h.interpolate),o&&(e=e.replace(o,v)),f&&(e=e.replace(f,g)),a!=H&&(H=a,F=RegExp("<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>"+(a?"|"+a.source:""),"g")),o=at.length,e=e.replace(F,m),o=o!=at.length,e="__p += '"+e | ||
.replace(it,c).replace(nt,l)+"';",at.length=0,p||(n=B||"obj",o?e="with("+n+"){"+e+"}":(n!=B&&(B=n,j=RegExp("(\\(\\s*)"+n+"\\."+n+"\\b","g")),e=e.replace(et,"$&"+n+".").replace(j,"$1__d"))),e=(o?e.replace(Q,""):e).replace(G,"$1").replace(Y,"$1;"),e="function("+n+"){"+(p?"":n+"||("+n+"={});")+"var __t,__p='',__e=_.escape"+(o?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(p?"":",__d="+n+"."+n+"||"+n)+";")+e+"return __p}";try{u=Function("_","return "+e)(s)}catch(d){throw d | ||
.source=e,d}return t?u(t):(u.source=e,u)},s.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a=r,s=e.apply(o,i)):u||(u=_t(n,f)),s}},s.times=function(e,t,n){var r=-1;if(n)for(;++r<e;)t.call(n,r);else for(;++r<e;)t(r)},s.toArray=function(e){if(!e)return[];if(e.toArray&&w(e.toArray))return e.toArray();var t=e.length;return-1<t&&t===t>>>0?(Ft?dt.call(e)==Ot:"string"==typeof e)?e.split(""):pt.call | ||
(e):Sn(e)},s.unescape=function(e){return e==r?"":(e+"").replace(K,y)},s.union=function(){for(var e=-1,t=[],n=ft.apply(t,arguments),r=n.length;++e<r;)0>k(t,n[e])&&t.push(n[e]);return t},s.uniq=M,s.uniqueId=function(e){var t=X++;return e?e+t:t},s.values=Sn,s.where=jn,s.without=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=u(arguments,1,20);++n<r;)i(e[n])||t.push(e[n]);return t},s.wrap=function(e,t){return function(){var n=[e];return arguments.length&&ct.apply(n,arguments),t.apply(this | ||
,n)}},s.zip=function(e){if(!e)return[];for(var t=-1,n=L(_n(arguments,"length")),r=Array(n);++t<n;)r[t]=_n(arguments,t);return r},s.all=Nn,s.any=Hn,s.collect=Mn,s.detect=kn,s.drop=A,s.each=Ln,s.foldl=Dn,s.foldr=T,s.head=N,s.include=xn,s.inject=Dn,s.methods=dn,s.select=Cn,s.tail=A,s.take=N,s.unique=M,Ln({Date:Ct,Number:kt,RegExp:At,String:Ot},function(e,t){s["is"+t]=function(t){return dt.call(t)==e}}),o.prototype=s.prototype,P(s),o.prototype.chain=function(){return this.__chain__=n,this},o.prototype | ||
.value=function(){return this.__wrapped__},Ln("pop push reverse shift sort splice unshift".split(" "),function(e){var t=q[e];o.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),Pt&&e.length===0&&delete e[0],this.__chain__&&(e=new o(e),e.__chain__=n),e}}),Ln(["concat","join","slice"],function(e){var t=q[e];o.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new o(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&& | ||
define.amd?(e._=s,define(function(){return s})):I?"object"==typeof module&&module&&module.exports==I?(module.exports=s)._=s:I._=s:e._=s})(this); | ||
;(function(e,t){function s(e){if(e&&e.__wrapped__)return e;if(!(this instanceof s))return new s(e);this.__wrapped__=e}function o(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||H),s=i?{}:e;if(i)for(var o=t-1;++o<r;)n=e[o]+"",(Q.call(s,n)?s[n]:s[n]=[]).push(e[o]);return function(e){if(i){var n=e+"";return Q.call(s,n)&&-1<x(s[n],e)}return-1<x(s,e,t)}}function u(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function a(e,t,n){function r(){var u=arguments | ||
,a=s?this:t;return i||(e=t[o]),n.length&&(u=u.length?n.concat(Z.call(u)):n),this instanceof r?(p.prototype=e.prototype,a=new p,(u=e.apply(a,u))&&Pt[typeof u]?u:a):e.apply(a,u)}var i=m(e),s=!n,o=e;return s&&(n=t),r}function f(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:A}function l(){for(var e,t,n,s=-1,o=arguments.length,a={e:"",p:"",c:{d:""},l:{d:""}};++s<o;)for(t in e=arguments[s],e)n=(n=e[t])==r?"":n,/d|h/.test(t)?("string"==typeof | ||
n&&(n={b:n,k:n}),a.c[t]=n.b||"",a.l[t]=n.k||""):a[t]=n;e=a.a,t=/^[^,]+/.exec(e)[0],n=a.i,s=a.r,a.f=t,a.g=wt,a.i=n==r?t:n,a.j=Ot,a.m=xt,a.o=J,a.q=a.q!==i,a.r=s==r?Mt:s,a.n==r&&(a.n=Ct);if("d"!=t||!a.c.h)a.c=r;t="",a.r&&(t+="'use strict';"),t+="var j,B,k="+a.f+",u",a.i&&(t+="="+a.i),t+=";"+a.p+";",a.c&&(t+="var l=k.length;j=-1;",a.l&&(t+="if(l===+l){"),a.n&&(t+="if(z.call(k)==x){k=k.split('')}"),t+=a.c.d+";while(++j<l){B=k[j];"+a.c.h+"}",a.l&&(t+="}"));if(a.l){a.c?t+="else {":a.m&&(t+="var l=k.length;j=-1;if(l&&P(k)){while(++j<l){B=k[j+=''];"+ | ||
a.l.h+"}}else {"),a.g||(t+="var v=typeof k=='function'&&r.call(k,'prototype');");if(a.j&&a.q)t+="var o=-1,p=Z[typeof k]?m(k):[],l=p.length;"+a.l.d+";while(++o<l){j=p[o];",a.g||(t+="if(!(v&&j=='prototype')){"),t+="B=k[j];"+a.l.h+"",a.g||(t+="}");else{t+=a.l.d+";for(j in k){";if(!a.g||a.q)t+="if(",a.g||(t+="!(v&&j=='prototype')"),!a.g&&a.q&&(t+="&&"),a.q&&(t+="h.call(k,j)"),t+="){";t+="B=k[j];"+a.l.h+";";if(!a.g||a.q)t+="}"}t+="}";if(a.g){t+="var g=k.constructor;";for(n=0;7>n;n++)t+="j='"+a.o[n]+"';if(" | ||
,"constructor"==a.o[n]&&(t+="!(g&&g.prototype===k)&&"),t+="h.call(k,j)){B=k[j];"+a.l.h+"}"}if(a.c||a.m)t+="}"}return t+=a.e+";return u",Function("E,F,G,J,e,f,K,h,i,N,P,R,T,U,Y,Z,m,r,w,x,z,A","var H=function("+e+"){"+t+"};return H")(_t,_,L,u,K,f,Zt,Q,A,x,v,Vt,m,$t,vt,Pt,ot,Y,Z,gt,et)}function c(e){return"\\"+Ht[e]}function h(e){return Kt[e]}function p(){}function d(e){return Qt[e]}function v(e){return et.call(e)==lt}function m(e){return"function"==typeof e}function g(e){var t=i;if(!e||"object"!=typeof | ||
e||v(e))return t;var n=e.constructor;return(!kt||"function"==typeof e.toString||"string"!=typeof (e+""))&&(!m(n)||n instanceof n)?St?(Zt(e,function(e,n,r){return t=!Q.call(r,n),i}),t===i):(Zt(e,function(e,n){t=n}),t===i||Q.call(e,t)):t}function y(e,t,s,o,u){if(e==r)return e;s&&(t=i);if(s=Pt[typeof e]){var a=et.call(e);if(!Dt[a]||Tt&&v(e))return e;var f=a==ct,s=f||(a==vt?$t(e):s)}if(!s||!t)return s?f?Z.call(e):Yt({},e):e;s=e.constructor;switch(a){case ht:return new s(e==n);case pt:return new s(+e) | ||
;case dt:case gt:return new s(e);case mt:return s(e.source,U.exec(e))}o||(o=[]),u||(u=[]);for(a=o.length;a--;)if(o[a]==e)return u[a];var l=f?s(a=e.length):{};o.push(e),u.push(l);if(f)for(f=-1;++f<a;)l[f]=y(e[f],t,r,o,u);else en(e,function(e,n){l[n]=y(e,t,r,o,u)});return l}function b(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Pt[typeof e]||Pt[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=et.call(e);if(u!=et.call(t))return i;switch(u){case ht:case pt:return+e==+t | ||
;case dt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case mt:case gt:return e==t+""}var a=_t[u];if(Tt&&!a&&(a=v(e))&&!v(t)||!a&&(u!=vt||kt&&("function"!=typeof e.toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var u=-1,f=n,l=0;s.push(e),o.push(t);if(a){l=e.length;if(f=l==t.length)for(;l--&&(f=b(e[l],t[l],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!m(a)||!(a instanceof | ||
a&&m(f)&&f instanceof f)))return i;for(var c in e)if(Q.call(e,c)&&(l++,!Q.call(t,c)||!b(e[c],t[c],s,o)))return i;for(c in t)if(Q.call(t,c)&&!(l--))return i;if(wt)for(;7>++u;)if(c=J[u],Q.call(e,c)&&(!Q.call(t,c)||!b(e[c],t[c],s,o)))return i;return n}function w(e,t,n,r){var s=e,o=e.length,u=3>arguments.length;if(o!==+o)var a=rn(e),o=a.length;else Ct&&et.call(e)==gt&&(s=e.split(""));return vn(e,function(e,f,l){f=a?a[--o]:--o,n=u?(u=i,s[f]):t.call(r,n,s[f],f,l)}),n}function E(e,t,n){return t==r||n?e[0 | ||
]:Z.call(e,0,t)}function S(e,t){for(var n,r=-1,i=e.length,s=[];++r<i;)n=e[r],Vt(n)?G.apply(s,t?n:S(n)):s.push(n);return s}function x(e,t,n){var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=C(e,t),e[r]===t?r:-1;r=(0>n?ut(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function T(e,t,n){for(var r=-Infinity,i=-1,s=e?e.length:0,o=r,t=f(t,n);++i<s;)n=t(e[i],i,e),n>r&&(r=n,o=e[i]);return o}function N(e,t,n){return Z.call(e,t==r||n?1:t)}function C(e,t,n,r){for(var i=0,s=e.length,n=f(n,r),t= | ||
n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r;return i}function k(e,t,n,r){var s=-1,o=e.length,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=f(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>x(a,r))a.push(r),u.push(e[s]);return u}function L(e,t){return At||tt&&2<arguments.length?tt.call.apply(tt,arguments):a(e,t,Z.call(arguments,2))}function A(e){return e}function O(e){vn(tn(e),function(t){var r=s[t]=e[t];s.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&G.apply(e | ||
,arguments),e=r.apply(s,e),this.__chain__&&(e=new s(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,M="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),_=Array.prototype,D=Object.prototype,P=0,H=30,B=e._,j=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,F=/&(?:amp|lt|gt|quot|#x27);/g,I=/\b__p\+='';/g,q=/\b(__p\+=)''\+/g,R=/(__e\(.*?\)|\b__t\))\+'';/g,U=/\w*$/,z=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,W=RegExp("^"+(D | ||
.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),X=/($^)/,V=/[&<>"']/g,$=/['\n\r\t\u2028\u2029\\]/g,J="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),K=_.concat,Q=D.hasOwnProperty,G=_.push,Y=D.propertyIsEnumerable,Z=_.slice,et=D.toString,tt=W.test(tt=Z.bind)&&tt,nt=Math.floor,rt=W.test(rt=Object.getPrototypeOf)&&rt,it=W.test(it=Array.isArray)&&it,st=e.isFinite,ot=W.test(ot=Object.keys)&&ot, | ||
ut=Math.max,at=Math.min,ft=Math.random,lt="[object Arguments]",ct="[object Array]",ht="[object Boolean]",pt="[object Date]",dt="[object Number]",vt="[object Object]",mt="[object RegExp]",gt="[object String]",yt=e.clearTimeout,bt=e.setTimeout,wt,Et,St,xt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)xt=!r;wt=4>(n+"").length,St="x"!=n[0],Et=(n.splice.call(t,0,1),t[0])})(1);var Tt=!v(arguments),Nt="x"!=Z.call("x" | ||
)[0],Ct="xx"!="x"[0]+Object("x")[0];try{var kt=("[object Object]",et.call(e.document||0)==vt)}catch(Lt){}var At=tt&&/\n|Opera/.test(tt+et.call(e.opera)),Ot=ot&&/^.+$|true/.test(ot+!!e.attachEvent),Mt=!At,_t={};_t[ht]=_t[pt]=_t["[object Function]"]=_t[dt]=_t[vt]=_t[mt]=i,_t[lt]=_t[ct]=_t[gt]=n;var Dt={};Dt[lt]=Dt["[object Function]"]=i,Dt[ct]=Dt[ht]=Dt[pt]=Dt[dt]=Dt[vt]=Dt[mt]=Dt[gt]=n;var Pt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Ht={"\\":"\\","'":"'","\n":"n" | ||
,"\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var Bt={a:"d,c,y",i:"d",p:"c=f(c,y)",h:"if(c(B,j,d)===false)return u"},jt={i:"{}",p:"c=f(c,y)",h:"var q=c(B,j,d);(h.call(u,q)?u[q]++:u[q]=1)"},Ft={i:"true",h:"if(!c(B,j,d))return!u"},It={q:i,r:i,a:"n",i:"n",p:"for(var a=1,b=arguments.length;a<b;a++){if(k=arguments[a]){",h:"u[j]=B",e:"}}"},qt={i:"[]",h:"c(B,j,d)&&u.push(B)"},Rt={p | ||
:"c=f(c,y)"},Ut={h:{k:Bt.h}},zt={i:"",d:{b:"u=Array(l)",k:"u="+(Ot?"Array(l)":"[]")},h:{b:"u[j]=c(B,j,d)",k:"u"+(Ot?"[o]=":".push")+"(c(B,j,d))"}},Wt={q:i,a:"n,c,y",i:"{}",p:"var S=typeof c=='function';if(S)c=f(c,y);else var t=e.apply(F,arguments)",h:"if(S?!c(B,j,n):N(t,j)<0)u[j]=B"},Xt=l({a:"n",i:"{}",h:"u[B]=j"});Tt&&(v=function(e){return!!e&&!!Q.call(e,"callee")});var Vt=it||function(e){return et.call(e)==ct};m(/x/)&&(m=function(e){return"[object Function]"==et.call(e)});var $t=rt?function(e){ | ||
if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=rt(t))&&rt(n);return n?e==n||rt(e)==n&&!v(e):g(e)}:g,Jt=l({a:"n",i:"[]",p:"if(!(n&&Z[typeof n]))throw TypeError()",h:"u.push(j)"}),Kt={"&":"&","<":"<",">":">",'"':""","'":"'"},Qt=Xt(Kt),Gt=l(It,{h:"if(u[j]==null)"+It.h}),Yt=l(It),Zt=l(Bt,Rt,Ut,{q:i}),en=l(Bt,Rt,Ut),tn=l({q:i,a:"n",i:"[]",h:"if(T(B))u.push(j)",e:"u.sort()"}),nn=l({a:"B",i:"true",p:"if(!B)return u;var I=z.call(B),l=B.length;if(E[I]"+(Tt?"||P(B)" | ||
:"")+"||(I==Y&&l===+l&&T(B.splice)))return!l",h:{k:"return false"}}),rn=ot?function(e){return"function"==typeof e&&Y.call(e,"prototype")?Jt(e):ot(e)}:Jt,sn=l(It,{a:"n,ee,O",p:"var Q,D=arguments,a=0;if(O==J){var b=2,ff=D[3],gg=D[4]}else var b=D.length,ff=[],gg=[];while(++a<b){if(k=D[a]){",h:"if((ee=B)&&((Q=R(ee))||U(ee))){var L=false,hh=ff.length;while(hh--)if(L=ff[hh]==ee)break;if(L){u[j]=gg[hh]}else {ff.push(ee);gg.push(B=(B=u[j])&&Q?(R(B)?B:[]):(U(B)?B:{}));u[j]=H(B,ee,J,ff,gg)}}else if(ee!=null)u[j]=ee" | ||
}),on=l(Wt),un=l({a:"n",i:"[]",h:"u"+(Ot?"[o]=":".push")+"([j,B])"}),an=l(Wt,{p:"if(typeof c!='function'){var q,t=e.apply(F,arguments),l=t.length;for(j=1;j<l;j++){q=t[j];if(q in n)u[q]=n[q]}}else {c=f(c,y)",h:"if(c(B,j,n))u[j]=B",e:"}"}),fn=l({a:"n",i:"[]",h:"u.push(B)"}),ln=l({a:"d,ii",i:"false",n:i,d:{b:"if(z.call(d)==x)return d.indexOf(ii)>-1"},h:"if(B===ii)return true"}),cn=l(Bt,jt),hn=l(Bt,Ft),pn=l(Bt,qt),dn=l(Bt,Rt,{i:"",h:"if(c(B,j,d))return B"}),vn=l(Bt,Rt),mn=l(Bt,jt,{h:"var q=c(B,j,d);(h.call(u,q)?u[q]:u[q]=[]).push(B)" | ||
}),gn=l(zt,{a:"d,V",p:"var D=w.call(arguments,2),S=typeof V=='function'",h:{b:"u[j]=(S?V:B[V]).apply(B,D)",k:"u"+(Ot?"[o]=":".push")+"((S?V:B[V]).apply(B,D))"}}),yn=l(Bt,zt),bn=l(zt,{a:"d,cc",h:{b:"u[j]=B[cc]",k:"u"+(Ot?"[o]=":".push")+"(B[cc])"}}),wn=l({a:"d,c,C,y",i:"C",p:"var W=arguments.length<3;c=f(c,y)",d:{b:"if(W)u=k[++j]"},h:{b:"u=c(u,B,j,d)",k:"u=W?(W=false,B):c(u,B,j,d)"}}),En=l(Bt,qt,{h:"!"+qt.h}),Sn=l(Bt,Ft,{i:"false",h:Ft.h.replace("!","")}),xn=l(Bt,jt,zt,{h:{b:"u[j]={a:c(B,j,d),b:j,c:B}" | ||
,k:"u"+(Ot?"[o]=":".push")+"({a:c(B,j,d),b:j,c:B})"},e:"u.sort(J);l=u.length;while(l--)u[l]=u[l].c"}),Tn=l(qt,{a:"d,bb",p:"var t=[];K(bb,function(B,q){t.push(q)});var dd=t.length",h:"for(var q,aa=true,s=0;s<dd;s++){q=t[s];if(!(aa=B[q]===bb[q]))break}aa&&u.push(B)"}),Nn=l({q:i,r:i,a:"n",p:"var M=arguments,l=M.length;if(l>1){for(var j=1;j<l;j++)u[M[j]]=G(u[M[j]],u);return u}",h:"if(T(u[j]))u[j]=G(u[j],u)"});s.VERSION="0.8.0",s.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this | ||
,arguments)}},s.bind=L,s.bindAll=Nn,s.chain=function(e){return e=new s(e),e.__chain__=n,e},s.clone=y,s.compact=function(e){for(var t=-1,n=e.length,r=[];++t<n;)e[t]&&r.push(e[t]);return r},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=ln,s.countBy=cn,s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,yt(a),a=bt(i,t),r&&(o=e.apply | ||
(u,s)),o}},s.defaults=Gt,s.defer=function(e){var n=Z.call(arguments,1);return bt(function(){return e.apply(t,n)},1)},s.delay=function(e,n){var r=Z.call(arguments,2);return bt(function(){return e.apply(t,r)},n)},s.difference=function(e){for(var t=-1,n=e.length,r=K.apply(_,arguments),r=o(r,n),i=[];++t<n;)r(e[t])||i.push(e[t]);return i},s.escape=function(e){return e==r?"":(e+"").replace(V,h)},s.every=hn,s.extend=Yt,s.filter=pn,s.find=dn,s.first=E,s.flatten=S,s.forEach=vn,s.forIn=Zt,s.forOwn=en,s.functions= | ||
tn,s.groupBy=mn,s.has=function(e,t){return Q.call(e,t)},s.identity=A,s.indexOf=x,s.initial=function(e,t,n){return Z.call(e,0,-(t==r||n?1:t))},s.intersection=function(e){var t,n=arguments.length,r=[],i=-1,s=e.length,u=[];e:for(;++i<s;)if(t=e[i],0>x(u,t)){for(var a=1;a<n;a++)if(!(r[a]||(r[a]=o(arguments[a])))(t))continue e;u.push(t)}return u},s.invert=Xt,s.invoke=gn,s.isArguments=v,s.isArray=Vt,s.isBoolean=function(e){return e===n||e===i||et.call(e)==ht},s.isDate=function(e){return et.call(e)==pt}, | ||
s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=nn,s.isEqual=b,s.isFinite=function(e){return st(e)&&et.call(e)==dt},s.isFunction=m,s.isNaN=function(e){return et.call(e)==dt&&e!=+e},s.isNull=function(e){return e===r},s.isNumber=function(e){return et.call(e)==dt},s.isObject=function(e){return e?Pt[typeof e]:i},s.isPlainObject=$t,s.isRegExp=function(e){return et.call(e)==mt},s.isString=function(e){return et.call(e)==gt},s.isUndefined=function(e){return e===t},s.keys=rn,s.last=function(e | ||
,t,n){var i=e.length;return t==r||n?e[i-1]:Z.call(e,-t||i)},s.lastIndexOf=function(e,t,n){var r=e.length;for(n&&"number"==typeof n&&(r=(0>n?ut(0,r+n):at(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.lateBind=function(e,t){return a(t,e,Z.call(arguments,2))},s.map=yn,s.max=T,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Q.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=sn,s.min=function(e,t,n){for(var r=Infinity,i=-1,s=e?e.length:0,o= | ||
r,t=f(t,n);++i<s;)n=t(e[i],i,e),n<r&&(r=n,o=e[i]);return o},s.mixin=O,s.noConflict=function(){return e._=B,this},s.object=function(e,t){for(var n=-1,r=e.length,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},s.omit=on,s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=un,s.partial=function(e){return a(e,Z.call(arguments,1))},s.pick=an,s.pluck=bn,s.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+nt(ft()*((+t||0)- | ||
e+1))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=ut(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=wn,s.reduceRight=w,s.reject=En,s.rest=N,s.result=function(e,t){var n=e?e[t]:r;return m(n)?e[t]():n},s.shuffle=function(e){for(var t,n=-1,r=e.length,i=Array(r);++n<r;)t=nt(ft()*(n+1)),i[n]=i[t],i[t]=e[n];return i},s.size=function(e){var t=e?e.length:0;return t===+t?t:rn(e).length},s.some=Sn,s.sortBy=xn,s.sortedIndex=C,s.tap=function(e,t){return t(e | ||
),e},s.template=function(e,t,n){n||(n={});var r,i,o=0,u=s.templateSettings,a="__p += '",f=n.variable||u.variable,l=f;e.replace(RegExp((n.escape||u.escape||X).source+"|"+(n.interpolate||u.interpolate||X).source+"|"+(n.evaluate||u.evaluate||X).source+"|$","g"),function(t,n,i,s,u){a+=e.slice(o,u).replace($,c),a+=n?"'+__e("+n+")+'":s?"';"+s+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=s||j.test(n||i)),o=u+t.length}),a+="';",l||(f="obj",r?a="with("+f+"){"+a+"}":(n=RegExp("(\\(\\s*)"+f+"\\."+ | ||
f+"\\b","g"),a=a.replace(z,"$&"+f+".").replace(n,"$1__d"))),a=(r?a.replace(I,""):a).replace(q,"$1").replace(R,"$1;"),a="function("+f+"){"+(l?"":f+"||("+f+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(l?"":",__d="+f+"."+f+"||"+f)+";")+a+"return __p}";try{i=Function("_","return "+a)(s)}catch(h){throw h.source=a,h}return t?i(t):(i.source=a,i)},s.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function( | ||
){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a=r,s=e.apply(o,i)):u||(u=bt(n,f)),s}},s.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},s.toArray=function(e){var t=e?e.length:0;return t===+t?(Nt?et.call(e)==gt:"string"==typeof e)?e.split(""):Z.call(e):fn(e)},s.unescape=function(e){return e==r?"":(e+"").replace(F,d)},s.union=function(){for(var e=-1,t=K.apply(_,arguments),n=t.length,r=[];++e<n;)0>x(r,t[e])&&r.push(t[e]);return r},s.uniq=k,s.uniqueId= | ||
function(e){var t=P++;return e?e+t:t},s.values=fn,s.where=Tn,s.without=function(e){for(var t=-1,n=e.length,r=o(arguments,1,20),i=[];++t<n;)r(e[t])||i.push(e[t]);return i},s.wrap=function(e,t){return function(){var n=[e];return arguments.length&&G.apply(n,arguments),t.apply(this,n)}},s.zip=function(e){for(var t=-1,n=T(bn(arguments,"length")),r=Array(n);++t<n;)r[t]=bn(arguments,t);return r},s.all=hn,s.any=Sn,s.collect=yn,s.detect=dn,s.drop=N,s.each=vn,s.foldl=wn,s.foldr=w,s.head=E,s.include=ln,s.inject= | ||
wn,s.methods=tn,s.select=pn,s.tail=N,s.take=E,s.unique=k,O(s),s.prototype.chain=function(){return this.__chain__=n,this},s.prototype.value=function(){return this.__wrapped__},vn("pop push reverse shift sort splice unshift".split(" "),function(e){var t=_[e];s.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),Et&&e.length===0&&delete e[0],this.__chain__&&(e=new s(e),e.__chain__=n),e}}),vn(["concat","join","slice"],function(e){var t=_[e];s.prototype[e]=function(){var e=t.apply | ||
(this.__wrapped__,arguments);return this.__chain__&&(e=new s(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=s,define(function(){return s})):M?"object"==typeof module&&module&&module.exports==M?(module.exports=s)._=s:M._=s:e._=s})(this); |
{ | ||
"name": "lodash", | ||
"version": "0.7.0", | ||
"version": "0.8.0", | ||
"description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.", | ||
"homepage": "http://lodash.com", | ||
"main": "lodash", | ||
"main": "./lodash", | ||
"keywords": [ | ||
@@ -46,8 +46,8 @@ "browser", | ||
"jam": { | ||
"main": "./lodash.min.js" | ||
"main": "./lodash.js" | ||
}, | ||
"scripts": { | ||
"build": "node build", | ||
"test": "node test/test" | ||
"test": "node test/test && node test/test-build" | ||
} | ||
} |
102
perf/perf.js
@@ -279,3 +279,2 @@ (function(window) { | ||
fiftyValues = Array(50),\ | ||
fiftyValues2 = Array(50),\ | ||
seventyFiveValues = Array(75),\ | ||
@@ -298,4 +297,2 @@ seventyFiveValues2 = Array(75),\ | ||
seventyFiveValues[index] = lowerChars[index];\ | ||
\ | ||
fiftyValues2[index] =\ | ||
seventyFiveValues2[index] = upperChars[index];\ | ||
@@ -306,3 +303,2 @@ }\ | ||
fiftyValues[index] = index;\ | ||
fiftyValues2[index] = index + (index < 40 ? 75 : 0);\ | ||
}\ | ||
@@ -581,9 +577,9 @@ seventyFiveValues[index] = index;\ | ||
suites.push( | ||
Benchmark.Suite('`_.difference` iterating 50 elements') | ||
Benchmark.Suite('`_.difference` iterating 50 and 75 elements') | ||
.add('Lo-Dash', { | ||
'fn': 'lodash.difference(fiftyValues, fiftyValues2)', | ||
'fn': 'lodash.difference(fiftyValues, seventyFiveValues2)', | ||
'teardown': 'function multiArrays(){}' | ||
}) | ||
.add('Underscore', { | ||
'fn': '_.difference(fiftyValues, fiftyValues2)', | ||
'fn': '_.difference(fiftyValues, seventyFiveValues2)', | ||
'teardown': 'function multiArrays(){}' | ||
@@ -846,9 +842,9 @@ }) | ||
suites.push( | ||
Benchmark.Suite('`_.intersection` iterating 50 elements') | ||
Benchmark.Suite('`_.intersection` iterating 50 and 75 elements') | ||
.add('Lo-Dash', { | ||
'fn': 'lodash.intersection(fiftyValues, fiftyValues2)', | ||
'fn': 'lodash.intersection(fiftyValues, seventyFiveValues2)', | ||
'teardown': 'function multiArrays(){}' | ||
}) | ||
.add('Underscore', { | ||
'fn': '_.intersection(fiftyValues, fiftyValues2)', | ||
'fn': '_.intersection(fiftyValues, seventyFiveValues2)', | ||
'teardown': 'function multiArrays(){}' | ||
@@ -1161,2 +1157,70 @@ }) | ||
suites.push( | ||
Benchmark.Suite('`_.reduce` iterating an array') | ||
.add('Lo-Dash', '\ | ||
lodash.reduce(numbers, function(result, value, index) {\ | ||
result[index] = value;\ | ||
return result;\ | ||
}, {});' | ||
) | ||
.add('Underscore', '\ | ||
_.reduce(numbers, function(result, value, index) {\ | ||
result[index] = value;\ | ||
return result;\ | ||
}, {});' | ||
) | ||
); | ||
suites.push( | ||
Benchmark.Suite('`_.reduce` iterating an object') | ||
.add('Lo-Dash', '\ | ||
lodash.reduce(object, function(result, value, key) {\ | ||
result.push([key, value]);\ | ||
return result;\ | ||
}, []);' | ||
) | ||
.add('Underscore', '\ | ||
_.reduce(object, function(result, value, key) {\ | ||
result.push([key, value]);\ | ||
return result;\ | ||
}, []);' | ||
) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('`_.reduceRight` iterating an array') | ||
.add('Lo-Dash', '\ | ||
lodash.reduceRight(numbers, function(result, value, index) {\ | ||
result[index] = value;\ | ||
return result;\ | ||
}, {});' | ||
) | ||
.add('Underscore', '\ | ||
_.reduceRight(numbers, function(result, value, index) {\ | ||
result[index] = value;\ | ||
return result;\ | ||
}, {});' | ||
) | ||
); | ||
suites.push( | ||
Benchmark.Suite('`_.reduceRight` iterating an object') | ||
.add('Lo-Dash', '\ | ||
lodash.reduceRight(object, function(result, value, key) {\ | ||
result.push([key, value]);\ | ||
return result;\ | ||
}, []);' | ||
) | ||
.add('Underscore', '\ | ||
_.reduceRight(object, function(result, value, key) {\ | ||
result.push([key, value]);\ | ||
return result;\ | ||
}, []);' | ||
) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('`_.shuffle`') | ||
@@ -1422,2 +1486,14 @@ .add('Lo-Dash', '\ | ||
suites.push( | ||
Benchmark.Suite('`_.where`') | ||
.add('Lo-Dash', '\ | ||
lodash.where(objects, { "num": 9 });' | ||
) | ||
.add('Underscore', '\ | ||
_.where(objects, { "num": 9 });' | ||
) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('`_.without`') | ||
@@ -1445,9 +1521,9 @@ .add('Lo-Dash', '\ | ||
suites.push( | ||
Benchmark.Suite('`_.without` iterating an array of 50 elements') | ||
Benchmark.Suite('`_.without` iterating an array of 75 and 50 elements') | ||
.add('Lo-Dash', { | ||
'fn': 'lodash.without.apply(lodash, [fiftyValues].concat(fiftyValues2));', | ||
'fn': 'lodash.without.apply(lodash, [seventyFiveValues2].concat(fiftyValues));', | ||
'teardown': 'function multiArrays(){}' | ||
}) | ||
.add('Underscore', { | ||
'fn': '_.without.apply(_, [fiftyValues].concat(fiftyValues2));', | ||
'fn': '_.without.apply(_, [seventyFiveValues2].concat(fiftyValues));', | ||
'teardown': 'function multiArrays(){}' | ||
@@ -1454,0 +1530,0 @@ }) |
161
README.md
@@ -1,4 +0,5 @@ | ||
# Lo-Dash <sup>v0.7.0</sup> | ||
# Lo-Dash <sup>v0.8.0</sup> | ||
[![build status](https://secure.travis-ci.org/bestiejs/lodash.png)](http://travis-ci.org/bestiejs/lodash) | ||
A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues-20), and [additional features](https://github.com/bestiejs/lodash#features). | ||
A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues), and [additional features](http://lodash.com/#features). | ||
@@ -9,6 +10,7 @@ Lo-Dash’s performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls. | ||
* [Development source](https://raw.github.com/bestiejs/lodash/v0.7.0/lodash.js) | ||
* [Production source](https://raw.github.com/bestiejs/lodash/v0.7.0/lodash.min.js) | ||
* CDN copies of ≤ [v0.7.0](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.7.0/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/) | ||
* For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need | ||
* [Development build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.js) | ||
* [Production build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.min.js) | ||
* [Underscore build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.underscore.min.js) tailored for projects already using Underscore | ||
* CDN copies of ≤ [v0.8.0](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.8.0/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/) | ||
* For optimal file size, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need | ||
@@ -36,22 +38,11 @@ ## Dive in | ||
* AMD loader support ([RequireJS](http://requirejs.org/), [curl.js](https://github.com/cujojs/curl), etc.) | ||
* [_.bind](http://lodash.com/docs#bind) supports *“lazy”* binding | ||
* [_.clone](http://lodash.com/docs#clone) supports *“deep”* cloning | ||
* [_.countBy](http://lodash.com/docs#countBy) as a companion function for [_.groupBy](http://lodash.com/docs#groupBy) and [_.sortBy](http://lodash.com/docs#sortBy) | ||
* [_.debounce](http://lodash.com/docs#debounce)’ed functions match [_.throttle](http://lodash.com/docs#throttle)’ed functions’ return value behavior | ||
* [_.forEach](http://lodash.com/docs#forEach) is chainable and supports exiting iteration early | ||
* [_.forIn](http://lodash.com/docs#forIn) for iterating over an object’s own and inherited properties | ||
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an object’s own properties | ||
* [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument | ||
* [_.invert](http://lodash.com/docs#invert) to create inverted objects | ||
* [_.lateBind](http://lodash.com/docs#lateBind) for late binding | ||
* [_.merge](http://lodash.com/docs#merge) for a *“deep”* [_.extend](http://lodash.com/docs#extend) | ||
* [_.object](http://lodash.com/docs#object) and [_.pairs](http://lodash.com/docs#pairs) for composing objects | ||
* [_.omit](http://lodash.com/docs#omit) for the inverse functionality of [_.pick](http://lodash.com/docs#pick) | ||
* [_.partial](http://lodash.com/docs#partial) for partial application without `this` binding | ||
* [_.pick](http://lodash.com/docs#pick) and [_.omit](http://lodash.com/docs#omit) accept `callback` and `thisArg` arguments | ||
* [_.random](http://lodash.com/docs#random) for generating random numbers within a given range | ||
* [_.sortBy](http://lodash.com/docs#sortBy) performs a [stable](http://en.wikipedia.org/wiki/Sorting_algorithm#Stability) sort | ||
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging | ||
* [_.unescape](http://lodash.com/docs#unescape) to unescape strings escaped by [_.escape](http://lodash.com/docs#escape) | ||
* [_.where](http://lodash.com/docs#where) for filtering collections by contained properties | ||
* [_.countBy](http://lodash.com/docs#countBy), [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument | ||
* [_.contains](http://lodash.com/docs#contains), [_.size](http://lodash.com/docs#size), [_.toArray](http://lodash.com/docs#toArray), | ||
@@ -62,3 +53,3 @@ [and more…](http://lodash.com/docs "_.countBy, _.every, _.filter, _.find, _.forEach, _.groupBy, _.invoke, _.map, _.pluck, _.reduce, _.reduceRight, _.reject, _.some, _.sortBy, _.where") accept strings | ||
Lo-Dash has been tested in at least Chrome 5-21, Firefox 1-15, IE 6-9, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.8, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5. | ||
Lo-Dash has been tested in at least Chrome 5-22, Firefox 1-15, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.11, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5. | ||
@@ -95,3 +86,3 @@ ## Custom builds | ||
* Underscore builds, with iteration fixes removed and only Underscore’s API, may be created using the `underscore` modifier argument. | ||
* Underscore builds, tailored for projects already using Underscore, may be created using the `underscore` modifier argument. | ||
```bash | ||
@@ -104,3 +95,3 @@ lodash underscore | ||
* Use the `category` argument to pass comma separated categories of methods to include in the build.<br> | ||
Valid categories are *“arrays”*, *“chaining”*, *“collections”*, *“functions”*, *“objects”*, and *“utilities”*. | ||
Valid categories (case-insensitive) are *“arrays”*, *“chaining”*, *“collections”*, *“functions”*, *“objects”*, and *“utilities”*. | ||
```bash | ||
@@ -111,13 +102,7 @@ lodash category=collections,functions | ||
* Use the `exclude` argument to pass comma separated names of methods to exclude from the build. | ||
```bash | ||
lodash exclude=union,uniq,zip | ||
lodash exclude="union, uniq, zip" | ||
``` | ||
* Use the `exports` argument to pass comma separated names of ways to export the `LoDash` function.<br> | ||
Valid exports are *“amd”*, *“commonjs”*, *“global”*, *“node”*, and *“none”*. | ||
Valid exports are *“amd”*, *“commonjs”*, *“global”*, *“node”*, and *“none”*. | ||
```bash | ||
lodash exports=amd,commonjs,node | ||
lodash include="amd, commonjs, node" | ||
lodash exports="amd, commonjs, node" | ||
``` | ||
@@ -130,3 +115,3 @@ | ||
* Use the `include` argument to pass comma separated names of methods to include in the build. | ||
* Use the `include` argument to pass comma separated method/category names to include in the build. | ||
```bash | ||
@@ -137,21 +122,39 @@ lodash include=each,filter,map | ||
All arguments, except `exclude` with `include` and `legacy` with `csp`/`mobile`, may be combined. | ||
* Use the `minus` argument to pass comma separated method/category names to remove from those included in the build. | ||
```bash | ||
lodash underscore minus=result,shuffle | ||
lodash underscore minus="result, shuffle" | ||
``` | ||
* Use the `plus` argument to pass comma separated method/category names to add to those included in the build. | ||
```bash | ||
lodash backbone legacy exports=global category=utilities exclude=first,last | ||
lodash -s underscore mobile strict exports=amd category=functions include=pick,uniq | ||
lodash backbone plus=random,template | ||
lodash backbone plus="random, template" | ||
``` | ||
* Use the `template` argument to pass the file path pattern used to match template files to precompile | ||
```bash | ||
lodash template="./*.jst" | ||
``` | ||
* Use the `settings` argument to pass the template settings used when precompiling templates | ||
```bash | ||
lodash settings="{interpolate:/\\{\\{([\\s\\S]+?)\\}\\}/g}" | ||
``` | ||
All arguments, except `legacy` with `csp` or `mobile`, may be combined.<br> | ||
Unless specified by `-o` or `--output`, all files created are saved to the current working directory. | ||
The following options are also supported: | ||
* `-c`, `--stdout` Write output to standard output | ||
* `-h`, `--help` Display help information | ||
* `-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 | ||
* `-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 | ||
The `lodash` command-line utility is available when Lo-Dash is installed as a global package (i.e. `npm install -g lodash`). | ||
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`. | ||
## Installation and usage | ||
@@ -203,29 +206,19 @@ | ||
## Resolved Underscore.js issues <sup>(20+)</sup> | ||
## Resolved Underscore.js issues | ||
* Allow iteration of objects with a `length` property [[#148](https://github.com/documentcloud/underscore/issues/148), [#154](https://github.com/documentcloud/underscore/issues/154), [#252](https://github.com/documentcloud/underscore/issues/252), [#448](https://github.com/documentcloud/underscore/issues/448), [#659](https://github.com/documentcloud/underscore/issues/659), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L543-549)] | ||
* Ensure array-like objects with invalid `length` properties are treated like regular objects [[#741](https://github.com/documentcloud/underscore/issues/741), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L491-501)] | ||
* Ensure *“Arrays”*, *“Collections”*, and *“Objects”* methods don’t error when passed falsey arguments [[#650](https://github.com/documentcloud/underscore/pull/650), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1719-1754)] | ||
* Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L503-520)] | ||
* Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L554-579)] | ||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L134-140)] | ||
* Register as an AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L118-132)] | ||
* `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L223-234)] | ||
* `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L289-298)] | ||
* `_.countBy` and `_.groupBy` should only add values to own, not inherited, properties [[#736](https://github.com/documentcloud/underscore/issues/736), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L306-313)] | ||
* `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L946-968)] | ||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L486-489)] | ||
* `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L581-600)] | ||
* `_.isElement` should use strict equality for its duck type check [[#734](https://github.com/documentcloud/underscore/issues/734), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L696-705)] | ||
* `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L732-737)] | ||
* `_.isEqual` should return `true` for like-objects from different documents [[#733](https://github.com/documentcloud/underscore/issues/733), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L784-795)] | ||
* `_.isEqual` should use custom `isEqual` methods before checking strict equality [[#748](https://github.com/documentcloud/underscore/issues/748), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L758-761)] | ||
* `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L803-815)] | ||
* `_.isNaN(new Number(NaN))` should return `true` [[#749](https://github.com/documentcloud/underscore/issues/749), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L823-825)] | ||
* `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L879-881)] | ||
* `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1222-1225)] | ||
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1257-1271)] | ||
* `_.sortedIndex` should support arrays with high `length` values [[#735](https://github.com/documentcloud/underscore/issues/735), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1404-1413)] | ||
* `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1534-1544)] | ||
* `_.toArray` uses custom `toArray` methods of arrays and strings [[#747](https://github.com/documentcloud/underscore/issues/747), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1571-1579)] | ||
* Add AMD loader support [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L118-140)] | ||
* Allow iteration of objects with a `length` property [[#799](https://github.com/documentcloud/underscore/pull/799), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L510-516)] | ||
* Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L470-487)] | ||
* Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L526-546)] | ||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L142-148)] | ||
* `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L215-224)] | ||
* `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L267-276)] | ||
* `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L946-968)] | ||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L465-468)] | ||
* `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L556-570)] | ||
* `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L703-708)] | ||
* `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L763-775)] | ||
* `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L856-858)] | ||
* `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L1222-1225)] | ||
* `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L1525-1535)] | ||
@@ -236,7 +229,5 @@ ## Optimized methods <sup>(50+)</sup> | ||
* `_.bindAll` | ||
* `_.clone` | ||
* `_.compact` | ||
* `_.contains`, `_.include` | ||
* `_.defaults` | ||
* `_.defer` | ||
* `_.difference` | ||
@@ -258,3 +249,2 @@ * `_.each` | ||
* `_.isDate` | ||
* `_.isEmpty` | ||
* `_.isFinite` | ||
@@ -286,3 +276,2 @@ * `_.isFunction` | ||
* `_.throttle` | ||
* `_.times` | ||
* `_.toArray` | ||
@@ -292,2 +281,3 @@ * `_.union` | ||
* `_.values` | ||
* `_.where` | ||
* `_.without` | ||
@@ -300,26 +290,21 @@ * `_.wrap` | ||
### <sup>v0.7.0</sup> | ||
### <sup>v0.8.0</sup> | ||
#### Compatibility Warnings #### | ||
* Renamed `_.zipObject` to `_.object` | ||
* Replaced `_.drop` with `_.omit` | ||
* Made `_.drop` alias `_.rest` | ||
* Made `_.random` return `0` or `1` when no arguments are passed | ||
* Moved late bind functionality from `_.bind` to [_.lateBind](http://lodash.com/docs#lateBind) | ||
* Removed first argument falsey checks from methods | ||
* Removed support for custom `clone`, `isEqual`, `toArray` methods from<br> | ||
`_.clone`, `_.isEqual`, and `_.toArray` | ||
#### Changes #### | ||
* Added [_.invert](http://lodash.com/docs#invert), [_.pairs](http://lodash.com/docs#pairs), and [_.random](http://lodash.com/docs#random) | ||
* Added `_.result` to the `backbone` build | ||
* Added `exports`, `iife`, `-c`/`--stdout`, `-o`/`--output`, and `-s`/`--silent` build options | ||
* Ensured `isPlainObject` works with objects from other documements | ||
* Ensured `_.isEqual` compares values with circular references correctly | ||
* Ensured `_.merge` work with four or more arguments | ||
* Ensured `_.sortBy` performs a stable sort for `undefined` values | ||
* Ensured `_.template` works with "interpolate" delimiters containing ternary operators | ||
* Ensured the production build works in Node.js | ||
* Ensured template delimiters are tokenized correctly | ||
* Made pseudo private properties `_chain` and `_wrapped` double-underscored to avoid conflicts | ||
* Made `minify.js` support `underscore.js` | ||
* Reduced the size of `mobile` and `underscore` builds | ||
* Simplified `_.isEqual` and `_.size` | ||
* Added `-d`/`--debug`, `-m/--minify`, `minus`, `plus`, `settings`, and `template` build options | ||
* Added `_.isPlainObject` and `_.lateBind` | ||
* Allowed `_.sortedIndex` to accept a property name as the `callback` argument | ||
* Ensured methods accept a `thisArg` of `null` | ||
* Fixed the `iife` build option to accept more values | ||
* Made `_.times` return an array of `callback` results | ||
* Simplified `_.max`, `_.min`, and `_.reduceRight` | ||
@@ -326,0 +311,0 @@ The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog). |
@@ -137,2 +137,3 @@ #!/usr/bin/env node | ||
'delay', | ||
'lateBind', | ||
'memoize', | ||
@@ -168,2 +169,3 @@ 'once', | ||
'isObject', | ||
'isPlainObject', | ||
'isRegExp', | ||
@@ -242,14 +244,8 @@ 'isString', | ||
var underscoreMethods = _.without.apply(_, [allMethods].concat([ | ||
'countBy', | ||
'forIn', | ||
'forOwn', | ||
'invert', | ||
'isPlainObject', | ||
'lateBind', | ||
'merge', | ||
'object', | ||
'omit', | ||
'pairs', | ||
'partial', | ||
'random', | ||
'unescape', | ||
'where' | ||
'partial' | ||
])); | ||
@@ -299,2 +295,27 @@ | ||
/** | ||
* Gets the names of methods belonging to the given `category`. | ||
* | ||
* @private | ||
* @param {String} category The category to filter by. | ||
* @returns {Array} Returns a new array of method names belonging to the given category. | ||
*/ | ||
function getMethodsByCategory(category) { | ||
switch (category) { | ||
case 'Arrays': | ||
return arraysMethods.slice(); | ||
case 'Chaining': | ||
return chainingMethods.slice(); | ||
case 'Collections': | ||
return collectionsMethods.slice(); | ||
case 'Functions': | ||
return functionsMethods.slice(); | ||
case 'Objects': | ||
return objectsMethods.slice(); | ||
case 'Utilities': | ||
return utilityMethods.slice(); | ||
} | ||
return []; | ||
} | ||
/** | ||
* Gets the real name, not alias, of a given function name. | ||
@@ -377,2 +398,6 @@ * | ||
func(1, noop); | ||
} else if (methodName == 'bindAll') { | ||
func({ 'noop': noop }); | ||
} else if (methodName == 'lateBind') { | ||
func(lodash, 'identity', array, string); | ||
} else if (/^(?:bind|partial)$/.test(methodName)) { | ||
@@ -384,4 +409,2 @@ func(noop, object, array, string); | ||
func(noop, 100); | ||
} else if (methodName == 'bindAll') { | ||
func({ 'noop': noop }); | ||
} else { | ||
@@ -422,3 +445,3 @@ func(noop); | ||
} | ||
equal(pass, true, methodName + ': ' + message); | ||
equal(pass, true, '_.' + methodName + ': ' + message); | ||
} | ||
@@ -428,93 +451,65 @@ | ||
QUnit.module('lodash build'); | ||
QUnit.module('minified AMD snippet'); | ||
(function() { | ||
var commands = [ | ||
'backbone', | ||
'csp', | ||
'legacy', | ||
'mobile', | ||
'strict', | ||
'underscore', | ||
'category=arrays', | ||
'category=chaining', | ||
'category=collections', | ||
'category=functions', | ||
'category=objects', | ||
'category=utilities', | ||
'exclude=union,uniq,zip', | ||
'include=each,filter,map', | ||
'category=collections,functions', | ||
'underscore backbone', | ||
'backbone legacy category=utilities exclude=first,last', | ||
'underscore mobile strict category=functions exports=amd,global include=pick,uniq', | ||
] | ||
.concat( | ||
allMethods.map(function(methodName) { | ||
return 'include=' + methodName; | ||
}) | ||
); | ||
var start = _.once(QUnit.start); | ||
commands.forEach(function(command) { | ||
asyncTest('`lodash`', function() { | ||
build(['-s'], function(source, filePath) { | ||
// used by r.js build optimizer | ||
var defineHasRegExp = /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g, | ||
basename = path.basename(filePath, '.js'); | ||
ok(!!defineHasRegExp.exec(source), basename); | ||
start(); | ||
}); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('template builds'); | ||
(function() { | ||
var templatePath = __dirname + '/template'; | ||
asyncTest('`lodash template=*.jst`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
asyncTest('`lodash ' + command +'`', function() { | ||
build(['--silent'].concat(command.split(' ')), function(source, filepath) { | ||
var basename = path.basename(filepath, '.js'), | ||
context = createContext(), | ||
methodNames = []; | ||
build(['-s', 'template=' + templatePath + '/*.jst'], function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
try { | ||
vm.runInContext(source, context); | ||
} catch(e) { } | ||
var data = { | ||
'a': { 'people': ['moe', 'larry', 'curly'] }, | ||
'b': { 'epithet': 'stooge' } | ||
}; | ||
if (/underscore/.test(command)) { | ||
methodNames = underscoreMethods; | ||
} | ||
if (/backbone/.test(command)) { | ||
methodNames = backboneDependencies; | ||
} | ||
if (/include/.test(command)) { | ||
methodNames = methodNames.concat(command.match(/include=(\S*)/)[1].split(/, */)); | ||
} | ||
if (/category/.test(command)) { | ||
methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) { | ||
switch (category) { | ||
case 'arrays': | ||
return result.concat(arraysMethods); | ||
case 'chaining': | ||
return result.concat(chainingMethods); | ||
case 'collections': | ||
return result.concat(collectionsMethods); | ||
case 'functions': | ||
return result.concat(functionsMethods); | ||
case 'objects': | ||
return result.concat(objectsMethods); | ||
case 'utilities': | ||
return result.concat(utilityMethods); | ||
} | ||
return result; | ||
}, methodNames); | ||
} | ||
if (!methodNames.length) { | ||
methodNames = allMethods; | ||
} | ||
context._ = _; | ||
vm.runInContext(source, context); | ||
var templates = context._.templates; | ||
if (/exclude/.test(command)) { | ||
methodNames = _.without.apply(_, [methodNames].concat( | ||
expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */)) | ||
)); | ||
} else { | ||
methodNames = expandMethodNames(methodNames); | ||
} | ||
equal(templates.a(data.a).replace(/[\r\n]+/g, ''), '<ul><li>moe</li><li>larry</li><li>curly</li></ul>', basename); | ||
equal(templates.b(data.b), 'Hello stooge.', basename); | ||
start(); | ||
}); | ||
}); | ||
var lodash = context._ || {}; | ||
methodNames = _.unique(methodNames); | ||
asyncTest('`lodash settings=...`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
methodNames.forEach(function(methodName) { | ||
testMethod(lodash, methodName, basename); | ||
}); | ||
build(['-s', 'template=' + templatePath + '/*.tpl', 'settings={interpolate:/\\{\\{([\\s\\S]+?)\\}\\}/}'], function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
start(); | ||
}); | ||
var data = { | ||
'c': { 'name': 'Mustache' } | ||
}; | ||
context._ = _; | ||
vm.runInContext(source, context); | ||
var templates = context._.templates; | ||
equal(templates.c(data.c), 'Hello Mustache!', basename); | ||
start(); | ||
}); | ||
@@ -526,2 +521,40 @@ }); | ||
QUnit.module('independent builds'); | ||
(function() { | ||
asyncTest('debug only', function() { | ||
var start = _.once(QUnit.start); | ||
build(['-d', '-s'], function(source, filePath) { | ||
equal(path.basename(filePath, '.js'), 'lodash'); | ||
start(); | ||
}); | ||
}); | ||
asyncTest('debug custom', function () { | ||
var start = _.once(QUnit.start); | ||
build(['-d', '-s', 'backbone'], function(source, filePath) { | ||
equal(path.basename(filePath, '.js'), 'lodash.custom'); | ||
start(); | ||
}); | ||
}); | ||
asyncTest('minified only', function() { | ||
var start = _.once(QUnit.start); | ||
build(['-m', '-s'], function(source, filePath) { | ||
equal(path.basename(filePath, '.js'), 'lodash.min'); | ||
start(); | ||
}); | ||
}); | ||
asyncTest('minified custom', function () { | ||
var start = _.once(QUnit.start); | ||
build(['-m', '-s', 'backbone'], function(source, filePath) { | ||
equal(path.basename(filePath, '.js'), 'lodash.custom.min'); | ||
start(); | ||
}); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('strict modifier'); | ||
@@ -536,12 +569,11 @@ | ||
['non-strict', 'strict'].forEach(function(strictMode, index) { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
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)); | ||
asyncTest(strictMode + ' should ' + (index ? 'error': 'silently fail') + ' attempting to overwrite read-only properties', function() { | ||
var commands = ['-s', 'include=bindAll,defaults,extend']; | ||
if (index) { | ||
commands.push('strict'); | ||
} | ||
build(commands, function(source, filepath) { | ||
var basename = path.basename(filepath, '.js'), | ||
build(commands, function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(), | ||
@@ -572,8 +604,9 @@ pass = !index; | ||
(function() { | ||
var start = _.once(QUnit.start); | ||
asyncTest('modified methods should work correctly', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
asyncTest('should not have deep clone', function() { | ||
build(['-s', 'underscore'], function(source, filepath) { | ||
var array = [{ 'a': 1 }], | ||
basename = path.basename(filepath, '.js'), | ||
build(['-s', 'underscore'], function(source, filePath) { | ||
var last, | ||
array = [{ 'value': 1 }, { 'value': 2 }], | ||
basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
@@ -584,6 +617,32 @@ | ||
ok(lodash.clone(array, true)[0] === array[0], basename); | ||
lodash.each(array, function(value) { | ||
last = value; | ||
return false; | ||
}); | ||
equal(last.value, 2, '_.each: ' + basename); | ||
equal(lodash.isEmpty('moe'), false, '_.isEmpty: ' + basename); | ||
var object = { 'fn': lodash.bind(function(x) { return this.x + x; }, { 'x': 1 }, 1) }; | ||
equal(object.fn(), 2, '_.bind: ' + basename); | ||
ok(lodash.clone(array, true)[0] === array[0], '_.clone: ' + basename); | ||
start(); | ||
}); | ||
}); | ||
asyncTest('`lodash underscore include=partial`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
build(['-s', 'underscore', 'include=partial'], function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
vm.runInContext(source, context); | ||
var lodash = context._; | ||
equal(lodash.partial(_.identity, 2)(), 2, '_.partial: ' + basename); | ||
start(); | ||
}); | ||
}); | ||
}()); | ||
@@ -605,7 +664,7 @@ | ||
commands.forEach(function(command, index) { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
asyncTest('`lodash ' + command +'`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
asyncTest('`lodash ' + command +'`', function() { | ||
build(['-s', command], function(source, filepath) { | ||
var basename = path.basename(filepath, '.js'), | ||
build(['-s', command], function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(), | ||
@@ -660,17 +719,29 @@ pass = false; | ||
(function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
var commands = [ | ||
'iife=this["lodash"]=(function(window,undefined){%output%;return lodash}(this))', | ||
'iife=define(function(window,undefined){return function(){%output%;return lodash}}(this));' | ||
]; | ||
asyncTest('`lodash iife=...`', function() { | ||
build(['-s', 'iife=!function(window,undefined){%output%}(this)'], function(source, filepath) { | ||
var basename = path.basename(filepath, '.js'), | ||
context = createContext(); | ||
commands.forEach(function(command) { | ||
asyncTest('`lodash ' + command +'`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
try { | ||
vm.runInContext(source, context); | ||
} catch(e) { } | ||
build(['-s', 'exports=none', command], function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
var lodash = context._ || {}; | ||
ok(_.isString(lodash.VERSION), basename); | ||
ok(/!function/.test(source), basename); | ||
start(); | ||
context.define = function(func) { | ||
context.lodash = func(); | ||
}; | ||
try { | ||
vm.runInContext(source, context); | ||
} catch(e) { | ||
console.log(e); | ||
} | ||
var lodash = context.lodash || {}; | ||
ok(_.isString(lodash.VERSION), basename); | ||
start(); | ||
}); | ||
}); | ||
@@ -686,7 +757,7 @@ }); | ||
['-o a.js', '--output a.js'].forEach(function(command, index) { | ||
var start = _.once(QUnit.start); | ||
asyncTest('`lodash ' + command +'`', function() { | ||
var start = _.once(QUnit.start); | ||
asyncTest('`lodash ' + command +'`', function() { | ||
build(['-s'].concat(command.split(' ')), function(source, filepath) { | ||
equal(filepath, 'a.js', command); | ||
build(['-s'].concat(command.split(' ')), function(source, filePath) { | ||
equal(path.basename(filePath, '.js'), 'a', command); | ||
start(); | ||
@@ -704,8 +775,14 @@ }); | ||
['-c', '--stdout'].forEach(function(command, index) { | ||
var descriptor = Object.getOwnPropertyDescriptor(global, 'console'), | ||
start = _.once(QUnit.start); | ||
asyncTest('`lodash ' + command +'`', function() { | ||
var written, | ||
start = _.once(QUnit.start), | ||
write = process.stdout.write; | ||
asyncTest('`lodash ' + command +'`', function() { | ||
build([command, 'exports=', 'include='], function(source, filepath) { | ||
equal(source, ''); | ||
process.stdout.write = function(string) { | ||
written = string; | ||
}; | ||
build([command, 'exports=', 'include='], function(source) { | ||
process.stdout.write = write; | ||
equal(written, source); | ||
equal(arguments.length, 1); | ||
@@ -723,6 +800,6 @@ start(); | ||
(function() { | ||
var start = _.once(QUnit.start); | ||
asyncTest('`node minify underscore.js`', function() { | ||
var source = fs.readFileSync(path.join(__dirname, '..', 'vendor', 'underscore', 'underscore.js'), 'utf8'), | ||
start = _.once(QUnit.start); | ||
asyncTest('`node minify underscore.js`', function() { | ||
var source = fs.readFileSync(path.join(__dirname, '..', 'vendor', 'underscore', 'underscore.js'), 'utf8'); | ||
minify(source, { | ||
@@ -736,7 +813,9 @@ 'silent': true, | ||
vm.runInContext(result, context); | ||
} catch(e) { } | ||
} catch(e) { | ||
console.log(e); | ||
} | ||
var underscore = context._ || {}; | ||
ok(_.isString(underscore.VERSION)); | ||
ok(result.match(/\n/g).length < source.match(/\n/g).length); | ||
ok(!/Lo-Dash/.test(result) && result.match(/\n/g).length < source.match(/\n/g).length); | ||
start(); | ||
@@ -748,2 +827,143 @@ } | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('mobile build'); | ||
(function() { | ||
asyncTest('`lodash mobile`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
build(['-s', 'mobile'], function(source, filePath) { | ||
var basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
try { | ||
vm.runInContext(source, context); | ||
} catch(e) { | ||
console.log(e); | ||
} | ||
var array = [1, 2, 3], | ||
object1 = [{ 'a': 1 }], | ||
object2 = [{ 'b': 2 }], | ||
object3 = [{ 'a': 1, 'b': 2 }], | ||
circular1 = { 'a': 1 }, | ||
circular2 = { 'a': 1 }, | ||
lodash = context._; | ||
circular1.b = circular1; | ||
circular2.b = circular2; | ||
deepEqual(lodash.merge(object1, object2), object3, basename); | ||
deepEqual(lodash.sortBy([3, 2, 1], _.identity), array, basename); | ||
equal(lodash.isEqual(circular1, circular2), true, basename); | ||
var actual = lodash.clone(circular1, true); | ||
ok(actual != circular1 && actual.b == actual, basename); | ||
start(); | ||
}); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash build'); | ||
(function() { | ||
var commands = [ | ||
'backbone', | ||
'csp', | ||
'legacy', | ||
'mobile', | ||
'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', | ||
'underscore backbone', | ||
'backbone legacy category=utilities minus=first,last', | ||
'underscore include=debounce,throttle plus=after minus=throttle', | ||
'underscore mobile strict category=functions exports=amd,global plus=pick,uniq', | ||
] | ||
.concat( | ||
allMethods.map(function(methodName) { | ||
return 'include=' + methodName; | ||
}) | ||
); | ||
commands.forEach(function(command) { | ||
asyncTest('`lodash ' + command +'`', function() { | ||
var start = _.after(2, _.once(QUnit.start)); | ||
build(['--silent'].concat(command.split(' ')), function(source, filePath) { | ||
var methodNames, | ||
basename = path.basename(filePath, '.js'), | ||
context = createContext(); | ||
try { | ||
vm.runInContext(source, context); | ||
} catch(e) { | ||
console.log(e); | ||
} | ||
// add method names explicitly | ||
if (/include/.test(command)) { | ||
methodNames = command.match(/include=(\S*)/)[1].split(/, */); | ||
} | ||
// add method names required by Backbone and Underscore builds | ||
if (/backbone/.test(command) && !methodNames) { | ||
methodNames = backboneDependencies.slice(); | ||
} | ||
if (/underscore/.test(command) && !methodNames) { | ||
methodNames = underscoreMethods.slice(); | ||
} | ||
// add method names explicitly by category | ||
if (/category/.test(command)) { | ||
// resolve method names belonging to each category (case-insensitive) | ||
methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) { | ||
var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1); | ||
return result.concat(getMethodsByCategory(capitalized)); | ||
}, methodNames || []); | ||
} | ||
// init `methodNames` if it hasn't been inited | ||
if (!methodNames) { | ||
methodNames = allMethods.slice(); | ||
} | ||
if (/plus/.test(command)) { | ||
methodNames = methodNames.concat(command.match(/plus=(\S*)/)[1].split(/, */)); | ||
} | ||
if (/minus/.test(command)) { | ||
methodNames = _.without.apply(_, [methodNames] | ||
.concat(expandMethodNames(command.match(/minus=(\S*)/)[1].split(/, */)))); | ||
} | ||
if (/exclude/.test(command)) { | ||
methodNames = _.without.apply(_, [methodNames] | ||
.concat(expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */)))); | ||
} | ||
// expand aliases and categories to real method names | ||
methodNames = expandMethodNames(methodNames).reduce(function(result, methodName) { | ||
return result.concat(methodName, getMethodsByCategory(methodName)); | ||
}, []); | ||
// remove nonexistent and duplicate method names | ||
methodNames = _.uniq(_.intersection(allMethods, expandMethodNames(methodNames))); | ||
var lodash = context._ || {}; | ||
methodNames.forEach(function(methodName) { | ||
testMethod(lodash, methodName, basename); | ||
}); | ||
start(); | ||
}); | ||
}); | ||
}); | ||
}()); | ||
}()); |
265
test/test.js
@@ -109,3 +109,3 @@ ;(function(window, undefined) { | ||
// ensure this test is executed before any other template tests to avoid false positives | ||
test('should initialize `reEvaluateDelimiter` correctly (test with production build)', function() { | ||
test('should initialize `reEvaluateDelimiter` (test with production build)', function() { | ||
var data = { 'a': [1, 2] }, | ||
@@ -127,2 +127,10 @@ settings = _.templateSettings; | ||
test('supports loading lodash.js with the Require.js "shim" configuration option', function() { | ||
if (window.document && window.require) { | ||
equal((shimmedModule || {}).moduleName, 'shimmed'); | ||
} else { | ||
skipTest(); | ||
} | ||
}); | ||
test('supports loading lodash.js as the "underscore" module', function() { | ||
@@ -165,3 +173,3 @@ if (window.document && window.require) { | ||
(function() { | ||
test('should correctly append array arguments to partially applied arguments (test in IE < 9)', function() { | ||
test('should append array arguments to partially applied arguments (test in IE < 9)', function() { | ||
var args, | ||
@@ -173,19 +181,2 @@ bound = _.bind(function() { args = slice.call(arguments); }, {}, 'a'); | ||
}); | ||
test('supports lazy bind', function() { | ||
var object = { | ||
'name': 'moe', | ||
'greet': function(greeting) { | ||
return greeting + ': ' + this.name; | ||
} | ||
}; | ||
var func = _.bind(object, 'greet', 'hi'); | ||
equal(func(), 'hi: moe'); | ||
object.greet = function(greeting) { | ||
return greeting + ' ' + this.name + '!'; | ||
}; | ||
equal(func(), 'hi moe!'); | ||
}); | ||
}()); | ||
@@ -228,3 +219,3 @@ | ||
_.forOwn(objects, function(object, key) { | ||
test('should deep clone ' + key + ' correctly', function() { | ||
test('should deep clone ' + key, function() { | ||
var clone = _.clone(object, true); | ||
@@ -268,15 +259,2 @@ ok(_.isEqual(object, clone)); | ||
test('should clone using Klass#clone', function() { | ||
var object = new Klass; | ||
Klass.prototype.clone = function() { return new Klass; }; | ||
var clone = _.clone(object); | ||
ok(clone !== object && clone instanceof Klass); | ||
clone = _.clone(object, true); | ||
ok(clone !== object && clone instanceof Klass); | ||
delete Klass.prototype.clone; | ||
}); | ||
test('should clone problem JScript properties (test in IE < 9)', function() { | ||
@@ -350,3 +328,3 @@ deepEqual(_.clone(shadowed), shadowed); | ||
(function() { | ||
test('should work correctly when using `cachedContains`', function() { | ||
test('should work when using `cachedContains`', function() { | ||
var array1 = _.range(27), | ||
@@ -410,7 +388,8 @@ array2 = array1.slice(), | ||
QUnit.module('strict mode checks'); | ||
_.each(['bindAll', 'defaults', 'extend'], function(methodName) { | ||
var func = _[methodName]; | ||
QUnit.module('lodash.' + methodName + ' strict mode checks'); | ||
test('should not throw strict mode errors', function() { | ||
test('lodash.' + methodName + ' should not throw strict mode errors', function() { | ||
var object = { 'a': null, 'b': function(){} }, | ||
@@ -427,3 +406,3 @@ pass = true; | ||
} | ||
} catch(e) { | ||
} catch(e) {console.log(e); | ||
pass = false; | ||
@@ -500,14 +479,2 @@ } | ||
test('should treat array-like object with invalid `length` as a regular object', function() { | ||
var keys = [], | ||
object = { 'length': -1 }; | ||
_.forEach(object, function(value, key) { keys.push(key); }); | ||
deepEqual(keys, ['length']); | ||
keys = []; object.length = Math.pow(2, 32); | ||
_.forEach(object, function(value, key) { keys.push(key); }); | ||
deepEqual(keys, ['length']); | ||
}); | ||
_.each({ | ||
@@ -564,7 +531,8 @@ 'literal': 'abc', | ||
QUnit.module('object iteration bugs'); | ||
_.each(['forEach', 'forIn', 'forOwn'], function(methodName) { | ||
var func = _[methodName]; | ||
QUnit.module('lodash.' + methodName + ' iteration bugs'); | ||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { | ||
test('lodash.' + methodName + ' fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { | ||
var keys = []; | ||
@@ -575,3 +543,3 @@ func(shadowed, function(value, key) { keys.push(key); }); | ||
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { | ||
test('lodash.' + methodName + ' skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { | ||
function Foo() {} | ||
@@ -593,7 +561,10 @@ Foo.prototype.a = 1; | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('exit early'); | ||
_.each(['forEach', 'forIn', 'forOwn'], function(methodName) { | ||
var func = _[methodName]; | ||
QUnit.module('lodash.' + methodName + ' can exit early'); | ||
test('can exit early when iterating arrays', function() { | ||
test('lodash.' + methodName + ' can exit early when iterating arrays', function() { | ||
var array = [1, 2, 3], | ||
@@ -606,3 +577,3 @@ values = []; | ||
test('can exit early when iterating objects', function() { | ||
test('lodash.' + methodName + ' can exit early when iterating objects', function() { | ||
var object = { 'a': 1, 'b': 2, 'c': 3 }, | ||
@@ -772,13 +743,2 @@ values = []; | ||
test('should respect custom `isEqual` result despite objects strict equaling each other', function() { | ||
var object = { 'isEqual': function() { return false; } }; | ||
equal(_.isEqual(object, object), false); | ||
}); | ||
test('should use custom `isEqual` methods on primitives', function() { | ||
Boolean.prototype.isEqual = function() { return true; }; | ||
equal(_.isEqual(true, false), true); | ||
delete Boolean.prototype.isEqual; | ||
}); | ||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { | ||
@@ -845,2 +805,20 @@ equal(_.isEqual(shadowed, {}), false); | ||
QUnit.module('lodash.isPlainObject'); | ||
(function() { | ||
test('should detect plain objects', function() { | ||
function Foo(a) { | ||
this.a = 1; | ||
} | ||
equal(_.isPlainObject(new Foo(1)), false); | ||
equal(_.isPlainObject([1, 2, 3]), false); | ||
equal(_.isPlainObject({ 'a': 1 }), true); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('isType checks'); | ||
_.each([ | ||
@@ -865,5 +843,4 @@ 'isArguments', | ||
var func = _[methodName]; | ||
QUnit.module('lodash.' + methodName + ' result'); | ||
test('should return a boolean', function() { | ||
test('lodash.' + methodName + ' should return a boolean', function() { | ||
var expected = 'boolean'; | ||
@@ -958,2 +935,25 @@ | ||
QUnit.module('lodash.lateBind'); | ||
(function() { | ||
test('should work when the target function is overwritten', function() { | ||
var object = { | ||
'name': 'moe', | ||
'greet': function(greeting) { | ||
return greeting + ': ' + this.name; | ||
} | ||
}; | ||
var func = _.lateBind(object, 'greet', 'hi'); | ||
equal(func(), 'hi: moe'); | ||
object.greet = function(greeting) { | ||
return greeting + ' ' + this.name + '!'; | ||
}; | ||
equal(func(), 'hi moe!'); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.merge'); | ||
@@ -1206,5 +1206,5 @@ | ||
(function() { | ||
test('should work like `Math.random` if no arguments are passed', function() { | ||
test('should return `0` or `1` when no arguments are passed', function() { | ||
var actual = _.random(); | ||
ok(actual >= 0 && actual < 1); | ||
ok(actual === 0 || actual === 1); | ||
}); | ||
@@ -1292,18 +1292,2 @@ | ||
test('should treat array-like object with invalid `length` as a regular object', function() { | ||
var args, | ||
object = { 'a': 1, 'length': -1 }, | ||
lastKey = _.keys(object).pop(); | ||
var expected = lastKey == 'length' | ||
? [-1, 1, 'a', object] | ||
: [1, -1, 'length', object]; | ||
_.reduceRight(object, function() { | ||
args || (args = slice.call(arguments)); | ||
}); | ||
deepEqual(args, expected); | ||
}); | ||
_.each({ | ||
@@ -1531,3 +1515,3 @@ 'literal': 'abc', | ||
test('should tokenize delimiters correctly', function() { | ||
test('should tokenize delimiters', function() { | ||
var compiled = _.template('<span class="icon-<%= type %>2"></span>'); | ||
@@ -1541,2 +1525,9 @@ equal(compiled({ 'type': 1 }), '<span class="icon-12"></span>'); | ||
}); | ||
test('should parse delimiters with newlines', function() { | ||
var expected = '<<\nprint("<p>" + (value ? "yes" : "no") + "</p>")\n>>', | ||
compiled = _.template(expected, null, { 'evaluate': /<<(.+?)>>/g }); | ||
equal(compiled({ 'value': true }), expected); | ||
}); | ||
}()); | ||
@@ -1593,12 +1584,2 @@ | ||
_.each({ | ||
'an array': ['a', 'b', 'c'], | ||
'a string': Object('abc') | ||
}, function(collection, key) { | ||
test('should call custom `toArray` method of ' + key, function() { | ||
collection.toArray = function() { return [3, 2, 1]; }; | ||
deepEqual(_.toArray(collection), [3, 2, 1]); | ||
}); | ||
}); | ||
test('should treat array-like objects like arrays', function() { | ||
@@ -1610,7 +1591,2 @@ var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 }; | ||
test('should treat array-like object with invalid `length` as a regular object', function() { | ||
var object = { 'length': -1 }; | ||
deepEqual(_.toArray(object), [-1]); | ||
}); | ||
test('should work with a string for `collection` (test in Opera < 10.52)', function() { | ||
@@ -1624,2 +1600,12 @@ deepEqual(_.toArray('abc'), ['a', 'b', 'c']); | ||
QUnit.module('lodash.times'); | ||
(function() { | ||
test('should return an array of the results of each `callback` execution', function() { | ||
deepEqual(_.times(3, function(n) { return n * 2; }), [0, 2, 4]); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.unescape'); | ||
@@ -1744,36 +1730,53 @@ | ||
(function() { | ||
test('should allow falsey arguments', function() { | ||
var funcs = _.without.apply(_, [_.functions(_)].concat([ | ||
'_', | ||
'_iteratorTemplate', | ||
'_shimKeys', | ||
'after', | ||
'bind', | ||
'bindAll', | ||
'compose', | ||
'debounce', | ||
'defer', | ||
'delay', | ||
'functions', | ||
'memoize', | ||
'once', | ||
'partial', | ||
'tap', | ||
'throttle', | ||
'wrap' | ||
])); | ||
test('should handle `null` `thisArg` arguments', function() { | ||
var thisArg, | ||
array = ['a'], | ||
callback = function() { thisArg = this; }, | ||
useStrict = (function() { return this; }).call(null) === null; | ||
var funcs = [ | ||
'countBy', | ||
'every', | ||
'filter', | ||
'find', | ||
'forEach', | ||
'forIn', | ||
'forOwn', | ||
'groupBy', | ||
'map', | ||
'max', | ||
'min', | ||
'omit', | ||
'pick', | ||
'reduce', | ||
'reduceRight', | ||
'reject', | ||
'some', | ||
'sortBy', | ||
'sortedIndex', | ||
'times', | ||
'uniq' | ||
]; | ||
_.each(funcs, function(methodName) { | ||
var func = _[methodName], | ||
pass = true; | ||
message = '_.' + methodName + ' handles `null` `thisArg` arguments'; | ||
_.each(falsey, function(value, index) { | ||
try { | ||
index ? func(value) : func(); | ||
} catch(e) { | ||
pass = false; | ||
} | ||
}); | ||
thisArg = undefined; | ||
ok(pass, methodName + ' allows falsey arguments'); | ||
if (/^reduce/.test(methodName)) { | ||
func(array, callback, 0, null); | ||
} else if (methodName == 'sortedIndex') { | ||
func(array, 'a', callback, null); | ||
} else if (methodName == 'times') { | ||
func(1, callback, null); | ||
} else { | ||
func(array, callback, null); | ||
} | ||
if (useStrict) { | ||
deepEqual(thisArg, null, message); | ||
} else { | ||
equal(thisArg, window, message); | ||
} | ||
}); | ||
@@ -1780,0 +1783,0 @@ }); |
# Benchmark.js <sup>v1.0.0</sup> | ||
[![build status](https://secure.travis-ci.org/bestiejs/benchmark.js.png)](http://travis-ci.org/bestiejs/benchmark.js) | ||
@@ -3,0 +4,0 @@ A [robust](http://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/ "Bulletproof JavaScript benchmarks") benchmarking library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>, supports high-resolution timers, and returns statistically significant results. As seen on [jsPerf](http://jsperf.com/). |
@@ -833,6 +833,6 @@ /*! | ||
// add browser/OS architecture | ||
if ((data = / (?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { | ||
if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { | ||
if (os) { | ||
os.architecture = 64; | ||
os.family = os.family.replace(data, ''); | ||
os.family = os.family.replace(RegExp(' *' + data), ''); | ||
} | ||
@@ -839,0 +839,0 @@ if (name && (/WOW64/i.test(ua) || |
@@ -174,3 +174,8 @@ /*! | ||
try { | ||
process.exit(); | ||
if (details.failed) { | ||
console.error('Error: ' + details.failed + ' of ' + details.total + ' tests failed.'); | ||
process.exit(1); | ||
} else { | ||
process.exit(0); | ||
} | ||
} catch(e) { } | ||
@@ -177,0 +182,0 @@ } |
@@ -1,33 +0,5 @@ | ||
// Underscore.js 1.3.3 | ||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. | ||
// Underscore may be freely distributed under the MIT license. | ||
// Portions of Underscore are inspired or borrowed from Prototype, | ||
// Oliver Steele's Functional, and John Resig's Micro-Templating. | ||
// For all details and documentation: | ||
// http://documentcloud.github.com/underscore | ||
(function(){var s=this,K=s._,o={},k=Array.prototype,p=Object.prototype,L=k.push,g=k.slice,l=p.toString,M=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,N=Object.keys,t=Function.prototype.bind,b=function(a){if(a instanceof b)return a;if(!(this instanceof b))return new b(a);this._wrapped=a};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b; | ||
b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,h=a.length;e<h;e++){if(c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,f,i){e[e.length]=c.call(b,a,f,i)});return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var h=arguments.length>2;a==null&&(a=[]);if(A&& | ||
a.reduce===A){e&&(c=b.bind(c,e));return h?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,g){if(h)d=c.call(e,d,a,b,g);else{d=a;h=true}});if(!h)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var h=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return h?a.reduceRight(c,d):a.reduceRight(c)}var f=b.toArray(a).reverse();e&&!h&&(c=b.bind(c,e));return h?b.reduce(f,c,d,e):b.reduce(f,c)};b.find=b.detect=function(a, | ||
c,b){var e;G(a,function(a,f,i){if(c.call(b,a,f,i)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,f,i){c.call(b,a,f,i)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,f,i){c.call(b,a,f,i)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,d){c||(c=b.identity);var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,d);j(a,function(a,b, | ||
i){if(!(e=e&&c.call(d,a,b,i)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,i){if(e||(e=c.call(d,a,b,i)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=g.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c:a[c]).apply(a, | ||
d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,i){b=c?c.call(d,a,b,i):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a, | ||
function(a,b,i){b=c?c.call(d,a,b,i):a;b<e.computed&&(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var c,b=0,e=[];j(a,function(a){c=Math.floor(Math.random()*++b);e[b-1]=e[c];e[c]=a});return e};b.sortBy=function(a,c,d){var e=H(a,c);return b.pluck(b.map(a,function(a,c,b){return{value:a,criteria:e.call(d,a,c,b)}}).sort(function(a,c){var b=a.criteria,d=c.criteria;return b===void 0?1:d===void 0?-1:b<d?-1:b>d?1:0}),"value")};var H=function(a,c){return b.isFunction(c)?c:function(a){return a[c]}}, | ||
I=function(a,c,b){var e={},h=H(a,c);j(a,function(a,c){var g=h(a,c);b(e,g,a)});return e};b.groupBy=function(a,c){return I(a,c,function(a,c,b){(a[c]||(a[c]=[])).push(b)})};b.countBy=function(a,c){return I(a,c,function(a,c){a[c]||(a[c]=0);a[c]++})};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var c=d(c),e=0,h=a.length;e<h;){var f=e+h>>1;d(a[f])<c?e=f+1:h=f}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?g.call(a):b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size= | ||
function(a){return a.length===+a.length?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,c,b){return c!=null&&!b?g.call(a,0,c):a[0]};b.initial=function(a,c,b){return g.call(a,0,a.length-(c==null||b?1:c))};b.last=function(a,c,b){return c!=null&&!b?g.call(a,Math.max(a.length-c,0)):a[a.length-1]};b.rest=b.tail=b.drop=function(a,c,b){return g.call(a,c==null||b?1:c)};b.compact=function(a){return b.filter(a,function(a){return!!a})};var r=function(a,c,d){j(a,function(a){b.isArray(a)?c?L.apply(d, | ||
a):r(a,c,d):d.push(a)});return d};b.flatten=function(a,b){return r(a,b,[])};b.without=function(a){return b.difference(a,g.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,f,i){if(c?b.last(d)!==f||!d.length:!b.include(d,f)){d.push(f);e.push(a[i])}return d},[]);return e};b.union=function(){return b.uniq(r(arguments,true,[]))};b.intersection=function(a){var c=g.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c, | ||
a)>=0})})};b.difference=function(a){var c=r(g.call(arguments,1),true,[]);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=g.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.object=function(a,b){for(var d={},e=0,h=a.length;e<h;e++)b?d[a[e]]=b[e]:d[a[e][0]]=a[e][1];return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d= | ||
0;for(e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<=1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),h=0,f=Array(e);h<e;){f[h++]=a;a=a+d}return f};var J=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,g.call(arguments,1));if(!b.isFunction(a))throw new TypeError; | ||
e=g.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(g.call(arguments)));J.prototype=a.prototype;var b=new J,f=a.apply(b,e.concat(g.call(arguments)));return Object(f)===f?f:b}};b.bindAll=function(a){var c=g.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay= | ||
function(a,b){var d=g.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(g.call(arguments,1)))};b.throttle=function(a,c){var d,e,h,f,i,g,j=b.debounce(function(){i=f=false},c);return function(){d=this;e=arguments;h||(h=setTimeout(function(){h=null;i&&(g=a.apply(d,e));j()},c));if(f)i=true;else{f=true;g=a.apply(d,e)}j();return g}};b.debounce=function(a,b,d){var e;return function(){var h=this,f=arguments,i=d&&!e;clearTimeout(e); | ||
e=setTimeout(function(){e=null;d||a.apply(h,f)},b);i&&a.apply(h,f)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;d=a.apply(this,arguments);a=null;return d}};b.wrap=function(a,b){return function(){var d=[a].concat(g.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}}; | ||
b.keys=N||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.pairs=function(a){return b.map(a,function(a,b){return[b,a]})};b.invert=function(a){return b.reduce(a,function(a,b,e){a[b]=e;return a},{})};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(g.call(arguments,1),function(b){for(var d in b)a[d]= | ||
b[d]});return a};b.pick=function(a){var c={},d=b.flatten(g.call(arguments,1));j(d,function(b){b in a&&(c[b]=a[b])});return c};b.omit=function(a){var c={},d=b.flatten(g.call(arguments,1)),e;for(e in a)b.include(d,e)||(c[e]=a[e]);return c};b.defaults=function(a){j(g.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};var u=function(a,c,d,e){if(a===c)return a!== | ||
0||1/a==1/c;if(a==null||c==null)return a===c;if(a instanceof b)a=a._wrapped;if(c instanceof b)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var h=l.call(a);if(h!=l.call(c))return false;switch(h){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==c.source&&a.global==c.global&& | ||
a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return e[f]==c;d.push(a);e.push(c);var f=0,i=true;if(h=="[object Array]"){f=a.length;if(i=f==c.length)for(;f--;)if(!(i=f in a==f in c&&u(a[f],c[f],d,e)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var g in a)if(b.has(a,g)){f++;if(!(i=b.has(c,g)&&u(a[g],c[g],d,e)))break}if(i){for(g in c)if(b.has(c,g)&&!f--)break; | ||
i=!f}}d.pop();e.pop();return i};b.isEqual=function(a,b){return u(a,b,[],[])};b.isEmpty=function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};j("Arguments,Function,String,Number,Date,RegExp".split(","),function(a){b["is"+a]=function(b){return l.call(b)=="[object "+ | ||
a+"]"}});b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return M.call(a,b)};b.noConflict=function(){s._=K;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e= | ||
0;e<a;e++)b.call(d,e)};b.random=function(a,b){return a+(0|Math.random()*(b-a+1))};var m={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};m.unescape=b.invert(m.escape);var O={escape:RegExp("["+b.keys(m.escape).join("")+"]","g"),unescape:RegExp("("+b.keys(m.unescape).join("|")+")","g")};b.each(["escape","unescape"],function(a){b[a]=function(b){return b==null?"":(""+b).replace(O[a],function(b){return m[a][b]})}});b.result=function(a,c){if(a==null)return null;var d= | ||
a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){var d=b[c]=a[c];b.prototype[c]=function(){var a=g.call(arguments);a.unshift(this._wrapped);a=d.apply(b,a);return this._chain?b(a).chain():a}})};var P=0;b.uniqueId=function(a){var b=P++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var v=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},w;for(w in n)n[n[w]]= | ||
w;var Q=/\\|'|\r|\n|\t|\u2028|\u2029/g,R=/\\(\\|'|r|n|t|u2028|u2029)/g,x=function(a){return a.replace(R,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults({},d,b.templateSettings);a="__p+='"+a.replace(Q,function(a){return"\\"+n[a]}).replace(d.escape||v,function(a,b){return"'+\n((__t=("+x(b)+"))==null?'':_.escape(__t))+\n'"}).replace(d.interpolate||v,function(a,b){return"'+\n((__t=("+x(b)+"))==null?'':__t)+\n'"}).replace(d.evaluate||v,function(a,b){return"';\n"+x(b)+"\n__p+='"})+ | ||
"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");a="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{var e=new Function(d.variable||"obj","_",a)}catch(g){g.source=a;throw g;}if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};b.chain=function(a){return b(a).chain()};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var c=k[a];b.prototype[a]= | ||
function(){var d=this._wrapped;c.apply(d,arguments);(a=="shift"||a=="splice")&&d.length===0&&delete d[0];return this._chain?b(d).chain():d}});j(["concat","join","slice"],function(a){var c=k[a];b.prototype[a]=function(){var a=c.apply(this._wrapped,arguments);return this._chain?b(a).chain():a}});b.extend(b.prototype,{chain:function(){this._chain=true;return this},value:function(){return this._wrapped}})}).call(this); | ||
// Underscore.js 1.4.0 | ||
// http://underscorejs.org | ||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. | ||
// Underscore may be freely distributed under the MIT license. | ||
(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.4.0";var N=T.each=T.forEach=function(e,t,r){if(h&&e.forEach===h)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(T.has(e,o)&&t.call(r,e[o],o,e)===n)return};T.map=T.collect=function(e,t,n){var r=[];return p&&e.map===p?e.map(t,n):(N(e,function(e,i,s){r[r.length]=t.call(n,e,i,s)}),r)},T.reduce=T.foldl=T.inject=function(e,t,n,r){var i=arguments.length>2;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;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 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 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 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 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 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;o<r.computed&&(r={value:e,computed:o})}),r.value},T.shuffle=function(e){var t,n=0,r=[];return N(e,function(e){t=T.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return T.isFunction(e)?e:function(t){return t[e]}};T.sortBy=function(e,t,n){var r=k(t);return T.pluck(T.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t);return N(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};T.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(T.has(e,t)?e[t]:e[t]=[]).push(n)})},T.countBy=function(e,t,n){return L(e,t,n,function(e,t,n){T.has(e,t)||(e[t]=0),e[t]++})},T.sortedIndex=function(e,t,n,r){n=n==null?T.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},T.toArray=function(e){return e?e.length===+e.length?u.call(e):T.values(e):[]},T.size=function(e){return e.length===+e.length?e.length:T.keys(e).length},T.first=T.head=T.take=function(e,t,n){return t!=null&&!n?u.call(e,0,t):e[0]},T.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},T.last=function(e,t,n){return t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},T.rest=T.tail=T.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},T.compact=function(e){return T.filter(e,function(e){return!!e})};var A=function(e,t,n){return N(e,function(e){T.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};T.flatten=function(e,t){return A(e,t,[])},T.without=function(e){return T.difference(e,u.call(arguments,1))},T.uniq=T.unique=function(e,t,n,r){var i=n?T.map(e,n,r):e,s=[],o=[];return N(i,function(n,r){if(t?!r||o[o.length-1]!==n:!T.contains(o,n))o.push(n),s.push(e[r])}),s},T.union=function(){return T.uniq(a.apply(r,arguments))},T.intersection=function(e){var t=u.call(arguments,1);return T.filter(T.uniq(e),function(e){return T.every(t,function(t){return T.indexOf(t,e)>=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<t;r++)n[r]=T.pluck(e,""+r);return n},T.object=function(e,t){var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},T.indexOf=function(e,t,n){var r=0,i=e.length;if(n){if(typeof n!="number")return r=T.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(b&&e.indexOf===b)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},T.lastIndexOf=function(e,t,n){var r=n!=null;if(w&&e.lastIndexOf===w)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},T.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};T.bind=function(t,n){var r,i;if(t.bind===x&&x)return x.apply(t,u.call(arguments,1));if(!T.isFunction(t))throw new TypeError;return i=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=t.prototype;var e=new O,s=t.apply(e,i.concat(u.call(arguments)));return Object(s)===s?s:e}return t.apply(n,i.concat(u.call(arguments)))}},T.bindAll=function(e){var t=u.call(arguments,1);return t.length==0&&(t=T.functions(e)),N(t,function(t){e[t]=T.bind(e[t],e)}),e},T.memoize=function(e,t){var n={};return t||(t=T.identity),function(){var r=t.apply(this,arguments);return T.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},T.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},T.defer=function(e){return T.delay.apply(T,[e,1].concat(u.call(arguments,1)))},T.throttle=function(e,t){var n,r,i,s,o,u,a=T.debounce(function(){o=s=!1},t);return function(){n=this,r=arguments;var f=function(){i=null,o&&(u=e.apply(n,r)),a()};return i||(i=setTimeout(f,t)),s?o=!0:(s=!0,u=e.apply(n,r)),a(),u}},T.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},T.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},T.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},T.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=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<e;r++)t.call(n,r)},T.random=function(e,t){return t==null&&(t=e,e=0),e+(0|Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.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); |
@@ -1,8 +0,5 @@ | ||
// Underscore.js 1.3.3 | ||
// Underscore.js 1.4.0 | ||
// http://underscorejs.org | ||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. | ||
// Underscore may be freely distributed under the MIT license. | ||
// Portions of Underscore are inspired or borrowed from Prototype, | ||
// Oliver Steele's Functional, and John Resig's Micro-Templating. | ||
// For all details and documentation: | ||
// http://documentcloud.github.com/underscore | ||
@@ -29,2 +26,3 @@ (function() { | ||
slice = ArrayProto.slice, | ||
concat = ArrayProto.concat, | ||
unshift = ArrayProto.unshift, | ||
@@ -71,3 +69,3 @@ toString = ObjProto.toString, | ||
// Current version. | ||
_.VERSION = '1.3.3'; | ||
_.VERSION = '1.4.0'; | ||
@@ -81,3 +79,2 @@ // Collection Functions | ||
var each = _.each = _.forEach = function(obj, iterator, context) { | ||
if (obj == null) return; | ||
if (nativeForEach && obj.forEach === nativeForEach) { | ||
@@ -102,3 +99,2 @@ obj.forEach(iterator, context); | ||
var results = []; | ||
if (obj == null) return results; | ||
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); | ||
@@ -115,3 +111,2 @@ each(obj, function(value, index, list) { | ||
var initial = arguments.length > 2; | ||
if (obj == null) obj = []; | ||
if (nativeReduce && obj.reduce === nativeReduce) { | ||
@@ -137,10 +132,22 @@ if (context) iterator = _.bind(iterator, context); | ||
var initial = arguments.length > 2; | ||
if (obj == null) obj = []; | ||
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { | ||
if (context) iterator = _.bind(iterator, context); | ||
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); | ||
return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); | ||
} | ||
var reversed = _.toArray(obj).reverse(); | ||
if (context && !initial) iterator = _.bind(iterator, context); | ||
return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); | ||
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; | ||
}; | ||
@@ -165,3 +172,2 @@ | ||
var results = []; | ||
if (obj == null) return results; | ||
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); | ||
@@ -177,3 +183,2 @@ each(obj, function(value, index, list) { | ||
var results = []; | ||
if (obj == null) return results; | ||
each(obj, function(value, index, list) { | ||
@@ -191,3 +196,2 @@ if (!iterator.call(context, value, index, list)) results[results.length] = value; | ||
var result = true; | ||
if (obj == null) return result; | ||
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); | ||
@@ -206,3 +210,2 @@ each(obj, function(value, index, list) { | ||
var result = false; | ||
if (obj == null) return result; | ||
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); | ||
@@ -215,7 +218,6 @@ each(obj, function(value, index, list) { | ||
// Determine if a given value is included in the array or object using `===`. | ||
// Aliased as `contains`. | ||
_.include = _.contains = function(obj, target) { | ||
// Determine if the array or object contains a given value (using `===`). | ||
// Aliased as `include`. | ||
_.contains = _.include = function(obj, target) { | ||
var found = false; | ||
if (obj == null) return found; | ||
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; | ||
@@ -241,2 +243,14 @@ found = any(obj, function(value) { | ||
// Convenience version of a common use case of `filter`: selecting only objects | ||
// with specific `key:value` pairs. | ||
_.where = function(obj, attrs) { | ||
if (_.isEmpty(attrs)) return []; | ||
return _.filter(obj, function(value) { | ||
for (var key in attrs) { | ||
if (attrs[key] !== value[key]) return false; | ||
} | ||
return true; | ||
}); | ||
}; | ||
// Return the maximum element or (element-based computation). | ||
@@ -278,3 +292,3 @@ // Can't optimize arrays of integers longer than 65,535 elements. | ||
each(obj, function(value) { | ||
rand = Math.floor(Math.random() * ++index); | ||
rand = _.random(index++); | ||
shuffled[index - 1] = shuffled[rand]; | ||
@@ -286,29 +300,33 @@ shuffled[rand] = value; | ||
// An internal function to generate lookup iterators. | ||
var lookupIterator = function(value) { | ||
return _.isFunction(value) ? value : function(obj){ return obj[value]; }; | ||
}; | ||
// Sort the object's values by a criterion produced by an iterator. | ||
_.sortBy = function(obj, val, context) { | ||
var iterator = lookupIterator(obj, val); | ||
_.sortBy = function(obj, value, context) { | ||
var iterator = lookupIterator(value); | ||
return _.pluck(_.map(obj, function(value, index, list) { | ||
return { | ||
value : value, | ||
index : index, | ||
criteria : iterator.call(context, value, index, list) | ||
}; | ||
}).sort(function(left, right) { | ||
var a = left.criteria, b = right.criteria; | ||
if (a === void 0) return 1; | ||
if (b === void 0) return -1; | ||
return a < b ? -1 : a > b ? 1 : 0; | ||
var a = left.criteria; | ||
var b = right.criteria; | ||
if (a !== b) { | ||
if (a > b || a === void 0) return 1; | ||
if (a < b || b === void 0) return -1; | ||
} | ||
return left.index < right.index ? -1 : 1; | ||
}), 'value'); | ||
}; | ||
// An internal function to generate lookup iterators. | ||
var lookupIterator = function(obj, val) { | ||
return _.isFunction(val) ? val : function(obj) { return obj[val]; }; | ||
}; | ||
// An internal function used for aggregate "group by" operations. | ||
var group = function(obj, val, behavior) { | ||
var group = function(obj, value, context, behavior) { | ||
var result = {}; | ||
var iterator = lookupIterator(obj, val); | ||
var iterator = lookupIterator(value); | ||
each(obj, function(value, index) { | ||
var key = iterator(value, index); | ||
var key = iterator.call(context, value, index, obj); | ||
behavior(result, key, value); | ||
@@ -321,5 +339,5 @@ }); | ||
// to group by, or a function that returns the criterion. | ||
_.groupBy = function(obj, val) { | ||
return group(obj, val, function(result, key, value) { | ||
(result[key] || (result[key] = [])).push(value); | ||
_.groupBy = function(obj, value, context) { | ||
return group(obj, value, context, function(result, key, value) { | ||
(_.has(result, key) ? result[key] : (result[key] = [])).push(value); | ||
}); | ||
@@ -331,5 +349,5 @@ }; | ||
// criterion. | ||
_.countBy = function(obj, val) { | ||
return group(obj, val, function(result, key, value) { | ||
result[key] || (result[key] = 0); | ||
_.countBy = function(obj, value, context) { | ||
return group(obj, value, context, function(result, key, value) { | ||
if (!_.has(result, key)) result[key] = 0; | ||
result[key]++; | ||
@@ -341,9 +359,9 @@ }); | ||
// an object should be inserted so as to maintain order. Uses binary search. | ||
_.sortedIndex = function(array, obj, iterator) { | ||
iterator || (iterator = _.identity); | ||
var value = iterator(obj); | ||
_.sortedIndex = function(array, obj, iterator, context) { | ||
iterator = iterator == null ? _.identity : lookupIterator(iterator); | ||
var value = iterator.call(context, obj); | ||
var low = 0, high = array.length; | ||
while (low < high) { | ||
var mid = (low + high) >> 1; | ||
iterator(array[mid]) < value ? low = mid + 1 : high = mid; | ||
var mid = (low + high) >>> 1; | ||
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; | ||
} | ||
@@ -355,5 +373,4 @@ return low; | ||
_.toArray = function(obj) { | ||
if (!obj) return []; | ||
if (_.isArray(obj) || _.isArguments(obj)) return slice.call(obj); | ||
if (_.isFunction(obj.toArray)) return obj.toArray(); | ||
if (!obj) return []; | ||
if (obj.length === +obj.length) return slice.call(obj); | ||
return _.values(obj); | ||
@@ -433,12 +450,12 @@ }; | ||
// Aliased as `unique`. | ||
_.uniq = _.unique = function(array, isSorted, iterator) { | ||
var initial = iterator ? _.map(array, iterator) : array; | ||
_.uniq = _.unique = function(array, isSorted, iterator, context) { | ||
var initial = iterator ? _.map(array, iterator, context) : array; | ||
var results = []; | ||
_.reduce(initial, function(memo, value, index) { | ||
if (isSorted ? (_.last(memo) !== value || !memo.length) : !_.include(memo, value)) { | ||
memo.push(value); | ||
var seen = []; | ||
each(initial, function(value, index) { | ||
if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { | ||
seen.push(value); | ||
results.push(array[index]); | ||
} | ||
return memo; | ||
}, []); | ||
}); | ||
return results; | ||
@@ -450,3 +467,3 @@ }; | ||
_.union = function() { | ||
return _.uniq(flatten(arguments, true, [])); | ||
return _.uniq(concat.apply(ArrayProto, arguments)); | ||
}; | ||
@@ -468,4 +485,4 @@ | ||
_.difference = function(array) { | ||
var rest = flatten(slice.call(arguments, 1), true, []); | ||
return _.filter(array, function(value){ return !_.include(rest, value); }); | ||
var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); | ||
return _.filter(array, function(value){ return !_.contains(rest, value); }); | ||
}; | ||
@@ -507,10 +524,13 @@ | ||
_.indexOf = function(array, item, isSorted) { | ||
if (array == null) return -1; | ||
var i, l; | ||
var i = 0, l = array.length; | ||
if (isSorted) { | ||
i = _.sortedIndex(array, item); | ||
return array[i] === item ? i : -1; | ||
if (typeof isSorted == 'number') { | ||
i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); | ||
} else { | ||
i = _.sortedIndex(array, item); | ||
return array[i] === item ? i : -1; | ||
} | ||
} | ||
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); | ||
for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; | ||
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); | ||
for (; i < l; i++) if (array[i] === item) return i; | ||
return -1; | ||
@@ -520,6 +540,8 @@ }; | ||
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. | ||
_.lastIndexOf = function(array, item) { | ||
if (array == null) return -1; | ||
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); | ||
var i = array.length; | ||
_.lastIndexOf = function(array, item, from) { | ||
var hasIndex = from != null; | ||
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { | ||
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); | ||
} | ||
var i = (hasIndex ? from : array.length); | ||
while (i--) if (array[i] === item) return i; | ||
@@ -639,3 +661,3 @@ return -1; | ||
_.debounce = function(func, wait, immediate) { | ||
var timeout; | ||
var timeout, result; | ||
return function() { | ||
@@ -645,3 +667,3 @@ var context = this, args = arguments; | ||
timeout = null; | ||
if (!immediate) func.apply(context, args); | ||
if (!immediate) result = func.apply(context, args); | ||
}; | ||
@@ -651,3 +673,4 @@ var callNow = immediate && !timeout; | ||
timeout = setTimeout(later, wait); | ||
if (callNow) func.apply(context, args); | ||
if (callNow) result = func.apply(context, args); | ||
return result; | ||
}; | ||
@@ -674,3 +697,4 @@ }; | ||
return function() { | ||
var args = [func].concat(slice.call(arguments, 0)); | ||
var args = [func]; | ||
push.apply(args, arguments); | ||
return wrapper.apply(this, args); | ||
@@ -717,3 +741,5 @@ }; | ||
_.values = function(obj) { | ||
return _.map(obj, _.identity); | ||
var values = []; | ||
for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); | ||
return values; | ||
}; | ||
@@ -723,5 +749,5 @@ | ||
_.pairs = function(obj) { | ||
return _.map(obj, function(value, key) { | ||
return [key, value]; | ||
}); | ||
var pairs = []; | ||
for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); | ||
return pairs; | ||
}; | ||
@@ -731,6 +757,5 @@ | ||
_.invert = function(obj) { | ||
return _.reduce(obj, function(memo, value, key) { | ||
memo[value] = key; | ||
return memo; | ||
}, {}); | ||
var result = {}; | ||
for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; | ||
return result; | ||
}; | ||
@@ -761,3 +786,3 @@ | ||
var copy = {}; | ||
var keys = _.flatten(slice.call(arguments, 1)); | ||
var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); | ||
each(keys, function(key) { | ||
@@ -772,5 +797,5 @@ if (key in obj) copy[key] = obj[key]; | ||
var copy = {}; | ||
var keys = _.flatten(slice.call(arguments, 1)); | ||
var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); | ||
for (var key in obj) { | ||
if (!_.include(keys, key)) copy[key] = obj[key]; | ||
if (!_.contains(keys, key)) copy[key] = obj[key]; | ||
} | ||
@@ -814,5 +839,2 @@ return copy; | ||
if (b instanceof _) b = b._wrapped; | ||
// Invoke a custom `isEqual` method if one is provided. | ||
if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); | ||
if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); | ||
// Compare `[[Class]]` names. | ||
@@ -865,9 +887,13 @@ var className = toString.call(a); | ||
while (size--) { | ||
// Ensure commutative equality for sparse arrays. | ||
if (!(result = size in a == size in b && eq(a[size], b[size], aStack, bStack))) break; | ||
if (!(result = eq(a[size], b[size], aStack, bStack))) break; | ||
} | ||
} | ||
} else { | ||
// Objects with different constructors are not equivalent. | ||
if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; | ||
// Objects with different constructors are not equivalent, but `Object`s | ||
// from different frames are. | ||
var aCtor = a.constructor, bCtor = b.constructor; | ||
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && | ||
_.isFunction(bCtor) && (bCtor instanceof bCtor))) { | ||
return false; | ||
} | ||
// Deep compare objects. | ||
@@ -912,3 +938,3 @@ for (var key in a) { | ||
_.isElement = function(obj) { | ||
return !!(obj && obj.nodeType == 1); | ||
return !!(obj && obj.nodeType === 1); | ||
}; | ||
@@ -942,2 +968,9 @@ | ||
// Optimize `isFunction` if appropriate. | ||
if (typeof (/./) !== 'function') { | ||
_.isFunction = function(obj) { | ||
return typeof obj === 'function'; | ||
}; | ||
} | ||
// Is a given object a finite number? | ||
@@ -948,6 +981,5 @@ _.isFinite = function(obj) { | ||
// Is the given value `NaN`? | ||
// Is the given value `NaN`? (NaN is the only number which does not equal itself). | ||
_.isNaN = function(obj) { | ||
// `NaN` is the only value for which `===` is not reflexive. | ||
return obj !== obj; | ||
return _.isNumber(obj) && obj != +obj; | ||
}; | ||
@@ -998,2 +1030,6 @@ | ||
_.random = function(min, max) { | ||
if (max == null) { | ||
max = min; | ||
min = 0; | ||
} | ||
return min + (0 | Math.random() * (max - min + 1)); | ||
@@ -1044,4 +1080,4 @@ }; | ||
_.prototype[name] = function() { | ||
var args = slice.call(arguments); | ||
args.unshift(this._wrapped); | ||
var args = [this._wrapped]; | ||
push.apply(args, arguments); | ||
return result.call(this, func.apply(_, args)); | ||
@@ -1071,3 +1107,3 @@ }; | ||
// guaranteed not to match. | ||
var noMatch = /.^/; | ||
var noMatch = /(.)^/; | ||
@@ -1077,23 +1113,13 @@ // Certain characters need to be escaped so that they can be put into a | ||
var escapes = { | ||
'\\': '\\', | ||
"'": "'", | ||
r: '\r', | ||
n: '\n', | ||
t: '\t', | ||
u2028: '\u2028', | ||
u2029: '\u2029' | ||
"'": "'", | ||
'\\': '\\', | ||
'\r': 'r', | ||
'\n': 'n', | ||
'\t': 't', | ||
'\u2028': 'u2028', | ||
'\u2029': 'u2029' | ||
}; | ||
for (var key in escapes) escapes[escapes[key]] = key; | ||
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; | ||
var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g; | ||
// Within an interpolation, evaluation, or escaping, remove HTML escaping | ||
// that had been previously added. | ||
var unescape = function(code) { | ||
return code.replace(unescaper, function(match, escape) { | ||
return escapes[escape]; | ||
}); | ||
}; | ||
// JavaScript micro-templating, similar to John Resig's implementation. | ||
@@ -1105,19 +1131,23 @@ // Underscore templating handles arbitrary delimiters, preserves whitespace, | ||
// Compile the template source, taking care to escape characters that | ||
// cannot be included in a string literal and then unescape them in code | ||
// blocks. | ||
var source = "__p+='" + text | ||
.replace(escaper, function(match) { | ||
return '\\' + escapes[match]; | ||
}) | ||
.replace(settings.escape || noMatch, function(match, code) { | ||
return "'+\n((__t=(" + unescape(code) + "))==null?'':_.escape(__t))+\n'"; | ||
}) | ||
.replace(settings.interpolate || noMatch, function(match, code) { | ||
return "'+\n((__t=(" + unescape(code) + "))==null?'':__t)+\n'"; | ||
}) | ||
.replace(settings.evaluate || noMatch, function(match, code) { | ||
return "';\n" + unescape(code) + "\n__p+='"; | ||
}) + "';\n"; | ||
// Combine delimiters into one regular expression via alternation. | ||
var matcher = new RegExp([ | ||
(settings.escape || noMatch).source, | ||
(settings.interpolate || noMatch).source, | ||
(settings.evaluate || noMatch).source | ||
].join('|') + '|$', 'g'); | ||
// Compile the template source, escaping string literals appropriately. | ||
var index = 0; | ||
var source = "__p+='"; | ||
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { | ||
source += text.slice(index, offset) | ||
.replace(escaper, function(match) { return '\\' + escapes[match]; }); | ||
source += | ||
escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" : | ||
interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" : | ||
evaluate ? "';\n" + evaluate + "\n__p+='" : ''; | ||
index = offset + match.length; | ||
}); | ||
source += "';\n"; | ||
// If a variable is not specified, place data values in local scope. | ||
@@ -1124,0 +1154,0 @@ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
6453191
44
23396
13
314
4