Skip to content

Commit

Permalink
Introduce trace flag to mark circular reference keys (sindresorhus#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeGkas committed Apr 23, 2022
1 parent 602d338 commit 6123b8d
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 4 deletions.
10 changes: 10 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ export type Options = {
Set it to `'\t'` for tab indentation or the number of spaces you want.
*/
readonly indentation?: string | number;

/**
Enable key tracing for circular references.
By default, this option is set to false.
*/
readonly trace?: boolean;
};

/**
Expand All @@ -24,6 +31,9 @@ console.log(safeStringify(foo));
console.log(JSON.stringify(foo));
//=> TypeError: Converting circular structure to JSON
console.log(safeStringify(foo, {trace: true}));
//=> '{ "a": true, "b": "[Circular *]" }'
```
*/
export default function safeStringify(value: unknown, options?: Options): string;
8 changes: 4 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const makeCircularReplacer = () => {
const makeCircularReplacer = ({trace} = {}) => {
const seen = new WeakMap();

return (key, value) => {
if (value !== null && typeof value === 'object') {
if (seen.has(value) && seen.get(value) !== key) {
return '[Circular]';
return trace ? `[Circular *${seen.get(value)}]` : '[Circular]';
}

seen.set(value, key);
Expand All @@ -14,6 +14,6 @@ const makeCircularReplacer = () => {
};
};

export default function safeStringify(object, {indentation} = {}) {
return JSON.stringify(object, makeCircularReplacer(), indentation);
export default function safeStringify(object, {indentation, trace} = {}) {
return JSON.stringify(object, makeCircularReplacer({trace}), indentation);
}
2 changes: 2 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ import safeStringify from './index.js';
expectType<string>(safeStringify(1));
safeStringify('foo', {indentation: '\t'});
safeStringify('foo', {indentation: 2});
safeStringify('foo', {trace: true});
safeStringify('foo', {trace: false});
11 changes: 11 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ console.log(safeStringify(foo));

console.log(JSON.stringify(foo));
//=> TypeError: Converting circular structure to JSON

console.log(safeStringify(foo, {trace: true}));
//=> '{ "a": true, "b": "[Circular *]" }'
```

## API
Expand Down Expand Up @@ -51,6 +54,14 @@ By default, the JSON is not indented.

Set it to `'\t'` for tab indentation or the number of spaces you want.

##### trace

Type: `boolean`

Enable key tracing for circular references.

By default, this option is set to false.

## FAQ

### Why another safe stringify package?
Expand Down
50 changes: 50 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const options = {
indentation: '\t',
};

const optionsWithTrace = {
indentation: '\t',
trace: true,
};

test('main', t => {
const fixture = {
a: true,
Expand All @@ -14,6 +19,7 @@ test('main', t => {
};

t.is(safeStringify(fixture, options), JSON.stringify(fixture, undefined, '\t'));
t.is(safeStringify(fixture, optionsWithTrace), JSON.stringify(fixture, undefined, '\t'));
});

test('circular object', t => {
Expand All @@ -32,6 +38,22 @@ test('circular object', t => {
t.snapshot(safeStringify(fixture, options));
});

test('circular object with trace enabled', t => {
const fixture = {
a: true,
};

fixture.b = fixture;

fixture.c = [fixture, fixture.b];

fixture.d = {
e: fixture.c,
};

t.snapshot(safeStringify(fixture, optionsWithTrace));
});

test('circular array', t => {
const fixture = [1];

Expand All @@ -40,6 +62,14 @@ test('circular array', t => {
t.snapshot(safeStringify(fixture, options));
});

test('circular array with trace enabled', t => {
const fixture = [1];

fixture.push(fixture, fixture);

t.snapshot(safeStringify(fixture, optionsWithTrace));
});

test('multiple circular objects in array', t => {
const fixture = {
a: true,
Expand All @@ -50,6 +80,16 @@ test('multiple circular objects in array', t => {
t.snapshot(safeStringify([fixture, fixture], options));
});

test('multiple circular objects in array with trace enabled', t => {
const fixture = {
a: true,
};

fixture.b = fixture;

t.snapshot(safeStringify([fixture, fixture], optionsWithTrace));
});

test('multiple circular objects in object', t => {
const fixture = {
a: true,
Expand All @@ -59,3 +99,13 @@ test('multiple circular objects in object', t => {

t.snapshot(safeStringify({x: fixture, y: fixture}, options));
});

test('multiple circular objects in object with trace enabled', t => {
const fixture = {
a: true,
};

fixture.b = fixture;

t.snapshot(safeStringify({x: fixture, y: fixture}, optionsWithTrace));
});
50 changes: 50 additions & 0 deletions test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ Generated by [AVA](https://avajs.dev).
}␊
}`

## circular object with trace enabled

> Snapshot 1
`{␊
"a": true,␊
"b": "[Circular *]",␊
"c": [␊
"[Circular *]",␊
"[Circular *]"␊
],␊
"d": {␊
"e": "[Circular *c]"␊
}␊
}`

## circular array

> Snapshot 1
Expand All @@ -30,6 +46,16 @@ Generated by [AVA](https://avajs.dev).
"[Circular]"␊
]`

## circular array with trace enabled

> Snapshot 1
`[␊
1,␊
"[Circular *]",␊
"[Circular *]"␊
]`

## multiple circular objects in array

> Snapshot 1
Expand All @@ -42,6 +68,18 @@ Generated by [AVA](https://avajs.dev).
"[Circular]"␊
]`

## multiple circular objects in array with trace enabled

> Snapshot 1
`[␊
{␊
"a": true,␊
"b": "[Circular *0]"␊
},␊
"[Circular *0]"␊
]`

## multiple circular objects in object

> Snapshot 1
Expand All @@ -53,3 +91,15 @@ Generated by [AVA](https://avajs.dev).
},␊
"y": "[Circular]"␊
}`

## multiple circular objects in object with trace enabled

> Snapshot 1
`{␊
"x": {␊
"a": true,␊
"b": "[Circular *x]"␊
},␊
"y": "[Circular *x]"␊
}`
Binary file modified test.js.snap
Binary file not shown.

0 comments on commit 6123b8d

Please sign in to comment.