/** * Layer 1 — Core JSON Extractor * * Single source of truth for "pull JSON from text / markdown." * Always returns an array. Supports streaming and non-streaming modes. * Never throws — failures are represented as empty results or warnings. */ type JsonValueType = "object" | "array" | "primitive"; type JsonSource = "fenced" | "bare-block" | "inline" | "whole-string"; interface ExtractedJson { value: unknown; type: JsonValueType; source: JsonSource; startIndex: number; endIndex: number; isComplete: boolean; repairApplied: boolean; warnings: string[]; } interface ExtractionOptions { /** When true, only uses conservative strategies (fenced blocks). Default false. */ isStreaming?: boolean; /** Enable bare-block / inline / whole-string fallbacks. Default false. */ allowFuzzy?: boolean; /** Max number of results to return. Default Infinity. */ maxResults?: number; /** Apply repair strategies (trailing commas, Python syntax, etc.). Default true. */ repairEnabled?: boolean; } /** * Extract all JSON values from a text / markdown string. * * Strategy order depends on mode: * * **Streaming (`isStreaming: true`)**: * 1. Fenced blocks (with auto-close for incomplete blocks) * 2. If `allowFuzzy` (or no fenced results): bare blocks (with auto-close) * * **Non-streaming (`isStreaming: false`)**: * 1. Fenced blocks (complete only) * 2. If `allowFuzzy` and still below `maxResults`: bare blocks * 3. If `allowFuzzy` and still no results: whole-string parse * * @returns Array of extracted JSON values, in document order. Empty if none found. */ declare function extractAllJson(text: string, options?: ExtractionOptions): ExtractedJson[]; /** * Extract the first JSON object from text. Returns `null` if none found. * This is the drop-in replacement for legacy `extractJsonFromText`. */ declare function extractFirstJson(text: string, options?: ExtractionOptions): ExtractedJson | null; /** * Extract the first JSON object (not array, not primitive) from text. */ declare function extractFirstObject(text: string, options?: ExtractionOptions): ExtractedJson | null; /** * Quick "does this text contain extractable JSON?" check. * Cheaper than full extraction when you only need a boolean. */ declare function containsJson(text: string, options?: ExtractionOptions): boolean; /** * Layer 0 — Structural Primitives * * Pure character-level utilities that every higher layer depends on. * No JSON.parse calls live here — only scanning, balancing, and fence detection. */ interface BalanceResult { endIndex: number; isComplete: boolean; } /** * Starting *after* the opening character at `startIndex`, walk the string * tracking depth, string literals, and escape sequences. Returns the index * of the matching close character or the end of the string if incomplete. * * `startIndex` must point at the opening `{` or `[`. */ declare function findBalancedEnd(text: string, startIndex: number, openChar: "{" | "[", closeChar: "}" | "]"): BalanceResult; /** * Count how many unclosed openers remain in a partial JSON string. * Returns the sequence of close characters needed (e.g. `"]}"` ). * * Handles string literals and escape sequences correctly. */ declare function computeClosingSequence(text: string): string; interface FencedBlock { content: string; language: string; fenceStart: number; contentStart: number; fenceEnd: number; isComplete: boolean; } /** * Every fenced block in `text`, in document order — THE one code-range rule * (@ai-matrx/content-ir/source): a fence opens only where a line starts with * it (never a mid-sentence ```), closes by the renderer's closer, and an * unclosed fence runs to the end (`isComplete: false`). */ declare function findAllFencedBlocks(text: string): FencedBlock[]; interface BareJsonCandidate { startIndex: number; endIndex: number; openChar: "{" | "["; isComplete: boolean; } /** * Scan `text` for top-level `{` or `[` characters that are NOT inside * a fenced block. Returns all candidates with balanced-end info. * * `excludeRanges` is an array of [start, end) index pairs to skip * (typically the ranges covered by fenced blocks). */ declare function findBareJsonCandidates(text: string, excludeRanges?: Array<[number, number]>): BareJsonCandidate[]; /** * Layer 3 — Streaming JSON Tracker * * Stateful wrapper around extractAllJson that tracks changes across * streaming chunks and avoids dispatching redundant updates. */ interface StreamingJsonState { results: ExtractedJson[]; /** True when all detected structures have balanced braces/brackets */ isAllComplete: boolean; /** True when we've detected an open ```json fence without a close */ hasOpenFence: boolean; /** Monotonically increasing — bumped only when results actually change */ revision: number; /** The accumulated text so far */ textLength: number; } interface StreamingJsonTrackerOptions { /** Max results to track. Default Infinity. */ maxResults?: number; /** Apply repair strategies. Default true. */ repairEnabled?: boolean; /** Enable fuzzy matching on finalize. Default true. */ fuzzyOnFinalize?: boolean; } declare class StreamingJsonTracker { private text; private state; private opts; private lastResultsHash; constructor(options?: StreamingJsonTrackerOptions); /** * Append a new chunk of text and re-extract. Returns the new state. * Only bumps `revision` if the extraction results actually changed. */ append(chunk: string): StreamingJsonState; /** * Run a final extraction pass with full strategies (including fuzzy). * Call once when the stream is complete. */ finalize(): StreamingJsonState; /** Replace the entire accumulated text (useful if you manage accumulation externally). */ setFullText(text: string): StreamingJsonState; /** Get the current state without re-extracting. */ getState(): StreamingJsonState; /** Get the accumulated text. */ getText(): string; /** Reset to initial state. */ reset(): void; private extract; /** * Cheap hash of extraction results for change detection. * We hash on: count, types, completeness, and the stringified values. * This avoids deep-equality checks on every chunk. */ private computeHash; } export { StreamingJsonTracker, computeClosingSequence, containsJson, extractAllJson, extractFirstJson, extractFirstObject, findAllFencedBlocks, findBalancedEnd, findBareJsonCandidates }; export type { BalanceResult, BareJsonCandidate, ExtractedJson, ExtractionOptions, FencedBlock, JsonSource, JsonValueType, StreamingJsonState, StreamingJsonTrackerOptions };