clone.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* eslint-disable */
  2. var clone = (function () {
  3. 'use strict';
  4. function _instanceof(obj, type) {
  5. return type != null && obj instanceof type;
  6. }
  7. var nativeMap;
  8. try {
  9. nativeMap = Map;
  10. } catch (_) {
  11. // maybe a reference error because no `Map`. Give it a dummy value that no
  12. // value will ever be an instanceof.
  13. nativeMap = function () {};
  14. }
  15. var nativeSet;
  16. try {
  17. nativeSet = Set;
  18. } catch (_) {
  19. nativeSet = function () {};
  20. }
  21. var nativePromise;
  22. try {
  23. nativePromise = Promise;
  24. } catch (_) {
  25. nativePromise = function () {};
  26. }
  27. /**
  28. * Clones (copies) an Object using deep copying.
  29. *
  30. * This function supports circular references by default, but if you are certain
  31. * there are no circular references in your object, you can save some CPU time
  32. * by calling clone(obj, false).
  33. *
  34. * Caution: if `circular` is false and `parent` contains circular references,
  35. * your program may enter an infinite loop and crash.
  36. *
  37. * @param `parent` - the object to be cloned
  38. * @param `circular` - set to true if the object to be cloned may contain
  39. * circular references. (optional - true by default)
  40. * @param `depth` - set to a number if the object is only to be cloned to
  41. * a particular depth. (optional - defaults to Infinity)
  42. * @param `prototype` - sets the prototype to be used when cloning an object.
  43. * (optional - defaults to parent prototype).
  44. * @param `includeNonEnumerable` - set to true if the non-enumerable properties
  45. * should be cloned as well. Non-enumerable properties on the prototype
  46. * chain will be ignored. (optional - false by default)
  47. */
  48. function clone(parent, circular, depth, prototype, includeNonEnumerable) {
  49. if (typeof circular === 'object') {
  50. depth = circular.depth;
  51. prototype = circular.prototype;
  52. includeNonEnumerable = circular.includeNonEnumerable;
  53. circular = circular.circular;
  54. }
  55. // maintain two arrays for circular references, where corresponding parents
  56. // and children have the same index
  57. var allParents = [];
  58. var allChildren = [];
  59. var useBuffer = typeof Buffer != 'undefined';
  60. if (typeof circular == 'undefined') circular = true;
  61. if (typeof depth == 'undefined') depth = Infinity;
  62. // recurse this function so we don't reset allParents and allChildren
  63. function _clone(parent, depth) {
  64. // cloning null always returns null
  65. if (parent === null) return null;
  66. if (depth === 0) return parent;
  67. var child;
  68. var proto;
  69. if (typeof parent != 'object') {
  70. return parent;
  71. }
  72. if (_instanceof(parent, nativeMap)) {
  73. child = new nativeMap();
  74. } else if (_instanceof(parent, nativeSet)) {
  75. child = new nativeSet();
  76. } else if (_instanceof(parent, nativePromise)) {
  77. child = new nativePromise(function (resolve, reject) {
  78. parent.then(
  79. function (value) {
  80. resolve(_clone(value, depth - 1));
  81. },
  82. function (err) {
  83. reject(_clone(err, depth - 1));
  84. },
  85. );
  86. });
  87. } else if (clone.__isArray(parent)) {
  88. child = [];
  89. } else if (clone.__isRegExp(parent)) {
  90. child = new RegExp(parent.source, __getRegExpFlags(parent));
  91. if (parent.lastIndex) child.lastIndex = parent.lastIndex;
  92. } else if (clone.__isDate(parent)) {
  93. child = new Date(parent.getTime());
  94. } else if (useBuffer && Buffer.isBuffer(parent)) {
  95. if (Buffer.from) {
  96. // Node.js >= 5.10.0
  97. child = Buffer.from(parent);
  98. } else {
  99. // Older Node.js versions
  100. child = new Buffer(parent.length);
  101. parent.copy(child);
  102. }
  103. return child;
  104. } else if (_instanceof(parent, Error)) {
  105. child = Object.create(parent);
  106. } else {
  107. if (typeof prototype == 'undefined') {
  108. proto = Object.getPrototypeOf(parent);
  109. child = Object.create(proto);
  110. } else {
  111. child = Object.create(prototype);
  112. proto = prototype;
  113. }
  114. }
  115. if (circular) {
  116. var index = allParents.indexOf(parent);
  117. if (index != -1) {
  118. return allChildren[index];
  119. }
  120. allParents.push(parent);
  121. allChildren.push(child);
  122. }
  123. if (_instanceof(parent, nativeMap)) {
  124. parent.forEach(function (value, key) {
  125. var keyChild = _clone(key, depth - 1);
  126. var valueChild = _clone(value, depth - 1);
  127. child.set(keyChild, valueChild);
  128. });
  129. }
  130. if (_instanceof(parent, nativeSet)) {
  131. parent.forEach(function (value) {
  132. var entryChild = _clone(value, depth - 1);
  133. child.add(entryChild);
  134. });
  135. }
  136. for (var i in parent) {
  137. var attrs = Object.getOwnPropertyDescriptor(parent, i);
  138. if (attrs) {
  139. child[i] = _clone(parent[i], depth - 1);
  140. }
  141. try {
  142. var objProperty = Object.getOwnPropertyDescriptor(parent, i);
  143. if (objProperty.set === 'undefined') {
  144. // no setter defined. Skip cloning this property
  145. continue;
  146. }
  147. child[i] = _clone(parent[i], depth - 1);
  148. } catch (e) {
  149. if (e instanceof TypeError) {
  150. // when in strict mode, TypeError will be thrown if child[i] property only has a getter
  151. // we can't do anything about this, other than inform the user that this property cannot be set.
  152. continue;
  153. } else if (e instanceof ReferenceError) {
  154. //this may happen in non strict mode
  155. continue;
  156. }
  157. }
  158. }
  159. if (Object.getOwnPropertySymbols) {
  160. var symbols = Object.getOwnPropertySymbols(parent);
  161. for (var i = 0; i < symbols.length; i++) {
  162. // Don't need to worry about cloning a symbol because it is a primitive,
  163. // like a number or string.
  164. var symbol = symbols[i];
  165. var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
  166. if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
  167. continue;
  168. }
  169. child[symbol] = _clone(parent[symbol], depth - 1);
  170. Object.defineProperty(child, symbol, descriptor);
  171. }
  172. }
  173. if (includeNonEnumerable) {
  174. var allPropertyNames = Object.getOwnPropertyNames(parent);
  175. for (var i = 0; i < allPropertyNames.length; i++) {
  176. var propertyName = allPropertyNames[i];
  177. var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
  178. if (descriptor && descriptor.enumerable) {
  179. continue;
  180. }
  181. child[propertyName] = _clone(parent[propertyName], depth - 1);
  182. Object.defineProperty(child, propertyName, descriptor);
  183. }
  184. }
  185. return child;
  186. }
  187. return _clone(parent, depth);
  188. }
  189. /**
  190. * Simple flat clone using prototype, accepts only objects, usefull for property
  191. * override on FLAT configuration object (no nested props).
  192. *
  193. * USE WITH CAUTION! This may not behave as you wish if you do not know how this
  194. * works.
  195. */
  196. clone.clonePrototype = function clonePrototype(parent) {
  197. if (parent === null) return null;
  198. var c = function () {};
  199. c.prototype = parent;
  200. return new c();
  201. };
  202. // private utility functions
  203. function __objToStr(o) {
  204. return Object.prototype.toString.call(o);
  205. }
  206. clone.__objToStr = __objToStr;
  207. function __isDate(o) {
  208. return typeof o === 'object' && __objToStr(o) === '[object Date]';
  209. }
  210. clone.__isDate = __isDate;
  211. function __isArray(o) {
  212. return typeof o === 'object' && __objToStr(o) === '[object Array]';
  213. }
  214. clone.__isArray = __isArray;
  215. function __isRegExp(o) {
  216. return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
  217. }
  218. clone.__isRegExp = __isRegExp;
  219. function __getRegExpFlags(re) {
  220. var flags = '';
  221. if (re.global) flags += 'g';
  222. if (re.ignoreCase) flags += 'i';
  223. if (re.multiline) flags += 'm';
  224. return flags;
  225. }
  226. clone.__getRegExpFlags = __getRegExpFlags;
  227. return clone;
  228. })();
  229. export default clone;