├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README.zh-CN.md ├── dist └── smartArrayToTree.js ├── example ├── browser │ ├── index.html │ └── smartArrayToTree.js ├── data.json └── node │ └── index.js ├── index.js ├── package.json ├── test └── test.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 internet5 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](./README.zh-CN.md) 2 | 3 | # smart-array-to-tree 4 | [![Build Status](https://travis-ci.org/internet5/smart-array-to-tree.svg?branch=master)](https://travis-ci.org/internet5/smart-array-to-tree)
5 | Convert large amounts of data array to nested data structure fastly!
6 | Use the test data that array length 46086, just take about 0.1 second.
7 |
8 | 9 | # Installation && Usage 10 | 11 | In Node.js: 12 | ```shell 13 | $ npm i smart-arraytotree --save 14 | ``` 15 | ```javascript 16 | var smartArrayToTree = require('../index.js'); 17 | var fetch = require('node-fetch'); 18 | //get test data length 46086 19 | fetch('https://raw.githubusercontent.com/internet5/smart-array-to-tree/master/example/data.json').then(function(response) { 20 | return response.json(); 21 | }).then(function(data) { 22 | //start time 23 | console.log(new Date()); 24 | //transform 25 | let tree = smartArrayToTree(data, { id:'regionId', pid:'parentId', firstPid:null }); 26 | //end time 27 | console.log(new Date()); 28 | }).catch(function(e) { 29 | console.log(e); 30 | }); 31 | /*console*/ 32 | //2017-11-21T09:51:37.930Z 33 | //2017-11-21T09:51:37.979Z 34 | ``` 35 | 36 | In a browser: 37 | ```html 38 | 39 | ``` 40 | ```html 41 | 43 | 44 | 54 | ``` 55 | ## API 56 | ### `smartArrayToTree(data, [options])` 57 | 58 | #### Parameters 59 | - **Array** `data`: An array of data 60 | - **Object** `options`: An object containing the following fields: 61 | - `id` (String): An unique node identifier. Default: 'id' 62 | - `pid` (String): A name of a property where a link to a parent node could be found. Default: 'pid' 63 | - `children` (String): The child node name that you want. Default: 'children' 64 |  - `firstPid` (String): The parent id of top level node . Default: null 65 | 66 | #### Return 67 | - **Array**: Result of transformation 68 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | [English](./README.md) | 简体中文 2 | 3 | # smart-array-to-tree 4 | [![Build Status](https://travis-ci.org/internet5/smart-array-to-tree.svg?branch=master)](https://travis-ci.org/internet5/smart-array-to-tree)
5 | 快速地转换数据量比较大的数组为树结构,转换数组长度为46086的组数时,只花了大约0.1秒的时间,而其他转换工具对于这个数据量要么就是转换不正确,要么就是直接挂掉 6 | # 安装 && 用法 7 | 8 | 在node中: 9 | ```shell 10 | $ npm i smart-arraytotree --save 11 | ``` 12 | ```javascript 13 | var smartArrayToTree = require('../index.js'); 14 | var fetch = require('node-fetch'); 15 | //get test data length 46086 16 | fetch('https://raw.githubusercontent.com/internet5/smart-array-to-tree/master/example/data.json').then(function(response) { 17 | return response.json(); 18 | }).then(function(data) { 19 | //start time 20 | console.log(new Date()); 21 | //transform 22 | let tree = smartArrayToTree(data, { id:'regionId', pid:'parentId', firstPid:null }); 23 | //end time 24 | console.log(new Date()); 25 | }).catch(function(e) { 26 | console.log(e); 27 | }); 28 | /*console*/ 29 | //2017-11-21T09:51:37.930Z 30 | //2017-11-21T09:51:37.979Z 31 | ``` 32 | 33 | 在浏览器中: 34 | ```html 35 | 36 | ``` 37 | ```html 38 | 40 | 41 | 51 | ``` 52 | ## API 53 | ### `smartArrayToTree(data, [options])` 54 | 55 | #### 参数 56 | - **Array** `data`: 数组数据 57 | - **Object** `options`: 包含下列属性的配置对象: 58 | - `id` (String): 数据的ID属性名称. 默认值: 'id' 59 | - `pid` (String): 数据的父ID属性名称. 默认值: 'pid' 60 | - `children` (String): 返回树结构对象中子节点属性名称. 默认值: 'children' 61 | - `firstPid` (String): 将作为树结构顶层节点的父节点值 . 默认值: null 62 | 63 | #### 返回 64 | - **Array**: 返回转换后的树结构数据 65 | -------------------------------------------------------------------------------- /dist/smartArrayToTree.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { 40 | /******/ configurable: false, 41 | /******/ enumerable: true, 42 | /******/ get: getter 43 | /******/ }); 44 | /******/ } 45 | /******/ }; 46 | /******/ 47 | /******/ // getDefaultExport function for compatibility with non-harmony modules 48 | /******/ __webpack_require__.n = function(module) { 49 | /******/ var getter = module && module.__esModule ? 50 | /******/ function getDefault() { return module['default']; } : 51 | /******/ function getModuleExports() { return module; }; 52 | /******/ __webpack_require__.d(getter, 'a', getter); 53 | /******/ return getter; 54 | /******/ }; 55 | /******/ 56 | /******/ // Object.prototype.hasOwnProperty.call 57 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 | /******/ 59 | /******/ // __webpack_public_path__ 60 | /******/ __webpack_require__.p = ""; 61 | /******/ 62 | /******/ // Load entry module and return exports 63 | /******/ return __webpack_require__(__webpack_require__.s = 1); 64 | /******/ }) 65 | /************************************************************************/ 66 | /******/ ([ 67 | /* 0 */ 68 | /***/ (function(module, exports) { 69 | 70 | var g; 71 | 72 | // This works in non-strict mode 73 | g = (function() { 74 | return this; 75 | })(); 76 | 77 | try { 78 | // This works if eval is allowed (see CSP) 79 | g = g || Function("return this")() || (1,eval)("this"); 80 | } catch(e) { 81 | // This works if the window reference is available 82 | if(typeof window === "object") 83 | g = window; 84 | } 85 | 86 | // g can still be undefined, but nothing to do about it... 87 | // We return undefined, instead of nothing here, so it's 88 | // easier to handle this case. if(!global) { ...} 89 | 90 | module.exports = g; 91 | 92 | 93 | /***/ }), 94 | /* 1 */ 95 | /***/ (function(module, exports, __webpack_require__) { 96 | 97 | "use strict"; 98 | /* WEBPACK VAR INJECTION */(function(global) { 99 | 100 | var groupBy = __webpack_require__(2) 101 | function smartArrayToTree(array, options) { 102 | options = Object.assign({ 103 | id: 'id', 104 | pid: 'pid', 105 | children: 'children', 106 | firstPid: null 107 | }, options); 108 | var groupArray = groupBy(array, function (n) { 109 | return n[options.pid]; 110 | }); 111 | var firstArray = groupArray[options.firstPid]; 112 | transform(firstArray); 113 | function transform(startList) { 114 | if (startList) 115 | for (var i = 0; i < startList.length; i++) { 116 | groupArray[startList[i][options.id]] && (startList[i][options.children] = groupArray[startList[i][options.id]]); 117 | transform(startList[i][options.children]); 118 | } 119 | } 120 | return firstArray; 121 | } 122 | global.smartArrayToTree=smartArrayToTree; 123 | module.exports=smartArrayToTree; 124 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 125 | 126 | /***/ }), 127 | /* 2 */ 128 | /***/ (function(module, exports, __webpack_require__) { 129 | 130 | /* WEBPACK VAR INJECTION */(function(global, module) {/** 131 | * lodash (Custom Build) 132 | * Build: `lodash modularize exports="npm" -o ./` 133 | * Copyright jQuery Foundation and other contributors 134 | * Released under MIT license 135 | * Based on Underscore.js 1.8.3 136 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 137 | */ 138 | 139 | /** Used as the size to enable large array optimizations. */ 140 | var LARGE_ARRAY_SIZE = 200; 141 | 142 | /** Used as the `TypeError` message for "Functions" methods. */ 143 | var FUNC_ERROR_TEXT = 'Expected a function'; 144 | 145 | /** Used to stand-in for `undefined` hash values. */ 146 | var HASH_UNDEFINED = '__lodash_hash_undefined__'; 147 | 148 | /** Used to compose bitmasks for comparison styles. */ 149 | var UNORDERED_COMPARE_FLAG = 1, 150 | PARTIAL_COMPARE_FLAG = 2; 151 | 152 | /** Used as references for various `Number` constants. */ 153 | var INFINITY = 1 / 0, 154 | MAX_SAFE_INTEGER = 9007199254740991; 155 | 156 | /** `Object#toString` result references. */ 157 | var argsTag = '[object Arguments]', 158 | arrayTag = '[object Array]', 159 | boolTag = '[object Boolean]', 160 | dateTag = '[object Date]', 161 | errorTag = '[object Error]', 162 | funcTag = '[object Function]', 163 | genTag = '[object GeneratorFunction]', 164 | mapTag = '[object Map]', 165 | numberTag = '[object Number]', 166 | objectTag = '[object Object]', 167 | promiseTag = '[object Promise]', 168 | regexpTag = '[object RegExp]', 169 | setTag = '[object Set]', 170 | stringTag = '[object String]', 171 | symbolTag = '[object Symbol]', 172 | weakMapTag = '[object WeakMap]'; 173 | 174 | var arrayBufferTag = '[object ArrayBuffer]', 175 | dataViewTag = '[object DataView]', 176 | float32Tag = '[object Float32Array]', 177 | float64Tag = '[object Float64Array]', 178 | int8Tag = '[object Int8Array]', 179 | int16Tag = '[object Int16Array]', 180 | int32Tag = '[object Int32Array]', 181 | uint8Tag = '[object Uint8Array]', 182 | uint8ClampedTag = '[object Uint8ClampedArray]', 183 | uint16Tag = '[object Uint16Array]', 184 | uint32Tag = '[object Uint32Array]'; 185 | 186 | /** Used to match property names within property paths. */ 187 | var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, 188 | reIsPlainProp = /^\w*$/, 189 | reLeadingDot = /^\./, 190 | rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; 191 | 192 | /** 193 | * Used to match `RegExp` 194 | * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). 195 | */ 196 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; 197 | 198 | /** Used to match backslashes in property paths. */ 199 | var reEscapeChar = /\\(\\)?/g; 200 | 201 | /** Used to detect host constructors (Safari). */ 202 | var reIsHostCtor = /^\[object .+?Constructor\]$/; 203 | 204 | /** Used to detect unsigned integer values. */ 205 | var reIsUint = /^(?:0|[1-9]\d*)$/; 206 | 207 | /** Used to identify `toStringTag` values of typed arrays. */ 208 | var typedArrayTags = {}; 209 | typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = 210 | typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = 211 | typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = 212 | typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = 213 | typedArrayTags[uint32Tag] = true; 214 | typedArrayTags[argsTag] = typedArrayTags[arrayTag] = 215 | typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = 216 | typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = 217 | typedArrayTags[errorTag] = typedArrayTags[funcTag] = 218 | typedArrayTags[mapTag] = typedArrayTags[numberTag] = 219 | typedArrayTags[objectTag] = typedArrayTags[regexpTag] = 220 | typedArrayTags[setTag] = typedArrayTags[stringTag] = 221 | typedArrayTags[weakMapTag] = false; 222 | 223 | /** Detect free variable `global` from Node.js. */ 224 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; 225 | 226 | /** Detect free variable `self`. */ 227 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self; 228 | 229 | /** Used as a reference to the global object. */ 230 | var root = freeGlobal || freeSelf || Function('return this')(); 231 | 232 | /** Detect free variable `exports`. */ 233 | var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; 234 | 235 | /** Detect free variable `module`. */ 236 | var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; 237 | 238 | /** Detect the popular CommonJS extension `module.exports`. */ 239 | var moduleExports = freeModule && freeModule.exports === freeExports; 240 | 241 | /** Detect free variable `process` from Node.js. */ 242 | var freeProcess = moduleExports && freeGlobal.process; 243 | 244 | /** Used to access faster Node.js helpers. */ 245 | var nodeUtil = (function() { 246 | try { 247 | return freeProcess && freeProcess.binding('util'); 248 | } catch (e) {} 249 | }()); 250 | 251 | /* Node.js helper references. */ 252 | var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; 253 | 254 | /** 255 | * A specialized version of `baseAggregator` for arrays. 256 | * 257 | * @private 258 | * @param {Array} [array] The array to iterate over. 259 | * @param {Function} setter The function to set `accumulator` values. 260 | * @param {Function} iteratee The iteratee to transform keys. 261 | * @param {Object} accumulator The initial aggregated object. 262 | * @returns {Function} Returns `accumulator`. 263 | */ 264 | function arrayAggregator(array, setter, iteratee, accumulator) { 265 | var index = -1, 266 | length = array ? array.length : 0; 267 | 268 | while (++index < length) { 269 | var value = array[index]; 270 | setter(accumulator, value, iteratee(value), array); 271 | } 272 | return accumulator; 273 | } 274 | 275 | /** 276 | * A specialized version of `_.some` for arrays without support for iteratee 277 | * shorthands. 278 | * 279 | * @private 280 | * @param {Array} [array] The array to iterate over. 281 | * @param {Function} predicate The function invoked per iteration. 282 | * @returns {boolean} Returns `true` if any element passes the predicate check, 283 | * else `false`. 284 | */ 285 | function arraySome(array, predicate) { 286 | var index = -1, 287 | length = array ? array.length : 0; 288 | 289 | while (++index < length) { 290 | if (predicate(array[index], index, array)) { 291 | return true; 292 | } 293 | } 294 | return false; 295 | } 296 | 297 | /** 298 | * The base implementation of `_.property` without support for deep paths. 299 | * 300 | * @private 301 | * @param {string} key The key of the property to get. 302 | * @returns {Function} Returns the new accessor function. 303 | */ 304 | function baseProperty(key) { 305 | return function(object) { 306 | return object == null ? undefined : object[key]; 307 | }; 308 | } 309 | 310 | /** 311 | * The base implementation of `_.times` without support for iteratee shorthands 312 | * or max array length checks. 313 | * 314 | * @private 315 | * @param {number} n The number of times to invoke `iteratee`. 316 | * @param {Function} iteratee The function invoked per iteration. 317 | * @returns {Array} Returns the array of results. 318 | */ 319 | function baseTimes(n, iteratee) { 320 | var index = -1, 321 | result = Array(n); 322 | 323 | while (++index < n) { 324 | result[index] = iteratee(index); 325 | } 326 | return result; 327 | } 328 | 329 | /** 330 | * The base implementation of `_.unary` without support for storing metadata. 331 | * 332 | * @private 333 | * @param {Function} func The function to cap arguments for. 334 | * @returns {Function} Returns the new capped function. 335 | */ 336 | function baseUnary(func) { 337 | return function(value) { 338 | return func(value); 339 | }; 340 | } 341 | 342 | /** 343 | * Gets the value at `key` of `object`. 344 | * 345 | * @private 346 | * @param {Object} [object] The object to query. 347 | * @param {string} key The key of the property to get. 348 | * @returns {*} Returns the property value. 349 | */ 350 | function getValue(object, key) { 351 | return object == null ? undefined : object[key]; 352 | } 353 | 354 | /** 355 | * Checks if `value` is a host object in IE < 9. 356 | * 357 | * @private 358 | * @param {*} value The value to check. 359 | * @returns {boolean} Returns `true` if `value` is a host object, else `false`. 360 | */ 361 | function isHostObject(value) { 362 | // Many host objects are `Object` objects that can coerce to strings 363 | // despite having improperly defined `toString` methods. 364 | var result = false; 365 | if (value != null && typeof value.toString != 'function') { 366 | try { 367 | result = !!(value + ''); 368 | } catch (e) {} 369 | } 370 | return result; 371 | } 372 | 373 | /** 374 | * Converts `map` to its key-value pairs. 375 | * 376 | * @private 377 | * @param {Object} map The map to convert. 378 | * @returns {Array} Returns the key-value pairs. 379 | */ 380 | function mapToArray(map) { 381 | var index = -1, 382 | result = Array(map.size); 383 | 384 | map.forEach(function(value, key) { 385 | result[++index] = [key, value]; 386 | }); 387 | return result; 388 | } 389 | 390 | /** 391 | * Creates a unary function that invokes `func` with its argument transformed. 392 | * 393 | * @private 394 | * @param {Function} func The function to wrap. 395 | * @param {Function} transform The argument transform. 396 | * @returns {Function} Returns the new function. 397 | */ 398 | function overArg(func, transform) { 399 | return function(arg) { 400 | return func(transform(arg)); 401 | }; 402 | } 403 | 404 | /** 405 | * Converts `set` to an array of its values. 406 | * 407 | * @private 408 | * @param {Object} set The set to convert. 409 | * @returns {Array} Returns the values. 410 | */ 411 | function setToArray(set) { 412 | var index = -1, 413 | result = Array(set.size); 414 | 415 | set.forEach(function(value) { 416 | result[++index] = value; 417 | }); 418 | return result; 419 | } 420 | 421 | /** Used for built-in method references. */ 422 | var arrayProto = Array.prototype, 423 | funcProto = Function.prototype, 424 | objectProto = Object.prototype; 425 | 426 | /** Used to detect overreaching core-js shims. */ 427 | var coreJsData = root['__core-js_shared__']; 428 | 429 | /** Used to detect methods masquerading as native. */ 430 | var maskSrcKey = (function() { 431 | var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); 432 | return uid ? ('Symbol(src)_1.' + uid) : ''; 433 | }()); 434 | 435 | /** Used to resolve the decompiled source of functions. */ 436 | var funcToString = funcProto.toString; 437 | 438 | /** Used to check objects for own properties. */ 439 | var hasOwnProperty = objectProto.hasOwnProperty; 440 | 441 | /** 442 | * Used to resolve the 443 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 444 | * of values. 445 | */ 446 | var objectToString = objectProto.toString; 447 | 448 | /** Used to detect if a method is native. */ 449 | var reIsNative = RegExp('^' + 450 | funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') 451 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 452 | ); 453 | 454 | /** Built-in value references. */ 455 | var Symbol = root.Symbol, 456 | Uint8Array = root.Uint8Array, 457 | propertyIsEnumerable = objectProto.propertyIsEnumerable, 458 | splice = arrayProto.splice; 459 | 460 | /* Built-in method references for those with the same name as other `lodash` methods. */ 461 | var nativeKeys = overArg(Object.keys, Object); 462 | 463 | /* Built-in method references that are verified to be native. */ 464 | var DataView = getNative(root, 'DataView'), 465 | Map = getNative(root, 'Map'), 466 | Promise = getNative(root, 'Promise'), 467 | Set = getNative(root, 'Set'), 468 | WeakMap = getNative(root, 'WeakMap'), 469 | nativeCreate = getNative(Object, 'create'); 470 | 471 | /** Used to detect maps, sets, and weakmaps. */ 472 | var dataViewCtorString = toSource(DataView), 473 | mapCtorString = toSource(Map), 474 | promiseCtorString = toSource(Promise), 475 | setCtorString = toSource(Set), 476 | weakMapCtorString = toSource(WeakMap); 477 | 478 | /** Used to convert symbols to primitives and strings. */ 479 | var symbolProto = Symbol ? Symbol.prototype : undefined, 480 | symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, 481 | symbolToString = symbolProto ? symbolProto.toString : undefined; 482 | 483 | /** 484 | * Creates a hash object. 485 | * 486 | * @private 487 | * @constructor 488 | * @param {Array} [entries] The key-value pairs to cache. 489 | */ 490 | function Hash(entries) { 491 | var index = -1, 492 | length = entries ? entries.length : 0; 493 | 494 | this.clear(); 495 | while (++index < length) { 496 | var entry = entries[index]; 497 | this.set(entry[0], entry[1]); 498 | } 499 | } 500 | 501 | /** 502 | * Removes all key-value entries from the hash. 503 | * 504 | * @private 505 | * @name clear 506 | * @memberOf Hash 507 | */ 508 | function hashClear() { 509 | this.__data__ = nativeCreate ? nativeCreate(null) : {}; 510 | } 511 | 512 | /** 513 | * Removes `key` and its value from the hash. 514 | * 515 | * @private 516 | * @name delete 517 | * @memberOf Hash 518 | * @param {Object} hash The hash to modify. 519 | * @param {string} key The key of the value to remove. 520 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 521 | */ 522 | function hashDelete(key) { 523 | return this.has(key) && delete this.__data__[key]; 524 | } 525 | 526 | /** 527 | * Gets the hash value for `key`. 528 | * 529 | * @private 530 | * @name get 531 | * @memberOf Hash 532 | * @param {string} key The key of the value to get. 533 | * @returns {*} Returns the entry value. 534 | */ 535 | function hashGet(key) { 536 | var data = this.__data__; 537 | if (nativeCreate) { 538 | var result = data[key]; 539 | return result === HASH_UNDEFINED ? undefined : result; 540 | } 541 | return hasOwnProperty.call(data, key) ? data[key] : undefined; 542 | } 543 | 544 | /** 545 | * Checks if a hash value for `key` exists. 546 | * 547 | * @private 548 | * @name has 549 | * @memberOf Hash 550 | * @param {string} key The key of the entry to check. 551 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 552 | */ 553 | function hashHas(key) { 554 | var data = this.__data__; 555 | return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); 556 | } 557 | 558 | /** 559 | * Sets the hash `key` to `value`. 560 | * 561 | * @private 562 | * @name set 563 | * @memberOf Hash 564 | * @param {string} key The key of the value to set. 565 | * @param {*} value The value to set. 566 | * @returns {Object} Returns the hash instance. 567 | */ 568 | function hashSet(key, value) { 569 | var data = this.__data__; 570 | data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; 571 | return this; 572 | } 573 | 574 | // Add methods to `Hash`. 575 | Hash.prototype.clear = hashClear; 576 | Hash.prototype['delete'] = hashDelete; 577 | Hash.prototype.get = hashGet; 578 | Hash.prototype.has = hashHas; 579 | Hash.prototype.set = hashSet; 580 | 581 | /** 582 | * Creates an list cache object. 583 | * 584 | * @private 585 | * @constructor 586 | * @param {Array} [entries] The key-value pairs to cache. 587 | */ 588 | function ListCache(entries) { 589 | var index = -1, 590 | length = entries ? entries.length : 0; 591 | 592 | this.clear(); 593 | while (++index < length) { 594 | var entry = entries[index]; 595 | this.set(entry[0], entry[1]); 596 | } 597 | } 598 | 599 | /** 600 | * Removes all key-value entries from the list cache. 601 | * 602 | * @private 603 | * @name clear 604 | * @memberOf ListCache 605 | */ 606 | function listCacheClear() { 607 | this.__data__ = []; 608 | } 609 | 610 | /** 611 | * Removes `key` and its value from the list cache. 612 | * 613 | * @private 614 | * @name delete 615 | * @memberOf ListCache 616 | * @param {string} key The key of the value to remove. 617 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 618 | */ 619 | function listCacheDelete(key) { 620 | var data = this.__data__, 621 | index = assocIndexOf(data, key); 622 | 623 | if (index < 0) { 624 | return false; 625 | } 626 | var lastIndex = data.length - 1; 627 | if (index == lastIndex) { 628 | data.pop(); 629 | } else { 630 | splice.call(data, index, 1); 631 | } 632 | return true; 633 | } 634 | 635 | /** 636 | * Gets the list cache value for `key`. 637 | * 638 | * @private 639 | * @name get 640 | * @memberOf ListCache 641 | * @param {string} key The key of the value to get. 642 | * @returns {*} Returns the entry value. 643 | */ 644 | function listCacheGet(key) { 645 | var data = this.__data__, 646 | index = assocIndexOf(data, key); 647 | 648 | return index < 0 ? undefined : data[index][1]; 649 | } 650 | 651 | /** 652 | * Checks if a list cache value for `key` exists. 653 | * 654 | * @private 655 | * @name has 656 | * @memberOf ListCache 657 | * @param {string} key The key of the entry to check. 658 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 659 | */ 660 | function listCacheHas(key) { 661 | return assocIndexOf(this.__data__, key) > -1; 662 | } 663 | 664 | /** 665 | * Sets the list cache `key` to `value`. 666 | * 667 | * @private 668 | * @name set 669 | * @memberOf ListCache 670 | * @param {string} key The key of the value to set. 671 | * @param {*} value The value to set. 672 | * @returns {Object} Returns the list cache instance. 673 | */ 674 | function listCacheSet(key, value) { 675 | var data = this.__data__, 676 | index = assocIndexOf(data, key); 677 | 678 | if (index < 0) { 679 | data.push([key, value]); 680 | } else { 681 | data[index][1] = value; 682 | } 683 | return this; 684 | } 685 | 686 | // Add methods to `ListCache`. 687 | ListCache.prototype.clear = listCacheClear; 688 | ListCache.prototype['delete'] = listCacheDelete; 689 | ListCache.prototype.get = listCacheGet; 690 | ListCache.prototype.has = listCacheHas; 691 | ListCache.prototype.set = listCacheSet; 692 | 693 | /** 694 | * Creates a map cache object to store key-value pairs. 695 | * 696 | * @private 697 | * @constructor 698 | * @param {Array} [entries] The key-value pairs to cache. 699 | */ 700 | function MapCache(entries) { 701 | var index = -1, 702 | length = entries ? entries.length : 0; 703 | 704 | this.clear(); 705 | while (++index < length) { 706 | var entry = entries[index]; 707 | this.set(entry[0], entry[1]); 708 | } 709 | } 710 | 711 | /** 712 | * Removes all key-value entries from the map. 713 | * 714 | * @private 715 | * @name clear 716 | * @memberOf MapCache 717 | */ 718 | function mapCacheClear() { 719 | this.__data__ = { 720 | 'hash': new Hash, 721 | 'map': new (Map || ListCache), 722 | 'string': new Hash 723 | }; 724 | } 725 | 726 | /** 727 | * Removes `key` and its value from the map. 728 | * 729 | * @private 730 | * @name delete 731 | * @memberOf MapCache 732 | * @param {string} key The key of the value to remove. 733 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 734 | */ 735 | function mapCacheDelete(key) { 736 | return getMapData(this, key)['delete'](key); 737 | } 738 | 739 | /** 740 | * Gets the map value for `key`. 741 | * 742 | * @private 743 | * @name get 744 | * @memberOf MapCache 745 | * @param {string} key The key of the value to get. 746 | * @returns {*} Returns the entry value. 747 | */ 748 | function mapCacheGet(key) { 749 | return getMapData(this, key).get(key); 750 | } 751 | 752 | /** 753 | * Checks if a map value for `key` exists. 754 | * 755 | * @private 756 | * @name has 757 | * @memberOf MapCache 758 | * @param {string} key The key of the entry to check. 759 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 760 | */ 761 | function mapCacheHas(key) { 762 | return getMapData(this, key).has(key); 763 | } 764 | 765 | /** 766 | * Sets the map `key` to `value`. 767 | * 768 | * @private 769 | * @name set 770 | * @memberOf MapCache 771 | * @param {string} key The key of the value to set. 772 | * @param {*} value The value to set. 773 | * @returns {Object} Returns the map cache instance. 774 | */ 775 | function mapCacheSet(key, value) { 776 | getMapData(this, key).set(key, value); 777 | return this; 778 | } 779 | 780 | // Add methods to `MapCache`. 781 | MapCache.prototype.clear = mapCacheClear; 782 | MapCache.prototype['delete'] = mapCacheDelete; 783 | MapCache.prototype.get = mapCacheGet; 784 | MapCache.prototype.has = mapCacheHas; 785 | MapCache.prototype.set = mapCacheSet; 786 | 787 | /** 788 | * 789 | * Creates an array cache object to store unique values. 790 | * 791 | * @private 792 | * @constructor 793 | * @param {Array} [values] The values to cache. 794 | */ 795 | function SetCache(values) { 796 | var index = -1, 797 | length = values ? values.length : 0; 798 | 799 | this.__data__ = new MapCache; 800 | while (++index < length) { 801 | this.add(values[index]); 802 | } 803 | } 804 | 805 | /** 806 | * Adds `value` to the array cache. 807 | * 808 | * @private 809 | * @name add 810 | * @memberOf SetCache 811 | * @alias push 812 | * @param {*} value The value to cache. 813 | * @returns {Object} Returns the cache instance. 814 | */ 815 | function setCacheAdd(value) { 816 | this.__data__.set(value, HASH_UNDEFINED); 817 | return this; 818 | } 819 | 820 | /** 821 | * Checks if `value` is in the array cache. 822 | * 823 | * @private 824 | * @name has 825 | * @memberOf SetCache 826 | * @param {*} value The value to search for. 827 | * @returns {number} Returns `true` if `value` is found, else `false`. 828 | */ 829 | function setCacheHas(value) { 830 | return this.__data__.has(value); 831 | } 832 | 833 | // Add methods to `SetCache`. 834 | SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; 835 | SetCache.prototype.has = setCacheHas; 836 | 837 | /** 838 | * Creates a stack cache object to store key-value pairs. 839 | * 840 | * @private 841 | * @constructor 842 | * @param {Array} [entries] The key-value pairs to cache. 843 | */ 844 | function Stack(entries) { 845 | this.__data__ = new ListCache(entries); 846 | } 847 | 848 | /** 849 | * Removes all key-value entries from the stack. 850 | * 851 | * @private 852 | * @name clear 853 | * @memberOf Stack 854 | */ 855 | function stackClear() { 856 | this.__data__ = new ListCache; 857 | } 858 | 859 | /** 860 | * Removes `key` and its value from the stack. 861 | * 862 | * @private 863 | * @name delete 864 | * @memberOf Stack 865 | * @param {string} key The key of the value to remove. 866 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 867 | */ 868 | function stackDelete(key) { 869 | return this.__data__['delete'](key); 870 | } 871 | 872 | /** 873 | * Gets the stack value for `key`. 874 | * 875 | * @private 876 | * @name get 877 | * @memberOf Stack 878 | * @param {string} key The key of the value to get. 879 | * @returns {*} Returns the entry value. 880 | */ 881 | function stackGet(key) { 882 | return this.__data__.get(key); 883 | } 884 | 885 | /** 886 | * Checks if a stack value for `key` exists. 887 | * 888 | * @private 889 | * @name has 890 | * @memberOf Stack 891 | * @param {string} key The key of the entry to check. 892 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 893 | */ 894 | function stackHas(key) { 895 | return this.__data__.has(key); 896 | } 897 | 898 | /** 899 | * Sets the stack `key` to `value`. 900 | * 901 | * @private 902 | * @name set 903 | * @memberOf Stack 904 | * @param {string} key The key of the value to set. 905 | * @param {*} value The value to set. 906 | * @returns {Object} Returns the stack cache instance. 907 | */ 908 | function stackSet(key, value) { 909 | var cache = this.__data__; 910 | if (cache instanceof ListCache) { 911 | var pairs = cache.__data__; 912 | if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { 913 | pairs.push([key, value]); 914 | return this; 915 | } 916 | cache = this.__data__ = new MapCache(pairs); 917 | } 918 | cache.set(key, value); 919 | return this; 920 | } 921 | 922 | // Add methods to `Stack`. 923 | Stack.prototype.clear = stackClear; 924 | Stack.prototype['delete'] = stackDelete; 925 | Stack.prototype.get = stackGet; 926 | Stack.prototype.has = stackHas; 927 | Stack.prototype.set = stackSet; 928 | 929 | /** 930 | * Creates an array of the enumerable property names of the array-like `value`. 931 | * 932 | * @private 933 | * @param {*} value The value to query. 934 | * @param {boolean} inherited Specify returning inherited property names. 935 | * @returns {Array} Returns the array of property names. 936 | */ 937 | function arrayLikeKeys(value, inherited) { 938 | // Safari 8.1 makes `arguments.callee` enumerable in strict mode. 939 | // Safari 9 makes `arguments.length` enumerable in strict mode. 940 | var result = (isArray(value) || isArguments(value)) 941 | ? baseTimes(value.length, String) 942 | : []; 943 | 944 | var length = result.length, 945 | skipIndexes = !!length; 946 | 947 | for (var key in value) { 948 | if ((inherited || hasOwnProperty.call(value, key)) && 949 | !(skipIndexes && (key == 'length' || isIndex(key, length)))) { 950 | result.push(key); 951 | } 952 | } 953 | return result; 954 | } 955 | 956 | /** 957 | * Gets the index at which the `key` is found in `array` of key-value pairs. 958 | * 959 | * @private 960 | * @param {Array} array The array to inspect. 961 | * @param {*} key The key to search for. 962 | * @returns {number} Returns the index of the matched value, else `-1`. 963 | */ 964 | function assocIndexOf(array, key) { 965 | var length = array.length; 966 | while (length--) { 967 | if (eq(array[length][0], key)) { 968 | return length; 969 | } 970 | } 971 | return -1; 972 | } 973 | 974 | /** 975 | * Aggregates elements of `collection` on `accumulator` with keys transformed 976 | * by `iteratee` and values set by `setter`. 977 | * 978 | * @private 979 | * @param {Array|Object} collection The collection to iterate over. 980 | * @param {Function} setter The function to set `accumulator` values. 981 | * @param {Function} iteratee The iteratee to transform keys. 982 | * @param {Object} accumulator The initial aggregated object. 983 | * @returns {Function} Returns `accumulator`. 984 | */ 985 | function baseAggregator(collection, setter, iteratee, accumulator) { 986 | baseEach(collection, function(value, key, collection) { 987 | setter(accumulator, value, iteratee(value), collection); 988 | }); 989 | return accumulator; 990 | } 991 | 992 | /** 993 | * The base implementation of `_.forEach` without support for iteratee shorthands. 994 | * 995 | * @private 996 | * @param {Array|Object} collection The collection to iterate over. 997 | * @param {Function} iteratee The function invoked per iteration. 998 | * @returns {Array|Object} Returns `collection`. 999 | */ 1000 | var baseEach = createBaseEach(baseForOwn); 1001 | 1002 | /** 1003 | * The base implementation of `baseForOwn` which iterates over `object` 1004 | * properties returned by `keysFunc` and invokes `iteratee` for each property. 1005 | * Iteratee functions may exit iteration early by explicitly returning `false`. 1006 | * 1007 | * @private 1008 | * @param {Object} object The object to iterate over. 1009 | * @param {Function} iteratee The function invoked per iteration. 1010 | * @param {Function} keysFunc The function to get the keys of `object`. 1011 | * @returns {Object} Returns `object`. 1012 | */ 1013 | var baseFor = createBaseFor(); 1014 | 1015 | /** 1016 | * The base implementation of `_.forOwn` without support for iteratee shorthands. 1017 | * 1018 | * @private 1019 | * @param {Object} object The object to iterate over. 1020 | * @param {Function} iteratee The function invoked per iteration. 1021 | * @returns {Object} Returns `object`. 1022 | */ 1023 | function baseForOwn(object, iteratee) { 1024 | return object && baseFor(object, iteratee, keys); 1025 | } 1026 | 1027 | /** 1028 | * The base implementation of `_.get` without support for default values. 1029 | * 1030 | * @private 1031 | * @param {Object} object The object to query. 1032 | * @param {Array|string} path The path of the property to get. 1033 | * @returns {*} Returns the resolved value. 1034 | */ 1035 | function baseGet(object, path) { 1036 | path = isKey(path, object) ? [path] : castPath(path); 1037 | 1038 | var index = 0, 1039 | length = path.length; 1040 | 1041 | while (object != null && index < length) { 1042 | object = object[toKey(path[index++])]; 1043 | } 1044 | return (index && index == length) ? object : undefined; 1045 | } 1046 | 1047 | /** 1048 | * The base implementation of `getTag`. 1049 | * 1050 | * @private 1051 | * @param {*} value The value to query. 1052 | * @returns {string} Returns the `toStringTag`. 1053 | */ 1054 | function baseGetTag(value) { 1055 | return objectToString.call(value); 1056 | } 1057 | 1058 | /** 1059 | * The base implementation of `_.hasIn` without support for deep paths. 1060 | * 1061 | * @private 1062 | * @param {Object} [object] The object to query. 1063 | * @param {Array|string} key The key to check. 1064 | * @returns {boolean} Returns `true` if `key` exists, else `false`. 1065 | */ 1066 | function baseHasIn(object, key) { 1067 | return object != null && key in Object(object); 1068 | } 1069 | 1070 | /** 1071 | * The base implementation of `_.isEqual` which supports partial comparisons 1072 | * and tracks traversed objects. 1073 | * 1074 | * @private 1075 | * @param {*} value The value to compare. 1076 | * @param {*} other The other value to compare. 1077 | * @param {Function} [customizer] The function to customize comparisons. 1078 | * @param {boolean} [bitmask] The bitmask of comparison flags. 1079 | * The bitmask may be composed of the following flags: 1080 | * 1 - Unordered comparison 1081 | * 2 - Partial comparison 1082 | * @param {Object} [stack] Tracks traversed `value` and `other` objects. 1083 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 1084 | */ 1085 | function baseIsEqual(value, other, customizer, bitmask, stack) { 1086 | if (value === other) { 1087 | return true; 1088 | } 1089 | if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { 1090 | return value !== value && other !== other; 1091 | } 1092 | return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); 1093 | } 1094 | 1095 | /** 1096 | * A specialized version of `baseIsEqual` for arrays and objects which performs 1097 | * deep comparisons and tracks traversed objects enabling objects with circular 1098 | * references to be compared. 1099 | * 1100 | * @private 1101 | * @param {Object} object The object to compare. 1102 | * @param {Object} other The other object to compare. 1103 | * @param {Function} equalFunc The function to determine equivalents of values. 1104 | * @param {Function} [customizer] The function to customize comparisons. 1105 | * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` 1106 | * for more details. 1107 | * @param {Object} [stack] Tracks traversed `object` and `other` objects. 1108 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 1109 | */ 1110 | function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { 1111 | var objIsArr = isArray(object), 1112 | othIsArr = isArray(other), 1113 | objTag = arrayTag, 1114 | othTag = arrayTag; 1115 | 1116 | if (!objIsArr) { 1117 | objTag = getTag(object); 1118 | objTag = objTag == argsTag ? objectTag : objTag; 1119 | } 1120 | if (!othIsArr) { 1121 | othTag = getTag(other); 1122 | othTag = othTag == argsTag ? objectTag : othTag; 1123 | } 1124 | var objIsObj = objTag == objectTag && !isHostObject(object), 1125 | othIsObj = othTag == objectTag && !isHostObject(other), 1126 | isSameTag = objTag == othTag; 1127 | 1128 | if (isSameTag && !objIsObj) { 1129 | stack || (stack = new Stack); 1130 | return (objIsArr || isTypedArray(object)) 1131 | ? equalArrays(object, other, equalFunc, customizer, bitmask, stack) 1132 | : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack); 1133 | } 1134 | if (!(bitmask & PARTIAL_COMPARE_FLAG)) { 1135 | var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), 1136 | othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); 1137 | 1138 | if (objIsWrapped || othIsWrapped) { 1139 | var objUnwrapped = objIsWrapped ? object.value() : object, 1140 | othUnwrapped = othIsWrapped ? other.value() : other; 1141 | 1142 | stack || (stack = new Stack); 1143 | return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); 1144 | } 1145 | } 1146 | if (!isSameTag) { 1147 | return false; 1148 | } 1149 | stack || (stack = new Stack); 1150 | return equalObjects(object, other, equalFunc, customizer, bitmask, stack); 1151 | } 1152 | 1153 | /** 1154 | * The base implementation of `_.isMatch` without support for iteratee shorthands. 1155 | * 1156 | * @private 1157 | * @param {Object} object The object to inspect. 1158 | * @param {Object} source The object of property values to match. 1159 | * @param {Array} matchData The property names, values, and compare flags to match. 1160 | * @param {Function} [customizer] The function to customize comparisons. 1161 | * @returns {boolean} Returns `true` if `object` is a match, else `false`. 1162 | */ 1163 | function baseIsMatch(object, source, matchData, customizer) { 1164 | var index = matchData.length, 1165 | length = index, 1166 | noCustomizer = !customizer; 1167 | 1168 | if (object == null) { 1169 | return !length; 1170 | } 1171 | object = Object(object); 1172 | while (index--) { 1173 | var data = matchData[index]; 1174 | if ((noCustomizer && data[2]) 1175 | ? data[1] !== object[data[0]] 1176 | : !(data[0] in object) 1177 | ) { 1178 | return false; 1179 | } 1180 | } 1181 | while (++index < length) { 1182 | data = matchData[index]; 1183 | var key = data[0], 1184 | objValue = object[key], 1185 | srcValue = data[1]; 1186 | 1187 | if (noCustomizer && data[2]) { 1188 | if (objValue === undefined && !(key in object)) { 1189 | return false; 1190 | } 1191 | } else { 1192 | var stack = new Stack; 1193 | if (customizer) { 1194 | var result = customizer(objValue, srcValue, key, object, source, stack); 1195 | } 1196 | if (!(result === undefined 1197 | ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack) 1198 | : result 1199 | )) { 1200 | return false; 1201 | } 1202 | } 1203 | } 1204 | return true; 1205 | } 1206 | 1207 | /** 1208 | * The base implementation of `_.isNative` without bad shim checks. 1209 | * 1210 | * @private 1211 | * @param {*} value The value to check. 1212 | * @returns {boolean} Returns `true` if `value` is a native function, 1213 | * else `false`. 1214 | */ 1215 | function baseIsNative(value) { 1216 | if (!isObject(value) || isMasked(value)) { 1217 | return false; 1218 | } 1219 | var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; 1220 | return pattern.test(toSource(value)); 1221 | } 1222 | 1223 | /** 1224 | * The base implementation of `_.isTypedArray` without Node.js optimizations. 1225 | * 1226 | * @private 1227 | * @param {*} value The value to check. 1228 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 1229 | */ 1230 | function baseIsTypedArray(value) { 1231 | return isObjectLike(value) && 1232 | isLength(value.length) && !!typedArrayTags[objectToString.call(value)]; 1233 | } 1234 | 1235 | /** 1236 | * The base implementation of `_.iteratee`. 1237 | * 1238 | * @private 1239 | * @param {*} [value=_.identity] The value to convert to an iteratee. 1240 | * @returns {Function} Returns the iteratee. 1241 | */ 1242 | function baseIteratee(value) { 1243 | // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. 1244 | // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. 1245 | if (typeof value == 'function') { 1246 | return value; 1247 | } 1248 | if (value == null) { 1249 | return identity; 1250 | } 1251 | if (typeof value == 'object') { 1252 | return isArray(value) 1253 | ? baseMatchesProperty(value[0], value[1]) 1254 | : baseMatches(value); 1255 | } 1256 | return property(value); 1257 | } 1258 | 1259 | /** 1260 | * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. 1261 | * 1262 | * @private 1263 | * @param {Object} object The object to query. 1264 | * @returns {Array} Returns the array of property names. 1265 | */ 1266 | function baseKeys(object) { 1267 | if (!isPrototype(object)) { 1268 | return nativeKeys(object); 1269 | } 1270 | var result = []; 1271 | for (var key in Object(object)) { 1272 | if (hasOwnProperty.call(object, key) && key != 'constructor') { 1273 | result.push(key); 1274 | } 1275 | } 1276 | return result; 1277 | } 1278 | 1279 | /** 1280 | * The base implementation of `_.matches` which doesn't clone `source`. 1281 | * 1282 | * @private 1283 | * @param {Object} source The object of property values to match. 1284 | * @returns {Function} Returns the new spec function. 1285 | */ 1286 | function baseMatches(source) { 1287 | var matchData = getMatchData(source); 1288 | if (matchData.length == 1 && matchData[0][2]) { 1289 | return matchesStrictComparable(matchData[0][0], matchData[0][1]); 1290 | } 1291 | return function(object) { 1292 | return object === source || baseIsMatch(object, source, matchData); 1293 | }; 1294 | } 1295 | 1296 | /** 1297 | * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. 1298 | * 1299 | * @private 1300 | * @param {string} path The path of the property to get. 1301 | * @param {*} srcValue The value to match. 1302 | * @returns {Function} Returns the new spec function. 1303 | */ 1304 | function baseMatchesProperty(path, srcValue) { 1305 | if (isKey(path) && isStrictComparable(srcValue)) { 1306 | return matchesStrictComparable(toKey(path), srcValue); 1307 | } 1308 | return function(object) { 1309 | var objValue = get(object, path); 1310 | return (objValue === undefined && objValue === srcValue) 1311 | ? hasIn(object, path) 1312 | : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG); 1313 | }; 1314 | } 1315 | 1316 | /** 1317 | * A specialized version of `baseProperty` which supports deep paths. 1318 | * 1319 | * @private 1320 | * @param {Array|string} path The path of the property to get. 1321 | * @returns {Function} Returns the new accessor function. 1322 | */ 1323 | function basePropertyDeep(path) { 1324 | return function(object) { 1325 | return baseGet(object, path); 1326 | }; 1327 | } 1328 | 1329 | /** 1330 | * The base implementation of `_.toString` which doesn't convert nullish 1331 | * values to empty strings. 1332 | * 1333 | * @private 1334 | * @param {*} value The value to process. 1335 | * @returns {string} Returns the string. 1336 | */ 1337 | function baseToString(value) { 1338 | // Exit early for strings to avoid a performance hit in some environments. 1339 | if (typeof value == 'string') { 1340 | return value; 1341 | } 1342 | if (isSymbol(value)) { 1343 | return symbolToString ? symbolToString.call(value) : ''; 1344 | } 1345 | var result = (value + ''); 1346 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 1347 | } 1348 | 1349 | /** 1350 | * Casts `value` to a path array if it's not one. 1351 | * 1352 | * @private 1353 | * @param {*} value The value to inspect. 1354 | * @returns {Array} Returns the cast property path array. 1355 | */ 1356 | function castPath(value) { 1357 | return isArray(value) ? value : stringToPath(value); 1358 | } 1359 | 1360 | /** 1361 | * Creates a function like `_.groupBy`. 1362 | * 1363 | * @private 1364 | * @param {Function} setter The function to set accumulator values. 1365 | * @param {Function} [initializer] The accumulator object initializer. 1366 | * @returns {Function} Returns the new aggregator function. 1367 | */ 1368 | function createAggregator(setter, initializer) { 1369 | return function(collection, iteratee) { 1370 | var func = isArray(collection) ? arrayAggregator : baseAggregator, 1371 | accumulator = initializer ? initializer() : {}; 1372 | 1373 | return func(collection, setter, baseIteratee(iteratee, 2), accumulator); 1374 | }; 1375 | } 1376 | 1377 | /** 1378 | * Creates a `baseEach` or `baseEachRight` function. 1379 | * 1380 | * @private 1381 | * @param {Function} eachFunc The function to iterate over a collection. 1382 | * @param {boolean} [fromRight] Specify iterating from right to left. 1383 | * @returns {Function} Returns the new base function. 1384 | */ 1385 | function createBaseEach(eachFunc, fromRight) { 1386 | return function(collection, iteratee) { 1387 | if (collection == null) { 1388 | return collection; 1389 | } 1390 | if (!isArrayLike(collection)) { 1391 | return eachFunc(collection, iteratee); 1392 | } 1393 | var length = collection.length, 1394 | index = fromRight ? length : -1, 1395 | iterable = Object(collection); 1396 | 1397 | while ((fromRight ? index-- : ++index < length)) { 1398 | if (iteratee(iterable[index], index, iterable) === false) { 1399 | break; 1400 | } 1401 | } 1402 | return collection; 1403 | }; 1404 | } 1405 | 1406 | /** 1407 | * Creates a base function for methods like `_.forIn` and `_.forOwn`. 1408 | * 1409 | * @private 1410 | * @param {boolean} [fromRight] Specify iterating from right to left. 1411 | * @returns {Function} Returns the new base function. 1412 | */ 1413 | function createBaseFor(fromRight) { 1414 | return function(object, iteratee, keysFunc) { 1415 | var index = -1, 1416 | iterable = Object(object), 1417 | props = keysFunc(object), 1418 | length = props.length; 1419 | 1420 | while (length--) { 1421 | var key = props[fromRight ? length : ++index]; 1422 | if (iteratee(iterable[key], key, iterable) === false) { 1423 | break; 1424 | } 1425 | } 1426 | return object; 1427 | }; 1428 | } 1429 | 1430 | /** 1431 | * A specialized version of `baseIsEqualDeep` for arrays with support for 1432 | * partial deep comparisons. 1433 | * 1434 | * @private 1435 | * @param {Array} array The array to compare. 1436 | * @param {Array} other The other array to compare. 1437 | * @param {Function} equalFunc The function to determine equivalents of values. 1438 | * @param {Function} customizer The function to customize comparisons. 1439 | * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` 1440 | * for more details. 1441 | * @param {Object} stack Tracks traversed `array` and `other` objects. 1442 | * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. 1443 | */ 1444 | function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { 1445 | var isPartial = bitmask & PARTIAL_COMPARE_FLAG, 1446 | arrLength = array.length, 1447 | othLength = other.length; 1448 | 1449 | if (arrLength != othLength && !(isPartial && othLength > arrLength)) { 1450 | return false; 1451 | } 1452 | // Assume cyclic values are equal. 1453 | var stacked = stack.get(array); 1454 | if (stacked && stack.get(other)) { 1455 | return stacked == other; 1456 | } 1457 | var index = -1, 1458 | result = true, 1459 | seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; 1460 | 1461 | stack.set(array, other); 1462 | stack.set(other, array); 1463 | 1464 | // Ignore non-index properties. 1465 | while (++index < arrLength) { 1466 | var arrValue = array[index], 1467 | othValue = other[index]; 1468 | 1469 | if (customizer) { 1470 | var compared = isPartial 1471 | ? customizer(othValue, arrValue, index, other, array, stack) 1472 | : customizer(arrValue, othValue, index, array, other, stack); 1473 | } 1474 | if (compared !== undefined) { 1475 | if (compared) { 1476 | continue; 1477 | } 1478 | result = false; 1479 | break; 1480 | } 1481 | // Recursively compare arrays (susceptible to call stack limits). 1482 | if (seen) { 1483 | if (!arraySome(other, function(othValue, othIndex) { 1484 | if (!seen.has(othIndex) && 1485 | (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { 1486 | return seen.add(othIndex); 1487 | } 1488 | })) { 1489 | result = false; 1490 | break; 1491 | } 1492 | } else if (!( 1493 | arrValue === othValue || 1494 | equalFunc(arrValue, othValue, customizer, bitmask, stack) 1495 | )) { 1496 | result = false; 1497 | break; 1498 | } 1499 | } 1500 | stack['delete'](array); 1501 | stack['delete'](other); 1502 | return result; 1503 | } 1504 | 1505 | /** 1506 | * A specialized version of `baseIsEqualDeep` for comparing objects of 1507 | * the same `toStringTag`. 1508 | * 1509 | * **Note:** This function only supports comparing values with tags of 1510 | * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. 1511 | * 1512 | * @private 1513 | * @param {Object} object The object to compare. 1514 | * @param {Object} other The other object to compare. 1515 | * @param {string} tag The `toStringTag` of the objects to compare. 1516 | * @param {Function} equalFunc The function to determine equivalents of values. 1517 | * @param {Function} customizer The function to customize comparisons. 1518 | * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` 1519 | * for more details. 1520 | * @param {Object} stack Tracks traversed `object` and `other` objects. 1521 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 1522 | */ 1523 | function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { 1524 | switch (tag) { 1525 | case dataViewTag: 1526 | if ((object.byteLength != other.byteLength) || 1527 | (object.byteOffset != other.byteOffset)) { 1528 | return false; 1529 | } 1530 | object = object.buffer; 1531 | other = other.buffer; 1532 | 1533 | case arrayBufferTag: 1534 | if ((object.byteLength != other.byteLength) || 1535 | !equalFunc(new Uint8Array(object), new Uint8Array(other))) { 1536 | return false; 1537 | } 1538 | return true; 1539 | 1540 | case boolTag: 1541 | case dateTag: 1542 | case numberTag: 1543 | // Coerce booleans to `1` or `0` and dates to milliseconds. 1544 | // Invalid dates are coerced to `NaN`. 1545 | return eq(+object, +other); 1546 | 1547 | case errorTag: 1548 | return object.name == other.name && object.message == other.message; 1549 | 1550 | case regexpTag: 1551 | case stringTag: 1552 | // Coerce regexes to strings and treat strings, primitives and objects, 1553 | // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring 1554 | // for more details. 1555 | return object == (other + ''); 1556 | 1557 | case mapTag: 1558 | var convert = mapToArray; 1559 | 1560 | case setTag: 1561 | var isPartial = bitmask & PARTIAL_COMPARE_FLAG; 1562 | convert || (convert = setToArray); 1563 | 1564 | if (object.size != other.size && !isPartial) { 1565 | return false; 1566 | } 1567 | // Assume cyclic values are equal. 1568 | var stacked = stack.get(object); 1569 | if (stacked) { 1570 | return stacked == other; 1571 | } 1572 | bitmask |= UNORDERED_COMPARE_FLAG; 1573 | 1574 | // Recursively compare objects (susceptible to call stack limits). 1575 | stack.set(object, other); 1576 | var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack); 1577 | stack['delete'](object); 1578 | return result; 1579 | 1580 | case symbolTag: 1581 | if (symbolValueOf) { 1582 | return symbolValueOf.call(object) == symbolValueOf.call(other); 1583 | } 1584 | } 1585 | return false; 1586 | } 1587 | 1588 | /** 1589 | * A specialized version of `baseIsEqualDeep` for objects with support for 1590 | * partial deep comparisons. 1591 | * 1592 | * @private 1593 | * @param {Object} object The object to compare. 1594 | * @param {Object} other The other object to compare. 1595 | * @param {Function} equalFunc The function to determine equivalents of values. 1596 | * @param {Function} customizer The function to customize comparisons. 1597 | * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` 1598 | * for more details. 1599 | * @param {Object} stack Tracks traversed `object` and `other` objects. 1600 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 1601 | */ 1602 | function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { 1603 | var isPartial = bitmask & PARTIAL_COMPARE_FLAG, 1604 | objProps = keys(object), 1605 | objLength = objProps.length, 1606 | othProps = keys(other), 1607 | othLength = othProps.length; 1608 | 1609 | if (objLength != othLength && !isPartial) { 1610 | return false; 1611 | } 1612 | var index = objLength; 1613 | while (index--) { 1614 | var key = objProps[index]; 1615 | if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { 1616 | return false; 1617 | } 1618 | } 1619 | // Assume cyclic values are equal. 1620 | var stacked = stack.get(object); 1621 | if (stacked && stack.get(other)) { 1622 | return stacked == other; 1623 | } 1624 | var result = true; 1625 | stack.set(object, other); 1626 | stack.set(other, object); 1627 | 1628 | var skipCtor = isPartial; 1629 | while (++index < objLength) { 1630 | key = objProps[index]; 1631 | var objValue = object[key], 1632 | othValue = other[key]; 1633 | 1634 | if (customizer) { 1635 | var compared = isPartial 1636 | ? customizer(othValue, objValue, key, other, object, stack) 1637 | : customizer(objValue, othValue, key, object, other, stack); 1638 | } 1639 | // Recursively compare objects (susceptible to call stack limits). 1640 | if (!(compared === undefined 1641 | ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) 1642 | : compared 1643 | )) { 1644 | result = false; 1645 | break; 1646 | } 1647 | skipCtor || (skipCtor = key == 'constructor'); 1648 | } 1649 | if (result && !skipCtor) { 1650 | var objCtor = object.constructor, 1651 | othCtor = other.constructor; 1652 | 1653 | // Non `Object` object instances with different constructors are not equal. 1654 | if (objCtor != othCtor && 1655 | ('constructor' in object && 'constructor' in other) && 1656 | !(typeof objCtor == 'function' && objCtor instanceof objCtor && 1657 | typeof othCtor == 'function' && othCtor instanceof othCtor)) { 1658 | result = false; 1659 | } 1660 | } 1661 | stack['delete'](object); 1662 | stack['delete'](other); 1663 | return result; 1664 | } 1665 | 1666 | /** 1667 | * Gets the data for `map`. 1668 | * 1669 | * @private 1670 | * @param {Object} map The map to query. 1671 | * @param {string} key The reference key. 1672 | * @returns {*} Returns the map data. 1673 | */ 1674 | function getMapData(map, key) { 1675 | var data = map.__data__; 1676 | return isKeyable(key) 1677 | ? data[typeof key == 'string' ? 'string' : 'hash'] 1678 | : data.map; 1679 | } 1680 | 1681 | /** 1682 | * Gets the property names, values, and compare flags of `object`. 1683 | * 1684 | * @private 1685 | * @param {Object} object The object to query. 1686 | * @returns {Array} Returns the match data of `object`. 1687 | */ 1688 | function getMatchData(object) { 1689 | var result = keys(object), 1690 | length = result.length; 1691 | 1692 | while (length--) { 1693 | var key = result[length], 1694 | value = object[key]; 1695 | 1696 | result[length] = [key, value, isStrictComparable(value)]; 1697 | } 1698 | return result; 1699 | } 1700 | 1701 | /** 1702 | * Gets the native function at `key` of `object`. 1703 | * 1704 | * @private 1705 | * @param {Object} object The object to query. 1706 | * @param {string} key The key of the method to get. 1707 | * @returns {*} Returns the function if it's native, else `undefined`. 1708 | */ 1709 | function getNative(object, key) { 1710 | var value = getValue(object, key); 1711 | return baseIsNative(value) ? value : undefined; 1712 | } 1713 | 1714 | /** 1715 | * Gets the `toStringTag` of `value`. 1716 | * 1717 | * @private 1718 | * @param {*} value The value to query. 1719 | * @returns {string} Returns the `toStringTag`. 1720 | */ 1721 | var getTag = baseGetTag; 1722 | 1723 | // Fallback for data views, maps, sets, and weak maps in IE 11, 1724 | // for data views in Edge < 14, and promises in Node.js. 1725 | if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || 1726 | (Map && getTag(new Map) != mapTag) || 1727 | (Promise && getTag(Promise.resolve()) != promiseTag) || 1728 | (Set && getTag(new Set) != setTag) || 1729 | (WeakMap && getTag(new WeakMap) != weakMapTag)) { 1730 | getTag = function(value) { 1731 | var result = objectToString.call(value), 1732 | Ctor = result == objectTag ? value.constructor : undefined, 1733 | ctorString = Ctor ? toSource(Ctor) : undefined; 1734 | 1735 | if (ctorString) { 1736 | switch (ctorString) { 1737 | case dataViewCtorString: return dataViewTag; 1738 | case mapCtorString: return mapTag; 1739 | case promiseCtorString: return promiseTag; 1740 | case setCtorString: return setTag; 1741 | case weakMapCtorString: return weakMapTag; 1742 | } 1743 | } 1744 | return result; 1745 | }; 1746 | } 1747 | 1748 | /** 1749 | * Checks if `path` exists on `object`. 1750 | * 1751 | * @private 1752 | * @param {Object} object The object to query. 1753 | * @param {Array|string} path The path to check. 1754 | * @param {Function} hasFunc The function to check properties. 1755 | * @returns {boolean} Returns `true` if `path` exists, else `false`. 1756 | */ 1757 | function hasPath(object, path, hasFunc) { 1758 | path = isKey(path, object) ? [path] : castPath(path); 1759 | 1760 | var result, 1761 | index = -1, 1762 | length = path.length; 1763 | 1764 | while (++index < length) { 1765 | var key = toKey(path[index]); 1766 | if (!(result = object != null && hasFunc(object, key))) { 1767 | break; 1768 | } 1769 | object = object[key]; 1770 | } 1771 | if (result) { 1772 | return result; 1773 | } 1774 | var length = object ? object.length : 0; 1775 | return !!length && isLength(length) && isIndex(key, length) && 1776 | (isArray(object) || isArguments(object)); 1777 | } 1778 | 1779 | /** 1780 | * Checks if `value` is a valid array-like index. 1781 | * 1782 | * @private 1783 | * @param {*} value The value to check. 1784 | * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. 1785 | * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. 1786 | */ 1787 | function isIndex(value, length) { 1788 | length = length == null ? MAX_SAFE_INTEGER : length; 1789 | return !!length && 1790 | (typeof value == 'number' || reIsUint.test(value)) && 1791 | (value > -1 && value % 1 == 0 && value < length); 1792 | } 1793 | 1794 | /** 1795 | * Checks if `value` is a property name and not a property path. 1796 | * 1797 | * @private 1798 | * @param {*} value The value to check. 1799 | * @param {Object} [object] The object to query keys on. 1800 | * @returns {boolean} Returns `true` if `value` is a property name, else `false`. 1801 | */ 1802 | function isKey(value, object) { 1803 | if (isArray(value)) { 1804 | return false; 1805 | } 1806 | var type = typeof value; 1807 | if (type == 'number' || type == 'symbol' || type == 'boolean' || 1808 | value == null || isSymbol(value)) { 1809 | return true; 1810 | } 1811 | return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || 1812 | (object != null && value in Object(object)); 1813 | } 1814 | 1815 | /** 1816 | * Checks if `value` is suitable for use as unique object key. 1817 | * 1818 | * @private 1819 | * @param {*} value The value to check. 1820 | * @returns {boolean} Returns `true` if `value` is suitable, else `false`. 1821 | */ 1822 | function isKeyable(value) { 1823 | var type = typeof value; 1824 | return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') 1825 | ? (value !== '__proto__') 1826 | : (value === null); 1827 | } 1828 | 1829 | /** 1830 | * Checks if `func` has its source masked. 1831 | * 1832 | * @private 1833 | * @param {Function} func The function to check. 1834 | * @returns {boolean} Returns `true` if `func` is masked, else `false`. 1835 | */ 1836 | function isMasked(func) { 1837 | return !!maskSrcKey && (maskSrcKey in func); 1838 | } 1839 | 1840 | /** 1841 | * Checks if `value` is likely a prototype object. 1842 | * 1843 | * @private 1844 | * @param {*} value The value to check. 1845 | * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. 1846 | */ 1847 | function isPrototype(value) { 1848 | var Ctor = value && value.constructor, 1849 | proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; 1850 | 1851 | return value === proto; 1852 | } 1853 | 1854 | /** 1855 | * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. 1856 | * 1857 | * @private 1858 | * @param {*} value The value to check. 1859 | * @returns {boolean} Returns `true` if `value` if suitable for strict 1860 | * equality comparisons, else `false`. 1861 | */ 1862 | function isStrictComparable(value) { 1863 | return value === value && !isObject(value); 1864 | } 1865 | 1866 | /** 1867 | * A specialized version of `matchesProperty` for source values suitable 1868 | * for strict equality comparisons, i.e. `===`. 1869 | * 1870 | * @private 1871 | * @param {string} key The key of the property to get. 1872 | * @param {*} srcValue The value to match. 1873 | * @returns {Function} Returns the new spec function. 1874 | */ 1875 | function matchesStrictComparable(key, srcValue) { 1876 | return function(object) { 1877 | if (object == null) { 1878 | return false; 1879 | } 1880 | return object[key] === srcValue && 1881 | (srcValue !== undefined || (key in Object(object))); 1882 | }; 1883 | } 1884 | 1885 | /** 1886 | * Converts `string` to a property path array. 1887 | * 1888 | * @private 1889 | * @param {string} string The string to convert. 1890 | * @returns {Array} Returns the property path array. 1891 | */ 1892 | var stringToPath = memoize(function(string) { 1893 | string = toString(string); 1894 | 1895 | var result = []; 1896 | if (reLeadingDot.test(string)) { 1897 | result.push(''); 1898 | } 1899 | string.replace(rePropName, function(match, number, quote, string) { 1900 | result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); 1901 | }); 1902 | return result; 1903 | }); 1904 | 1905 | /** 1906 | * Converts `value` to a string key if it's not a string or symbol. 1907 | * 1908 | * @private 1909 | * @param {*} value The value to inspect. 1910 | * @returns {string|symbol} Returns the key. 1911 | */ 1912 | function toKey(value) { 1913 | if (typeof value == 'string' || isSymbol(value)) { 1914 | return value; 1915 | } 1916 | var result = (value + ''); 1917 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 1918 | } 1919 | 1920 | /** 1921 | * Converts `func` to its source code. 1922 | * 1923 | * @private 1924 | * @param {Function} func The function to process. 1925 | * @returns {string} Returns the source code. 1926 | */ 1927 | function toSource(func) { 1928 | if (func != null) { 1929 | try { 1930 | return funcToString.call(func); 1931 | } catch (e) {} 1932 | try { 1933 | return (func + ''); 1934 | } catch (e) {} 1935 | } 1936 | return ''; 1937 | } 1938 | 1939 | /** 1940 | * Creates an object composed of keys generated from the results of running 1941 | * each element of `collection` thru `iteratee`. The order of grouped values 1942 | * is determined by the order they occur in `collection`. The corresponding 1943 | * value of each key is an array of elements responsible for generating the 1944 | * key. The iteratee is invoked with one argument: (value). 1945 | * 1946 | * @static 1947 | * @memberOf _ 1948 | * @since 0.1.0 1949 | * @category Collection 1950 | * @param {Array|Object} collection The collection to iterate over. 1951 | * @param {Function} [iteratee=_.identity] 1952 | * The iteratee to transform keys. 1953 | * @returns {Object} Returns the composed aggregate object. 1954 | * @example 1955 | * 1956 | * _.groupBy([6.1, 4.2, 6.3], Math.floor); 1957 | * // => { '4': [4.2], '6': [6.1, 6.3] } 1958 | * 1959 | * // The `_.property` iteratee shorthand. 1960 | * _.groupBy(['one', 'two', 'three'], 'length'); 1961 | * // => { '3': ['one', 'two'], '5': ['three'] } 1962 | */ 1963 | var groupBy = createAggregator(function(result, value, key) { 1964 | if (hasOwnProperty.call(result, key)) { 1965 | result[key].push(value); 1966 | } else { 1967 | result[key] = [value]; 1968 | } 1969 | }); 1970 | 1971 | /** 1972 | * Creates a function that memoizes the result of `func`. If `resolver` is 1973 | * provided, it determines the cache key for storing the result based on the 1974 | * arguments provided to the memoized function. By default, the first argument 1975 | * provided to the memoized function is used as the map cache key. The `func` 1976 | * is invoked with the `this` binding of the memoized function. 1977 | * 1978 | * **Note:** The cache is exposed as the `cache` property on the memoized 1979 | * function. Its creation may be customized by replacing the `_.memoize.Cache` 1980 | * constructor with one whose instances implement the 1981 | * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) 1982 | * method interface of `delete`, `get`, `has`, and `set`. 1983 | * 1984 | * @static 1985 | * @memberOf _ 1986 | * @since 0.1.0 1987 | * @category Function 1988 | * @param {Function} func The function to have its output memoized. 1989 | * @param {Function} [resolver] The function to resolve the cache key. 1990 | * @returns {Function} Returns the new memoized function. 1991 | * @example 1992 | * 1993 | * var object = { 'a': 1, 'b': 2 }; 1994 | * var other = { 'c': 3, 'd': 4 }; 1995 | * 1996 | * var values = _.memoize(_.values); 1997 | * values(object); 1998 | * // => [1, 2] 1999 | * 2000 | * values(other); 2001 | * // => [3, 4] 2002 | * 2003 | * object.a = 2; 2004 | * values(object); 2005 | * // => [1, 2] 2006 | * 2007 | * // Modify the result cache. 2008 | * values.cache.set(object, ['a', 'b']); 2009 | * values(object); 2010 | * // => ['a', 'b'] 2011 | * 2012 | * // Replace `_.memoize.Cache`. 2013 | * _.memoize.Cache = WeakMap; 2014 | */ 2015 | function memoize(func, resolver) { 2016 | if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { 2017 | throw new TypeError(FUNC_ERROR_TEXT); 2018 | } 2019 | var memoized = function() { 2020 | var args = arguments, 2021 | key = resolver ? resolver.apply(this, args) : args[0], 2022 | cache = memoized.cache; 2023 | 2024 | if (cache.has(key)) { 2025 | return cache.get(key); 2026 | } 2027 | var result = func.apply(this, args); 2028 | memoized.cache = cache.set(key, result); 2029 | return result; 2030 | }; 2031 | memoized.cache = new (memoize.Cache || MapCache); 2032 | return memoized; 2033 | } 2034 | 2035 | // Assign cache to `_.memoize`. 2036 | memoize.Cache = MapCache; 2037 | 2038 | /** 2039 | * Performs a 2040 | * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) 2041 | * comparison between two values to determine if they are equivalent. 2042 | * 2043 | * @static 2044 | * @memberOf _ 2045 | * @since 4.0.0 2046 | * @category Lang 2047 | * @param {*} value The value to compare. 2048 | * @param {*} other The other value to compare. 2049 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 2050 | * @example 2051 | * 2052 | * var object = { 'a': 1 }; 2053 | * var other = { 'a': 1 }; 2054 | * 2055 | * _.eq(object, object); 2056 | * // => true 2057 | * 2058 | * _.eq(object, other); 2059 | * // => false 2060 | * 2061 | * _.eq('a', 'a'); 2062 | * // => true 2063 | * 2064 | * _.eq('a', Object('a')); 2065 | * // => false 2066 | * 2067 | * _.eq(NaN, NaN); 2068 | * // => true 2069 | */ 2070 | function eq(value, other) { 2071 | return value === other || (value !== value && other !== other); 2072 | } 2073 | 2074 | /** 2075 | * Checks if `value` is likely an `arguments` object. 2076 | * 2077 | * @static 2078 | * @memberOf _ 2079 | * @since 0.1.0 2080 | * @category Lang 2081 | * @param {*} value The value to check. 2082 | * @returns {boolean} Returns `true` if `value` is an `arguments` object, 2083 | * else `false`. 2084 | * @example 2085 | * 2086 | * _.isArguments(function() { return arguments; }()); 2087 | * // => true 2088 | * 2089 | * _.isArguments([1, 2, 3]); 2090 | * // => false 2091 | */ 2092 | function isArguments(value) { 2093 | // Safari 8.1 makes `arguments.callee` enumerable in strict mode. 2094 | return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && 2095 | (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); 2096 | } 2097 | 2098 | /** 2099 | * Checks if `value` is classified as an `Array` object. 2100 | * 2101 | * @static 2102 | * @memberOf _ 2103 | * @since 0.1.0 2104 | * @category Lang 2105 | * @param {*} value The value to check. 2106 | * @returns {boolean} Returns `true` if `value` is an array, else `false`. 2107 | * @example 2108 | * 2109 | * _.isArray([1, 2, 3]); 2110 | * // => true 2111 | * 2112 | * _.isArray(document.body.children); 2113 | * // => false 2114 | * 2115 | * _.isArray('abc'); 2116 | * // => false 2117 | * 2118 | * _.isArray(_.noop); 2119 | * // => false 2120 | */ 2121 | var isArray = Array.isArray; 2122 | 2123 | /** 2124 | * Checks if `value` is array-like. A value is considered array-like if it's 2125 | * not a function and has a `value.length` that's an integer greater than or 2126 | * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. 2127 | * 2128 | * @static 2129 | * @memberOf _ 2130 | * @since 4.0.0 2131 | * @category Lang 2132 | * @param {*} value The value to check. 2133 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 2134 | * @example 2135 | * 2136 | * _.isArrayLike([1, 2, 3]); 2137 | * // => true 2138 | * 2139 | * _.isArrayLike(document.body.children); 2140 | * // => true 2141 | * 2142 | * _.isArrayLike('abc'); 2143 | * // => true 2144 | * 2145 | * _.isArrayLike(_.noop); 2146 | * // => false 2147 | */ 2148 | function isArrayLike(value) { 2149 | return value != null && isLength(value.length) && !isFunction(value); 2150 | } 2151 | 2152 | /** 2153 | * This method is like `_.isArrayLike` except that it also checks if `value` 2154 | * is an object. 2155 | * 2156 | * @static 2157 | * @memberOf _ 2158 | * @since 4.0.0 2159 | * @category Lang 2160 | * @param {*} value The value to check. 2161 | * @returns {boolean} Returns `true` if `value` is an array-like object, 2162 | * else `false`. 2163 | * @example 2164 | * 2165 | * _.isArrayLikeObject([1, 2, 3]); 2166 | * // => true 2167 | * 2168 | * _.isArrayLikeObject(document.body.children); 2169 | * // => true 2170 | * 2171 | * _.isArrayLikeObject('abc'); 2172 | * // => false 2173 | * 2174 | * _.isArrayLikeObject(_.noop); 2175 | * // => false 2176 | */ 2177 | function isArrayLikeObject(value) { 2178 | return isObjectLike(value) && isArrayLike(value); 2179 | } 2180 | 2181 | /** 2182 | * Checks if `value` is classified as a `Function` object. 2183 | * 2184 | * @static 2185 | * @memberOf _ 2186 | * @since 0.1.0 2187 | * @category Lang 2188 | * @param {*} value The value to check. 2189 | * @returns {boolean} Returns `true` if `value` is a function, else `false`. 2190 | * @example 2191 | * 2192 | * _.isFunction(_); 2193 | * // => true 2194 | * 2195 | * _.isFunction(/abc/); 2196 | * // => false 2197 | */ 2198 | function isFunction(value) { 2199 | // The use of `Object#toString` avoids issues with the `typeof` operator 2200 | // in Safari 8-9 which returns 'object' for typed array and other constructors. 2201 | var tag = isObject(value) ? objectToString.call(value) : ''; 2202 | return tag == funcTag || tag == genTag; 2203 | } 2204 | 2205 | /** 2206 | * Checks if `value` is a valid array-like length. 2207 | * 2208 | * **Note:** This method is loosely based on 2209 | * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). 2210 | * 2211 | * @static 2212 | * @memberOf _ 2213 | * @since 4.0.0 2214 | * @category Lang 2215 | * @param {*} value The value to check. 2216 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 2217 | * @example 2218 | * 2219 | * _.isLength(3); 2220 | * // => true 2221 | * 2222 | * _.isLength(Number.MIN_VALUE); 2223 | * // => false 2224 | * 2225 | * _.isLength(Infinity); 2226 | * // => false 2227 | * 2228 | * _.isLength('3'); 2229 | * // => false 2230 | */ 2231 | function isLength(value) { 2232 | return typeof value == 'number' && 2233 | value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; 2234 | } 2235 | 2236 | /** 2237 | * Checks if `value` is the 2238 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) 2239 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 2240 | * 2241 | * @static 2242 | * @memberOf _ 2243 | * @since 0.1.0 2244 | * @category Lang 2245 | * @param {*} value The value to check. 2246 | * @returns {boolean} Returns `true` if `value` is an object, else `false`. 2247 | * @example 2248 | * 2249 | * _.isObject({}); 2250 | * // => true 2251 | * 2252 | * _.isObject([1, 2, 3]); 2253 | * // => true 2254 | * 2255 | * _.isObject(_.noop); 2256 | * // => true 2257 | * 2258 | * _.isObject(null); 2259 | * // => false 2260 | */ 2261 | function isObject(value) { 2262 | var type = typeof value; 2263 | return !!value && (type == 'object' || type == 'function'); 2264 | } 2265 | 2266 | /** 2267 | * Checks if `value` is object-like. A value is object-like if it's not `null` 2268 | * and has a `typeof` result of "object". 2269 | * 2270 | * @static 2271 | * @memberOf _ 2272 | * @since 4.0.0 2273 | * @category Lang 2274 | * @param {*} value The value to check. 2275 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 2276 | * @example 2277 | * 2278 | * _.isObjectLike({}); 2279 | * // => true 2280 | * 2281 | * _.isObjectLike([1, 2, 3]); 2282 | * // => true 2283 | * 2284 | * _.isObjectLike(_.noop); 2285 | * // => false 2286 | * 2287 | * _.isObjectLike(null); 2288 | * // => false 2289 | */ 2290 | function isObjectLike(value) { 2291 | return !!value && typeof value == 'object'; 2292 | } 2293 | 2294 | /** 2295 | * Checks if `value` is classified as a `Symbol` primitive or object. 2296 | * 2297 | * @static 2298 | * @memberOf _ 2299 | * @since 4.0.0 2300 | * @category Lang 2301 | * @param {*} value The value to check. 2302 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. 2303 | * @example 2304 | * 2305 | * _.isSymbol(Symbol.iterator); 2306 | * // => true 2307 | * 2308 | * _.isSymbol('abc'); 2309 | * // => false 2310 | */ 2311 | function isSymbol(value) { 2312 | return typeof value == 'symbol' || 2313 | (isObjectLike(value) && objectToString.call(value) == symbolTag); 2314 | } 2315 | 2316 | /** 2317 | * Checks if `value` is classified as a typed array. 2318 | * 2319 | * @static 2320 | * @memberOf _ 2321 | * @since 3.0.0 2322 | * @category Lang 2323 | * @param {*} value The value to check. 2324 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 2325 | * @example 2326 | * 2327 | * _.isTypedArray(new Uint8Array); 2328 | * // => true 2329 | * 2330 | * _.isTypedArray([]); 2331 | * // => false 2332 | */ 2333 | var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; 2334 | 2335 | /** 2336 | * Converts `value` to a string. An empty string is returned for `null` 2337 | * and `undefined` values. The sign of `-0` is preserved. 2338 | * 2339 | * @static 2340 | * @memberOf _ 2341 | * @since 4.0.0 2342 | * @category Lang 2343 | * @param {*} value The value to process. 2344 | * @returns {string} Returns the string. 2345 | * @example 2346 | * 2347 | * _.toString(null); 2348 | * // => '' 2349 | * 2350 | * _.toString(-0); 2351 | * // => '-0' 2352 | * 2353 | * _.toString([1, 2, 3]); 2354 | * // => '1,2,3' 2355 | */ 2356 | function toString(value) { 2357 | return value == null ? '' : baseToString(value); 2358 | } 2359 | 2360 | /** 2361 | * Gets the value at `path` of `object`. If the resolved value is 2362 | * `undefined`, the `defaultValue` is returned in its place. 2363 | * 2364 | * @static 2365 | * @memberOf _ 2366 | * @since 3.7.0 2367 | * @category Object 2368 | * @param {Object} object The object to query. 2369 | * @param {Array|string} path The path of the property to get. 2370 | * @param {*} [defaultValue] The value returned for `undefined` resolved values. 2371 | * @returns {*} Returns the resolved value. 2372 | * @example 2373 | * 2374 | * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 2375 | * 2376 | * _.get(object, 'a[0].b.c'); 2377 | * // => 3 2378 | * 2379 | * _.get(object, ['a', '0', 'b', 'c']); 2380 | * // => 3 2381 | * 2382 | * _.get(object, 'a.b.c', 'default'); 2383 | * // => 'default' 2384 | */ 2385 | function get(object, path, defaultValue) { 2386 | var result = object == null ? undefined : baseGet(object, path); 2387 | return result === undefined ? defaultValue : result; 2388 | } 2389 | 2390 | /** 2391 | * Checks if `path` is a direct or inherited property of `object`. 2392 | * 2393 | * @static 2394 | * @memberOf _ 2395 | * @since 4.0.0 2396 | * @category Object 2397 | * @param {Object} object The object to query. 2398 | * @param {Array|string} path The path to check. 2399 | * @returns {boolean} Returns `true` if `path` exists, else `false`. 2400 | * @example 2401 | * 2402 | * var object = _.create({ 'a': _.create({ 'b': 2 }) }); 2403 | * 2404 | * _.hasIn(object, 'a'); 2405 | * // => true 2406 | * 2407 | * _.hasIn(object, 'a.b'); 2408 | * // => true 2409 | * 2410 | * _.hasIn(object, ['a', 'b']); 2411 | * // => true 2412 | * 2413 | * _.hasIn(object, 'b'); 2414 | * // => false 2415 | */ 2416 | function hasIn(object, path) { 2417 | return object != null && hasPath(object, path, baseHasIn); 2418 | } 2419 | 2420 | /** 2421 | * Creates an array of the own enumerable property names of `object`. 2422 | * 2423 | * **Note:** Non-object values are coerced to objects. See the 2424 | * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) 2425 | * for more details. 2426 | * 2427 | * @static 2428 | * @since 0.1.0 2429 | * @memberOf _ 2430 | * @category Object 2431 | * @param {Object} object The object to query. 2432 | * @returns {Array} Returns the array of property names. 2433 | * @example 2434 | * 2435 | * function Foo() { 2436 | * this.a = 1; 2437 | * this.b = 2; 2438 | * } 2439 | * 2440 | * Foo.prototype.c = 3; 2441 | * 2442 | * _.keys(new Foo); 2443 | * // => ['a', 'b'] (iteration order is not guaranteed) 2444 | * 2445 | * _.keys('hi'); 2446 | * // => ['0', '1'] 2447 | */ 2448 | function keys(object) { 2449 | return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); 2450 | } 2451 | 2452 | /** 2453 | * This method returns the first argument it receives. 2454 | * 2455 | * @static 2456 | * @since 0.1.0 2457 | * @memberOf _ 2458 | * @category Util 2459 | * @param {*} value Any value. 2460 | * @returns {*} Returns `value`. 2461 | * @example 2462 | * 2463 | * var object = { 'a': 1 }; 2464 | * 2465 | * console.log(_.identity(object) === object); 2466 | * // => true 2467 | */ 2468 | function identity(value) { 2469 | return value; 2470 | } 2471 | 2472 | /** 2473 | * Creates a function that returns the value at `path` of a given object. 2474 | * 2475 | * @static 2476 | * @memberOf _ 2477 | * @since 2.4.0 2478 | * @category Util 2479 | * @param {Array|string} path The path of the property to get. 2480 | * @returns {Function} Returns the new accessor function. 2481 | * @example 2482 | * 2483 | * var objects = [ 2484 | * { 'a': { 'b': 2 } }, 2485 | * { 'a': { 'b': 1 } } 2486 | * ]; 2487 | * 2488 | * _.map(objects, _.property('a.b')); 2489 | * // => [2, 1] 2490 | * 2491 | * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); 2492 | * // => [1, 2] 2493 | */ 2494 | function property(path) { 2495 | return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); 2496 | } 2497 | 2498 | module.exports = groupBy; 2499 | 2500 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(3)(module))) 2501 | 2502 | /***/ }), 2503 | /* 3 */ 2504 | /***/ (function(module, exports) { 2505 | 2506 | module.exports = function(module) { 2507 | if(!module.webpackPolyfill) { 2508 | module.deprecate = function() {}; 2509 | module.paths = []; 2510 | // module.parent = undefined by default 2511 | if(!module.children) module.children = []; 2512 | Object.defineProperty(module, "loaded", { 2513 | enumerable: true, 2514 | get: function() { 2515 | return module.l; 2516 | } 2517 | }); 2518 | Object.defineProperty(module, "id", { 2519 | enumerable: true, 2520 | get: function() { 2521 | return module.i; 2522 | } 2523 | }); 2524 | module.webpackPolyfill = 1; 2525 | } 2526 | return module; 2527 | }; 2528 | 2529 | 2530 | /***/ }) 2531 | /******/ ]); -------------------------------------------------------------------------------- /example/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 5 | 6 | 7 | 8 | 10 | 11 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /example/browser/smartArrayToTree.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { 40 | /******/ configurable: false, 41 | /******/ enumerable: true, 42 | /******/ get: getter 43 | /******/ }); 44 | /******/ } 45 | /******/ }; 46 | /******/ 47 | /******/ // getDefaultExport function for compatibility with non-harmony modules 48 | /******/ __webpack_require__.n = function(module) { 49 | /******/ var getter = module && module.__esModule ? 50 | /******/ function getDefault() { return module['default']; } : 51 | /******/ function getModuleExports() { return module; }; 52 | /******/ __webpack_require__.d(getter, 'a', getter); 53 | /******/ return getter; 54 | /******/ }; 55 | /******/ 56 | /******/ // Object.prototype.hasOwnProperty.call 57 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 | /******/ 59 | /******/ // __webpack_public_path__ 60 | /******/ __webpack_require__.p = ""; 61 | /******/ 62 | /******/ // Load entry module and return exports 63 | /******/ return __webpack_require__(__webpack_require__.s = 1); 64 | /******/ }) 65 | /************************************************************************/ 66 | /******/ ([ 67 | /* 0 */ 68 | /***/ (function(module, exports) { 69 | 70 | var g; 71 | 72 | // This works in non-strict mode 73 | g = (function() { 74 | return this; 75 | })(); 76 | 77 | try { 78 | // This works if eval is allowed (see CSP) 79 | g = g || Function("return this")() || (1,eval)("this"); 80 | } catch(e) { 81 | // This works if the window reference is available 82 | if(typeof window === "object") 83 | g = window; 84 | } 85 | 86 | // g can still be undefined, but nothing to do about it... 87 | // We return undefined, instead of nothing here, so it's 88 | // easier to handle this case. if(!global) { ...} 89 | 90 | module.exports = g; 91 | 92 | 93 | /***/ }), 94 | /* 1 */ 95 | /***/ (function(module, exports, __webpack_require__) { 96 | 97 | "use strict"; 98 | /* WEBPACK VAR INJECTION */(function(global) { 99 | 100 | var groupBy = __webpack_require__(2) 101 | function smartArrayToTree(array, options) { 102 | options = Object.assign({ 103 | id: 'id', 104 | pid: 'pid', 105 | children: 'children', 106 | firstPid: null 107 | }, options); 108 | var groupArray = groupBy(array, function (n) { 109 | return n[options.pid]; 110 | }); 111 | var firstArray = groupArray[options.firstPid]; 112 | transform(firstArray); 113 | function transform(startList) { 114 | if (startList) 115 | for (var i = 0; i < startList.length; i++) { 116 | groupArray[startList[i][options.id]] && (startList[i][options.children] = groupArray[startList[i][options.id]]); 117 | transform(startList[i][options.children]); 118 | } 119 | } 120 | return firstArray; 121 | } 122 | global.smartArrayToTree=smartArrayToTree; 123 | module.exports=smartArrayToTree; 124 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 125 | 126 | /***/ }), 127 | /* 2 */ 128 | /***/ (function(module, exports, __webpack_require__) { 129 | 130 | /* WEBPACK VAR INJECTION */(function(global, module) {/** 131 | * lodash (Custom Build) 132 | * Build: `lodash modularize exports="npm" -o ./` 133 | * Copyright jQuery Foundation and other contributors 134 | * Released under MIT license 135 | * Based on Underscore.js 1.8.3 136 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 137 | */ 138 | 139 | /** Used as the size to enable large array optimizations. */ 140 | var LARGE_ARRAY_SIZE = 200; 141 | 142 | /** Used as the `TypeError` message for "Functions" methods. */ 143 | var FUNC_ERROR_TEXT = 'Expected a function'; 144 | 145 | /** Used to stand-in for `undefined` hash values. */ 146 | var HASH_UNDEFINED = '__lodash_hash_undefined__'; 147 | 148 | /** Used to compose bitmasks for comparison styles. */ 149 | var UNORDERED_COMPARE_FLAG = 1, 150 | PARTIAL_COMPARE_FLAG = 2; 151 | 152 | /** Used as references for various `Number` constants. */ 153 | var INFINITY = 1 / 0, 154 | MAX_SAFE_INTEGER = 9007199254740991; 155 | 156 | /** `Object#toString` result references. */ 157 | var argsTag = '[object Arguments]', 158 | arrayTag = '[object Array]', 159 | boolTag = '[object Boolean]', 160 | dateTag = '[object Date]', 161 | errorTag = '[object Error]', 162 | funcTag = '[object Function]', 163 | genTag = '[object GeneratorFunction]', 164 | mapTag = '[object Map]', 165 | numberTag = '[object Number]', 166 | objectTag = '[object Object]', 167 | promiseTag = '[object Promise]', 168 | regexpTag = '[object RegExp]', 169 | setTag = '[object Set]', 170 | stringTag = '[object String]', 171 | symbolTag = '[object Symbol]', 172 | weakMapTag = '[object WeakMap]'; 173 | 174 | var arrayBufferTag = '[object ArrayBuffer]', 175 | dataViewTag = '[object DataView]', 176 | float32Tag = '[object Float32Array]', 177 | float64Tag = '[object Float64Array]', 178 | int8Tag = '[object Int8Array]', 179 | int16Tag = '[object Int16Array]', 180 | int32Tag = '[object Int32Array]', 181 | uint8Tag = '[object Uint8Array]', 182 | uint8ClampedTag = '[object Uint8ClampedArray]', 183 | uint16Tag = '[object Uint16Array]', 184 | uint32Tag = '[object Uint32Array]'; 185 | 186 | /** Used to match property names within property paths. */ 187 | var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, 188 | reIsPlainProp = /^\w*$/, 189 | reLeadingDot = /^\./, 190 | rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; 191 | 192 | /** 193 | * Used to match `RegExp` 194 | * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). 195 | */ 196 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; 197 | 198 | /** Used to match backslashes in property paths. */ 199 | var reEscapeChar = /\\(\\)?/g; 200 | 201 | /** Used to detect host constructors (Safari). */ 202 | var reIsHostCtor = /^\[object .+?Constructor\]$/; 203 | 204 | /** Used to detect unsigned integer values. */ 205 | var reIsUint = /^(?:0|[1-9]\d*)$/; 206 | 207 | /** Used to identify `toStringTag` values of typed arrays. */ 208 | var typedArrayTags = {}; 209 | typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = 210 | typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = 211 | typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = 212 | typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = 213 | typedArrayTags[uint32Tag] = true; 214 | typedArrayTags[argsTag] = typedArrayTags[arrayTag] = 215 | typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = 216 | typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = 217 | typedArrayTags[errorTag] = typedArrayTags[funcTag] = 218 | typedArrayTags[mapTag] = typedArrayTags[numberTag] = 219 | typedArrayTags[objectTag] = typedArrayTags[regexpTag] = 220 | typedArrayTags[setTag] = typedArrayTags[stringTag] = 221 | typedArrayTags[weakMapTag] = false; 222 | 223 | /** Detect free variable `global` from Node.js. */ 224 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; 225 | 226 | /** Detect free variable `self`. */ 227 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self; 228 | 229 | /** Used as a reference to the global object. */ 230 | var root = freeGlobal || freeSelf || Function('return this')(); 231 | 232 | /** Detect free variable `exports`. */ 233 | var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; 234 | 235 | /** Detect free variable `module`. */ 236 | var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; 237 | 238 | /** Detect the popular CommonJS extension `module.exports`. */ 239 | var moduleExports = freeModule && freeModule.exports === freeExports; 240 | 241 | /** Detect free variable `process` from Node.js. */ 242 | var freeProcess = moduleExports && freeGlobal.process; 243 | 244 | /** Used to access faster Node.js helpers. */ 245 | var nodeUtil = (function() { 246 | try { 247 | return freeProcess && freeProcess.binding('util'); 248 | } catch (e) {} 249 | }()); 250 | 251 | /* Node.js helper references. */ 252 | var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; 253 | 254 | /** 255 | * A specialized version of `baseAggregator` for arrays. 256 | * 257 | * @private 258 | * @param {Array} [array] The array to iterate over. 259 | * @param {Function} setter The function to set `accumulator` values. 260 | * @param {Function} iteratee The iteratee to transform keys. 261 | * @param {Object} accumulator The initial aggregated object. 262 | * @returns {Function} Returns `accumulator`. 263 | */ 264 | function arrayAggregator(array, setter, iteratee, accumulator) { 265 | var index = -1, 266 | length = array ? array.length : 0; 267 | 268 | while (++index < length) { 269 | var value = array[index]; 270 | setter(accumulator, value, iteratee(value), array); 271 | } 272 | return accumulator; 273 | } 274 | 275 | /** 276 | * A specialized version of `_.some` for arrays without support for iteratee 277 | * shorthands. 278 | * 279 | * @private 280 | * @param {Array} [array] The array to iterate over. 281 | * @param {Function} predicate The function invoked per iteration. 282 | * @returns {boolean} Returns `true` if any element passes the predicate check, 283 | * else `false`. 284 | */ 285 | function arraySome(array, predicate) { 286 | var index = -1, 287 | length = array ? array.length : 0; 288 | 289 | while (++index < length) { 290 | if (predicate(array[index], index, array)) { 291 | return true; 292 | } 293 | } 294 | return false; 295 | } 296 | 297 | /** 298 | * The base implementation of `_.property` without support for deep paths. 299 | * 300 | * @private 301 | * @param {string} key The key of the property to get. 302 | * @returns {Function} Returns the new accessor function. 303 | */ 304 | function baseProperty(key) { 305 | return function(object) { 306 | return object == null ? undefined : object[key]; 307 | }; 308 | } 309 | 310 | /** 311 | * The base implementation of `_.times` without support for iteratee shorthands 312 | * or max array length checks. 313 | * 314 | * @private 315 | * @param {number} n The number of times to invoke `iteratee`. 316 | * @param {Function} iteratee The function invoked per iteration. 317 | * @returns {Array} Returns the array of results. 318 | */ 319 | function baseTimes(n, iteratee) { 320 | var index = -1, 321 | result = Array(n); 322 | 323 | while (++index < n) { 324 | result[index] = iteratee(index); 325 | } 326 | return result; 327 | } 328 | 329 | /** 330 | * The base implementation of `_.unary` without support for storing metadata. 331 | * 332 | * @private 333 | * @param {Function} func The function to cap arguments for. 334 | * @returns {Function} Returns the new capped function. 335 | */ 336 | function baseUnary(func) { 337 | return function(value) { 338 | return func(value); 339 | }; 340 | } 341 | 342 | /** 343 | * Gets the value at `key` of `object`. 344 | * 345 | * @private 346 | * @param {Object} [object] The object to query. 347 | * @param {string} key The key of the property to get. 348 | * @returns {*} Returns the property value. 349 | */ 350 | function getValue(object, key) { 351 | return object == null ? undefined : object[key]; 352 | } 353 | 354 | /** 355 | * Checks if `value` is a host object in IE < 9. 356 | * 357 | * @private 358 | * @param {*} value The value to check. 359 | * @returns {boolean} Returns `true` if `value` is a host object, else `false`. 360 | */ 361 | function isHostObject(value) { 362 | // Many host objects are `Object` objects that can coerce to strings 363 | // despite having improperly defined `toString` methods. 364 | var result = false; 365 | if (value != null && typeof value.toString != 'function') { 366 | try { 367 | result = !!(value + ''); 368 | } catch (e) {} 369 | } 370 | return result; 371 | } 372 | 373 | /** 374 | * Converts `map` to its key-value pairs. 375 | * 376 | * @private 377 | * @param {Object} map The map to convert. 378 | * @returns {Array} Returns the key-value pairs. 379 | */ 380 | function mapToArray(map) { 381 | var index = -1, 382 | result = Array(map.size); 383 | 384 | map.forEach(function(value, key) { 385 | result[++index] = [key, value]; 386 | }); 387 | return result; 388 | } 389 | 390 | /** 391 | * Creates a unary function that invokes `func` with its argument transformed. 392 | * 393 | * @private 394 | * @param {Function} func The function to wrap. 395 | * @param {Function} transform The argument transform. 396 | * @returns {Function} Returns the new function. 397 | */ 398 | function overArg(func, transform) { 399 | return function(arg) { 400 | return func(transform(arg)); 401 | }; 402 | } 403 | 404 | /** 405 | * Converts `set` to an array of its values. 406 | * 407 | * @private 408 | * @param {Object} set The set to convert. 409 | * @returns {Array} Returns the values. 410 | */ 411 | function setToArray(set) { 412 | var index = -1, 413 | result = Array(set.size); 414 | 415 | set.forEach(function(value) { 416 | result[++index] = value; 417 | }); 418 | return result; 419 | } 420 | 421 | /** Used for built-in method references. */ 422 | var arrayProto = Array.prototype, 423 | funcProto = Function.prototype, 424 | objectProto = Object.prototype; 425 | 426 | /** Used to detect overreaching core-js shims. */ 427 | var coreJsData = root['__core-js_shared__']; 428 | 429 | /** Used to detect methods masquerading as native. */ 430 | var maskSrcKey = (function() { 431 | var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); 432 | return uid ? ('Symbol(src)_1.' + uid) : ''; 433 | }()); 434 | 435 | /** Used to resolve the decompiled source of functions. */ 436 | var funcToString = funcProto.toString; 437 | 438 | /** Used to check objects for own properties. */ 439 | var hasOwnProperty = objectProto.hasOwnProperty; 440 | 441 | /** 442 | * Used to resolve the 443 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 444 | * of values. 445 | */ 446 | var objectToString = objectProto.toString; 447 | 448 | /** Used to detect if a method is native. */ 449 | var reIsNative = RegExp('^' + 450 | funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') 451 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 452 | ); 453 | 454 | /** Built-in value references. */ 455 | var Symbol = root.Symbol, 456 | Uint8Array = root.Uint8Array, 457 | propertyIsEnumerable = objectProto.propertyIsEnumerable, 458 | splice = arrayProto.splice; 459 | 460 | /* Built-in method references for those with the same name as other `lodash` methods. */ 461 | var nativeKeys = overArg(Object.keys, Object); 462 | 463 | /* Built-in method references that are verified to be native. */ 464 | var DataView = getNative(root, 'DataView'), 465 | Map = getNative(root, 'Map'), 466 | Promise = getNative(root, 'Promise'), 467 | Set = getNative(root, 'Set'), 468 | WeakMap = getNative(root, 'WeakMap'), 469 | nativeCreate = getNative(Object, 'create'); 470 | 471 | /** Used to detect maps, sets, and weakmaps. */ 472 | var dataViewCtorString = toSource(DataView), 473 | mapCtorString = toSource(Map), 474 | promiseCtorString = toSource(Promise), 475 | setCtorString = toSource(Set), 476 | weakMapCtorString = toSource(WeakMap); 477 | 478 | /** Used to convert symbols to primitives and strings. */ 479 | var symbolProto = Symbol ? Symbol.prototype : undefined, 480 | symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, 481 | symbolToString = symbolProto ? symbolProto.toString : undefined; 482 | 483 | /** 484 | * Creates a hash object. 485 | * 486 | * @private 487 | * @constructor 488 | * @param {Array} [entries] The key-value pairs to cache. 489 | */ 490 | function Hash(entries) { 491 | var index = -1, 492 | length = entries ? entries.length : 0; 493 | 494 | this.clear(); 495 | while (++index < length) { 496 | var entry = entries[index]; 497 | this.set(entry[0], entry[1]); 498 | } 499 | } 500 | 501 | /** 502 | * Removes all key-value entries from the hash. 503 | * 504 | * @private 505 | * @name clear 506 | * @memberOf Hash 507 | */ 508 | function hashClear() { 509 | this.__data__ = nativeCreate ? nativeCreate(null) : {}; 510 | } 511 | 512 | /** 513 | * Removes `key` and its value from the hash. 514 | * 515 | * @private 516 | * @name delete 517 | * @memberOf Hash 518 | * @param {Object} hash The hash to modify. 519 | * @param {string} key The key of the value to remove. 520 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 521 | */ 522 | function hashDelete(key) { 523 | return this.has(key) && delete this.__data__[key]; 524 | } 525 | 526 | /** 527 | * Gets the hash value for `key`. 528 | * 529 | * @private 530 | * @name get 531 | * @memberOf Hash 532 | * @param {string} key The key of the value to get. 533 | * @returns {*} Returns the entry value. 534 | */ 535 | function hashGet(key) { 536 | var data = this.__data__; 537 | if (nativeCreate) { 538 | var result = data[key]; 539 | return result === HASH_UNDEFINED ? undefined : result; 540 | } 541 | return hasOwnProperty.call(data, key) ? data[key] : undefined; 542 | } 543 | 544 | /** 545 | * Checks if a hash value for `key` exists. 546 | * 547 | * @private 548 | * @name has 549 | * @memberOf Hash 550 | * @param {string} key The key of the entry to check. 551 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 552 | */ 553 | function hashHas(key) { 554 | var data = this.__data__; 555 | return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); 556 | } 557 | 558 | /** 559 | * Sets the hash `key` to `value`. 560 | * 561 | * @private 562 | * @name set 563 | * @memberOf Hash 564 | * @param {string} key The key of the value to set. 565 | * @param {*} value The value to set. 566 | * @returns {Object} Returns the hash instance. 567 | */ 568 | function hashSet(key, value) { 569 | var data = this.__data__; 570 | data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; 571 | return this; 572 | } 573 | 574 | // Add methods to `Hash`. 575 | Hash.prototype.clear = hashClear; 576 | Hash.prototype['delete'] = hashDelete; 577 | Hash.prototype.get = hashGet; 578 | Hash.prototype.has = hashHas; 579 | Hash.prototype.set = hashSet; 580 | 581 | /** 582 | * Creates an list cache object. 583 | * 584 | * @private 585 | * @constructor 586 | * @param {Array} [entries] The key-value pairs to cache. 587 | */ 588 | function ListCache(entries) { 589 | var index = -1, 590 | length = entries ? entries.length : 0; 591 | 592 | this.clear(); 593 | while (++index < length) { 594 | var entry = entries[index]; 595 | this.set(entry[0], entry[1]); 596 | } 597 | } 598 | 599 | /** 600 | * Removes all key-value entries from the list cache. 601 | * 602 | * @private 603 | * @name clear 604 | * @memberOf ListCache 605 | */ 606 | function listCacheClear() { 607 | this.__data__ = []; 608 | } 609 | 610 | /** 611 | * Removes `key` and its value from the list cache. 612 | * 613 | * @private 614 | * @name delete 615 | * @memberOf ListCache 616 | * @param {string} key The key of the value to remove. 617 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 618 | */ 619 | function listCacheDelete(key) { 620 | var data = this.__data__, 621 | index = assocIndexOf(data, key); 622 | 623 | if (index < 0) { 624 | return false; 625 | } 626 | var lastIndex = data.length - 1; 627 | if (index == lastIndex) { 628 | data.pop(); 629 | } else { 630 | splice.call(data, index, 1); 631 | } 632 | return true; 633 | } 634 | 635 | /** 636 | * Gets the list cache value for `key`. 637 | * 638 | * @private 639 | * @name get 640 | * @memberOf ListCache 641 | * @param {string} key The key of the value to get. 642 | * @returns {*} Returns the entry value. 643 | */ 644 | function listCacheGet(key) { 645 | var data = this.__data__, 646 | index = assocIndexOf(data, key); 647 | 648 | return index < 0 ? undefined : data[index][1]; 649 | } 650 | 651 | /** 652 | * Checks if a list cache value for `key` exists. 653 | * 654 | * @private 655 | * @name has 656 | * @memberOf ListCache 657 | * @param {string} key The key of the entry to check. 658 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 659 | */ 660 | function listCacheHas(key) { 661 | return assocIndexOf(this.__data__, key) > -1; 662 | } 663 | 664 | /** 665 | * Sets the list cache `key` to `value`. 666 | * 667 | * @private 668 | * @name set 669 | * @memberOf ListCache 670 | * @param {string} key The key of the value to set. 671 | * @param {*} value The value to set. 672 | * @returns {Object} Returns the list cache instance. 673 | */ 674 | function listCacheSet(key, value) { 675 | var data = this.__data__, 676 | index = assocIndexOf(data, key); 677 | 678 | if (index < 0) { 679 | data.push([key, value]); 680 | } else { 681 | data[index][1] = value; 682 | } 683 | return this; 684 | } 685 | 686 | // Add methods to `ListCache`. 687 | ListCache.prototype.clear = listCacheClear; 688 | ListCache.prototype['delete'] = listCacheDelete; 689 | ListCache.prototype.get = listCacheGet; 690 | ListCache.prototype.has = listCacheHas; 691 | ListCache.prototype.set = listCacheSet; 692 | 693 | /** 694 | * Creates a map cache object to store key-value pairs. 695 | * 696 | * @private 697 | * @constructor 698 | * @param {Array} [entries] The key-value pairs to cache. 699 | */ 700 | function MapCache(entries) { 701 | var index = -1, 702 | length = entries ? entries.length : 0; 703 | 704 | this.clear(); 705 | while (++index < length) { 706 | var entry = entries[index]; 707 | this.set(entry[0], entry[1]); 708 | } 709 | } 710 | 711 | /** 712 | * Removes all key-value entries from the map. 713 | * 714 | * @private 715 | * @name clear 716 | * @memberOf MapCache 717 | */ 718 | function mapCacheClear() { 719 | this.__data__ = { 720 | 'hash': new Hash, 721 | 'map': new (Map || ListCache), 722 | 'string': new Hash 723 | }; 724 | } 725 | 726 | /** 727 | * Removes `key` and its value from the map. 728 | * 729 | * @private 730 | * @name delete 731 | * @memberOf MapCache 732 | * @param {string} key The key of the value to remove. 733 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 734 | */ 735 | function mapCacheDelete(key) { 736 | return getMapData(this, key)['delete'](key); 737 | } 738 | 739 | /** 740 | * Gets the map value for `key`. 741 | * 742 | * @private 743 | * @name get 744 | * @memberOf MapCache 745 | * @param {string} key The key of the value to get. 746 | * @returns {*} Returns the entry value. 747 | */ 748 | function mapCacheGet(key) { 749 | return getMapData(this, key).get(key); 750 | } 751 | 752 | /** 753 | * Checks if a map value for `key` exists. 754 | * 755 | * @private 756 | * @name has 757 | * @memberOf MapCache 758 | * @param {string} key The key of the entry to check. 759 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 760 | */ 761 | function mapCacheHas(key) { 762 | return getMapData(this, key).has(key); 763 | } 764 | 765 | /** 766 | * Sets the map `key` to `value`. 767 | * 768 | * @private 769 | * @name set 770 | * @memberOf MapCache 771 | * @param {string} key The key of the value to set. 772 | * @param {*} value The value to set. 773 | * @returns {Object} Returns the map cache instance. 774 | */ 775 | function mapCacheSet(key, value) { 776 | getMapData(this, key).set(key, value); 777 | return this; 778 | } 779 | 780 | // Add methods to `MapCache`. 781 | MapCache.prototype.clear = mapCacheClear; 782 | MapCache.prototype['delete'] = mapCacheDelete; 783 | MapCache.prototype.get = mapCacheGet; 784 | MapCache.prototype.has = mapCacheHas; 785 | MapCache.prototype.set = mapCacheSet; 786 | 787 | /** 788 | * 789 | * Creates an array cache object to store unique values. 790 | * 791 | * @private 792 | * @constructor 793 | * @param {Array} [values] The values to cache. 794 | */ 795 | function SetCache(values) { 796 | var index = -1, 797 | length = values ? values.length : 0; 798 | 799 | this.__data__ = new MapCache; 800 | while (++index < length) { 801 | this.add(values[index]); 802 | } 803 | } 804 | 805 | /** 806 | * Adds `value` to the array cache. 807 | * 808 | * @private 809 | * @name add 810 | * @memberOf SetCache 811 | * @alias push 812 | * @param {*} value The value to cache. 813 | * @returns {Object} Returns the cache instance. 814 | */ 815 | function setCacheAdd(value) { 816 | this.__data__.set(value, HASH_UNDEFINED); 817 | return this; 818 | } 819 | 820 | /** 821 | * Checks if `value` is in the array cache. 822 | * 823 | * @private 824 | * @name has 825 | * @memberOf SetCache 826 | * @param {*} value The value to search for. 827 | * @returns {number} Returns `true` if `value` is found, else `false`. 828 | */ 829 | function setCacheHas(value) { 830 | return this.__data__.has(value); 831 | } 832 | 833 | // Add methods to `SetCache`. 834 | SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; 835 | SetCache.prototype.has = setCacheHas; 836 | 837 | /** 838 | * Creates a stack cache object to store key-value pairs. 839 | * 840 | * @private 841 | * @constructor 842 | * @param {Array} [entries] The key-value pairs to cache. 843 | */ 844 | function Stack(entries) { 845 | this.__data__ = new ListCache(entries); 846 | } 847 | 848 | /** 849 | * Removes all key-value entries from the stack. 850 | * 851 | * @private 852 | * @name clear 853 | * @memberOf Stack 854 | */ 855 | function stackClear() { 856 | this.__data__ = new ListCache; 857 | } 858 | 859 | /** 860 | * Removes `key` and its value from the stack. 861 | * 862 | * @private 863 | * @name delete 864 | * @memberOf Stack 865 | * @param {string} key The key of the value to remove. 866 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 867 | */ 868 | function stackDelete(key) { 869 | return this.__data__['delete'](key); 870 | } 871 | 872 | /** 873 | * Gets the stack value for `key`. 874 | * 875 | * @private 876 | * @name get 877 | * @memberOf Stack 878 | * @param {string} key The key of the value to get. 879 | * @returns {*} Returns the entry value. 880 | */ 881 | function stackGet(key) { 882 | return this.__data__.get(key); 883 | } 884 | 885 | /** 886 | * Checks if a stack value for `key` exists. 887 | * 888 | * @private 889 | * @name has 890 | * @memberOf Stack 891 | * @param {string} key The key of the entry to check. 892 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 893 | */ 894 | function stackHas(key) { 895 | return this.__data__.has(key); 896 | } 897 | 898 | /** 899 | * Sets the stack `key` to `value`. 900 | * 901 | * @private 902 | * @name set 903 | * @memberOf Stack 904 | * @param {string} key The key of the value to set. 905 | * @param {*} value The value to set. 906 | * @returns {Object} Returns the stack cache instance. 907 | */ 908 | function stackSet(key, value) { 909 | var cache = this.__data__; 910 | if (cache instanceof ListCache) { 911 | var pairs = cache.__data__; 912 | if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { 913 | pairs.push([key, value]); 914 | return this; 915 | } 916 | cache = this.__data__ = new MapCache(pairs); 917 | } 918 | cache.set(key, value); 919 | return this; 920 | } 921 | 922 | // Add methods to `Stack`. 923 | Stack.prototype.clear = stackClear; 924 | Stack.prototype['delete'] = stackDelete; 925 | Stack.prototype.get = stackGet; 926 | Stack.prototype.has = stackHas; 927 | Stack.prototype.set = stackSet; 928 | 929 | /** 930 | * Creates an array of the enumerable property names of the array-like `value`. 931 | * 932 | * @private 933 | * @param {*} value The value to query. 934 | * @param {boolean} inherited Specify returning inherited property names. 935 | * @returns {Array} Returns the array of property names. 936 | */ 937 | function arrayLikeKeys(value, inherited) { 938 | // Safari 8.1 makes `arguments.callee` enumerable in strict mode. 939 | // Safari 9 makes `arguments.length` enumerable in strict mode. 940 | var result = (isArray(value) || isArguments(value)) 941 | ? baseTimes(value.length, String) 942 | : []; 943 | 944 | var length = result.length, 945 | skipIndexes = !!length; 946 | 947 | for (var key in value) { 948 | if ((inherited || hasOwnProperty.call(value, key)) && 949 | !(skipIndexes && (key == 'length' || isIndex(key, length)))) { 950 | result.push(key); 951 | } 952 | } 953 | return result; 954 | } 955 | 956 | /** 957 | * Gets the index at which the `key` is found in `array` of key-value pairs. 958 | * 959 | * @private 960 | * @param {Array} array The array to inspect. 961 | * @param {*} key The key to search for. 962 | * @returns {number} Returns the index of the matched value, else `-1`. 963 | */ 964 | function assocIndexOf(array, key) { 965 | var length = array.length; 966 | while (length--) { 967 | if (eq(array[length][0], key)) { 968 | return length; 969 | } 970 | } 971 | return -1; 972 | } 973 | 974 | /** 975 | * Aggregates elements of `collection` on `accumulator` with keys transformed 976 | * by `iteratee` and values set by `setter`. 977 | * 978 | * @private 979 | * @param {Array|Object} collection The collection to iterate over. 980 | * @param {Function} setter The function to set `accumulator` values. 981 | * @param {Function} iteratee The iteratee to transform keys. 982 | * @param {Object} accumulator The initial aggregated object. 983 | * @returns {Function} Returns `accumulator`. 984 | */ 985 | function baseAggregator(collection, setter, iteratee, accumulator) { 986 | baseEach(collection, function(value, key, collection) { 987 | setter(accumulator, value, iteratee(value), collection); 988 | }); 989 | return accumulator; 990 | } 991 | 992 | /** 993 | * The base implementation of `_.forEach` without support for iteratee shorthands. 994 | * 995 | * @private 996 | * @param {Array|Object} collection The collection to iterate over. 997 | * @param {Function} iteratee The function invoked per iteration. 998 | * @returns {Array|Object} Returns `collection`. 999 | */ 1000 | var baseEach = createBaseEach(baseForOwn); 1001 | 1002 | /** 1003 | * The base implementation of `baseForOwn` which iterates over `object` 1004 | * properties returned by `keysFunc` and invokes `iteratee` for each property. 1005 | * Iteratee functions may exit iteration early by explicitly returning `false`. 1006 | * 1007 | * @private 1008 | * @param {Object} object The object to iterate over. 1009 | * @param {Function} iteratee The function invoked per iteration. 1010 | * @param {Function} keysFunc The function to get the keys of `object`. 1011 | * @returns {Object} Returns `object`. 1012 | */ 1013 | var baseFor = createBaseFor(); 1014 | 1015 | /** 1016 | * The base implementation of `_.forOwn` without support for iteratee shorthands. 1017 | * 1018 | * @private 1019 | * @param {Object} object The object to iterate over. 1020 | * @param {Function} iteratee The function invoked per iteration. 1021 | * @returns {Object} Returns `object`. 1022 | */ 1023 | function baseForOwn(object, iteratee) { 1024 | return object && baseFor(object, iteratee, keys); 1025 | } 1026 | 1027 | /** 1028 | * The base implementation of `_.get` without support for default values. 1029 | * 1030 | * @private 1031 | * @param {Object} object The object to query. 1032 | * @param {Array|string} path The path of the property to get. 1033 | * @returns {*} Returns the resolved value. 1034 | */ 1035 | function baseGet(object, path) { 1036 | path = isKey(path, object) ? [path] : castPath(path); 1037 | 1038 | var index = 0, 1039 | length = path.length; 1040 | 1041 | while (object != null && index < length) { 1042 | object = object[toKey(path[index++])]; 1043 | } 1044 | return (index && index == length) ? object : undefined; 1045 | } 1046 | 1047 | /** 1048 | * The base implementation of `getTag`. 1049 | * 1050 | * @private 1051 | * @param {*} value The value to query. 1052 | * @returns {string} Returns the `toStringTag`. 1053 | */ 1054 | function baseGetTag(value) { 1055 | return objectToString.call(value); 1056 | } 1057 | 1058 | /** 1059 | * The base implementation of `_.hasIn` without support for deep paths. 1060 | * 1061 | * @private 1062 | * @param {Object} [object] The object to query. 1063 | * @param {Array|string} key The key to check. 1064 | * @returns {boolean} Returns `true` if `key` exists, else `false`. 1065 | */ 1066 | function baseHasIn(object, key) { 1067 | return object != null && key in Object(object); 1068 | } 1069 | 1070 | /** 1071 | * The base implementation of `_.isEqual` which supports partial comparisons 1072 | * and tracks traversed objects. 1073 | * 1074 | * @private 1075 | * @param {*} value The value to compare. 1076 | * @param {*} other The other value to compare. 1077 | * @param {Function} [customizer] The function to customize comparisons. 1078 | * @param {boolean} [bitmask] The bitmask of comparison flags. 1079 | * The bitmask may be composed of the following flags: 1080 | * 1 - Unordered comparison 1081 | * 2 - Partial comparison 1082 | * @param {Object} [stack] Tracks traversed `value` and `other` objects. 1083 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 1084 | */ 1085 | function baseIsEqual(value, other, customizer, bitmask, stack) { 1086 | if (value === other) { 1087 | return true; 1088 | } 1089 | if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { 1090 | return value !== value && other !== other; 1091 | } 1092 | return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); 1093 | } 1094 | 1095 | /** 1096 | * A specialized version of `baseIsEqual` for arrays and objects which performs 1097 | * deep comparisons and tracks traversed objects enabling objects with circular 1098 | * references to be compared. 1099 | * 1100 | * @private 1101 | * @param {Object} object The object to compare. 1102 | * @param {Object} other The other object to compare. 1103 | * @param {Function} equalFunc The function to determine equivalents of values. 1104 | * @param {Function} [customizer] The function to customize comparisons. 1105 | * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` 1106 | * for more details. 1107 | * @param {Object} [stack] Tracks traversed `object` and `other` objects. 1108 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 1109 | */ 1110 | function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { 1111 | var objIsArr = isArray(object), 1112 | othIsArr = isArray(other), 1113 | objTag = arrayTag, 1114 | othTag = arrayTag; 1115 | 1116 | if (!objIsArr) { 1117 | objTag = getTag(object); 1118 | objTag = objTag == argsTag ? objectTag : objTag; 1119 | } 1120 | if (!othIsArr) { 1121 | othTag = getTag(other); 1122 | othTag = othTag == argsTag ? objectTag : othTag; 1123 | } 1124 | var objIsObj = objTag == objectTag && !isHostObject(object), 1125 | othIsObj = othTag == objectTag && !isHostObject(other), 1126 | isSameTag = objTag == othTag; 1127 | 1128 | if (isSameTag && !objIsObj) { 1129 | stack || (stack = new Stack); 1130 | return (objIsArr || isTypedArray(object)) 1131 | ? equalArrays(object, other, equalFunc, customizer, bitmask, stack) 1132 | : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack); 1133 | } 1134 | if (!(bitmask & PARTIAL_COMPARE_FLAG)) { 1135 | var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), 1136 | othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); 1137 | 1138 | if (objIsWrapped || othIsWrapped) { 1139 | var objUnwrapped = objIsWrapped ? object.value() : object, 1140 | othUnwrapped = othIsWrapped ? other.value() : other; 1141 | 1142 | stack || (stack = new Stack); 1143 | return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); 1144 | } 1145 | } 1146 | if (!isSameTag) { 1147 | return false; 1148 | } 1149 | stack || (stack = new Stack); 1150 | return equalObjects(object, other, equalFunc, customizer, bitmask, stack); 1151 | } 1152 | 1153 | /** 1154 | * The base implementation of `_.isMatch` without support for iteratee shorthands. 1155 | * 1156 | * @private 1157 | * @param {Object} object The object to inspect. 1158 | * @param {Object} source The object of property values to match. 1159 | * @param {Array} matchData The property names, values, and compare flags to match. 1160 | * @param {Function} [customizer] The function to customize comparisons. 1161 | * @returns {boolean} Returns `true` if `object` is a match, else `false`. 1162 | */ 1163 | function baseIsMatch(object, source, matchData, customizer) { 1164 | var index = matchData.length, 1165 | length = index, 1166 | noCustomizer = !customizer; 1167 | 1168 | if (object == null) { 1169 | return !length; 1170 | } 1171 | object = Object(object); 1172 | while (index--) { 1173 | var data = matchData[index]; 1174 | if ((noCustomizer && data[2]) 1175 | ? data[1] !== object[data[0]] 1176 | : !(data[0] in object) 1177 | ) { 1178 | return false; 1179 | } 1180 | } 1181 | while (++index < length) { 1182 | data = matchData[index]; 1183 | var key = data[0], 1184 | objValue = object[key], 1185 | srcValue = data[1]; 1186 | 1187 | if (noCustomizer && data[2]) { 1188 | if (objValue === undefined && !(key in object)) { 1189 | return false; 1190 | } 1191 | } else { 1192 | var stack = new Stack; 1193 | if (customizer) { 1194 | var result = customizer(objValue, srcValue, key, object, source, stack); 1195 | } 1196 | if (!(result === undefined 1197 | ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack) 1198 | : result 1199 | )) { 1200 | return false; 1201 | } 1202 | } 1203 | } 1204 | return true; 1205 | } 1206 | 1207 | /** 1208 | * The base implementation of `_.isNative` without bad shim checks. 1209 | * 1210 | * @private 1211 | * @param {*} value The value to check. 1212 | * @returns {boolean} Returns `true` if `value` is a native function, 1213 | * else `false`. 1214 | */ 1215 | function baseIsNative(value) { 1216 | if (!isObject(value) || isMasked(value)) { 1217 | return false; 1218 | } 1219 | var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; 1220 | return pattern.test(toSource(value)); 1221 | } 1222 | 1223 | /** 1224 | * The base implementation of `_.isTypedArray` without Node.js optimizations. 1225 | * 1226 | * @private 1227 | * @param {*} value The value to check. 1228 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 1229 | */ 1230 | function baseIsTypedArray(value) { 1231 | return isObjectLike(value) && 1232 | isLength(value.length) && !!typedArrayTags[objectToString.call(value)]; 1233 | } 1234 | 1235 | /** 1236 | * The base implementation of `_.iteratee`. 1237 | * 1238 | * @private 1239 | * @param {*} [value=_.identity] The value to convert to an iteratee. 1240 | * @returns {Function} Returns the iteratee. 1241 | */ 1242 | function baseIteratee(value) { 1243 | // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. 1244 | // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. 1245 | if (typeof value == 'function') { 1246 | return value; 1247 | } 1248 | if (value == null) { 1249 | return identity; 1250 | } 1251 | if (typeof value == 'object') { 1252 | return isArray(value) 1253 | ? baseMatchesProperty(value[0], value[1]) 1254 | : baseMatches(value); 1255 | } 1256 | return property(value); 1257 | } 1258 | 1259 | /** 1260 | * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. 1261 | * 1262 | * @private 1263 | * @param {Object} object The object to query. 1264 | * @returns {Array} Returns the array of property names. 1265 | */ 1266 | function baseKeys(object) { 1267 | if (!isPrototype(object)) { 1268 | return nativeKeys(object); 1269 | } 1270 | var result = []; 1271 | for (var key in Object(object)) { 1272 | if (hasOwnProperty.call(object, key) && key != 'constructor') { 1273 | result.push(key); 1274 | } 1275 | } 1276 | return result; 1277 | } 1278 | 1279 | /** 1280 | * The base implementation of `_.matches` which doesn't clone `source`. 1281 | * 1282 | * @private 1283 | * @param {Object} source The object of property values to match. 1284 | * @returns {Function} Returns the new spec function. 1285 | */ 1286 | function baseMatches(source) { 1287 | var matchData = getMatchData(source); 1288 | if (matchData.length == 1 && matchData[0][2]) { 1289 | return matchesStrictComparable(matchData[0][0], matchData[0][1]); 1290 | } 1291 | return function(object) { 1292 | return object === source || baseIsMatch(object, source, matchData); 1293 | }; 1294 | } 1295 | 1296 | /** 1297 | * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. 1298 | * 1299 | * @private 1300 | * @param {string} path The path of the property to get. 1301 | * @param {*} srcValue The value to match. 1302 | * @returns {Function} Returns the new spec function. 1303 | */ 1304 | function baseMatchesProperty(path, srcValue) { 1305 | if (isKey(path) && isStrictComparable(srcValue)) { 1306 | return matchesStrictComparable(toKey(path), srcValue); 1307 | } 1308 | return function(object) { 1309 | var objValue = get(object, path); 1310 | return (objValue === undefined && objValue === srcValue) 1311 | ? hasIn(object, path) 1312 | : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG); 1313 | }; 1314 | } 1315 | 1316 | /** 1317 | * A specialized version of `baseProperty` which supports deep paths. 1318 | * 1319 | * @private 1320 | * @param {Array|string} path The path of the property to get. 1321 | * @returns {Function} Returns the new accessor function. 1322 | */ 1323 | function basePropertyDeep(path) { 1324 | return function(object) { 1325 | return baseGet(object, path); 1326 | }; 1327 | } 1328 | 1329 | /** 1330 | * The base implementation of `_.toString` which doesn't convert nullish 1331 | * values to empty strings. 1332 | * 1333 | * @private 1334 | * @param {*} value The value to process. 1335 | * @returns {string} Returns the string. 1336 | */ 1337 | function baseToString(value) { 1338 | // Exit early for strings to avoid a performance hit in some environments. 1339 | if (typeof value == 'string') { 1340 | return value; 1341 | } 1342 | if (isSymbol(value)) { 1343 | return symbolToString ? symbolToString.call(value) : ''; 1344 | } 1345 | var result = (value + ''); 1346 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 1347 | } 1348 | 1349 | /** 1350 | * Casts `value` to a path array if it's not one. 1351 | * 1352 | * @private 1353 | * @param {*} value The value to inspect. 1354 | * @returns {Array} Returns the cast property path array. 1355 | */ 1356 | function castPath(value) { 1357 | return isArray(value) ? value : stringToPath(value); 1358 | } 1359 | 1360 | /** 1361 | * Creates a function like `_.groupBy`. 1362 | * 1363 | * @private 1364 | * @param {Function} setter The function to set accumulator values. 1365 | * @param {Function} [initializer] The accumulator object initializer. 1366 | * @returns {Function} Returns the new aggregator function. 1367 | */ 1368 | function createAggregator(setter, initializer) { 1369 | return function(collection, iteratee) { 1370 | var func = isArray(collection) ? arrayAggregator : baseAggregator, 1371 | accumulator = initializer ? initializer() : {}; 1372 | 1373 | return func(collection, setter, baseIteratee(iteratee, 2), accumulator); 1374 | }; 1375 | } 1376 | 1377 | /** 1378 | * Creates a `baseEach` or `baseEachRight` function. 1379 | * 1380 | * @private 1381 | * @param {Function} eachFunc The function to iterate over a collection. 1382 | * @param {boolean} [fromRight] Specify iterating from right to left. 1383 | * @returns {Function} Returns the new base function. 1384 | */ 1385 | function createBaseEach(eachFunc, fromRight) { 1386 | return function(collection, iteratee) { 1387 | if (collection == null) { 1388 | return collection; 1389 | } 1390 | if (!isArrayLike(collection)) { 1391 | return eachFunc(collection, iteratee); 1392 | } 1393 | var length = collection.length, 1394 | index = fromRight ? length : -1, 1395 | iterable = Object(collection); 1396 | 1397 | while ((fromRight ? index-- : ++index < length)) { 1398 | if (iteratee(iterable[index], index, iterable) === false) { 1399 | break; 1400 | } 1401 | } 1402 | return collection; 1403 | }; 1404 | } 1405 | 1406 | /** 1407 | * Creates a base function for methods like `_.forIn` and `_.forOwn`. 1408 | * 1409 | * @private 1410 | * @param {boolean} [fromRight] Specify iterating from right to left. 1411 | * @returns {Function} Returns the new base function. 1412 | */ 1413 | function createBaseFor(fromRight) { 1414 | return function(object, iteratee, keysFunc) { 1415 | var index = -1, 1416 | iterable = Object(object), 1417 | props = keysFunc(object), 1418 | length = props.length; 1419 | 1420 | while (length--) { 1421 | var key = props[fromRight ? length : ++index]; 1422 | if (iteratee(iterable[key], key, iterable) === false) { 1423 | break; 1424 | } 1425 | } 1426 | return object; 1427 | }; 1428 | } 1429 | 1430 | /** 1431 | * A specialized version of `baseIsEqualDeep` for arrays with support for 1432 | * partial deep comparisons. 1433 | * 1434 | * @private 1435 | * @param {Array} array The array to compare. 1436 | * @param {Array} other The other array to compare. 1437 | * @param {Function} equalFunc The function to determine equivalents of values. 1438 | * @param {Function} customizer The function to customize comparisons. 1439 | * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` 1440 | * for more details. 1441 | * @param {Object} stack Tracks traversed `array` and `other` objects. 1442 | * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. 1443 | */ 1444 | function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { 1445 | var isPartial = bitmask & PARTIAL_COMPARE_FLAG, 1446 | arrLength = array.length, 1447 | othLength = other.length; 1448 | 1449 | if (arrLength != othLength && !(isPartial && othLength > arrLength)) { 1450 | return false; 1451 | } 1452 | // Assume cyclic values are equal. 1453 | var stacked = stack.get(array); 1454 | if (stacked && stack.get(other)) { 1455 | return stacked == other; 1456 | } 1457 | var index = -1, 1458 | result = true, 1459 | seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; 1460 | 1461 | stack.set(array, other); 1462 | stack.set(other, array); 1463 | 1464 | // Ignore non-index properties. 1465 | while (++index < arrLength) { 1466 | var arrValue = array[index], 1467 | othValue = other[index]; 1468 | 1469 | if (customizer) { 1470 | var compared = isPartial 1471 | ? customizer(othValue, arrValue, index, other, array, stack) 1472 | : customizer(arrValue, othValue, index, array, other, stack); 1473 | } 1474 | if (compared !== undefined) { 1475 | if (compared) { 1476 | continue; 1477 | } 1478 | result = false; 1479 | break; 1480 | } 1481 | // Recursively compare arrays (susceptible to call stack limits). 1482 | if (seen) { 1483 | if (!arraySome(other, function(othValue, othIndex) { 1484 | if (!seen.has(othIndex) && 1485 | (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { 1486 | return seen.add(othIndex); 1487 | } 1488 | })) { 1489 | result = false; 1490 | break; 1491 | } 1492 | } else if (!( 1493 | arrValue === othValue || 1494 | equalFunc(arrValue, othValue, customizer, bitmask, stack) 1495 | )) { 1496 | result = false; 1497 | break; 1498 | } 1499 | } 1500 | stack['delete'](array); 1501 | stack['delete'](other); 1502 | return result; 1503 | } 1504 | 1505 | /** 1506 | * A specialized version of `baseIsEqualDeep` for comparing objects of 1507 | * the same `toStringTag`. 1508 | * 1509 | * **Note:** This function only supports comparing values with tags of 1510 | * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. 1511 | * 1512 | * @private 1513 | * @param {Object} object The object to compare. 1514 | * @param {Object} other The other object to compare. 1515 | * @param {string} tag The `toStringTag` of the objects to compare. 1516 | * @param {Function} equalFunc The function to determine equivalents of values. 1517 | * @param {Function} customizer The function to customize comparisons. 1518 | * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` 1519 | * for more details. 1520 | * @param {Object} stack Tracks traversed `object` and `other` objects. 1521 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 1522 | */ 1523 | function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { 1524 | switch (tag) { 1525 | case dataViewTag: 1526 | if ((object.byteLength != other.byteLength) || 1527 | (object.byteOffset != other.byteOffset)) { 1528 | return false; 1529 | } 1530 | object = object.buffer; 1531 | other = other.buffer; 1532 | 1533 | case arrayBufferTag: 1534 | if ((object.byteLength != other.byteLength) || 1535 | !equalFunc(new Uint8Array(object), new Uint8Array(other))) { 1536 | return false; 1537 | } 1538 | return true; 1539 | 1540 | case boolTag: 1541 | case dateTag: 1542 | case numberTag: 1543 | // Coerce booleans to `1` or `0` and dates to milliseconds. 1544 | // Invalid dates are coerced to `NaN`. 1545 | return eq(+object, +other); 1546 | 1547 | case errorTag: 1548 | return object.name == other.name && object.message == other.message; 1549 | 1550 | case regexpTag: 1551 | case stringTag: 1552 | // Coerce regexes to strings and treat strings, primitives and objects, 1553 | // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring 1554 | // for more details. 1555 | return object == (other + ''); 1556 | 1557 | case mapTag: 1558 | var convert = mapToArray; 1559 | 1560 | case setTag: 1561 | var isPartial = bitmask & PARTIAL_COMPARE_FLAG; 1562 | convert || (convert = setToArray); 1563 | 1564 | if (object.size != other.size && !isPartial) { 1565 | return false; 1566 | } 1567 | // Assume cyclic values are equal. 1568 | var stacked = stack.get(object); 1569 | if (stacked) { 1570 | return stacked == other; 1571 | } 1572 | bitmask |= UNORDERED_COMPARE_FLAG; 1573 | 1574 | // Recursively compare objects (susceptible to call stack limits). 1575 | stack.set(object, other); 1576 | var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack); 1577 | stack['delete'](object); 1578 | return result; 1579 | 1580 | case symbolTag: 1581 | if (symbolValueOf) { 1582 | return symbolValueOf.call(object) == symbolValueOf.call(other); 1583 | } 1584 | } 1585 | return false; 1586 | } 1587 | 1588 | /** 1589 | * A specialized version of `baseIsEqualDeep` for objects with support for 1590 | * partial deep comparisons. 1591 | * 1592 | * @private 1593 | * @param {Object} object The object to compare. 1594 | * @param {Object} other The other object to compare. 1595 | * @param {Function} equalFunc The function to determine equivalents of values. 1596 | * @param {Function} customizer The function to customize comparisons. 1597 | * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` 1598 | * for more details. 1599 | * @param {Object} stack Tracks traversed `object` and `other` objects. 1600 | * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 1601 | */ 1602 | function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { 1603 | var isPartial = bitmask & PARTIAL_COMPARE_FLAG, 1604 | objProps = keys(object), 1605 | objLength = objProps.length, 1606 | othProps = keys(other), 1607 | othLength = othProps.length; 1608 | 1609 | if (objLength != othLength && !isPartial) { 1610 | return false; 1611 | } 1612 | var index = objLength; 1613 | while (index--) { 1614 | var key = objProps[index]; 1615 | if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { 1616 | return false; 1617 | } 1618 | } 1619 | // Assume cyclic values are equal. 1620 | var stacked = stack.get(object); 1621 | if (stacked && stack.get(other)) { 1622 | return stacked == other; 1623 | } 1624 | var result = true; 1625 | stack.set(object, other); 1626 | stack.set(other, object); 1627 | 1628 | var skipCtor = isPartial; 1629 | while (++index < objLength) { 1630 | key = objProps[index]; 1631 | var objValue = object[key], 1632 | othValue = other[key]; 1633 | 1634 | if (customizer) { 1635 | var compared = isPartial 1636 | ? customizer(othValue, objValue, key, other, object, stack) 1637 | : customizer(objValue, othValue, key, object, other, stack); 1638 | } 1639 | // Recursively compare objects (susceptible to call stack limits). 1640 | if (!(compared === undefined 1641 | ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) 1642 | : compared 1643 | )) { 1644 | result = false; 1645 | break; 1646 | } 1647 | skipCtor || (skipCtor = key == 'constructor'); 1648 | } 1649 | if (result && !skipCtor) { 1650 | var objCtor = object.constructor, 1651 | othCtor = other.constructor; 1652 | 1653 | // Non `Object` object instances with different constructors are not equal. 1654 | if (objCtor != othCtor && 1655 | ('constructor' in object && 'constructor' in other) && 1656 | !(typeof objCtor == 'function' && objCtor instanceof objCtor && 1657 | typeof othCtor == 'function' && othCtor instanceof othCtor)) { 1658 | result = false; 1659 | } 1660 | } 1661 | stack['delete'](object); 1662 | stack['delete'](other); 1663 | return result; 1664 | } 1665 | 1666 | /** 1667 | * Gets the data for `map`. 1668 | * 1669 | * @private 1670 | * @param {Object} map The map to query. 1671 | * @param {string} key The reference key. 1672 | * @returns {*} Returns the map data. 1673 | */ 1674 | function getMapData(map, key) { 1675 | var data = map.__data__; 1676 | return isKeyable(key) 1677 | ? data[typeof key == 'string' ? 'string' : 'hash'] 1678 | : data.map; 1679 | } 1680 | 1681 | /** 1682 | * Gets the property names, values, and compare flags of `object`. 1683 | * 1684 | * @private 1685 | * @param {Object} object The object to query. 1686 | * @returns {Array} Returns the match data of `object`. 1687 | */ 1688 | function getMatchData(object) { 1689 | var result = keys(object), 1690 | length = result.length; 1691 | 1692 | while (length--) { 1693 | var key = result[length], 1694 | value = object[key]; 1695 | 1696 | result[length] = [key, value, isStrictComparable(value)]; 1697 | } 1698 | return result; 1699 | } 1700 | 1701 | /** 1702 | * Gets the native function at `key` of `object`. 1703 | * 1704 | * @private 1705 | * @param {Object} object The object to query. 1706 | * @param {string} key The key of the method to get. 1707 | * @returns {*} Returns the function if it's native, else `undefined`. 1708 | */ 1709 | function getNative(object, key) { 1710 | var value = getValue(object, key); 1711 | return baseIsNative(value) ? value : undefined; 1712 | } 1713 | 1714 | /** 1715 | * Gets the `toStringTag` of `value`. 1716 | * 1717 | * @private 1718 | * @param {*} value The value to query. 1719 | * @returns {string} Returns the `toStringTag`. 1720 | */ 1721 | var getTag = baseGetTag; 1722 | 1723 | // Fallback for data views, maps, sets, and weak maps in IE 11, 1724 | // for data views in Edge < 14, and promises in Node.js. 1725 | if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || 1726 | (Map && getTag(new Map) != mapTag) || 1727 | (Promise && getTag(Promise.resolve()) != promiseTag) || 1728 | (Set && getTag(new Set) != setTag) || 1729 | (WeakMap && getTag(new WeakMap) != weakMapTag)) { 1730 | getTag = function(value) { 1731 | var result = objectToString.call(value), 1732 | Ctor = result == objectTag ? value.constructor : undefined, 1733 | ctorString = Ctor ? toSource(Ctor) : undefined; 1734 | 1735 | if (ctorString) { 1736 | switch (ctorString) { 1737 | case dataViewCtorString: return dataViewTag; 1738 | case mapCtorString: return mapTag; 1739 | case promiseCtorString: return promiseTag; 1740 | case setCtorString: return setTag; 1741 | case weakMapCtorString: return weakMapTag; 1742 | } 1743 | } 1744 | return result; 1745 | }; 1746 | } 1747 | 1748 | /** 1749 | * Checks if `path` exists on `object`. 1750 | * 1751 | * @private 1752 | * @param {Object} object The object to query. 1753 | * @param {Array|string} path The path to check. 1754 | * @param {Function} hasFunc The function to check properties. 1755 | * @returns {boolean} Returns `true` if `path` exists, else `false`. 1756 | */ 1757 | function hasPath(object, path, hasFunc) { 1758 | path = isKey(path, object) ? [path] : castPath(path); 1759 | 1760 | var result, 1761 | index = -1, 1762 | length = path.length; 1763 | 1764 | while (++index < length) { 1765 | var key = toKey(path[index]); 1766 | if (!(result = object != null && hasFunc(object, key))) { 1767 | break; 1768 | } 1769 | object = object[key]; 1770 | } 1771 | if (result) { 1772 | return result; 1773 | } 1774 | var length = object ? object.length : 0; 1775 | return !!length && isLength(length) && isIndex(key, length) && 1776 | (isArray(object) || isArguments(object)); 1777 | } 1778 | 1779 | /** 1780 | * Checks if `value` is a valid array-like index. 1781 | * 1782 | * @private 1783 | * @param {*} value The value to check. 1784 | * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. 1785 | * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. 1786 | */ 1787 | function isIndex(value, length) { 1788 | length = length == null ? MAX_SAFE_INTEGER : length; 1789 | return !!length && 1790 | (typeof value == 'number' || reIsUint.test(value)) && 1791 | (value > -1 && value % 1 == 0 && value < length); 1792 | } 1793 | 1794 | /** 1795 | * Checks if `value` is a property name and not a property path. 1796 | * 1797 | * @private 1798 | * @param {*} value The value to check. 1799 | * @param {Object} [object] The object to query keys on. 1800 | * @returns {boolean} Returns `true` if `value` is a property name, else `false`. 1801 | */ 1802 | function isKey(value, object) { 1803 | if (isArray(value)) { 1804 | return false; 1805 | } 1806 | var type = typeof value; 1807 | if (type == 'number' || type == 'symbol' || type == 'boolean' || 1808 | value == null || isSymbol(value)) { 1809 | return true; 1810 | } 1811 | return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || 1812 | (object != null && value in Object(object)); 1813 | } 1814 | 1815 | /** 1816 | * Checks if `value` is suitable for use as unique object key. 1817 | * 1818 | * @private 1819 | * @param {*} value The value to check. 1820 | * @returns {boolean} Returns `true` if `value` is suitable, else `false`. 1821 | */ 1822 | function isKeyable(value) { 1823 | var type = typeof value; 1824 | return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') 1825 | ? (value !== '__proto__') 1826 | : (value === null); 1827 | } 1828 | 1829 | /** 1830 | * Checks if `func` has its source masked. 1831 | * 1832 | * @private 1833 | * @param {Function} func The function to check. 1834 | * @returns {boolean} Returns `true` if `func` is masked, else `false`. 1835 | */ 1836 | function isMasked(func) { 1837 | return !!maskSrcKey && (maskSrcKey in func); 1838 | } 1839 | 1840 | /** 1841 | * Checks if `value` is likely a prototype object. 1842 | * 1843 | * @private 1844 | * @param {*} value The value to check. 1845 | * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. 1846 | */ 1847 | function isPrototype(value) { 1848 | var Ctor = value && value.constructor, 1849 | proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; 1850 | 1851 | return value === proto; 1852 | } 1853 | 1854 | /** 1855 | * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. 1856 | * 1857 | * @private 1858 | * @param {*} value The value to check. 1859 | * @returns {boolean} Returns `true` if `value` if suitable for strict 1860 | * equality comparisons, else `false`. 1861 | */ 1862 | function isStrictComparable(value) { 1863 | return value === value && !isObject(value); 1864 | } 1865 | 1866 | /** 1867 | * A specialized version of `matchesProperty` for source values suitable 1868 | * for strict equality comparisons, i.e. `===`. 1869 | * 1870 | * @private 1871 | * @param {string} key The key of the property to get. 1872 | * @param {*} srcValue The value to match. 1873 | * @returns {Function} Returns the new spec function. 1874 | */ 1875 | function matchesStrictComparable(key, srcValue) { 1876 | return function(object) { 1877 | if (object == null) { 1878 | return false; 1879 | } 1880 | return object[key] === srcValue && 1881 | (srcValue !== undefined || (key in Object(object))); 1882 | }; 1883 | } 1884 | 1885 | /** 1886 | * Converts `string` to a property path array. 1887 | * 1888 | * @private 1889 | * @param {string} string The string to convert. 1890 | * @returns {Array} Returns the property path array. 1891 | */ 1892 | var stringToPath = memoize(function(string) { 1893 | string = toString(string); 1894 | 1895 | var result = []; 1896 | if (reLeadingDot.test(string)) { 1897 | result.push(''); 1898 | } 1899 | string.replace(rePropName, function(match, number, quote, string) { 1900 | result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); 1901 | }); 1902 | return result; 1903 | }); 1904 | 1905 | /** 1906 | * Converts `value` to a string key if it's not a string or symbol. 1907 | * 1908 | * @private 1909 | * @param {*} value The value to inspect. 1910 | * @returns {string|symbol} Returns the key. 1911 | */ 1912 | function toKey(value) { 1913 | if (typeof value == 'string' || isSymbol(value)) { 1914 | return value; 1915 | } 1916 | var result = (value + ''); 1917 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 1918 | } 1919 | 1920 | /** 1921 | * Converts `func` to its source code. 1922 | * 1923 | * @private 1924 | * @param {Function} func The function to process. 1925 | * @returns {string} Returns the source code. 1926 | */ 1927 | function toSource(func) { 1928 | if (func != null) { 1929 | try { 1930 | return funcToString.call(func); 1931 | } catch (e) {} 1932 | try { 1933 | return (func + ''); 1934 | } catch (e) {} 1935 | } 1936 | return ''; 1937 | } 1938 | 1939 | /** 1940 | * Creates an object composed of keys generated from the results of running 1941 | * each element of `collection` thru `iteratee`. The order of grouped values 1942 | * is determined by the order they occur in `collection`. The corresponding 1943 | * value of each key is an array of elements responsible for generating the 1944 | * key. The iteratee is invoked with one argument: (value). 1945 | * 1946 | * @static 1947 | * @memberOf _ 1948 | * @since 0.1.0 1949 | * @category Collection 1950 | * @param {Array|Object} collection The collection to iterate over. 1951 | * @param {Function} [iteratee=_.identity] 1952 | * The iteratee to transform keys. 1953 | * @returns {Object} Returns the composed aggregate object. 1954 | * @example 1955 | * 1956 | * _.groupBy([6.1, 4.2, 6.3], Math.floor); 1957 | * // => { '4': [4.2], '6': [6.1, 6.3] } 1958 | * 1959 | * // The `_.property` iteratee shorthand. 1960 | * _.groupBy(['one', 'two', 'three'], 'length'); 1961 | * // => { '3': ['one', 'two'], '5': ['three'] } 1962 | */ 1963 | var groupBy = createAggregator(function(result, value, key) { 1964 | if (hasOwnProperty.call(result, key)) { 1965 | result[key].push(value); 1966 | } else { 1967 | result[key] = [value]; 1968 | } 1969 | }); 1970 | 1971 | /** 1972 | * Creates a function that memoizes the result of `func`. If `resolver` is 1973 | * provided, it determines the cache key for storing the result based on the 1974 | * arguments provided to the memoized function. By default, the first argument 1975 | * provided to the memoized function is used as the map cache key. The `func` 1976 | * is invoked with the `this` binding of the memoized function. 1977 | * 1978 | * **Note:** The cache is exposed as the `cache` property on the memoized 1979 | * function. Its creation may be customized by replacing the `_.memoize.Cache` 1980 | * constructor with one whose instances implement the 1981 | * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) 1982 | * method interface of `delete`, `get`, `has`, and `set`. 1983 | * 1984 | * @static 1985 | * @memberOf _ 1986 | * @since 0.1.0 1987 | * @category Function 1988 | * @param {Function} func The function to have its output memoized. 1989 | * @param {Function} [resolver] The function to resolve the cache key. 1990 | * @returns {Function} Returns the new memoized function. 1991 | * @example 1992 | * 1993 | * var object = { 'a': 1, 'b': 2 }; 1994 | * var other = { 'c': 3, 'd': 4 }; 1995 | * 1996 | * var values = _.memoize(_.values); 1997 | * values(object); 1998 | * // => [1, 2] 1999 | * 2000 | * values(other); 2001 | * // => [3, 4] 2002 | * 2003 | * object.a = 2; 2004 | * values(object); 2005 | * // => [1, 2] 2006 | * 2007 | * // Modify the result cache. 2008 | * values.cache.set(object, ['a', 'b']); 2009 | * values(object); 2010 | * // => ['a', 'b'] 2011 | * 2012 | * // Replace `_.memoize.Cache`. 2013 | * _.memoize.Cache = WeakMap; 2014 | */ 2015 | function memoize(func, resolver) { 2016 | if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { 2017 | throw new TypeError(FUNC_ERROR_TEXT); 2018 | } 2019 | var memoized = function() { 2020 | var args = arguments, 2021 | key = resolver ? resolver.apply(this, args) : args[0], 2022 | cache = memoized.cache; 2023 | 2024 | if (cache.has(key)) { 2025 | return cache.get(key); 2026 | } 2027 | var result = func.apply(this, args); 2028 | memoized.cache = cache.set(key, result); 2029 | return result; 2030 | }; 2031 | memoized.cache = new (memoize.Cache || MapCache); 2032 | return memoized; 2033 | } 2034 | 2035 | // Assign cache to `_.memoize`. 2036 | memoize.Cache = MapCache; 2037 | 2038 | /** 2039 | * Performs a 2040 | * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) 2041 | * comparison between two values to determine if they are equivalent. 2042 | * 2043 | * @static 2044 | * @memberOf _ 2045 | * @since 4.0.0 2046 | * @category Lang 2047 | * @param {*} value The value to compare. 2048 | * @param {*} other The other value to compare. 2049 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 2050 | * @example 2051 | * 2052 | * var object = { 'a': 1 }; 2053 | * var other = { 'a': 1 }; 2054 | * 2055 | * _.eq(object, object); 2056 | * // => true 2057 | * 2058 | * _.eq(object, other); 2059 | * // => false 2060 | * 2061 | * _.eq('a', 'a'); 2062 | * // => true 2063 | * 2064 | * _.eq('a', Object('a')); 2065 | * // => false 2066 | * 2067 | * _.eq(NaN, NaN); 2068 | * // => true 2069 | */ 2070 | function eq(value, other) { 2071 | return value === other || (value !== value && other !== other); 2072 | } 2073 | 2074 | /** 2075 | * Checks if `value` is likely an `arguments` object. 2076 | * 2077 | * @static 2078 | * @memberOf _ 2079 | * @since 0.1.0 2080 | * @category Lang 2081 | * @param {*} value The value to check. 2082 | * @returns {boolean} Returns `true` if `value` is an `arguments` object, 2083 | * else `false`. 2084 | * @example 2085 | * 2086 | * _.isArguments(function() { return arguments; }()); 2087 | * // => true 2088 | * 2089 | * _.isArguments([1, 2, 3]); 2090 | * // => false 2091 | */ 2092 | function isArguments(value) { 2093 | // Safari 8.1 makes `arguments.callee` enumerable in strict mode. 2094 | return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && 2095 | (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); 2096 | } 2097 | 2098 | /** 2099 | * Checks if `value` is classified as an `Array` object. 2100 | * 2101 | * @static 2102 | * @memberOf _ 2103 | * @since 0.1.0 2104 | * @category Lang 2105 | * @param {*} value The value to check. 2106 | * @returns {boolean} Returns `true` if `value` is an array, else `false`. 2107 | * @example 2108 | * 2109 | * _.isArray([1, 2, 3]); 2110 | * // => true 2111 | * 2112 | * _.isArray(document.body.children); 2113 | * // => false 2114 | * 2115 | * _.isArray('abc'); 2116 | * // => false 2117 | * 2118 | * _.isArray(_.noop); 2119 | * // => false 2120 | */ 2121 | var isArray = Array.isArray; 2122 | 2123 | /** 2124 | * Checks if `value` is array-like. A value is considered array-like if it's 2125 | * not a function and has a `value.length` that's an integer greater than or 2126 | * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. 2127 | * 2128 | * @static 2129 | * @memberOf _ 2130 | * @since 4.0.0 2131 | * @category Lang 2132 | * @param {*} value The value to check. 2133 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 2134 | * @example 2135 | * 2136 | * _.isArrayLike([1, 2, 3]); 2137 | * // => true 2138 | * 2139 | * _.isArrayLike(document.body.children); 2140 | * // => true 2141 | * 2142 | * _.isArrayLike('abc'); 2143 | * // => true 2144 | * 2145 | * _.isArrayLike(_.noop); 2146 | * // => false 2147 | */ 2148 | function isArrayLike(value) { 2149 | return value != null && isLength(value.length) && !isFunction(value); 2150 | } 2151 | 2152 | /** 2153 | * This method is like `_.isArrayLike` except that it also checks if `value` 2154 | * is an object. 2155 | * 2156 | * @static 2157 | * @memberOf _ 2158 | * @since 4.0.0 2159 | * @category Lang 2160 | * @param {*} value The value to check. 2161 | * @returns {boolean} Returns `true` if `value` is an array-like object, 2162 | * else `false`. 2163 | * @example 2164 | * 2165 | * _.isArrayLikeObject([1, 2, 3]); 2166 | * // => true 2167 | * 2168 | * _.isArrayLikeObject(document.body.children); 2169 | * // => true 2170 | * 2171 | * _.isArrayLikeObject('abc'); 2172 | * // => false 2173 | * 2174 | * _.isArrayLikeObject(_.noop); 2175 | * // => false 2176 | */ 2177 | function isArrayLikeObject(value) { 2178 | return isObjectLike(value) && isArrayLike(value); 2179 | } 2180 | 2181 | /** 2182 | * Checks if `value` is classified as a `Function` object. 2183 | * 2184 | * @static 2185 | * @memberOf _ 2186 | * @since 0.1.0 2187 | * @category Lang 2188 | * @param {*} value The value to check. 2189 | * @returns {boolean} Returns `true` if `value` is a function, else `false`. 2190 | * @example 2191 | * 2192 | * _.isFunction(_); 2193 | * // => true 2194 | * 2195 | * _.isFunction(/abc/); 2196 | * // => false 2197 | */ 2198 | function isFunction(value) { 2199 | // The use of `Object#toString` avoids issues with the `typeof` operator 2200 | // in Safari 8-9 which returns 'object' for typed array and other constructors. 2201 | var tag = isObject(value) ? objectToString.call(value) : ''; 2202 | return tag == funcTag || tag == genTag; 2203 | } 2204 | 2205 | /** 2206 | * Checks if `value` is a valid array-like length. 2207 | * 2208 | * **Note:** This method is loosely based on 2209 | * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). 2210 | * 2211 | * @static 2212 | * @memberOf _ 2213 | * @since 4.0.0 2214 | * @category Lang 2215 | * @param {*} value The value to check. 2216 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 2217 | * @example 2218 | * 2219 | * _.isLength(3); 2220 | * // => true 2221 | * 2222 | * _.isLength(Number.MIN_VALUE); 2223 | * // => false 2224 | * 2225 | * _.isLength(Infinity); 2226 | * // => false 2227 | * 2228 | * _.isLength('3'); 2229 | * // => false 2230 | */ 2231 | function isLength(value) { 2232 | return typeof value == 'number' && 2233 | value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; 2234 | } 2235 | 2236 | /** 2237 | * Checks if `value` is the 2238 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) 2239 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 2240 | * 2241 | * @static 2242 | * @memberOf _ 2243 | * @since 0.1.0 2244 | * @category Lang 2245 | * @param {*} value The value to check. 2246 | * @returns {boolean} Returns `true` if `value` is an object, else `false`. 2247 | * @example 2248 | * 2249 | * _.isObject({}); 2250 | * // => true 2251 | * 2252 | * _.isObject([1, 2, 3]); 2253 | * // => true 2254 | * 2255 | * _.isObject(_.noop); 2256 | * // => true 2257 | * 2258 | * _.isObject(null); 2259 | * // => false 2260 | */ 2261 | function isObject(value) { 2262 | var type = typeof value; 2263 | return !!value && (type == 'object' || type == 'function'); 2264 | } 2265 | 2266 | /** 2267 | * Checks if `value` is object-like. A value is object-like if it's not `null` 2268 | * and has a `typeof` result of "object". 2269 | * 2270 | * @static 2271 | * @memberOf _ 2272 | * @since 4.0.0 2273 | * @category Lang 2274 | * @param {*} value The value to check. 2275 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 2276 | * @example 2277 | * 2278 | * _.isObjectLike({}); 2279 | * // => true 2280 | * 2281 | * _.isObjectLike([1, 2, 3]); 2282 | * // => true 2283 | * 2284 | * _.isObjectLike(_.noop); 2285 | * // => false 2286 | * 2287 | * _.isObjectLike(null); 2288 | * // => false 2289 | */ 2290 | function isObjectLike(value) { 2291 | return !!value && typeof value == 'object'; 2292 | } 2293 | 2294 | /** 2295 | * Checks if `value` is classified as a `Symbol` primitive or object. 2296 | * 2297 | * @static 2298 | * @memberOf _ 2299 | * @since 4.0.0 2300 | * @category Lang 2301 | * @param {*} value The value to check. 2302 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. 2303 | * @example 2304 | * 2305 | * _.isSymbol(Symbol.iterator); 2306 | * // => true 2307 | * 2308 | * _.isSymbol('abc'); 2309 | * // => false 2310 | */ 2311 | function isSymbol(value) { 2312 | return typeof value == 'symbol' || 2313 | (isObjectLike(value) && objectToString.call(value) == symbolTag); 2314 | } 2315 | 2316 | /** 2317 | * Checks if `value` is classified as a typed array. 2318 | * 2319 | * @static 2320 | * @memberOf _ 2321 | * @since 3.0.0 2322 | * @category Lang 2323 | * @param {*} value The value to check. 2324 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 2325 | * @example 2326 | * 2327 | * _.isTypedArray(new Uint8Array); 2328 | * // => true 2329 | * 2330 | * _.isTypedArray([]); 2331 | * // => false 2332 | */ 2333 | var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; 2334 | 2335 | /** 2336 | * Converts `value` to a string. An empty string is returned for `null` 2337 | * and `undefined` values. The sign of `-0` is preserved. 2338 | * 2339 | * @static 2340 | * @memberOf _ 2341 | * @since 4.0.0 2342 | * @category Lang 2343 | * @param {*} value The value to process. 2344 | * @returns {string} Returns the string. 2345 | * @example 2346 | * 2347 | * _.toString(null); 2348 | * // => '' 2349 | * 2350 | * _.toString(-0); 2351 | * // => '-0' 2352 | * 2353 | * _.toString([1, 2, 3]); 2354 | * // => '1,2,3' 2355 | */ 2356 | function toString(value) { 2357 | return value == null ? '' : baseToString(value); 2358 | } 2359 | 2360 | /** 2361 | * Gets the value at `path` of `object`. If the resolved value is 2362 | * `undefined`, the `defaultValue` is returned in its place. 2363 | * 2364 | * @static 2365 | * @memberOf _ 2366 | * @since 3.7.0 2367 | * @category Object 2368 | * @param {Object} object The object to query. 2369 | * @param {Array|string} path The path of the property to get. 2370 | * @param {*} [defaultValue] The value returned for `undefined` resolved values. 2371 | * @returns {*} Returns the resolved value. 2372 | * @example 2373 | * 2374 | * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 2375 | * 2376 | * _.get(object, 'a[0].b.c'); 2377 | * // => 3 2378 | * 2379 | * _.get(object, ['a', '0', 'b', 'c']); 2380 | * // => 3 2381 | * 2382 | * _.get(object, 'a.b.c', 'default'); 2383 | * // => 'default' 2384 | */ 2385 | function get(object, path, defaultValue) { 2386 | var result = object == null ? undefined : baseGet(object, path); 2387 | return result === undefined ? defaultValue : result; 2388 | } 2389 | 2390 | /** 2391 | * Checks if `path` is a direct or inherited property of `object`. 2392 | * 2393 | * @static 2394 | * @memberOf _ 2395 | * @since 4.0.0 2396 | * @category Object 2397 | * @param {Object} object The object to query. 2398 | * @param {Array|string} path The path to check. 2399 | * @returns {boolean} Returns `true` if `path` exists, else `false`. 2400 | * @example 2401 | * 2402 | * var object = _.create({ 'a': _.create({ 'b': 2 }) }); 2403 | * 2404 | * _.hasIn(object, 'a'); 2405 | * // => true 2406 | * 2407 | * _.hasIn(object, 'a.b'); 2408 | * // => true 2409 | * 2410 | * _.hasIn(object, ['a', 'b']); 2411 | * // => true 2412 | * 2413 | * _.hasIn(object, 'b'); 2414 | * // => false 2415 | */ 2416 | function hasIn(object, path) { 2417 | return object != null && hasPath(object, path, baseHasIn); 2418 | } 2419 | 2420 | /** 2421 | * Creates an array of the own enumerable property names of `object`. 2422 | * 2423 | * **Note:** Non-object values are coerced to objects. See the 2424 | * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) 2425 | * for more details. 2426 | * 2427 | * @static 2428 | * @since 0.1.0 2429 | * @memberOf _ 2430 | * @category Object 2431 | * @param {Object} object The object to query. 2432 | * @returns {Array} Returns the array of property names. 2433 | * @example 2434 | * 2435 | * function Foo() { 2436 | * this.a = 1; 2437 | * this.b = 2; 2438 | * } 2439 | * 2440 | * Foo.prototype.c = 3; 2441 | * 2442 | * _.keys(new Foo); 2443 | * // => ['a', 'b'] (iteration order is not guaranteed) 2444 | * 2445 | * _.keys('hi'); 2446 | * // => ['0', '1'] 2447 | */ 2448 | function keys(object) { 2449 | return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); 2450 | } 2451 | 2452 | /** 2453 | * This method returns the first argument it receives. 2454 | * 2455 | * @static 2456 | * @since 0.1.0 2457 | * @memberOf _ 2458 | * @category Util 2459 | * @param {*} value Any value. 2460 | * @returns {*} Returns `value`. 2461 | * @example 2462 | * 2463 | * var object = { 'a': 1 }; 2464 | * 2465 | * console.log(_.identity(object) === object); 2466 | * // => true 2467 | */ 2468 | function identity(value) { 2469 | return value; 2470 | } 2471 | 2472 | /** 2473 | * Creates a function that returns the value at `path` of a given object. 2474 | * 2475 | * @static 2476 | * @memberOf _ 2477 | * @since 2.4.0 2478 | * @category Util 2479 | * @param {Array|string} path The path of the property to get. 2480 | * @returns {Function} Returns the new accessor function. 2481 | * @example 2482 | * 2483 | * var objects = [ 2484 | * { 'a': { 'b': 2 } }, 2485 | * { 'a': { 'b': 1 } } 2486 | * ]; 2487 | * 2488 | * _.map(objects, _.property('a.b')); 2489 | * // => [2, 1] 2490 | * 2491 | * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); 2492 | * // => [1, 2] 2493 | */ 2494 | function property(path) { 2495 | return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); 2496 | } 2497 | 2498 | module.exports = groupBy; 2499 | 2500 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(3)(module))) 2501 | 2502 | /***/ }), 2503 | /* 3 */ 2504 | /***/ (function(module, exports) { 2505 | 2506 | module.exports = function(module) { 2507 | if(!module.webpackPolyfill) { 2508 | module.deprecate = function() {}; 2509 | module.paths = []; 2510 | // module.parent = undefined by default 2511 | if(!module.children) module.children = []; 2512 | Object.defineProperty(module, "loaded", { 2513 | enumerable: true, 2514 | get: function() { 2515 | return module.l; 2516 | } 2517 | }); 2518 | Object.defineProperty(module, "id", { 2519 | enumerable: true, 2520 | get: function() { 2521 | return module.i; 2522 | } 2523 | }); 2524 | module.webpackPolyfill = 1; 2525 | } 2526 | return module; 2527 | }; 2528 | 2529 | 2530 | /***/ }) 2531 | /******/ ]); -------------------------------------------------------------------------------- /example/node/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var smartArrayToTree = require('../index.js'); 3 | var fetch = require('node-fetch'); 4 | fetch('https://raw.githubusercontent.com/internet5/smart-array-to-tree/master/example/data.json').then(function(response) { 5 | return response.json(); 6 | }).then(function(data) { 7 | console.log(new Date()); 8 | var tree = smartArrayToTree(data, { id:'regionId', pid:'parentId', firstPid:null }); 9 | console.log(new Date()); 10 | console.log(tree) 11 | }).catch(function(e) { 12 | console.log(e); 13 | }); 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var groupBy = require('lodash.groupby') 4 | function smartArrayToTree(array, options) { 5 | if(!array || array.length==0) 6 | return array 7 | options = Object.assign({ 8 | id: 'id', 9 | pid: 'pid', 10 | children: 'children', 11 | firstPid: null 12 | }, options); 13 | var groupArray = groupBy(array, function (n) { 14 | return n[options.pid]; 15 | }); 16 | var firstArray = groupArray[options.firstPid]; 17 | transform(firstArray); 18 | function transform(startList) { 19 | if (startList) 20 | for (var i = 0; i < startList.length; i++) { 21 | groupArray[startList[i][options.id]] && (startList[i][options.children] = groupArray[startList[i][options.id]]); 22 | transform(startList[i][options.children]); 23 | } 24 | } 25 | return firstArray; 26 | } 27 | global.smartArrayToTree=smartArrayToTree; 28 | module.exports=smartArrayToTree; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smart-arraytotree", 3 | "version": "1.1.1", 4 | "description": "Convert large amounts of data array to tree fastly", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack", 8 | "test": "node test/test.js" 9 | }, 10 | "keywords": [ 11 | "fast", 12 | "array", 13 | "list", 14 | "tree", 15 | "large" 16 | ], 17 | "author": "williamxx", 18 | "license": "LGPL-3.0", 19 | "dependencies": { 20 | "lodash.groupby": "^4.6.0" 21 | }, 22 | "devDependencies": { 23 | "node-fetch": "^2.6.1", 24 | "tape": "^4.8.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var smartArrayToTree = require('../index.js'); 3 | var test = require('tape'); 4 | 5 | test('totree test', function (t) { 6 | var list=[ 7 | { 8 | id:'1', 9 | param1:'xx', 10 | pid:null, 11 | }, 12 | { 13 | id:'2', 14 | param1:'xx', 15 | pid:null, 16 | }, 17 | { 18 | id:'3', 19 | param1:'xx', 20 | pid:null, 21 | }, 22 | { 23 | id:'11', 24 | param1:'yy', 25 | pid:'1', 26 | }, 27 | { 28 | id:'22', 29 | param1:'yy', 30 | pid:'2', 31 | }, 32 | { 33 | id:'33', 34 | param1:'yy', 35 | pid:'3', 36 | }, 37 | ] 38 | var tree = smartArrayToTree(list); 39 | 40 | t.equal(tree.length, 3); 41 | 42 | t.end(); 43 | }); 44 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: './index.js', 5 | output: { 6 | filename: 'smartArrayToTree.js', 7 | path: path.resolve(__dirname, 'dist') 8 | } 9 | }; --------------------------------------------------------------------------------