Skip to content

Commit

Permalink
Merge branch 'main' into pr/69
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Sep 25, 2024
2 parents 4a2b8ca + 566b961 commit a4fe876
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [16]
node-version: [16, 18, 20]
os: [ubuntu-latest]
steps:
- run: git config --global core.autocrlf false
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# devalue changelog

## 5.0.0

- Ignore non-enumerable symbolic keys ([#78](https://github.com/Rich-Harris/devalue/pull/78))

## 4.3.3

- Support invalid dates ([#61](https://github.com/Rich-Harris/devalue/pull/61))
- Fix incorrect `error.path` when object contains a map ([#64](https://github.com/Rich-Harris/devalue/pull/64))

## 4.3.2

- Better type declarations ([#66](https://github.com/Rich-Harris/devalue/pull/66))
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const data = devalue.unflatten(JSON.parse(json).data);

## Custom types

You can serialize and serialize custom types by passing a second argument to `stringify` containing an object of types and their _reducers_, and a second argument to `parse` or `unflatten` containing an object of types and their _revivers_:
You can serialize and deserialize custom types by passing a second argument to `stringify` containing an object of types and their _reducers_, and a second argument to `parse` or `unflatten` containing an object of types and their _revivers_:

```js
class Vector {
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"name": "devalue",
"description": "Gets the job done when JSON.stringify can't",
"version": "4.3.2",
"version": "5.0.0",
"repository": "Rich-Harris/devalue",
"sideEffects": false,
"exports": {
".": {
"types": "./types/index.d.ts",
Expand All @@ -25,9 +26,9 @@
"scripts": {
"build": "dts-buddy",
"test": "uvu test",
"prepublishOnly": "npm test && publint && npm run build"
"prepublishOnly": "npm test && npm run build && publint"
},
"license": "MIT",
"type": "module",
"packageManager": "[email protected]"
}
}
7 changes: 5 additions & 2 deletions src/stringify.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
DevalueError,
enumerable_symbols,
get_type,
is_plain_object,
is_primitive,
Expand Down Expand Up @@ -82,7 +83,8 @@ export function stringify(value, reducers) {
break;

case 'Date':
str = `["Date","${thing.toISOString()}"]`;
const valid = !isNaN(thing.getDate());
str = `["Date","${valid ? thing.toISOString() : ''}"]`;
break;

case 'RegExp':
Expand Down Expand Up @@ -129,6 +131,7 @@ export function stringify(value, reducers) {
`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`
);
str += `,${flatten(key)},${flatten(value)}`;
keys.pop();
}

str += ']';
Expand Down Expand Up @@ -169,7 +172,7 @@ export function stringify(value, reducers) {
);
}

if (Object.getOwnPropertySymbols(thing).length > 0) {
if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(
`Cannot stringify POJOs with symbolic keys`,
keys
Expand Down
3 changes: 2 additions & 1 deletion src/uneval.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
DevalueError,
enumerable_symbols,
escaped,
get_type,
is_plain_object,
Expand Down Expand Up @@ -105,7 +106,7 @@ export function uneval(value, replacer) {
);
}

if (Object.getOwnPropertySymbols(thing).length > 0) {
if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(
`Cannot stringify POJOs with symbolic keys`,
keys
Expand Down
7 changes: 7 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,10 @@ export function stringify_string(str) {

return `"${last_pos === 0 ? str : result + str.slice(last_pos)}"`;
}

/** @param {Record<string | symbol, any>} object */
export function enumerable_symbols(object) {
return Object.getOwnPropertySymbols(object).filter(
(symbol) => Object.getOwnPropertyDescriptor(object, symbol).enumerable
);
}
52 changes: 50 additions & 2 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Custom {
}
}

const node_version = +process.versions.node.split('.')[0];

const fixtures = {
basics: [
{
Expand Down Expand Up @@ -107,6 +109,15 @@ const fixtures = {
js: 'new Date(1000000000000)',
json: '[["Date","2001-09-09T01:46:40.000Z"]]'
},
{
name: 'invalid Date',
value: new Date(''),
js: 'new Date(NaN)',
json: '[["Date",""]]',
validate: (value) => {
assert.ok(isNaN(value.valueOf()));
}
},
{
name: 'Array',
value: ['a', 'b', 'c'],
Expand Down Expand Up @@ -391,6 +402,19 @@ const fixtures = {
assert.equal(Object.getPrototypeOf(value), Object.prototype);
assert.equal(Object.keys(value).length, 0);
}
},
{
name: 'non-enumerable symbolic key',
value: (() => {
const obj = { x: 1 };
Object.defineProperty(obj, Symbol('key'), {
value: 'value',
enumerable: false
});
return obj;
})(),
js: '{x:1}',
json: '[{"x":1},1]'
}
],

Expand Down Expand Up @@ -487,7 +511,10 @@ const invalid = [
{
name: 'invalid JSON',
json: '][',
message: 'Unexpected token ] in JSON at position 0'
message:
node_version >= 20
? `Unexpected token ']', "][" is not valid JSON`
: 'Unexpected token ] in JSON at position 0'
},
{
name: 'hole',
Expand Down Expand Up @@ -530,7 +557,13 @@ for (const { name, json, message } of invalid) {
uvu.test(`parse error: ${name}`, () => {
assert.throws(
() => parse(json),
(error) => error.message === message
(error) => {
const match = error.message === message;
if (!match) {
console.error(`Expected: ${message}, got: ${error.message}`);
}
return match;
}
);
});
}
Expand Down Expand Up @@ -572,6 +605,21 @@ for (const fn of [uneval, stringify]) {
assert.equal(e.path, '.foo.map.get("key")');
}
});

uvu.test(`${fn.name} populates error.path after maps (#64)`, () => {
try {
fn({
map: new Map([['key', 'value']]),
object: {
invalid() {}
}
});
} catch (e) {
assert.equal(e.name, 'DevalueError');
assert.equal(e.message, 'Cannot stringify a function');
assert.equal(e.path, '.object.invalid');
}
});
}

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

0 comments on commit a4fe876

Please sign in to comment.