Skip to content

Commit

Permalink
fix: better polyfill implementation for cloning arrays and objects
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed May 28, 2023
1 parent f321163 commit fad6beb
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 11 deletions.
51 changes: 40 additions & 11 deletions src/utils/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,51 @@ const gT = (() => {
throw new Error('unable to locate global object');
})();

export function polyfillClone<T>(input: T) {
const map = new WeakMap();

const fn = <A>(value: A) : A => {
if (Array.isArray(value)) {
if (map.has(value)) {
return map.get(value);
}

const cloned = [] as A;
map.set(value, cloned);

value.map((el) => (cloned as any[]).push(fn(el)));

return cloned;
}

if (isObject(value)) {
if (map.has(value)) {
return map.get(value);
}

const output = {} as A;
const keys = Object.keys(value);

map.set(value, output);
for (let i = 0; i < keys.length; i++) {
output[keys[i] as keyof A] = fn(value[keys[i]]);
}

return output;
}

return value;
};

return fn(input);
}

/* istanbul ignore next */
export function clone<T>(value: T) : T {
if (gT.structuredClone) {
return gT.structuredClone(value);
}

/* istanbul ignore next */
if (isObject(value)) {
return { ...value };
}

/* istanbul ignore next */
if (Array.isArray(value)) {
return [...value] as T;
}

/* istanbul ignore next */
return value;
return polyfillClone(value);
}
26 changes: 26 additions & 0 deletions test/unit/utils/clone.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import {polyfillClone} from "../../../src";

describe('src/utils/clone', function () {
it('should polyfill clone objects with circular reference', () => {
const foo : Record<string, any> = {bar: 'baz'};
foo.boz = foo;

const copy = polyfillClone(foo);
expect(copy).toEqual(foo);
});

it('should polyfill clone arrays with circular reference', () => {
const foo : any = ['bar'];
foo.push(foo);

const copy = polyfillClone(foo);
expect(copy).toEqual(foo);
})
});

0 comments on commit fad6beb

Please sign in to comment.