deepCyclicCopy.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = deepCyclicCopy;
  6. /**
  7. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  8. *
  9. * This source code is licensed under the MIT license found in the
  10. * LICENSE file in the root directory of this source tree.
  11. */
  12. const EMPTY = new Set();
  13. // Node 6 does not have gOPDs, so we define a simple polyfill for it.
  14. if (!Object.getOwnPropertyDescriptors) {
  15. // @ts-ignore: polyfill
  16. Object.getOwnPropertyDescriptors = obj => {
  17. const list = {};
  18. Object.getOwnPropertyNames(obj)
  19. .concat(Object.getOwnPropertySymbols(obj))
  20. .forEach(key => {
  21. // @ts-ignore: assignment with a Symbol is OK.
  22. list[key] = Object.getOwnPropertyDescriptor(obj, key);
  23. });
  24. return list;
  25. };
  26. }
  27. function deepCyclicCopy(
  28. value,
  29. options = {
  30. blacklist: EMPTY,
  31. keepPrototype: false
  32. },
  33. cycles = new WeakMap()
  34. ) {
  35. if (typeof value !== 'object' || value === null) {
  36. return value;
  37. } else if (cycles.has(value)) {
  38. return cycles.get(value);
  39. } else if (Array.isArray(value)) {
  40. return deepCyclicCopyArray(value, options, cycles);
  41. } else {
  42. return deepCyclicCopyObject(value, options, cycles);
  43. }
  44. }
  45. function deepCyclicCopyObject(object, options, cycles) {
  46. const newObject = options.keepPrototype
  47. ? Object.create(Object.getPrototypeOf(object))
  48. : {};
  49. const descriptors = Object.getOwnPropertyDescriptors(object);
  50. cycles.set(object, newObject);
  51. Object.keys(descriptors).forEach(key => {
  52. if (options.blacklist && options.blacklist.has(key)) {
  53. delete descriptors[key];
  54. return;
  55. }
  56. const descriptor = descriptors[key];
  57. if (typeof descriptor.value !== 'undefined') {
  58. descriptor.value = deepCyclicCopy(
  59. descriptor.value,
  60. {
  61. blacklist: EMPTY,
  62. keepPrototype: options.keepPrototype
  63. },
  64. cycles
  65. );
  66. }
  67. descriptor.configurable = true;
  68. });
  69. return Object.defineProperties(newObject, descriptors);
  70. }
  71. function deepCyclicCopyArray(array, options, cycles) {
  72. const newArray = options.keepPrototype
  73. ? new (Object.getPrototypeOf(array)).constructor(array.length)
  74. : [];
  75. const length = array.length;
  76. cycles.set(array, newArray);
  77. for (let i = 0; i < length; i++) {
  78. newArray[i] = deepCyclicCopy(
  79. array[i],
  80. {
  81. blacklist: EMPTY,
  82. keepPrototype: options.keepPrototype
  83. },
  84. cycles
  85. );
  86. }
  87. return newArray;
  88. }