Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lovely-sheep-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"devalue": minor
---

feat: expose `DevalueError` for `instanceof` checks in `catch` clauses
5 changes: 5 additions & 0 deletions .changeset/odd-areas-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"devalue": minor
---

feat: add `value` and `root` properties in `DevalueError` instances
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { uneval } from './src/uneval.js';
export { parse, unflatten } from './src/parse.js';
export { stringify } from './src/stringify.js';
export { DevalueError } from './src/utils.js';
10 changes: 7 additions & 3 deletions src/stringify.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function stringify(value, reducers) {
}

if (typeof thing === 'function') {
throw new DevalueError(`Cannot stringify a function`, keys);
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
}

let str = '';
Expand Down Expand Up @@ -200,14 +200,18 @@ export function stringify(value, reducers) {
if (!is_plain_object(thing)) {
throw new DevalueError(
`Cannot stringify arbitrary non-POJOs`,
keys
keys,
thing,
value
);
}

if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(
`Cannot stringify POJOs with symbolic keys`,
keys
keys,
thing,
value
);
}

Expand Down
10 changes: 7 additions & 3 deletions src/uneval.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function uneval(value, replacer) {
}

if (typeof thing === 'function') {
throw new DevalueError(`Cannot stringify a function`, keys);
throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
}

const type = get_type(thing);
Expand Down Expand Up @@ -116,14 +116,18 @@ export function uneval(value, replacer) {
if (!is_plain_object(thing)) {
throw new DevalueError(
`Cannot stringify arbitrary non-POJOs`,
keys
keys,
thing,
value
);
}

if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(
`Cannot stringify POJOs with symbolic keys`,
keys
keys,
thing,
value
);
}

Expand Down
6 changes: 5 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ export class DevalueError extends Error {
/**
* @param {string} message
* @param {string[]} keys
* @param {any} [value] - The value that failed to be serialized
* @param {any} [root] - The root value being serialized
*/
constructor(message, keys) {
constructor(message, keys, value, root) {
super(message);
this.name = 'DevalueError';
this.path = keys.join('');
this.value = value;
this.root = root;
}
}

Expand Down
61 changes: 61 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,67 @@ for (const fn of [uneval, stringify]) {
assert.equal(e.path, '.object.invalid');
}
});

uvu.test(`${fn.name} populates error.value with the problematic value`, () => {
const testFn = function invalid() {};
try {
fn({
foo: {
array: [testFn]
}
});
} catch (e) {
assert.equal(e.name, 'DevalueError');
assert.equal(e.message, 'Cannot stringify a function');
assert.equal(e.value, testFn);
}
});

uvu.test(`${fn.name} populates error.root with the root value`, () => {
const root = {
foo: {
array: [function invalid() {}]
}
};
try {
fn(root);
} catch (e) {
assert.equal(e.name, 'DevalueError');
assert.equal(e.message, 'Cannot stringify a function');
assert.equal(e.root, root);
}
});

uvu.test(`${fn.name} includes value and root on arbitrary non-POJOs error`, () => {
class Whatever {}
const problematicValue = new Whatever();
const root = {
foo: {
['string-key']: new Map([['key', problematicValue]])
}
};
try {
fn(root);
} catch (e) {
assert.equal(e.name, 'DevalueError');
assert.equal(e.message, 'Cannot stringify arbitrary non-POJOs');
assert.equal(e.value, problematicValue);
assert.equal(e.root, root);
}
});

uvu.test(`${fn.name} includes value and root on symbolic keys error`, () => {
const symbolKey = Symbol('key');
const root = { [symbolKey]: 'value' };
try {
fn(root);
} catch (e) {
assert.equal(e.name, 'DevalueError');
assert.equal(e.message, 'Cannot stringify POJOs with symbolic keys');
assert.equal(e.value, root);
assert.equal(e.root, root);
}
});
}

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