Skip to content

Commit 9306d09

Browse files
authored
feat: pass uneval to replacer, for handling nested custom types (#114)
1 parent 2124b5b commit 9306d09

File tree

3 files changed

+31
-13
lines changed

3 files changed

+31
-13
lines changed

.changeset/shaggy-paths-rhyme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'devalue': minor
3+
---
4+
5+
feat: pass `uneval` to replacer, for handling nested custom types

src/uneval.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const reserved =
1717
/**
1818
* Turn a value into the JavaScript that creates an equivalent value
1919
* @param {any} value
20-
* @param {(value: any) => string | void} [replacer]
20+
* @param {(value: any, uneval: (value: any) => string | void) => string | void} [replacer]
2121
*/
2222
export function uneval(value, replacer) {
2323
const counts = new Map();
@@ -42,7 +42,7 @@ export function uneval(value, replacer) {
4242
counts.set(thing, 1);
4343

4444
if (replacer) {
45-
const str = replacer(thing);
45+
const str = replacer(thing, (value) => uneval(value, replacer));
4646

4747
if (typeof str === 'string') {
4848
custom.set(thing, str);

test/test.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ import { uneval, unflatten, parse, stringify } from '../index.js';
55

66
globalThis.Temporal ??= (await import('@js-temporal/polyfill')).Temporal;
77

8-
class Custom {
8+
class Foo {
9+
constructor(value) {
10+
this.value = value;
11+
}
12+
}
13+
14+
class Bar {
915
constructor(value) {
1016
this.value = value;
1117
}
@@ -549,27 +555,34 @@ const fixtures = {
549555
{
550556
name: 'Custom type',
551557
value: [instance, instance],
552-
js: '(function(a){return [a,a]}(new Custom({answer:42})))',
553-
json: '[[1,1],["Custom",2],{"answer":3},42]',
554-
replacer: (value) => {
555-
if (value instanceof Custom) {
556-
return `new Custom(${uneval(value.value)})`;
558+
js: '(function(a){return [a,a]}(new Foo({bar:new Bar({answer:42})})))',
559+
json: '[[1,1],["Foo",2],{"bar":3},["Bar",4],{"answer":5},42]',
560+
replacer: (value, uneval) => {
561+
if (value instanceof Foo) {
562+
return `new Foo(${uneval(value.value)})`;
563+
}
564+
565+
if (value instanceof Bar) {
566+
return `new Bar(${uneval(value.value)})`;
557567
}
558568
},
559569
// test for https://github.com/Rich-Harris/devalue/pull/80
560570
reducers: Object.assign(Object.create({ polluted: true }), {
561-
Custom: (x) => x instanceof Custom && x.value
571+
Foo: (x) => x instanceof Foo && x.value,
572+
Bar: (x) => x instanceof Bar && x.value
562573
}),
563574
revivers: {
564-
Custom: (x) => new Custom(x)
575+
Foo: (x) => new Foo(x),
576+
Bar: (x) => new Bar(x)
565577
},
566578
validate: ([obj1, obj2]) => {
567579
assert.is(obj1, obj2);
568-
assert.ok(obj1 instanceof Custom);
569-
assert.equal(obj1.value.answer, 42);
580+
assert.ok(obj1 instanceof Foo);
581+
assert.ok(obj1.value.bar instanceof Bar);
582+
assert.equal(obj1.value.bar.value.answer, 42);
570583
}
571584
}
572-
])(new Custom({ answer: 42 }))
585+
])(new Foo({ bar: new Bar({ answer: 42 }) }))
573586
};
574587

575588
for (const [name, tests] of Object.entries(fixtures)) {

0 commit comments

Comments
 (0)