Better error JSON errors

pull/251/head
Anton Medvedev 1 year ago
parent ef426202ab
commit 5824c3c1f6
No known key found for this signature in database

@ -157,22 +157,12 @@ function sleepSync(ms) {
}
function* parseJson(stdin) {
let pos = 0, buffer = '', lastChar, done = false
let lineNumber = 1, buffer = '', lastChar, done = false
function next() {
({value: lastChar, done} = stdin.next())
pos++
buffer = buffer.slice(-10) + lastChar
}
function errorSnippet() {
let nextChars = ''
for (let i = 0; i < 10; i++) {
const {value: ch} = stdin.next()
if (ch === '\n') break
nextChars += ch || ''
}
return `\n\n ${buffer}${nextChars}\n ${'.'.repeat(buffer.length - 1)}^\n`
if (lastChar === '\n') lineNumber++
buffer = buffer.slice(-40) + (lastChar || '')
}
next()
@ -208,7 +198,7 @@ function* parseJson(stdin) {
for (let i = 0; i < 4; i++) {
next()
if (!isHexDigit(lastChar)) {
throw new SyntaxError(`Invalid Unicode escape sequence '\\u${unicode}${lastChar}' at position ${pos}`)
throw new SyntaxError(errorSnippet(`Invalid Unicode escape sequence '\\u${unicode}${lastChar}'`))
}
unicode += lastChar
}
@ -225,7 +215,7 @@ function* parseJson(stdin) {
't': '\t'
}[lastChar]
if (!escapedChar) {
throw new SyntaxError(`Invalid escape sequence '\\${lastChar}' at position ${pos}`)
throw new SyntaxError(errorSnippet())
}
str += escapedChar
}
@ -235,7 +225,7 @@ function* parseJson(stdin) {
} else if (lastChar === '"') {
break
} else if (lastChar === undefined) {
throw new SyntaxError(`Unterminated string literal at position ${pos}`)
throw new SyntaxError(errorSnippet())
} else {
str += lastChar
}
@ -251,7 +241,7 @@ function* parseJson(stdin) {
numStr += lastChar
next()
if (!isDigit(lastChar)) {
throw new SyntaxError(`Invalid number format at position ${pos}.`)
throw new SyntaxError(errorSnippet())
}
}
if (lastChar === '0') {
@ -267,7 +257,7 @@ function* parseJson(stdin) {
numStr += lastChar
next()
if (!isDigit(lastChar)) {
throw new SyntaxError(`Invalid number format at position ${pos}.`)
throw new SyntaxError(errorSnippet())
}
while (isDigit(lastChar)) {
numStr += lastChar
@ -282,7 +272,7 @@ function* parseJson(stdin) {
next()
}
if (!isDigit(lastChar)) {
throw new SyntaxError(`Invalid number format at position ${pos}.`)
throw new SyntaxError(errorSnippet())
}
while (isDigit(lastChar)) {
numStr += lastChar
@ -308,7 +298,7 @@ function* parseJson(stdin) {
const key = parseString()
skipWhitespace()
if (lastChar !== ':') {
throw new SyntaxError(`Unexpected character '${lastChar}' at position ${pos}. Expected ':'.`)
throw new SyntaxError(errorSnippet())
}
next()
const value = parseValue()
@ -322,7 +312,7 @@ function* parseJson(stdin) {
next()
skipWhitespace()
} else {
throw new SyntaxError(`Unexpected character '${lastChar}' at position ${pos}. Expected ',' or '}'.`)
throw new SyntaxError(errorSnippet())
}
}
}
@ -348,7 +338,7 @@ function* parseJson(stdin) {
next()
skipWhitespace()
} else {
throw new SyntaxError(`Unexpected character '${lastChar}' at position ${pos}. Expected ',' or ']'.`)
throw new SyntaxError(errorSnippet())
}
}
}
@ -358,14 +348,14 @@ function* parseJson(stdin) {
for (let i = 1; i < name.length; i++) {
next()
if (lastChar !== name[i]) {
throw new SyntaxError(`Unexpected character '${lastChar}' at position ${pos}.`)
throw new SyntaxError(errorSnippet())
}
}
next()
if (isWhitespace(lastChar) || lastChar === ',' || lastChar === '}' || lastChar === ']' || lastChar === undefined) {
return value
}
throw new SyntaxError(`Unexpected character '${lastChar}' at position ${pos}.`)
throw new SyntaxError(errorSnippet())
}
function skipWhitespace() {
@ -399,8 +389,30 @@ function* parseJson(stdin) {
function expectValue(value) {
if (value === undefined) {
throw new SyntaxError(`JSON value expected but got '${value}' at position ${pos}. ${errorSnippet()}`)
throw new SyntaxError(errorSnippet(`JSON value expected`))
}
}
function errorSnippet(message = `Unexpected character '${lastChar}'`) {
if (!lastChar) {
message = 'Unexpected end of input'
}
const lines = buffer.split('\n')
const lastLine = lines.pop()
const source =
lines.map(line => ` ${line}\n`).join('')
+ ` ${lastLine}${readEOL()}\n`
const p = ` ${'.'.repeat(Math.max(0, lastLine.length - 1))}^\n`
return `${message} on line ${lineNumber}.\n\n${source}${p}`
}
function readEOL() {
let line = ''
for (const ch of stdin) {
if (!ch || ch === '\n' || line.length >= 60) break
line += ch
}
return line
}
}

@ -12,7 +12,7 @@
},
"repository": "antonmedv/fx",
"homepage": "https://fx.wtf",
"description": Command-line JSON viewer",
"description": "Command-line JSON viewer",
"author": "Anton Medvedev <anton@medv.io>",
"license": "MIT"
}

Loading…
Cancel
Save