@willbooster/shared-lib 10.16.1 → 10.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.cjs +2 -0
- package/dist/array.cjs.map +1 -0
- package/dist/array.d.ts +2 -0
- package/dist/array.js +2 -0
- package/dist/array.js.map +1 -0
- package/dist/concurrency.cjs +1 -1
- package/dist/concurrency.cjs.map +1 -1
- package/dist/concurrency.d.ts +5 -1
- package/dist/concurrency.js +1 -1
- package/dist/concurrency.js.map +1 -1
- package/dist/error.cjs +2 -2
- package/dist/error.cjs.map +1 -1
- package/dist/error.d.ts +9 -0
- package/dist/error.js +2 -2
- package/dist/error.js.map +1 -1
- package/dist/filePath.cjs +2 -0
- package/dist/filePath.cjs.map +1 -0
- package/dist/filePath.d.ts +5 -0
- package/dist/filePath.js +2 -0
- package/dist/filePath.js.map +1 -0
- package/dist/foreignCjk.cjs +1 -1
- package/dist/foreignCjk.cjs.map +1 -1
- package/dist/foreignCjk.js +1 -1
- package/dist/foreignCjk.js.map +1 -1
- package/dist/formatIsoDate.cjs +2 -0
- package/dist/formatIsoDate.cjs.map +1 -0
- package/dist/formatIsoDate.d.ts +7 -0
- package/dist/formatIsoDate.js +2 -0
- package/dist/formatIsoDate.js.map +1 -0
- package/dist/github.cjs +2 -0
- package/dist/github.cjs.map +1 -0
- package/dist/github.d.ts +8 -0
- package/dist/github.js +2 -0
- package/dist/github.js.map +1 -0
- package/dist/http.cjs +2 -0
- package/dist/http.cjs.map +1 -0
- package/dist/http.d.ts +7 -0
- package/dist/http.js +2 -0
- package/dist/http.js.map +1 -0
- package/dist/humanize.cjs +1 -1
- package/dist/humanize.cjs.map +1 -1
- package/dist/humanize.d.ts +5 -0
- package/dist/humanize.js +1 -1
- package/dist/humanize.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.js +1 -1
- package/dist/markdown.cjs +1 -1
- package/dist/markdown.cjs.map +1 -1
- package/dist/markdown.js +1 -1
- package/dist/markdown.js.map +1 -1
- package/dist/number.cjs +2 -0
- package/dist/number.cjs.map +1 -0
- package/dist/number.d.ts +7 -0
- package/dist/number.js +2 -0
- package/dist/number.js.map +1 -0
- package/dist/object.cjs +2 -0
- package/dist/object.cjs.map +1 -0
- package/dist/object.d.ts +16 -0
- package/dist/object.js +2 -0
- package/dist/object.js.map +1 -0
- package/dist/parseIsoDate.cjs +1 -1
- package/dist/parseIsoDate.cjs.map +1 -1
- package/dist/parseIsoDate.js +1 -1
- package/dist/parseIsoDate.js.map +1 -1
- package/dist/prompt.cjs +2 -2
- package/dist/prompt.cjs.map +1 -1
- package/dist/prompt.js +10 -10
- package/dist/prompt.js.map +1 -1
- package/dist/promptFormatters.cjs +1 -1
- package/dist/promptFormatters.cjs.map +1 -1
- package/dist/promptFormatters.js +1 -1
- package/dist/promptFormatters.js.map +1 -1
- package/dist/recoverJson.cjs +2 -2
- package/dist/recoverJson.cjs.map +1 -1
- package/dist/recoverJson.js +2 -1
- package/dist/recoverJson.js.map +1 -1
- package/dist/sqlite.cjs +1 -1
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.ts +7 -0
- package/dist/sqlite.js +1 -1
- package/dist/sqlite.js.map +1 -1
- package/dist/text.cjs +1 -1
- package/dist/text.cjs.map +1 -1
- package/dist/text.d.ts +12 -0
- package/dist/text.js +1 -1
- package/dist/text.js.map +1 -1
- package/dist/timeout.cjs +2 -0
- package/dist/timeout.cjs.map +1 -0
- package/dist/timeout.d.ts +12 -0
- package/dist/timeout.js +2 -0
- package/dist/timeout.js.map +1 -0
- package/dist/yaml.cjs +2 -0
- package/dist/yaml.cjs.map +1 -0
- package/dist/yaml.d.ts +8 -0
- package/dist/yaml.js +2 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +3 -3
package/dist/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","names":[],"sources":["../src/prompt.ts"],"sourcesContent":["import { escapeRegExp, toTildeCodeBlock } from './text.js';\n\nconst INDENT_STEP = ' ';\nconst MAX_IMPLICIT_KEY_LENGTH = 1024;\nconst MIN_MULTI_LINE_DOUBLE_QUOTED_LENGTH = 40;\n\n/** Strings matching this would be read back as a non-string scalar (null, bool, int, or float), so they must be quoted. */\nconst NON_STRING_SCALAR =\n /^(?:~|[Nn]ull|NULL|[Tt]rue|TRUE|[Ff]alse|FALSE|0o[0-7]+|[-+]?[0-9]+|0x[0-9a-fA-F]+|[-+]?\\.(?:inf|Inf|INF)|\\.nan|\\.NaN|\\.NAN|[-+]?(?:\\.[0-9]+|[0-9]+(?:\\.[0-9]*)?)[eE][-+]?[0-9]+|[-+]?(?:\\.[0-9]+|[0-9]+\\.[0-9]*))?$/u;\n\n// A single-line string must be quoted if it matches any of these. Checking the start, the middle, and the end separately\n// is much faster on long strings than one regex whose anchored alternatives are retried at every position.\nconst UNSAFE_PLAIN_START = /^(?:[\\t ,[\\]{}#&*!|>'\"%@`]|[?-](?:[ \\t]|$))/u;\nconst UNSAFE_PLAIN_MIDDLE = /:[ \\t]|[ \\t]#/u;\nconst UNSAFE_PLAIN_END = /[\\t :]$/u;\n\nconst SHORT_UNICODE_ESCAPES: Record<string, string> = {\n '0000': String.raw`\\0`,\n '0007': String.raw`\\a`,\n '000b': String.raw`\\v`,\n '001b': String.raw`\\e`,\n};\n\ninterface Context {\n indent: string;\n implicitKey?: boolean;\n tagPatterns?: readonly RegExp[];\n}\n\n/**\n * Serializes data into a code block to embed in an LLM prompt, so that the LLM can read its contents.\n * Accepts JSON data (honoring `toJSON` such as that of `Date`) as well as `undefined`, `NaN`, `Infinity`, bigints,\n * `Map`s (including non-string keys), `Set`s and other iterables, `Error`s (with their name, message, cause, and own properties),\n * and `RegExp`s. Symbols and functions without `toJSON` throw. The output is not meant to be deserialized back into the original value.\n * The format inside the code block is an implementation detail and may change.\n */\nexport function serializeForPrompt(value: unknown): string {\n return toTildeCodeBlock(`${stringifyValue(toSerializable(value), { indent: '' })}\\n`, 'yaml');\n}\n\n/**\n * Serializes data with `serializeForPrompt` for embedding inside a `<tagName>` element of a prompt, escaping that tag\n * in every string so that untrusted data cannot close the element and have the rest read as instructions.\n * The caller must wrap the result in the same tag.\n *\n * Only the named elements are protected, so a block nested inside other tagged elements takes every enclosing name.\n * Escaping the finished block instead is not an option: it would turn a plain scalar holding the escaped notation\n * into a YAML flow sequence, since the quoting of each scalar is decided as it is written.\n *\n * The escaped notation is the one `escapePromptTag` writes, and text that already holds it is left as it is, so two\n * strings differing only in that notation are written alike. Keys taken from untrusted data can therefore collide\n * into one duplicate key of the emitted mapping.\n */\nexport function serializeForPromptInTag(value: unknown, tagName: string | readonly string[]): string {\n const escapedTags = typeof tagName === 'string' ? [tagName] : tagName;\n const tagPatterns = escapedTags.flatMap(createTagPatterns);\n return toTildeCodeBlock(`${stringifyValue(toSerializable(value), { indent: '', tagPatterns })}\\n`, 'yaml');\n}\n\n/**\n * Replaces `<tagName` and `</tagName` not followed by `[\\w-]` with a harmless notation such as `[/tagName]`, so that\n * data embedded in a `<tagName>` element of a prompt cannot close the element and have the rest read as instructions.\n * A closing `>` is not required, since an HTML reader also closes an element on a tag carrying attribute-like junk,\n * on a trailing solidus, or on the next `>` anywhere in the prompt; the whitespace between `<` and the name is\n * dropped along with the brackets. Case is ignored deliberately: `tagName` is expected to be a literal written by\n * the caller, while the data is not.\n */\nexport function escapePromptTag(text: string, tagName: string): string {\n return text.includes('<') ? escapeTags(text, createTagPatterns(tagName)) : text;\n}\n\nfunction createTagPatterns(tagName: string): RegExp[] {\n const name = escapeRegExp(tagName);\n // Keep well-formed tags readable while also catching incomplete and malformed tags.\n return [\n new RegExp(`<\\\\s*(?:(/)\\\\s*)?(${name})\\\\s*>`, 'giu'),\n new RegExp(`<\\\\s*(?:(/)\\\\s*)?(${name})(?![\\\\w-])`, 'giu'),\n ];\n}\n\nfunction escapeTags(text: string, patterns: readonly RegExp[]): string {\n if (!text.includes('<')) return text;\n for (const pattern of patterns) text = text.replaceAll(pattern, '[$1$2]');\n return text;\n}\n\n/** The line opening a fenced block, with the indentation an interpolation may put before it. */\nconst BLOCK_OPENER = /^[ \\t]*((`{3,}|~{3,})[^\\n]*)$/u;\n\n/** A block interpolated after other text on its line, which no rule can tell from prose that ends in `~~~yaml`. */\nconst MISPLACED_BLOCK_OPENER = /[^\\s~][ \\t]*~{3,}yaml[ \\t]*$/u;\n\ninterface PromptBlock {\n opener: string;\n end: number;\n}\n\n/**\n * Strips template-literal indentation from Markdown headings, code fences, and triple-quote delimiters (`\"\"\"` and\n * `'''`), and collapses blank lines.\n * The contents of a fenced block are left untouched, since reindenting them would rewrite the data they carry, such\n * as the YAML of `serializeForPrompt` or the source of `toCodeBlock`. Every fenced block must be interpolated at\n * the start of a line. Only recognizable mid-line `~~~yaml` markers throw, including prose mentions;\n * this is not a complete placement validator, since preceding tildes can merge into an indistinguishable fence.\n * Blocks end at the first compatible same-character fence, which may carry trailing prose, unless a longer fence\n * of the same character opens and contains that candidate closing line. Other fence characters have no nesting\n * significance. Balance authored fences before interpolating blocks: an unmatched sample can consume part of a\n * later block and leave its tail subject to prose formatting.\n */\nexport function formatPrompt(prompt: string): string {\n const lines = prompt.split('\\n');\n const blocks = findBlocks(lines);\n let formatted = '';\n let prose = '';\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index] ?? '';\n const block = blocks[index];\n if (block === undefined) {\n // An opening fence the prompt itself writes and never closes is prose, and so is every line inside a block.\n if (MISPLACED_BLOCK_OPENER.test(line)) {\n throw new TypeError('Interpolate a serializeForPrompt block at the start of a line');\n }\n prose += `${line}\\n`;\n continue;\n }\n // Dropping the opener's indentation keeps four spaces of it from turning the fence into an indented code block.\n const blockLines = lines.slice(index + 1, block.end + 1);\n blockLines[blockLines.length - 1] = blockLines.at(-1)?.trimStart() ?? '';\n formatted += `${dedentPromptMarkers(prose)}${block.opener}\\n${blockLines.join('\\n')}`;\n prose = '\\n';\n index = block.end;\n }\n return (formatted + dedentPromptMarkers(prose)).trim();\n}\n\nfunction findBlocks(lines: string[]): (PromptBlock | undefined)[] {\n const blocks: (PromptBlock | undefined)[] = [];\n const nestedFenceLengths = new Map<string, Uint32Array>();\n const backtickClosers: { length: number; index: number }[] = [];\n const tildeClosers: { length: number; index: number }[] = [];\n for (let index = lines.length - 1; index >= 0; index--) {\n const match = BLOCK_OPENER.exec(lines[index] ?? '');\n const opener = match?.[1]?.trimEnd();\n const fence = match?.[2];\n if (opener === undefined || fence === undefined) continue;\n const closers = fence[0] === '`' ? backtickClosers : tildeClosers;\n let low = 0;\n let high = closers.length;\n while (low < high) {\n const middle = (low + high) >>> 1;\n if ((closers[middle]?.length ?? 0) >= fence.length) low = middle + 1;\n else high = middle;\n }\n let end = closers[low - 1]?.index ?? -1;\n if (/^(?:[ \\t].*)?$/u.test((match?.[1] ?? '').slice(fence.length))) {\n // A nearer, longer closer also closes every fence that a shorter one could close.\n while (closers.length > 0 && (closers.at(-1)?.length ?? 0) <= fence.length) closers.pop();\n closers.push({ length: fence.length, index });\n }\n let lengths = nestedFenceLengths.get(fence[0] ?? '');\n if (end !== -1 && lengths !== undefined && maximumFenceLengthAt(lengths, end) > fence.length) end = -1;\n if (end !== -1) {\n blocks[index] = { opener, end };\n if (lengths === undefined) {\n lengths = new Uint32Array(lines.length * 2);\n nestedFenceLengths.set(fence[0] ?? '', lengths);\n }\n recordFenceLength(lengths, index + 1, end, fence.length);\n }\n }\n return blocks;\n}\n\nfunction maximumFenceLengthAt(lengths: Uint32Array, index: number): number {\n let maximum = 0;\n for (let node = index + lengths.length / 2; node > 0; node >>>= 1) {\n maximum = Math.max(maximum, lengths[node] ?? 0);\n }\n return maximum;\n}\n\nfunction recordFenceLength(lengths: Uint32Array, start: number, end: number, length: number): void {\n let left = start + lengths.length / 2;\n let right = end + lengths.length / 2;\n while (left <= right) {\n if (left % 2 === 1) {\n lengths[left] = Math.max(lengths[left] ?? 0, length);\n left++;\n }\n if (right % 2 === 0) {\n lengths[right] = Math.max(lengths[right] ?? 0, length);\n right--;\n }\n left >>>= 1;\n right >>>= 1;\n }\n}\n\nfunction dedentPromptMarkers(text: string): string {\n // Consume failed marker searches, and start blank-line searches only at whitespace-run boundaries.\n return text\n .replaceAll(/\\n\\s+(\"\"\"|'''|```|~{3,})|\\n\\s*/gu, replaceIndentedMarker)\n .replaceAll(/\\n\\s+(#+\\s)|\\n\\s*/gu, replaceIndentedMarker)\n .replaceAll(/(?<!\\s)\\s*\\n\\s*\\n/gu, '\\n\\n');\n}\n\nfunction replaceIndentedMarker(match: string, marker: string | undefined): string {\n return marker === undefined ? match : `\\n${marker}`;\n}\n\n/** Cuts text down to `maxLength` characters, marking it so that an LLM reads the rest as missing rather than absent. */\nexport function truncateForPrompt(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n const kept = text.slice(0, maxLength);\n // Cutting between the halves of a surrogate pair would leave an unpaired one, which encoders replace with U+FFFD.\n return `${/[\\uD800-\\uDBFF]$/u.test(kept) ? kept.slice(0, -1) : kept}\\n...<truncated>`;\n}\n\n// The functions below reproduce `stringify(value, { lineWidth: 0, aliasDuplicateObjects: false, blockQuote: 'literal' })`\n// of the `yaml` package, except that `toSerializable` makes `Error`s and `RegExp`s readable instead of `{}`.\n\nfunction stringifyValue(value: unknown, ctx: Context): string {\n switch (typeof value) {\n case 'undefined': {\n return 'null';\n }\n case 'boolean': {\n return String(value);\n }\n case 'number': {\n return stringifyNumber(value);\n }\n case 'bigint': {\n return String(value);\n }\n case 'string': {\n return stringifyString(value, ctx);\n }\n case 'object': {\n if (value === null) return 'null';\n const separator = `\\n${ctx.indent}`;\n let str = '';\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n const itemCtx = { indent: ctx.indent + INDENT_STEP, tagPatterns: ctx.tagPatterns };\n for (const item of value as unknown[]) {\n str += `${str ? separator : ''}- ${stringifyValue(toSerializable(item), itemCtx)}`;\n }\n return str;\n }\n if (value instanceof Map) {\n for (const [key, item] of value) {\n if (item !== undefined) str += `${str ? separator : ''}${stringifyPair(key, item, ctx)}`;\n }\n return str || '{}';\n }\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n const item = record[key];\n if (item !== undefined) str += `${str ? separator : ''}${stringifyPair(key, item, ctx)}`;\n }\n return str || '{}';\n }\n default: {\n throw new TypeError(`Cannot serialize a ${typeof value} value for a prompt`);\n }\n }\n}\n\nfunction stringifyPair(rawKey: unknown, rawValue: unknown, ctx: Context): string {\n const indent = ctx.indent + INDENT_STEP;\n const key = toSerializable(rawKey);\n const value = toSerializable(rawValue);\n const keyStr = stringifyValue(key, { indent, implicitKey: true, tagPatterns: ctx.tagPatterns });\n const valueStr = stringifyValue(value, { indent, tagPatterns: ctx.tagPatterns });\n if (isCollection(key) || keyStr.length > MAX_IMPLICIT_KEY_LENGTH) return `? ${keyStr}\\n${ctx.indent}: ${valueStr}`;\n const isBlockCollection = isCollection(value) && valueStr !== '[]' && valueStr !== '{}';\n return `${keyStr}:${isBlockCollection ? `\\n${indent}` : ' '}${valueStr}`;\n}\n\nfunction toSerializable(rawValue: unknown): unknown {\n // Like `yaml`, call `toJSON` only once, but classify its result.\n const value =\n typeof (rawValue as { toJSON?: unknown } | null | undefined)?.toJSON === 'function'\n ? (rawValue as { toJSON: () => unknown }).toJSON()\n : rawValue;\n if (typeof value !== 'object' || value === null || Array.isArray(value) || value instanceof Map) return value;\n // oxlint-disable-next-line unicorn/no-instanceof-builtins -- boxed primitives have no typeof check; `yaml` unwraps them the same way.\n if (value instanceof String || value instanceof Number || value instanceof Boolean || value instanceof BigInt) {\n return value.valueOf();\n }\n if (value instanceof Error) {\n // `name` and `message` usually live on the prototype, and `cause` and `errors` are not enumerable.\n return {\n name: value.name,\n message: value.message,\n ...Object.fromEntries(Object.entries(value)),\n ...('cause' in value && { cause: value.cause }),\n ...(value instanceof AggregateError && { errors: value.errors }),\n };\n }\n if (value instanceof RegExp) return String(value);\n return Symbol.iterator in value ? [...(value as Iterable<unknown>)] : value;\n}\n\nfunction isCollection(value: unknown): value is object {\n return typeof value === 'object' && value !== null;\n}\n\nfunction stringifyNumber(value: number): string {\n if (Number.isNaN(value)) return '.nan';\n if (!Number.isFinite(value)) return value < 0 ? '-.inf' : '.inf';\n return Object.is(value, -0) ? '-0' : JSON.stringify(value);\n}\n\nfunction stringifyString(rawValue: string, ctx: Context): string {\n const value = ctx.tagPatterns === undefined ? rawValue : escapeTags(rawValue, ctx.tagPatterns);\n // A closing quote separates an unfinished tag prefix from the next mapping key.\n if (ctx.tagPatterns?.length && /<\\s*(?:\\/\\s*)?$/u.test(value)) return doubleQuotedString(value, ctx, false);\n // oxlint-disable-next-line no-control-regex -- control characters and lone surrogates can only be written escaped.\n return /[\\u0000-\\u0008\\u000B-\\u001F\\u007F-\\u009F\\u{D800}-\\u{DFFF}]/u.test(value)\n ? doubleQuotedString(value, ctx)\n : plainString(value, ctx);\n}\n\nfunction plainString(value: string, ctx: Context): string {\n const { implicitKey, indent } = ctx;\n if (value.includes('\\n')) return implicitKey ? quotedString(value, ctx) : blockString(value, ctx);\n if (UNSAFE_PLAIN_START.test(value) || UNSAFE_PLAIN_END.test(value.slice(-1)) || UNSAFE_PLAIN_MIDDLE.test(value)) {\n return quotedString(value, ctx);\n }\n if (containsDocumentMarker(value)) {\n if (indent === '') return blockString(value, ctx);\n if (implicitKey && indent === INDENT_STEP) return quotedString(value, ctx);\n }\n return NON_STRING_SCALAR.test(value) ? quotedString(value, ctx) : value;\n}\n\nfunction blockString(value: string, ctx: Context): string {\n let endStart = value.length;\n while (endStart > 0 && isBlockEndWhitespace(value.codePointAt(endStart - 1))) endStart--;\n let end = value.slice(endStart);\n // A block scalar cannot end with a whitespace-only line.\n if (end.includes('\\n') && !end.endsWith('\\n')) return quotedString(value, ctx);\n const indent = ctx.indent || (containsDocumentMarker(value) ? INDENT_STEP : '');\n\n const endNewlinePos = end.indexOf('\\n');\n const chomp = endNewlinePos === -1 ? '-' : value === end || endNewlinePos !== end.length - 1 ? '+' : '';\n if (end) {\n value = value.slice(0, -end.length);\n if (end.endsWith('\\n')) end = end.slice(0, -1);\n end = end.replaceAll(/(?:^|(?<!\\n))\\n+(?!\\n|$)/gu, `$&${indent}`);\n }\n\n const leadingWhitespace = /^[\\n ]*/u.exec(value)?.[0] ?? '';\n const startsWithSpace = leadingWhitespace.includes(' ');\n let start = value.slice(0, leadingWhitespace.lastIndexOf('\\n') + 1);\n if (start) {\n value = value.slice(start.length);\n start = start.replaceAll(/\\n+/gu, `$&${indent}`);\n }\n\n const header = (startsWithSpace ? (indent ? '2' : '1') : '') + chomp;\n return `|${header}\\n${indent}${start}${indentLines(value, indent)}${end}`;\n}\n\nfunction quotedString(value: string, ctx: Context): string {\n return value.includes('\"') && !value.includes(\"'\") ? singleQuotedString(value, ctx) : doubleQuotedString(value, ctx);\n}\n\nfunction singleQuotedString(value: string, ctx: Context): string {\n // Every multi-line value reaching here would contain a space or tab next to a newline or be an implicit key,\n // both of which need double quotes.\n if (value.includes('\\n')) return doubleQuotedString(value, ctx);\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction doubleQuotedString(value: string, ctx: Context, foldMultiline = !ctx.implicitKey): string {\n const json = JSON.stringify(value);\n const indent = ctx.indent || (containsDocumentMarker(value) ? INDENT_STEP : '');\n let str = '';\n let start = 0;\n for (let i = 0; i < json.length; i++) {\n let ch = json[i];\n if (ch === ' ' && json[i + 1] === '\\\\' && json[i + 2] === 'n') {\n // A space before a line break would be folded away unless escaped.\n str += `${json.slice(start, i)}\\\\ `;\n i++;\n start = i;\n ch = '\\\\';\n }\n if (ch !== '\\\\') continue;\n if (json[i + 1] === 'u') {\n const code = json.slice(i + 2, i + 6);\n str +=\n json.slice(start, i) +\n (SHORT_UNICODE_ESCAPES[code] ?? (code.startsWith('00') ? `\\\\x${code.slice(2)}` : json.slice(i, i + 6)));\n i += 5;\n start = i + 1;\n } else if (\n json[i + 1] === 'n' &&\n foldMultiline &&\n json[i + 2] !== '\"' &&\n json.length >= MIN_MULTI_LINE_DOUBLE_QUOTED_LENGTH\n ) {\n // Folding turns the first of the written line breaks back into a space, hence the extra one.\n str += `${json.slice(start, i)}\\n\\n`;\n while (json[i + 2] === '\\\\' && json[i + 3] === 'n' && json[i + 4] !== '\"') {\n str += '\\n';\n i += 2;\n }\n str += indent;\n // A space after a line break would be folded away unless escaped.\n if (json[i + 2] === ' ') str += '\\\\';\n i++;\n start = i + 1;\n } else {\n i++;\n }\n }\n return start ? str + json.slice(start) : json;\n}\n\nfunction containsDocumentMarker(value: string): boolean {\n return /^(?:%|---|\\.\\.\\.)/mu.test(value);\n}\n\n/** Equivalent to `text.replaceAll(/\\n+/g, `$&${indent}`)` for text without leading or trailing newlines, but faster. */\nfunction indentLines(text: string, indent: string): string {\n const lines = text.split('\\n');\n let str = lines[0] ?? '';\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n str += line ? `\\n${indent}${line}` : '\\n';\n }\n return str;\n}\n\nfunction isBlockEndWhitespace(codePoint: number | undefined): boolean {\n return codePoint === 0x0A || codePoint === 0x09 || codePoint === 0x20;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prompt.js","names":[],"sources":["../src/prompt.ts"],"sourcesContent":["import { escapeRegExp, sliceWithoutSplittingSurrogates, toTildeCodeBlock } from './text.js';\n\nconst INDENT_STEP = ' ';\nconst MAX_IMPLICIT_KEY_LENGTH = 1024;\nconst MIN_MULTI_LINE_DOUBLE_QUOTED_LENGTH = 40;\n\n/** Strings matching this would be read back as a non-string scalar (null, bool, int, or float), so they must be quoted. */\nconst NON_STRING_SCALAR =\n /^(?:~|[Nn]ull|NULL|[Tt]rue|TRUE|[Ff]alse|FALSE|0o[0-7]+|[-+]?[0-9]+|0x[0-9a-fA-F]+|[-+]?\\.(?:inf|Inf|INF)|\\.nan|\\.NaN|\\.NAN|[-+]?(?:\\.[0-9]+|[0-9]+(?:\\.[0-9]*)?)[eE][-+]?[0-9]+|[-+]?(?:\\.[0-9]+|[0-9]+\\.[0-9]*))?$/u;\n\n// A single-line string must be quoted if it matches any of these. Checking the start, the middle, and the end separately\n// is much faster on long strings than one regex whose anchored alternatives are retried at every position.\nconst UNSAFE_PLAIN_START = /^(?:[\\t ,[\\]{}#&*!|>'\"%@`]|[?-](?:[ \\t]|$))/u;\nconst UNSAFE_PLAIN_MIDDLE = /:[ \\t]|[ \\t]#/u;\nconst UNSAFE_PLAIN_END = /[\\t :]$/u;\n\nconst SHORT_UNICODE_ESCAPES: Record<string, string> = {\n '0000': String.raw`\\0`,\n '0007': String.raw`\\a`,\n '000b': String.raw`\\v`,\n '001b': String.raw`\\e`,\n};\n\ninterface Context {\n indent: string;\n implicitKey?: boolean;\n tagPatterns?: readonly RegExp[];\n}\n\n/**\n * Serializes data into a code block to embed in an LLM prompt, so that the LLM can read its contents.\n * Accepts JSON data (honoring `toJSON` such as that of `Date`) as well as `undefined`, `NaN`, `Infinity`, bigints,\n * `Map`s (including non-string keys), `Set`s and other iterables, `Error`s (with their name, message, cause, and own properties),\n * and `RegExp`s. Symbols and functions without `toJSON` throw. The output is not meant to be deserialized back into the original value.\n * The format inside the code block is an implementation detail and may change.\n */\nexport function serializeForPrompt(value: unknown): string {\n return toTildeCodeBlock(`${stringifyValue(toSerializable(value), { indent: '' })}\\n`, 'yaml');\n}\n\n/**\n * Serializes data with `serializeForPrompt` for embedding inside a `<tagName>` element of a prompt, escaping that tag\n * in every string so that untrusted data cannot close the element and have the rest read as instructions.\n * The caller must wrap the result in the same tag.\n *\n * Only the named elements are protected, so a block nested inside other tagged elements takes every enclosing name.\n * Escaping the finished block instead is not an option: it would turn a plain scalar holding the escaped notation\n * into a YAML flow sequence, since the quoting of each scalar is decided as it is written.\n *\n * The escaped notation is the one `escapePromptTag` writes, and text that already holds it is left as it is, so two\n * strings differing only in that notation are written alike. Keys taken from untrusted data can therefore collide\n * into one duplicate key of the emitted mapping.\n */\nexport function serializeForPromptInTag(value: unknown, tagName: string | readonly string[]): string {\n const escapedTags = typeof tagName === 'string' ? [tagName] : tagName;\n const tagPatterns = escapedTags.flatMap(createTagPatterns);\n return toTildeCodeBlock(`${stringifyValue(toSerializable(value), { indent: '', tagPatterns })}\\n`, 'yaml');\n}\n\n/**\n * Replaces `<tagName` and `</tagName` not followed by `[\\w-]` with a harmless notation such as `[/tagName]`, so that\n * data embedded in a `<tagName>` element of a prompt cannot close the element and have the rest read as instructions.\n * A closing `>` is not required, since an HTML reader also closes an element on a tag carrying attribute-like junk,\n * on a trailing solidus, or on the next `>` anywhere in the prompt; the whitespace between `<` and the name is\n * dropped along with the brackets. Case is ignored deliberately: `tagName` is expected to be a literal written by\n * the caller, while the data is not.\n */\nexport function escapePromptTag(text: string, tagName: string): string {\n return text.includes('<') ? escapeTags(text, createTagPatterns(tagName)) : text;\n}\n\nfunction createTagPatterns(tagName: string): RegExp[] {\n const name = escapeRegExp(tagName);\n // Keep well-formed tags readable while also catching incomplete and malformed tags.\n return [\n new RegExp(`<\\\\s*(?:(/)\\\\s*)?(${name})\\\\s*>`, 'giu'),\n new RegExp(`<\\\\s*(?:(/)\\\\s*)?(${name})(?![\\\\w-])`, 'giu'),\n ];\n}\n\nfunction escapeTags(text: string, patterns: readonly RegExp[]): string {\n if (!text.includes('<')) return text;\n for (const pattern of patterns) text = text.replaceAll(pattern, '[$1$2]');\n return text;\n}\n\n/** The line opening a fenced block, with the indentation an interpolation may put before it. */\nconst BLOCK_OPENER = /^[ \\t]*((`{3,}|~{3,})[^\\n]*)$/u;\n\n/** A block interpolated after other text on its line, which no rule can tell from prose that ends in `~~~yaml`. */\nconst MISPLACED_BLOCK_OPENER = /[^\\s~][ \\t]*~{3,}yaml[ \\t]*$/u;\n\ninterface PromptBlock {\n opener: string;\n end: number;\n}\n\n/**\n * Strips template-literal indentation from Markdown headings, code fences, and triple-quote delimiters (`\"\"\"` and\n * `'''`), and collapses blank lines.\n * The contents of a fenced block are left untouched, since reindenting them would rewrite the data they carry, such\n * as the YAML of `serializeForPrompt` or the source of `toCodeBlock`. Every fenced block must be interpolated at\n * the start of a line. Only recognizable mid-line `~~~yaml` markers throw, including prose mentions;\n * this is not a complete placement validator, since preceding tildes can merge into an indistinguishable fence.\n * Blocks end at the first compatible same-character fence, which may carry trailing prose, unless a longer fence\n * of the same character opens and contains that candidate closing line. Other fence characters have no nesting\n * significance. Balance authored fences before interpolating blocks: an unmatched sample can consume part of a\n * later block and leave its tail subject to prose formatting.\n */\nexport function formatPrompt(prompt: string): string {\n const lines = prompt.split('\\n');\n const blocks = findBlocks(lines);\n let formatted = '';\n let prose = '';\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index] ?? '';\n const block = blocks[index];\n if (block === undefined) {\n // An opening fence the prompt itself writes and never closes is prose, and so is every line inside a block.\n if (MISPLACED_BLOCK_OPENER.test(line)) {\n throw new TypeError('Interpolate a serializeForPrompt block at the start of a line');\n }\n prose += `${line}\\n`;\n continue;\n }\n // Dropping the opener's indentation keeps four spaces of it from turning the fence into an indented code block.\n const blockLines = lines.slice(index + 1, block.end + 1);\n blockLines[blockLines.length - 1] = blockLines.at(-1)?.trimStart() ?? '';\n formatted += `${dedentPromptMarkers(prose)}${block.opener}\\n${blockLines.join('\\n')}`;\n prose = '\\n';\n index = block.end;\n }\n return (formatted + dedentPromptMarkers(prose)).trim();\n}\n\nfunction findBlocks(lines: string[]): (PromptBlock | undefined)[] {\n const blocks: (PromptBlock | undefined)[] = [];\n const nestedFenceLengths = new Map<string, Uint32Array>();\n const backtickClosers: { length: number; index: number }[] = [];\n const tildeClosers: { length: number; index: number }[] = [];\n for (let index = lines.length - 1; index >= 0; index--) {\n const match = BLOCK_OPENER.exec(lines[index] ?? '');\n const opener = match?.[1]?.trimEnd();\n const fence = match?.[2];\n if (opener === undefined || fence === undefined) continue;\n const closers = fence[0] === '`' ? backtickClosers : tildeClosers;\n let low = 0;\n let high = closers.length;\n while (low < high) {\n const middle = (low + high) >>> 1;\n if ((closers[middle]?.length ?? 0) >= fence.length) low = middle + 1;\n else high = middle;\n }\n let end = closers[low - 1]?.index ?? -1;\n if (/^(?:[ \\t].*)?$/u.test((match?.[1] ?? '').slice(fence.length))) {\n // A nearer, longer closer also closes every fence that a shorter one could close.\n while (closers.length > 0 && (closers.at(-1)?.length ?? 0) <= fence.length) closers.pop();\n closers.push({ length: fence.length, index });\n }\n let lengths = nestedFenceLengths.get(fence[0] ?? '');\n if (end !== -1 && lengths !== undefined && maximumFenceLengthAt(lengths, end) > fence.length) end = -1;\n if (end !== -1) {\n blocks[index] = { opener, end };\n if (lengths === undefined) {\n lengths = new Uint32Array(lines.length * 2);\n nestedFenceLengths.set(fence[0] ?? '', lengths);\n }\n recordFenceLength(lengths, index + 1, end, fence.length);\n }\n }\n return blocks;\n}\n\nfunction maximumFenceLengthAt(lengths: Uint32Array, index: number): number {\n let maximum = 0;\n for (let node = index + lengths.length / 2; node > 0; node >>>= 1) {\n maximum = Math.max(maximum, lengths[node] ?? 0);\n }\n return maximum;\n}\n\nfunction recordFenceLength(lengths: Uint32Array, start: number, end: number, length: number): void {\n let left = start + lengths.length / 2;\n let right = end + lengths.length / 2;\n while (left <= right) {\n if (left % 2 === 1) {\n lengths[left] = Math.max(lengths[left] ?? 0, length);\n left++;\n }\n if (right % 2 === 0) {\n lengths[right] = Math.max(lengths[right] ?? 0, length);\n right--;\n }\n left >>>= 1;\n right >>>= 1;\n }\n}\n\nfunction dedentPromptMarkers(text: string): string {\n // Consume failed marker searches, and start blank-line searches only at whitespace-run boundaries.\n return text\n .replaceAll(/\\n\\s+(\"\"\"|'''|```|~{3,})|\\n\\s*/gu, replaceIndentedMarker)\n .replaceAll(/\\n\\s+(#+\\s)|\\n\\s*/gu, replaceIndentedMarker)\n .replaceAll(/(?<!\\s)\\s*\\n\\s*\\n/gu, '\\n\\n');\n}\n\nfunction replaceIndentedMarker(match: string, marker: string | undefined): string {\n return marker === undefined ? match : `\\n${marker}`;\n}\n\n/** Cuts text down to `maxLength` characters, marking it so that an LLM reads the rest as missing rather than absent. */\nexport function truncateForPrompt(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return `${sliceWithoutSplittingSurrogates(text, maxLength)}\\n...<truncated>`;\n}\n\n// The functions below reproduce `stringify(value, { lineWidth: 0, aliasDuplicateObjects: false, blockQuote: 'literal' })`\n// of the `yaml` package, except that `toSerializable` makes `Error`s and `RegExp`s readable instead of `{}`.\n\nfunction stringifyValue(value: unknown, ctx: Context): string {\n switch (typeof value) {\n case 'undefined': {\n return 'null';\n }\n case 'boolean': {\n return String(value);\n }\n case 'number': {\n return stringifyNumber(value);\n }\n case 'bigint': {\n return String(value);\n }\n case 'string': {\n return stringifyString(value, ctx);\n }\n case 'object': {\n if (value === null) return 'null';\n const separator = `\\n${ctx.indent}`;\n let str = '';\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n const itemCtx = { indent: ctx.indent + INDENT_STEP, tagPatterns: ctx.tagPatterns };\n for (const item of value as unknown[]) {\n str += `${str ? separator : ''}- ${stringifyValue(toSerializable(item), itemCtx)}`;\n }\n return str;\n }\n if (value instanceof Map) {\n for (const [key, item] of value) {\n if (item !== undefined) str += `${str ? separator : ''}${stringifyPair(key, item, ctx)}`;\n }\n return str || '{}';\n }\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n const item = record[key];\n if (item !== undefined) str += `${str ? separator : ''}${stringifyPair(key, item, ctx)}`;\n }\n return str || '{}';\n }\n default: {\n throw new TypeError(`Cannot serialize a ${typeof value} value for a prompt`);\n }\n }\n}\n\nfunction stringifyPair(rawKey: unknown, rawValue: unknown, ctx: Context): string {\n const indent = ctx.indent + INDENT_STEP;\n const key = toSerializable(rawKey);\n const value = toSerializable(rawValue);\n const keyStr = stringifyValue(key, { indent, implicitKey: true, tagPatterns: ctx.tagPatterns });\n const valueStr = stringifyValue(value, { indent, tagPatterns: ctx.tagPatterns });\n if (isCollection(key) || keyStr.length > MAX_IMPLICIT_KEY_LENGTH) return `? ${keyStr}\\n${ctx.indent}: ${valueStr}`;\n const isBlockCollection = isCollection(value) && valueStr !== '[]' && valueStr !== '{}';\n return `${keyStr}:${isBlockCollection ? `\\n${indent}` : ' '}${valueStr}`;\n}\n\nfunction toSerializable(rawValue: unknown): unknown {\n // Like `yaml`, call `toJSON` only once, but classify its result.\n const value =\n typeof (rawValue as { toJSON?: unknown } | null | undefined)?.toJSON === 'function'\n ? (rawValue as { toJSON: () => unknown }).toJSON()\n : rawValue;\n if (typeof value !== 'object' || value === null || Array.isArray(value) || value instanceof Map) return value;\n // oxlint-disable-next-line unicorn/no-instanceof-builtins -- boxed primitives have no typeof check; `yaml` unwraps them the same way.\n if (value instanceof String || value instanceof Number || value instanceof Boolean || value instanceof BigInt) {\n return value.valueOf();\n }\n if (value instanceof Error) {\n // `name` and `message` usually live on the prototype, and `cause` and `errors` are not enumerable.\n return {\n name: value.name,\n message: value.message,\n ...Object.fromEntries(Object.entries(value)),\n ...('cause' in value && { cause: value.cause }),\n ...(value instanceof AggregateError && { errors: value.errors }),\n };\n }\n if (value instanceof RegExp) return String(value);\n return Symbol.iterator in value ? [...(value as Iterable<unknown>)] : value;\n}\n\nfunction isCollection(value: unknown): value is object {\n return typeof value === 'object' && value !== null;\n}\n\nfunction stringifyNumber(value: number): string {\n if (Number.isNaN(value)) return '.nan';\n if (!Number.isFinite(value)) return value < 0 ? '-.inf' : '.inf';\n return Object.is(value, -0) ? '-0' : JSON.stringify(value);\n}\n\nfunction stringifyString(rawValue: string, ctx: Context): string {\n const value = ctx.tagPatterns === undefined ? rawValue : escapeTags(rawValue, ctx.tagPatterns);\n // A closing quote separates an unfinished tag prefix from the next mapping key.\n if (ctx.tagPatterns?.length && /<\\s*(?:\\/\\s*)?$/u.test(value)) return doubleQuotedString(value, ctx, false);\n // oxlint-disable-next-line no-control-regex -- control characters and lone surrogates can only be written escaped.\n return /[\\u0000-\\u0008\\u000B-\\u001F\\u007F-\\u009F\\u{D800}-\\u{DFFF}]/u.test(value)\n ? doubleQuotedString(value, ctx)\n : plainString(value, ctx);\n}\n\nfunction plainString(value: string, ctx: Context): string {\n const { implicitKey, indent } = ctx;\n if (value.includes('\\n')) return implicitKey ? quotedString(value, ctx) : blockString(value, ctx);\n if (UNSAFE_PLAIN_START.test(value) || UNSAFE_PLAIN_END.test(value.slice(-1)) || UNSAFE_PLAIN_MIDDLE.test(value)) {\n return quotedString(value, ctx);\n }\n if (containsDocumentMarker(value)) {\n if (indent === '') return blockString(value, ctx);\n if (implicitKey && indent === INDENT_STEP) return quotedString(value, ctx);\n }\n return NON_STRING_SCALAR.test(value) ? quotedString(value, ctx) : value;\n}\n\nfunction blockString(value: string, ctx: Context): string {\n let endStart = value.length;\n while (endStart > 0 && isBlockEndWhitespace(value.codePointAt(endStart - 1))) endStart--;\n let end = value.slice(endStart);\n // A block scalar cannot end with a whitespace-only line.\n if (end.includes('\\n') && !end.endsWith('\\n')) return quotedString(value, ctx);\n const indent = ctx.indent || (containsDocumentMarker(value) ? INDENT_STEP : '');\n\n const endNewlinePos = end.indexOf('\\n');\n const chomp = endNewlinePos === -1 ? '-' : value === end || endNewlinePos !== end.length - 1 ? '+' : '';\n if (end) {\n value = value.slice(0, -end.length);\n if (end.endsWith('\\n')) end = end.slice(0, -1);\n end = end.replaceAll(/(?:^|(?<!\\n))\\n+(?!\\n|$)/gu, `$&${indent}`);\n }\n\n const leadingWhitespace = /^[\\n ]*/u.exec(value)?.[0] ?? '';\n const startsWithSpace = leadingWhitespace.includes(' ');\n let start = value.slice(0, leadingWhitespace.lastIndexOf('\\n') + 1);\n if (start) {\n value = value.slice(start.length);\n start = start.replaceAll(/\\n+/gu, `$&${indent}`);\n }\n\n const header = (startsWithSpace ? (indent ? '2' : '1') : '') + chomp;\n return `|${header}\\n${indent}${start}${indentLines(value, indent)}${end}`;\n}\n\nfunction quotedString(value: string, ctx: Context): string {\n return value.includes('\"') && !value.includes(\"'\") ? singleQuotedString(value, ctx) : doubleQuotedString(value, ctx);\n}\n\nfunction singleQuotedString(value: string, ctx: Context): string {\n // Every multi-line value reaching here would contain a space or tab next to a newline or be an implicit key,\n // both of which need double quotes.\n if (value.includes('\\n')) return doubleQuotedString(value, ctx);\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction doubleQuotedString(value: string, ctx: Context, foldMultiline = !ctx.implicitKey): string {\n const json = JSON.stringify(value);\n const indent = ctx.indent || (containsDocumentMarker(value) ? INDENT_STEP : '');\n let str = '';\n let start = 0;\n for (let i = 0; i < json.length; i++) {\n let ch = json[i];\n if (ch === ' ' && json[i + 1] === '\\\\' && json[i + 2] === 'n') {\n // A space before a line break would be folded away unless escaped.\n str += `${json.slice(start, i)}\\\\ `;\n i++;\n start = i;\n ch = '\\\\';\n }\n if (ch !== '\\\\') continue;\n if (json[i + 1] === 'u') {\n const code = json.slice(i + 2, i + 6);\n str +=\n json.slice(start, i) +\n (SHORT_UNICODE_ESCAPES[code] ?? (code.startsWith('00') ? `\\\\x${code.slice(2)}` : json.slice(i, i + 6)));\n i += 5;\n start = i + 1;\n } else if (\n json[i + 1] === 'n' &&\n foldMultiline &&\n json[i + 2] !== '\"' &&\n json.length >= MIN_MULTI_LINE_DOUBLE_QUOTED_LENGTH\n ) {\n // Folding turns the first of the written line breaks back into a space, hence the extra one.\n str += `${json.slice(start, i)}\\n\\n`;\n while (json[i + 2] === '\\\\' && json[i + 3] === 'n' && json[i + 4] !== '\"') {\n str += '\\n';\n i += 2;\n }\n str += indent;\n // A space after a line break would be folded away unless escaped.\n if (json[i + 2] === ' ') str += '\\\\';\n i++;\n start = i + 1;\n } else {\n i++;\n }\n }\n return start ? str + json.slice(start) : json;\n}\n\nfunction containsDocumentMarker(value: string): boolean {\n return /^(?:%|---|\\.\\.\\.)/mu.test(value);\n}\n\n/** Equivalent to `text.replaceAll(/\\n+/g, `$&${indent}`)` for text without leading or trailing newlines, but faster. */\nfunction indentLines(text: string, indent: string): string {\n const lines = text.split('\\n');\n let str = lines[0] ?? '';\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n str += line ? `\\n${indent}${line}` : '\\n';\n }\n return str;\n}\n\nfunction isBlockEndWhitespace(codePoint: number | undefined): boolean {\n return codePoint === 0x0A || codePoint === 0x09 || codePoint === 0x20;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";const e=require("./text.cjs"),t=require("./prompt.cjs");function n(t,n=1){let i=`#`.repeat(n);return t.map(t=>`${i} ${r(t.path)}\n\n${e.toCodeBlock(t.data.replaceAll(/\r\n?/gu,`
|
|
2
2
|
`).trimEnd())}`).join(`
|
|
3
3
|
|
|
4
|
-
`)}function r(e){let t=1;for(let n of e.matchAll(/`+/gu))t=Math.max(t,n[0].length+1);let n="`".repeat(t);return`${n} ${e} ${n}`}function i(e){let n=[
|
|
4
|
+
`)}function r(e){let t=1;for(let n of e.matchAll(/`+/gu))t=Math.max(t,n[0].length+1);let n="`".repeat(t);return`${n} ${e} ${n}`}function i(e){let n=[.../* @__PURE__ */ new Set([`system`,`developer`,`user`,`assistant`,`tool`,...e.map(e=>e.role)])];return e.map(e=>{let r=e.content;for(let e of n)r=t.escapePromptTag(r,e);return`<${e.role}>\n${r}\n</${e.role}>`}).join(`
|
|
5
5
|
|
|
6
6
|
`)}exports.formatFilesForPrompt=n,exports.formatMessagesForPrompt=i;
|
|
7
7
|
//# sourceMappingURL=promptFormatters.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptFormatters.cjs","names":["toCodeBlock","escapePromptTag"],"sources":["../src/promptFormatters.ts"],"sourcesContent":["import { escapePromptTag } from './prompt.js';\nimport { toCodeBlock } from './text.js';\n\n/**\n * Renders files as Markdown sections for an LLM prompt: a heading holding the single-line path in inline code,\n * followed by the file contents in a code block whose fence the contents cannot close. Line endings are normalized\n * to LF and trailing whitespace is removed.\n * The output reads back with `extractSections` (keyed by path) and `extractIfSingleOutermostCodeBlock`, so an\n * LLM can be asked to answer in the same format.\n */\nexport function formatFilesForPrompt(files: readonly { path: string; data: string }[], headingLevel = 1): string {\n const headingMarker = '#'.repeat(headingLevel);\n return files\n .map(\n (file) =>\n `${headingMarker} ${formatPath(file.path)}\\n\\n${toCodeBlock(file.data.replaceAll(/\\r\\n?/gu, '\\n').trimEnd())}`\n )\n .join('\\n\\n');\n}\n\nfunction formatPath(path: string): string {\n let length = 1;\n for (const match of path.matchAll(/`+/gu)) length = Math.max(length, match[0].length + 1);\n const delimiter = '`'.repeat(length);\n return `${delimiter} ${path} ${delimiter}`;\n}\n\n/**\n * Renders chat messages as `<role>` elements separated by blank lines, e.g. to embed a conversation log in a prompt.\n * Escapes system, developer, user, assistant, tool, and every supplied role's tags in message contents.\n * Roles must be trusted literal tag names supplied by the caller. This preserves delimiters, not instruction priority.\n * To wrap the result in another element, escape that tag in the result with `escapePromptTag`.\n */\nexport function formatMessagesForPrompt(messages: readonly { role: string; content: string }[]): string {\n const roles = [\n ...new Set(['system', 'developer', 'user', 'assistant', 'tool', ...messages.map((message) => message.role)]),\n ];\n return messages\n .map((message) => {\n let content = message.content;\n for (const role of roles) content = escapePromptTag(content, role);\n return `<${message.role}>\\n${content}\\n</${message.role}>`;\n })\n .join('\\n\\n');\n}\n"],"mappings":"qEAUA,SAAgB,EAAqB,EAAkD,EAAe,EAAW,CAC/G,IAAM,EAAgB,IAAI,OAAO,CAAY,EAC7C,OAAO,EACJ,IACE,GACC,GAAG,EAAc,GAAG,EAAW,EAAK,IAAI,EAAE,MAAMA,EAAAA,YAAY,EAAK,KAAK,WAAW,UAAW;CAAI,CAAC,CAAC,QAAQ,CAAC,GAC/G,CAAC,CACA,KAAK;;CAAM,CAChB,CAEA,SAAS,EAAW,EAAsB,CACxC,IAAI,EAAS,EACb,IAAK,IAAM,KAAS,EAAK,SAAS,MAAM,EAAG,EAAS,KAAK,IAAI,EAAQ,EAAM,EAAE,CAAC,OAAS,CAAC,EACxF,IAAM,EAAY,IAAI,OAAO,CAAM,EACnC,MAAO,GAAG,EAAU,GAAG,EAAK,GAAG,GACjC,CAQA,SAAgB,EAAwB,EAAgE,CACtG,IAAM,EAAQ,CACZ,
|
|
1
|
+
{"version":3,"file":"promptFormatters.cjs","names":["toCodeBlock","escapePromptTag"],"sources":["../src/promptFormatters.ts"],"sourcesContent":["import { escapePromptTag } from './prompt.js';\nimport { toCodeBlock } from './text.js';\n\n/**\n * Renders files as Markdown sections for an LLM prompt: a heading holding the single-line path in inline code,\n * followed by the file contents in a code block whose fence the contents cannot close. Line endings are normalized\n * to LF and trailing whitespace is removed.\n * The output reads back with `extractSections` (keyed by path) and `extractIfSingleOutermostCodeBlock`, so an\n * LLM can be asked to answer in the same format.\n */\nexport function formatFilesForPrompt(files: readonly { path: string; data: string }[], headingLevel = 1): string {\n const headingMarker = '#'.repeat(headingLevel);\n return files\n .map(\n (file) =>\n `${headingMarker} ${formatPath(file.path)}\\n\\n${toCodeBlock(file.data.replaceAll(/\\r\\n?/gu, '\\n').trimEnd())}`\n )\n .join('\\n\\n');\n}\n\nfunction formatPath(path: string): string {\n let length = 1;\n for (const match of path.matchAll(/`+/gu)) length = Math.max(length, match[0].length + 1);\n const delimiter = '`'.repeat(length);\n return `${delimiter} ${path} ${delimiter}`;\n}\n\n/**\n * Renders chat messages as `<role>` elements separated by blank lines, e.g. to embed a conversation log in a prompt.\n * Escapes system, developer, user, assistant, tool, and every supplied role's tags in message contents.\n * Roles must be trusted literal tag names supplied by the caller. This preserves delimiters, not instruction priority.\n * To wrap the result in another element, escape that tag in the result with `escapePromptTag`.\n */\nexport function formatMessagesForPrompt(messages: readonly { role: string; content: string }[]): string {\n const roles = [\n ...new Set(['system', 'developer', 'user', 'assistant', 'tool', ...messages.map((message) => message.role)]),\n ];\n return messages\n .map((message) => {\n let content = message.content;\n for (const role of roles) content = escapePromptTag(content, role);\n return `<${message.role}>\\n${content}\\n</${message.role}>`;\n })\n .join('\\n\\n');\n}\n"],"mappings":"qEAUA,SAAgB,EAAqB,EAAkD,EAAe,EAAW,CAC/G,IAAM,EAAgB,IAAI,OAAO,CAAY,EAC7C,OAAO,EACJ,IACE,GACC,GAAG,EAAc,GAAG,EAAW,EAAK,IAAI,EAAE,MAAMA,EAAAA,YAAY,EAAK,KAAK,WAAW,UAAW;CAAI,CAAC,CAAC,QAAQ,CAAC,GAC/G,CAAC,CACA,KAAK;;CAAM,CAChB,CAEA,SAAS,EAAW,EAAsB,CACxC,IAAI,EAAS,EACb,IAAK,IAAM,KAAS,EAAK,SAAS,MAAM,EAAG,EAAS,KAAK,IAAI,EAAQ,EAAM,EAAE,CAAC,OAAS,CAAC,EACxF,IAAM,EAAY,IAAI,OAAO,CAAM,EACnC,MAAO,GAAG,EAAU,GAAG,EAAK,GAAG,GACjC,CAQA,SAAgB,EAAwB,EAAgE,CACtG,IAAM,EAAQ,CACZ,mBAAG,IAAI,IAAI,CAAC,SAAU,YAAa,OAAQ,YAAa,OAAQ,GAAG,EAAS,IAAK,GAAY,EAAQ,IAAI,CAAC,CAAC,CAC7G,EACA,OAAO,EACJ,IAAK,GAAY,CAChB,IAAI,EAAU,EAAQ,QACtB,IAAK,IAAM,KAAQ,EAAO,EAAUC,EAAAA,gBAAgB,EAAS,CAAI,EACjE,MAAO,IAAI,EAAQ,KAAK,KAAK,EAAQ,MAAM,EAAQ,KAAK,EAC1D,CAAC,CAAC,CACD,KAAK;;CAAM,CAChB"}
|
package/dist/promptFormatters.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import{toCodeBlock as e}from"./text.js";import{escapePromptTag as t}from"./prompt.js";function n(t,n=1){let i=`#`.repeat(n);return t.map(t=>`${i} ${r(t.path)}\n\n${e(t.data.replaceAll(/\r\n?/gu,`
|
|
2
2
|
`).trimEnd())}`).join(`
|
|
3
3
|
|
|
4
|
-
`)}function r(e){let t=1;for(let n of e.matchAll(/`+/gu))t=Math.max(t,n[0].length+1);let n="`".repeat(t);return`${n} ${e} ${n}`}function i(e){let n=[
|
|
4
|
+
`)}function r(e){let t=1;for(let n of e.matchAll(/`+/gu))t=Math.max(t,n[0].length+1);let n="`".repeat(t);return`${n} ${e} ${n}`}function i(e){let n=[.../* @__PURE__ */ new Set([`system`,`developer`,`user`,`assistant`,`tool`,...e.map(e=>e.role)])];return e.map(e=>{let r=e.content;for(let e of n)r=t(r,e);return`<${e.role}>\n${r}\n</${e.role}>`}).join(`
|
|
5
5
|
|
|
6
6
|
`)}export{n as formatFilesForPrompt,i as formatMessagesForPrompt};
|
|
7
7
|
//# sourceMappingURL=promptFormatters.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptFormatters.js","names":[],"sources":["../src/promptFormatters.ts"],"sourcesContent":["import { escapePromptTag } from './prompt.js';\nimport { toCodeBlock } from './text.js';\n\n/**\n * Renders files as Markdown sections for an LLM prompt: a heading holding the single-line path in inline code,\n * followed by the file contents in a code block whose fence the contents cannot close. Line endings are normalized\n * to LF and trailing whitespace is removed.\n * The output reads back with `extractSections` (keyed by path) and `extractIfSingleOutermostCodeBlock`, so an\n * LLM can be asked to answer in the same format.\n */\nexport function formatFilesForPrompt(files: readonly { path: string; data: string }[], headingLevel = 1): string {\n const headingMarker = '#'.repeat(headingLevel);\n return files\n .map(\n (file) =>\n `${headingMarker} ${formatPath(file.path)}\\n\\n${toCodeBlock(file.data.replaceAll(/\\r\\n?/gu, '\\n').trimEnd())}`\n )\n .join('\\n\\n');\n}\n\nfunction formatPath(path: string): string {\n let length = 1;\n for (const match of path.matchAll(/`+/gu)) length = Math.max(length, match[0].length + 1);\n const delimiter = '`'.repeat(length);\n return `${delimiter} ${path} ${delimiter}`;\n}\n\n/**\n * Renders chat messages as `<role>` elements separated by blank lines, e.g. to embed a conversation log in a prompt.\n * Escapes system, developer, user, assistant, tool, and every supplied role's tags in message contents.\n * Roles must be trusted literal tag names supplied by the caller. This preserves delimiters, not instruction priority.\n * To wrap the result in another element, escape that tag in the result with `escapePromptTag`.\n */\nexport function formatMessagesForPrompt(messages: readonly { role: string; content: string }[]): string {\n const roles = [\n ...new Set(['system', 'developer', 'user', 'assistant', 'tool', ...messages.map((message) => message.role)]),\n ];\n return messages\n .map((message) => {\n let content = message.content;\n for (const role of roles) content = escapePromptTag(content, role);\n return `<${message.role}>\\n${content}\\n</${message.role}>`;\n })\n .join('\\n\\n');\n}\n"],"mappings":"sFAUA,SAAgB,EAAqB,EAAkD,EAAe,EAAW,CAC/G,IAAM,EAAgB,IAAI,OAAO,CAAY,EAC7C,OAAO,EACJ,IACE,GACC,GAAG,EAAc,GAAG,EAAW,EAAK,IAAI,EAAE,MAAM,EAAY,EAAK,KAAK,WAAW,UAAW;CAAI,CAAC,CAAC,QAAQ,CAAC,GAC/G,CAAC,CACA,KAAK;;CAAM,CAChB,CAEA,SAAS,EAAW,EAAsB,CACxC,IAAI,EAAS,EACb,IAAK,IAAM,KAAS,EAAK,SAAS,MAAM,EAAG,EAAS,KAAK,IAAI,EAAQ,EAAM,EAAE,CAAC,OAAS,CAAC,EACxF,IAAM,EAAY,IAAI,OAAO,CAAM,EACnC,MAAO,GAAG,EAAU,GAAG,EAAK,GAAG,GACjC,CAQA,SAAgB,EAAwB,EAAgE,CACtG,IAAM,EAAQ,CACZ,
|
|
1
|
+
{"version":3,"file":"promptFormatters.js","names":[],"sources":["../src/promptFormatters.ts"],"sourcesContent":["import { escapePromptTag } from './prompt.js';\nimport { toCodeBlock } from './text.js';\n\n/**\n * Renders files as Markdown sections for an LLM prompt: a heading holding the single-line path in inline code,\n * followed by the file contents in a code block whose fence the contents cannot close. Line endings are normalized\n * to LF and trailing whitespace is removed.\n * The output reads back with `extractSections` (keyed by path) and `extractIfSingleOutermostCodeBlock`, so an\n * LLM can be asked to answer in the same format.\n */\nexport function formatFilesForPrompt(files: readonly { path: string; data: string }[], headingLevel = 1): string {\n const headingMarker = '#'.repeat(headingLevel);\n return files\n .map(\n (file) =>\n `${headingMarker} ${formatPath(file.path)}\\n\\n${toCodeBlock(file.data.replaceAll(/\\r\\n?/gu, '\\n').trimEnd())}`\n )\n .join('\\n\\n');\n}\n\nfunction formatPath(path: string): string {\n let length = 1;\n for (const match of path.matchAll(/`+/gu)) length = Math.max(length, match[0].length + 1);\n const delimiter = '`'.repeat(length);\n return `${delimiter} ${path} ${delimiter}`;\n}\n\n/**\n * Renders chat messages as `<role>` elements separated by blank lines, e.g. to embed a conversation log in a prompt.\n * Escapes system, developer, user, assistant, tool, and every supplied role's tags in message contents.\n * Roles must be trusted literal tag names supplied by the caller. This preserves delimiters, not instruction priority.\n * To wrap the result in another element, escape that tag in the result with `escapePromptTag`.\n */\nexport function formatMessagesForPrompt(messages: readonly { role: string; content: string }[]): string {\n const roles = [\n ...new Set(['system', 'developer', 'user', 'assistant', 'tool', ...messages.map((message) => message.role)]),\n ];\n return messages\n .map((message) => {\n let content = message.content;\n for (const role of roles) content = escapePromptTag(content, role);\n return `<${message.role}>\\n${content}\\n</${message.role}>`;\n })\n .join('\\n\\n');\n}\n"],"mappings":"sFAUA,SAAgB,EAAqB,EAAkD,EAAe,EAAW,CAC/G,IAAM,EAAgB,IAAI,OAAO,CAAY,EAC7C,OAAO,EACJ,IACE,GACC,GAAG,EAAc,GAAG,EAAW,EAAK,IAAI,EAAE,MAAM,EAAY,EAAK,KAAK,WAAW,UAAW;CAAI,CAAC,CAAC,QAAQ,CAAC,GAC/G,CAAC,CACA,KAAK;;CAAM,CAChB,CAEA,SAAS,EAAW,EAAsB,CACxC,IAAI,EAAS,EACb,IAAK,IAAM,KAAS,EAAK,SAAS,MAAM,EAAG,EAAS,KAAK,IAAI,EAAQ,EAAM,EAAE,CAAC,OAAS,CAAC,EACxF,IAAM,EAAY,IAAI,OAAO,CAAM,EACnC,MAAO,GAAG,EAAU,GAAG,EAAK,GAAG,GACjC,CAQA,SAAgB,EAAwB,EAAgE,CACtG,IAAM,EAAQ,CACZ,mBAAG,IAAI,IAAI,CAAC,SAAU,YAAa,OAAQ,YAAa,OAAQ,GAAG,EAAS,IAAK,GAAY,EAAQ,IAAI,CAAC,CAAC,CAC7G,EACA,OAAO,EACJ,IAAK,GAAY,CAChB,IAAI,EAAU,EAAQ,QACtB,IAAK,IAAM,KAAQ,EAAO,EAAU,EAAgB,EAAS,CAAI,EACjE,MAAO,IAAI,EAAQ,KAAK,KAAK,EAAQ,MAAM,EAAQ,KAAK,EAC1D,CAAC,CAAC,CACD,KAAK;;CAAM,CAChB"}
|
package/dist/recoverJson.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";const e=require("./error.cjs"),t=1e6,n={'"':`"`,"'":`'`,"“":`”`,"”":`”`,"‘":`’`,"’":`’`},r={true:`true`,false:`false`,null:`null`,True:`true`,False:`false`,None:`null`}
|
|
2
2
|
/*! JSON recovery informed by jsonrepair, Copyright (c) 2020-2026 Jos de Jong (ISC). See NOTICE. */
|
|
3
|
-
const e=1e6,t={'"':`"`,"'":`'`,"“":`”`,"”":`”`,"‘":`’`,"’":`’`},n={true:`true`,false:`false`,null:`null`,True:`true`,False:`false`,None:`null`};function r(t){let n={candidates:[],errors:[]};if(t.length>e)return n.errors.push({offset:e,message:`JSON recovery input exceeds one million characters`}),n;let r=[...t.matchAll(/^(?: {0,3})(`{3,}|~{3,})[^\r\n]*(?:\r\n|[\r\n]|$)/gm)].flatMap(e=>{let n=e[1],r=e.index+e[0].indexOf(n)+n.length,i=e.index+e[0].length,o=t.slice(r,i),s=/^[ \t]*json(?=[ \t{["'“”‘’])[ \t]*/i.exec(o),c=s===null?i:r+s[0].length,l=t[c]===`{`||t[c]===`[`||a(t,c,i)?c:i;return n[0]==="`"&&l===i&&o.includes("`")?[]:[{index:e.index,marker:n,start:l}]});if(r.length>0){let e=0;for(let a of r){if(a.index<e)continue;i(t,e,a.index,n);let o=n.candidates.at(-1)?.end??e;if(o>a.index){e=o;continue}let{marker:s,start:c}=a,l=RegExp(`^ {0,3}${s[0]}{${s.length},}[ \\t]*$`,`gm`);l.lastIndex=c;let u=l.exec(t),d=u?.index??t.length;i(t,c,d,n);let f=n.candidates.at(-1)?.end??c;if(f>d){l.lastIndex=f;let a=l.exec(t);if(a!==null&&!r.some(e=>e.index>=f&&e.index<a.index)){i(t,f,a.index,n),e=a.index+a[0].length;continue}}e=Math.max(n.candidates.at(-1)?.end??c,u===null?t.length:u.index+u[0].length)}i(t,e,t.length,n)}else i(t,0,t.length,n);if(n.candidates.length===32){let e={offset:n.candidates.at(-1).end,message:`JSON candidate limit reached; extraction may be incomplete`};n.errors.length===32?n.errors[31]=e:n.errors.push(e)}return n}function i(e,n,r,c,l=!1){if(c.candidates.length>=32)return;let u=n,d=0,f=!1,p=!0,m=n,h=n,g=n;for(;u<r&&/\s/.test(e[u]);)u++;let _=u,v=new o(e,u,r);l||v.space();let y=v.index;if(y>=r){v.repairs.some(e=>e.kind===`incomplete`)&&c.errors.length<32&&c.errors.push({offset:u,message:`Incomplete leading JSON comment`});return}let b=e[y],x=a(e,y,r)||b===`{`||b===`[`;for(x||(u=y);u<r&&c.candidates.length<32&&d<32;){if(!x||u!==_)for(;u<r&&e[u]!==`{`&&e[u]!==`[`&&!(p&&a(e,u,r));){let t=u===n||!/[\w+.-]/.test(e[u-1])?s(e,u,r):void 0;if(t!==void 0){if(u>=h){let t=e.slice(u,r).search(/\s/);h=t===-1?r:u+t,g=u}if(u>=g){let t=e.slice(u,h).search(/[{[]/);g=t===-1?h:u+t}g<h&&(m=Math.max(m,h)),u=Math.min(t,g),p=!1;continue}if(!l&&e[u]===`/`){let t=new o(e,u,r);if(t.space(),t.index>u){t.repairs.some(e=>e.kind===`incomplete`)&&c.errors.length<32&&c.errors.push({offset:u,message:`Possibly unterminated comment-like span in prose`}),i(e,u+2,t.index,c,!0),p||=/[\r\n]/.test(e.slice(u,t.index)),u=t.index;continue}}/[\r\n]/.test(e[u])?p=!0:/[\s,]/.test(e[u])||(p=!1),u++}if(u>=r||c.candidates.length>=32)break;let y=x&&u===_?v:new o(e,u,r),b=y.index;try{let n=y.value(0);if(!l&&(e[b]===`{`||e[b]===`[`)&&y.index===r&&r<e.length){let t=new o(e,u,e.length);try{let e=t.value(0);t.index>r&&t.repairs.every(e=>e.reason===`unescaped-control-character`)&&(t.repairs.push({offset:r,kind:`ambiguous`,reason:`literal-fence-in-string`}),y=t,n=e)}catch{}}let i=y.index;if(e[b]!==`{`&&e[b]!==`[`&&!y.finishScalar(r,b)){p=!1,u=i;continue}if(y.space(),!l&&d===0&&y.index<r&&/[}\]]/.test(e[y.index])){let t=y.index;for(;y.index<r&&/[}\]]/.test(e[y.index]);)y.repairs.push({offset:y.index,kind:`ambiguous`,reason:`surplus-closing-bracket`}),y.index++,y.space();if(c.errors.length<32){let n=Math.min(r,t+256);c.errors.push({offset:t,message:`Surplus closing brackets and possible continuation (${n<r?`truncated excerpt`:`excerpt`}): ${JSON.stringify(e.slice(t,n))}`})}}if(e[b]in t&&y.repairs.some(e=>e.reason===`trailing-scalar-content`)&&c.errors.length<32){let t=Math.min(r,i+256);c.errors.push({offset:i,message:`Ambiguous quoted-scalar tail (${t<r?`truncated excerpt`:`excerpt`}): ${JSON.stringify(e.slice(i,t))}`})}l&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`fragment-in-comment-like-prose`}),d>0&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`fragment-after-rejected-document`}),f&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`fragment-after-ambiguous-scalar`}),u<m&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`ambiguous-uri-boundary`}),f||=y.repairs.some(e=>e.reason===`trailing-scalar-content`),c.candidates.push({value:JSON.parse(n),json:n,start:u,end:y.index,repairs:y.repairs,requiresConfirmation:y.repairs.some(e=>e.kind!==`syntax`)})}catch(e){c.errors.length<32&&c.errors.push({offset:y.index,message:e instanceof Error?e.message:String(e)}),d++,u=b+1,p=!1;continue}u=Math.max(u+1,y.index),p=!0}}function a(e,r,i){let a=e[r];if(a===void 0)return!1;let o=/^([A-Za-z]+)/.exec(e.slice(r,i))?.[1];return a in t||/[-\d]/.test(a)||o!==void 0&&(Object.hasOwn(n,o)||Object.keys(n).some(e=>e.startsWith(o))&&/^[^\S\r\n]*(?:[\r\n]|$)/.test(e.slice(r+o.length,i)))}var o=class e{repairs=[];text;end;index;constructor(e,t,n){this.text=e,this.index=t,this.end=n}finishScalar(e,n){let r=this.index,i=this.text.slice(n,r),a=i===`-`&&/\s/.test(this.text[r]??``),o=this.text[n]in t||this.repairs.some(e=>e.reason===`unquoted-value`);return this.space(),a?!1:this.index>=e?!0:/[\r\n]/.test(this.text.slice(r,this.index))?(this.repair(`ambiguous`,`scalar-before-prose`,r),!0):/^\d+[.)]$/.test(i)&&/[ \t]/.test(this.text[r]??``)?!1:o||/^[\p{P}\p{S}]/u.test(this.text.slice(this.index,e))?(this.repair(`ambiguous`,`trailing-scalar-content`,r),!0):!1}value(e){if(e>128)throw Error(`JSON nesting exceeds 128 levels`);this.space();let r=this.text[this.index];if(this.index>=this.end||r===`,`||r===`}`||r===`]`)return this.repair(`incomplete`,`missing-value`),`null`;if(r===`{`||r===`[`){if(e>=128)throw Error(`JSON nesting exceeds 128 levels`);return this.container(e,r===`{`)}if(r!==void 0&&r in t)return this.string(e>0?`value`:`root`);let i=this.index,a=s(this.text,i,this.end);if(a!==void 0)this.index=a;else for(;this.index<this.end&&!/[\s,}\]]/.test(this.text[this.index])&&!(e===0&&/[{[]/.test(this.text[this.index]))&&!this.comment();)this.index++;if(this.index===i)throw Error(`Expected a JSON value`);let o=this.text.slice(i,this.index);if(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(o))return o;if(Object.hasOwn(n,o)){let e=n[o];return e!==o&&this.repair(`syntax`,`python-keyword`,i),e}return this.repair(this.index>=this.end?`incomplete`:`ambiguous`,`unquoted-value`,i),JSON.stringify(o)}container(e,n){this.index++;let r=n?`}`:`]`,i=[],a=new Set,o=!1,s=this.index;for(;;){if(this.space(),this.index>=this.end||this.text[this.index]===r)return this.index>=this.end?this.repair(`incomplete`,`missing-${r}`):this.index++,o&&this.repair(`syntax`,`trailing-comma`,s),(n?`{`:`[`)+i.join(`,`)+r;if(this.text[this.index]===`}`||this.text[this.index]===`]`)throw Error(`Mismatched closing bracket`);if(this.text[this.index]===`,`){n?this.repair(`ambiguous`,`extra-comma`):(i.push(`null`),this.repair(`incomplete`,`missing-value`)),s=this.index,o=!0,this.index++;continue}let c;if(n){let e=this.index;if(this.text[this.index]in t)c=this.string();else{for(;this.index<this.end&&!/[\s:,{}[\]]/.test(this.text[this.index])&&!this.comment();)this.index++;if(this.index===e)throw Error(`Expected an object key`);let t=this.text.slice(e,this.index);c=JSON.stringify(t),this.repair(/["'“”‘’]/.test(t)?`ambiguous`:`syntax`,`unquoted-key`,e)}let n=JSON.parse(c);a.has(n)&&this.repair(`ambiguous`,`duplicate-key`,e),a.add(n),this.space(),this.text[this.index]===`:`?this.index++:this.repair(`ambiguous`,`missing-colon`)}let l=this.value(e+1);i.push(c===void 0?l:`${c}:${l}`),this.space(),o=this.text[this.index]===`,`,o?(s=this.index,this.index++):this.index<this.end&&this.text[this.index]!==r&&this.repair(`syntax`,`missing-comma`)}}string(e=`key`){let n=this.index,r=this.text[this.index++],i=t[r];r!==`"`&&this.repair(`syntax`,`non-json-quote`,n);let a=``,o=``,s=e=>{a+=e,o=(o+e).slice(-2)},c=!1,l=`"“”`.includes(r)?`"“”`:`'‘’`,u;for(;this.index<this.end;){let t=this.text[this.index++];if(`'‘’`.includes(r)&&`'’`.includes(t)&&/[\p{L}\p{N}]$/u.test(o)&&/^[\p{L}\p{N}]/u.test(this.text.slice(this.index,this.end))){this.repair(`ambiguous`,`literal-apostrophe`,this.index-1),s(t);continue}if(l.includes(t)){let n=this.text.slice(this.index,this.end).trimStart()[0],r=n===void 0||/[,}\]:"']/.test(n);if(t===i){if(c){c=!1,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}if(e!==`root`&&u!==void 0&&!r)return this.index=u.end,this.repairs.length=u.repairCount,this.repair(`ambiguous`,`mismatched-quote`,this.index-1),JSON.stringify(u.value);let n=this.text.indexOf(i,this.index),o=this.text.slice(n+1,this.end).trimStart()[0];if(e===`value`&&!r&&!/\s/.test(this.text[this.index]??``)&&n>this.index&&n<this.end&&o!==void 0&&(!/[,}:\]]/.test(o)||o===`,`&&this.continuesStringAfterComma(n+1,i))&&!/[\\*:,{}[\]\r\n]|\/\//.test(this.text.slice(this.index,n))&&!this.startsKey(n)){c=!0,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}return JSON.stringify(a)}r&&(u??={end:this.index,value:a,repairCount:this.repairs.length})}if(t!==`\\`){t.codePointAt(0)<32&&this.repair(`syntax`,`unescaped-control-character`,this.index-1),s(t);continue}let n=this.index-1;if(this.index>=this.end){s(`\\`),this.repair(`incomplete`,`truncated-escape`,n);break}let d=this.text[this.index++];if(d===`u`){let e=this.text.slice(this.index,Math.min(this.index+4,this.end));/^[\da-fA-F]{4}$/.test(e)?(s(String.fromCodePoint(Number.parseInt(e,16))),this.index+=4):(s(String.raw`\u`),this.repair(/^[\da-fA-F]{0,3}$/.test(e)?`incomplete`:`ambiguous`,`invalid-unicode-escape`,n))}else String.raw`"\/bfnrt`.includes(d)?s(JSON.parse(`"\\${d}"`)):d===`'`&&r===`'`?s(`'`):(s(`\\${d}`),this.repair(`ambiguous`,`invalid-escape`,n))}return this.repair(`incomplete`,`unterminated-string`,n),JSON.stringify(a)}continuesStringAfterComma(t,n){let r=new e(this.text,t-1,this.end);r.string();let i=r.index-1;if(this.text[i]!==n||r.repairs.some(e=>![`non-json-quote`,`literal-apostrophe`,`unescaped-control-character`].includes(e.reason)))return!1;let a=this.text.slice(t,i),o=this.text.slice(i+1,this.end).trimStart()[0];return/^\s*,\s*[\p{L}\p{N}]/u.test(a)&&!/[\\:{}[\]]/.test(a)&&(o===void 0||/[,}\]]/.test(o))}startsKey(t){let n=new e(this.text,t,this.end);return n.string(),n.space(),this.text[n.index]===`:`}space(){for(;this.index<this.end;)if(/\s/.test(this.text[this.index]))/[ \t\r\n]/.test(this.text[this.index])||this.repair(`syntax`,`non-json-whitespace`),this.index++;else if(this.text.startsWith(`//`,this.index))for(this.repair(`syntax`,`line-comment`);this.index<this.end&&!/[\r\n]/.test(this.text[this.index]);)this.index++;else if(this.text.startsWith(`/*`,this.index)){let e=this.text.indexOf(`*/`,this.index+2);this.repair(e===-1||e>=this.end?`incomplete`:`syntax`,`block-comment`),this.index=e===-1||e>=this.end?this.end:e+2}else break}repair(e,t,n=this.index){this.repairs.push({offset:n,kind:e,reason:t})}comment(){return this.text.startsWith(`//`,this.index)||this.text.startsWith(`/*`,this.index)}};function s(e,t,n){let r=/^[A-Za-z][A-Za-z\d+.-]*:\/\//.exec(e.slice(t,n));if(r===null)return;let i=t+r[0].length,a=0;for(;i<n&&!/[\s}]/.test(e[i])&&(e[i]!==`,`||a!==0);){if(e[i]===`[`)a++;else if(e[i]===`]`){if(a===0)break;a--}i++}return i}exports.recoverJson=r;
|
|
3
|
+
;function i(e){let n={candidates:[],errors:[]};if(e.length>t)return n.errors.push({offset:t,message:`JSON recovery input exceeds one million characters`}),n;let r=[...e.matchAll(/^(?: {0,3})(`{3,}|~{3,})[^\r\n]*(?:\r\n|[\r\n]|$)/gm)].flatMap(t=>{let n=t[1],r=t.index+t[0].indexOf(n)+n.length,i=t.index+t[0].length,a=e.slice(r,i),s=/^[ \t]*json(?=[ \t{["'“”‘’])[ \t]*/i.exec(a),c=s===null?i:r+s[0].length,l=e[c]===`{`||e[c]===`[`||o(e,c,i)?c:i;return n[0]==="`"&&l===i&&a.includes("`")?[]:[{index:t.index,marker:n,start:l}]});if(r.length>0){let t=0;for(let i of r){if(i.index<t)continue;a(e,t,i.index,n);let o=n.candidates.at(-1)?.end??t;if(o>i.index){t=o;continue}let{marker:s,start:c}=i,l=RegExp(`^ {0,3}${s[0]}{${s.length},}[ \\t]*$`,`gm`);l.lastIndex=c;let u=l.exec(e),d=u?.index??e.length;a(e,c,d,n);let f=n.candidates.at(-1)?.end??c;if(f>d){l.lastIndex=f;let i=l.exec(e);if(i!==null&&!r.some(e=>e.index>=f&&e.index<i.index)){a(e,f,i.index,n),t=i.index+i[0].length;continue}}t=Math.max(n.candidates.at(-1)?.end??c,u===null?e.length:u.index+u[0].length)}a(e,t,e.length,n)}else a(e,0,e.length,n);if(n.candidates.length===32){let e={offset:n.candidates.at(-1).end,message:`JSON candidate limit reached; extraction may be incomplete`};n.errors.length===32?n.errors[31]=e:n.errors.push(e)}return n}function a(t,r,i,l,u=!1){if(l.candidates.length>=32)return;let d=r,f=0,p=!1,m=!0,h=r,g=r,_=r;for(;d<i&&/\s/.test(t[d]);)d++;let v=d,y=new s(t,d,i);u||y.space();let b=y.index;if(b>=i){y.repairs.some(e=>e.kind===`incomplete`)&&l.errors.length<32&&l.errors.push({offset:d,message:`Incomplete leading JSON comment`});return}let x=t[b],S=o(t,b,i)||x===`{`||x===`[`;for(S||(d=b);d<i&&l.candidates.length<32&&f<32;){if(!S||d!==v)for(;d<i&&t[d]!==`{`&&t[d]!==`[`&&!(m&&o(t,d,i));){let e=d===r||!/[\w+.-]/.test(t[d-1])?c(t,d,i):void 0;if(e!==void 0){if(d>=g){let e=t.slice(d,i).search(/\s/);g=e===-1?i:d+e,_=d}if(d>=_){let e=t.slice(d,g).search(/[{[]/);_=e===-1?g:d+e}_<g&&(h=Math.max(h,g)),d=Math.min(e,_),m=!1;continue}if(!u&&t[d]===`/`){let e=new s(t,d,i);if(e.space(),e.index>d){e.repairs.some(e=>e.kind===`incomplete`)&&l.errors.length<32&&l.errors.push({offset:d,message:`Possibly unterminated comment-like span in prose`}),a(t,d+2,e.index,l,!0),m||=/[\r\n]/.test(t.slice(d,e.index)),d=e.index;continue}}/[\r\n]/.test(t[d])?m=!0:/[\s,]/.test(t[d])||(m=!1),d++}if(d>=i||l.candidates.length>=32)break;let b=S&&d===v?y:new s(t,d,i),x=b.index;try{let e=b.value(0);if(!u&&(t[x]===`{`||t[x]===`[`)&&b.index===i&&i<t.length){let n=new s(t,d,t.length);try{let t=n.value(0);n.index>i&&n.repairs.every(e=>e.reason===`unescaped-control-character`)&&(n.repairs.push({offset:i,kind:`ambiguous`,reason:`literal-fence-in-string`}),b=n,e=t)}catch{}}let r=b.index;if(t[x]!==`{`&&t[x]!==`[`&&!b.finishScalar(i,x)){m=!1,d=r;continue}if(b.space(),!u&&f===0&&b.index<i&&/[}\]]/.test(t[b.index])){let e=b.index;for(;b.index<i&&/[}\]]/.test(t[b.index]);)b.repairs.push({offset:b.index,kind:`ambiguous`,reason:`surplus-closing-bracket`}),b.index++,b.space();if(l.errors.length<32){let n=Math.min(i,e+256);l.errors.push({offset:e,message:`Surplus closing brackets and possible continuation (${n<i?`truncated excerpt`:`excerpt`}): ${JSON.stringify(t.slice(e,n))}`})}}if(t[x]in n&&b.repairs.some(e=>e.reason===`trailing-scalar-content`)&&l.errors.length<32){let e=Math.min(i,r+256);l.errors.push({offset:r,message:`Ambiguous quoted-scalar tail (${e<i?`truncated excerpt`:`excerpt`}): ${JSON.stringify(t.slice(r,e))}`})}u&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`fragment-in-comment-like-prose`}),f>0&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`fragment-after-rejected-document`}),p&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`fragment-after-ambiguous-scalar`}),d<h&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`ambiguous-uri-boundary`}),p||=b.repairs.some(e=>e.reason===`trailing-scalar-content`),l.candidates.push({value:JSON.parse(e),json:e,start:d,end:b.index,repairs:b.repairs,requiresConfirmation:b.repairs.some(e=>e.kind!==`syntax`)})}catch(t){l.errors.length<32&&l.errors.push({offset:b.index,message:e.getErrorMessage(t)}),f++,d=x+1,m=!1;continue}d=Math.max(d+1,b.index),m=!0}}function o(e,t,i){let a=e[t];if(a===void 0)return!1;let o=/^([A-Za-z]+)/.exec(e.slice(t,i))?.[1];return a in n||/[-\d]/.test(a)||o!==void 0&&(Object.hasOwn(r,o)||Object.keys(r).some(e=>e.startsWith(o))&&/^[^\S\r\n]*(?:[\r\n]|$)/.test(e.slice(t+o.length,i)))}var s=class e{repairs=[];text;end;index;constructor(e,t,n){this.text=e,this.index=t,this.end=n}finishScalar(e,t){let r=this.index,i=this.text.slice(t,r),a=i===`-`&&/\s/.test(this.text[r]??``),o=this.text[t]in n||this.repairs.some(e=>e.reason===`unquoted-value`);return this.space(),a?!1:this.index>=e?!0:/[\r\n]/.test(this.text.slice(r,this.index))?(this.repair(`ambiguous`,`scalar-before-prose`,r),!0):/^\d+[.)]$/.test(i)&&/[ \t]/.test(this.text[r]??``)?!1:o||/^[\p{P}\p{S}]/u.test(this.text.slice(this.index,e))?(this.repair(`ambiguous`,`trailing-scalar-content`,r),!0):!1}value(e){if(e>128)throw Error(`JSON nesting exceeds 128 levels`);this.space();let t=this.text[this.index];if(this.index>=this.end||t===`,`||t===`}`||t===`]`)return this.repair(`incomplete`,`missing-value`),`null`;if(t===`{`||t===`[`){if(e>=128)throw Error(`JSON nesting exceeds 128 levels`);return this.container(e,t===`{`)}if(t!==void 0&&t in n)return this.string(e>0?`value`:`root`);let i=this.index,a=c(this.text,i,this.end);if(a!==void 0)this.index=a;else for(;this.index<this.end&&!/[\s,}\]]/.test(this.text[this.index])&&!(e===0&&/[{[]/.test(this.text[this.index]))&&!this.comment();)this.index++;if(this.index===i)throw Error(`Expected a JSON value`);let o=this.text.slice(i,this.index);if(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(o))return o;if(Object.hasOwn(r,o)){let e=r[o];return e!==o&&this.repair(`syntax`,`python-keyword`,i),e}return this.repair(this.index>=this.end?`incomplete`:`ambiguous`,`unquoted-value`,i),JSON.stringify(o)}container(e,t){this.index++;let r=t?`}`:`]`,i=[],a=/* @__PURE__ */ new Set,o=!1,s=this.index;for(;;){if(this.space(),this.index>=this.end||this.text[this.index]===r)return this.index>=this.end?this.repair(`incomplete`,`missing-${r}`):this.index++,o&&this.repair(`syntax`,`trailing-comma`,s),(t?`{`:`[`)+i.join(`,`)+r;if(this.text[this.index]===`}`||this.text[this.index]===`]`)throw Error(`Mismatched closing bracket`);if(this.text[this.index]===`,`){t?this.repair(`ambiguous`,`extra-comma`):(i.push(`null`),this.repair(`incomplete`,`missing-value`)),s=this.index,o=!0,this.index++;continue}let c;if(t){let e=this.index;if(this.text[this.index]in n)c=this.string();else{for(;this.index<this.end&&!/[\s:,{}[\]]/.test(this.text[this.index])&&!this.comment();)this.index++;if(this.index===e)throw Error(`Expected an object key`);let t=this.text.slice(e,this.index);c=JSON.stringify(t),this.repair(/["'“”‘’]/.test(t)?`ambiguous`:`syntax`,`unquoted-key`,e)}let t=JSON.parse(c);a.has(t)&&this.repair(`ambiguous`,`duplicate-key`,e),a.add(t),this.space(),this.text[this.index]===`:`?this.index++:this.repair(`ambiguous`,`missing-colon`)}let l=this.value(e+1);i.push(c===void 0?l:`${c}:${l}`),this.space(),o=this.text[this.index]===`,`,o?(s=this.index,this.index++):this.index<this.end&&this.text[this.index]!==r&&this.repair(`syntax`,`missing-comma`)}}string(e=`key`){let t=this.index,r=this.text[this.index++],i=n[r];r!==`"`&&this.repair(`syntax`,`non-json-quote`,t);let a=``,o=``,s=e=>{a+=e,o=(o+e).slice(-2)},c=!1,l=`"“”`.includes(r)?`"“”`:`'‘’`,u;for(;this.index<this.end;){let t=this.text[this.index++];if(`'‘’`.includes(r)&&`'’`.includes(t)&&/[\p{L}\p{N}]$/u.test(o)&&/^[\p{L}\p{N}]/u.test(this.text.slice(this.index,this.end))){this.repair(`ambiguous`,`literal-apostrophe`,this.index-1),s(t);continue}if(l.includes(t)){let n=this.text.slice(this.index,this.end).trimStart()[0],r=n===void 0||/[,}\]:"']/.test(n);if(t===i){if(c){c=!1,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}if(e!==`root`&&u!==void 0&&!r)return this.index=u.end,this.repairs.length=u.repairCount,this.repair(`ambiguous`,`mismatched-quote`,this.index-1),JSON.stringify(u.value);let n=this.text.indexOf(i,this.index),o=this.text.slice(n+1,this.end).trimStart()[0];if(e===`value`&&!r&&!/\s/.test(this.text[this.index]??``)&&n>this.index&&n<this.end&&o!==void 0&&(!/[,}:\]]/.test(o)||o===`,`&&this.continuesStringAfterComma(n+1,i))&&!/[\\*:,{}[\]\r\n]|\/\//.test(this.text.slice(this.index,n))&&!this.startsKey(n)){c=!0,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}return JSON.stringify(a)}r&&(u??={end:this.index,value:a,repairCount:this.repairs.length})}if(t!==`\\`){t.codePointAt(0)<32&&this.repair(`syntax`,`unescaped-control-character`,this.index-1),s(t);continue}let n=this.index-1;if(this.index>=this.end){s(`\\`),this.repair(`incomplete`,`truncated-escape`,n);break}let d=this.text[this.index++];if(d===`u`){let e=this.text.slice(this.index,Math.min(this.index+4,this.end));/^[\da-fA-F]{4}$/.test(e)?(s(String.fromCodePoint(Number.parseInt(e,16))),this.index+=4):(s(String.raw`\u`),this.repair(/^[\da-fA-F]{0,3}$/.test(e)?`incomplete`:`ambiguous`,`invalid-unicode-escape`,n))}else String.raw`"\/bfnrt`.includes(d)?s(JSON.parse(`"\\${d}"`)):d===`'`&&r===`'`?s(`'`):(s(`\\${d}`),this.repair(`ambiguous`,`invalid-escape`,n))}return this.repair(`incomplete`,`unterminated-string`,t),JSON.stringify(a)}continuesStringAfterComma(t,n){let r=new e(this.text,t-1,this.end);r.string();let i=r.index-1;if(this.text[i]!==n||r.repairs.some(e=>![`non-json-quote`,`literal-apostrophe`,`unescaped-control-character`].includes(e.reason)))return!1;let a=this.text.slice(t,i),o=this.text.slice(i+1,this.end).trimStart()[0];return/^\s*,\s*[\p{L}\p{N}]/u.test(a)&&!/[\\:{}[\]]/.test(a)&&(o===void 0||/[,}\]]/.test(o))}startsKey(t){let n=new e(this.text,t,this.end);return n.string(),n.space(),this.text[n.index]===`:`}space(){for(;this.index<this.end;)if(/\s/.test(this.text[this.index]))/[ \t\r\n]/.test(this.text[this.index])||this.repair(`syntax`,`non-json-whitespace`),this.index++;else if(this.text.startsWith(`//`,this.index))for(this.repair(`syntax`,`line-comment`);this.index<this.end&&!/[\r\n]/.test(this.text[this.index]);)this.index++;else if(this.text.startsWith(`/*`,this.index)){let e=this.text.indexOf(`*/`,this.index+2);this.repair(e===-1||e>=this.end?`incomplete`:`syntax`,`block-comment`),this.index=e===-1||e>=this.end?this.end:e+2}else break}repair(e,t,n=this.index){this.repairs.push({offset:n,kind:e,reason:t})}comment(){return this.text.startsWith(`//`,this.index)||this.text.startsWith(`/*`,this.index)}};function c(e,t,n){let r=/^[A-Za-z][A-Za-z\d+.-]*:\/\//.exec(e.slice(t,n));if(r===null)return;let i=t+r[0].length,a=0;for(;i<n&&!/[\s}]/.test(e[i])&&(e[i]!==`,`||a!==0);){if(e[i]===`[`)a++;else if(e[i]===`]`){if(a===0)break;a--}i++}return i}exports.recoverJson=i;
|
|
4
4
|
//# sourceMappingURL=recoverJson.cjs.map
|
package/dist/recoverJson.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recoverJson.cjs","names":[],"sources":["../src/recoverJson.ts"],"sourcesContent":["/*! JSON recovery informed by jsonrepair, Copyright (c) 2020-2026 Jos de Jong (ISC). See NOTICE. */\n\nexport interface JsonRepair {\n /** UTF-16 offset in the original response. */\n offset: number;\n kind: 'syntax' | 'incomplete' | 'ambiguous';\n reason: string;\n}\n\nexport interface RecoveredJson {\n value: unknown;\n json: string;\n start: number;\n end: number;\n repairs: JsonRepair[];\n /** Missing content or an ambiguous interpretation requires confirmation before acting on this value. */\n requiresConfirmation: boolean;\n}\n\nexport interface JsonRecovery {\n candidates: RecoveredJson[];\n errors: { offset: number; message: string }[];\n}\n\nconst MAX_INPUT_LENGTH = 1_000_000;\nconst MAX_DEPTH = 128;\nconst MAX_CANDIDATES = 32;\nconst MAX_ERRORS = 32;\nconst MAX_DIAGNOSTIC_EXCERPT = 256;\nconst QUOTES: Record<string, string> = { '\"': '\"', \"'\": \"'\", '“': '”', '”': '”', '‘': '’', '’': '’' };\nconst KEYWORDS: Record<string, string> = {\n true: 'true',\n false: 'false',\n null: 'null',\n True: 'true',\n False: 'false',\n None: 'null',\n};\n\n/**\n * Extracts JSON values from a response, repairing common LLM syntax and retaining repair provenance.\n * Offsets refer to the original string. All candidates are returned: choosing among multiple answers,\n * schema validation, and provider truncation signals belong to the caller. No schema values are coerced.\n * Bounded to one million UTF-16 code units, 128 nesting levels, and 32 candidates/errors each.\n * A region is abandoned after 32 failed starts; later Markdown regions can still yield candidates.\n */\nexport function recoverJson(text: string): JsonRecovery {\n const result: JsonRecovery = { candidates: [], errors: [] };\n if (text.length > MAX_INPUT_LENGTH) {\n result.errors.push({ offset: MAX_INPUT_LENGTH, message: 'JSON recovery input exceeds one million characters' });\n return result;\n }\n const fences = [...text.matchAll(/^(?: {0,3})(`{3,}|~{3,})[^\\r\\n]*(?:\\r\\n|[\\r\\n]|$)/gm)].flatMap((fence) => {\n const marker = fence[1]!;\n const markerEnd = fence.index + fence[0].indexOf(marker) + marker.length;\n const lineEnd = fence.index + fence[0].length;\n const info = text.slice(markerEnd, lineEnd);\n const inlinePrefix = /^[ \\t]*json(?=[ \\t{[\"'“”‘’])[ \\t]*/i.exec(info);\n const inlineStart = inlinePrefix === null ? lineEnd : markerEnd + inlinePrefix[0].length;\n const start =\n text[inlineStart] === '{' || text[inlineStart] === '[' || scalarStart(text, inlineStart, lineEnd)\n ? inlineStart\n : lineEnd;\n return marker[0] === '`' && start === lineEnd && info.includes('`') ? [] : [{ index: fence.index, marker, start }];\n });\n if (fences.length > 0) {\n let consumed = 0;\n for (const fence of fences) {\n if (fence.index < consumed) continue;\n extractRegion(text, consumed, fence.index, result);\n const parsedThrough = result.candidates.at(-1)?.end ?? consumed;\n if (parsedThrough > fence.index) {\n consumed = parsedThrough;\n continue;\n }\n const { marker, start } = fence;\n const close = new RegExp(`^ {0,3}${marker[0]}{${marker.length},}[ \\\\t]*$`, 'gm');\n close.lastIndex = start;\n const match = close.exec(text);\n const end = match?.index ?? text.length;\n extractRegion(text, start, end, result);\n const extendedEnd = result.candidates.at(-1)?.end ?? start;\n if (extendedEnd > end) {\n close.lastIndex = extendedEnd;\n const outerClose = close.exec(text);\n if (outerClose !== null && !fences.some((next) => next.index >= extendedEnd && next.index < outerClose.index)) {\n extractRegion(text, extendedEnd, outerClose.index, result);\n consumed = outerClose.index + outerClose[0].length;\n continue;\n }\n }\n consumed = Math.max(\n result.candidates.at(-1)?.end ?? start,\n match === null ? text.length : match.index + match[0].length\n );\n }\n extractRegion(text, consumed, text.length, result);\n } else {\n extractRegion(text, 0, text.length, result);\n }\n if (result.candidates.length === MAX_CANDIDATES) {\n const error = {\n offset: result.candidates.at(-1)!.end,\n message: 'JSON candidate limit reached; extraction may be incomplete',\n };\n if (result.errors.length === MAX_ERRORS) result.errors[MAX_ERRORS - 1] = error;\n else result.errors.push(error);\n }\n return result;\n}\n\nfunction extractRegion(text: string, start: number, end: number, result: JsonRecovery, commentFragment = false): void {\n if (result.candidates.length >= MAX_CANDIDATES) return;\n let index = start;\n let failures = 0;\n let ambiguousScalarTail = false;\n let scalarBoundary = true;\n let uriBoundaryEnd = start;\n let uriTokenEnd = start;\n let uriContainerStart = start;\n while (index < end && /\\s/.test(text[index]!)) index++;\n const firstIndex = index;\n const initialParser = new RecoveryParser(text, index, end);\n if (!commentFragment) initialParser.space();\n const initialValueStart = initialParser.index;\n if (initialValueStart >= end) {\n if (initialParser.repairs.some((repair) => repair.kind === 'incomplete') && result.errors.length < MAX_ERRORS)\n result.errors.push({ offset: index, message: 'Incomplete leading JSON comment' });\n return;\n }\n const first = text[initialValueStart];\n // Within prose, scalar starts need a line boundary; containers may appear inline.\n const rootValue = scalarStart(text, initialValueStart, end);\n const initialValue = rootValue || first === '{' || first === '[';\n if (!initialValue) index = initialValueStart;\n while (index < end && result.candidates.length < MAX_CANDIDATES && failures < MAX_ERRORS) {\n if (!initialValue || index !== firstIndex) {\n while (index < end && text[index] !== '{' && text[index] !== '[') {\n if (scalarBoundary && scalarStart(text, index, end)) break;\n const uriEnd =\n index === start || !/[\\w+.-]/.test(text[index - 1]!) ? unquotedUriEnd(text, index, end) : undefined;\n if (uriEnd !== undefined) {\n if (index >= uriTokenEnd) {\n const whitespace = text.slice(index, end).search(/\\s/);\n uriTokenEnd = whitespace === -1 ? end : index + whitespace;\n uriContainerStart = index;\n }\n if (index >= uriContainerStart) {\n const container = text.slice(index, uriTokenEnd).search(/[{[]/);\n uriContainerStart = container === -1 ? uriTokenEnd : index + container;\n }\n if (uriContainerStart < uriTokenEnd) uriBoundaryEnd = Math.max(uriBoundaryEnd, uriTokenEnd);\n index = Math.min(uriEnd, uriContainerStart);\n scalarBoundary = false;\n continue;\n }\n if (!commentFragment && text[index] === '/') {\n const trivia = new RecoveryParser(text, index, end);\n trivia.space();\n if (trivia.index > index) {\n if (trivia.repairs.some((repair) => repair.kind === 'incomplete') && result.errors.length < MAX_ERRORS)\n result.errors.push({ offset: index, message: 'Possibly unterminated comment-like span in prose' });\n extractRegion(text, index + 2, trivia.index, result, true);\n scalarBoundary ||= /[\\r\\n]/.test(text.slice(index, trivia.index));\n index = trivia.index;\n continue;\n }\n }\n if (/[\\r\\n]/.test(text[index]!)) scalarBoundary = true;\n else if (!/[\\s,]/.test(text[index]!)) scalarBoundary = false;\n index++;\n }\n }\n if (index >= end || result.candidates.length >= MAX_CANDIDATES) break;\n let parser = initialValue && index === firstIndex ? initialParser : new RecoveryParser(text, index, end);\n const valueStart = parser.index;\n try {\n let json = parser.value(0);\n if (\n !commentFragment &&\n (text[valueStart] === '{' || text[valueStart] === '[') &&\n parser.index === end &&\n end < text.length\n ) {\n const extended = new RecoveryParser(text, index, text.length);\n try {\n const extendedJson = extended.value(0);\n if (\n extended.index > end &&\n extended.repairs.every((repair) => repair.reason === 'unescaped-control-character')\n ) {\n extended.repairs.push({ offset: end, kind: 'ambiguous', reason: 'literal-fence-in-string' });\n parser = extended;\n json = extendedJson;\n }\n } catch {\n // Keep the bounded interpretation when extending it is not a complete JSON document.\n }\n }\n const valueEnd = parser.index;\n if (text[valueStart] !== '{' && text[valueStart] !== '[' && !parser.finishScalar(end, valueStart)) {\n scalarBoundary = false;\n index = valueEnd;\n continue;\n }\n parser.space();\n if (!commentFragment && failures === 0 && parser.index < end && /[}\\]]/.test(text[parser.index]!)) {\n const surplusStart = parser.index;\n while (parser.index < end && /[}\\]]/.test(text[parser.index]!)) {\n parser.repairs.push({ offset: parser.index, kind: 'ambiguous', reason: 'surplus-closing-bracket' });\n parser.index++;\n parser.space();\n }\n if (result.errors.length < MAX_ERRORS) {\n const excerptEnd = Math.min(end, surplusStart + MAX_DIAGNOSTIC_EXCERPT);\n result.errors.push({\n offset: surplusStart,\n message: `Surplus closing brackets and possible continuation (${excerptEnd < end ? 'truncated excerpt' : 'excerpt'}): ${JSON.stringify(text.slice(surplusStart, excerptEnd))}`,\n });\n }\n }\n if (\n text[valueStart]! in QUOTES &&\n parser.repairs.some((repair) => repair.reason === 'trailing-scalar-content') &&\n result.errors.length < MAX_ERRORS\n ) {\n const excerptEnd = Math.min(end, valueEnd + MAX_DIAGNOSTIC_EXCERPT);\n result.errors.push({\n offset: valueEnd,\n message: `Ambiguous quoted-scalar tail (${excerptEnd < end ? 'truncated excerpt' : 'excerpt'}): ${JSON.stringify(text.slice(valueEnd, excerptEnd))}`,\n });\n }\n if (commentFragment)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'fragment-in-comment-like-prose' });\n if (failures > 0)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'fragment-after-rejected-document' });\n if (ambiguousScalarTail)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'fragment-after-ambiguous-scalar' });\n if (index < uriBoundaryEnd)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'ambiguous-uri-boundary' });\n ambiguousScalarTail ||= parser.repairs.some((repair) => repair.reason === 'trailing-scalar-content');\n result.candidates.push({\n value: JSON.parse(json),\n json,\n start: index,\n end: parser.index,\n repairs: parser.repairs,\n requiresConfirmation: parser.repairs.some((repair) => repair.kind !== 'syntax'),\n });\n } catch (error) {\n if (result.errors.length < MAX_ERRORS)\n result.errors.push({ offset: parser.index, message: error instanceof Error ? error.message : String(error) });\n failures++;\n index = valueStart + 1;\n scalarBoundary = false;\n continue;\n }\n index = Math.max(index + 1, parser.index);\n scalarBoundary = true;\n }\n}\n\nfunction scalarStart(text: string, start: number, end: number): boolean {\n const first = text[start];\n if (first === undefined) return false;\n const keyword = /^([A-Za-z]+)/.exec(text.slice(start, end))?.[1];\n return (\n first in QUOTES ||\n /[-\\d]/.test(first) ||\n (keyword !== undefined &&\n (Object.hasOwn(KEYWORDS, keyword) ||\n (Object.keys(KEYWORDS).some((word) => word.startsWith(keyword)) &&\n /^[^\\S\\r\\n]*(?:[\\r\\n]|$)/.test(text.slice(start + keyword.length, end)))))\n );\n}\n\nclass RecoveryParser {\n readonly repairs: JsonRepair[] = [];\n readonly text: string;\n readonly end: number;\n index: number;\n\n constructor(text: string, index: number, end: number) {\n this.text = text;\n this.index = index;\n this.end = end;\n }\n\n finishScalar(regionEnd: number, start: number): boolean {\n const valueEnd = this.index;\n const atom = this.text.slice(start, valueEnd);\n const bullet = atom === '-' && /\\s/.test(this.text[valueEnd] ?? '');\n const retainLiteral =\n this.text[start]! in QUOTES || this.repairs.some((repair) => repair.reason === 'unquoted-value');\n this.space();\n if (bullet) return false;\n if (this.index >= regionEnd) return true;\n if (/[\\r\\n]/.test(this.text.slice(valueEnd, this.index))) {\n this.repair('ambiguous', 'scalar-before-prose', valueEnd);\n return true;\n }\n if (/^\\d+[.)]$/.test(atom) && /[ \\t]/.test(this.text[valueEnd] ?? '')) return false;\n if (retainLiteral || /^[\\p{P}\\p{S}]/u.test(this.text.slice(this.index, regionEnd))) {\n this.repair('ambiguous', 'trailing-scalar-content', valueEnd);\n return true;\n }\n return false;\n }\n\n value(depth: number): string {\n if (depth > MAX_DEPTH) throw new Error('JSON nesting exceeds 128 levels');\n this.space();\n const char = this.text[this.index];\n if (this.index >= this.end || char === ',' || char === '}' || char === ']') {\n this.repair('incomplete', 'missing-value');\n return 'null';\n }\n if (char === '{' || char === '[') {\n if (depth >= MAX_DEPTH) throw new Error('JSON nesting exceeds 128 levels');\n return this.container(depth, char === '{');\n }\n if (char !== undefined && char in QUOTES) return this.string(depth > 0 ? 'value' : 'root');\n const start = this.index;\n const uriEnd = unquotedUriEnd(this.text, start, this.end);\n if (uriEnd !== undefined) this.index = uriEnd;\n else\n while (\n this.index < this.end &&\n !/[\\s,}\\]]/.test(this.text[this.index]!) &&\n !(depth === 0 && /[{[]/.test(this.text[this.index]!)) &&\n !this.comment()\n )\n this.index++;\n if (this.index === start) throw new Error('Expected a JSON value');\n const token = this.text.slice(start, this.index);\n if (/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$/.test(token)) return token;\n if (Object.hasOwn(KEYWORDS, token)) {\n const canonical = KEYWORDS[token]!;\n if (canonical !== token) this.repair('syntax', 'python-keyword', start);\n return canonical;\n }\n this.repair(this.index >= this.end ? 'incomplete' : 'ambiguous', 'unquoted-value', start);\n return JSON.stringify(token);\n }\n\n private container(depth: number, object: boolean): string {\n this.index++;\n const close = object ? '}' : ']';\n const items: string[] = [];\n const keys = new Set<string>();\n let afterComma = false;\n let commaOffset = this.index;\n for (;;) {\n this.space();\n if (this.index >= this.end || this.text[this.index] === close) {\n if (this.index >= this.end) this.repair('incomplete', `missing-${close}`);\n else this.index++;\n if (afterComma) this.repair('syntax', 'trailing-comma', commaOffset);\n return (object ? '{' : '[') + items.join(',') + close;\n }\n if (this.text[this.index] === '}' || this.text[this.index] === ']') throw new Error('Mismatched closing bracket');\n if (this.text[this.index] === ',') {\n if (object) this.repair('ambiguous', 'extra-comma');\n else {\n items.push('null');\n this.repair('incomplete', 'missing-value');\n }\n commaOffset = this.index;\n afterComma = true;\n this.index++;\n continue;\n }\n let key: string | undefined;\n if (object) {\n const start = this.index;\n if (this.text[this.index]! in QUOTES) key = this.string();\n else {\n while (this.index < this.end && !/[\\s:,{}[\\]]/.test(this.text[this.index]!) && !this.comment()) this.index++;\n if (this.index === start) throw new Error('Expected an object key');\n const rawKey = this.text.slice(start, this.index);\n key = JSON.stringify(rawKey);\n this.repair(/[\"'“”‘’]/.test(rawKey) ? 'ambiguous' : 'syntax', 'unquoted-key', start);\n }\n const decoded: string = JSON.parse(key);\n if (keys.has(decoded)) this.repair('ambiguous', 'duplicate-key', start);\n keys.add(decoded);\n this.space();\n if (this.text[this.index] === ':') this.index++;\n else this.repair('ambiguous', 'missing-colon');\n }\n const value = this.value(depth + 1);\n items.push(key === undefined ? value : `${key}:${value}`);\n this.space();\n afterComma = this.text[this.index] === ',';\n if (afterComma) {\n commaOffset = this.index;\n this.index++;\n } else if (this.index < this.end && this.text[this.index] !== close) this.repair('syntax', 'missing-comma');\n }\n }\n\n private string(context: 'root' | 'key' | 'value' = 'key'): string {\n const start = this.index;\n const open = this.text[this.index++]!;\n const close = QUOTES[open]!;\n if (open !== '\"') this.repair('syntax', 'non-json-quote', start);\n let value = '';\n let tail = '';\n const append = (text: string): void => {\n value += text;\n tail = (tail + text).slice(-2);\n };\n let embeddedQuote = false;\n const family = '\"“”'.includes(open) ? '\"“”' : \"'‘’\";\n let alternative: { end: number; value: string; repairCount: number } | undefined;\n while (this.index < this.end) {\n const char = this.text[this.index++]!;\n if (\n \"'‘’\".includes(open) &&\n \"'’\".includes(char) &&\n /[\\p{L}\\p{N}]$/u.test(tail) &&\n /^[\\p{L}\\p{N}]/u.test(this.text.slice(this.index, this.end))\n ) {\n this.repair('ambiguous', 'literal-apostrophe', this.index - 1);\n append(char);\n continue;\n }\n if (family.includes(char)) {\n const after = this.text.slice(this.index, this.end).trimStart()[0];\n const delimited = after === undefined || /[,}\\]:\"']/.test(after);\n if (char === close) {\n if (embeddedQuote) {\n embeddedQuote = false;\n this.repair('ambiguous', 'unescaped-quote', this.index - 1);\n append(char);\n continue;\n }\n if (context !== 'root' && alternative !== undefined && !delimited) {\n this.index = alternative.end;\n this.repairs.length = alternative.repairCount;\n this.repair('ambiguous', 'mismatched-quote', this.index - 1);\n return JSON.stringify(alternative.value);\n }\n const nextClose = this.text.indexOf(close, this.index);\n const afterNext = this.text.slice(nextClose + 1, this.end).trimStart()[0];\n if (\n context === 'value' &&\n !delimited &&\n !/\\s/.test(this.text[this.index] ?? '') &&\n nextClose > this.index &&\n nextClose < this.end &&\n afterNext !== undefined &&\n (!/[,}:\\]]/.test(afterNext) ||\n (afterNext === ',' && this.continuesStringAfterComma(nextClose + 1, close))) &&\n !/[\\\\*:,{}[\\]\\r\\n]|\\/\\//.test(this.text.slice(this.index, nextClose)) &&\n !this.startsKey(nextClose)\n ) {\n embeddedQuote = true;\n this.repair('ambiguous', 'unescaped-quote', this.index - 1);\n append(char);\n continue;\n }\n return JSON.stringify(value);\n }\n if (delimited) alternative ??= { end: this.index, value, repairCount: this.repairs.length };\n }\n if (char !== '\\\\') {\n if (char.codePointAt(0)! < 32) this.repair('syntax', 'unescaped-control-character', this.index - 1);\n append(char);\n continue;\n }\n const escapeOffset = this.index - 1;\n if (this.index >= this.end) {\n append('\\\\');\n this.repair('incomplete', 'truncated-escape', escapeOffset);\n break;\n }\n const escape = this.text[this.index++]!;\n if (escape === 'u') {\n const hex = this.text.slice(this.index, Math.min(this.index + 4, this.end));\n if (/^[\\da-fA-F]{4}$/.test(hex)) {\n append(String.fromCodePoint(Number.parseInt(hex, 16)));\n this.index += 4;\n } else {\n append(String.raw`\\u`);\n this.repair(\n /^[\\da-fA-F]{0,3}$/.test(hex) ? 'incomplete' : 'ambiguous',\n 'invalid-unicode-escape',\n escapeOffset\n );\n }\n } else if (String.raw`\"\\/bfnrt`.includes(escape)) {\n append(JSON.parse(`\"\\\\${escape}\"`) as string);\n } else if (escape === \"'\" && open === \"'\") append(\"'\");\n else {\n append(`\\\\${escape}`);\n this.repair('ambiguous', 'invalid-escape', escapeOffset);\n }\n }\n this.repair('incomplete', 'unterminated-string', start);\n return JSON.stringify(value);\n }\n\n private continuesStringAfterComma(start: number, quote: string): boolean {\n const parser = new RecoveryParser(this.text, start - 1, this.end);\n parser.string();\n const end = parser.index - 1;\n if (\n this.text[end] !== quote ||\n parser.repairs.some(\n (repair) => !['non-json-quote', 'literal-apostrophe', 'unescaped-control-character'].includes(repair.reason)\n )\n )\n return false;\n const continuation = this.text.slice(start, end);\n const after = this.text.slice(end + 1, this.end).trimStart()[0];\n return (\n /^\\s*,\\s*[\\p{L}\\p{N}]/u.test(continuation) &&\n !/[\\\\:{}[\\]]/.test(continuation) &&\n (after === undefined || /[,}\\]]/.test(after))\n );\n }\n\n private startsKey(index: number): boolean {\n const parser = new RecoveryParser(this.text, index, this.end);\n parser.string();\n parser.space();\n return this.text[parser.index] === ':';\n }\n\n space(): void {\n while (this.index < this.end) {\n if (/\\s/.test(this.text[this.index]!)) {\n if (!/[ \\t\\r\\n]/.test(this.text[this.index]!)) this.repair('syntax', 'non-json-whitespace');\n this.index++;\n } else if (this.text.startsWith('//', this.index)) {\n this.repair('syntax', 'line-comment');\n while (this.index < this.end && !/[\\r\\n]/.test(this.text[this.index]!)) this.index++;\n } else if (this.text.startsWith('/*', this.index)) {\n const end = this.text.indexOf('*/', this.index + 2);\n this.repair(end === -1 || end >= this.end ? 'incomplete' : 'syntax', 'block-comment');\n this.index = end === -1 || end >= this.end ? this.end : end + 2;\n } else break;\n }\n }\n\n private repair(kind: JsonRepair['kind'], reason: string, offset = this.index): void {\n this.repairs.push({ offset, kind, reason });\n }\n\n private comment(): boolean {\n return this.text.startsWith('//', this.index) || this.text.startsWith('/*', this.index);\n }\n}\n\nfunction unquotedUriEnd(text: string, start: number, end: number): number | undefined {\n const match = /^[A-Za-z][A-Za-z\\d+.-]*:\\/\\//.exec(text.slice(start, end));\n if (match === null) return;\n let index = start + match[0].length;\n let brackets = 0;\n while (index < end && !/[\\s}]/.test(text[index]!)) {\n if (text[index] === ',' && brackets === 0) break;\n if (text[index] === '[') brackets++;\n else if (text[index] === ']') {\n if (brackets === 0) break;\n brackets--;\n }\n index++;\n }\n return index;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"recoverJson.cjs","names":["getErrorMessage"],"sources":["../src/recoverJson.ts"],"sourcesContent":["/*! JSON recovery informed by jsonrepair, Copyright (c) 2020-2026 Jos de Jong (ISC). See NOTICE. */\n\nimport { getErrorMessage } from './error.js';\n\nexport interface JsonRepair {\n /** UTF-16 offset in the original response. */\n offset: number;\n kind: 'syntax' | 'incomplete' | 'ambiguous';\n reason: string;\n}\n\nexport interface RecoveredJson {\n value: unknown;\n json: string;\n start: number;\n end: number;\n repairs: JsonRepair[];\n /** Missing content or an ambiguous interpretation requires confirmation before acting on this value. */\n requiresConfirmation: boolean;\n}\n\nexport interface JsonRecovery {\n candidates: RecoveredJson[];\n errors: { offset: number; message: string }[];\n}\n\nconst MAX_INPUT_LENGTH = 1_000_000;\nconst MAX_DEPTH = 128;\nconst MAX_CANDIDATES = 32;\nconst MAX_ERRORS = 32;\nconst MAX_DIAGNOSTIC_EXCERPT = 256;\nconst QUOTES: Record<string, string> = { '\"': '\"', \"'\": \"'\", '“': '”', '”': '”', '‘': '’', '’': '’' };\nconst KEYWORDS: Record<string, string> = {\n true: 'true',\n false: 'false',\n null: 'null',\n True: 'true',\n False: 'false',\n None: 'null',\n};\n\n/**\n * Extracts JSON values from a response, repairing common LLM syntax and retaining repair provenance.\n * Offsets refer to the original string. All candidates are returned: choosing among multiple answers,\n * schema validation, and provider truncation signals belong to the caller. No schema values are coerced.\n * Bounded to one million UTF-16 code units, 128 nesting levels, and 32 candidates/errors each.\n * A region is abandoned after 32 failed starts; later Markdown regions can still yield candidates.\n */\nexport function recoverJson(text: string): JsonRecovery {\n const result: JsonRecovery = { candidates: [], errors: [] };\n if (text.length > MAX_INPUT_LENGTH) {\n result.errors.push({ offset: MAX_INPUT_LENGTH, message: 'JSON recovery input exceeds one million characters' });\n return result;\n }\n const fences = [...text.matchAll(/^(?: {0,3})(`{3,}|~{3,})[^\\r\\n]*(?:\\r\\n|[\\r\\n]|$)/gm)].flatMap((fence) => {\n const marker = fence[1]!;\n const markerEnd = fence.index + fence[0].indexOf(marker) + marker.length;\n const lineEnd = fence.index + fence[0].length;\n const info = text.slice(markerEnd, lineEnd);\n const inlinePrefix = /^[ \\t]*json(?=[ \\t{[\"'“”‘’])[ \\t]*/i.exec(info);\n const inlineStart = inlinePrefix === null ? lineEnd : markerEnd + inlinePrefix[0].length;\n const start =\n text[inlineStart] === '{' || text[inlineStart] === '[' || scalarStart(text, inlineStart, lineEnd)\n ? inlineStart\n : lineEnd;\n return marker[0] === '`' && start === lineEnd && info.includes('`') ? [] : [{ index: fence.index, marker, start }];\n });\n if (fences.length > 0) {\n let consumed = 0;\n for (const fence of fences) {\n if (fence.index < consumed) continue;\n extractRegion(text, consumed, fence.index, result);\n const parsedThrough = result.candidates.at(-1)?.end ?? consumed;\n if (parsedThrough > fence.index) {\n consumed = parsedThrough;\n continue;\n }\n const { marker, start } = fence;\n const close = new RegExp(`^ {0,3}${marker[0]}{${marker.length},}[ \\\\t]*$`, 'gm');\n close.lastIndex = start;\n const match = close.exec(text);\n const end = match?.index ?? text.length;\n extractRegion(text, start, end, result);\n const extendedEnd = result.candidates.at(-1)?.end ?? start;\n if (extendedEnd > end) {\n close.lastIndex = extendedEnd;\n const outerClose = close.exec(text);\n if (outerClose !== null && !fences.some((next) => next.index >= extendedEnd && next.index < outerClose.index)) {\n extractRegion(text, extendedEnd, outerClose.index, result);\n consumed = outerClose.index + outerClose[0].length;\n continue;\n }\n }\n consumed = Math.max(\n result.candidates.at(-1)?.end ?? start,\n match === null ? text.length : match.index + match[0].length\n );\n }\n extractRegion(text, consumed, text.length, result);\n } else {\n extractRegion(text, 0, text.length, result);\n }\n if (result.candidates.length === MAX_CANDIDATES) {\n const error = {\n offset: result.candidates.at(-1)!.end,\n message: 'JSON candidate limit reached; extraction may be incomplete',\n };\n if (result.errors.length === MAX_ERRORS) result.errors[MAX_ERRORS - 1] = error;\n else result.errors.push(error);\n }\n return result;\n}\n\nfunction extractRegion(text: string, start: number, end: number, result: JsonRecovery, commentFragment = false): void {\n if (result.candidates.length >= MAX_CANDIDATES) return;\n let index = start;\n let failures = 0;\n let ambiguousScalarTail = false;\n let scalarBoundary = true;\n let uriBoundaryEnd = start;\n let uriTokenEnd = start;\n let uriContainerStart = start;\n while (index < end && /\\s/.test(text[index]!)) index++;\n const firstIndex = index;\n const initialParser = new RecoveryParser(text, index, end);\n if (!commentFragment) initialParser.space();\n const initialValueStart = initialParser.index;\n if (initialValueStart >= end) {\n if (initialParser.repairs.some((repair) => repair.kind === 'incomplete') && result.errors.length < MAX_ERRORS)\n result.errors.push({ offset: index, message: 'Incomplete leading JSON comment' });\n return;\n }\n const first = text[initialValueStart];\n // Within prose, scalar starts need a line boundary; containers may appear inline.\n const rootValue = scalarStart(text, initialValueStart, end);\n const initialValue = rootValue || first === '{' || first === '[';\n if (!initialValue) index = initialValueStart;\n while (index < end && result.candidates.length < MAX_CANDIDATES && failures < MAX_ERRORS) {\n if (!initialValue || index !== firstIndex) {\n while (index < end && text[index] !== '{' && text[index] !== '[') {\n if (scalarBoundary && scalarStart(text, index, end)) break;\n const uriEnd =\n index === start || !/[\\w+.-]/.test(text[index - 1]!) ? unquotedUriEnd(text, index, end) : undefined;\n if (uriEnd !== undefined) {\n if (index >= uriTokenEnd) {\n const whitespace = text.slice(index, end).search(/\\s/);\n uriTokenEnd = whitespace === -1 ? end : index + whitespace;\n uriContainerStart = index;\n }\n if (index >= uriContainerStart) {\n const container = text.slice(index, uriTokenEnd).search(/[{[]/);\n uriContainerStart = container === -1 ? uriTokenEnd : index + container;\n }\n if (uriContainerStart < uriTokenEnd) uriBoundaryEnd = Math.max(uriBoundaryEnd, uriTokenEnd);\n index = Math.min(uriEnd, uriContainerStart);\n scalarBoundary = false;\n continue;\n }\n if (!commentFragment && text[index] === '/') {\n const trivia = new RecoveryParser(text, index, end);\n trivia.space();\n if (trivia.index > index) {\n if (trivia.repairs.some((repair) => repair.kind === 'incomplete') && result.errors.length < MAX_ERRORS)\n result.errors.push({ offset: index, message: 'Possibly unterminated comment-like span in prose' });\n extractRegion(text, index + 2, trivia.index, result, true);\n scalarBoundary ||= /[\\r\\n]/.test(text.slice(index, trivia.index));\n index = trivia.index;\n continue;\n }\n }\n if (/[\\r\\n]/.test(text[index]!)) scalarBoundary = true;\n else if (!/[\\s,]/.test(text[index]!)) scalarBoundary = false;\n index++;\n }\n }\n if (index >= end || result.candidates.length >= MAX_CANDIDATES) break;\n let parser = initialValue && index === firstIndex ? initialParser : new RecoveryParser(text, index, end);\n const valueStart = parser.index;\n try {\n let json = parser.value(0);\n if (\n !commentFragment &&\n (text[valueStart] === '{' || text[valueStart] === '[') &&\n parser.index === end &&\n end < text.length\n ) {\n const extended = new RecoveryParser(text, index, text.length);\n try {\n const extendedJson = extended.value(0);\n if (\n extended.index > end &&\n extended.repairs.every((repair) => repair.reason === 'unescaped-control-character')\n ) {\n extended.repairs.push({ offset: end, kind: 'ambiguous', reason: 'literal-fence-in-string' });\n parser = extended;\n json = extendedJson;\n }\n } catch {\n // Keep the bounded interpretation when extending it is not a complete JSON document.\n }\n }\n const valueEnd = parser.index;\n if (text[valueStart] !== '{' && text[valueStart] !== '[' && !parser.finishScalar(end, valueStart)) {\n scalarBoundary = false;\n index = valueEnd;\n continue;\n }\n parser.space();\n if (!commentFragment && failures === 0 && parser.index < end && /[}\\]]/.test(text[parser.index]!)) {\n const surplusStart = parser.index;\n while (parser.index < end && /[}\\]]/.test(text[parser.index]!)) {\n parser.repairs.push({ offset: parser.index, kind: 'ambiguous', reason: 'surplus-closing-bracket' });\n parser.index++;\n parser.space();\n }\n if (result.errors.length < MAX_ERRORS) {\n const excerptEnd = Math.min(end, surplusStart + MAX_DIAGNOSTIC_EXCERPT);\n result.errors.push({\n offset: surplusStart,\n message: `Surplus closing brackets and possible continuation (${excerptEnd < end ? 'truncated excerpt' : 'excerpt'}): ${JSON.stringify(text.slice(surplusStart, excerptEnd))}`,\n });\n }\n }\n if (\n text[valueStart]! in QUOTES &&\n parser.repairs.some((repair) => repair.reason === 'trailing-scalar-content') &&\n result.errors.length < MAX_ERRORS\n ) {\n const excerptEnd = Math.min(end, valueEnd + MAX_DIAGNOSTIC_EXCERPT);\n result.errors.push({\n offset: valueEnd,\n message: `Ambiguous quoted-scalar tail (${excerptEnd < end ? 'truncated excerpt' : 'excerpt'}): ${JSON.stringify(text.slice(valueEnd, excerptEnd))}`,\n });\n }\n if (commentFragment)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'fragment-in-comment-like-prose' });\n if (failures > 0)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'fragment-after-rejected-document' });\n if (ambiguousScalarTail)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'fragment-after-ambiguous-scalar' });\n if (index < uriBoundaryEnd)\n parser.repairs.unshift({ offset: index, kind: 'ambiguous', reason: 'ambiguous-uri-boundary' });\n ambiguousScalarTail ||= parser.repairs.some((repair) => repair.reason === 'trailing-scalar-content');\n result.candidates.push({\n value: JSON.parse(json),\n json,\n start: index,\n end: parser.index,\n repairs: parser.repairs,\n requiresConfirmation: parser.repairs.some((repair) => repair.kind !== 'syntax'),\n });\n } catch (error) {\n if (result.errors.length < MAX_ERRORS)\n result.errors.push({ offset: parser.index, message: getErrorMessage(error) });\n failures++;\n index = valueStart + 1;\n scalarBoundary = false;\n continue;\n }\n index = Math.max(index + 1, parser.index);\n scalarBoundary = true;\n }\n}\n\nfunction scalarStart(text: string, start: number, end: number): boolean {\n const first = text[start];\n if (first === undefined) return false;\n const keyword = /^([A-Za-z]+)/.exec(text.slice(start, end))?.[1];\n return (\n first in QUOTES ||\n /[-\\d]/.test(first) ||\n (keyword !== undefined &&\n (Object.hasOwn(KEYWORDS, keyword) ||\n (Object.keys(KEYWORDS).some((word) => word.startsWith(keyword)) &&\n /^[^\\S\\r\\n]*(?:[\\r\\n]|$)/.test(text.slice(start + keyword.length, end)))))\n );\n}\n\nclass RecoveryParser {\n readonly repairs: JsonRepair[] = [];\n readonly text: string;\n readonly end: number;\n index: number;\n\n constructor(text: string, index: number, end: number) {\n this.text = text;\n this.index = index;\n this.end = end;\n }\n\n finishScalar(regionEnd: number, start: number): boolean {\n const valueEnd = this.index;\n const atom = this.text.slice(start, valueEnd);\n const bullet = atom === '-' && /\\s/.test(this.text[valueEnd] ?? '');\n const retainLiteral =\n this.text[start]! in QUOTES || this.repairs.some((repair) => repair.reason === 'unquoted-value');\n this.space();\n if (bullet) return false;\n if (this.index >= regionEnd) return true;\n if (/[\\r\\n]/.test(this.text.slice(valueEnd, this.index))) {\n this.repair('ambiguous', 'scalar-before-prose', valueEnd);\n return true;\n }\n if (/^\\d+[.)]$/.test(atom) && /[ \\t]/.test(this.text[valueEnd] ?? '')) return false;\n if (retainLiteral || /^[\\p{P}\\p{S}]/u.test(this.text.slice(this.index, regionEnd))) {\n this.repair('ambiguous', 'trailing-scalar-content', valueEnd);\n return true;\n }\n return false;\n }\n\n value(depth: number): string {\n if (depth > MAX_DEPTH) throw new Error('JSON nesting exceeds 128 levels');\n this.space();\n const char = this.text[this.index];\n if (this.index >= this.end || char === ',' || char === '}' || char === ']') {\n this.repair('incomplete', 'missing-value');\n return 'null';\n }\n if (char === '{' || char === '[') {\n if (depth >= MAX_DEPTH) throw new Error('JSON nesting exceeds 128 levels');\n return this.container(depth, char === '{');\n }\n if (char !== undefined && char in QUOTES) return this.string(depth > 0 ? 'value' : 'root');\n const start = this.index;\n const uriEnd = unquotedUriEnd(this.text, start, this.end);\n if (uriEnd !== undefined) this.index = uriEnd;\n else\n while (\n this.index < this.end &&\n !/[\\s,}\\]]/.test(this.text[this.index]!) &&\n !(depth === 0 && /[{[]/.test(this.text[this.index]!)) &&\n !this.comment()\n )\n this.index++;\n if (this.index === start) throw new Error('Expected a JSON value');\n const token = this.text.slice(start, this.index);\n if (/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$/.test(token)) return token;\n if (Object.hasOwn(KEYWORDS, token)) {\n const canonical = KEYWORDS[token]!;\n if (canonical !== token) this.repair('syntax', 'python-keyword', start);\n return canonical;\n }\n this.repair(this.index >= this.end ? 'incomplete' : 'ambiguous', 'unquoted-value', start);\n return JSON.stringify(token);\n }\n\n private container(depth: number, object: boolean): string {\n this.index++;\n const close = object ? '}' : ']';\n const items: string[] = [];\n const keys = new Set<string>();\n let afterComma = false;\n let commaOffset = this.index;\n for (;;) {\n this.space();\n if (this.index >= this.end || this.text[this.index] === close) {\n if (this.index >= this.end) this.repair('incomplete', `missing-${close}`);\n else this.index++;\n if (afterComma) this.repair('syntax', 'trailing-comma', commaOffset);\n return (object ? '{' : '[') + items.join(',') + close;\n }\n if (this.text[this.index] === '}' || this.text[this.index] === ']') throw new Error('Mismatched closing bracket');\n if (this.text[this.index] === ',') {\n if (object) this.repair('ambiguous', 'extra-comma');\n else {\n items.push('null');\n this.repair('incomplete', 'missing-value');\n }\n commaOffset = this.index;\n afterComma = true;\n this.index++;\n continue;\n }\n let key: string | undefined;\n if (object) {\n const start = this.index;\n if (this.text[this.index]! in QUOTES) key = this.string();\n else {\n while (this.index < this.end && !/[\\s:,{}[\\]]/.test(this.text[this.index]!) && !this.comment()) this.index++;\n if (this.index === start) throw new Error('Expected an object key');\n const rawKey = this.text.slice(start, this.index);\n key = JSON.stringify(rawKey);\n this.repair(/[\"'“”‘’]/.test(rawKey) ? 'ambiguous' : 'syntax', 'unquoted-key', start);\n }\n const decoded: string = JSON.parse(key);\n if (keys.has(decoded)) this.repair('ambiguous', 'duplicate-key', start);\n keys.add(decoded);\n this.space();\n if (this.text[this.index] === ':') this.index++;\n else this.repair('ambiguous', 'missing-colon');\n }\n const value = this.value(depth + 1);\n items.push(key === undefined ? value : `${key}:${value}`);\n this.space();\n afterComma = this.text[this.index] === ',';\n if (afterComma) {\n commaOffset = this.index;\n this.index++;\n } else if (this.index < this.end && this.text[this.index] !== close) this.repair('syntax', 'missing-comma');\n }\n }\n\n private string(context: 'root' | 'key' | 'value' = 'key'): string {\n const start = this.index;\n const open = this.text[this.index++]!;\n const close = QUOTES[open]!;\n if (open !== '\"') this.repair('syntax', 'non-json-quote', start);\n let value = '';\n let tail = '';\n const append = (text: string): void => {\n value += text;\n tail = (tail + text).slice(-2);\n };\n let embeddedQuote = false;\n const family = '\"“”'.includes(open) ? '\"“”' : \"'‘’\";\n let alternative: { end: number; value: string; repairCount: number } | undefined;\n while (this.index < this.end) {\n const char = this.text[this.index++]!;\n if (\n \"'‘’\".includes(open) &&\n \"'’\".includes(char) &&\n /[\\p{L}\\p{N}]$/u.test(tail) &&\n /^[\\p{L}\\p{N}]/u.test(this.text.slice(this.index, this.end))\n ) {\n this.repair('ambiguous', 'literal-apostrophe', this.index - 1);\n append(char);\n continue;\n }\n if (family.includes(char)) {\n const after = this.text.slice(this.index, this.end).trimStart()[0];\n const delimited = after === undefined || /[,}\\]:\"']/.test(after);\n if (char === close) {\n if (embeddedQuote) {\n embeddedQuote = false;\n this.repair('ambiguous', 'unescaped-quote', this.index - 1);\n append(char);\n continue;\n }\n if (context !== 'root' && alternative !== undefined && !delimited) {\n this.index = alternative.end;\n this.repairs.length = alternative.repairCount;\n this.repair('ambiguous', 'mismatched-quote', this.index - 1);\n return JSON.stringify(alternative.value);\n }\n const nextClose = this.text.indexOf(close, this.index);\n const afterNext = this.text.slice(nextClose + 1, this.end).trimStart()[0];\n if (\n context === 'value' &&\n !delimited &&\n !/\\s/.test(this.text[this.index] ?? '') &&\n nextClose > this.index &&\n nextClose < this.end &&\n afterNext !== undefined &&\n (!/[,}:\\]]/.test(afterNext) ||\n (afterNext === ',' && this.continuesStringAfterComma(nextClose + 1, close))) &&\n !/[\\\\*:,{}[\\]\\r\\n]|\\/\\//.test(this.text.slice(this.index, nextClose)) &&\n !this.startsKey(nextClose)\n ) {\n embeddedQuote = true;\n this.repair('ambiguous', 'unescaped-quote', this.index - 1);\n append(char);\n continue;\n }\n return JSON.stringify(value);\n }\n if (delimited) alternative ??= { end: this.index, value, repairCount: this.repairs.length };\n }\n if (char !== '\\\\') {\n if (char.codePointAt(0)! < 32) this.repair('syntax', 'unescaped-control-character', this.index - 1);\n append(char);\n continue;\n }\n const escapeOffset = this.index - 1;\n if (this.index >= this.end) {\n append('\\\\');\n this.repair('incomplete', 'truncated-escape', escapeOffset);\n break;\n }\n const escape = this.text[this.index++]!;\n if (escape === 'u') {\n const hex = this.text.slice(this.index, Math.min(this.index + 4, this.end));\n if (/^[\\da-fA-F]{4}$/.test(hex)) {\n append(String.fromCodePoint(Number.parseInt(hex, 16)));\n this.index += 4;\n } else {\n append(String.raw`\\u`);\n this.repair(\n /^[\\da-fA-F]{0,3}$/.test(hex) ? 'incomplete' : 'ambiguous',\n 'invalid-unicode-escape',\n escapeOffset\n );\n }\n } else if (String.raw`\"\\/bfnrt`.includes(escape)) {\n append(JSON.parse(`\"\\\\${escape}\"`) as string);\n } else if (escape === \"'\" && open === \"'\") append(\"'\");\n else {\n append(`\\\\${escape}`);\n this.repair('ambiguous', 'invalid-escape', escapeOffset);\n }\n }\n this.repair('incomplete', 'unterminated-string', start);\n return JSON.stringify(value);\n }\n\n private continuesStringAfterComma(start: number, quote: string): boolean {\n const parser = new RecoveryParser(this.text, start - 1, this.end);\n parser.string();\n const end = parser.index - 1;\n if (\n this.text[end] !== quote ||\n parser.repairs.some(\n (repair) => !['non-json-quote', 'literal-apostrophe', 'unescaped-control-character'].includes(repair.reason)\n )\n )\n return false;\n const continuation = this.text.slice(start, end);\n const after = this.text.slice(end + 1, this.end).trimStart()[0];\n return (\n /^\\s*,\\s*[\\p{L}\\p{N}]/u.test(continuation) &&\n !/[\\\\:{}[\\]]/.test(continuation) &&\n (after === undefined || /[,}\\]]/.test(after))\n );\n }\n\n private startsKey(index: number): boolean {\n const parser = new RecoveryParser(this.text, index, this.end);\n parser.string();\n parser.space();\n return this.text[parser.index] === ':';\n }\n\n space(): void {\n while (this.index < this.end) {\n if (/\\s/.test(this.text[this.index]!)) {\n if (!/[ \\t\\r\\n]/.test(this.text[this.index]!)) this.repair('syntax', 'non-json-whitespace');\n this.index++;\n } else if (this.text.startsWith('//', this.index)) {\n this.repair('syntax', 'line-comment');\n while (this.index < this.end && !/[\\r\\n]/.test(this.text[this.index]!)) this.index++;\n } else if (this.text.startsWith('/*', this.index)) {\n const end = this.text.indexOf('*/', this.index + 2);\n this.repair(end === -1 || end >= this.end ? 'incomplete' : 'syntax', 'block-comment');\n this.index = end === -1 || end >= this.end ? this.end : end + 2;\n } else break;\n }\n }\n\n private repair(kind: JsonRepair['kind'], reason: string, offset = this.index): void {\n this.repairs.push({ offset, kind, reason });\n }\n\n private comment(): boolean {\n return this.text.startsWith('//', this.index) || this.text.startsWith('/*', this.index);\n }\n}\n\nfunction unquotedUriEnd(text: string, start: number, end: number): number | undefined {\n const match = /^[A-Za-z][A-Za-z\\d+.-]*:\\/\\//.exec(text.slice(start, end));\n if (match === null) return;\n let index = start + match[0].length;\n let brackets = 0;\n while (index < end && !/[\\s}]/.test(text[index]!)) {\n if (text[index] === ',' && brackets === 0) break;\n if (text[index] === '[') brackets++;\n else if (text[index] === ']') {\n if (brackets === 0) break;\n brackets--;\n }\n index++;\n }\n return index;\n}\n"],"mappings":"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"}
|
package/dist/recoverJson.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import{getErrorMessage as e}from"./error.js";
|
|
1
2
|
/*! JSON recovery informed by jsonrepair, Copyright (c) 2020-2026 Jos de Jong (ISC). See NOTICE. */
|
|
2
|
-
const e=1e6,t={'"':`"`,"'":`'`,"“":`”`,"”":`”`,"‘":`’`,"’":`’`},n={true:`true`,false:`false`,null:`null`,True:`true`,False:`false`,None:`null`};function r(t){let n={candidates:[],errors:[]};if(t.length>e)return n.errors.push({offset:e,message:`JSON recovery input exceeds one million characters`}),n;let r=[...t.matchAll(/^(?: {0,3})(`{3,}|~{3,})[^\r\n]*(?:\r\n|[\r\n]|$)/gm)].flatMap(e=>{let n=e[1],r=e.index+e[0].indexOf(n)+n.length,i=e.index+e[0].length,o=t.slice(r,i),s=/^[ \t]*json(?=[ \t{["'“”‘’])[ \t]*/i.exec(o),c=s===null?i:r+s[0].length,l=t[c]===`{`||t[c]===`[`||a(t,c,i)?c:i;return n[0]==="`"&&l===i&&o.includes("`")?[]:[{index:e.index,marker:n,start:l}]});if(r.length>0){let e=0;for(let a of r){if(a.index<e)continue;i(t,e,a.index,n);let o=n.candidates.at(-1)?.end??e;if(o>a.index){e=o;continue}let{marker:s,start:c}=a,l=RegExp(`^ {0,3}${s[0]}{${s.length},}[ \\t]*$`,`gm`);l.lastIndex=c;let u=l.exec(t),d=u?.index??t.length;i(t,c,d,n);let f=n.candidates.at(-1)?.end??c;if(f>d){l.lastIndex=f;let a=l.exec(t);if(a!==null&&!r.some(e=>e.index>=f&&e.index<a.index)){i(t,f,a.index,n),e=a.index+a[0].length;continue}}e=Math.max(n.candidates.at(-1)?.end??c,u===null?t.length:u.index+u[0].length)}i(t,e,t.length,n)}else i(t,0,t.length,n);if(n.candidates.length===32){let e={offset:n.candidates.at(-1).end,message:`JSON candidate limit reached; extraction may be incomplete`};n.errors.length===32?n.errors[31]=e:n.errors.push(e)}return n}function i(e,n,r,c,l=!1){if(c.candidates.length>=32)return;let u=n,d=0,f=!1,p=!0,m=n,h=n,g=n;for(;u<r&&/\s/.test(e[u]);)u++;let _=u,v=new o(e,u,r);l||v.space();let y=v.index;if(y>=r){v.repairs.some(e=>e.kind===`incomplete`)&&c.errors.length<32&&c.errors.push({offset:u,message:`Incomplete leading JSON comment`});return}let b=e[y],x=a(e,y,r)||b===`{`||b===`[`;for(x||(u=y);u<r&&c.candidates.length<32&&d<32;){if(!x||u!==_)for(;u<r&&e[u]!==`{`&&e[u]!==`[`&&!(p&&a(e,u,r));){let t=u===n||!/[\w+.-]/.test(e[u-1])?s(e,u,r):void 0;if(t!==void 0){if(u>=h){let t=e.slice(u,r).search(/\s/);h=t===-1?r:u+t,g=u}if(u>=g){let t=e.slice(u,h).search(/[{[]/);g=t===-1?h:u+t}g<h&&(m=Math.max(m,h)),u=Math.min(t,g),p=!1;continue}if(!l&&e[u]===`/`){let t=new o(e,u,r);if(t.space(),t.index>u){t.repairs.some(e=>e.kind===`incomplete`)&&c.errors.length<32&&c.errors.push({offset:u,message:`Possibly unterminated comment-like span in prose`}),i(e,u+2,t.index,c,!0),p||=/[\r\n]/.test(e.slice(u,t.index)),u=t.index;continue}}/[\r\n]/.test(e[u])?p=!0:/[\s,]/.test(e[u])||(p=!1),u++}if(u>=r||c.candidates.length>=32)break;let y=x&&u===_?v:new o(e,u,r),b=y.index;try{let n=y.value(0);if(!l&&(e[b]===`{`||e[b]===`[`)&&y.index===r&&r<e.length){let t=new o(e,u,e.length);try{let e=t.value(0);t.index>r&&t.repairs.every(e=>e.reason===`unescaped-control-character`)&&(t.repairs.push({offset:r,kind:`ambiguous`,reason:`literal-fence-in-string`}),y=t,n=e)}catch{}}let i=y.index;if(e[b]!==`{`&&e[b]!==`[`&&!y.finishScalar(r,b)){p=!1,u=i;continue}if(y.space(),!l&&d===0&&y.index<r&&/[}\]]/.test(e[y.index])){let t=y.index;for(;y.index<r&&/[}\]]/.test(e[y.index]);)y.repairs.push({offset:y.index,kind:`ambiguous`,reason:`surplus-closing-bracket`}),y.index++,y.space();if(c.errors.length<32){let n=Math.min(r,t+256);c.errors.push({offset:t,message:`Surplus closing brackets and possible continuation (${n<r?`truncated excerpt`:`excerpt`}): ${JSON.stringify(e.slice(t,n))}`})}}if(e[b]in t&&y.repairs.some(e=>e.reason===`trailing-scalar-content`)&&c.errors.length<32){let t=Math.min(r,i+256);c.errors.push({offset:i,message:`Ambiguous quoted-scalar tail (${t<r?`truncated excerpt`:`excerpt`}): ${JSON.stringify(e.slice(i,t))}`})}l&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`fragment-in-comment-like-prose`}),d>0&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`fragment-after-rejected-document`}),f&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`fragment-after-ambiguous-scalar`}),u<m&&y.repairs.unshift({offset:u,kind:`ambiguous`,reason:`ambiguous-uri-boundary`}),f||=y.repairs.some(e=>e.reason===`trailing-scalar-content`),c.candidates.push({value:JSON.parse(n),json:n,start:u,end:y.index,repairs:y.repairs,requiresConfirmation:y.repairs.some(e=>e.kind!==`syntax`)})}catch(e){c.errors.length<32&&c.errors.push({offset:y.index,message:e instanceof Error?e.message:String(e)}),d++,u=b+1,p=!1;continue}u=Math.max(u+1,y.index),p=!0}}function a(e,r,i){let a=e[r];if(a===void 0)return!1;let o=/^([A-Za-z]+)/.exec(e.slice(r,i))?.[1];return a in t||/[-\d]/.test(a)||o!==void 0&&(Object.hasOwn(n,o)||Object.keys(n).some(e=>e.startsWith(o))&&/^[^\S\r\n]*(?:[\r\n]|$)/.test(e.slice(r+o.length,i)))}var o=class e{repairs=[];text;end;index;constructor(e,t,n){this.text=e,this.index=t,this.end=n}finishScalar(e,n){let r=this.index,i=this.text.slice(n,r),a=i===`-`&&/\s/.test(this.text[r]??``),o=this.text[n]in t||this.repairs.some(e=>e.reason===`unquoted-value`);return this.space(),a?!1:this.index>=e?!0:/[\r\n]/.test(this.text.slice(r,this.index))?(this.repair(`ambiguous`,`scalar-before-prose`,r),!0):/^\d+[.)]$/.test(i)&&/[ \t]/.test(this.text[r]??``)?!1:o||/^[\p{P}\p{S}]/u.test(this.text.slice(this.index,e))?(this.repair(`ambiguous`,`trailing-scalar-content`,r),!0):!1}value(e){if(e>128)throw Error(`JSON nesting exceeds 128 levels`);this.space();let r=this.text[this.index];if(this.index>=this.end||r===`,`||r===`}`||r===`]`)return this.repair(`incomplete`,`missing-value`),`null`;if(r===`{`||r===`[`){if(e>=128)throw Error(`JSON nesting exceeds 128 levels`);return this.container(e,r===`{`)}if(r!==void 0&&r in t)return this.string(e>0?`value`:`root`);let i=this.index,a=s(this.text,i,this.end);if(a!==void 0)this.index=a;else for(;this.index<this.end&&!/[\s,}\]]/.test(this.text[this.index])&&!(e===0&&/[{[]/.test(this.text[this.index]))&&!this.comment();)this.index++;if(this.index===i)throw Error(`Expected a JSON value`);let o=this.text.slice(i,this.index);if(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(o))return o;if(Object.hasOwn(n,o)){let e=n[o];return e!==o&&this.repair(`syntax`,`python-keyword`,i),e}return this.repair(this.index>=this.end?`incomplete`:`ambiguous`,`unquoted-value`,i),JSON.stringify(o)}container(e,n){this.index++;let r=n?`}`:`]`,i=[],a=new Set,o=!1,s=this.index;for(;;){if(this.space(),this.index>=this.end||this.text[this.index]===r)return this.index>=this.end?this.repair(`incomplete`,`missing-${r}`):this.index++,o&&this.repair(`syntax`,`trailing-comma`,s),(n?`{`:`[`)+i.join(`,`)+r;if(this.text[this.index]===`}`||this.text[this.index]===`]`)throw Error(`Mismatched closing bracket`);if(this.text[this.index]===`,`){n?this.repair(`ambiguous`,`extra-comma`):(i.push(`null`),this.repair(`incomplete`,`missing-value`)),s=this.index,o=!0,this.index++;continue}let c;if(n){let e=this.index;if(this.text[this.index]in t)c=this.string();else{for(;this.index<this.end&&!/[\s:,{}[\]]/.test(this.text[this.index])&&!this.comment();)this.index++;if(this.index===e)throw Error(`Expected an object key`);let t=this.text.slice(e,this.index);c=JSON.stringify(t),this.repair(/["'“”‘’]/.test(t)?`ambiguous`:`syntax`,`unquoted-key`,e)}let n=JSON.parse(c);a.has(n)&&this.repair(`ambiguous`,`duplicate-key`,e),a.add(n),this.space(),this.text[this.index]===`:`?this.index++:this.repair(`ambiguous`,`missing-colon`)}let l=this.value(e+1);i.push(c===void 0?l:`${c}:${l}`),this.space(),o=this.text[this.index]===`,`,o?(s=this.index,this.index++):this.index<this.end&&this.text[this.index]!==r&&this.repair(`syntax`,`missing-comma`)}}string(e=`key`){let n=this.index,r=this.text[this.index++],i=t[r];r!==`"`&&this.repair(`syntax`,`non-json-quote`,n);let a=``,o=``,s=e=>{a+=e,o=(o+e).slice(-2)},c=!1,l=`"“”`.includes(r)?`"“”`:`'‘’`,u;for(;this.index<this.end;){let t=this.text[this.index++];if(`'‘’`.includes(r)&&`'’`.includes(t)&&/[\p{L}\p{N}]$/u.test(o)&&/^[\p{L}\p{N}]/u.test(this.text.slice(this.index,this.end))){this.repair(`ambiguous`,`literal-apostrophe`,this.index-1),s(t);continue}if(l.includes(t)){let n=this.text.slice(this.index,this.end).trimStart()[0],r=n===void 0||/[,}\]:"']/.test(n);if(t===i){if(c){c=!1,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}if(e!==`root`&&u!==void 0&&!r)return this.index=u.end,this.repairs.length=u.repairCount,this.repair(`ambiguous`,`mismatched-quote`,this.index-1),JSON.stringify(u.value);let n=this.text.indexOf(i,this.index),o=this.text.slice(n+1,this.end).trimStart()[0];if(e===`value`&&!r&&!/\s/.test(this.text[this.index]??``)&&n>this.index&&n<this.end&&o!==void 0&&(!/[,}:\]]/.test(o)||o===`,`&&this.continuesStringAfterComma(n+1,i))&&!/[\\*:,{}[\]\r\n]|\/\//.test(this.text.slice(this.index,n))&&!this.startsKey(n)){c=!0,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}return JSON.stringify(a)}r&&(u??={end:this.index,value:a,repairCount:this.repairs.length})}if(t!==`\\`){t.codePointAt(0)<32&&this.repair(`syntax`,`unescaped-control-character`,this.index-1),s(t);continue}let n=this.index-1;if(this.index>=this.end){s(`\\`),this.repair(`incomplete`,`truncated-escape`,n);break}let d=this.text[this.index++];if(d===`u`){let e=this.text.slice(this.index,Math.min(this.index+4,this.end));/^[\da-fA-F]{4}$/.test(e)?(s(String.fromCodePoint(Number.parseInt(e,16))),this.index+=4):(s(String.raw`\u`),this.repair(/^[\da-fA-F]{0,3}$/.test(e)?`incomplete`:`ambiguous`,`invalid-unicode-escape`,n))}else String.raw`"\/bfnrt`.includes(d)?s(JSON.parse(`"\\${d}"`)):d===`'`&&r===`'`?s(`'`):(s(`\\${d}`),this.repair(`ambiguous`,`invalid-escape`,n))}return this.repair(`incomplete`,`unterminated-string`,n),JSON.stringify(a)}continuesStringAfterComma(t,n){let r=new e(this.text,t-1,this.end);r.string();let i=r.index-1;if(this.text[i]!==n||r.repairs.some(e=>![`non-json-quote`,`literal-apostrophe`,`unescaped-control-character`].includes(e.reason)))return!1;let a=this.text.slice(t,i),o=this.text.slice(i+1,this.end).trimStart()[0];return/^\s*,\s*[\p{L}\p{N}]/u.test(a)&&!/[\\:{}[\]]/.test(a)&&(o===void 0||/[,}\]]/.test(o))}startsKey(t){let n=new e(this.text,t,this.end);return n.string(),n.space(),this.text[n.index]===`:`}space(){for(;this.index<this.end;)if(/\s/.test(this.text[this.index]))/[ \t\r\n]/.test(this.text[this.index])||this.repair(`syntax`,`non-json-whitespace`),this.index++;else if(this.text.startsWith(`//`,this.index))for(this.repair(`syntax`,`line-comment`);this.index<this.end&&!/[\r\n]/.test(this.text[this.index]);)this.index++;else if(this.text.startsWith(`/*`,this.index)){let e=this.text.indexOf(`*/`,this.index+2);this.repair(e===-1||e>=this.end?`incomplete`:`syntax`,`block-comment`),this.index=e===-1||e>=this.end?this.end:e+2}else break}repair(e,t,n=this.index){this.repairs.push({offset:n,kind:e,reason:t})}comment(){return this.text.startsWith(`//`,this.index)||this.text.startsWith(`/*`,this.index)}};function s(e,t,n){let r=/^[A-Za-z][A-Za-z\d+.-]*:\/\//.exec(e.slice(t,n));if(r===null)return;let i=t+r[0].length,a=0;for(;i<n&&!/[\s}]/.test(e[i])&&(e[i]!==`,`||a!==0);){if(e[i]===`[`)a++;else if(e[i]===`]`){if(a===0)break;a--}i++}return i}export{r as recoverJson};
|
|
3
|
+
const t=1e6,n={'"':`"`,"'":`'`,"“":`”`,"”":`”`,"‘":`’`,"’":`’`},r={true:`true`,false:`false`,null:`null`,True:`true`,False:`false`,None:`null`};function i(e){let n={candidates:[],errors:[]};if(e.length>t)return n.errors.push({offset:t,message:`JSON recovery input exceeds one million characters`}),n;let r=[...e.matchAll(/^(?: {0,3})(`{3,}|~{3,})[^\r\n]*(?:\r\n|[\r\n]|$)/gm)].flatMap(t=>{let n=t[1],r=t.index+t[0].indexOf(n)+n.length,i=t.index+t[0].length,a=e.slice(r,i),s=/^[ \t]*json(?=[ \t{["'“”‘’])[ \t]*/i.exec(a),c=s===null?i:r+s[0].length,l=e[c]===`{`||e[c]===`[`||o(e,c,i)?c:i;return n[0]==="`"&&l===i&&a.includes("`")?[]:[{index:t.index,marker:n,start:l}]});if(r.length>0){let t=0;for(let i of r){if(i.index<t)continue;a(e,t,i.index,n);let o=n.candidates.at(-1)?.end??t;if(o>i.index){t=o;continue}let{marker:s,start:c}=i,l=RegExp(`^ {0,3}${s[0]}{${s.length},}[ \\t]*$`,`gm`);l.lastIndex=c;let u=l.exec(e),d=u?.index??e.length;a(e,c,d,n);let f=n.candidates.at(-1)?.end??c;if(f>d){l.lastIndex=f;let i=l.exec(e);if(i!==null&&!r.some(e=>e.index>=f&&e.index<i.index)){a(e,f,i.index,n),t=i.index+i[0].length;continue}}t=Math.max(n.candidates.at(-1)?.end??c,u===null?e.length:u.index+u[0].length)}a(e,t,e.length,n)}else a(e,0,e.length,n);if(n.candidates.length===32){let e={offset:n.candidates.at(-1).end,message:`JSON candidate limit reached; extraction may be incomplete`};n.errors.length===32?n.errors[31]=e:n.errors.push(e)}return n}function a(t,r,i,l,u=!1){if(l.candidates.length>=32)return;let d=r,f=0,p=!1,m=!0,h=r,g=r,_=r;for(;d<i&&/\s/.test(t[d]);)d++;let v=d,y=new s(t,d,i);u||y.space();let b=y.index;if(b>=i){y.repairs.some(e=>e.kind===`incomplete`)&&l.errors.length<32&&l.errors.push({offset:d,message:`Incomplete leading JSON comment`});return}let x=t[b],S=o(t,b,i)||x===`{`||x===`[`;for(S||(d=b);d<i&&l.candidates.length<32&&f<32;){if(!S||d!==v)for(;d<i&&t[d]!==`{`&&t[d]!==`[`&&!(m&&o(t,d,i));){let e=d===r||!/[\w+.-]/.test(t[d-1])?c(t,d,i):void 0;if(e!==void 0){if(d>=g){let e=t.slice(d,i).search(/\s/);g=e===-1?i:d+e,_=d}if(d>=_){let e=t.slice(d,g).search(/[{[]/);_=e===-1?g:d+e}_<g&&(h=Math.max(h,g)),d=Math.min(e,_),m=!1;continue}if(!u&&t[d]===`/`){let e=new s(t,d,i);if(e.space(),e.index>d){e.repairs.some(e=>e.kind===`incomplete`)&&l.errors.length<32&&l.errors.push({offset:d,message:`Possibly unterminated comment-like span in prose`}),a(t,d+2,e.index,l,!0),m||=/[\r\n]/.test(t.slice(d,e.index)),d=e.index;continue}}/[\r\n]/.test(t[d])?m=!0:/[\s,]/.test(t[d])||(m=!1),d++}if(d>=i||l.candidates.length>=32)break;let b=S&&d===v?y:new s(t,d,i),x=b.index;try{let e=b.value(0);if(!u&&(t[x]===`{`||t[x]===`[`)&&b.index===i&&i<t.length){let n=new s(t,d,t.length);try{let t=n.value(0);n.index>i&&n.repairs.every(e=>e.reason===`unescaped-control-character`)&&(n.repairs.push({offset:i,kind:`ambiguous`,reason:`literal-fence-in-string`}),b=n,e=t)}catch{}}let r=b.index;if(t[x]!==`{`&&t[x]!==`[`&&!b.finishScalar(i,x)){m=!1,d=r;continue}if(b.space(),!u&&f===0&&b.index<i&&/[}\]]/.test(t[b.index])){let e=b.index;for(;b.index<i&&/[}\]]/.test(t[b.index]);)b.repairs.push({offset:b.index,kind:`ambiguous`,reason:`surplus-closing-bracket`}),b.index++,b.space();if(l.errors.length<32){let n=Math.min(i,e+256);l.errors.push({offset:e,message:`Surplus closing brackets and possible continuation (${n<i?`truncated excerpt`:`excerpt`}): ${JSON.stringify(t.slice(e,n))}`})}}if(t[x]in n&&b.repairs.some(e=>e.reason===`trailing-scalar-content`)&&l.errors.length<32){let e=Math.min(i,r+256);l.errors.push({offset:r,message:`Ambiguous quoted-scalar tail (${e<i?`truncated excerpt`:`excerpt`}): ${JSON.stringify(t.slice(r,e))}`})}u&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`fragment-in-comment-like-prose`}),f>0&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`fragment-after-rejected-document`}),p&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`fragment-after-ambiguous-scalar`}),d<h&&b.repairs.unshift({offset:d,kind:`ambiguous`,reason:`ambiguous-uri-boundary`}),p||=b.repairs.some(e=>e.reason===`trailing-scalar-content`),l.candidates.push({value:JSON.parse(e),json:e,start:d,end:b.index,repairs:b.repairs,requiresConfirmation:b.repairs.some(e=>e.kind!==`syntax`)})}catch(t){l.errors.length<32&&l.errors.push({offset:b.index,message:e(t)}),f++,d=x+1,m=!1;continue}d=Math.max(d+1,b.index),m=!0}}function o(e,t,i){let a=e[t];if(a===void 0)return!1;let o=/^([A-Za-z]+)/.exec(e.slice(t,i))?.[1];return a in n||/[-\d]/.test(a)||o!==void 0&&(Object.hasOwn(r,o)||Object.keys(r).some(e=>e.startsWith(o))&&/^[^\S\r\n]*(?:[\r\n]|$)/.test(e.slice(t+o.length,i)))}var s=class e{repairs=[];text;end;index;constructor(e,t,n){this.text=e,this.index=t,this.end=n}finishScalar(e,t){let r=this.index,i=this.text.slice(t,r),a=i===`-`&&/\s/.test(this.text[r]??``),o=this.text[t]in n||this.repairs.some(e=>e.reason===`unquoted-value`);return this.space(),a?!1:this.index>=e?!0:/[\r\n]/.test(this.text.slice(r,this.index))?(this.repair(`ambiguous`,`scalar-before-prose`,r),!0):/^\d+[.)]$/.test(i)&&/[ \t]/.test(this.text[r]??``)?!1:o||/^[\p{P}\p{S}]/u.test(this.text.slice(this.index,e))?(this.repair(`ambiguous`,`trailing-scalar-content`,r),!0):!1}value(e){if(e>128)throw Error(`JSON nesting exceeds 128 levels`);this.space();let t=this.text[this.index];if(this.index>=this.end||t===`,`||t===`}`||t===`]`)return this.repair(`incomplete`,`missing-value`),`null`;if(t===`{`||t===`[`){if(e>=128)throw Error(`JSON nesting exceeds 128 levels`);return this.container(e,t===`{`)}if(t!==void 0&&t in n)return this.string(e>0?`value`:`root`);let i=this.index,a=c(this.text,i,this.end);if(a!==void 0)this.index=a;else for(;this.index<this.end&&!/[\s,}\]]/.test(this.text[this.index])&&!(e===0&&/[{[]/.test(this.text[this.index]))&&!this.comment();)this.index++;if(this.index===i)throw Error(`Expected a JSON value`);let o=this.text.slice(i,this.index);if(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(o))return o;if(Object.hasOwn(r,o)){let e=r[o];return e!==o&&this.repair(`syntax`,`python-keyword`,i),e}return this.repair(this.index>=this.end?`incomplete`:`ambiguous`,`unquoted-value`,i),JSON.stringify(o)}container(e,t){this.index++;let r=t?`}`:`]`,i=[],a=/* @__PURE__ */ new Set,o=!1,s=this.index;for(;;){if(this.space(),this.index>=this.end||this.text[this.index]===r)return this.index>=this.end?this.repair(`incomplete`,`missing-${r}`):this.index++,o&&this.repair(`syntax`,`trailing-comma`,s),(t?`{`:`[`)+i.join(`,`)+r;if(this.text[this.index]===`}`||this.text[this.index]===`]`)throw Error(`Mismatched closing bracket`);if(this.text[this.index]===`,`){t?this.repair(`ambiguous`,`extra-comma`):(i.push(`null`),this.repair(`incomplete`,`missing-value`)),s=this.index,o=!0,this.index++;continue}let c;if(t){let e=this.index;if(this.text[this.index]in n)c=this.string();else{for(;this.index<this.end&&!/[\s:,{}[\]]/.test(this.text[this.index])&&!this.comment();)this.index++;if(this.index===e)throw Error(`Expected an object key`);let t=this.text.slice(e,this.index);c=JSON.stringify(t),this.repair(/["'“”‘’]/.test(t)?`ambiguous`:`syntax`,`unquoted-key`,e)}let t=JSON.parse(c);a.has(t)&&this.repair(`ambiguous`,`duplicate-key`,e),a.add(t),this.space(),this.text[this.index]===`:`?this.index++:this.repair(`ambiguous`,`missing-colon`)}let l=this.value(e+1);i.push(c===void 0?l:`${c}:${l}`),this.space(),o=this.text[this.index]===`,`,o?(s=this.index,this.index++):this.index<this.end&&this.text[this.index]!==r&&this.repair(`syntax`,`missing-comma`)}}string(e=`key`){let t=this.index,r=this.text[this.index++],i=n[r];r!==`"`&&this.repair(`syntax`,`non-json-quote`,t);let a=``,o=``,s=e=>{a+=e,o=(o+e).slice(-2)},c=!1,l=`"“”`.includes(r)?`"“”`:`'‘’`,u;for(;this.index<this.end;){let t=this.text[this.index++];if(`'‘’`.includes(r)&&`'’`.includes(t)&&/[\p{L}\p{N}]$/u.test(o)&&/^[\p{L}\p{N}]/u.test(this.text.slice(this.index,this.end))){this.repair(`ambiguous`,`literal-apostrophe`,this.index-1),s(t);continue}if(l.includes(t)){let n=this.text.slice(this.index,this.end).trimStart()[0],r=n===void 0||/[,}\]:"']/.test(n);if(t===i){if(c){c=!1,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}if(e!==`root`&&u!==void 0&&!r)return this.index=u.end,this.repairs.length=u.repairCount,this.repair(`ambiguous`,`mismatched-quote`,this.index-1),JSON.stringify(u.value);let n=this.text.indexOf(i,this.index),o=this.text.slice(n+1,this.end).trimStart()[0];if(e===`value`&&!r&&!/\s/.test(this.text[this.index]??``)&&n>this.index&&n<this.end&&o!==void 0&&(!/[,}:\]]/.test(o)||o===`,`&&this.continuesStringAfterComma(n+1,i))&&!/[\\*:,{}[\]\r\n]|\/\//.test(this.text.slice(this.index,n))&&!this.startsKey(n)){c=!0,this.repair(`ambiguous`,`unescaped-quote`,this.index-1),s(t);continue}return JSON.stringify(a)}r&&(u??={end:this.index,value:a,repairCount:this.repairs.length})}if(t!==`\\`){t.codePointAt(0)<32&&this.repair(`syntax`,`unescaped-control-character`,this.index-1),s(t);continue}let n=this.index-1;if(this.index>=this.end){s(`\\`),this.repair(`incomplete`,`truncated-escape`,n);break}let d=this.text[this.index++];if(d===`u`){let e=this.text.slice(this.index,Math.min(this.index+4,this.end));/^[\da-fA-F]{4}$/.test(e)?(s(String.fromCodePoint(Number.parseInt(e,16))),this.index+=4):(s(String.raw`\u`),this.repair(/^[\da-fA-F]{0,3}$/.test(e)?`incomplete`:`ambiguous`,`invalid-unicode-escape`,n))}else String.raw`"\/bfnrt`.includes(d)?s(JSON.parse(`"\\${d}"`)):d===`'`&&r===`'`?s(`'`):(s(`\\${d}`),this.repair(`ambiguous`,`invalid-escape`,n))}return this.repair(`incomplete`,`unterminated-string`,t),JSON.stringify(a)}continuesStringAfterComma(t,n){let r=new e(this.text,t-1,this.end);r.string();let i=r.index-1;if(this.text[i]!==n||r.repairs.some(e=>![`non-json-quote`,`literal-apostrophe`,`unescaped-control-character`].includes(e.reason)))return!1;let a=this.text.slice(t,i),o=this.text.slice(i+1,this.end).trimStart()[0];return/^\s*,\s*[\p{L}\p{N}]/u.test(a)&&!/[\\:{}[\]]/.test(a)&&(o===void 0||/[,}\]]/.test(o))}startsKey(t){let n=new e(this.text,t,this.end);return n.string(),n.space(),this.text[n.index]===`:`}space(){for(;this.index<this.end;)if(/\s/.test(this.text[this.index]))/[ \t\r\n]/.test(this.text[this.index])||this.repair(`syntax`,`non-json-whitespace`),this.index++;else if(this.text.startsWith(`//`,this.index))for(this.repair(`syntax`,`line-comment`);this.index<this.end&&!/[\r\n]/.test(this.text[this.index]);)this.index++;else if(this.text.startsWith(`/*`,this.index)){let e=this.text.indexOf(`*/`,this.index+2);this.repair(e===-1||e>=this.end?`incomplete`:`syntax`,`block-comment`),this.index=e===-1||e>=this.end?this.end:e+2}else break}repair(e,t,n=this.index){this.repairs.push({offset:n,kind:e,reason:t})}comment(){return this.text.startsWith(`//`,this.index)||this.text.startsWith(`/*`,this.index)}};function c(e,t,n){let r=/^[A-Za-z][A-Za-z\d+.-]*:\/\//.exec(e.slice(t,n));if(r===null)return;let i=t+r[0].length,a=0;for(;i<n&&!/[\s}]/.test(e[i])&&(e[i]!==`,`||a!==0);){if(e[i]===`[`)a++;else if(e[i]===`]`){if(a===0)break;a--}i++}return i}export{i as recoverJson};
|
|
3
4
|
//# sourceMappingURL=recoverJson.js.map
|