From 661ac64bb0f1aabe9f7473b6b1ee0694589fe8ca Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Thu, 7 Sep 2023 01:46:41 +0200 Subject: [PATCH] perf: add and use homemade optimized deep cloning implementation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- package.json | 1 - pnpm-lock.yaml | 7 ------- src/utils/Utils.ts | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 460bb213..e1732833 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,6 @@ "basic-ftp": "^5.0.3", "chalk": "^5.3.0", "date-fns": "^2.30.0", - "deep-clone": "^4.0.0", "http-status-codes": "^2.2.0", "just-merge": "^3.2.0", "logform": "^2.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85782385..c685cfe3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,9 +40,6 @@ dependencies: date-fns: specifier: ^2.30.0 version: 2.30.0 - deep-clone: - specifier: ^4.0.0 - version: 4.0.0 http-status-codes: specifier: ^2.2.0 version: 2.2.0 @@ -3452,10 +3449,6 @@ packages: mimic-response: 3.1.0 dev: true - /deep-clone@4.0.0: - resolution: {integrity: sha512-bMvDVR8GiGCGHT4SgqXyXDD9Zmo3kv9YLq8aSO2xslP97A3mFkpNBg+t+fjXERvewzhmtk9efvL+V52iVkD0lg==} - dev: false - /deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index e01aa75f..c29f8d15 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -12,7 +12,6 @@ import { minutesToSeconds, secondsToMilliseconds, } from 'date-fns'; -import deepClone from 'deep-clone'; import { Constants } from './Constants'; import { type TimestampedData, WebSocketCloseEventStatusString } from '../types'; @@ -215,8 +214,44 @@ type CloneableData = | CloneableData[] | { [key: string]: CloneableData }; +type FormatKey = (key: string) => string; + +function deepClone( + value: I, + formatKey?: FormatKey, + refs: Map = new Map(), +): O { + const ref = refs.get(value); + if (ref !== undefined) { + return ref; + } + if (Array.isArray(value)) { + const clone: CloneableData[] = []; + refs.set(value, clone as O); + for (let i = 0; i < value.length; i++) { + clone[i] = deepClone(value[i], formatKey, refs); + } + return clone as O; + } + if (value instanceof Date) { + return new Date(value.valueOf()) as O; + } + if (typeof value !== 'object' || value === null) { + return value as unknown as O; + } + const clone: Record = {}; + refs.set(value, clone as O); + for (const key of Object.keys(value)) { + clone[typeof formatKey === 'function' ? formatKey(key) : key] = deepClone( + value[key], + formatKey, + refs, + ); + } + return clone as O; +} + export const cloneObject = (object: T): T => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call return deepClone(object as CloneableData) as T; }; -- 2.34.1