diff --git a/index.js b/index.js index c707549..77ce865 100644 --- a/index.js +++ b/index.js @@ -43,13 +43,21 @@ const getErrorLocation = (string, message) => { return; } - const {index, line, column} = match.groups; + let {index, line, column} = match.groups; if (line && column) { return {line: Number(line), column: Number(column)}; } - return indexToPosition(string, Number(index), {oneBased: true}); + index = Number(index); + + // The error location can be out of bounds. + if (index === string.length) { + const {line, column} = indexToPosition(string, string.length - 1, {oneBased: true}); + return {line, column: column + 1}; + } + + return indexToPosition(string, index, {oneBased: true}); }; export default function parseJson(string, reviver, filename) { diff --git a/test.js b/test.js index 208c77c..fff1022 100644 --- a/test.js +++ b/test.js @@ -4,14 +4,14 @@ import {outdent} from 'outdent'; import stripAnsi from 'strip-ansi'; import parseJson, {JSONError} from './index.js'; -const errorMessageRegex = (() => { - const version = Number(process.versions.node.split('.')[0]); +const NODE_JS_VERSION = Number(process.versions.node.split('.')[0]); - if (version < 20) { +const errorMessageRegex = (() => { + if (NODE_JS_VERSION < 20) { return /Unexpected token "}"/; } - if (version < 21) { + if (NODE_JS_VERSION < 21) { return /Expected double-quoted property name in JSON at position 16 while parsing/; } @@ -85,3 +85,24 @@ test('has error frame properties', t => { t.is(stripAnsi(error.codeFrame), EXPECTED_CODE_FRAME); } }); + +test('allow error location out of bounds', t => { + try { + parseJson('{'); + } catch (error) { + t.true(error instanceof JSONError); + t.is(error.rawCodeFrame, NODE_JS_VERSION === 18 ? undefined : outdent` + > 1 | { + | ^ + `); + } +}); + +test('empty string', t => { + try { + parseJson(''); + } catch (error) { + t.true(error instanceof JSONError); + t.is(error.rawCodeFrame, undefined); + } +});