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