Skip to content

Commit ccea3e3

Browse files
fix(dereference): modification for circular ref for delete objects (#132)
* fix(dereference): modification for circular ref * fix(dereference): added comments * fix: update test cases for circular objects * fix: update variable name
1 parent 3ddde69 commit ccea3e3

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

src/__tests__/decycle.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('decycle', () => {
105105
});
106106
});
107107

108-
it('should not create refs for objects that are not circular', () => {
108+
it('should create refs circular objects and repeated values', () => {
109109
const obj2 = {
110110
circle: {},
111111
};
@@ -131,7 +131,7 @@ describe('decycle', () => {
131131
foo: 'bar',
132132
},
133133
obj3B: {
134-
foo: 'bar',
134+
$ref: '#/obj3A',
135135
},
136136
paths: {
137137
'/circle': {

src/decycle.ts

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,46 @@
11
import { isPlainObject } from './isPlainObject';
22
import { pathToPointer } from './pathToPointer';
33

4-
export const decycle = (obj: unknown, replacer?: (value: any) => any) => {
4+
export function decycle(obj: unknown, replacer?: (value: any) => any) {
55
const objs = new WeakMap<object, string>();
6-
return (function derez(value: any, path: string[]) {
7-
// The new object or array
8-
let curObj: any;
9-
10-
// If a replacer function was provided, then call it to get a replacement value.
11-
if (replacer) value = replacer(value);
6+
const objectsToBeDeleted: object[] = []; // To keep track of objects to delete later
127

8+
function derez(value: any, path: (string | number)[]): any {
9+
if (replacer) {
10+
value = replacer(value);
11+
}
1312
if (isPlainObject(value) || Array.isArray(value)) {
14-
// The path of an earlier occurance of value
1513
const oldPath = objs.get(value);
14+
1615
// If the value is an object or array, look to see if we have already
1716
// encountered it. If so, return a {"$ref":PATH} object.
18-
if (oldPath) return { $ref: oldPath };
19-
17+
if (oldPath) {
18+
return { $ref: oldPath };
19+
}
2020
objs.set(value, pathToPointer(path));
2121
// If it is an array, replicate the array.
2222
if (Array.isArray(value)) {
23-
curObj = value.map((element, i) => derez(element, [...path, String(i)]));
24-
} else {
25-
// It is an object, replicate the object.
26-
curObj = {};
27-
Object.keys(value).forEach(name => {
28-
curObj[name] = derez(value[name], [...path, name]);
29-
});
23+
return value.map((element, i) => derez(element, [...path, i]));
3024
}
31-
objs.delete(value);
32-
return curObj;
25+
const newObj: Record<string, any> = {};
26+
for (const name in value) {
27+
if (Object.prototype.hasOwnProperty.call(value, name)) {
28+
newObj[name] = derez(value[name], [...path, name]);
29+
}
30+
}
31+
// Schedule object for deletion after derez completes
32+
objectsToBeDeleted.push(value);
33+
return newObj;
3334
}
3435
return value;
35-
})(obj, []);
36-
};
36+
}
37+
38+
const result = derez(obj, []);
39+
40+
// Clean up objs for objects that were processed
41+
objectsToBeDeleted.forEach(obj => {
42+
objs.delete(obj);
43+
});
44+
45+
return result;
46+
}

0 commit comments

Comments
 (0)