deepcopy.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. /*!
  2. * @license deepcopy.js Copyright(c) 2013 sasa+1
  3. * https://github.com/sasaplus1/deepcopy.js
  4. * Released under the MIT license.
  5. *
  6. * type-detect
  7. * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
  8. * MIT Licensed
  9. */
  10. (function (global, factory) {
  11. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  12. typeof define === 'function' && define.amd ? define(factory) :
  13. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.deepcopy = factory());
  14. }(this, (function () { 'use strict';
  15. var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  16. function createCommonjsModule(fn, module) {
  17. return module = { exports: {} }, fn(module, module.exports), module.exports;
  18. }
  19. var typeDetect = createCommonjsModule(function (module, exports) {
  20. (function (global, factory) {
  21. module.exports = factory() ;
  22. }(commonjsGlobal, (function () {
  23. /* !
  24. * type-detect
  25. * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
  26. * MIT Licensed
  27. */
  28. var promiseExists = typeof Promise === 'function';
  29. /* eslint-disable no-undef */
  30. var globalObject = typeof self === 'object' ? self : commonjsGlobal; // eslint-disable-line id-blacklist
  31. var symbolExists = typeof Symbol !== 'undefined';
  32. var mapExists = typeof Map !== 'undefined';
  33. var setExists = typeof Set !== 'undefined';
  34. var weakMapExists = typeof WeakMap !== 'undefined';
  35. var weakSetExists = typeof WeakSet !== 'undefined';
  36. var dataViewExists = typeof DataView !== 'undefined';
  37. var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';
  38. var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';
  39. var setEntriesExists = setExists && typeof Set.prototype.entries === 'function';
  40. var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';
  41. var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());
  42. var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());
  43. var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
  44. var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());
  45. var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function';
  46. var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());
  47. var toStringLeftSliceLength = 8;
  48. var toStringRightSliceLength = -1;
  49. /**
  50. * ### typeOf (obj)
  51. *
  52. * Uses `Object.prototype.toString` to determine the type of an object,
  53. * normalising behaviour across engine versions & well optimised.
  54. *
  55. * @param {Mixed} object
  56. * @return {String} object type
  57. * @api public
  58. */
  59. function typeDetect(obj) {
  60. /* ! Speed optimisation
  61. * Pre:
  62. * string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled)
  63. * boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled)
  64. * number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled)
  65. * undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled)
  66. * function x 2,556,769 ops/sec ±1.73% (77 runs sampled)
  67. * Post:
  68. * string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled)
  69. * boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled)
  70. * number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled)
  71. * undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled)
  72. * function x 31,296,870 ops/sec ±0.96% (83 runs sampled)
  73. */
  74. var typeofObj = typeof obj;
  75. if (typeofObj !== 'object') {
  76. return typeofObj;
  77. }
  78. /* ! Speed optimisation
  79. * Pre:
  80. * null x 28,645,765 ops/sec ±1.17% (82 runs sampled)
  81. * Post:
  82. * null x 36,428,962 ops/sec ±1.37% (84 runs sampled)
  83. */
  84. if (obj === null) {
  85. return 'null';
  86. }
  87. /* ! Spec Conformance
  88. * Test: `Object.prototype.toString.call(window)``
  89. * - Node === "[object global]"
  90. * - Chrome === "[object global]"
  91. * - Firefox === "[object Window]"
  92. * - PhantomJS === "[object Window]"
  93. * - Safari === "[object Window]"
  94. * - IE 11 === "[object Window]"
  95. * - IE Edge === "[object Window]"
  96. * Test: `Object.prototype.toString.call(this)``
  97. * - Chrome Worker === "[object global]"
  98. * - Firefox Worker === "[object DedicatedWorkerGlobalScope]"
  99. * - Safari Worker === "[object DedicatedWorkerGlobalScope]"
  100. * - IE 11 Worker === "[object WorkerGlobalScope]"
  101. * - IE Edge Worker === "[object WorkerGlobalScope]"
  102. */
  103. if (obj === globalObject) {
  104. return 'global';
  105. }
  106. /* ! Speed optimisation
  107. * Pre:
  108. * array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled)
  109. * Post:
  110. * array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled)
  111. */
  112. if (
  113. Array.isArray(obj) &&
  114. (symbolToStringTagExists === false || !(Symbol.toStringTag in obj))
  115. ) {
  116. return 'Array';
  117. }
  118. // Not caching existence of `window` and related properties due to potential
  119. // for `window` to be unset before tests in quasi-browser environments.
  120. if (typeof window === 'object' && window !== null) {
  121. /* ! Spec Conformance
  122. * (https://html.spec.whatwg.org/multipage/browsers.html#location)
  123. * WhatWG HTML$7.7.3 - The `Location` interface
  124. * Test: `Object.prototype.toString.call(window.location)``
  125. * - IE <=11 === "[object Object]"
  126. * - IE Edge <=13 === "[object Object]"
  127. */
  128. if (typeof window.location === 'object' && obj === window.location) {
  129. return 'Location';
  130. }
  131. /* ! Spec Conformance
  132. * (https://html.spec.whatwg.org/#document)
  133. * WhatWG HTML$3.1.1 - The `Document` object
  134. * Note: Most browsers currently adher to the W3C DOM Level 2 spec
  135. * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)
  136. * which suggests that browsers should use HTMLTableCellElement for
  137. * both TD and TH elements. WhatWG separates these.
  138. * WhatWG HTML states:
  139. * > For historical reasons, Window objects must also have a
  140. * > writable, configurable, non-enumerable property named
  141. * > HTMLDocument whose value is the Document interface object.
  142. * Test: `Object.prototype.toString.call(document)``
  143. * - Chrome === "[object HTMLDocument]"
  144. * - Firefox === "[object HTMLDocument]"
  145. * - Safari === "[object HTMLDocument]"
  146. * - IE <=10 === "[object Document]"
  147. * - IE 11 === "[object HTMLDocument]"
  148. * - IE Edge <=13 === "[object HTMLDocument]"
  149. */
  150. if (typeof window.document === 'object' && obj === window.document) {
  151. return 'Document';
  152. }
  153. if (typeof window.navigator === 'object') {
  154. /* ! Spec Conformance
  155. * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)
  156. * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray
  157. * Test: `Object.prototype.toString.call(navigator.mimeTypes)``
  158. * - IE <=10 === "[object MSMimeTypesCollection]"
  159. */
  160. if (typeof window.navigator.mimeTypes === 'object' &&
  161. obj === window.navigator.mimeTypes) {
  162. return 'MimeTypeArray';
  163. }
  164. /* ! Spec Conformance
  165. * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
  166. * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray
  167. * Test: `Object.prototype.toString.call(navigator.plugins)``
  168. * - IE <=10 === "[object MSPluginsCollection]"
  169. */
  170. if (typeof window.navigator.plugins === 'object' &&
  171. obj === window.navigator.plugins) {
  172. return 'PluginArray';
  173. }
  174. }
  175. if ((typeof window.HTMLElement === 'function' ||
  176. typeof window.HTMLElement === 'object') &&
  177. obj instanceof window.HTMLElement) {
  178. /* ! Spec Conformance
  179. * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
  180. * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`
  181. * Test: `Object.prototype.toString.call(document.createElement('blockquote'))``
  182. * - IE <=10 === "[object HTMLBlockElement]"
  183. */
  184. if (obj.tagName === 'BLOCKQUOTE') {
  185. return 'HTMLQuoteElement';
  186. }
  187. /* ! Spec Conformance
  188. * (https://html.spec.whatwg.org/#htmltabledatacellelement)
  189. * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`
  190. * Note: Most browsers currently adher to the W3C DOM Level 2 spec
  191. * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
  192. * which suggests that browsers should use HTMLTableCellElement for
  193. * both TD and TH elements. WhatWG separates these.
  194. * Test: Object.prototype.toString.call(document.createElement('td'))
  195. * - Chrome === "[object HTMLTableCellElement]"
  196. * - Firefox === "[object HTMLTableCellElement]"
  197. * - Safari === "[object HTMLTableCellElement]"
  198. */
  199. if (obj.tagName === 'TD') {
  200. return 'HTMLTableDataCellElement';
  201. }
  202. /* ! Spec Conformance
  203. * (https://html.spec.whatwg.org/#htmltableheadercellelement)
  204. * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`
  205. * Note: Most browsers currently adher to the W3C DOM Level 2 spec
  206. * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
  207. * which suggests that browsers should use HTMLTableCellElement for
  208. * both TD and TH elements. WhatWG separates these.
  209. * Test: Object.prototype.toString.call(document.createElement('th'))
  210. * - Chrome === "[object HTMLTableCellElement]"
  211. * - Firefox === "[object HTMLTableCellElement]"
  212. * - Safari === "[object HTMLTableCellElement]"
  213. */
  214. if (obj.tagName === 'TH') {
  215. return 'HTMLTableHeaderCellElement';
  216. }
  217. }
  218. }
  219. /* ! Speed optimisation
  220. * Pre:
  221. * Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled)
  222. * Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled)
  223. * Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled)
  224. * Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled)
  225. * Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled)
  226. * Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled)
  227. * Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled)
  228. * Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled)
  229. * Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled)
  230. * Post:
  231. * Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled)
  232. * Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled)
  233. * Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled)
  234. * Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled)
  235. * Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled)
  236. * Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled)
  237. * Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled)
  238. * Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled)
  239. * Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled)
  240. */
  241. var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
  242. if (typeof stringTag === 'string') {
  243. return stringTag;
  244. }
  245. var objPrototype = Object.getPrototypeOf(obj);
  246. /* ! Speed optimisation
  247. * Pre:
  248. * regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled)
  249. * regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled)
  250. * Post:
  251. * regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled)
  252. * regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled)
  253. */
  254. if (objPrototype === RegExp.prototype) {
  255. return 'RegExp';
  256. }
  257. /* ! Speed optimisation
  258. * Pre:
  259. * date x 2,130,074 ops/sec ±4.42% (68 runs sampled)
  260. * Post:
  261. * date x 3,953,779 ops/sec ±1.35% (77 runs sampled)
  262. */
  263. if (objPrototype === Date.prototype) {
  264. return 'Date';
  265. }
  266. /* ! Spec Conformance
  267. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)
  268. * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise":
  269. * Test: `Object.prototype.toString.call(Promise.resolve())``
  270. * - Chrome <=47 === "[object Object]"
  271. * - Edge <=20 === "[object Object]"
  272. * - Firefox 29-Latest === "[object Promise]"
  273. * - Safari 7.1-Latest === "[object Promise]"
  274. */
  275. if (promiseExists && objPrototype === Promise.prototype) {
  276. return 'Promise';
  277. }
  278. /* ! Speed optimisation
  279. * Pre:
  280. * set x 2,222,186 ops/sec ±1.31% (82 runs sampled)
  281. * Post:
  282. * set x 4,545,879 ops/sec ±1.13% (83 runs sampled)
  283. */
  284. if (setExists && objPrototype === Set.prototype) {
  285. return 'Set';
  286. }
  287. /* ! Speed optimisation
  288. * Pre:
  289. * map x 2,396,842 ops/sec ±1.59% (81 runs sampled)
  290. * Post:
  291. * map x 4,183,945 ops/sec ±6.59% (82 runs sampled)
  292. */
  293. if (mapExists && objPrototype === Map.prototype) {
  294. return 'Map';
  295. }
  296. /* ! Speed optimisation
  297. * Pre:
  298. * weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled)
  299. * Post:
  300. * weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled)
  301. */
  302. if (weakSetExists && objPrototype === WeakSet.prototype) {
  303. return 'WeakSet';
  304. }
  305. /* ! Speed optimisation
  306. * Pre:
  307. * weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled)
  308. * Post:
  309. * weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled)
  310. */
  311. if (weakMapExists && objPrototype === WeakMap.prototype) {
  312. return 'WeakMap';
  313. }
  314. /* ! Spec Conformance
  315. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)
  316. * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView":
  317. * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``
  318. * - Edge <=13 === "[object Object]"
  319. */
  320. if (dataViewExists && objPrototype === DataView.prototype) {
  321. return 'DataView';
  322. }
  323. /* ! Spec Conformance
  324. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)
  325. * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator":
  326. * Test: `Object.prototype.toString.call(new Map().entries())``
  327. * - Edge <=13 === "[object Object]"
  328. */
  329. if (mapExists && objPrototype === mapIteratorPrototype) {
  330. return 'Map Iterator';
  331. }
  332. /* ! Spec Conformance
  333. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)
  334. * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator":
  335. * Test: `Object.prototype.toString.call(new Set().entries())``
  336. * - Edge <=13 === "[object Object]"
  337. */
  338. if (setExists && objPrototype === setIteratorPrototype) {
  339. return 'Set Iterator';
  340. }
  341. /* ! Spec Conformance
  342. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)
  343. * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator":
  344. * Test: `Object.prototype.toString.call([][Symbol.iterator]())``
  345. * - Edge <=13 === "[object Object]"
  346. */
  347. if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
  348. return 'Array Iterator';
  349. }
  350. /* ! Spec Conformance
  351. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)
  352. * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator":
  353. * Test: `Object.prototype.toString.call(''[Symbol.iterator]())``
  354. * - Edge <=13 === "[object Object]"
  355. */
  356. if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
  357. return 'String Iterator';
  358. }
  359. /* ! Speed optimisation
  360. * Pre:
  361. * object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled)
  362. * Post:
  363. * object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled)
  364. */
  365. if (objPrototype === null) {
  366. return 'Object';
  367. }
  368. return Object
  369. .prototype
  370. .toString
  371. .call(obj)
  372. .slice(toStringLeftSliceLength, toStringRightSliceLength);
  373. }
  374. return typeDetect;
  375. })));
  376. });
  377. const isBufferExists = typeof Buffer !== 'undefined';
  378. const isBufferFromExists = isBufferExists && typeof Buffer.from !== 'undefined';
  379. const isBuffer = isBufferExists
  380. ? /**
  381. * is value is Buffer?
  382. *
  383. * @param {*} value
  384. * @return {boolean}
  385. */
  386. function isBuffer(value) {
  387. return Buffer.isBuffer(value);
  388. }
  389. : /**
  390. * return false
  391. *
  392. * NOTE: for Buffer unsupported
  393. *
  394. * @return {boolean}
  395. */
  396. function isBuffer() {
  397. return false;
  398. };
  399. const copy = isBufferFromExists
  400. ? /**
  401. * copy Buffer
  402. *
  403. * @param {Buffer} value
  404. * @return {Buffer}
  405. */
  406. function copy(value) {
  407. return Buffer.from(value);
  408. }
  409. : isBufferExists
  410. ? /**
  411. * copy Buffer
  412. *
  413. * NOTE: for old node.js
  414. *
  415. * @param {Buffer} value
  416. * @return {Buffer}
  417. */
  418. function copy(value) {
  419. return new Buffer(value);
  420. }
  421. : /**
  422. * shallow copy
  423. *
  424. * NOTE: for Buffer unsupported
  425. *
  426. * @param {*}
  427. * @return {*}
  428. */
  429. function copy(value) {
  430. return value;
  431. };
  432. /**
  433. * detect type of value
  434. *
  435. * @param {*} value
  436. * @return {string}
  437. */
  438. function detectType(value) {
  439. // NOTE: isBuffer must execute before type-detect,
  440. // because type-detect returns 'Uint8Array'.
  441. if (isBuffer(value)) {
  442. return 'Buffer';
  443. }
  444. return typeDetect(value);
  445. }
  446. /**
  447. * collection types
  448. */
  449. const collectionTypeSet = new Set([
  450. 'Arguments',
  451. 'Array',
  452. 'Map',
  453. 'Object',
  454. 'Set'
  455. ]);
  456. /**
  457. * get value from collection
  458. *
  459. * @param {Array|Object|Map|Set} collection
  460. * @param {string|number|symbol} key
  461. * @param {string} [type=null]
  462. * @return {*}
  463. */
  464. function get(collection, key, type = null) {
  465. const valueType = type || detectType(collection);
  466. switch (valueType) {
  467. case 'Arguments':
  468. case 'Array':
  469. case 'Object':
  470. return collection[key];
  471. case 'Map':
  472. return collection.get(key);
  473. case 'Set':
  474. // NOTE: Set.prototype.keys is alias of Set.prototype.values
  475. // it means key is equals value
  476. return key;
  477. }
  478. }
  479. /**
  480. * check to type string is collection
  481. *
  482. * @param {string} type
  483. */
  484. function isCollection(type) {
  485. return collectionTypeSet.has(type);
  486. }
  487. /**
  488. * set value to collection
  489. *
  490. * @param {Array|Object|Map|Set} collection
  491. * @param {string|number|symbol} key
  492. * @param {*} value
  493. * @param {string} [type=null]
  494. * @return {Array|Object|Map|Set}
  495. */
  496. function set(collection, key, value, type = null) {
  497. const valueType = type || detectType(collection);
  498. switch (valueType) {
  499. case 'Arguments':
  500. case 'Array':
  501. case 'Object':
  502. collection[key] = value;
  503. break;
  504. case 'Map':
  505. collection.set(key, value);
  506. break;
  507. case 'Set':
  508. collection.add(value);
  509. break;
  510. }
  511. return collection;
  512. }
  513. const freeGlobalThis =
  514. typeof globalThis !== 'undefined' &&
  515. globalThis !== null &&
  516. globalThis.Object === Object &&
  517. globalThis;
  518. const freeGlobal =
  519. typeof global !== 'undefined' &&
  520. global !== null &&
  521. global.Object === Object &&
  522. global;
  523. const freeSelf =
  524. typeof self !== 'undefined' &&
  525. self !== null &&
  526. self.Object === Object &&
  527. self;
  528. const globalObject =
  529. freeGlobalThis || freeGlobal || freeSelf || Function('return this')();
  530. /**
  531. * copy ArrayBuffer
  532. *
  533. * @param {ArrayBuffer} value
  534. * @return {ArrayBuffer}
  535. */
  536. function copyArrayBuffer(value) {
  537. return value.slice(0);
  538. }
  539. /**
  540. * copy Boolean
  541. *
  542. * @param {Boolean} value
  543. * @return {Boolean}
  544. */
  545. function copyBoolean(value) {
  546. return new Boolean(value.valueOf());
  547. }
  548. /**
  549. * copy DataView
  550. *
  551. * @param {DataView} value
  552. * @return {DataView}
  553. */
  554. function copyDataView(value) {
  555. // TODO: copy ArrayBuffer?
  556. return new DataView(value.buffer);
  557. }
  558. /**
  559. * copy Buffer
  560. *
  561. * @param {Buffer} value
  562. * @return {Buffer}
  563. */
  564. function copyBuffer(value) {
  565. return copy(value);
  566. }
  567. /**
  568. * copy Date
  569. *
  570. * @param {Date} value
  571. * @return {Date}
  572. */
  573. function copyDate(value) {
  574. return new Date(value.getTime());
  575. }
  576. /**
  577. * copy Number
  578. *
  579. * @param {Number} value
  580. * @return {Number}
  581. */
  582. function copyNumber(value) {
  583. return new Number(value);
  584. }
  585. /**
  586. * copy RegExp
  587. *
  588. * @param {RegExp} value
  589. * @return {RegExp}
  590. */
  591. function copyRegExp(value) {
  592. return new RegExp(value.source, value.flags);
  593. }
  594. /**
  595. * copy String
  596. *
  597. * @param {String} value
  598. * @return {String}
  599. */
  600. function copyString(value) {
  601. return new String(value);
  602. }
  603. /**
  604. * copy TypedArray
  605. *
  606. * @param {*} value
  607. * @return {*}
  608. */
  609. function copyTypedArray(value, type) {
  610. const typedArray = globalObject[type];
  611. if (typedArray.from) {
  612. return globalObject[type].from(value);
  613. }
  614. return new globalObject[type](value);
  615. }
  616. /**
  617. * shallow copy
  618. *
  619. * @param {*} value
  620. * @return {*}
  621. */
  622. function shallowCopy(value) {
  623. return value;
  624. }
  625. /**
  626. * get empty Array
  627. *
  628. * @return {Array}
  629. */
  630. function getEmptyArray() {
  631. return [];
  632. }
  633. /**
  634. * get empty Map
  635. *
  636. * @return {Map}
  637. */
  638. function getEmptyMap() {
  639. return new Map();
  640. }
  641. /**
  642. * get empty Object
  643. *
  644. * @return {Object}
  645. */
  646. function getEmptyObject() {
  647. return {};
  648. }
  649. /**
  650. * get empty Set
  651. *
  652. * @return {Set}
  653. */
  654. function getEmptySet() {
  655. return new Set();
  656. }
  657. var copyMap = new Map([
  658. // deep copy
  659. ['ArrayBuffer', copyArrayBuffer],
  660. ['Boolean', copyBoolean],
  661. ['Buffer', copyBuffer],
  662. ['DataView', copyDataView],
  663. ['Date', copyDate],
  664. ['Number', copyNumber],
  665. ['RegExp', copyRegExp],
  666. ['String', copyString],
  667. // typed arrays
  668. // TODO: pass bound function
  669. ['Float32Array', copyTypedArray],
  670. ['Float64Array', copyTypedArray],
  671. ['Int16Array', copyTypedArray],
  672. ['Int32Array', copyTypedArray],
  673. ['Int8Array', copyTypedArray],
  674. ['Uint16Array', copyTypedArray],
  675. ['Uint32Array', copyTypedArray],
  676. ['Uint8Array', copyTypedArray],
  677. ['Uint8ClampedArray', copyTypedArray],
  678. // shallow copy
  679. ['Array Iterator', shallowCopy],
  680. ['Map Iterator', shallowCopy],
  681. ['Promise', shallowCopy],
  682. ['Set Iterator', shallowCopy],
  683. ['String Iterator', shallowCopy],
  684. ['function', shallowCopy],
  685. ['global', shallowCopy],
  686. // NOTE: WeakMap and WeakSet cannot get entries
  687. ['WeakMap', shallowCopy],
  688. ['WeakSet', shallowCopy],
  689. // primitives
  690. ['boolean', shallowCopy],
  691. ['null', shallowCopy],
  692. ['number', shallowCopy],
  693. ['string', shallowCopy],
  694. ['symbol', shallowCopy],
  695. ['undefined', shallowCopy],
  696. // collections
  697. // NOTE: return empty value, because recursively copy later.
  698. ['Arguments', getEmptyArray],
  699. ['Array', getEmptyArray],
  700. ['Map', getEmptyMap],
  701. ['Object', getEmptyObject],
  702. ['Set', getEmptySet]
  703. // NOTE: type-detect returns following types
  704. // 'Location'
  705. // 'Document'
  706. // 'MimeTypeArray'
  707. // 'PluginArray'
  708. // 'HTMLQuoteElement'
  709. // 'HTMLTableDataCellElement'
  710. // 'HTMLTableHeaderCellElement'
  711. // TODO: is type-detect never return 'object'?
  712. // 'object'
  713. ]);
  714. /**
  715. * no operation
  716. */
  717. function noop() {}
  718. /**
  719. * copy value
  720. *
  721. * @param {*} value
  722. * @param {string} [type=null]
  723. * @param {Function} [customizer=noop]
  724. * @return {*}
  725. */
  726. function copy$1(value, type = null, customizer = noop) {
  727. if (arguments.length === 2 && typeof type === 'function') {
  728. customizer = type;
  729. type = null;
  730. }
  731. const valueType = type || detectType(value);
  732. const copyFunction = copyMap.get(valueType);
  733. if (valueType === 'Object') {
  734. const result = customizer(value, valueType);
  735. if (result !== undefined) {
  736. return result;
  737. }
  738. }
  739. // NOTE: TypedArray needs pass type to argument
  740. return copyFunction ? copyFunction(value, valueType) : value;
  741. }
  742. /**
  743. * deepcopy function
  744. *
  745. * @param {*} value
  746. * @param {Object|Function} [options]
  747. * @return {*}
  748. */
  749. function deepcopy(value, options = {}) {
  750. if (typeof options === 'function') {
  751. options = {
  752. customizer: options
  753. };
  754. }
  755. const {
  756. // TODO: before/after customizer
  757. customizer
  758. // TODO: max depth
  759. // depth = Infinity,
  760. } = options;
  761. const valueType = detectType(value);
  762. if (!isCollection(valueType)) {
  763. return recursiveCopy(value, null, null, null);
  764. }
  765. const copiedValue = copy$1(value, valueType, customizer);
  766. const references = new WeakMap([[value, copiedValue]]);
  767. const visited = new WeakSet([value]);
  768. return recursiveCopy(value, copiedValue, references, visited);
  769. }
  770. /**
  771. * recursively copy
  772. *
  773. * @param {*} value target value
  774. * @param {*} clone clone of value
  775. * @param {WeakMap} references visited references of clone
  776. * @param {WeakSet} visited visited references of value
  777. * @param {Function} customizer user customize function
  778. * @return {*}
  779. */
  780. function recursiveCopy(value, clone, references, visited, customizer) {
  781. const type = detectType(value);
  782. const copiedValue = copy$1(value, type);
  783. // return if not a collection value
  784. if (!isCollection(type)) {
  785. return copiedValue;
  786. }
  787. let keys;
  788. switch (type) {
  789. case 'Arguments':
  790. case 'Array':
  791. keys = Object.keys(value);
  792. break;
  793. case 'Object':
  794. keys = Object.keys(value);
  795. keys.push(...Object.getOwnPropertySymbols(value));
  796. break;
  797. case 'Map':
  798. case 'Set':
  799. keys = value.keys();
  800. break;
  801. }
  802. // walk within collection with iterator
  803. for (let collectionKey of keys) {
  804. const collectionValue = get(value, collectionKey, type);
  805. if (visited.has(collectionValue)) {
  806. // for [Circular]
  807. set(clone, collectionKey, references.get(collectionValue), type);
  808. } else {
  809. const collectionValueType = detectType(collectionValue);
  810. const copiedCollectionValue = copy$1(collectionValue, collectionValueType);
  811. // save reference if value is collection
  812. if (isCollection(collectionValueType)) {
  813. references.set(collectionValue, copiedCollectionValue);
  814. visited.add(collectionValue);
  815. }
  816. set(
  817. clone,
  818. collectionKey,
  819. recursiveCopy(
  820. collectionValue,
  821. copiedCollectionValue,
  822. references,
  823. visited),
  824. type
  825. );
  826. }
  827. }
  828. // TODO: isSealed/isFrozen/isExtensible
  829. return clone;
  830. }
  831. return deepcopy;
  832. })));
  833. //# sourceMappingURL=deepcopy.js.map