diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2020-04-23 00:06:51 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-22 10:06:51 -0400 |
commit | 8bcfc03d71cbd2cfd7ab68035ec0968d9f93b5b8 (patch) | |
tree | e1769ca51d2afde57ae18eb25b7a91388fcbf00a /cli/js/web/util.ts | |
parent | b270d6c8d090669601465f8c9c94512d6c6a07d4 (diff) |
Rewrite streams (#4842)
Diffstat (limited to 'cli/js/web/util.ts')
-rw-r--r-- | cli/js/web/util.ts | 113 |
1 files changed, 102 insertions, 11 deletions
diff --git a/cli/js/web/util.ts b/cli/js/web/util.ts index 32e73c443..824d00d4b 100644 --- a/cli/js/web/util.ts +++ b/cli/js/web/util.ts @@ -1,5 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { DOMExceptionImpl as DOMException } from "./dom_exception.ts"; + export type TypedArray = | Int8Array | Uint8Array @@ -13,17 +15,7 @@ export type TypedArray = // @internal export function isTypedArray(x: unknown): x is TypedArray { - return ( - x instanceof Int8Array || - x instanceof Uint8Array || - x instanceof Uint8ClampedArray || - x instanceof Int16Array || - x instanceof Uint16Array || - x instanceof Int32Array || - x instanceof Uint32Array || - x instanceof Float32Array || - x instanceof Float64Array - ); + return ArrayBuffer.isView(x) && !(x instanceof DataView); } // @internal @@ -78,6 +70,105 @@ export function isIterable<T, P extends keyof T, K extends T[P]>( ); } +const objectCloneMemo = new WeakMap(); + +function cloneArrayBuffer( + srcBuffer: ArrayBufferLike, + srcByteOffset: number, + srcLength: number, + cloneConstructor: ArrayBufferConstructor | SharedArrayBufferConstructor +): InstanceType<typeof cloneConstructor> { + // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway + return srcBuffer.slice( + srcByteOffset, + srcByteOffset + srcLength + ) as InstanceType<typeof cloneConstructor>; +} + +/** Clone a value in a similar way to structured cloning. It is similar to a + * StructureDeserialize(StructuredSerialize(...)). */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function cloneValue(value: any): any { + switch (typeof value) { + case "number": + case "string": + case "boolean": + case "undefined": + case "bigint": + return value; + case "object": { + if (objectCloneMemo.has(value)) { + return objectCloneMemo.get(value); + } + if (value === null) { + return value; + } + if (value instanceof Date) { + return new Date(value.valueOf()); + } + if (value instanceof RegExp) { + return new RegExp(value); + } + if (value instanceof SharedArrayBuffer) { + return value; + } + if (value instanceof ArrayBuffer) { + const cloned = cloneArrayBuffer( + value, + 0, + value.byteLength, + ArrayBuffer + ); + objectCloneMemo.set(value, cloned); + return cloned; + } + if (ArrayBuffer.isView(value)) { + const clonedBuffer = cloneValue(value.buffer) as ArrayBufferLike; + // Use DataViewConstructor type purely for type-checking, can be a + // DataView or TypedArray. They use the same constructor signature, + // only DataView has a length in bytes and TypedArrays use a length in + // terms of elements, so we adjust for that. + let length: number; + if (value instanceof DataView) { + length = value.byteLength; + } else { + length = (value as Uint8Array).length; + } + return new (value.constructor as DataViewConstructor)( + clonedBuffer, + value.byteOffset, + length + ); + } + if (value instanceof Map) { + const clonedMap = new Map(); + objectCloneMemo.set(value, clonedMap); + value.forEach((v, k) => clonedMap.set(k, cloneValue(v))); + return clonedMap; + } + if (value instanceof Set) { + const clonedSet = new Map(); + objectCloneMemo.set(value, clonedSet); + value.forEach((v, k) => clonedSet.set(k, cloneValue(v))); + return clonedSet; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const clonedObj = {} as Record<string, any>; + objectCloneMemo.set(value, clonedObj); + const sourceKeys = Object.getOwnPropertyNames(value); + for (const key of sourceKeys) { + clonedObj[key] = cloneValue(value[key]); + } + return clonedObj; + } + case "symbol": + case "function": + default: + throw new DOMException("Uncloneable value in stream", "DataCloneError"); + } +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any interface GenericConstructor<T = any> { prototype: T; |