177 lines
4.3 KiB
TypeScript
177 lines
4.3 KiB
TypeScript
|
const rxParseJson = /position\s(\d+)$/
|
||
|
|
||
|
export function parseJson(s: string, pos: number): unknown {
|
||
|
let endPos: number | undefined
|
||
|
parseJson.message = undefined
|
||
|
let matches: RegExpExecArray | null
|
||
|
if (pos) s = s.slice(pos)
|
||
|
try {
|
||
|
parseJson.position = pos + s.length
|
||
|
return JSON.parse(s)
|
||
|
} catch (e) {
|
||
|
matches = rxParseJson.exec((e as Error).message)
|
||
|
if (!matches) {
|
||
|
parseJson.message = "unexpected end"
|
||
|
return undefined
|
||
|
}
|
||
|
endPos = +matches[1]
|
||
|
const c = s[endPos]
|
||
|
s = s.slice(0, endPos)
|
||
|
parseJson.position = pos + endPos
|
||
|
try {
|
||
|
return JSON.parse(s)
|
||
|
} catch (e1) {
|
||
|
parseJson.message = `unexpected token ${c}`
|
||
|
return undefined
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
parseJson.message = undefined as string | undefined
|
||
|
parseJson.position = 0 as number
|
||
|
parseJson.code = 'require("ajv/dist/runtime/parseJson").parseJson'
|
||
|
|
||
|
export function parseJsonNumber(s: string, pos: number, maxDigits?: number): number | undefined {
|
||
|
let numStr = ""
|
||
|
let c: string
|
||
|
parseJsonNumber.message = undefined
|
||
|
if (s[pos] === "-") {
|
||
|
numStr += "-"
|
||
|
pos++
|
||
|
}
|
||
|
if (s[pos] === "0") {
|
||
|
numStr += "0"
|
||
|
pos++
|
||
|
} else {
|
||
|
if (!parseDigits(maxDigits)) {
|
||
|
errorMessage()
|
||
|
return undefined
|
||
|
}
|
||
|
}
|
||
|
if (maxDigits) {
|
||
|
parseJsonNumber.position = pos
|
||
|
return +numStr
|
||
|
}
|
||
|
if (s[pos] === ".") {
|
||
|
numStr += "."
|
||
|
pos++
|
||
|
if (!parseDigits()) {
|
||
|
errorMessage()
|
||
|
return undefined
|
||
|
}
|
||
|
}
|
||
|
if (((c = s[pos]), c === "e" || c === "E")) {
|
||
|
numStr += "e"
|
||
|
pos++
|
||
|
if (((c = s[pos]), c === "+" || c === "-")) {
|
||
|
numStr += c
|
||
|
pos++
|
||
|
}
|
||
|
if (!parseDigits()) {
|
||
|
errorMessage()
|
||
|
return undefined
|
||
|
}
|
||
|
}
|
||
|
parseJsonNumber.position = pos
|
||
|
return +numStr
|
||
|
|
||
|
function parseDigits(maxLen?: number): boolean {
|
||
|
let digit = false
|
||
|
while (((c = s[pos]), c >= "0" && c <= "9" && (maxLen === undefined || maxLen-- > 0))) {
|
||
|
digit = true
|
||
|
numStr += c
|
||
|
pos++
|
||
|
}
|
||
|
return digit
|
||
|
}
|
||
|
|
||
|
function errorMessage(): void {
|
||
|
parseJsonNumber.position = pos
|
||
|
parseJsonNumber.message = pos < s.length ? `unexpected token ${s[pos]}` : "unexpected end"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
parseJsonNumber.message = undefined as string | undefined
|
||
|
parseJsonNumber.position = 0 as number
|
||
|
parseJsonNumber.code = 'require("ajv/dist/runtime/parseJson").parseJsonNumber'
|
||
|
|
||
|
const escapedChars: {[X in string]?: string} = {
|
||
|
b: "\b",
|
||
|
f: "\f",
|
||
|
n: "\n",
|
||
|
r: "\r",
|
||
|
t: "\t",
|
||
|
'"': '"',
|
||
|
"/": "/",
|
||
|
"\\": "\\",
|
||
|
}
|
||
|
|
||
|
const CODE_A: number = "a".charCodeAt(0)
|
||
|
const CODE_0: number = "0".charCodeAt(0)
|
||
|
|
||
|
export function parseJsonString(s: string, pos: number): string | undefined {
|
||
|
let str = ""
|
||
|
let c: string | undefined
|
||
|
parseJsonString.message = undefined
|
||
|
// eslint-disable-next-line no-constant-condition, @typescript-eslint/no-unnecessary-condition
|
||
|
while (true) {
|
||
|
c = s[pos++]
|
||
|
if (c === '"') break
|
||
|
if (c === "\\") {
|
||
|
c = s[pos]
|
||
|
if (c in escapedChars) {
|
||
|
str += escapedChars[c]
|
||
|
pos++
|
||
|
} else if (c === "u") {
|
||
|
pos++
|
||
|
let count = 4
|
||
|
let code = 0
|
||
|
while (count--) {
|
||
|
code <<= 4
|
||
|
c = s[pos]
|
||
|
if (c === undefined) {
|
||
|
errorMessage("unexpected end")
|
||
|
return undefined
|
||
|
}
|
||
|
c = c.toLowerCase()
|
||
|
if (c >= "a" && c <= "f") {
|
||
|
code += c.charCodeAt(0) - CODE_A + 10
|
||
|
} else if (c >= "0" && c <= "9") {
|
||
|
code += c.charCodeAt(0) - CODE_0
|
||
|
} else {
|
||
|
errorMessage(`unexpected token ${c}`)
|
||
|
return undefined
|
||
|
}
|
||
|
pos++
|
||
|
}
|
||
|
str += String.fromCharCode(code)
|
||
|
} else {
|
||
|
errorMessage(`unexpected token ${c}`)
|
||
|
return undefined
|
||
|
}
|
||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||
|
} else if (c === undefined) {
|
||
|
errorMessage("unexpected end")
|
||
|
return undefined
|
||
|
} else {
|
||
|
if (c.charCodeAt(0) >= 0x20) {
|
||
|
str += c
|
||
|
} else {
|
||
|
errorMessage(`unexpected token ${c}`)
|
||
|
return undefined
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
parseJsonString.position = pos
|
||
|
return str
|
||
|
|
||
|
function errorMessage(msg: string): void {
|
||
|
parseJsonString.position = pos
|
||
|
parseJsonString.message = msg
|
||
|
}
|
||
|
}
|
||
|
|
||
|
parseJsonString.message = undefined as string | undefined
|
||
|
parseJsonString.position = 0 as number
|
||
|
parseJsonString.code = 'require("ajv/dist/runtime/parseJson").parseJsonString'
|