Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): make deepCopy backward compatible #4505

Merged
merged 12 commits into from
Nov 2, 2022
Merged
29 changes: 19 additions & 10 deletions packages/workflow/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument */
export const deepCopy = <T>(source: T, hash = new WeakMap(), path = ''): T => {
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return */
cstuncsik marked this conversation as resolved.
Show resolved Hide resolved

type Serializable = any & { toJSON?: (key?: any) => string };
netroy marked this conversation as resolved.
Show resolved Hide resolved

export const deepCopy = <T extends any | Serializable>(
source: T,
hash = new WeakMap(),
path = '',
): T => {
let clone: any;
let i: any;
const hasOwnProp = Object.prototype.hasOwnProperty.bind(source);
// Primitives & Null & Function
if (typeof source !== 'object' || source === null || source instanceof Function) {
Expand All @@ -10,23 +16,26 @@ export const deepCopy = <T>(source: T, hash = new WeakMap(), path = ''): T => {
if (hash.has(source)) {
return hash.get(source);
}
// Date
if (source instanceof Date) {
cstuncsik marked this conversation as resolved.
Show resolved Hide resolved
return new Date(source.getTime()) as T;
}
// Array
if (Array.isArray(source)) {
clone = [];
const len = source.length;
for (i = 0; i < len; i++) {
clone[i] = deepCopy(source[i], hash, path + `[${i as string}]`);
for (let i = 0; i < len; i++) {
clone[i] = deepCopy(source[i], hash, path + `[${i}]`);
}
return clone;
}
// Date and other Serializable objects
const toJSON = (source as Serializable).toJSON;
if (typeof toJSON === 'function') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
return toJSON.call(source) as T;
}

cstuncsik marked this conversation as resolved.
Show resolved Hide resolved
// Object
clone = {};
hash.set(source, clone);
for (i in source) {
for (const i in source) {
if (hasOwnProp(i)) {
clone[i] = deepCopy((source as any)[i], hash, path + `.${i as string}`);
}
Expand Down
23 changes: 16 additions & 7 deletions packages/workflow/test/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ describe('jsonParse', () => {

describe('deepCopy', () => {
it('should deep copy an object', () => {
const serializable = {
x: 1,
y: 2,
toJSON: () => 'x:1,y:2',
};
const object = {
deep: {
props: {
list: [{ a: 1 }, { b: 2 }, { c: 3 }],
},
arr: [1, 2, 3],
},
serializable,
arr: [
{
prop: {
Expand All @@ -34,17 +40,18 @@ describe('deepCopy', () => {
},
],
func: () => {},
date: new Date(),
date: new Date(1667389172201),
undef: undefined,
nil: null,
bool: true,
num: 1,
};
const copy = deepCopy(object);
expect(copy).toEqual(object);
expect(copy).not.toBe(object);
expect(copy.arr).toEqual(object.arr);
expect(copy.arr).not.toBe(object.arr);
expect(copy.date).toBe('2022-11-02T11:39:32.201Z');
expect(copy.serializable).toBe(serializable.toJSON());
expect(copy.deep.props).toEqual(object.deep.props);
expect(copy.deep.props).not.toBe(object.deep.props);
});
Expand All @@ -65,7 +72,7 @@ describe('deepCopy', () => {
},
],
func: () => {},
date: new Date(),
date: new Date(1667389172201),
undef: undefined,
nil: null,
bool: true,
Expand All @@ -74,14 +81,16 @@ describe('deepCopy', () => {

object.circular = object;
object.deep.props.circular = object;
object.deep.arr.push(object)
object.deep.arr.push(object);

const copy = deepCopy(object);
expect(copy).toEqual(object);
expect(copy).not.toBe(object);
expect(copy.arr).toEqual(object.arr);
expect(copy.arr).not.toBe(object.arr);
expect(copy.deep.props).toEqual(object.deep.props);
expect(copy.deep.props).not.toBe(object.deep.props);
expect(copy.date).toBe('2022-11-02T11:39:32.201Z');
expect(copy.deep.props.circular).toBe(copy);
expect(copy.deep.props.circular).not.toBe(object);
expect(copy.deep.arr.slice(-1)[0]).toBe(copy);
expect(copy.deep.arr.slice(-1)[0]).not.toBe(object);
});
});