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'