Skip to content

Commit

Permalink
fix(dereference): modification for circular ref for delete objects (#132
Browse files Browse the repository at this point in the history
)

* fix(dereference): modification for circular ref

* fix(dereference): added comments

* fix: update test cases for circular objects

* fix: update variable name
  • Loading branch information
SB-rohitdesai authored Jul 18, 2024
1 parent 3ddde69 commit ccea3e3
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/__tests__/decycle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe('decycle', () => {
});
});

it('should not create refs for objects that are not circular', () => {
it('should create refs circular objects and repeated values', () => {
const obj2 = {
circle: {},
};
Expand All @@ -131,7 +131,7 @@ describe('decycle', () => {
foo: 'bar',
},
obj3B: {
foo: 'bar',
$ref: '#/obj3A',
},
paths: {
'/circle': {
Expand Down
52 changes: 31 additions & 21 deletions src/decycle.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
import { isPlainObject } from './isPlainObject';
import { pathToPointer } from './pathToPointer';

export const decycle = (obj: unknown, replacer?: (value: any) => any) => {
export function decycle(obj: unknown, replacer?: (value: any) => any) {
const objs = new WeakMap<object, string>();
return (function derez(value: any, path: string[]) {
// The new object or array
let curObj: any;

// If a replacer function was provided, then call it to get a replacement value.
if (replacer) value = replacer(value);
const objectsToBeDeleted: object[] = []; // To keep track of objects to delete later

function derez(value: any, path: (string | number)[]): any {
if (replacer) {
value = replacer(value);
}
if (isPlainObject(value) || Array.isArray(value)) {
// The path of an earlier occurance of value
const oldPath = objs.get(value);

// If the value is an object or array, look to see if we have already
// encountered it. If so, return a {"$ref":PATH} object.
if (oldPath) return { $ref: oldPath };

if (oldPath) {
return { $ref: oldPath };
}
objs.set(value, pathToPointer(path));
// If it is an array, replicate the array.
if (Array.isArray(value)) {
curObj = value.map((element, i) => derez(element, [...path, String(i)]));
} else {
// It is an object, replicate the object.
curObj = {};
Object.keys(value).forEach(name => {
curObj[name] = derez(value[name], [...path, name]);
});
return value.map((element, i) => derez(element, [...path, i]));
}
objs.delete(value);
return curObj;
const newObj: Record<string, any> = {};
for (const name in value) {
if (Object.prototype.hasOwnProperty.call(value, name)) {
newObj[name] = derez(value[name], [...path, name]);
}
}
// Schedule object for deletion after derez completes
objectsToBeDeleted.push(value);
return newObj;
}
return value;
})(obj, []);
};
}

const result = derez(obj, []);

// Clean up objs for objects that were processed
objectsToBeDeleted.forEach(obj => {
objs.delete(obj);
});

return result;
}

0 comments on commit ccea3e3

Please sign in to comment.