web.structured-clone.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. 'use strict';
  2. var IS_PURE = require('../internals/is-pure');
  3. var $ = require('../internals/export');
  4. var global = require('../internals/global');
  5. var getBuiltin = require('../internals/get-built-in');
  6. var uncurryThis = require('../internals/function-uncurry-this');
  7. var fails = require('../internals/fails');
  8. var uid = require('../internals/uid');
  9. var isCallable = require('../internals/is-callable');
  10. var isConstructor = require('../internals/is-constructor');
  11. var isNullOrUndefined = require('../internals/is-null-or-undefined');
  12. var isObject = require('../internals/is-object');
  13. var isSymbol = require('../internals/is-symbol');
  14. var iterate = require('../internals/iterate');
  15. var anObject = require('../internals/an-object');
  16. var classof = require('../internals/classof');
  17. var hasOwn = require('../internals/has-own-property');
  18. var createProperty = require('../internals/create-property');
  19. var createNonEnumerableProperty = require('../internals/create-non-enumerable-property');
  20. var lengthOfArrayLike = require('../internals/length-of-array-like');
  21. var validateArgumentsLength = require('../internals/validate-arguments-length');
  22. var getRegExpFlags = require('../internals/regexp-get-flags');
  23. var MapHelpers = require('../internals/map-helpers');
  24. var SetHelpers = require('../internals/set-helpers');
  25. var arrayBufferTransfer = require('../internals/array-buffer-transfer');
  26. var ERROR_STACK_INSTALLABLE = require('../internals/error-stack-installable');
  27. var PROPER_STRUCTURED_CLONE_TRANSFER = require('../internals/structured-clone-proper-transfer');
  28. var Object = global.Object;
  29. var Array = global.Array;
  30. var Date = global.Date;
  31. var Error = global.Error;
  32. var EvalError = global.EvalError;
  33. var RangeError = global.RangeError;
  34. var ReferenceError = global.ReferenceError;
  35. var SyntaxError = global.SyntaxError;
  36. var TypeError = global.TypeError;
  37. var URIError = global.URIError;
  38. var PerformanceMark = global.PerformanceMark;
  39. var WebAssembly = global.WebAssembly;
  40. var CompileError = WebAssembly && WebAssembly.CompileError || Error;
  41. var LinkError = WebAssembly && WebAssembly.LinkError || Error;
  42. var RuntimeError = WebAssembly && WebAssembly.RuntimeError || Error;
  43. var DOMException = getBuiltin('DOMException');
  44. var Map = MapHelpers.Map;
  45. var mapHas = MapHelpers.has;
  46. var mapGet = MapHelpers.get;
  47. var mapSet = MapHelpers.set;
  48. var Set = SetHelpers.Set;
  49. var setAdd = SetHelpers.add;
  50. var objectKeys = getBuiltin('Object', 'keys');
  51. var push = uncurryThis([].push);
  52. var thisBooleanValue = uncurryThis(true.valueOf);
  53. var thisNumberValue = uncurryThis(1.0.valueOf);
  54. var thisStringValue = uncurryThis(''.valueOf);
  55. var thisTimeValue = uncurryThis(Date.prototype.getTime);
  56. var PERFORMANCE_MARK = uid('structuredClone');
  57. var DATA_CLONE_ERROR = 'DataCloneError';
  58. var TRANSFERRING = 'Transferring';
  59. var checkBasicSemantic = function (structuredCloneImplementation) {
  60. return !fails(function () {
  61. var set1 = new global.Set([7]);
  62. var set2 = structuredCloneImplementation(set1);
  63. var number = structuredCloneImplementation(Object(7));
  64. return set2 === set1 || !set2.has(7) || typeof number != 'object' || +number !== 7;
  65. }) && structuredCloneImplementation;
  66. };
  67. var checkErrorsCloning = function (structuredCloneImplementation, $Error) {
  68. return !fails(function () {
  69. var error = new $Error();
  70. var test = structuredCloneImplementation({ a: error, b: error });
  71. return !(test && test.a === test.b && test.a instanceof $Error && test.a.stack === error.stack);
  72. });
  73. };
  74. // https://github.com/whatwg/html/pull/5749
  75. var checkNewErrorsCloningSemantic = function (structuredCloneImplementation) {
  76. return !fails(function () {
  77. var test = structuredCloneImplementation(new global.AggregateError([1], PERFORMANCE_MARK, { cause: 3 }));
  78. return test.name !== 'AggregateError' || test.errors[0] !== 1 || test.message !== PERFORMANCE_MARK || test.cause !== 3;
  79. });
  80. };
  81. // FF94+, Safari 15.4+, Chrome 98+, NodeJS 17.0+, Deno 1.13+
  82. // FF<103 and Safari implementations can't clone errors
  83. // https://bugzilla.mozilla.org/show_bug.cgi?id=1556604
  84. // FF103 can clone errors, but `.stack` of clone is an empty string
  85. // https://bugzilla.mozilla.org/show_bug.cgi?id=1778762
  86. // FF104+ fixed it on usual errors, but not on DOMExceptions
  87. // https://bugzilla.mozilla.org/show_bug.cgi?id=1777321
  88. // Chrome <102 returns `null` if cloned object contains multiple references to one error
  89. // https://bugs.chromium.org/p/v8/issues/detail?id=12542
  90. // NodeJS implementation can't clone DOMExceptions
  91. // https://github.com/nodejs/node/issues/41038
  92. // only FF103+ supports new (html/5749) error cloning semantic
  93. var nativeStructuredClone = global.structuredClone;
  94. var FORCED_REPLACEMENT = IS_PURE
  95. || !checkErrorsCloning(nativeStructuredClone, Error)
  96. || !checkErrorsCloning(nativeStructuredClone, DOMException)
  97. || !checkNewErrorsCloningSemantic(nativeStructuredClone);
  98. // Chrome 82+, Safari 14.1+, Deno 1.11+
  99. // Chrome 78-81 implementation swaps `.name` and `.message` of cloned `DOMException`
  100. // Chrome returns `null` if cloned object contains multiple references to one error
  101. // Safari 14.1 implementation doesn't clone some `RegExp` flags, so requires a workaround
  102. // Safari implementation can't clone errors
  103. // Deno 1.2-1.10 implementations too naive
  104. // NodeJS 16.0+ does not have `PerformanceMark` constructor
  105. // NodeJS <17.2 structured cloning implementation from `performance.mark` is too naive
  106. // and can't clone, for example, `RegExp` or some boxed primitives
  107. // https://github.com/nodejs/node/issues/40840
  108. // no one of those implementations supports new (html/5749) error cloning semantic
  109. var structuredCloneFromMark = !nativeStructuredClone && checkBasicSemantic(function (value) {
  110. return new PerformanceMark(PERFORMANCE_MARK, { detail: value }).detail;
  111. });
  112. var nativeRestrictedStructuredClone = checkBasicSemantic(nativeStructuredClone) || structuredCloneFromMark;
  113. var throwUncloneable = function (type) {
  114. throw new DOMException('Uncloneable type: ' + type, DATA_CLONE_ERROR);
  115. };
  116. var throwUnpolyfillable = function (type, action) {
  117. throw new DOMException((action || 'Cloning') + ' of ' + type + ' cannot be properly polyfilled in this engine', DATA_CLONE_ERROR);
  118. };
  119. var tryNativeRestrictedStructuredClone = function (value, type) {
  120. if (!nativeRestrictedStructuredClone) throwUnpolyfillable(type);
  121. return nativeRestrictedStructuredClone(value);
  122. };
  123. var createDataTransfer = function () {
  124. var dataTransfer;
  125. try {
  126. dataTransfer = new global.DataTransfer();
  127. } catch (error) {
  128. try {
  129. dataTransfer = new global.ClipboardEvent('').clipboardData;
  130. } catch (error2) { /* empty */ }
  131. }
  132. return dataTransfer && dataTransfer.items && dataTransfer.files ? dataTransfer : null;
  133. };
  134. var cloneBuffer = function (value, map, $type) {
  135. if (mapHas(map, value)) return mapGet(map, value);
  136. var type = $type || classof(value);
  137. var clone, length, options, source, target, i;
  138. if (type === 'SharedArrayBuffer') {
  139. if (nativeRestrictedStructuredClone) clone = nativeRestrictedStructuredClone(value);
  140. // SharedArrayBuffer should use shared memory, we can't polyfill it, so return the original
  141. else clone = value;
  142. } else {
  143. var DataView = global.DataView;
  144. // `ArrayBuffer#slice` is not available in IE10
  145. // `ArrayBuffer#slice` and `DataView` are not available in old FF
  146. if (!DataView && typeof value.slice != 'function') throwUnpolyfillable('ArrayBuffer');
  147. // detached buffers throws in `DataView` and `.slice`
  148. try {
  149. if (typeof value.slice == 'function' && !value.resizable) {
  150. clone = value.slice(0);
  151. } else {
  152. length = value.byteLength;
  153. options = 'maxByteLength' in value ? { maxByteLength: value.maxByteLength } : undefined;
  154. clone = new ArrayBuffer(length, options);
  155. source = new DataView(value);
  156. target = new DataView(clone);
  157. for (i = 0; i < length; i++) {
  158. target.setUint8(i, source.getUint8(i));
  159. }
  160. }
  161. } catch (error) {
  162. throw new DOMException('ArrayBuffer is detached', DATA_CLONE_ERROR);
  163. }
  164. }
  165. mapSet(map, value, clone);
  166. return clone;
  167. };
  168. var cloneView = function (value, type, offset, length, map) {
  169. var C = global[type];
  170. // in some old engines like Safari 9, typeof C is 'object'
  171. // on Uint8ClampedArray or some other constructors
  172. if (!isObject(C)) throwUnpolyfillable(type);
  173. return new C(cloneBuffer(value.buffer, map), offset, length);
  174. };
  175. var Placeholder = function (object, type, metadata) {
  176. this.object = object;
  177. this.type = type;
  178. this.metadata = metadata;
  179. };
  180. var structuredCloneInternal = function (value, map, transferredBuffers) {
  181. if (isSymbol(value)) throwUncloneable('Symbol');
  182. if (!isObject(value)) return value;
  183. // effectively preserves circular references
  184. if (map) {
  185. if (mapHas(map, value)) return mapGet(map, value);
  186. } else map = new Map();
  187. var type = classof(value);
  188. var C, name, cloned, dataTransfer, i, length, keys, key;
  189. switch (type) {
  190. case 'Array':
  191. cloned = Array(lengthOfArrayLike(value));
  192. break;
  193. case 'Object':
  194. cloned = {};
  195. break;
  196. case 'Map':
  197. cloned = new Map();
  198. break;
  199. case 'Set':
  200. cloned = new Set();
  201. break;
  202. case 'RegExp':
  203. // in this block because of a Safari 14.1 bug
  204. // old FF does not clone regexes passed to the constructor, so get the source and flags directly
  205. cloned = new RegExp(value.source, getRegExpFlags(value));
  206. break;
  207. case 'Error':
  208. name = value.name;
  209. switch (name) {
  210. case 'AggregateError':
  211. cloned = new (getBuiltin('AggregateError'))([]);
  212. break;
  213. case 'EvalError':
  214. cloned = new EvalError();
  215. break;
  216. case 'RangeError':
  217. cloned = new RangeError();
  218. break;
  219. case 'ReferenceError':
  220. cloned = new ReferenceError();
  221. break;
  222. case 'SyntaxError':
  223. cloned = new SyntaxError();
  224. break;
  225. case 'TypeError':
  226. cloned = new TypeError();
  227. break;
  228. case 'URIError':
  229. cloned = new URIError();
  230. break;
  231. case 'CompileError':
  232. cloned = new CompileError();
  233. break;
  234. case 'LinkError':
  235. cloned = new LinkError();
  236. break;
  237. case 'RuntimeError':
  238. cloned = new RuntimeError();
  239. break;
  240. default:
  241. cloned = new Error();
  242. }
  243. break;
  244. case 'DOMException':
  245. cloned = new DOMException(value.message, value.name);
  246. break;
  247. case 'ArrayBuffer':
  248. case 'SharedArrayBuffer':
  249. cloned = transferredBuffers
  250. ? new Placeholder(value, type)
  251. : cloneBuffer(value, map, type);
  252. break;
  253. case 'DataView':
  254. case 'Int8Array':
  255. case 'Uint8Array':
  256. case 'Uint8ClampedArray':
  257. case 'Int16Array':
  258. case 'Uint16Array':
  259. case 'Int32Array':
  260. case 'Uint32Array':
  261. case 'Float16Array':
  262. case 'Float32Array':
  263. case 'Float64Array':
  264. case 'BigInt64Array':
  265. case 'BigUint64Array':
  266. length = type === 'DataView' ? value.byteLength : value.length;
  267. cloned = transferredBuffers
  268. ? new Placeholder(value, type, { offset: value.byteOffset, length: length })
  269. : cloneView(value, type, value.byteOffset, length, map);
  270. break;
  271. case 'DOMQuad':
  272. try {
  273. cloned = new DOMQuad(
  274. structuredCloneInternal(value.p1, map, transferredBuffers),
  275. structuredCloneInternal(value.p2, map, transferredBuffers),
  276. structuredCloneInternal(value.p3, map, transferredBuffers),
  277. structuredCloneInternal(value.p4, map, transferredBuffers)
  278. );
  279. } catch (error) {
  280. cloned = tryNativeRestrictedStructuredClone(value, type);
  281. }
  282. break;
  283. case 'File':
  284. if (nativeRestrictedStructuredClone) try {
  285. cloned = nativeRestrictedStructuredClone(value);
  286. // NodeJS 20.0.0 bug, https://github.com/nodejs/node/issues/47612
  287. if (classof(cloned) !== type) cloned = undefined;
  288. } catch (error) { /* empty */ }
  289. if (!cloned) try {
  290. cloned = new File([value], value.name, value);
  291. } catch (error) { /* empty */ }
  292. if (!cloned) throwUnpolyfillable(type);
  293. break;
  294. case 'FileList':
  295. dataTransfer = createDataTransfer();
  296. if (dataTransfer) {
  297. for (i = 0, length = lengthOfArrayLike(value); i < length; i++) {
  298. dataTransfer.items.add(structuredCloneInternal(value[i], map, transferredBuffers));
  299. }
  300. cloned = dataTransfer.files;
  301. } else cloned = tryNativeRestrictedStructuredClone(value, type);
  302. break;
  303. case 'ImageData':
  304. // Safari 9 ImageData is a constructor, but typeof ImageData is 'object'
  305. try {
  306. cloned = new ImageData(
  307. structuredCloneInternal(value.data, map, transferredBuffers),
  308. value.width,
  309. value.height,
  310. { colorSpace: value.colorSpace }
  311. );
  312. } catch (error) {
  313. cloned = tryNativeRestrictedStructuredClone(value, type);
  314. } break;
  315. default:
  316. if (nativeRestrictedStructuredClone) {
  317. cloned = nativeRestrictedStructuredClone(value);
  318. } else switch (type) {
  319. case 'BigInt':
  320. // can be a 3rd party polyfill
  321. cloned = Object(value.valueOf());
  322. break;
  323. case 'Boolean':
  324. cloned = Object(thisBooleanValue(value));
  325. break;
  326. case 'Number':
  327. cloned = Object(thisNumberValue(value));
  328. break;
  329. case 'String':
  330. cloned = Object(thisStringValue(value));
  331. break;
  332. case 'Date':
  333. cloned = new Date(thisTimeValue(value));
  334. break;
  335. case 'Blob':
  336. try {
  337. cloned = value.slice(0, value.size, value.type);
  338. } catch (error) {
  339. throwUnpolyfillable(type);
  340. } break;
  341. case 'DOMPoint':
  342. case 'DOMPointReadOnly':
  343. C = global[type];
  344. try {
  345. cloned = C.fromPoint
  346. ? C.fromPoint(value)
  347. : new C(value.x, value.y, value.z, value.w);
  348. } catch (error) {
  349. throwUnpolyfillable(type);
  350. } break;
  351. case 'DOMRect':
  352. case 'DOMRectReadOnly':
  353. C = global[type];
  354. try {
  355. cloned = C.fromRect
  356. ? C.fromRect(value)
  357. : new C(value.x, value.y, value.width, value.height);
  358. } catch (error) {
  359. throwUnpolyfillable(type);
  360. } break;
  361. case 'DOMMatrix':
  362. case 'DOMMatrixReadOnly':
  363. C = global[type];
  364. try {
  365. cloned = C.fromMatrix
  366. ? C.fromMatrix(value)
  367. : new C(value);
  368. } catch (error) {
  369. throwUnpolyfillable(type);
  370. } break;
  371. case 'AudioData':
  372. case 'VideoFrame':
  373. if (!isCallable(value.clone)) throwUnpolyfillable(type);
  374. try {
  375. cloned = value.clone();
  376. } catch (error) {
  377. throwUncloneable(type);
  378. } break;
  379. case 'CropTarget':
  380. case 'CryptoKey':
  381. case 'FileSystemDirectoryHandle':
  382. case 'FileSystemFileHandle':
  383. case 'FileSystemHandle':
  384. case 'GPUCompilationInfo':
  385. case 'GPUCompilationMessage':
  386. case 'ImageBitmap':
  387. case 'RTCCertificate':
  388. case 'WebAssembly.Module':
  389. throwUnpolyfillable(type);
  390. // break omitted
  391. default:
  392. throwUncloneable(type);
  393. }
  394. }
  395. mapSet(map, value, cloned);
  396. switch (type) {
  397. case 'Array':
  398. case 'Object':
  399. keys = objectKeys(value);
  400. for (i = 0, length = lengthOfArrayLike(keys); i < length; i++) {
  401. key = keys[i];
  402. createProperty(cloned, key, structuredCloneInternal(value[key], map, transferredBuffers));
  403. } break;
  404. case 'Map':
  405. value.forEach(function (v, k) {
  406. mapSet(cloned, structuredCloneInternal(k, map, transferredBuffers), structuredCloneInternal(v, map, transferredBuffers));
  407. });
  408. break;
  409. case 'Set':
  410. value.forEach(function (v) {
  411. setAdd(cloned, structuredCloneInternal(v, map, transferredBuffers));
  412. });
  413. break;
  414. case 'Error':
  415. createNonEnumerableProperty(cloned, 'message', structuredCloneInternal(value.message, map, transferredBuffers));
  416. if (hasOwn(value, 'cause')) {
  417. createNonEnumerableProperty(cloned, 'cause', structuredCloneInternal(value.cause, map, transferredBuffers));
  418. }
  419. if (name === 'AggregateError') {
  420. cloned.errors = structuredCloneInternal(value.errors, map, transferredBuffers);
  421. } // break omitted
  422. case 'DOMException':
  423. if (ERROR_STACK_INSTALLABLE) {
  424. createNonEnumerableProperty(cloned, 'stack', structuredCloneInternal(value.stack, map, transferredBuffers));
  425. }
  426. }
  427. return cloned;
  428. };
  429. var replacePlaceholders = function (value, map) {
  430. if (!isObject(value)) return value;
  431. if (mapHas(map, value)) return mapGet(map, value);
  432. var type, object, metadata, i, length, keys, key, replacement;
  433. if (value instanceof Placeholder) {
  434. type = value.type;
  435. object = value.object;
  436. switch (type) {
  437. case 'ArrayBuffer':
  438. case 'SharedArrayBuffer':
  439. replacement = cloneBuffer(object, map, type);
  440. break;
  441. case 'DataView':
  442. case 'Int8Array':
  443. case 'Uint8Array':
  444. case 'Uint8ClampedArray':
  445. case 'Int16Array':
  446. case 'Uint16Array':
  447. case 'Int32Array':
  448. case 'Uint32Array':
  449. case 'Float16Array':
  450. case 'Float32Array':
  451. case 'Float64Array':
  452. case 'BigInt64Array':
  453. case 'BigUint64Array':
  454. metadata = value.metadata;
  455. replacement = cloneView(object, type, metadata.offset, metadata.length, map);
  456. }
  457. } else switch (classof(value)) {
  458. case 'Array':
  459. case 'Object':
  460. keys = objectKeys(value);
  461. for (i = 0, length = lengthOfArrayLike(keys); i < length; i++) {
  462. key = keys[i];
  463. value[key] = replacePlaceholders(value[key], map);
  464. } break;
  465. case 'Map':
  466. replacement = new Map();
  467. value.forEach(function (v, k) {
  468. mapSet(replacement, replacePlaceholders(k, map), replacePlaceholders(v, map));
  469. });
  470. break;
  471. case 'Set':
  472. replacement = new Set();
  473. value.forEach(function (v) {
  474. setAdd(replacement, replacePlaceholders(v, map));
  475. });
  476. break;
  477. case 'Error':
  478. value.message = replacePlaceholders(value.message, map);
  479. if (hasOwn(value, 'cause')) {
  480. value.cause = replacePlaceholders(value.cause, map);
  481. }
  482. if (value.name === 'AggregateError') {
  483. value.errors = replacePlaceholders(value.errors, map);
  484. } // break omitted
  485. case 'DOMException':
  486. if (ERROR_STACK_INSTALLABLE) {
  487. value.stack = replacePlaceholders(value.stack, map);
  488. }
  489. }
  490. mapSet(map, value, replacement || value);
  491. return replacement || value;
  492. };
  493. var tryToTransfer = function (rawTransfer, map) {
  494. if (!isObject(rawTransfer)) throw new TypeError('Transfer option cannot be converted to a sequence');
  495. var transfer = [];
  496. iterate(rawTransfer, function (value) {
  497. push(transfer, anObject(value));
  498. });
  499. var i = 0;
  500. var length = lengthOfArrayLike(transfer);
  501. var buffers = [];
  502. var value, type, C, transferred, canvas, context;
  503. while (i < length) {
  504. value = transfer[i++];
  505. type = classof(value);
  506. if (type === 'ArrayBuffer') {
  507. push(buffers, value);
  508. continue;
  509. }
  510. if (mapHas(map, value)) throw new DOMException('Duplicate transferable', DATA_CLONE_ERROR);
  511. if (PROPER_STRUCTURED_CLONE_TRANSFER) {
  512. transferred = nativeStructuredClone(value, { transfer: [value] });
  513. } else switch (type) {
  514. case 'ImageBitmap':
  515. C = global.OffscreenCanvas;
  516. if (!isConstructor(C)) throwUnpolyfillable(type, TRANSFERRING);
  517. try {
  518. canvas = new C(value.width, value.height);
  519. context = canvas.getContext('bitmaprenderer');
  520. context.transferFromImageBitmap(value);
  521. transferred = canvas.transferToImageBitmap();
  522. } catch (error) { /* empty */ }
  523. break;
  524. case 'AudioData':
  525. case 'VideoFrame':
  526. if (!isCallable(value.clone) || !isCallable(value.close)) throwUnpolyfillable(type, TRANSFERRING);
  527. try {
  528. transferred = value.clone();
  529. value.close();
  530. } catch (error) { /* empty */ }
  531. break;
  532. case 'MediaSourceHandle':
  533. case 'MessagePort':
  534. case 'OffscreenCanvas':
  535. case 'ReadableStream':
  536. case 'TransformStream':
  537. case 'WritableStream':
  538. throwUnpolyfillable(type, TRANSFERRING);
  539. }
  540. if (transferred === undefined) throw new DOMException('This object cannot be transferred: ' + type, DATA_CLONE_ERROR);
  541. mapSet(map, value, transferred);
  542. }
  543. return buffers;
  544. };
  545. var tryToTransferBuffers = function (transfer, map) {
  546. var i = 0;
  547. var length = lengthOfArrayLike(transfer);
  548. var value, transferred;
  549. while (i < length) {
  550. value = transfer[i++];
  551. if (mapHas(map, value)) throw new DOMException('Duplicate transferable', DATA_CLONE_ERROR);
  552. if (arrayBufferTransfer) {
  553. transferred = arrayBufferTransfer(value, undefined, true);
  554. } else {
  555. if (!isCallable(value.transfer)) throwUnpolyfillable('ArrayBuffer', TRANSFERRING);
  556. transferred = value.transfer();
  557. }
  558. mapSet(map, value, transferred);
  559. }
  560. };
  561. // `structuredClone` method
  562. // https://html.spec.whatwg.org/multipage/structured-data.html#dom-structuredclone
  563. $({ global: true, enumerable: true, sham: !PROPER_STRUCTURED_CLONE_TRANSFER, forced: FORCED_REPLACEMENT }, {
  564. structuredClone: function structuredClone(value /* , { transfer } */) {
  565. var options = validateArgumentsLength(arguments.length, 1) > 1 && !isNullOrUndefined(arguments[1]) ? anObject(arguments[1]) : undefined;
  566. var transfer = options ? options.transfer : undefined;
  567. var transferredBuffers = false;
  568. var map, buffers;
  569. if (transfer !== undefined) {
  570. map = new Map();
  571. buffers = tryToTransfer(transfer, map);
  572. transferredBuffers = !!lengthOfArrayLike(buffers);
  573. }
  574. var clone = structuredCloneInternal(value, map, transferredBuffers);
  575. // since of an issue with cloning views of transferred buffers, we a forced to transfer / clone them in 2 steps
  576. // https://github.com/zloirock/core-js/issues/1265
  577. if (transferredBuffers) {
  578. map = new Map();
  579. tryToTransferBuffers(transfer, map);
  580. clone = replacePlaceholders(clone, map);
  581. }
  582. return clone;
  583. }
  584. });