├── .npmignore ├── .gitignore ├── test └── test.js ├── .github └── workflows │ └── ci.yml ├── README.md ├── package.json └── lodash.custom.js /.npmignore: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const test = require("ava"); 2 | const lodash = require("../") 3 | 4 | test("get", t => { 5 | t.is(lodash.get({ mine: 1 }, "mine"), 1); 6 | }); 7 | 8 | test("set", t => { 9 | let obj = { mine: 1 }; 10 | lodash.set(obj, "mine", 2) 11 | t.is(obj.mine, 2); 12 | }); 13 | 14 | test("chunk", t => { 15 | // taken from the docs https://lodash.com/docs/4.17.15#chunk 16 | t.deepEqual(lodash.chunk(['a', 'b', 'c', 'd'], 2), [['a', 'b'], ['c', 'd']]); 17 | }); -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches-ignore: 4 | - "gh-pages" 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | os: ["ubuntu-latest", "macos-latest", "windows-latest"] 11 | node: ["14", "16", "18"] 12 | name: Node.js ${{ matrix.node }} on ${{ matrix.os }} 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Setup node 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: ${{ matrix.node }} 19 | # cache: npm 20 | - run: npm install 21 | - run: npm test 22 | env: 23 | YARN_GPG: no 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @11ty/lodash-custom 2 | 3 | Eleventy uses 3 small `lodash` functions: 4 | 5 | * [`get`](https://lodash.com/docs/4#get) 6 | * [`set`](https://lodash.com/docs/4#set) 7 | * [`chunk`](https://lodash.com/docs/4#chunk) 8 | 9 | ## Why? 10 | 11 | 1. The top level `lodash` package includes all of `lodash` and is a hefty 5 MB. 12 | 1. Using the individual, modularized `lodash.get`, `lodash.set`, `lodash.chunk` packages are a much smaller 106 KB but do contain duplicated code. More problematically, these are not being maintained/updated with the newest versions of `lodash`. 13 | 14 | This package creates one focused custom dependency using the tools that `lodash` provides to do custom builds ([`lodash-cli`](https://lodash.com/custom-builds)) for these three `lodash` functions with updated versions of `lodash`. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@11ty/lodash-custom", 3 | "version": "4.17.21", 4 | "description": "A custom, focused build of lodash exclusively for use internally in Eleventy.", 5 | "main": "lodash.custom.js", 6 | "scripts": { 7 | "build": "npx lodash exports=node include=get,set,chunk && rm lodash.custom.min.js", 8 | "test": "npx ava" 9 | }, 10 | "publishConfig": { 11 | "access": "public" 12 | }, 13 | "license": "MIT", 14 | "engines": { 15 | "node": ">=14" 16 | }, 17 | "funding": { 18 | "type": "opencollective", 19 | "url": "https://opencollective.com/11ty" 20 | }, 21 | "author": { 22 | "name": "Zach Leatherman", 23 | "email": "zachleatherman@gmail.com", 24 | "url": "https://zachleat.com/" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git://github.com/11ty/lodash-custom.git" 29 | }, 30 | "bugs": "https://github.com/11ty/lodash-custom/issues", 31 | "homepage": "https://github.com/11ty/lodash-custom/", 32 | "devDependencies": { 33 | "ava": "^5.2.0", 34 | "lodash-cli": "^4.17.5" 35 | }, 36 | "overrides": { 37 | "lodash": "4.17.21" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lodash.custom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Lodash (Custom Build) 4 | * Build: `lodash exports="node" include="get,set,chunk"` 5 | * Copyright OpenJS Foundation and other contributors 6 | * Released under MIT license 7 | * Based on Underscore.js 1.8.3 8 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 9 | */ 10 | ;(function() { 11 | 12 | /** Used as a safe reference for `undefined` in pre-ES5 environments. */ 13 | var undefined; 14 | 15 | /** Used as the semantic version number. */ 16 | var VERSION = '4.17.21'; 17 | 18 | /** Error message constants. */ 19 | var FUNC_ERROR_TEXT = 'Expected a function'; 20 | 21 | /** Used to stand-in for `undefined` hash values. */ 22 | var HASH_UNDEFINED = '__lodash_hash_undefined__'; 23 | 24 | /** Used as the maximum memoize cache size. */ 25 | var MAX_MEMOIZE_SIZE = 500; 26 | 27 | /** Used as references for various `Number` constants. */ 28 | var INFINITY = 1 / 0, 29 | MAX_SAFE_INTEGER = 9007199254740991, 30 | MAX_INTEGER = 1.7976931348623157e+308, 31 | NAN = 0 / 0; 32 | 33 | /** `Object#toString` result references. */ 34 | var asyncTag = '[object AsyncFunction]', 35 | funcTag = '[object Function]', 36 | genTag = '[object GeneratorFunction]', 37 | nullTag = '[object Null]', 38 | proxyTag = '[object Proxy]', 39 | symbolTag = '[object Symbol]', 40 | undefinedTag = '[object Undefined]'; 41 | 42 | /** Used to match property names within property paths. */ 43 | var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, 44 | reIsPlainProp = /^\w*$/, 45 | rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; 46 | 47 | /** 48 | * Used to match `RegExp` 49 | * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). 50 | */ 51 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; 52 | 53 | /** Used to match leading whitespace. */ 54 | var reTrimStart = /^\s+/; 55 | 56 | /** Used to match a single whitespace character. */ 57 | var reWhitespace = /\s/; 58 | 59 | /** Used to match backslashes in property paths. */ 60 | var reEscapeChar = /\\(\\)?/g; 61 | 62 | /** Used to detect bad signed hexadecimal string values. */ 63 | var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; 64 | 65 | /** Used to detect binary string values. */ 66 | var reIsBinary = /^0b[01]+$/i; 67 | 68 | /** Used to detect host constructors (Safari). */ 69 | var reIsHostCtor = /^\[object .+?Constructor\]$/; 70 | 71 | /** Used to detect octal string values. */ 72 | var reIsOctal = /^0o[0-7]+$/i; 73 | 74 | /** Used to detect unsigned integer values. */ 75 | var reIsUint = /^(?:0|[1-9]\d*)$/; 76 | 77 | /** Built-in method references without a dependency on `root`. */ 78 | var freeParseInt = parseInt; 79 | 80 | /** Detect free variable `global` from Node.js. */ 81 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; 82 | 83 | /** Detect free variable `self`. */ 84 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self; 85 | 86 | /** Used as a reference to the global object. */ 87 | var root = freeGlobal || freeSelf || Function('return this')(); 88 | 89 | /** Detect free variable `exports`. */ 90 | var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; 91 | 92 | /** Detect free variable `module`. */ 93 | var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; 94 | 95 | /*--------------------------------------------------------------------------*/ 96 | 97 | /** 98 | * A specialized version of `_.map` for arrays without support for iteratee 99 | * shorthands. 100 | * 101 | * @private 102 | * @param {Array} [array] The array to iterate over. 103 | * @param {Function} iteratee The function invoked per iteration. 104 | * @returns {Array} Returns the new mapped array. 105 | */ 106 | function arrayMap(array, iteratee) { 107 | var index = -1, 108 | length = array == null ? 0 : array.length, 109 | result = Array(length); 110 | 111 | while (++index < length) { 112 | result[index] = iteratee(array[index], index, array); 113 | } 114 | return result; 115 | } 116 | 117 | /** 118 | * The base implementation of `_.trim`. 119 | * 120 | * @private 121 | * @param {string} string The string to trim. 122 | * @returns {string} Returns the trimmed string. 123 | */ 124 | function baseTrim(string) { 125 | return string 126 | ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') 127 | : string; 128 | } 129 | 130 | /** 131 | * Gets the value at `key` of `object`. 132 | * 133 | * @private 134 | * @param {Object} [object] The object to query. 135 | * @param {string} key The key of the property to get. 136 | * @returns {*} Returns the property value. 137 | */ 138 | function getValue(object, key) { 139 | return object == null ? undefined : object[key]; 140 | } 141 | 142 | /** 143 | * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace 144 | * character of `string`. 145 | * 146 | * @private 147 | * @param {string} string The string to inspect. 148 | * @returns {number} Returns the index of the last non-whitespace character. 149 | */ 150 | function trimmedEndIndex(string) { 151 | var index = string.length; 152 | 153 | while (index-- && reWhitespace.test(string.charAt(index))) {} 154 | return index; 155 | } 156 | 157 | /*--------------------------------------------------------------------------*/ 158 | 159 | /** Used for built-in method references. */ 160 | var arrayProto = Array.prototype, 161 | funcProto = Function.prototype, 162 | objectProto = Object.prototype; 163 | 164 | /** Used to detect overreaching core-js shims. */ 165 | var coreJsData = root['__core-js_shared__']; 166 | 167 | /** Used to resolve the decompiled source of functions. */ 168 | var funcToString = funcProto.toString; 169 | 170 | /** Used to check objects for own properties. */ 171 | var hasOwnProperty = objectProto.hasOwnProperty; 172 | 173 | /** Used to detect methods masquerading as native. */ 174 | var maskSrcKey = (function() { 175 | var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); 176 | return uid ? ('Symbol(src)_1.' + uid) : ''; 177 | }()); 178 | 179 | /** 180 | * Used to resolve the 181 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 182 | * of values. 183 | */ 184 | var nativeObjectToString = objectProto.toString; 185 | 186 | /** Used to detect if a method is native. */ 187 | var reIsNative = RegExp('^' + 188 | funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') 189 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 190 | ); 191 | 192 | /** Built-in value references. */ 193 | var Symbol = root.Symbol, 194 | splice = arrayProto.splice, 195 | symToStringTag = Symbol ? Symbol.toStringTag : undefined; 196 | 197 | var defineProperty = (function() { 198 | try { 199 | var func = getNative(Object, 'defineProperty'); 200 | func({}, '', {}); 201 | return func; 202 | } catch (e) {} 203 | }()); 204 | 205 | /* Built-in method references for those with the same name as other `lodash` methods. */ 206 | var nativeCeil = Math.ceil, 207 | nativeMax = Math.max; 208 | 209 | /* Built-in method references that are verified to be native. */ 210 | var Map = getNative(root, 'Map'), 211 | nativeCreate = getNative(Object, 'create'); 212 | 213 | /** Used to lookup unminified function names. */ 214 | var realNames = {}; 215 | 216 | /** Used to convert symbols to primitives and strings. */ 217 | var symbolProto = Symbol ? Symbol.prototype : undefined, 218 | symbolToString = symbolProto ? symbolProto.toString : undefined; 219 | 220 | /*------------------------------------------------------------------------*/ 221 | 222 | /** 223 | * Creates a `lodash` object which wraps `value` to enable implicit method 224 | * chain sequences. Methods that operate on and return arrays, collections, 225 | * and functions can be chained together. Methods that retrieve a single value 226 | * or may return a primitive value will automatically end the chain sequence 227 | * and return the unwrapped value. Otherwise, the value must be unwrapped 228 | * with `_#value`. 229 | * 230 | * Explicit chain sequences, which must be unwrapped with `_#value`, may be 231 | * enabled using `_.chain`. 232 | * 233 | * The execution of chained methods is lazy, that is, it's deferred until 234 | * `_#value` is implicitly or explicitly called. 235 | * 236 | * Lazy evaluation allows several methods to support shortcut fusion. 237 | * Shortcut fusion is an optimization to merge iteratee calls; this avoids 238 | * the creation of intermediate arrays and can greatly reduce the number of 239 | * iteratee executions. Sections of a chain sequence qualify for shortcut 240 | * fusion if the section is applied to an array and iteratees accept only 241 | * one argument. The heuristic for whether a section qualifies for shortcut 242 | * fusion is subject to change. 243 | * 244 | * Chaining is supported in custom builds as long as the `_#value` method is 245 | * directly or indirectly included in the build. 246 | * 247 | * In addition to lodash methods, wrappers have `Array` and `String` methods. 248 | * 249 | * The wrapper `Array` methods are: 250 | * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` 251 | * 252 | * The wrapper `String` methods are: 253 | * `replace` and `split` 254 | * 255 | * The wrapper methods that support shortcut fusion are: 256 | * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, 257 | * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, 258 | * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` 259 | * 260 | * The chainable wrapper methods are: 261 | * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, 262 | * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, 263 | * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, 264 | * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, 265 | * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, 266 | * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, 267 | * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, 268 | * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, 269 | * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, 270 | * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, 271 | * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, 272 | * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, 273 | * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, 274 | * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, 275 | * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, 276 | * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, 277 | * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, 278 | * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, 279 | * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, 280 | * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, 281 | * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, 282 | * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, 283 | * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, 284 | * `zipObject`, `zipObjectDeep`, and `zipWith` 285 | * 286 | * The wrapper methods that are **not** chainable by default are: 287 | * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, 288 | * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, 289 | * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, 290 | * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, 291 | * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, 292 | * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, 293 | * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, 294 | * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, 295 | * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, 296 | * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, 297 | * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, 298 | * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, 299 | * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, 300 | * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, 301 | * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, 302 | * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, 303 | * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, 304 | * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, 305 | * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, 306 | * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, 307 | * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, 308 | * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, 309 | * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, 310 | * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, 311 | * `upperFirst`, `value`, and `words` 312 | * 313 | * @name _ 314 | * @constructor 315 | * @category Seq 316 | * @param {*} value The value to wrap in a `lodash` instance. 317 | * @returns {Object} Returns the new `lodash` wrapper instance. 318 | * @example 319 | * 320 | * function square(n) { 321 | * return n * n; 322 | * } 323 | * 324 | * var wrapped = _([1, 2, 3]); 325 | * 326 | * // Returns an unwrapped value. 327 | * wrapped.reduce(_.add); 328 | * // => 6 329 | * 330 | * // Returns a wrapped value. 331 | * var squares = wrapped.map(square); 332 | * 333 | * _.isArray(squares); 334 | * // => false 335 | * 336 | * _.isArray(squares.value()); 337 | * // => true 338 | */ 339 | function lodash() { 340 | // No operation performed. 341 | } 342 | 343 | /*------------------------------------------------------------------------*/ 344 | 345 | /** 346 | * Creates a hash object. 347 | * 348 | * @private 349 | * @constructor 350 | * @param {Array} [entries] The key-value pairs to cache. 351 | */ 352 | function Hash(entries) { 353 | var index = -1, 354 | length = entries == null ? 0 : entries.length; 355 | 356 | this.clear(); 357 | while (++index < length) { 358 | var entry = entries[index]; 359 | this.set(entry[0], entry[1]); 360 | } 361 | } 362 | 363 | /** 364 | * Removes all key-value entries from the hash. 365 | * 366 | * @private 367 | * @name clear 368 | * @memberOf Hash 369 | */ 370 | function hashClear() { 371 | this.__data__ = nativeCreate ? nativeCreate(null) : {}; 372 | this.size = 0; 373 | } 374 | 375 | /** 376 | * Removes `key` and its value from the hash. 377 | * 378 | * @private 379 | * @name delete 380 | * @memberOf Hash 381 | * @param {Object} hash The hash to modify. 382 | * @param {string} key The key of the value to remove. 383 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 384 | */ 385 | function hashDelete(key) { 386 | var result = this.has(key) && delete this.__data__[key]; 387 | this.size -= result ? 1 : 0; 388 | return result; 389 | } 390 | 391 | /** 392 | * Gets the hash value for `key`. 393 | * 394 | * @private 395 | * @name get 396 | * @memberOf Hash 397 | * @param {string} key The key of the value to get. 398 | * @returns {*} Returns the entry value. 399 | */ 400 | function hashGet(key) { 401 | var data = this.__data__; 402 | if (nativeCreate) { 403 | var result = data[key]; 404 | return result === HASH_UNDEFINED ? undefined : result; 405 | } 406 | return hasOwnProperty.call(data, key) ? data[key] : undefined; 407 | } 408 | 409 | /** 410 | * Checks if a hash value for `key` exists. 411 | * 412 | * @private 413 | * @name has 414 | * @memberOf Hash 415 | * @param {string} key The key of the entry to check. 416 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 417 | */ 418 | function hashHas(key) { 419 | var data = this.__data__; 420 | return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); 421 | } 422 | 423 | /** 424 | * Sets the hash `key` to `value`. 425 | * 426 | * @private 427 | * @name set 428 | * @memberOf Hash 429 | * @param {string} key The key of the value to set. 430 | * @param {*} value The value to set. 431 | * @returns {Object} Returns the hash instance. 432 | */ 433 | function hashSet(key, value) { 434 | var data = this.__data__; 435 | this.size += this.has(key) ? 0 : 1; 436 | data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; 437 | return this; 438 | } 439 | 440 | // Add methods to `Hash`. 441 | Hash.prototype.clear = hashClear; 442 | Hash.prototype['delete'] = hashDelete; 443 | Hash.prototype.get = hashGet; 444 | Hash.prototype.has = hashHas; 445 | Hash.prototype.set = hashSet; 446 | 447 | /*------------------------------------------------------------------------*/ 448 | 449 | /** 450 | * Creates an list cache object. 451 | * 452 | * @private 453 | * @constructor 454 | * @param {Array} [entries] The key-value pairs to cache. 455 | */ 456 | function ListCache(entries) { 457 | var index = -1, 458 | length = entries == null ? 0 : entries.length; 459 | 460 | this.clear(); 461 | while (++index < length) { 462 | var entry = entries[index]; 463 | this.set(entry[0], entry[1]); 464 | } 465 | } 466 | 467 | /** 468 | * Removes all key-value entries from the list cache. 469 | * 470 | * @private 471 | * @name clear 472 | * @memberOf ListCache 473 | */ 474 | function listCacheClear() { 475 | this.__data__ = []; 476 | this.size = 0; 477 | } 478 | 479 | /** 480 | * Removes `key` and its value from the list cache. 481 | * 482 | * @private 483 | * @name delete 484 | * @memberOf ListCache 485 | * @param {string} key The key of the value to remove. 486 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 487 | */ 488 | function listCacheDelete(key) { 489 | var data = this.__data__, 490 | index = assocIndexOf(data, key); 491 | 492 | if (index < 0) { 493 | return false; 494 | } 495 | var lastIndex = data.length - 1; 496 | if (index == lastIndex) { 497 | data.pop(); 498 | } else { 499 | splice.call(data, index, 1); 500 | } 501 | --this.size; 502 | return true; 503 | } 504 | 505 | /** 506 | * Gets the list cache value for `key`. 507 | * 508 | * @private 509 | * @name get 510 | * @memberOf ListCache 511 | * @param {string} key The key of the value to get. 512 | * @returns {*} Returns the entry value. 513 | */ 514 | function listCacheGet(key) { 515 | var data = this.__data__, 516 | index = assocIndexOf(data, key); 517 | 518 | return index < 0 ? undefined : data[index][1]; 519 | } 520 | 521 | /** 522 | * Checks if a list cache value for `key` exists. 523 | * 524 | * @private 525 | * @name has 526 | * @memberOf ListCache 527 | * @param {string} key The key of the entry to check. 528 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 529 | */ 530 | function listCacheHas(key) { 531 | return assocIndexOf(this.__data__, key) > -1; 532 | } 533 | 534 | /** 535 | * Sets the list cache `key` to `value`. 536 | * 537 | * @private 538 | * @name set 539 | * @memberOf ListCache 540 | * @param {string} key The key of the value to set. 541 | * @param {*} value The value to set. 542 | * @returns {Object} Returns the list cache instance. 543 | */ 544 | function listCacheSet(key, value) { 545 | var data = this.__data__, 546 | index = assocIndexOf(data, key); 547 | 548 | if (index < 0) { 549 | ++this.size; 550 | data.push([key, value]); 551 | } else { 552 | data[index][1] = value; 553 | } 554 | return this; 555 | } 556 | 557 | // Add methods to `ListCache`. 558 | ListCache.prototype.clear = listCacheClear; 559 | ListCache.prototype['delete'] = listCacheDelete; 560 | ListCache.prototype.get = listCacheGet; 561 | ListCache.prototype.has = listCacheHas; 562 | ListCache.prototype.set = listCacheSet; 563 | 564 | /*------------------------------------------------------------------------*/ 565 | 566 | /** 567 | * Creates a map cache object to store key-value pairs. 568 | * 569 | * @private 570 | * @constructor 571 | * @param {Array} [entries] The key-value pairs to cache. 572 | */ 573 | function MapCache(entries) { 574 | var index = -1, 575 | length = entries == null ? 0 : entries.length; 576 | 577 | this.clear(); 578 | while (++index < length) { 579 | var entry = entries[index]; 580 | this.set(entry[0], entry[1]); 581 | } 582 | } 583 | 584 | /** 585 | * Removes all key-value entries from the map. 586 | * 587 | * @private 588 | * @name clear 589 | * @memberOf MapCache 590 | */ 591 | function mapCacheClear() { 592 | this.size = 0; 593 | this.__data__ = { 594 | 'hash': new Hash, 595 | 'map': new (Map || ListCache), 596 | 'string': new Hash 597 | }; 598 | } 599 | 600 | /** 601 | * Removes `key` and its value from the map. 602 | * 603 | * @private 604 | * @name delete 605 | * @memberOf MapCache 606 | * @param {string} key The key of the value to remove. 607 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 608 | */ 609 | function mapCacheDelete(key) { 610 | var result = getMapData(this, key)['delete'](key); 611 | this.size -= result ? 1 : 0; 612 | return result; 613 | } 614 | 615 | /** 616 | * Gets the map value for `key`. 617 | * 618 | * @private 619 | * @name get 620 | * @memberOf MapCache 621 | * @param {string} key The key of the value to get. 622 | * @returns {*} Returns the entry value. 623 | */ 624 | function mapCacheGet(key) { 625 | return getMapData(this, key).get(key); 626 | } 627 | 628 | /** 629 | * Checks if a map value for `key` exists. 630 | * 631 | * @private 632 | * @name has 633 | * @memberOf MapCache 634 | * @param {string} key The key of the entry to check. 635 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 636 | */ 637 | function mapCacheHas(key) { 638 | return getMapData(this, key).has(key); 639 | } 640 | 641 | /** 642 | * Sets the map `key` to `value`. 643 | * 644 | * @private 645 | * @name set 646 | * @memberOf MapCache 647 | * @param {string} key The key of the value to set. 648 | * @param {*} value The value to set. 649 | * @returns {Object} Returns the map cache instance. 650 | */ 651 | function mapCacheSet(key, value) { 652 | var data = getMapData(this, key), 653 | size = data.size; 654 | 655 | data.set(key, value); 656 | this.size += data.size == size ? 0 : 1; 657 | return this; 658 | } 659 | 660 | // Add methods to `MapCache`. 661 | MapCache.prototype.clear = mapCacheClear; 662 | MapCache.prototype['delete'] = mapCacheDelete; 663 | MapCache.prototype.get = mapCacheGet; 664 | MapCache.prototype.has = mapCacheHas; 665 | MapCache.prototype.set = mapCacheSet; 666 | 667 | /*------------------------------------------------------------------------*/ 668 | 669 | /** 670 | * Assigns `value` to `key` of `object` if the existing value is not equivalent 671 | * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) 672 | * for equality comparisons. 673 | * 674 | * @private 675 | * @param {Object} object The object to modify. 676 | * @param {string} key The key of the property to assign. 677 | * @param {*} value The value to assign. 678 | */ 679 | function assignValue(object, key, value) { 680 | var objValue = object[key]; 681 | if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || 682 | (value === undefined && !(key in object))) { 683 | baseAssignValue(object, key, value); 684 | } 685 | } 686 | 687 | /** 688 | * Gets the index at which the `key` is found in `array` of key-value pairs. 689 | * 690 | * @private 691 | * @param {Array} array The array to inspect. 692 | * @param {*} key The key to search for. 693 | * @returns {number} Returns the index of the matched value, else `-1`. 694 | */ 695 | function assocIndexOf(array, key) { 696 | var length = array.length; 697 | while (length--) { 698 | if (eq(array[length][0], key)) { 699 | return length; 700 | } 701 | } 702 | return -1; 703 | } 704 | 705 | /** 706 | * The base implementation of `assignValue` and `assignMergeValue` without 707 | * value checks. 708 | * 709 | * @private 710 | * @param {Object} object The object to modify. 711 | * @param {string} key The key of the property to assign. 712 | * @param {*} value The value to assign. 713 | */ 714 | function baseAssignValue(object, key, value) { 715 | if (key == '__proto__' && defineProperty) { 716 | defineProperty(object, key, { 717 | 'configurable': true, 718 | 'enumerable': true, 719 | 'value': value, 720 | 'writable': true 721 | }); 722 | } else { 723 | object[key] = value; 724 | } 725 | } 726 | 727 | /** 728 | * The base implementation of `_.get` without support for default values. 729 | * 730 | * @private 731 | * @param {Object} object The object to query. 732 | * @param {Array|string} path The path of the property to get. 733 | * @returns {*} Returns the resolved value. 734 | */ 735 | function baseGet(object, path) { 736 | path = castPath(path, object); 737 | 738 | var index = 0, 739 | length = path.length; 740 | 741 | while (object != null && index < length) { 742 | object = object[toKey(path[index++])]; 743 | } 744 | return (index && index == length) ? object : undefined; 745 | } 746 | 747 | /** 748 | * The base implementation of `getTag` without fallbacks for buggy environments. 749 | * 750 | * @private 751 | * @param {*} value The value to query. 752 | * @returns {string} Returns the `toStringTag`. 753 | */ 754 | function baseGetTag(value) { 755 | if (value == null) { 756 | return value === undefined ? undefinedTag : nullTag; 757 | } 758 | return (symToStringTag && symToStringTag in Object(value)) 759 | ? getRawTag(value) 760 | : objectToString(value); 761 | } 762 | 763 | /** 764 | * The base implementation of `_.isNative` without bad shim checks. 765 | * 766 | * @private 767 | * @param {*} value The value to check. 768 | * @returns {boolean} Returns `true` if `value` is a native function, 769 | * else `false`. 770 | */ 771 | function baseIsNative(value) { 772 | if (!isObject(value) || isMasked(value)) { 773 | return false; 774 | } 775 | var pattern = isFunction(value) ? reIsNative : reIsHostCtor; 776 | return pattern.test(toSource(value)); 777 | } 778 | 779 | /** 780 | * The base implementation of `_.set`. 781 | * 782 | * @private 783 | * @param {Object} object The object to modify. 784 | * @param {Array|string} path The path of the property to set. 785 | * @param {*} value The value to set. 786 | * @param {Function} [customizer] The function to customize path creation. 787 | * @returns {Object} Returns `object`. 788 | */ 789 | function baseSet(object, path, value, customizer) { 790 | if (!isObject(object)) { 791 | return object; 792 | } 793 | path = castPath(path, object); 794 | 795 | var index = -1, 796 | length = path.length, 797 | lastIndex = length - 1, 798 | nested = object; 799 | 800 | while (nested != null && ++index < length) { 801 | var key = toKey(path[index]), 802 | newValue = value; 803 | 804 | if (key === '__proto__' || key === 'constructor' || key === 'prototype') { 805 | return object; 806 | } 807 | 808 | if (index != lastIndex) { 809 | var objValue = nested[key]; 810 | newValue = customizer ? customizer(objValue, key, nested) : undefined; 811 | if (newValue === undefined) { 812 | newValue = isObject(objValue) 813 | ? objValue 814 | : (isIndex(path[index + 1]) ? [] : {}); 815 | } 816 | } 817 | assignValue(nested, key, newValue); 818 | nested = nested[key]; 819 | } 820 | return object; 821 | } 822 | 823 | /** 824 | * The base implementation of `_.slice` without an iteratee call guard. 825 | * 826 | * @private 827 | * @param {Array} array The array to slice. 828 | * @param {number} [start=0] The start position. 829 | * @param {number} [end=array.length] The end position. 830 | * @returns {Array} Returns the slice of `array`. 831 | */ 832 | function baseSlice(array, start, end) { 833 | var index = -1, 834 | length = array.length; 835 | 836 | if (start < 0) { 837 | start = -start > length ? 0 : (length + start); 838 | } 839 | end = end > length ? length : end; 840 | if (end < 0) { 841 | end += length; 842 | } 843 | length = start > end ? 0 : ((end - start) >>> 0); 844 | start >>>= 0; 845 | 846 | var result = Array(length); 847 | while (++index < length) { 848 | result[index] = array[index + start]; 849 | } 850 | return result; 851 | } 852 | 853 | /** 854 | * The base implementation of `_.toString` which doesn't convert nullish 855 | * values to empty strings. 856 | * 857 | * @private 858 | * @param {*} value The value to process. 859 | * @returns {string} Returns the string. 860 | */ 861 | function baseToString(value) { 862 | // Exit early for strings to avoid a performance hit in some environments. 863 | if (typeof value == 'string') { 864 | return value; 865 | } 866 | if (isArray(value)) { 867 | // Recursively convert values (susceptible to call stack limits). 868 | return arrayMap(value, baseToString) + ''; 869 | } 870 | if (isSymbol(value)) { 871 | return symbolToString ? symbolToString.call(value) : ''; 872 | } 873 | var result = (value + ''); 874 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 875 | } 876 | 877 | /** 878 | * Casts `value` to a path array if it's not one. 879 | * 880 | * @private 881 | * @param {*} value The value to inspect. 882 | * @param {Object} [object] The object to query keys on. 883 | * @returns {Array} Returns the cast property path array. 884 | */ 885 | function castPath(value, object) { 886 | if (isArray(value)) { 887 | return value; 888 | } 889 | return isKey(value, object) ? [value] : stringToPath(toString(value)); 890 | } 891 | 892 | /** 893 | * Gets the data for `map`. 894 | * 895 | * @private 896 | * @param {Object} map The map to query. 897 | * @param {string} key The reference key. 898 | * @returns {*} Returns the map data. 899 | */ 900 | function getMapData(map, key) { 901 | var data = map.__data__; 902 | return isKeyable(key) 903 | ? data[typeof key == 'string' ? 'string' : 'hash'] 904 | : data.map; 905 | } 906 | 907 | /** 908 | * Gets the native function at `key` of `object`. 909 | * 910 | * @private 911 | * @param {Object} object The object to query. 912 | * @param {string} key The key of the method to get. 913 | * @returns {*} Returns the function if it's native, else `undefined`. 914 | */ 915 | function getNative(object, key) { 916 | var value = getValue(object, key); 917 | return baseIsNative(value) ? value : undefined; 918 | } 919 | 920 | /** 921 | * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. 922 | * 923 | * @private 924 | * @param {*} value The value to query. 925 | * @returns {string} Returns the raw `toStringTag`. 926 | */ 927 | function getRawTag(value) { 928 | var isOwn = hasOwnProperty.call(value, symToStringTag), 929 | tag = value[symToStringTag]; 930 | 931 | try { 932 | value[symToStringTag] = undefined; 933 | var unmasked = true; 934 | } catch (e) {} 935 | 936 | var result = nativeObjectToString.call(value); 937 | if (unmasked) { 938 | if (isOwn) { 939 | value[symToStringTag] = tag; 940 | } else { 941 | delete value[symToStringTag]; 942 | } 943 | } 944 | return result; 945 | } 946 | 947 | /** 948 | * Checks if `value` is a valid array-like index. 949 | * 950 | * @private 951 | * @param {*} value The value to check. 952 | * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. 953 | * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. 954 | */ 955 | function isIndex(value, length) { 956 | var type = typeof value; 957 | length = length == null ? MAX_SAFE_INTEGER : length; 958 | 959 | return !!length && 960 | (type == 'number' || 961 | (type != 'symbol' && reIsUint.test(value))) && 962 | (value > -1 && value % 1 == 0 && value < length); 963 | } 964 | 965 | /** 966 | * Checks if the given arguments are from an iteratee call. 967 | * 968 | * @private 969 | * @param {*} value The potential iteratee value argument. 970 | * @param {*} index The potential iteratee index or key argument. 971 | * @param {*} object The potential iteratee object argument. 972 | * @returns {boolean} Returns `true` if the arguments are from an iteratee call, 973 | * else `false`. 974 | */ 975 | function isIterateeCall(value, index, object) { 976 | if (!isObject(object)) { 977 | return false; 978 | } 979 | var type = typeof index; 980 | if (type == 'number' 981 | ? (isArrayLike(object) && isIndex(index, object.length)) 982 | : (type == 'string' && index in object) 983 | ) { 984 | return eq(object[index], value); 985 | } 986 | return false; 987 | } 988 | 989 | /** 990 | * Checks if `value` is a property name and not a property path. 991 | * 992 | * @private 993 | * @param {*} value The value to check. 994 | * @param {Object} [object] The object to query keys on. 995 | * @returns {boolean} Returns `true` if `value` is a property name, else `false`. 996 | */ 997 | function isKey(value, object) { 998 | if (isArray(value)) { 999 | return false; 1000 | } 1001 | var type = typeof value; 1002 | if (type == 'number' || type == 'symbol' || type == 'boolean' || 1003 | value == null || isSymbol(value)) { 1004 | return true; 1005 | } 1006 | return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || 1007 | (object != null && value in Object(object)); 1008 | } 1009 | 1010 | /** 1011 | * Checks if `value` is suitable for use as unique object key. 1012 | * 1013 | * @private 1014 | * @param {*} value The value to check. 1015 | * @returns {boolean} Returns `true` if `value` is suitable, else `false`. 1016 | */ 1017 | function isKeyable(value) { 1018 | var type = typeof value; 1019 | return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') 1020 | ? (value !== '__proto__') 1021 | : (value === null); 1022 | } 1023 | 1024 | /** 1025 | * Checks if `func` has its source masked. 1026 | * 1027 | * @private 1028 | * @param {Function} func The function to check. 1029 | * @returns {boolean} Returns `true` if `func` is masked, else `false`. 1030 | */ 1031 | function isMasked(func) { 1032 | return !!maskSrcKey && (maskSrcKey in func); 1033 | } 1034 | 1035 | /** 1036 | * A specialized version of `_.memoize` which clears the memoized function's 1037 | * cache when it exceeds `MAX_MEMOIZE_SIZE`. 1038 | * 1039 | * @private 1040 | * @param {Function} func The function to have its output memoized. 1041 | * @returns {Function} Returns the new memoized function. 1042 | */ 1043 | function memoizeCapped(func) { 1044 | var result = memoize(func, function(key) { 1045 | if (cache.size === MAX_MEMOIZE_SIZE) { 1046 | cache.clear(); 1047 | } 1048 | return key; 1049 | }); 1050 | 1051 | var cache = result.cache; 1052 | return result; 1053 | } 1054 | 1055 | /** 1056 | * Converts `value` to a string using `Object.prototype.toString`. 1057 | * 1058 | * @private 1059 | * @param {*} value The value to convert. 1060 | * @returns {string} Returns the converted string. 1061 | */ 1062 | function objectToString(value) { 1063 | return nativeObjectToString.call(value); 1064 | } 1065 | 1066 | /** 1067 | * Converts `string` to a property path array. 1068 | * 1069 | * @private 1070 | * @param {string} string The string to convert. 1071 | * @returns {Array} Returns the property path array. 1072 | */ 1073 | var stringToPath = memoizeCapped(function(string) { 1074 | var result = []; 1075 | if (string.charCodeAt(0) === 46 /* . */) { 1076 | result.push(''); 1077 | } 1078 | string.replace(rePropName, function(match, number, quote, subString) { 1079 | result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); 1080 | }); 1081 | return result; 1082 | }); 1083 | 1084 | /** 1085 | * Converts `value` to a string key if it's not a string or symbol. 1086 | * 1087 | * @private 1088 | * @param {*} value The value to inspect. 1089 | * @returns {string|symbol} Returns the key. 1090 | */ 1091 | function toKey(value) { 1092 | if (typeof value == 'string' || isSymbol(value)) { 1093 | return value; 1094 | } 1095 | var result = (value + ''); 1096 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 1097 | } 1098 | 1099 | /** 1100 | * Converts `func` to its source code. 1101 | * 1102 | * @private 1103 | * @param {Function} func The function to convert. 1104 | * @returns {string} Returns the source code. 1105 | */ 1106 | function toSource(func) { 1107 | if (func != null) { 1108 | try { 1109 | return funcToString.call(func); 1110 | } catch (e) {} 1111 | try { 1112 | return (func + ''); 1113 | } catch (e) {} 1114 | } 1115 | return ''; 1116 | } 1117 | 1118 | /*------------------------------------------------------------------------*/ 1119 | 1120 | /** 1121 | * Creates an array of elements split into groups the length of `size`. 1122 | * If `array` can't be split evenly, the final chunk will be the remaining 1123 | * elements. 1124 | * 1125 | * @static 1126 | * @memberOf _ 1127 | * @since 3.0.0 1128 | * @category Array 1129 | * @param {Array} array The array to process. 1130 | * @param {number} [size=1] The length of each chunk 1131 | * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. 1132 | * @returns {Array} Returns the new array of chunks. 1133 | * @example 1134 | * 1135 | * _.chunk(['a', 'b', 'c', 'd'], 2); 1136 | * // => [['a', 'b'], ['c', 'd']] 1137 | * 1138 | * _.chunk(['a', 'b', 'c', 'd'], 3); 1139 | * // => [['a', 'b', 'c'], ['d']] 1140 | */ 1141 | function chunk(array, size, guard) { 1142 | if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { 1143 | size = 1; 1144 | } else { 1145 | size = nativeMax(toInteger(size), 0); 1146 | } 1147 | var length = array == null ? 0 : array.length; 1148 | if (!length || size < 1) { 1149 | return []; 1150 | } 1151 | var index = 0, 1152 | resIndex = 0, 1153 | result = Array(nativeCeil(length / size)); 1154 | 1155 | while (index < length) { 1156 | result[resIndex++] = baseSlice(array, index, (index += size)); 1157 | } 1158 | return result; 1159 | } 1160 | 1161 | /*------------------------------------------------------------------------*/ 1162 | 1163 | /** 1164 | * Creates a function that memoizes the result of `func`. If `resolver` is 1165 | * provided, it determines the cache key for storing the result based on the 1166 | * arguments provided to the memoized function. By default, the first argument 1167 | * provided to the memoized function is used as the map cache key. The `func` 1168 | * is invoked with the `this` binding of the memoized function. 1169 | * 1170 | * **Note:** The cache is exposed as the `cache` property on the memoized 1171 | * function. Its creation may be customized by replacing the `_.memoize.Cache` 1172 | * constructor with one whose instances implement the 1173 | * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) 1174 | * method interface of `clear`, `delete`, `get`, `has`, and `set`. 1175 | * 1176 | * @static 1177 | * @memberOf _ 1178 | * @since 0.1.0 1179 | * @category Function 1180 | * @param {Function} func The function to have its output memoized. 1181 | * @param {Function} [resolver] The function to resolve the cache key. 1182 | * @returns {Function} Returns the new memoized function. 1183 | * @example 1184 | * 1185 | * var object = { 'a': 1, 'b': 2 }; 1186 | * var other = { 'c': 3, 'd': 4 }; 1187 | * 1188 | * var values = _.memoize(_.values); 1189 | * values(object); 1190 | * // => [1, 2] 1191 | * 1192 | * values(other); 1193 | * // => [3, 4] 1194 | * 1195 | * object.a = 2; 1196 | * values(object); 1197 | * // => [1, 2] 1198 | * 1199 | * // Modify the result cache. 1200 | * values.cache.set(object, ['a', 'b']); 1201 | * values(object); 1202 | * // => ['a', 'b'] 1203 | * 1204 | * // Replace `_.memoize.Cache`. 1205 | * _.memoize.Cache = WeakMap; 1206 | */ 1207 | function memoize(func, resolver) { 1208 | if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { 1209 | throw new TypeError(FUNC_ERROR_TEXT); 1210 | } 1211 | var memoized = function() { 1212 | var args = arguments, 1213 | key = resolver ? resolver.apply(this, args) : args[0], 1214 | cache = memoized.cache; 1215 | 1216 | if (cache.has(key)) { 1217 | return cache.get(key); 1218 | } 1219 | var result = func.apply(this, args); 1220 | memoized.cache = cache.set(key, result) || cache; 1221 | return result; 1222 | }; 1223 | memoized.cache = new (memoize.Cache || MapCache); 1224 | return memoized; 1225 | } 1226 | 1227 | // Expose `MapCache`. 1228 | memoize.Cache = MapCache; 1229 | 1230 | /*------------------------------------------------------------------------*/ 1231 | 1232 | /** 1233 | * Performs a 1234 | * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) 1235 | * comparison between two values to determine if they are equivalent. 1236 | * 1237 | * @static 1238 | * @memberOf _ 1239 | * @since 4.0.0 1240 | * @category Lang 1241 | * @param {*} value The value to compare. 1242 | * @param {*} other The other value to compare. 1243 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 1244 | * @example 1245 | * 1246 | * var object = { 'a': 1 }; 1247 | * var other = { 'a': 1 }; 1248 | * 1249 | * _.eq(object, object); 1250 | * // => true 1251 | * 1252 | * _.eq(object, other); 1253 | * // => false 1254 | * 1255 | * _.eq('a', 'a'); 1256 | * // => true 1257 | * 1258 | * _.eq('a', Object('a')); 1259 | * // => false 1260 | * 1261 | * _.eq(NaN, NaN); 1262 | * // => true 1263 | */ 1264 | function eq(value, other) { 1265 | return value === other || (value !== value && other !== other); 1266 | } 1267 | 1268 | /** 1269 | * Checks if `value` is classified as an `Array` object. 1270 | * 1271 | * @static 1272 | * @memberOf _ 1273 | * @since 0.1.0 1274 | * @category Lang 1275 | * @param {*} value The value to check. 1276 | * @returns {boolean} Returns `true` if `value` is an array, else `false`. 1277 | * @example 1278 | * 1279 | * _.isArray([1, 2, 3]); 1280 | * // => true 1281 | * 1282 | * _.isArray(document.body.children); 1283 | * // => false 1284 | * 1285 | * _.isArray('abc'); 1286 | * // => false 1287 | * 1288 | * _.isArray(_.noop); 1289 | * // => false 1290 | */ 1291 | var isArray = Array.isArray; 1292 | 1293 | /** 1294 | * Checks if `value` is array-like. A value is considered array-like if it's 1295 | * not a function and has a `value.length` that's an integer greater than or 1296 | * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. 1297 | * 1298 | * @static 1299 | * @memberOf _ 1300 | * @since 4.0.0 1301 | * @category Lang 1302 | * @param {*} value The value to check. 1303 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 1304 | * @example 1305 | * 1306 | * _.isArrayLike([1, 2, 3]); 1307 | * // => true 1308 | * 1309 | * _.isArrayLike(document.body.children); 1310 | * // => true 1311 | * 1312 | * _.isArrayLike('abc'); 1313 | * // => true 1314 | * 1315 | * _.isArrayLike(_.noop); 1316 | * // => false 1317 | */ 1318 | function isArrayLike(value) { 1319 | return value != null && isLength(value.length) && !isFunction(value); 1320 | } 1321 | 1322 | /** 1323 | * Checks if `value` is classified as a `Function` object. 1324 | * 1325 | * @static 1326 | * @memberOf _ 1327 | * @since 0.1.0 1328 | * @category Lang 1329 | * @param {*} value The value to check. 1330 | * @returns {boolean} Returns `true` if `value` is a function, else `false`. 1331 | * @example 1332 | * 1333 | * _.isFunction(_); 1334 | * // => true 1335 | * 1336 | * _.isFunction(/abc/); 1337 | * // => false 1338 | */ 1339 | function isFunction(value) { 1340 | if (!isObject(value)) { 1341 | return false; 1342 | } 1343 | // The use of `Object#toString` avoids issues with the `typeof` operator 1344 | // in Safari 9 which returns 'object' for typed arrays and other constructors. 1345 | var tag = baseGetTag(value); 1346 | return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; 1347 | } 1348 | 1349 | /** 1350 | * Checks if `value` is a valid array-like length. 1351 | * 1352 | * **Note:** This method is loosely based on 1353 | * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). 1354 | * 1355 | * @static 1356 | * @memberOf _ 1357 | * @since 4.0.0 1358 | * @category Lang 1359 | * @param {*} value The value to check. 1360 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 1361 | * @example 1362 | * 1363 | * _.isLength(3); 1364 | * // => true 1365 | * 1366 | * _.isLength(Number.MIN_VALUE); 1367 | * // => false 1368 | * 1369 | * _.isLength(Infinity); 1370 | * // => false 1371 | * 1372 | * _.isLength('3'); 1373 | * // => false 1374 | */ 1375 | function isLength(value) { 1376 | return typeof value == 'number' && 1377 | value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; 1378 | } 1379 | 1380 | /** 1381 | * Checks if `value` is the 1382 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) 1383 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 1384 | * 1385 | * @static 1386 | * @memberOf _ 1387 | * @since 0.1.0 1388 | * @category Lang 1389 | * @param {*} value The value to check. 1390 | * @returns {boolean} Returns `true` if `value` is an object, else `false`. 1391 | * @example 1392 | * 1393 | * _.isObject({}); 1394 | * // => true 1395 | * 1396 | * _.isObject([1, 2, 3]); 1397 | * // => true 1398 | * 1399 | * _.isObject(_.noop); 1400 | * // => true 1401 | * 1402 | * _.isObject(null); 1403 | * // => false 1404 | */ 1405 | function isObject(value) { 1406 | var type = typeof value; 1407 | return value != null && (type == 'object' || type == 'function'); 1408 | } 1409 | 1410 | /** 1411 | * Checks if `value` is object-like. A value is object-like if it's not `null` 1412 | * and has a `typeof` result of "object". 1413 | * 1414 | * @static 1415 | * @memberOf _ 1416 | * @since 4.0.0 1417 | * @category Lang 1418 | * @param {*} value The value to check. 1419 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 1420 | * @example 1421 | * 1422 | * _.isObjectLike({}); 1423 | * // => true 1424 | * 1425 | * _.isObjectLike([1, 2, 3]); 1426 | * // => true 1427 | * 1428 | * _.isObjectLike(_.noop); 1429 | * // => false 1430 | * 1431 | * _.isObjectLike(null); 1432 | * // => false 1433 | */ 1434 | function isObjectLike(value) { 1435 | return value != null && typeof value == 'object'; 1436 | } 1437 | 1438 | /** 1439 | * Checks if `value` is classified as a `Symbol` primitive or object. 1440 | * 1441 | * @static 1442 | * @memberOf _ 1443 | * @since 4.0.0 1444 | * @category Lang 1445 | * @param {*} value The value to check. 1446 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. 1447 | * @example 1448 | * 1449 | * _.isSymbol(Symbol.iterator); 1450 | * // => true 1451 | * 1452 | * _.isSymbol('abc'); 1453 | * // => false 1454 | */ 1455 | function isSymbol(value) { 1456 | return typeof value == 'symbol' || 1457 | (isObjectLike(value) && baseGetTag(value) == symbolTag); 1458 | } 1459 | 1460 | /** 1461 | * Converts `value` to a finite number. 1462 | * 1463 | * @static 1464 | * @memberOf _ 1465 | * @since 4.12.0 1466 | * @category Lang 1467 | * @param {*} value The value to convert. 1468 | * @returns {number} Returns the converted number. 1469 | * @example 1470 | * 1471 | * _.toFinite(3.2); 1472 | * // => 3.2 1473 | * 1474 | * _.toFinite(Number.MIN_VALUE); 1475 | * // => 5e-324 1476 | * 1477 | * _.toFinite(Infinity); 1478 | * // => 1.7976931348623157e+308 1479 | * 1480 | * _.toFinite('3.2'); 1481 | * // => 3.2 1482 | */ 1483 | function toFinite(value) { 1484 | if (!value) { 1485 | return value === 0 ? value : 0; 1486 | } 1487 | value = toNumber(value); 1488 | if (value === INFINITY || value === -INFINITY) { 1489 | var sign = (value < 0 ? -1 : 1); 1490 | return sign * MAX_INTEGER; 1491 | } 1492 | return value === value ? value : 0; 1493 | } 1494 | 1495 | /** 1496 | * Converts `value` to an integer. 1497 | * 1498 | * **Note:** This method is loosely based on 1499 | * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). 1500 | * 1501 | * @static 1502 | * @memberOf _ 1503 | * @since 4.0.0 1504 | * @category Lang 1505 | * @param {*} value The value to convert. 1506 | * @returns {number} Returns the converted integer. 1507 | * @example 1508 | * 1509 | * _.toInteger(3.2); 1510 | * // => 3 1511 | * 1512 | * _.toInteger(Number.MIN_VALUE); 1513 | * // => 0 1514 | * 1515 | * _.toInteger(Infinity); 1516 | * // => 1.7976931348623157e+308 1517 | * 1518 | * _.toInteger('3.2'); 1519 | * // => 3 1520 | */ 1521 | function toInteger(value) { 1522 | var result = toFinite(value), 1523 | remainder = result % 1; 1524 | 1525 | return result === result ? (remainder ? result - remainder : result) : 0; 1526 | } 1527 | 1528 | /** 1529 | * Converts `value` to a number. 1530 | * 1531 | * @static 1532 | * @memberOf _ 1533 | * @since 4.0.0 1534 | * @category Lang 1535 | * @param {*} value The value to process. 1536 | * @returns {number} Returns the number. 1537 | * @example 1538 | * 1539 | * _.toNumber(3.2); 1540 | * // => 3.2 1541 | * 1542 | * _.toNumber(Number.MIN_VALUE); 1543 | * // => 5e-324 1544 | * 1545 | * _.toNumber(Infinity); 1546 | * // => Infinity 1547 | * 1548 | * _.toNumber('3.2'); 1549 | * // => 3.2 1550 | */ 1551 | function toNumber(value) { 1552 | if (typeof value == 'number') { 1553 | return value; 1554 | } 1555 | if (isSymbol(value)) { 1556 | return NAN; 1557 | } 1558 | if (isObject(value)) { 1559 | var other = typeof value.valueOf == 'function' ? value.valueOf() : value; 1560 | value = isObject(other) ? (other + '') : other; 1561 | } 1562 | if (typeof value != 'string') { 1563 | return value === 0 ? value : +value; 1564 | } 1565 | value = baseTrim(value); 1566 | var isBinary = reIsBinary.test(value); 1567 | return (isBinary || reIsOctal.test(value)) 1568 | ? freeParseInt(value.slice(2), isBinary ? 2 : 8) 1569 | : (reIsBadHex.test(value) ? NAN : +value); 1570 | } 1571 | 1572 | /** 1573 | * Converts `value` to a string. An empty string is returned for `null` 1574 | * and `undefined` values. The sign of `-0` is preserved. 1575 | * 1576 | * @static 1577 | * @memberOf _ 1578 | * @since 4.0.0 1579 | * @category Lang 1580 | * @param {*} value The value to convert. 1581 | * @returns {string} Returns the converted string. 1582 | * @example 1583 | * 1584 | * _.toString(null); 1585 | * // => '' 1586 | * 1587 | * _.toString(-0); 1588 | * // => '-0' 1589 | * 1590 | * _.toString([1, 2, 3]); 1591 | * // => '1,2,3' 1592 | */ 1593 | function toString(value) { 1594 | return value == null ? '' : baseToString(value); 1595 | } 1596 | 1597 | /*------------------------------------------------------------------------*/ 1598 | 1599 | /** 1600 | * Gets the value at `path` of `object`. If the resolved value is 1601 | * `undefined`, the `defaultValue` is returned in its place. 1602 | * 1603 | * @static 1604 | * @memberOf _ 1605 | * @since 3.7.0 1606 | * @category Object 1607 | * @param {Object} object The object to query. 1608 | * @param {Array|string} path The path of the property to get. 1609 | * @param {*} [defaultValue] The value returned for `undefined` resolved values. 1610 | * @returns {*} Returns the resolved value. 1611 | * @example 1612 | * 1613 | * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 1614 | * 1615 | * _.get(object, 'a[0].b.c'); 1616 | * // => 3 1617 | * 1618 | * _.get(object, ['a', '0', 'b', 'c']); 1619 | * // => 3 1620 | * 1621 | * _.get(object, 'a.b.c', 'default'); 1622 | * // => 'default' 1623 | */ 1624 | function get(object, path, defaultValue) { 1625 | var result = object == null ? undefined : baseGet(object, path); 1626 | return result === undefined ? defaultValue : result; 1627 | } 1628 | 1629 | /** 1630 | * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, 1631 | * it's created. Arrays are created for missing index properties while objects 1632 | * are created for all other missing properties. Use `_.setWith` to customize 1633 | * `path` creation. 1634 | * 1635 | * **Note:** This method mutates `object`. 1636 | * 1637 | * @static 1638 | * @memberOf _ 1639 | * @since 3.7.0 1640 | * @category Object 1641 | * @param {Object} object The object to modify. 1642 | * @param {Array|string} path The path of the property to set. 1643 | * @param {*} value The value to set. 1644 | * @returns {Object} Returns `object`. 1645 | * @example 1646 | * 1647 | * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 1648 | * 1649 | * _.set(object, 'a[0].b.c', 4); 1650 | * console.log(object.a[0].b.c); 1651 | * // => 4 1652 | * 1653 | * _.set(object, ['x', '0', 'y', 'z'], 5); 1654 | * console.log(object.x[0].y.z); 1655 | * // => 5 1656 | */ 1657 | function set(object, path, value) { 1658 | return object == null ? object : baseSet(object, path, value); 1659 | } 1660 | 1661 | /*------------------------------------------------------------------------*/ 1662 | 1663 | // Add methods that return wrapped values in chain sequences. 1664 | lodash.chunk = chunk; 1665 | lodash.memoize = memoize; 1666 | lodash.set = set; 1667 | 1668 | /*------------------------------------------------------------------------*/ 1669 | 1670 | // Add methods that return unwrapped values in chain sequences. 1671 | lodash.eq = eq; 1672 | lodash.get = get; 1673 | lodash.isArray = isArray; 1674 | lodash.isArrayLike = isArrayLike; 1675 | lodash.isFunction = isFunction; 1676 | lodash.isLength = isLength; 1677 | lodash.isObject = isObject; 1678 | lodash.isObjectLike = isObjectLike; 1679 | lodash.isSymbol = isSymbol; 1680 | lodash.toFinite = toFinite; 1681 | lodash.toInteger = toInteger; 1682 | lodash.toNumber = toNumber; 1683 | lodash.toString = toString; 1684 | 1685 | /*------------------------------------------------------------------------*/ 1686 | 1687 | /** 1688 | * The semantic version number. 1689 | * 1690 | * @static 1691 | * @memberOf _ 1692 | * @type {string} 1693 | */ 1694 | lodash.VERSION = VERSION; 1695 | 1696 | /*--------------------------------------------------------------------------*/ 1697 | 1698 | if (freeModule) { 1699 | // Export for Node.js. 1700 | (freeModule.exports = lodash)._ = lodash; 1701 | // Export for CommonJS support. 1702 | freeExports._ = lodash; 1703 | } 1704 | }.call(this)); 1705 | --------------------------------------------------------------------------------