Skip to content

Commit e928a52

Browse files
authored
Merge pull request #43 from haines/syntax-errors
Throw syntax errors when parsing invalid input
2 parents bd87340 + 57126da commit e928a52

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

src/parse.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,26 @@ import {
1414
export function parse(serialized) {
1515
const parsed = JSON.parse(serialized);
1616

17-
if (typeof parsed === 'number') return hydrate(parsed);
17+
if (typeof parsed === 'number') return hydrate(parsed, true);
18+
19+
if (!Array.isArray(parsed) || parsed.length === 0) {
20+
throw new Error('Invalid input');
21+
}
1822

1923
const values = /** @type {any[]} */ (parsed);
24+
2025
const hydrated = Array(values.length);
2126

2227
/** @param {number} index */
23-
function hydrate(index) {
28+
function hydrate(index, standalone = false) {
2429
if (index === UNDEFINED) return undefined;
2530
if (index === NAN) return NaN;
2631
if (index === POSITIVE_INFINITY) return Infinity;
2732
if (index === NEGATIVE_INFINITY) return -Infinity;
2833
if (index === NEGATIVE_ZERO) return -0;
2934

35+
if (standalone) throw new Error(`Invalid input`);
36+
3037
if (index in hydrated) return hydrated[index];
3138

3239
const value = values[index];

test/test.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,63 @@ for (const [name, tests] of Object.entries(fixtures)) {
406406
test.run();
407407
}
408408

409+
const invalid = [
410+
{
411+
name: 'empty string',
412+
json: '',
413+
message: 'Unexpected end of JSON input'
414+
},
415+
{
416+
name: 'invalid JSON',
417+
json: '][',
418+
message: 'Unexpected token ] in JSON at position 0'
419+
},
420+
{
421+
name: 'hole',
422+
json: '-2',
423+
message: 'Invalid input'
424+
},
425+
{
426+
name: 'string',
427+
json: '"hello"',
428+
message: 'Invalid input'
429+
},
430+
{
431+
name: 'number',
432+
json: '42',
433+
message: 'Invalid input'
434+
},
435+
{
436+
name: 'boolean',
437+
json: 'true',
438+
message: 'Invalid input'
439+
},
440+
{
441+
name: 'null',
442+
json: 'null',
443+
message: 'Invalid input'
444+
},
445+
{
446+
name: 'object',
447+
json: '{}',
448+
message: 'Invalid input'
449+
},
450+
{
451+
name: 'empty array',
452+
json: '[]',
453+
message: 'Invalid input'
454+
}
455+
];
456+
457+
for (const { name, json, message } of invalid) {
458+
uvu.test(`parse error: ${name}`, () => {
459+
assert.throws(
460+
() => parse(json),
461+
(error) => error.message === message
462+
);
463+
});
464+
}
465+
409466
for (const fn of [uneval, stringify]) {
410467
uvu.test(`${fn.name} throws for non-POJOs`, () => {
411468
class Foo {}

0 commit comments

Comments
 (0)