typia
Version:
Superfast runtime validators with only one line
139 lines (138 loc) • 6.32 kB
JavaScript
//#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