summaryrefslogtreecommitdiff
path: root/cli/js/web/util.ts
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2020-04-23 00:06:51 +1000
committerGitHub <noreply@github.com>2020-04-22 10:06:51 -0400
commit8bcfc03d71cbd2cfd7ab68035ec0968d9f93b5b8 (patch)
treee1769ca51d2afde57ae18eb25b7a91388fcbf00a /cli/js/web/util.ts
parentb270d6c8d090669601465f8c9c94512d6c6a07d4 (diff)
Rewrite streams (#4842)
Diffstat (limited to 'cli/js/web/util.ts')
-rw-r--r--cli/js/web/util.ts113
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;