import type { Token, TokenTree } from '../types.js'; export interface MarkdocPair { open: Token; close: Token; /** * Nesting depth of `open` at the moment it was pushed: 0 for a top-level tag, * 1 for a tag opened inside exactly one other, and so on. It stays fixed even * when `close` jumps over an intervening unmatched open (see `crossed`), since * it describes where `open` appeared, not where its match landed. */ depth: number; } /** * The five buckets are disjoint: a pair lands in `pairs` or `crossed` but never * both, and a token appears in at most one bucket. */ export interface MarkdocPairing { /** Cleanly matched open/close pairs (no crossing involved on either side). */ pairs: MarkdocPair[]; /** Opens with no close by EOF (excluding schema-known void tags, below). */ unclosed: Token[]; /** Closes that match no open anywhere on the stack. */ orphaned: Token[]; /** Matched pairs whose open or close jumped, or was jumped by, another pair. */ crossed: MarkdocPair[]; /** Opens whose name is schema-declared self-closing, written without `/%}`. */ voidMissingSlash: Token[]; } /** * A "nothing was paired" result for callers that must still supply a * `MarkdocPairing` but have no reason to run the pass -- the runner uses it when * the Markdoc flag is on but no active rule can read the buckets anyway. A * factory rather than a shared constant, because the buckets are mutable arrays * and one shared instance would let an accidental push leak across files. */ export declare function emptyMarkdocPairing(): MarkdocPairing; export interface PairingOptions { /** * Tag names a schema declares self-closing. A plain `Set` rather than * a dependency on the schema module, so the schema's shape can change without * this pass knowing anything beyond which names never take a close tag. */ selfClosingTags?: ReadonlySet; } /** * Computes open/close pairing for a document's `markdocTag` tokens with a single * stack walk in document order. The filtered list is sorted by position rather * than trusting whatever order `tree.flat` happens to be in, since * `structureMarkdocTags` (structure.ts) appends its own synthesized children to * the end of that same array. * * Deliberate divergence from upstream Markdoc, which tests a close only against * the immediate top of its stack and never searches deeper: for * `{% a %}{% b %}{% /a %}{% /b %}` upstream reports a missing-closing plus a * missing-opening and lets `a`'s node swallow everything to EOF, while this pass * searches the whole stack innermost-first and reports both pairs as `crossed`. * "These two pairs are interleaved" is the more actionable diagnostic, and a * crossing can never silently land in `pairs`, so no error upstream reports is * lost. The cost is that consumers relying on pair ranges see a narrower range * for a crossed `open` than upstream's AST would give. */ export declare function computeMarkdocPairing(tree: TokenTree, options?: PairingOptions): MarkdocPairing; //# sourceMappingURL=pairing.d.ts.map