Skip to content

Commit a3d09d4

Browse files
Add value and root properties in DevalueError instances (#126)
* feat: enhance DevalueError to include problematic `value` and `root` context in errors * changeset * changeset * Update .changeset/odd-areas-enjoy.md --------- Co-authored-by: Rich Harris <hello@rich-harris.dev>
1 parent f4b37f3 commit a3d09d4

File tree

7 files changed

+91
-7
lines changed

7 files changed

+91
-7
lines changed

.changeset/lovely-sheep-prove.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: expose `DevalueError` for `instanceof` checks in `catch` clauses

.changeset/odd-areas-enjoy.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: add `value` and `root` properties in `DevalueError` instances

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { uneval } from './src/uneval.js';
22
export { parse, unflatten } from './src/parse.js';
33
export { stringify } from './src/stringify.js';
4+
export { DevalueError } from './src/utils.js';

src/stringify.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export function stringify(value, reducers) {
6464
}
6565

6666
if (typeof thing === 'function') {
67-
throw new DevalueError(`Cannot stringify a function`, keys);
67+
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
6868
}
6969

7070
let str = '';
@@ -200,14 +200,18 @@ export function stringify(value, reducers) {
200200
if (!is_plain_object(thing)) {
201201
throw new DevalueError(
202202
`Cannot stringify arbitrary non-POJOs`,
203-
keys
203+
keys,
204+
thing,
205+
value
204206
);
205207
}
206208

207209
if (enumerable_symbols(thing).length > 0) {
208210
throw new DevalueError(
209211
`Cannot stringify POJOs with symbolic keys`,
210-
keys
212+
keys,
213+
thing,
214+
value
211215
);
212216
}
213217

src/uneval.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function uneval(value, replacer) {
4747
}
4848

4949
if (typeof thing === 'function') {
50-
throw new DevalueError(`Cannot stringify a function`, keys);
50+
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
5151
}
5252

5353
const type = get_type(thing);
@@ -116,14 +116,18 @@ export function uneval(value, replacer) {
116116
if (!is_plain_object(thing)) {
117117
throw new DevalueError(
118118
`Cannot stringify arbitrary non-POJOs`,
119-
keys
119+
keys,
120+
thing,
121+
value
120122
);
121123
}
122124

123125
if (enumerable_symbols(thing).length > 0) {
124126
throw new DevalueError(
125127
`Cannot stringify POJOs with symbolic keys`,
126-
keys
128+
keys,
129+
thing,
130+
value
127131
);
128132
}
129133

src/utils.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ export class DevalueError extends Error {
1515
/**
1616
* @param {string} message
1717
* @param {string[]} keys
18+
* @param {any} [value] - The value that failed to be serialized
19+
* @param {any} [root] - The root value being serialized
1820
*/
19-
constructor(message, keys) {
21+
constructor(message, keys, value, root) {
2022
super(message);
2123
this.name = 'DevalueError';
2224
this.path = keys.join('');
25+
this.value = value;
26+
this.root = root;
2327
}
2428
}
2529

test/test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,67 @@ for (const fn of [uneval, stringify]) {
867867
assert.equal(e.path, '.object.invalid');
868868
}
869869
});
870+
871+
uvu.test(`${fn.name} populates error.value with the problematic value`, () => {
872+
const testFn = function invalid() {};
873+
try {
874+
fn({
875+
foo: {
876+
array: [testFn]
877+
}
878+
});
879+
} catch (e) {
880+
assert.equal(e.name, 'DevalueError');
881+
assert.equal(e.message, 'Cannot stringify a function');
882+
assert.equal(e.value, testFn);
883+
}
884+
});
885+
886+
uvu.test(`${fn.name} populates error.root with the root value`, () => {
887+
const root = {
888+
foo: {
889+
array: [function invalid() {}]
890+
}
891+
};
892+
try {
893+
fn(root);
894+
} catch (e) {
895+
assert.equal(e.name, 'DevalueError');
896+
assert.equal(e.message, 'Cannot stringify a function');
897+
assert.equal(e.root, root);
898+
}
899+
});
900+
901+
uvu.test(`${fn.name} includes value and root on arbitrary non-POJOs error`, () => {
902+
class Whatever {}
903+
const problematicValue = new Whatever();
904+
const root = {
905+
foo: {
906+
['string-key']: new Map([['key', problematicValue]])
907+
}
908+
};
909+
try {
910+
fn(root);
911+
} catch (e) {
912+
assert.equal(e.name, 'DevalueError');
913+
assert.equal(e.message, 'Cannot stringify arbitrary non-POJOs');
914+
assert.equal(e.value, problematicValue);
915+
assert.equal(e.root, root);
916+
}
917+
});
918+
919+
uvu.test(`${fn.name} includes value and root on symbolic keys error`, () => {
920+
const symbolKey = Symbol('key');
921+
const root = { [symbolKey]: 'value' };
922+
try {
923+
fn(root);
924+
} catch (e) {
925+
assert.equal(e.name, 'DevalueError');
926+
assert.equal(e.message, 'Cannot stringify POJOs with symbolic keys');
927+
assert.equal(e.value, root);
928+
assert.equal(e.root, root);
929+
}
930+
});
870931
}
871932

872933
uvu.test('does not create duplicate parameter names', () => {

0 commit comments

Comments
 (0)