diff --git a/.gitignore b/.gitignore index d583af498f..150de05ff2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .DS_Store *.custom.* +*.template.* +*.d.ts *.map node_modules vendor/closure-compiler diff --git a/.jamignore b/.jamignore index 59c0c1afeb..dfb9ed2d4a 100644 --- a/.jamignore +++ b/.jamignore @@ -1,10 +1,12 @@ .* *.custom.* +*.template.* *.d.ts *.map *.md *.txt build.js +lodash.js index.js bower.json component.json diff --git a/.npmignore b/.npmignore index 5a206d2aa5..c9ec59ceff 100644 --- a/.npmignore +++ b/.npmignore @@ -1,12 +1,12 @@ .* *.custom.* +*.template.* *.d.ts *.map *.md bower.json component.json doc -node_modules perf test vendor/*.gz diff --git a/.travis.yml b/.travis.yml index a60089eef9..458651f2a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,14 @@ language: node_js node_js: - 0.6 - 0.9 + - 0.10 env: + - TEST_COMMAND="istanbul cover ./test/test.js" - TEST_COMMAND="phantomjs ./test/test.js ../dist/lodash.compat.js" - TEST_COMMAND="phantomjs ./test/test.js ../dist/lodash.compat.min.js" - TEST_COMMAND="node ./test/test.js ../dist/lodash.js" - TEST_COMMAND="node ./test/test.js ../dist/lodash.min.js" - - TEST_COMMAND="node ./test/test-build.js --time-limit 49m30s" + - TEST_COMMAND="node ./test/test-build.js --time-limit 48m" git: depth: 1 branches: @@ -16,5 +18,6 @@ branches: before_script: - "tar -xzvf vendor/closure-compiler.tar.gz -C vendor" - "tar -xzvf vendor/uglifyjs.tar.gz -C vendor" + - "npm install -g istanbul" script: $TEST_COMMAND diff --git a/README.md b/README.md index 0f8dbc0fe4..f498f53360 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,28 @@ -# Lo-Dash v1.2.1 +# Lo-Dash v1.3.0 A low-level utility library delivering consistency, [customization](https://github.com/bestiejs/lodash#custom-builds), [performance](http://lodash.com/benchmarks), and [extra features](https://github.com/bestiejs/lodash#features). ## Download * Lo-Dash builds (for modern environments):
-[Development](https://raw.github.com/bestiejs/lodash/v1.2.1/dist/lodash.js) and -[Production](https://raw.github.com/bestiejs/lodash/v1.2.1/dist/lodash.min.js) +[Development](https://raw.github.com/bestiejs/lodash/v1.3.0/dist/lodash.js) and +[Production](https://raw.github.com/bestiejs/lodash/v1.3.0/dist/lodash.min.js) * Lo-Dash compatibility builds (for legacy and modern environments):
-[Development](https://raw.github.com/bestiejs/lodash/v1.2.1/dist/lodash.compat.js) and -[Production](https://raw.github.com/bestiejs/lodash/v1.2.1/dist/lodash.compat.min.js) +[Development](https://raw.github.com/bestiejs/lodash/v1.3.0/dist/lodash.compat.js) and +[Production](https://raw.github.com/bestiejs/lodash/v1.3.0/dist/lodash.compat.min.js) * Underscore compatibility builds:
-[Development](https://raw.github.com/bestiejs/lodash/v1.2.1/dist/lodash.underscore.js) and -[Production](https://raw.github.com/bestiejs/lodash/v1.2.1/dist/lodash.underscore.min.js) +[Development](https://raw.github.com/bestiejs/lodash/v1.3.0/dist/lodash.underscore.js) and +[Production](https://raw.github.com/bestiejs/lodash/v1.3.0/dist/lodash.underscore.min.js) -* CDN copies of ≤ v1.2.1’s builds are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/):
-[Lo-Dash dev](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.js), -[Lo-Dash prod](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js),
-[Lo-Dash compat-dev](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.compat.js), -[Lo-Dash compat-prod](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.compat.min.js),
-[Underscore compat-dev](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.underscore.js), and -[Underscore compat-prod](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.underscore.min.js) +* CDN copies of ≤ v1.3.0’s builds are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/):
+[Lo-Dash dev](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.0/lodash.js), +[Lo-Dash prod](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.0/lodash.min.js),
+[Lo-Dash compat-dev](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.0/lodash.compat.js), +[Lo-Dash compat-prod](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.0/lodash.compat.min.js),
+[Underscore compat-dev](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.0/lodash.underscore.js), and +[Underscore compat-prod](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.0/lodash.underscore.min.js) * For optimal file size, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need @@ -68,6 +68,7 @@ For more information check out these articles, screencasts, and other videos ove * [_.runInContext](http://lodash.com/docs#runInContext) for easier mocking and extended environment support * [_.support](http://lodash.com/docs#support) to flag environment features * [_.template](http://lodash.com/docs#template) supports [*“imports”* options](http://lodash.com/docs#templateSettings_imports), [ES6 template delimiters](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6), and [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * [_.transform](http://lodash.com/docs#transform) as a powerful alternative to [_.reduce](http://lodash.com/docs#reduce) for transforming objects * [_.unzip](http://lodash.com/docs#unzip) as the inverse of [_.zip](http://lodash.com/docs#zip) * [_.where](http://lodash.com/docs#where) supports deep object comparisons * [_.clone](http://lodash.com/docs#clone), [_.omit](http://lodash.com/docs#omit), [_.pick](http://lodash.com/docs#pick), @@ -79,13 +80,13 @@ For more information check out these articles, screencasts, and other videos ove ## Support -Lo-Dash has been tested in at least Chrome 5~26, Firefox 2~20, IE 6-10, Opera 9.25~12, Safari 3-6, Node.js 0.4.8-0.10.5, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. +Lo-Dash has been tested in at least Chrome 5~27, Firefox 2~21, IE 6-10, Opera 9.25~12, Safari 3-6, Node.js 0.4.8-0.10.7 (Node bug [#5622](https://github.com/joyent/node/issues/5622) prevents 0.10.8-0.10.10 from working), Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. ## Custom builds Custom builds make it easy to create lightweight versions of Lo-Dash containing only the methods you need. To top it off, we handle all method dependency and alias mapping for you. -For a more detailed summary over the differences between various builds, check out our [wiki entry](https://github.com/bestiejs/lodash/wiki/build-differences). +For a more detailed summary over the differences between various builds, check out the [wiki page](https://github.com/bestiejs/lodash/wiki/build-differences). * Backbone builds, with only methods required by Backbone, may be created using the `backbone` modifier argument. ```bash @@ -248,14 +249,39 @@ require({ ## Release Notes -### v1.2.1 - - * Added Component package support - * Updated the build utility to work with changes in GitHub’s API - * Ensured `_.isPlainObject` works with objects created by `Object.create(null)` - * Ensured *“isType”* methods return `false` for subclassed values - * Ensured debounced functions, with `leading` and `trailing` calls enabled,
- only perform trailing calls after they’re called more than once +### v1.3.0 + + * Added `_.transform` method + * Added `_.chain` and `_.findWhere` aliases + * Added internal array and object pooling + * Added Istanbul test coverage reports to Travis CI + * Added `maxWait` option to `_.debounce` + * Added support for floating point numbers to `_.random` + * Added Volo configuration to package.json + * Adjusted UMD for `component build` + * Allowed more stable mixing of `lodash` and `underscore` build methods + * Ensured debounced function with, `leading` and `trailing` options, works as expected + * Ensured minified builds work with the Dojo builder + * Ensured minification avoids deoptimizing expressions containing boolean values + * Ensured unknown types return `false` in `_.isObject` and `_.isRegExp` + * Ensured `_.clone`, `_.flatten`, and `_.uniq` can be used as a `callback` for methods like `_.map` + * Ensured `_.forIn` works on objects with longer inheritance chains in IE < 9 + * Ensured `_.isPlainObject` returns `true` for empty objects in IE < 9 + * Ensured `_.max` and `_.min` chain correctly + * Ensured `clearTimeout` use doesn’t cause errors in Titanium + * Ensured that the `--stdout` build option doesn't write to a file + * Exposed memoized function’s `cache` + * Fixed `Error.prototype` iteration bugs + * Fixed "scripts" paths in component.json + * Made methods support customizing `_.indexOf` + * Made the build track dependencies of private functions + * Made the `template` pre-compiler build option avoid escaping non-ascii characters + * Made `_.createCallback` avoid binding functions if they don’t reference `this` + * Optimized the Closure Compiler minification process + * Optimized the large array cache for `_.difference`, `_.intersection`, and `_.uniq` + * Optimized internal `_.flatten` and `_.indexOf` use + * Reduced `_.unzip` and `_.zip` + * Removed special handling of arrays in `_.assign` and `_.defaults` The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog). diff --git a/bower.json b/bower.json index 086e1aaf6a..f6f65c5107 100644 --- a/bower.json +++ b/bower.json @@ -1,10 +1,11 @@ { "name": "lodash", - "version": "1.2.1", + "version": "1.3.0", "main": "./dist/lodash.compat.js", "ignore": [ ".*", "*.custom.*", + "*.template.*", "*.d.ts", "*.map", "*.md", diff --git a/build.js b/build.js index 5f7fd42a5e..0be61ba029 100755 --- a/build.js +++ b/build.js @@ -18,11 +18,14 @@ var cwd = process.cwd(); /** Used for array method references */ - var arrayRef = []; + var arrayRef = Array.prototype; /** Shortcut used to push arrays of values to an array */ var push = arrayRef.push; + /** Used to create regexes that may detect multi-line comment blocks */ + var multilineComment = '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n'; + /** Used to detect the Node.js executable in command-line arguments */ var reNode = RegExp('(?:^|' + path.sepEscaped + ')node(?:\\.exe)?$'); @@ -41,6 +44,7 @@ 'drop': 'rest', 'each': 'forEach', 'extend': 'assign', + 'findWhere': 'find', 'foldl': 'reduce', 'foldr': 'reduceRight', 'head': 'first', @@ -60,7 +64,7 @@ 'contains': ['include'], 'every': ['all'], 'filter': ['select'], - 'find': ['detect'], + 'find': ['detect', 'findWhere'], 'first': ['head', 'take'], 'forEach': ['each'], 'functions': ['methods'], @@ -76,41 +80,41 @@ /** Used to track function dependencies */ var dependencyMap = { 'after': [], - 'assign': ['isArray', 'keys'], + 'assign': ['createIterator', 'isArguments', 'keys'], 'at': ['isString'], - 'bind': ['isFunction', 'isObject'], + 'bind': ['createBound'], 'bindAll': ['bind', 'functions'], - 'bindKey': ['isFunction', 'isObject'], - 'clone': ['assign', 'forEach', 'forOwn', 'isArray', 'isObject'], + 'bindKey': ['createBound'], + 'clone': ['assign', 'forEach', 'forOwn', 'getArray', 'isArray', 'isObject', 'isNode', 'releaseArray', 'slice'], 'cloneDeep': ['clone'], 'compact': [], 'compose': [], - 'contains': ['indexOf', 'isString'], + 'contains': ['basicEach', 'getIndexOf', 'isString'], 'countBy': ['createCallback', 'forEach'], 'createCallback': ['identity', 'isEqual', 'keys'], - 'debounce': [], - 'defaults': ['isArray', 'keys'], + 'debounce': ['isObject'], + 'defaults': ['createIterator', 'isArguments', 'keys'], 'defer': ['bind'], 'delay': [], - 'difference': ['indexOf'], - 'escape': [], - 'every': ['createCallback', 'isArray'], - 'filter': ['createCallback', 'isArray'], - 'find': ['createCallback', 'forEach', 'isArray'], + 'difference': ['cacheIndexOf', 'createCache', 'getIndexOf', 'releaseObject'], + 'escape': ['escapeHtmlChar'], + 'every': ['basicEach', 'createCallback', 'isArray'], + 'filter': ['basicEach', 'createCallback', 'isArray'], + 'find': ['basicEach', 'createCallback', 'isArray'], 'findIndex': ['createCallback'], - 'findKey': ['createCallback'], - 'first': [], - 'flatten': ['createCallback', 'isArray'], - 'forEach': ['createCallback', 'isArguments', 'isArray', 'isString', 'keys'], - 'forIn': ['createCallback', 'isArguments'], - 'forOwn': ['createCallback', 'isArguments', 'keys'], + 'findKey': ['createCallback', 'forOwn'], + 'first': ['slice'], + 'flatten': ['isArray', 'overloadWrapper'], + 'forEach': ['basicEach', 'createCallback', 'isArguments', 'isArray', 'isString', 'keys'], + 'forIn': ['createCallback', 'createIterator', 'isArguments'], + 'forOwn': ['createCallback', 'createIterator', 'isArguments', 'keys'], 'functions': ['forIn', 'isFunction'], 'groupBy': ['createCallback', 'forEach'], 'has': [], 'identity': [], - 'indexOf': ['sortedIndex'], - 'initial': [], - 'intersection': ['indexOf'], + 'indexOf': ['basicIndexOf', 'sortedIndex'], + 'initial': ['slice'], + 'intersection': ['cacheIndexOf', 'createCache', 'getArray', 'getIndexOf', 'releaseArray', 'releaseObject'], 'invert': ['keys'], 'invoke': ['forEach'], 'isArguments': [], @@ -119,90 +123,120 @@ 'isDate': [], 'isElement': [], 'isEmpty': ['forOwn', 'isArguments', 'isFunction'], - 'isEqual': ['forIn', 'isArguments', 'isFunction'], + 'isEqual': ['forIn', 'getArray', 'isArguments', 'isFunction', 'isNode', 'releaseArray'], 'isFinite': [], 'isFunction': [], 'isNaN': ['isNumber'], 'isNull': [], 'isNumber': [], 'isObject': [], - 'isPlainObject': ['forIn', 'isArguments', 'isFunction'], + 'isPlainObject': ['isArguments', 'shimIsPlainObject'], 'isRegExp': [], 'isString': [], 'isUndefined': [], - 'keys': ['forOwn', 'isArguments', 'isObject'], - 'last': [], + 'keys': ['isArguments', 'isObject', 'shimKeys'], + 'last': ['slice'], 'lastIndexOf': [], - 'map': ['createCallback', 'isArray'], - 'max': ['createCallback', 'isArray', 'isString'], + 'map': ['basicEach', 'createCallback', 'isArray'], + 'max': ['basicEach', 'charAtCallback', 'createCallback', 'isArray', 'isString'], 'memoize': [], - 'merge': ['forEach', 'forOwn', 'isArray', 'isObject', 'isPlainObject'], - 'min': ['createCallback', 'isArray', 'isString'], + 'merge': ['forEach', 'forOwn', 'getArray', 'isArray', 'isObject', 'isPlainObject', 'releaseArray'], + 'min': ['basicEach', 'charAtCallback', 'createCallback', 'isArray', 'isString'], 'mixin': ['forEach', 'functions'], 'noConflict': [], - 'omit': ['forIn', 'indexOf'], + 'omit': ['forIn', 'getIndexOf'], 'once': [], 'pairs': ['keys'], 'parseInt': ['isString'], - 'partial': ['isFunction', 'isObject'], - 'partialRight': ['isFunction', 'isObject'], + 'partial': ['createBound'], + 'partialRight': ['createBound'], 'pick': ['forIn', 'isObject'], 'pluck': ['map'], 'random': [], 'range': [], - 'reduce': ['createCallback', 'isArray'], + 'reduce': ['basicEach', 'createCallback', 'isArray'], 'reduceRight': ['createCallback', 'forEach', 'isString', 'keys'], 'reject': ['createCallback', 'filter'], - 'rest': [], + 'rest': ['slice'], 'result': ['isFunction'], 'runInContext': ['defaults', 'pick'], 'shuffle': ['forEach'], 'size': ['keys'], - 'some': ['createCallback', 'isArray'], - 'sortBy': ['createCallback', 'forEach'], + 'some': ['basicEach', 'createCallback', 'isArray'], + 'sortBy': ['compareAscending', 'createCallback', 'forEach', 'getObject', 'releaseObject'], 'sortedIndex': ['createCallback', 'identity'], 'tap': ['value'], - 'template': ['defaults', 'escape', 'keys', 'values'], - 'throttle': [], + 'template': ['defaults', 'escape', 'escapeStringChar', 'keys', 'values'], + 'throttle': ['debounce', 'getObject', 'isObject', 'releaseObject'], 'times': ['createCallback'], - 'toArray': ['isString', 'values'], - 'unescape': [], + 'toArray': ['isString', 'slice', 'values'], + 'transform': ['createCallback', 'createObject', 'forOwn', 'isArray'], + 'unescape': ['unescapeHtmlChar'], 'union': ['isArray', 'uniq'], - 'uniq': ['createCallback', 'indexOf'], + 'uniq': ['cacheIndexOf', 'createCache', 'getArray', 'getIndexOf', 'overloadWrapper', 'releaseArray', 'releaseObject'], 'uniqueId': [], 'unzip': ['max', 'pluck'], - 'value': ['forOwn', 'isArray'], + 'value': ['basicEach', 'forOwn', 'isArray', 'lodashWrapper'], 'values': ['keys'], 'where': ['filter'], 'without': ['difference'], 'wrap': [], - 'zip': ['max', 'pluck'], + 'zip': ['unzip'], 'zipObject': [], + // private methods + 'basicEach': ['createIterator', 'isArguments', 'isArray', 'isString', 'keys'], + 'basicIndexOf': [], + 'cacheIndexOf': ['basicIndexOf'], + 'cachePush': [], + 'charAtCallback': [], + 'compareAscending': [], + 'createBound': ['createObject', 'isFunction', 'isObject'], + 'createCache': ['cachePush', 'getObject', 'releaseObject'], + 'createIterator': ['getObject', 'iteratorTemplate', 'releaseObject'], + 'createObject': [ 'isObject', 'noop'], + 'escapeHtmlChar': [], + 'escapeStringChar': [], + 'getArray': [], + 'getIndexOf': ['basicIndexOf', 'indexOf'], + 'getObject': [], + 'iteratorTemplate': [], + 'isNode': [], + 'lodashWrapper': [], + 'noop': [], + 'overloadWrapper': ['createCallback'], + 'releaseArray': [], + 'releaseObject': [], + 'shimIsPlainObject': ['forIn', 'isArguments', 'isFunction', 'isNode'], + 'shimKeys': ['createIterator', 'isArguments'], + 'slice': [], + 'unescapeHtmlChar': [], + // method used by the `backbone` and `underscore` builds 'chain': ['value'], - 'findWhere': ['find'] + 'findWhere': ['where'] }; /** Used to inline `iteratorTemplate` */ var iteratorOptions = [ 'args', - 'arrays', + 'array', 'bottom', 'firstArg', 'init', 'loop', 'shadowedProps', + 'support', 'top', 'useHas', 'useKeys' ]; /** List of all methods */ - var allMethods = _.without(_.keys(dependencyMap)); + var allMethods = _.keys(dependencyMap); /** List of Lo-Dash methods */ - var lodashMethods = _.without(allMethods, 'chain', 'findWhere'); + var lodashMethods = _.without(allMethods, 'findWhere'); /** List of Backbone's Lo-Dash dependencies */ var backboneDependencies = [ @@ -276,12 +310,10 @@ 'parseInt', 'partialRight', 'runInContext', + 'transform', 'unzip' ]; - /** List of Underscore methods */ - var underscoreMethods = _.without.apply(_, [allMethods].concat(lodashOnlyMethods)); - /** List of ways to export the `lodash` function */ var exportsAll = [ 'amd', @@ -290,6 +322,46 @@ 'node' ]; + /** List of valid method categories */ + var methodCategories = [ + 'Arrays', + 'Chaining', + 'Collections', + 'Functions', + 'Objects', + 'Utilities' + ]; + + /** List of private methods */ + var privateMethods = [ + 'basicEach', + 'basicIndex', + 'cacheIndexOf', + 'cachePush', + 'charAtCallback', + 'compareAscending', + 'createBound', + 'createCache', + 'createIterator', + 'escapeHtmlChar', + 'escapeStringChar', + 'getArray', + 'getObject', + 'isNode', + 'iteratorTemplate', + 'lodashWrapper', + 'overloadWrapper', + 'releaseArray', + 'releaseObject', + 'shimIsPlainObject', + 'shimKeys', + 'slice', + 'unescapeHtmlChar' + ]; + + /** List of Underscore methods */ + var underscoreMethods = _.without.apply(_, [allMethods].concat(lodashOnlyMethods, privateMethods)); + /*--------------------------------------------------------------------------*/ /** @@ -366,14 +438,6 @@ ].join('\n' + indent)); }); - // add `lodash.chain` assignment - source = source.replace(getMethodAssignments(source), function(match) { - return match.replace(/^(?: *\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\n)?( *)lodash\.VERSION *=/m, '$1lodash.chain = chain;\n\n$&'); - }); - - // add `lodash.prototype.chain` assignment - source = source.replace(/^( *)lodash\.prototype\.value *=.+\n/m, '$1lodash.prototype.chain = wrapperChain;\n$&'); - // remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, ''); @@ -402,7 +466,7 @@ ].join('\n')); // replace wrapper `Array` method assignments - source = source.replace(/^(?:(?: *\/\/.*\n)*(?: *if *\(.+\n)?( *)(each|forEach)\(\['[\s\S]+?\n\1}\);(?:\n *})?\n+)+/m, function(match, indent, funcName) { + source = source.replace(/^(?:(?: *\/\/.*\n)*(?: *if *\(.+\n)?( *)(basicEach|forEach)\(\['[\s\S]+?\n\1}\);(?:\n *})?\n+)+/m, function(match, indent, funcName) { return indent + [ '// add `Array` mutator functions to the wrapper', funcName + "(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {", @@ -438,6 +502,11 @@ ].join('\n' + indent); }); + // replace `_.chain` assignment + source = source.replace(getMethodAssignments(source), function(match) { + return match.replace(/^( *lodash\.chain *= *)[\s\S]+?(?=;\n)/m, '$1chain') + }); + // move `mixin(lodash)` to after the method assignments source = source.replace(/(?:\s*\/\/.*)*\n( *)mixin\(lodash\).+/, ''); source = source.replace(getMethodAssignments(source), function(match) { @@ -450,6 +519,11 @@ ].join('\n' + indent); }); + // move the `lodash.prototype.chain` assignment to after `mixin(lodash)` + source = source + .replace(/^ *lodash\.prototype\.chain *=[\s\S]+?;\n/m, '') + .replace(/^( *)lodash\.prototype\.value *=/m, '$1lodash.prototype.chain = wrapperChain;\n$&'); + return source; } @@ -510,12 +584,19 @@ var source = [ ';(function(window) {', - " var freeExports = typeof exports == 'object' && typeof require == 'function' && exports;", + ' var undefined;', + '', + ' var objectTypes = {', + " 'function': true,", + " 'object': true", + ' };', '', - " var freeModule = typeof module == 'object' && module && module.exports == freeExports && module;", + " var freeExports = objectTypes[typeof exports] && typeof require == 'function' && exports;", '', - " var freeGlobal = typeof global == 'object' && global;", - ' if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {', + " var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module;", + '', + " var freeGlobal = objectTypes[typeof global] && global;", + ' if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {', ' window = freeGlobal;', ' }', '', @@ -535,7 +616,7 @@ var filePath = path.join(directory, filename); if (pattern.test(filename)) { var text = fs.readFileSync(filePath, 'utf8'), - precompiled = getFunctionSource(_.template(text, null, options)), + precompiled = cleanupCompiled(getFunctionSource(_.template(text, null, options))), prop = filename.replace(/\..*$/, ''); source.push(" templates['" + prop.replace(/['\n\r\t]/g, '\\$&') + "'] = " + precompiled + ';', ''); @@ -572,7 +653,18 @@ * @returns {String} Returns the capitalized string. */ function capitalize(string) { - return string[0].toUpperCase() + string.toLowerCase().slice(1); + return string[0].toUpperCase() + string.slice(1); + } + + /** + * Removes unnecessary semicolons and whitespace from compiled code. + * + * @private + * @param {String} source The source to process. + * @returns {String} Returns the modified source. + */ + function cleanupCompiled(source) { + return source.replace(/([{}]) *;/g, '$1'); } /** @@ -655,7 +747,9 @@ * @returns {Array} Returns an array of aliases. */ function getAliases(methodName) { - return realToAliasMap[methodName] || []; + return (realToAliasMap[methodName] || []).filter(function(methodName) { + return !dependencyMap[methodName]; + }); } /** @@ -668,7 +762,11 @@ */ function getCategory(source, methodName) { var result = /@category +(\w+)/.exec(matchFunction(source, methodName)); - return result ? result[1] : ''; + if (result) { + return result[1]; + } + // check for the `_.chain` alias + return methodName == 'chain' ? 'Chaining' : ''; } /** @@ -695,17 +793,20 @@ } /** - * Gets an array of depenants for a method by a given name. + * Gets an array of depenants for the given method name(s). * * @private - * @param {String} methodName The method name. + * @param {String} methodName A method name or array of method names. * @returns {Array} Returns an array of method dependants. */ function getDependants(methodName) { - // iterate over the `dependencyMap`, adding the names of methods that - // have `methodName` as a dependency + // iterate over the `dependencyMap`, adding names of methods + // that have the `methodName` as a dependency + var methodNames = _.isArray(methodName) ? methodName : [methodName]; return _.reduce(dependencyMap, function(result, dependencies, otherName) { - if (_.contains(dependencies, methodName)) { + if (_.some(methodNames, function(methodName) { + return _.contains(dependencies, methodName); + })) { result.push(otherName); } return result; @@ -718,13 +819,12 @@ * plus any additional detected sub-dependencies. * * @private - * @param {Array|String} methodName A single method name or array of - * dependencies to query. + * @param {Array|String} methodName A method name or array of dependencies to query. * @param- {Object} [stackA=[]] Internally used track queried methods. * @returns {Array} Returns an array of method dependencies. */ function getDependencies(methodName, stack) { - var dependencies = Array.isArray(methodName) ? methodName : dependencyMap[methodName]; + var dependencies = _.isArray(methodName) ? methodName : dependencyMap[methodName]; if (!dependencies) { return []; } @@ -783,7 +883,7 @@ * @returns {String} Returns the `isArguments` fallback. */ function getIsArgumentsFallback(source) { - return (source.match(/(?:\s*\/\/.*)*\n( *)if *\((?:!support\.argsClass|!isArguments)[\s\S]+?};\n\1}/) || [''])[0]; + return (source.match(/(?:\s*\/\/.*)*\n( *)if *\((?:!support\.argsClass|!isArguments)[\s\S]+?\n *};\n\1}/) || [''])[0]; } /** @@ -807,7 +907,18 @@ * @returns {String} Returns the `isFunction` fallback. */ function getIsFunctionFallback(source) { - return (source.match(/(?:\s*\/\/.*)*\n( *)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/) || [''])[0]; + return (source.match(/(?:\s*\/\/.*)*\n( *)if *\(isFunction\(\/x\/[\s\S]+?\n *};\n\1}/) || [''])[0]; + } + + /** + * Gets the `createObject` fallback from `source`. + * + * @private + * @param {String} source The source to inspect. + * @returns {String} Returns the `isArguments` fallback. + */ + function getCreateObjectFallback(source) { + return (source.match(/(?:\s*\/\/.*)*\n( *)if *\((?:!nativeCreate)[\s\S]+?\n *};\n\1}/) || [''])[0]; } /** @@ -854,7 +965,7 @@ * @returns {String} Returns the real method name. */ function getRealName(methodName) { - return aliasToRealMap[methodName] || methodName; + return (!dependencyMap[methodName] && aliasToRealMap[methodName]) || methodName; } /** @@ -869,7 +980,7 @@ return slice.call(arguments, 1).every(function(funcName) { return !( matchFunction(source, funcName) || - RegExp('^ *lodash\\.prototype\\.' + funcName + ' *=.+', 'm').test(source) + RegExp('^ *lodash\\.prototype\\.' + funcName + ' *=[\\s\\S]+?;\\n', 'm').test(source) ); }); } @@ -885,27 +996,30 @@ */ function matchFunction(source, funcName) { var result = source.match(RegExp( - // match multi-line comment block - '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' + + multilineComment + + // match variable declarations with `createIterator` or `overloadWrapper` + '( *)var ' + funcName + ' *=.*?(?:createIterator\\([\\s\\S]+?|overloadWrapper\\([\\s\\S]+?\\n\\1})\\);\\n' + )); + + result || (result = source.match(RegExp( + multilineComment + // begin non-capturing group '( *)(?:' + // match a function declaration 'function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' + // match a variable declaration with function expression - 'var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\1};' + + 'var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\1}(?:\\(\\)\\))?;' + // end non-capturing group ')\\n' - )); + ))); - // match variables that are explicitly defined as functions result || (result = source.match(RegExp( - // match multi-line comment block - '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' + - // match simple variable declarations and those with `createIterator` - ' *var ' + funcName + ' *=(?:.+?|.*?createIterator\\([\\s\\S]+?\\));\\n' + multilineComment + + // match simple variable declarations + '( *)var ' + funcName + ' *=.+?;\\n' ))); - return /@type +Function|function\s*\w*\(/.test(result) ? result[0] : ''; + return /@type +Function|\b(?:function\s*\w*|createIterator|overloadWrapper)\(/.test(result) ? result[0] : ''; } /** @@ -942,7 +1056,7 @@ } /** - * Removes the all references to `varName` from `createIterator` in `source`. + * Removes all references to `identifier` from `createIterator` in `source`. * * @private * @param {String} source The source to process. @@ -955,27 +1069,60 @@ return source; } // remove data object property assignment - var modified = snippet - .replace(RegExp("^(?: *\\/\\/.*\\n)* *'" + identifier + "':.+\\n+", 'm'), '') - .replace(/,(?=\s*})/, ''); + var modified = snippet.replace(RegExp("^(?: *\\/\\/.*\\n)* *(\\w+)\\." + identifier + " *= *(.+\\n+)", 'm'), function(match, object, postlude) { + return RegExp('\\b' + object + '\\.').test(postlude) ? postlude : ''; + }); source = source.replace(snippet, function() { return modified; }); - // clip at the `factory` assignment + // clip to the `factory` assignment snippet = modified.match(/Function\([\s\S]+$/)[0]; - modified = snippet - .replace(RegExp('\\b' + identifier + '\\b,? *', 'g'), '') - .replace(/, *(?=',)/, '') - .replace(/,(?=\s*\))/, '') + // remove `factory` arguments + source = source.replace(snippet, function(match) { + return match + .replace(RegExp('\\b' + identifier + '\\b,? *', 'g'), '') + .replace(/, *(?=',)/, '') + .replace(/,(?=\s*\))/, ''); + }); + + return removeFromGetObject(source, identifier); + } - source = source.replace(snippet, function() { - return modified; + /** + * Removes all references to `identifier` from `getObject` in `source`. + * + * @private + * @param {String} source The source to process. + * @param {String} identifier The name of the property to remove. + * @returns {String} Returns the modified source. + */ + function removeFromGetObject(source, identifier) { + return source.replace(matchFunction(source, 'getObject'), function(match) { + // remove object property assignments + return match + .replace(RegExp("^(?: *\\/\\/.*\\n)* *'" + identifier + "':.+\\n+", 'm'), '') + .replace(/,(?=\s*})/, ''); }); + } - return source; + /** + * Removes all references to `identifier` from `releaseObject` in `source`. + * + * @private + * @param {String} source The source to process. + * @param {String} identifier The name of the property to remove. + * @returns {String} Returns the modified source. + */ + function removeFromReleaseObject(source, identifier) { + return source.replace(matchFunction(source, 'releaseObject'), function(match) { + // remove object property assignments + return match.replace(RegExp("(?:(^ *)| *)(\\w+)\\." + identifier + " *= *(.+\\n+)", 'm'), function(match, indent, object, postlude) { + return (indent || '') + RegExp('\\b' + object + '\\.').test(postlude) ? postlude : ''; + }); + }); } /** @@ -993,21 +1140,22 @@ // remove function if (funcName == 'runInContext') { source = removeRunInContext(source, funcName); - } else if (funcName != 'each' && (snippet = matchFunction(source, funcName))) { + } else if ((snippet = matchFunction(source, funcName))) { source = source.replace(snippet, ''); } - // grab the method assignments snippet - snippet = getMethodAssignments(source); // remove method assignment from `lodash.prototype` - source = source.replace(RegExp('^ *lodash\\.prototype\\.' + funcName + ' *=.+\\n', 'm'), ''); + source = source.replace(RegExp('^ *lodash\\.prototype\\.' + funcName + ' *=[\\s\\S]+?;\\n', 'm'), ''); // remove pseudo private methods - source = source.replace(RegExp('^(?: *//.*\\s*)* *lodash\\._' + funcName + ' *=.+\\n', 'm'), ''); + source = source.replace(RegExp('^(?: *//.*\\s*)* *lodash\\._' + funcName + ' *=[\\s\\S]+?;\\n', 'm'), ''); + + // grab the method assignments snippet + snippet = getMethodAssignments(source); // remove assignment and aliases var modified = getAliases(funcName).concat(funcName).reduce(function(result, otherName) { - return result.replace(RegExp('^(?: *//.*\\s*)* *lodash\\.' + otherName + ' *=.+\\n', 'm'), ''); + return result.replace(RegExp('^(?: *//.*\\s*)* *lodash\\.' + otherName + ' *=[\\s\\S]+?;\\n', 'm'), ''); }, snippet); // replace with the modified snippet @@ -1051,6 +1199,37 @@ return source.replace(getIsFunctionFallback(source), ''); } + /** + * Removes the `createObject` fallback from `source`. + * + * @private + * @param {String} source The source to process. + * @returns {String} Returns the modified source. + */ + function removeCreateObjectFallback(source) { + return source.replace(getCreateObjectFallback(source), ''); + } + + /** + * Removes the binding optimization from `source`. + * + * @private + * @param {String} source The source to process. + * @returns {String} Returns the modified source. + */ + function removeBindingOptimization(source) { + source = removeVar(source, 'fnToString'); + source = removeVar(source, 'reThis'); + + // remove `reThis` from `createCallback` + source = source.replace(matchFunction(source, 'createCallback'), function(match) { + return match.replace(/\s*\|\|\s*\(reThis[\s\S]+?\)\)\)/, ''); + }); + + return source; + } + + /** * Removes the `Object.keys` object iteration optimization from `source`. * @@ -1136,6 +1315,27 @@ return source; } + /** + * Removes all `support.enumErrorProps` references from `source`. + * + * @private + * @param {String} source The source to process. + * @returns {String} Returns the modified source. + */ + function removeSupportEnumErrorProps(source) { + source = removeSupportProp(source, 'enumErrorProps'); + + // remove `support.enumErrorProps` from `iteratorTemplate` + source = source.replace(getIteratorTemplate(source), function(match) { + return match + .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumErrorProps *(?:&&|\))(.+?}["']|[\s\S]+?<% *} *(?:%>|["'])).+/g, '') + .replace(/support\.enumErrorProps\s*\|\|\s*/g, ''); + }); + + return source; + } + + /** * Removes all `support.enumPrototypes` references from `source`. * @@ -1156,7 +1356,7 @@ // remove `support.enumPrototypes` from `iteratorTemplate` source = source.replace(getIteratorTemplate(source), function(match) { return match - .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumPrototypes *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '') + .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumPrototypes *(?:&&|\))(.+?}["']|[\s\S]+?<% *} *(?:%>|["'])).+/g, '') .replace(/support\.enumPrototypes\s*\|\|\s*/g, ''); }); @@ -1174,14 +1374,11 @@ source = removeFunction(source, 'isNode'); source = removeSupportProp(source, 'nodeClass'); - // remove `support.nodeClass` from `shimIsPlainObject` - source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) { - return match.replace(/\(support\.nodeClass[\s\S]+?\)\)/, 'true'); - }); - - // remove `support.nodeClass` from `_.clone` - source = source.replace(matchFunction(source, 'clone'), function(match) { - return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, ''); + // remove `support.nodeClass` from `_.clone` and `shimIsPlainObject` + _.each(['clone', 'shimIsPlainObject'], function(methodName) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, ''); + }); }); // remove `support.nodeClass` from `_.isEqual` @@ -1205,7 +1402,7 @@ // remove `support.nonEnumArgs` from `_.keys` source = source.replace(matchFunction(source, 'keys'), function(match) { return match - .replace(/(?:\s*\|\|\s*)?\(support\.nonEnumArgs[^)]+\)\)/, '') + .replace(/(?:\s*\|\|\s*)?\(support\.nonEnumArgs[\s\S]+?\)\)/, '') .replace(/\s*if *\(\s*\)[^}]+}/, ''); }); @@ -1228,9 +1425,13 @@ */ function removeSupportNonEnumShadows(source) { source = removeSupportProp(source, 'nonEnumShadows'); + source = removeVar(source, 'nonEnumProps'); source = removeVar(source, 'shadowedProps'); source = removeFromCreateIterator(source, 'shadowedProps'); + // remove nested `nonEnumProps` assignments + source = source.replace(/^ *\(function[\s\S]+?\n *var length\b[\s\S]+?shadowedProps[\s\S]+?}\(\)\);\n/m, ''); + // remove `support.nonEnumShadows` from `iteratorTemplate` source = source.replace(getIteratorTemplate(source), function(match) { return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(support\.nonEnumShadows[\s\S]+?["']\1<% *} *%>.+/, ''); @@ -1301,7 +1502,7 @@ // remove `support.unindexedChars` from `iteratorTemplate` source = source.replace(getIteratorTemplate(source), function(match) { return match - .replace(/'if *\(<%= *arrays *%>[^']*/, '$&\\n') + .replace(/'if *\(<%= *array *%>[^']*/, '$&\\n') .replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(support\.unindexedChars[\s\S]+?["']\1<% *} *%>.+/, ''); }); @@ -1318,6 +1519,9 @@ function removeRunInContext(source) { source = removeVar(source, 'contextProps'); + // replace reference in `reThis` assignment + source = source.replace(/\btest\(runInContext\)/, 'test(function() { return this; })'); + // remove function scaffolding, leaving most of its content source = source.replace(matchFunction(source, 'runInContext'), function(match) { return match @@ -1361,8 +1565,7 @@ */ function removeSupportProp(source, propName) { return source.replace(RegExp( - // match multi-line comment block - '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' + + multilineComment + // match a `try` block '(?: *try\\b.+\\n)?' + // match the `support` property assignment @@ -1382,15 +1585,14 @@ */ function removeVar(source, varName) { // simplify complex variable assignments - if (/^(?:cloneableClasses|contextProps|ctorByClass|shadowedProps|whitespace)$/.test(varName)) { + if (/^(?:cloneableClasses|contextProps|ctorByClass|nonEnumProps|shadowedProps|whitespace)$/.test(varName)) { source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?;\\n\\n'), '$1=null;\n\n'); } source = removeFunction(source, varName); source = source.replace(RegExp( - // match multi-line comment block - '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' + + multilineComment + // match a variable declaration that's not part of a declaration list '( *)var ' + varName + ' *= *(?:.+?(?:;|&&\\n[^;]+;)|(?:\\w+\\(|{)[\\s\\S]+?\\n\\1.+?;)\\n|' + // match a variable in a declaration list @@ -1432,7 +1634,6 @@ return source; } - /** * Replaces the `support` object `propName` property value in `source` with `propValue`. * @@ -1593,7 +1794,7 @@ // used to specify a custom IIFE to wrap Lo-Dash var iife = options.reduce(function(result, value) { - var match = value.match(/iife=(.*)/); + var match = value.match(/^iife=(.*)$/); return match ? match[1] : result; }, null); @@ -1648,7 +1849,7 @@ // 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; + return /^exports=.*$/.test(value) ? optionToArray(value).sort() : result; }, isUnderscore ? ['commonjs', 'global', 'node'] : exportsAll.slice() @@ -1656,13 +1857,13 @@ // used to specify the AMD module ID of Lo-Dash used by precompiled templates var moduleId = options.reduce(function(result, value) { - var match = value.match(/moduleId=(.*)/); + var match = value.match(/^moduleId=(.*)$/); return match ? match[1] : result; }, 'lodash'); // used to specify the output path for builds var outputPath = options.reduce(function(result, value, index) { - if (/-o|--output/.test(value)) { + if (/^(?:-o|--output)$/.test(value)) { result = options[index + 1]; var dirname = path.dirname(result); fs.mkdirpSync(dirname); @@ -1673,7 +1874,7 @@ // used to match external template files to precompile var templatePattern = options.reduce(function(result, value) { - var match = value.match(/template=(.+)$/); + var match = value.match(/^template=(.+)$/); return match ? path.join(fs.realpathSync(path.dirname(match[1])), path.basename(match[1])) : result; @@ -1681,7 +1882,7 @@ // used as the template settings for precompiled templates var templateSettings = options.reduce(function(result, value) { - var match = value.match(/settings=(.+)$/); + var match = value.match(/^settings=(.+)$/); return match ? _.assign(result, Function('return {' + match[1].replace(/^{|}$/g, '') + '}')()) : result; @@ -1712,33 +1913,38 @@ return _.contains(methods, methodName); }; + // delete the `_.findWhere` dependency map to enable its alias mapping + if (!isUnderscore || useLodashMethod('findWhere')) { + delete dependencyMap.findWhere; + } + // methods to include in the build var includeMethods = options.reduce(function(accumulator, value) { - return /include/.test(value) + return /^include=.*$/.test(value) ? _.union(accumulator, optionToMethodsArray(source, value)) : accumulator; }, []); // methods to remove from the build var minusMethods = options.reduce(function(accumulator, value) { - return /exclude|minus/.test(value) + return /^(?:exclude|minus)=.*$/.test(value) ? _.union(accumulator, optionToMethodsArray(source, value)) : accumulator; }, []); // methods to add to the build var plusMethods = options.reduce(function(accumulator, value) { - return /plus/.test(value) + return /^plus=.*$/.test(value) ? _.union(accumulator, optionToMethodsArray(source, value)) : accumulator; }, []); // methods categories to include in the build var categories = options.reduce(function(accumulator, value) { - if (/category|exclude|include|minus|plus/.test(value)) { + if (/^(category|exclude|include|minus|plus)=.+$/.test(value)) { var array = optionToArray(value); - accumulator = _.union(accumulator, /category/.test(value) - ? array.map(capitalize) + accumulator = _.union(accumulator, /^category=.*$/.test(value) + ? array.map(function(category) { return capitalize(category.toLowerCase()); }) : array.filter(function(category) { return /^[A-Z]/.test(category); }) ); } @@ -1756,49 +1962,107 @@ if (isModern) { dependencyMap.reduceRight = _.without(dependencyMap.reduceRight, 'isString'); - if (!isMobile) { - dependencyMap.isEmpty = _.without(dependencyMap.isEmpty, 'isArguments'); - dependencyMap.isEqual = _.without(dependencyMap.isEqual, 'isArguments'); - dependencyMap.isPlainObject = _.without(dependencyMap.isPlainObject, 'isArguments'); - dependencyMap.keys = _.without(dependencyMap.keys, 'isArguments'); + if (isMobile) { + _.each(['assign', 'defaults'], function(methodName) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'keys'); + }); + } + else { + _.each(['isEmpty', 'isEqual', 'isPlainObject', 'keys'], function(methodName) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'isArguments'); + }); } } if (isUnderscore) { - dependencyMap.contains = _.without(dependencyMap.contains, 'isString'); - dependencyMap.createCallback = _.without(dependencyMap.createCallback, 'isEqual'); - dependencyMap.findWhere = ['where']; - dependencyMap.flatten = _.without(dependencyMap.flatten, 'createCallback'); - dependencyMap.isEmpty = ['isArray', 'isString']; - dependencyMap.isEqual = _.without(dependencyMap.isEqual, 'forIn', 'isArguments'); - dependencyMap.max = _.without(dependencyMap.max, 'isArray', 'isString'); - dependencyMap.min = _.without(dependencyMap.min, 'isArray', 'isString'); - dependencyMap.pick = _.without(dependencyMap.pick, 'forIn', 'isObject'); - dependencyMap.reduceRight = _.without(dependencyMap.reduceRight, 'isString'); - dependencyMap.template = _.without(dependencyMap.template, 'keys', 'values'); - dependencyMap.toArray.push('isArray', 'map'); - dependencyMap.value = _.without(dependencyMap.value, 'isArray'); - dependencyMap.where.push('find', 'isEmpty'); - if (!useLodashMethod('clone') && !useLodashMethod('cloneDeep')) { dependencyMap.clone = _.without(dependencyMap.clone, 'forEach', 'forOwn'); } + if (!useLodashMethod('contains')) { + dependencyMap.contains = _.without(dependencyMap.contains, 'isString'); + } + if (!useLodashMethod('flatten')) { + dependencyMap.flatten = _.without(dependencyMap.flatten, 'createCallback'); + } + if (!useLodashMethod('isEmpty')) { + dependencyMap.isEmpty = ['isArray', 'isString']; + } + if (!useLodashMethod('isEqual')) { + dependencyMap.isEqual = _.without(dependencyMap.isEqual, 'forIn', 'isArguments'); + } + if (!useLodashMethod('pick')){ + dependencyMap.pick = _.without(dependencyMap.pick, 'forIn', 'isObject'); + } + if (!useLodashMethod('template')) { + dependencyMap.template = _.without(dependencyMap.template, 'keys', 'values'); + } + if (!useLodashMethod('toArray')) { + dependencyMap.toArray.push('isArray', 'map'); + } + if (!useLodashMethod('where')) { + dependencyMap.createCallback = _.without(dependencyMap.createCallback, 'isEqual'); + dependencyMap.where.push('find', 'isEmpty'); + } + + _.each(['clone', 'difference', 'intersection', 'isEqual', 'sortBy', 'uniq'], function(methodName) { + if (methodName == 'clone' + ? (!useLodashMethod('clone') && !useLodashMethod('cloneDeep')) + : !useLodashMethod(methodName) + ) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'getArray', 'getObject', 'releaseArray', 'releaseObject'); + } + }); + + _.each(['debounce', 'throttle'], function(methodName) { + if (!useLodashMethod(methodName)) { + dependencyMap[methodName] = []; + } + }); + + _.each(['difference', 'intersection', 'uniq'], function(methodName) { + if (!useLodashMethod(methodName)) { + dependencyMap[methodName] = ['getIndexOf'].concat(_.without(dependencyMap[methodName], 'cacheIndexOf', 'createCache')); + } + }); + + _.each(['flatten', 'uniq'], function(methodName) { + if (!useLodashMethod(methodName)) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'overloadWrapper'); + } + }); + + _.each(['max', 'min'], function(methodName) { + if (!useLodashMethod(methodName)) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'charAtCallback', 'isArray', 'isString'); + } + }); } if (isModern || isUnderscore) { - dependencyMap.at = _.without(dependencyMap.at, 'isString'); - dependencyMap.forEach = _.without(dependencyMap.forEach, 'isString'); - dependencyMap.toArray = _.without(dependencyMap.toArray, 'isString'); + dependencyMap.reduceRight = _.without(dependencyMap.reduceRight, 'isString'); + + _.each(['assign', 'basicEach', 'defaults', 'forIn', 'forOwn', 'shimKeys'], function(methodName) { + if (!(isUnderscore && useLodashMethod(methodName))) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'createIterator'); + } + }); + + _.each(['at', 'forEach', 'toArray'], function(methodName) { + if (!(isUnderscore && useLodashMethod(methodName))) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'isString'); + } + }); if (!isMobile) { - dependencyMap.every = _.without(dependencyMap.every, 'isArray'); - dependencyMap.find = _.without(dependencyMap.find, 'isArray'); - dependencyMap.filter = _.without(dependencyMap.filter, 'isArray'); - dependencyMap.forEach = _.without(dependencyMap.forEach, 'isArguments', 'isArray'); - dependencyMap.forIn = _.without(dependencyMap.forIn, 'isArguments'); - dependencyMap.forOwn = _.without(dependencyMap.forOwn, 'isArguments'); - dependencyMap.map = _.without(dependencyMap.map, 'isArray'); - dependencyMap.max.push('forEach'); - dependencyMap.min.push('forEach'); - dependencyMap.reduce = _.without(dependencyMap.reduce, 'isArray'); + _.each(['every', 'find', 'filter', 'forEach', 'forIn', 'forOwn', 'map', 'reduce'], function(methodName) { + if (!(isUnderscore && useLodashMethod(methodName))) { + dependencyMap[methodName] = _.without(dependencyMap[methodName], 'isArguments', 'isArray'); + } + }); + + _.each(['max', 'min'], function(methodName) { + if (!(isUnderscore && useLodashMethod(methodName))) { + dependencyMap[methodName].push('forEach'); + } + }); } } // add method names explicitly @@ -1820,10 +2084,10 @@ // add `chain` and `findWhere` if (isUnderscore) { - if (_.contains(categories, 'Chaining')) { + if (_.contains(categories, 'Chaining') && !_.contains(methodNames, 'chain')) { methodNames.push('chain'); } - if (_.contains(categories, 'Collections')) { + if (_.contains(categories, 'Collections') && !_.contains(methodNames, 'findWhere')) { methodNames.push('findWhere'); } } @@ -1866,16 +2130,10 @@ source = setUseStrictOption(source, isStrict); if (isLegacy) { - source = removeKeysOptimization(source); - source = removeSetImmediate(source); source = removeSupportProp(source, 'fastBind'); source = replaceSupportProp(source, 'argsClass', 'false'); - _.each(['getPrototypeOf', 'nativeBind', 'nativeIsArray', 'nativeKeys'], function(varName) { - source = replaceVar(source, varName, 'false'); - }); - - _.each(['isIeOpera', 'isV8', 'nativeBind', 'nativeIsArray', 'nativeKeys', 'reNative'], function(varName) { + _.each(['isIeOpera', 'isV8', 'getPrototypeOf', 'nativeBind', 'nativeCreate', 'nativeIsArray', 'nativeKeys', 'reNative'], function(varName) { source = removeVar(source, varName); }); @@ -1889,6 +2147,31 @@ return match.replace(/\bnativeIsArray\s*\|\|\s*/, ''); }); + // replace `createObject` and `isArguments` with their fallbacks + _.each(['createObject', 'isArguments'], function(methodName) { + var capitalized = capitalize(methodName), + get = eval('get' + capitalized + 'Fallback'), + remove = eval('remove' + capitalized + 'Fallback'); + + source = source.replace(matchFunction(source, methodName).replace(RegExp('[\\s\\S]+?function ' + methodName), ''), function() { + var snippet = get(source), + body = snippet.match(RegExp(methodName + ' *= *function([\\s\\S]+?\\n *});'))[1], + indent = getIndent(snippet); + + return body.replace(RegExp('^' + indent, 'gm'), indent.slice(0, -2)) + '\n'; + }); + + source = remove(source); + }); + + // replace `_.isPlainObject` with `shimIsPlainObject` + source = source.replace( + matchFunction(source, 'isPlainObject').replace(/[\s\S]+?var isPlainObject *= */, ''), + matchFunction(source, 'shimIsPlainObject').replace(/[\s\S]+?function shimIsPlainObject/, 'function').replace(/\s*$/, ';\n') + ); + + source = removeFunction(source, 'shimIsPlainObject'); + // replace `_.keys` with `shimKeys` source = source.replace( matchFunction(source, 'keys').replace(/[\s\S]+?var keys *= */, ''), @@ -1896,17 +2179,6 @@ ); source = removeFunction(source, 'shimKeys'); - - // replace `_.isArguments` with fallback - source = source.replace(matchFunction(source, 'isArguments').replace(/[\s\S]+?function isArguments/, ''), function() { - var fallback = getIsArgumentsFallback(source), - body = fallback.match(/isArguments *= *function([\s\S]+? *});/)[1], - indent = getIndent(fallback); - - return body.replace(RegExp('^' + indent, 'gm'), indent.slice(0, -2)) + '\n'; - }); - - source = removeIsArgumentsFallback(source); } if (isModern) { source = removeSupportSpliceObjects(source); @@ -1919,23 +2191,24 @@ else { source = removeIsArrayFallback(source); source = removeIsFunctionFallback(source); + source = removeCreateObjectFallback(source); // remove `shimIsPlainObject` from `_.isPlainObject` source = source.replace(matchFunction(source, 'isPlainObject'), function(match) { return match.replace(/!getPrototypeOf[^:]+:\s*/, ''); }); - - // replace `_.isRegExp` - source = replaceFunction(source, 'isRegExp', [ - 'function isRegExp(value) {', - " return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;", - '}' - ].join('\n')); } } - if (isMobile || isUnderscore) { - source = removeKeysOptimization(source); - source = removeSetImmediate(source); + if ((isLegacy || isMobile || isUnderscore) && !useLodashMethod('createCallback')) { + source = removeBindingOptimization(source); + } + if (isLegacy || isMobile || isUnderscore) { + if (isMobile || (!useLodashMethod('assign') && !useLodashMethod('defaults') && !useLodashMethod('forIn') && !useLodashMethod('forOwn'))) { + source = removeKeysOptimization(source); + } + if (!useLodashMethod('defer')) { + source = removeSetImmediate(source); + } } if (isModern || isUnderscore) { source = removeSupportArgsClass(source); @@ -1946,6 +2219,7 @@ source = removeSupportNodeClass(source); if (!isMobile) { + source = removeSupportEnumErrorProps(source); source = removeSupportEnumPrototypes(source); source = removeSupportNonEnumArgs(source); @@ -1963,12 +2237,21 @@ ' }', ' }', ' } else {', - ' each(collection, callback);', + ' basicEach(collection, callback);', ' }', ' return collection;', '}', ].join('\n')); + // replace `_.isRegExp` + if (!isUnderscore || (isUnderscore && useLodashMethod('isRegExp'))) { + source = replaceFunction(source, 'isRegExp', [ + 'function isRegExp(value) {', + " return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;", + '}' + ].join('\n')); + } + // replace `_.map` source = replaceFunction(source, 'map', [ 'function map(collection, callback, thisArg) {', @@ -1983,7 +2266,7 @@ ' }', ' } else {', ' result = [];', - ' each(collection, function(value, key, collection) {', + ' basicEach(collection, function(value, key, collection) {', ' result[++index] = callback(value, key, collection);', ' });', ' }', @@ -2014,14 +2297,14 @@ match = match.replace(/^( *)var noaccum\b/m, '$1if (!collection) return accumulator;\n$&'); } else if (/^(?:max|min)$/.test(methodName)) { - match = match.replace(/\beach\(/, 'forEach('); - if (!isUnderscore) { + match = match.replace(/\bbasicEach\(/, 'forEach('); + if (!isUnderscore || useLodashMethod(methodName)) { return match; } } return match.replace(/^(( *)if *\(.*?\bisArray\([^\)]+\).*?\) *{\n)(( *)var index[^;]+.+\n+)/m, function(snippet, statement, indent, vars) { vars = vars - .replace(/\b(length *=)[^;]+/, '$1 collection' + (methodName == 'reduce' ? '.length' : ' ? collection.length : 0')) + .replace(/\b(length *=)[^;=]+/, '$1 collection' + (methodName == 'reduce' ? '.length' : ' ? collection.length : 0')) .replace(RegExp('^ ' + indent, 'gm'), indent); return vars + statement.replace(/\bisArray\([^\)]+\)/, "typeof length == 'number'"); @@ -2029,31 +2312,41 @@ }); }); - // replace `arrays` property value of `eachIteratorOptions` with `false` + // replace `array` property value of `eachIteratorOptions` with `false` source = source.replace(/^( *)var eachIteratorOptions *= *[\s\S]+?\n\1};\n/m, function(match) { - return match.replace(/(^ *'arrays':)[^,]+/m, '$1 false'); + return match.replace(/(^ *'array':)[^,]+/m, '$1 false'); }); } } if (isUnderscore) { - // replace `_.assign` - source = replaceFunction(source, 'assign', [ - 'function assign(object) {', - ' if (!object) {', - ' return object;', - ' }', - ' for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {', - ' var iterable = arguments[argsIndex];', - ' if (iterable) {', - ' for (var key in iterable) {', - ' object[key] = iterable[key];', - ' }', - ' }', - ' }', - ' return object;', + // replace `lodash` + source = replaceFunction(source, 'lodash', [ + 'function lodash(value) {', + ' return (value instanceof lodash)', + ' ? value', + ' : new lodashWrapper(value);', '}' ].join('\n')); + // replace `_.assign` + if (!useLodashMethod('assign')) { + source = replaceFunction(source, 'assign', [ + 'function assign(object) {', + ' if (!object) {', + ' return object;', + ' }', + ' for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {', + ' var iterable = arguments[argsIndex];', + ' if (iterable) {', + ' for (var key in iterable) {', + ' object[key] = iterable[key];', + ' }', + ' }', + ' }', + ' return object;', + '}' + ].join('\n')); + } // replace `_.clone` if (!useLodashMethod('clone') && !useLodashMethod('cloneDeep')) { source = replaceFunction(source, 'clone', [ @@ -2064,529 +2357,621 @@ '}' ].join('\n')); } - // replace `_.contains` - source = replaceFunction(source, 'contains', [ - 'function contains(collection, target) {', - ' var length = collection ? collection.length : 0,', - ' result = false;', - " if (typeof length == 'number') {", - ' result = indexOf(collection, target) > -1;', - ' } else {', - ' each(collection, function(value) {', - ' return (result = value === target) && indicatorObject;', - ' });', - ' }', - ' return result;', - '}' - ].join('\n')); - + if (!useLodashMethod('contains')) { + source = replaceFunction(source, 'contains', [ + 'function contains(collection, target) {', + ' var indexOf = getIndexOf(),', + ' length = collection ? collection.length : 0,', + ' result = false;', + " if (length && typeof length == 'number') {", + ' result = indexOf(collection, target) > -1;', + ' } else {', + ' basicEach(collection, function(value) {', + ' return !(result = value === target);', + ' });', + ' }', + ' return result;', + '}' + ].join('\n')); + } // replace `_.debounce` - source = replaceFunction(source, 'debounce', [ - 'function debounce(func, wait, immediate) {', - ' var args,', - ' result,', - ' thisArg,', - ' timeoutId;', - '', - ' function delayed() {', - ' timeoutId = null;', - ' if (!immediate) {', - ' result = func.apply(thisArg, args);', - ' }', - ' }', - ' return function() {', - ' var isImmediate = immediate && !timeoutId;', - ' args = arguments;', - ' thisArg = this;', - '', - ' clearTimeout(timeoutId);', - ' timeoutId = setTimeout(delayed, wait);', - '', - ' if (isImmediate) {', - ' result = func.apply(thisArg, args);', - ' }', - ' return result;', - ' };', - '}' - ].join('\n')); - + if (!useLodashMethod('debounce')) { + source = replaceFunction(source, 'debounce', [ + 'function debounce(func, wait, immediate) {', + ' var args,', + ' result,', + ' thisArg,', + ' timeoutId = null;', + '', + ' function delayed() {', + ' timeoutId = null;', + ' if (!immediate) {', + ' result = func.apply(thisArg, args);', + ' }', + ' }', + ' return function() {', + ' var isImmediate = immediate && !timeoutId;', + ' args = arguments;', + ' thisArg = this;', + '', + ' clearTimeout(timeoutId);', + ' timeoutId = setTimeout(delayed, wait);', + '', + ' if (isImmediate) {', + ' result = func.apply(thisArg, args);', + ' }', + ' return result;', + ' };', + '}' + ].join('\n')); + } // replace `_.defaults` - source = replaceFunction(source, 'defaults', [ - 'function defaults(object) {', - ' if (!object) {', - ' return object;', - ' }', - ' for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {', - ' var iterable = arguments[argsIndex];', - ' if (iterable) {', - ' for (var key in iterable) {', - ' if (object[key] == null) {', - ' object[key] = iterable[key];', - ' }', - ' }', - ' }', - ' }', - ' return object;', - '}' - ].join('\n')); - + if (!useLodashMethod('defaults')) { + source = replaceFunction(source, 'defaults', [ + 'function defaults(object) {', + ' if (!object) {', + ' return object;', + ' }', + ' for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {', + ' var iterable = arguments[argsIndex];', + ' if (iterable) {', + ' for (var key in iterable) {', + ' if (object[key] == null) {', + ' object[key] = iterable[key];', + ' }', + ' }', + ' }', + ' }', + ' return object;', + '}' + ].join('\n')); + } // replace `_.difference` - source = replaceFunction(source, 'difference', [ - 'function difference(array) {', - ' var index = -1,', - ' length = array.length,', - ' flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),', - ' result = [];', - '', - ' while (++index < length) {', - ' var value = array[index];', - ' if (indexOf(flattened, value) < 0) {', - ' result.push(value);', - ' }', - ' }', - ' return result;', - '}' - ].join('\n')); - - // replace `_.flatten` - source = replaceFunction(source, 'flatten', [ - 'function flatten(array, isShallow) {', - ' var index = -1,', - ' length = array ? array.length : 0,', - ' result = [];', - '' , - ' while (++index < length) {', - ' var value = array[index];', - ' if (isArray(value)) {', - ' push.apply(result, isShallow ? value : flatten(value));', - ' } else {', - ' result.push(value);', - ' }', - ' }', - ' return result;', - '}' - ].join('\n')); - - // replace `_.intersection` - source = replaceFunction(source, 'intersection', [ - 'function intersection(array) {', - ' var args = arguments,', - ' argsLength = args.length,', - ' index = -1,', - ' length = array ? array.length : 0,', - ' result = [];', - '', - ' outer:', - ' while (++index < length) {', - ' var value = array[index];', - ' if (indexOf(result, value) < 0) {', - ' var argsIndex = argsLength;', - ' while (--argsIndex) {', - ' if (indexOf(args[argsIndex], value) < 0) {', - ' continue outer;', - ' }', - ' }', - ' result.push(value);', - ' }', - ' }', - ' return result;', - '}' - ].join('\n')); - - // replace `_.isEmpty` - source = replaceFunction(source, 'isEmpty', [ - 'function isEmpty(value) {', - ' if (!value) {', - ' return true;', - ' }', - ' if (isArray(value) || isString(value)) {', - ' return !value.length;', - ' }', - ' for (var key in value) {', - ' if (hasOwnProperty.call(value, key)) {', - ' return false;', - ' }', - ' }', - ' return true;', - '}' - ].join('\n')); + if (!useLodashMethod('difference')) { + source = replaceFunction(source, 'difference', [ + 'function difference(array) {', + ' var index = -1,', + ' indexOf = getIndexOf(),', + ' length = array.length,', + ' flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),', + ' result = [];', + '', + ' while (++index < length) {', + ' var value = array[index];', + ' if (indexOf(flattened, value) < 0) {', + ' result.push(value);', + ' }', + ' }', + ' return result;', + '}' + ].join('\n')); + } + // add Underscore's `_.findWhere` + if (!useLodashMethod('findWhere') && !useLodashMethod('where')) { + source = source.replace(matchFunction(source, 'find'), function(match) { + var indent = getIndent(match); + return match && (match + [ + '', + '/**', + ' * Examines each element in a `collection`, returning the first that', + ' * has the given `properties`. When checking `properties`, this method', + ' * performs a deep comparison between values to determine if they are', + ' * equivalent to each other.', + ' *', + ' * @static', + ' * @memberOf _', + ' * @category Collections', + ' * @param {Array|Object|String} collection The collection to iterate over.', + ' * @param {Object} properties The object of property values to filter by.', + ' * @returns {Mixed} Returns the found element, else `undefined`.', + ' * @example', + ' *', + ' * var food = [', + " * { 'name': 'apple', 'organic': false, 'type': 'fruit' },", + " * { 'name': 'banana', 'organic': true, 'type': 'fruit' },", + " * { 'name': 'beet', 'organic': false, 'type': 'vegetable' }", + ' * ];', + ' *', + " * _.findWhere(food, { 'type': 'vegetable' });", + " * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }", + ' */', + 'function findWhere(object, properties) {', + ' return where(object, properties, true);', + '}', + '' + ].join('\n' + indent)); + }); + // replace alias assignment + source = source.replace(getMethodAssignments(source), function(match) { + return match.replace(/^( *lodash.findWhere *= *).+/m, '$1findWhere;'); + }); + } + // replace `_.flatten` + if (!useLodashMethod('flatten')) { + source = replaceFunction(source, 'flatten', [ + 'function flatten(array, isShallow) {', + ' var index = -1,', + ' length = array ? array.length : 0,', + ' result = [];', + '' , + ' while (++index < length) {', + ' var value = array[index];', + ' if (isArray(value)) {', + ' push.apply(result, isShallow ? value : flatten(value));', + ' } else {', + ' result.push(value);', + ' }', + ' }', + ' return result;', + '}' + ].join('\n')); + } + // replace `_.intersection` + if (!useLodashMethod('intersection')) { + source = replaceFunction(source, 'intersection', [ + 'function intersection(array) {', + ' var args = arguments,', + ' argsLength = args.length,', + ' index = -1,', + ' indexOf = getIndexOf(),', + ' length = array ? array.length : 0,', + ' result = [];', + '', + ' outer:', + ' while (++index < length) {', + ' var value = array[index];', + ' if (indexOf(result, value) < 0) {', + ' var argsIndex = argsLength;', + ' while (--argsIndex) {', + ' if (indexOf(args[argsIndex], value) < 0) {', + ' continue outer;', + ' }', + ' }', + ' result.push(value);', + ' }', + ' }', + ' return result;', + '}' + ].join('\n')); + } + // replace `_.isEmpty` + if (!useLodashMethod('isEmpty')) { + source = replaceFunction(source, 'isEmpty', [ + 'function isEmpty(value) {', + ' if (!value) {', + ' return true;', + ' }', + ' if (isArray(value) || isString(value)) {', + ' return !value.length;', + ' }', + ' for (var key in value) {', + ' if (hasOwnProperty.call(value, key)) {', + ' return false;', + ' }', + ' }', + ' return true;', + '}' + ].join('\n')); + } // replace `_.isEqual` - source = replaceFunction(source, 'isEqual', [ - 'function isEqual(a, b, stackA, stackB) {', - ' if (a === b) {', - ' return a !== 0 || (1 / a == 1 / b);', - ' }', - ' var type = typeof a,', - ' otherType = typeof b;', - '', - ' if (a === a &&', - " (!a || (type != 'function' && type != 'object')) &&", - " (!b || (otherType != 'function' && otherType != 'object'))) {", - ' return false;', - ' }', - ' if (a == null || b == null) {', - ' return a === b;', - ' }', - ' var className = toString.call(a),', - ' otherClass = toString.call(b);', - '', - ' if (className != otherClass) {', - ' return false;', - ' }', - ' switch (className) {', - ' case boolClass:', - ' case dateClass:', - ' return +a == +b;', - '', - ' case numberClass:', - ' return a != +a', - ' ? b != +b', - ' : (a == 0 ? (1 / a == 1 / b) : a == +b);', - '', - ' case regexpClass:', - ' case stringClass:', - ' return a == String(b);', - ' }', - ' var isArr = className == arrayClass;', - ' if (!isArr) {', - ' if (a instanceof lodash || b instanceof lodash) {', - ' return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, stackA, stackB);', - ' }', - ' if (className != objectClass) {', - ' return false;', - ' }', - ' var ctorA = a.constructor,', - ' ctorB = b.constructor;', - '', - ' if (ctorA != ctorB && !(', - ' isFunction(ctorA) && ctorA instanceof ctorA &&', - ' isFunction(ctorB) && ctorB instanceof ctorB', - ' )) {', - ' return false;', - ' }', - ' }', - ' stackA || (stackA = []);', - ' stackB || (stackB = []);', - '', - ' var length = stackA.length;', - ' while (length--) {', - ' if (stackA[length] == a) {', - ' return stackB[length] == b;', - ' }', - ' }', - ' var result = true,', - ' size = 0;', - '', - ' stackA.push(a);', - ' stackB.push(b);', - '', - ' if (isArr) {', - ' size = b.length;', - ' result = size == a.length;', - '', - ' if (result) {', - ' while (size--) {', - ' if (!(result = isEqual(a[size], b[size], stackA, stackB))) {', - ' break;', - ' }', - ' }', - ' }', - ' return result;', - ' }', - ' forIn(b, function(value, key, b) {', - ' if (hasOwnProperty.call(b, key)) {', - ' size++;', - ' return !(result = hasOwnProperty.call(a, key) && isEqual(a[key], value, stackA, stackB)) && indicatorObject;', - ' }', - ' });', - '', - ' if (result) {', - ' forIn(a, function(value, key, a) {', - ' if (hasOwnProperty.call(a, key)) {', - ' return !(result = --size > -1) && indicatorObject;', - ' }', - ' });', - ' }', - ' return result;', - '}' - ].join('\n')); - - // replace `lodash` - source = replaceFunction(source, 'lodash', [ - 'function lodash(value) {', - ' return (value instanceof lodash)', - ' ? value', - ' : new lodashWrapper(value);', - '}' - ].join('\n')); - + if (!useLodashMethod('isEqual')) { + source = replaceFunction(source, 'isEqual', [ + 'function isEqual(a, b, stackA, stackB) {', + ' if (a === b) {', + ' return a !== 0 || (1 / a == 1 / b);', + ' }', + ' var type = typeof a,', + ' otherType = typeof b;', + '', + ' if (a === a &&', + " (!a || (type != 'function' && type != 'object')) &&", + " (!b || (otherType != 'function' && otherType != 'object'))) {", + ' return false;', + ' }', + ' if (a == null || b == null) {', + ' return a === b;', + ' }', + ' var className = toString.call(a),', + ' otherClass = toString.call(b);', + '', + ' if (className != otherClass) {', + ' return false;', + ' }', + ' switch (className) {', + ' case boolClass:', + ' case dateClass:', + ' return +a == +b;', + '', + ' case numberClass:', + ' return a != +a', + ' ? b != +b', + ' : (a == 0 ? (1 / a == 1 / b) : a == +b);', + '', + ' case regexpClass:', + ' case stringClass:', + ' return a == String(b);', + ' }', + ' var isArr = className == arrayClass;', + ' if (!isArr) {', + ' if (a instanceof lodash || b instanceof lodash) {', + ' return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, stackA, stackB);', + ' }', + ' if (className != objectClass) {', + ' return false;', + ' }', + ' var ctorA = a.constructor,', + ' ctorB = b.constructor;', + '', + ' if (ctorA != ctorB && !(', + ' isFunction(ctorA) && ctorA instanceof ctorA &&', + ' isFunction(ctorB) && ctorB instanceof ctorB', + ' )) {', + ' return false;', + ' }', + ' }', + ' stackA || (stackA = []);', + ' stackB || (stackB = []);', + '', + ' var length = stackA.length;', + ' while (length--) {', + ' if (stackA[length] == a) {', + ' return stackB[length] == b;', + ' }', + ' }', + ' var result = true,', + ' size = 0;', + '', + ' stackA.push(a);', + ' stackB.push(b);', + '', + ' if (isArr) {', + ' size = b.length;', + ' result = size == a.length;', + '', + ' if (result) {', + ' while (size--) {', + ' if (!(result = isEqual(a[size], b[size], stackA, stackB))) {', + ' break;', + ' }', + ' }', + ' }', + ' return result;', + ' }', + ' forIn(b, function(value, key, b) {', + ' if (hasOwnProperty.call(b, key)) {', + ' size++;', + ' return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, stackA, stackB));', + ' }', + ' });', + '', + ' if (result) {', + ' forIn(a, function(value, key, a) {', + ' if (hasOwnProperty.call(a, key)) {', + ' return (result = --size > -1);', + ' }', + ' });', + ' }', + ' return result;', + '}' + ].join('\n')); + } + // replace `_.memoize` + if (!useLodashMethod('memoize')) { + source = replaceFunction(source, 'memoize', [ + 'function memoize(func, resolver) {', + ' var cache = {};', + ' return function() {', + ' var key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]);', + ' return hasOwnProperty.call(cache, key)', + ' ? cache[key]', + ' : (cache[key] = func.apply(this, arguments));', + ' };', + '}' + ].join('\n')); + } // replace `_.omit` - source = replaceFunction(source, 'omit', [ - 'function omit(object) {', - ' var props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),', - ' result = {};', - '', - ' forIn(object, function(value, key) {', - ' if (indexOf(props, key) < 0) {', - ' result[key] = value;', - ' }', - ' });', - ' return result;', - '}' - ].join('\n')); - + if (!useLodashMethod('omit')) { + source = replaceFunction(source, 'omit', [ + 'function omit(object) {', + ' var indexOf = getIndexOf(),', + ' props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),', + ' result = {};', + '', + ' forIn(object, function(value, key) {', + ' if (indexOf(props, key) < 0) {', + ' result[key] = value;', + ' }', + ' });', + ' return result;', + '}' + ].join('\n')); + } // replace `_.pick` - source = replaceFunction(source, 'pick', [ - 'function pick(object) {', - ' var index = -1,', - ' props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),', - ' length = props.length,', - ' result = {};', - '', - ' while (++index < length) {', - ' var prop = props[index];', - ' if (prop in object) {', - ' result[prop] = object[prop];', - ' }', - ' }', - ' return result;', - '}' - ].join('\n')); - + if (!useLodashMethod('pick')) { + source = replaceFunction(source, 'pick', [ + 'function pick(object) {', + ' var index = -1,', + ' props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),', + ' length = props.length,', + ' result = {};', + '', + ' while (++index < length) {', + ' var prop = props[index];', + ' if (prop in object) {', + ' result[prop] = object[prop];', + ' }', + ' }', + ' return result;', + '}' + ].join('\n')); + } // replace `_.result` - source = replaceFunction(source, 'result', [ - 'function result(object, property) {', - ' var value = object ? object[property] : null;', - ' return isFunction(value) ? object[property]() : value;', - '}' - ].join('\n')); - + if (!useLodashMethod('result')) { + source = replaceFunction(source, 'result', [ + 'function result(object, property) {', + ' var value = object ? object[property] : null;', + ' return isFunction(value) ? object[property]() : value;', + '}' + ].join('\n')); + } + // replace `_.sortBy` + if (!useLodashMethod('sortBy')) { + source = replaceFunction(source, 'sortBy', [ + 'function sortBy(collection, callback, thisArg) {', + ' var index = -1,', + ' length = collection ? collection.length : 0,', + " result = Array(typeof length == 'number' ? length : 0);", + '', + ' callback = lodash.createCallback(callback, thisArg);', + ' forEach(collection, function(value, key, collection) {', + ' result[++index] = {', + " 'criteria': callback(value, key, collection),", + " 'index': index,", + " 'value': value", + ' };', + ' });', + '', + ' length = result.length;', + ' result.sort(compareAscending);', + ' while (length--) {', + ' result[length] = result[length].value;', + ' }', + ' return result;', + '}' + ].join('\n')); + } // replace `_.template` - source = replaceFunction(source, 'template', [ - 'function template(text, data, options) {', - " text || (text = '');", - ' options = defaults({}, options, lodash.templateSettings);', - '', - ' var index = 0,', - ' source = "__p += \'",', - ' variable = options.variable;', - '', - ' var reDelimiters = RegExp(', - " (options.escape || reNoMatch).source + '|' +", - " (options.interpolate || reNoMatch).source + '|' +", - " (options.evaluate || reNoMatch).source + '|$'", - " , 'g');", - '', - ' text.replace(reDelimiters, function(match, escapeValue, interpolateValue, evaluateValue, offset) {', - ' source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);', - ' if (escapeValue) {', - ' source += "\' +\\n_.escape(" + escapeValue + ") +\\n\'";', - ' }', - ' if (evaluateValue) {', - ' source += "\';\\n" + evaluateValue + ";\\n__p += \'";', - ' }', - ' if (interpolateValue) {', - ' source += "\' +\\n((__t = (" + interpolateValue + ")) == null ? \'\' : __t) +\\n\'";', - ' }', - ' index = offset + match.length;', - ' return match;', - ' });', - '', - ' source += "\';\\n";', - ' if (!variable) {', - " variable = 'obj';", - " source = 'with (' + variable + ' || {}) {\\n' + source + '\\n}\\n';", - ' }', - " source = 'function(' + variable + ') {\\n' +", - ' "var __t, __p = \'\', __j = Array.prototype.join;\\n" +', - ' "function print() { __p += __j.call(arguments, \'\') }\\n" +', - ' source +', - " 'return __p\\n}';", - '', - ' try {', - " var result = Function('_', 'return ' + source)(lodash);", - ' } catch(e) {', - ' e.source = source;', - ' throw e;', - ' }', - ' if (data) {', - ' return result(data);', - ' }', - ' result.source = source;', - ' return result;', - '}' - ].join('\n')); - + if (!useLodashMethod('template')) { + // remove `_.templateSettings.imports assignment + source = source.replace(/,[^']*'imports':[^}]+}/, ''); + + source = replaceFunction(source, 'template', [ + 'function template(text, data, options) {', + ' var settings = lodash.templateSettings;', + " text || (text = '');", + ' options = iteratorTemplate ? defaults({}, options, settings) : settings;', + '', + ' var index = 0,', + ' source = "__p += \'",', + ' variable = options.variable;', + '', + ' var reDelimiters = RegExp(', + " (options.escape || reNoMatch).source + '|' +", + " (options.interpolate || reNoMatch).source + '|' +", + " (options.evaluate || reNoMatch).source + '|$'", + " , 'g');", + '', + ' text.replace(reDelimiters, function(match, escapeValue, interpolateValue, evaluateValue, offset) {', + ' source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);', + ' if (escapeValue) {', + ' source += "\' +\\n_.escape(" + escapeValue + ") +\\n\'";', + ' }', + ' if (evaluateValue) {', + ' source += "\';\\n" + evaluateValue + ";\\n__p += \'";', + ' }', + ' if (interpolateValue) {', + ' source += "\' +\\n((__t = (" + interpolateValue + ")) == null ? \'\' : __t) +\\n\'";', + ' }', + ' index = offset + match.length;', + ' return match;', + ' });', + '', + ' source += "\';\\n";', + ' if (!variable) {', + " variable = 'obj';", + " source = 'with (' + variable + ' || {}) {\\n' + source + '\\n}\\n';", + ' }', + " source = 'function(' + variable + ') {\\n' +", + ' "var __t, __p = \'\', __j = Array.prototype.join;\\n" +', + ' "function print() { __p += __j.call(arguments, \'\') }\\n" +', + ' source +', + " 'return __p\\n}';", + '', + ' try {', + " var result = Function('_', 'return ' + source)(lodash);", + ' } catch(e) {', + ' e.source = source;', + ' throw e;', + ' }', + ' if (data) {', + ' return result(data);', + ' }', + ' result.source = source;', + ' return result;', + '}' + ].join('\n')); + } // replace `_.throttle` - source = replaceFunction(source, 'throttle', [ - 'function throttle(func, wait) {', - ' var args,', - ' result,', - ' thisArg,', - ' timeoutId,', - ' lastCalled = 0;', - '', - ' function trailingCall() {', - ' lastCalled = new Date;', - ' timeoutId = null;', - ' result = func.apply(thisArg, args);', - ' }', - ' return function() {', - ' var now = new Date,', - ' remaining = wait - (now - lastCalled);', - '', - ' args = arguments;', - ' thisArg = this;', - '', - ' if (remaining <= 0) {', - ' clearTimeout(timeoutId);', - ' timeoutId = null;', - ' lastCalled = now;', - ' result = func.apply(thisArg, args);', - ' }', - ' else if (!timeoutId) {', - ' timeoutId = setTimeout(trailingCall, remaining);', - ' }', - ' return result;', - ' };', - '}' - ].join('\n')); - + if (!useLodashMethod('throttle')) { + source = replaceFunction(source, 'throttle', [ + 'function throttle(func, wait) {', + ' var args,', + ' result,', + ' thisArg,', + ' lastCalled = 0,', + ' timeoutId = null;', + '', + ' function trailingCall() {', + ' lastCalled = new Date;', + ' timeoutId = null;', + ' result = func.apply(thisArg, args);', + ' }', + ' return function() {', + ' var now = new Date,', + ' remaining = wait - (now - lastCalled);', + '', + ' args = arguments;', + ' thisArg = this;', + '', + ' if (remaining <= 0) {', + ' clearTimeout(timeoutId);', + ' timeoutId = null;', + ' lastCalled = now;', + ' result = func.apply(thisArg, args);', + ' }', + ' else if (!timeoutId) {', + ' timeoutId = setTimeout(trailingCall, remaining);', + ' }', + ' return result;', + ' };', + '}' + ].join('\n')); + } // replace `_.times` - source = replaceFunction(source, 'times', [ - 'function times(n, callback, thisArg) {', - ' var index = -1,', - ' result = Array(n > -1 ? n : 0);', - '', - ' while (++index < n) {', - ' result[index] = callback.call(thisArg, index);', - ' }', - ' return result;', - '}' - ].join('\n')); - + if (!useLodashMethod('times')) { + source = replaceFunction(source, 'times', [ + 'function times(n, callback, thisArg) {', + ' var index = -1,', + ' result = Array(n > -1 ? n : 0);', + '', + ' while (++index < n) {', + ' result[index] = callback.call(thisArg, index);', + ' }', + ' return result;', + '}' + ].join('\n')); + } // replace `_.toArray` - source = replaceFunction(source, 'toArray', [ - 'function toArray(collection) {', - ' if (isArray(collection)) {', - ' return slice(collection);', - ' }', - " if (collection && typeof collection.length == 'number') {", - ' return map(collection);', - ' }', - ' return values(collection);', - '}' - ].join('\n')); - + if (!useLodashMethod('toArray')) { + source = replaceFunction(source, 'toArray', [ + 'function toArray(collection) {', + ' if (isArray(collection)) {', + ' return slice(collection);', + ' }', + " if (collection && typeof collection.length == 'number') {", + ' return map(collection);', + ' }', + ' return values(collection);', + '}' + ].join('\n')); + } // replace `_.uniq` - source = replaceFunction(source, 'uniq', [ - 'function uniq(array, isSorted, callback, thisArg) {', - ' var index = -1,', - ' length = array ? array.length : 0,', - ' result = [],', - ' seen = result;', - '', - " if (typeof isSorted != 'boolean' && isSorted != null) {", - ' thisArg = callback;', - ' callback = isSorted;', - ' isSorted = false;', - ' }', - ' if (callback != null) {', - ' seen = [];', - ' callback = lodash.createCallback(callback, thisArg);', - ' }', - ' while (++index < length) {', - ' var value = array[index],', - ' computed = callback ? callback(value, index, array) : value;', - '', - ' if (isSorted', - ' ? !index || seen[seen.length - 1] !== computed', - ' : indexOf(seen, computed) < 0', - ' ) {', - ' if (callback) {', - ' seen.push(computed);', - ' }', - ' result.push(value);', - ' }', - ' }', - ' return result;', - '}' - ].join('\n')); - + if (!useLodashMethod('uniq')) { + source = replaceFunction(source, 'uniq', [ + 'function uniq(array, isSorted, callback, thisArg) {', + ' var index = -1,', + ' indexOf = getIndexOf(),', + ' length = array ? array.length : 0,', + ' result = [],', + ' seen = result;', + '', + " if (typeof isSorted != 'boolean' && isSorted != null) {", + ' thisArg = callback;', + ' callback = isSorted;', + ' isSorted = false;', + ' }', + ' if (callback != null) {', + ' seen = [];', + ' callback = lodash.createCallback(callback, thisArg);', + ' }', + ' while (++index < length) {', + ' var value = array[index],', + ' computed = callback ? callback(value, index, array) : value;', + '', + ' if (isSorted', + ' ? !index || seen[seen.length - 1] !== computed', + ' : indexOf(seen, computed) < 0', + ' ) {', + ' if (callback) {', + ' seen.push(computed);', + ' }', + ' result.push(value);', + ' }', + ' }', + ' return result;', + '}' + ].join('\n')); + } // replace `_.uniqueId` - source = replaceFunction(source, 'uniqueId', [ - 'function uniqueId(prefix) {', - " var id = ++idCounter + '';", - ' return prefix ? prefix + id : id;', - '}' - ].join('\n')); - + if (!useLodashMethod('uniqueId')) { + source = replaceFunction(source, 'uniqueId', [ + 'function uniqueId(prefix) {', + " var id = ++idCounter + '';", + ' return prefix ? prefix + id : id;', + '}' + ].join('\n')); + } // replace `_.where` - source = replaceFunction(source, 'where', [ - 'function where(collection, properties, first) {', - ' return (first && isEmpty(properties))', - ' ? null', - ' : (first ? find : filter)(collection, properties);', - '}' - ].join('\n')); + if (!useLodashMethod('where')) { + source = replaceFunction(source, 'where', [ + 'function where(collection, properties, first) {', + ' return (first && isEmpty(properties))', + ' ? null', + ' : (first ? find : filter)(collection, properties);', + '}' + ].join('\n')); + } + // replace `_.zip` + if (!useLodashMethod('unzip')) { + source = replaceFunction(source, 'zip', [ + 'function zip(array) {', + ' var index = -1,', + " length = array ? max(pluck(arguments, 'length')) : 0,", + ' result = Array(length < 0 ? 0 : length);', + '', + ' while (++index < length) {', + ' result[index] = pluck(arguments, index);', + ' }', + ' return result;', + '}' + ].join('\n')); + } // unexpose `lodash.support` source = source.replace(/lodash\.support *= */, ''); - // remove `_.templateSettings.imports assignment - source = source.replace(/,[^']*'imports':[^}]+}/, ''); - - // remove large array optimizations - source = removeFunction(source, 'cachedContains'); - // replace `slice` with `nativeSlice.call` - source = removeFunction(source, 'slice'); - source = source.replace(/([^.])\bslice\(/g, '$1nativeSlice.call('); - - // remove `_.isEqual` use from `createCallback` - source = source.replace(matchFunction(source, 'createCallback'), function(match) { - return match.replace(/\bisEqual\(([^,]+), *([^,]+)[^)]+\)/, '$1 === $2'); + _.each(['clone', 'first', 'initial', 'last', 'rest', 'toArray'], function(methodName) { + if (methodName == 'clone' + ? (!useLodashMethod('clone') && !useLodashMethod('cloneDeep')) + : !useLodashMethod(methodName) + ) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match.replace(/([^.])\bslice\(/g, '$1nativeSlice.call('); + }); + } }); // remove conditional `charCodeCallback` use from `_.max` and `_.min` _.each(['max', 'min'], function(methodName) { - source = source.replace(matchFunction(source, methodName), function(match) { - return match.replace(/=.+?callback *&& *isString[^:]+:\s*/g, '= '); - }); - }); - - // modify `_.every`, `_.find`, `_.isEqual`, and `_.some` to use the private `indicatorObject` - _.each(['every', 'isEqual'], function(methodName) { - source = source.replace(matchFunction(source, methodName), function(match) { - return match.replace(/\(result *= *(.+?)\);/g, '!(result = $1) && indicatorObject;'); - }); - }); - - source = source.replace(matchFunction(source, 'find'), function(match) { - return match.replace(/return false/, 'return indicatorObject'); - }); - - source = source.replace(matchFunction(source, 'some'), function(match) { - return match.replace(/!\(result *= *(.+?)\);/, '(result = $1) && indicatorObject;'); + if (!useLodashMethod(methodName)) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match.replace(/=.+?callback *&& *isString[^:]+:\s*/g, '= '); + }); + } }); - - // remove unneeded variables if (!useLodashMethod('clone') && !useLodashMethod('cloneDeep')) { source = removeVar(source, 'cloneableClasses'); source = removeVar(source, 'ctorByClass'); } - // remove chainability from `each` and `_.forEach` - if (!useLodashMethod('forEach')) { - _.each(['each', 'forEach'], function(methodName) { - source = source.replace(matchFunction(source, methodName), function(match) { - return match - .replace(/\n *return .+?([};\s]+)$/, '$1') - .replace(/\b(return) +result\b/, '$1') - }); + // remove `_.isEqual` use from `createCallback` + if (!useLodashMethod('where')) { + source = source.replace(matchFunction(source, 'createCallback'), function(match) { + return match.replace(/\bisEqual\(([^,]+), *([^,]+)[^)]+\)/, '$1 === $2'); }); } // remove unused features from `createBound` @@ -2606,66 +2991,30 @@ ].join(indent); }) .replace(/thisBinding *=[^}]+}/, 'thisBinding = thisArg;\n') - .replace(/\(args *=.+/, 'partialArgs.concat(slice(args))'); + .replace(/\(args *=.+/, 'partialArgs.concat(nativeSlice.call(args))'); }); } } - // add Underscore's `_.findWhere` - if (_.contains(buildMethods, 'findWhere')) { - if (isUnderscore) { - source = source.replace(matchFunction(source, 'find'), function(match) { - var indent = getIndent(match); - return match && (match + [ - '', - '/**', - ' * Examines each element in a `collection`, returning the first that', - ' * has the given `properties`. When checking `properties`, this method', - ' * performs a deep comparison between values to determine if they are', - ' * equivalent to each other.', - ' *', - ' * @static', - ' * @memberOf _', - ' * @category Collections', - ' * @param {Array|Object|String} collection The collection to iterate over.', - ' * @param {Object} properties The object of property values to filter by.', - ' * @returns {Mixed} Returns the found element, else `undefined`.', - ' * @example', - ' *', - ' * var food = [', - " * { 'name': 'apple', 'organic': false, 'type': 'fruit' },", - " * { 'name': 'banana', 'organic': true, 'type': 'fruit' },", - " * { 'name': 'beet', 'organic': false, 'type': 'vegetable' }", - ' * ];', - ' *', - " * _.findWhere(food, { 'type': 'vegetable' });", - " * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }", - ' */', - 'function findWhere(object, properties) {', - ' return where(object, properties, true);', - '}', - '' - ].join('\n' + indent)); - }); - } - source = source.replace(getMethodAssignments(source), function(match) { - var methodName = isUnderscore ? 'findWhere' : 'find'; - return match.replace(/^( *)lodash.find *=.+/m, '$&\n$1lodash.findWhere = ' + methodName + ';'); - }); - } // add Underscore's chaining methods - if (_.contains(buildMethods, 'chain')) { + if (isUnderscore ? !_.contains(plusMethods, 'chain') : _.contains(plusMethods, 'chain')) { source = addChainMethods(source); } - // replace `each` references with `forEach` and `forOwn` + // replace `basicEach` references with `forEach` and `forOwn` if ((isUnderscore || (isModern && !isMobile)) && - _.contains(buildMethods, 'forEach') && - (_.contains(buildMethods, 'forOwn') || !useLodashMethod('forOwn')) - ) { - source = source - .replace(matchFunction(source, 'each'), '') - .replace(/^ *lodash\._each *=.+\n/gm, '') - .replace(/\beach(?=\(collection)/g, 'forOwn') - .replace(/\beach(?=\(\[)/g, 'forEach'); + _.contains(buildMethods, 'forEach') && _.contains(buildMethods, 'forOwn')) { + source = removeFunction(source, 'basicEach'); + + // remove `lodash._basicEach` pseudo property + source = source.replace(/^ *lodash\._basicEach *=.+\n/m, ''); + + // replace `basicEach` with `_.forOwn` in "Collections" methods + source = source.replace(/\bbasicEach(?=\(collection)/g, 'forOwn'); + + // replace `basicEach` with `_.forEach` in the rest of the methods + source = source.replace(/(\?\s*)basicEach(?=\s*:)/g, '$1forEach'); + + // replace `basicEach` with `_.forEach` in the method assignment snippet + source = source.replace(/\bbasicEach(?=\(\[)/g, 'forEach'); } var context = vm.createContext({ @@ -2686,7 +3035,8 @@ else { // remove methods from the build allMethods.forEach(function(otherName) { - if (!_.contains(buildMethods, otherName)) { + if (!_.contains(buildMethods, otherName) && + !(otherName == 'findWhere' && !isUnderscore)) { source = removeFunction(source, otherName); } }); @@ -2701,6 +3051,14 @@ /*----------------------------------------------------------------------*/ if (isModern || isUnderscore) { + source = removeFunction(source, 'createIterator'); + + iteratorOptions.forEach(function(prop) { + if (prop != 'array') { + source = removeFromGetObject(source, prop); + } + }); + // inline all functions defined with `createIterator` _.functions(lodash).forEach(function(methodName) { // strip leading underscores to match pseudo private functions @@ -2709,21 +3067,52 @@ // extract, format, and inject the compiled function's source code source = source.replace(reFunc, function(match, indent, left) { return (indent + left) + - getFunctionSource(lodash[methodName], indent) + ';\n'; + cleanupCompiled(getFunctionSource(lodash[methodName], indent)) + ';\n'; }); } }); if (isUnderscore) { - // unexpose "exit early" feature of `each`, `_.forEach`, `_.forIn`, and `_.forOwn` - _.each(['each', 'forEach', 'forIn', 'forOwn'], function(methodName) { - if (methodName == 'each' || !useLodashMethod(methodName)) { + // unexpose "exit early" feature of `basicEach`, `_.forEach`, `_.forIn`, and `_.forOwn` + _.each(['basicEach', 'forEach', 'forIn', 'forOwn'], function(methodName) { + if (methodName == 'basicEach' || !useLodashMethod(methodName)) { source = source.replace(matchFunction(source, methodName), function(match) { return match.replace(/=== *false\)/g, '=== indicatorObject)'); }); } }); + // modify `_.contains`, `_.every`, `_.find`, `_.some`, and `_.transform` to use the private `indicatorObject` + if (isUnderscore && (/\bbasicEach\(/.test(source) || !useLodashMethod('forOwn'))) { + source = source.replace(matchFunction(source, 'every'), function(match) { + return match.replace(/\(result *= *(.+?)\);/g, '!(result = $1) && indicatorObject;'); + }); + + source = source.replace(matchFunction(source, 'find'), function(match) { + return match.replace(/return false/, 'return indicatorObject'); + }); + + source = source.replace(matchFunction(source, 'transform'), function(match) { + return match.replace(/return callback[^)]+\)/, '$& && indicatorObject'); + }); + + _.each(['contains', 'some'], function(methodName) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match.replace(/!\(result *= *(.+?)\);/, '(result = $1) && indicatorObject;'); + }); + }); + } + // modify `_.isEqual` and `shimIsPlainObject` to use the private `indicatorObject` + if (!useLodashMethod('forIn')) { + source = source.replace(matchFunction(source, 'isEqual'), function(match) { + return match.replace(/\(result *= *(.+?)\);/g, '!(result = $1) && indicatorObject;'); + }); + + source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) { + return match.replace(/return false/, 'return indicatorObject'); + }); + } + // remove `thisArg` from unexposed `forIn` and `forOwn` _.each(['forIn', 'forOwn'], function(methodName) { if (!useLodashMethod(methodName)) { @@ -2739,29 +3128,27 @@ if (!useLodashMethod('createCallback')) { source = source.replace(/\blodash\.(createCallback\()\b/g, '$1'); } - // remove `_.assign`, `_.forIn`, `_.forOwn`, `_.isPlainObject`, and `_.zipObject` assignments + // remove chainability from `basicEach` and `_.forEach` + if (!useLodashMethod('forEach')) { + _.each(['basicEach', 'forEach'], function(methodName) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match + .replace(/\n *return .+?([};\s]+)$/, '$1') + .replace(/\b(return) +result\b/, '$1') + }); + }); + } + // remove `_.assign`, `_.forIn`, `_.forOwn`, `_.isPlainObject`, `_.unzip`, and `_.zipObject` assignments (function() { var snippet = getMethodAssignments(source), modified = snippet; - if (!useLodashMethod('assign')) { - modified = modified.replace(/^(?: *\/\/.*\s*)* *lodash\.assign *=.+\n/m, ''); - } - if (!useLodashMethod('createCallback')) { - modified = modified.replace(/^(?: *\/\/.*\s*)* *lodash\.createCallback *=.+\n/m, ''); - } - if (!useLodashMethod('forIn')) { - modified = modified.replace(/^(?: *\/\/.*\s*)* *lodash\.forIn *=.+\n/m, ''); - } - if (!useLodashMethod('forOwn')) { - modified = modified.replace(/^(?: *\/\/.*\s*)* *lodash\.forOwn *=.+\n/m, ''); - } - if (!useLodashMethod('isPlainObject')) { - modified = modified.replace(/^(?: *\/\/.*\s*)* *lodash\.isPlainObject *=.+\n/m, ''); - } - if (!useLodashMethod('zipObject')) { - modified = modified.replace(/^(?: *\/\/.*\s*)* *lodash\.zipObject *=.+\n/m, ''); - } + _.each(['assign', 'createCallback', 'forIn', 'forOwn', 'isPlainObject', 'unzip', 'zipObject'], function(methodName) { + if (!useLodashMethod(methodName)) { + modified = modified.replace(RegExp('^(?: *//.*\\s*)* *lodash\\.' + methodName + ' *=.+\\n', 'm'), ''); + } + }); + source = source.replace(snippet, function() { return modified; }); @@ -2774,12 +3161,14 @@ // inline `iteratorTemplate` template source = source.replace(getIteratorTemplate(source), function(match) { var indent = getIndent(match), - snippet = getFunctionSource(lodash._iteratorTemplate, indent); + snippet = cleanupCompiled(getFunctionSource(lodash._iteratorTemplate, indent)); // 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); + iteratorOptions.forEach(function(prop) { + if (prop !== 'support') { + snippet = snippet.replace(RegExp('([^\\w.])\\b' + prop + '\\b', 'g'), '$1obj.' + prop); + } }); // remove unnecessary code @@ -2790,8 +3179,7 @@ .replace(/__p *\+= *' *';/g, '') .replace(/\s*\+\s*'';/g, ';') .replace(/(__p *\+= *)' *' *\+/g, '$1') - .replace(/(?:; *)([{}])|([{}])(?: *;)/g, '$1$2') - .replace(/\(\(__t *= *\( *([^)]+?) *\)\) *== *null *\? *'' *: *__t\)/g, '($1)'); + .replace(/\(\(__t *= *\( *([\s\S]+?) *\)\) *== *null *\? *'' *: *__t\)/g, '($1)'); // remove the with-statement snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1'); @@ -2859,6 +3247,14 @@ if (isRemoved(source, 'clone', 'isEqual', 'isPlainObject')) { source = removeSupportNodeClass(source); } + if (isRemoved(source, 'createIterator')) { + source = removeVar(source, 'defaultsIteratorOptions'); + source = removeVar(source, 'eachIteratorOptions'); + source = removeVar(source, 'forOwnIteratorOptions'); + source = removeVar(source, 'iteratorTemplate'); + source = removeVar(source, 'templateIterator'); + source = removeSupportNonEnumShadows(source); + } if (isRemoved(source, 'createIterator', 'bind', 'keys')) { source = removeSupportProp(source, 'fastBind'); source = removeVar(source, 'isV8'); @@ -2872,11 +3268,23 @@ if (isRemoved(source, 'defer')) { source = removeSetImmediate(source); } + if (isRemoved(source, 'escape', 'unescape')) { + source = removeVar(source, 'htmlEscapes'); + source = removeVar(source, 'htmlUnescapes'); + } + if (isRemoved(source, 'getArray', 'releaseArray')) { + source = removeVar(source, 'arrayPool'); + } + if (isRemoved(source, 'getObject', 'releaseObject')) { + source = removeVar(source, 'objectPool'); + } + if (isRemoved(source, 'releaseArray', 'releaseObject')) { + source = removeVar(source, 'maxPoolSize'); + } if (isRemoved(source, 'invert')) { source = replaceVar(source, 'htmlUnescapes', "{'&':'&','<':'<','>':'>','"':'\"',''':\"'\"}"); } if (isRemoved(source, 'isArguments')) { - source = removeIsArgumentsFallback(source); source = replaceSupportProp(source, 'argsClass', 'true'); } if (isRemoved(source, 'isArguments', 'isEmpty')) { @@ -2884,9 +3292,7 @@ } if (isRemoved(source, 'isArray')) { source = removeVar(source, 'nativeIsArray'); - } - if (isRemoved(source, 'isFunction')) { - source = removeIsFunctionFallback(source); + source = removeIsArrayFallback(source); } if (isRemoved(source, 'isPlainObject')) { source = removeFunction(source, 'shimIsPlainObject'); @@ -2925,11 +3331,24 @@ source = removeVar(source, 'reLeadingSpacesAndZeros'); source = removeVar(source, 'whitespace'); } + if (isRemoved(source, 'sortBy')) { + _.each([removeFromGetObject, removeFromReleaseObject], function(func) { + source = func(source, 'criteria'); + source = func(source, 'index'); + source = func(source, 'value'); + }); + } if (isRemoved(source, 'template')) { // remove `templateSettings` assignment source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, ''); } + if (isRemoved(source, 'throttle')) { + _.each(['leading', 'maxWait', 'trailing'], function(prop) { + source = removeFromGetObject(source, prop); + }); + } if (isRemoved(source, 'value')) { + source = removeFunction(source, 'chain'); source = removeFunction(source, 'wrapperToString'); source = removeFunction(source, 'wrapperValueOf'); source = removeSupportSpliceObjects(source); @@ -2954,21 +3373,35 @@ // remove all `lodash.prototype` additions source = source .replace(/(?:\s*\/\/.*)*\n( *)forOwn\(lodash, *function\(func, *methodName\)[\s\S]+?\n\1}.+/g, '') - .replace(/(?:\s*\/\/.*)*\n( *)(?:each|forEach)\(\['[\s\S]+?\n\1}.+/g, '') - .replace(/(?:\s*\/\/.*)*\n *lodash\.prototype.+/g, ''); + .replace(/(?:\s*\/\/.*)*\n( *)(?:basicEach|forEach)\(\['[\s\S]+?\n\1}.+/g, '') + .replace(/(?:\s*\/\/.*)*\n *lodash\.prototype.[\s\S]+?;/g, ''); } - if (!/\beach\(/.test(source)) { - source = source.replace(matchFunction(source, 'each'), ''); + + // remove method fallbacks + _.each(['createObject', 'isArguments', 'isArray', 'isFunction'], function(methodName) { + if (_.size(source.match(RegExp(methodName + '\\(', 'g'))) < 2) { + source = eval('remove' + capitalize(methodName) + 'Fallback')(source); + } + }); + + if (!/\bbasicEach\(/.test(source)) { + source = removeFunction(source, 'basicEach'); } - if ((source.match(/\bcreateIterator\b/g) || []).length < 2) { - source = removeFunction(source, 'createIterator'); - source = removeVar(source, 'defaultsIteratorOptions'); - source = removeVar(source, 'eachIteratorOptions'); - source = removeVar(source, 'forOwnIteratorOptions'); - source = removeVar(source, 'iteratorTemplate'); - source = removeVar(source, 'templateIterator'); - source = removeSupportNonEnumShadows(source); + if (_.size(source.match(/[^.]slice\(/g)) < 2) { + source = removeFunction(source, 'slice'); } + if (!/^ *support\.(?:enumErrorProps|nonEnumShadows) *=/m.test(source)) { + source = removeVar(source, 'Error'); + source = removeVar(source, 'errorProto'); + source = removeFromCreateIterator(source, 'errorClass'); + source = removeFromCreateIterator(source, 'errorProto'); + + // remove 'Error' from the `contextProps` array + source = source.replace(/^ *var contextProps *=[\s\S]+?;/m, function(match) { + return match.replace(/'Error', */, ''); + }); + } + // remove code used to resolve unneeded `support` properties source = source.replace(/^ *\(function[\s\S]+?\n(( *)var ctor *= *function[\s\S]+?(?:\n *for.+)+\n)([\s\S]+?)}\(1\)\);\n/m, function(match, setup, indent, body) { var modified = setup; @@ -2981,7 +3414,7 @@ modified = modified .replace(/\bctor *=.+\s+/, '') .replace(/^ *ctor\.prototype.+\s+.+\n/m, '') - .replace(/(?:,\n)? *props *=[^;]+/, '') + .replace(/(?:,\n)? *props *=[^;=]+/, '') .replace(/^ *for *\((?=prop)/, '$&var ') } if (!/support\.nonEnumArgs *=(?! *(?:false|true))/.test(match)) { @@ -3004,7 +3437,7 @@ } debugSource = cleanupSource(source); - source = cleanupSource(source); + source = debugSource; /*------------------------------------------------------------------------*/ @@ -3014,7 +3447,7 @@ // flag to specify creating a custom build var isCustom = ( isLegacy || isMapped || isModern || isNoDep || isStrict || isUnderscore || outputPath || - /(?:category|exclude|exports|iife|include|minus|plus)=/.test(options) || + /(?:category|exclude|exports|iife|include|minus|plus)=.*$/.test(options) || !_.isEqual(exportsOptions, exportsAll) ); @@ -3066,11 +3499,10 @@ data.source = addCommandsToHeader(data.source, options); } if (isStdOut) { + delete data.outputPath; stdout.write(data.source); - callback(data); - } else { - callback(data); } + callback(data); } }); } diff --git a/build/minify.js b/build/minify.js index 2b8a670ecd..64cf27e60b 100755 --- a/build/minify.js +++ b/build/minify.js @@ -3,8 +3,8 @@ 'use strict'; /** Load Node.js modules */ - var https = require('https'), - spawn = require('child_process').spawn, + var cp = require('child_process'), + https = require('https'), zlib = require('zlib'); /** Load other modules */ @@ -19,10 +19,10 @@ path = util.path; /** The Git object ID of `closure-compiler.tar.gz` */ - var closureId = '7815712f73ccb21f587bf3fb72a2f50be788515d'; + var closureId = '9fd5d61c1b706e7505aeb5187941c2c5497e5fd8'; /** The Git object ID of `uglifyjs.tar.gz` */ - var uglifyId = 'fb620e8672ad194b3ab501790e19c40c8ac79286'; + var uglifyId = '7de2795a3af58d1b293e3b0e83cdbc994f4941dc'; /** The path of the directory that is the base of the repository */ var basePath = fs.realpathSync(path.join(__dirname, '..')); @@ -324,6 +324,30 @@ }); } + /** + * Retrieves the Java command-line options used for faster minification by + * the Closure Compiler, invoking the `callback` when finished. Subsequent + * calls will lazily return the previously retrieved options. The `callback` + * is invoked with one argument; (options). + * + * See https://code.google.com/p/closure-compiler/wiki/FAQ#What_are_the_recommended_Java_VM_command-line_options?. + * + * @private + * @param {Function} callback The function called once the options have been retrieved. + */ + function getJavaOptions(callback) { + var result = []; + cp.exec('java -version -client -d32', function(error) { + if (!error && process.platform != 'win32') { + result.push('-client', '-d32'); + } + getJavaOptions = function(callback) { + _.defer(callback, result); + }; + callback(result); + }); + } + /** * Resolves the source map path from the given output path. * @@ -350,6 +374,8 @@ var filePath = this.filePath, isAdvanced = mode == 'advanced', isMapped = this.isMapped, + isSilent = this.isSilent, + isTemplate = this.isTemplate, options = closureOptions.slice(), outputPath = this.outputPath, mapPath = getMapPath(outputPath), @@ -375,58 +401,63 @@ if (isMapped) { options.push('--create_source_map=' + mapPath, '--source_map_format=V3'); } - - var compiler = spawn('java', ['-jar', closurePath].concat(options)); - if (!this.isSilent) { - console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...'); + if (isTemplate) { + options.push('--charset=UTF-8'); } - var error = ''; - compiler.stderr.on('data', function(data) { - error += data; - }); + getJavaOptions(function(javaOptions) { + var compiler = cp.spawn('java', javaOptions.concat('-jar', closurePath, options)); + if (!isSilent) { + console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...'); + } - var output = ''; - compiler.stdout.on('data', function(data) { - output += data; - }); + var error = ''; + compiler.stderr.on('data', function(data) { + error += data; + }); - compiler.on('exit', function(status) { - // `status` contains the process exit code - if (status) { - var exception = new Error(error); - exception.status = status; - } - // restore IIFE and move exposed vars inside the IIFE - if (hasIIFE && isAdvanced) { - output = output - .replace(/__iife__\(/, '(') - .replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1') - .replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1'); - } - // inject "use strict" directive - if (isStrict) { - output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";'); - } - // restore copyright header - if (license) { - output = license + output; - } - if (isMapped) { - var mapOutput = fs.readFileSync(mapPath, 'utf8'); - fs.unlinkSync(mapPath); - output = output.replace(/[\s;]*$/, '\n/*\n//@ sourceMappingURL=' + sourceMapURL) + '\n*/'; - - mapOutput = JSON.parse(mapOutput); - mapOutput.file = path.basename(outputPath); - mapOutput.sources = [path.basename(filePath)]; - mapOutput = JSON.stringify(mapOutput, null, 2); - } - callback(exception, output, mapOutput); - }); + var output = ''; + compiler.stdout.on('data', function(data) { + output += data; + }); - // proxy the standard input to the Closure Compiler - compiler.stdin.end(source); + compiler.on('exit', function(status) { + // `status` contains the process exit code + if (status) { + var exception = new Error(error); + exception.status = status; + } + // restore IIFE and move exposed vars inside the IIFE + if (hasIIFE && isAdvanced) { + output = output + .replace(/__iife__\(/, '(') + .replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1') + .replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1'); + } + // inject "use strict" directive + if (isStrict) { + output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";'); + } + // restore copyright header + if (license) { + output = license + output; + } + if (isMapped) { + var mapOutput = fs.readFileSync(mapPath, 'utf8'); + fs.unlinkSync(mapPath); + output = output.replace(/[\s;]*$/, '\n/*\n//@ sourceMappingURL=' + sourceMapURL) + '\n*/'; + + mapOutput = JSON.parse(mapOutput); + mapOutput.file = path.basename(outputPath); + mapOutput.sources = [path.basename(filePath)]; + mapOutput = JSON.stringify(mapOutput, null, 2); + } + callback(exception, output, mapOutput); + }); + + // proxy the standard input to the Closure Compiler + compiler.stdin.end(source); + }); } /** @@ -470,7 +501,7 @@ // 4. output // restrict lines to 500 characters for consistency with the Closure Compiler var stream = uglifyJS.OutputStream({ - 'ascii_only': true, + 'ascii_only': !this.isTemplate, 'comments': /@cc_on|@license|@preserve/i, 'max_line_len': 500, }); diff --git a/build/post-compile.js b/build/post-compile.js index 2d1da80be6..0ff394d244 100644 --- a/build/post-compile.js +++ b/build/post-compile.js @@ -2,8 +2,9 @@ ;(function() { 'use strict'; - /** The Node.js filesystem module */ - var fs = require('fs'); + /** Load Node.js modules */ + var fs = require('fs'), + vm = require('vm'); /** The minimal license/copyright template */ var licenseTemplate = [ @@ -24,19 +25,44 @@ * @returns {String} Returns the processed source. */ function postprocess(source) { - // remove copyright header - source = source.replace(/^\/\**[\s\S]+?\*\/\n/, ''); - // correct overly aggressive Closure Compiler advanced optimization source = source .replace(/(document[^&]+&&)\s*(?:\w+|!\d)/, '$1!({toString:0}+"")') .replace(/"\t"/g, '"\\t"') - .replace(/"[^"]*?\\u180e[^"]*?"/g, + .replace(/"[^"]*?\\f[^"]*?"/g, '" \\t\\x0B\\f\\xa0\\ufeff' + '\\n\\r\\u2028\\u2029' + '\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000"' ); + try { + var context = vm.createContext({}); + vm.runInContext(source, context); + } catch(e) { } + + ['forEach', 'forIn', 'forOwn'].forEach(function(methodName) { + var pairs = /[!=]==\s*([a-zA-Z]+)(?!\()|([a-zA-Z]+)\s*[!=]==/.exec((context._ || {})[methodName]), + varName = pairs && (pairs[1] || pairs[2]), + value = (value = varName && RegExp('\\b' + varName + '\\s*=\\s*!([01])\\b').exec(source)) && !+value[1]; + + if (typeof value == 'boolean') { + // replace vars for `false` and `true` with boolean literals + source = source.replace(RegExp('([!=]==\\s*)' + varName + '\\b(?!\\()|\\b' + varName + '(\\s*[!=]==)', 'g'), function(match, prelude, postlude, at) { + // avoid replacing local variables with the same name + return RegExp('\\b' + varName + '\\s*(?:,|=[^=])').test(source.slice(at - 10, at)) + ? match + : (prelude || '') + value + (postlude || ''); + }); + } + }); + + // replace `!1` and `!0` in expressions with `false` and `true` values + [/([!=]==)\s*!1\b|(.)!1\s*([!=]==)/g, /([!=]==)\s*!0\b|(.)!0\s*([!=]==)/g].forEach(function(regexp, index) { + source = source.replace(regexp, function(match, prelude, chr, postlude) { + return (prelude || chr + (/\w/.test(chr) ? ' ' : '')) + !!index + (postlude || ''); + }); + }); + // flip `typeof` expressions to help optimize Safari and // correct the AMD module definition for AMD build optimizers // (e.g. from `"number" == typeof x` to `typeof x == "number") @@ -44,6 +70,11 @@ return (other ? other + ' ' : '') + expression + equality + type; }); + // add a space so `define` is detected by the Dojo builder + source = source.replace(/(.)(define\()/, function(match, prelude, define) { + return prelude + (/^\S/.test(prelude) ? ' ' : '') + define; + }); + // add trailing semicolon if (source) { source = source.replace(/[\s;]*?(\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*$/, ';$1'); @@ -53,6 +84,9 @@ if (!snippet) { return source; } + // remove copyright header + source = source.replace(/^\/\**[\s\S]+?\*\/\n/, ''); + // add new copyright header var version = snippet[2]; source = licenseTemplate.replace('<%= VERSION %>', version) + '\n;' + source; diff --git a/build/pre-compile.js b/build/pre-compile.js index 4b4d8e3bc5..f7c1ef4ed1 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -11,32 +11,44 @@ 'argsIndex', 'argsLength', 'callback', + 'className', 'collection', + 'conditions', 'ctor', + 'errorClass', + 'errorProto', 'guard', 'hasOwnProperty', 'index', 'isArguments', 'isArray', + 'isProto', 'isString', 'iterable', 'length', 'keys', 'lodash', + 'nonEnum', + 'nonEnumProps', 'object', + 'objectProto', 'objectTypes', 'ownIndex', 'ownProps', 'result', + 'skipErrorProps', 'skipProto', 'source', - 'thisArg' + 'stringClass', + 'stringProto', + 'thisArg', + 'toString' ]; /** Used to minify `iteratorTemplate` data properties */ var iteratorOptions = [ 'args', - 'arrays', + 'array', 'bottom', 'firstArg', 'init', @@ -58,6 +70,7 @@ 'Array', 'Boolean', 'Date', + 'Error', 'Function', 'Math', 'Number', @@ -74,12 +87,14 @@ 'any', 'argsClass', 'argsObject', + 'array', 'assign', 'at', 'attachEvent', 'bind', 'bindAll', 'bindKey', + 'cache', 'clearTimeout', 'clone', 'cloneDeep', @@ -98,6 +113,7 @@ 'difference', 'drop', 'each', + 'enumErrorProps', 'enumPrototypes', 'environment', 'escape', @@ -118,6 +134,7 @@ 'forEach', 'forIn', 'forOwn', + 'function', 'functions', 'global', 'groupBy', @@ -159,6 +176,7 @@ 'leading', 'map', 'max', + 'maxWait', 'memoize', 'merge', 'methods', @@ -168,6 +186,8 @@ 'nodeClass', 'nonEnumArgs', 'nonEnumShadows', + 'null', + 'number', 'object', 'omit', 'once', @@ -196,6 +216,7 @@ 'sortedIndex', 'source', 'spliceObjects', + 'string', 'support', 'tail', 'take', @@ -206,6 +227,8 @@ 'times', 'toArray', 'trailing', + 'transform', + 'undefined', 'unescape', 'unindexedChars', 'union', @@ -276,7 +299,7 @@ string = string.slice(left.length); } // avoids removing the '\n' of the `stringEscapes` object - string = string.replace(/\[object |delete |else (?!{)|function | in |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) { + string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) { return match == false || match == '\\n' ? '' : match; }); // unclip @@ -296,11 +319,27 @@ // remove debug sourceURL use in `_.template` source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, ''); - // minify internal properties used by 'compareAscending' and `_.sortBy` + // minify internal properties (function() { - var properties = ['criteria', 'index', 'value'], - snippets = source.match(/( +)function (?:compareAscending|sortBy)\b[\s\S]+?\n\1}/g); - + var methods = [ + 'cacheIndexOf', + 'cachePush', + 'compareAscending', + 'createCache', + 'getObject', + 'releaseObject', + 'sortBy', + 'uniq' + ]; + + var props = [ + 'cache', + 'criteria', + 'index', + 'value' + ]; + + var snippets = source.match(RegExp('^( *)(?:var|function) +(?:' + methods.join('|') + ')\\b[\\s\\S]+?\\n\\1}', 'gm')); if (!snippets) { return; } @@ -308,11 +347,12 @@ var modified = snippet; // minify properties - properties.forEach(function(property, index) { - var minName = minNames[index], - reBracketProp = RegExp("\\['(" + property + ")'\\]", 'g'), - reDotProp = RegExp('\\.' + property + '\\b', 'g'), - rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + property + "\\2 *:", 'g'); + props.forEach(function(prop, index) { + // use minified names different than those chosen for `iteratorOptions` + var minName = minNames[iteratorOptions.length + index], + reBracketProp = RegExp("\\['(" + prop + ")'\\]", 'g'), + reDotProp = RegExp('\\.' + prop + '\\b', 'g'), + rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + prop + "\\2 *:", 'g'); modified = modified .replace(reBracketProp, "['" + minName + "']") @@ -331,14 +371,14 @@ var snippets = source.match( RegExp([ // match the `iteratorTemplate` - '( +)var iteratorTemplate\\b[\\s\\S]+?\\n\\1}', + '^( *)var iteratorTemplate\\b[\\s\\S]+?\\n\\1}', // match methods created by `createIterator` calls 'createIterator\\((?:{|[a-zA-Z]+)[\\s\\S]*?\\);\\n', // match variables storing `createIterator` options - '( +)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\2}', - // match the the `createIterator` function - '( +)function createIterator\\b[\\s\\S]+?\\n\\3}' - ].join('|'), 'g') + '^( *)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\2}', + // match `cachePush`, `createCache`, `createIterator`, `getObject`, `releaseObject`, and `uniq` functions + '^( *)(?:var|function) +(?:cachePush|createCache|createIterator|getObject|releaseObject|uniq)\\b[\\s\\S]+?\\n\\3}' + ].join('|'), 'gm') ); // exit early if no compilable snippets @@ -347,7 +387,7 @@ } snippets.forEach(function(snippet, index) { - var isCreateIterator = /function createIterator\b/.test(snippet), + var isFunc = /\bfunction *[ \w]*\(/.test(snippet), isIteratorTemplate = /var iteratorTemplate\b/.test(snippet), modified = snippet; @@ -356,6 +396,11 @@ return "['" + prop.replace(/['\n\r\t]/g, '\\$&') + "']"; }); + // remove unnecessary semicolons in strings + modified = modified.replace(/;(?:}["']|(?:\\n|\s)*["']\s*\+\s*["'](?:\\n|\s)*})/g, function(match) { + return match.slice(1); + }); + // minify `createIterator` option property names iteratorOptions.forEach(function(property, index) { var minName = minNames[index]; @@ -371,16 +416,24 @@ var minName = minNames[index]; // minify variable names present in strings - if (isCreateIterator) { - modified = modified.replace(RegExp('(([\'"])[^\\n\\2]*?)\\b' + varName + '\\b(?=[^\\n\\2]*\\2[ ,+]+$)', 'gm'), '$1' + minName); + if (isFunc && !isIteratorTemplate) { + modified = modified.replace(RegExp('((["\'])[^\\n\\2]*?)\\b' + varName + '\\b(?=[^\\n\\2]*\\2[ ,+;]+$)', 'gm'), function(match, prelude) { + return prelude + minName; + }); } // ensure properties in compiled strings aren't minified else { - modified = modified.replace(RegExp('([^.])\\b' + varName + '\\b(?!\' *[\\]:])', 'g'), '$1' + minName); + modified = modified.replace(RegExp('([^.])\\b' + varName + '\\b(?!\' *[\\]:])', 'g'), function(match, prelude) { + return prelude + minName; + }); } - // correct `typeof` values + // correct `typeof` string values if (/^(?:boolean|function|object|number|string|undefined)$/.test(varName)) { - modified = modified.replace(RegExp("(typeof [^']+')" + minName + "'", 'g'), '$1' + varName + "'"); + modified = modified.replace(RegExp('(= *)(["\'])' + minName + '\\2|(["\'])' + minName + '\\3( *=)', 'g'), function(match, prelude, preQuote, postQuote, postlude) { + return prelude + ? prelude + preQuote + varName + preQuote + : postQuote + varName + postQuote + postlude; + }); } }); diff --git a/component.json b/component.json index 74238c99d4..459ecc9c08 100644 --- a/component.json +++ b/component.json @@ -1,12 +1,12 @@ { "name": "lodash", "repo": "bestiejs/lodash", - "version": "1.2.1", + "version": "1.3.0", "description": "A low-level utility library delivering consistency, customization, performance, and extra features.", "license": "MIT", "scripts": [ - "./index.js", - "./dist/lodash.compat.js" + "index.js", + "dist/lodash.compat.js" ], "keywords": [ "browser", diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index a9db586aec..909499e2a4 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -1,6 +1,6 @@ /** * @license - * Lo-Dash 1.2.1 (Custom Build) + * Lo-Dash 1.3.0 (Custom Build) * Build: `lodash -o ./dist/lodash.compat.js` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.4.4 @@ -12,17 +12,9 @@ /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports; - - /** Detect free variable `module` */ - var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; - - /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - window = freeGlobal; - } + /** Used to pool arrays and objects used internally */ + var arrayPool = [], + objectPool = []; /** Used to generate unique IDs */ var idCounter = 0; @@ -34,7 +26,10 @@ var keyPrefix = +new Date + ''; /** Used as the size when optimizations are enabled for large arrays */ - var largeArraySize = 200; + var largeArraySize = 75; + + /** Used as the max size of the `arrayPool` and `objectPool` */ + var maxPoolSize = 10; /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, @@ -56,6 +51,9 @@ /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; + /** Used to detect functions containing a `this` reference */ + var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis; + /** Used to detect and test whitespace */ var whitespace = ( // whitespace @@ -82,9 +80,9 @@ /** Used to assign default `context` object properties */ var contextProps = [ - 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp', - 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 'parseInt', - 'setImmediate', 'setTimeout' + 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object', + 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', + 'parseInt', 'setImmediate', 'setTimeout' ]; /** Used to fix the JScript [[DontEnum]] bug */ @@ -101,6 +99,7 @@ arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', + errorClass = '[object Error]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', @@ -136,6 +135,305 @@ '\u2029': 'u2029' }; + /** Detect free variable `exports` */ + var freeExports = objectTypes[typeof exports] && exports; + + /** Detect free variable `module` */ + var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module; + + /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ + var freeGlobal = objectTypes[typeof global] && global; + if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { + window = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + /** + * A basic implementation of `_.indexOf` without support for binary searches + * or `fromIndex` constraints. + * + * @private + * @param {Array} array The array to search. + * @param {Mixed} value The value to search for. + * @param {Number} [fromIndex=0] The index to search from. + * @returns {Number} Returns the index of the matched value or `-1`. + */ + function basicIndexOf(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * An implementation of `_.contains` for cache objects that mimics the return + * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache object to inspect. + * @param {Mixed} value The value to search for. + * @returns {Number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var type = typeof value; + cache = cache.cache; + + if (type == 'boolean' || value == null) { + return cache[value]; + } + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value; + cache = cache[type] || (cache[type] = {}); + + return type == 'object' + ? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1) + : (cache[key] ? 0 : -1); + } + + /** + * Adds a given `value` to the corresponding cache object. + * + * @private + * @param {Mixed} value The value to add to the cache. + */ + function cachePush(value) { + var cache = this.cache, + type = typeof value; + + if (type == 'boolean' || value == null) { + cache[value] = true; + } else { + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value, + typeCache = cache[type] || (cache[type] = {}); + + if (type == 'object') { + if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) { + cache[type] = false; + } + } else { + typeCache[key] = true; + } + } + } + + /** + * Used by `_.max` and `_.min` as the default `callback` when a given + * `collection` is a string value. + * + * @private + * @param {String} value The character to inspect. + * @returns {Number} Returns the code unit of given character. + */ + function charAtCallback(value) { + return value.charCodeAt(0); + } + + /** + * Used by `sortBy` to compare transformed `collection` values, stable sorting + * them in ascending order. + * + * @private + * @param {Object} a The object to compare to `b`. + * @param {Object} b The object to compare to `a`. + * @returns {Number} Returns the sort order indicator of `1` or `-1`. + */ + function compareAscending(a, b) { + var ai = a.index, + bi = b.index; + + a = a.criteria; + b = b.criteria; + + // ensure a stable sort in V8 and other engines + // http://code.google.com/p/v8/issues/detail?id=90 + if (a !== b) { + if (a > b || typeof a == 'undefined') { + return 1; + } + if (a < b || typeof b == 'undefined') { + return -1; + } + } + return ai < bi ? -1 : 1; + } + + /** + * Creates a cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [array=[]] The array to search. + * @returns {Null|Object} Returns the cache object or `null` if caching should not be used. + */ + function createCache(array) { + var index = -1, + length = array.length; + + var cache = getObject(); + cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; + + var result = getObject(); + result.array = array; + result.cache = cache; + result.push = cachePush; + + while (++index < length) { + result.push(array[index]); + } + return cache.object === false + ? (releaseObject(result), null) + : result; + } + + /** + * Used by `template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {String} match The matched character to escape. + * @returns {String} Returns the escaped character. + */ + function escapeStringChar(match) { + return '\\' + stringEscapes[match]; + } + + /** + * Gets an array from the array pool or creates a new one if the pool is empty. + * + * @private + * @returns {Array} The array from the pool. + */ + function getArray() { + return arrayPool.pop() || []; + } + + /** + * Gets an object from the object pool or creates a new one if the pool is empty. + * + * @private + * @returns {Object} The object from the pool. + */ + function getObject() { + return objectPool.pop() || { + 'args': '', + 'array': null, + 'bottom': '', + 'criteria': null, + 'false': false, + 'firstArg': '', + 'index': 0, + 'init': '', + 'leading': false, + 'loop': '', + 'maxWait': 0, + 'null': false, + 'number': null, + 'object': null, + 'push': null, + 'shadowedProps': null, + 'string': null, + 'top': '', + 'trailing': false, + 'true': false, + 'undefined': false, + 'useHas': false, + 'useKeys': false, + 'value': null + }; + } + + /** + * Checks if `value` is a DOM node in IE < 9. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. + */ + function isNode(value) { + // IE < 9 presents DOM nodes as `Object` objects except they have `toString` + // methods that are `typeof` "string" and still can coerce nodes to strings + return typeof value.toString != 'function' && typeof (value + '') == 'string'; + } + + /** + * A no-operation function. + * + * @private + */ + function noop() { + // no operation performed + } + + /** + * Releases the given `array` back to the array pool. + * + * @private + * @param {Array} [array] The array to release. + */ + function releaseArray(array) { + if (arrayPool.length == maxPoolSize) { + arrayPool.length = maxPoolSize - 1; + } + array.length = 0; + arrayPool.push(array); + } + + /** + * Releases the given `object` back to the object pool. + * + * @private + * @param {Object} [object] The object to release. + */ + function releaseObject(object) { + var cache = object.cache; + if (cache) { + releaseObject(cache); + } + if (objectPool.length == maxPoolSize) { + objectPool.length = maxPoolSize - 1; + } + object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; + objectPool.push(object); + } + + /** + * Slices the `collection` from the `start` index up to, but not including, + * the `end` index. + * + * Note: This function is used, instead of `Array#slice`, to support node lists + * in IE < 9 and to ensure dense arrays are returned. + * + * @private + * @param {Array|Object|String} collection The collection to slice. + * @param {Number} start The start index. + * @param {Number} end The end index. + * @returns {Array} Returns the new array. + */ + function slice(array, start, end) { + start || (start = 0); + if (typeof end == 'undefined') { + end = array ? array.length : 0; + } + var index = -1, + length = end - start || 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = array[start + index]; + } + return result; + } + /*--------------------------------------------------------------------------*/ /** @@ -158,6 +456,7 @@ var Array = context.Array, Boolean = context.Boolean, Date = context.Date, + Error = context.Error, Function = context.Function, Math = context.Math, Number = context.Number, @@ -166,16 +465,25 @@ String = context.String, TypeError = context.TypeError; - /** Used for `Array` and `Object` method references */ - var arrayRef = Array(), - objectRef = Object(); + /** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ + var arrayRef = []; + + /** Used for native method references */ + var errorProto = Error.prototype, + objectProto = Object.prototype, + stringProto = String.prototype; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = context._; /** Used to detect if a method is native */ var reNative = RegExp('^' + - String(objectRef.valueOf) + String(objectProto.valueOf) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); @@ -185,15 +493,18 @@ clearTimeout = context.clearTimeout, concat = arrayRef.concat, floor = Math.floor, + fnToString = Function.prototype.toString, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, - hasOwnProperty = objectRef.hasOwnProperty, + hasOwnProperty = objectProto.hasOwnProperty, push = arrayRef.push, + propertyIsEnumerable = objectProto.propertyIsEnumerable, setImmediate = context.setImmediate, setTimeout = context.setTimeout, - toString = objectRef.toString; + toString = objectProto.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, + nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = context.isFinite, nativeIsNaN = context.isNaN, @@ -213,11 +524,31 @@ ctorByClass[arrayClass] = Array; ctorByClass[boolClass] = Boolean; ctorByClass[dateClass] = Date; + ctorByClass[funcClass] = Function; ctorByClass[objectClass] = Object; ctorByClass[numberClass] = Number; ctorByClass[regexpClass] = RegExp; ctorByClass[stringClass] = String; + /** Used to avoid iterating non-enumerable properties in IE < 9 */ + var nonEnumProps = {}; + nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true }; + nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true }; + nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true }; + nonEnumProps[objectClass] = { 'constructor': true }; + + (function() { + var length = shadowedProps.length; + while (length--) { + var prop = shadowedProps[length]; + for (var className in nonEnumProps) { + if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], prop)) { + nonEnumProps[className][prop] = false; + } + } + } + }()); + /*--------------------------------------------------------------------------*/ /** @@ -239,8 +570,8 @@ * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, * `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, - * `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `unshift`, `unzip`, - * `values`, `where`, `without`, `wrap`, and `zip` + * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, + * `unzip`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, @@ -256,6 +587,7 @@ * * @name _ * @constructor + * @alias chain * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. @@ -287,6 +619,19 @@ : new lodashWrapper(value); } + /** + * A fast path for creating `lodash` wrapper objects. + * + * @private + * @param {Mixed} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + */ + function lodashWrapper(value) { + this.__wrapped__ = value; + } + // ensure `new lodashWrapper` is an instance of `lodash` + lodashWrapper.prototype = lodash.prototype; + /** * An object used to flag environments features. * @@ -321,6 +666,15 @@ */ support.argsClass = isArguments(arguments); + /** + * Detect if `name` or `message` properties of `Error.prototype` are + * enumerable by default. (IE < 9, Safari < 5.1) + * + * @memberOf _.support + * @type Boolean + */ + support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name'); + /** * Detect if `prototype` properties are enumerable by default. * @@ -332,7 +686,7 @@ * @memberOf _.support * @type Boolean */ - support.enumPrototypes = ctor.propertyIsEnumerable('prototype'); + support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype'); /** * Detect if `Function#bind` exists and is inferred to be fast (all but V8). @@ -488,77 +842,80 @@ (obj.init) + ';\nif (!iterable) return result;\n' + (obj.top) + - ';\n'; - if (obj.arrays) { - __p += 'var length = iterable.length; index = -1;\nif (' + - (obj.arrays) + + ';'; + if (obj.array) { + __p += '\nvar length = iterable.length; index = -1;\nif (' + + (obj.array) + ') { '; if (support.unindexedChars) { __p += '\n if (isString(iterable)) {\n iterable = iterable.split(\'\')\n } '; } __p += '\n while (++index < length) {\n ' + (obj.loop) + - '\n }\n}\nelse { '; - } else if (support.nonEnumArgs) { + ';\n }\n}\nelse { '; + } else if (support.nonEnumArgs) { __p += '\n var length = iterable.length; index = -1;\n if (length && isArguments(iterable)) {\n while (++index < length) {\n index += \'\';\n ' + (obj.loop) + - '\n }\n } else { '; + ';\n }\n } else { '; } if (support.enumPrototypes) { __p += '\n var skipProto = typeof iterable == \'function\';\n '; } + if (support.enumErrorProps) { + __p += '\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n '; + } + + var conditions = []; if (support.enumPrototypes) { conditions.push('!(skipProto && index == "prototype")'); } if (support.enumErrorProps) { conditions.push('!(skipErrorProps && (index == "message" || index == "name"))'); } + if (obj.useHas && obj.useKeys) { - __p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] ? keys(iterable) : [],\n length = ownProps.length;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n '; - if (support.enumPrototypes) { - __p += 'if (!(skipProto && index == \'prototype\')) {\n '; + __p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n'; + if (conditions.length) { + __p += ' if (' + + (conditions.join(' && ')) + + ') {\n '; } __p += - (obj.loop); - if (support.enumPrototypes) { - __p += '}\n'; + (obj.loop) + + '; '; + if (conditions.length) { + __p += '\n }'; } - __p += ' } '; + __p += '\n } '; } else { - __p += '\n for (index in iterable) {'; - if (support.enumPrototypes || obj.useHas) { - __p += '\n if ('; - if (support.enumPrototypes) { - __p += '!(skipProto && index == \'prototype\')'; - } if (support.enumPrototypes && obj.useHas) { - __p += ' && '; - } if (obj.useHas) { - __p += 'hasOwnProperty.call(iterable, index)'; - } - __p += ') { '; + __p += '\n for (index in iterable) {\n'; + if (obj.useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); } if (conditions.length) { + __p += ' if (' + + (conditions.join(' && ')) + + ') {\n '; } __p += (obj.loop) + '; '; - if (support.enumPrototypes || obj.useHas) { + if (conditions.length) { __p += '\n }'; } __p += '\n } '; if (support.nonEnumShadows) { - __p += '\n\n var ctor = iterable.constructor;\n '; - for (var k = 0; k < 7; k++) { - __p += '\n index = \'' + + __p += '\n\n if (iterable !== objectProto) {\n var ctor = iterable.constructor,\n isProto = iterable === (ctor && ctor.prototype),\n className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n nonEnum = nonEnumProps[className];\n '; + for (k = 0; k < 7; k++) { + __p += '\n index = \'' + (obj.shadowedProps[k]) + - '\';\n if ('; - if (obj.shadowedProps[k] == 'constructor') { - __p += '!(ctor && ctor.prototype === iterable) && '; - } - __p += 'hasOwnProperty.call(iterable, index)) {\n ' + + '\';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))'; + if (!obj.useHas) { + __p += ' || (!nonEnum[index] && iterable[index] !== objectProto[index])'; + } + __p += ') {\n ' + (obj.loop) + - '\n } '; + ';\n } '; } - + __p += '\n } '; } } - if (obj.arrays || support.nonEnumArgs) { + if (obj.array || support.nonEnumArgs) { __p += '\n}'; } __p += @@ -586,90 +943,18 @@ var eachIteratorOptions = { 'args': 'collection, callback, thisArg', 'top': "callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg)", - 'arrays': "typeof length == 'number'", + 'array': "typeof length == 'number'", 'loop': 'if (callback(iterable[index], index, collection) === false) return result' }; /** Reusable iterator options for `forIn` and `forOwn` */ var forOwnIteratorOptions = { 'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top, - 'arrays': false + 'array': false }; /*--------------------------------------------------------------------------*/ - /** - * Creates a function optimized to search large arrays for a given `value`, - * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. - * - * @private - * @param {Array} array The array to search. - * @param {Mixed} value The value to search for. - * @returns {Boolean} Returns `true`, if `value` is found, else `false`. - */ - function cachedContains(array) { - var length = array.length, - isLarge = length >= largeArraySize; - - if (isLarge) { - var cache = {}, - index = -1; - - while (++index < length) { - var key = keyPrefix + array[index]; - (cache[key] || (cache[key] = [])).push(array[index]); - } - } - return function(value) { - if (isLarge) { - var key = keyPrefix + value; - return cache[key] && indexOf(cache[key], value) > -1; - } - return indexOf(array, value) > -1; - } - } - - /** - * Used by `_.max` and `_.min` as the default `callback` when a given - * `collection` is a string value. - * - * @private - * @param {String} value The character to inspect. - * @returns {Number} Returns the code unit of given character. - */ - function charAtCallback(value) { - return value.charCodeAt(0); - } - - /** - * Used by `sortBy` to compare transformed `collection` values, stable sorting - * them in ascending order. - * - * @private - * @param {Object} a The object to compare to `b`. - * @param {Object} b The object to compare to `a`. - * @returns {Number} Returns the sort order indicator of `1` or `-1`. - */ - function compareAscending(a, b) { - var ai = a.index, - bi = b.index; - - a = a.criteria; - b = b.criteria; - - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (a !== b) { - if (a > b || typeof a == 'undefined') { - return 1; - } - if (a < b || typeof b == 'undefined') { - return -1; - } - } - return ai < bi ? -1 : 1; - } - /** * Creates a function that, when called, invokes `func` with the `this` binding * of `thisArg` and prepends any `partialArgs` to the arguments passed to the @@ -716,9 +1001,7 @@ } if (this instanceof bound) { // ensure `new bound` is an instance of `func` - noop.prototype = func.prototype; - thisBinding = new noop; - noop.prototype = null; + thisBinding = createObject(func.prototype); // mimic the constructor's `return` behavior // http://es5.github.com/#x13.2.2 @@ -735,7 +1018,7 @@ * * @private * @param {Object} [options1, options2, ...] The compile options object(s). - * arrays - A string of code to determine if the iterable is an array or array-like. + * array - A string of code to determine if the iterable is an array or array-like. * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. * useKeys - A boolean to specify using `_.keys` for own property iteration. * args - A string of comma separated arguments the iteration function will accept. @@ -745,18 +1028,15 @@ * @returns {Function} Returns the compiled function. */ function createIterator() { - var data = { - // data properties - 'shadowedProps': shadowedProps, - // iterator options - 'arrays': 'isArray(iterable)', - 'bottom': '', - 'init': 'iterable', - 'loop': '', - 'top': '', - 'useHas': true, - 'useKeys': !!keys - }; + var data = getObject(); + + // data properties + data.shadowedProps = shadowedProps; + // iterator options + data.array = data.bottom = data.loop = data.top = ''; + data.init = 'iterable'; + data.useHas = true; + data.useKeys = !!keys; // merge options into a template data object for (var object, index = 0; object = arguments[index]; index++) { @@ -769,27 +1049,42 @@ // create the function factory var factory = Function( - 'hasOwnProperty, isArguments, isArray, isString, keys, ' + - 'lodash, objectTypes', + 'errorClass, errorProto, hasOwnProperty, isArguments, isArray, ' + + 'isString, keys, lodash, objectProto, objectTypes, nonEnumProps, ' + + 'stringClass, stringProto, toString', 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' ); + + releaseObject(data); + // return the compiled function return factory( - hasOwnProperty, isArguments, isArray, isString, keys, - lodash, objectTypes + errorClass, errorProto, hasOwnProperty, isArguments, isArray, + isString, keys, lodash, objectProto, objectTypes, nonEnumProps, + stringClass, stringProto, toString ); } /** - * Used by `template` to escape characters for inclusion in compiled - * string literals. + * Creates a new object with the specified `prototype`. * * @private - * @param {String} match The matched character to escape. - * @returns {String} Returns the escaped character. + * @param {Object} prototype The prototype object. + * @returns {Object} Returns the new object. */ - function escapeStringChar(match) { - return '\\' + stringEscapes[match]; + function createObject(prototype) { + return isObject(prototype) ? nativeCreate(prototype) : {}; + } + // fallback for browsers without `Object.create` + if (!nativeCreate) { + var createObject = function(prototype) { + if (isObject(prototype)) { + noop.prototype = prototype; + var result = new noop; + noop.prototype = null; + } + return result || {}; + }; } /** @@ -804,38 +1099,39 @@ } /** - * Checks if `value` is a DOM node in IE < 9. + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized, this method returns the custom method, otherwise it returns + * the `basicIndexOf` function. * * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. + * @returns {Function} Returns the "indexOf" function. */ - function isNode(value) { - // IE < 9 presents DOM nodes as `Object` objects except they have `toString` - // methods that are `typeof` "string" and still can coerce nodes to strings - return typeof value.toString != 'function' && typeof (value + '') == 'string'; - } - - /** - * A fast path for creating `lodash` wrapper objects. - * - * @private - * @param {Mixed} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns a `lodash` instance. - */ - function lodashWrapper(value) { - this.__wrapped__ = value; + function getIndexOf(array, value, fromIndex) { + var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result; + return result; } - // ensure `new lodashWrapper` is an instance of `lodash` - lodashWrapper.prototype = lodash.prototype; /** - * A no-operation function. + * Creates a function that juggles arguments, allowing argument overloading + * for `_.flatten` and `_.uniq`, before passing them to the given `func`. * * @private + * @param {Function} func The function to wrap. + * @returns {Function} Returns the new function. */ - function noop() { - // no operation performed + function overloadWrapper(func) { + return function(array, flag, callback, thisArg) { + // juggle arguments + if (typeof flag != 'boolean' && flag != null) { + thisArg = callback; + callback = !(thisArg && thisArg[flag] === array) ? flag : undefined; + flag = false; + } + if (callback != null) { + callback = lodash.createCallback(callback, thisArg); + } + return func(array, flag, callback, thisArg); + }; } /** @@ -849,62 +1145,33 @@ * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { - // avoid non-objects and false positives for `arguments` objects - var result = false; - if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { - return result; - } - // check that the constructor is `Object` (i.e. `Object instanceof Object`) - var ctor = value.constructor; - - if (isFunction(ctor) ? ctor instanceof ctor : (support.nodeClass || !isNode(value))) { - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - if (support.ownLast) { - forIn(value, function(value, key, object) { - result = hasOwnProperty.call(object, key); - return false; - }); - return result === true; - } - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - forIn(value, function(value, key) { - result = key; - }); - return result === false || hasOwnProperty.call(value, result); - } - return result; - } + var ctor, + result; - /** - * Slices the `collection` from the `start` index up to, but not including, - * the `end` index. - * - * Note: This function is used, instead of `Array#slice`, to support node lists - * in IE < 9 and to ensure dense arrays are returned. - * - * @private - * @param {Array|Object|String} collection The collection to slice. - * @param {Number} start The start index. - * @param {Number} end The end index. - * @returns {Array} Returns the new array. - */ - function slice(array, start, end) { - start || (start = 0); - if (typeof end == 'undefined') { - end = array ? array.length : 0; + // avoid non Object objects, `arguments` objects, and DOM elements + if (!(value && toString.call(value) == objectClass) || + (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) || + (!support.argsClass && isArguments(value)) || + (!support.nodeClass && isNode(value))) { + return false; } - var index = -1, - length = end - start || 0, - result = Array(length < 0 ? 0 : length); - - while (++index < length) { - result[index] = array[start + index]; + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + if (support.ownLast) { + forIn(value, function(value, key, object) { + result = hasOwnProperty.call(object, key); + return false; + }); + return result !== false; } - return result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + forIn(value, function(value, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); } /** @@ -979,8 +1246,7 @@ 'args': 'object', 'init': '[]', 'top': 'if (!(objectTypes[typeof object])) return result', - 'loop': 'result.push(index)', - 'arrays': false + 'loop': 'result.push(index)' }); /** @@ -1021,7 +1287,7 @@ * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. */ - var each = createIterator(eachIteratorOptions); + var basicEach = createIterator(eachIteratorOptions); /** * Used to convert characters to HTML entities: @@ -1134,7 +1400,7 @@ // allows working with "Collections" methods without using their `callback` // argument, `index|key`, for this method's `callback` - if (typeof deep == 'function') { + if (typeof deep != 'boolean' && deep != null) { thisArg = callback; callback = deep; deep = false; @@ -1179,8 +1445,9 @@ return ctor(result.source, reFlags.exec(result)); } // check for circular references and return corresponding clone - stackA || (stackA = []); - stackB || (stackB = []); + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); var length = stackA.length; while (length--) { @@ -1206,10 +1473,14 @@ stackB.push(result); // recursively populate clone (susceptible to call stack limits) - (isArr ? forEach : forOwn)(value, function(objValue, key) { + (isArr ? basicEach : forOwn)(value, function(objValue, key) { result[key] = clone(objValue, deep, callback, undefined, stackA, stackB); }); + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return result; } @@ -1219,7 +1490,7 @@ * `undefined`, cloning will be handled by the method instead. The `callback` * is bound to `thisArg` and invoked with one argument; (value). * - * Note: This function is loosely based on the structured clone algorithm. Functions + * Note: This method is loosely based on the structured clone algorithm. Functions * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and * objects created by constructors other than `Object` are cloned to plain `Object` objects. * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. @@ -1656,8 +1927,9 @@ // assume cyclic structures are equal // the algorithm for detecting cyclic structures is adapted from ES 5.1 // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) - stackA || (stackA = []); - stackB || (stackB = []); + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); var length = stackA.length; while (length--) { @@ -1719,6 +1991,10 @@ } }); } + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return result; } @@ -1802,7 +2078,7 @@ // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 - return value ? objectTypes[typeof value] : false; + return !!(value && objectTypes[typeof value]); } /** @@ -1923,7 +2199,7 @@ * // => true */ function isRegExp(value) { - return value ? (objectTypes[typeof value] && toString.call(value) == regexpClass) : false; + return !!(value && objectTypes[typeof value]) && toString.call(value) == regexpClass; } /** @@ -2028,8 +2304,9 @@ stackA = args[4], stackB = args[5]; } else { - stackA = []; - stackB = []; + var initedStack = true; + stackA = getArray(); + stackB = getArray(); // allows working with `_.reduce` and `_.reduceRight` without // using their `callback` arguments, `index|key` and `collection` @@ -2095,6 +2372,11 @@ object[key] = value; }); } + + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return object; } @@ -2125,7 +2407,8 @@ * // => { 'name': 'moe' } */ function omit(object, callback, thisArg) { - var isFunc = typeof callback == 'function', + var indexOf = getIndexOf(), + isFunc = typeof callback == 'function', result = {}; if (isFunc) { @@ -2220,6 +2503,57 @@ return result; } + /** + * An alternative to `_.reduce`, this method transforms an `object` to a new + * `accumulator` object which is the result of running each of its elements + * through the `callback`, with each `callback` execution potentially mutating + * the `accumulator` object. The `callback` is bound to `thisArg` and invoked + * with four arguments; (accumulator, value, key, object). Callbacks may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {Mixed} [accumulator] The custom accumulator value. + * @param {Mixed} [thisArg] The `this` binding of `callback`. + * @returns {Mixed} Returns the accumulated value. + * @example + * + * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { + * num *= num; + * if (num % 2) { + * return result.push(num) < 3; + * } + * }); + * // => [1, 9, 25] + * + * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { + * result[key] = num * 3; + * }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ + function transform(object, callback, accumulator, thisArg) { + var isArr = isArray(object); + callback = lodash.createCallback(callback, thisArg, 4); + + if (accumulator == null) { + if (isArr) { + accumulator = []; + } else { + var ctor = object && object.constructor, + proto = ctor && ctor.prototype; + + accumulator = createObject(proto); + } + } + (isArr ? basicEach : forOwn)(object, function(value, index, object) { + return callback(accumulator, value, index, object); + }); + return accumulator; + } + /** * Creates an array composed of the own enumerable property values of `object`. * @@ -2312,17 +2646,18 @@ */ function contains(collection, target, fromIndex) { var index = -1, + indexOf = getIndexOf(), length = collection ? collection.length : 0, result = false; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; - if (typeof length == 'number') { + if (length && typeof length == 'number') { result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex) ) > -1; } else { - each(collection, function(value) { + basicEach(collection, function(value) { if (++index >= fromIndex) { return !(result = value === target); } @@ -2430,7 +2765,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { return (result = !!callback(value, index, collection)); }); } @@ -2492,7 +2827,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result.push(value); } @@ -2515,7 +2850,7 @@ * * @static * @memberOf _ - * @alias detect + * @alias detect, findWhere * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per @@ -2559,7 +2894,7 @@ } } else { var result; - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result = value; return false; @@ -2602,7 +2937,7 @@ } } } else { - each(collection, callback, thisArg); + basicEach(collection, callback, thisArg); } return collection; } @@ -2737,7 +3072,7 @@ result[index] = callback(collection[index], index, collection); } } else { - each(collection, function(value, key, collection) { + basicEach(collection, function(value, key, collection) { result[++index] = callback(value, key, collection); }); } @@ -2802,7 +3137,7 @@ ? charAtCallback : lodash.createCallback(callback, thisArg); - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current > computed) { computed = current; @@ -2871,7 +3206,7 @@ ? charAtCallback : lodash.createCallback(callback, thisArg); - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current < computed) { computed = current; @@ -2949,7 +3284,7 @@ accumulator = callback(accumulator, collection[index], index, collection); } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, collection) @@ -3152,7 +3487,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { return !(result = callback(value, index, collection)); }); } @@ -3201,17 +3536,18 @@ callback = lodash.createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { - result[++index] = { - 'criteria': callback(value, key, collection), - 'index': index, - 'value': value - }; + var object = result[++index] = getObject(); + object.criteria = callback(value, key, collection); + object.index = index; + object.value = value; }); length = result.length; result.sort(compareAscending); while (length--) { - result[length] = result[length].value; + var object = result[length]; + result[length] = object.value; + releaseObject(object); } return result; } @@ -3311,17 +3647,31 @@ */ function difference(array) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), - contains = cachedContains(flattened), + seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), result = []; + var isLarge = length >= largeArraySize && indexOf === basicIndexOf; + + if (isLarge) { + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + } + } while (++index < length) { var value = array[index]; - if (!contains(value)) { + if (indexOf(seen, value) < 0) { result.push(value); } } + if (isLarge) { + releaseObject(seen); + } return result; } @@ -3477,20 +3827,11 @@ * _.flatten(stooges, 'quotes'); * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] */ - function flatten(array, isShallow, callback, thisArg) { + var flatten = overloadWrapper(function flatten(array, isShallow, callback) { var index = -1, length = array ? array.length : 0, result = []; - // juggle arguments - if (typeof isShallow != 'boolean' && isShallow != null) { - thisArg = callback; - callback = isShallow; - isShallow = false; - } - if (callback != null) { - callback = lodash.createCallback(callback, thisArg); - } while (++index < length) { var value = array[index]; if (callback) { @@ -3504,7 +3845,7 @@ } } return result; - } + }); /** * Gets the index at which the first occurrence of `value` is found using @@ -3531,21 +3872,14 @@ * // => 2 */ function indexOf(array, value, fromIndex) { - var index = -1, - length = array ? array.length : 0; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; + var length = array ? array.length : 0; + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); } else if (fromIndex) { - index = sortedIndex(array, value); + var index = sortedIndex(array, value); return array[index] === value ? index : -1; } - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; + return array ? basicIndexOf(array, value, fromIndex) : -1; } /** @@ -3641,35 +3975,45 @@ function intersection(array) { var args = arguments, argsLength = args.length, - cache = { '0': {} }, + argsIndex = -1, + caches = getArray(), index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - isLarge = length >= largeArraySize, result = [], - seen = result; + seen = getArray(); + while (++argsIndex < argsLength) { + var value = args[argsIndex]; + caches[argsIndex] = indexOf === basicIndexOf && + (value ? value.length : 0) >= largeArraySize && + createCache(argsIndex ? args[argsIndex] : seen); + } outer: while (++index < length) { - var value = array[index]; - if (isLarge) { - var key = keyPrefix + value; - var inited = cache[0][key] - ? !(seen = cache[0][key]) - : (seen = cache[0][key] = []); - } - if (inited || indexOf(seen, value) < 0) { - if (isLarge) { - seen.push(value); - } - var argsIndex = argsLength; + var cache = caches[0]; + value = array[index]; + + if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { + argsIndex = argsLength; + (cache || seen).push(value); while (--argsIndex) { - if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex])))(value)) { + cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { continue outer; } } result.push(value); } } + while (argsLength--) { + cache = caches[argsLength]; + if (cache) { + releaseObject(cache); + } + } + releaseArray(caches); + releaseArray(seen); return result; } @@ -3998,7 +4342,7 @@ * Creates a duplicate-value-free version of the `array` using strict equality * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` * for `isSorted` will run a faster algorithm. If `callback` is passed, each - * element of `array` is passed through a `callback` before uniqueness is computed. + * element of `array` is passed through the `callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style @@ -4027,50 +4371,42 @@ * _.uniq([1, 1, 2, 2, 3], true); * // => [1, 2, 3] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); - * // => [1, 2, 3] + * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); + * // => ['A', 'b', 'C'] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); - * // => [1, 2, 3] + * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); + * // => [1, 2.5, 3] * * // using "_.pluck" callback shorthand * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniq(array, isSorted, callback, thisArg) { + var uniq = overloadWrapper(function(array, isSorted, callback) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - result = [], - seen = result; + result = []; + + var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf, + seen = (callback || isLarge) ? getArray() : result; - // juggle arguments - if (typeof isSorted != 'boolean' && isSorted != null) { - thisArg = callback; - callback = isSorted; - isSorted = false; - } - // init value cache for large arrays - var isLarge = !isSorted && length >= largeArraySize; if (isLarge) { - var cache = {}; - } - if (callback != null) { - seen = []; - callback = lodash.createCallback(callback, thisArg); + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + seen = callback ? seen : (releaseArray(seen), result); + } } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; - if (isLarge) { - var key = keyPrefix + computed; - var inited = cache[key] - ? !(seen = cache[key]) - : (seen = cache[key] = []); - } if (isSorted ? !index || seen[seen.length - 1] !== computed - : inited || indexOf(seen, computed) < 0 + : indexOf(seen, computed) < 0 ) { if (callback || isLarge) { seen.push(computed); @@ -4078,8 +4414,14 @@ result.push(value); } } + if (isLarge) { + releaseArray(seen.array); + releaseObject(seen); + } else if (callback) { + releaseArray(seen); + } return result; - } + }); /** * The inverse of `_.zip`, this method splits groups of elements into arrays @@ -4097,17 +4439,11 @@ */ function unzip(array) { var index = -1, - length = array ? array.length : 0, - tupleLength = length ? max(pluck(array, 'length')) : 0, - result = Array(tupleLength); + length = array ? max(pluck(array, 'length')) : 0, + result = Array(length < 0 ? 0 : length); while (++index < length) { - var tupleIndex = -1, - tuple = array[index]; - - while (++tupleIndex < tupleLength) { - (result[tupleIndex] || (result[tupleIndex] = Array(length)))[index] = tuple[tupleIndex]; - } + result[index] = pluck(array, index); } return result; } @@ -4148,14 +4484,7 @@ * // => [['moe', 30, true], ['larry', 40, false]] */ function zip(array) { - var index = -1, - length = array ? max(pluck(arguments, 'length')) : 0, - result = Array(length); - - while (++index < length) { - result[index] = pluck(arguments, index); - } - return result; + return array ? unzip(arguments) : []; } /** @@ -4431,27 +4760,27 @@ return result; }; } - if (typeof thisArg != 'undefined') { - if (argCount === 1) { - return function(value) { - return func.call(thisArg, value); - }; - } - if (argCount === 2) { - return function(a, b) { - return func.call(thisArg, a, b); - }; - } - if (argCount === 4) { - return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return function(value, index, collection) { - return func.call(thisArg, value, index, collection); + if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) { + return func; + } + if (argCount === 1) { + return function(value) { + return func.call(thisArg, value); + }; + } + if (argCount === 2) { + return function(a, b) { + return func.call(thisArg, a, b); }; } - return func; + if (argCount === 4) { + return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; } /** @@ -4472,6 +4801,7 @@ * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. * [leading=false] A boolean to specify execution on the leading edge of the timeout. + * [maxWait] The maximum time `func` is allowed to be delayed before it's called. * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example @@ -4486,34 +4816,80 @@ */ function debounce(func, wait, options) { var args, - inited, result, thisArg, - timeoutId, + callCount = 0, + lastCalled = 0, + maxWait = false, + maxTimeoutId = null, + timeoutId = null, trailing = true; + function clear() { + clearTimeout(maxTimeoutId); + clearTimeout(timeoutId); + callCount = 0; + maxTimeoutId = timeoutId = null; + } + function delayed() { - inited = timeoutId = null; - if (trailing) { + var isCalled = trailing && (!leading || callCount > 1); + clear(); + if (isCalled) { + if (maxWait !== false) { + lastCalled = new Date; + } + result = func.apply(thisArg, args); + } + } + + function maxDelayed() { + clear(); + if (trailing || (maxWait !== wait)) { + lastCalled = new Date; result = func.apply(thisArg, args); } } + + wait = nativeMax(0, wait || 0); if (options === true) { var leading = true; trailing = false; - } else if (options && objectTypes[typeof options]) { + } else if (isObject(options)) { leading = options.leading; + maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0); trailing = 'trailing' in options ? options.trailing : trailing; } return function() { args = arguments; thisArg = this; + callCount++; + + // avoid issues with Titanium and `undefined` timeout ids + // https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192 clearTimeout(timeoutId); - if (!inited && leading) { - inited = true; - result = func.apply(thisArg, args); + if (maxWait === false) { + if (leading && callCount < 2) { + result = func.apply(thisArg, args); + } } else { + var now = new Date; + if (!maxTimeoutId && !leading) { + lastCalled = now; + } + var remaining = maxWait - (now - lastCalled); + if (remaining <= 0) { + clearTimeout(maxTimeoutId); + maxTimeoutId = null; + lastCalled = now; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (wait !== maxWait) { timeoutId = setTimeout(delayed, wait); } return result; @@ -4571,7 +4947,8 @@ * passed, it will be used to determine the cache key for storing the result * based on the arguments passed to the memoized function. By default, the first * argument passed to the memoized function is used as the cache key. The `func` - * is executed with the `this` binding of the memoized function. + * is executed with the `this` binding of the memoized function. The result + * cache is exposed as the `cache` property on the memoized function. * * @static * @memberOf _ @@ -4586,13 +4963,16 @@ * }); */ function memoize(func, resolver) { - var cache = {}; - return function() { - var key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); + function memoized() { + var cache = memoized.cache, + key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); + return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); - }; + } + memoized.cache = {}; + return memoized; } /** @@ -4712,47 +5092,23 @@ * })); */ function throttle(func, wait, options) { - var args, - result, - thisArg, - timeoutId, - lastCalled = 0, - leading = true, + var leading = true, trailing = true; - function trailingCall() { - timeoutId = null; - if (trailing) { - lastCalled = new Date; - result = func.apply(thisArg, args); - } - } if (options === false) { leading = false; - } else if (options && objectTypes[typeof options]) { + } else if (isObject(options)) { leading = 'leading' in options ? options.leading : leading; trailing = 'trailing' in options ? options.trailing : trailing; } - return function() { - var now = new Date; - if (!timeoutId && !leading) { - lastCalled = now; - } - var remaining = wait - (now - lastCalled); - args = arguments; - thisArg = this; + options = getObject(); + options.leading = leading; + options.maxWait = wait; + options.trailing = trailing; - if (remaining <= 0) { - clearTimeout(timeoutId); - timeoutId = null; - lastCalled = now; - result = func.apply(thisArg, args); - } - else if (!timeoutId) { - timeoutId = setTimeout(trailingCall, remaining); - } - return result; - }; + var result = debounce(func, wait, options); + releaseObject(options); + return result; } /** @@ -4805,7 +5161,7 @@ } /** - * This function returns the first argument passed to it. + * This method returns the first argument passed to it. * * @static * @memberOf _ @@ -4854,7 +5210,7 @@ push.apply(args, arguments); var result = func.apply(lodash, args); - return (value && typeof value == 'object' && value == result) + return (value && typeof value == 'object' && value === result) ? this : new lodashWrapper(result); }; @@ -4928,8 +5284,13 @@ if (max == null) { max = min; min = 0; + } else { + max = +max || 0; } - return min + floor(nativeRandom() * ((+max || 0) - min + 1)); + var rand = nativeRandom(); + return (min % 1 || max % 1) + ? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max) + : min + floor(rand * (max - min + 1)); } /** @@ -5332,6 +5693,7 @@ lodash.throttle = throttle; lodash.times = times; lodash.toArray = toArray; + lodash.transform = transform; lodash.union = union; lodash.uniq = uniq; lodash.unzip = unzip; @@ -5356,6 +5718,10 @@ // add functions to `lodash.prototype` mixin(lodash); + // add Underscore compat + lodash.chain = lodash; + lodash.prototype.chain = function() { return this; }; + /*--------------------------------------------------------------------------*/ // add functions that return unwrapped values when chaining @@ -5407,6 +5773,7 @@ lodash.all = every; lodash.any = some; lodash.detect = find; + lodash.findWhere = find; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.include = contains; @@ -5452,7 +5819,7 @@ * @memberOf _ * @type String */ - lodash.VERSION = '1.2.1'; + lodash.VERSION = '1.3.0'; // add "Chaining" functions to the wrapper lodash.prototype.toString = wrapperToString; @@ -5460,7 +5827,7 @@ lodash.prototype.valueOf = wrapperValueOf; // add `Array` functions that return unwrapped values - each(['join', 'pop', 'shift'], function(methodName) { + basicEach(['join', 'pop', 'shift'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { return func.apply(this.__wrapped__, arguments); @@ -5468,7 +5835,7 @@ }); // add `Array` functions that return the wrapped value - each(['push', 'reverse', 'sort', 'unshift'], function(methodName) { + basicEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { func.apply(this.__wrapped__, arguments); @@ -5477,7 +5844,7 @@ }); // add `Array` functions that return new wrapped values - each(['concat', 'slice', 'splice'], function(methodName) { + basicEach(['concat', 'slice', 'splice'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { return new lodashWrapper(func.apply(this.__wrapped__, arguments)); @@ -5487,7 +5854,7 @@ // avoid array-like object bugs with `Array#shift` and `Array#splice` // in Firefox < 10 and IE < 9 if (!support.spliceObjects) { - each(['pop', 'shift', 'splice'], function(methodName) { + basicEach(['pop', 'shift', 'splice'], function(methodName) { var func = arrayRef[methodName], isSplice = methodName == 'splice'; diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index 1dba81c94a..ba807370b4 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -1,47 +1,51 @@ /** * @license - * Lo-Dash 1.2.1 (Custom Build) lodash.com/license + * Lo-Dash 1.3.0 (Custom Build) lodash.com/license * Build: `lodash -o ./dist/lodash.compat.js` * Underscore.js 1.4.4 underscorejs.org/LICENSE */ -;(function(n){function t(r){function a(n){return n&&typeof n=="object"&&!me(n)&&Qt.call(n,"__wrapped__")?n:new V(n)}function R(n){var t=n.length,e=t>=l;if(e)for(var r={},u=-1;++ut||typeof n=="undefined")return 1;if(nu;u++)r+="i='"+t.g[u]+"';if(","constructor"==t.g[u]&&(r+="!(f&&f.prototype===m)&&"),r+="h.call(m,i)){"+t.f+"}"}return(t.b||ve.nonEnumArgs)&&(r+="}"),r+=t.c+";return u",e("h,j,k,l,o,p,r","return function("+n+"){"+r+"}")(Qt,W,me,ut,be,a,q) -}function K(n){return"\\"+B[n]}function M(n){return we[n]}function U(n){return typeof n.toString!="function"&&typeof(n+"")=="string"}function V(n){this.__wrapped__=n}function G(){}function H(n){var t=!1;if(!n||Zt.call(n)!=I||!ve.argsClass&&W(n))return t;var e=n.constructor;return(tt(e)?e instanceof e:ve.nodeClass||!U(n))?ve.ownLast?(xe(n,function(n,e,r){return t=Qt.call(r,e),!1}),!0===t):(xe(n,function(n,e){t=e}),!1===t||Qt.call(n,t)):t}function J(n,t,e){t||(t=0),typeof e=="undefined"&&(e=n?n.length:0); -var r=-1;e=e-t||0;for(var u=It(0>e?0:e);++re?ae(0,u+e):e)||0,typeof u=="number"?a=-1<(ut(n)?n.indexOf(t,e):_t(n,t,e)):_e(n,function(n){return++ru&&(u=i)}}else t=!t&&ut(n)?T:a.createCallback(t,e),_e(n,function(n,e,a){e=t(n,e,a),e>r&&(r=e,u=n) -});return u}function gt(n,t,e,r){var u=3>arguments.length;if(t=a.createCallback(t,r,4),me(n)){var o=-1,i=n.length;for(u&&(e=n[++o]);++oarguments.length;if(typeof o!="number")var f=be(n),o=f.length;else ve.unindexedChars&&ut(n)&&(u=n.split(""));return t=a.createCallback(t,r,4),pt(n,function(n,r,a){r=f?f[--o]:--o,e=i?(i=!1,u[r]):t(e,u[r],r,a)}),e}function ht(n,t,e){var r; -if(t=a.createCallback(t,e),me(n)){e=-1;for(var u=n.length;++ee?ae(0,u+e):e||0)-1;else if(e)return r=Ct(n,t),n[r]===t?r:-1;for(;++r>>1,e(n[r])=l;if(p)var s={};for(null!=e&&(c=[],e=a.createCallback(e,r));++u_t(c,v))&&((e||p)&&c.push(v),i.push(r))}return i}function kt(n,t){for(var e=-1,r=n?n.length:0,u={};++e/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:h,variable:"",imports:{_:a}};var ge={a:"q,w,g",h:"var a=arguments,b=0,c=typeof g=='number'?2:a.length;while(++b":">",'"':""","'":"'"},Ce=Z(we),je=L(ge,{h:ge.h.replace(";",";if(c>3&&typeof a[c-2]=='function'){var d=p.createCallback(a[--c-1],a[c--],2);}else if(c>2&&typeof a[c-1]=='function'){d=a[--c];}"),f:"u[i]=d?d(u[i],m[i]):m[i]"}),ke=L(ge),xe=L(ye,he,{i:!1}),Oe=L(ye,he); -tt(/x/)&&(tt=function(n){return typeof n=="function"&&Zt.call(n)==S});var Ee=Jt?function(n){if(!n||Zt.call(n)!=I||!ve.argsClass&&W(n))return!1;var t=n.valueOf,e=typeof t=="function"&&(e=Jt(t))&&Jt(e);return e?n==e||Jt(n)==e:H(n)}:H;pe&&u&&typeof Xt=="function"&&(Ot=xt(Xt,r));var Se=8==ie(m+"08")?ie:function(n,t){return ie(ut(n)?n.replace(d,""):n,t||0)};return a.after=function(n,t){return 1>n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},a.assign=je,a.at=function(n){var t=-1,e=Gt.apply(zt,le.call(arguments,1)),r=e.length,u=It(r); -for(ve.unindexedChars&&ut(n)&&(n=n.split(""));++t=l,i=[],c=i;n:for(;++u_t(c,p)){o&&c.push(p); -for(var v=e;--v;)if(!(r[v]||(r[v]=R(t[v])))(p))continue n;i.push(p)}}return i},a.invert=Z,a.invoke=function(n,t){var e=le.call(arguments,2),r=-1,u=typeof t=="function",a=n?n.length:0,o=It(typeof a=="number"?a:0);return pt(n,function(n){o[++r]=(u?t:n[t]).apply(n,e)}),o},a.keys=be,a.map=st,a.max=vt,a.memoize=function(n,t){var e={};return function(){var r=f+(t?t.apply(this,arguments):arguments[0]);return Qt.call(e,r)?e[r]:e[r]=n.apply(this,arguments)}},a.merge=at,a.min=function(n,t,e){var r=1/0,u=r; -if(!t&&me(n)){e=-1;for(var o=n.length;++e_t(o,e))&&(u[e]=n)}),u},a.once=function(n){var t,e;return function(){return t?e:(t=!0,e=n.apply(this,arguments),n=null,e)}},a.pairs=function(n){for(var t=-1,e=be(n),r=e.length,u=It(r);++te?ae(0,r+e):oe(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},a.mixin=St,a.noConflict=function(){return r._=Kt,this},a.parseInt=Se,a.random=function(n,t){return null==n&&null==t&&(t=1),n=+n||0,null==t&&(t=n,n=0),n+Ht(fe()*((+t||0)-n+1))},a.reduce=gt,a.reduceRight=yt,a.result=function(n,t){var r=n?n[t]:e;return tt(r)?n[t]():r},a.runInContext=t,a.size=function(n){var t=n?n.length:0; -return typeof t=="number"?t:be(n).length},a.some=ht,a.sortedIndex=Ct,a.template=function(n,t,r){var u=a.templateSettings;n||(n=""),r=ke({},r,u);var o,i=ke({},r.imports,u.imports),u=be(i),i=ot(i),f=0,l=r.interpolate||b,v="__p+='",l=Rt((r.escape||b).source+"|"+l.source+"|"+(l===h?g:b).source+"|"+(r.evaluate||b).source+"|$","g");n.replace(l,function(t,e,r,u,a,i){return r||(r=u),v+=n.slice(f,i).replace(w,K),e&&(v+="'+__e("+e+")+'"),a&&(o=!0,v+="';"+a+";__p+='"),r&&(v+="'+((__t=("+r+"))==null?'':__t)+'"),f=i+t.length,t -}),v+="';\n",l=r=r.variable,l||(r="obj",v="with("+r+"){"+v+"}"),v=(o?v.replace(c,""):v).replace(p,"$1").replace(s,"$1;"),v="function("+r+"){"+(l?"":r+"||("+r+"={});")+"var __t,__p='',__e=_.escape"+(o?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+v+"return __p}";try{var y=$t(u,"return "+v).apply(e,i)}catch(m){throw m.source=v,m}return t?y(t):(y.source=v,y)},a.unescape=function(n){return null==n?"":Tt(n).replace(v,Q)},a.uniqueId=function(n){var t=++o;return Tt(null==n?"":n)+t -},a.all=ft,a.any=ht,a.detect=ct,a.foldl=gt,a.foldr=yt,a.include=it,a.inject=gt,Oe(a,function(n,t){a.prototype[t]||(a.prototype[t]=function(){var t=[this.__wrapped__];return Wt.apply(t,arguments),n.apply(a,t)})}),a.first=dt,a.last=function(n,t,e){if(n){var r=0,u=n.length;if(typeof t!="number"&&null!=t){var o=u;for(t=a.createCallback(t,e);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n[u-1];return J(n,ae(0,u-r))}},a.take=dt,a.head=dt,Oe(a,function(n,t){a.prototype[t]||(a.prototype[t]=function(t,e){var r=n(this.__wrapped__,t,e); -return null==t||e&&typeof t!="function"?r:new V(r)})}),a.VERSION="1.2.1",a.prototype.toString=function(){return Tt(this.__wrapped__)},a.prototype.value=At,a.prototype.valueOf=At,_e(["join","pop","shift"],function(n){var t=zt[n];a.prototype[n]=function(){return t.apply(this.__wrapped__,arguments)}}),_e(["push","reverse","sort","unshift"],function(n){var t=zt[n];a.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),_e(["concat","slice","splice"],function(n){var t=zt[n];a.prototype[n]=function(){return new V(t.apply(this.__wrapped__,arguments)) -}}),ve.spliceObjects||_e(["pop","shift","splice"],function(n){var t=zt[n],e="splice"==n;a.prototype[n]=function(){var n=this.__wrapped__,r=t.apply(n,arguments);return 0===n.length&&delete n[0],e?new V(r):r}}),a}var e,r=typeof exports=="object"&&exports,u=typeof module=="object"&&module&&module.exports==r&&module,a=typeof global=="object"&&global;(a.global===a||a.window===a)&&(n=a);var o=0,i={},f=+new Date+"",l=200,c=/\b__p\+='';/g,p=/\b(__p\+=)''\+/g,s=/(__e\(.*?\)|\b__t\))\+'';/g,v=/&(?:amp|lt|gt|quot|#39);/g,g=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,y=/\w*$/,h=/<%=([\s\S]+?)%>/g,m=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",d=RegExp("^["+m+"]*0+(?=.$)"),b=/($^)/,_=/[&<>"']/g,w=/['\n\r\t\u2028\u2029\\]/g,C="Array Boolean Date Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),j="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),k="[object Arguments]",x="[object Array]",O="[object Boolean]",E="[object Date]",S="[object Function]",A="[object Number]",I="[object Object]",P="[object RegExp]",N="[object String]",$={}; -$[S]=!1,$[k]=$[x]=$[O]=$[E]=$[A]=$[I]=$[P]=$[N]=!0;var q={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},B={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},F=t();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(n._=F,define(function(){return F})):r&&!r.nodeType?u?(u.exports=F)._=F:r._=F:n._=F})(this); \ No newline at end of file +;!function(n){function t(n,t,r){r=(r||0)-1;for(var e=n.length;++rt||typeof n=="undefined")return 1;if(nr?0:r);++ek;k++)e+="m='"+n.g[k]+"';if((!(p&&v[m])&&l.call(r,m))",n.i||(e+="||(!v[m]&&r[m]!==y[m])"),e+="){"+n.f+"}"; +e+="}"}return(n.b||Pr.nonEnumArgs)&&(e+="}"),e+=n.c+";return C",t=t("i,j,l,n,o,q,t,u,y,z,w,G,H,J",r+e+"}"),g(n),t(M,tr,sr,ft,qr,dt,Rr,_,rr,nt,Nr,Y,er,yr)}function rt(n){return mt(n)?br(n):{}}function ut(n){return Wr[n]}function ot(){var n=(n=_.indexOf)===Pt?t:n;return n}function it(n){return function(t,r,e,u){return typeof r!="boolean"&&r!=d&&(u=e,e=u&&u[r]===t?m:r,r=b),e!=d&&(e=_.createCallback(e,u)),n(t,r,e,u)}}function lt(n){var t,r;return!n||yr.call(n)!=Q||(t=n.constructor,ht(t)&&!(t instanceof t))||!Pr.argsClass&&ft(n)||!Pr.nodeClass&&f(n)?b:Pr.ownLast?(Jr(n,function(n,t,e){return r=sr.call(e,t),b +}),r!==false):(Jr(n,function(n,t){r=t}),r===m||sr.call(n,r))}function ct(n){return Lr[n]}function ft(n){return yr.call(n)==G}function pt(n,t,r,e,u,a){var o=n;if(typeof t!="boolean"&&t!=d&&(e=r,r=t,t=b),typeof r=="function"){if(r=typeof e=="undefined"?r:_.createCallback(r,e,1),o=r(o),typeof o!="undefined")return o;o=n}if(e=mt(o)){var i=yr.call(o);if(!Z[i]||!Pr.nodeClass&&f(o))return o;var c=qr(o)}if(!e||!t)return e?c?v(o):Gr({},o):o;switch(e=Br[i],i){case J:case K:return new e(+o);case V:case Y:return new e(o); +case X:return e(o.source,P.exec(o))}i=!u,u||(u=l()),a||(a=l());for(var p=u.length;p--;)if(u[p]==n)return a[p];return o=c?e(o.length):{},c&&(sr.call(n,"index")&&(o.index=n.index),sr.call(n,"input")&&(o.input=n.input)),u.push(n),a.push(o),(c?Tr:Kr)(n,function(n,e){o[e]=pt(n,t,r,m,u,a)}),i&&(s(u),s(a)),o}function st(n){var t=[];return Jr(n,function(n,r){ht(n)&&t.push(r)}),t.sort()}function gt(n){for(var t=-1,r=Rr(n),e=r.length,u={};++tr?kr(0,a+r):r)||0,a&&typeof a=="number"?o=-1<(dt(n)?n.indexOf(t,r):u(n,t,r)):Tr(n,function(n){return++ea&&(a=i)}}else t=!t&&dt(n)?u:_.createCallback(t,r),Tr(n,function(n,r,u){r=t(n,r,u),r>e&&(e=r,a=n)});return a}function St(n,t,r,e){var u=3>arguments.length;if(t=_.createCallback(t,e,4),qr(n)){var a=-1,o=n.length;for(u&&(r=n[++a]);++aarguments.length;if(typeof a!="number")var i=Rr(n),a=i.length;else Pr.unindexedChars&&dt(n)&&(u=n.split(""));return t=_.createCallback(t,e,4),xt(n,function(n,e,l){e=i?i[--a]:--a,r=o?(o=b,u[e]):t(r,u[e],e,l) +}),r}function It(n,t,r){var e;if(t=_.createCallback(t,r),qr(n)){r=-1;for(var u=n.length;++r=O&&u===t;if(c){var f=o(i);f?(u=r,i=f):c=b}for(;++eu(i,f)&&l.push(f);return c&&g(i),l}function Nt(n,t,r){if(n){var e=0,u=n.length;if(typeof t!="number"&&t!=d){var a=-1;for(t=_.createCallback(t,r);++ae?kr(0,u+e):e||0}else if(e)return e=Ft(n,r),n[e]===r?e:-1;return n?t(n,r,e):-1}function zt(n,t,r){if(typeof t!="number"&&t!=d){var e=0,u=-1,a=n?n.length:0;for(t=_.createCallback(t,r);++u>>1,r(n[e])r?0:r);++tc&&(i=n.apply(l,o));else{var r=new Kt;!s&&!h&&(f=r);var e=p-(r-f);0/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:z,variable:"",imports:{_:_}};var zr={a:"x,F,k",h:"var a=arguments,b=0,c=typeof k=='number'?2:a.length;while(++b":">",'"':""","'":"'"},Lr=gt(Wr),Gr=tt(zr,{h:zr.h.replace(";",";if(c>3&&typeof a[c-2]=='function'){var d=u.createCallback(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){d=a[--c]}"),f:"C[m]=d?d(C[m],r[m]):r[m]"}),Hr=tt(zr),Jr=tt(Fr,$r,{i:b}),Kr=tt(Fr,$r); +ht(/x/)&&(ht=function(n){return typeof n=="function"&&yr.call(n)==U});var Mr=pr?function(n){if(!n||yr.call(n)!=Q||!Pr.argsClass&&ft(n))return b;var t=n.valueOf,r=typeof t=="function"&&(r=pr(t))&&pr(r);return r?n==r||pr(n)==r:lt(n)}:lt,Ur=Ot,Vr=it(function Yr(n,t,r){for(var e=-1,u=n?n.length:0,a=[];++e=O&&i===t,v=u||p?l():f;if(p){var h=o(v);h?(i=r,v=h):(p=b,v=u?v:(s(v),f)) +}for(;++ai(v,m))&&((u||p)&&v.push(m),f.push(h))}return p?(s(v.b),g(v)):u&&s(v),f});Ir&&et&&typeof hr=="function"&&(Tt=Dt(hr,e));var Xr=8==Or($+"08")?Or:function(n,t){return Or(dt(n)?n.replace(q,""):n,t||0)};return _.after=function(n,t){return 1>n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},_.assign=Gr,_.at=function(n){var t=-1,r=lr.apply(nr,Sr.call(arguments,1)),e=r.length,u=Ht(e);for(Pr.unindexedChars&&dt(n)&&(n=n.split(""));++t=O&&o(a?e[a]:h)}n:for(;++c(y?r(y,m):f(h,m))){for(a=u,(y||h).push(m);--a;)if(y=i[a],0>(y?r(y,m):f(e[a],m)))continue n;v.push(m)}}for(;u--;)(y=i[u])&&g(y);return s(i),s(h),v},_.invert=gt,_.invoke=function(n,t){var r=Sr.call(arguments,2),e=-1,u=typeof t=="function",a=n?n.length:0,o=Ht(typeof a=="number"?a:0);return xt(n,function(n){o[++e]=(u?t:n[t]).apply(n,r)}),o},_.keys=Rr,_.map=Ot,_.max=Et,_.memoize=function(n,t){function r(){var e=r.cache,u=x+(t?t.apply(this,arguments):arguments[0]); +return sr.call(e,u)?e[u]:e[u]=n.apply(this,arguments)}return r.cache={},r},_.merge=bt,_.min=function(n,t,r){var e=1/0,a=e;if(!t&&qr(n)){r=-1;for(var o=n.length;++re(o,r))&&(a[r]=n)}),a},_.once=function(n){var t,r; +return function(){return t?r:(t=y,r=n.apply(this,arguments),n=d,r)}},_.pairs=function(n){for(var t=-1,r=Rr(n),e=r.length,u=Ht(e);++tr?kr(0,e+r):xr(r,e-1))+1);e--;)if(n[e]===t)return e;return-1},_.mixin=Lt,_.noConflict=function(){return e._=ur,this},_.parseInt=Xr,_.random=function(n,t){n==d&&t==d&&(t=1),n=+n||0,t==d?(t=n,n=0):t=+t||0; +var r=Er();return n%1||t%1?n+xr(r*(t-n+parseFloat("1e-"+((r+"").length-1))),t):n+cr(r*(t-n+1))},_.reduce=St,_.reduceRight=At,_.result=function(n,t){var r=n?n[t]:m;return ht(r)?n[t]():r},_.runInContext=h,_.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Rr(n).length},_.some=It,_.sortedIndex=Ft,_.template=function(n,t,r){var e=_.templateSettings;n||(n=""),r=Hr({},r,e);var u,a=Hr({},r.imports,e.imports),e=Rr(a),a=_t(a),o=0,l=r.interpolate||D,c="__p+='",l=Xt((r.escape||D).source+"|"+l.source+"|"+(l===z?N:D).source+"|"+(r.evaluate||D).source+"|$","g"); +n.replace(l,function(t,r,e,a,l,f){return e||(e=a),c+=n.slice(o,f).replace(T,i),r&&(c+="'+__e("+r+")+'"),l&&(u=y,c+="';"+l+";__p+='"),e&&(c+="'+((__t=("+e+"))==null?'':__t)+'"),o=f+t.length,t}),c+="';\n",l=r=r.variable,l||(r="obj",c="with("+r+"){"+c+"}"),c=(u?c.replace(S,""):c).replace(A,"$1").replace(I,"$1;"),c="function("+r+"){"+(l?"":r+"||("+r+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+c+"return __p}";try{var f=Mt(e,"return "+c).apply(m,a) +}catch(p){throw p.source=c,p}return t?f(t):(f.source=c,f)},_.unescape=function(n){return n==d?"":Yt(n).replace(B,ct)},_.uniqueId=function(n){var t=++j;return Yt(n==d?"":n)+t},_.all=jt,_.any=It,_.detect=kt,_.findWhere=kt,_.foldl=St,_.foldr=At,_.include=Ct,_.inject=St,Kr(_,function(n,t){_.prototype[t]||(_.prototype[t]=function(){var t=[this.__wrapped__];return gr.apply(t,arguments),n.apply(_,t)})}),_.first=Nt,_.last=function(n,t,r){if(n){var e=0,u=n.length;if(typeof t!="number"&&t!=d){var a=u;for(t=_.createCallback(t,r);a--&&t(n[a],a,n);)e++ +}else if(e=t,e==d||r)return n[u-1];return v(n,kr(0,u-e))}},_.take=Nt,_.head=Nt,Kr(_,function(n,t){_.prototype[t]||(_.prototype[t]=function(t,r){var e=n(this.__wrapped__,t,r);return t==d||r&&typeof t!="function"?e:new C(e)})}),_.VERSION="1.3.0",_.prototype.toString=function(){return Yt(this.__wrapped__)},_.prototype.value=Gt,_.prototype.valueOf=Gt,Tr(["join","pop","shift"],function(n){var t=nr[n];_.prototype[n]=function(){return t.apply(this.__wrapped__,arguments)}}),Tr(["push","reverse","sort","unshift"],function(n){var t=nr[n]; +_.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),Tr(["concat","slice","splice"],function(n){var t=nr[n];_.prototype[n]=function(){return new C(t.apply(this.__wrapped__,arguments))}}),Pr.spliceObjects||Tr(["pop","shift","splice"],function(n){var t=nr[n],r="splice"==n;_.prototype[n]=function(){var n=this.__wrapped__,e=t.apply(n,arguments);return 0===n.length&&delete n[0],r?new C(e):e}}),_}var m,y=!0,d=null,b=!1,_=[],C=[],j=0,w={},x=+new Date+"",O=75,E=10,S=/\b__p\+='';/g,A=/\b(__p\+=)''\+/g,I=/(__e\(.*?\)|\b__t\))\+'';/g,B=/&(?:amp|lt|gt|quot|#39);/g,N=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,P=/\w*$/,z=/<%=([\s\S]+?)%>/g,F=(F=/\bthis\b/)&&F.test(h)&&F,$=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",q=RegExp("^["+$+"]*0+(?=.$)"),D=/($^)/,R=/[&<>"']/g,T=/['\n\r\t\u2028\u2029\\]/g,W="Array Boolean Date Error Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),L="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),G="[object Arguments]",H="[object Array]",J="[object Boolean]",K="[object Date]",M="[object Error]",U="[object Function]",V="[object Number]",Q="[object Object]",X="[object RegExp]",Y="[object String]",Z={}; +Z[U]=b,Z[G]=Z[H]=Z[J]=Z[K]=Z[V]=Z[Q]=Z[X]=Z[Y]=y;var nt={"boolean":b,"function":y,object:y,number:b,string:b,undefined:b},tt={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},rt=nt[typeof exports]&&exports,et=nt[typeof module]&&module&&module.exports==rt&&module,ut=nt[typeof global]&&global;!ut||ut.global!==ut&&ut.window!==ut||(n=ut);var at=h();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(n._=at, define(function(){return at})):rt&&!rt.nodeType?et?(et.exports=at)._=at:rt._=at:n._=at +}(this); \ No newline at end of file diff --git a/dist/lodash.js b/dist/lodash.js index c20653549e..299b649888 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -1,6 +1,6 @@ /** * @license - * Lo-Dash 1.2.1 (Custom Build) + * Lo-Dash 1.3.0 (Custom Build) * Build: `lodash modern -o ./dist/lodash.js` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.4.4 @@ -12,17 +12,9 @@ /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports; - - /** Detect free variable `module` */ - var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; - - /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - window = freeGlobal; - } + /** Used to pool arrays and objects used internally */ + var arrayPool = [], + objectPool = []; /** Used to generate unique IDs */ var idCounter = 0; @@ -34,7 +26,10 @@ var keyPrefix = +new Date + ''; /** Used as the size when optimizations are enabled for large arrays */ - var largeArraySize = 200; + var largeArraySize = 75; + + /** Used as the max size of the `arrayPool` and `objectPool` */ + var maxPoolSize = 10; /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, @@ -56,6 +51,9 @@ /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; + /** Used to detect functions containing a `this` reference */ + var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis; + /** Used to detect and test whitespace */ var whitespace = ( // whitespace @@ -82,9 +80,9 @@ /** Used to assign default `context` object properties */ var contextProps = [ - 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp', - 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 'parseInt', - 'setImmediate', 'setTimeout' + 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', + 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', + 'parseInt', 'setImmediate', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify */ @@ -95,6 +93,7 @@ arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', + errorClass = '[object Error]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', @@ -130,6 +129,283 @@ '\u2029': 'u2029' }; + /** Detect free variable `exports` */ + var freeExports = objectTypes[typeof exports] && exports; + + /** Detect free variable `module` */ + var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module; + + /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ + var freeGlobal = objectTypes[typeof global] && global; + if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { + window = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + /** + * A basic implementation of `_.indexOf` without support for binary searches + * or `fromIndex` constraints. + * + * @private + * @param {Array} array The array to search. + * @param {Mixed} value The value to search for. + * @param {Number} [fromIndex=0] The index to search from. + * @returns {Number} Returns the index of the matched value or `-1`. + */ + function basicIndexOf(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * An implementation of `_.contains` for cache objects that mimics the return + * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache object to inspect. + * @param {Mixed} value The value to search for. + * @returns {Number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var type = typeof value; + cache = cache.cache; + + if (type == 'boolean' || value == null) { + return cache[value]; + } + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value; + cache = cache[type] || (cache[type] = {}); + + return type == 'object' + ? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1) + : (cache[key] ? 0 : -1); + } + + /** + * Adds a given `value` to the corresponding cache object. + * + * @private + * @param {Mixed} value The value to add to the cache. + */ + function cachePush(value) { + var cache = this.cache, + type = typeof value; + + if (type == 'boolean' || value == null) { + cache[value] = true; + } else { + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value, + typeCache = cache[type] || (cache[type] = {}); + + if (type == 'object') { + if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) { + cache[type] = false; + } + } else { + typeCache[key] = true; + } + } + } + + /** + * Used by `_.max` and `_.min` as the default `callback` when a given + * `collection` is a string value. + * + * @private + * @param {String} value The character to inspect. + * @returns {Number} Returns the code unit of given character. + */ + function charAtCallback(value) { + return value.charCodeAt(0); + } + + /** + * Used by `sortBy` to compare transformed `collection` values, stable sorting + * them in ascending order. + * + * @private + * @param {Object} a The object to compare to `b`. + * @param {Object} b The object to compare to `a`. + * @returns {Number} Returns the sort order indicator of `1` or `-1`. + */ + function compareAscending(a, b) { + var ai = a.index, + bi = b.index; + + a = a.criteria; + b = b.criteria; + + // ensure a stable sort in V8 and other engines + // http://code.google.com/p/v8/issues/detail?id=90 + if (a !== b) { + if (a > b || typeof a == 'undefined') { + return 1; + } + if (a < b || typeof b == 'undefined') { + return -1; + } + } + return ai < bi ? -1 : 1; + } + + /** + * Creates a cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [array=[]] The array to search. + * @returns {Null|Object} Returns the cache object or `null` if caching should not be used. + */ + function createCache(array) { + var index = -1, + length = array.length; + + var cache = getObject(); + cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; + + var result = getObject(); + result.array = array; + result.cache = cache; + result.push = cachePush; + + while (++index < length) { + result.push(array[index]); + } + return cache.object === false + ? (releaseObject(result), null) + : result; + } + + /** + * Used by `template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {String} match The matched character to escape. + * @returns {String} Returns the escaped character. + */ + function escapeStringChar(match) { + return '\\' + stringEscapes[match]; + } + + /** + * Gets an array from the array pool or creates a new one if the pool is empty. + * + * @private + * @returns {Array} The array from the pool. + */ + function getArray() { + return arrayPool.pop() || []; + } + + /** + * Gets an object from the object pool or creates a new one if the pool is empty. + * + * @private + * @returns {Object} The object from the pool. + */ + function getObject() { + return objectPool.pop() || { + 'array': null, + 'criteria': null, + 'false': false, + 'index': 0, + 'leading': false, + 'maxWait': 0, + 'null': false, + 'number': null, + 'object': null, + 'push': null, + 'string': null, + 'trailing': false, + 'true': false, + 'undefined': false, + 'value': null + }; + } + + /** + * A no-operation function. + * + * @private + */ + function noop() { + // no operation performed + } + + /** + * Releases the given `array` back to the array pool. + * + * @private + * @param {Array} [array] The array to release. + */ + function releaseArray(array) { + if (arrayPool.length == maxPoolSize) { + arrayPool.length = maxPoolSize - 1; + } + array.length = 0; + arrayPool.push(array); + } + + /** + * Releases the given `object` back to the object pool. + * + * @private + * @param {Object} [object] The object to release. + */ + function releaseObject(object) { + var cache = object.cache; + if (cache) { + releaseObject(cache); + } + if (objectPool.length == maxPoolSize) { + objectPool.length = maxPoolSize - 1; + } + object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; + objectPool.push(object); + } + + /** + * Slices the `collection` from the `start` index up to, but not including, + * the `end` index. + * + * Note: This function is used, instead of `Array#slice`, to support node lists + * in IE < 9 and to ensure dense arrays are returned. + * + * @private + * @param {Array|Object|String} collection The collection to slice. + * @param {Number} start The start index. + * @param {Number} end The end index. + * @returns {Array} Returns the new array. + */ + function slice(array, start, end) { + start || (start = 0); + if (typeof end == 'undefined') { + end = array ? array.length : 0; + } + var index = -1, + length = end - start || 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = array[start + index]; + } + return result; + } + /*--------------------------------------------------------------------------*/ /** @@ -160,16 +436,24 @@ String = context.String, TypeError = context.TypeError; - /** Used for `Array` and `Object` method references */ - var arrayRef = Array(), - objectRef = Object(); + /** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ + var arrayRef = []; + + /** Used for native method references */ + var objectProto = Object.prototype, + stringProto = String.prototype; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = context._; /** Used to detect if a method is native */ var reNative = RegExp('^' + - String(objectRef.valueOf) + String(objectProto.valueOf) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); @@ -179,15 +463,18 @@ clearTimeout = context.clearTimeout, concat = arrayRef.concat, floor = Math.floor, + fnToString = Function.prototype.toString, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, - hasOwnProperty = objectRef.hasOwnProperty, + hasOwnProperty = objectProto.hasOwnProperty, push = arrayRef.push, + propertyIsEnumerable = objectProto.propertyIsEnumerable, setImmediate = context.setImmediate, setTimeout = context.setTimeout, - toString = objectRef.toString; + toString = objectProto.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, + nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = context.isFinite, nativeIsNaN = context.isNaN, @@ -207,6 +494,7 @@ ctorByClass[arrayClass] = Array; ctorByClass[boolClass] = Boolean; ctorByClass[dateClass] = Date; + ctorByClass[funcClass] = Function; ctorByClass[objectClass] = Object; ctorByClass[numberClass] = Number; ctorByClass[regexpClass] = RegExp; @@ -233,8 +521,8 @@ * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, * `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, - * `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `unshift`, `unzip`, - * `values`, `where`, `without`, `wrap`, and `zip` + * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, + * `unzip`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, @@ -250,6 +538,7 @@ * * @name _ * @constructor + * @alias chain * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. @@ -281,6 +570,19 @@ : new lodashWrapper(value); } + /** + * A fast path for creating `lodash` wrapper objects. + * + * @private + * @param {Mixed} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + */ + function lodashWrapper(value) { + this.__wrapped__ = value; + } + // ensure `new lodashWrapper` is an instance of `lodash` + lodashWrapper.prototype = lodash.prototype; + /** * An object used to flag environments features. * @@ -361,78 +663,6 @@ /*--------------------------------------------------------------------------*/ - /** - * Creates a function optimized to search large arrays for a given `value`, - * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. - * - * @private - * @param {Array} array The array to search. - * @param {Mixed} value The value to search for. - * @returns {Boolean} Returns `true`, if `value` is found, else `false`. - */ - function cachedContains(array) { - var length = array.length, - isLarge = length >= largeArraySize; - - if (isLarge) { - var cache = {}, - index = -1; - - while (++index < length) { - var key = keyPrefix + array[index]; - (cache[key] || (cache[key] = [])).push(array[index]); - } - } - return function(value) { - if (isLarge) { - var key = keyPrefix + value; - return cache[key] && indexOf(cache[key], value) > -1; - } - return indexOf(array, value) > -1; - } - } - - /** - * Used by `_.max` and `_.min` as the default `callback` when a given - * `collection` is a string value. - * - * @private - * @param {String} value The character to inspect. - * @returns {Number} Returns the code unit of given character. - */ - function charAtCallback(value) { - return value.charCodeAt(0); - } - - /** - * Used by `sortBy` to compare transformed `collection` values, stable sorting - * them in ascending order. - * - * @private - * @param {Object} a The object to compare to `b`. - * @param {Object} b The object to compare to `a`. - * @returns {Number} Returns the sort order indicator of `1` or `-1`. - */ - function compareAscending(a, b) { - var ai = a.index, - bi = b.index; - - a = a.criteria; - b = b.criteria; - - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (a !== b) { - if (a > b || typeof a == 'undefined') { - return 1; - } - if (a < b || typeof b == 'undefined') { - return -1; - } - } - return ai < bi ? -1 : 1; - } - /** * Creates a function that, when called, invokes `func` with the `this` binding * of `thisArg` and prepends any `partialArgs` to the arguments passed to the @@ -479,9 +709,7 @@ } if (this instanceof bound) { // ensure `new bound` is an instance of `func` - noop.prototype = func.prototype; - thisBinding = new noop; - noop.prototype = null; + thisBinding = createObject(func.prototype); // mimic the constructor's `return` behavior // http://es5.github.com/#x13.2.2 @@ -494,15 +722,14 @@ } /** - * Used by `template` to escape characters for inclusion in compiled - * string literals. + * Creates a new object with the specified `prototype`. * * @private - * @param {String} match The matched character to escape. - * @returns {String} Returns the escaped character. + * @param {Object} prototype The prototype object. + * @returns {Object} Returns the new object. */ - function escapeStringChar(match) { - return '\\' + stringEscapes[match]; + function createObject(prototype) { + return isObject(prototype) ? nativeCreate(prototype) : {}; } /** @@ -517,25 +744,39 @@ } /** - * A fast path for creating `lodash` wrapper objects. + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized, this method returns the custom method, otherwise it returns + * the `basicIndexOf` function. * * @private - * @param {Mixed} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns a `lodash` instance. + * @returns {Function} Returns the "indexOf" function. */ - function lodashWrapper(value) { - this.__wrapped__ = value; + function getIndexOf(array, value, fromIndex) { + var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result; + return result; } - // ensure `new lodashWrapper` is an instance of `lodash` - lodashWrapper.prototype = lodash.prototype; /** - * A no-operation function. + * Creates a function that juggles arguments, allowing argument overloading + * for `_.flatten` and `_.uniq`, before passing them to the given `func`. * * @private + * @param {Function} func The function to wrap. + * @returns {Function} Returns the new function. */ - function noop() { - // no operation performed + function overloadWrapper(func) { + return function(array, flag, callback, thisArg) { + // juggle arguments + if (typeof flag != 'boolean' && flag != null) { + thisArg = callback; + callback = !(thisArg && thisArg[flag] === array) ? flag : undefined; + flag = false; + } + if (callback != null) { + callback = lodash.createCallback(callback, thisArg); + } + return func(array, flag, callback, thisArg); + }; } /** @@ -549,52 +790,21 @@ * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { - // avoid non-objects and false positives for `arguments` objects - var result = false; - if (!(value && toString.call(value) == objectClass)) { - return result; - } - // check that the constructor is `Object` (i.e. `Object instanceof Object`) - var ctor = value.constructor; - - if (isFunction(ctor) ? ctor instanceof ctor : true) { - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - forIn(value, function(value, key) { - result = key; - }); - return result === false || hasOwnProperty.call(value, result); - } - return result; - } - - /** - * Slices the `collection` from the `start` index up to, but not including, - * the `end` index. - * - * Note: This function is used, instead of `Array#slice`, to support node lists - * in IE < 9 and to ensure dense arrays are returned. - * - * @private - * @param {Array|Object|String} collection The collection to slice. - * @param {Number} start The start index. - * @param {Number} end The end index. - * @returns {Array} Returns the new array. - */ - function slice(array, start, end) { - start || (start = 0); - if (typeof end == 'undefined') { - end = array ? array.length : 0; - } - var index = -1, - length = end - start || 0, - result = Array(length < 0 ? 0 : length); + var ctor, + result; - while (++index < length) { - result[index] = array[start + index]; + // avoid non Object objects, `arguments` objects, and DOM elements + if (!(value && toString.call(value) == objectClass) || + (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) { + return false; } - return result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + forIn(value, function(value, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); } /** @@ -660,11 +870,10 @@ var shimKeys = function (object) { var index, iterable = object, result = []; if (!iterable) return result; - if (!(objectTypes[typeof object])) return result; - + if (!(objectTypes[typeof object])) return result; for (index in iterable) { - if (hasOwnProperty.call(iterable, index)) { - result.push(index); + if (hasOwnProperty.call(iterable, index)) { + result.push(index); } } return result @@ -754,25 +963,17 @@ } while (++argsIndex < argsLength) { iterable = args[argsIndex]; - if (iterable && objectTypes[typeof iterable]) {; - var length = iterable.length; index = -1; - if (isArray(iterable)) { - while (++index < length) { - result[index] = callback ? callback(result[index], iterable[index]) : iterable[index] - } - } - else { + if (iterable && objectTypes[typeof iterable]) { var ownIndex = -1, - ownProps = objectTypes[typeof iterable] ? keys(iterable) : [], - length = ownProps.length; + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; while (++ownIndex < length) { index = ownProps[ownIndex]; - result[index] = callback ? callback(result[index], iterable[index]) : iterable[index] + result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; } - } } - }; + } return result }; @@ -823,7 +1024,7 @@ // allows working with "Collections" methods without using their `callback` // argument, `index|key`, for this method's `callback` - if (typeof deep == 'function') { + if (typeof deep != 'boolean' && deep != null) { thisArg = callback; callback = deep; deep = false; @@ -868,8 +1069,9 @@ return ctor(result.source, reFlags.exec(result)); } // check for circular references and return corresponding clone - stackA || (stackA = []); - stackB || (stackB = []); + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); var length = stackA.length; while (length--) { @@ -899,6 +1101,10 @@ result[key] = clone(objValue, deep, callback, undefined, stackA, stackB); }); + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return result; } @@ -908,7 +1114,7 @@ * `undefined`, cloning will be handled by the method instead. The `callback` * is bound to `thisArg` and invoked with one argument; (value). * - * Note: This function is loosely based on the structured clone algorithm. Functions + * Note: This method is loosely based on the structured clone algorithm. Functions * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and * objects created by constructors other than `Object` are cloned to plain `Object` objects. * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. @@ -975,25 +1181,17 @@ argsLength = typeof guard == 'number' ? 2 : args.length; while (++argsIndex < argsLength) { iterable = args[argsIndex]; - if (iterable && objectTypes[typeof iterable]) {; - var length = iterable.length; index = -1; - if (isArray(iterable)) { - while (++index < length) { - if (typeof result[index] == 'undefined') result[index] = iterable[index] - } - } - else { + if (iterable && objectTypes[typeof iterable]) { var ownIndex = -1, - ownProps = objectTypes[typeof iterable] ? keys(iterable) : [], - length = ownProps.length; + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; while (++ownIndex < length) { index = ownProps[ownIndex]; - if (typeof result[index] == 'undefined') result[index] = iterable[index] + if (typeof result[index] == 'undefined') result[index] = iterable[index]; } - } } - }; + } return result }; @@ -1062,8 +1260,7 @@ var index, iterable = collection, result = iterable; if (!iterable) return result; if (!objectTypes[typeof iterable]) return result; - callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); - + callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); for (index in iterable) { if (callback(iterable[index], index, collection) === false) return result; } @@ -1095,15 +1292,14 @@ var index, iterable = collection, result = iterable; if (!iterable) return result; if (!objectTypes[typeof iterable]) return result; - callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); - + callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); var ownIndex = -1, - ownProps = objectTypes[typeof iterable] ? keys(iterable) : [], - length = ownProps.length; + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; while (++ownIndex < length) { index = ownProps[ownIndex]; - if (callback(iterable[index], index, collection) === false) return result + if (callback(iterable[index], index, collection) === false) return result; } return result }; @@ -1395,8 +1591,9 @@ // assume cyclic structures are equal // the algorithm for detecting cyclic structures is adapted from ES 5.1 // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) - stackA || (stackA = []); - stackB || (stackB = []); + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); var length = stackA.length; while (length--) { @@ -1458,6 +1655,10 @@ } }); } + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return result; } @@ -1535,7 +1736,7 @@ // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 - return value ? objectTypes[typeof value] : false; + return !!(value && objectTypes[typeof value]); } /** @@ -1761,8 +1962,9 @@ stackA = args[4], stackB = args[5]; } else { - stackA = []; - stackB = []; + var initedStack = true; + stackA = getArray(); + stackB = getArray(); // allows working with `_.reduce` and `_.reduceRight` without // using their `callback` arguments, `index|key` and `collection` @@ -1828,6 +2030,11 @@ object[key] = value; }); } + + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return object; } @@ -1858,7 +2065,8 @@ * // => { 'name': 'moe' } */ function omit(object, callback, thisArg) { - var isFunc = typeof callback == 'function', + var indexOf = getIndexOf(), + isFunc = typeof callback == 'function', result = {}; if (isFunc) { @@ -1953,6 +2161,57 @@ return result; } + /** + * An alternative to `_.reduce`, this method transforms an `object` to a new + * `accumulator` object which is the result of running each of its elements + * through the `callback`, with each `callback` execution potentially mutating + * the `accumulator` object. The `callback` is bound to `thisArg` and invoked + * with four arguments; (accumulator, value, key, object). Callbacks may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {Mixed} [accumulator] The custom accumulator value. + * @param {Mixed} [thisArg] The `this` binding of `callback`. + * @returns {Mixed} Returns the accumulated value. + * @example + * + * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { + * num *= num; + * if (num % 2) { + * return result.push(num) < 3; + * } + * }); + * // => [1, 9, 25] + * + * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { + * result[key] = num * 3; + * }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ + function transform(object, callback, accumulator, thisArg) { + var isArr = isArray(object); + callback = lodash.createCallback(callback, thisArg, 4); + + if (accumulator == null) { + if (isArr) { + accumulator = []; + } else { + var ctor = object && object.constructor, + proto = ctor && ctor.prototype; + + accumulator = createObject(proto); + } + } + (isArr ? forEach : forOwn)(object, function(value, index, object) { + return callback(accumulator, value, index, object); + }); + return accumulator; + } + /** * Creates an array composed of the own enumerable property values of `object`. * @@ -2042,11 +2301,12 @@ */ function contains(collection, target, fromIndex) { var index = -1, + indexOf = getIndexOf(), length = collection ? collection.length : 0, result = false; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; - if (typeof length == 'number') { + if (length && typeof length == 'number') { result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex) @@ -2245,7 +2505,7 @@ * * @static * @memberOf _ - * @alias detect + * @alias detect, findWhere * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per @@ -2943,17 +3203,18 @@ callback = lodash.createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { - result[++index] = { - 'criteria': callback(value, key, collection), - 'index': index, - 'value': value - }; + var object = result[++index] = getObject(); + object.criteria = callback(value, key, collection); + object.index = index; + object.value = value; }); length = result.length; result.sort(compareAscending); while (length--) { - result[length] = result[length].value; + var object = result[length]; + result[length] = object.value; + releaseObject(object); } return result; } @@ -3051,17 +3312,31 @@ */ function difference(array) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), - contains = cachedContains(flattened), + seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), result = []; + var isLarge = length >= largeArraySize && indexOf === basicIndexOf; + + if (isLarge) { + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + } + } while (++index < length) { var value = array[index]; - if (!contains(value)) { + if (indexOf(seen, value) < 0) { result.push(value); } } + if (isLarge) { + releaseObject(seen); + } return result; } @@ -3217,20 +3492,11 @@ * _.flatten(stooges, 'quotes'); * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] */ - function flatten(array, isShallow, callback, thisArg) { + var flatten = overloadWrapper(function flatten(array, isShallow, callback) { var index = -1, length = array ? array.length : 0, result = []; - // juggle arguments - if (typeof isShallow != 'boolean' && isShallow != null) { - thisArg = callback; - callback = isShallow; - isShallow = false; - } - if (callback != null) { - callback = lodash.createCallback(callback, thisArg); - } while (++index < length) { var value = array[index]; if (callback) { @@ -3244,7 +3510,7 @@ } } return result; - } + }); /** * Gets the index at which the first occurrence of `value` is found using @@ -3271,21 +3537,14 @@ * // => 2 */ function indexOf(array, value, fromIndex) { - var index = -1, - length = array ? array.length : 0; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; + var length = array ? array.length : 0; + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); } else if (fromIndex) { - index = sortedIndex(array, value); + var index = sortedIndex(array, value); return array[index] === value ? index : -1; } - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; + return array ? basicIndexOf(array, value, fromIndex) : -1; } /** @@ -3381,35 +3640,45 @@ function intersection(array) { var args = arguments, argsLength = args.length, - cache = { '0': {} }, + argsIndex = -1, + caches = getArray(), index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - isLarge = length >= largeArraySize, result = [], - seen = result; + seen = getArray(); + while (++argsIndex < argsLength) { + var value = args[argsIndex]; + caches[argsIndex] = indexOf === basicIndexOf && + (value ? value.length : 0) >= largeArraySize && + createCache(argsIndex ? args[argsIndex] : seen); + } outer: while (++index < length) { - var value = array[index]; - if (isLarge) { - var key = keyPrefix + value; - var inited = cache[0][key] - ? !(seen = cache[0][key]) - : (seen = cache[0][key] = []); - } - if (inited || indexOf(seen, value) < 0) { - if (isLarge) { - seen.push(value); - } - var argsIndex = argsLength; + var cache = caches[0]; + value = array[index]; + + if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { + argsIndex = argsLength; + (cache || seen).push(value); while (--argsIndex) { - if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex])))(value)) { + cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { continue outer; } } result.push(value); } } + while (argsLength--) { + cache = caches[argsLength]; + if (cache) { + releaseObject(cache); + } + } + releaseArray(caches); + releaseArray(seen); return result; } @@ -3738,7 +4007,7 @@ * Creates a duplicate-value-free version of the `array` using strict equality * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` * for `isSorted` will run a faster algorithm. If `callback` is passed, each - * element of `array` is passed through a `callback` before uniqueness is computed. + * element of `array` is passed through the `callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style @@ -3767,50 +4036,42 @@ * _.uniq([1, 1, 2, 2, 3], true); * // => [1, 2, 3] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); - * // => [1, 2, 3] + * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); + * // => ['A', 'b', 'C'] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); - * // => [1, 2, 3] + * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); + * // => [1, 2.5, 3] * * // using "_.pluck" callback shorthand * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniq(array, isSorted, callback, thisArg) { + var uniq = overloadWrapper(function(array, isSorted, callback) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - result = [], - seen = result; + result = []; + + var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf, + seen = (callback || isLarge) ? getArray() : result; - // juggle arguments - if (typeof isSorted != 'boolean' && isSorted != null) { - thisArg = callback; - callback = isSorted; - isSorted = false; - } - // init value cache for large arrays - var isLarge = !isSorted && length >= largeArraySize; if (isLarge) { - var cache = {}; - } - if (callback != null) { - seen = []; - callback = lodash.createCallback(callback, thisArg); + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + seen = callback ? seen : (releaseArray(seen), result); + } } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; - if (isLarge) { - var key = keyPrefix + computed; - var inited = cache[key] - ? !(seen = cache[key]) - : (seen = cache[key] = []); - } if (isSorted ? !index || seen[seen.length - 1] !== computed - : inited || indexOf(seen, computed) < 0 + : indexOf(seen, computed) < 0 ) { if (callback || isLarge) { seen.push(computed); @@ -3818,8 +4079,14 @@ result.push(value); } } + if (isLarge) { + releaseArray(seen.array); + releaseObject(seen); + } else if (callback) { + releaseArray(seen); + } return result; - } + }); /** * The inverse of `_.zip`, this method splits groups of elements into arrays @@ -3837,17 +4104,11 @@ */ function unzip(array) { var index = -1, - length = array ? array.length : 0, - tupleLength = length ? max(pluck(array, 'length')) : 0, - result = Array(tupleLength); + length = array ? max(pluck(array, 'length')) : 0, + result = Array(length < 0 ? 0 : length); while (++index < length) { - var tupleIndex = -1, - tuple = array[index]; - - while (++tupleIndex < tupleLength) { - (result[tupleIndex] || (result[tupleIndex] = Array(length)))[index] = tuple[tupleIndex]; - } + result[index] = pluck(array, index); } return result; } @@ -3888,14 +4149,7 @@ * // => [['moe', 30, true], ['larry', 40, false]] */ function zip(array) { - var index = -1, - length = array ? max(pluck(arguments, 'length')) : 0, - result = Array(length); - - while (++index < length) { - result[index] = pluck(arguments, index); - } - return result; + return array ? unzip(arguments) : []; } /** @@ -4171,27 +4425,27 @@ return result; }; } - if (typeof thisArg != 'undefined') { - if (argCount === 1) { - return function(value) { - return func.call(thisArg, value); - }; - } - if (argCount === 2) { - return function(a, b) { - return func.call(thisArg, a, b); - }; - } - if (argCount === 4) { - return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return function(value, index, collection) { - return func.call(thisArg, value, index, collection); + if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) { + return func; + } + if (argCount === 1) { + return function(value) { + return func.call(thisArg, value); + }; + } + if (argCount === 2) { + return function(a, b) { + return func.call(thisArg, a, b); }; } - return func; + if (argCount === 4) { + return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; } /** @@ -4212,6 +4466,7 @@ * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. * [leading=false] A boolean to specify execution on the leading edge of the timeout. + * [maxWait] The maximum time `func` is allowed to be delayed before it's called. * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example @@ -4226,34 +4481,80 @@ */ function debounce(func, wait, options) { var args, - inited, result, thisArg, - timeoutId, + callCount = 0, + lastCalled = 0, + maxWait = false, + maxTimeoutId = null, + timeoutId = null, trailing = true; + function clear() { + clearTimeout(maxTimeoutId); + clearTimeout(timeoutId); + callCount = 0; + maxTimeoutId = timeoutId = null; + } + function delayed() { - inited = timeoutId = null; - if (trailing) { + var isCalled = trailing && (!leading || callCount > 1); + clear(); + if (isCalled) { + if (maxWait !== false) { + lastCalled = new Date; + } result = func.apply(thisArg, args); } } + + function maxDelayed() { + clear(); + if (trailing || (maxWait !== wait)) { + lastCalled = new Date; + result = func.apply(thisArg, args); + } + } + + wait = nativeMax(0, wait || 0); if (options === true) { var leading = true; trailing = false; - } else if (options && objectTypes[typeof options]) { + } else if (isObject(options)) { leading = options.leading; + maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0); trailing = 'trailing' in options ? options.trailing : trailing; } return function() { args = arguments; thisArg = this; + callCount++; + + // avoid issues with Titanium and `undefined` timeout ids + // https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192 clearTimeout(timeoutId); - if (!inited && leading) { - inited = true; - result = func.apply(thisArg, args); + if (maxWait === false) { + if (leading && callCount < 2) { + result = func.apply(thisArg, args); + } } else { + var now = new Date; + if (!maxTimeoutId && !leading) { + lastCalled = now; + } + var remaining = maxWait - (now - lastCalled); + if (remaining <= 0) { + clearTimeout(maxTimeoutId); + maxTimeoutId = null; + lastCalled = now; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (wait !== maxWait) { timeoutId = setTimeout(delayed, wait); } return result; @@ -4311,7 +4612,8 @@ * passed, it will be used to determine the cache key for storing the result * based on the arguments passed to the memoized function. By default, the first * argument passed to the memoized function is used as the cache key. The `func` - * is executed with the `this` binding of the memoized function. + * is executed with the `this` binding of the memoized function. The result + * cache is exposed as the `cache` property on the memoized function. * * @static * @memberOf _ @@ -4326,13 +4628,16 @@ * }); */ function memoize(func, resolver) { - var cache = {}; - return function() { - var key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); + function memoized() { + var cache = memoized.cache, + key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); + return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); - }; + } + memoized.cache = {}; + return memoized; } /** @@ -4452,47 +4757,23 @@ * })); */ function throttle(func, wait, options) { - var args, - result, - thisArg, - timeoutId, - lastCalled = 0, - leading = true, + var leading = true, trailing = true; - function trailingCall() { - timeoutId = null; - if (trailing) { - lastCalled = new Date; - result = func.apply(thisArg, args); - } - } if (options === false) { leading = false; - } else if (options && objectTypes[typeof options]) { + } else if (isObject(options)) { leading = 'leading' in options ? options.leading : leading; trailing = 'trailing' in options ? options.trailing : trailing; } - return function() { - var now = new Date; - if (!timeoutId && !leading) { - lastCalled = now; - } - var remaining = wait - (now - lastCalled); - args = arguments; - thisArg = this; + options = getObject(); + options.leading = leading; + options.maxWait = wait; + options.trailing = trailing; - if (remaining <= 0) { - clearTimeout(timeoutId); - timeoutId = null; - lastCalled = now; - result = func.apply(thisArg, args); - } - else if (!timeoutId) { - timeoutId = setTimeout(trailingCall, remaining); - } - return result; - }; + var result = debounce(func, wait, options); + releaseObject(options); + return result; } /** @@ -4545,7 +4826,7 @@ } /** - * This function returns the first argument passed to it. + * This method returns the first argument passed to it. * * @static * @memberOf _ @@ -4594,7 +4875,7 @@ push.apply(args, arguments); var result = func.apply(lodash, args); - return (value && typeof value == 'object' && value == result) + return (value && typeof value == 'object' && value === result) ? this : new lodashWrapper(result); }; @@ -4668,8 +4949,13 @@ if (max == null) { max = min; min = 0; + } else { + max = +max || 0; } - return min + floor(nativeRandom() * ((+max || 0) - min + 1)); + var rand = nativeRandom(); + return (min % 1 || max % 1) + ? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max) + : min + floor(rand * (max - min + 1)); } /** @@ -5072,6 +5358,7 @@ lodash.throttle = throttle; lodash.times = times; lodash.toArray = toArray; + lodash.transform = transform; lodash.union = union; lodash.uniq = uniq; lodash.unzip = unzip; @@ -5096,6 +5383,10 @@ // add functions to `lodash.prototype` mixin(lodash); + // add Underscore compat + lodash.chain = lodash; + lodash.prototype.chain = function() { return this; }; + /*--------------------------------------------------------------------------*/ // add functions that return unwrapped values when chaining @@ -5147,6 +5438,7 @@ lodash.all = every; lodash.any = some; lodash.detect = find; + lodash.findWhere = find; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.include = contains; @@ -5192,7 +5484,7 @@ * @memberOf _ * @type String */ - lodash.VERSION = '1.2.1'; + lodash.VERSION = '1.3.0'; // add "Chaining" functions to the wrapper lodash.prototype.toString = wrapperToString; diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 3c4f07240c..90ffbe8a5c 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -1,44 +1,48 @@ /** * @license - * Lo-Dash 1.2.1 (Custom Build) lodash.com/license + * Lo-Dash 1.3.0 (Custom Build) lodash.com/license * Build: `lodash modern -o ./dist/lodash.js` * Underscore.js 1.4.4 underscorejs.org/LICENSE */ -;(function(n){function t(o){function f(n){if(!n||ue.call(n)!=A)return a;var t=n.valueOf,e=typeof t=="function"&&(e=Zt(t))&&Zt(e);return e?n==e||Zt(n)==e:Y(n)}function D(n,t,e){if(!n||!R[typeof n])return n;t=t&&typeof e=="undefined"?t:U.createCallback(t,e);for(var r=-1,u=R[typeof n]?be(n):[],o=u.length;++r=s;if(e)for(var r={},u=-1;++ut||typeof n=="undefined")return 1;if(ne?0:e);++re?le(0,u+e):e)||0,typeof u=="number"?o=-1<(ft(n)?n.indexOf(t,e):xt(n,t,e)):D(n,function(n){return++ru&&(u=o) -}}else t=!t&&ft(n)?G:U.createCallback(t,e),yt(n,function(n,e,a){e=t(n,e,a),e>r&&(r=e,u=n)});return u}function bt(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Rt(r);++earguments.length;t=U.createCallback(t,r,4);var o=-1,i=n.length;if(typeof i=="number")for(u&&(e=n[++o]);++oarguments.length; -if(typeof u!="number")var i=be(n),u=i.length;return t=U.createCallback(t,r,4),yt(n,function(r,f,c){f=i?i[--u]:--u,e=o?(o=a,n[f]):t(e,n[f],f,c)}),e}function kt(n,t,e){var r;t=U.createCallback(t,e),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++ee?le(0,u+e):e||0)-1;else if(e)return r=Et(n,t),n[r]===t?r:-1;for(;++r>>1,e(n[r])=s;if(l)var v={};for(e!=u&&(c=[],e=U.createCallback(e,r));++oxt(c,g))&&((e||l)&&c.push(g),f.push(r))}return f}function Nt(n,t){for(var e=-1,r=n?n.length:0,u={};++e/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:d,variable:"",imports:{_:U}},W.prototype=U.prototype;var me=oe,be=ce?function(n){return ot(n)?ce(n):[]}:M,de={"&":"&","<":"<",">":">",'"':""","'":"'"},_e=rt(de);return zt&&i&&typeof ee=="function"&&(At=St(ee,o)),Tt=8==se(_+"08")?se:function(n,t){return se(ft(n)?n.replace(k,""):n,t||0)},U.after=function(n,t){return 1>n?t():function(){return 1>--n?t.apply(this,arguments):void 0 -}},U.assign=K,U.at=function(n){for(var t=-1,e=Xt.apply(Gt,ge.call(arguments,1)),r=e.length,u=Rt(r);++t=s,i=[],f=i;n:for(;++uxt(f,c)){o&&f.push(c); -for(var v=e;--v;)if(!(r[v]||(r[v]=V(t[v])))(c))continue n;i.push(c)}}return i},U.invert=rt,U.invoke=function(n,t){var e=ge.call(arguments,2),r=-1,u=typeof t=="function",a=n?n.length:0,o=Rt(typeof a=="number"?a:0);return yt(n,function(n){o[++r]=(u?t:n[t]).apply(n,e)}),o},U.keys=be,U.map=ht,U.max=mt,U.memoize=function(n,t){var e={};return function(){var r=p+(t?t.apply(this,arguments):arguments[0]);return ne.call(e,r)?e[r]:e[r]=n.apply(this,arguments)}},U.merge=ct,U.min=function(n,t,e){var r=1/0,u=r; -if(!t&&me(n)){e=-1;for(var a=n.length;++ext(a,e))&&(u[e]=n)}),u},U.once=function(n){var t,e;return function(){return t?e:(t=r,e=n.apply(this,arguments),n=u,e)}},U.pairs=function(n){for(var t=-1,e=be(n),r=e.length,u=Rt(r);++te?le(0,r+e):pe(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},U.mixin=Bt,U.noConflict=function(){return o._=Jt,this},U.parseInt=Tt,U.random=function(n,t){return n==u&&t==u&&(t=1),n=+n||0,t==u&&(t=n,n=0),n+Yt(ve()*((+t||0)-n+1))},U.reduce=dt,U.reduceRight=_t,U.result=function(n,t){var r=n?n[t]:e;return at(r)?n[t]():r},U.runInContext=t,U.size=function(n){var t=n?n.length:0; -return typeof t=="number"?t:be(n).length},U.some=kt,U.sortedIndex=Et,U.template=function(n,t,u){var a=U.templateSettings;n||(n=""),u=P({},u,a);var o,i=P({},u.imports,a.imports),a=be(i),i=lt(i),f=0,c=u.interpolate||w,l="__p+='",c=Mt((u.escape||w).source+"|"+c.source+"|"+(c===d?m:w).source+"|"+(u.evaluate||w).source+"|$","g");n.replace(c,function(t,e,u,a,i,c){return u||(u=a),l+=n.slice(f,c).replace(C,L),e&&(l+="'+__e("+e+")+'"),i&&(o=r,l+="';"+i+";__p+='"),u&&(l+="'+((__t=("+u+"))==null?'':__t)+'"),f=c+t.length,t -}),l+="';\n",c=u=u.variable,c||(u="obj",l="with("+u+"){"+l+"}"),l=(o?l.replace(v,""):l).replace(g,"$1").replace(y,"$1;"),l="function("+u+"){"+(c?"":u+"||("+u+"={});")+"var __t,__p='',__e=_.escape"+(o?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}";try{var p=Dt(a,"return "+l).apply(e,i)}catch(s){throw s.source=l,s}return t?p(t):(p.source=l,p)},U.unescape=function(n){return n==u?"":Ut(n).replace(h,nt)},U.uniqueId=function(n){var t=++c;return Ut(n==u?"":n)+t -},U.all=st,U.any=kt,U.detect=gt,U.foldl=dt,U.foldr=_t,U.include=pt,U.inject=dt,D(U,function(n,t){U.prototype[t]||(U.prototype[t]=function(){var t=[this.__wrapped__];return te.apply(t,arguments),n.apply(U,t)})}),U.first=jt,U.last=function(n,t,e){if(n){var r=0,a=n.length;if(typeof t!="number"&&t!=u){var o=a;for(t=U.createCallback(t,e);o--&&t(n[o],o,n);)r++}else if(r=t,r==u||e)return n[a-1];return Z(n,le(0,a-r))}},U.take=jt,U.head=jt,D(U,function(n,t){U.prototype[t]||(U.prototype[t]=function(t,e){var r=n(this.__wrapped__,t,e); -return t==u||e&&typeof t!="function"?r:new W(r)})}),U.VERSION="1.2.1",U.prototype.toString=function(){return Ut(this.__wrapped__)},U.prototype.value=Ft,U.prototype.valueOf=Ft,yt(["join","pop","shift"],function(n){var t=Gt[n];U.prototype[n]=function(){return t.apply(this.__wrapped__,arguments)}}),yt(["push","reverse","sort","unshift"],function(n){var t=Gt[n];U.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),yt(["concat","slice","splice"],function(n){var t=Gt[n];U.prototype[n]=function(){return new W(t.apply(this.__wrapped__,arguments)) -}}),U}var e,r=!0,u=null,a=!1,o=typeof exports=="object"&&exports,i=typeof module=="object"&&module&&module.exports==o&&module,f=typeof global=="object"&&global;(f.global===f||f.window===f)&&(n=f);var c=0,l={},p=+new Date+"",s=200,v=/\b__p\+='';/g,g=/\b(__p\+=)''\+/g,y=/(__e\(.*?\)|\b__t\))\+'';/g,h=/&(?:amp|lt|gt|quot|#39);/g,m=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,b=/\w*$/,d=/<%=([\s\S]+?)%>/g,_=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",k=RegExp("^["+_+"]*0+(?=.$)"),w=/($^)/,j=/[&<>"']/g,C=/['\n\r\t\u2028\u2029\\]/g,x="Array Boolean Date Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),O="[object Arguments]",E="[object Array]",I="[object Boolean]",N="[object Date]",S="[object Number]",A="[object Object]",$="[object RegExp]",B="[object String]",F={"[object Function]":a}; -F[O]=F[E]=F[I]=F[N]=F[S]=F[A]=F[$]=F[B]=r;var R={"boolean":a,"function":r,object:r,number:a,string:a,undefined:a},T={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},q=t();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(n._=q,define(function(){return q})):o&&!o.nodeType?i?(i.exports=q)._=q:o._=q:n._=q})(this); \ No newline at end of file +;!function(n){function t(n,t,e){e=(e||0)-1;for(var r=n.length;++et||typeof n=="undefined")return 1;if(ne?0:e);++re?_e(0,a+e):e)||0,a&&typeof a=="number"?o=-1<(yt(n)?n.indexOf(t,e):u(n,t,e)):d(n,function(n){return++ra&&(a=i) +}}else t=!t&&yt(n)?u:tt.createCallback(t,e),wt(n,function(n,e,u){e=t(n,e,u),e>r&&(r=e,a=n)});return a}function Ot(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Mt(r);++earguments.length;t=tt.createCallback(t,r,4);var a=-1,o=n.length;if(typeof o=="number")for(u&&(e=n[++a]);++aarguments.length; +if(typeof u!="number")var o=Se(n),u=o.length;return t=tt.createCallback(t,r,4),wt(n,function(r,i,f){i=o?o[--u]:--u,e=a?(a=b,n[i]):t(e,n[i],i,f)}),e}function It(n,t,e){var r;t=tt.createCallback(t,e),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e=w&&u===t;if(l){var c=o(i);c?(u=e,i=c):l=b}for(;++ru(i,c)&&f.push(c); +return l&&p(i),f}function Nt(n,t,e){if(n){var r=0,u=n.length;if(typeof t!="number"&&t!=y){var a=-1;for(t=tt.createCallback(t,e);++ar?_e(0,u+r):r||0}else if(r)return r=Ft(n,e),n[r]===e?r:-1;return n?t(n,e,r):-1}function Bt(n,t,e){if(typeof t!="number"&&t!=y){var r=0,u=-1,a=n?n.length:0;for(t=tt.createCallback(t,e);++u>>1,e(n[r])e?0:e);++tl&&(i=n.apply(f,o));else{var e=new Vt;!s&&!m&&(c=e);var r=p-(e-c);0/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:tt}};var Ee=ye,Se=de?function(n){return gt(n)?de(n):[]}:Z,Ie={"&":"&","<":"<",">":">",'"':""","'":"'"},Ae=pt(Ie),Ut=ot(function $e(n,t,e){for(var r=-1,u=n?n.length:0,a=[];++r=w&&i===t,g=u||v?f():s;if(v){var h=o(g);h?(i=e,g=h):(v=b,g=u?g:(c(g),s))}for(;++ai(g,y))&&((u||v)&&g.push(y),s.push(h))}return v?(c(g.b),p(g)):u&&c(g),s});return Ht&&Y&&typeof pe=="function"&&(zt=qt(pe,r)),pe=8==je(B+"08")?je:function(n,t){return je(yt(n)?n.replace(F,""):n,t||0)},tt.after=function(n,t){return 1>n?t():function(){return 1>--n?t.apply(this,arguments):void 0 +}},tt.assign=X,tt.at=function(n){for(var t=-1,e=ae.apply(Zt,Ce.call(arguments,1)),r=e.length,u=Mt(r);++t=w&&o(a?r[a]:h)}n:for(;++l(b?e(b,y):s(h,y))){for(a=u,(b||h).push(y);--a;)if(b=i[a],0>(b?e(b,y):s(r[a],y)))continue n;g.push(y)}}for(;u--;)(b=i[u])&&p(b);return c(i),c(h),g +},tt.invert=pt,tt.invoke=function(n,t){var e=Ce.call(arguments,2),r=-1,u=typeof t=="function",a=n?n.length:0,o=Mt(typeof a=="number"?a:0);return wt(n,function(n){o[++r]=(u?t:n[t]).apply(n,e)}),o},tt.keys=Se,tt.map=Ct,tt.max=xt,tt.memoize=function(n,t){function e(){var r=e.cache,u=j+(t?t.apply(this,arguments):arguments[0]);return le.call(r,u)?r[u]:r[u]=n.apply(this,arguments)}return e.cache={},e},tt.merge=bt,tt.min=function(n,t,e){var r=1/0,a=r;if(!t&&Ee(n)){e=-1;for(var o=n.length;++er(o,e))&&(a[e]=n)}),a},tt.once=function(n){var t,e;return function(){return t?e:(t=h,e=n.apply(this,arguments),n=y,e)}},tt.pairs=function(n){for(var t=-1,e=Se(n),r=e.length,u=Mt(r);++te?_e(0,r+e):ke(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},tt.mixin=Pt,tt.noConflict=function(){return r._=te,this},tt.parseInt=pe,tt.random=function(n,t){n==y&&t==y&&(t=1),n=+n||0,t==y?(t=n,n=0):t=+t||0; +var e=we();return n%1||t%1?n+ke(e*(t-n+parseFloat("1e-"+((e+"").length-1))),t):n+oe(e*(t-n+1))},tt.reduce=Et,tt.reduceRight=St,tt.result=function(n,t){var e=n?n[t]:g;return vt(e)?n[t]():e},tt.runInContext=v,tt.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Se(n).length},tt.some=It,tt.sortedIndex=Ft,tt.template=function(n,t,e){var r=tt.templateSettings;n||(n=""),e=Q({},e,r);var u,a=Q({},e.imports,r.imports),r=Se(a),a=mt(a),o=0,f=e.interpolate||R,l="__p+='",f=Qt((e.escape||R).source+"|"+f.source+"|"+(f===N?I:R).source+"|"+(e.evaluate||R).source+"|$","g"); +n.replace(f,function(t,e,r,a,f,c){return r||(r=a),l+=n.slice(o,c).replace(q,i),e&&(l+="'+__e("+e+")+'"),f&&(u=h,l+="';"+f+";__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'"),o=c+t.length,t}),l+="';\n",f=e=e.variable,f||(e="obj",l="with("+e+"){"+l+"}"),l=(u?l.replace(x,""):l).replace(O,"$1").replace(E,"$1;"),l="function("+e+"){"+(f?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}";try{var c=Gt(r,"return "+l).apply(g,a) +}catch(p){throw p.source=l,p}return t?c(t):(c.source=l,c)},tt.unescape=function(n){return n==y?"":Xt(n).replace(S,ft)},tt.uniqueId=function(n){var t=++_;return Xt(n==y?"":n)+t},tt.all=_t,tt.any=It,tt.detect=jt,tt.findWhere=jt,tt.foldl=Et,tt.foldr=St,tt.include=dt,tt.inject=Et,d(tt,function(n,t){tt.prototype[t]||(tt.prototype[t]=function(){var t=[this.__wrapped__];return ce.apply(t,arguments),n.apply(tt,t)})}),tt.first=Nt,tt.last=function(n,t,e){if(n){var r=0,u=n.length;if(typeof t!="number"&&t!=y){var a=u; +for(t=tt.createCallback(t,e);a--&&t(n[a],a,n);)r++}else if(r=t,r==y||e)return n[u-1];return s(n,_e(0,u-r))}},tt.take=Nt,tt.head=Nt,d(tt,function(n,t){tt.prototype[t]||(tt.prototype[t]=function(t,e){var r=n(this.__wrapped__,t,e);return t==y||e&&typeof t!="function"?r:new et(r)})}),tt.VERSION="1.3.0",tt.prototype.toString=function(){return Xt(this.__wrapped__)},tt.prototype.value=Kt,tt.prototype.valueOf=Kt,wt(["join","pop","shift"],function(n){var t=Zt[n];tt.prototype[n]=function(){return t.apply(this.__wrapped__,arguments) +}}),wt(["push","reverse","sort","unshift"],function(n){var t=Zt[n];tt.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),wt(["concat","slice","splice"],function(n){var t=Zt[n];tt.prototype[n]=function(){return new et(t.apply(this.__wrapped__,arguments))}}),tt}var g,h=!0,y=null,b=!1,m=[],d=[],_=0,k={},j=+new Date+"",w=75,C=10,x=/\b__p\+='';/g,O=/\b(__p\+=)''\+/g,E=/(__e\(.*?\)|\b__t\))\+'';/g,S=/&(?:amp|lt|gt|quot|#39);/g,I=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,A=/\w*$/,N=/<%=([\s\S]+?)%>/g,$=($=/\bthis\b/)&&$.test(v)&&$,B=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",F=RegExp("^["+B+"]*0+(?=.$)"),R=/($^)/,T=/[&<>"']/g,q=/['\n\r\t\u2028\u2029\\]/g,D="Array Boolean Date Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),z="[object Arguments]",W="[object Array]",P="[object Boolean]",K="[object Date]",M="[object Function]",U="[object Number]",V="[object Object]",G="[object RegExp]",H="[object String]",J={}; +J[M]=b,J[z]=J[W]=J[P]=J[K]=J[U]=J[V]=J[G]=J[H]=h;var L={"boolean":b,"function":h,object:h,number:b,string:b,undefined:b},Q={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},X=L[typeof exports]&&exports,Y=L[typeof module]&&module&&module.exports==X&&module,Z=L[typeof global]&&global;!Z||Z.global!==Z&&Z.window!==Z||(n=Z);var nt=v();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(n._=nt, define(function(){return nt})):X&&!X.nodeType?Y?(Y.exports=nt)._=nt:X._=nt:n._=nt +}(this); \ No newline at end of file diff --git a/dist/lodash.underscore.js b/dist/lodash.underscore.js index 8f0b17d5b6..31f74237cb 100644 --- a/dist/lodash.underscore.js +++ b/dist/lodash.underscore.js @@ -1,6 +1,6 @@ /** * @license - * Lo-Dash 1.2.1 (Custom Build) + * Lo-Dash 1.3.0 (Custom Build) * Build: `lodash underscore exports="amd,commonjs,global,node" -o ./dist/lodash.underscore.js` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.4.4 @@ -12,18 +12,6 @@ /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports; - - /** Detect free variable `module` */ - var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; - - /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - window = freeGlobal; - } - /** Used to generate unique IDs */ var idCounter = 0; @@ -34,7 +22,7 @@ var keyPrefix = +new Date + ''; /** Used as the size when optimizations are enabled for large arrays */ - var largeArraySize = 200; + var largeArraySize = 75; /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, @@ -73,6 +61,7 @@ arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', + errorClass = '[object Error]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', @@ -100,18 +89,112 @@ '\u2029': 'u2029' }; + /** Detect free variable `exports` */ + var freeExports = objectTypes[typeof exports] && exports; + + /** Detect free variable `module` */ + var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module; + + /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ + var freeGlobal = objectTypes[typeof global] && global; + if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { + window = freeGlobal; + } + /*--------------------------------------------------------------------------*/ - /** Used for `Array` and `Object` method references */ - var arrayRef = Array(), - objectRef = Object(); + /** + * A basic implementation of `_.indexOf` without support for binary searches + * or `fromIndex` constraints. + * + * @private + * @param {Array} array The array to search. + * @param {Mixed} value The value to search for. + * @param {Number} [fromIndex=0] The index to search from. + * @returns {Number} Returns the index of the matched value or `-1`. + */ + function basicIndexOf(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * Used by `sortBy` to compare transformed `collection` values, stable sorting + * them in ascending order. + * + * @private + * @param {Object} a The object to compare to `b`. + * @param {Object} b The object to compare to `a`. + * @returns {Number} Returns the sort order indicator of `1` or `-1`. + */ + function compareAscending(a, b) { + var ai = a.index, + bi = b.index; + + a = a.criteria; + b = b.criteria; + + // ensure a stable sort in V8 and other engines + // http://code.google.com/p/v8/issues/detail?id=90 + if (a !== b) { + if (a > b || typeof a == 'undefined') { + return 1; + } + if (a < b || typeof b == 'undefined') { + return -1; + } + } + return ai < bi ? -1 : 1; + } + + /** + * Used by `template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {String} match The matched character to escape. + * @returns {String} Returns the escaped character. + */ + function escapeStringChar(match) { + return '\\' + stringEscapes[match]; + } + + /** + * A no-operation function. + * + * @private + */ + function noop() { + // no operation performed + } + + /*--------------------------------------------------------------------------*/ + + /** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ + var arrayRef = []; + + /** Used for native method references */ + var objectProto = Object.prototype, + stringProto = String.prototype; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = window._; /** Used to detect if a method is native */ var reNative = RegExp('^' + - String(objectRef.valueOf) + String(objectProto.valueOf) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); @@ -121,13 +204,15 @@ clearTimeout = window.clearTimeout, concat = arrayRef.concat, floor = Math.floor, - hasOwnProperty = objectRef.hasOwnProperty, + hasOwnProperty = objectProto.hasOwnProperty, push = arrayRef.push, + propertyIsEnumerable = objectProto.propertyIsEnumerable, setTimeout = window.setTimeout, - toString = objectRef.toString; + toString = objectProto.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, + nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = window.isFinite, nativeIsNaN = window.isNaN, @@ -162,8 +247,8 @@ * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, * `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, - * `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `unshift`, `unzip`, - * `values`, `where`, `without`, `wrap`, and `zip` + * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, + * `unzip`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, @@ -179,6 +264,7 @@ * * @name _ * @constructor + * @alias chain * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. @@ -209,6 +295,19 @@ : new lodashWrapper(value); } + /** + * A fast path for creating `lodash` wrapper objects. + * + * @private + * @param {Mixed} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + */ + function lodashWrapper(value) { + this.__wrapped__ = value; + } + // ensure `new lodashWrapper` is an instance of `lodash` + lodashWrapper.prototype = lodash.prototype; + /** * An object used to flag environments features. * @@ -290,47 +389,6 @@ /*--------------------------------------------------------------------------*/ - /** - * Used by `_.max` and `_.min` as the default `callback` when a given - * `collection` is a string value. - * - * @private - * @param {String} value The character to inspect. - * @returns {Number} Returns the code unit of given character. - */ - function charAtCallback(value) { - return value.charCodeAt(0); - } - - /** - * Used by `sortBy` to compare transformed `collection` values, stable sorting - * them in ascending order. - * - * @private - * @param {Object} a The object to compare to `b`. - * @param {Object} b The object to compare to `a`. - * @returns {Number} Returns the sort order indicator of `1` or `-1`. - */ - function compareAscending(a, b) { - var ai = a.index, - bi = b.index; - - a = a.criteria; - b = b.criteria; - - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (a !== b) { - if (a > b || typeof a == 'undefined') { - return 1; - } - if (a < b || typeof b == 'undefined') { - return -1; - } - } - return ai < bi ? -1 : 1; - } - /** * Creates a function that, when called, invokes `func` with the `this` binding * of `thisArg` and prepends any `partialArgs` to the arguments passed to the @@ -377,9 +435,7 @@ } if (this instanceof bound) { // ensure `new bound` is an instance of `func` - noop.prototype = func.prototype; - thisBinding = new noop; - noop.prototype = null; + thisBinding = createObject(func.prototype); // mimic the constructor's `return` behavior // http://es5.github.com/#x13.2.2 @@ -392,15 +448,25 @@ } /** - * Used by `template` to escape characters for inclusion in compiled - * string literals. + * Creates a new object with the specified `prototype`. * * @private - * @param {String} match The matched character to escape. - * @returns {String} Returns the escaped character. + * @param {Object} prototype The prototype object. + * @returns {Object} Returns the new object. */ - function escapeStringChar(match) { - return '\\' + stringEscapes[match]; + function createObject(prototype) { + return isObject(prototype) ? nativeCreate(prototype) : {}; + } + // fallback for browsers without `Object.create` + if (!nativeCreate) { + var createObject = function(prototype) { + if (isObject(prototype)) { + noop.prototype = prototype; + var result = new noop; + noop.prototype = null; + } + return result || {}; + }; } /** @@ -415,25 +481,16 @@ } /** - * A fast path for creating `lodash` wrapper objects. + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized, this method returns the custom method, otherwise it returns + * the `basicIndexOf` function. * * @private - * @param {Mixed} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns a `lodash` instance. + * @returns {Function} Returns the "indexOf" function. */ - function lodashWrapper(value) { - this.__wrapped__ = value; - } - // ensure `new lodashWrapper` is an instance of `lodash` - lodashWrapper.prototype = lodash.prototype; - - /** - * A no-operation function. - * - * @private - */ - function noop() { - // no operation performed + function getIndexOf(array, value, fromIndex) { + var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result; + return result; } /** @@ -507,11 +564,10 @@ var shimKeys = function (object) { var index, iterable = object, result = []; if (!iterable) return result; - if (!(objectTypes[typeof object])) return result; - + if (!(objectTypes[typeof object])) return result; for (index in iterable) { - if (hasOwnProperty.call(iterable, index)) { - result.push(index); + if (hasOwnProperty.call(iterable, index)) { + result.push(index); } } return result @@ -721,7 +777,6 @@ var index, iterable = collection, result = iterable; if (!iterable) return result; if (!objectTypes[typeof iterable]) return result; - for (index in iterable) { if (callback(iterable[index], index, collection) === indicatorObject) return result; } @@ -753,10 +808,9 @@ var index, iterable = collection, result = iterable; if (!iterable) return result; if (!objectTypes[typeof iterable]) return result; - for (index in iterable) { - if (hasOwnProperty.call(iterable, index)) { - if (callback(iterable[index], index, collection) === indicatorObject) return result; + if (hasOwnProperty.call(iterable, index)) { + if (callback(iterable[index], index, collection) === indicatorObject) return result; } } return result @@ -1137,7 +1191,7 @@ // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 - return value ? objectTypes[typeof value] : false; + return !!(value && objectTypes[typeof value]); } /** @@ -1222,7 +1276,7 @@ * // => true */ function isRegExp(value) { - return value ? (objectTypes[typeof value] && toString.call(value) == regexpClass) : false; + return !!(value && objectTypes[typeof value]) && toString.call(value) == regexpClass; } /** @@ -1286,7 +1340,8 @@ * // => { 'name': 'moe' } */ function omit(object) { - var props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), + var indexOf = getIndexOf(), + props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), result = {}; forIn(object, function(value, key) { @@ -1419,9 +1474,10 @@ * // => true */ function contains(collection, target) { - var length = collection ? collection.length : 0, + var indexOf = getIndexOf(), + length = collection ? collection.length : 0, result = false; - if (typeof length == 'number') { + if (length && typeof length == 'number') { result = indexOf(collection, target) > -1; } else { forOwn(collection, function(value) { @@ -1615,7 +1671,7 @@ * * @static * @memberOf _ - * @alias detect + * @alias detect, findWhere * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per @@ -2450,6 +2506,7 @@ */ function difference(array) { var index = -1, + indexOf = getIndexOf(), length = array.length, flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), result = []; @@ -2623,21 +2680,14 @@ * // => 2 */ function indexOf(array, value, fromIndex) { - var index = -1, - length = array ? array.length : 0; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; + var length = array ? array.length : 0; + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); } else if (fromIndex) { - index = sortedIndex(array, value); + var index = sortedIndex(array, value); return array[index] === value ? index : -1; } - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; + return array ? basicIndexOf(array, value, fromIndex) : -1; } /** @@ -2734,6 +2784,7 @@ var args = arguments, argsLength = args.length, index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, result = []; @@ -3078,7 +3129,7 @@ * Creates a duplicate-value-free version of the `array` using strict equality * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` * for `isSorted` will run a faster algorithm. If `callback` is passed, each - * element of `array` is passed through a `callback` before uniqueness is computed. + * element of `array` is passed through the `callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style @@ -3107,11 +3158,11 @@ * _.uniq([1, 1, 2, 2, 3], true); * // => [1, 2, 3] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); - * // => [1, 2, 3] + * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); + * // => ['A', 'b', 'C'] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); - * // => [1, 2, 3] + * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); + * // => [1, 2.5, 3] * * // using "_.pluck" callback shorthand * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); @@ -3119,6 +3170,7 @@ */ function uniq(array, isSorted, callback, thisArg) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, result = [], seen = result; @@ -3149,6 +3201,31 @@ return result; } + /** + * The inverse of `_.zip`, this method splits groups of elements into arrays + * composed of elements from each group at their corresponding indexes. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to process. + * @returns {Array} Returns a new array of the composed arrays. + * @example + * + * _.unzip([['moe', 30, true], ['larry', 40, false]]); + * // => [['moe', 'larry'], [30, 40], [true, false]]; + */ + function unzip(array) { + var index = -1, + length = array ? max(pluck(array, 'length')) : 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = pluck(array, index); + } + return result; + } + /** * Creates an array with all occurrences of the passed values removed using * strict equality for comparisons, i.e. `===`. @@ -3187,7 +3264,7 @@ function zip(array) { var index = -1, length = array ? max(pluck(arguments, 'length')) : 0, - result = Array(length); + result = Array(length < 0 ? 0 : length); while (++index < length) { result[index] = pluck(arguments, index); @@ -3430,27 +3507,27 @@ return result; }; } - if (typeof thisArg != 'undefined') { - if (argCount === 1) { - return function(value) { - return func.call(thisArg, value); - }; - } - if (argCount === 2) { - return function(a, b) { - return func.call(thisArg, a, b); - }; - } - if (argCount === 4) { - return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return function(value, index, collection) { - return func.call(thisArg, value, index, collection); + if (typeof thisArg == 'undefined') { + return func; + } + if (argCount === 1) { + return function(value) { + return func.call(thisArg, value); }; } - return func; + if (argCount === 2) { + return function(a, b) { + return func.call(thisArg, a, b); + }; + } + if (argCount === 4) { + return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; } /** @@ -3471,6 +3548,7 @@ * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. * [leading=false] A boolean to specify execution on the leading edge of the timeout. + * [maxWait] The maximum time `func` is allowed to be delayed before it's called. * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example @@ -3487,7 +3565,7 @@ var args, result, thisArg, - timeoutId; + timeoutId = null; function delayed() { timeoutId = null; @@ -3557,7 +3635,8 @@ * passed, it will be used to determine the cache key for storing the result * based on the arguments passed to the memoized function. By default, the first * argument passed to the memoized function is used as the cache key. The `func` - * is executed with the `this` binding of the memoized function. + * is executed with the `this` binding of the memoized function. The result + * cache is exposed as the `cache` property on the memoized function. * * @static * @memberOf _ @@ -3670,8 +3749,8 @@ var args, result, thisArg, - timeoutId, - lastCalled = 0; + lastCalled = 0, + timeoutId = null; function trailingCall() { lastCalled = new Date; @@ -3748,7 +3827,7 @@ } /** - * This function returns the first argument passed to it. + * This method returns the first argument passed to it. * * @static * @memberOf _ @@ -3848,8 +3927,13 @@ if (max == null) { max = min; min = 0; + } else { + max = +max || 0; } - return min + floor(nativeRandom() * ((+max || 0) - min + 1)); + var rand = nativeRandom(); + return (min % 1 || max % 1) + ? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max) + : min + floor(rand * (max - min + 1)); } /** @@ -3964,8 +4048,9 @@ * '); */ function template(text, data, options) { + var settings = lodash.templateSettings; text || (text = ''); - options = defaults({}, options, lodash.templateSettings); + options = defaults({}, options, settings); var index = 0, source = "__p += '", @@ -4260,6 +4345,9 @@ lodash.tail = rest; lodash.unique = uniq; + // add Underscore compat + lodash.chain = chain; + /*--------------------------------------------------------------------------*/ // add functions that return unwrapped values when chaining @@ -4268,7 +4356,6 @@ lodash.escape = escape; lodash.every = every; lodash.find = find; - lodash.findWhere = findWhere; lodash.has = has; lodash.identity = identity; lodash.indexOf = indexOf; @@ -4306,6 +4393,7 @@ lodash.all = every; lodash.any = some; lodash.detect = find; + lodash.findWhere = findWhere; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.include = contains; @@ -4323,8 +4411,6 @@ /*--------------------------------------------------------------------------*/ - lodash.chain = chain; - /** * The semantic version number. * @@ -4332,7 +4418,7 @@ * @memberOf _ * @type String */ - lodash.VERSION = '1.2.1'; + lodash.VERSION = '1.3.0'; // add functions to `lodash.prototype` mixin(lodash); diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index 57eaeee95b..2cd3559627 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -1,35 +1,35 @@ /** * @license - * Lo-Dash 1.2.1 (Custom Build) lodash.com/license + * Lo-Dash 1.3.0 (Custom Build) lodash.com/license * Build: `lodash underscore exports="amd,commonjs,global,node" -o ./dist/lodash.underscore.js` * Underscore.js 1.4.4 underscorejs.org/LICENSE */ -;(function(n){function t(n){return n instanceof t?n:new i(n)}function r(n,t){var r=n.b,e=t.b;if(n=n.a,t=t.a,n!==t){if(n>t||typeof n=="undefined")return 1;if(ne&&(e=r,u=n)});else for(;++ou&&(u=r);return u}function N(n,t){var r=-1,e=n?n.length:0; -if(typeof e=="number")for(var u=Array(e);++rarguments.length;t=P(t,e,4);var o=-1,i=n.length;if(typeof i=="number")for(u&&(r=n[++o]);++oarguments.length;if(typeof u!="number")var i=Rt(n),u=i.length;return t=P(t,e,4),E(n,function(e,a,f){a=i?i[--u]:--u,r=o?(o=!1,n[a]):t(r,n[a],a,f)}),r}function q(n,t,r){var e; -t=P(t,r),r=-1;var u=n?n.length:0;if(typeof u=="number")for(;++rT(e,o)&&u.push(o)}return u}function D(n,t,r){if(n){var e=0,u=n.length;if(typeof t!="number"&&null!=t){var o=-1;for(t=P(t,r);++or?Ot(0,u+r):r||0)-1;else if(r)return e=I(n,t),n[e]===t?e:-1;for(;++e>>1,r(n[e])T(a,f))&&(r&&a.push(f),i.push(e))}return i}function C(n,t){return qt.fastBind||jt&&2"']/g,Z=/['\n\r\t\u2028\u2029\\]/g,nt="[object Arguments]",tt="[object Array]",rt="[object Boolean]",et="[object Date]",ut="[object Number]",ot="[object Object]",it="[object RegExp]",at="[object String]",ft={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},lt={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},ct=[],H={},pt=n._,st=RegExp("^"+(H.valueOf+"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),vt=Math.ceil,gt=n.clearTimeout,ht=ct.concat,yt=Math.floor,mt=H.hasOwnProperty,_t=ct.push,bt=n.setTimeout,dt=H.toString,jt=st.test(jt=dt.bind)&&jt,wt=st.test(wt=Array.isArray)&&wt,At=n.isFinite,xt=n.isNaN,Et=st.test(Et=Object.keys)&&Et,Ot=Math.max,St=Math.min,Nt=Math.random,Bt=ct.slice,H=st.test(n.attachEvent),kt=jt&&!/\n|true/.test(jt+H),qt={}; -(function(){var n={0:1,length:1};qt.fastBind=jt&&!kt,qt.spliceObjects=(ct.splice.call(n,0,1),!n[0])})(1),t.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""},i.prototype=t.prototype,l(arguments)||(l=function(n){return n?mt.call(n,"callee"):!1});var Ft=wt||function(n){return n?typeof n=="object"&&dt.call(n)==tt:!1},wt=function(n){var t,r=[];if(!n||!ft[typeof n])return r;for(t in n)mt.call(n,t)&&r.push(t);return r},Rt=Et?function(n){return m(n)?Et(n):[] -}:wt,Dt={"&":"&","<":"<",">":">",'"':""","'":"'"},Mt=v(Dt),Tt=function(n,t){var r;if(!n||!ft[typeof n])return n;for(r in n)if(t(n[r],r,n)===K)break;return n},$t=function(n,t){var r;if(!n||!ft[typeof n])return n;for(r in n)if(mt.call(n,r)&&t(n[r],r,n)===K)break;return n};y(/x/)&&(y=function(n){return typeof n=="function"&&"[object Function]"==dt.call(n)}),t.after=function(n,t){return 1>n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},t.bind=C,t.bindAll=function(n){for(var t=1T(o,i)){for(var a=r;--a;)if(0>T(t[a],i))continue n;o.push(i)}}return o},t.invert=v,t.invoke=function(n,t){var r=Bt.call(arguments,2),e=-1,u=typeof t=="function",o=n?n.length:0,i=Array(typeof o=="number"?o:0);return E(n,function(n){i[++e]=(u?t:n[t]).apply(n,r)}),i},t.keys=Rt,t.map=O,t.max=S,t.memoize=function(n,t){var r={};return function(){var e=L+(t?t.apply(this,arguments):arguments[0]); -return mt.call(r,e)?r[e]:r[e]=n.apply(this,arguments)}},t.min=function(n,t,r){var e=1/0,u=e,o=-1,i=n?n.length:0;if(t||typeof i!="number")t=P(t,r),E(n,function(n,r,o){r=t(n,r,o),rT(t,e)&&(r[e]=n)}),r},t.once=function(n){var t,r;return function(){return t?r:(t=!0,r=n.apply(this,arguments),n=null,r)}},t.pairs=function(n){for(var t=-1,r=Rt(n),e=r.length,u=Array(e);++tr?Ot(0,e+r):St(r,e-1))+1);e--;)if(n[e]===t)return e;return-1},t.mixin=V,t.noConflict=function(){return n._=pt,this},t.random=function(n,t){return null==n&&null==t&&(t=1),n=+n||0,null==t&&(t=n,n=0),n+yt(Nt()*((+t||0)-n+1))},t.reduce=B,t.reduceRight=k,t.result=function(n,t){var r=n?n[t]:null;return y(r)?n[t]():r},t.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Rt(n).length},t.some=q,t.sortedIndex=I,t.template=function(n,r,e){n||(n=""),e=p({},e,t.templateSettings); -var o=0,i="__p+='",a=e.variable;n.replace(RegExp((e.escape||X).source+"|"+(e.interpolate||X).source+"|"+(e.evaluate||X).source+"|$","g"),function(t,r,e,a,f){return i+=n.slice(o,f).replace(Z,u),r&&(i+="'+_['escape']("+r+")+'"),a&&(i+="';"+a+";__p+='"),e&&(i+="'+((__t=("+e+"))==null?'':__t)+'"),o=f+t.length,t}),i+="';\n",a||(a="obj",i="with("+a+"||{}){"+i+"}"),i="function("+a+"){var __t,__p='',__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+i+"return __p}";try{var f=Function("_","return "+i)(t) -}catch(l){throw l.source=i,l}return r?f(r):(f.source=i,f)},t.unescape=function(n){return null==n?"":(n+"").replace(Q,f)},t.uniqueId=function(n){var t=++J+"";return n?n+t:t},t.all=w,t.any=q,t.detect=x,t.foldl=B,t.foldr=k,t.include=j,t.inject=B,t.first=D,t.last=function(n,t,r){if(n){var e=0,u=n.length;if(typeof t!="number"&&null!=t){var o=u;for(t=P(t,r);o--&&t(n[o],o,n);)e++}else if(e=t,null==e||r)return n[u-1];return Bt.call(n,Ot(0,u-e))}},t.take=D,t.head=D,t.chain=function(n){return n=new i(n),n.__chain__=!0,n -},t.VERSION="1.2.1",V(t),t.prototype.chain=function(){return this.__chain__=!0,this},t.prototype.value=function(){return this.__wrapped__},E("pop push reverse shift sort splice unshift".split(" "),function(n){var r=ct[n];t.prototype[n]=function(){var n=this.__wrapped__;return r.apply(n,arguments),!qt.spliceObjects&&0===n.length&&delete n[0],this}}),E(["concat","join","slice"],function(n){var r=ct[n];t.prototype[n]=function(){var n=r.apply(this.__wrapped__,arguments);return this.__chain__&&(n=new i(n),n.__chain__=!0),n -}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(n._=t,define(function(){return t})):W&&!W.nodeType?G?(G.exports=t)._=t:W._=t:n._=t})(this); \ No newline at end of file +;!function(n){function t(n,t){var r;if(n&>[typeof n])for(r in n)if(Et.call(n,r)&&t(n[r],r,n)===nt)break}function r(n,t){var r;if(n&>[typeof n])for(r in n)if(t(n[r],r,n)===nt)break}function e(n){var t,r=[];if(!n||!gt[typeof n])return r;for(t in n)Et.call(n,t)&&r.push(t);return r}function u(n,t,r){r=(r||0)-1;for(var e=n.length;++rt||typeof n=="undefined")return 1;if(ne&&(e=r,u=n)});else for(;++ou&&(u=r);return u}function D(n,t){var r=-1,e=n?n.length:0;if(typeof e=="number")for(var u=Array(e);++rarguments.length;r=J(r,u,4);var i=-1,a=n.length;if(typeof a=="number")for(o&&(e=n[++i]);++iarguments.length;if(typeof u!="number")var i=Vt(n),u=i.length;return t=J(t,e,4),F(n,function(e,a,f){a=i?i[--u]:--u,r=o?(o=Y,n[a]):t(r,n[a],a,f)}),r}function $(n,r,e){var u;r=J(r,e),e=-1;var o=n?n.length:0;if(typeof o=="number")for(;++er(u,i)&&o.push(i)}return o}function C(n,t,r){if(n){var e=0,u=n.length;if(typeof t!="number"&&t!=X){var o=-1;for(t=J(t,r);++or?Tt(0,e+r):r||0}else if(r)return r=W(n,t),n[r]===t?r:-1;return n?u(n,t,r):-1}function V(n,t,r){if(typeof t!="number"&&t!=X){var e=0,u=-1,o=n?n.length:0;for(t=J(t,r);++u>>1,r(n[e])o(f,c))&&(r&&f.push(c),a.push(e))}return a}function H(n,t){return Pt.fastBind||Bt&&2"']/g,ot=/['\n\r\t\u2028\u2029\\]/g,it="[object Arguments]",at="[object Array]",ft="[object Boolean]",ct="[object Date]",lt="[object Number]",pt="[object Object]",st="[object RegExp]",vt="[object String]",gt={"boolean":Y,"function":Q,object:Q,number:Y,string:Y,undefined:Y},ht={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},yt=gt[typeof exports]&&exports,mt=gt[typeof module]&&module&&module.exports==yt&&module,_t=gt[typeof global]&&global; +!_t||_t.global!==_t&&_t.window!==_t||(n=_t);var dt=[],_t=Object.prototype,bt=n._,jt=RegExp("^"+(_t.valueOf+"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),wt=Math.ceil,At=n.clearTimeout,xt=dt.concat,Ot=Math.floor,Et=_t.hasOwnProperty,St=dt.push,Nt=n.setTimeout,kt=_t.toString,Bt=jt.test(Bt=kt.bind)&&Bt,Ft=jt.test(Ft=Object.create)&&Ft,qt=jt.test(qt=Array.isArray)&&qt,Rt=n.isFinite,Dt=n.isNaN,Mt=jt.test(Mt=Object.keys)&&Mt,Tt=Math.max,$t=Math.min,It=Math.random,zt=dt.slice,_t=jt.test(n.attachEvent),Ct=Bt&&!/\n|true/.test(Bt+_t); +c.prototype=f.prototype;var Pt={};!function(){var n={0:1,length:1};Pt.fastBind=Bt&&!Ct,Pt.spliceObjects=(dt.splice.call(n,0,1),!n[0])}(1),f.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""},Ft||(p=function(n){if(A(n)){a.prototype=n;var t=new a;a.prototype=X}return t||{}}),h(arguments)||(h=function(n){return n?Et.call(n,"callee"):Y});var Ut=qt||function(n){return n?typeof n=="object"&&kt.call(n)==at:Y},Vt=Mt?function(n){return A(n)?Mt(n):[] +}:e,Wt={"&":"&","<":"<",">":">",'"':""","'":"'"},Gt=d(Wt);w(/x/)&&(w=function(n){return typeof n=="function"&&"[object Function]"==kt.call(n)}),f.after=function(n,t){return 1>n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},f.bind=H,f.bindAll=function(n){for(var t=1u(i,a)){for(var f=r;--f;)if(0>u(t[f],a))continue n;i.push(a)}}return i},f.invert=d,f.invoke=function(n,t){var r=zt.call(arguments,2),e=-1,u=typeof t=="function",o=n?n.length:0,i=Array(typeof o=="number"?o:0);return F(n,function(n){i[++e]=(u?t:n[t]).apply(n,r)}),i},f.keys=Vt,f.map=q,f.max=R,f.memoize=function(n,t){var r={};return function(){var e=tt+(t?t.apply(this,arguments):arguments[0]);return Et.call(r,e)?r[e]:r[e]=n.apply(this,arguments)}},f.min=function(n,t,r){var e=1/0,u=e,o=-1,i=n?n.length:0; +if(t||typeof i!="number")t=J(t,r),F(n,function(n,r,o){r=t(n,r,o),rt(e,r)&&(u[r]=n)}),u},f.once=function(n){var t,r;return function(){return t?r:(t=Q,r=n.apply(this,arguments),n=X,r)}},f.pairs=function(n){for(var t=-1,r=Vt(n),e=r.length,u=Array(e);++tr?0:r);++tr?Tt(0,e+r):$t(r,e-1))+1);e--;)if(n[e]===t)return e;return-1},f.mixin=L,f.noConflict=function(){return n._=bt,this +},f.random=function(n,t){n==X&&t==X&&(t=1),n=+n||0,t==X?(t=n,n=0):t=+t||0;var r=It();return n%1||t%1?n+$t(r*(t-n+parseFloat("1e-"+((r+"").length-1))),t):n+Ot(r*(t-n+1))},f.reduce=M,f.reduceRight=T,f.result=function(n,t){var r=n?n[t]:X;return w(r)?n[t]():r},f.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Vt(n).length},f.some=$,f.sortedIndex=W,f.template=function(n,t,r){var e=f.templateSettings;n||(n=""),r=m({},r,e);var u=0,o="__p+='",e=r.variable;n.replace(RegExp((r.escape||et).source+"|"+(r.interpolate||et).source+"|"+(r.evaluate||et).source+"|$","g"),function(t,r,e,a,f){return o+=n.slice(u,f).replace(ot,i),r&&(o+="'+_['escape']("+r+")+'"),a&&(o+="';"+a+";__p+='"),e&&(o+="'+((__t=("+e+"))==null?'':__t)+'"),u=f+t.length,t +}),o+="';\n",e||(e="obj",o="with("+e+"||{}){"+o+"}"),o="function("+e+"){var __t,__p='',__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+o+"return __p}";try{var a=Function("_","return "+o)(f)}catch(c){throw c.source=o,c}return t?a(t):(a.source=o,a)},f.unescape=function(n){return n==X?"":(n+"").replace(rt,g)},f.uniqueId=function(n){var t=++Z+"";return n?n+t:t},f.all=N,f.any=$,f.detect=B,f.findWhere=function(n,t){return I(n,t,Q)},f.foldl=M,f.foldr=T,f.include=S,f.inject=M,f.first=C,f.last=function(n,t,r){if(n){var e=0,u=n.length; +if(typeof t!="number"&&t!=X){var o=u;for(t=J(t,r);o--&&t(n[o],o,n);)e++}else if(e=t,e==X||r)return n[u-1];return zt.call(n,Tt(0,u-e))}},f.take=C,f.head=C,f.VERSION="1.3.0",L(f),f.prototype.chain=function(){return this.__chain__=Q,this},f.prototype.value=function(){return this.__wrapped__},F("pop push reverse shift sort splice unshift".split(" "),function(n){var t=dt[n];f.prototype[n]=function(){var n=this.__wrapped__;return t.apply(n,arguments),!Pt.spliceObjects&&0===n.length&&delete n[0],this}}),F(["concat","join","slice"],function(n){var t=dt[n]; +f.prototype[n]=function(){var n=t.apply(this.__wrapped__,arguments);return this.__chain__&&(n=new c(n),n.__chain__=Q),n}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(n._=f, define(function(){return f})):yt&&!yt.nodeType?mt?(mt.exports=f)._=f:yt._=f:n._=f}(this); \ No newline at end of file diff --git a/doc/README.md b/doc/README.md index 5d27aac76b..c1fe895c29 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,4 +1,4 @@ -# Lo-Dash v1.2.1 +# Lo-Dash v1.3.0 @@ -39,6 +39,7 @@ ## `Chaining` * [`_`](#_value) +* [`_.chain`](#_value) * [`_.tap`](#_tapvalue-interceptor) * [`_.prototype.toString`](#_prototypetostring) * [`_.prototype.value`](#_prototypevalueof) @@ -61,6 +62,7 @@ * [`_.every`](#_everycollection--callbackidentity-thisarg) * [`_.filter`](#_filtercollection--callbackidentity-thisarg) * [`_.find`](#_findcollection--callbackidentity-thisarg) +* [`_.findWhere`](#_findcollection--callbackidentity-thisarg) * [`_.foldl`](#_reducecollection--callbackidentity-accumulator-thisarg) * [`_.foldr`](#_reducerightcollection--callbackidentity-accumulator-thisarg) * [`_.forEach`](#_foreachcollection--callbackidentity-thisarg) @@ -145,6 +147,7 @@ * [`_.omit`](#_omitobject-callback-prop1-prop2--thisarg) * [`_.pairs`](#_pairsobject) * [`_.pick`](#_pickobject-callback-prop1-prop2--thisarg) +* [`_.transform`](#_transformcollection--callbackidentity-accumulator-thisarg) * [`_.values`](#_valuesobject) @@ -184,6 +187,7 @@ * [`_.support`](#_support) * [`_.support.argsClass`](#_supportargsclass) * [`_.support.argsObject`](#_supportargsobject) +* [`_.support.enumErrorProps`](#_supportenumerrorprops) * [`_.support.enumPrototypes`](#_supportenumprototypes) * [`_.support.fastBind`](#_supportfastbind) * [`_.support.nonEnumArgs`](#_supportnonenumargs) @@ -214,7 +218,7 @@ ### `_.compact(array)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3291 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3637 "View in source") [Ⓣ][1] Creates an array with all falsey values of `array` removed. The values `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. @@ -238,7 +242,7 @@ _.compact([0, 1, false, 2, '', 3]); ### `_.difference(array [, array1, array2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3321 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3667 "View in source") [Ⓣ][1] Creates an array of `array` elements not present in the other arrays using strict equality for comparisons, i.e. `===`. @@ -263,7 +267,7 @@ _.difference([1, 2, 3, 4, 5], [5, 2, 10]); ### `_.findIndex(array [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3357 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3717 "View in source") [Ⓣ][1] This method is similar to `_.find`, except that it returns the index of the element that passes the callback check, instead of the element itself. @@ -291,7 +295,7 @@ _.findIndex(['apple', 'banana', 'beet'], function(food) { ### `_.first(array [, callback|n, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3427 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3787 "View in source") [Ⓣ][1] Gets the first element of the `array`. If a number `n` is passed, the first `n` elements of the `array` are returned. If a `callback` function is passed, elements at the beginning of the array are returned as long as the `callback` returns truthy. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*. @@ -351,7 +355,7 @@ _.first(food, { 'type': 'fruit' }); ### `_.flatten(array [, isShallow=false, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3489 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3849 "View in source") [Ⓣ][1] Flattens a nested array *(the nesting can be to any depth)*. If `isShallow` is truthy, `array` will only be flattened a single level. If `callback` is passed, each element of `array` is passed through a `callback` before flattening. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*. @@ -394,7 +398,7 @@ _.flatten(stooges, 'quotes'); ### `_.indexOf(array, value [, fromIndex=0])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3542 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3893 "View in source") [Ⓣ][1] Gets the index at which the first occurrence of `value` is found using strict equality for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` for `fromIndex` will run a faster binary search. @@ -426,7 +430,7 @@ _.indexOf([1, 1, 2, 2, 3, 3], 2, true); ### `_.initial(array [, callback|n=1, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3616 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3960 "View in source") [Ⓣ][1] Gets all but the last element of `array`. If a number `n` is passed, the last `n` elements are excluded from the result. If a `callback` function is passed, elements at the end of the array are excluded from the result as long as the `callback` returns truthy. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*. @@ -483,7 +487,7 @@ _.initial(food, { 'type': 'vegetable' }); ### `_.intersection([array1, array2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3650 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3994 "View in source") [Ⓣ][1] Computes the intersection of all the passed-in arrays using strict equality for comparisons, i.e. `===`. @@ -507,7 +511,7 @@ _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); ### `_.last(array [, callback|n, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3742 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4096 "View in source") [Ⓣ][1] Gets the last element of the `array`. If a number `n` is passed, the last `n` elements of the `array` are returned. If a `callback` function is passed, elements at the end of the array are returned as long as the `callback` returns truthy. The `callback` is bound to `thisArg` and invoked with three arguments;(value, index, array). @@ -564,7 +568,7 @@ _.last(food, { 'type': 'vegetable' }); ### `_.lastIndexOf(array, value [, fromIndex=array.length-1])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3783 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4137 "View in source") [Ⓣ][1] Gets the index at which the last occurrence of `value` is found using strict equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the offset from the end of the collection. @@ -593,7 +597,7 @@ _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); ### `_.range([start=0], end [, step=1])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3824 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4178 "View in source") [Ⓣ][1] Creates an array of numbers *(positive and/or negative)* progressing from `start` up to but not including `end`. @@ -631,7 +635,7 @@ _.range(0); ### `_.rest(array [, callback|n=1, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3903 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4257 "View in source") [Ⓣ][1] The opposite of `_.initial`, this method gets all but the first value of `array`. If a number `n` is passed, the first `n` values are excluded from the result. If a `callback` function is passed, elements at the beginning of the array are excluded from the result as long as the `callback` returns truthy. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*. @@ -691,7 +695,7 @@ _.rest(food, { 'type': 'fruit' }); ### `_.sortedIndex(array, value [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3967 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4321 "View in source") [Ⓣ][1] Uses a binary search to determine the smallest index at which the `value` should be inserted into `array` in order to maintain the sort order of the sorted `array`. If `callback` is passed, it will be executed for `value` and each element in `array` to compute their sort ranking. The `callback` is bound to `thisArg` and invoked with one argument; *(value)*. @@ -740,7 +744,7 @@ _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { ### `_.union([array1, array2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3999 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4353 "View in source") [Ⓣ][1] Computes the union of the passed-in arrays using strict equality for comparisons, i.e. `===`. @@ -764,9 +768,9 @@ _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); ### `_.uniq(array [, isSorted=false, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4049 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4403 "View in source") [Ⓣ][1] -Creates a duplicate-value-free version of the `array` using strict equality for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` for `isSorted` will run a faster algorithm. If `callback` is passed, each element of `array` is passed through a `callback` before uniqueness is computed. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*. +Creates a duplicate-value-free version of the `array` using strict equality for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` for `isSorted` will run a faster algorithm. If `callback` is passed, each element of `array` is passed through the `callback` before uniqueness is computed. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, array)*. If a property name is passed for `callback`, the created "_.pluck" style callback will return the property value of the given element. @@ -792,11 +796,11 @@ _.uniq([1, 2, 1, 3, 1]); _.uniq([1, 1, 2, 2, 3], true); // => [1, 2, 3] -_.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); -// => [1, 2, 3] +_.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); +// => ['A', 'b', 'C'] -_.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); -// => [1, 2, 3] +_.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); +// => [1, 2.5, 3] // using "_.pluck" callback shorthand _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); @@ -811,7 +815,7 @@ _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); ### `_.unzip(array)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4107 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4459 "View in source") [Ⓣ][1] The inverse of `_.zip`, this method splits groups of elements into arrays composed of elements from each group at their corresponding indexes. @@ -835,7 +839,7 @@ _.unzip([['moe', 30, true], ['larry', 40, false]]); ### `_.without(array [, value1, value2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4139 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4485 "View in source") [Ⓣ][1] Creates an array with all occurrences of the passed values removed using strict equality for comparisons, i.e. `===`. @@ -860,7 +864,7 @@ _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); ### `_.zip([array1, array2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4159 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4505 "View in source") [Ⓣ][1] Groups the elements of each array at their corresponding indexes. Useful for separate data sources that are coordinated through matching array indexes. For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix in a similar fashion. @@ -884,7 +888,7 @@ _.zip(['moe', 'larry'], [30, 40], [true, false]); ### `_.zipObject(keys [, values=[]])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4188 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4527 "View in source") [Ⓣ][1] Creates an object composed from arrays of `keys` and `values`. Pass either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or two arrays, one of `keys` and one of corresponding `values`. @@ -919,7 +923,7 @@ _.zipObject(['moe', 'larry'], [30, 40]); ### `_(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L282 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L615 "View in source") [Ⓣ][1] Creates a `lodash` object, which wraps the given `value`, to enable method chaining. @@ -929,13 +933,16 @@ In addition to Lo-Dash methods, wrappers also have the following `Array` methods Chaining is supported in custom builds as long as the `value` method is implicitly or explicitly included in the build. The chainable wrapper functions are:
-`after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, `concat`, `countBy`, `createCallback`, `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`, and `zip` +`after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, `concat`, `countBy`, `createCallback`, `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`, and `zip` The non-chainable wrapper functions are:
`clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`, `template`, `unescape`, `uniqueId`, and `value` The wrapper functions `first` and `last` return wrapped values when `n` is passed, otherwise they return unwrapped values. +#### Aliases +*chain* + #### Arguments 1. `value` *(Mixed)*: The value to wrap in a `lodash` instance. @@ -972,7 +979,7 @@ _.isArray(squares.value()); ### `_.tap(value, interceptor)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5255 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5626 "View in source") [Ⓣ][1] Invokes `interceptor` with the `value` as the first argument, and then returns `value`. The purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. @@ -1002,7 +1009,7 @@ _([1, 2, 3, 4]) ### `_.prototype.toString()` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5272 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5643 "View in source") [Ⓣ][1] Produces the `toString` result of the wrapped value. @@ -1023,7 +1030,7 @@ _([1, 2, 3]).toString(); ### `_.prototype.valueOf()` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5289 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5660 "View in source") [Ⓣ][1] Extracts the wrapped value. @@ -1054,7 +1061,7 @@ _([1, 2, 3]).valueOf(); ### `_.at(collection [, index1, index2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2280 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2624 "View in source") [Ⓣ][1] Creates an array of elements from the specified indexes, or keys, of the `collection`. Indexes may be specified as individual arguments or as arrays of indexes. @@ -1082,7 +1089,7 @@ _.at(['moe', 'larry', 'curly'], 0, 2); ### `_.contains(collection, target [, fromIndex=0])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2322 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2666 "View in source") [Ⓣ][1] Checks if a given `target` element is present in a `collection` using strict equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the offset from the end of the collection. @@ -1120,7 +1127,7 @@ _.contains('curly', 'ur'); ### `_.countBy(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2376 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2721 "View in source") [Ⓣ][1] Creates an object composed of keys returned from running each element of the `collection` through the given `callback`. The corresponding value of each key is the number of times the key was returned by the `callback`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1156,7 +1163,7 @@ _.countBy(['one', 'two', 'three'], 'length'); ### `_.every(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2428 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2773 "View in source") [Ⓣ][1] Checks if the `callback` returns a truthy value for **all** elements of a `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1202,7 +1209,7 @@ _.every(stooges, { 'age': 50 }); ### `_.filter(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2489 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2834 "View in source") [Ⓣ][1] Examines each element in a `collection`, returning an array of all elements the `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1248,7 +1255,7 @@ _.filter(food, { 'type': 'fruit' }); ### `_.find(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2556 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2901 "View in source") [Ⓣ][1] Examines each element in a `collection`, returning the first that the `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1257,7 +1264,7 @@ If a property name is passed for `callback`, the created "_.pluck" style callbac If an object is passed for `callback`, the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`. #### Aliases -*detect* +*detect, findWhere* #### Arguments 1. `collection` *(Array|Object|String)*: The collection to iterate over. @@ -1297,7 +1304,7 @@ _.find(food, 'organic'); ### `_.forEach(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2603 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2948 "View in source") [Ⓣ][1] Iterates over a `collection`, executing the `callback` for each element in the `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. Callbacks may exit iteration early by explicitly returning `false`. @@ -1329,7 +1336,7 @@ _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); ### `_.groupBy(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2653 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2998 "View in source") [Ⓣ][1] Creates an object composed of keys returned from running each element of the `collection` through the `callback`. The corresponding value of each key is an array of elements passed to `callback` that returned the key. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1366,7 +1373,7 @@ _.groupBy(['one', 'two', 'three'], 'length'); ### `_.invoke(collection, methodName [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2686 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3031 "View in source") [Ⓣ][1] Invokes the method named by `methodName` on each element in the `collection`, returning an array of the results of each invoked method. Additional arguments will be passed to each invoked method. If `methodName` is a function, it will be invoked for, and `this` bound to, each element in the `collection`. @@ -1395,7 +1402,7 @@ _.invoke([123, 456], String.prototype.split, ''); ### `_.map(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2738 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3083 "View in source") [Ⓣ][1] Creates an array of values by running each element in the `collection` through the `callback`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1440,7 +1447,7 @@ _.map(stooges, 'name'); ### `_.max(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2795 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3140 "View in source") [Ⓣ][1] Retrieves the maximum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, collection)*. @@ -1482,7 +1489,7 @@ _.max(stooges, 'age'); ### `_.min(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2864 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3209 "View in source") [Ⓣ][1] Retrieves the minimum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index, collection)*. @@ -1524,7 +1531,7 @@ _.min(stooges, 'age'); ### `_.pluck(collection, property)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2914 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3259 "View in source") [Ⓣ][1] Retrieves the value of a specified property from all elements in the `collection`. @@ -1554,7 +1561,7 @@ _.pluck(stooges, 'name'); ### `_.reduce(collection [, callback=identity, accumulator, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2946 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3291 "View in source") [Ⓣ][1] Reduces a `collection` to a value which is the accumulated result of running each element in the `collection` through the `callback`, where each successive `callback` execution consumes the return value of the previous execution. If `accumulator` is not passed, the first element of the `collection` will be used as the initial `accumulator` value. The `callback` is bound to `thisArg` and invoked with four arguments; *(accumulator, value, index|key, collection)*. @@ -1592,7 +1599,7 @@ var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { ### `_.reduceRight(collection [, callback=identity, accumulator, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2989 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3334 "View in source") [Ⓣ][1] This method is similar to `_.reduce`, except that it iterates over a `collection` from right to left. @@ -1623,7 +1630,7 @@ var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); ### `_.reject(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3049 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3394 "View in source") [Ⓣ][1] The opposite of `_.filter`, this method returns the elements of a `collection` that `callback` does **not** return truthy for. @@ -1666,7 +1673,7 @@ _.reject(food, { 'type': 'fruit' }); ### `_.shuffle(collection)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3070 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3415 "View in source") [Ⓣ][1] Creates an array of shuffled `array` values, using a version of the Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. @@ -1690,7 +1697,7 @@ _.shuffle([1, 2, 3, 4, 5, 6]); ### `_.size(collection)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3103 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3448 "View in source") [Ⓣ][1] Gets the size of the `collection` by returning `collection.length` for arrays and array-like objects or the number of own enumerable properties for objects. @@ -1720,7 +1727,7 @@ _.size('curly'); ### `_.some(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3150 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3495 "View in source") [Ⓣ][1] Checks if the `callback` returns a truthy value for **any** element of a `collection`. The function returns as soon as it finds passing value, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1766,7 +1773,7 @@ _.some(food, { 'type': 'meat' }); ### `_.sortBy(collection [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3206 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3551 "View in source") [Ⓣ][1] Creates an array of elements, sorted in ascending order by the results of running each element in the `collection` through the `callback`. This method performs a stable sort, that is, it will preserve the original sort order of equal elements. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. @@ -1803,7 +1810,7 @@ _.sortBy(['banana', 'strawberry', 'apple'], 'length'); ### `_.toArray(collection)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3241 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3587 "View in source") [Ⓣ][1] Converts the `collection` to an array. @@ -1827,7 +1834,7 @@ Converts the `collection` to an array. ### `_.where(collection, properties)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3273 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L3619 "View in source") [Ⓣ][1] Examines each element in a `collection`, returning an array of all elements that have the given `properties`. When checking `properties`, this method performs a deep comparison between values to determine if they are equivalent to each other. @@ -1864,7 +1871,7 @@ _.where(stooges, { 'age': 40 }); ### `_.after(n, func)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4228 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4567 "View in source") [Ⓣ][1] If `n` is greater than `0`, a function is created that is restricted to executing `func`, with the `this` binding and arguments of the created function, only after it is called `n` times. If `n` is less than `1`, `func` is executed immediately, without a `this` binding or additional arguments, and its result is returned. @@ -1892,7 +1899,7 @@ _.forEach(notes, function(note) { ### `_.bind(func [, thisArg, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4261 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4600 "View in source") [Ⓣ][1] Creates a function that, when called, invokes `func` with the `this` binding of `thisArg` and prepends any additional `bind` arguments to those passed to the bound function. @@ -1923,7 +1930,7 @@ func(); ### `_.bindAll(object [, methodName1, methodName2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4292 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4631 "View in source") [Ⓣ][1] Binds methods on `object` to `object`, overwriting the existing method. Method names may be specified as individual arguments or as arrays of method names. If no method names are provided, all the function properties of `object` will be bound. @@ -1954,7 +1961,7 @@ jQuery('#docs').on('click', view.onClick); ### `_.bindKey(object, key [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4338 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4677 "View in source") [Ⓣ][1] Creates a function that, when called, invokes the method at `object[key]` and prepends any additional `bindKey` arguments to those passed to the bound function. This method differs from `_.bind` by allowing bound functions to reference methods that will be redefined or don't yet exist. See http://michaux.ca/articles/lazy-function-definition-pattern. @@ -1995,7 +2002,7 @@ func(); ### `_.compose([func1, func2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4361 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4700 "View in source") [Ⓣ][1] Creates a function that is the composition of the passed functions, where each function consumes the return value of the function that follows. For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. Each function is executed with the `this` binding of the composed function. @@ -2022,7 +2029,7 @@ welcome('moe'); ### `_.createCallback([func=identity, thisArg, argCount=3])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4420 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4759 "View in source") [Ⓣ][1] Produces a callback bound to an optional `thisArg`. If `func` is a property name, the created callback will return the property value for a given element. If `func` is an object, the created callback will return `true` for elements that contain the equivalent object properties, otherwise it will return `false`. @@ -2076,7 +2083,7 @@ _.toLookup(stooges, 'name'); ### `_.debounce(func, wait, options)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4496 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4836 "View in source") [Ⓣ][1] Creates a function that will delay the execution of `func` until after `wait` milliseconds have elapsed since the last time it was invoked. Pass an `options` object to indicate that `func` should be invoked on the leading and/or trailing edge of the `wait` timeout. Subsequent calls to the debounced function will return the result of the last `func` call. @@ -2085,7 +2092,7 @@ Note: If `leading` and `trailing` options are `true`, `func` will be called on t #### Arguments 1. `func` *(Function)*: The function to debounce. 2. `wait` *(Number)*: The number of milliseconds to delay. -3. `options` *(Object)*: The options object. [leading=false] A boolean to specify execution on the leading edge of the timeout. [trailing=true] A boolean to specify execution on the trailing edge of the timeout. +3. `options` *(Object)*: The options object. [leading=false] A boolean to specify execution on the leading edge of the timeout. [maxWait] The maximum time `func` is allowed to be delayed before it's called. [trailing=true] A boolean to specify execution on the trailing edge of the timeout. #### Returns *(Function)*: Returns the new debounced function. @@ -2109,7 +2116,7 @@ jQuery('#postbox').on('click', _.debounce(sendMail, 200, { ### `_.defer(func [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4547 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4933 "View in source") [Ⓣ][1] Defers executing the `func` function until the current call stack has cleared. Additional arguments will be passed to `func` when it is invoked. @@ -2134,7 +2141,7 @@ _.defer(function() { alert('deferred'); }); ### `_.delay(func, wait [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4573 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4959 "View in source") [Ⓣ][1] Executes the `func` function after `wait` milliseconds. Additional arguments will be passed to `func` when it is invoked. @@ -2161,9 +2168,9 @@ _.delay(log, 1000, 'logged later'); ### `_.memoize(func [, resolver])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4597 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L4984 "View in source") [Ⓣ][1] -Creates a function that memoizes the result of `func`. If `resolver` is passed, it will be used to determine the cache key for storing the result based on the arguments passed to the memoized function. By default, the first argument passed to the memoized function is used as the cache key. The `func` is executed with the `this` binding of the memoized function. +Creates a function that memoizes the result of `func`. If `resolver` is passed, it will be used to determine the cache key for storing the result based on the arguments passed to the memoized function. By default, the first argument passed to the memoized function is used as the cache key. The `func` is executed with the `this` binding of the memoized function. The result cache is exposed as the `cache` property on the memoized function. #### Arguments 1. `func` *(Function)*: The function to have its output memoized. @@ -2187,7 +2194,7 @@ var fibonacci = _.memoize(function(n) { ### `_.once(func)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4624 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5014 "View in source") [Ⓣ][1] Creates a function that is restricted to execute `func` once. Repeat calls to the function will return the value of the first call. The `func` is executed with the `this` binding of the created function. @@ -2213,7 +2220,7 @@ initialize(); ### `_.partial(func [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4659 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5049 "View in source") [Ⓣ][1] Creates a function that, when called, invokes `func` with any additional `partial` arguments prepended to those passed to the new function. This method is similar to `_.bind`, except it does **not** alter the `this` binding. @@ -2240,7 +2247,7 @@ hi('moe'); ### `_.partialRight(func [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4690 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5080 "View in source") [Ⓣ][1] This method is similar to `_.partial`, except that `partial` arguments are appended to those passed to the new function. @@ -2277,7 +2284,7 @@ options.imports ### `_.throttle(func, wait, options)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4723 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5113 "View in source") [Ⓣ][1] Creates a function that, when executed, will only call the `func` function at most once per every `wait` milliseconds. Pass an `options` object to indicate that `func` should be invoked on the leading and/or trailing edge of the `wait` timeout. Subsequent calls to the throttled function will return the result of the last `func` call. @@ -2309,7 +2316,7 @@ jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { ### `_.wrap(value, wrapper)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4788 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5154 "View in source") [Ⓣ][1] Creates a function that passes `value` to the `wrapper` function as its first argument. Additional arguments passed to the function are appended to those passed to the `wrapper` function. The `wrapper` is executed with the `this` binding of the created function. @@ -2345,7 +2352,7 @@ hello(); ### `_.assign(object [, source1, source2, ..., callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1086 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1362 "View in source") [Ⓣ][1] Assigns own enumerable properties of source object(s) to the destination object. Subsequent sources will overwrite property assignments of previous sources. If a `callback` function is passed, it will be executed to produce the assigned values. The `callback` is bound to `thisArg` and invoked with two arguments; *(objectValue, sourceValue)*. @@ -2383,7 +2390,7 @@ defaults(food, { 'name': 'banana', 'type': 'fruit' }); ### `_.clone(value [, deep=false, callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1141 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1417 "View in source") [Ⓣ][1] Creates a clone of `value`. If `deep` is `true`, nested objects will also be cloned, otherwise they will be assigned by reference. If a `callback` function is passed, it will be executed to produce the cloned values. If `callback` returns `undefined`, cloning will be handled by the method instead. The `callback` is bound to `thisArg` and invoked with one argument; *(value)*. @@ -2430,11 +2437,11 @@ clone.childNodes.length; ### `_.cloneDeep(value [, callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1266 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1547 "View in source") [Ⓣ][1] Creates a deep clone of `value`. If a `callback` function is passed, it will be executed to produce the cloned values. If `callback` returns `undefined`, cloning will be handled by the method instead. The `callback` is bound to `thisArg` and invoked with one argument; *(value)*. -Note: This function is loosely based on the structured clone algorithm. Functions and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and objects created by constructors other than `Object` are cloned to plain `Object` objects. See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. +Note: This method is loosely based on the structured clone algorithm. Functions and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and objects created by constructors other than `Object` are cloned to plain `Object` objects. See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. #### Arguments 1. `value` *(Mixed)*: The value to deep clone. @@ -2476,7 +2483,7 @@ clone.node == view.node; ### `_.defaults(object [, source1, source2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1290 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1571 "View in source") [Ⓣ][1] Assigns own enumerable properties of source object(s) to the destination object for all destination properties that resolve to `undefined`. Once a property is set, additional defaults of the same property will be ignored. @@ -2502,7 +2509,7 @@ _.defaults(food, { 'name': 'banana', 'type': 'fruit' }); ### `_.findKey(object [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1312 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1593 "View in source") [Ⓣ][1] This method is similar to `_.find`, except that it returns the key of the element that passes the callback check, instead of the element itself. @@ -2530,7 +2537,7 @@ _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) { ### `_.forIn(object [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1353 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1634 "View in source") [Ⓣ][1] Iterates over `object`'s own and inherited enumerable properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`. @@ -2566,7 +2573,7 @@ _.forIn(new Dog('Dagny'), function(value, key) { ### `_.forOwn(object [, callback=identity, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1378 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1659 "View in source") [Ⓣ][1] Iterates over an object's own enumerable properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`. @@ -2594,7 +2601,7 @@ _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { ### `_.functions(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1395 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1676 "View in source") [Ⓣ][1] Creates a sorted array of all enumerable properties, own and inherited, of `object` that have function values. @@ -2621,7 +2628,7 @@ _.functions(_); ### `_.has(object, property)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1420 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1701 "View in source") [Ⓣ][1] Checks if the specified object `property` exists and is a direct property, instead of an inherited property. @@ -2646,7 +2653,7 @@ _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); ### `_.invert(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1437 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1718 "View in source") [Ⓣ][1] Creates an object composed of the inverted keys and values of the given `object`. @@ -2670,7 +2677,7 @@ _.invert({ 'first': 'moe', 'second': 'larry' }); ### `_.isArguments(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L948 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1225 "View in source") [Ⓣ][1] Checks if `value` is an `arguments` object. @@ -2697,7 +2704,7 @@ _.isArguments([1, 2, 3]); ### `_.isArray(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L974 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1251 "View in source") [Ⓣ][1] Checks if `value` is an array. @@ -2724,7 +2731,7 @@ _.isArray([1, 2, 3]); ### `_.isBoolean(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1463 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1744 "View in source") [Ⓣ][1] Checks if `value` is a boolean value. @@ -2748,7 +2755,7 @@ _.isBoolean(null); ### `_.isDate(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1480 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1761 "View in source") [Ⓣ][1] Checks if `value` is a date. @@ -2772,7 +2779,7 @@ _.isDate(new Date); ### `_.isElement(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1497 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1778 "View in source") [Ⓣ][1] Checks if `value` is a DOM element. @@ -2796,7 +2803,7 @@ _.isElement(document.body); ### `_.isEmpty(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1522 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1803 "View in source") [Ⓣ][1] Checks if `value` is empty. Arrays, strings, or `arguments` objects with a length of `0` and objects with no own enumerable properties are considered "empty". @@ -2826,7 +2833,7 @@ _.isEmpty(''); ### `_.isEqual(a, b [, callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1581 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1862 "View in source") [Ⓣ][1] Performs a deep comparison between two values to determine if they are equivalent to each other. If `callback` is passed, it will be executed to compare values. If `callback` returns `undefined`, comparisons will be handled by the method instead. The `callback` is bound to `thisArg` and invoked with two arguments; *(a, b)*. @@ -2871,7 +2878,7 @@ _.isEqual(words, otherWords, function(a, b) { ### `_.isFinite(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1762 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2048 "View in source") [Ⓣ][1] Checks if `value` is, or can be coerced to, a finite number. @@ -2909,7 +2916,7 @@ _.isFinite(Infinity); ### `_.isFunction(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1779 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2065 "View in source") [Ⓣ][1] Checks if `value` is a function. @@ -2933,7 +2940,7 @@ _.isFunction(_); ### `_.isNaN(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1842 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2128 "View in source") [Ⓣ][1] Checks if `value` is `NaN`. @@ -2968,7 +2975,7 @@ _.isNaN(undefined); ### `_.isNull(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1864 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2150 "View in source") [Ⓣ][1] Checks if `value` is `null`. @@ -2995,7 +3002,7 @@ _.isNull(undefined); ### `_.isNumber(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1881 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2167 "View in source") [Ⓣ][1] Checks if `value` is a number. @@ -3019,7 +3026,7 @@ _.isNumber(8.4 * 5); ### `_.isObject(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1809 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2095 "View in source") [Ⓣ][1] Checks if `value` is the language type of Object. *(e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)* @@ -3049,7 +3056,7 @@ _.isObject(1); ### `_.isPlainObject(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1909 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2195 "View in source") [Ⓣ][1] Checks if a given `value` is an object created by the `Object` constructor. @@ -3084,7 +3091,7 @@ _.isPlainObject({ 'name': 'moe', 'age': 40 }); ### `_.isRegExp(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1934 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2220 "View in source") [Ⓣ][1] Checks if `value` is a regular expression. @@ -3108,7 +3115,7 @@ _.isRegExp(/moe/); ### `_.isString(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1951 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2237 "View in source") [Ⓣ][1] Checks if `value` is a string. @@ -3132,7 +3139,7 @@ _.isString('moe'); ### `_.isUndefined(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1968 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2254 "View in source") [Ⓣ][1] Checks if `value` is `undefined`. @@ -3156,7 +3163,7 @@ _.isUndefined(void 0); ### `_.keys(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1008 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L1284 "View in source") [Ⓣ][1] Creates an array composed of the own enumerable property names of `object`. @@ -3180,7 +3187,7 @@ _.keys({ 'one': 1, 'two': 2, 'three': 3 }); ### `_.merge(object [, source1, source2, ..., callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2027 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2313 "View in source") [Ⓣ][1] Recursively merges own enumerable properties of the source object(s), that don't resolve to `undefined`, into the destination object. Subsequent sources will overwrite property assignments of previous sources. If a `callback` function is passed, it will be executed to produce the merged values of the destination and source properties. If `callback` returns `undefined`, merging will be handled by the method instead. The `callback` is bound to `thisArg` and invoked with two arguments; *(objectValue, sourceValue)*. @@ -3236,7 +3243,7 @@ _.merge(food, otherFood, function(a, b) { ### `_.omit(object, callback|[prop1, prop2, ..., thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2136 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2428 "View in source") [Ⓣ][1] Creates a shallow clone of `object` excluding the specified properties. Property names may be specified as individual arguments or as arrays of property names. If a `callback` function is passed, it will be executed for each property in the `object`, omitting the properties `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. @@ -3267,7 +3274,7 @@ _.omit({ 'name': 'moe', 'age': 40 }, function(value) { ### `_.pairs(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2170 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2463 "View in source") [Ⓣ][1] Creates a two dimensional array of the given object's key-value pairs, i.e. `[[key1, value1], [key2, value2]]`. @@ -3291,7 +3298,7 @@ _.pairs({ 'moe': 30, 'larry': 40 }); ### `_.pick(object, callback|[prop1, prop2, ..., thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2208 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2501 "View in source") [Ⓣ][1] Creates a shallow clone of `object` composed of the specified properties. Property names may be specified as individual arguments or as arrays of property names. If `callback` is passed, it will be executed for each property in the `object`, picking the properties `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. @@ -3319,10 +3326,47 @@ _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) { + + +### `_.transform(collection [, callback=identity, accumulator, thisArg])` +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2556 "View in source") [Ⓣ][1] + +An alternative to `_.reduce`, this method transforms an `object` to a new `accumulator` object which is the result of running each of its elements through the `callback`, with each `callback` execution potentially mutating the `accumulator` object. The `callback` is bound to `thisArg` and invoked with four arguments; *(accumulator, value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`. + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `[callback=identity]` *(Function)*: The function called per iteration. +3. `[accumulator]` *(Mixed)*: The custom accumulator value. +4. `[thisArg]` *(Mixed)*: The `this` binding of `callback`. + +#### Returns +*(Mixed)*: Returns the accumulated value. + +#### Example +```js +var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { + num *= num; + if (num % 2) { + return result.push(num) < 3; + } +}); +// => [1, 9, 25] + +var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { + result[key] = num * 3; +}); +// => { 'a': 3, 'b': 6, 'c': 9 } +``` + +* * * + + + + ### `_.values(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2245 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L2589 "View in source") [Ⓣ][1] Creates an array composed of the own enumerable property values of `object`. @@ -3353,7 +3397,7 @@ _.values({ 'one': 1, 'two': 2, 'three': 3 }); ### `_.escape(string)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4812 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5178 "View in source") [Ⓣ][1] Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their corresponding HTML entities. @@ -3377,9 +3421,9 @@ _.escape('Moe, Larry & Curly'); ### `_.identity(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4830 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5196 "View in source") [Ⓣ][1] -This function returns the first argument passed to it. +This method returns the first argument passed to it. #### Arguments 1. `value` *(Mixed)*: Any value. @@ -3402,7 +3446,7 @@ moe === _.identity(moe); ### `_.mixin(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4856 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5222 "View in source") [Ⓣ][1] Adds functions properties of `object` to the `lodash` function and chainable wrapper. @@ -3432,7 +3476,7 @@ _('moe').capitalize(); ### `_.noConflict()` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4885 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5251 "View in source") [Ⓣ][1] Reverts the '_' variable to its previous value and returns a reference to the `lodash` function. @@ -3452,7 +3496,7 @@ var lodash = _.noConflict(); ### `_.parseInt(value [, radix])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4909 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5275 "View in source") [Ⓣ][1] Converts the given `value` into an integer of the specified `radix`. If `radix` is `undefined` or `0`, a `radix` of `10` is used unless the `value` is a hexadecimal, in which case a `radix` of `16` is used. @@ -3479,7 +3523,7 @@ _.parseInt('08'); ### `_.random([min=0, max=1])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4932 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5298 "View in source") [Ⓣ][1] Produces a random number between `min` and `max` *(inclusive)*. If only one argument is passed, a number between `0` and the given number will be returned. @@ -3507,7 +3551,7 @@ _.random(5); ### `_.result(object, property)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L4971 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5342 "View in source") [Ⓣ][1] Resolves the value of `property` on `object`. If `property` is a function, it will be invoked with the `this` binding of `object` and its result returned, else the property value is returned. If `object` is falsey, then `undefined` is returned. @@ -3542,7 +3586,7 @@ _.result(object, 'stuff'); ### `_.runInContext([context=window])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L149 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L448 "View in source") [Ⓣ][1] Create a new `lodash` function using the given `context` object. @@ -3560,7 +3604,7 @@ Create a new `lodash` function using the given `context` object. ### `_.template(text, data, options)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5055 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5426 "View in source") [Ⓣ][1] A micro-templating method that handles arbitrary delimiters, preserves whitespace, and correctly escapes quotes within interpolated code. @@ -3642,7 +3686,7 @@ fs.writeFileSync(path.join(cwd, 'jst.js'), '\ ### `_.times(n, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5180 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5551 "View in source") [Ⓣ][1] Executes the `callback` function `n` times, returning an array of the results of each `callback` execution. The `callback` is bound to `thisArg` and invoked with one argument; *(index)*. @@ -3674,7 +3718,7 @@ _.times(3, function(n) { this.cast(n); }, mage); ### `_.unescape(string)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5207 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5578 "View in source") [Ⓣ][1] The inverse of `_.escape`, this method converts the HTML entities `&`, `<`, `>`, `"`, and `'` in `string` to their corresponding characters. @@ -3698,7 +3742,7 @@ _.unescape('Moe, Larry & Curly'); ### `_.uniqueId([prefix])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5227 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5598 "View in source") [Ⓣ][1] Generates a unique ID. If `prefix` is passed, the ID will be appended to it. @@ -3732,7 +3776,7 @@ _.uniqueId(); ### `_.templateSettings.imports._` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L469 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L824 "View in source") [Ⓣ][1] A reference to the `lodash` function. @@ -3751,7 +3795,7 @@ A reference to the `lodash` function. ### `_.VERSION` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L5464 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L5841 "View in source") [Ⓣ][1] *(String)*: The semantic version number. @@ -3763,7 +3807,7 @@ A reference to the `lodash` function. ### `_.support` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L296 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L642 "View in source") [Ⓣ][1] *(Object)*: An object used to flag environments features. @@ -3775,7 +3819,7 @@ A reference to the `lodash` function. ### `_.support.argsClass` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L321 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L667 "View in source") [Ⓣ][1] *(Boolean)*: Detect if an `arguments` object's [[Class]] is resolvable *(all but Firefox < `4`, IE < `9`)*. @@ -3787,7 +3831,7 @@ A reference to the `lodash` function. ### `_.support.argsObject` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L313 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L659 "View in source") [Ⓣ][1] *(Boolean)*: Detect if `arguments` objects are `Object` objects *(all but Narwhal and Opera < `10.5`)*. @@ -3796,10 +3840,22 @@ A reference to the `lodash` function. + + +### `_.support.enumErrorProps` +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L676 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if `name` or `message` properties of `Error.prototype` are enumerable by default. *(IE < `9`, Safari < `5.1`)* + +* * * + + + + ### `_.support.enumPrototypes` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L334 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L689 "View in source") [Ⓣ][1] *(Boolean)*: Detect if `prototype` properties are enumerable by default. @@ -3813,7 +3869,7 @@ Firefox < `3.6`, Opera > `9.50` - Opera < `11.60`, and Safari < `5.1` *(if the p ### `_.support.fastBind` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L342 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L697 "View in source") [Ⓣ][1] *(Boolean)*: Detect if `Function#bind` exists and is inferred to be fast *(all but V8)*. @@ -3825,7 +3881,7 @@ Firefox < `3.6`, Opera > `9.50` - Opera < `11.60`, and Safari < `5.1` *(if the p ### `_.support.nonEnumArgs` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L359 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L714 "View in source") [Ⓣ][1] *(Boolean)*: Detect if `arguments` object indexes are non-enumerable *(Firefox < `4`, IE < `9`, PhantomJS, Safari < `5.1`)*. @@ -3837,7 +3893,7 @@ Firefox < `3.6`, Opera > `9.50` - Opera < `11.60`, and Safari < `5.1` *(if the p ### `_.support.nonEnumShadows` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L370 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L725 "View in source") [Ⓣ][1] *(Boolean)*: Detect if properties shadowing those on `Object.prototype` are non-enumerable. @@ -3851,7 +3907,7 @@ In IE < `9` an objects own properties, shadowing non-enumerable ones, are made n ### `_.support.ownLast` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L350 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L705 "View in source") [Ⓣ][1] *(Boolean)*: Detect if own properties are iterated after inherited properties *(all but IE < `9`)*. @@ -3863,7 +3919,7 @@ In IE < `9` an objects own properties, shadowing non-enumerable ones, are made n ### `_.support.spliceObjects` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L384 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L739 "View in source") [Ⓣ][1] *(Boolean)*: Detect if `Array#shift` and `Array#splice` augment array-like objects correctly. @@ -3877,7 +3933,7 @@ Firefox < `10`, IE compatibility mode, and IE < `9` have buggy Array `shift()` a ### `_.support.unindexedChars` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L395 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L750 "View in source") [Ⓣ][1] *(Boolean)*: Detect lack of support for accessing string characters by index. @@ -3891,7 +3947,7 @@ IE < `8` can't access characters by index and IE `8` can only access characters ### `_.templateSettings` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L421 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L776 "View in source") [Ⓣ][1] *(Object)*: By default, the template delimiters used by Lo-Dash are similar to those in embedded Ruby *(ERB)*. Change the following template settings to use alternative delimiters. @@ -3903,7 +3959,7 @@ IE < `8` can't access characters by index and IE `8` can only access characters ### `_.templateSettings.escape` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L429 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L784 "View in source") [Ⓣ][1] *(RegExp)*: Used to detect `data` property values to be HTML-escaped. @@ -3915,7 +3971,7 @@ IE < `8` can't access characters by index and IE `8` can only access characters ### `_.templateSettings.evaluate` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L437 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L792 "View in source") [Ⓣ][1] *(RegExp)*: Used to detect code to be evaluated. @@ -3927,7 +3983,7 @@ IE < `8` can't access characters by index and IE `8` can only access characters ### `_.templateSettings.interpolate` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L445 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L800 "View in source") [Ⓣ][1] *(RegExp)*: Used to detect `data` property values to inject. @@ -3939,7 +3995,7 @@ IE < `8` can't access characters by index and IE `8` can only access characters ### `_.templateSettings.variable` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L453 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L808 "View in source") [Ⓣ][1] *(String)*: Used to reference the data object in the template text. @@ -3951,7 +4007,7 @@ IE < `8` can't access characters by index and IE `8` can only access characters ### `_.templateSettings.imports` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L461 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/lodash/lodash/blob/1.3.0/lodash.js#L816 "View in source") [Ⓣ][1] *(Object)*: Used to import variables into the compiled template. @@ -3966,4 +4022,4 @@ IE < `8` can't access characters by index and IE `8` can only access characters - [1]: #Arrays "Jump back to the TOC." \ No newline at end of file + [1]: #Arrays "Jump back to the TOC." diff --git a/doc/parse.php b/doc/parse.php index 8a4177f3b9..1d5081e958 100644 --- a/doc/parse.php +++ b/doc/parse.php @@ -21,9 +21,9 @@ // generate Markdown $markdown = docdown(array( 'path' => '../' . $file, - 'title' => 'Lo-Dash v1.2.1', + 'title' => 'Lo-Dash v1.3.0', 'toc' => 'categories', - 'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js' + 'url' => 'https://github.com/lodash/lodash/blob/1.3.0/lodash.js' )); // save to a .md file @@ -33,4 +33,4 @@ header('Content-Type: text/plain;charset=utf-8'); echo $markdown . PHP_EOL; -?> \ No newline at end of file +?> diff --git a/lodash.js b/lodash.js index 65069f0f38..6f022e33c2 100644 --- a/lodash.js +++ b/lodash.js @@ -1,6 +1,6 @@ /** * @license - * Lo-Dash 1.2.1 + * Lo-Dash 1.3.0 * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.4.4 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. @@ -11,17 +11,9 @@ /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports; - - /** Detect free variable `module` */ - var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; - - /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - window = freeGlobal; - } + /** Used to pool arrays and objects used internally */ + var arrayPool = [], + objectPool = []; /** Used to generate unique IDs */ var idCounter = 0; @@ -33,7 +25,10 @@ var keyPrefix = +new Date + ''; /** Used as the size when optimizations are enabled for large arrays */ - var largeArraySize = 200; + var largeArraySize = 75; + + /** Used as the max size of the `arrayPool` and `objectPool` */ + var maxPoolSize = 10; /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, @@ -55,6 +50,9 @@ /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; + /** Used to detect functions containing a `this` reference */ + var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis; + /** Used to detect and test whitespace */ var whitespace = ( // whitespace @@ -81,9 +79,9 @@ /** Used to assign default `context` object properties */ var contextProps = [ - 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp', - 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 'parseInt', - 'setImmediate', 'setTimeout' + 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object', + 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', + 'parseInt', 'setImmediate', 'setTimeout' ]; /** Used to fix the JScript [[DontEnum]] bug */ @@ -100,6 +98,7 @@ arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', + errorClass = '[object Error]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', @@ -135,6 +134,306 @@ '\u2029': 'u2029' }; + /** Detect free variable `exports` */ + var freeExports = objectTypes[typeof exports] && exports; + + /** Detect free variable `module` */ + var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module; + + /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */ + var freeGlobal = objectTypes[typeof global] && global; + if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { + window = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + /** + * A basic implementation of `_.indexOf` without support for binary searches + * or `fromIndex` constraints. + * + * @private + * @param {Array} array The array to search. + * @param {Mixed} value The value to search for. + * @param {Number} [fromIndex=0] The index to search from. + * @returns {Number} Returns the index of the matched value or `-1`. + */ + function basicIndexOf(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * An implementation of `_.contains` for cache objects that mimics the return + * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache object to inspect. + * @param {Mixed} value The value to search for. + * @returns {Number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var type = typeof value; + cache = cache.cache; + + if (type == 'boolean' || value == null) { + return cache[value]; + } + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value; + cache = cache[type] || (cache[type] = {}); + + return type == 'object' + ? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1) + : (cache[key] ? 0 : -1); + } + + /** + * Adds a given `value` to the corresponding cache object. + * + * @private + * @param {Mixed} value The value to add to the cache. + */ + function cachePush(value) { + var cache = this.cache, + type = typeof value; + + if (type == 'boolean' || value == null) { + cache[value] = true; + } else { + if (type != 'number' && type != 'string') { + type = 'object'; + } + var key = type == 'number' ? value : keyPrefix + value, + typeCache = cache[type] || (cache[type] = {}); + + if (type == 'object') { + if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) { + cache[type] = false; + } + } else { + typeCache[key] = true; + } + } + } + + /** + * Used by `_.max` and `_.min` as the default `callback` when a given + * `collection` is a string value. + * + * @private + * @param {String} value The character to inspect. + * @returns {Number} Returns the code unit of given character. + */ + function charAtCallback(value) { + return value.charCodeAt(0); + } + + /** + * Used by `sortBy` to compare transformed `collection` values, stable sorting + * them in ascending order. + * + * @private + * @param {Object} a The object to compare to `b`. + * @param {Object} b The object to compare to `a`. + * @returns {Number} Returns the sort order indicator of `1` or `-1`. + */ + function compareAscending(a, b) { + var ai = a.index, + bi = b.index; + + a = a.criteria; + b = b.criteria; + + // ensure a stable sort in V8 and other engines + // http://code.google.com/p/v8/issues/detail?id=90 + if (a !== b) { + if (a > b || typeof a == 'undefined') { + return 1; + } + if (a < b || typeof b == 'undefined') { + return -1; + } + } + return ai < bi ? -1 : 1; + } + + /** + * Creates a cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [array=[]] The array to search. + * @returns {Null|Object} Returns the cache object or `null` if caching should not be used. + */ + function createCache(array) { + var index = -1, + length = array.length; + + var cache = getObject(); + cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; + + var result = getObject(); + result.array = array; + result.cache = cache; + result.push = cachePush; + + while (++index < length) { + result.push(array[index]); + } + return cache.object === false + ? (releaseObject(result), null) + : result; + } + + /** + * Used by `template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {String} match The matched character to escape. + * @returns {String} Returns the escaped character. + */ + function escapeStringChar(match) { + return '\\' + stringEscapes[match]; + } + + /** + * Gets an array from the array pool or creates a new one if the pool is empty. + * + * @private + * @returns {Array} The array from the pool. + */ + function getArray() { + return arrayPool.pop() || []; + } + + /** + * Gets an object from the object pool or creates a new one if the pool is empty. + * + * @private + * @returns {Object} The object from the pool. + */ + function getObject() { + return objectPool.pop() || { + 'args': '', + 'array': null, + 'bottom': '', + 'criteria': null, + 'false': false, + 'firstArg': '', + 'index': 0, + 'init': '', + 'leading': false, + 'loop': '', + 'maxWait': 0, + 'null': false, + 'number': null, + 'object': null, + 'push': null, + 'shadowedProps': null, + 'string': null, + 'support': null, + 'top': '', + 'trailing': false, + 'true': false, + 'undefined': false, + 'useHas': false, + 'useKeys': false, + 'value': null + }; + } + + /** + * Checks if `value` is a DOM node in IE < 9. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. + */ + function isNode(value) { + // IE < 9 presents DOM nodes as `Object` objects except they have `toString` + // methods that are `typeof` "string" and still can coerce nodes to strings + return typeof value.toString != 'function' && typeof (value + '') == 'string'; + } + + /** + * A no-operation function. + * + * @private + */ + function noop() { + // no operation performed + } + + /** + * Releases the given `array` back to the array pool. + * + * @private + * @param {Array} [array] The array to release. + */ + function releaseArray(array) { + if (arrayPool.length == maxPoolSize) { + arrayPool.length = maxPoolSize - 1; + } + array.length = 0; + arrayPool.push(array); + } + + /** + * Releases the given `object` back to the object pool. + * + * @private + * @param {Object} [object] The object to release. + */ + function releaseObject(object) { + var cache = object.cache; + if (cache) { + releaseObject(cache); + } + if (objectPool.length == maxPoolSize) { + objectPool.length = maxPoolSize - 1; + } + object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; + objectPool.push(object); + } + + /** + * Slices the `collection` from the `start` index up to, but not including, + * the `end` index. + * + * Note: This function is used, instead of `Array#slice`, to support node lists + * in IE < 9 and to ensure dense arrays are returned. + * + * @private + * @param {Array|Object|String} collection The collection to slice. + * @param {Number} start The start index. + * @param {Number} end The end index. + * @returns {Array} Returns the new array. + */ + function slice(array, start, end) { + start || (start = 0); + if (typeof end == 'undefined') { + end = array ? array.length : 0; + } + var index = -1, + length = end - start || 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = array[start + index]; + } + return result; + } + /*--------------------------------------------------------------------------*/ /** @@ -157,6 +456,7 @@ var Array = context.Array, Boolean = context.Boolean, Date = context.Date, + Error = context.Error, Function = context.Function, Math = context.Math, Number = context.Number, @@ -165,16 +465,25 @@ String = context.String, TypeError = context.TypeError; - /** Used for `Array` and `Object` method references */ - var arrayRef = Array(), - objectRef = Object(); + /** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ + var arrayRef = []; + + /** Used for native method references */ + var errorProto = Error.prototype, + objectProto = Object.prototype, + stringProto = String.prototype; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = context._; /** Used to detect if a method is native */ var reNative = RegExp('^' + - String(objectRef.valueOf) + String(objectProto.valueOf) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); @@ -184,15 +493,18 @@ clearTimeout = context.clearTimeout, concat = arrayRef.concat, floor = Math.floor, + fnToString = Function.prototype.toString, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, - hasOwnProperty = objectRef.hasOwnProperty, + hasOwnProperty = objectProto.hasOwnProperty, push = arrayRef.push, + propertyIsEnumerable = objectProto.propertyIsEnumerable, setImmediate = context.setImmediate, setTimeout = context.setTimeout, - toString = objectRef.toString; + toString = objectProto.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, + nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = context.isFinite, nativeIsNaN = context.isNaN, @@ -212,11 +524,31 @@ ctorByClass[arrayClass] = Array; ctorByClass[boolClass] = Boolean; ctorByClass[dateClass] = Date; + ctorByClass[funcClass] = Function; ctorByClass[objectClass] = Object; ctorByClass[numberClass] = Number; ctorByClass[regexpClass] = RegExp; ctorByClass[stringClass] = String; + /** Used to avoid iterating non-enumerable properties in IE < 9 */ + var nonEnumProps = {}; + nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true }; + nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true }; + nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true }; + nonEnumProps[objectClass] = { 'constructor': true }; + + (function() { + var length = shadowedProps.length; + while (length--) { + var prop = shadowedProps[length]; + for (var className in nonEnumProps) { + if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], prop)) { + nonEnumProps[className][prop] = false; + } + } + } + }()); + /*--------------------------------------------------------------------------*/ /** @@ -238,8 +570,8 @@ * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`, * `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, - * `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `unshift`, `unzip`, - * `values`, `where`, `without`, `wrap`, and `zip` + * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, + * `unzip`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, @@ -255,6 +587,7 @@ * * @name _ * @constructor + * @alias chain * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. @@ -286,6 +619,19 @@ : new lodashWrapper(value); } + /** + * A fast path for creating `lodash` wrapper objects. + * + * @private + * @param {Mixed} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + */ + function lodashWrapper(value) { + this.__wrapped__ = value; + } + // ensure `new lodashWrapper` is an instance of `lodash` + lodashWrapper.prototype = lodash.prototype; + /** * An object used to flag environments features. * @@ -320,6 +666,15 @@ */ support.argsClass = isArguments(arguments); + /** + * Detect if `name` or `message` properties of `Error.prototype` are + * enumerable by default. (IE < 9, Safari < 5.1) + * + * @memberOf _.support + * @type Boolean + */ + support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name'); + /** * Detect if `prototype` properties are enumerable by default. * @@ -331,7 +686,7 @@ * @memberOf _.support * @type Boolean */ - support.enumPrototypes = ctor.propertyIsEnumerable('prototype'); + support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype'); /** * Detect if `Function#bind` exists and is inferred to be fast (all but V8). @@ -487,12 +842,12 @@ // exit early if the first argument is falsey 'if (!iterable) return result;\n' + // add code before the iteration branches - '<%= top %>;\n' + + '<%= top %>;' + // array-like iteration: - '<% if (arrays) { %>' + + '<% if (array) { %>\n' + 'var length = iterable.length; index = -1;\n' + - 'if (<%= arrays %>) {' + + 'if (<%= array %>) {' + // add support for accessing string characters by index if needed ' <% if (support.unindexedChars) { %>\n' + @@ -503,19 +858,19 @@ // iterate over the array-like value ' while (++index < length) {\n' + - ' <%= loop %>\n' + + ' <%= loop %>;\n' + ' }\n' + '}\n' + 'else {' + // object iteration: // add support for iterating over `arguments` objects if needed - ' <% } else if (support.nonEnumArgs) { %>\n' + + ' <% } else if (support.nonEnumArgs) { %>\n' + ' var length = iterable.length; index = -1;\n' + ' if (length && isArguments(iterable)) {\n' + ' while (++index < length) {\n' + " index += '';\n" + - ' <%= loop %>\n' + + ' <%= loop %>;\n' + ' }\n' + ' } else {' + ' <% } %>' + @@ -525,29 +880,37 @@ " var skipProto = typeof iterable == 'function';\n" + ' <% } %>' + - // iterate own properties using `Object.keys` if it's fast + // avoid iterating over `Error.prototype` properties in older IE and Safari + ' <% if (support.enumErrorProps) { %>\n' + + ' var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n' + + ' <% } %>' + + + // define conditions used in the loop + ' <%' + + ' var conditions = [];' + + ' if (support.enumPrototypes) { conditions.push(\'!(skipProto && index == "prototype")\'); }' + + ' if (support.enumErrorProps) { conditions.push(\'!(skipErrorProps && (index == "message" || index == "name"))\'); }' + + ' %>' + + + // iterate own properties using `Object.keys` ' <% if (useHas && useKeys) { %>\n' + ' var ownIndex = -1,\n' + - ' ownProps = objectTypes[typeof iterable] ? keys(iterable) : [],\n' + - ' length = ownProps.length;\n\n' + + ' ownProps = objectTypes[typeof iterable] && keys(iterable),\n' + + ' length = ownProps ? ownProps.length : 0;\n\n' + ' while (++ownIndex < length) {\n' + - ' index = ownProps[ownIndex];\n' + - " <% if (support.enumPrototypes) { %>if (!(skipProto && index == 'prototype')) {\n <% } %>" + - ' <%= loop %>\n' + - ' <% if (support.enumPrototypes) { %>}\n<% } %>' + + ' index = ownProps[ownIndex];\n<%' + + " if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" + + ' <%= loop %>;' + + ' <% if (conditions.length) { %>\n }<% } %>\n' + ' }' + // else using a for-in loop ' <% } else { %>\n' + - ' for (index in iterable) {<%' + - ' if (support.enumPrototypes || useHas) { %>\n if (<%' + - " if (support.enumPrototypes) { %>!(skipProto && index == 'prototype')<% }" + - ' if (support.enumPrototypes && useHas) { %> && <% }' + - ' if (useHas) { %>hasOwnProperty.call(iterable, index)<% }' + - ' %>) {' + - ' <% } %>\n' + + ' for (index in iterable) {\n<%' + + ' if (useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); }' + + " if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" + ' <%= loop %>;' + - ' <% if (support.enumPrototypes || useHas) { %>\n }<% } %>\n' + + ' <% if (conditions.length) { %>\n }<% } %>\n' + ' }' + // Because IE < 9 can't set the `[[Enumerable]]` attribute of an @@ -555,19 +918,23 @@ // defaults to non-enumerable, Lo-Dash skips the `constructor` // property when it infers it's iterating over a `prototype` object. ' <% if (support.nonEnumShadows) { %>\n\n' + - ' var ctor = iterable.constructor;\n' + - ' <% for (var k = 0; k < 7; k++) { %>\n' + - " index = '<%= shadowedProps[k] %>';\n" + - ' if (<%' + - " if (shadowedProps[k] == 'constructor') {" + - ' %>!(ctor && ctor.prototype === iterable) && <%' + - ' } %>hasOwnProperty.call(iterable, index)) {\n' + - ' <%= loop %>\n' + + ' if (iterable !== objectProto) {\n' + + " var ctor = iterable.constructor,\n" + + ' isProto = iterable === (ctor && ctor.prototype),\n' + + ' className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n' + + ' nonEnum = nonEnumProps[className];\n' + + ' <% for (k = 0; k < 7; k++) { %>\n' + + " index = '<%= shadowedProps[k] %>';\n" + + ' if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))<%' + + ' if (!useHas) { %> || (!nonEnum[index] && iterable[index] !== objectProto[index])<% }' + + ' %>) {\n' + + ' <%= loop %>;\n' + + ' }' + + ' <% } %>\n' + ' }' + - ' <% } %>' + ' <% } %>' + ' <% } %>' + - ' <% if (arrays || support.nonEnumArgs) { %>\n}<% } %>\n' + + ' <% if (array || support.nonEnumArgs) { %>\n}<% } %>\n' + // add code to the bottom of the iteration function '<%= bottom %>;\n' + @@ -593,90 +960,18 @@ var eachIteratorOptions = { 'args': 'collection, callback, thisArg', 'top': "callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg)", - 'arrays': "typeof length == 'number'", + 'array': "typeof length == 'number'", 'loop': 'if (callback(iterable[index], index, collection) === false) return result' }; /** Reusable iterator options for `forIn` and `forOwn` */ var forOwnIteratorOptions = { 'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top, - 'arrays': false + 'array': false }; /*--------------------------------------------------------------------------*/ - /** - * Creates a function optimized to search large arrays for a given `value`, - * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. - * - * @private - * @param {Array} array The array to search. - * @param {Mixed} value The value to search for. - * @returns {Boolean} Returns `true`, if `value` is found, else `false`. - */ - function cachedContains(array) { - var length = array.length, - isLarge = length >= largeArraySize; - - if (isLarge) { - var cache = {}, - index = -1; - - while (++index < length) { - var key = keyPrefix + array[index]; - (cache[key] || (cache[key] = [])).push(array[index]); - } - } - return function(value) { - if (isLarge) { - var key = keyPrefix + value; - return cache[key] && indexOf(cache[key], value) > -1; - } - return indexOf(array, value) > -1; - } - } - - /** - * Used by `_.max` and `_.min` as the default `callback` when a given - * `collection` is a string value. - * - * @private - * @param {String} value The character to inspect. - * @returns {Number} Returns the code unit of given character. - */ - function charAtCallback(value) { - return value.charCodeAt(0); - } - - /** - * Used by `sortBy` to compare transformed `collection` values, stable sorting - * them in ascending order. - * - * @private - * @param {Object} a The object to compare to `b`. - * @param {Object} b The object to compare to `a`. - * @returns {Number} Returns the sort order indicator of `1` or `-1`. - */ - function compareAscending(a, b) { - var ai = a.index, - bi = b.index; - - a = a.criteria; - b = b.criteria; - - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (a !== b) { - if (a > b || typeof a == 'undefined') { - return 1; - } - if (a < b || typeof b == 'undefined') { - return -1; - } - } - return ai < bi ? -1 : 1; - } - /** * Creates a function that, when called, invokes `func` with the `this` binding * of `thisArg` and prepends any `partialArgs` to the arguments passed to the @@ -723,9 +1018,7 @@ } if (this instanceof bound) { // ensure `new bound` is an instance of `func` - noop.prototype = func.prototype; - thisBinding = new noop; - noop.prototype = null; + thisBinding = createObject(func.prototype); // mimic the constructor's `return` behavior // http://es5.github.com/#x13.2.2 @@ -742,7 +1035,7 @@ * * @private * @param {Object} [options1, options2, ...] The compile options object(s). - * arrays - A string of code to determine if the iterable is an array or array-like. + * array - A string of code to determine if the iterable is an array or array-like. * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. * useKeys - A boolean to specify using `_.keys` for own property iteration. * args - A string of comma separated arguments the iteration function will accept. @@ -752,20 +1045,17 @@ * @returns {Function} Returns the compiled function. */ function createIterator() { - var data = { - // data properties - 'shadowedProps': shadowedProps, - 'support': support, - - // iterator options - 'arrays': 'isArray(iterable)', - 'bottom': '', - 'init': 'iterable', - 'loop': '', - 'top': '', - 'useHas': true, - 'useKeys': !!keys - }; + var data = getObject(); + + // data properties + data.shadowedProps = shadowedProps; + data.support = support; + + // iterator options + data.array = data.bottom = data.loop = data.top = ''; + data.init = 'iterable'; + data.useHas = true; + data.useKeys = !!keys; // merge options into a template data object for (var object, index = 0; object = arguments[index]; index++) { @@ -778,27 +1068,42 @@ // create the function factory var factory = Function( - 'hasOwnProperty, isArguments, isArray, isString, keys, ' + - 'lodash, objectTypes', + 'errorClass, errorProto, hasOwnProperty, isArguments, isArray, ' + + 'isString, keys, lodash, objectProto, objectTypes, nonEnumProps, ' + + 'stringClass, stringProto, toString', 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' ); + + releaseObject(data); + // return the compiled function return factory( - hasOwnProperty, isArguments, isArray, isString, keys, - lodash, objectTypes + errorClass, errorProto, hasOwnProperty, isArguments, isArray, + isString, keys, lodash, objectProto, objectTypes, nonEnumProps, + stringClass, stringProto, toString ); } /** - * Used by `template` to escape characters for inclusion in compiled - * string literals. + * Creates a new object with the specified `prototype`. * * @private - * @param {String} match The matched character to escape. - * @returns {String} Returns the escaped character. + * @param {Object} prototype The prototype object. + * @returns {Object} Returns the new object. */ - function escapeStringChar(match) { - return '\\' + stringEscapes[match]; + function createObject(prototype) { + return isObject(prototype) ? nativeCreate(prototype) : {}; + } + // fallback for browsers without `Object.create` + if (!nativeCreate) { + var createObject = function(prototype) { + if (isObject(prototype)) { + noop.prototype = prototype; + var result = new noop; + noop.prototype = null; + } + return result || {}; + }; } /** @@ -813,38 +1118,39 @@ } /** - * Checks if `value` is a DOM node in IE < 9. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. - */ - function isNode(value) { - // IE < 9 presents DOM nodes as `Object` objects except they have `toString` - // methods that are `typeof` "string" and still can coerce nodes to strings - return typeof value.toString != 'function' && typeof (value + '') == 'string'; - } - - /** - * A fast path for creating `lodash` wrapper objects. + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized, this method returns the custom method, otherwise it returns + * the `basicIndexOf` function. * * @private - * @param {Mixed} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns a `lodash` instance. + * @returns {Function} Returns the "indexOf" function. */ - function lodashWrapper(value) { - this.__wrapped__ = value; + function getIndexOf(array, value, fromIndex) { + var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result; + return result; } - // ensure `new lodashWrapper` is an instance of `lodash` - lodashWrapper.prototype = lodash.prototype; /** - * A no-operation function. + * Creates a function that juggles arguments, allowing argument overloading + * for `_.flatten` and `_.uniq`, before passing them to the given `func`. * * @private + * @param {Function} func The function to wrap. + * @returns {Function} Returns the new function. */ - function noop() { - // no operation performed + function overloadWrapper(func) { + return function(array, flag, callback, thisArg) { + // juggle arguments + if (typeof flag != 'boolean' && flag != null) { + thisArg = callback; + callback = !(thisArg && thisArg[flag] === array) ? flag : undefined; + flag = false; + } + if (callback != null) { + callback = lodash.createCallback(callback, thisArg); + } + return func(array, flag, callback, thisArg); + }; } /** @@ -858,62 +1164,33 @@ * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { - // avoid non-objects and false positives for `arguments` objects - var result = false; - if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { - return result; - } - // check that the constructor is `Object` (i.e. `Object instanceof Object`) - var ctor = value.constructor; - - if (isFunction(ctor) ? ctor instanceof ctor : (support.nodeClass || !isNode(value))) { - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - if (support.ownLast) { - forIn(value, function(value, key, object) { - result = hasOwnProperty.call(object, key); - return false; - }); - return result === true; - } - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - forIn(value, function(value, key) { - result = key; - }); - return result === false || hasOwnProperty.call(value, result); - } - return result; - } + var ctor, + result; - /** - * Slices the `collection` from the `start` index up to, but not including, - * the `end` index. - * - * Note: This function is used, instead of `Array#slice`, to support node lists - * in IE < 9 and to ensure dense arrays are returned. - * - * @private - * @param {Array|Object|String} collection The collection to slice. - * @param {Number} start The start index. - * @param {Number} end The end index. - * @returns {Array} Returns the new array. - */ - function slice(array, start, end) { - start || (start = 0); - if (typeof end == 'undefined') { - end = array ? array.length : 0; + // avoid non Object objects, `arguments` objects, and DOM elements + if (!(value && toString.call(value) == objectClass) || + (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) || + (!support.argsClass && isArguments(value)) || + (!support.nodeClass && isNode(value))) { + return false; } - var index = -1, - length = end - start || 0, - result = Array(length < 0 ? 0 : length); - - while (++index < length) { - result[index] = array[start + index]; + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + if (support.ownLast) { + forIn(value, function(value, key, object) { + result = hasOwnProperty.call(object, key); + return false; + }); + return result !== false; } - return result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + forIn(value, function(value, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); } /** @@ -988,8 +1265,7 @@ 'args': 'object', 'init': '[]', 'top': 'if (!(objectTypes[typeof object])) return result', - 'loop': 'result.push(index)', - 'arrays': false + 'loop': 'result.push(index)' }); /** @@ -1030,7 +1306,7 @@ * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. */ - var each = createIterator(eachIteratorOptions); + var basicEach = createIterator(eachIteratorOptions); /** * Used to convert characters to HTML entities: @@ -1143,7 +1419,7 @@ // allows working with "Collections" methods without using their `callback` // argument, `index|key`, for this method's `callback` - if (typeof deep == 'function') { + if (typeof deep != 'boolean' && deep != null) { thisArg = callback; callback = deep; deep = false; @@ -1188,8 +1464,9 @@ return ctor(result.source, reFlags.exec(result)); } // check for circular references and return corresponding clone - stackA || (stackA = []); - stackB || (stackB = []); + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); var length = stackA.length; while (length--) { @@ -1215,10 +1492,14 @@ stackB.push(result); // recursively populate clone (susceptible to call stack limits) - (isArr ? forEach : forOwn)(value, function(objValue, key) { + (isArr ? basicEach : forOwn)(value, function(objValue, key) { result[key] = clone(objValue, deep, callback, undefined, stackA, stackB); }); + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return result; } @@ -1228,7 +1509,7 @@ * `undefined`, cloning will be handled by the method instead. The `callback` * is bound to `thisArg` and invoked with one argument; (value). * - * Note: This function is loosely based on the structured clone algorithm. Functions + * Note: This method is loosely based on the structured clone algorithm. Functions * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and * objects created by constructors other than `Object` are cloned to plain `Object` objects. * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. @@ -1665,8 +1946,9 @@ // assume cyclic structures are equal // the algorithm for detecting cyclic structures is adapted from ES 5.1 // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) - stackA || (stackA = []); - stackB || (stackB = []); + var initedStack = !stackA; + stackA || (stackA = getArray()); + stackB || (stackB = getArray()); var length = stackA.length; while (length--) { @@ -1728,6 +2010,10 @@ } }); } + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return result; } @@ -1811,7 +2097,7 @@ // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 - return value ? objectTypes[typeof value] : false; + return !!(value && objectTypes[typeof value]); } /** @@ -1932,7 +2218,7 @@ * // => true */ function isRegExp(value) { - return value ? (objectTypes[typeof value] && toString.call(value) == regexpClass) : false; + return !!(value && objectTypes[typeof value]) && toString.call(value) == regexpClass; } /** @@ -2037,8 +2323,9 @@ stackA = args[4], stackB = args[5]; } else { - stackA = []; - stackB = []; + var initedStack = true; + stackA = getArray(); + stackB = getArray(); // allows working with `_.reduce` and `_.reduceRight` without // using their `callback` arguments, `index|key` and `collection` @@ -2104,6 +2391,11 @@ object[key] = value; }); } + + if (initedStack) { + releaseArray(stackA); + releaseArray(stackB); + } return object; } @@ -2134,7 +2426,8 @@ * // => { 'name': 'moe' } */ function omit(object, callback, thisArg) { - var isFunc = typeof callback == 'function', + var indexOf = getIndexOf(), + isFunc = typeof callback == 'function', result = {}; if (isFunc) { @@ -2229,6 +2522,57 @@ return result; } + /** + * An alternative to `_.reduce`, this method transforms an `object` to a new + * `accumulator` object which is the result of running each of its elements + * through the `callback`, with each `callback` execution potentially mutating + * the `accumulator` object. The `callback` is bound to `thisArg` and invoked + * with four arguments; (accumulator, value, key, object). Callbacks may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {Mixed} [accumulator] The custom accumulator value. + * @param {Mixed} [thisArg] The `this` binding of `callback`. + * @returns {Mixed} Returns the accumulated value. + * @example + * + * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { + * num *= num; + * if (num % 2) { + * return result.push(num) < 3; + * } + * }); + * // => [1, 9, 25] + * + * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { + * result[key] = num * 3; + * }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ + function transform(object, callback, accumulator, thisArg) { + var isArr = isArray(object); + callback = lodash.createCallback(callback, thisArg, 4); + + if (accumulator == null) { + if (isArr) { + accumulator = []; + } else { + var ctor = object && object.constructor, + proto = ctor && ctor.prototype; + + accumulator = createObject(proto); + } + } + (isArr ? basicEach : forOwn)(object, function(value, index, object) { + return callback(accumulator, value, index, object); + }); + return accumulator; + } + /** * Creates an array composed of the own enumerable property values of `object`. * @@ -2321,17 +2665,18 @@ */ function contains(collection, target, fromIndex) { var index = -1, + indexOf = getIndexOf(), length = collection ? collection.length : 0, result = false; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; - if (typeof length == 'number') { + if (length && typeof length == 'number') { result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex) ) > -1; } else { - each(collection, function(value) { + basicEach(collection, function(value) { if (++index >= fromIndex) { return !(result = value === target); } @@ -2439,7 +2784,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { return (result = !!callback(value, index, collection)); }); } @@ -2501,7 +2846,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result.push(value); } @@ -2524,7 +2869,7 @@ * * @static * @memberOf _ - * @alias detect + * @alias detect, findWhere * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|Object|String} [callback=identity] The function called per @@ -2568,7 +2913,7 @@ } } else { var result; - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result = value; return false; @@ -2611,7 +2956,7 @@ } } } else { - each(collection, callback, thisArg); + basicEach(collection, callback, thisArg); } return collection; } @@ -2746,7 +3091,7 @@ result[index] = callback(collection[index], index, collection); } } else { - each(collection, function(value, key, collection) { + basicEach(collection, function(value, key, collection) { result[++index] = callback(value, key, collection); }); } @@ -2811,7 +3156,7 @@ ? charAtCallback : lodash.createCallback(callback, thisArg); - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current > computed) { computed = current; @@ -2880,7 +3225,7 @@ ? charAtCallback : lodash.createCallback(callback, thisArg); - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current < computed) { computed = current; @@ -2958,7 +3303,7 @@ accumulator = callback(accumulator, collection[index], index, collection); } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, collection) @@ -3161,7 +3506,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { return !(result = callback(value, index, collection)); }); } @@ -3210,17 +3555,18 @@ callback = lodash.createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { - result[++index] = { - 'criteria': callback(value, key, collection), - 'index': index, - 'value': value - }; + var object = result[++index] = getObject(); + object.criteria = callback(value, key, collection); + object.index = index; + object.value = value; }); length = result.length; result.sort(compareAscending); while (length--) { - result[length] = result[length].value; + var object = result[length]; + result[length] = object.value; + releaseObject(object); } return result; } @@ -3320,17 +3666,31 @@ */ function difference(array) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), - contains = cachedContains(flattened), + seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)), result = []; + var isLarge = length >= largeArraySize && indexOf === basicIndexOf; + + if (isLarge) { + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + } + } while (++index < length) { var value = array[index]; - if (!contains(value)) { + if (indexOf(seen, value) < 0) { result.push(value); } } + if (isLarge) { + releaseObject(seen); + } return result; } @@ -3486,20 +3846,11 @@ * _.flatten(stooges, 'quotes'); * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] */ - function flatten(array, isShallow, callback, thisArg) { + var flatten = overloadWrapper(function flatten(array, isShallow, callback) { var index = -1, length = array ? array.length : 0, result = []; - // juggle arguments - if (typeof isShallow != 'boolean' && isShallow != null) { - thisArg = callback; - callback = isShallow; - isShallow = false; - } - if (callback != null) { - callback = lodash.createCallback(callback, thisArg); - } while (++index < length) { var value = array[index]; if (callback) { @@ -3513,7 +3864,7 @@ } } return result; - } + }); /** * Gets the index at which the first occurrence of `value` is found using @@ -3540,21 +3891,14 @@ * // => 2 */ function indexOf(array, value, fromIndex) { - var index = -1, - length = array ? array.length : 0; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; + var length = array ? array.length : 0; + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); } else if (fromIndex) { - index = sortedIndex(array, value); + var index = sortedIndex(array, value); return array[index] === value ? index : -1; } - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; + return array ? basicIndexOf(array, value, fromIndex) : -1; } /** @@ -3650,35 +3994,45 @@ function intersection(array) { var args = arguments, argsLength = args.length, - cache = { '0': {} }, + argsIndex = -1, + caches = getArray(), index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - isLarge = length >= largeArraySize, result = [], - seen = result; + seen = getArray(); + while (++argsIndex < argsLength) { + var value = args[argsIndex]; + caches[argsIndex] = indexOf === basicIndexOf && + (value ? value.length : 0) >= largeArraySize && + createCache(argsIndex ? args[argsIndex] : seen); + } outer: while (++index < length) { - var value = array[index]; - if (isLarge) { - var key = keyPrefix + value; - var inited = cache[0][key] - ? !(seen = cache[0][key]) - : (seen = cache[0][key] = []); - } - if (inited || indexOf(seen, value) < 0) { - if (isLarge) { - seen.push(value); - } - var argsIndex = argsLength; + var cache = caches[0]; + value = array[index]; + + if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { + argsIndex = argsLength; + (cache || seen).push(value); while (--argsIndex) { - if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex])))(value)) { + cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { continue outer; } } result.push(value); } } + while (argsLength--) { + cache = caches[argsLength]; + if (cache) { + releaseObject(cache); + } + } + releaseArray(caches); + releaseArray(seen); return result; } @@ -4007,7 +4361,7 @@ * Creates a duplicate-value-free version of the `array` using strict equality * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` * for `isSorted` will run a faster algorithm. If `callback` is passed, each - * element of `array` is passed through a `callback` before uniqueness is computed. + * element of `array` is passed through the `callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * If a property name is passed for `callback`, the created "_.pluck" style @@ -4036,50 +4390,42 @@ * _.uniq([1, 1, 2, 2, 3], true); * // => [1, 2, 3] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); }); - * // => [1, 2, 3] + * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); + * // => ['A', 'b', 'C'] * - * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); - * // => [1, 2, 3] + * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); + * // => [1, 2.5, 3] * * // using "_.pluck" callback shorthand * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniq(array, isSorted, callback, thisArg) { + var uniq = overloadWrapper(function(array, isSorted, callback) { var index = -1, + indexOf = getIndexOf(), length = array ? array.length : 0, - result = [], - seen = result; + result = []; + + var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf, + seen = (callback || isLarge) ? getArray() : result; - // juggle arguments - if (typeof isSorted != 'boolean' && isSorted != null) { - thisArg = callback; - callback = isSorted; - isSorted = false; - } - // init value cache for large arrays - var isLarge = !isSorted && length >= largeArraySize; if (isLarge) { - var cache = {}; - } - if (callback != null) { - seen = []; - callback = lodash.createCallback(callback, thisArg); + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + seen = callback ? seen : (releaseArray(seen), result); + } } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; - if (isLarge) { - var key = keyPrefix + computed; - var inited = cache[key] - ? !(seen = cache[key]) - : (seen = cache[key] = []); - } if (isSorted ? !index || seen[seen.length - 1] !== computed - : inited || indexOf(seen, computed) < 0 + : indexOf(seen, computed) < 0 ) { if (callback || isLarge) { seen.push(computed); @@ -4087,8 +4433,14 @@ result.push(value); } } + if (isLarge) { + releaseArray(seen.array); + releaseObject(seen); + } else if (callback) { + releaseArray(seen); + } return result; - } + }); /** * The inverse of `_.zip`, this method splits groups of elements into arrays @@ -4106,17 +4458,11 @@ */ function unzip(array) { var index = -1, - length = array ? array.length : 0, - tupleLength = length ? max(pluck(array, 'length')) : 0, - result = Array(tupleLength); + length = array ? max(pluck(array, 'length')) : 0, + result = Array(length < 0 ? 0 : length); while (++index < length) { - var tupleIndex = -1, - tuple = array[index]; - - while (++tupleIndex < tupleLength) { - (result[tupleIndex] || (result[tupleIndex] = Array(length)))[index] = tuple[tupleIndex]; - } + result[index] = pluck(array, index); } return result; } @@ -4157,14 +4503,7 @@ * // => [['moe', 30, true], ['larry', 40, false]] */ function zip(array) { - var index = -1, - length = array ? max(pluck(arguments, 'length')) : 0, - result = Array(length); - - while (++index < length) { - result[index] = pluck(arguments, index); - } - return result; + return array ? unzip(arguments) : []; } /** @@ -4440,27 +4779,27 @@ return result; }; } - if (typeof thisArg != 'undefined') { - if (argCount === 1) { - return function(value) { - return func.call(thisArg, value); - }; - } - if (argCount === 2) { - return function(a, b) { - return func.call(thisArg, a, b); - }; - } - if (argCount === 4) { - return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return function(value, index, collection) { - return func.call(thisArg, value, index, collection); + if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) { + return func; + } + if (argCount === 1) { + return function(value) { + return func.call(thisArg, value); }; } - return func; + if (argCount === 2) { + return function(a, b) { + return func.call(thisArg, a, b); + }; + } + if (argCount === 4) { + return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; } /** @@ -4481,6 +4820,7 @@ * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. * [leading=false] A boolean to specify execution on the leading edge of the timeout. + * [maxWait] The maximum time `func` is allowed to be delayed before it's called. * [trailing=true] A boolean to specify execution on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example @@ -4495,34 +4835,80 @@ */ function debounce(func, wait, options) { var args, - inited, result, thisArg, - timeoutId, + callCount = 0, + lastCalled = 0, + maxWait = false, + maxTimeoutId = null, + timeoutId = null, trailing = true; + function clear() { + clearTimeout(maxTimeoutId); + clearTimeout(timeoutId); + callCount = 0; + maxTimeoutId = timeoutId = null; + } + function delayed() { - inited = timeoutId = null; - if (trailing) { + var isCalled = trailing && (!leading || callCount > 1); + clear(); + if (isCalled) { + if (maxWait !== false) { + lastCalled = new Date; + } + result = func.apply(thisArg, args); + } + } + + function maxDelayed() { + clear(); + if (trailing || (maxWait !== wait)) { + lastCalled = new Date; result = func.apply(thisArg, args); } } + + wait = nativeMax(0, wait || 0); if (options === true) { var leading = true; trailing = false; - } else if (options && objectTypes[typeof options]) { + } else if (isObject(options)) { leading = options.leading; + maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0); trailing = 'trailing' in options ? options.trailing : trailing; } return function() { args = arguments; thisArg = this; + callCount++; + + // avoid issues with Titanium and `undefined` timeout ids + // https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192 clearTimeout(timeoutId); - if (!inited && leading) { - inited = true; - result = func.apply(thisArg, args); + if (maxWait === false) { + if (leading && callCount < 2) { + result = func.apply(thisArg, args); + } } else { + var now = new Date; + if (!maxTimeoutId && !leading) { + lastCalled = now; + } + var remaining = maxWait - (now - lastCalled); + if (remaining <= 0) { + clearTimeout(maxTimeoutId); + maxTimeoutId = null; + lastCalled = now; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (wait !== maxWait) { timeoutId = setTimeout(delayed, wait); } return result; @@ -4580,7 +4966,8 @@ * passed, it will be used to determine the cache key for storing the result * based on the arguments passed to the memoized function. By default, the first * argument passed to the memoized function is used as the cache key. The `func` - * is executed with the `this` binding of the memoized function. + * is executed with the `this` binding of the memoized function. The result + * cache is exposed as the `cache` property on the memoized function. * * @static * @memberOf _ @@ -4595,13 +4982,16 @@ * }); */ function memoize(func, resolver) { - var cache = {}; - return function() { - var key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); + function memoized() { + var cache = memoized.cache, + key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]); + return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); - }; + } + memoized.cache = {}; + return memoized; } /** @@ -4721,47 +5111,23 @@ * })); */ function throttle(func, wait, options) { - var args, - result, - thisArg, - timeoutId, - lastCalled = 0, - leading = true, + var leading = true, trailing = true; - function trailingCall() { - timeoutId = null; - if (trailing) { - lastCalled = new Date; - result = func.apply(thisArg, args); - } - } if (options === false) { leading = false; - } else if (options && objectTypes[typeof options]) { + } else if (isObject(options)) { leading = 'leading' in options ? options.leading : leading; trailing = 'trailing' in options ? options.trailing : trailing; } - return function() { - var now = new Date; - if (!timeoutId && !leading) { - lastCalled = now; - } - var remaining = wait - (now - lastCalled); - args = arguments; - thisArg = this; + options = getObject(); + options.leading = leading; + options.maxWait = wait; + options.trailing = trailing; - if (remaining <= 0) { - clearTimeout(timeoutId); - timeoutId = null; - lastCalled = now; - result = func.apply(thisArg, args); - } - else if (!timeoutId) { - timeoutId = setTimeout(trailingCall, remaining); - } - return result; - }; + var result = debounce(func, wait, options); + releaseObject(options); + return result; } /** @@ -4814,7 +5180,7 @@ } /** - * This function returns the first argument passed to it. + * This method returns the first argument passed to it. * * @static * @memberOf _ @@ -4863,7 +5229,7 @@ push.apply(args, arguments); var result = func.apply(lodash, args); - return (value && typeof value == 'object' && value == result) + return (value && typeof value == 'object' && value === result) ? this : new lodashWrapper(result); }; @@ -4937,8 +5303,13 @@ if (max == null) { max = min; min = 0; + } else { + max = +max || 0; } - return min + floor(nativeRandom() * ((+max || 0) - min + 1)); + var rand = nativeRandom(); + return (min % 1 || max % 1) + ? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max) + : min + floor(rand * (max - min + 1)); } /** @@ -5341,6 +5712,7 @@ lodash.throttle = throttle; lodash.times = times; lodash.toArray = toArray; + lodash.transform = transform; lodash.union = union; lodash.uniq = uniq; lodash.unzip = unzip; @@ -5365,6 +5737,10 @@ // add functions to `lodash.prototype` mixin(lodash); + // add Underscore compat + lodash.chain = lodash; + lodash.prototype.chain = function() { return this; }; + /*--------------------------------------------------------------------------*/ // add functions that return unwrapped values when chaining @@ -5416,6 +5792,7 @@ lodash.all = every; lodash.any = some; lodash.detect = find; + lodash.findWhere = find; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.include = contains; @@ -5461,7 +5838,7 @@ * @memberOf _ * @type String */ - lodash.VERSION = '1.2.1'; + lodash.VERSION = '1.3.0'; // add "Chaining" functions to the wrapper lodash.prototype.toString = wrapperToString; @@ -5469,7 +5846,7 @@ lodash.prototype.valueOf = wrapperValueOf; // add `Array` functions that return unwrapped values - each(['join', 'pop', 'shift'], function(methodName) { + basicEach(['join', 'pop', 'shift'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { return func.apply(this.__wrapped__, arguments); @@ -5477,7 +5854,7 @@ }); // add `Array` functions that return the wrapped value - each(['push', 'reverse', 'sort', 'unshift'], function(methodName) { + basicEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { func.apply(this.__wrapped__, arguments); @@ -5486,7 +5863,7 @@ }); // add `Array` functions that return new wrapped values - each(['concat', 'slice', 'splice'], function(methodName) { + basicEach(['concat', 'slice', 'splice'], function(methodName) { var func = arrayRef[methodName]; lodash.prototype[methodName] = function() { return new lodashWrapper(func.apply(this.__wrapped__, arguments)); @@ -5496,7 +5873,7 @@ // avoid array-like object bugs with `Array#shift` and `Array#splice` // in Firefox < 10 and IE < 9 if (!support.spliceObjects) { - each(['pop', 'shift', 'splice'], function(methodName) { + basicEach(['pop', 'shift', 'splice'], function(methodName) { var func = arrayRef[methodName], isSplice = methodName == 'splice'; @@ -5513,7 +5890,7 @@ } // add pseudo private property to be used and removed during the build process - lodash._each = each; + lodash._basicEach = basicEach; lodash._iteratorTemplate = iteratorTemplate; lodash._shimKeys = shimKeys; diff --git a/package.json b/package.json index 28941b07ef..a4f287c2a0 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "lodash", - "version": "1.2.1", + "version": "1.3.0", "description": "A low-level utility library delivering consistency, customization, performance, and extra features.", - "homepage": "http://lodash.com", + "homepage": "http://lodash.com/", "license": "MIT", "main": "./dist/lodash.js", "keywords": [ @@ -35,5 +35,28 @@ ], "jam": { "main": "./dist/lodash.compat.js" + }, + "volo": { + "type": "directory", + "ignore": [ + ".*", + "*.custom.*", + "*.template.*", + "*.d.ts", + "*.map", + "*.md", + "*.txt", + "build.js", + "lodash.js", + "index.js", + "bower.json", + "component.json", + "build", + "doc", + "node_modules", + "perf", + "test", + "vendor" + ] } } diff --git a/perf/perf.js b/perf/perf.js index dd27c2ce2a..cfcfeedbf5 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -775,6 +775,18 @@ ) ); + suites.push( + Benchmark.Suite('`_.difference` iterating 75 elements') + .add(buildName, { + 'fn': 'lodash.difference(seventyFiveValues, seventyFiveValues2)', + 'teardown': 'function multiArrays(){}' + }) + .add(otherName, { + 'fn': '_.difference(seventyFiveValues, seventyFiveValues2)', + 'teardown': 'function multiArrays(){}' + }) + ); + suites.push( Benchmark.Suite('`_.difference` iterating 200 elements') .add(buildName, { @@ -1076,6 +1088,18 @@ ) ); + suites.push( + Benchmark.Suite('`_.intersection` iterating 75 elements') + .add(buildName, { + 'fn': 'lodash.intersection(seventyFiveValues, seventyFiveValues2)', + 'teardown': 'function multiArrays(){}' + }) + .add(otherName, { + 'fn': '_.intersection(seventyFiveValues, seventyFiveValues2)', + 'teardown': 'function multiArrays(){}' + }) + ); + suites.push( Benchmark.Suite('`_.intersection` iterating 200 elements') .add(buildName, { @@ -1731,11 +1755,23 @@ suites.push( Benchmark.Suite('`_.union` iterating an array of 75 elements') .add(buildName, { - 'fn': 'lodash.union(fiftyValues, twentyFiveValues2)', + 'fn': 'lodash.union(twentyFiveValues, fiftyValues2)', 'teardown': 'function multiArrays(){}' }) .add(otherName, { - 'fn': '_.union(fiftyValues, twentyFiveValues2)', + 'fn': '_.union(twentyFiveValues, fiftyValues2)', + 'teardown': 'function multiArrays(){}' + }) + ); + + suites.push( + Benchmark.Suite('`_.union` iterating an array of 200 elements') + .add(buildName, { + 'fn': 'lodash.union(oneHundredValues, oneHundredValues2)', + 'teardown': 'function multiArrays(){}' + }) + .add(otherName, { + 'fn': '_.union(oneHundredValues, oneHundredValues2)', 'teardown': 'function multiArrays(){}' }) ); @@ -1766,6 +1802,18 @@ ) ); + suites.push( + Benchmark.Suite('`_.uniq` iterating an array of 75 elements') + .add(buildName, { + 'fn': 'lodash.uniq(twentyFiveValues.concat(fiftyValues2))', + 'teardown': 'function multiArrays(){}' + }) + .add(otherName, { + 'fn': '_.uniq(twentyFiveValues.concat(fiftyValues2))', + 'teardown': 'function multiArrays(){}' + }) + ); + suites.push( Benchmark.Suite('`_.uniq` iterating an array of 200 elements') .add(buildName, { diff --git a/test/backbone.html b/test/backbone.html index 13d283975e..462c0e50d9 100644 --- a/test/backbone.html +++ b/test/backbone.html @@ -33,13 +33,6 @@

Test

'debounce': lodash.debounce, 'defer': lodash.defer }); - if (!_.chain) { - _.mixin({ - 'chain': function(value) { - return new _(value); - } - }); - } diff --git a/test/run-test.sh b/test/run-test.sh old mode 100755 new mode 100644 diff --git a/test/template/d.tpl b/test/template/d.tpl index c7a43bc1fd..fdb97d1a4c 100644 --- a/test/template/d.tpl +++ b/test/template/d.tpl @@ -1 +1 @@ -Hello {{ name }}! \ No newline at end of file +Hallå {{ name }}! \ No newline at end of file diff --git a/test/test-build.js b/test/test-build.js index a39496bc01..59f8a67810 100644 --- a/test/test-build.js +++ b/test/test-build.js @@ -6,7 +6,7 @@ var vm = require('vm'); /** Load other modules */ - var _ = require('../lodash.js'), + var _ = require('../dist/lodash.js'), build = require('../build.js'), minify = require('../build/minify.js'), util = require('../build/util.js'); @@ -89,13 +89,13 @@ 'zipObject': ['object'] }; - /** List of all Lo-Dash methods */ - var lodashMethods = _.functions(_).filter(function(methodName) { + /** List of all methods */ + var allMethods = _.functions(_).filter(function(methodName) { return !/^_/.test(methodName); }); - /** List of all methods */ - var allMethods = lodashMethods.concat('chain', 'findWhere'); + /** List of all Lo-Dash methods */ + var lodashMethods = _.without(allMethods, 'findWhere'); /** List of "Arrays" category methods */ var arraysMethods = [ @@ -225,6 +225,7 @@ 'omit', 'pairs', 'pick', + 'transform', 'values' ]; @@ -316,6 +317,7 @@ 'parseInt', 'partialRight', 'runInContext', + 'transform', 'unzip' ]; @@ -332,7 +334,7 @@ * @returns {String} Returns the capitalized string. */ function capitalize(string) { - return string[0].toUpperCase() + string.toLowerCase().slice(1); + return string[0].toUpperCase() + string.slice(1); } /** @@ -461,7 +463,7 @@ func(array, 'slice'); func(object, 'toFixed'); } - else if (methodName == 'where') { + else if (methodName == 'findWhere' || methodName == 'where') { func(array, object); func(object, object); } @@ -650,7 +652,7 @@ vm.runInContext(data.source, context); equal(moduleId, expectedId, basename); - equal(_.templates.d(object.d), 'Hello Mustache!', basename); + equal(_.templates.d(object.d), 'Hallå Mustache!', basename); delete _.templates; start(); }); @@ -1054,7 +1056,7 @@ ]; commands.forEach(function(command, index) { - asyncTest('`lodash ' + command +'`', function() { + asyncTest('`lodash underscore ' + command +'`', function() { var start = _.after(2, _.once(QUnit.start)); build(['-s', 'underscore', command], function(data) { @@ -1127,6 +1129,80 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('exclude command'); + + (function() { + var commands = [ + 'exclude', + 'minus' + ]; + + commands.forEach(function(command) { + asyncTest('`lodash ' + command + '=runInContext`', function() { + var start = _.after(2, _.once(QUnit.start)); + + build(['-s', command + '=runInContext'], function(data) { + var basename = path.basename(data.outputPath, '.js'), + context = createContext(), + source = data.source; + + vm.runInContext(data.source, context); + + var lodash = context._, + array = [0]; + + var actual = lodash.map(array, function() { + return String(this[0]); + }, array); + + deepEqual(actual, ['0'], basename); + equal('runInContext' in lodash, false, basename); + start(); + }); + }); + + asyncTest('`lodash ' + command + '=mixin`', function() { + var start = _.after(2, _.once(QUnit.start)); + + build(['-s', command + '=mixin'], function(data) { + var basename = path.basename(data.outputPath, '.js'), + context = createContext(), + source = data.source; + + vm.runInContext(data.source, context); + var lodash = context._; + + var actual = lodash([1, 2, 3]) + .map(function(num) { return num * num; }) + .value(); + + deepEqual(actual, [1, 4, 9], basename); + equal('mixin' in lodash, false, basename); + start(); + }); + }); + + asyncTest('`lodash ' + command + '=value`', function() { + var start = _.after(2, _.once(QUnit.start)); + + build(['-s', command + '=value'], function(data) { + var basename = path.basename(data.outputPath, '.js'), + context = createContext(), + source = data.source; + + vm.runInContext(data.source, context); + var lodash = context._; + + strictEqual(lodash([1]), undefined, basename); + deepEqual(_.keys(lodash.prototype), [], basename); + start(); + }); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('exports command'); (function() { @@ -1265,37 +1341,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('commands with findWhere'); - - (function() { - var commands = [ - 'underscore include=findWhere', - 'modern include=findWhere', - 'plus=findWhere' - ]; - - commands.forEach(function(command) { - asyncTest('`lodash ' + command + '`', function() { - var start = _.after(2, _.once(QUnit.start)); - - build(['-s'].concat(command.split(' ')), function(data) { - var basename = path.basename(data.outputPath, '.js'), - context = createContext(); - - vm.runInContext(data.source, context); - var lodash = context._; - - var collection = [{ 'a': 1 }, { 'a': 1 }]; - deepEqual(lodash.findWhere(collection, { 'a': 1 }), collection[0], '_.findWhere: ' + basename); - - start(); - }); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('no-dep option'); (function() { @@ -1334,7 +1379,8 @@ '--output b.js', '-o ' + path.join('a', 'b', 'c.js'), '-o ' + relativePrefix + path.join('a', 'b', 'c.js'), - '-o ' + path.join(nestedPath, 'c.js') + '-o ' + path.join(nestedPath, 'c.js'), + '-o name_with_keywords_like_category_include_exclude_plus_minus.js' ]; commands.forEach(function(command) { @@ -1386,6 +1432,8 @@ build(['exports=', 'include='].concat(command.split(' ')), function(data) { process.stdout.write = write; + + strictEqual('outputPath' in data, false); equal(written, data.source); equal(arguments.length, 1); start(); @@ -1396,6 +1444,111 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('underscore builds with lodash methods'); + + (function() { + var methodNames = [ + 'assign', + 'bindKey', + 'clone', + 'contains', + 'debouce', + 'defaults', + 'defer', + 'difference', + 'every', + 'filter', + 'find', + 'findWhere', + 'first', + 'flatten', + 'forEach', + 'forOwn', + 'intersection', + 'initial', + 'isEmpty', + 'isEqual', + 'isPlainObject', + 'isRegExp', + 'last', + 'map', + 'max', + 'memoize', + 'min', + 'omit', + 'partial', + 'partialRight', + 'pick', + 'pluck', + 'reduce', + 'reduceRight', + 'result', + 'rest', + 'some', + 'tap', + 'template', + 'throttle', + 'times', + 'toArray', + 'transform', + 'uniq', + 'uniqueId', + 'value', + 'where', + 'zip' + ]; + + function strip(value) { + return String(value) + .replace(/^ *\/\/.*/gm, '') + .replace(/\b(?:basicEach|context|forEach|forOwn|window)\b/g, '') + .replace(/\blodash\.(createCallback\()\b/g, '$1') + .replace(/[\s;]/g, ''); + } + + methodNames.forEach(function(methodName) { + var command = 'underscore plus=' + methodName; + + if (methodName == 'createCallback') { + command += ',where'; + } + if (methodName == 'zip') { + command += ',unzip'; + } + if (methodName != 'chain' && _.contains(chainingMethods.concat('mixin'), methodName)) { + command += ',chain'; + } + if (_.contains(['isEqual', 'isPlainObject'], methodName)) { + command += ',forIn'; + } + if (_.contains(['contains', 'every', 'find', 'some', 'transform'], methodName)) { + command += ',forOwn'; + } + asyncTest('`lodash ' + command +'`', function() { + var start = _.after(2, _.once(QUnit.start)); + + build(['-s'].concat(command.split(' ')), function(data) { + var array = [{ 'value': 1 }], + basename = path.basename(data.outputPath, '.js'), + context = createContext(); + + vm.runInContext(data.source, context, true); + var lodash = context._; + + if (methodName == 'chain' || methodName == 'findWhere' || (methodName == 'defer' && global.setImmediate)) { + notEqual(strip(lodash[methodName]), strip(_[methodName]), basename); + } else if (!/\.min$/.test(basename)) { + equal(strip(lodash[methodName]), strip(_[methodName]), basename); + } + testMethod(lodash, methodName, basename); + start(); + }); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash build'); (function() { @@ -1435,19 +1588,19 @@ var command = origCommand; if (index == 1) { - if (/legacy|mobile/.test(command)) { + if (/\b(?:legacy|mobile)\b/.test(command)) { return; } command = 'mobile ' + command; } else if (index == 2) { - if (/legacy|modern/.test(command)) { + if (/\b(?:legacy|modern)\b/.test(command)) { return; } command = 'modern ' + command; } else if (index == 3) { - if (/category|legacy|underscore/.test(command)) { + if (/\b(?:category|legacy|underscore)\b/.test(command)) { return; } command = 'underscore ' + command; @@ -1459,8 +1612,8 @@ var methodNames, basename = path.basename(data.outputPath, '.js'), context = createContext(), - isBackbone = /backbone/.test(command), - isUnderscore = isBackbone || /underscore/.test(command), + isBackbone = /\bbackbone\b/.test(command), + isUnderscore = isBackbone || /\bunderscore\b/.test(command), exposeAssign = !isUnderscore, exposeZipObject = !isUnderscore; @@ -1470,11 +1623,11 @@ console.log(e); } // add method names explicitly - if (/include/.test(command)) { - methodNames = command.match(/include=(\S*)/)[1].split(/, */); + if (/\binclude=/.test(command)) { + methodNames = command.match(/\binclude=(\S*)/)[1].split(/, */); } // add method names required by Backbone and Underscore builds - if (/backbone/.test(command) && !methodNames) { + if (/\bbackbone\b/.test(command) && !methodNames) { methodNames = backboneDependencies.slice(); } if (isUnderscore) { @@ -1485,20 +1638,22 @@ methodNames = underscoreMethods.slice(); } } - if (/category/.test(command)) { - methodNames = (methodNames || []).concat(command.match(/category=(\S*)/)[1].split(/, */).map(capitalize)); + if (/\bcategory=/.test(command)) { + methodNames = (methodNames || []).concat(command.match(/\bcategory=(\S*)/)[1].split(/, */).map(function(category) { + return capitalize(category.toLowerCase()); + })); } if (!methodNames) { methodNames = lodashMethods.slice(); } - if (/plus/.test(command)) { - methodNames = methodNames.concat(command.match(/plus=(\S*)/)[1].split(/, */)); + if (/\bplus=/.test(command)) { + methodNames = methodNames.concat(command.match(/\bplus=(\S*)/)[1].split(/, */)); } - if (/minus/.test(command)) { - methodNames = _.without.apply(_, [methodNames].concat(expandMethodNames(command.match(/minus=(\S*)/)[1].split(/, */)))); + if (/\bminus=/.test(command)) { + methodNames = _.without.apply(_, [methodNames].concat(expandMethodNames(command.match(/\bminus=(\S*)/)[1].split(/, */)))); } - if (/exclude/.test(command)) { - methodNames = _.without.apply(_, [methodNames].concat(expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */)))); + if (/\bexclude=/.test(command)) { + methodNames = _.without.apply(_, [methodNames].concat(expandMethodNames(command.match(/\bexclude=(\S*)/)[1].split(/, */)))); } // expand categories to real method names diff --git a/test/test.js b/test/test.js index 11b23cb1b9..c21766b79c 100644 --- a/test/test.js +++ b/test/test.js @@ -72,6 +72,9 @@ undefined ]; + /** Used as the size when optimizations are enabled for large arrays */ + var largeArraySize = 75; + /** Used to set property descriptors */ var setDescriptor = (function() { try { @@ -338,6 +341,23 @@ }); }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.chain'); + + (function() { + test('should return a wrapped value', function() { + var actual = _.chain({ 'a': 0 }); + ok(actual instanceof _); + }); + + test('should return the existing wrapper when chaining', function() { + var wrapper = _({ 'a': 0 }); + equal(wrapper.chain(), wrapper); + }); + }()); + /*--------------------------------------------------------------------------*/ QUnit.module('cloning'); @@ -392,11 +412,11 @@ }); }); - test('should shallow clone when used as `callback` for `_.map`', function() { + test('should perform a shallow clone when used as `callback` for `_.map`', function() { var expected = [{ 'a': [0] }, { 'b': [1] }], actual = _.map(expected, _.clone); - ok(actual != expected && actual.a == expected.a && actual.b == expected.b); + ok(actual[0] != expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b); }); test('should deep clone `index` and `input` array properties', function() { @@ -558,14 +578,19 @@ }); asyncTest('should work with `leading` option', function() { - var counts = [0, 0, 0]; + var withLeadingAndTrailing, + counts = [0, 0, 0]; + _.each([true, { 'leading': true }], function(options, index) { - var withLeading = _.debounce(function(value) { + var debounced = _.debounce(function(value) { counts[index]++; return value; }, 32, options); - equal(withLeading('x'), 'x'); + if (index == 1) { + withLeadingAndTrailing = debounced; + } + equal(debounced('x'), 'x'); }); _.times(2, _.debounce(function() { counts[2]++; }, 32, { 'leading': true })); @@ -578,6 +603,10 @@ setTimeout(function() { deepEqual(counts, [1, 1, 2]); + + withLeadingAndTrailing('x'); + equal(counts[1], 2); + QUnit.start(); }, 64); }); @@ -605,6 +634,34 @@ QUnit.start(); }, 64); }); + + asyncTest('should work with `maxWait` option', function() { + var limit = 96, + withCount = 0, + withoutCount = 0; + + var withMaxWait = _.debounce(function() { + withCount++; + }, 32, { 'maxWait': 64 }); + + var withoutMaxWait = _.debounce(function() { + withoutCount++; + }, 32); + + var start = new Date; + while ((new Date - start) < limit) { + withMaxWait(); + withoutMaxWait(); + } + strictEqual(withCount, 1); + strictEqual(withoutCount, 0); + + setTimeout(function() { + strictEqual(withCount, 2); + strictEqual(withoutCount, 1); + QUnit.start(); + }, 64); + }); }()); /*--------------------------------------------------------------------------*/ @@ -697,19 +754,21 @@ deepEqual(func({}, new Foo), {}); }); - test('lodash.' + methodName + ' should treat sparse arrays as dense', function() { - var array = Array(3); - array[0] = 1; - array[2] = 3; + if (methodName == 'merge') { + test('lodash.' + methodName + ' should treat sparse arrays as dense', function() { + var array = Array(3); + array[0] = 1; + array[2] = 3; - var actual = func([], array), - expected = array.slice(); + var actual = func([], array), + expected = array.slice(); - expected[1] = undefined; + expected[1] = undefined; - ok(1 in actual); - deepEqual(actual, expected); - }); + ok(1 in actual); + deepEqual(actual, expected); + }); + } }); /*--------------------------------------------------------------------------*/ @@ -832,7 +891,7 @@ deepEqual(args, [1, 0, array]); }); - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.first(array, function(value, index) { return this[index] < 3; }, array); @@ -905,7 +964,7 @@ deepEqual(args, [{ 'a': [1, [2]] }, 0, array]); }); - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.flatten(array, function(value, index) { return this[index].a; }, array); @@ -917,6 +976,13 @@ deepEqual(_.flatten(array, 'a'), [1, 2, 3]); }); + test('should perform a deep flatten when used as `callback` for `_.map`', function() { + var array = [[[['a']]], [[['b']]]], + actual = _.map(array, _.flatten); + + deepEqual(actual, [['a'], ['b']]); + }); + test('should treat sparse arrays as dense', function() { var array = [[1, 2, 3], Array(3)], expected = [1, 2, 3], @@ -948,7 +1014,7 @@ equal(wrapper.forEach(Boolean), wrapper); }); - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual; function callback(value, index) { @@ -988,12 +1054,25 @@ (function() { test('iterates over inherited properties', function() { - function Dog(name) { this.name = name; } - Dog.prototype.bark = function() { /* Woof, woof! */ }; + function Foo() { this.a = 1; } + Foo.prototype.b = 2; + + var keys = []; + _.forIn(new Foo, function(value, key) { keys.push(key); }); + deepEqual(keys.sort(), ['a', 'b']); + }); + + test('fixes the JScript [[DontEnum]] bug with inherited properties (test in IE < 9)', function() { + function Foo() {} + Foo.prototype = shadowedObject; + + function Bar() {} + Bar.prototype = new Foo; + Bar.prototype.constructor = Bar; var keys = []; - _.forIn(new Dog('Dagny'), function(value, key) { keys.push(key); }); - deepEqual(keys.sort(), ['bark', 'name']); + _.forIn(shadowedObject, function(value, key) { keys.push(key); }); + deepEqual(keys.sort(), shadowedProps); }); }()); @@ -1024,6 +1103,37 @@ deepEqual(keys.sort(), shadowedProps); }); + test('lodash.' + methodName + ' does not iterate over non-enumerable properties (test in IE < 9)', function() { + _.forOwn({ + 'Array': Array.prototype, + 'Boolean': Boolean.prototype, + 'Date': Date.prototype, + 'Error': Error.prototype, + 'Function': Function.prototype, + 'Object': Object.prototype, + 'Number': Number.prototype, + 'TypeError': TypeError.prototype, + 'RegExp': RegExp.prototype, + 'String': String.prototype + }, + function(object, builtin) { + var message = 'non-enumerable properties on ' + builtin + '.prototype', + props = []; + + func(object, function(value, prop) { + props.push(prop); + }); + + if (/Error/.test(builtin)) { + ok(_.every(['constructor', 'toString'], function(prop) { + return !_.contains(props, prop); + }), message); + } else { + deepEqual(props, [], message); + } + }); + }); + 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() {} Foo.prototype.a = 1; @@ -1173,7 +1283,7 @@ stringObject = Object(stringLiteral), expected = [stringLiteral, stringObject]; - var array = _.times(100, function(count) { + var array = _.times(largeArraySize, function(count) { return count % 2 ? stringObject : stringLiteral; }); @@ -1199,7 +1309,7 @@ QUnit.module('lodash.groupBy'); (function() { - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); @@ -1238,6 +1348,18 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.has'); + + (function() { + test('should return `false` for primitives', function() { + _.each(falsey.concat(1, 'a'), function(value) { + strictEqual(_.has(value, 'valueOf'), false); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.indexOf'); (function() { @@ -1274,6 +1396,68 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('custom `_.indexOf` methods'); + + (function() { + function custom(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + var other = array[index]; + if (other === value || + (_.isObject(value) && other instanceof Foo) || + (other === 'x' && /[13]/.test(value))) { + return index; + } + } + return -1; + } + + function Foo() {} + + var array = [1, new Foo, 3, new Foo], + indexOf = _.indexOf; + + test('_.contains should work with a custom `_.indexOf` method', function() { + _.indexOf = custom; + ok(_.contains(array, new Foo)); + _.indexOf = indexOf; + }); + + test('_.difference should work with a custom `_.indexOf` method', function() { + _.indexOf = custom; + deepEqual(_.difference(array, [new Foo]), [1, 3]); + _.indexOf = indexOf; + }); + + test('_.intersection should work with a custom `_.indexOf` method', function() { + _.indexOf = custom; + deepEqual(_.intersection(array, [new Foo]), [array[1]]); + _.indexOf = indexOf; + }); + + test('_.omit should work with a custom `_.indexOf` method', function() { + _.indexOf = custom; + deepEqual(_.omit(array, ['x']), { '0': 1, '2': 3 }); + _.indexOf = indexOf; + }); + + test('_.uniq should work with a custom `_.indexOf` method', function() { + _.indexOf = custom; + deepEqual(_.uniq(array), array.slice(0, 3)); + + var largeArray = _.times(largeArraySize, function() { + return new Foo; + }); + + deepEqual(_.uniq(largeArray), [largeArray[0]]); + _.indexOf = indexOf; + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.initial'); (function() { @@ -1324,7 +1508,7 @@ deepEqual(args, [3, 2, array]); }); - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.initial(array, function(value, index) { return this[index] > 1; }, array); @@ -1575,12 +1759,16 @@ } }); + test('should return `true` for empty objects', function() { + strictEqual(_.isPlainObject({}), true); + }); + test('should return `false` for Object objects without a [[Class]] of "Object"', function() { strictEqual(_.isPlainObject(arguments), false); strictEqual(_.isPlainObject(Error), false); strictEqual(_.isPlainObject(Math), false); strictEqual(_.isPlainObject(window), false); - }) + }); }()); /*--------------------------------------------------------------------------*/ @@ -1718,7 +1906,7 @@ deepEqual(args, [3, 2, array]); }); - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.last(array, function(value, index) { return this[index] > 1; }, array); @@ -1844,6 +2032,33 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.max and lodash.min chaining'); + + _.each(['max', 'min'], function(methodName) { + test('lodash.' + methodName + ' should resolve the correct value when passed an array containing only one value', function() { + var actual = _([40])[methodName]().value(); + strictEqual(actual, 40); + }); + }); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.memoize'); + + (function() { + test('should expose a `cache` object on the `memoized` function', function() { + var memoized = _.memoize(_.identity); + memoized('x'); + + var cache = memoized.cache, + key = _.keys(cache)[0]; + + equal(cache[key], 'x'); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.merge'); (function() { @@ -2234,6 +2449,15 @@ test('should coerce arguments to numbers', function() { strictEqual(_.random('1', '1'), 1); }); + + test('should support floats', function() { + var min = 1.5, + max = 1.6, + actual = _.random(min, max); + + ok(actual % 1); + ok(actual >= min && actual <= max); + }); }()); /*--------------------------------------------------------------------------*/ @@ -2537,7 +2761,7 @@ deepEqual(actual, collection); }); - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); @@ -2559,7 +2783,7 @@ QUnit.module('lodash.sortedIndex'); (function() { - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.sortedIndex([1, 2, 3], 4, function(num) { return this.sin(num); }, Math); @@ -2974,6 +3198,67 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.transform'); + + (function() { + test('should produce an that is an instance of the given object\'s constructor', function() { + function Foo() { + this.a = 1; + this.b = 2; + this.c = 3; + } + + var actual = _.transform(new Foo, function(result, value, key) { + result[key] = value * value; + }); + + ok(actual instanceof Foo); + deepEqual(_.clone(actual), { 'a': 1, 'b': 4, 'c': 9 }); + }); + + test('should treat sparse arrays as dense', function() { + var actual = _.transform(Array(1), function(result, value, index) { + result[index] = String(value); + }); + + deepEqual(actual, ['undefined']); + }); + + _.each({ + 'array': [1, 2, 3], + 'object': { 'a': 1, 'b': 2, 'c': 3 } + }, + function(object, key) { + test('should pass the correct `callback` arguments when transforming an ' + key, function() { + var args; + + _.transform(object, function() { + args || (args = slice.call(arguments)); + }); + + var first = args[0]; + if (key == 'array') { + ok(first != object && _.isArray(first)); + deepEqual(args, [first, 1, 0, object]); + } else { + ok(first != object && _.isPlainObject(first)); + deepEqual(args, [first, 1, 'a', object]); + } + }); + + test('should support the `thisArg` argument when transforming an ' + key, function() { + var actual = _.transform(object, function(result, value, key) { + result[key] = this[key]; + }, null, object); + + notEqual(actual, object); + deepEqual(actual, object); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.unescape'); (function() { @@ -3016,7 +3301,7 @@ QUnit.module('lodash.uniq'); (function() { - test('supports the `thisArg` argument', function() { + test('should support the `thisArg` argument', function() { var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math); @@ -3024,15 +3309,23 @@ deepEqual(actual, [1, 2, 3]); }); + test('should perform an unsorted uniq operation when used as `callback` for `_.map`', function() { + var array = [[2, 1, 2], [1, 2, 1]], + actual = _.map(array, _.uniq); + + deepEqual(actual, [[2, 1], [1, 2]]); + }); + test('should distinguish between numbers and numeric strings', function() { var array = [], - expected = ['2', 2, Object('2'), Object(2)]; + expected = ['2', 2, Object('2'), Object(2)], + count = Math.ceil(largeArraySize / expected.length); - _.times(50, function() { + _.times(count, function() { array.push.apply(array, expected); }); - deepEqual(_.uniq(expected), expected); + deepEqual(_.uniq(array), expected); }); _.each({ diff --git a/test/underscore.html b/test/underscore.html index e93f26d98c..5fd8e650b4 100644 --- a/test/underscore.html +++ b/test/underscore.html @@ -34,7 +34,7 @@ push = arrayProto.push, slice = arrayProto.slice; - if (_.chain) { + if (_.chain().__chain__) { return; } _.mixin = function(object) { diff --git a/vendor/benchmark.js/README.md b/vendor/benchmark.js/README.md index d2a03e3fe6..488cbc1a08 100644 --- a/vendor/benchmark.js/README.md +++ b/vendor/benchmark.js/README.md @@ -15,7 +15,7 @@ For a list of upcoming features, check out our [roadmap](https://github.com/best ## Support -Benchmark.js has been tested in at least Chrome 5~26, Firefox 2~20, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.10.5, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. +Benchmark.js has been tested in at least Chrome 5~27, Firefox 2~21, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.10.7, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. ## Installation and usage diff --git a/vendor/benchmark.js/benchmark.js b/vendor/benchmark.js/benchmark.js index 4a48ab9b5a..cb22503dff 100644 --- a/vendor/benchmark.js/benchmark.js +++ b/vendor/benchmark.js/benchmark.js @@ -1675,7 +1675,7 @@ // start timer 't#.start(d#);' + // execute `deferred.fn` and return a dummy object - '}d#.fn();return{}' + '}d#.fn();return{uid:"${uid}"}' : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count,n#=t#.ns;${setup}\n${begin};' + 'while(i#--){${fn}\n}${end};${teardown}\nreturn{elapsed:r#,uid:"${uid}"}' diff --git a/vendor/docdown/src/DocDown/Entry.php b/vendor/docdown/src/DocDown/Entry.php index f7e96f76e2..a973d9a679 100644 --- a/vendor/docdown/src/DocDown/Entry.php +++ b/vendor/docdown/src/DocDown/Entry.php @@ -58,7 +58,7 @@ public function __construct( $entry, $source, $lang = 'js' ) { * @returns {Array} The array of entries. */ public static function getEntries( $source ) { - preg_match_all('#/\*\*(?![-!])[\s\S]*?\*/\s*[^\n]+#', $source, $result); + preg_match_all('#/\*\*(?![-!])[\s\S]*?\*/\s*.+#', $source, $result); return array_pop($result); } @@ -77,7 +77,7 @@ private function isFunction() { $this->isCtor() || count($this->getParams()) || count($this->getReturns()) || - preg_match('/\* *@function\b/', $this->entry) + preg_match('/\*[\t ]*@function\b/', $this->entry) ); } return $this->_isFunction; @@ -94,10 +94,10 @@ private function isFunction() { */ public function getAliases( $index = null ) { if (!isset($this->_aliases)) { - preg_match('#\* *@alias\s+([^\n]+)#', $this->entry, $result); + preg_match('#\*[\t ]*@alias\s+(.+)#', $this->entry, $result); if (count($result)) { - $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1])); $result = preg_split('/,\s*/', $result); natsort($result); @@ -129,7 +129,7 @@ public function getCall() { } // resolve name // avoid $this->getName() because it calls $this->getCall() - preg_match('#\* *@name\s+([^\n]+)#', $this->entry, $name); + preg_match('#\*[\t ]*@name\s+(.+)#', $this->entry, $name); if (count($name)) { $name = trim($name[1]); } else { @@ -163,9 +163,9 @@ public function getCategory() { return $this->_category; } - preg_match('#\* *@category\s+([^\n]+)#', $this->entry, $result); + preg_match('#\*[\t ]*@category\s+(.+)#', $this->entry, $result); if (count($result)) { - $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1])); } else { $result = $this->getType() == 'Function' ? 'Methods' : 'Properties'; } @@ -187,9 +187,9 @@ public function getDesc() { preg_match('#/\*\*(?:\s*\*)?([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); if (count($result)) { $type = $this->getType(); - $result = preg_replace('/:\n *\* */', ":
\n", $result[1]); - $result = preg_replace('/(?:^|\n) *\*\n *\* */', "\n\n", $result); - $result = preg_replace('/(?:^|\n) *\* ?/', ' ', $result); + $result = preg_replace('/:\n[\t ]*\*[\t ]*/', ":
\n", $result[1]); + $result = preg_replace('/(?:^|\n)[\t ]*\*\n[\t ]*\*[\t ]*/', "\n\n", $result); + $result = preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result); $result = trim($result); $result = ($type == 'Function' ? '' : '(' . str_replace('|', ', ', trim($type, '{}')) . '): ') . $result; } @@ -208,9 +208,9 @@ public function getExample() { return $this->_example; } - preg_match('#\* *@example\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); + preg_match('#\*[\t ]*@example\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); if (count($result)) { - $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', "\n", $result[1])); + $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', "\n", $result[1])); $result = '```' . $this->lang . "\n" . $result . "\n```"; } $this->_example = $result; @@ -235,7 +235,7 @@ public function isAlias() { */ public function isCtor() { if (!isset($this->_isCtor)) { - $this->_isCtor = !!preg_match('/\* *@constructor\b/', $this->entry); + $this->_isCtor = !!preg_match('/\*[\t ]*@constructor\b/', $this->entry); } return $this->_isCtor; } @@ -248,7 +248,7 @@ public function isCtor() { */ public function isLicense() { if (!isset($this->_isLicense)) { - $this->_isLicense = !!preg_match('/\* *@license\b/', $this->entry); + $this->_isLicense = !!preg_match('/\*[\t ]*@license\b/', $this->entry); } return $this->_isLicense; } @@ -274,7 +274,7 @@ public function isPlugin() { */ public function isPrivate() { if (!isset($this->_isPrivate)) { - $this->_isPrivate = $this->isLicense() || !!preg_match('/\* *@private\b/', $this->entry) || !preg_match('/\* *@[a-z]+\b/', $this->entry); + $this->_isPrivate = $this->isLicense() || !!preg_match('/\*[\t ]*@private\b/', $this->entry) || !preg_match('/\*[\t ]*@[a-z]+\b/', $this->entry); } return $this->_isPrivate; } @@ -291,7 +291,7 @@ public function isStatic() { } $public = !$this->isPrivate(); - $result = $public && !!preg_match('/\* *@static\b/', $this->entry); + $result = $public && !!preg_match('/\*[\t ]*@static\b/', $this->entry); // set in cases where it isn't explicitly stated if ($public && !$result) { @@ -334,9 +334,9 @@ public function getLineNumber() { */ public function getMembers( $index = null ) { if (!isset($this->_members)) { - preg_match('#\* *@member(?:Of)?\s+([^\n]+)#', $this->entry, $result); + preg_match('#\*[\t ]*@member(?:Of)?\s+(.+)#', $this->entry, $result); if (count($result)) { - $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1])); $result = preg_split('/,\s*/', $result); natsort($result); } @@ -358,9 +358,9 @@ public function getName() { return $this->_name; } - preg_match('#\* *@name\s+([^\n]+)#', $this->entry, $result); + preg_match('#\*[\t ]*@name\s+(.+)#', $this->entry, $result); if (count($result)) { - $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1])); } else { $result = array_shift(explode('(', $this->getCall())); } @@ -377,7 +377,7 @@ public function getName() { */ public function getParams( $index = null ) { if (!isset($this->_params)) { - preg_match_all('#\* *@param\s+\{([^}]+)\}\s+(\[.+\]|[$\w|]+(?:\[.+\])?)\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#i', $this->entry, $result); + preg_match_all('#\*[\t ]*@param\s+\{([^}]+)\}\s+(\[.+\]|[$\w|]+(?:\[.+\])?)\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#i', $this->entry, $result); if (count($result = array_filter(array_slice($result, 1)))) { // repurpose array foreach ($result as $param) { @@ -385,7 +385,7 @@ public function getParams( $index = null ) { if (!is_array($result[0][$key])) { $result[0][$key] = array(); } - $result[0][$key][] = trim(preg_replace('/(?:^|\n)\s*\* */', ' ', $value)); + $result[0][$key][] = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]*/', ' ', $value)); } } $result = $result[0]; @@ -408,11 +408,11 @@ public function getReturns() { return $this->_returns; } - preg_match('#\* *@returns\s+\{([^}]+)\}\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); + preg_match('#\*[\t ]*@returns\s+\{([^}]+)\}\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); if (count($result)) { $result = array_map('trim', array_slice($result, 1)); $result[0] = str_replace('|', ', ', $result[0]); - $result[1] = preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]); + $result[1] = preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]); } $this->_returns = $result; return $result; @@ -429,9 +429,9 @@ public function getType() { return $this->_type; } - preg_match('#\* *@type\s+([^\n]+)#', $this->entry, $result); + preg_match('#\*[\t ]*@type\s+(.+)#', $this->entry, $result); if (count($result)) { - $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1])); } else { $result = $this->isFunction() ? 'Function' : 'Unknown'; } diff --git a/vendor/docdown/src/DocDown/Generator.php b/vendor/docdown/src/DocDown/Generator.php index 691d92e92b..5dc2583f8b 100644 --- a/vendor/docdown/src/DocDown/Generator.php +++ b/vendor/docdown/src/DocDown/Generator.php @@ -121,7 +121,7 @@ private static function format( $string ) { $string = preg_replace('/(^|\s)(\([^)]+\))/', '$1*$2*', $string); // mark numbers as inline code - $string = preg_replace('/ (-?\d+(?:.\d+)?)(?!\.[^\n])/', ' `$1`', $string); + $string = preg_replace('/[\t ](-?\d+(?:.\d+)?)(?!\.[^\n])/', ' `$1`', $string); // detokenize inline code snippets $counter = 0; @@ -321,9 +321,7 @@ public function generate() { $api[$member] = $entry; foreach ($entry->getAliases() as $alias) { - $api[$member] = $alias; - $alias->static = array(); - $alias->plugin = array(); + $api[$member]->static[] = $alias; } } else if ($entry->isStatic()) { @@ -559,7 +557,7 @@ function sortCompare($a, $b) { array_push($result, $closeTag, $closeTag, '', ' [1]: #' . $toc . ' "Jump back to the TOC."'); // cleanup whitespace - return trim(preg_replace('/ +\n/', "\n", join($result, "\n"))); + return trim(preg_replace('/[\t ]+\n/', "\n", join($result, "\n"))); } } ?> diff --git a/vendor/platform.js/README.md b/vendor/platform.js/README.md index a1f06caffd..8c773f1221 100644 --- a/vendor/platform.js/README.md +++ b/vendor/platform.js/README.md @@ -18,7 +18,7 @@ For a list of upcoming features, check out our [roadmap](https://github.com/best ## Support -Platform.js has been tested in at least Chrome 5~26, Firefox 2~20, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.10.5, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. +Platform.js has been tested in at least Chrome 5~27, Firefox 2~21, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.10.7, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. ## Installation and usage diff --git a/vendor/qunit-clib/README.md b/vendor/qunit-clib/README.md index 1f4f8818ed..a8d2328e0a 100644 --- a/vendor/qunit-clib/README.md +++ b/vendor/qunit-clib/README.md @@ -9,7 +9,7 @@ QUnit CLIB helps extend QUnit’s CLI support to many common CLI environments. ## Support -QUnit CLIB has been tested in at least Node.js 0.4.8-0.10.5, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. +QUnit CLIB has been tested in at least Node.js 0.4.8-0.10.7, Narwhal 0.3.2, PhantomJS 1.9.0, RingoJS 0.9, and Rhino 1.7RC5. ## Usage diff --git a/vendor/requirejs/require.js b/vendor/requirejs/require.js index 062516acd9..2109a25149 100644 --- a/vendor/requirejs/require.js +++ b/vendor/requirejs/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.5', + version = '2.1.6', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -22,7 +22,7 @@ var requirejs, require, define; hasOwn = op.hasOwnProperty, ap = Array.prototype, apsp = ap.splice, - isBrowser = !!(typeof window !== 'undefined' && navigator && document), + isBrowser = !!(typeof window !== 'undefined' && navigator && window.document), isWebWorker = !isBrowser && typeof importScripts !== 'undefined', //PS3 indicates loaded and complete, but need to wait for complete //specifically. Sequence is 'loading', 'loaded', execution, @@ -134,6 +134,10 @@ var requirejs, require, define; return document.getElementsByTagName('script'); } + function defaultOnError(err) { + throw err; + } + //Allow getting a global that expressed in //dot notation, like 'a.b.c'. function getGlobal(value) { @@ -500,7 +504,12 @@ var requirejs, require, define; fn(defined[id]); } } else { - getModule(depMap).on(name, fn); + mod = getModule(depMap); + if (mod.error && name === 'error') { + fn(mod.error); + } else { + mod.on(name, fn); + } } } @@ -571,7 +580,13 @@ var requirejs, require, define; id: mod.map.id, uri: mod.map.url, config: function () { - return (config.config && getOwn(config.config, mod.map.id)) || {}; + var c, + pkg = getOwn(config.pkgs, mod.map.id); + // For packages, only support config targeted + // at the main module. + c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) : + getOwn(config.config, mod.map.id); + return c || {}; }, exports: defined[mod.map.id] }); @@ -840,8 +855,13 @@ var requirejs, require, define; if (this.depCount < 1 && !this.defined) { if (isFunction(factory)) { //If there is an error listener, favor passing - //to that instead of throwing an error. - if (this.events.error) { + //to that instead of throwing an error. However, + //only do it for define()'d modules. require + //errbacks should not be called for failures in + //their callbacks (#699). However if a global + //onError is set, use that. + if ((this.events.error && this.map.isDefine) || + req.onError !== defaultOnError) { try { exports = context.execCb(id, factory, depExports, exports); } catch (e) { @@ -869,8 +889,8 @@ var requirejs, require, define; if (err) { err.requireMap = this.map; - err.requireModules = [this.map.id]; - err.requireType = 'define'; + err.requireModules = this.map.isDefine ? [this.map.id] : null; + err.requireType = this.map.isDefine ? 'define' : 'require'; return onError((this.error = err)); } @@ -1093,7 +1113,7 @@ var requirejs, require, define; })); if (this.errback) { - on(depMap, 'error', this.errback); + on(depMap, 'error', bind(this, this.errback)); } } @@ -1605,7 +1625,7 @@ var requirejs, require, define; }, /** - * Executes a module callack function. Broken out as a separate function + * Executes a module callback function. Broken out as a separate function * solely to allow the build system to sequence the files in the built * layer in the right sequence. * @@ -1643,7 +1663,7 @@ var requirejs, require, define; onScriptError: function (evt) { var data = getScriptData(evt); if (!hasPathFallback(data.id)) { - return onError(makeError('scripterror', 'Script error', evt, [data.id])); + return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id])); } } }; @@ -1772,9 +1792,7 @@ var requirejs, require, define; * function. Intercept/override it if you want custom error handling. * @param {Error} err the error object. */ - req.onError = function (err) { - throw err; - }; + req.onError = defaultOnError; /** * Does the request to load a module for the browser case. @@ -1906,24 +1924,31 @@ var requirejs, require, define; //baseUrl, if it is not already set. dataMain = script.getAttribute('data-main'); if (dataMain) { + //Preserve dataMain in case it is a path (i.e. contains '?') + mainScript = dataMain; + //Set final baseUrl if there is not already an explicit one. if (!cfg.baseUrl) { //Pull off the directory of data-main for use as the //baseUrl. - src = dataMain.split('/'); + src = mainScript.split('/'); mainScript = src.pop(); subPath = src.length ? src.join('/') + '/' : './'; cfg.baseUrl = subPath; - dataMain = mainScript; } - //Strip off any trailing .js since dataMain is now + //Strip off any trailing .js since mainScript is now //like a module name. - dataMain = dataMain.replace(jsSuffixRegExp, ''); + mainScript = mainScript.replace(jsSuffixRegExp, ''); + + //If mainScript is still a path, fall back to dataMain + if (req.jsExtRegExp.test(mainScript)) { + mainScript = dataMain; + } //Put the data-main script in the files to load. - cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; + cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; return true; } @@ -1951,12 +1976,13 @@ var requirejs, require, define; //This module may not have dependencies if (!isArray(deps)) { callback = deps; - deps = []; + deps = null; } //If no name, and callback is a function, then figure out if it a //CommonJS thing with dependencies. - if (!deps.length && isFunction(callback)) { + if (!deps && isFunction(callback)) { + deps = []; //Remove comments from the callback string, //look for require calls, and pull them into the dependencies, //but only if there are function args. diff --git a/vendor/underscore/underscore-min.js b/vendor/underscore/underscore-min.js index 603aeb330c..9a1c57a76f 100644 --- a/vendor/underscore/underscore-min.js +++ b/vendor/underscore/underscore-min.js @@ -3,4 +3,4 @@ // (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc. // (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. -(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,m=e.every,g=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var E="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(E);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(E);return r},w.find=w.detect=function(n,t,r){var e;return O(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:m&&n.every===m?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var O=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:g&&n.some===g?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:O(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?void 0:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.indexi;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.unzip=function(n){var t=w.max(w.pluck(n,"length"));return w.times(t,w.partial(w.pluck,n))},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i};var M=function(){};w.bind=function(n,t){var r,e;if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));if(!w.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));M.prototype=n.prototype;var u=new M;M.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw Error("bindAll must be passed function names");return A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t,r){var e,u,i,a,o=0,c=function(){o=new Date,i=null,a=n.apply(e,u)};return function(){var l=new Date;o||r!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(i),i=null,o=l,a=n.apply(e,u)):i||(i=setTimeout(c,f)),a}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&t.push(r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var S={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};S.unescape=w.invert(S.escape);var T={escape:RegExp("["+w.keys(S.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(S.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(T[n],function(t){return S[n][t]})}}),w.result=function(n,t){if(null==n)return void 0;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},z=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(z,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.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{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file +(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,m=e.every,g=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var E="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(E);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(E);return r},w.find=w.detect=function(n,t,r){var e;return O(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:m&&n.every===m?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var O=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:g&&n.some===g?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:O(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?void 0:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var F=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=F(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.indexi;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)||w.isArguments(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(w.flatten(arguments,!0))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){return w.unzip(o.call(arguments))},w.unzip=function(n){for(var t=w.max(w.pluck(n,"length").concat(0)),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i};var M=function(){};w.bind=function(n,t){var r,e;if(j&&n.bind===j)return j.apply(n,o.call(arguments,1));if(!w.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));M.prototype=n.prototype;var u=new M;M.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw Error("bindAll must be passed function names");return A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t,r){var e,u,i,a=null,o=0,c=function(){o=new Date,a=null,i=n.apply(e,u)};return function(){var l=new Date;o||r!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u)):a||(a=setTimeout(c,f)),i}},w.debounce=function(n,t,r){var e,u=null;return function(){var i=this,a=arguments,o=function(){u=null,r||(e=n.apply(i,a))},c=r&&!u;return clearTimeout(u),u=setTimeout(o,t),c&&(e=n.apply(i,a)),e}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&t.push(r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var S={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};S.unescape=w.invert(S.escape);var T={escape:RegExp("["+w.keys(S.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(S.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(T[n],function(t){return S[n][t]})}}),w.result=function(n,t){if(null==n)return void 0;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},z=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(z,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.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{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file diff --git a/vendor/underscore/underscore.js b/vendor/underscore/underscore.js index 7b116b1042..cd384fcb7c 100644 --- a/vendor/underscore/underscore.js +++ b/vendor/underscore/underscore.js @@ -266,7 +266,7 @@ var result = {computed : -Infinity, value: -Infinity}; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); + computed > result.computed && (result = {value : value, computed : computed}); }); return result.value; }; @@ -365,7 +365,7 @@ return low; }; - // Safely convert anything iterable into a real, live array. + // Safely create a real, live array from anything iterable. _.toArray = function(obj) { if (!obj) return []; if (_.isArray(obj)) return slice.call(obj); @@ -425,7 +425,7 @@ // Internal implementation of a recursive `flatten` function. var flatten = function(input, shallow, output) { each(input, function(value) { - if (_.isArray(value)) { + if (_.isArray(value) || _.isArguments(value)) { shallow ? push.apply(output, value) : flatten(value, shallow, output); } else { output.push(value); @@ -468,7 +468,7 @@ // Produce an array that contains the union: each distinct element from all of // the passed-in arrays. _.union = function() { - return _.uniq(concat.apply(ArrayProto, arguments)); + return _.uniq(_.flatten(arguments, true)); }; // Produce an array that contains every item shared between all the @@ -492,13 +492,7 @@ // Zip together multiple lists into a single array -- elements that share // an index go together. _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) { - results[i] = _.pluck(args, "" + i); - } - return results; + return _.unzip(slice.call(arguments)); }; // The inverse operation to `_.zip`. If given an array of pairs it @@ -507,9 +501,13 @@ // three element array and so on. For example, `_.unzip` given // `[['a',1],['b',2],['c',3]]` returns the array // [['a','b','c'],[1,2,3]]. - _.unzip = function(tuples) { - var maxLen = _.max(_.pluck(tuples, "length")) - return _.times(maxLen, _.partial(_.pluck, tuples)); + _.unzip = function(list) { + var length = _.max(_.pluck(list, "length").concat(0)); + var results = new Array(length); + for (var i = 0; i < length; i++) { + results[i] = _.pluck(list, '' + i); + } + return results; }; // Converts lists into objects. Pass either a single array of `[key, value]` @@ -595,7 +593,7 @@ // available. _.bind = function(func, context) { var args, bound; - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); if (!_.isFunction(func)) throw new TypeError; args = slice.call(arguments, 2); return bound = function() { @@ -653,7 +651,8 @@ // Returns a function, that, when invoked, will only be triggered at most once // during a given window of time. _.throttle = function(func, wait, immediate) { - var context, args, timeout, result; + var context, args, result; + var timeout = null; var previous = 0; var later = function() { previous = new Date; @@ -683,7 +682,8 @@ // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { - var timeout, result; + var result; + var timeout = null; return function() { var context = this, args = arguments; var later = function() {