UNPKG

@qntm-code/utils

Version:

A collection of useful utility functions with associated TypeScript types. All functions have been unit tested.

103 lines (102 loc) 3.59 kB
import { isPlainObject } from '../type-predicates/isPlainObject.js'; import { typeOf, ValueType } from '../type-predicates/typeOf.js'; /** * Recursively (deep) clones native types, like Object, Array, RegExp, Date, Map, Set, Symbol, Error as well as primitives. */ export function clone(value, instanceClone = false) { switch (typeOf(value)) { case ValueType.object: { return cloneObjectDeep(value, instanceClone); } case ValueType.array: case ValueType.int8array: case ValueType.uint8array: case ValueType.uint8clampedarray: case ValueType.int16array: case ValueType.uint16array: case ValueType.int32array: case ValueType.uint32array: case ValueType.float32array: case ValueType.float64array: case ValueType.bigint64array: case ValueType.biguint64array: { return cloneArrayDeep(value, instanceClone); } default: { return cloneShallow(value); } } } function cloneShallow(value) { switch (typeOf(value)) { case ValueType.buffer: { return cloneBuffer(value); } case ValueType.symbol: { return cloneSymbol(value); } case ValueType.error: { return Object.create(value); } case ValueType.map: { return new Map(value); } case ValueType.set: { return new Set(value); } case ValueType.date: { return new Date(value); } case ValueType.regexp: { return cloneRegExp(value); } case ValueType.moment: { return value.clone(); } } return value; } function cloneObjectDeep(value, instanceClone) { if (typeof instanceClone === 'function') { return instanceClone(value); } if (instanceClone || isPlainObject(value)) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access const cloned = new value.constructor(); for (const key in value) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access cloned[key] = clone(value[key]); } // eslint-disable-next-line @typescript-eslint/no-unsafe-return return cloned; } return value; } function cloneArrayDeep(value, instanceClone) { const length = value.length; // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access const cloned = new value.constructor(length); for (let i = 0; i < length; i++) { cloned[i] = clone(value[i], instanceClone); } return cloned; } function cloneRegExp(value) { // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access const cloned = new value.constructor(value.source, value.flags); cloned.lastIndex = value.lastIndex; return cloned; } function cloneBuffer(value) { const length = value.length; // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const buffer = Buffer.allocUnsafe ? Buffer.allocUnsafe(length) : Buffer.from(length); value.copy(buffer); return buffer; } // eslint-disable-next-line @typescript-eslint/unbound-method const valueOf = Symbol.prototype.valueOf; function cloneSymbol(value) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return valueOf ? Object(valueOf.call(value)) : {}; }