perf: switch to deep-clone for cloning (20% faster)
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 28 Jul 2023 14:50:17 +0000 (16:50 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 28 Jul 2023 14:50:17 +0000 (16:50 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
package.json
pnpm-lock.yaml
rollup.config.mjs
src/charging-station/AutomaticTransactionGenerator.ts
src/utils/Utils.ts
test/utils/Utils.test.ts

index c08a92569243bf895e49ead778ddd46ab7f789ea..3d6c669459e5e949ab392d5977add4989a02c8bb 100644 (file)
     "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-clone": "^6.2.0",
     "just-merge": "^3.2.0",
     "logform": "^2.5.1",
     "mnemonist": "^0.39.5",
index 811187b69cd7a9583403a74f7ff73e2a7e5d61a0..3b084ed15c9e31a58e64a8db51d4174fa60c5dec 100644 (file)
@@ -39,12 +39,12 @@ 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
-  just-clone:
-    specifier: ^6.2.0
-    version: 6.2.0
   just-merge:
     specifier: ^3.2.0
     version: 3.2.0
@@ -3444,6 +3444,10 @@ 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'}
@@ -6028,10 +6032,6 @@ packages:
       verror: 1.10.0
     dev: true
 
-  /just-clone@6.2.0:
-    resolution: {integrity: sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==}
-    dev: false
-
   /just-extend@4.2.1:
     resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==}
     dev: true
index baaeda78fe4753b19b52de5620f07ace98e20512..83c2e009b3d585b1c32afcf611f7cf0bd8046ddb 100644 (file)
@@ -44,8 +44,8 @@ export default {
     'basic-ftp',
     'chalk',
     'date-fns',
+    'deep-clone',
     'http-status-codes',
-    'just-clone',
     'just-merge',
     'mnemonist/lru-map-with-delete.js',
     'mnemonist/queue.js',
index 5ed5be42e83237067ee4d32b766e643cc9cdba71..f90662fc88cd3513568eca74fb3eda5059a5c9bb 100644 (file)
@@ -355,7 +355,9 @@ export class AutomaticTransactionGenerator extends AsyncResource {
 
   private getConnectorStatus(connectorId: number): Status {
     const connectorStatus = this.chargingStation.getAutomaticTransactionGeneratorStatuses()
-      ? cloneObject(this.chargingStation.getAutomaticTransactionGeneratorStatuses()!)[connectorId]
+      ? cloneObject<Status[]>(this.chargingStation.getAutomaticTransactionGeneratorStatuses()!)[
+          connectorId
+        ]
       : undefined;
     delete connectorStatus?.startDate;
     delete connectorStatus?.lastRunDate;
index 73bb0ba927d2edce72ddf493635915a461d85051..c5a276bc92609e21bb55f79f2df4549a5f0fe447 100644 (file)
@@ -12,7 +12,7 @@ import {
   minutesToSeconds,
   secondsToMilliseconds,
 } from 'date-fns';
-import clone from 'just-clone';
+import deepClone from 'deep-clone';
 
 import { Constants } from './Constants';
 import { type TimestampedData, WebSocketCloseEventStatusString } from '../types';
@@ -206,8 +206,19 @@ export const isObject = (item: unknown): boolean => {
   );
 };
 
-export const cloneObject = <T extends object>(object: T): T => {
-  return clone<T>(object);
+type CloneableData =
+  | number
+  | string
+  | boolean
+  | null
+  | undefined
+  | Date
+  | CloneableData[]
+  | { [key: string]: CloneableData };
+
+export const cloneObject = <T>(object: T): T => {
+  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+  return deepClone(object as CloneableData) as T;
 };
 
 export const hasOwnProp = (object: unknown, property: PropertyKey): boolean => {
index 96fd18b42096a485871c34568c3e8cbce791f4bf..243e8547731a8ba55e973a196679ddd1a3a03f06 100644 (file)
@@ -242,28 +242,29 @@ describe('Utils test suite', () => {
     const obj = { 1: 1 };
     expect(cloneObject(obj)).toStrictEqual(obj);
     expect(cloneObject(obj) === obj).toBe(false);
+    const nestedObj = { 1: obj, 2: obj };
+    expect(cloneObject(nestedObj)).toStrictEqual(nestedObj);
+    expect(cloneObject(nestedObj) === nestedObj).toBe(false);
     const array = [1, 2];
     expect(cloneObject(array)).toStrictEqual(array);
     expect(cloneObject(array) === array).toBe(false);
+    const objArray = [obj, obj];
+    expect(cloneObject(objArray)).toStrictEqual(objArray);
+    expect(cloneObject(objArray) === objArray).toBe(false);
     const date = new Date();
     expect(cloneObject(date)).toStrictEqual(date);
     expect(cloneObject(date) === date).toBe(false);
     const map = new Map([['1', '2']]);
-    expect(cloneObject(map)).toStrictEqual(map);
-    expect(cloneObject(map) === map).toBe(false);
+    expect(cloneObject(map)).toStrictEqual({});
     const set = new Set(['1']);
-    expect(cloneObject(set)).toStrictEqual(set);
-    expect(cloneObject(set) === set).toBe(false);
+    expect(cloneObject(set)).toStrictEqual({});
     // The URL object seems to have not enumerable properties
     const url = new URL('https://domain.tld');
-    expect(cloneObject(url)).toStrictEqual(url);
-    expect(cloneObject(url) === url).toBe(true);
+    expect(cloneObject(url)).toStrictEqual({});
     const weakMap = new WeakMap([[{ 1: 1 }, { 2: 2 }]]);
-    expect(cloneObject(weakMap)).toStrictEqual(weakMap);
-    expect(cloneObject(weakMap) === weakMap).toBe(true);
+    expect(cloneObject(weakMap)).toStrictEqual({});
     const weakSet = new WeakSet([{ 1: 1 }, { 2: 2 }]);
-    expect(cloneObject(weakSet)).toStrictEqual(weakSet);
-    expect(cloneObject(weakSet) === weakSet).toBe(true);
+    expect(cloneObject(weakSet)).toStrictEqual({});
   });
 
   it('Verify hasOwnProp()', () => {