diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f421f0..2edff8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4724a8a..ba98edd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # devalue changelog +## 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)) diff --git a/README.md b/README.md index 9e38635..f1cb41e 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,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 { diff --git a/package.json b/package.json index cf3aeb1..1f43014 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "devalue", "description": "Gets the job done when JSON.stringify can't", - "version": "4.3.2", + "version": "4.3.3", "repository": "Rich-Harris/devalue", "exports": { ".": { @@ -30,4 +30,4 @@ "license": "MIT", "type": "module", "packageManager": "pnpm@8.5.1" -} \ No newline at end of file +} diff --git a/src/stringify.js b/src/stringify.js index 8ce427e..d4c562b 100644 --- a/src/stringify.js +++ b/src/stringify.js @@ -81,7 +81,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': @@ -128,6 +129,7 @@ export function stringify(value, reducers) { `.get(${is_primitive(key) ? stringify_primitive(key) : '...'})` ); str += `,${flatten(key)},${flatten(value)}`; + keys.pop(); } str += ']'; diff --git a/test/test.js b/test/test.js index afe3557..d4089e7 100644 --- a/test/test.js +++ b/test/test.js @@ -9,6 +9,8 @@ class Custom { } } +const node_version = +process.versions.node.split('.')[0]; + const fixtures = { basics: [ { @@ -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'], @@ -475,7 +486,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', @@ -518,7 +532,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; + } ); }); } @@ -560,6 +580,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', () => {