UNPKG

typia

Version:

Superfast runtime validators with only one line

139 lines (138 loc) • 6.32 kB
//#region src/internal/_plainCloneAny.ts const _plainCloneAny = (value) => cloneMain(value); const NOT_NATIVE = Symbol("not-native"); const objectToString = Object.prototype.toString; const getter = (prototype, key) => Object.getOwnPropertyDescriptor(prototype, key).get; const read = (accessor, value) => Reflect.apply(accessor, value, []); const tryRead = (accessor, value) => { if (accessor === void 0) return { success: false }; try { return { success: true, value: read(accessor, value) }; } catch { return { success: false }; } }; const arrayBufferByteLength = getter(ArrayBuffer.prototype, "byteLength"); const sharedArrayBufferByteLength = typeof SharedArrayBuffer === "undefined" ? void 0 : getter(SharedArrayBuffer.prototype, "byteLength"); const dataViewBuffer = getter(DataView.prototype, "buffer"); const dataViewByteLength = getter(DataView.prototype, "byteLength"); const dataViewByteOffset = getter(DataView.prototype, "byteOffset"); const typedArrayName = getter(Object.getPrototypeOf(Uint8Array.prototype), Symbol.toStringTag); const blobSize = typeof Blob === "undefined" ? void 0 : getter(Blob.prototype, "size"); const blobType = typeof Blob === "undefined" ? void 0 : getter(Blob.prototype, "type"); const fileName = typeof File === "undefined" ? void 0 : getter(File.prototype, "name"); const fileLastModified = typeof File === "undefined" ? void 0 : getter(File.prototype, "lastModified"); const regexpSource = getter(RegExp.prototype, "source"); const regexpFlags = getter(RegExp.prototype, "flags"); const nativeTag = (value) => { let tagged; try { tagged = Symbol.toStringTag in value; } catch { return; } if (!tagged) try { return objectToString.call(value); } catch { return; } if (tryRead(Date.prototype.getTime, value).success) return "[object Date]"; const typed = tryRead(typedArrayName, value); if (typed.success && typed.value !== void 0) return `[object ${typed.value}]`; if (tryRead(arrayBufferByteLength, value).success) return "[object ArrayBuffer]"; if (tryRead(sharedArrayBufferByteLength, value).success) return "[object SharedArrayBuffer]"; if (tryRead(dataViewBuffer, value).success) return "[object DataView]"; if (tryRead(fileName, value).success) return "[object File]"; if (tryRead(blobSize, value).success) return "[object Blob]"; if (tryRead(regexpSource, value).success) return "[object RegExp]"; }; const cloneMain = (value) => { if (value === void 0) return void 0; else if (typeof value === "object") if (value === null) return null; else if (Array.isArray(value)) return value.map(cloneMain); else { const native = cloneNative(value); if (native !== NOT_NATIVE) return native; else if (value instanceof Set) return new Set([...value].map(cloneMain)); else if (value instanceof Map) return new Map([...value].map(([k, v]) => [cloneMain(k), cloneMain(v)])); else if (value instanceof WeakSet || value instanceof WeakMap) throw new Error("WeakSet and WeakMap are not supported"); else { const primitive = value.valueOf(); if (primitive !== value) return cloneMain(primitive); return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, cloneMain(v)]).filter(([, v]) => v !== void 0)); } } else if (typeof value === "function") return void 0; return value; }; const cloneNative = (value) => { switch (nativeTag(value)) { case "[object Date]": { const time = tryRead(Date.prototype.getTime, value); return time.success ? new Date(time.value) : NOT_NATIVE; } case "[object Uint8Array]": return new Uint8Array(value); case "[object Uint8ClampedArray]": return new Uint8ClampedArray(value); case "[object Uint16Array]": return new Uint16Array(value); case "[object Uint32Array]": return new Uint32Array(value); case "[object BigUint64Array]": return new BigUint64Array(value); case "[object Int8Array]": return new Int8Array(value); case "[object Int16Array]": return new Int16Array(value); case "[object Int32Array]": return new Int32Array(value); case "[object BigInt64Array]": return new BigInt64Array(value); case "[object Float32Array]": return new Float32Array(value); case "[object Float64Array]": return new Float64Array(value); case "[object ArrayBuffer]": { const byteLength = tryRead(arrayBufferByteLength, value); return byteLength.success ? cloneBufferRange(value, 0, byteLength.value, false) : NOT_NATIVE; } case "[object SharedArrayBuffer]": { const byteLength = tryRead(sharedArrayBufferByteLength, value); return byteLength.success ? cloneBufferRange(value, 0, byteLength.value, true) : NOT_NATIVE; } case "[object DataView]": { const buffer = tryRead(dataViewBuffer, value); if (!buffer.success) return NOT_NATIVE; const byteOffset = read(dataViewByteOffset, value); const byteLength = read(dataViewByteLength, value); return new DataView(cloneBufferRange(buffer.value, byteOffset, byteLength)); } case "[object File]": { const size = tryRead(blobSize, value); if (typeof File === "undefined" || !size.success || blobType === void 0 || fileName === void 0 || fileLastModified === void 0) return NOT_NATIVE; return new File([value], read(fileName, value), { type: read(blobType, value), lastModified: read(fileLastModified, value) }); } case "[object Blob]": { const size = tryRead(blobSize, value); if (typeof Blob === "undefined" || !size.success || blobType === void 0) return NOT_NATIVE; return new Blob([value], { type: read(blobType, value) }); } case "[object RegExp]": { const source = tryRead(regexpSource, value); return source.success ? new RegExp(source.value, read(regexpFlags, value)) : NOT_NATIVE; } default: return NOT_NATIVE; } }; const cloneBufferRange = (input, byteOffset, byteLength, shared) => { if (shared === void 0) shared = tryRead(sharedArrayBufferByteLength, input).success; let output; if (shared) { if (typeof SharedArrayBuffer === "undefined") throw new TypeError("SharedArrayBuffer is not available"); output = new SharedArrayBuffer(byteLength); } else { read(arrayBufferByteLength, input); output = new ArrayBuffer(byteLength); } new Uint8Array(output).set(new Uint8Array(input, byteOffset, byteLength)); return output; }; //#endregion export { _plainCloneAny }; //# sourceMappingURL=_plainCloneAny.mjs.map