@hawkeyexl/manni 4.0.3 → 4.2.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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/meta/core/reencrypt.ts","../src/cite/index.ts","../src/cite/types.ts","../src/cite/errors.ts","../src/cite/core/severity.ts","../src/cite/core/range.ts","../src/cite/core/hash.ts","../src/cite/core/spell.ts","../src/cite/core/sources.ts","../src/cite/core/page.ts","../src/shared/code-regions.ts","../src/cite/core/statements.ts","../src/cite/core/reanchor.ts","../src/cite/core/claims.ts","../src/cite/core/git.ts","../src/cite/core/history.ts","../src/cite/core/classify.ts","../src/cite/core/shift.ts","../src/cite/core/sidecar.ts","../src/cite/core/manifest.ts","../src/cite/core/write.ts","../src/cite/core/adapt.ts","../src/cite/core/check-page.ts","../src/cite/core/mint.ts","../src/cite/core/config.ts","../src/shared/severity.ts","../src/cite/commands/check.ts","../src/cite/commands/add.ts","../src/cite/commands/remove.ts","../src/cite/commands/update.ts","../src/cite/core/reencrypt.ts","../src/cite/reporters/pretty.ts","../src/cite/reporters/json.ts","../src/cite/reporters/github.ts","../src/key/errors.ts","../src/key/commands/rotate.ts","../src/key/core/config.ts","../src/key/commands/set.ts","../src/lint/types.ts","../src/lint/parsers/markdown.ts","../src/lint/parsers/mdast.ts","../src/lint/parsers/sectionize.ts","../src/lint/parsers/metadata.ts","../src/lint/parsers/html.ts","../src/lint/parsers/rst.ts","../src/lint/parsers/xml.ts","../src/lint/parsers/asciidoc.ts","../src/lint/parsers/index.ts","../src/lint/rules/heading.ts","../src/lint/rules/paragraphs.ts","../src/lint/rules/code-blocks.ts","../src/lint/rules/tables.ts","../src/lint/rules/admonitions.ts","../src/lint/rules/images.ts","../src/lint/rules/blockquotes.ts","../src/lint/rules/definition-lists.ts","../src/lint/rules/sequence.ts","../src/lint/rules/elements.ts","../src/lint/rules/contains.ts","../src/lint/rules/lists.ts","../src/lint/rules/index.ts","../src/lint/core/template.ts","../src/lint/core/template-registry.ts","../src/shared/package-root.ts","../schemas/lint/template.json","../templates/lint/tgdp/manifest.json","../src/lint/core/resolve-template.ts","../src/lint/core/match.ts","../src/lint/core/validator.ts","../src/lint/core/config.ts","../schemas/lint/config.json","../src/lint/tools/dita-ot.ts","../src/lint/tools/index.ts","../src/lint/commands/lint.ts","../src/lint/core/infer.ts","../src/lint/commands/templates.ts","../src/lint/commands/tools.ts","../src/lint/core/rule-id.ts","../src/lint/reporters/junit.ts","../src/lint/reporters/sarif.ts","../src/lint/reporters/alignment.ts","../src/lint/reporters/index.ts"],"sourcesContent":["/**\n * Re-encrypt a page's metadata under a new key: meta's half of `manni key\n * rotate` (proposal 0045).\n *\n * Values are found by their ciphertext, not through schema marks. Every\n * string at any depth of the metadata that has the ciphertext shape is a\n * candidate, and the authentication tag decides whether it is ours: no schema\n * is resolved, so a mark from a `-s` schema or an unreachable remote cannot\n * hide a value from rotation. `citations` is left alone; cite owns it, and\n * re-encrypts its own sources with their pins.\n *\n * Pure: no IO. The caller reads the page and writes `content` back.\n */\nimport { extname } from \"node:path\";\nimport { decryptValue, encryptValue, isEncryptedValue } from \"../../shared/encryption.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { escapePointerSegment } from \"../extractors/pointer.js\";\nimport { extractorByName, extractorForExtension, supportedExtensions } from \"../extractors/index.js\";\nimport { DocmetaError, type MetadataExtractor, type MetadataPatch } from \"../types.js\";\nimport { META_CONTEXT, withValueAt } from \"./encrypted.js\";\n\n/** One value re-encrypted: where, and the ciphertext before and after. */\nexport interface ReencryptedValue {\n pointer: string;\n from: string;\n to: string;\n}\n\nexport interface ReencryptMetadataResult {\n /** The page with every rewritten value; the input itself when nothing was. */\n content: string;\n rewritten: ReencryptedValue[];\n /** Values that could not be re-encrypted, and why. */\n skipped: { pointer: string; message: string }[];\n}\n\nexport interface ReencryptDataResult {\n /** The metadata with every rewritten value; the input itself when nothing was. */\n data: Record<string, unknown>;\n rewritten: ReencryptedValue[];\n /** Values that could not be re-encrypted, and why. */\n skipped: { pointer: string; message: string }[];\n /** The top-level keys whose value changed, in document order. */\n keys: string[];\n}\n\n/** The subtree cite owns. */\nconst CITATIONS_KEY = \"citations\";\n\nconst NOT_OURS = \"does not decrypt under the current key\";\nconst READ_ONLY = \"this format cannot be written\";\n\n/**\n * Re-encrypt every encrypted value in one page's metadata from `fromKey` to\n * `toKey`.\n *\n * - A value that decrypts under `fromKey` is rewritten under `toKey`.\n * - One that already decrypts under `toKey` is done: an interrupted rotation\n * can be run again. It is neither rewritten nor skipped.\n * - One that decrypts under neither is skipped.\n *\n * The format is `page.format` (an extractor name) when given, else the\n * file's extension. A nested value rewrites its top-level key; everything\n * else in the page is kept. A format that cannot be written lists every value\n * it would have rewritten as skipped, and returns the content unchanged.\n */\nexport function reencryptMetadata(\n page: { file: string; content: string; format?: string },\n opts: { fromKey: string; toKey: string },\n): ReencryptMetadataResult {\n const extractor =\n page.format !== undefined\n ? extractorByName(page.format)\n : extractorForExtension(extname(page.file));\n if (!extractor) {\n throw new DocmetaError(\n page.format !== undefined\n ? `Unknown format \"${page.format}\" for \"${page.file}\".`\n : `Unsupported file type \"${extname(page.file)}\" for \"${page.file}\". Supported: ${supportedExtensions().join(\", \")}.`,\n );\n }\n return reencryptWith(extractor, page, opts);\n}\n\ninterface Found {\n pointer: string;\n top: string;\n token: string;\n}\n\n/** Every ciphertext in `data`, in document order, outside `citations`. */\nfunction tokensIn(data: Record<string, unknown>): Found[] {\n const found: Found[] = [];\n const walk = (node: unknown, pointer: string, top: string): void => {\n if (isEncryptedValue(node)) {\n found.push({ pointer, top, token: node });\n return;\n }\n if (Array.isArray(node)) {\n (node as unknown[]).forEach((item, i) => {\n walk(item, `${pointer}/${String(i)}`, top);\n });\n return;\n }\n if (typeof node === \"object\" && node !== null && !(node instanceof Date)) {\n for (const [k, v] of Object.entries(node)) {\n walk(v, `${pointer}/${escapePointerSegment(k)}`, top);\n }\n }\n };\n for (const [key, value] of Object.entries(data)) {\n if (key === CITATIONS_KEY) continue;\n walk(value, `/${escapePointerSegment(key)}`, key);\n }\n return found;\n}\n\n/**\n * Re-encrypt every ciphertext in one metadata object, `citations` aside.\n *\n * The rule `reencryptMetadata` runs on a page, on the data alone: a value\n * that decrypts under `fromKey` is rewritten under `toKey`, one already under\n * `toKey` is done, and one under neither is skipped. `manni key rotate` calls\n * it a second time for the values an external-metadata manifest supplies,\n * which live in the manifest rather than in any page.\n *\n * `writable` says whether the caller can write what it plans. `false` lists\n * every value it would have rewritten as skipped instead, in document order\n * beside the ones that could not be read, and rewrites nothing.\n */\nexport function reencryptData(\n data: Record<string, unknown>,\n opts: { fromKey: string; toKey: string; writable?: boolean },\n): ReencryptDataResult {\n const writable = opts.writable ?? true;\n const rewritten: ReencryptedValue[] = [];\n const skipped: { pointer: string; message: string }[] = [];\n const found = tokensIn(data);\n for (const { pointer, token } of found) {\n const opened = decryptValue(token, opts.fromKey, META_CONTEXT);\n if (opened.ok) {\n if (!writable) {\n skipped.push({ pointer, message: READ_ONLY });\n continue;\n }\n rewritten.push({\n pointer,\n from: token,\n to: encryptValue(opened.value, opts.toKey, META_CONTEXT),\n });\n continue;\n }\n if (decryptValue(token, opts.toKey, META_CONTEXT).ok) continue;\n skipped.push({ pointer, message: NOT_OURS });\n }\n if (rewritten.length === 0) return { data, rewritten, skipped, keys: [] };\n\n let next: Record<string, unknown> = data;\n for (const r of rewritten) next = withValueAt(next, r.pointer, r.to);\n const done = new Set(rewritten.map((r) => r.pointer));\n const keys = [...new Set(found.filter((f) => done.has(f.pointer)).map((f) => f.top))];\n return { data: next, rewritten, skipped, keys };\n}\n\n/** `reencryptMetadata` with the extractor chosen. Exported for tests. */\nexport function reencryptWith(\n extractor: MetadataExtractor,\n page: { file: string; content: string },\n opts: { fromKey: string; toKey: string },\n): ReencryptMetadataResult {\n const read = (content: string): Record<string, unknown> => {\n try {\n return extractor.extract(content, page.file).data;\n } catch (err) {\n if (err instanceof DocmetaError) throw err;\n throw new DocmetaError(`${page.file}: ${errorMessage(err)}`);\n }\n };\n const data = read(page.content);\n const apply = extractor.apply;\n const plan = reencryptData(data, { ...opts, writable: apply !== undefined });\n const { rewritten, skipped } = plan;\n if (rewritten.length === 0 || apply === undefined) {\n return { content: page.content, rewritten: [], skipped };\n }\n\n // One patch entry per top-level key: the whole value, with its tokens\n // replaced, because a writer sets top-level keys and nothing deeper.\n const patch: MetadataPatch = {};\n for (const top of plan.keys) patch[top] = plan.data[top];\n const content = apply(page.content, patch, { filePath: page.file });\n\n // A writer that cannot keep a value is worse than a refused rotation: the\n // old ciphertext would be gone and the new one nowhere.\n const reread = tokensIn(read(content));\n for (const r of rewritten) {\n if (!reread.some((f) => f.pointer === r.pointer && f.token === r.to)) {\n throw new DocmetaError(\n `${page.file}: the ${extractor.name} writer did not keep ${r.pointer}; nothing was re-encrypted.`,\n );\n }\n }\n return { content, rewritten, skipped };\n}\n","/**\n * The citation tool's programmatic API, exported from the package as the\n * `cite` namespace: `import { cite } from \"@hawkeyexl/manni\"`.\n */\nexport * from \"./types.js\";\nexport { CiteError } from \"./errors.js\";\nexport { DEFAULT_SEVERITY, RULE_ID_PREFIX, isCiteRule, resolveSeverity, ruleId } from \"./core/severity.js\";\nexport {\n FILE_PATTERN,\n SRC_PATTERN,\n formatSrc,\n lineSpec,\n parseLines,\n parseSrc,\n rangeLines,\n sourceRange,\n spellLines,\n spellSource,\n} from \"./core/range.js\";\nexport { hashLines, hashRange, isKeyedPin, normalizeText, sliceLines, splitLines } from \"./core/hash.js\";\nexport { shortCommit, shortLine, shortPin, shortSrc, spellAt } from \"./core/spell.js\";\nexport { buildSourceIndex, readSource } from \"./core/sources.js\";\nexport type { BuildIndexOptions, ReadSourceResult } from \"./core/sources.js\";\nexport {\n isUnitText,\n markerClaimEnd,\n markerRunAt,\n misplacedMarkerAt,\n misplacedMarkers,\n movedUnit,\n pre43Span,\n splitUnit,\n unitText,\n} from \"./core/reanchor.js\";\nexport type { MisplacedMarker } from \"./core/reanchor.js\";\nexport {\n anchoredLines,\n detectEol,\n fenceSpanAt,\n fencedBlockAfter,\n fencedBlockAt,\n fencedBlocks,\n formatStatement,\n insideFence,\n isBoundLine,\n isTableRow,\n lineAt,\n offsetOfLine,\n paragraphAfter,\n parseStatements,\n statementForms,\n} from \"./core/statements.js\";\nexport type { StatementForm } from \"./core/statements.js\";\nexport {\n blockMatches,\n claimEnd,\n claimLine,\n markerUnit,\n noUnitAt,\n normalizeWhitespace,\n pinOfLines,\n toBodyLines,\n toFileLines,\n unitAt,\n} from \"./core/claims.js\";\nexport type { ClaimUnit, NoUnit } from \"./core/claims.js\";\nexport {\n GIT_UNAVAILABLE_COMMIT,\n GIT_UNAVAILABLE_HISTORY,\n PAGE_HISTORY_UNAVAILABLE,\n gitClient,\n noGit,\n} from \"./core/git.js\";\nexport {\n MAX_PAGE_COMMITS,\n claimDiff,\n claimHistory,\n claimWords,\n holdsWords,\n refineClaim,\n runsHolding,\n sentencesOf,\n sharesSentence,\n stripMarkers,\n} from \"./core/history.js\";\nexport type { ClaimHistory, ClaimHistoryInput, RefineClaimInput } from \"./core/history.js\";\nexport { MAX_RANGE_LINES, MOVE_BUDGET_BYTES, MOVE_WINDOW_LINES, classifyCitation, findWindows, historyOf } from \"./core/classify.js\";\nexport type { ClassifyOptions, FindWindowsOptions, History } from \"./core/classify.js\";\nexport {\n MARKER_JSON,\n MAX_MARKERS_PER_PAGE,\n bodyLineOf,\n citationInputs,\n ownedMessage,\n pickExtractor,\n readPage,\n validateEntry,\n} from \"./core/page.js\";\nexport { shiftedEntries, withClaimLines } from \"./core/shift.js\";\nexport type { ShiftOptions, Shifted } from \"./core/shift.js\";\nexport {\n CITATIONS_KEY,\n duplicateJoinRefusal,\n loadCitationSidecars,\n orphanRefusal,\n sidecarsFor,\n twoManifestsRefusal,\n urlManifestRefusal,\n} from \"./core/sidecar.js\";\nexport type {\n CitationManifest,\n CitationSidecars,\n LoadSidecarOptions,\n PageSidecar,\n} from \"./core/sidecar.js\";\nexport { ManifestSet, itemLine, splice } from \"./core/manifest.js\";\nexport type { HeldManifest } from \"./core/manifest.js\";\nexport type { ReadPageOptions } from \"./core/page.js\";\nexport { checkCitations } from \"./core/check-page.js\";\nexport {\n claimMessageFor,\n errorSite,\n findingsFor,\n messageFor,\n misplacedMessageFor,\n toValidationResult,\n} from \"./core/adapt.js\";\nexport {\n appendFrontmatterCitation,\n entryObject,\n insertStatementBefore,\n removeFrontmatterCitations,\n removeLine,\n spliceEntryField,\n unifiedDiff,\n} from \"./core/write.js\";\nexport type { EntryPath } from \"./core/write.js\";\nexport { mintCitation } from \"./core/mint.js\";\nexport { CITE_SECTION, DEFAULT_CITE_BASELINE_PATH, loadCiteConfig, parseCiteConfig, readCiteConfigFile, resolveCiteRun } from \"./core/config.js\";\nexport type { CiteRunOptions } from \"./core/config.js\";\n\nexport { runCheck } from \"./commands/check.js\";\nexport { runAdd } from \"./commands/add.js\";\nexport { runRemove } from \"./commands/remove.js\";\nexport { runUpdate } from \"./commands/update.js\";\nexport { reencryptCitationEntries, reencryptCitations } from \"./core/reencrypt.js\";\nexport type { ReencryptEntriesResult, ReencryptOptions } from \"./core/reencrypt.js\";\nexport {\n refusalLine,\n removalLine,\n renderCheckPretty,\n renderRemovePretty,\n renderUpdatePretty,\n rewriteLine,\n} from \"./reporters/pretty.js\";\nexport type { PrettyOptions } from \"./reporters/pretty.js\";\nexport { renderCheckJson, renderRemoveJson, renderUpdateJson } from \"./reporters/json.js\";\nexport { renderCheckGithub } from \"./reporters/github.js\";\n","/**\n * The citation tool's types. Proposal 0044 is the record, and stress test 25\n * the shape: an entry has two ends, `claim` and `source`, each a line range\n * and a hash, and a check classifies both with one set of rules.\n *\n * Vocabulary: a page's `citations` live in its frontmatter, or in a manifest\n * a collection declares (handed in through `CheckPageOptions.citations`). A\n * body marker, `cite <id>` in the format's comment syntax, is the other way\n * to anchor an entry's claim.\n */\nimport type { ValidationResult } from \"../meta/index.js\";\nimport type { CollectionConfig } from \"../shared/collections.js\";\nimport type { ConfigFile } from \"../shared/config-file.js\";\nimport type { KeySource } from \"../shared/encryption-key.js\";\nimport type { LineSpec, PageLines } from \"../shared/pin.js\";\nimport type { Confirm } from \"../shared/prompt.js\";\nimport type { Severity } from \"../shared/severity.js\";\n\n/** A parsed `<src>` or `source`: a path or `~` ciphertext, and an optional line range. */\nexport interface SourceRange {\n /** Repo-root-relative posix path, or the `~` ciphertext when `encrypted`. */\n path: string;\n /** `true` when `path` is an encrypted source (`~` and 82+ base64url characters) rather than a path. */\n encrypted: boolean;\n /** 1-based, inclusive. Both absent for a whole-file citation. */\n start?: number;\n end?: number;\n}\n\n// The line shapes are the shared pin engine's, re-exported so cite's imports and its namespace keep them.\nexport type { LineSpec, PageLines };\n\n/** The page text a citation supports. */\nexport interface CitationClaim {\n /** Body lines: counted from the first line after the frontmatter. Absent when a marker anchors the entry. */\n lines?: LineSpec;\n /** `sha256-<64 hex>` over the claimed lines, always plain. */\n integrity: string;\n}\n\n/** The lines a claim rests on. */\nexport interface CitationSource {\n /** Root-relative posix path, or `~` and the path encrypted with the family key. */\n file: string;\n /** File lines. Absent pins the whole file. */\n lines?: LineSpec;\n /** `sha256-<64 hex>`, or `hmac-sha256-<64 hex>` exactly when `file` is encrypted. */\n integrity: string;\n /** The git commit hash the pin was taken at: 7 to 64 lowercase hex. */\n \"commit-sha\"?: string;\n}\n\n/** One entry of `citations`, as the schema (`manni:citations:1.0.0`) spells it. */\nexport interface Citation {\n id?: string;\n claim?: CitationClaim;\n source: CitationSource;\n quote?: boolean;\n}\n\n/** Where an entry is kept: the page's frontmatter, or a manifest a collection declares. */\nexport type OriginKind = \"frontmatter\" | \"manifest\";\n\n/** Where an entry sits. */\nexport interface CitationOrigin {\n kind: OriginKind;\n /** The file the entry sits in: the page for frontmatter, the manifest otherwise. */\n file: string;\n /** Line of the entry in that file. */\n line?: number;\n /** Index in the page's `citations` list. */\n index: number;\n}\n\n/**\n * One entry handed to `checkCitations` from outside the page, already merged\n * from a manifest. `entry` is the raw value and is validated as a frontmatter\n * entry is; its index is its position in the list.\n */\nexport interface CitationInput {\n entry: unknown;\n origin: { kind: OriginKind; file: string; line?: number };\n}\n\n/** How a citation's claim is anchored: by its lines, by a body marker, or not at all. */\nexport type CitationAnchor = \"claim\" | \"marker\" | null;\n\nexport type SourceStatus =\n | \"current\"\n | \"moved\"\n | \"moved-ambiguous\"\n | \"changed\"\n | \"missing\"\n | \"never-true\"\n | \"skipped\";\n\nexport type ClaimStatus =\n | \"current\"\n | \"moved\"\n | \"moved-ambiguous\"\n | \"reanchored\"\n | \"changed\"\n | \"skipped\";\n\n/** Where a misplaced marker is, and where it belongs (proposal 0054). */\nexport interface MisplacedMarkerReport {\n /** The paragraph the marker's run splits, in file lines. */\n unit: string;\n /** The file line the marker takes once its run has moved. */\n to: number;\n}\n\n/** The marker that anchors a citation: its line, and its misplacement when it has one. */\nexport interface MarkerEnd {\n /** File line of the marker. */\n line: number;\n /** Present only when the marker line sits inside a paragraph. */\n misplaced?: MisplacedMarkerReport;\n}\n\n/**\n * Why a source could not be read: not a tracked file under the root, an\n * encrypted source with no key to decrypt it, one that does not decrypt under\n * the key there is, or a tracked file that could not be read.\n */\nexport type MissingReason = \"untracked\" | \"no-key\" | \"undecryptable\" | \"unreadable\";\n\n/**\n * Every rule a finding can carry, stated once. The union and the default\n * severity table are derived from this array so the three cannot disagree.\n */\nexport const CITE_RULES = [\n \"source-moved\",\n \"source-moved-ambiguous\",\n \"source-changed\",\n \"source-never-true\",\n \"source-missing\",\n \"claim-moved\",\n \"claim-moved-ambiguous\",\n \"claim-reanchored\",\n \"claim-changed\",\n \"marker-orphan\",\n \"marker-invalid\",\n \"marker-repeated\",\n \"marker-misplaced\",\n \"anchor-invalid\",\n \"entry-invalid\",\n \"quote-drift\",\n] as const;\nexport type CiteRule = (typeof CITE_RULES)[number];\n\n/**\n * A rule's level: the family scale (`src/shared/severity.ts`) plus `off`,\n * which drops the rule's findings altogether.\n */\nexport type CiteSeverity = Severity | \"off\";\n\n/** The claim end of a classified citation. Line specs are `\"L\"` or `\"L1-L2\"`. */\nexport interface ClaimEnd {\n /** The entry's body lines. Absent when a marker anchors the claim. */\n lines?: string;\n /** Where the claim is judged, in file lines: the recorded lines, or what the marker anchors. */\n fileLines?: string;\n status: ClaimStatus;\n /** For `moved`: the new body lines. */\n newLines?: string;\n /** For `moved-ambiguous`: every candidate, in body lines. */\n candidates?: string[];\n /** For `moved`: the new file lines. Pretty-only. */\n newFileLines?: string;\n /** For `moved-ambiguous`: every candidate, in file lines. Pretty-only. */\n candidateFileLines?: string[];\n /** For `changed`: the page lines at the claim now, for `--show-diff`. Pretty-only. */\n text?: string[];\n /**\n * For `changed` and `reanchored`: the baseline, the newest commit whose\n * page held the pin. Derived from the page's history, never stored (0053).\n */\n commitSha?: string;\n /** For `changed`: `false` when the walk hit a shallow boundary or its cap. */\n historyAvailable?: boolean;\n /** Subjects of the commits that touched the page since the baseline. Pretty-only. */\n commitsSince?: string[];\n /** Unified diff of the claim's lines since the baseline. Pretty-only, `--show-diff`. */\n diff?: string;\n /**\n * The claim's lines as they were at the baseline. Never serialized: it is\n * what `update --accept` reads to tell an edit from a replacement.\n */\n baselineText?: string[];\n}\n\n/** The source end of a classified citation. */\nexport interface SourceEnd {\n /** `file` and `lines` as the entry spells them: `path`, `path:L`, `path:L1-L2`, the ciphertext for `path`. */\n src: string;\n status: SourceStatus;\n /**\n * The path an encrypted source decrypted to. Never printed except by the\n * pretty reporter under `--reveal`; never serialized to a machine format.\n */\n resolvedPath?: string;\n /**\n * The path a moved encrypted source's `newSrc` decrypts to. Printed only by\n * the pretty reporter under `--reveal`; never serialized to a machine format.\n */\n resolvedNewPath?: string;\n /** For `missing`: why the source could not be read. Composes the message, which never names a path. */\n missingReason?: MissingReason;\n /**\n * For `moved`: the new file lines. For `changed`: the span the pinned\n * range's old first and last lines now cover, when each sits exactly once\n * and in order (proposal 0055).\n */\n newLines?: string;\n /**\n * For `moved`: the new `src`, spelled as the entry spells sources. It names\n * another file when the pin followed its text across one, and carries the\n * new path encrypted for an encrypted source.\n */\n newSrc?: string;\n /** For `moved-ambiguous`: every candidate `src`. */\n candidates?: string[];\n /** The commit the pin was taken at. */\n commitSha?: string;\n /** For `changed` with a commit: whether git could show that commit. */\n historyAvailable?: boolean;\n /** Subjects of commits touching the path since the commit. Pretty-only. */\n commitsSince?: string[];\n /** Unified diff of the path since the commit. Pretty-only, `--show-diff`. */\n diff?: string;\n /** The move search hit its byte budget before covering the file. */\n truncatedSearch?: boolean;\n /**\n * The truncation happened across the files a commit touched rather than\n * inside one file, which is the other half of the notice a run raises. Never\n * serialized: `truncatedSearch` stays the one boolean the output carries.\n */\n truncatedAcross?: boolean;\n}\n\n/** One classified citation: both ends, and how it is anchored. */\nexport interface CitationResult {\n citation: Citation;\n origin: CitationOrigin;\n anchor: CitationAnchor;\n /** File line of the marker that names the entry, when one does. */\n markerLine?: number;\n /**\n * File line the citation anchors to now: the claim's first line, or the\n * first line of the text a marker anchors. Where its findings sit.\n */\n anchorLine?: number;\n /** The marker that names the entry, when one does, and its misplacement. */\n marker?: MarkerEnd;\n /** `null` for an entry with no `claim`: a bare pin, or a marker with no drift check. */\n claim: ClaimEnd | null;\n source: SourceEnd;\n}\n\nexport interface CitationFinding {\n rule: CiteRule;\n /** `manni:cite/<rule>`. */\n ruleId: string;\n /** On the family scale: an `error` fails the file; a `warning` or a `notice` is reported and never does. */\n severity: Severity;\n message: string;\n /** Line the finding anchors to: in the page, or in `file` when that is set. */\n line?: number;\n /** The manifest, when the finding sits there rather than on the page. */\n file?: string;\n id?: string;\n /** The source, spelled as the entry spells it. */\n src?: string;\n newSrc?: string;\n /** Index in the page's `citations` for a finding about one entry. */\n index?: number;\n}\n\nexport interface PageCitationReport {\n file: string;\n format: string;\n citations: CitationResult[];\n findings: CitationFinding[];\n /** Run-level advice, said once per run by the caller: shallow clone, root fallback. */\n notices: string[];\n}\n\n/** What `showFile` answers: the bytes, or why it could not. */\nexport type ShownFile = { text: string } | { missing: \"commit\" | \"path\" };\n\n/** One commit that touched a path. */\nexport interface PageCommit {\n /** The full hash. */\n sha: string;\n subject: string;\n}\n\n/**\n * What `pageCommits` answers: the commits that touched a path, newest first.\n * `shallow` is a repository whose oldest commit may have an unfetched parent,\n * and `truncated` a list the cap cut short. Either means a walk that exhausts\n * the list cannot say the pin never held.\n */\nexport interface PageHistory {\n commits: PageCommit[];\n shallow: boolean;\n truncated: boolean;\n}\n\n/**\n * A thin git client over `execFile(\"git\", …)`, memoized per call shape so a\n * page with a thousand citations against one path runs one `git show`.\n */\nexport interface GitClient {\n available(): Promise<boolean>;\n head(): Promise<string | null>;\n /** Tracked files, posix, relative to the root. */\n lsFiles(): Promise<string[]>;\n showFile(commit: string, path: string): Promise<ShownFile>;\n subjectsSince(commit: string, path: string): Promise<string[]>;\n diffSince(commit: string, path: string): Promise<string>;\n /**\n * Paths whose content differs between `commit` and `HEAD`: committed\n * changes only. The candidate list a pin is followed across (proposal\n * 0055). A client without it follows no source out of its own file.\n */\n changedSince?(commit: string): Promise<string[]>;\n /**\n * The commits that touched `path`, newest first, at most `cap` of them. A\n * client without it reads no claim history, so a claim that no longer holds\n * is `changed` with no baseline.\n */\n pageCommits?(path: string, cap: number): Promise<PageHistory>;\n /**\n * Whether the clone is shallow, so a commit it lacks may still be in the\n * history. A client without it, or without `isAncestor`, never re-records\n * a commit for being outside the history.\n */\n shallow?(): Promise<boolean>;\n /**\n * Whether `commit` is `of` or one of its ancestors. A commit the clone does\n * not have is not.\n */\n isAncestor?(commit: string, of: string): Promise<boolean>;\n}\n\n/**\n * The files a source may resolve to. Built from `git ls-files` when git is\n * available, else from a walk that follows no symlinks. Every entry is\n * realpath-contained in the root.\n */\nexport interface SourceIndex {\n files(): readonly string[];\n /** Whether `path` is a tracked file under the root. An encrypted source is decrypted first, then asked here. */\n has(path: string): boolean;\n}\n\nexport interface CheckPageOptions {\n /** Absolute directory source paths resolve from. */\n root: string;\n /** Default true. False: page-side rules only; every source status is `skipped`. Claim ends are still judged. */\n checkSources?: boolean;\n /**\n * The encryption key: decrypts encrypted sources and keys their pins.\n * Absent, an encrypted citation is `missing` (no key to decrypt it).\n */\n key?: string;\n severity?: Partial<Record<CiteRule, CiteSeverity>>;\n /**\n * The git client the source index and history are read through. Defaults\n * to one over the root, which is used whenever git is on PATH and the root\n * is inside a work tree. A caller that wants no git at all passes `noGit()`.\n */\n gitClient?: GitClient;\n /**\n * Directory the page's own path resolves from, and so the repository its\n * history is read in. Defaults to `root`, the same directory unless\n * `--root` sent the sources to another checkout.\n */\n pageRoot?: string;\n /** The client the page's history is read through. Defaults to one over `pageRoot`. */\n pageGitClient?: GitClient;\n /** How many commits the claim history walk reads. Defaults to `MAX_PAGE_COMMITS`. */\n pageCommitCap?: number;\n sourceIndex?: SourceIndex;\n /**\n * The page's citations as merged from a manifest, each with where it sits.\n * Given, the page's own frontmatter `citations` is not read. Without it, a\n * grader calling `checkCitations` on a sidecar page would find no citations.\n */\n citations?: readonly CitationInput[];\n /**\n * The manifest that owns this page's `citations`, when one does. A page\n * that carries its own anyway is `entry-invalid`, in meta's `external:owned`\n * words.\n */\n owned?: { file: string; collection: string };\n}\n\nexport interface MintOptions {\n root: string;\n /** `path`, `path:L`, `path:L1-L2`, or an encrypted `~file` with the same line forms. */\n src: string;\n id?: string;\n /** The claim pin, already taken over the page lines. */\n claim?: CitationClaim;\n quote?: boolean;\n /** A commit to record; `false` records none; absent records HEAD when git has one. */\n commitSha?: string | false;\n /**\n * Write `file` encrypted and pin the lines with the keyed pin; needs `key`.\n * A source that is already encrypted stays encrypted either way.\n */\n encrypt?: boolean;\n /** The encryption key: encrypts, decrypts an encrypted source, and keys its pin. */\n key?: string;\n gitClient?: GitClient;\n sourceIndex?: SourceIndex;\n}\n\n/**\n * One replacement against a fixed text: the bytes `[start, end)` become\n * `text`. A writer that has a position from a parse hands back an edit rather\n * than a rewritten page, so several of them can be collected against that one\n * parse and applied together (`applyEdits`). Nothing is then read out of a\n * text that has already been written to.\n */\nexport interface TextEdit {\n start: number;\n end: number;\n text: string;\n}\n\n/** One marker found in a page body: `cite <id>` in the format's comment syntax. */\nexport interface InlineStatement {\n /** File line of the marker. */\n line: number;\n /** File line of the anchored text: the rest of the marker's line, else the paragraph or block that follows. */\n anchorLine?: number;\n /**\n * The ids the marker names, in the order written, or why the marker is not\n * read. A payload of one id is what proposal 0044 shipped; 0056 widened it\n * to a space-separated list, and every id in the list anchors the same text.\n */\n payload:\n | { kind: \"ref\"; ids: [string, ...string[]] }\n | { kind: \"bad\"; reason: string; json?: boolean };\n /** The marker text between the delimiters, trimmed. */\n raw: string;\n /** Character offsets of the whole marker in the file, for rewriting. */\n start: number;\n end: number;\n}\n\n/** A validated citation with where it sits and the marker that names it, before classification. */\nexport interface PageCitation {\n citation: Citation;\n origin: CitationOrigin;\n /** The first marker naming the entry's id. */\n marker?: InlineStatement;\n}\n\n/** What `readPage` returns: the entries, the markers, and page-side findings. */\nexport interface PageCitations {\n file: string;\n format: string;\n content: string;\n /** Offset where the body starts (just past the closing fence, or 0). */\n bodyOffset: number;\n /** File line of body line 1: the first line after the frontmatter, or 1. */\n bodyLine: number;\n citations: PageCitation[];\n statements: InlineStatement[];\n findings: CitationFinding[];\n}\n\nexport interface CheckOptions {\n /** Positional inputs; empty means the configured collections' `paths:` (0041). */\n inputs: string[];\n /**\n * `--collection <name>`, repeatable: the collections this run covers. Empty\n * or absent means every declared one; see `selectCollections`.\n */\n collection?: string[];\n exts?: string[];\n /** `--exclude`, appended to the selected collections' `exclude:` when the run reads from them. */\n exclude?: string[];\n as?: string;\n configPath?: string;\n noConfig?: boolean;\n cwd?: string;\n stdinContent?: string;\n allowEmpty?: boolean;\n respectGitignore?: boolean;\n onNotice?: (message: string) => void;\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n baseline?: string | boolean;\n writeBaseline?: string | boolean;\n /** `--no-check-sources` (false): page-side rules only. Absent leaves `checkSources:` in charge. */\n checkSources?: boolean;\n /**\n * `--show-diff`: the report will want diffs and commit subjects. The check\n * is the same either way; the run only says, once, when git is not there\n * to give them.\n */\n showDiff?: boolean;\n root?: string;\n /**\n * The git client every page is checked through. Defaults to one over the\n * root, used whenever git is on PATH and the root is inside a work tree; a\n * test hands in a fake.\n */\n gitClient?: GitClient;\n /**\n * The client every page's own history is read through, over the directory\n * the page paths resolve from. Defaults to one there; a test hands in a fake.\n */\n pageGitClient?: GitClient;\n /** Defaults to `process.env`; read for `MANNI_ENCRYPTION_KEY`. A test hands in its own. */\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface CheckRun {\n results: ValidationResult[];\n summary: import(\"../meta/index.js\").RunSummary;\n frame: import(\"../meta/index.js\").FingerprintContext;\n pages: PageCitationReport[];\n warnings: number;\n notices: number;\n}\n\n\nexport interface AddOptions {\n page: string;\n /** The claim's lines as an editor numbers them (`page:L`, `page:L1-L2`). Absent: a bare pin. */\n pageLines?: PageLines;\n src: string;\n id?: string;\n /** Write a marker above the page lines instead of claim lines, and pin the text it anchors. Needs `pageLines` and `id`. */\n marker?: boolean;\n /** The page lines are a fenced block that reproduces the source. Needs `pageLines`. */\n quote?: boolean;\n /**\n * `--encrypt`: write `file` encrypted, with a keyed pin, even when no key is\n * available yet, in which case `confirm` is asked whether to generate one.\n * An available key encrypts every add without it, so `false` and absent\n * are the same.\n */\n encrypt?: boolean;\n /** `false` records no `commit-sha`. */\n commitSha?: boolean;\n dryRun?: boolean;\n as?: string;\n configPath?: string;\n noConfig?: boolean;\n cwd?: string;\n stdinContent?: string;\n root?: string;\n /**\n * The git client HEAD and the source index are read through. Defaults to\n * one over the root; a test hands in a fake.\n */\n gitClient?: GitClient;\n /** Defaults to `process.env`; read for `MANNI_ENCRYPTION_KEY`. A test hands in its own. */\n env?: NodeJS.ProcessEnv;\n onNotice?: (message: string) => void;\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n /**\n * Asked when `encrypt` needs a key and there is none; the CLI passes\n * `terminalConfirm()`. Absent, the add refuses instead of asking.\n */\n confirm?: Confirm;\n}\n\n/** The manifest half of a write: what it says now, and whether it was saved. */\nexport interface ManifestWrite {\n /** The manifest as the run reports it. */\n file: string;\n /** 1-based line the written entry now sits on. */\n line: number;\n /** The whole manifest, rewritten. */\n content: string;\n diff: string;\n written: boolean;\n}\n\nexport interface AddResult {\n file: string;\n citation: Citation;\n /**\n * Where the entry was written: the page's frontmatter, or the manifest the\n * page's collection declares. The config decides, not a flag.\n */\n placed: \"frontmatter\" | \"manifest\";\n /** The manifest the entry went to, under `placed: \"manifest\"`. */\n manifest?: ManifestWrite;\n /** File lines of the claim after the write: the claim lines, or the text the marker anchors. */\n claimLines?: PageLines;\n /** File line of the marker that names the entry, under `marker`. */\n markerLine?: number;\n /**\n * Whether the id joined the list of a marker already there, rather than\n * getting a marker line of its own. A join moves no line on the page.\n */\n markerJoined?: boolean;\n /**\n * The first pinned source line, as the file holds it, so a mis-typed range\n * is visible at write time. Absent for a whole file, which has no first\n * line worth naming, and for an encrypted source, which no output reveals.\n */\n sourceLine?: string;\n /** The rewritten page. */\n content: string;\n diff: string;\n written: boolean;\n}\n\nexport interface UpdateOptions extends Omit<CheckOptions, \"baseline\" | \"writeBaseline\"> {\n accept?: boolean;\n only?: string[];\n dryRun?: boolean;\n /**\n * Re-record `commit-sha` where the recorded commit does not contain the\n * pinned lines. Rewrites that one field and nothing else.\n */\n recommit?: boolean;\n}\n\n/**\n * One end `update` rewrote.\n *\n * Read the typed pairs: `fromLines`/`toLines` for lines, `fromPin`/`toPin`\n * for pins. `from` and `to` carry the same values, but which of the two a row\n * holds depends on the row, so they are easy to misuse.\n */\n/** Why `--recommit` re-recorded a commit. */\nexport type RecommitReason = \"not-contained\" | \"not-in-history\";\n\nexport interface UpdateRewrite {\n id?: string;\n /** Index in the page's `citations`. */\n index: number;\n /** File line of the entry. */\n line?: number;\n end: \"claim\" | \"source\" | \"marker\";\n /**\n * `re-anchored` covers both re-pins: the pin held over another span (0054),\n * and the words held while the anchor moved (0053). `status` is what tells\n * those apart. `replaced` is a claim `--accept` refused to re-pin.\n */\n reason: \"moved\" | \"accepted\" | \"re-anchored\" | \"shifted\" | \"replaced\" | \"recommitted\";\n /**\n * The status that was repaired. `replaced` is a claim whose line held\n * wholly other text, accepted because `--only` named it.\n */\n status: \"moved\" | \"changed\" | \"reanchored\" | \"replaced\" | \"never-true\" | \"misplaced\" | \"current\";\n /**\n * Before and after. A moved or shifted claim, and a moved marker: file\n * lines. A moved source: its `src`. An accepted or re-anchored end: its pin.\n * The typed pairs below say which, so prefer them.\n */\n from: string;\n to: string;\n /** A moved marker, or a moved or shifted claim: its file lines, before and after. */\n fromLines?: string;\n toLines?: string;\n /** An accepted or re-anchored end: its pin, before and after. */\n fromPin?: string;\n toPin?: string;\n /** A re-committed source: the commit it recorded, and the one it records now. */\n fromCommit?: string;\n toCommit?: string;\n /**\n * A re-committed source: why the recorded commit could not stand.\n * `not-contained`: it does not hold the pinned lines. `not-in-history`: it\n * holds them, but is not in the history of HEAD.\n */\n because?: RecommitReason;\n /** A re-anchored claim: the span that held, in file lines. */\n lines?: string;\n /** A re-anchored claim: the span now pinned, in file lines. */\n newLines?: string;\n /** An accepted, re-anchored or refused claim: the file line of its first body line. */\n at?: number;\n /** An accepted claim a marker anchors: the marker's file line. Pretty-only. */\n markerLine?: number;\n /** An accepted claim: the text now pinned, whitespace collapsed. */\n text?: string;\n /** An accepted source: its `src`. */\n src?: string;\n /**\n * An accepted source: the commit recorded in the entry, when it records\n * one. A re-anchored or refused claim: the baseline its words were read\n * against.\n */\n commitSha?: string;\n /**\n * A refused claim the word-overlap test refused: the share of the claim's\n * words, from 0 to 1, that its line still holds. Absent on a claim the\n * sentence test refused, which is how a report tells the two apart.\n */\n wordShare?: number;\n}\n\nexport interface UpdatePage {\n file: string;\n rewritten: UpdateRewrite[];\n /**\n * Claims `--accept` refused to re-pin, because the stored first line now\n * holds text that shares no sentence with the claim at its baseline, or too\n * few of its words. Each carries `reason: \"replaced\"`, and each is work left\n * undone: exit 1.\n */\n refused: UpdateRewrite[];\n skipped: CitationFinding[];\n diff: string;\n written: boolean;\n /** The rewritten page, for the stdin input only: it has no file to be written to. */\n content?: string;\n}\n\n/** One manifest a run rewrote: what changed in it, and whether it was saved. */\nexport interface ManifestChange {\n /** The manifest as the run reports it. */\n file: string;\n diff: string;\n written: boolean;\n}\n\nexport interface UpdateRun {\n pages: UpdatePage[];\n rewritten: number;\n skipped: number;\n /** The manifests this run rewrote, each written once however many pages it holds. */\n manifests?: ManifestChange[];\n exitCode: 0 | 1;\n}\n\nexport interface RemoveOptions\n extends Omit<CheckOptions, \"baseline\" | \"writeBaseline\" | \"checkSources\" | \"showDiff\"> {\n /**\n * `--only <id>`, repeatable: the entries to remove, each named by its id or\n * by its pointer (`/citations/N`). Required, and an empty list is a\n * refusal: `remove` never takes every citation off a page.\n */\n only: string[];\n dryRun?: boolean;\n}\n\n/** One entry `remove` took out, and the markers that went with it. */\nexport interface Removal {\n id?: string;\n /** Index in the page's `citations`. Absent for a marker that named no entry. */\n index?: number;\n /** Where the entry was kept. Absent for a marker that named no entry. */\n origin?: { kind: OriginKind; file: string; line?: number };\n /** File lines of the markers removed with it, in the page as it was. */\n markerLines: number[];\n}\n\nexport interface RemovePage {\n file: string;\n removed: Removal[];\n diff: string;\n written: boolean;\n /** The rewritten page, for the stdin input only: it has no file to be written to. */\n content?: string;\n}\n\nexport interface RemoveRun {\n pages: RemovePage[];\n /** Entries removed, counting a marker that named no entry as one. */\n removed: number;\n /** The manifests this run rewrote, each written once however many pages it holds. */\n manifests?: ManifestChange[];\n}\n\n/** One citation `reencryptCitations` rewrote: where it sits, and its source before and after. */\nexport interface ReencryptedCitation {\n id?: string;\n /** Index in `citations`. */\n index?: number;\n /** File line of the entry. */\n line?: number;\n /** `file` and its line suffix, under the old key and under the new. */\n from: string;\n to: string;\n}\n\n/** What `reencryptCitations` did to one page. */\nexport interface ReencryptCitationsResult {\n /** The page with every re-encrypted citation rewritten; the input itself when none was. */\n content: string;\n rewritten: ReencryptedCitation[];\n /** Citations that could not be re-encrypted, and why. A message never names a path. */\n skipped: { id?: string; index?: number; line?: number; message: string }[];\n}\n\n/**\n * Config under `cite:` in manni.config.yaml, camelCase as `meta:` is. The\n * document set is not here: proposal 0041 moved `paths` and `exclude` to the\n * family-level `collections:` list, which every tool reads. Neither is the\n * encryption key, the top-level `encryptionKey:` every tool reads (0045).\n */\nexport interface CiteConfig {\n allowEmpty?: boolean;\n respectGitignore?: boolean;\n root?: string;\n baseline?: string;\n checkSources?: boolean;\n severity?: Partial<Record<CiteRule, CiteSeverity>>;\n}\n\nexport interface LoadedCiteConfig {\n config: CiteConfig;\n path: string;\n dir: string;\n /** The file as the user would name it, for messages. */\n source: string;\n /** The family file's top-level `collections:`, parsed by the shared layer (0041). */\n collections: CollectionConfig[];\n}\n\n/** What every command core resolves before touching a file. */\nexport interface CiteRun {\n config: CiteConfig | null;\n /** The positional inputs, or the selected collections' `paths:` in declaration order. */\n inputs: string[];\n /** Directory the inputs resolve from: cwd for positional inputs, the config directory for collections. */\n base: string;\n /**\n * The collections this run covers: every declared one, or the ones\n * `--collection` named. `[]` when no config governs the run.\n */\n collections: CollectionConfig[];\n /** Whether `inputs` came from the collections rather than the command line. */\n fromCollections: boolean;\n configDir?: string;\n configPath?: string;\n /** The config file as the user would name it, for messages. */\n configSource?: string;\n /** Absolute root source paths resolve from. */\n root: string;\n /**\n * The family encryption key (proposal 0045): `MANNI_ENCRYPTION_KEY`, else\n * the config's top-level `encryptionKey:`. Absent when neither is set.\n */\n key?: string;\n /** Where `key` came from. The environment wins over the config. */\n keySource: KeySource;\n /**\n * The config file that governs the run, as discovery found it. A write\n * that needs a key (`add --encrypt` with none) puts one there.\n */\n configFile?: ConfigFile;\n}\n","import { ToolError } from \"../shared/errors.js\";\nimport { LineRangeError } from \"../shared/pin.js\";\n\n/** An operational or usage error in the citation tool: exit 2. */\nexport class CiteError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"CiteError\";\n }\n}\n\n/**\n * Run a shared pin-engine call under cite's error contract: a\n * `LineRangeError` comes back as a `CiteError` with the same message, which is\n * what cite's callers (and library users of the `cite` namespace) match on.\n */\nexport function asCiteError<T>(call: () => T): T {\n try {\n return call();\n } catch (error) {\n if (error instanceof LineRangeError) throw new CiteError(error.message);\n throw error;\n }\n}\n","/**\n * Which rules fail a run, which only warn, and which are notices.\n *\n * Warnings and notices never affect the exit code (docevals' rule).\n * `source-moved` is a warning because `cite update` fixes it mechanically,\n * and a PR job that failed on it would make the ratchet noisy. `claim-moved`\n * is a notice: the text is found verbatim, so nothing drifted.\n * `claim-reanchored` is a notice for the same reason (proposal 0053): the\n * words the pin covered are found unchanged since the baseline, so only the\n * layout moved, and plain `cite update` re-pins it.\n * `claim-changed` is a warning, since it fires on any edit to a pinned\n * paragraph, a typo fix beside the cited sentence included. A repository that\n * wants either hard sets `severity: { claim-changed: error }`.\n * `marker-misplaced` is a warning too: it annotates the pull request, and one\n * `cite update` clears it, so a job that failed on it would block on a page\n * that was fine yesterday (proposal 0054, stress test 15).\n */\nimport { CITE_RULES, type CiteRule, type CiteSeverity } from \"../types.js\";\n\nexport const DEFAULT_SEVERITY: Readonly<Record<CiteRule, CiteSeverity>> = {\n \"source-moved\": \"warning\",\n \"source-moved-ambiguous\": \"error\",\n \"source-changed\": \"error\",\n \"source-never-true\": \"error\",\n \"source-missing\": \"error\",\n \"claim-moved\": \"notice\",\n \"claim-moved-ambiguous\": \"warning\",\n \"claim-reanchored\": \"notice\",\n \"claim-changed\": \"warning\",\n \"marker-orphan\": \"error\",\n \"marker-invalid\": \"error\",\n \"marker-repeated\": \"warning\",\n \"marker-misplaced\": \"warning\",\n \"anchor-invalid\": \"error\",\n \"entry-invalid\": \"error\",\n \"quote-drift\": \"error\",\n};\n\nexport const RULE_ID_PREFIX = \"manni:cite\";\n\n/** `manni:cite/<rule>`: the SARIF rule id and the JUnit failure type. */\nexport function ruleId(rule: CiteRule): string {\n return `${RULE_ID_PREFIX}/${rule}`;\n}\n\nexport function isCiteRule(value: string): value is CiteRule {\n return (CITE_RULES as readonly string[]).includes(value);\n}\n\n/** The effective severity table: defaults with the config's overrides. */\nexport function resolveSeverity(\n overrides?: Partial<Record<CiteRule, CiteSeverity>>,\n): Record<CiteRule, CiteSeverity> {\n return { ...DEFAULT_SEVERITY, ...(overrides ?? {}) };\n}\n","/**\n * Source and line grammar.\n *\n * An entry's `source.file` is a path or an encrypted source (`~` and at least\n * 82 base64url characters, proposal 0045), and its `lines` an integer or\n * `\"L1-L2\"`. `FILE_PATTERN` is the schema's `$defs.fileRef.pattern`, spelled\n * once here and once in the registered `manni:citations:1.0.0` schema\n * (`src/meta/schemas/citations/1.0.0.json`); `test/cite/range.test.ts` pins\n * the two equal.\n *\n * The command line spells a source as one string, `path`, `path:L` or\n * `path:L1-L2` (`SRC_PATTERN`), and reports spell it that way too.\n */\nimport { isEncryptedValue } from \"../../shared/encryption.js\";\nimport { MAX_RANGE_LINES, lineSpec, parseLines } from \"../../shared/pin.js\";\nimport { CiteError } from \"../errors.js\";\nimport type { CitationSource, LineSpec, PageLines, SourceRange } from \"../types.js\";\n\n// The line grammar is the shared pin engine's; this path keeps cite's imports working.\nexport { lineSpec, parseLines, spellLines } from \"../../shared/pin.js\";\n\n/** The schema's `$defs.fileRef.pattern`, as a RegExp. */\nexport const FILE_PATTERN =\n /^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\\.\\.?(?:\\/|$))[^/\\\\:\\r\\n\\t]+)(?:\\/(?:(?!\\.\\.?(?:\\/|$))[^/\\\\:\\r\\n\\t]+))*)$/;\n\n/** A source on the command line: a `file`, then an optional `:L` or `:L1-L2`. */\nexport const SRC_PATTERN =\n /^(?:~[A-Za-z0-9_-]{82,}|(?!~)(?:(?!\\.\\.?(?:\\/|:|$))[^/\\\\:\\r\\n\\t]+)(?:\\/(?:(?!\\.\\.?(?:\\/|:|$))[^/\\\\:\\r\\n\\t]+))*)(?::[1-9][0-9]*(?:-[1-9][0-9]*)?)?$/;\n\n/**\n * Parse a command-line source. Throws `CiteError` on bad grammar or an end\n * line before the start. A one-line `path:L` comes back with `end` equal to\n * `start`, so a range's width is always `end - start + 1`.\n */\nexport function parseSrc(src: string): SourceRange {\n if (!SRC_PATTERN.test(src)) {\n throw new CiteError(\n `Invalid src \"${src}\": expected path, path:L, path:L1-L2, or an encrypted source (~ and at least 82 base64url characters) with the same line forms; ` +\n \"the path is repo-root-relative, posix, and free of . and .. segments.\",\n );\n }\n // The grammar keeps `:` out of every path segment and out of the base64url\n // alphabet, so the first one starts the line suffix.\n const colon = src.indexOf(\":\");\n const path = colon === -1 ? src : src.slice(0, colon);\n const range: SourceRange = { path, encrypted: isEncryptedValue(path) };\n if (colon === -1) return range;\n const [startText, endText] = src.slice(colon + 1).split(\"-\");\n const start = Number(startText);\n const end = endText === undefined ? start : Number(endText);\n if (end < start) {\n throw new CiteError(`Invalid range \"${src}\": end line ${end} is before start line ${start}.`);\n }\n range.start = start;\n range.end = end;\n return range;\n}\n\n/**\n * How a range too wide to cite is refused: `spans N lines, more than 5000`.\n * Undefined for a range of at most `MAX_RANGE_LINES` lines.\n */\nexport function tooWide(lines: PageLines): string | undefined {\n const width = lines.end - lines.start + 1;\n return width > MAX_RANGE_LINES\n ? `spans ${String(width)} lines, more than ${String(MAX_RANGE_LINES)}`\n : undefined;\n}\n\n/** The canonical spelling: `path:L` for one line, `path:L1-L2` otherwise. */\nexport function formatSrc(range: SourceRange): string {\n const { path, start, end } = range;\n if (start === undefined) return path;\n if (end === undefined || end === start) return `${path}:${start}`;\n return `${path}:${start}-${end}`;\n}\n\n/** An entry's source as a range. Its lines must already be valid (see `parseLines`). */\nexport function sourceRange(source: CitationSource): SourceRange {\n const range: SourceRange = { path: source.file, encrypted: isEncryptedValue(source.file) };\n if (source.lines === undefined) return range;\n const lines = parseLines(source.lines);\n if (lines !== undefined) {\n range.start = lines.start;\n range.end = lines.end;\n }\n return range;\n}\n\n/** An entry's source spelled as one string, `path:L1-L2`, the way the command line takes it. */\nexport function spellSource(source: CitationSource): string {\n return formatSrc(sourceRange(source));\n}\n\n/** A range's lines as an entry writes them; undefined for a whole file. */\nexport function rangeLines(range: SourceRange): LineSpec | undefined {\n if (range.start === undefined) return undefined;\n return lineSpec({ start: range.start, end: range.end ?? range.start });\n}\n","/**\n * The hashing rule, as cite uses it. The engine is `src/shared/pin.ts`, shared\n * with meta; this module keeps cite's import path and its error contract: a\n * range past the end of the text throws `CiteError`.\n */\nimport {\n hashRange as sharedHashRange,\n sliceLines as sharedSliceLines,\n type LineRange,\n} from \"../../shared/pin.js\";\nimport { asCiteError } from \"../errors.js\";\n\nexport { hashLines, isKeyedPin, normalizeText, splitLines } from \"../../shared/pin.js\";\n\n/**\n * The cited lines joined by LF. Throws `CiteError` when the range runs past\n * the end of the text (`<path> has N lines; line M is out of range`).\n */\nexport function sliceLines(lines: readonly string[], range?: LineRange, label?: string): string {\n return asCiteError(() => sharedSliceLines(lines, range, label));\n}\n\n/** The pin of the cited lines: plain, or the keyed pin under `key` when one is given. Throws `CiteError` past the end. */\nexport function hashRange(text: string, range?: LineRange, key?: string): string {\n return asCiteError(() => sharedHashRange(text, range, key));\n}\n","/**\n * How a citation reads on a terminal. A pin is sixty-four hex digits and a\n * ciphertext is longer still, so both are abbreviated for a person, and every\n * report and every `add` line abbreviates them the same way.\n */\nimport type { PageLines } from \"../types.js\";\n\n/** `sha256-78af1d33…`, `hmac-sha256-5e0c1a2b…`: the prefix and eight hex digits. */\nexport function shortPin(integrity: string): string {\n const m = /^((?:hmac-)?sha256-)([0-9a-f]{8})/i.exec(integrity);\n const prefix = m?.[1];\n const digits = m?.[2];\n if (prefix === undefined || digits === undefined) return integrity;\n return `${prefix}${digits}…`;\n}\n\n/** The seven characters a person reads a commit by. */\nexport function shortCommit(commit: string): string {\n return commit.slice(0, 7);\n}\n\n/**\n * `~AQx7…:2`: an encrypted source, abbreviated, with its line suffix kept. A\n * plain path is spelled in full, because that is what a reader has to find.\n */\nexport function shortSrc(src: string): string {\n if (!src.startsWith(\"~\")) return src;\n const colon = src.indexOf(\":\");\n const token = colon === -1 ? src : src.slice(0, colon);\n const lines = colon === -1 ? \"\" : src.slice(colon);\n return token.length <= 5 ? src : `${token.slice(0, 5)}…${lines}`;\n}\n\n/** The widest a quoted line of a file is printed at. */\nconst LINE_WIDTH = 60;\n\n/**\n * A line of a file as a report quotes it: whitespace collapsed to single\n * spaces, then sixty characters and an ellipsis. The report is one line, so\n * neither an indented source line nor a long one decides how it reads.\n */\nexport function shortLine(text: string): string {\n const one = text.replace(/\\s+/g, \" \").trim();\n return one.length <= LINE_WIDTH ? one : `${one.slice(0, LINE_WIDTH)}…`;\n}\n\n/**\n * `line 9`, or `lines 9-12`: where on a page a span sits. Every refusal,\n * report and message that names one reads it this way, so `add`, `update`\n * and the reporters spell it once.\n */\nexport function spellAt(lines: PageLines): string {\n return lines.start === lines.end\n ? `line ${String(lines.start)}`\n : `lines ${String(lines.start)}-${String(lines.end)}`;\n}\n\n/** `a`, `a and b`, `a, b and c`: a list as a sentence reads it. */\nexport function listOf(values: readonly string[]): string {\n if (values.length <= 1) return values.join(\"\");\n return `${values.slice(0, -1).join(\", \")} and ${values[values.length - 1] ?? \"\"}`;\n}\n","/**\n * Where a `src` may resolve to, and how an encrypted source is written and\n * read.\n *\n * Sources resolve through tracked files only (`git ls-files -z`) when git is\n * available, else through a walk that follows no symlinks. Every candidate is\n * realpath-contained in the root, so a committed symlink or a `..` cannot reach\n * outside it. A page is untrusted input to the CI job that checks it.\n *\n * An encrypted source is the path encrypted with the family key in the\n * `cite-src` context (proposal 0045). Reading one decrypts it to the path and\n * then asks the index exactly as a plain path is asked, so a ciphertext is\n * never a way around the tracked-file rule.\n */\nimport fg from \"fast-glob\";\nimport { lstat, readFile, realpath } from \"node:fs/promises\";\nimport { join, sep } from \"node:path\";\nimport { decryptValue, encryptValue } from \"../../shared/encryption.js\";\nimport { CiteError } from \"../errors.js\";\nimport type { GitClient, MissingReason, SourceIndex, SourceRange } from \"../types.js\";\nimport { SRC_PATTERN } from \"./range.js\";\n\n/** The one context cite encrypts in, bound as associated data. */\nconst CONTEXT = \"cite-src\";\n\n/** `path` encrypted under `key`: `~` and at least 82 base64url characters. */\nexport function encryptSourcePath(path: string, key: string): string {\n return encryptValue(path, key, CONTEXT);\n}\n\n/**\n * The path an encrypted source holds, or `undefined` when it does not decrypt\n * under `key` in the `cite-src` context, or holds anything but a path a plain\n * `src` could spell. A ciphertext is trusted no further than the page's own\n * paths are.\n */\nexport function decryptSourcePath(token: string, key: string): string | undefined {\n const opened = decryptValue(token, key, CONTEXT);\n if (!opened.ok || typeof opened.value !== \"string\") return undefined;\n const path = opened.value;\n // A bare plain path: no line suffix, and no ciphertext inside a ciphertext.\n if (path.includes(\":\") || path.startsWith(\"~\") || !SRC_PATTERN.test(path)) return undefined;\n return path;\n}\n\nexport interface BuildIndexOptions {\n /** `git ls-files` when this client reports git available; a walk when it does not, or with no client. */\n gitClient?: GitClient;\n}\n\n/** `true` when `real` is `realRoot` itself or lies below it. */\nfunction isUnder(real: string, realRoot: string): boolean {\n return real === realRoot || real.startsWith(realRoot.endsWith(sep) ? realRoot : realRoot + sep);\n}\n\n/**\n * The candidate's posix relative path if it is a regular file whose real\n * location lies under the real root; `undefined` to drop it. A symlink is\n * dropped by `lstat` before it is ever followed; a path that walks out, or a\n * file reached through a symlinked directory, is dropped by the realpath check.\n */\nasync function admit(root: string, realRoot: string, rel: string): Promise<string | undefined> {\n const abs = join(root, rel);\n try {\n const info = await lstat(abs);\n if (!info.isFile()) return undefined;\n const real = await realpath(abs);\n return isUnder(real, realRoot) ? rel : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function candidates(root: string, opts: BuildIndexOptions | undefined): Promise<string[]> {\n const client = opts?.gitClient;\n if (client !== undefined && (await client.available())) {\n return client.lsFiles();\n }\n return fg(\"**/*\", {\n cwd: root,\n onlyFiles: true,\n dot: true,\n followSymbolicLinks: false,\n ignore: [\"**/.git/**\", \"**/node_modules/**\"],\n });\n}\n\nexport async function buildSourceIndex(root: string, opts?: BuildIndexOptions): Promise<SourceIndex> {\n const realRoot = await realpath(root);\n const admitted = await Promise.all(\n (await candidates(root, opts)).map((rel) => admit(root, realRoot, rel)),\n );\n const files = Object.freeze(\n [...new Set(admitted.filter((rel): rel is string => rel !== undefined))].sort(),\n );\n const byPath = new Set(files);\n return {\n files: () => files,\n has: (path) => byPath.has(path),\n };\n}\n\nfunction isEnoent(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\n/**\n * The source index for a run, with a root that is not there refused as a\n * `CiteError`. Every verb that reads sources builds its index here, so the\n * refusal reads the same on each.\n */\nexport async function sourceIndexFor(root: string, client: GitClient): Promise<SourceIndex> {\n try {\n return await buildSourceIndex(root, { gitClient: client });\n } catch (error) {\n if (isEnoent(error)) throw new CiteError(`Root directory not found: ${root}.`);\n throw error;\n }\n}\n\nexport type ReadSourceResult =\n | { kind: \"ok\"; resolvedPath: string; text: string }\n | { kind: \"missing\"; reason: MissingReason };\n\n/**\n * The path a range names, whether or not the file is there. An encrypted\n * source is decrypted under `key` first: with no key that is `no-key`, under\n * another key `undecryptable`. Whether the path is tracked and readable is a\n * separate question, which `readSource` asks next; a path that is gone still\n * has history, and that is what a move search reads.\n */\nexport function resolveSourcePath(\n range: SourceRange,\n key?: string,\n): { path: string } | { reason: Extract<MissingReason, \"no-key\" | \"undecryptable\"> } {\n if (!range.encrypted) return { path: range.path };\n if (key === undefined) return { reason: \"no-key\" };\n const path = decryptSourcePath(range.path, key);\n return path === undefined ? { reason: \"undecryptable\" } : { path };\n}\n\n/**\n * Read the file a range names. An encrypted source is decrypted under `key`\n * first: with no key it is `no-key`, under another key `undecryptable`. Never\n * reads a path the index does not hold.\n */\nexport async function readSource(\n root: string,\n index: SourceIndex,\n range: SourceRange,\n key?: string,\n): Promise<ReadSourceResult> {\n const resolved = resolveSourcePath(range, key);\n if (\"reason\" in resolved) return { kind: \"missing\", reason: resolved.reason };\n const resolvedPath = resolved.path;\n if (!index.has(resolvedPath)) return { kind: \"missing\", reason: \"untracked\" };\n const text = await readTracked(root, resolvedPath);\n return text === undefined\n ? { kind: \"missing\", reason: \"unreadable\" }\n : { kind: \"ok\", resolvedPath, text };\n}\n\n/**\n * One tracked file's bytes, or undefined when it cannot be read: a permission\n * error, or a path the diff named that is no longer on disk. A move search\n * skips such a candidate rather than failing the run over it.\n */\nexport async function readTracked(root: string, path: string): Promise<string | undefined> {\n try {\n return await readFile(join(root, path), \"utf8\");\n } catch {\n return undefined;\n }\n}\n","/**\n * Read a page's citations and its markers.\n *\n * Entries come from the frontmatter (via meta's extractor for the format), or\n * from `CheckPageOptions.citations` when a manifest owns them; either way each\n * one is validated against the registered `manni:citations:1.0.0` schema and\n * carries where it sits.\n * Markers are `cite <id> [<id>…]` comments in the body, resolved to the\n * entries they name, so each citation knows what anchors it. Every id one\n * marker names anchors the same text, so every claim under it pins the same\n * bytes and holds the same hash (proposal 0056).\n *\n * The findings made here are the ones that need no source: `entry-invalid`,\n * `marker-invalid`, `marker-orphan`, `marker-repeated` and `anchor-invalid`.\n */\nimport { extname } from \"node:path\";\nimport * as Ajv2020Ns from \"ajv/dist/2020.js\";\nimport type { ValidateFunction } from \"ajv/dist/2020.js\";\nimport citationsSchema from \"../../meta/schemas/citations/1.0.0.json\" with { type: \"json\" };\nimport {\n extractorForExtension,\n locateFrontmatter,\n supportedExtensions,\n type ExtractedMetadata,\n type MetadataExtractor,\n} from \"../../meta/index.js\";\nimport { extractorByName, hasFrontmatterFence } from \"../../meta/internal.js\";\nimport { isEncryptedValue } from \"../../shared/encryption.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n Citation,\n CitationFinding,\n CitationInput,\n CitationOrigin,\n CiteRule,\n PageCitation,\n PageCitations,\n} from \"../types.js\";\nimport { isKeyedPin } from \"./hash.js\";\nimport { parseLines, spellSource, tooWide } from \"./range.js\";\nimport { DEFAULT_SEVERITY, ruleId } from \"./severity.js\";\nimport { lineAt, parseStatements } from \"./statements.js\";\n\nexport { MAX_IDS_PER_MARKER } from \"./statements.js\";\n\nexport const MAX_MARKERS_PER_PAGE = 500;\n\n/** Formats whose leading fenced block is frontmatter meta would read. */\nconst ELEMENT_BACKED = new Set([\"html\", \"xml\"]);\n/** Formats whose only metadata channel is a fenced block. */\nconst FENCE_ONLY = new Set([\"markdown\", \"mdx\"]);\n\n/** What a marker with a JSON payload is told, since an entry never lives in the body. */\nexport const MARKER_JSON =\n \"A marker names an entry by id. Write the entry in frontmatter or the sidecar.\";\n\nexport interface ReadPageOptions {\n /** Extractor name; derived from the file's extension when absent. */\n format?: string;\n /**\n * The page's citations as a manifest owns them, already merged. Given, the\n * page's own frontmatter `citations` is not read.\n */\n citations?: readonly CitationInput[];\n /**\n * The manifest that owns this page's `citations`, when one does. A page\n * that also carries its own is `entry-invalid`: neither channel wins, and\n * the discarded value would be exactly the one nobody checked.\n */\n owned?: { file: string; collection: string };\n}\n\n/** Meta's `external:owned` sentence, said by `cite check` under `entry-invalid`. */\nexport function ownedMessage(owner: { file: string; collection: string }): string {\n return `\"citations\" is owned by manifest ${owner.file} (collection ${owner.collection}); remove it from the document`;\n}\n\n// ajv is CommonJS with a default export; under NodeNext the constructor lives\n// on `.default`, as src/meta/core/validator.ts notes.\ntype AjvCtor = typeof import(\"ajv/dist/2020.js\").default;\nconst Ajv2020 = Ajv2020Ns.default as unknown as AjvCtor;\n\nlet entryValidator: ValidateFunction | undefined;\n\nfunction compileEntryValidator(): ValidateFunction {\n if (entryValidator) return entryValidator;\n const ajv = new Ajv2020({ allErrors: false, strict: false });\n ajv.addSchema(citationsSchema);\n entryValidator = ajv.compile({\n $ref: `${citationsSchema.$id}#/$defs/citationEntry`,\n });\n return entryValidator;\n}\n\n/** Ajv validation of one entry object against `$defs.citationEntry`; the first error text, or undefined. */\nexport function validateEntry(entry: unknown): string | undefined {\n const validate = compileEntryValidator();\n if (validate(entry)) return undefined;\n const first = validate.errors?.[0];\n if (!first) return \"invalid entry\";\n return `${first.instancePath} ${first.message ?? \"is invalid\"}`.trim();\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Copy a validated entry into the `Citation` shape, field by field. */\nfunction toCitation(entry: Record<string, unknown>): Citation {\n const source = isRecord(entry.source) ? entry.source : {};\n const citation: Citation = {\n source: {\n file: String(source.file),\n integrity: String(source.integrity),\n },\n };\n if (typeof source.lines === \"number\" || typeof source.lines === \"string\") {\n citation.source.lines = source.lines;\n }\n if (typeof source[\"commit-sha\"] === \"string\") {\n citation.source[\"commit-sha\"] = source[\"commit-sha\"];\n }\n if (typeof entry.id === \"string\") citation.id = entry.id;\n if (isRecord(entry.claim)) {\n const claim = entry.claim;\n citation.claim = { integrity: String(claim.integrity) };\n if (typeof claim.lines === \"number\" || typeof claim.lines === \"string\") {\n citation.claim.lines = claim.lines;\n }\n }\n if (typeof entry.quote === \"boolean\") citation.quote = entry.quote;\n return citation;\n}\n\ntype FindingExtra = Pick<CitationFinding, \"line\" | \"id\" | \"src\" | \"index\" | \"file\">;\n\nfunction finding(rule: CiteRule, message: string, extra: FindingExtra): CitationFinding {\n const level = DEFAULT_SEVERITY[rule];\n const out: CitationFinding = {\n rule,\n ruleId: ruleId(rule),\n // The caller re-applies the configured severity table; no page-side rule\n // defaults to `off`, so there is nothing to collapse.\n severity: level === \"off\" ? \"error\" : level,\n message,\n };\n if (extra.line !== undefined) out.line = extra.line;\n if (extra.file !== undefined) out.file = extra.file;\n if (extra.id !== undefined) out.id = extra.id;\n if (extra.src !== undefined) out.src = extra.src;\n if (extra.index !== undefined) out.index = extra.index;\n return out;\n}\n\n/** `<id>: <text>`, or the text alone for an entry with no id. */\nfunction named(id: string | undefined, text: string): string {\n return id === undefined ? text : `${id}: ${text}`;\n}\n\n/** The `id`/`src` a finding carries for an entry that may not have validated. */\nfunction subjectOf(entry: unknown): Pick<FindingExtra, \"id\" | \"src\"> {\n const out: Pick<FindingExtra, \"id\" | \"src\"> = {};\n if (!isRecord(entry)) return out;\n if (typeof entry.id === \"string\") out.id = entry.id;\n if (isRecord(entry.source) && typeof entry.source.file === \"string\") out.src = entry.source.file;\n return out;\n}\n\nexport function pickExtractor(file: string, format: string | undefined): MetadataExtractor {\n if (format !== undefined) {\n const forced = extractorByName(format);\n if (forced === undefined) {\n throw new CiteError(\n `Unknown format \"${format}\". Supported extensions: ${supportedExtensions().join(\", \")}.`,\n );\n }\n return forced;\n }\n const extension = extname(file);\n const byExt = extractorForExtension(extension);\n if (!byExt) {\n throw new CiteError(\n `Unsupported file type \"${extension}\" for \"${file}\". Supported: ${supportedExtensions().join(\", \")}. Use --as to override.`,\n );\n }\n return byExt;\n}\n\nfunction byLine(a: CitationFinding, b: CitationFinding): number {\n return (a.line ?? Number.MAX_SAFE_INTEGER) - (b.line ?? Number.MAX_SAFE_INTEGER);\n}\n\n/** File line of body line 1: the first line after the frontmatter, or 1. */\nexport function bodyLineOf(content: string, bodyOffset: number): number {\n if (bodyOffset <= 0) return 1;\n const line = lineAt(content, bodyOffset);\n // A page that ends at the closing fence with no newline leaves the body\n // starting on the line after the one the offset sits at the end of.\n return content.charCodeAt(bodyOffset - 1) === 10 ? line : line + 1;\n}\n\n/**\n * A page's citation entries as they are written, each with where it sits: the\n * manifest's when one owns them, else the page's own frontmatter. The entries\n * are raw, so one the schema refuses is still in the list at its own index,\n * which is how `remove` reaches an entry `check` can only report.\n */\nexport function citationInputs(\n file: string,\n extracted: ExtractedMetadata,\n injected?: readonly CitationInput[],\n): CitationInput[] {\n if (injected !== undefined) return [...injected];\n const raw: unknown = extracted.data.citations;\n const list: unknown[] = Array.isArray(raw) ? (raw as unknown[]) : [];\n return list.map((entry, index) => {\n const origin: CitationInput[\"origin\"] = { kind: \"frontmatter\", file };\n const line = extracted.lineFor(`/citations/${String(index)}`);\n if (line !== undefined) origin.line = line;\n return { entry, origin };\n });\n}\n\nexport function readPage(\n file: string,\n content: string,\n opts?: ReadPageOptions,\n): PageCitations {\n const extractor = pickExtractor(file, opts?.format);\n const format = extractor.name;\n // An opening fence with no close is not a block, so the extractor reads no\n // metadata and every entry the page carries would silently vanish. rst and\n // asciidoc read a stray fence as body on purpose, ahead of their native\n // headers; the fence-only formats have no such reading.\n if (FENCE_ONLY.has(format) && hasFrontmatterFence(content) && locateFrontmatter(content) === null) {\n throw new CiteError(\n `${file}: Unterminated front matter fence: the opening fence has no matching close, so the page's citations cannot be read. Add a closing fence.`,\n );\n }\n const extracted = extractor.extract(content, file);\n const data = extracted.data;\n const bodyOffset = ELEMENT_BACKED.has(format)\n ? 0\n : (locateFrontmatter(content)?.closeEnd ?? 0);\n const bodyLine = bodyLineOf(content, bodyOffset);\n\n const findings: CitationFinding[] = [];\n const citations: PageCitation[] = [];\n /** Entries by id, for marker resolution. */\n const byId = new Map<string, PageCitation>();\n /** Every id seen, for uniqueness. */\n const ids = new Set<string>();\n /** The first marker naming an entry, by entry. */\n const markedAt = new Map<PageCitation, number>();\n\n // The page root reserves the whole `citation-` prefix, so a typo fails\n // loudly rather than passing as a key of somebody else's.\n for (const key of Object.keys(data)) {\n if (!key.startsWith(\"citation-\")) continue;\n findings.push(\n finding(\n \"entry-invalid\",\n `\"${key}\" is not a citations key; the page root reserves the citation- prefix`,\n { line: extracted.lineFor(`/${key}`) },\n ),\n );\n }\n\n const injected = opts?.citations;\n const rawCitations = data.citations;\n // The page carries a key a manifest owns (0020 across files). The page's\n // own entries are still read and checked, so the report shows what the\n // page would publish; the finding says the manifest is the one authority.\n if (opts?.owned !== undefined && rawCitations !== undefined) {\n findings.push(\n finding(\"entry-invalid\", ownedMessage(opts.owned), {\n line: extracted.lineFor(\"/citations\"),\n }),\n );\n }\n if (injected === undefined && rawCitations !== undefined && !Array.isArray(rawCitations)) {\n findings.push(\n finding(\"entry-invalid\", \"citations must be an array of entries\", {\n line: extracted.lineFor(\"/citations\"),\n }),\n );\n }\n const inputs = citationInputs(file, extracted, injected);\n\n inputs.forEach((input, index) => {\n const origin: CitationOrigin = { ...input.origin, index };\n /** Where a finding about the entry itself sits: the entry's own line, in its own file. */\n const where: FindingExtra = { index };\n if (origin.line !== undefined) where.line = origin.line;\n if (origin.kind === \"manifest\") where.file = origin.file;\n\n const entry = input.entry;\n const error = validateEntry(entry);\n if (error !== undefined || !isRecord(entry)) {\n findings.push(finding(\"entry-invalid\", error ?? \"must be object\", { ...where, ...subjectOf(entry) }));\n return;\n }\n const citation = toCitation(entry);\n const subject: FindingExtra = { ...where, src: spellSource(citation.source) };\n if (citation.id !== undefined) subject.id = citation.id;\n\n // A range that ends before it starts: the schema cannot compare two\n // numbers, so the rule is kept here.\n const bad = ([\"claim\", \"source\"] as const).find((end) => {\n const lines = end === \"claim\" ? citation.claim?.lines : citation.source.lines;\n return lines !== undefined && parseLines(lines) === undefined;\n });\n if (bad !== undefined) {\n const lines = bad === \"claim\" ? citation.claim?.lines : citation.source.lines;\n findings.push(\n finding(\n \"entry-invalid\",\n named(citation.id, `${bad}.lines \"${String(lines)}\" ends before it starts`),\n subject,\n ),\n );\n return;\n }\n\n // A range wider than the cap is refused at either end (proposal 0044).\n const wide = ([\"claim\", \"source\"] as const)\n .map((end) => {\n const lines = end === \"claim\" ? citation.claim?.lines : citation.source.lines;\n const parsed = lines === undefined ? undefined : parseLines(lines);\n const reason = parsed === undefined ? undefined : tooWide(parsed);\n return reason === undefined ? undefined : `${end}.lines \"${String(lines)}\" ${reason}`;\n })\n .find((message) => message !== undefined);\n if (wide !== undefined) {\n findings.push(finding(\"entry-invalid\", named(citation.id, wide), subject));\n return;\n }\n\n // The pin's prefix says how it was taken, and only an encrypted source\n // carries a keyed one.\n const encrypted = isEncryptedValue(citation.source.file);\n if (encrypted !== isKeyedPin(citation.source.integrity)) {\n findings.push(\n finding(\n \"entry-invalid\",\n named(\n citation.id,\n encrypted\n ? \"an encrypted source is pinned with hmac-sha256-, not sha256-.\"\n : \"a plain source is pinned with sha256-, not hmac-sha256-.\",\n ),\n subject,\n ),\n );\n return;\n }\n\n const page: PageCitation = { citation, origin };\n citations.push(page);\n if (citation.id !== undefined) {\n if (ids.has(citation.id)) {\n findings.push(finding(\"entry-invalid\", `duplicate id \"${citation.id}\"`, subject));\n } else {\n ids.add(citation.id);\n byId.set(citation.id, page);\n }\n }\n });\n\n // Markers.\n const body = content.slice(bodyOffset);\n const statements = parseStatements(body, format, {\n offset: bodyOffset,\n line: bodyLine,\n });\n if (statements.length > MAX_MARKERS_PER_PAGE) {\n findings.push(\n finding(\n \"marker-invalid\",\n `more than ${String(MAX_MARKERS_PER_PAGE)} markers on one page (${String(statements.length)}); the rest are not read`,\n { line: statements[MAX_MARKERS_PER_PAGE]?.line },\n ),\n );\n }\n\n for (const statement of statements.slice(0, MAX_MARKERS_PER_PAGE)) {\n const { payload } = statement;\n if (payload.kind === \"bad\") {\n findings.push(\n finding(\n \"marker-invalid\",\n payload.json === true ? MARKER_JSON : `invalid marker: ${payload.reason}`,\n { line: statement.line },\n ),\n );\n continue;\n }\n // Each named id reports on its own: an orphan is a well-formed id with a\n // missing entry, so each one is its own subject and its own fix. A\n // malformed marker is one line and one fix, and was handled above.\n // The entries this marker actually anchors. An id the marker repeats is\n // reported and left to the marker that won it, so it never lands here.\n const anchored: PageCitation[] = [];\n for (const id of payload.ids) {\n const target = byId.get(id);\n if (target === undefined) {\n findings.push(\n finding(\"marker-orphan\", `no entry has id \"${id}\"`, {\n line: statement.line,\n id,\n }),\n );\n continue;\n }\n const first = markedAt.get(target);\n if (first !== undefined) {\n findings.push(\n finding(\n \"marker-repeated\",\n `${id} is named by markers at lines ${String(first)} and ${String(statement.line)}; the first anchors it.`,\n {\n line: statement.line,\n id,\n index: target.origin.index,\n src: spellSource(target.citation.source),\n },\n ),\n );\n continue;\n }\n markedAt.set(target, statement.line);\n target.marker = statement;\n anchored.push(target);\n }\n // A quote entry anchors the next fenced block and a plain one anchors the\n // paragraph, so a list that mixes them would mean two spans on one line,\n // and the page would not say which id got which.\n const quoted = anchored.find((entry) => entry.citation.quote === true);\n const plain = anchored.find((entry) => entry.citation.quote !== true);\n if (quoted !== undefined && plain !== undefined) {\n const mixed: FindingExtra = {\n line: statement.line,\n index: quoted.origin.index,\n src: spellSource(quoted.citation.source),\n };\n if (quoted.citation.id !== undefined) mixed.id = quoted.citation.id;\n findings.push(\n finding(\n \"anchor-invalid\",\n named(\n quoted.citation.id,\n \"a quote entry shares a marker with a non-quote entry. Give the quote its own marker.\",\n ),\n mixed,\n ),\n );\n }\n }\n\n // Anchors: exactly one way in, and a quote needs one of them.\n for (const entry of citations) {\n const { citation, origin, marker } = entry;\n const subject: FindingExtra = { index: origin.index, src: spellSource(citation.source) };\n if (citation.id !== undefined) subject.id = citation.id;\n if (origin.line !== undefined) subject.line = origin.line;\n if (origin.kind === \"manifest\") subject.file = origin.file;\n\n if (citation.claim?.lines !== undefined && marker !== undefined) {\n // A marker names an id, so an entry with both always has one. The\n // finding sits on the marker, which is the half a reader can see.\n const onPage: FindingExtra = { index: origin.index, line: marker.line, src: subject.src };\n if (citation.id !== undefined) onPage.id = citation.id;\n findings.push(\n finding(\n \"anchor-invalid\",\n `${citation.id ?? \"the entry\"} has claim lines and a marker. Keep one.`,\n onPage,\n ),\n );\n continue;\n }\n if (citation.quote === true && citation.claim?.lines === undefined && marker === undefined) {\n findings.push(\n finding(\"anchor-invalid\", named(citation.id, \"quote needs a claim or a marker.\"), subject),\n );\n }\n }\n\n return {\n file,\n format,\n content,\n bodyOffset,\n bodyLine,\n citations,\n statements,\n findings: findings.sort(byLine),\n };\n}\n","/**\n * The stretches of a text that are code, so a scanner can skip them: a page\n * that documents a syntax is not an instance of it. cite skips code when it\n * looks for markers, and term's body readers skip it when they look for\n * glossary entries.\n *\n * - A fenced block: ``` or ~~~ in markdown and mdx, indented or not, since a\n * fence keeps its meaning inside a list item; `----` at column 0 in\n * asciidoc. It is closed by the same character, at least as many of it, and\n * nothing else on the line. An unclosed fence runs to the end, as a renderer\n * reads it.\n * - A backtick span, in markdown, mdx, asciidoc and rst: a run of backticks\n * closed by a run of the same length on the same line. A run with no closer\n * is literal text.\n *\n * html and xml have neither; a `<pre>` is not code here.\n */\n\n/** A stretch of code, as `[start, end)` offsets of the text it was found in. */\nexport interface CodeRegion {\n start: number;\n end: number;\n}\n\nexport interface CodeRegionOptions {\n /** Include backtick spans. Default `true`; `false` returns fenced blocks only. */\n spans?: boolean;\n}\n\nconst SKIP_MARKDOWN_FENCE = /^[ \\t]*(`{3,}|~{3,})/;\nconst SKIP_ASCIIDOC_FENCE = /^(-{4,})/;\n/** Formats where a backtick span is inline code. */\nconst SPAN_FORMATS = new Set([\"markdown\", \"mdx\", \"asciidoc\", \"rst\"]);\nconst BACKTICK = 96;\n\n/** The fence-opener pattern for a format, or undefined when it has no fences. */\nfunction fenceFor(format: string): RegExp | undefined {\n switch (format) {\n case \"markdown\":\n case \"mdx\":\n return SKIP_MARKDOWN_FENCE;\n case \"asciidoc\":\n return SKIP_ASCIIDOC_FENCE;\n default:\n return undefined;\n }\n}\n\n/** Length of the run of backticks starting at `i` in `text` (0 when none). */\nfunction backtickRun(text: string, i: number): number {\n let n = 0;\n while (text.charCodeAt(i + n) === BACKTICK) n++;\n return n;\n}\n\n/** The backtick spans on one line, appended to `out` as offsets of the whole text. */\nfunction spanRegions(line: string, lineStart: number, out: CodeRegion[]): void {\n let i = 0;\n while (i < line.length) {\n const n = backtickRun(line, i);\n if (n === 0) {\n i++;\n continue;\n }\n let j = i + n;\n let closer = -1;\n while (j < line.length) {\n const m = backtickRun(line, j);\n if (m === 0) {\n j++;\n continue;\n }\n if (m === n) {\n closer = j;\n break;\n }\n j += m;\n }\n if (closer === -1) {\n i += n;\n continue;\n }\n out.push({ start: lineStart + i, end: lineStart + closer + n });\n i = closer + n;\n }\n}\n\n/**\n * Whether a line closes the fence `open`. A longer run does not close a\n * shorter one's block, which is how a ```` block carries a ``` block inside it.\n */\nfunction closesFence(line: string, open: { char: string; length: number }): boolean {\n const trimmed = line.trim();\n let n = 0;\n while (trimmed.charAt(n) === open.char) n++;\n return n >= open.length && n === trimmed.length;\n}\n\n/**\n * Every fenced block and backtick span in `text`, in order, for a format that\n * has them. A closed fence's region ends at its closing line's terminator; an\n * unclosed one ends at the end of the text. Spans are not looked for inside a\n * fence.\n */\nexport function codeRegions(\n text: string,\n format: string,\n options: CodeRegionOptions = {},\n): CodeRegion[] {\n const fence = fenceFor(format);\n const spans = options.spans !== false && SPAN_FORMATS.has(format);\n const out: CodeRegion[] = [];\n if (fence === undefined && !spans) return out;\n let open: { char: string; length: number; start: number } | undefined;\n let pos = 0;\n while (pos < text.length) {\n const nl = text.indexOf(\"\\n\", pos);\n const end = nl === -1 ? text.length : nl;\n const raw = text.slice(pos, end);\n const line = raw.endsWith(\"\\r\") ? raw.slice(0, -1) : raw;\n if (open !== undefined) {\n if (closesFence(line, open)) {\n out.push({ start: open.start, end });\n open = undefined;\n }\n } else {\n const opener = fence?.exec(line)?.[1];\n if (opener !== undefined) {\n open = { char: opener.charAt(0), length: opener.length, start: pos };\n } else if (spans) {\n spanRegions(line, pos, out);\n }\n }\n pos = end + 1;\n }\n if (open !== undefined) out.push({ start: open.start, end: text.length });\n return out;\n}\n\n/** The end of the region `offset` falls in, or undefined when it falls in none. */\nexport function codeEndAt(regions: readonly CodeRegion[], offset: number): number | undefined {\n return regions.find((r) => offset >= r.start && offset < r.end)?.end;\n}\n","/**\n * Markers: `cite <id> [<id>…]` inside the format's comment syntax.\n *\n * | Format | Forms |\n * |---------------|------------------------------------------------------------------------------------|\n * | markdown, mdx | `<!-- cite a b -->`, `{/* cite a b *\\/}`, `[comment]: # (cite a b)` |\n * | html, xml | `<!-- cite a b -->` |\n * | asciidoc | `// (cite a b)` |\n * | rst | `.. (cite a b)` |\n *\n * A marker carries one or more ids, separated by spaces, and nothing else\n * (`cite true` names id `true`). Every id in the list anchors the text the\n * marker anchors, so a paragraph resting on four sources carries one comment\n * rather than four (proposal 0056). An id cannot hold `(`, `)`, `{`, `}`, `<`,\n * `>` or a leading `-`, so no list can close a parenthesised comment early.\n *\n * A word starting with `{` was the inline entry of proposal 0044's first\n * draft; it is `marker-invalid` now, because an entry lives in frontmatter or\n * a manifest and a source is never written into the body. The scanner uses\n * `indexOf` for the delimiters, never a regex over the whole page, and is\n * handed the body only, so a `cite` inside frontmatter is never matched.\n *\n * It does not read code. An opener inside a fenced block or a backtick span,\n * as `src/shared/code-regions.ts` finds them, is skipped, so a page that\n * documents the syntax carries no statements.\n *\n * Every form parses in both markdown and mdx. The first form is what\n * `formatStatement` writes: the html comment for markdown, the jsx comment\n * for mdx, which rejects an html comment.\n */\nimport type { InlineStatement, TextEdit } from \"../types.js\";\nimport { codeEndAt, codeRegions } from \"../../shared/code-regions.js\";\nimport { CiteError } from \"../errors.js\";\n\nexport interface StatementForm {\n open: string;\n close: string;\n}\n\nconst HTML_COMMENT: StatementForm = { open: \"<!--\", close: \"-->\" };\nconst JSX_COMMENT: StatementForm = { open: \"{/*\", close: \"*/}\" };\nconst LINK_REFERENCE: StatementForm = { open: \"[comment]: # (\", close: \")\" };\nconst MARKDOWN_FORMS: readonly StatementForm[] = [HTML_COMMENT, JSX_COMMENT, LINK_REFERENCE];\nconst MDX_FORMS: readonly StatementForm[] = [JSX_COMMENT, HTML_COMMENT, LINK_REFERENCE];\nconst COMMENT_FORMS: readonly StatementForm[] = [{ open: \"<!--\", close: \"-->\" }];\nconst ASCIIDOC_FORMS: readonly StatementForm[] = [{ open: \"// (\", close: \")\" }];\nconst RST_FORMS: readonly StatementForm[] = [{ open: \".. (\", close: \")\" }];\n\nconst ID = /^[a-z0-9][a-z0-9-]*$/;\n\n/**\n * A fence opener in any format. `paragraphAfter` reads it whether or not it\n * was given a format, and so does the claim search (`claims.ts`), so every\n * family's opener counts; the per-format locators below are what `quote`\n * anchoring uses.\n * A markdown fence keeps its meaning when indented, as inside a list item, so\n * it is read there too, matching the code skip in `src/shared/code-regions.ts`; the\n * asciidoc `----` stays at column 0.\n */\nexport const ANY_FENCE = /^(?:[ \\t]*(?:`{3,}|~{3,})|-{4,})/;\nconst MARKDOWN_FENCE = /^(`{3,}|~{3,})/;\nconst ASCIIDOC_FENCE = /^(-{4,})/;\n/** The forms per extractor name. Unknown formats have none. */\nexport function statementForms(format: string): readonly StatementForm[] {\n switch (format) {\n case \"markdown\":\n return MARKDOWN_FORMS;\n case \"mdx\":\n return MDX_FORMS;\n case \"html\":\n case \"xml\":\n return COMMENT_FORMS;\n case \"asciidoc\":\n return ASCIIDOC_FORMS;\n case \"rst\":\n return RST_FORMS;\n default:\n return [];\n }\n}\n\n/** The fence-opener pattern for a format, or undefined when it has no locator. */\nfunction fenceFor(format: string): RegExp | undefined {\n switch (format) {\n case \"markdown\":\n case \"mdx\":\n return MARKDOWN_FENCE;\n case \"asciidoc\":\n return ASCIIDOC_FENCE;\n default:\n return undefined;\n }\n}\n\n/** Offset of the terminator of the line containing `pos` (or the text length). */\nfunction lineEnd(content: string, pos: number): number {\n const nl = content.indexOf(\"\\n\", pos);\n return nl === -1 ? content.length : nl;\n}\n\n/** The text of the line `[pos, end)`, without a trailing CR. */\nfunction lineText(content: string, pos: number, end: number): string {\n const text = content.slice(pos, end);\n return text.endsWith(\"\\r\") ? text.slice(0, -1) : text;\n}\n\n/** `end` pulled back over a CR so a CRLF terminator is excluded whole. */\nfunction beforeCr(content: string, end: number): number {\n return end > 0 && content.charCodeAt(end - 1) === 13 ? end - 1 : end;\n}\n\n/**\n * Where a forward scan of whole lines starts from `offset`: the next line when\n * `offset` sits inside one (the rest of a statement's own line), the line\n * itself when `offset` is already at its start.\n */\nfunction nextLineStart(content: string, offset: number): number {\n if (offset === 0 || content.charCodeAt(offset - 1) === 10) return offset;\n return lineEnd(content, offset) + 1;\n}\n\n/**\n * A marker holds at most 25 ids. Past that it is `marker-invalid`, on the\n * same grounds as the 500 markers a page may hold: an unbounded list is an\n * unbounded allocation from a file the tool did not write. The cap counts\n * ids rather than characters, because a character cap moves with how long\n * the ids happen to be. Proposal 0056 is the record.\n */\nexport const MAX_IDS_PER_MARKER = 25;\n\n/**\n * The payload, as one or more ids separated by spaces. The checks run in a\n * stated order and the first defect is the finding, so one marker raises one\n * `marker-invalid` however many of its words are wrong.\n *\n * A run of spaces separates as one, which is what a soft-wrapped editor and a\n * shell both do. A comma is never a separator: `cite a,b` is one token, that\n * token is not an id, and the message quotes it back (proposal 0034's one\n * separator per list).\n */\nfunction payloadOf(payload: string): InlineStatement[\"payload\"] {\n if (payload === \"\") return { kind: \"bad\", reason: \"empty payload\" };\n // A marker is one line: `isMarkerLine` tests one line, so half a wrapped\n // marker would land inside the pin of the text below it.\n if (/[\\r\\n]/.test(payload)) {\n return { kind: \"bad\", reason: \"a marker is one line; write two markers\" };\n }\n // Destructured rather than cast: a `ref` carries at least one id, and the\n // head is what proves it to the compiler.\n const [head, ...rest] = payload.split(\" \").filter((word) => word !== \"\");\n if (head === undefined) return { kind: \"bad\", reason: \"empty payload\" };\n const words: [string, ...string[]] = [head, ...rest];\n // An entry lives in frontmatter or a manifest; the body carries names. This\n // runs before the id test so the more actionable message fires.\n if (words.some((word) => word.startsWith(\"{\"))) {\n return { kind: \"bad\", reason: \"a JSON payload\", json: true };\n }\n if (words.length > MAX_IDS_PER_MARKER) {\n return {\n kind: \"bad\",\n reason: `more than ${String(MAX_IDS_PER_MARKER)} ids in one marker (${String(words.length)}); write a second marker`,\n };\n }\n const bad = words.find((word) => !ID.test(word));\n if (bad !== undefined) return { kind: \"bad\", reason: `\"${bad}\" is not an id` };\n const seen = new Set<string>();\n for (const word of words) {\n // One id named twice inside one marker has no second anchor and no winner\n // to pick, so it is a typo in one line rather than `marker-repeated`.\n if (seen.has(word)) {\n return { kind: \"bad\", reason: `\"${word}\" is named twice in one marker` };\n }\n seen.add(word);\n }\n return { kind: \"ref\", ids: words };\n}\n\n/** Whether the text between a form's delimiters is a cite statement. */\nfunction isCite(inner: string): boolean {\n return inner === \"cite\" || (inner.startsWith(\"cite\") && /\\s/.test(inner.charAt(4)));\n}\n\n/**\n * Whether a line holds one marker and nothing else, in any of the format's\n * forms. Such a line is never text a marker anchors: markers stacked above a\n * paragraph all anchor the paragraph, and none of them is part of its pin.\n */\nexport function isMarkerLine(line: string, format: string): boolean {\n const text = line.trim();\n return statementForms(format).some((form) => {\n if (text.length < form.open.length + form.close.length) return false;\n if (!text.startsWith(form.open)) return false;\n // The first close is the last thing on the line, so there is one marker.\n const closeAt = text.indexOf(form.close, form.open.length);\n if (closeAt !== text.length - form.close.length) return false;\n return isCite(text.slice(form.open.length, closeAt).trim());\n });\n}\n\n/** An ATX heading: one to six `#`, then a space or the end of the line. */\nconst ATX_HEADING = /^[ \\t]*#{1,6}([ \\t]|$)/;\n/** An asciidoc section title: one to six `=`, then a space. */\nconst ASCIIDOC_TITLE = /^={1,6}[ \\t]/;\n/**\n * A line of one punctuation character repeated three or more times, spaces\n * allowed: a setext underline, a thematic break, an rst adornment.\n */\nconst ADORNMENT = /^[ \\t]*([-=~^\"'*+#_:<>])(?:[ \\t]*\\1){2,}[ \\t]*$/;\n/** A line that is nothing but one JSX or HTML tag, opening or closing. */\nconst TAG_LINE = /^[ \\t]*<\\/?[A-Za-z][^<>]*>[ \\t]*$/;\n/** A table row: a line whose first non-blank character is a pipe. */\nconst TABLE_ROW = /^[ \\t]*\\|/;\n\n/**\n * Whether a line is a table row. The header row, the `|---|---|` delimiter row\n * and every body row all open with a pipe, so all three read as rows. Leading\n * whitespace is allowed, because a table inside a list item is indented and is\n * still a table.\n *\n * A row is a statement of its own. Nothing else separates one row from the\n * next, so a paragraph walk reads a whole table as one paragraph, and a claim\n * pinned to one row would re-pin every row below it. `unitAt` in\n * `src/cite/core/claims.ts` reads this instead, so a re-pin covers the row and\n * no more.\n */\nexport function isTableRow(line: string): boolean {\n return TABLE_ROW.test(line);\n}\n\n/**\n * A table rule: the `|---|---|` line under a header row. The outer pipes are\n * optional, a cell may carry `:` alignment markers, and the whole line may be\n * indented, because a table inside a list item is indented and is still a\n * table.\n *\n * A rule has to carry at least one `|`, which is what the leading lookahead\n * asks. Every pipe in the pattern that follows is optional on its own, so\n * without that test a bare `---` reads as a table rule, and `---` is a\n * thematic break or the underline of a setext heading instead.\n *\n * `isTableRow` reads a rule as a row, deliberately: a claim over a header, its\n * rule and a body row covers three rows and keeps all three. This asks the\n * narrower question `unitAt` needs, which is whether a span holds nothing but\n * rules. Such a span carries no words, so `update --accept` refuses to pin one.\n */\nconst TABLE_RULE = /^(?=[^|]*\\|)[ \\t]*\\|?(?:[ \\t]*:?-+:?[ \\t]*\\|)*[ \\t]*:?-+:?[ \\t]*\\|?[ \\t]*$/;\n\nexport function isTableSeparator(line: string): boolean {\n return TABLE_RULE.test(line);\n}\n\n/**\n * Whether a line is a **bound line**: one the format makes a block on its own,\n * so no paragraph continues across it, and no pin covers it beside text.\n *\n * | Format | Bound lines |\n * |---|---|\n * | markdown, mdx | An ATX heading, and a line that is nothing but one tag. |\n * | html, xml | A line that is nothing but one tag. |\n * | asciidoc | A section title. |\n * | every format | An adornment: one of `-=~^\"'*+#_:<>` repeated three or more times. |\n *\n * Proposal 0054 is the record, and its stress tests 8 and 9 say why a heading\n * and a tag line are read this way rather than joined to the text below them.\n * A tag line is bound in every format that reads one, so a marker under\n * `<body>` anchors the element below it and never the whole document.\n */\nexport function isBoundLine(line: string, format: string): boolean {\n if (ADORNMENT.test(line)) return true;\n switch (format) {\n case \"markdown\":\n case \"mdx\":\n return ATX_HEADING.test(line) || TAG_LINE.test(line);\n case \"html\":\n case \"xml\":\n return TAG_LINE.test(line);\n case \"asciidoc\":\n return ASCIIDOC_TITLE.test(line);\n default:\n return false;\n }\n}\n\n/** Scan a body for statements. `from` maps body offsets/lines to file offsets/lines. */\nexport function parseStatements(\n body: string,\n format: string,\n from: { offset: number; line: number } = { offset: 0, line: 1 },\n): InlineStatement[] {\n const out: InlineStatement[] = [];\n const fileLine = (bodyOffset: number): number =>\n from.line + lineAt(body, bodyOffset) - 1;\n const code = codeRegions(body, format);\n\n for (const form of statementForms(format)) {\n let cursor = 0;\n for (;;) {\n const at = body.indexOf(form.open, cursor);\n if (at === -1) break;\n const codeEnd = codeEndAt(code, at);\n if (codeEnd !== undefined) {\n cursor = codeEnd;\n continue;\n }\n const closeAt = body.indexOf(form.close, at + form.open.length);\n if (closeAt === -1) break;\n const end = closeAt + form.close.length;\n cursor = end;\n const inner = body.slice(at + form.open.length, closeAt).trim();\n if (!isCite(inner)) continue;\n const payload = inner.slice(4).trim();\n\n // Anchor: the rest of the close delimiter's line when it carries text,\n // else the paragraph or fenced block that follows.\n const unit = anchoredLines(body, end, format);\n const anchorLine = unit === undefined ? undefined : from.line + unit.start - 1;\n\n const statement: InlineStatement = {\n line: fileLine(at),\n payload: payloadOf(payload),\n raw: inner,\n start: from.offset + at,\n end: from.offset + end,\n };\n if (anchorLine !== undefined) statement.anchorLine = anchorLine;\n out.push(statement);\n }\n }\n return out.sort((a, b) => a.start - b.start);\n}\n\n/** `\"\\r\\n\"` when the text's first line break is CRLF, else `\"\\n\"`. */\nexport function detectEol(text: string): \"\\n\" | \"\\r\\n\" {\n const nl = text.indexOf(\"\\n\");\n return nl > 0 && text.charCodeAt(nl - 1) === 13 ? \"\\r\\n\" : \"\\n\";\n}\n\n/**\n * The paragraph starting at or after `offset` (skipping blank lines), as\n * `{ start, end, line }` file offsets and the file line it starts on. A fence\n * opener ends the search with no paragraph. Given a `format`, a marker-only\n * line is skipped like a blank one before the paragraph, and ends it after,\n * and a bound line is a unit of one line: it ends a paragraph above it, and\n * stands alone when it is the first line found.\n */\nexport function paragraphAfter(\n content: string,\n offset: number,\n format?: string,\n): { start: number; end: number; line: number } | undefined {\n const marker = (text: string): boolean => format !== undefined && isMarkerLine(text, format);\n const bound = (text: string): boolean => format !== undefined && isBoundLine(text, format);\n let pos = offset;\n // The rest of the line `offset` sits in counts when it carries text; when\n // it is blank the paragraph can only start on a later line.\n const firstEnd = lineEnd(content, pos);\n if (lineText(content, pos, firstEnd).trim() === \"\") pos = firstEnd + 1;\n\n while (pos < content.length) {\n const end = lineEnd(content, pos);\n const text = lineText(content, pos, end);\n if (text.trim() === \"\" || marker(text)) {\n pos = end + 1;\n continue;\n }\n if (ANY_FENCE.test(text)) return undefined;\n const start = pos;\n let last = end;\n // A bound line is its own unit, so it never gathers the lines under it.\n let cursor = bound(text) ? content.length : end + 1;\n while (cursor < content.length) {\n const e = lineEnd(content, cursor);\n const t = lineText(content, cursor, e);\n if (t.trim() === \"\" || ANY_FENCE.test(t) || marker(t) || bound(t)) break;\n last = e;\n cursor = e + 1;\n }\n return { start, end: beforeCr(content, last), line: lineAt(content, start) };\n }\n return undefined;\n}\n\ninterface FencedBlock {\n start: number;\n end: number;\n line: number;\n text: string;\n}\n\n/**\n * The next fenced block whose opener matches `fence`, scanning whole lines\n * from `offset`, plus the offset just past its closing fence line so a caller\n * can continue.\n */\nfunction scanFence(\n content: string,\n offset: number,\n fence: RegExp,\n): (FencedBlock & { next: number }) | undefined {\n let pos = nextLineStart(content, offset);\n while (pos < content.length) {\n const end = lineEnd(content, pos);\n const text = lineText(content, pos, end);\n const opener = fence.exec(text)?.[1];\n if (opener === undefined) {\n pos = end + 1;\n continue;\n }\n const line = lineAt(content, pos);\n const start = Math.min(end + 1, content.length);\n let cursor = start;\n while (cursor < content.length) {\n const e = lineEnd(content, cursor);\n if (lineText(content, cursor, e).startsWith(opener)) {\n return {\n start,\n end: cursor,\n line,\n text: content.slice(start, cursor),\n next: e + 1,\n };\n }\n cursor = e + 1;\n }\n return undefined;\n }\n return undefined;\n}\n\n/**\n * The fenced code block starting at or after `offset` (``` or ~~~; asciidoc\n * `----`), as file offsets of its content lines and the file line of the\n * opening fence. `undefined` for formats with no locator (html, xml, rst).\n */\nexport function fencedBlockAfter(\n content: string,\n offset: number,\n format: string,\n): { start: number; end: number; line: number; text: string } | undefined {\n const fence = fenceFor(format);\n if (!fence) return undefined;\n const block = scanFence(content, offset, fence);\n if (!block) return undefined;\n const { start, end, line, text } = block;\n return { start, end, line, text };\n}\n\n/**\n * The fenced block at `offset` in any fence family, for callers that have no\n * format at hand (the claim search). Undefined when the line at `offset` is\n * not an opener.\n */\nexport function fencedBlockAt(\n content: string,\n offset: number,\n): { start: number; end: number; line: number; text: string } | undefined {\n const pos = nextLineStart(content, offset);\n if (!ANY_FENCE.test(lineText(content, pos, lineEnd(content, pos)))) {\n return undefined;\n }\n const block =\n scanFence(content, pos, MARKDOWN_FENCE) ?? scanFence(content, pos, ASCIIDOC_FENCE);\n if (!block || block.line !== lineAt(content, pos)) return undefined;\n const { start, end, line, text } = block;\n return { start, end, line, text };\n}\n\n/** Every fenced block in the body, for `--quote` without `--claim`. */\nexport function fencedBlocks(\n content: string,\n bodyOffset: number,\n format: string,\n): { start: number; end: number; line: number; text: string }[] {\n const fence = fenceFor(format);\n if (!fence) return [];\n const out: FencedBlock[] = [];\n let pos = bodyOffset;\n for (;;) {\n const block = scanFence(content, pos, fence);\n if (!block) return out;\n const { start, end, line, text } = block;\n out.push({ start, end, line, text });\n pos = block.next;\n }\n}\n\n/** The form `formatStatement` writes for a format, or a refusal naming the format. */\nfunction writtenForm(format: string): StatementForm {\n const form = statementForms(format)[0];\n if (!form) {\n throw new CiteError(`No marker syntax for format \"${format}\".`);\n }\n return form;\n}\n\n/** Render a marker in the format's first form, e.g. `<!-- cite fetch-timeout -->`. */\nexport function formatStatement(\n format: string,\n payload: { kind: \"ref\"; ids: readonly [string, ...string[]] },\n): string {\n const form = writtenForm(format);\n // `[comment]: # (`, `// (` and `.. (` hug their parentheses; the comment\n // forms take a space inside each delimiter.\n const pad = form.open.endsWith(\"(\") ? \"\" : \" \";\n return `${form.open}${pad}cite ${payload.ids.join(\" \")}${pad}${form.close}`;\n}\n\n/**\n * The one edit that replaces a marker's payload with `ids`, as a span of\n * `content` and the text to put in it. The marker keeps its own form rather\n * than being rendered afresh, so a page that spells its markers in a form\n * `formatStatement` would not choose keeps that form, along with its\n * indentation and inner spacing.\n *\n * Returned as an edit rather than applied, so a caller with several of them\n * can collect them all against one parse and apply them together. That is how\n * `remove` rewrites a page: nothing it reads a position from has been written\n * to yet.\n *\n * `content` must be the text the statement was parsed from; the payload is\n * found inside the span the statement recorded, and the answer is undefined\n * when it is not there. The marker must also open and close on one line, since\n * a payload spanning lines would be folded onto one here, changing the line\n * count and moving every claim below it. Both callers hold to that: `remove`\n * refuses a marker line it cannot read whole, and `add` joins only a marker\n * with no line break in it.\n */\nexport function respellEdit(\n content: string,\n statement: InlineStatement,\n ids: readonly [string, ...string[]],\n): TextEdit | undefined {\n const text = content.slice(statement.start, statement.end);\n // No open delimiter carries `cite`, so the first occurrence of the trimmed\n // inner text is the payload itself.\n const at = text.indexOf(statement.raw);\n if (at === -1) return undefined;\n return {\n start: statement.start + at,\n end: statement.start + at + statement.raw.length,\n text: `cite ${ids.join(\" \")}`,\n };\n}\n\n/**\n * `content` with the marker's payload replaced by `ids`. The one-edit form of\n * `respellEdit`, for a caller rewriting a single marker; `content` unchanged\n * when the payload is not where the statement says.\n */\nexport function respellStatement(\n content: string,\n statement: InlineStatement,\n ids: readonly [string, ...string[]],\n): string {\n const edit = respellEdit(content, statement, ids);\n if (edit === undefined) return content;\n return content.slice(0, edit.start) + edit.text + content.slice(edit.end);\n}\n\n/**\n * The first line at or after `offset` that is neither blank nor a marker on\n * its own, as a 1-based line of `text`.\n */\nfunction nextTextLine(text: string, offset: number, format: string): number | undefined {\n let pos = nextLineStart(text, offset);\n while (pos < text.length) {\n const end = lineEnd(text, pos);\n const line = lineText(text, pos, end);\n if (line.trim() !== \"\" && !isMarkerLine(line, format)) return lineAt(text, pos);\n pos = end + 1;\n }\n return undefined;\n}\n\n/**\n * The fenced block opening on `line`, as the lines it spans, fences included.\n * Undefined when that line is not an opener the format knows, or the block is\n * never closed.\n */\nexport function fenceSpanAt(\n text: string,\n line: number,\n format: string,\n): { start: number; end: number } | undefined {\n const fence = fenceFor(format);\n if (!fence) return undefined;\n const block = scanFence(text, offsetOfLine(text, line), fence);\n if (!block || block.line !== line) return undefined;\n return { start: line, end: lineAt(text, block.end) };\n}\n\n/**\n * The fenced block `line` sits inside rather than opens, as the lines it\n * spans, fences included. Undefined when the line opens a block, sits in no\n * block, or the format has no fence. The closing fence counts as inside, so a\n * caller that wants a content line asks whether its span ends before the\n * block does.\n */\nexport function fenceAround(\n text: string,\n bodyOffset: number,\n line: number,\n format: string,\n): { start: number; end: number } | undefined {\n const block = fencedBlocks(text, bodyOffset, format).find(\n (b) => line > b.line && line <= lineAt(text, b.end),\n );\n return block === undefined ? undefined : { start: block.line, end: lineAt(text, block.end) };\n}\n\n/** Whether `line` sits inside a fenced block rather than opening one. */\nexport function insideFence(\n text: string,\n bodyOffset: number,\n line: number,\n format: string,\n): boolean {\n return fenceAround(text, bodyOffset, line, format) !== undefined;\n}\n\n/**\n * The paragraph or fenced block that holds `line`, as the lines it spans,\n * fences included: what a marker written above it anchors. A paragraph runs\n * up to a blank line, a fence, a marker-only line, a bound line or the body's\n * start, and down as `paragraphAfter` reads it. Undefined for a blank line, a\n * marker-only line, or a line nothing can anchor.\n */\nexport function unitHolding(\n text: string,\n line: number,\n format: string,\n body: { offset: number; line: number },\n): { start: number; end: number; kind: \"paragraph\" | \"block\" } | undefined {\n const textOf = (n: number): string => lineText(text, offsetOfLine(text, n), lineEnd(text, offsetOfLine(text, n)));\n const own = textOf(line);\n if (own.trim() === \"\" || isMarkerLine(own, format)) return undefined;\n const block = fencedBlocks(text, body.offset, format).find(\n (b) => line >= b.line && line <= lineAt(text, b.end),\n );\n if (block !== undefined) {\n return { start: block.line, end: lineAt(text, block.end), kind: \"block\" };\n }\n if (ANY_FENCE.test(own)) return undefined;\n let start = line;\n // A bound line is its own unit, so the walk up never leaves it.\n while (start - 1 >= body.line && !isBoundLine(own, format)) {\n const above = textOf(start - 1);\n if (\n above.trim() === \"\" ||\n ANY_FENCE.test(above) ||\n isMarkerLine(above, format) ||\n isBoundLine(above, format)\n ) {\n break;\n }\n start--;\n }\n const paragraph = paragraphAfter(text, offsetOfLine(text, start), format);\n if (paragraph?.line !== start) return undefined;\n return { start, end: lineAt(text, paragraph.end), kind: \"paragraph\" };\n}\n\n/** A markdown list item's opening line: its indentation, its bullet or number, and the gap after. */\nconst LIST_ITEM = /^([ \\t]*)([-*+]|\\d{1,9}[.)])([ \\t]+|$)/;\n/** A thematic break, which a list item's pattern would otherwise read as `* * *`. */\nconst THEMATIC_BREAK = /^[ \\t]*([-*_])(?:[ \\t]*\\1){2,}[ \\t]*$/;\n\n/** The text of 1-based line `n` of `text`. */\nfunction textOfLine(text: string, n: number): string {\n const pos = offsetOfLine(text, n);\n return lineText(text, pos, lineEnd(text, pos));\n}\n\n/** The leading spaces and tabs of a line. */\nfunction indentOf(line: string): string {\n return /^[ \\t]*/.exec(line)?.[0] ?? \"\";\n}\n\n/** The column a run of spaces and tabs reaches, with tab stops every 4 columns. */\nfunction columnOf(indent: string): number {\n let column = 0;\n for (const ch of indent) column = ch === \"\\t\" ? column + 4 - (column % 4) : column + 1;\n return column;\n}\n\n/** The list item a markdown line opens, or undefined. */\nfunction listItemOf(line: string): { lead: string; bullet: string; gap: string } | undefined {\n if (THEMATIC_BREAK.test(line)) return undefined;\n const match = LIST_ITEM.exec(line);\n if (match === null) return undefined;\n const [, lead = \"\", bullet = \"\", gap = \"\"] = match;\n return { lead, bullet, gap };\n}\n\n/**\n * Whether the list item on `line` follows an earlier item of its list: the\n * nearest text above it, past blank and marker-only lines, is indented deeper\n * than the item, or sits in a paragraph holding an item at the same column.\n */\nfunction continuesList(\n text: string,\n line: number,\n format: string,\n bodyLine: number,\n column: number,\n): boolean {\n let n = line - 1;\n while (n >= bodyLine) {\n const above = textOfLine(text, n);\n if (above.trim() !== \"\" && !isMarkerLine(above, format)) break;\n n--;\n }\n if (n < bodyLine) return false;\n if (columnOf(indentOf(textOfLine(text, n))) > column) return true;\n for (; n >= bodyLine; n--) {\n const above = textOfLine(text, n);\n if (\n above.trim() === \"\" ||\n ANY_FENCE.test(above) ||\n isMarkerLine(above, format) ||\n isBoundLine(above, format)\n ) {\n break;\n }\n const item = listItemOf(above);\n if (item !== undefined && columnOf(item.lead) === column) return true;\n }\n return false;\n}\n\n/**\n * The indentation a marker written above `line` carries, so it stays in the\n * container the line is in. A paragraph's own leading spaces and tabs, copied\n * as they are. Above a markdown list item that follows an earlier item, the\n * column of the item's text, which keeps the marker inside the list: at the\n * item's own column it would end the list. asciidoc never indents one, since\n * a comment there starts at column 0.\n */\nexport function markerIndent(\n text: string,\n line: number,\n format: string,\n bodyLine: number,\n): string {\n if (format === \"asciidoc\") return \"\";\n const own = textOfLine(text, line);\n const indent = indentOf(own);\n if (format !== \"markdown\" && format !== \"mdx\") return indent;\n const item = listItemOf(own);\n if (item === undefined || !continuesList(text, line, format, bodyLine, columnOf(item.lead))) {\n return indent;\n }\n // A gap of five spaces or more is one space and indented code, so the text starts after one.\n const gap = item.gap === \"\" || columnOf(item.gap) > 4 ? \" \" : item.gap;\n return item.lead + \" \".repeat(item.bullet.length) + gap;\n}\n\n/**\n * The lines a marker anchors, as 1-based lines of `text`: the rest of its own\n * line when that carries text, else the paragraph or fenced block that\n * follows. Marker-only lines below it are skipped, so markers stacked above\n * one paragraph all anchor it, and none is part of the pin. With `quote`, the\n * next fenced block after it, wherever that is. Undefined when nothing\n * follows to anchor.\n */\nexport function anchoredLines(\n text: string,\n after: number,\n format: string,\n quote = false,\n): { start: number; end: number } | undefined {\n if (quote) {\n const block = fencedBlockAfter(text, after, format);\n return block === undefined ? undefined : { start: block.line, end: lineAt(text, block.end) };\n }\n const restEnd = lineEnd(text, after);\n if (text.slice(after, restEnd).trim() !== \"\") {\n const line = lineAt(text, after);\n return { start: line, end: line };\n }\n const paragraph = paragraphAfter(text, after, format);\n if (paragraph !== undefined) {\n return { start: paragraph.line, end: lineAt(text, paragraph.end) };\n }\n // A fence where a paragraph would be: the block is what the marker anchors.\n const line = nextTextLine(text, after, format);\n return line === undefined ? undefined : fenceSpanAt(text, line, format);\n}\n\n/** 1-based file line of a file offset, counting CRLF once. */\nexport function lineAt(content: string, offset: number): number {\n const stop = Math.min(offset, content.length);\n let line = 1;\n for (let i = 0; i < stop; i++) {\n if (content.charCodeAt(i) === 10) line++;\n }\n return line;\n}\n\n/** File offset of the first character of a 1-based line (the length when past the end). */\nexport function offsetOfLine(content: string, line: number): number {\n let pos = 0;\n for (let n = 1; n < line; n++) {\n const nl = content.indexOf(\"\\n\", pos);\n if (nl === -1) return content.length;\n pos = nl + 1;\n }\n return pos;\n}\n","/**\n * Misplaced markers, and what to do about them. Proposal 0054 is the record.\n *\n * A **marker run** is one or more consecutive lines that each hold one marker\n * and nothing else. A run is **misplaced** when the line directly above it and\n * the line directly below it are both unit text: deleting the run would join\n * them into one paragraph. Such a marker splits the paragraph for the renderer\n * and for the tool, and the lines above it are anchored by nothing.\n *\n * A misplaced marker belongs where `add --marker` writes one: above the first\n * line of the unit, or, for a `quote: true` entry, above the block it anchors.\n * A run moves in its own order, so two markers that were stacked stay stacked.\n *\n * The claim of a marker-anchored entry is read against three spans, in order:\n * the unit the marker belongs to, the span it anchors now, and the span it was\n * pinned over before PR #43 (marker lines included, down to the next blank\n * line or fence). The second or third holding means the pinned text is on the\n * page and the marker anchors a different span: `claim-moved`.\n */\nimport type { ClaimEnd, PageCitation, PageCitations, PageLines } from \"../types.js\";\nimport { hashLines } from \"./hash.js\";\nimport { MAX_MARKERS_PER_PAGE } from \"./page.js\";\nimport { spellLines } from \"../../shared/pin.js\";\nimport { ANY_FENCE, anchoredLines, isBoundLine, isMarkerLine } from \"./statements.js\";\n\n/** Whether a line is text a paragraph is made of. */\nexport function isUnitText(line: string | undefined, format: string): boolean {\n if (line === undefined) return false;\n if (line.trim() === \"\") return false;\n if (ANY_FENCE.test(line)) return false;\n if (isMarkerLine(line, format)) return false;\n return !isBoundLine(line, format);\n}\n\n/** Whether the file line `n` holds one marker and nothing else. */\nfunction markerAt(lines: readonly string[], n: number, format: string): boolean {\n const line = lines[n - 1];\n return line !== undefined && isMarkerLine(line, format);\n}\n\n/** The run of marker-only lines that holds `line`. */\nexport function markerRunAt(\n lines: readonly string[],\n line: number,\n format: string,\n bodyLine: number,\n): PageLines {\n let start = line;\n while (start - 1 >= bodyLine && markerAt(lines, start - 1, format)) start--;\n let end = line;\n while (end + 1 <= lines.length && markerAt(lines, end + 1, format)) end++;\n return { start, end };\n}\n\n/**\n * The paragraph a run splits, in file lines, marker lines included.\n * `undefined` when the run sits where `add` writes markers: after a blank\n * line, a fence, a bound line, or the body's first line.\n */\nexport function splitUnit(\n lines: readonly string[],\n run: PageLines,\n format: string,\n bodyLine: number,\n): PageLines | undefined {\n if (run.start - 1 < bodyLine) return undefined;\n if (!isUnitText(lines[run.start - 2], format)) return undefined;\n if (!isUnitText(lines[run.end], format)) return undefined;\n let start = run.start - 1;\n while (start - 1 >= bodyLine && isUnitText(lines[start - 2], format)) start--;\n let end = run.end + 1;\n while (end + 1 <= lines.length && isUnitText(lines[end], format)) end++;\n return { start, end };\n}\n\n/**\n * The span a marker was pinned over before PR #43: from the line below it\n * through the next blank line or fence, marker lines included. `undefined`\n * when the line below is blank or a fence, so the old reading covered nothing.\n */\nexport function pre43Span(\n lines: readonly string[],\n markerLine: number,\n): PageLines | undefined {\n const start = markerLine + 1;\n const first = lines[start - 1];\n if (first === undefined || first.trim() === \"\" || ANY_FENCE.test(first)) return undefined;\n let end = start;\n while (end + 1 <= lines.length) {\n const next = lines[end];\n if (next === undefined || next.trim() === \"\" || ANY_FENCE.test(next)) break;\n end++;\n }\n return { start, end };\n}\n\n/** One marker line that splits a paragraph. */\nexport interface MisplacedMarker {\n /** File line of the marker. */\n line: number;\n /** The whole run of marker-only lines it belongs to. */\n run: PageLines;\n /** Its position in that run, counted from zero, so stacked markers keep their order. */\n order: number;\n /** The paragraph the run splits, in file lines as the page reads now. */\n unit: PageLines;\n /** The file line the marker belongs above. */\n place: number;\n /** Whether `place` is a fenced block the entry quotes rather than the unit's first line. */\n block: boolean;\n /** The file line the marker takes once the whole run has moved. */\n to: number;\n /** The entry the marker names, when one is anchored by it. */\n entry?: PageCitation;\n}\n\n/** The lines of a run, which is `end - start + 1` markers. */\nfunction runLength(run: PageLines): number {\n return run.end - run.start + 1;\n}\n\n/** Whether a misplaced marker at `line` splits a paragraph, and where it belongs. */\nexport function misplacedMarkerAt(\n page: PageCitations,\n lines: readonly string[],\n line: number,\n entry?: PageCitation,\n): MisplacedMarker | undefined {\n if (!markerAt(lines, line, page.format)) return undefined;\n const run = markerRunAt(lines, line, page.format, page.bodyLine);\n const unit = splitUnit(lines, run, page.format, page.bodyLine);\n if (unit === undefined) return undefined;\n const order = line - run.start;\n const quote = entry?.citation.quote === true;\n const marker = entry?.marker;\n const blockAt =\n quote && marker !== undefined\n ? anchoredLines(page.content, marker.end, page.format, true)?.start\n : undefined;\n const out: MisplacedMarker = blockAt === undefined\n ? { line, run, order, unit, place: unit.start, block: false, to: unit.start + order }\n : {\n line,\n run,\n order,\n unit,\n place: blockAt,\n block: true,\n to: blockAt - runLength(run) + order,\n };\n if (entry !== undefined) out.entry = entry;\n return out;\n}\n\n/**\n * Every misplaced marker on a page, in the order the page reads. An orphan,\n * repeated or invalid marker is reported like any other: it splits the\n * paragraph whether or not it names an entry.\n */\nexport function misplacedMarkers(\n page: PageCitations,\n lines: readonly string[],\n): MisplacedMarker[] {\n const out: MisplacedMarker[] = [];\n for (const statement of page.statements.slice(0, MAX_MARKERS_PER_PAGE)) {\n const entry = page.citations.find((c) => c.marker?.line === statement.line);\n const found = misplacedMarkerAt(page, lines, statement.line, entry);\n if (found !== undefined) out.push(found);\n }\n return out;\n}\n\n/**\n * The span the pin covers once a misplaced run has moved: the joined unit,\n * pushed down by the markers now above it. A quote marker's pin covers its\n * block, which no move touches, so this is never asked of one.\n */\nexport function movedUnit(misplaced: MisplacedMarker): PageLines {\n return { start: misplaced.unit.start + runLength(misplaced.run), end: misplaced.unit.end };\n}\n\n/** The unit's text, the run's marker lines left out: what the pin covers after the move. */\nexport function unitText(lines: readonly string[], misplaced: MisplacedMarker): string[] {\n const { unit, run } = misplaced;\n const out: string[] = [];\n for (let n = unit.start; n <= unit.end; n++) {\n if (n >= run.start && n <= run.end) continue;\n const line = lines[n - 1];\n if (line !== undefined) out.push(line);\n }\n return out;\n}\n\n/** One marker line a rewrite moves, and the file line it goes above. */\nexport interface MarkerMove {\n from: number;\n place: number;\n}\n\n/** A page with its markers moved, and where its lines went. */\nexport interface MovedPage {\n content: string;\n /** The new file line of an old one. */\n line(old: number): number;\n}\n\n/** A page split into line texts and the terminator each position carries. */\nfunction splitKeepingEol(content: string): { texts: string[]; eols: string[] } {\n const parts = content.match(/[^\\n]*\\n|[^\\n]+$/g) ?? [];\n const texts: string[] = [];\n const eols: string[] = [];\n for (const part of parts) {\n const eol = /\\r?\\n$/.exec(part)?.[0] ?? \"\";\n texts.push(part.slice(0, part.length - eol.length));\n eols.push(eol);\n }\n return { texts, eols };\n}\n\n/**\n * The page with each named marker line lifted out and written above its place,\n * in the order the moves are given, so a run that was stacked stays stacked.\n * A moved marker takes the indentation `add` would write it at, and the file's\n * terminators stay where they are: the lines are permuted, never re-joined.\n *\n * Read the join carefully. A line's text comes from where it was, and its\n * terminator from where it now sits. That asymmetry is deliberate: the last\n * position of a page with no final newline carries no terminator, and it has\n * to stay the last position. Were terminators to travel with their lines, a\n * move that lifted that last line would carry the missing terminator into the\n * middle of the page and glue two lines together.\n *\n * The cost is that a page mixing `\\r\\n` and `\\n` has the endings of the two\n * swapped positions trade places. No byte is gained or lost, and the file\n * still ends as it began. A uniform page, which is what a checkout gives,\n * cannot tell the difference.\n */\nexport function applyMarkerMoves(\n content: string,\n moves: readonly MarkerMove[],\n indentAt: (line: number) => string,\n): MovedPage {\n const { texts, eols } = splitKeepingEol(content);\n const moving = new Set(moves.map((move) => move.from));\n const inserts = new Map<number, number[]>();\n for (const move of moves) {\n const list = inserts.get(move.place) ?? [];\n list.push(move.from);\n inserts.set(move.place, list);\n }\n const order: number[] = [];\n for (let n = 1; n <= texts.length; n++) {\n for (const from of inserts.get(n) ?? []) order.push(from);\n if (!moving.has(n)) order.push(n);\n }\n const moved = new Map<number, string>();\n for (const move of moves) {\n moved.set(move.from, indentAt(move.place) + (texts[move.from - 1] ?? \"\").trim());\n }\n const at = new Map<number, number>();\n order.forEach((old, index) => at.set(old, index + 1));\n const out = order\n .map((old, index) => (moved.get(old) ?? texts[old - 1] ?? \"\") + (eols[index] ?? \"\"))\n .join(\"\");\n return { content: out, line: (old) => at.get(old) ?? old };\n}\n\n/** The plain pin of a span of lines, or of an explicit list of them. */\nfunction pinOf(lines: readonly string[], span: PageLines): string | undefined {\n if (span.start < 1 || span.end > lines.length || span.end < span.start) return undefined;\n return hashLines(lines.slice(span.start - 1, span.end).join(\"\\n\"));\n}\n\n/**\n * The claim end of a marker-anchored entry, read against proposal 0054's\n * three spans. `misplaced` is the marker's misplacement, when it has one.\n *\n * For a misplaced marker at `moved`, `fileLines` is the span that held and\n * `newLines` the span the pin will cover once the marker moves. Both are file\n * lines: a marker-anchored claim has no body lines of its own.\n */\nexport function markerClaimEnd(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n misplaced: MisplacedMarker | undefined,\n): ClaimEnd {\n const { citation, marker } = entry;\n const pin = citation.claim?.integrity;\n const quote = citation.quote === true;\n if (marker === undefined || pin === undefined) return { status: \"changed\" };\n const current = anchoredLines(page.content, marker.end, page.format, quote);\n if (current === undefined) return { status: \"changed\" };\n\n /** The claim end this span reads as, and where the move will take it. */\n const claimAt = (span: PageLines, status: ClaimEnd[\"status\"], to?: PageLines): ClaimEnd => {\n const end: ClaimEnd = { fileLines: spellLines(span), status };\n if (to !== undefined) {\n end.newLines = spellLines(to);\n end.newFileLines = end.newLines;\n }\n if (status === \"changed\") end.text = lines.slice(span.start - 1, Math.min(span.end, lines.length));\n return end;\n };\n\n // A quote marker's pin covers its block, which no move touches, and the\n // block reading never changed, so there is one span to read it against.\n if (quote) {\n return claimAt(current, pinOf(lines, current) === pin ? \"current\" : \"changed\");\n }\n\n if (misplaced !== undefined) {\n const to = movedUnit(misplaced);\n if (hashLines(unitText(lines, misplaced).join(\"\\n\")) === pin) return claimAt(to, \"current\");\n if (pinOf(lines, current) === pin) return claimAt(current, \"moved\", to);\n const pre43 = pre43Span(lines, marker.line);\n if (pre43 !== undefined && pinOf(lines, pre43) === pin) return claimAt(pre43, \"moved\", to);\n return claimAt(current, \"changed\");\n }\n\n if (pinOf(lines, current) === pin) return claimAt(current, \"current\");\n // Stacked markers written before PR #43 were pinned over a sibling marker\n // line and the paragraph. That renders fine, so only the pin is repaired.\n const pre43 = pre43Span(lines, marker.line);\n if (pre43 !== undefined && pinOf(lines, pre43) === pin) return claimAt(pre43, \"moved\", current);\n return claimAt(current, \"changed\");\n}\n","/**\n * The claim end: the page text a citation supports, classified by the same\n * machinery as the source end and against the page as it is now.\n *\n * The claim's lines are body-relative, so editing the frontmatter never moves\n * them; every line a person reads is a file line, translated here. The pin\n * holds at the recorded lines: `current`. The same text is found verbatim\n * elsewhere in the body: `moved`, once, or `moved-ambiguous`. Nowhere:\n * `changed`, the sentence was edited. A marker-anchored claim pins what the\n * marker anchors, so its text never moves on the page; it is `current`,\n * `changed`, or, when the pin holds over a span the marker no longer anchors,\n * `moved`. `src/cite/core/reanchor.ts` reads those spans.\n */\nimport type {\n ClaimEnd,\n PageCitation,\n PageCitations,\n PageLines,\n} from \"../types.js\";\nimport {\n findWindows,\n parseLines,\n pinOfLines,\n spellLines,\n toBodyLines,\n toFileLines,\n} from \"../../shared/pin.js\";\nimport {\n markerClaimEnd,\n misplacedMarkerAt,\n type MisplacedMarker,\n} from \"./reanchor.js\";\nimport {\n anchoredLines,\n fenceAround,\n fenceSpanAt,\n isMarkerLine,\n isTableRow,\n isTableSeparator,\n lineAt,\n offsetOfLine,\n paragraphAfter,\n} from \"./statements.js\";\n\n// The line translation and the claim pin are the shared pin engine's; this path keeps cite's imports working.\nexport { pinOfLines, toBodyLines, toFileLines } from \"../../shared/pin.js\";\n\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * The hashing rule's normalization for a whole quoted block: one BOM, CRLF →\n * LF, and one trailing LF dropped. It differs from the shared `normalizeText`\n * only in that last step, because a quote is compared as one joined block\n * rather than split into lines first.\n */\nfunction normalizeBlock(text: string): string {\n let out = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n out = out.replace(/\\r\\n/g, \"\\n\");\n return out.endsWith(\"\\n\") ? out.slice(0, -1) : out;\n}\n\n/** `true` when the block's normalized text equals the cited lines under the hashing rule. */\nexport function blockMatches(blockText: string, citedJoined: string): boolean {\n return normalizeBlock(blockText) === normalizeBlock(citedJoined);\n}\n\n/** The page lines a range covers, as far as the page reaches. */\nfunction textAt(lines: readonly string[], range: PageLines): string[] {\n return lines.slice(range.start - 1, Math.min(range.end, lines.length));\n}\n\n/** The first file line of a classified claim: where its findings sit. */\nexport function claimLine(claim: ClaimEnd): number | undefined {\n const at = claim.fileLines === undefined ? undefined : parseLines(claim.fileLines);\n return at?.start;\n}\n\n/** Where the claim is now: the moved-to lines when it moved, else the recorded ones. */\nexport function claimLineNow(claim: ClaimEnd): number | undefined {\n const spec = claim.newFileLines ?? claim.candidateFileLines?.[0] ?? claim.fileLines;\n const at = spec === undefined ? undefined : parseLines(spec);\n return at?.start;\n}\n\n/** The file lines the claim occupies now, for the quote check. */\nexport function claimLinesNow(claim: ClaimEnd): PageLines | undefined {\n const spec = claim.newFileLines ?? claim.candidateFileLines?.[0] ?? claim.fileLines;\n return spec === undefined ? undefined : parseLines(spec);\n}\n\n/**\n * Classify one entry's claim end against the page. `lines` is the page under\n * the hashing rule (`splitLines`). `null` for an entry with no `claim`: a\n * bare pin, or a marker with no drift check on its sentence.\n */\nexport function claimEnd(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n misplaced?: MisplacedMarker,\n): ClaimEnd | null {\n const { citation, marker } = entry;\n const claim = citation.claim;\n if (claim === undefined) return null;\n const body = page.bodyLine;\n\n if (claim.lines !== undefined) {\n const recorded = parseLines(claim.lines);\n // An unreadable range is `entry-invalid`, and that entry is never classified.\n if (recorded === undefined) return { status: \"skipped\" };\n const file = toFileLines(recorded, body);\n const end: ClaimEnd = {\n lines: spellLines(recorded),\n fileLines: spellLines(file),\n status: \"changed\",\n };\n // Lines and a marker both: `anchor-invalid`, and neither anchor is judged.\n if (marker !== undefined) return { ...end, status: \"skipped\" };\n if (pinOfLines(lines, file) === claim.integrity) return { ...end, status: \"current\" };\n\n const width = recorded.end - recorded.start + 1;\n const found = findWindows(lines.slice(body - 1), width, claim.integrity, undefined, {\n around: recorded.start,\n });\n const spans = found.starts.map((start) => ({ start, end: start + width - 1 }));\n const [only] = spans;\n if (spans.length === 1 && only !== undefined) {\n return {\n ...end,\n status: \"moved\",\n newLines: spellLines(only),\n newFileLines: spellLines(toFileLines(only, body)),\n };\n }\n if (spans.length > 1) {\n return {\n ...end,\n status: \"moved-ambiguous\",\n candidates: spans.map(spellLines),\n candidateFileLines: spans.map((span) => spellLines(toFileLines(span, body))),\n };\n }\n return { ...end, text: textAt(lines, file) };\n }\n\n if (marker !== undefined) {\n // The marker travels with its text, so what moves is the span the marker\n // anchors, not the text. `reanchor.ts` reads the three spans.\n return markerClaimEnd(\n page,\n entry,\n lines,\n misplaced ?? misplacedMarkerAt(page, lines, marker.line, entry),\n );\n }\n\n // A claim pin with neither lines nor a marker anchors nothing at all.\n return { status: \"changed\" };\n}\n\n/**\n * Where else in the body the claim's text sits, as file lines. A claim whose\n * text repeats is `moved-ambiguous` the moment it moves, so `add` says so\n * while the pin is still being written, and `update --accept` says so before\n * it mints a pin that cannot tell two copies apart. The search is the\n * classifier's own.\n */\nexport function otherClaimSpans(\n lines: readonly string[],\n pageLines: PageLines,\n pin: string,\n bodyLine: number,\n): PageLines[] {\n const width = pageLines.end - pageLines.start + 1;\n const found = findWindows(lines.slice(bodyLine - 1), width, pin, undefined, {\n around: toBodyLines(pageLines, bodyLine).start,\n });\n return found.starts\n .map((start) => toFileLines({ start, end: start + width - 1 }, bodyLine))\n .filter((span) => span.start !== pageLines.start);\n}\n\n/** How many other locations a notice names before it starts counting them. */\nconst NAMED_SPANS = 3;\n\n/** `line 17`, `lines 16 and 18`, `lines 16, 18, 20 and 2 more`. */\nexport function spellElsewhere(spans: readonly PageLines[]): string {\n const first = spans[0];\n const noun = spans.length === 1 && first !== undefined && first.start === first.end ? \"line\" : \"lines\";\n const named = spans.slice(0, NAMED_SPANS).map((span) => spellLines(span));\n const rest = spans.length - named.length;\n if (rest > 0) return `${noun} ${named.join(\", \")} and ${String(rest)} more`;\n const last = named.pop() ?? \"\";\n return named.length === 0 ? `${noun} ${last}` : `${noun} ${named.join(\", \")} and ${last}`;\n}\n\n/**\n * What `update --accept` re-pins over: the paragraph, whole fenced block, or\n * lines inside a fenced block at a line.\n *\n * The three kinds are not interchangeable. `\"block\"` covers a fence, its\n * content and its closing fence, which is the only shape a `quote: true`\n * entry may hold. `\"fenced-lines\"` covers content lines inside a block and\n * neither fence, which is what a claim minted over part of a code sample\n * holds. `\"paragraph\"` covers prose, and table rows too, since `ClaimUnit`\n * draws no line between them.\n */\nexport interface ClaimUnit {\n lines: PageLines;\n kind: \"paragraph\" | \"block\" | \"fenced-lines\";\n text: string[];\n}\n\n/**\n * Why no unit sits at a file line. Each one is a different problem with a\n * different repair, so `update --accept` names which it hit rather than\n * leaving the entry skipped with no reason.\n */\nexport type NoUnit =\n | \"outside\"\n | \"blank\"\n | \"fence-crossed\"\n | \"marker\"\n | \"not-a-paragraph\"\n | \"table-short\"\n | \"table-rule\";\n\n/**\n * The span a claim of the recorded width holds at a line. A unit whose extent\n * is the author's, rather than the page's, keeps the number of lines it was\n * minted over: table rows and lines inside a fenced block both. One recorded\n * line gives one line, and five give five.\n */\nfunction spanOf(line: number, recorded: PageLines | undefined): PageLines {\n const width = recorded === undefined ? 1 : Math.max(1, recorded.end - recorded.start + 1);\n return { start: line, end: line + width - 1 };\n}\n\n/**\n * The rows a claim on a table re-pins over, or why there are none.\n *\n * A row is a statement, so a claim over N rows is a claim over N statements.\n * The extent is the author's, and re-pinning re-mints the hash over it rather\n * than redesigning it: one recorded line gives one row, and five give five.\n * Rows below a one-line claim are other statements, and a table that no longer\n * reaches the recorded end is a question only the author can answer.\n *\n * The unit comes back as `kind: \"paragraph\"`, since `ClaimUnit` names how a\n * unit is bounded and not what it holds. A caller wanting to know whether it\n * holds rows has to ask `isTableRow` about the text, not read `kind`.\n *\n * A span of nothing but `|---|---|` rules is refused. Those lines carry no\n * words, so a pin over them says nothing about what the page claims, and a\n * claim that shifted onto one is a claim the page lost. A header, its rule and\n * a body row is three rows and keeps all three.\n */\nfunction rowsAt(\n line: number,\n lines: readonly string[],\n recorded: PageLines | undefined,\n named: boolean,\n): ClaimUnit | NoUnit {\n const end = spanOf(line, recorded).end;\n if (end > lines.length) return \"table-short\";\n for (let n = line; n <= end; n++) {\n if (!isTableRow(lines[n - 1] ?? \"\")) return \"table-short\";\n }\n const text = lines.slice(line - 1, end);\n if (!named && text.every((row) => isTableSeparator(row))) return \"table-rule\";\n return { lines: { start: line, end }, kind: \"paragraph\", text };\n}\n\n/**\n * The unit at a file line, or why there is none. `unitAt` and `noUnitAt` are\n * the two halves a caller reads, so the guards are written once. `recorded` is\n * the span the claim holds now, which only a table reads. `named` is the\n * operator having named the entry with `--only`: the structural refusals a\n * blanket accept would hit are the ones they have looked at, so they stand\n * down and the line is read as the text it is.\n */\nfunction unitOrWhy(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): ClaimUnit | NoUnit {\n if (line < page.bodyLine || line > lines.length) return \"outside\";\n const own = lines[line - 1] ?? \"\";\n if (own.trim() === \"\") return \"blank\";\n // A line that is one marker and nothing else is another entry's anchor, not\n // claim text. Reading it as text is how a shifted claim gets a confident pin\n // over a comment.\n const marker = isMarkerLine(own, page.format);\n if (marker && !named) return \"marker\";\n const block = fenceSpanAt(page.content, line, page.format);\n if (block !== undefined) {\n return { lines: block, kind: \"block\", text: lines.slice(block.start - 1, block.end) };\n }\n const around = fenceAround(page.content, page.bodyOffset, line, page.format);\n if (around !== undefined) {\n // The claim was minted over lines inside this block, so it is re-pinned\n // over as many lines as it recorded, at the line it starts on. Re-pinning\n // the block around them would widen what the pin covers, which is the one\n // thing an accept may never do. A span reaching the closing fence, or past\n // it, is not lines inside a block at all, and stays refused.\n const span = spanOf(line, recorded);\n return span.end < around.end\n ? { lines: span, kind: \"fenced-lines\", text: lines.slice(span.start - 1, span.end) }\n : \"fence-crossed\";\n }\n // A table row is a statement of its own, and nothing between two rows ends a\n // paragraph, so the walk below would read the rest of the table as one.\n if (isTableRow(own)) return rowsAt(line, lines, recorded, named);\n // The format ends the paragraph at a marker under it, so a re-pin never\n // swallows another entry's anchor. A named entry sitting on a marker is read\n // without it, because there the marker is the line being accepted.\n const paragraph = paragraphAfter(\n page.content,\n offsetOfLine(page.content, line),\n marker ? undefined : page.format,\n );\n if (paragraph === undefined || paragraph.line !== line) return \"not-a-paragraph\";\n const span: PageLines = { start: line, end: lineAt(page.content, paragraph.end) };\n return { lines: span, kind: \"paragraph\", text: lines.slice(span.start - 1, span.end) };\n}\n\n/**\n * The paragraph, fenced block, fenced lines or table rows at a file line.\n * Undefined when the line holds no claim at all: it is blank, outside the\n * body, another entry's marker, a table rule, or a line whose claim runs out\n * of the fenced block it starts in. Those are the claims `update --accept`\n * skips, and `noUnitAt` says which of them it is.\n *\n * A paragraph runs from this line to its end, not from the paragraph's own\n * first line. The line asked about is the claim's first line, and re-pinning\n * has to leave that where it is, so a claim that started mid-paragraph keeps\n * starting there. A paragraph that gained a sentence gained it as part of the\n * same statement, which is why a claim grows with it.\n *\n * A table does not work that way. Each row is a statement, so a claim keeps\n * the number of rows `recorded` gives it, and refuses when the table no longer\n * reaches that far. Callers that know the claim's current span pass it.\n */\nexport function unitAt(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): ClaimUnit | undefined {\n const found = unitOrWhy(page, line, lines, recorded, named);\n return typeof found === \"string\" ? undefined : found;\n}\n\n/** Why `unitAt` found nothing at a file line, or undefined when it found a unit. */\nexport function noUnitAt(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): NoUnit | undefined {\n const found = unitOrWhy(page, line, lines, recorded, named);\n return typeof found === \"string\" ? found : undefined;\n}\n\n/** The lines a marker anchors now, for `update --accept` on a marker-anchored claim. */\nexport function markerUnit(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n): ClaimUnit | undefined {\n const { marker, citation } = entry;\n if (marker === undefined) return undefined;\n const span = anchoredLines(page.content, marker.end, page.format, citation.quote === true);\n if (span === undefined || span.end > lines.length) return undefined;\n return {\n lines: span,\n kind: citation.quote === true ? \"block\" : \"paragraph\",\n text: lines.slice(span.start - 1, span.end),\n };\n}\n","/**\n * A thin git client. Every call is `execFile(\"git\", args, { cwd: root,\n * windowsHide: true, maxBuffer: 32 MiB })` with `-c core.quotepath=false`,\n * `--end-of-options` before a commit, `--` before a path, and `<commit>:./<path>`\n * for `show` so the path resolves against the root, not the repository top.\n * Results are memoized per (call, commit, path). The commit is validated\n * against the schema's hex pattern by the caller before it reaches here.\n */\nimport { execFile } from \"node:child_process\";\nimport { CiteError } from \"../errors.js\";\nimport type { GitClient, PageCommit, PageHistory, ShownFile } from \"../types.js\";\n\nconst MAX_BUFFER = 32 * 1024 * 1024;\n\n/** Stderr shapes `git show` uses for a revision it does not have. */\nconst NO_COMMIT = /invalid object name|bad revision|unknown revision|bad object/i;\n/**\n * Stderr shapes for a path absent from the tree at a revision. Git uses these\n * for an unknown *full-length* commit too (`path 'x' does not exist in\n * '<40 hex>'`; only an abbreviated unknown commit says \"invalid object name\"),\n * so a path-shaped failure is trusted only once `rev-parse --verify` has said\n * the commit exists. A shallow clone must degrade to \"history unavailable\",\n * never to \"never true\".\n */\nconst NO_PATH = /does not exist in|exists on disk, but not in|path .* does not exist/i;\n\ntype Outcome =\n | { ok: true; stdout: string }\n /** `code` is git's exit status; absent when git could not be run at all. */\n | { ok: false; stderr: string; message: string; code?: number };\n\nfunction run(root: string, args: readonly string[]): Promise<Outcome> {\n return new Promise((resolve) => {\n execFile(\n \"git\",\n [\"-c\", \"core.quotepath=false\", ...args],\n { cwd: root, windowsHide: true, maxBuffer: MAX_BUFFER, encoding: \"utf8\" },\n (error, stdout, stderr) => {\n if (error) {\n const failure: Outcome = { ok: false, stderr, message: error.message };\n if (typeof error.code === \"number\") failure.code = error.code;\n resolve(failure);\n } else resolve({ ok: true, stdout });\n },\n );\n });\n}\n\n/** `git` at `root`, as a client; see the module comment for the call shapes. */\nexport function gitClient(root: string): GitClient {\n const memo = new Map<string, Promise<unknown>>();\n const once = <T>(key: string, compute: () => Promise<T>): Promise<T> => {\n const held = memo.get(key);\n if (held !== undefined) return held as Promise<T>;\n const made = compute();\n memo.set(key, made);\n return made;\n };\n\n const available = (): Promise<boolean> =>\n once(\"available\", async () => (await run(root, [\"rev-parse\", \"--show-toplevel\"])).ok);\n\n const failed = (verb: string, outcome: Extract<Outcome, { ok: false }>): CiteError =>\n new CiteError(`git ${verb} failed: ${outcome.stderr.trim() || outcome.message}`);\n\n /**\n * Whether the repository has the commit. `--verify --quiet` exits 1 for an\n * object it does not have, and that alone is \"no\": any other failure is\n * git itself failing, and reading it as \"no\" would turn a broken checkout\n * into shallow-clone advice.\n */\n /**\n * Whether the repository is shallow. A shallow oldest commit has a parent\n * nobody fetched, so a walk that runs out of commits there has not reached\n * the beginning of anything.\n */\n const shallow = (): Promise<boolean> =>\n once(\"shallow\", async () => {\n const out = await run(root, [\"rev-parse\", \"--is-shallow-repository\"]);\n return out.ok && out.stdout.trim() === \"true\";\n });\n\n const hasCommit = (commit: string): Promise<boolean> =>\n once(`has\\0${commit}`, async () => {\n const out = await run(root, [\"rev-parse\", \"--verify\", \"--quiet\", \"--end-of-options\", `${commit}^{commit}`]);\n if (out.ok) return true;\n if (out.code === 1) return false;\n throw failed(\"rev-parse\", out);\n });\n\n return {\n available,\n\n shallow,\n\n // `merge-base --is-ancestor` exits 0 for yes and 1 for no. For a commit\n // it does not have it exits 128, `Not a valid commit name`, which reads\n // as git failing. So `hasCommit` answers first, and is required rather\n // than an optimization: a commit git lacks is in no history it holds,\n // which is a no, and exactly the pin a deleted branch leaves behind.\n isAncestor: (commit, of) =>\n once(`ancestor\\0${commit}\\0${of}`, async () => {\n if (!(await hasCommit(commit))) return false;\n const out = await run(root, [\"merge-base\", \"--is-ancestor\", \"--end-of-options\", commit, of]);\n if (out.ok) return true;\n if (out.code === 1) return false;\n throw failed(\"merge-base\", out);\n }),\n\n head: () =>\n once(\"head\", async () => {\n if (!(await available())) return null;\n const out = await run(root, [\"rev-parse\", \"HEAD\"]);\n return out.ok ? out.stdout.trim() : null;\n }),\n\n lsFiles: () =>\n once(\"ls-files\", async () => {\n if (!(await available())) return [];\n const out = await run(root, [\"ls-files\", \"-z\"]);\n if (!out.ok) throw failed(\"ls-files\", out);\n return out.stdout.split(\"\\0\").filter((entry) => entry !== \"\");\n }),\n\n showFile: (commit, path) =>\n once(`show\\0${commit}\\0${path}`, async (): Promise<ShownFile> => {\n const out = await run(root, [\"show\", \"--end-of-options\", `${commit}:./${path}`]);\n if (out.ok) return { text: out.stdout };\n if (NO_COMMIT.test(out.stderr)) return { missing: \"commit\" };\n if (NO_PATH.test(out.stderr)) {\n return (await hasCommit(commit)) ? { missing: \"path\" } : { missing: \"commit\" };\n }\n throw failed(\"show\", out);\n }),\n\n subjectsSince: (commit, path) =>\n once(`log\\0${commit}\\0${path}`, async () => {\n const out = await run(root, [\"log\", \"--format=%s\", \"--end-of-options\", `${commit}..HEAD`, \"--\", path]);\n if (!out.ok) throw failed(\"log\", out);\n return out.stdout.split(/\\r?\\n/).filter((line) => line !== \"\");\n }),\n\n // `HEAD` is written out: with no second revision git compares the commit\n // to the working tree, and this list is committed changes only, so a move\n // that is merely saved is never followed into a page (0055 stress test 8).\n changedSince: (commit) =>\n once(`changed\\0${commit}`, async () => {\n if (!(await available())) return [];\n const out = await run(root, [\"diff\", \"--name-only\", \"--end-of-options\", commit, \"HEAD\"]);\n if (!out.ok) throw failed(\"diff\", out);\n return out.stdout.split(/\\r?\\n/).filter((line) => line !== \"\");\n }),\n\n diffSince: (commit, path) =>\n once(`diff\\0${commit}\\0${path}`, async () => {\n const out = await run(root, [\"diff\", \"--end-of-options\", commit, \"--\", path]);\n if (!out.ok) throw failed(\"diff\", out);\n return out.stdout;\n }),\n\n pageCommits: (path, cap) =>\n once(`commits\\0${String(cap)}\\0${path}`, async (): Promise<PageHistory> => {\n if (!(await available())) return { commits: [], shallow: false, truncated: false };\n // One more than the cap, so a list the cap cut short says so rather\n // than reading as a history that simply ended there.\n // `--topo-order`, because the default date order interleaves the\n // lineages either side of a merge. A walk back through an interleaved\n // list reads one branch's commits as if they came before the other's.\n const out = await run(root, [\n \"log\",\n `--format=%H${UNIT}%s`,\n \"--topo-order\",\n `-n${String(cap + 1)}`,\n \"HEAD\",\n \"--\",\n path,\n ]);\n if (!out.ok) throw failed(\"log\", out);\n const commits: PageCommit[] = [];\n for (const line of out.stdout.split(/\\r?\\n/)) {\n if (line === \"\") continue;\n const at = line.indexOf(UNIT);\n if (at === -1) continue;\n commits.push({ sha: line.slice(0, at), subject: line.slice(at + 1) });\n }\n const truncated = commits.length > cap;\n return { commits: commits.slice(0, cap), shallow: await shallow(), truncated };\n }),\n };\n}\n\n/** The separator between a commit's hash and its subject: never in either. */\nconst UNIT = \"\u001f\";\n\n/**\n * What a run says, once, when git is not there and the run wanted it: a\n * citation carries a commit, or `--show-diff` asked for diffs, so history\n * would have been read. Said through `onNotice`; never a finding.\n */\nexport const GIT_UNAVAILABLE_HISTORY =\n \"git is not available here, so citations are checked without history: no never-true, no reanchored claims, no diffs, no commit subjects.\";\n\n/**\n * What a run says, once, when a claim's walk ran out of commits before the\n * pin held: a shallow checkout, or the 256-commit cap. Without the rest of\n * the history a layout change and an edit read the same.\n */\nexport const PAGE_HISTORY_UNAVAILABLE =\n \"the page history ends before the pin held; use fetch-depth: 0 to tell reanchored claims from changed ones\";\n\n/**\n * What `update --recommit` says, once, in a shallow clone. A commit the clone\n * lacks may still be in the history, so only the containment test ran.\n */\nexport const SHALLOW_RECOMMIT =\n \"this clone is shallow, so --recommit re-recorded only commits that do not contain their lines. Fetch full history to check the rest.\";\n\n/** What `add` and `update --accept` say, once, when a commit would have been recorded and git is not there. */\nexport const GIT_UNAVAILABLE_COMMIT = \"git is not available here, so the citation records no commit.\";\n\n/**\n * A client that answers \"no git\": `available()` false, everything else empty.\n * What a caller passes as `gitClient` to run without git where git is there.\n */\nexport function noGit(): GitClient {\n return {\n available: () => Promise.resolve(false),\n head: () => Promise.resolve(null),\n lsFiles: () => Promise.resolve([]),\n showFile: () => Promise.resolve({ missing: \"commit\" }),\n subjectsSince: () => Promise.resolve([]),\n diffSince: () => Promise.resolve(\"\"),\n changedSince: () => Promise.resolve([]),\n pageCommits: () => Promise.resolve({ commits: [], shallow: false, truncated: false }),\n };\n}\n","/**\n * The claim end read against the page's own history. Proposal 0053 is the\n * record, and the source end's `historyOf` is the shape it follows.\n *\n * A claim that no longer holds says nothing on its own: the pin is a hash, and\n * 0044 chose never to copy the text. So the baseline is derived. It is the\n * newest commit whose page still held the pinned text, found by walking the\n * commits that touched the page, newest first. Nothing is stored, so a squash,\n * a rebase or an uncommitted page cannot make it wrong.\n *\n * With a baseline there are three strings, each normalized the same way.\n * `W0` is the text the pin covered then, `W1` the text the anchor covers now,\n * and `P0` the whole page body then. The claim is **reanchored** when `W0`\n * sits inside `W1` and `W1` sits inside `P0`: every word the pin covered is\n * still there, and every word the claim covers now was on the page already.\n * Anything else is **changed**, which is what the first condition catches for\n * an edit inside the claim and the second for a sentence added beside it.\n */\nimport type {\n ClaimEnd,\n GitClient,\n InlineStatement,\n PageCitation,\n PageCitations,\n PageLines,\n} from \"../types.js\";\nimport { spellLines, toBodyLines } from \"../../shared/pin.js\";\nimport { claimEnd } from \"./claims.js\";\nimport { hashLines, splitLines } from \"./hash.js\";\nimport { readPage } from \"./page.js\";\nimport { parseLines } from \"./range.js\";\nimport { misplacedMarkerAt, movedUnit, unitText } from \"./reanchor.js\";\nimport { shortCommit } from \"./spell.js\";\nimport { ANY_FENCE, isMarkerLine } from \"./statements.js\";\n\n/**\n * How many commits that touched the page one walk reads. A page with a long\n * history stops here, and the run says the history ended before the pin held.\n */\nexport const MAX_PAGE_COMMITS = 256;\n\n/** A page's marker-only lines dropped: the lines whose words a claim is made of. */\nexport function stripMarkers(lines: readonly string[], format: string): string[] {\n return lines.filter((line) => !isMarkerLine(line, format));\n}\n\n/**\n * The words a span of lines holds: marker-only lines dropped, then every run\n * of whitespace collapsed to one space and both ends trimmed. Punctuation,\n * emphasis and inline markup are words here, as 0044 stress test 18 has it.\n */\nexport function claimWords(lines: readonly string[], format: string): string {\n return stripMarkers(lines, format).join(\" \").replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * A text split into sentences, each with its whitespace collapsed and its\n * case dropped. What `update --accept` intersects, so a line that now holds\n * wholly other text is refused rather than blessed.\n */\nexport function sentencesOf(text: string): string[] {\n return text\n .split(/(?<=[.!?])\\s+/)\n .map((sentence) => sentence.replace(/\\s+/g, \" \").trim().toLowerCase())\n .filter((sentence) => sentence !== \"\");\n}\n\n/** Whether two texts share at least one sentence. */\nexport function sharesSentence(a: string, b: string): boolean {\n const left = new Set(sentencesOf(a));\n return sentencesOf(b).some((sentence) => left.has(sentence));\n}\n\n/** A text's distinct words, case dropped. Whitespace is the only separator. */\nfunction wordSet(text: string): Set<string> {\n return new Set(\n text\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word !== \"\"),\n );\n}\n\n/**\n * How much of `was` the text `now` still holds, from 0 to 1: the size of the\n * two word sets' intersection over `was`'s own size.\n *\n * Intersection over the baseline, not over the union, so the number reads as\n * the share of the claim's words that survived, and a line that grew around\n * the claim is not punished for the words it gained.\n *\n * Distinct words, because a table row's repeated `|` says nothing about\n * whether this is the same statement. A baseline with no words scores 1:\n * there is nothing for the line to have lost.\n */\nexport function wordShare(was: string, now: string): number {\n const left = wordSet(was);\n if (left.size === 0) return 1;\n const right = wordSet(now);\n let held = 0;\n for (const word of left) if (right.has(word)) held++;\n return held / left.size;\n}\n\n/** `true` when `inner`'s words sit inside `outer`'s, in order, at word boundaries. */\nexport function holdsWords(outer: string, inner: string): boolean {\n if (inner === \"\") return true;\n if (outer === inner) return true;\n if (outer.startsWith(`${inner} `)) return true;\n if (outer.endsWith(` ${inner}`)) return true;\n return outer.includes(` ${inner} `);\n}\n\n/**\n * Every run of whole body lines whose words hold `inner`, minimal under\n * containment. The page's words are laid out once with the line each\n * character came from, so a run is read off each occurrence rather than\n * searched for line by line.\n */\nexport function runsHolding(\n lines: readonly string[],\n format: string,\n bodyLine: number,\n inner: string,\n): PageLines[] {\n if (inner === \"\") return [];\n let text = \"\";\n const at: number[] = [];\n for (let n = Math.max(bodyLine, 1); n <= lines.length; n++) {\n const line = lines[n - 1] ?? \"\";\n if (isMarkerLine(line, format)) continue;\n const words = line.replace(/\\s+/g, \" \").trim();\n if (words === \"\") continue;\n if (text !== \"\") {\n text += \" \";\n at.push(n);\n }\n for (let i = 0; i < words.length; i++) at.push(n);\n text += words;\n }\n const out: PageLines[] = [];\n let from = 0;\n for (;;) {\n const found = text.indexOf(inner, from);\n if (found === -1) break;\n from = found + 1;\n const before = found === 0 ? \" \" : text[found - 1];\n const afterAt = found + inner.length;\n const after = afterAt === text.length ? \" \" : text[afterAt];\n if (before !== \" \" || after !== \" \") continue;\n const start = at[found];\n const end = at[afterAt - 1];\n if (start === undefined || end === undefined) continue;\n if (!out.some((span) => span.start === start && span.end === end)) out.push({ start, end });\n }\n // A run that holds another is not minimal: the tighter one is the claim.\n return out.filter(\n (span) =>\n !out.some(\n (other) =>\n (other.start !== span.start || other.end !== span.end) &&\n other.start >= span.start &&\n other.end <= span.end,\n ),\n );\n}\n\n/** What the walk needs to read one entry's history. */\nexport interface ClaimHistoryInput {\n /** The page as it is now: its format, its body line, and the marker. */\n page: PageCitations;\n entry: PageCitation;\n /** The claim end `claimEnd` classified as `changed`. */\n claim: ClaimEnd;\n /** The page's path, as the client below resolves it. */\n path: string;\n git: GitClient;\n /** The manifest that owns the entry, at the path the config declares now. */\n manifest?: string;\n /** Commits to read. Defaults to `MAX_PAGE_COMMITS`. */\n cap?: number;\n}\n\n/**\n * What the page's history says about a claim that no longer holds.\n * `unavailable` is a walk that ran out of commits, so no verdict is safe.\n * `none` is a walk that reached the entry's birth, or a client with no\n * history to read.\n */\nexport type ClaimHistory =\n | { kind: \"unavailable\" }\n | { kind: \"none\" }\n | {\n kind: \"baseline\";\n /** The newest commit whose page held the pin, as the full hash. */\n commit: string;\n /** Subjects of the commits that touched the page after it, newest first. */\n commitsSince: string[];\n /** `W0`: the words the pin covered at the baseline. */\n words: string;\n /** `P0`: the words the whole page body held at the baseline. */\n pageWords: string;\n /** The pinned lines as they were, for the diff. */\n lines: string[];\n /** The file lines they sat at, for the diff's label. */\n at: string;\n };\n\n/** Whether a line closes the window a marker's anchor may reach. */\nfunction bounds(line: string | undefined): boolean {\n return line === undefined || line.trim() === \"\" || ANY_FENCE.test(line);\n}\n\n/** The plain pin over a span of lines, or undefined when the span is not there. */\nfunction pinOf(lines: readonly string[], span: PageLines): string | undefined {\n if (span.start < 1 || span.end > lines.length || span.end < span.start) return undefined;\n return hashLines(lines.slice(span.start - 1, span.end).join(\"\\n\"));\n}\n\n/** Where the pin sat in one older page, or why the walk should stop. */\ntype FoundAt =\n | { kind: \"found\"; span: PageLines; lines: string[] }\n | { kind: \"absent\" }\n /** The marker that anchors the entry is not in that page, so nothing older can hold it. */\n | { kind: \"no-marker\" };\n\n/** One older page, read as this page is read. */\ninterface ThenPage {\n page: PageCitations;\n lines: string[];\n /** The marker naming the entry, for a marker-anchored one. */\n marker?: InlineStatement;\n}\n\n/** An older page, with the marker that named the entry there. */\nfunction readThen(input: ClaimHistoryInput, text: string): ThenPage | undefined {\n const then = readPage(input.page.file, text, { format: input.page.format });\n const lines = splitLines(then.content);\n if (input.entry.citation.claim?.lines !== undefined) return { page: then, lines };\n const id = input.entry.citation.id;\n if (id === undefined) return undefined;\n const marker = then.statements.find(\n (statement) => statement.payload.kind === \"ref\" && statement.payload.ids.includes(id),\n );\n // A marker absent at a commit is looked for no further back: the entry was\n // a claim-lines entry then, or it did not exist.\n if (marker === undefined) return undefined;\n return { page: then, lines, marker };\n}\n\n/**\n * Whether the pin held on an older page, read by the classifier itself, and\n * over which lines.\n *\n * The classifier is what decides, rather than a bare search for the bytes,\n * because the baseline has to be the last moment the page *said* what the pin\n * recorded. A commit where the pinned sentence merely sits somewhere inside\n * the anchor is not that moment, and taking it as the baseline would let a\n * sentence added beside the claim pass condition 2 (0053 stress test 5).\n * `claimEnd` already knows today's anchor rule, the rule PR #43 replaced, and\n * 0054's joined unit, so all three read here.\n */\nfunction anchorHeldAt(input: ClaimHistoryInput, then: ThenPage): FoundAt {\n const pin = input.entry.citation.claim?.integrity;\n if (pin === undefined) return { kind: \"absent\" };\n const was: PageCitation = {\n citation: input.entry.citation,\n origin: input.entry.origin,\n ...(then.marker === undefined ? {} : { marker: then.marker }),\n };\n const split =\n then.marker === undefined\n ? undefined\n : misplacedMarkerAt(then.page, then.lines, then.marker.line, was);\n const end = claimEnd(then.page, was, then.lines, split);\n if (end === null || (end.status !== \"current\" && end.status !== \"moved\")) {\n return { kind: \"absent\" };\n }\n // Which of the two specs held depends on the anchor and the status, so the\n // pin says: it is the one it matches.\n for (const spec of [end.fileLines, end.newFileLines]) {\n const span = spec === undefined ? undefined : parseLines(spec);\n if (span !== undefined && pinOf(then.lines, span) === pin) {\n return { kind: \"found\", span, lines: then.lines.slice(span.start - 1, span.end) };\n }\n }\n // 0054's case: the pin covered the paragraph a misplaced marker splits,\n // whose lines are not one span.\n if (split !== undefined) {\n const text = unitText(then.lines, split);\n if (hashLines(text.join(\"\\n\")) === pin) {\n return { kind: \"found\", span: movedUnit(split), lines: text };\n }\n }\n return { kind: \"absent\" };\n}\n\n/**\n * The bounded window search, for a marker-anchored pin minted under an anchor\n * rule the tool no longer models. The window runs from the marker to the next\n * blank line or fence, the add rule's own anchor window. A span starts on the\n * marker's line, or on any non-blank, non-marker line inside the window, and\n * ends at or before the window's last line. Only a walk that found no commit\n * where the anchor held asks this, so a wider span never outranks an anchor.\n */\nfunction windowHeldAt(input: ClaimHistoryInput, then: ThenPage): FoundAt {\n const pin = input.entry.citation.claim?.integrity;\n const marker = then.marker;\n if (pin === undefined || marker === undefined) return { kind: \"absent\" };\n if (input.entry.citation.quote === true) return { kind: \"absent\" };\n const lines = then.lines;\n let stop = marker.line;\n for (let n = marker.line + 1; n <= lines.length; n++) {\n if (bounds(lines[n - 1])) break;\n stop = n;\n }\n const starts = [marker.line];\n for (let n = marker.line + 1; n <= stop; n++) {\n const line = lines[n - 1] ?? \"\";\n if (line.trim() === \"\" || isMarkerLine(line, then.page.format)) continue;\n starts.push(n);\n }\n for (const start of starts) {\n for (let end = start; end <= stop; end++) {\n if (pinOf(lines, { start, end }) === pin) {\n return { kind: \"found\", span: { start, end }, lines: lines.slice(start - 1, end) };\n }\n }\n }\n return { kind: \"absent\" };\n}\n\n/**\n * Whether the entry is still written down at a commit, which is how the walk\n * knows it has not passed the entry's birth.\n *\n * A manifest-owned entry is asked of the manifest at the path the current\n * config declares. Absent there means no baseline, which is a plainer verdict\n * rather than a wrong one, so the walk stops.\n *\n * A frontmatter entry is asked of the page. A page without the pin is *not*\n * a stop, because either side of a merge is a lineage the other's pins never\n * reached. It only records that the walk saw a page born without the entry.\n */\nasync function stillWritten(\n input: ClaimHistoryInput,\n commit: string,\n pageText: string,\n): Promise<{ stop: boolean; born: boolean }> {\n const pin = input.entry.citation.claim?.integrity;\n if (pin === undefined) return { stop: true, born: true };\n const manifest = input.manifest;\n if (manifest !== undefined) {\n const shown = await input.git.showFile(commit, manifest);\n const held = \"text\" in shown && shown.text.includes(pin);\n return { stop: !held, born: !held };\n }\n const held = pageText.includes(pin);\n return { stop: false, born: !held };\n}\n\n/**\n * The newest commit whose page held the pin, and what it held. Walks the\n * commits that touched the page, newest first, stopping at the entry's birth\n * and at the cap.\n */\nexport async function claimHistory(input: ClaimHistoryInput): Promise<ClaimHistory> {\n const { git, path } = input;\n if (git.pageCommits === undefined) return { kind: \"none\" };\n if (!(await git.available())) return { kind: \"none\" };\n const cap = input.cap ?? MAX_PAGE_COMMITS;\n const history = await git.pageCommits(path, cap);\n const { commits } = history;\n if (commits.length === 0) return { kind: \"none\" };\n\n const format = input.page.format;\n const baselineAt = (index: number, then: ThenPage, found: FoundAt): ClaimHistory => {\n if (found.kind !== \"found\") return { kind: \"none\" };\n const commit = commits[index];\n if (commit === undefined) return { kind: \"none\" };\n return {\n kind: \"baseline\",\n commit: commit.sha,\n commitsSince: commits.slice(0, index).map((c) => c.subject),\n words: claimWords(found.lines, format),\n pageWords: claimWords(then.lines.slice(then.page.bodyLine - 1), format),\n lines: found.lines,\n at: spellLines(found.span),\n };\n };\n\n /** The pages the walk read, so the fallback search does not re-read them. */\n const examined: ThenPage[] = [];\n let ended: \"birth\" | \"unavailable\" | \"cap\" = \"cap\";\n /** Whether any commit the walk read was older than the entry. */\n let born = false;\n for (let i = 0; i < commits.length; i++) {\n const commit = commits[i];\n if (commit === undefined) continue;\n const shown = await git.showFile(commit.sha, path);\n if (!(\"text\" in shown)) {\n // A commit git cannot show is a shallow boundary; a path absent there\n // is the page's own birth.\n ended = shown.missing === \"commit\" ? \"unavailable\" : \"birth\";\n break;\n }\n const then = readThen(input, shown.text);\n if (then === undefined) {\n ended = \"birth\";\n break;\n }\n examined.push(then);\n const found = anchorHeldAt(input, then);\n if (found.kind === \"found\") return baselineAt(i, then, found);\n const written = await stillWritten(input, commit.sha, shown.text);\n if (written.born) born = true;\n if (written.stop) {\n ended = \"birth\";\n break;\n }\n }\n\n // No commit held the pin at its anchor. A pin minted under an anchor rule\n // the tool no longer models still deserves a baseline, so the bounded\n // window search reads the same pages once.\n for (const [i, then] of examined.entries()) {\n const found = windowHeldAt(input, then);\n if (found.kind === \"found\") return baselineAt(i, then, found);\n }\n\n // Only a walk that reached the entry's birth can say the pin never held; a\n // cut-short one says the history is not all there. A walk that read a page\n // the entry was not on yet has reached that birth, wherever in the list it\n // sat, which is what `born` records.\n if (ended === \"birth\" || born) return { kind: \"none\" };\n if (ended === \"unavailable\") return { kind: \"unavailable\" };\n return history.truncated || history.shallow ? { kind: \"unavailable\" } : { kind: \"none\" };\n}\n\n/** A unified diff of the claim's lines, from the baseline to now, with file-line labels. */\nexport function claimDiff(input: {\n file: string;\n commit: string;\n was: { at: string; lines: readonly string[] };\n now: { at: string; lines: readonly string[] };\n}): string {\n const a = input.was.lines;\n const b = input.now.lines;\n let head = 0;\n while (head < a.length && head < b.length && a[head] === b[head]) head++;\n let tail = 0;\n while (\n tail < a.length - head &&\n tail < b.length - head &&\n a[a.length - 1 - tail] === b[b.length - 1 - tail]\n ) {\n tail++;\n }\n const out = [\n `--- ${input.file}@${shortCommit(input.commit)}:${input.was.at}`,\n `+++ ${input.file}:${input.now.at}`,\n ];\n for (const line of a.slice(0, head)) out.push(` ${line}`);\n for (const line of a.slice(head, a.length - tail)) out.push(`-${line}`);\n for (const line of b.slice(head, b.length - tail)) out.push(`+${line}`);\n for (const line of a.slice(a.length - tail)) out.push(` ${line}`);\n return out.join(\"\\n\");\n}\n\n/** What `refineClaim` needs beyond the history it was given. */\nexport interface RefineClaimInput extends Omit<ClaimHistoryInput, \"git\" | \"cap\"> {\n /** The page now, under the hashing rule. */\n lines: readonly string[];\n history: ClaimHistory;\n}\n\n/**\n * The claim end the words test leaves: `reanchored` where only the layout\n * moved, `moved-ambiguous` where the claim's words now sit in several runs,\n * and `changed` with its baseline otherwise.\n */\nexport function refineClaim(input: RefineClaimInput): ClaimEnd {\n const { claim, history, entry, page, lines } = input;\n if (history.kind === \"unavailable\") return { ...claim, historyAvailable: false };\n if (history.kind === \"none\") return claim;\n const format = page.format;\n const base: ClaimEnd = {\n ...claim,\n commitSha: history.commit,\n historyAvailable: true,\n commitsSince: history.commitsSince,\n baselineText: history.lines,\n };\n // The diff is attached whenever there is a baseline, as the source end's\n // is. `pretty` prints it under `--show-diff`, and no other reporter reads it.\n const withDiff = (end: ClaimEnd, now: { at: string; lines: readonly string[] }): ClaimEnd => {\n const diff = claimDiff({\n file: page.file,\n commit: history.commit,\n was: { at: history.at, lines: history.lines },\n now,\n });\n return { ...end, diff };\n };\n\n // A quote pins source code inside a fence, where collapsing whitespace\n // would hide a real change. So its words test is equality on the lines the\n // hashing rule reads, with only marker lines dropped.\n if (entry.citation.quote === true) {\n const now = claim.text ?? [];\n const same =\n stripMarkers(now, format).join(\"\\n\") === stripMarkers(history.lines, format).join(\"\\n\");\n const at = claim.fileLines ?? history.at;\n return withDiff(same ? { ...base, status: \"reanchored\" } : base, { at, lines: now });\n }\n\n // A marker travels with its text, so the span it anchors now is the claim.\n if (entry.citation.claim?.lines === undefined) {\n const now = claim.text ?? [];\n const w1 = claimWords(now, format);\n const at = claim.fileLines ?? history.at;\n const held = holdsWords(w1, history.words) && holdsWords(history.pageWords, w1);\n return withDiff(held ? { ...base, status: \"reanchored\" } : base, { at, lines: now });\n }\n\n const runs = runsHolding(lines, format, page.bodyLine, history.words);\n const [only] = runs;\n if (runs.length > 1) {\n return {\n ...claim,\n status: \"moved-ambiguous\",\n candidates: runs.map((span) => spellLines(toBodyLines(span, page.bodyLine))),\n candidateFileLines: runs.map(spellLines),\n };\n }\n if (only === undefined) {\n return withDiff(base, { at: claim.fileLines ?? history.at, lines: claim.text ?? [] });\n }\n const now = lines.slice(only.start - 1, only.end);\n const w1 = claimWords(now, format);\n if (!holdsWords(history.pageWords, w1)) {\n return withDiff(base, { at: claim.fileLines ?? history.at, lines: claim.text ?? [] });\n }\n return withDiff(\n {\n ...base,\n status: \"reanchored\",\n newLines: spellLines(toBodyLines(only, page.bodyLine)),\n newFileLines: spellLines(only),\n },\n { at: spellLines(only), lines: now },\n );\n}\n","/**\n * Source-side classification of one citation.\n *\n * current: the range hashes to the pin. moved / moved-ambiguous: a window of\n * the same length hashes equal elsewhere (once / more than once); whole-file\n * citations never move. changed: none equal; with a commit and history,\n * the diff and commit subjects are attached (pretty-only). never-true: no\n * window of the range's length anywhere in the file at the commit hashes to\n * the pin, or the path is absent there. The recorded lines are tried first;\n * the rest of the file is searched because `update` rewrites `src` for a move\n * without touching `commit`, so the lines a pin was minted from may sit\n * elsewhere in the file as it was then. A window that matches there is the\n * original for the move search below. missing: the source cannot be read.\n *\n * Move search: with the original text (git could show the commit), candidate\n * offsets are where the first line matches, compared lexically, hashed only on\n * a full match. Without it, a ±2000-line window around the original position\n * first, then the rest of the file under a 64 MiB hashing budget; past the\n * budget the result is `changed` with `truncatedSearch`.\n *\n * Order, as the ladder has it: the move search runs whenever the pin does not\n * hold, and history decides only what a non-match is called. So a pin that\n * never held at its commit but whose bytes sit elsewhere in the file is\n * `moved`, not `never-true`; the search sees the file as it is.\n *\n * Proposal 0055 widens that in two directions, both gated on the original\n * text. A pin that holds nowhere in its own file is looked for in every file\n * that changed in committed history since its commit, so a rename is `moved`\n * with a new path rather than `missing`. And a `changed` end is bracketed by\n * its old first and last line, so the finding names the span they cover now\n * and `update --accept` re-mints there rather than over a stale range. The\n * 64 MiB budget is one counter per citation, spent in ladder order by every\n * search that settles it.\n */\nimport type {\n GitClient,\n PageCitation,\n PageLines,\n SourceEnd,\n SourceIndex,\n SourceRange,\n} from \"../types.js\";\nimport {\n MAX_RANGE_LINES,\n MOVE_BUDGET_BYTES,\n findWindows,\n type FindWindowsOptions,\n type SearchBudget,\n} from \"../../shared/pin.js\";\nimport { hashLines, sliceLines, splitLines } from \"./hash.js\";\nimport { formatSrc, lineSpec, sourceRange, spellSource } from \"./range.js\";\nimport { encryptSourcePath, readSource, readTracked, resolveSourcePath } from \"./sources.js\";\n\n// The move search is the shared pin engine's; this path keeps cite's imports working.\nexport { MAX_RANGE_LINES, MOVE_BUDGET_BYTES, MOVE_WINDOW_LINES, findWindows } from \"../../shared/pin.js\";\nexport type { FindWindowsOptions } from \"../../shared/pin.js\";\n\nexport interface ClassifyOptions {\n root: string;\n index: SourceIndex;\n /** History is read through it when it reports git available, and never otherwise. */\n git: GitClient;\n /** The encryption key: decrypts an encrypted source and keys its pin. */\n key?: string;\n /** Hashing budget for the blind move search, in bytes. Default `MOVE_BUDGET_BYTES`. */\n budget?: number;\n}\n\n/**\n * What git could say about the pin at the recorded commit. `unknown` is a\n * file at the commit too large to search under the budget with the pin found\n * nowhere in the part that was: neither true nor never true. `original`\n * carries the cited lines as they were then, which `reencryptCitations` re-keys\n * from when the pin no longer holds today.\n */\nexport type History =\n | { kind: \"none\" }\n | { kind: \"unavailable\" }\n | { kind: \"never-true\" }\n | { kind: \"unknown\" }\n | { kind: \"original\"; lines: string[] };\n\nexport async function historyOf(\n git: GitClient,\n commit: string,\n path: string,\n range: SourceRange,\n pin: string,\n key: string | undefined,\n budget: number | undefined,\n counter?: SearchBudget,\n): Promise<History> {\n const shown = await git.showFile(commit, path);\n if (\"missing\" in shown) {\n return shown.missing === \"commit\" ? { kind: \"unavailable\" } : { kind: \"never-true\" };\n }\n const then = splitLines(shown.text);\n let joined: string | undefined;\n try {\n joined = sliceLines(then, range);\n } catch {\n // The range ran past the end of the file as it was at the commit.\n joined = undefined;\n }\n if (joined !== undefined && hashLines(joined, key) === pin) {\n return { kind: \"original\", lines: joined.split(\"\\n\") };\n }\n\n // Not at the recorded lines. An entry can carry a `commit` older than its\n // `lines`: one pinned by hand, or one an `update` before this rule\n // re-anchored without advancing the commit. So the lines the pin was minted\n // from may sit elsewhere in the file as it was then. Only a pin found\n // nowhere there never held. A whole-file pin has nowhere else to be.\n if (range.start === undefined) return { kind: \"never-true\" };\n const length = (range.end ?? range.start) - range.start + 1;\n const search: FindWindowsOptions = { around: range.start };\n if (budget !== undefined) search.budget = budget;\n if (counter !== undefined) search.counter = counter;\n const found = findWindows(then, length, pin, key, search);\n const [first] = found.starts;\n if (first !== undefined) {\n return { kind: \"original\", lines: then.slice(first - 1, first - 1 + length) };\n }\n return found.truncated ? { kind: \"unknown\" } : { kind: \"never-true\" };\n}\n\n/** One window that hashes to the pin, at the file it was found in. */\nexport interface CrossFileHit {\n path: string;\n /** 1-based start line in that file. */\n start: number;\n}\n\n/**\n * Every file a commit touched that holds the pinned lines. The candidate list\n * is `git diff --name-only <commit> HEAD`, so it is committed changes only;\n * the entry's own file is dropped because the in-file search covered it, and a\n * path the tracked-file index does not hold is dropped exactly as a cited path\n * would be. The bytes come from the working tree, as every other source read\n * does. Each candidate costs its own bytes against the citation's counter, and\n * the `original` lines take `findWindows` down its filtered path, which hashes\n * only a start line whose text already matches.\n */\nexport async function followAcross(\n ask: {\n git: GitClient;\n root: string;\n index: SourceIndex;\n commit: string;\n /** The entry's own path, already searched. */\n own: string;\n pin: string;\n key: string | undefined;\n /** The pinned lines as they were at the commit: the window's length and its filter. */\n original: readonly string[];\n },\n counter: SearchBudget,\n): Promise<{ hits: CrossFileHit[]; truncated: boolean }> {\n const hits: CrossFileHit[] = [];\n const length = ask.original.length;\n if (length < 1 || ask.git.changedSince === undefined) return { hits, truncated: false };\n // Git prints the diff sorted by path, so a search that stops early stops at\n // the same place twice.\n const candidates = (await ask.git.changedSince(ask.commit)).filter(\n (path) => path !== ask.own && ask.index.has(path),\n );\n for (const path of candidates) {\n const text = await readTracked(ask.root, path);\n // A deletion the diff named, a permission error, or a file that went away\n // between the diff and the read: skipped, never an operational error.\n if (text === undefined) continue;\n const bytes = Buffer.byteLength(text, \"utf8\");\n if (bytes > counter.left) return { hits, truncated: true };\n counter.left -= bytes;\n const found = findWindows(splitLines(text), length, ask.pin, ask.key, {\n original: ask.original,\n });\n for (const start of found.starts) hits.push({ path, start });\n }\n return { hits, truncated: false };\n}\n\n/**\n * The span the pinned range's old first and last line cover in the file as it\n * stands: each must sit exactly once, the last at or after the first, and the\n * span no wider than `MAX_RANGE_LINES`, so an accepted span is never a range\n * the schema refuses. Undefined when any of those fails, which leaves the\n * finding exactly what it is without this search.\n */\nexport function spanOf(\n lines: readonly string[],\n original: readonly string[],\n): PageLines | undefined {\n const first = original[0];\n const last = original[original.length - 1];\n if (first === undefined || last === undefined) return undefined;\n const at = onlyLine(lines, first);\n if (at === undefined) return undefined;\n // A one-line pin's first and last line are the same line, so one occurrence\n // serves both ends and the span is that line.\n const to = original.length === 1 ? at : onlyLine(lines, last);\n if (to === undefined || to < at || to - at + 1 > MAX_RANGE_LINES) return undefined;\n return { start: at, end: to };\n}\n\n/** The 1-based line holding exactly this text, or undefined for none or several. */\nfunction onlyLine(lines: readonly string[], text: string): number | undefined {\n let at: number | undefined;\n for (let i = 0; i < lines.length; i++) {\n if (lines[i] !== text) continue;\n if (at !== undefined) return undefined;\n at = i + 1;\n }\n return at;\n}\n\nexport async function classifyCitation(\n entry: PageCitation,\n opts: ClassifyOptions,\n): Promise<SourceEnd> {\n const { citation } = entry;\n const range = sourceRange(citation.source);\n const commit = citation.source[\"commit-sha\"];\n const result: SourceEnd = { src: spellSource(citation.source), status: \"missing\" };\n if (commit !== undefined) result.commitSha = commit;\n\n // A source whose path will not resolve at all names no file to search from,\n // so its verdict is settled here as it always was.\n const resolved = resolveSourcePath(range, opts.key);\n if (\"reason\" in resolved) {\n result.missingReason = resolved.reason;\n return result;\n }\n const path = resolved.path;\n\n // Only an encrypted source carries a keyed pin, and reading one needed the key.\n const key = range.encrypted ? opts.key : undefined;\n const pin = citation.source.integrity;\n\n // The path may be gone, which is a verdict that now waits: `git show` reads\n // the file at the recorded commit rather than from disk, so a rename is\n // still answerable.\n const source = await readSource(opts.root, opts.index, range, opts.key);\n const lines = source.kind === \"ok\" ? splitLines(source.text) : undefined;\n if (source.kind === \"missing\") result.missingReason = source.reason;\n else result.resolvedPath = source.resolvedPath;\n\n if (lines !== undefined) {\n let here: string | undefined;\n try {\n here = hashLines(sliceLines(lines, range), key);\n } catch {\n // The range runs past the end of the file: nothing to compare, so it is\n // `changed`, and the search below has no window of that length to find.\n here = undefined;\n }\n if (here === pin) {\n result.status = \"current\";\n return result;\n }\n }\n\n // One counter for this citation, spent in ladder order by every search below.\n const counter: SearchBudget = { left: opts.budget ?? MOVE_BUDGET_BYTES };\n\n let history: History = { kind: \"none\" };\n if (commit !== undefined && (await opts.git.available())) {\n history = await historyOf(opts.git, commit, path, range, pin, key, opts.budget, counter);\n }\n const original = history.kind === \"original\" ? history.lines : undefined;\n\n /** The new source as the entry spells sources: a ciphertext stays one. */\n const spellAt = (at: string, start?: number, end?: number): string => {\n const written = range.encrypted && opts.key !== undefined ? encryptSourcePath(at, opts.key) : at;\n return formatSrc({ path: written, encrypted: range.encrypted, ...(start === undefined ? {} : { start, end }) });\n };\n\n // A whole-file pin has nowhere to move to inside its file.\n if (lines !== undefined && range.start !== undefined) {\n const start = range.start;\n const end = range.end ?? start;\n const search: FindWindowsOptions = { around: start, counter };\n if (original !== undefined) search.original = original;\n const found = findWindows(lines, end - start + 1, pin, key, search);\n if (found.truncated) result.truncatedSearch = true;\n // The file is the entry's own, so it is spelled as the entry spelled it.\n const spell = (at: number): string =>\n formatSrc({ ...range, start: at, end: at + (end - start) });\n const [only] = found.starts;\n if (found.starts.length === 1 && only !== undefined) {\n result.status = \"moved\";\n result.newSrc = spell(only);\n result.newLines = String(lineSpec({ start: only, end: only + (end - start) }));\n if (range.encrypted) result.resolvedNewPath = path;\n return result;\n }\n if (found.starts.length > 1) {\n result.status = \"moved-ambiguous\";\n result.candidates = found.starts.map(spell);\n return result;\n }\n }\n\n // The pin holds nowhere in its own file. Every file the commit touched is\n // asked the same question, and a hit is a move whatever else is true of the\n // old range.\n if (commit !== undefined && original !== undefined) {\n const across = await followAcross(\n { git: opts.git, root: opts.root, index: opts.index, commit, own: path, pin, key, original },\n counter,\n );\n if (across.truncated) {\n result.truncatedSearch = true;\n result.truncatedAcross = true;\n }\n const width = range.start === undefined ? undefined : original.length - 1;\n const spell = (hit: CrossFileHit): string =>\n width === undefined ? spellAt(hit.path) : spellAt(hit.path, hit.start, hit.start + width);\n // This is the one place a source whose path would not read settles as\n // something other than `missing`. A reason was recorded because the old\n // path was gone; the verdict is no longer `missing`, so it does not\n // travel with it.\n if (across.hits.length > 0) delete result.missingReason;\n const [only] = across.hits;\n if (across.hits.length === 1 && only !== undefined) {\n result.status = \"moved\";\n result.newSrc = spell(only);\n if (width !== undefined) {\n result.newLines = String(lineSpec({ start: only.start, end: only.start + width }));\n }\n if (range.encrypted) result.resolvedNewPath = only.path;\n return result;\n }\n if (across.hits.length > 1) {\n result.status = \"moved-ambiguous\";\n result.candidates = across.hits.map(spell);\n return result;\n }\n }\n\n // The path is gone and the pin is nowhere a commit touched.\n if (lines === undefined) return result;\n\n if (history.kind === \"never-true\") {\n result.status = \"never-true\";\n return result;\n }\n result.status = \"changed\";\n if (history.kind === \"unavailable\") result.historyAvailable = false;\n if (history.kind === \"unknown\") result.truncatedSearch = true;\n if (original !== undefined && commit !== undefined) {\n result.historyAvailable = true;\n result.commitsSince = await opts.git.subjectsSince(commit, path);\n result.diff = await opts.git.diffSince(commit, path);\n // Where the old first and last line sit now. The content between them did\n // change, so the status stands; what the span buys is a diff and an\n // `--accept` over the lines the sentence rests on.\n //\n // A whole-file pin is left out for the reason it never moves inside its\n // own file: it has no range, so it has nothing to grow. Its `original` is\n // the whole file as it was, whose first and last line usually do still sit\n // once each, so without this guard it would gain a `source.lines` it never\n // had and `--accept` would quietly narrow the citation to a range.\n const span = range.start === undefined ? undefined : spanOf(lines, original);\n if (span !== undefined) result.newLines = String(lineSpec(span));\n }\n return result;\n}\n","/**\n * Moving claim lines when a marker line comes or goes.\n *\n * `add --marker` inserts one line above a paragraph; `remove` deletes the\n * marker lines of the entries it takes out. Either way the claims below the\n * change have to move with the text they pin, in the same write, or the next\n * check reports a page nobody edited. One rule decides both directions, so\n * the two commands cannot disagree about which entries move.\n *\n * A change that lands *inside* a claim's own lines is not a move: it would\n * change what the pin covers. That is a refusal, and nothing is written.\n */\nimport { CiteError } from \"../errors.js\";\nimport type { LineSpec, PageCitation } from \"../types.js\";\nimport { toFileLines } from \"./claims.js\";\nimport { lineSpec, parseLines } from \"./range.js\";\nimport { spellAt } from \"./spell.js\";\n\n/** The new `claim.lines` of each entry the change moves, by where the entry lives. */\nexport interface Shifted {\n frontmatter: { index: number; lines: LineSpec }[];\n manifest: Map<number, LineSpec>;\n}\n\nexport interface ShiftOptions {\n /** The entries to move: on a removal, the ones that survive it. */\n citations: readonly PageCitation[];\n /** File lines where a marker line is inserted, or where one is removed. */\n at: readonly number[];\n /** `1` for lines coming in, `-1` for lines going out. */\n delta: 1 | -1;\n /** File line of body line 1, since `claim.lines` count the body. */\n bodyLine: number;\n /** The page as the run reports it, for the refusal. */\n label: string;\n}\n\n/**\n * The entries whose claim lines move, each by however many of `at` sit above\n * them. An insertion at a claim's first line pushes the whole claim down; a\n * removal of that line is inside the claim instead, because the line is the\n * claim's own. Hence the two comparisons.\n */\nexport function shiftedEntries(opts: ShiftOptions): Shifted {\n const { citations, at, delta, bodyLine, label } = opts;\n const out: Shifted = { frontmatter: [], manifest: new Map() };\n if (at.length === 0) return out;\n for (const { citation, origin } of citations) {\n const spec = citation.claim?.lines;\n const recorded = spec === undefined ? undefined : parseLines(spec);\n if (recorded === undefined) continue;\n const file = toFileLines(recorded, bodyLine);\n const inside = at.find((line) =>\n delta === 1\n ? line > file.start && line <= file.end\n : line >= file.start && line <= file.end,\n );\n if (inside !== undefined) {\n const whose =\n citation.id === undefined\n ? `the claim at ${spellAt(file)}`\n : `the claim of ${citation.id} (${spellAt(file)})`;\n const why =\n delta === 1\n ? \"A marker there would change its pin.\"\n : \"Removing the marker there would change its pin.\";\n throw new CiteError(`${label}:${String(inside)} is inside ${whose}. ${why}`);\n }\n const lines = at.filter((line) => (delta === 1 ? line <= file.start : line < file.start)).length;\n if (lines === 0) continue;\n const moved = lineSpec({\n start: recorded.start + lines * delta,\n end: recorded.end + lines * delta,\n });\n if (origin.kind === \"manifest\") out.manifest.set(origin.index, moved);\n else out.frontmatter.push({ index: origin.index, lines: moved });\n }\n return out;\n}\n\n/** A copy of a manifest entry with its `claim.lines` replaced. */\nexport function withClaimLines(entry: unknown, lines: LineSpec): unknown {\n if (typeof entry !== \"object\" || entry === null || Array.isArray(entry)) return entry;\n const claim: unknown = (entry as Record<string, unknown>).claim;\n if (typeof claim !== \"object\" || claim === null || Array.isArray(claim)) return entry;\n return { ...entry, claim: { ...claim, lines } };\n}\n","/**\n * Citations kept outside the page, in an external-metadata manifest a\n * collection declares (proposal 0037, and 0044's \"the sidecar is external\n * metadata\"). No `cite:` key turns this on: a collection whose\n * `externalMetadata:` owns `citations` keeps its pages' entries there.\n *\n * Reading is meta's merge, not a second loader. `loadCitationSidecars` loads\n * every manifest that owns `citations`, and `forPage` merges one page through\n * `mergeExternalMetadata`, so the join rules, the ownership rules and the\n * per-item lines are the ones `meta validate` already applies.\n *\n * Three things are cite's own, because cite *writes* manifests where meta\n * only reads them:\n *\n * - **Membership is decided by every declared collection**, not by the ones\n * `--collection` or the positional paths selected. A page named by path is\n * still a member of the collection that contains it, and its citations are\n * still in that collection's manifest; a run that read frontmatter instead\n * would report every entry as missing and then write a second copy.\n * - **A URL manifest may not own `citations`** (exit 2). cite writes them,\n * and a URL is not somewhere to write; it would also put a private\n * `source.file` in public CI output. A URL manifest with no `keys`\n * (proposal 0068) is refused for the pages whose schemas give it them.\n * - **A page whose collections own `citations` twice is refused** (exit 2),\n * even before either manifest has an entry for it: a writer has to know\n * which file to write to, and picking one would be the tiebreak 0020\n * refuses.\n *\n * `--no-config` never reaches here: with no config there are no collections,\n * so a page's citations are its frontmatter's.\n */\nimport { existsSync } from \"node:fs\";\nimport { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { configMarks, gitIgnored, mergeWithMarks, type PageMarks } from \"../../meta/internal.js\";\nimport {\n classifyRef,\n externalMetadataJoin,\n loadExternalMetadata,\n memberOf,\n orphanEntries,\n orphanError,\n orphanJoins,\n PATH_JOIN,\n type CollectionConfig,\n type ExternalMetadataConfig,\n type ExternalMetadataEntry,\n type ExternalMetadataIndex,\n type ExternalMetadataJoin,\n type ExtractedMetadata,\n} from \"../../meta/index.js\";\nimport { hasPagePlaceholder, pageManifestPath } from \"../../shared/page-manifest.js\";\nimport { ownsKey } from \"../../shared/collections.js\";\nimport { CiteError } from \"../errors.js\";\nimport type { CitationInput, CiteRun } from \"../types.js\";\nimport { pickExtractor } from \"./page.js\";\n\n/** The one key cite keeps in a manifest. */\nexport const CITATIONS_KEY = \"citations\";\n\nconst toPosix = (path: string): string => path.split(sep).join(\"/\");\n\n/** How a run spells a manifest: relative to its base, posix, like every file label. */\nfunction reportedPath(abs: string, base: string): string {\n const rel = relative(base, abs);\n return rel === \"\" ? \".\" : toPosix(rel);\n}\n\n/** A manifest that owns `citations` for one collection. */\nexport interface CitationManifest {\n /** The collection that declares it. */\n collection: string;\n /** Absolute path of the manifest file. */\n path: string;\n /** The manifest as the run reports it. */\n file: string;\n /** `path`, or the page field the manifest joins on. */\n join: string;\n /**\n * The `{page}` pattern as the config writes it (proposal 0058), present\n * only when each page has a manifest of its own. The page's file is\n * resolved from it, and one that does not exist yet reads as empty and is\n * created by the first write.\n */\n pattern?: string;\n /**\n * The manifest names no `keys` (proposal 0068), so it keeps a page's\n * citations only when the page's schemas mark `citations` external. The\n * declaration, for `ownsKey`.\n */\n implied?: { collection: CollectionConfig; manifest: ExternalMetadataConfig };\n}\n\n/** Where one page's citations are kept, and what the manifest already holds. */\nexport interface PageSidecar {\n /** The manifest that owns this page's citations, when one does. */\n owner?: CitationManifest;\n /**\n * The key under which this page is written in the manifest: its path\n * relative to the config directory, or its value of the join field.\n * Undefined when the manifest joins on a field the page does not carry, so\n * a writer refuses rather than inventing a key.\n */\n entry?: string;\n /** The manifest's entries for this page, when it supplies any. */\n citations?: CitationInput[];\n /** Field-joined entries this page matched, for the duplicate-join check. */\n joins: readonly ExternalMetadataJoin[];\n}\n\nexport interface CitationSidecars {\n /** The manifests that own `citations`, by collection. */\n manifests: readonly CitationManifest[];\n /** Directory manifest paths and manifest keys resolve from. */\n configDir: string;\n /** Directory the run's file labels are relative to. */\n base: string;\n forPage(label: string, content: string, format?: string): Promise<PageSidecar>;\n /**\n * Manifest entries naming a page this run did not load, under meta's own\n * corpus invariant. `covered` names the collections a `--collection` run\n * narrowed to, or `undefined` for a whole-corpus run.\n */\n orphans(loaded: readonly string[], covered?: readonly string[]): ExternalMetadataEntry[];\n /** Field entries no loaded page matched, same invariant. */\n orphanJoins(\n matched: ReadonlyMap<string, ReadonlySet<string>>,\n covered?: readonly string[],\n ): ExternalMetadataEntry[];\n /**\n * The `{page}` manifests (proposal 0058) of the loaded pages that exist and\n * that `.gitignore` covers, as the run reports them. A checkout would have\n * none of them, so CI would read those pages as citing nothing.\n */\n ignoredManifests(loaded: readonly string[]): Promise<string[]>;\n}\n\nexport interface LoadSidecarOptions {\n /** Every collection the config declares, not only the ones the run selected. */\n collections: readonly CollectionConfig[];\n /** The config file's directory. */\n configDir: string;\n /** Directory the run's file labels are relative to. */\n base: string;\n /** The config file as the user would name it, for the URL refusal. */\n configSource: string;\n /**\n * The run's pages, as absolute paths. A `{page}` manifest (proposal 0058)\n * is read for exactly these; without them it reads nothing.\n */\n pages?: readonly string[];\n /** The family encryption key, for a join field a page holds encrypted. */\n key?: string;\n /** The tool's error class; `CiteError` unless a sibling command says otherwise. */\n toError?: (message: string) => Error;\n /**\n * What a page's schemas mark external (proposal 0068), asked only for a\n * page a manifest with no `keys` may keep citations for.\n */\n marks?: () => Promise<PageMarks | undefined>;\n}\n\n/** `collection <name>: citations cannot come from a URL manifest, because cite writes them.` */\nexport function urlManifestRefusal(source: string, collection: string): string {\n return `${source}: collection ${collection}: ${CITATIONS_KEY} cannot come from a URL manifest, because cite writes them.`;\n}\n\n/** `<page> is in collections a and b, and both keep citations in a manifest.` */\nexport function twoManifestsRefusal(label: string, a: string, b: string): string {\n return `${label} is in collections ${a} and ${b}, and both keep citations in a manifest.`;\n}\n\n/**\n * May this manifest keep `citations`? One whose `keys` name them does. One\n * with no `keys` (proposal 0068) may, for the pages whose schemas mark them\n * external, which `forPage` decides.\n */\nfunction ownsCitations(manifest: ExternalMetadataConfig): boolean {\n return manifest.keys === undefined || manifest.keys.includes(CITATIONS_KEY);\n}\n\n/** An index with no manifest in it, for a run whose only candidates are keyless URL manifests. */\nfunction emptyIndex(): ExternalMetadataIndex {\n return { owners: new Map(), byPath: new Map(), byField: new Map(), entries: [] };\n}\n\n/**\n * Load every manifest that owns `citations`, or `null` when none does — which\n * is every setup that keeps its citations in frontmatter, and costs nothing.\n *\n * Only the citations-owning manifests are loaded. A sibling manifest of the\n * same collection, supplying meta's own keys from a URL, is none of cite's\n * business and is never fetched here.\n */\nexport async function loadCitationSidecars(\n opts: LoadSidecarOptions,\n): Promise<CitationSidecars | null> {\n const toError = opts.toError ?? ((message: string): Error => new CiteError(message));\n const manifests: CitationManifest[] = [];\n /** Keyless URL manifests: never fetched, and refused for a page they would keep citations for. */\n const urls: CitationManifest[] = [];\n const scoped: CollectionConfig[] = [];\n for (const collection of opts.collections) {\n const owning = collection.externalMetadata.filter(ownsCitations);\n if (owning.length === 0) continue;\n const loaded: ExternalMetadataConfig[] = [];\n for (const manifest of owning) {\n const implied = manifest.keys === undefined ? { implied: { collection, manifest } } : {};\n if (classifyRef(manifest.file).kind === \"url\") {\n if (manifest.keys !== undefined) {\n throw toError(urlManifestRefusal(opts.configSource, collection.name));\n }\n urls.push({ collection: collection.name, path: manifest.file, file: manifest.file, join: externalMetadataJoin(manifest), ...implied });\n continue;\n }\n loaded.push(manifest);\n const path = isAbsolute(manifest.file)\n ? manifest.file\n : resolve(opts.configDir, manifest.file);\n manifests.push({\n collection: collection.name,\n path,\n file: reportedPath(path, opts.base),\n join: externalMetadataJoin(manifest),\n ...(hasPagePlaceholder(manifest.file) ? { pattern: manifest.file } : {}),\n ...implied,\n });\n }\n if (loaded.length > 0) scoped.push({ ...collection, externalMetadata: loaded });\n }\n if (manifests.length === 0 && urls.length === 0) return null;\n\n // A keyless URL manifest is never loaded, but a page it would keep\n // citations for is still refused. With no local manifest to load, an empty\n // index lets each page reach that refusal.\n const index =\n (await loadExternalMetadata(scoped, {\n configDir: opts.configDir,\n base: opts.base,\n ...(opts.pages === undefined ? {} : { pages: opts.pages }),\n })) ?? (urls.length > 0 ? emptyIndex() : null);\n if (index === null) return null;\n return sidecars(index, manifests, urls, scoped, opts);\n}\n\nfunction sidecars(\n index: ExternalMetadataIndex,\n manifests: readonly CitationManifest[],\n urls: readonly CitationManifest[],\n collections: readonly CollectionConfig[],\n opts: LoadSidecarOptions,\n): CitationSidecars {\n const toError = opts.toError ?? ((message: string): Error => new CiteError(message));\n const { configDir, base } = opts;\n let marks: Promise<PageMarks | undefined> | undefined;\n const marksOnce = (): Promise<PageMarks | undefined> => (marks ??= opts.marks?.() ?? Promise.resolve(undefined));\n\n /**\n * The manifest a page's citations live in. A concrete `file` is the one\n * manifest the collection declares. A `{page}` pattern (proposal 0058) is\n * a rule, so the page's own file is resolved from its path, and reported\n * relative to the run's base like every other manifest. Everything else\n * about the owner carries through the spread.\n */\n const pageOwner = (owner: CitationManifest, label: string): CitationManifest | undefined => {\n if (owner.pattern === undefined) return owner;\n const resolved = pageManifestPath(owner.pattern, configDir, resolve(base, label));\n // A page above the config directory is a member of nothing, so this is\n // not reached for one; the guard is for the type.\n if (\"outside\" in resolved) return undefined;\n return { ...owner, path: resolved.abs, file: reportedPath(resolved.abs, base) };\n };\n\n const forPage = async (label: string, content: string, format?: string): Promise<PageSidecar> => {\n // Membership over every declared collection: a keyless URL manifest's\n // collection may not be among the ones loaded.\n const declaredMembers = memberOf(opts.collections, configDir, base, label);\n if (declaredMembers.length === 0) return { joins: [] };\n const members = memberOf(collections, configDir, base, label);\n const memberOfCollection = (m: CitationManifest): boolean => declaredMembers.includes(m.collection);\n\n // A manifest with no keys (proposal 0068) keeps the page's citations\n // when the page's schemas mark them external, asked with them in place.\n // This asks over every declared collection, because which manifest owns\n // a page's citations is decided by all of them. The merge below asks\n // again over the collections this run loaded, for the other fields.\n let extracted: ExtractedMetadata | undefined;\n const extract = (): ExtractedMetadata => (extracted ??= pickExtractor(label, format).extract(content, label));\n const candidates = [...manifests, ...urls].filter((m) => m.implied !== undefined && memberOfCollection(m));\n let marked: ReadonlySet<string> | undefined;\n if (candidates.length > 0) {\n const read = await marksOnce();\n const data = extract().data;\n marked =\n read === undefined\n ? undefined\n : await read(label, Object.hasOwn(data, CITATIONS_KEY) ? data : { ...data, [CITATIONS_KEY]: null }, declaredMembers);\n }\n const keeps = (m: CitationManifest): boolean =>\n m.implied === undefined || ownsKey(m.implied.collection, m.implied.manifest, CITATIONS_KEY, marked);\n const url = urls.find((m) => memberOfCollection(m) && keeps(m));\n if (url !== undefined) throw toError(urlManifestRefusal(opts.configSource, url.collection));\n\n // The owning manifest is the page's, decided before any entry is read:\n // two of them is a refusal even when only one has an entry today.\n const mine = manifests.filter((m) => members.includes(m.collection) && keeps(m));\n const [declared, second] = mine;\n if (declared === undefined) return { joins: [] };\n if (second !== undefined) {\n throw toError(twoManifestsRefusal(label, declared.collection, second.collection));\n }\n const owner = pageOwner(declared, label);\n if (owner === undefined) return { joins: [] };\n\n // The merge judges every field a keyless manifest holds, not only\n // `citations`, so it reads the page's marks with those values in place,\n // as meta's own merge does.\n const readMarks = await marksOnce();\n const merged = await mergeWithMarks(label, extract(), index, members, base, {\n encryptionKey: () => opts.key,\n ...(readMarks === undefined ? {} : { marks: readMarks }),\n });\n\n const out: PageSidecar = { owner, joins: merged.joins };\n if (owner.join === PATH_JOIN) {\n out.entry = toPosix(relative(configDir, resolve(base, label)));\n } else {\n const value = merged.joins.find((j) => j.field === owner.join)?.value;\n // No match: the page's own value of the join field still keys it, so a\n // first `add` can write an entry a later run will match.\n const raw = value ?? extract().data[owner.join];\n if (typeof raw === \"string\" && raw !== \"\") out.entry = raw;\n else if (typeof raw === \"number\" || typeof raw === \"boolean\") out.entry = String(raw);\n }\n\n // The manifest supplied the key exactly when `locate` answers for it;\n // a page carrying its own `citations:` keeps them (the collision is a\n // finding, not a tiebreak), and `locate` then answers `undefined`.\n const where = merged.locate(`/${CITATIONS_KEY}`);\n if (where !== undefined) {\n const supplied: unknown = merged.extracted.data[CITATIONS_KEY];\n const list: unknown[] = Array.isArray(supplied) ? (supplied as unknown[]) : [supplied];\n out.citations = list.map((entry, i) => {\n const at = merged.locate(`/${CITATIONS_KEY}/${String(i)}`);\n const line = (Array.isArray(supplied) ? at?.line : undefined) ?? where.line;\n return {\n entry,\n origin: {\n kind: \"manifest\" as const,\n file: where.file,\n ...(line === undefined ? {} : { line }),\n },\n };\n });\n }\n return out;\n };\n\n const ignoredManifests = async (loaded: readonly string[]): Promise<string[]> => {\n const existing = new Set<string>();\n for (const label of loaded) {\n const members = memberOf(collections, configDir, base, label);\n for (const declared of manifests) {\n if (declared.pattern === undefined || !members.includes(declared.collection)) continue;\n const owner = pageOwner(declared, label);\n if (owner !== undefined && existsSync(owner.path)) existing.add(owner.file);\n }\n }\n if (existing.size === 0) return [];\n const { ignored } = await gitIgnored([...existing], base);\n return [...existing].filter((file) => ignored.has(file));\n };\n\n return {\n manifests,\n configDir,\n base,\n forPage,\n orphans: (loaded, covered) => orphanEntries(index, loaded, base, covered),\n orphanJoins: (matched, covered) => orphanJoins(index, matched, covered),\n ignoredManifests,\n };\n}\n\n/** `<manifest> is covered by .gitignore, so CI checks out a page with no citations.` */\nexport function ignoredManifestWarning(file: string): string {\n return `${file} is covered by .gitignore, so CI checks out a page with no citations.`;\n}\n\n/** The refusal a whole-corpus run raises for a manifest entry naming nothing. */\nexport function orphanRefusal(\n orphans: readonly ExternalMetadataEntry[],\n toError: (message: string) => Error = (m) => new CiteError(m),\n): Error {\n return toError(orphanError(orphans).message);\n}\n\n/**\n * Two pages carrying one `join:` value: the manifest cannot tell them apart,\n * and cite would write one page's entry over the other's. Meta files this as\n * a finding on each document; here it is the run's problem, because the run\n * writes.\n */\nexport function duplicateJoinRefusal(\n field: string,\n value: string,\n file: string,\n labels: readonly string[],\n): string {\n return `${String(labels.length)} pages carry ${field} \"${value}\"; ${file} cannot tell them apart (${labels.join(\", \")}).`;\n}\n\n/**\n * Load the sidecars a resolved run governs; `null` with no config, or no\n * citations manifest. `base` overrides the run's when a command labels its\n * pages from somewhere else — `add` takes one page from the command line and\n * labels it from the working directory, whatever the collections would.\n * `pages` are the run's pages as absolute paths, which a `{page}` manifest\n * (proposal 0058) is read for.\n */\nexport function sidecarsFor(\n run: CiteRun,\n over: {\n base?: string;\n toError?: (message: string) => Error;\n pages?: readonly string[];\n } = {},\n): Promise<CitationSidecars | null> {\n const declared = run.configFile?.collections ?? [];\n if (run.configDir === undefined || declared.length === 0) return Promise.resolve(null);\n // A const, so the narrowing below holds inside the closure.\n const { configPath } = run;\n return loadCitationSidecars({\n // Every declared collection, whatever `--collection` or the paths chose.\n collections: declared,\n configDir: run.configDir,\n base: over.base ?? run.base,\n configSource: run.configSource ?? run.configPath ?? \"the config\",\n ...(run.key === undefined ? {} : { key: run.key }),\n ...(over.toError === undefined ? {} : { toError: over.toError }),\n ...(over.pages === undefined ? {} : { pages: over.pages }),\n // A keyless manifest (proposal 0068) keeps what a page's schemas mark,\n // read from meta's section of the same file.\n ...(configPath === undefined ? {} : { marks: () => configMarks(configPath, run.base) }),\n });\n}\n","/**\n * Writing a page's `citations` into the manifest that owns them.\n *\n * The splice itself is meta's (`spliceManifestValue` on the family-internal\n * barrel): one owned value of one entry is replaced, every other byte of the\n * file survives by construction, and the result is read back before it is\n * returned. This module is the part cite owns — holding each manifest's text\n * for the length of a run so it is written once, and finding the line a\n * written entry now sits on, which is what `add` reports and what a finding\n * about an entry points at.\n *\n * Only `commit` touches the disk. A caller reads the manifests it needs and\n * writes them when the whole run has succeeded, the way `key rotate` writes\n * pages only once every one of them could be re-encrypted.\n *\n * That gap is why `commit` re-reads. A run holds a manifest from its first\n * `hold` to its last write, which is seconds of minting, hashing and git, and\n * two runs over one working copy overlap easily. The compare-and-swap that\n * makes the second write see the first is `src/shared/manifest-cas.ts`, which\n * `meta fill` and `meta derive` hold their manifests with too; what stays here\n * is what cite means by an edit, which is one entry's `citations`.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { posix } from \"node:path\";\nimport { LineCounter, isMap, isNode, isScalar, isSeq, parseDocument } from \"yaml\";\nimport { DocmetaError, writeFileAtomic } from \"../../meta/index.js\";\nimport {\n readManifestValue,\n removeManifestKey,\n spliceManifestValue,\n} from \"../../meta/internal.js\";\nimport {\n heldManifest,\n isMissing,\n rebaseable,\n settle,\n type CommitIo as CasCommitIo,\n type HeldManifest as CasHeldManifest,\n type ManifestCodec,\n type ManifestOp as CasManifestOp,\n} from \"../../shared/manifest-cas.js\";\nimport { CiteError } from \"../errors.js\";\nimport { unifiedDiff } from \"./write.js\";\nimport { CITATIONS_KEY, type CitationManifest } from \"./sidecar.js\";\n\n/** One edit this run made, replayable onto bytes read later. */\ntype ManifestOp = CasManifestOp &\n ({ kind: \"splice\"; value: unknown[] } | { kind: \"remove\" });\n\n/** One manifest held for the length of a run: its text before, and now. */\nexport type HeldManifest = CasHeldManifest<ManifestOp>;\n\n/** One recorded edit, and one `citations` value read back, over a manifest. */\nconst codec: ManifestCodec<ManifestOp> = { apply, read: readManifestValue };\n\n/** One manifest this run rewrote, as `changed()` and `commit()` report it. */\nexport interface ManifestChange {\n path: string;\n file: string;\n before: string;\n text: string;\n /**\n * `before` against `text`. A commit that rebased moves `before` to the bytes\n * it compared against, so the diff then shows what this run added on top of\n * a concurrent write rather than against the read `hold()` made.\n */\n diff: string;\n}\n\n/** What `commit()` does with each manifest it settles. */\nexport type CommitIo = CasCommitIo<ManifestChange>;\n\n/** Every manifest one run writes, read once and spliced in memory. */\nexport class ManifestSet {\n private readonly held = new Map<string, HeldManifest>();\n\n /** Read a manifest, or hand back the copy this run has already rewritten. */\n async hold(manifest: CitationManifest): Promise<HeldManifest> {\n const already = this.held.get(manifest.path);\n if (already !== undefined) return already;\n let before: string;\n let absent = false;\n try {\n before = await readFile(manifest.path, \"utf8\");\n } catch (error) {\n // A per-page manifest (proposal 0058) that does not exist yet is a page\n // with nothing cited: held as empty text marked absent, and created by\n // the commit. A missing concrete manifest is refused, as it always was.\n if (manifest.pattern === undefined || !isMissing(error)) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new CiteError(`Manifest ${manifest.file} could not be read: ${reason}`);\n }\n before = \"\";\n absent = true;\n }\n const fresh = heldManifest<ManifestOp>(manifest.path, manifest.file, before, absent);\n this.held.set(manifest.path, fresh);\n return fresh;\n }\n\n /**\n * Write one page's whole `citations` list into its entry, and answer where\n * the entry at `index` now sits. The manifest is not saved: `changed()`\n * lists what the run would write.\n */\n async write(\n manifest: CitationManifest,\n entry: string,\n citations: readonly unknown[],\n index: number,\n ): Promise<{ file: string; line: number }> {\n const held = await this.hold(manifest);\n const op: ManifestOp = {\n kind: \"splice\",\n entry,\n key: CITATIONS_KEY,\n join: manifest.join,\n file: manifest.file,\n value: [...citations],\n };\n rebaseable(held, op, codec);\n const spliced = splice(held.text, {\n entry,\n key: CITATIONS_KEY,\n value: op.value,\n join: manifest.join,\n file: manifest.file,\n });\n held.text = spliced.text;\n held.ops.push(op);\n return { file: manifest.file, line: itemLine(spliced.text, entry, index, manifest.join) ?? spliced.line };\n }\n\n /**\n * Where one item of an entry's `citations` sits in the manifest as this run\n * will write it. `add` names a line in its report, and `commit` may have\n * replayed the entry onto bytes that moved it, so the line is read back from\n * the settled text rather than kept from the splice.\n */\n lineOf(manifest: CitationManifest, entry: string, index: number): number | undefined {\n const held = this.held.get(manifest.path);\n if (held === undefined) return undefined;\n return itemLine(held.text, entry, index, manifest.join);\n }\n\n /**\n * Take a page's `citations` key out of the manifest, for the removal that\n * leaves it with no entries. The entry itself goes when that key was all it\n * had, so a manifest never keeps a document nothing is recorded about.\n */\n async remove(manifest: CitationManifest, entry: string): Promise<void> {\n const held = await this.hold(manifest);\n const op: ManifestOp = {\n kind: \"remove\",\n entry,\n key: CITATIONS_KEY,\n join: manifest.join,\n file: manifest.file,\n };\n rebaseable(held, op, codec);\n held.text = apply(held.text, op);\n held.ops.push(op);\n }\n\n /** The manifests this run rewrote, with the diff of each. */\n changed(): ManifestChange[] {\n return [...this.held.values()]\n .filter((m) => m.text !== m.before)\n .map((m) => ({ ...m, diff: unifiedDiff(m.file, m.before, m.text) }));\n }\n\n /**\n * Write every manifest this run rewrote, and report what landed.\n *\n * The write is the last thing a run does, so this is the one place that\n * knows a manifest is about to be replaced by bytes derived from a read\n * that may be seconds old.\n */\n async commit(io: CommitIo = {}): Promise<ManifestChange[]> {\n // A per-page manifest (proposal 0058) may be the first file in its directory.\n const write =\n io.write ?? ((at: string, text: string): Promise<void> => writeFileAtomic(at, text, { createParents: true }));\n const read = io.read ?? ((at: string): Promise<string> => readFile(at, \"utf8\"));\n const landed: ManifestChange[] = [];\n for (const held of this.held.values()) {\n if (held.text === held.before) continue;\n try {\n await settle(held, { codec, write, read, toError: (message) => new CiteError(message) });\n } catch (error) {\n if (io.onError !== undefined) await io.onError(changeOf(held), error);\n throw error;\n }\n const change = changeOf(held);\n landed.push(change);\n io.after?.(change);\n }\n return landed;\n }\n}\n\n/** The change one held manifest reports, against the bytes it will replace. */\nfunction changeOf(held: HeldManifest): ManifestChange {\n return {\n path: held.path,\n file: held.file,\n before: held.before,\n text: held.text,\n diff: unifiedDiff(held.file, held.before, held.text),\n };\n}\n\n/** One recorded edit, against whatever text it is handed. */\nfunction apply(text: string, op: ManifestOp): string {\n const where = { entry: op.entry, key: op.key, join: op.join, file: op.file };\n if (op.kind === \"splice\") return splice(text, { ...where, value: op.value }).text;\n try {\n return removeManifestKey(text, where).text;\n } catch (error) {\n if (error instanceof DocmetaError) throw new CiteError(error.message);\n throw error;\n }\n}\n\n/** `spliceManifestValue`, with meta's refusal reported as this tool's. */\nexport function splice(\n text: string,\n options: Parameters<typeof spliceManifestValue>[1],\n): { text: string; line: number } {\n try {\n return spliceManifestValue(text, options);\n } catch (error) {\n if (error instanceof DocmetaError) throw new CiteError(error.message);\n throw error;\n }\n}\n\n/**\n * The 1-based line of one item of an entry's `citations`, in a manifest that\n * may not have been written yet. The loader answers this for a manifest on\n * disk; a freshly spliced one has to be read where it stands, so `add` can\n * say where the entry it just wrote went.\n */\nexport function itemLine(\n text: string,\n entry: string,\n index: number,\n join: string,\n): number | undefined {\n const lc = new LineCounter();\n const doc = parseDocument(text, { lineCounter: lc, uniqueKeys: false });\n if (doc.errors.length > 0) return undefined;\n const root = doc.contents;\n if (!isMap(root)) return undefined;\n const same = (key: unknown): boolean => {\n const spelled = isScalar(key) ? String(key.value) : String(key);\n return join === \"path\" ? posix.normalize(spelled) === posix.normalize(entry) : spelled === entry;\n };\n const pair = root.items.find((p) => same(p.key));\n const value = pair?.value;\n if (!isMap(value)) return undefined;\n const kv = value.items.find(\n (p) => (isScalar(p.key) ? String(p.key.value) : String(p.key)) === CITATIONS_KEY,\n );\n const list = kv?.value;\n if (!isSeq(list)) return undefined;\n const item: unknown = list.items[index];\n const range = isNode(item) ? item.range : undefined;\n return range ? lc.linePos(range[0]).line : undefined;\n}\n","/**\n * Every way the tool rewrites a page. Frontmatter appends go through meta's\n * `applyFrontmatter` (comments and key order preserved). A repair splices one\n * scalar textually at `lineFor(\"/citations/N/source/lines\")` and the like, so\n * nothing else in the block is touched. Markers are inserted by offset with\n * the page's own EOL. Files are written with `writeFileAtomic`.\n *\n * A rewrite of the body goes through `applyEdits`: the caller collects every\n * span it means to replace against one parse and hands them over together, so\n * no position is ever read out of text that has already been written to.\n */\nimport { DocmetaError, locateFrontmatter, type MetadataExtractor } from \"../../meta/index.js\";\nimport { extractorByName } from \"../../meta/internal.js\";\nimport { CiteError } from \"../errors.js\";\nimport type { Citation, LineSpec, TextEdit } from \"../types.js\";\nimport { splitLines } from \"./hash.js\";\nimport { detectEol, lineAt, offsetOfLine } from \"./statements.js\";\n\nfunction extractorFor(format: string): MetadataExtractor {\n const extractor = extractorByName(format);\n if (!extractor) throw new CiteError(`Unknown format \"${format}\".`);\n return extractor;\n}\n\n/**\n * Whether the format reads a leading fenced block as its frontmatter. Asked\n * of the extractor itself rather than kept as a list of names here, so a\n * format added to meta's registry answers for itself. An element-backed\n * format (html, xml) sees the probe as body text and says no.\n */\nfunction readsFencedFrontmatter(extractor: MetadataExtractor, label: string): boolean {\n return extractor.extract(\"---\\nprobe: 1\\n---\\n\", label).fenced === true;\n}\n\n/** Append one entry to `citations` (creating the key), via the format's extractor. */\nexport function appendFrontmatterCitation(\n content: string,\n format: string,\n citation: Citation,\n filePath?: string,\n): string {\n const label = filePath ?? \"the page\";\n const extractor = extractorFor(format);\n // Element-backed metadata (html, xml) has `apply` too, but it is not\n // frontmatter. Whether this *page* can take a block is `apply`'s call:\n // markdown creates one, asciidoc and rst refuse when none exists.\n if (!extractor.apply || !readsFencedFrontmatter(extractor, label)) {\n throw new CiteError(\n `${label} has no frontmatter to write to; keep its citations in a manifest instead.`,\n );\n }\n const extracted = extractor.extract(content, label);\n if (locateFrontmatter(content)?.flavor === \"toml\") {\n throw new CiteError(\n `${label} has TOML frontmatter; manni cannot add a citations table without re-emitting the whole block, which would drop its comments. Add the entry by hand.`,\n );\n }\n\n const raw: unknown = extracted.data.citations ?? [];\n if (!Array.isArray(raw)) {\n throw new CiteError(`${label}: \\`citations\\` is not a list; edit it by hand.`);\n }\n // `isArray` narrows `unknown` to `any[]`; name the element type before it spreads.\n const existing: unknown[] = raw;\n const entry = entryObject(citation);\n try {\n return extractor.apply(content, { citations: [...existing, entry] });\n } catch (e) {\n if (e instanceof DocmetaError) throw new CiteError(`${label}: ${e.message}`);\n throw e;\n }\n}\n\n/**\n * Take entries out of a page's `citations`, by their index in the list, and\n * write what is left back through the format's extractor. An empty list\n * removes the key: an entry deleted by hand once left a `citations:` with\n * nothing under it, and a page that carries no citations should say so by\n * carrying no key.\n *\n * The write is the inverse of `appendFrontmatterCitation` and goes the same\n * way, so a page manni can add to is a page manni can remove from.\n */\nexport function removeFrontmatterCitations(\n content: string,\n format: string,\n drop: ReadonlySet<number>,\n filePath?: string,\n): string {\n const label = filePath ?? \"the page\";\n const extractor = extractorFor(format);\n if (!extractor.apply || !readsFencedFrontmatter(extractor, label)) {\n throw new CiteError(\n `${label} has no frontmatter to write to; keep its citations in a manifest instead.`,\n );\n }\n if (locateFrontmatter(content)?.flavor === \"toml\") {\n throw new CiteError(\n `${label} has TOML frontmatter; manni cannot rewrite a citations table without re-emitting the whole block, which would drop its comments. Remove the entry by hand.`,\n );\n }\n const raw: unknown = extractor.extract(content, label).data.citations ?? [];\n if (!Array.isArray(raw)) {\n throw new CiteError(`${label}: \\`citations\\` is not a list; edit it by hand.`);\n }\n const existing: unknown[] = raw;\n const kept = existing.filter((_entry, index) => !drop.has(index));\n try {\n return kept.length === 0\n ? extractor.apply(content, {}, { deletions: [\"citations\"] })\n : extractor.apply(content, { citations: kept });\n } catch (e) {\n if (e instanceof DocmetaError) throw new CiteError(`${label}: ${e.message}`);\n throw e;\n }\n}\n\n/**\n * `content` with every edit applied in one pass. Each edit's `start` and `end`\n * index `content` as it was handed in, never the text an earlier edit\n * produced, and that is the whole point: a caller collects its edits from one\n * parse and applies them together, so no position outlives the text it was\n * read from and the order they were collected in cannot matter.\n *\n * Edits may not overlap. Two writers reaching for the same bytes is a bug in\n * the caller rather than something to resolve here, so it throws instead of\n * picking a winner. `lineRemovals` is what keeps two neighbouring lines from\n * being that bug.\n */\nexport function applyEdits(content: string, edits: readonly TextEdit[]): string {\n const sorted = [...edits].sort((a, b) => a.start - b.start);\n let out = \"\";\n let at = 0;\n for (const edit of sorted) {\n if (edit.end < edit.start) {\n throw new Error(`cite: backwards edit [${String(edit.start)}, ${String(edit.end)})`);\n }\n if (edit.start < at) {\n throw new Error(`cite: overlapping edits at ${String(edit.start)}`);\n }\n out += content.slice(at, edit.start) + edit.text;\n at = edit.end;\n }\n return out + content.slice(at);\n}\n\n/**\n * The edits that take 1-based `lines` out of `content`, their terminators\n * included: one edit per run of consecutive lines, so two neighbours never\n * reach for the same break. Order and repeats in `lines` do not matter.\n */\nexport function lineRemovals(content: string, lines: readonly number[]): TextEdit[] {\n const sorted = [...new Set(lines)].sort((a, b) => a - b);\n const out: TextEdit[] = [];\n let run: { first: number; last: number } | undefined;\n for (const line of sorted) {\n if (run !== undefined && line === run.last + 1) run.last = line;\n else {\n if (run !== undefined) out.push(runRemoval(content, run.first, run.last));\n run = { first: line, last: line };\n }\n }\n if (run !== undefined) out.push(runRemoval(content, run.first, run.last));\n return out;\n}\n\n/** The span covering 1-based lines `first`..`last` and their terminator. */\nfunction runRemoval(content: string, first: number, last: number): TextEdit {\n let start = offsetOfLine(content, first);\n // `offsetOfLine` answers the length when asked past the end, so a run whose\n // span reaches it on a page with no final newline is the tail of the file.\n // It has no terminator below it to take, so it takes the one above: on CRLF\n // that break is two bytes, and stopping at the LF would leave the CR behind\n // as the tail of a line that is gone. `spliceEntryField` pulls back over a\n // CR for the same reason.\n const end = offsetOfLine(content, last + 1);\n if (end === content.length && !content.endsWith(\"\\n\") && start > 0) {\n let above = content.lastIndexOf(\"\\n\", start - 1);\n if (above > 0 && content.charAt(above - 1) === \"\\r\") above--;\n start = above === -1 ? 0 : above;\n }\n return { start, end, text: \"\" };\n}\n\n/** Delete the whole of 1-based `line`, its terminator included. */\nexport function removeLine(content: string, line: number): string {\n return applyEdits(content, lineRemovals(content, [line]));\n}\n\n/**\n * The entry as a plain object, in the order a reader scans it, with every\n * absent optional left out rather than written as `null`.\n */\nexport function entryObject(citation: Citation): Record<string, unknown> {\n const source: Record<string, unknown> = { file: citation.source.file };\n if (citation.source.lines !== undefined) source.lines = citation.source.lines;\n source.integrity = citation.source.integrity;\n if (citation.source[\"commit-sha\"] !== undefined) {\n source[\"commit-sha\"] = citation.source[\"commit-sha\"];\n }\n const entry: Record<string, unknown> = {};\n if (citation.id !== undefined) entry.id = citation.id;\n if (citation.claim !== undefined) {\n const claim: Record<string, unknown> = {};\n if (citation.claim.lines !== undefined) claim.lines = citation.claim.lines;\n claim.integrity = citation.claim.integrity;\n entry.claim = claim;\n }\n entry.source = source;\n if (citation.quote !== undefined) entry.quote = citation.quote;\n return entry;\n}\n\n/** Plain YAML scalars that would read back as something other than the string. */\nfunction needsYamlQuotes(value: string): boolean {\n return (\n value === \"\" ||\n /^[\\s!&*?|>'\"%@`{}[\\],#]/.test(value) ||\n /^-(\\s|$)/.test(value) ||\n /:\\s|\\s#|:$|\\s$/.test(value) ||\n /^(?:true|false|null|~|yes|no|on|off|[-+]?(?:\\d[\\d_]*\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?)$/i.test(value)\n );\n}\n\n/** `\"…\"` with the escapes YAML and JSON share. */\nconst doubleQuote = (value: string): string => JSON.stringify(value);\nconst singleQuote = (value: string): string => `'${value.replace(/'/g, \"''\")}'`;\n\n/**\n * Split a `key: value` line into its lead (` - src: `), the scalar, and what\n * trails it (a comment, a JSON comma). Undefined when the line does not carry\n * `field`.\n */\nfunction splitScalarLine(\n line: string,\n field: string,\n): { lead: string; scalar: string; trail: string } | undefined {\n const keyed = new RegExp(`^(\\\\s*(?:-\\\\s+)?\"?${field}\"?\\\\s*:\\\\s*)(.*)$`).exec(line);\n const lead = keyed?.[1];\n const rest = keyed?.[2];\n if (lead === undefined || rest === undefined) return undefined;\n const quote = rest.charAt(0);\n let end: number;\n if (quote === '\"' || quote === \"'\") {\n end = -1;\n for (let i = 1; i < rest.length; i++) {\n const ch = rest.charAt(i);\n if (quote === '\"' && ch === \"\\\\\") {\n i++;\n } else if (ch === quote) {\n if (quote === \"'\" && rest.charAt(i + 1) === \"'\") {\n i++;\n continue;\n }\n end = i + 1;\n break;\n }\n }\n if (end < 0) return undefined;\n } else {\n const comment = /\\s#/.exec(rest);\n end = comment ? comment.index : rest.length;\n while (end > 0 && /\\s/.test(rest.charAt(end - 1))) end--;\n }\n return { lead, scalar: rest.slice(0, end), trail: rest.slice(end) };\n}\n\n/** One scalar of an entry a repair may rewrite: a file, an end's lines, its pin, or the commit. */\nexport type EntryPath = readonly [\n end: \"claim\" | \"source\",\n field: \"file\" | \"lines\" | \"integrity\" | \"commit-sha\",\n];\n\n/** Replace the scalar on one line of entry N, e.g. `source.lines` after a move. */\nexport function spliceEntryField(\n content: string,\n format: string,\n index: number,\n path: EntryPath,\n value: LineSpec,\n): string {\n const [which, field] = path;\n const refuse = (): CiteError =>\n new CiteError(\n `Cannot rewrite citations[${String(index)}].${which}.${field} in ${format} frontmatter; edit it by hand.`,\n );\n const extractor = extractorFor(format);\n const pointer = `/citations/${String(index)}/${which}/${field}`;\n // `lineFor` walks up to the nearest recorded ancestor when the exact\n // pointer is unknown (TOML records top-level keys only), so the line it\n // names is checked for the field before anything is touched.\n const line = extractor.extract(content, \"page\").lineFor(pointer);\n if (line === undefined) throw refuse();\n const start = offsetOfLine(content, line);\n const nl = content.indexOf(\"\\n\", start);\n let end = nl === -1 ? content.length : nl;\n if (end > start && content.charAt(end - 1) === \"\\r\") end--;\n const parts = splitScalarLine(content.slice(start, end), field);\n if (!parts) throw refuse();\n\n const quote = parts.scalar.charAt(0);\n // A number is written plain whatever the old value's quoting was, so that\n // a range that became one line reads back as the integer it now is.\n const spelled =\n typeof value === \"number\" ? String(value)\n : quote === '\"' ? doubleQuote(value)\n : quote === \"'\" ? singleQuote(value)\n : needsYamlQuotes(value) ? doubleQuote(value)\n : value;\n const out = content.slice(0, start) + parts.lead + spelled + parts.trail + content.slice(end);\n\n // Read it back: a splice that lands anywhere but on that one value is a\n // refusal, not a damaged page.\n const check: unknown = extractor.extract(out, \"page\").data.citations;\n const entry: unknown = Array.isArray(check) ? check[index] : undefined;\n const block = isRecord(entry) ? entry[which] : undefined;\n const readBack = isRecord(block) ? block[field] : undefined;\n if (readBack !== value) throw refuse();\n return out;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Insert a statement line before the line containing `offset`, with the page's EOL. */\nexport function insertStatementBefore(\n content: string,\n offset: number,\n statement: string,\n): string {\n const start = offsetOfLine(content, lineAt(content, offset));\n return content.slice(0, start) + statement + detectEol(content) + content.slice(start);\n}\n\ntype Edit = { op: \" \" | \"-\" | \"+\"; text: string };\n\n/**\n * A unified diff of two texts, `---`/`+++` headers with the same label. Lines\n * are the hashing rule's (`splitLines`): a BOM is never part of a line, so a\n * page that carries one diffs the same as one that does not.\n */\nexport function unifiedDiff(label: string, before: string, after: string): string {\n const a = splitLines(before);\n const b = splitLines(after);\n // Shared prefix and suffix leave the LCS table to the lines that differ.\n let head = 0;\n while (head < a.length && head < b.length && a[head] === b[head]) head++;\n let tail = 0;\n while (tail < a.length - head && tail < b.length - head && a[a.length - 1 - tail] === b[b.length - 1 - tail]) tail++;\n const x = a.slice(head, a.length - tail);\n const y = b.slice(head, b.length - tail);\n if (x.length === 0 && y.length === 0) return \"\";\n\n const width = y.length + 1;\n const lcs = new Uint32Array((x.length + 1) * width);\n for (let i = x.length - 1; i >= 0; i--) {\n for (let j = y.length - 1; j >= 0; j--) {\n lcs[i * width + j] =\n x[i] === y[j]\n ? (lcs[(i + 1) * width + j + 1] ?? 0) + 1\n : Math.max(lcs[(i + 1) * width + j] ?? 0, lcs[i * width + j + 1] ?? 0);\n }\n }\n const edits: Edit[] = a.slice(0, head).map((text) => ({ op: \" \", text }));\n let i = 0;\n let j = 0;\n while (i < x.length || j < y.length) {\n const xi = x[i];\n const yj = y[j];\n if (xi !== undefined && yj !== undefined && xi === yj) {\n edits.push({ op: \" \", text: xi });\n i++;\n j++;\n } else if (xi !== undefined && (yj === undefined || (lcs[(i + 1) * width + j] ?? 0) >= (lcs[i * width + j + 1] ?? 0))) {\n // Deletions before insertions on a tie, as unified diffs read.\n edits.push({ op: \"-\", text: xi });\n i++;\n } else if (yj !== undefined) {\n edits.push({ op: \"+\", text: yj });\n j++;\n }\n }\n edits.push(...a.slice(a.length - tail).map((text) => ({ op: \" \" as const, text })));\n\n // Hunks: each change with one line of context; hunks whose context touches merge.\n const CONTEXT = 1;\n const out = [`--- ${label}`, `+++ ${label}`];\n let pos = 0;\n while (pos < edits.length) {\n if (edits[pos]?.op === \" \") {\n pos++;\n continue;\n }\n const from = Math.max(0, pos - CONTEXT);\n let to = pos;\n for (let k = pos; k < edits.length; k++) {\n if (edits[k]?.op !== \" \") to = k;\n else if (k - to > CONTEXT * 2) break;\n }\n to = Math.min(edits.length - 1, to + CONTEXT);\n let oldStart = 1;\n let newStart = 1;\n for (let k = 0; k < from; k++) {\n const op = edits[k]?.op;\n if (op !== \"+\") oldStart++;\n if (op !== \"-\") newStart++;\n }\n const slice = edits.slice(from, to + 1);\n const oldCount = slice.filter((e) => e.op !== \"+\").length;\n const newCount = slice.filter((e) => e.op !== \"-\").length;\n out.push(\n `@@ -${oldCount === 0 ? oldStart - 1 : oldStart},${oldCount} +${newCount === 0 ? newStart - 1 : newStart},${newCount} @@`,\n ...slice.map((e) => e.op + e.text),\n );\n pos = to + 1;\n }\n return out.join(\"\\n\") + \"\\n\";\n}\n","/**\n * Findings, their messages, and the bridge to meta's `ValidationResult`, so\n * the github/sarif/junit reporters and the baseline ratchet work unchanged.\n *\n * A claim or marker finding sits on the page line a reviewer reads. A finding\n * about the entry itself, `entry-invalid` or a bare pin whose source changed,\n * sits on the entry's own line, in the manifest when one owns it.\n *\n * FieldError: schema \"manni:cite\" (matches BUILTIN_ID, so canonicalSchemaRef\n * leaves it alone), keyword = rule, instancePath \"/citations/N\", subject =\n * id ?? source.integrity, never the claim's pin, so accepting a claim does\n * not reopen baselined findings. `ok` is true iff no error-severity finding.\n *\n * Every message spells the source as the entry spelled it. `resolvedPath`,\n * `commitsSince` and `diff` never enter a message: they are pretty-only\n * fields, shown under `--reveal` and `--show-diff`.\n */\nimport { isAbsolute } from \"node:path\";\nimport { isErrorSeverity, type FieldError, type ValidationResult } from \"../../meta/index.js\";\nimport type {\n CitationFinding,\n CitationResult,\n CiteRule,\n CiteSeverity,\n ClaimEnd,\n PageCitationReport,\n SourceEnd,\n SourceStatus,\n} from \"../types.js\";\nimport { claimLine } from \"./claims.js\";\nimport { parseSrc } from \"./range.js\";\nimport { RULE_ID_PREFIX, ruleId } from \"./severity.js\";\nimport { listOf, shortSrc } from \"./spell.js\";\n\n/** The seven characters a person reads a commit by. */\nfunction short(commit: string): string {\n return commit.slice(0, 7);\n}\n\nfunction plural(n: number, noun: string): string {\n return `${String(n)} ${noun}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** Whether the entry spelled this source encrypted. */\nfunction citesEncrypted(src: string): boolean {\n try {\n return parseSrc(src).encrypted;\n } catch {\n return false;\n }\n}\n\n/**\n * Why an encrypted source is missing, in words that never name the path. A\n * plain path names its own file, so the bare status says the rest.\n */\nfunction missingMessage(source: SourceEnd): string {\n if (!citesEncrypted(source.src)) return \"missing\";\n switch (source.missingReason) {\n case \"no-key\":\n return \"missing (no encryption key is available to decrypt it)\";\n case \"undecryptable\":\n return \"missing (does not decrypt under the current key)\";\n case \"untracked\":\n return \"missing (no tracked file matches; wrong --root?)\";\n case \"unreadable\":\n case undefined:\n return \"missing\";\n }\n}\n\n/** The one place a source end's message is composed, per status. */\nexport function messageFor(source: SourceEnd): string {\n switch (source.status) {\n case \"current\":\n return \"current\";\n case \"skipped\":\n return \"skipped\";\n case \"moved\":\n // An encrypted source's new path is a ciphertext, abbreviated as the\n // entry's own is: `--reveal` stays the only way to read either.\n return `moved -> ${shortSrc(source.newSrc ?? \"?\")}`;\n case \"moved-ambiguous\": {\n const candidates = source.candidates ?? [];\n return `moved, ${plural(candidates.length, \"candidate\")} (${candidates.map(shortSrc).join(\", \")}); widen the range`;\n }\n case \"changed\": {\n // Where the old first and last line sit now, when the in-range search\n // found each exactly once: the span `update --accept` re-mints at.\n const span = source.newLines === undefined ? \"\" : `; now at lines ${source.newLines}`;\n if (source.commitSha === undefined) return `changed${span}`;\n const at = short(source.commitSha);\n if (source.historyAvailable === false) {\n return `changed (history unavailable: commit ${at} not found; fetch-depth: 0)`;\n }\n if (source.commitsSince === undefined) return `changed since ${at}${span}`;\n return `changed since ${at}, ${plural(source.commitsSince.length, \"commit\")}${span}`;\n }\n case \"never-true\":\n return source.commitSha === undefined\n ? \"never true: the pin does not match at the recorded commit\"\n : `never true: the pin does not match at ${short(source.commitSha)}`;\n case \"missing\":\n return missingMessage(source);\n }\n}\n\n/** `<id>: <text>`, or the text alone for an entry with no id. */\nfunction named(id: string | undefined, text: string): string {\n return id === undefined ? text : `${id}: ${text}`;\n}\n\n/** `line 9`, or `lines 9-10` when the claim covers several. */\nfunction at(spec: string): string {\n return spec.includes(\"-\") ? `lines ${spec}` : `line ${spec}`;\n}\n\n/** The one place a claim end's message is composed, per status. */\nexport function claimMessageFor(result: CitationResult): string {\n const claim = result.claim;\n const id = result.citation.id;\n if (claim === null) return \"\";\n // A marker-anchored claim has no lines of its own; it is judged where the\n // marker's text sits, and that is what the message names.\n const where =\n claim.fileLines ??\n (result.markerLine === undefined ? undefined : String(result.markerLine));\n switch (claim.status) {\n case \"moved\":\n return named(\n id,\n `the claim moved from ${at(where ?? \"?\")} to ${at(claim.newFileLines ?? \"?\")}.`,\n );\n case \"moved-ambiguous\":\n return named(\n id,\n `the claim at ${at(where ?? \"?\")} now appears at lines ${listOf(claim.candidateFileLines ?? [])}.`,\n );\n case \"reanchored\": {\n const since = claim.commitSha === undefined ? \"\" : ` since ${short(claim.commitSha)}`;\n // A claim-lines entry moved onto its new run; a marker-anchored one\n // never moves, because the marker travels with its own text.\n const to =\n claim.newFileLines === undefined ? \"\" : `, to ${at(claim.newFileLines)}`;\n return named(\n id,\n `the claim at ${at(where ?? \"?\")} was reanchored${since}${to}. Its words are unchanged.`,\n );\n }\n case \"changed\":\n if (where === undefined) {\n return named(\n id,\n \"the claim has no lines and no marker names the entry, so its pin anchors nothing.\",\n );\n }\n return named(id, `the claim at ${at(where)} has ${claimChange(claim)}`);\n case \"current\":\n case \"skipped\":\n return \"\";\n }\n}\n\n/** How a changed claim says since when, which is what its history could say. */\nfunction claimChange(claim: ClaimEnd): string {\n if (claim.historyAvailable === false) {\n return \"changed since it was pinned (history unavailable; fetch-depth: 0).\";\n }\n if (claim.commitSha === undefined) return \"changed since it was pinned.\";\n const at = short(claim.commitSha);\n // Zero commits since would read as \"just now\". The working tree holding the\n // change is what it actually means, so it says that.\n const since = claim.commitsSince ?? [];\n const count = since.length === 0 ? \"uncommitted\" : plural(since.length, \"commit\");\n return `changed since ${at}, ${count}.`;\n}\n\n/**\n * The one place a `marker-misplaced` message is composed. A quote marker's\n * place is above the block it anchors; every other marker's is the first line\n * of the paragraph its run splits.\n */\nexport function misplacedMessageFor(\n id: string | undefined,\n marker: { line: number; unit: string; place: number; block: boolean },\n): string {\n const place = marker.block\n ? `above the block at line ${String(marker.place)}`\n : `above line ${String(marker.place)}`;\n return named(\n id,\n `the marker at line ${String(marker.line)} splits the paragraph at ${at(marker.unit)}. Its place is ${place}.`,\n );\n}\n\n/** The rule a source status reports under, or undefined for one that is not a finding. */\nfunction sourceRuleOf(status: SourceStatus): CiteRule | undefined {\n if (status === \"skipped\" || status === \"current\") return undefined;\n return `source-${status}`;\n}\n\n/** The rule a claim status reports under, or undefined. */\nfunction claimRuleOf(claim: ClaimEnd): CiteRule | undefined {\n const status = claim.status;\n if (status === \"skipped\" || status === \"current\") return undefined;\n return `claim-${status}`;\n}\n\n/** Where a finding about a whole entry sits: its own line, in its own file. */\nfunction entrySite(result: CitationResult): Pick<CitationFinding, \"line\" | \"file\"> {\n const site: Pick<CitationFinding, \"line\" | \"file\"> = {};\n if (result.origin.line !== undefined) site.line = result.origin.line;\n if (result.origin.kind === \"manifest\") site.file = result.origin.file;\n return site;\n}\n\n/** Where a finding about an anchored citation sits: the page line it anchors to. */\nfunction anchorSite(result: CitationResult): Pick<CitationFinding, \"line\" | \"file\"> {\n if (result.anchorLine !== undefined) return { line: result.anchorLine };\n return entrySite(result);\n}\n\n/** Findings for classified citations under a severity table; `off` rules produce none. */\nexport function findingsFor(\n results: readonly CitationResult[],\n severity: Readonly<Record<CiteRule, CiteSeverity>>,\n): CitationFinding[] {\n const out: CitationFinding[] = [];\n const push = (\n result: CitationResult,\n rule: CiteRule,\n message: string,\n site: Pick<CitationFinding, \"line\" | \"file\">,\n extra?: Pick<CitationFinding, \"newSrc\">,\n ): void => {\n const level = severity[rule];\n if (level === \"off\") return;\n const finding: CitationFinding = {\n rule,\n ruleId: ruleId(rule),\n severity: level,\n message,\n src: result.source.src,\n index: result.origin.index,\n };\n if (site.line !== undefined) finding.line = site.line;\n if (site.file !== undefined) finding.file = site.file;\n if (result.citation.id !== undefined) finding.id = result.citation.id;\n if (extra?.newSrc !== undefined) finding.newSrc = extra.newSrc;\n out.push(finding);\n };\n\n for (const result of results) {\n const claim = result.claim;\n if (claim !== null) {\n const rule = claimRuleOf(claim);\n // A claim pin that anchors nothing has no page line to sit on.\n if (rule !== undefined) {\n const site =\n claimLine(claim) === undefined && result.markerLine === undefined\n ? entrySite(result)\n : { line: claimLine(claim) ?? result.markerLine };\n push(result, rule, claimMessageFor(result), site);\n }\n }\n const rule = sourceRuleOf(result.source.status);\n if (rule === undefined) continue;\n const extra =\n result.source.newSrc === undefined ? undefined : { newSrc: result.source.newSrc };\n push(result, rule, messageFor(result.source), anchorSite(result), extra);\n }\n return out;\n}\n\n/**\n * The pin of the citation a finding is about, for the fingerprint subject of\n * an entry with no id. Always the source's: accepting a changed claim must\n * not reopen a baselined finding.\n */\nfunction integrityFor(\n finding: CitationFinding,\n results: readonly CitationResult[],\n): string | undefined {\n if (finding.index === undefined) return undefined;\n return results.find((r) => r.origin.index === finding.index)?.citation.source.integrity;\n}\n\n/**\n * Where a finding is located once it becomes a `FieldError`: the page, or\n * the manifest the entry sits in.\n *\n * A manifest outside the repository has no location any reporter can use —\n * SARIF drops a uri that rebases to `../…`, and a GitHub annotation on one\n * lands nowhere — so the finding falls back to the page, and its line goes\n * with the file it belonged to. Inside the tree, both travel, and `file`\n * is what every reporter reads to annotate the manifest instead.\n */\nexport function errorSite(\n finding: CitationFinding,\n): Pick<CitationFinding, \"line\" | \"file\"> {\n if (finding.file === undefined) {\n return finding.line === undefined ? {} : { line: finding.line };\n }\n if (finding.file.startsWith(\"../\") || isAbsolute(finding.file)) return {};\n return {\n file: finding.file,\n ...(finding.line === undefined ? {} : { line: finding.line }),\n };\n}\n\nexport function toValidationResult(report: PageCitationReport): ValidationResult {\n const errors: FieldError[] = report.findings.map((finding) => {\n const error: FieldError = {\n schema: RULE_ID_PREFIX,\n instancePath: finding.index === undefined ? \"\" : `/citations/${String(finding.index)}`,\n message: finding.message,\n keyword: finding.rule,\n severity: finding.severity,\n };\n const subject = finding.id ?? integrityFor(finding, report.citations);\n if (subject !== undefined) error.subject = subject;\n const site = errorSite(finding);\n if (site.file !== undefined) error.file = site.file;\n if (site.line !== undefined) error.line = site.line;\n return error;\n });\n return {\n file: report.file,\n format: report.format,\n ok: !errors.some(isErrorSeverity),\n schemas: [RULE_ID_PREFIX],\n errors,\n };\n}\n","/**\n * `checkCitations`: the programmatic core a docevals `tool:cite` grader calls\n * for one page. Reads the entries and markers, classifies both ends of each\n * citation, applies the severity table, and returns findings whose messages\n * spell sources exactly as the entry spelled them.\n *\n * The claim end is page-side, so it is judged even under `--no-check-sources`,\n * which a public docs checkout runs. The source end needs the files.\n *\n * `quote: true` is settled here. The claim must still be a fenced block\n * (`anchor-invalid`), and the block is faithful when it reproduces the cited\n * lines as pinned (which survives a move and a missing source) or as they are\n * now (a block someone refreshed ahead of a re-mint). Neither: `quote-drift`.\n */\nimport type {\n CheckPageOptions,\n CitationFinding,\n CitationResult,\n CiteRule,\n CiteSeverity,\n ClaimEnd,\n GitClient,\n PageCitation,\n PageCitationReport,\n PageCitations,\n PageLines,\n SourceEnd,\n SourceIndex,\n} from \"../types.js\";\nimport { findingsFor, misplacedMessageFor } from \"./adapt.js\";\nimport { misplacedMarkers, type MisplacedMarker } from \"./reanchor.js\";\nimport { spellLines } from \"../../shared/pin.js\";\nimport { classifyCitation, MOVE_BUDGET_BYTES } from \"./classify.js\";\nimport { blockMatches, claimEnd, claimLineNow, claimLinesNow } from \"./claims.js\";\nimport { GIT_UNAVAILABLE_HISTORY, PAGE_HISTORY_UNAVAILABLE, gitClient } from \"./git.js\";\nimport { claimHistory, refineClaim } from \"./history.js\";\nimport { hashLines, sliceLines, splitLines } from \"./hash.js\";\nimport { readPage } from \"./page.js\";\nimport { STDIN_LABEL } from \"../../meta/internal.js\";\nimport { parseSrc, sourceRange, spellSource } from \"./range.js\";\nimport { buildSourceIndex, readSource } from \"./sources.js\";\nimport { resolveSeverity, ruleId } from \"./severity.js\";\nimport { anchoredLines, fenceSpanAt } from \"./statements.js\";\n\nfunction byLine(a: CitationFinding, b: CitationFinding): number {\n return (a.line ?? Number.MAX_SAFE_INTEGER) - (b.line ?? Number.MAX_SAFE_INTEGER);\n}\n\n/** A page-side finding under the configured table: dropped when `off`, else re-levelled. */\nfunction relevel(\n finding: CitationFinding,\n severity: Readonly<Record<CiteRule, CiteSeverity>>,\n): CitationFinding | undefined {\n const level = severity[finding.rule];\n if (level === \"off\") return undefined;\n return { ...finding, severity: level };\n}\n\ninterface QuoteInput {\n page: PageCitations;\n lines: string[];\n root: string;\n index: Parameters<typeof readSource>[1];\n key?: string;\n checkSources: boolean;\n}\n\n/** The cited lines as they are now, or undefined when they cannot be read. */\nasync function citedNow(\n input: QuoteInput,\n source: SourceEnd,\n entry: PageCitation,\n): Promise<string | undefined> {\n const range = sourceRange(entry.citation.source);\n const read = await readSource(input.root, input.index, range, input.key);\n if (read.kind === \"missing\") return undefined;\n // After a move the bytes live at the new range; compare against those.\n const at = source.status === \"moved\" && source.newSrc !== undefined ? parseSrc(source.newSrc) : range;\n try {\n return sliceLines(splitLines(read.text), at);\n } catch {\n return undefined;\n }\n}\n\n/** Whether a block reproduces the citation, as pinned or as the source is now. */\nfunction faithful(\n blockText: string,\n pin: string,\n key: string | undefined,\n now: string | undefined,\n): boolean {\n return hashLines(splitLines(blockText).join(\"\\n\"), key) === pin || (now !== undefined && blockMatches(blockText, now));\n}\n\n/** The lines inside a block's fences, joined as the hashing rule joins them. */\nfunction insideOf(lines: readonly string[], block: PageLines): string {\n return lines.slice(block.start, block.end - 1).join(\"\\n\");\n}\n\n/**\n * The quote check for one entry: where its block is, whether that is still a\n * fenced block, and whether it still reproduces the source. Findings here are\n * `anchor-invalid` (page-side) and `quote-drift` (needs the source).\n */\nasync function quoteFindings(\n input: QuoteInput,\n entry: PageCitation,\n result: CitationResult,\n): Promise<{ rule: CiteRule; message: string; line?: number }[]> {\n const { citation } = entry;\n if (citation.quote !== true || result.anchor === null) return [];\n const id = citation.id;\n const named = (text: string): string => (id === undefined ? text : `${id}: ${text}`);\n const { page } = input;\n\n let block: PageLines | undefined;\n if (result.anchor === \"marker\" && entry.marker !== undefined) {\n block = anchoredLines(page.content, entry.marker.end, page.format, true);\n if (block === undefined) {\n return [\n {\n rule: \"quote-drift\",\n message: \"quote: true, but no fenced block follows the marker\",\n ...(result.markerLine === undefined ? {} : { line: result.markerLine }),\n },\n ];\n }\n } else {\n const at = result.claim === null ? undefined : claimLinesNow(result.claim);\n if (at === undefined) return [];\n const span = fenceSpanAt(page.content, at.start, page.format);\n if (span === undefined || span.end !== at.end) {\n return [\n {\n rule: \"anchor-invalid\",\n message: named(\n `the quote's claim lines ${at.start === at.end ? String(at.start) : `${String(at.start)}-${String(at.end)}`} are no longer a fenced block.`,\n ),\n line: at.start,\n },\n ];\n }\n block = span;\n }\n\n if (!input.checkSources || result.source.status === \"missing\") return [];\n const key = sourceRange(citation.source).encrypted ? input.key : undefined;\n const now = await citedNow(input, result.source, entry);\n const inside = insideOf(input.lines, block);\n if (faithful(inside, citation.source.integrity, key, now)) return [];\n return [\n {\n rule: \"quote-drift\",\n message: \"quote: true, but the fenced block does not reproduce the cited lines\",\n line: block.start,\n },\n ];\n}\n\n/** The marker end of a result: its line, plus its misplacement when it has one. */\nfunction markerEnd(\n entry: PageCitation,\n misplaced: MisplacedMarker | undefined,\n): Pick<CitationResult, \"marker\"> {\n const { marker } = entry;\n if (marker === undefined) return {};\n if (misplaced === undefined) return { marker: { line: marker.line } };\n return {\n marker: {\n line: marker.line,\n misplaced: { unit: spellLines(misplaced.unit), to: misplaced.to },\n },\n };\n}\n\n/** How a citation is anchored, and the page line it anchors to. */\nfunction anchorOf(\n entry: PageCitation,\n claim: ClaimEnd | null,\n page: PageCitations,\n): Pick<CitationResult, \"anchor\" | \"markerLine\" | \"anchorLine\"> {\n const { citation, marker } = entry;\n const hasLines = citation.claim?.lines !== undefined;\n const out: Pick<CitationResult, \"anchor\" | \"markerLine\" | \"anchorLine\"> = { anchor: null };\n if (marker !== undefined) out.markerLine = marker.line;\n // Lines and a marker both is `anchor-invalid`: neither anchor is trusted.\n if (hasLines && marker !== undefined) return out;\n if (hasLines) {\n out.anchor = \"claim\";\n const at = claim === null ? undefined : claimLineNow(claim);\n if (at !== undefined) out.anchorLine = at;\n return out;\n }\n if (marker !== undefined) {\n out.anchor = \"marker\";\n const unit = anchoredLines(page.content, marker.end, page.format, citation.quote === true);\n out.anchorLine = unit?.start ?? marker.line;\n }\n return out;\n}\n\nexport async function checkCitations(\n page: { file: string; content: string; format?: string },\n opts: CheckPageOptions,\n): Promise<PageCitationReport> {\n const readOptions: Parameters<typeof readPage>[2] = {};\n if (page.format !== undefined) readOptions.format = page.format;\n if (opts.citations !== undefined) readOptions.citations = opts.citations;\n if (opts.owned !== undefined) readOptions.owned = opts.owned;\n const read = readPage(page.file, page.content, readOptions);\n const severity = resolveSeverity(opts.severity);\n const client = opts.gitClient ?? gitClient(opts.root);\n // The page's history lives in the page's own repository, which is not the\n // sources' when `--root` sent those to another checkout.\n const pageGit =\n opts.pageGitClient ??\n (opts.pageRoot === undefined || opts.pageRoot === opts.root\n ? client\n : gitClient(opts.pageRoot));\n const checkSources = opts.checkSources !== false;\n const lines = splitLines(read.content);\n\n const results: CitationResult[] = [];\n const findings: CitationFinding[] = [];\n const notices: string[] = [];\n for (const finding of read.findings) {\n const kept = relevel(finding, severity);\n if (kept !== undefined) findings.push(kept);\n }\n\n const index = checkSources\n ? (opts.sourceIndex ?? (await buildSourceIndex(opts.root, { gitClient: client })))\n : undefined;\n const classifyOpts =\n index === undefined\n ? undefined\n : ({ root: opts.root, index, git: client, ...(opts.key === undefined ? {} : { key: opts.key }) } satisfies Parameters<\n typeof classifyCitation\n >[1]);\n\n // A quote is judged page-side even with the sources off, so this stands\n // whether or not there is an index; `quoteFindings` reads a source only\n // when `checkSources` says it may.\n const quoteInput: QuoteInput = {\n page: read,\n lines,\n root: opts.root,\n index: index ?? emptyIndex,\n checkSources,\n ...(opts.key === undefined ? {} : { key: opts.key }),\n };\n\n // Every marker line that splits a paragraph, read once for the page: its\n // entry's claim is judged against it, and each one is its own finding.\n const misplaced = misplacedMarkers(read, lines);\n const misplacedAt = new Map(misplaced.map((found) => [found.line, found]));\n\n for (const entry of read.citations) {\n const split = entry.marker === undefined ? undefined : misplacedAt.get(entry.marker.line);\n const claim = await withClaimHistory(\n { page: read, entry, claim: claimEnd(read, entry, lines, split), lines },\n { path: read.file, git: pageGit, ...(opts.pageCommitCap === undefined ? {} : { cap: opts.pageCommitCap }), ...(opts.owned === undefined ? {} : { manifest: opts.owned.file }) },\n );\n const source: SourceEnd =\n classifyOpts === undefined\n ? skippedSource(entry)\n : await classifyCitation(entry, classifyOpts);\n const result: CitationResult = {\n citation: entry.citation,\n origin: entry.origin,\n ...anchorOf(entry, claim, read),\n ...markerEnd(entry, split),\n claim,\n source,\n };\n results.push(result);\n\n for (const found of await quoteFindings(quoteInput, entry, result)) {\n const level = severity[found.rule];\n if (level === \"off\") continue;\n const finding: CitationFinding = {\n rule: found.rule,\n ruleId: ruleId(found.rule),\n severity: level,\n message: found.message,\n src: source.src,\n index: entry.origin.index,\n };\n if (found.line !== undefined) finding.line = found.line;\n if (entry.citation.id !== undefined) finding.id = entry.citation.id;\n findings.push(finding);\n }\n }\n\n // One finding per misplaced marker, so a run of three is three. An orphan\n // in a run is reported too, with no id, beside its `marker-orphan`.\n const misplacedLevel = severity[\"marker-misplaced\"];\n if (misplacedLevel !== \"off\") {\n for (const found of misplaced) {\n const entry = found.entry;\n const finding: CitationFinding = {\n rule: \"marker-misplaced\",\n ruleId: ruleId(\"marker-misplaced\"),\n severity: misplacedLevel,\n message: misplacedMessageFor(entry?.citation.id, {\n line: found.line,\n unit: spellLines(found.unit),\n place: found.place,\n block: found.block,\n }),\n line: found.line,\n };\n if (entry !== undefined) {\n finding.index = entry.origin.index;\n finding.src = spellSource(entry.citation.source);\n if (entry.citation.id !== undefined) finding.id = entry.citation.id;\n }\n findings.push(finding);\n }\n }\n\n findings.push(...findingsFor(results, severity));\n\n // History is read for a citation with a commit, and for every claim that no\n // longer holds, so a page holding either and with no git to read it through\n // says why its verdicts are plainer. With the sources off nothing is\n // classified, but a claim end still is, and it still wants the page's past.\n const wantsSourceHistory =\n checkSources &&\n read.citations.some(({ citation }) => citation.source[\"commit-sha\"] !== undefined);\n const wantsClaimHistory = results.some((r) => r.claim?.status === \"changed\");\n if (wantsSourceHistory && !(await client.available())) notices.push(GIT_UNAVAILABLE_HISTORY);\n else if (wantsClaimHistory && !(await pageGit.available())) {\n notices.push(GIT_UNAVAILABLE_HISTORY);\n }\n // A claim whose walk ran out of commits: the rest of the history would have\n // told a layout change from an edit.\n if (results.some((r) => r.claim?.historyAvailable === false)) {\n notices.push(PAGE_HISTORY_UNAVAILABLE);\n }\n\n const unavailable = results.find((r) => r.source.historyAvailable === false);\n if (unavailable?.source.commitSha !== undefined) {\n notices.push(\n `commit ${unavailable.source.commitSha.slice(0, 7)} not found in history; use fetch-depth: 0 to enable never-true and diffs`,\n );\n }\n // Two forms, because \"the file\" is the wrong noun for a scan across the\n // files a commit touched. A run raises each at most once, and both when it\n // hit both.\n const budget = String(MOVE_BUDGET_BYTES / (1024 * 1024));\n if (results.some((r) => r.source.truncatedSearch === true && r.source.truncatedAcross !== true)) {\n notices.push(\n `a move search hit its ${budget} MiB budget before covering the file; a citation may read changed rather than moved`,\n );\n }\n if (results.some((r) => r.source.truncatedAcross === true)) {\n notices.push(\n `a move search hit its ${budget} MiB budget before covering the files changed since the pin's commit; a citation may read changed or missing rather than moved`,\n );\n }\n\n return {\n file: read.file,\n format: read.format,\n citations: results,\n findings: findings.sort(byLine),\n notices,\n };\n}\n\n/**\n * The claim end read against the page's history, for a claim that no longer\n * holds. Every other status is what it was: the walk runs only where a\n * verdict is in doubt, so a clean corpus costs no git at all.\n */\nasync function withClaimHistory(\n now: {\n page: PageCitations;\n entry: PageCitation;\n claim: ClaimEnd | null;\n lines: readonly string[];\n },\n read: { path: string; git: GitClient; cap?: number; manifest?: string },\n): Promise<ClaimEnd | null> {\n const { claim } = now;\n if (claim === null || claim.status !== \"changed\") return claim;\n // A page read from stdin has no path in the repository, so it has no history.\n if (read.path === STDIN_LABEL) return claim;\n const input = { page: now.page, entry: now.entry, claim, ...read };\n const history = await claimHistory(input);\n return refineClaim({ ...input, lines: now.lines, history });\n}\n\n/** With `--no-check-sources` no file is read, so every source end is `skipped`. */\nfunction skippedSource(entry: PageCitation): SourceEnd {\n const { source } = entry.citation;\n const out: SourceEnd = { src: spellSource(source), status: \"skipped\" };\n if (source[\"commit-sha\"] !== undefined) out.commitSha = source[\"commit-sha\"];\n return out;\n}\n\n/** Stands in where a quote is judged page-side only; nothing is ever read from it. */\nconst emptyIndex: SourceIndex = { files: () => [], has: () => false };\n","/**\n * Mint a citation's source end: read the range through the source index, hash\n * it under the rule (the keyed pin when the source is encrypted), record HEAD\n * unless told not to. Refuses (CiteError) a source the index does not hold, an\n * encrypted source the key cannot open, a range wider than\n * `MAX_RANGE_LINES`, a range past EOF, or a commit that does not contain the\n * lines it would be recorded against. No refusal names the path an encrypted\n * source holds.\n *\n * The claim end is minted by the caller, over the page lines it was given,\n * and passed in whole.\n */\nimport { ENCRYPTION_KEY_ENV } from \"../../shared/encryption-key.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n Citation,\n CitationSource,\n MintOptions,\n MissingReason,\n SourceRange,\n} from \"../types.js\";\nimport { historyOf } from \"./classify.js\";\nimport { hashLines, sliceLines, splitLines } from \"./hash.js\";\nimport { parseSrc, rangeLines, tooWide } from \"./range.js\";\nimport { buildSourceIndex, encryptSourcePath, readSource } from \"./sources.js\";\n\n/** The schema's `commit-sha` pattern: seven to sixty-four lowercase hex digits. */\nconst COMMIT_PATTERN = /^[0-9a-f]{7,64}$/;\n\nasync function commitFor(opts: MintOptions): Promise<string | undefined> {\n if (opts.commitSha === false) return undefined;\n if (typeof opts.commitSha === \"string\") {\n if (!COMMIT_PATTERN.test(opts.commitSha)) {\n throw new CiteError(\n `Invalid commit-sha \"${opts.commitSha}\": expected 7 to 64 lowercase hex digits.`,\n );\n }\n return opts.commitSha;\n }\n const client = opts.gitClient;\n if (client === undefined || !(await client.available())) return undefined;\n return (await client.head()) ?? undefined;\n}\n\n/**\n * Refuse a commit that does not contain the lines it would be recorded\n * against. The range is read from the working tree, so an uncommitted edit\n * would otherwise be dated to a commit that never held it. Such a pin reads as\n * `current` forever, because `classifyCitation` returns at the working-tree\n * match without consulting the commit, and then accuses the source of\n * `source-never-true` the first time it changes.\n *\n * `historyOf` is the same question `check` asks, so the answers agree. It\n * accepts the lines sitting elsewhere in the file at that commit, which is what\n * `update` leaves behind when it follows a move and keeps `commit`.\n *\n * A commit git cannot read is recorded unverified. A shallow clone must\n * degrade to \"history unavailable\" rather than refuse (`git.ts`).\n */\nasync function assertCommitHolds(\n opts: MintOptions,\n commit: string,\n path: string,\n range: SourceRange,\n pin: string,\n key: string | undefined,\n): Promise<void> {\n const client = opts.gitClient;\n if (client === undefined || !(await client.available())) return;\n const history = await historyOf(client, commit, path, range, pin, key, undefined);\n if (history.kind !== \"never-true\") return;\n // Named as the caller spelled it: an encrypted source stays a ciphertext.\n throw new CiteError(\n `${opts.src} is not committed: ${commit.slice(0, 7)} does not contain those lines. Commit the source, or use --no-commit-sha.`,\n );\n}\n\n/**\n * The refusal for a source that could not be read, naming it as the caller\n * spelled it: an encrypted source stays a ciphertext even on stderr.\n */\nfunction refusalFor(reason: MissingReason, path: string, encrypted: boolean): CiteError {\n switch (reason) {\n case \"untracked\":\n return new CiteError(\n encrypted\n ? `No tracked file matches ${path} (wrong --root?).`\n : `Source not found: ${path} is not a tracked file under the root.`,\n );\n case \"no-key\":\n return new CiteError(`${path} is encrypted, and no encryption key is available to decrypt it.`);\n case \"undecryptable\":\n return new CiteError(`${path} does not decrypt under the current key.`);\n case \"unreadable\":\n return new CiteError(`Source not readable: ${path} could not be read.`);\n }\n}\n\nexport async function mintCitation(opts: MintOptions): Promise<Citation> {\n const range = parseSrc(opts.src);\n const wide =\n range.start === undefined || range.end === undefined\n ? undefined\n : tooWide({ start: range.start, end: range.end });\n if (wide !== undefined) throw new CiteError(`Invalid range \"${opts.src}\": it ${wide}.`);\n const { key } = opts;\n // A source that is already encrypted stays encrypted whatever `encrypt`\n // says: the check side keys every pin whose file is encrypted, so a plain\n // pin under a ciphertext would never hold.\n const encrypt = opts.encrypt === true || range.encrypted;\n if (encrypt && !range.encrypted && key === undefined) {\n throw new CiteError(\n `${opts.src} must be encrypted, and no encryption key is available. Run \\`manni key set\\`, or set ${ENCRYPTION_KEY_ENV}.`,\n );\n }\n const index = opts.sourceIndex ?? (await buildSourceIndex(opts.root, { gitClient: opts.gitClient }));\n\n const read = await readSource(opts.root, index, range, key);\n if (read.kind === \"missing\") throw refusalFor(read.reason, range.path, range.encrypted);\n\n // The out-of-range error names the source as the caller spelled it, never a\n // decrypted path.\n const joined = sliceLines(splitLines(read.text), range, range.path);\n // Set whenever `encrypt` is: refused above for a plain source, and an\n // encrypted one could not have been read without it.\n const pinKey = encrypt ? key : undefined;\n const file =\n pinKey !== undefined && !range.encrypted ? encryptSourcePath(read.resolvedPath, pinKey) : range.path;\n const lines = rangeLines(range);\n const commitSha = await commitFor(opts);\n const integrity = hashLines(joined, pinKey);\n if (commitSha !== undefined) {\n await assertCommitHolds(opts, commitSha, read.resolvedPath, range, integrity, pinKey);\n }\n\n const source: CitationSource = { file, integrity };\n // Field order is the order a reader scans a source in: which file, which\n // lines, what they hashed to, and when that was taken.\n const ordered: CitationSource = {\n file: source.file,\n ...(lines === undefined ? {} : { lines }),\n integrity: source.integrity,\n ...(commitSha === undefined ? {} : { \"commit-sha\": commitSha }),\n };\n // And an entry reads: what it is called, what it says, what it rests on.\n return {\n ...(opts.id === undefined ? {} : { id: opts.id }),\n ...(opts.claim === undefined ? {} : { claim: opts.claim }),\n source: ordered,\n ...(opts.quote === undefined ? {} : { quote: opts.quote }),\n };\n}\n","/**\n * The `cite:` section of manni.config.yaml, and the run resolution every\n * command shares (meta's rule: positional inputs resolve from cwd, a\n * collection's `paths` from the config directory; `root` and `baseline` are\n * config-dir relative). The document set itself is not a `cite:` key:\n * proposal 0041 put it in the family-level `collections:` list, which the\n * shared loader parses and `resolveCiteRun` selects from. Unknown keys, rules\n * or levels are errors that name the supported keys and never echo a value.\n * Root resolution: `--root` (cwd-relative) > `cite.root` > git root > cwd,\n * with a notice on the last fallback. The encryption key is the family's, not\n * a `cite:` key: `MANNI_ENCRYPTION_KEY` > the top-level `encryptionKey:` >\n * none, resolved in src/shared/encryption-key.ts (proposal 0045).\n */\nimport { resolve } from \"node:path\";\nimport { selectCollections } from \"../../shared/collections.js\";\nimport {\n findConfigFile,\n readConfigFile,\n type ConfigFile,\n type ConfigFileOptions,\n} from \"../../shared/config-file.js\";\nimport { resolveEncryptionKey } from \"../../shared/encryption-key.js\";\nimport { findGitRoot } from \"../../shared/git-root.js\";\nimport { SEVERITIES } from \"../../shared/severity.js\";\nimport { CiteError } from \"../errors.js\";\nimport {\n CITE_RULES,\n type CiteConfig,\n type CiteRule,\n type CiteRun,\n type CiteSeverity,\n type LoadedCiteConfig,\n} from \"../types.js\";\nimport { isCiteRule } from \"./severity.js\";\n\nexport const CITE_SECTION = \"cite\";\n\nexport const DEFAULT_CITE_BASELINE_PATH = \".manni-cite-baseline.json\";\n\n/** The keys `cite:` accepts, in the order the reference table lists them. */\nconst CONFIG_KEYS: readonly (keyof CiteConfig)[] = [\n \"allowEmpty\",\n \"respectGitignore\",\n \"root\",\n \"baseline\",\n \"checkSources\",\n \"severity\",\n];\n\n/**\n * The key the family encryption key replaced (proposal 0045). It keyed cite's\n * own hashed tokens; values are now encrypted under one key every tool reads,\n * so the old key is refused by name rather than called a typo. The message\n * never quotes the value, which was a secret.\n */\nconst SALT_KEY = \"salt\";\nconst saltRefusal = (source: string): string =>\n `${source}: \"salt\" is no longer a cite key. Values are encrypted with a family key: a top-level encryptionKey:, or MANNI_ENCRYPTION_KEY. Run \\`manni key set\\`.`;\n\n/**\n * The levels a rule takes: the family scale, most severe first, then `off`.\n * Built from `SEVERITIES`, so a level the family adds is a level cite takes.\n */\nconst SEVERITY_LEVELS: readonly CiteSeverity[] = [...[...SEVERITIES].reverse(), \"off\"];\n\nfunction isLevel(value: unknown): value is CiteSeverity {\n return typeof value === \"string\" && (SEVERITY_LEVELS as readonly string[]).includes(value);\n}\n\n/**\n * Where the metadata tool's configuration reference documents `collections:`.\n * The literal meta's `config.ts` carries, repeated because that module is\n * meta's own and sibling tools import only its public and family barrels.\n */\nconst CONFIG_REF = \"https://hawkeyexl.github.io/manni/meta/reference/configuration/\";\n\n/**\n * The two keys proposal 0041 moved out of `cite:` and up to the family level.\n * Refused rather than aliased, as meta refuses them: an alias would be a\n * second place to declare a document set that is meant to be declared once.\n */\nconst MOVED_KEYS: readonly string[] = [\"paths\", \"exclude\"];\n\n/**\n * Refuse a moved key before the unknown-key check, which would otherwise call\n * `paths` a typo. Same sentence as meta's, with the section renamed.\n */\nfunction assertNoMovedKeys(raw: Record<string, unknown>, source: string): void {\n for (const key of MOVED_KEYS) {\n if (Object.hasOwn(raw, key)) {\n throw new CiteError(\n `${source}: \"${key}\" is no longer a cite key. Document sets are declared once for every tool, under a top-level collections: list. See ${CONFIG_REF}#collections`,\n );\n }\n }\n}\n\nconst CONFIG_FILE: ConfigFileOptions = {\n section: CITE_SECTION,\n // The citation tool never had a file of its own before the family file.\n legacyNames: [],\n toError: (message) => new CiteError(message),\n};\n\n/**\n * A key the parser does not know is a typo, not a no-op. Dropping it in\n * silence would let `allowEmtpy: true` read as configured and be nothing.\n * `where` is the mapping as the user spells it: `cite` or `cite.severity`.\n */\nfunction rejectUnknownKeys(\n obj: Record<string, unknown>,\n allowed: readonly string[],\n where: string,\n source: string,\n): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.includes(key)) {\n throw new CiteError(\n `Unknown key \"${key}\" under ${where}: in ${source}. Supported keys: ${allowed.join(\", \")}.`,\n );\n }\n }\n}\n\n/**\n * Every type error names the key and the type it wanted, and nothing else.\n * A value can be a secret pasted under the wrong key, and a message that\n * quoted it would put it in a CI log; the same shape for every key keeps that\n * a rule rather than a special case.\n */\nfunction wrongType(key: string, expected: string, source: string): CiteError {\n return new CiteError(`cite.${key} in ${source} must be ${expected}.`);\n}\n\nfunction asBoolean(value: unknown, key: string, source: string): boolean {\n if (typeof value !== \"boolean\") throw wrongType(key, \"a boolean\", source);\n return value;\n}\n\nfunction asString(value: unknown, key: string, source: string): string {\n if (typeof value !== \"string\") throw wrongType(key, \"a string\", source);\n return value;\n}\n\nfunction isMapping(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseSeverity(\n value: unknown,\n source: string,\n): Partial<Record<CiteRule, CiteSeverity>> {\n if (!isMapping(value)) throw wrongType(\"severity\", \"a mapping\", source);\n rejectUnknownKeys(value, CITE_RULES, \"cite.severity\", source);\n const severity: Partial<Record<CiteRule, CiteSeverity>> = {};\n for (const [rule, level] of Object.entries(value)) {\n // `rejectUnknownKeys` already settled this; the guard is for the type.\n if (!isCiteRule(rule)) continue;\n if (!isLevel(level)) {\n // A level is not a secret, so a string one is quoted back: `eror` reads\n // as the typo it is. Anything else is described by type only.\n const got = typeof level === \"string\" ? `, not \"${level}\"` : \"\";\n throw new CiteError(\n `cite.severity.${rule} in ${source} must be one of ${SEVERITY_LEVELS.join(\", \")}${got}.`,\n );\n }\n severity[rule] = level;\n }\n return severity;\n}\n\n/**\n * Validate the `cite:` slice of a family file. `raw` is what the loader cut\n * out: `null` for an empty section, which is the same as no keys at all.\n * `source` is the file as the user would name it, for the messages.\n */\nexport function parseCiteConfig(raw: unknown, source: string): CiteConfig {\n if (raw == null) return {};\n if (!isMapping(raw)) {\n throw new CiteError(`cite: in ${source} must be a mapping.`);\n }\n assertNoMovedKeys(raw, source);\n // Before the unknown-key check, which would call it a typo.\n if (Object.hasOwn(raw, SALT_KEY)) throw new CiteError(saltRefusal(source));\n rejectUnknownKeys(raw, CONFIG_KEYS, \"cite\", source);\n const config: CiteConfig = {};\n if (raw.allowEmpty !== undefined)\n config.allowEmpty = asBoolean(raw.allowEmpty, \"allowEmpty\", source);\n if (raw.respectGitignore !== undefined)\n config.respectGitignore = asBoolean(raw.respectGitignore, \"respectGitignore\", source);\n if (raw.root !== undefined) config.root = asString(raw.root, \"root\", source);\n if (raw.baseline !== undefined)\n config.baseline = asString(raw.baseline, \"baseline\", source);\n if (raw.checkSources !== undefined)\n config.checkSources = asBoolean(raw.checkSources, \"checkSources\", source);\n\n if (raw.severity !== undefined) config.severity = parseSeverity(raw.severity, source);\n return config;\n}\n\n/**\n * The family file itself, found as `loadCiteConfig` finds it but before its\n * `cite:` slice is parsed: the text, the section shape and the family keys\n * (`collections:`, `encryptionKey:`), for a caller that needs more than the\n * values, such as a write that puts a key there. `null` when discovery finds\n * nothing.\n */\nexport function readCiteConfigFile(\n explicitPath: string | undefined,\n cwd: string,\n): Promise<ConfigFile | null> {\n return explicitPath\n ? readConfigFile(explicitPath, cwd, CONFIG_FILE)\n : findConfigFile(cwd, CONFIG_FILE);\n}\n\n/**\n * Load the config from an explicit path (an error if missing) or by\n * discovery: cwd and each ancestor up to the nearest `.git` boundary, reading\n * `manni.config.yaml` at its `cite:` key. A family file with neither `cite:`\n * nor `collections:` belongs to a sibling tool and discovery keeps looking;\n * one with `collections:` alone is this tool's config with no options of its\n * own (0041). See src/shared/config-file.ts for the rules. `null` when\n * discovery finds nothing.\n */\nexport async function loadCiteConfig(\n explicitPath?: string,\n cwd: string = process.cwd(),\n): Promise<LoadedCiteConfig | null> {\n const file = await readCiteConfigFile(explicitPath, cwd);\n return file === null ? null : toLoaded(file);\n}\n\n/** A discovered file's `cite:` slice, parsed, with where it came from. */\nfunction toLoaded(file: ConfigFile): LoadedCiteConfig {\n return {\n config: parseCiteConfig(file.value, file.source),\n path: file.path,\n dir: file.dir,\n source: file.source,\n collections: file.collections,\n };\n}\n\nexport interface CiteRunOptions {\n cwd: string;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /**\n * Positional inputs; empty means fall back to the selected collections'\n * `paths:`. The stdin token `-` cancels that implicit fallback like any\n * other input, but never an explicit `--collection`: stdin is no path, so\n * it rides beside the flag and the named collection is still resolved.\n */\n inputs: string[];\n /**\n * `--collection <name>`, repeatable: the collections this run covers. Empty\n * or absent means every declared one, the same thing, because commander's\n * collector hands `[]` over when the flag was never typed.\n */\n collection?: string[];\n /** `--root`, cwd-relative. */\n root?: string;\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n /** Told once when the root fell back to cwd. */\n onNotice?: (message: string) => void;\n /**\n * Whether the run resolves `src:` paths at all. Default true. `false`\n * silences the notice about where they would resolve from, which `remove`\n * has no use for: it edits a page and never reads a source.\n */\n resolvesSources?: boolean;\n /** Defaults to `process.env`; a test hands in its own. */\n env?: NodeJS.ProcessEnv;\n}\n\n/** The stdin token, repeated so this module does not depend on the file loader above it. */\nconst STDIN = \"-\";\n\n/**\n * Settle what every command core needs before it touches a file: which\n * config governs the run, what to resolve and from where, the root `src:`\n * paths resolve against, and the encryption key.\n */\nexport async function resolveCiteRun(opts: CiteRunOptions): Promise<CiteRun> {\n const cwd = resolve(opts.cwd);\n const env = opts.env ?? process.env;\n\n // `--collection` names something only a config can define, and selects a\n // set the operator did not type, so it composes with neither positional\n // paths nor `--no-config`. The same two sentences meta and a11y use.\n // Stdin is one more input rather than a path, so it rides beside the flag.\n const wanted = opts.collection ?? [];\n // The paths the operator actually typed. Stdin is not one of them, which is\n // what lets a `-` ride beside the flag instead of being refused as a path.\n const typedInputs = opts.inputs.filter((input) => input !== STDIN);\n if (wanted.length > 0 && typedInputs.length > 0) {\n throw new CiteError(\n \"--collection selects a configured collection; it cannot be combined with paths.\",\n );\n }\n\n // `--no-config` wins over an explicit path, as in meta: the CLI cannot\n // supply both, but the cores are public API. It drops the collections with\n // the section: the file the run was told to ignore is where both live.\n const file = opts.noConfig ? null : await readCiteConfigFile(opts.configPath, cwd);\n const loaded = file === null ? null : toLoaded(file);\n if (wanted.length > 0 && loaded === null) {\n throw new CiteError(\"--collection needs a config file to select from.\");\n }\n if (loaded) opts.onConfigLoaded?.({ path: loaded.path, dir: loaded.dir });\n const config = loaded ? loaded.config : null;\n\n // Selected whatever the inputs are: a typed file is still a member of the\n // collections that contain it. An unknown name is the shared helper's error.\n const collections = loaded\n ? selectCollections(loaded.collections, wanted, loaded.source, (message) => new CiteError(message))\n : [];\n\n // One base per run: positional paths are typed from a shell and stay\n // cwd-relative; a collection's `paths:` was written next to the config and\n // resolves there.\n // `--collection` is a request the run has to honour, as in meta: the named\n // collection's pages are resolved even when stdin rides beside the flag.\n // Counting `-` as a path made `cite check - --as markdown --collection\n // pages` check stdin, open no page of the collection, print no finding and\n // exit 0. The implicit fallback is not a request, and a lone `-` cancels it\n // as before: a piped page is a run of its own.\n const fromCollections = wanted.length > 0 || opts.inputs.length === 0;\n const collectionPaths = fromCollections ? collections.flatMap((c) => c.paths) : [];\n // Stdin keeps its typed position; the globs follow it in declaration order.\n const inputs = fromCollections ? [...opts.inputs, ...collectionPaths] : opts.inputs;\n // Only a path needs a base, so it follows the globs when they contributed\n // and stays at the working directory otherwise — stdin included.\n const base = collectionPaths.length > 0 && loaded ? loaded.dir : cwd;\n\n let root: string;\n if (opts.root !== undefined) {\n root = resolve(cwd, opts.root);\n } else if (loaded && config?.root !== undefined) {\n root = resolve(loaded.dir, config.root);\n } else {\n const gitRoot = findGitRoot(cwd);\n if (gitRoot !== null) {\n root = gitRoot;\n } else {\n root = cwd;\n // Said only to a run that will resolve a source against it.\n if (opts.resolvesSources !== false) {\n opts.onNotice?.(`No git root found; resolving src: paths from ${cwd}`);\n }\n }\n }\n\n // The family key, from the environment or the file's top level. A\n // malformed one is refused here, before any page is read.\n const { key, source: keySource } = resolveEncryptionKey({\n env,\n file,\n toError: (message) => new CiteError(message),\n });\n\n return {\n config,\n inputs,\n base,\n collections,\n fromCollections,\n ...(loaded ? { configDir: loaded.dir, configPath: loaded.path, configSource: loaded.source } : {}),\n root,\n key,\n keySource,\n ...(file === null ? {} : { configFile: file }),\n };\n}\n","/**\n * The one severity scale every manni tool speaks. Least to most severe.\n *\n * Three values, chosen to match the sinks every tool writes to and the\n * linters that sit beside it. GitHub annotations are `error`, `warning` and\n * `notice`; so are ESLint's and Vale's levels, and pa11y's. A flag or config\n * key that two domains both have carries the same name and the same values,\n * and this is where the values for `severity` are defined once.\n *\n * A domain whose source speaks another scale maps onto this one and keeps\n * the source's value in a field of its own, so nothing is lost for lookup.\n * a11y is the first case: axe reports four impacts, the analyzer folds them\n * onto these three, and each finding still carries axe's word as `impact`.\n */\nexport const SEVERITIES = [\"notice\", \"warning\", \"error\"] as const;\nexport type Severity = (typeof SEVERITIES)[number];\n\n/** The list the way a usage message spells it: `notice | warning | error`. */\nexport const SEVERITY_LIST: string = SEVERITIES.join(\" | \");\n\nexport function isSeverity(value: string): value is Severity {\n return (SEVERITIES as readonly string[]).includes(value);\n}\n\n/** `true` when `severity` is at or above `min`. */\nexport function meetsSeverity(severity: Severity, min: Severity): boolean {\n return SEVERITIES.indexOf(severity) >= SEVERITIES.indexOf(min);\n}\n","/**\n * `manni cite check`: resolve targets, check every page, settle the baseline.\n *\n * The run shape is meta's `validate`: `resolveCiteRun` → `resolveTargetSet` /\n * `assertNonEmpty` → one `checkCitations` per page → `settleBaseline`. One git\n * client and one source index are built for the run and handed to every page,\n * so a thousand pages against one root cost one `git ls-files`. `prepareRun`\n * is the shared front half; `update` runs the same one.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n isErrorSeverity,\n supportedExtensions,\n type FieldError,\n type FingerprintContext,\n type MetadataExtractor,\n type RunSummary,\n} from \"../../meta/index.js\";\nimport {\n assertNonEmpty,\n extractorByName,\n gitignoreOptions,\n resolveBaselineRequest,\n resolveTargetSet,\n settleBaseline,\n STDIN_LABEL,\n STDIN_TOKEN,\n} from \"../../meta/internal.js\";\nimport { toValidationResult } from \"../core/adapt.js\";\nimport { checkCitations } from \"../core/check-page.js\";\nimport { DEFAULT_CITE_BASELINE_PATH, resolveCiteRun } from \"../core/config.js\";\nimport { GIT_UNAVAILABLE_HISTORY, gitClient } from \"../core/git.js\";\nimport {\n duplicateJoinRefusal,\n ignoredManifestWarning,\n orphanRefusal,\n sidecarsFor,\n type CitationSidecars,\n type PageSidecar,\n} from \"../core/sidecar.js\";\nimport { sourceIndexFor } from \"../core/sources.js\";\nimport { warn } from \"../../shared/warn.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n CheckOptions,\n CheckPageOptions,\n CheckRun,\n CiteRun,\n GitClient,\n PageCitationReport,\n} from \"../types.js\";\n\n/** What `check` and `update` settle before touching a page. */\nexport interface PreparedRun {\n cwd: string;\n run: CiteRun;\n /** Files to process, posix and relative to `run.base`. */\n files: string[];\n gitignoreSkipped: number;\n usingStdin: boolean;\n /** The `--as` extractor, validated. */\n forced?: MetadataExtractor;\n /** What every `checkCitations` call in the run shares: root, key, table, client, index. */\n pageOptions: CheckPageOptions;\n /** The git client every page shares, the one in `pageOptions`. */\n git: GitClient;\n /** The manifests that own `citations`, or `null` when none does. */\n sidecars: CitationSidecars | null;\n /**\n * What this page's manifest supplies, and the options that carry it. One\n * call per page, so a page named by path still finds its sidecar.\n */\n setupFor: (label: string, content: string) => Promise<PageSetup>;\n /** Whether a flag reshaped the input set, which turns the corpus checks off. */\n scopedByFlags: boolean;\n /** The collections a `--collection` run narrowed to; `undefined` for a whole corpus. */\n covered?: string[];\n}\n\n/** One page's manifest entries, and the check options that carry them. */\nexport interface PageSetup {\n options: CheckPageOptions;\n /** Absent when no manifest owns this page's citations. */\n sidecar?: PageSidecar;\n}\n\n/**\n * The join values pages carried, for the duplicate-join refusal and the\n * orphan check that follows the per-page loop.\n */\nexport interface JoinHits {\n record: (page: PageSidecar, label: string) => void;\n /** Field -> the values loaded pages carried. */\n matched: Map<string, Set<string>>;\n}\n\nexport function joinHits(): JoinHits {\n const matched = new Map<string, Set<string>>();\n const seen = new Map<string, { file: string; labels: string[] }>();\n return {\n matched,\n record(page, label) {\n for (const join of page.joins) {\n const values = matched.get(join.field) ?? new Set<string>();\n values.add(join.value);\n matched.set(join.field, values);\n const id = `${join.field}\\u0000${join.value}`;\n const hit = seen.get(id) ?? { file: join.file, labels: [] };\n if (!hit.labels.includes(label)) hit.labels.push(label);\n seen.set(id, hit);\n // Two pages behind one entry: the manifest cannot tell them apart,\n // and a write would land on whichever the run reached last.\n if (hit.labels.length > 1) {\n throw new CiteError(\n duplicateJoinRefusal(join.field, join.value, join.file, hit.labels),\n );\n }\n }\n },\n };\n}\n\n/** What a command's sources mean to it, where that is not `check`'s answer. */\nexport interface SourceNeeds {\n /** The run cannot work without them: `--no-check-sources` is refused (`update`). */\n require?: boolean;\n /** The run resolves `src:` paths at all. `false` for `remove`, which edits the page. */\n resolve?: boolean;\n}\n\n/**\n * The front half of a run: which config governs it, which files it covers,\n * and the clients every page shares. `action` is the past-tense verb the\n * empty-set error uses (\"checked\"), `verb` the imperative one (\"check\").\n */\nexport async function prepareRun(\n opts: CheckOptions,\n action: string,\n verb: string,\n sources: SourceNeeds = {},\n): Promise<PreparedRun> {\n const requireSources = sources.require === true;\n const cwd = resolve(opts.cwd ?? process.cwd());\n const run = await resolveCiteRun({\n cwd,\n configPath: opts.configPath,\n noConfig: opts.noConfig,\n inputs: opts.inputs,\n collection: opts.collection,\n root: opts.root,\n onConfigLoaded: opts.onConfigLoaded,\n onNotice: opts.onNotice,\n env: opts.env,\n ...(sources.resolve === false ? { resolvesSources: false } : {}),\n });\n const { config, inputs, base } = run;\n\n const checkSources = opts.checkSources ?? config?.checkSources ?? true;\n if (requireSources && !checkSources) {\n throw new CiteError(`${verb} needs the sources: drop --no-check-sources (or \\`checkSources: false\\`).`);\n }\n if (inputs.length === 0) {\n throw new CiteError(\n `No files to ${verb}. Pass paths/globs, or declare a collection under \\`collections:\\` in manni.config.yaml.`,\n );\n }\n\n const usingStdin = inputs.includes(STDIN_TOKEN);\n const forced = opts.as === undefined ? undefined : extractorByName(opts.as);\n if (opts.as !== undefined && forced === undefined) {\n throw new CiteError(\n `Unknown format \"${opts.as}\". Supported extensions: ${supportedExtensions().join(\", \")}.`,\n );\n }\n if (usingStdin && forced === undefined) {\n throw new CiteError(\"Reading from stdin (`-`) requires --as <format> to choose an extractor.\");\n }\n\n const exts = opts.exts ?? forced?.extensions;\n const fileInputs = inputs.filter((input) => input !== STDIN_TOKEN);\n const allowEmpty = opts.allowEmpty ?? config?.allowEmpty;\n // A collection's `exclude:` shapes the collection, so it applies when the\n // inputs came from the collections and never to a path the operator typed.\n // `--exclude` filters either way; the union is deduplicated, first spelling wins.\n const exclude = [\n ...new Set([\n ...(opts.exclude ?? []),\n ...(run.fromCollections ? run.collections.flatMap((c) => c.exclude) : []),\n ]),\n ];\n const { files, gitignoreSkipped } = await resolveTargetSet({\n inputs: fileInputs,\n exts,\n exclude,\n cwd: base,\n allowEmpty,\n ...gitignoreOptions({\n flag: opts.respectGitignore,\n configured: config?.respectGitignore,\n onNotice: opts.onNotice,\n }),\n });\n assertNonEmpty({ files, inputs: fileInputs, usingStdin, allowEmpty, exclude, exts, gitignoreSkipped, action });\n\n // Git is used whenever it is there: on PATH, with the root inside a work\n // tree. Where it is not, the index is a walk and history is off, and a page\n // whose citations wanted history says so (see `checkCitations`).\n const git = opts.gitClient ?? gitClient(run.root);\n // A claim's history is the page's own, so it is read in the repository the\n // page paths resolve from, which is not the sources' under `--root`.\n const pageGit =\n opts.pageGitClient ?? (run.base === run.root ? git : gitClient(run.base));\n const pageOptions: CheckPageOptions = {\n root: run.root,\n checkSources,\n key: run.key,\n severity: config?.severity,\n gitClient: git,\n pageRoot: run.base,\n pageGitClient: pageGit,\n };\n if (checkSources) pageOptions.sourceIndex = await sourceIndexFor(run.root, git);\n\n // The sidecar manifests, read once per run. Membership is every declared\n // collection's, whatever this run selected, so a page given by path still\n // finds the manifest that owns its citations.\n // A `{page}` manifest (0058) is read for exactly the pages this run checks.\n const sidecars = await sidecarsFor(run, { pages: files.map((file) => resolve(base, file)) });\n const setupFor = async (label: string, content: string): Promise<PageSetup> => {\n const page = await sidecars?.forPage(label, content, forced?.name);\n if (page?.owner === undefined) return { options: pageOptions };\n return {\n sidecar: page,\n options: {\n ...pageOptions,\n owned: { file: page.owner.file, collection: page.owner.collection },\n ...(page.citations === undefined ? {} : { citations: page.citations }),\n },\n };\n };\n\n // The corpus invariant meta's orphan checks use: any CLI reshaping of the\n // input set means the operator chose to look at part of the corpus, and an\n // entry for the rest is expected rather than orphaned. `--collection` is\n // not such a reshaping; it makes each named collection a corpus of its own.\n const scopedByFlags =\n // The inputs the operator typed, not the collection globs they resolved\n // to: a corpus run has none of the first and all of the second.\n opts.inputs.length > 0 ||\n usingStdin ||\n opts.as !== undefined ||\n opts.exts !== undefined ||\n (opts.exclude !== undefined && opts.exclude.length > 0) ||\n opts.respectGitignore !== undefined;\n const covered = (opts.collection?.length ?? 0) > 0 ? run.collections.map((c) => c.name) : undefined;\n\n return {\n cwd,\n run,\n files,\n gitignoreSkipped,\n usingStdin,\n forced,\n pageOptions,\n git,\n sidecars,\n setupFor,\n scopedByFlags,\n ...(covered === undefined ? {} : { covered }),\n };\n}\n\n/**\n * The manifest entries a corpus run found nothing for, and the stray\n * `{page}` manifests (proposal 0058). A run the CLI narrowed checks nothing:\n * it never claimed to cover the corpus.\n *\n * A whole run, not narrowed by `--collection` either, also warns once for a\n * page's own manifest that `.gitignore` covers: CI checks out the page\n * without it.\n */\nexport async function assertNoOrphans(prepared: PreparedRun): Promise<void> {\n const { sidecars } = prepared;\n if (sidecars === null || prepared.scopedByFlags) return;\n const orphans = sidecars.orphans(prepared.files, prepared.covered);\n if (orphans.length > 0) throw orphanRefusal(orphans);\n if (prepared.covered !== undefined) return;\n for (const file of await sidecars.ignoredManifests(prepared.files)) warn(ignoredManifestWarning(file));\n}\n\n/** The same invariant, for field-joined entries no loaded page matched. */\nexport function assertNoOrphanJoins(prepared: PreparedRun, hits: JoinHits): void {\n const { sidecars } = prepared;\n if (sidecars === null || prepared.scopedByFlags) return;\n const orphans = sidecars.orphanJoins(hits.matched, prepared.covered);\n if (orphans.length > 0) throw orphanRefusal(orphans);\n}\n\n/** Read a resolved target, as the run labelled it. */\nexport function readTarget(run: CiteRun, file: string): Promise<string> {\n return readFile(resolve(run.base, file), \"utf8\");\n}\n\n/**\n * Run-level notices are said once per run, however many pages raised them.\n * `also` is what the run has to say beyond its pages: said after them, and\n * not again when a page already said it.\n */\nexport function sayNotices(\n pages: readonly PageCitationReport[],\n onNotice: CheckOptions[\"onNotice\"],\n also: readonly string[] = [],\n): void {\n const said = new Set<string>();\n for (const notice of [...pages.flatMap((page) => page.notices), ...also]) {\n if (said.has(notice)) continue;\n said.add(notice);\n onNotice?.(notice);\n }\n}\n\nexport async function runCheck(opts: CheckOptions): Promise<CheckRun> {\n const prepared = await prepareRun(opts, \"checked\", \"check\");\n const { cwd, run, files, gitignoreSkipped, usingStdin, forced, pageOptions, git } = prepared;\n await assertNoOrphans(prepared);\n const hits = joinHits();\n\n const pages: PageCitationReport[] = [];\n const checkOne = async (label: string, content: string): Promise<void> => {\n const setup = await prepared.setupFor(label, content);\n if (setup.sidecar !== undefined) hits.record(setup.sidecar, label);\n pages.push(await checkCitations({ file: label, content, format: forced?.name }, setup.options));\n };\n if (usingStdin) await checkOne(STDIN_LABEL, opts.stdinContent ?? \"\");\n for (const file of files) await checkOne(file, await readTarget(run, file));\n assertNoOrphanJoins(prepared, hits);\n // `--show-diff` wants history whatever the pages carry. With the sources\n // off nothing is classified, so nothing wants git.\n const wantsDiff = opts.showDiff === true && pageOptions.checkSources !== false && !(await git.available());\n sayNotices(pages, opts.onNotice, wantsDiff ? [GIT_UNAVAILABLE_HISTORY] : []);\n\n const results = pages.map(toValidationResult);\n // Fingerprints must not depend on where the command was run from, so they\n // are measured from the config's directory when one governs the run.\n const frame: FingerprintContext = { cwd, base: run.configDir ?? cwd, runBase: run.base };\n const request = resolveBaselineRequest(opts, run.config?.baseline, run.configDir, cwd, {\n current: DEFAULT_CITE_BASELINE_PATH,\n });\n // The ratchet's own not-found error names `meta validate`; this tool's\n // baseline is recorded by its own command, so the advice has to say so.\n if (request !== null && !request.write && !existsSync(request.absPath)) {\n throw new CiteError(\n `Baseline \"${request.label}\" not found. Record one with \\`manni cite check --write-baseline\\`, or drop --baseline.`,\n );\n }\n const { results: reported, baseline } = await settleBaseline(results, request, frame);\n\n const failed = reported.filter((r) => !r.ok).length;\n const count = (keep: (e: FieldError) => boolean): number =>\n reported.reduce((n, r) => n + r.errors.filter(keep).length, 0);\n const warnings = count((e) => e.severity === \"warning\");\n const notices = count((e) => e.severity === \"notice\");\n const summary: RunSummary = {\n files: reported.length,\n passed: reported.length - failed,\n failed,\n errors: count(isErrorSeverity),\n // Omitted at zero, as meta's summary has them, so the JSON shape of a\n // clean run is the one every consumer of `meta validate` already reads.\n ...(warnings > 0 ? { warnings } : {}),\n ...(notices > 0 ? { notices } : {}),\n ...(gitignoreSkipped > 0 ? { gitignoreSkipped } : {}),\n ...(baseline ? { baseline } : {}),\n };\n\n return { results: reported, summary, frame, pages, warnings, notices };\n}\n","/**\n * `manni cite add`: mint one citation and write it to a page.\n *\n * The page lines are the claim: `add docs/limits.md:9 lib/limits.ts:2` pins\n * line 9 of the page to line 2 of the source. Lines reach the command as an\n * editor numbers them and are stored body-relative, so editing the\n * frontmatter never moves them. `--marker` writes a `cite <id>` comment above\n * those lines instead, and pins the text it anchors; `--quote` says the lines\n * are a fenced block that reproduces the source. No lines at all is a bare\n * pin: this page rests on these lines, say so when they change.\n *\n * Every refusal is a `CiteError` (exit 2) with the page and the source\n * spelled as the caller spelled them, and nothing is written. Among them are\n * the pins the command can already see are wrong: a duplicate of an entry the\n * page has, and a claim whose lines hold no text at all.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\nimport { locateFrontmatter, writeFileAtomic } from \"../../meta/index.js\";\nimport { STDIN_LABEL, STDIN_TOKEN } from \"../../meta/internal.js\";\nimport { ensureEncryptionKey } from \"../../shared/prompt.js\";\nimport { isEncryptedValue } from \"../../shared/encryption.js\";\nimport {\n blockMatches,\n otherClaimSpans,\n pinOfLines,\n spellElsewhere,\n toBodyLines,\n toFileLines,\n} from \"../core/claims.js\";\nimport { resolveCiteRun } from \"../core/config.js\";\nimport { GIT_UNAVAILABLE_COMMIT, gitClient } from \"../core/git.js\";\nimport { sliceLines, splitLines } from \"../core/hash.js\";\nimport { mintCitation } from \"../core/mint.js\";\nimport { bodyLineOf, readPage } from \"../core/page.js\";\nimport {\n formatSrc,\n lineSpec,\n parseLines,\n parseSrc,\n spellLines,\n spellSource,\n tooWide,\n} from \"../core/range.js\";\nimport { misplacedMarkers } from \"../core/reanchor.js\";\nimport { shiftedEntries, withClaimLines, type Shifted } from \"../core/shift.js\";\nimport { readSource, sourceIndexFor } from \"../core/sources.js\";\nimport { shortSrc, spellAt } from \"../core/spell.js\";\nimport { ManifestSet } from \"../core/manifest.js\";\nimport { sidecarsFor, type PageSidecar } from \"../core/sidecar.js\";\nimport {\n ANY_FENCE,\n MAX_IDS_PER_MARKER,\n anchoredLines,\n fenceSpanAt,\n formatStatement,\n isMarkerLine,\n markerIndent,\n offsetOfLine,\n respellStatement,\n unitHolding,\n} from \"../core/statements.js\";\nimport {\n appendFrontmatterCitation,\n entryObject,\n insertStatementBefore,\n spliceEntryField,\n unifiedDiff,\n} from \"../core/write.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n AddOptions,\n AddResult,\n Citation,\n CitationClaim,\n PageCitation,\n PageCitations,\n PageLines,\n SourceIndex,\n} from \"../types.js\";\n\n/** The schema's id grammar, checked before anything is written. */\nconst ID = /^[a-z0-9][a-z0-9-]*$/;\n\nconst toPosix = (path: string): string => path.replace(/\\\\/g, \"/\");\n\nfunction isEnoent(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nasync function readPageFile(path: string, label: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error) {\n if (isEnoent(error)) throw new CiteError(`File not found: \"${label}\".`);\n throw error;\n }\n}\n\n/** The cited lines, joined as the hashing rule joins them. */\nasync function citedText(\n root: string,\n index: SourceIndex,\n src: string,\n key: string | undefined,\n): Promise<string> {\n const range = parseSrc(src);\n const source = await readSource(root, index, range, key);\n // Minting already read this range, so a miss here is a race with the disk.\n if (source.kind === \"missing\") {\n throw new CiteError(`Source not readable: ${range.path} could not be read.`);\n }\n return sliceLines(splitLines(source.text), range, range.path);\n}\n\n/** How a refusal names an entry: its id, or the pointer a report would use. */\nfunction entryName(entry: PageCitation): string {\n return entry.citation.id ?? `/citations/${String(entry.origin.index)}`;\n}\n\n/**\n * The entry that already pins these very page lines to this very source, in\n * the frontmatter or in the manifest that owns the page's citations. A bare\n * pin matches another bare pin over the same source.\n *\n * The source is compared as each end spells it, so an encrypted one compares\n * as its ciphertext and no path is decrypted to say so. A marker add is not\n * asked: it stores no claim lines, and its own id and anchor checks cover it.\n */\nfunction duplicateOf(\n page: PageCitations,\n src: string,\n pageLines: PageLines | undefined,\n): PageCitation | undefined {\n // opts.src is the caller's plain-path spelling; an existing entry encrypted\n // under a key compares as its ciphertext and will never match here.\n const wanted = formatSrc(parseSrc(src));\n return page.citations.find((entry) => {\n const { citation } = entry;\n if (spellSource(citation.source) !== wanted) return false;\n if (pageLines === undefined) return citation.claim === undefined;\n const spec = citation.claim?.lines;\n if (spec === undefined) return false;\n const recorded = parseLines(spec);\n if (recorded === undefined) return false;\n const file = toFileLines(recorded, page.bodyLine);\n return file.start === pageLines.start && file.end === pageLines.end;\n });\n}\n\n/** Whether a page line can hold no claim at all: it is blank, or it is a fence. */\nfunction holdsNoText(text: string): boolean {\n return text.trim() === \"\" || ANY_FENCE.test(text);\n}\n\n/**\n * The refusal for a claim whose lines hold no text, `at` being the page and\n * the lines as the caller spelled them. Undefined when at least one line\n * carries text. `--quote` never asks, because a quote is fences and content\n * by design.\n */\nfunction emptyClaimRefusal(\n lines: readonly string[],\n pageLines: PageLines,\n at: string,\n): string | undefined {\n const span = lines.slice(pageLines.start - 1, pageLines.end);\n if (span.some((text) => !holdsNoText(text))) return undefined;\n if (pageLines.start !== pageLines.end) return `${at} holds no claim text.`;\n const only = span[0] ?? \"\";\n return only.trim() === \"\" ? `${at} is blank.` : `${at} is a fence line, not claim text.`;\n}\n\nexport async function runAdd(opts: AddOptions): Promise<AddResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const run = await resolveCiteRun({\n cwd,\n configPath: opts.configPath,\n noConfig: opts.noConfig,\n inputs: [],\n root: opts.root,\n onConfigLoaded: opts.onConfigLoaded,\n onNotice: opts.onNotice,\n env: opts.env,\n });\n const { root } = run;\n\n const usingStdin = opts.page === STDIN_TOKEN;\n if (usingStdin && opts.as === undefined) {\n throw new CiteError(\"Reading from stdin (`-`) requires --as <format> to choose an extractor.\");\n }\n // `-` names no file: nothing to resolve, and nothing to write back to.\n const path = usingStdin ? undefined : resolve(cwd, opts.page);\n const label = path === undefined ? STDIN_LABEL : toPosix(relative(cwd, path));\n const content = path === undefined ? (opts.stdinContent ?? \"\") : await readPageFile(path, label);\n\n // The manifests that own `citations`, if any collection declares one. The\n // page is labelled from the working directory here, so membership is\n // measured from there too.\n const sidecars = await sidecarsFor(run, {\n base: cwd,\n // A `{page}` manifest (0058) is read for the one page being cited.\n ...(path === undefined ? {} : { pages: [path] }),\n });\n const firstManifest = sidecars?.manifests[0];\n if (usingStdin && firstManifest !== undefined) {\n const keyedBy = firstManifest.join === \"path\" ? \"path\" : firstManifest.join;\n throw new CiteError(\n `A page read from stdin has no path, and its citations live in ${firstManifest.file}, which is keyed by ${keyedBy}.`,\n );\n }\n const sidecar: PageSidecar | undefined = usingStdin\n ? undefined\n : await sidecars?.forPage(label, content, opts.as);\n const owner = sidecar?.owner;\n\n const page = readPage(label, content, {\n ...(opts.as === undefined ? {} : { format: opts.as }),\n // The entries already there are the manifest's, so `--id` uniqueness and\n // the marker checks are measured against them and not against a page\n // that carries none.\n ...(sidecar?.citations === undefined ? {} : { citations: sidecar.citations }),\n ...(owner === undefined ? {} : { owned: { file: owner.file, collection: owner.collection } }),\n });\n const { format } = page;\n\n const pageLines = opts.pageLines;\n const marker = opts.marker === true;\n const quote = opts.quote === true;\n const at = pageLines === undefined ? \"\" : `${label}:${spellLines(pageLines)}`;\n\n // Composition first: these need no source and no search.\n if (marker && pageLines === undefined) {\n throw new CiteError(`--marker needs the page lines to anchor: ${label}:L.`);\n }\n if (marker && opts.id === undefined) {\n throw new CiteError(\"--marker needs --id: the marker names the entry.\");\n }\n const wide = pageLines === undefined ? undefined : tooWide(pageLines);\n if (wide !== undefined) throw new CiteError(`Invalid range \"${at}\": it ${wide}.`);\n if (quote && pageLines === undefined) {\n throw new CiteError(`--quote needs the block's lines: ${label}:L1-L2.`);\n }\n if (opts.id !== undefined && !ID.test(opts.id)) {\n throw new CiteError(\n `Invalid id \"${opts.id}\": use lowercase letters, digits and hyphens, starting with a letter or digit.`,\n );\n }\n if (opts.id !== undefined && page.citations.some((c) => c.citation.id === opts.id)) {\n throw new CiteError(`${label} already has an entry ${opts.id}.`);\n }\n if (marker && opts.id !== undefined) {\n // Joining an id a marker already names would write it twice into one\n // list, which is `marker-invalid`. The entry check above catches the\n // ordinary case; this one is left by a marker whose entry went away.\n const already = page.statements.find(\n (s) => s.payload.kind === \"ref\" && s.payload.ids.includes(opts.id ?? \"\"),\n );\n if (already !== undefined) {\n throw new CiteError(\n `${label} already has a marker ${opts.id} at line ${String(already.line)}.`,\n );\n }\n }\n // The same claim on the same source twice is one citation reported twice,\n // and the second is what a re-run of a script writes.\n const duplicate = marker ? undefined : duplicateOf(page, opts.src, pageLines);\n if (duplicate !== undefined) {\n const src = shortSrc(spellSource(duplicate.citation.source));\n const what =\n pageLines === undefined\n ? `a bare pin for ${src}`\n : `an entry for ${spellAt(pageLines)} and ${src}`;\n throw new CiteError(`${label} already has ${what} (${entryName(duplicate)}).`);\n }\n\n const lines = splitLines(content);\n if (pageLines !== undefined) {\n if (pageLines.end > lines.length) {\n throw new CiteError(`${at} is past the end of the page (${String(lines.length)} lines).`);\n }\n if (pageLines.start < page.bodyLine) {\n throw new CiteError(`${at} is in the frontmatter. A claim is body text.`);\n }\n if (quote) {\n const span = fenceSpanAt(content, pageLines.start, format);\n if (span === undefined || span.end !== pageLines.end) {\n throw new CiteError(`${at} is not a fenced block, so it cannot be a quote.`);\n }\n } else if (!marker) {\n // A pin over a fence or a blank line holds for as long as the page has\n // one, so a check would call it `current` whatever the prose does.\n const empty = emptyClaimRefusal(lines, pageLines, at);\n if (empty !== undefined) throw new CiteError(empty);\n }\n // `add` does not move a marker it did not write, so it refuses to write\n // where a misplaced one would make its entry wrong (proposal 0054).\n const split = misplacedMarkers(page, lines);\n const held = split.find(\n (found) => found.line >= pageLines.start && found.line <= pageLines.end,\n );\n if (held !== undefined) {\n throw new CiteError(\n `${at} holds the marker at line ${String(held.line)}, which splits its paragraph. Run manni cite update first.`,\n );\n }\n const inside = marker\n ? split.find(\n (found) => pageLines.start >= found.unit.start && pageLines.start <= found.unit.end,\n )\n : undefined;\n if (inside !== undefined) {\n throw new CiteError(\n `${at} is in the paragraph at ${spellAt(inside.unit)}, which the marker at line ${String(inside.line)} splits. Run manni cite update first.`,\n );\n }\n }\n\n // Git is used whenever it is there, as on check and update: the index is\n // `git ls-files` and the commit is HEAD. Where it is not, a walk and none.\n const client = opts.gitClient ?? gitClient(root);\n const sourceIndex = await sourceIndexFor(root, client);\n\n // The marker goes in before the claim is pinned, because what it anchors is\n // what the claim pins. Everything below counts lines in `body`, the page\n // with the marker, and the frontmatter append shifts them once at the end.\n let body = content;\n let markerAt: number | undefined;\n /** Whether the id joined a marker already there, rather than getting a line. */\n let markerJoined = false;\n let claimSpan: PageLines | undefined;\n let claim: CitationClaim | undefined;\n // Where else the claim's text sits, for the notice at the end of the run.\n let elsewhere: PageLines[] = [];\n // Entries whose claim lines sit below a marker move down with the text.\n let shifted: Shifted = { frontmatter: [], manifest: new Map() };\n if (marker && pageLines !== undefined) {\n // The marker goes above the paragraph or block holding the lines, below\n // any markers already stacked there, at its indentation, and the lines\n // must stay inside it.\n // A marker line is never part of a pin, so a marker written there would\n // change what the line below it pins. The refusal is keyed to the line\n // rather than to what the marker names.\n if (isMarkerLine(lines[pageLines.start - 1] ?? \"\", format)) {\n throw new CiteError(\n `${label}:${String(pageLines.start)} is a marker line. A marker there would change its pin.`,\n );\n }\n const holding = unitHolding(content, pageLines.start, format, {\n offset: page.bodyOffset,\n line: page.bodyLine,\n });\n if (holding === undefined) {\n throw new CiteError(`${at} has no paragraph or block for a marker to anchor.`);\n }\n if (pageLines.end > holding.end) {\n throw new CiteError(\n `${at} runs past the ${holding.kind} at ${spellAt(holding)}. A marker anchors one paragraph.`,\n );\n }\n // A marker pins everything it anchors, so the range limit applies to that.\n const unitWide = tooWide({ start: holding.start, end: holding.end });\n if (unitWide !== undefined) {\n throw new CiteError(\n `${at} is in a ${holding.kind} at ${spellAt(holding)} that ${unitWide}. A marker anchors the whole ${holding.kind}.`,\n );\n }\n // The marker nearest the anchored text: the one on the text own line when\n // there is one, else the last marker line above it. A reader associates\n // the nearest comment with the prose, and appending there needs no other\n // line to move (proposal 0056).\n const above = page.statements.filter((s) => s.anchorLine === holding.start);\n const nearest = above[above.length - 1];\n // A marker already holding the cap takes no more, so the twenty-sixth\n // citation gets a marker line of its own. Refusing would leave no way to\n // cite the paragraph short of editing the line by hand. A marker the\n // scanner could not read is left alone for the same reason.\n //\n // So is one whose delimiters sit on different lines. That parses, but\n // respelling it folds it onto one line, and the claims below it would\n // then all be one line out while this path shifts nothing.\n const held =\n nearest !== undefined &&\n nearest.payload.kind === \"ref\" &&\n nearest.payload.ids.length < MAX_IDS_PER_MARKER &&\n !/[\\r\\n]/.test(nearest.raw)\n ? nearest.payload.ids\n : undefined;\n /** Where the marker ends in `body`, so what follows it can be anchored. */\n let after: number;\n if (nearest !== undefined && held !== undefined) {\n body = respellStatement(content, nearest, [...held, opts.id ?? \"\"]);\n // Joining changes one line in place, so nothing below it moves and no\n // claim on the page is re-spelled.\n after = nearest.end + (body.length - content.length);\n markerAt = nearest.line;\n markerJoined = true;\n } else {\n shifted = shiftedEntries({\n citations: page.citations,\n at: [holding.start],\n delta: 1,\n bodyLine: page.bodyLine,\n label,\n });\n const statement =\n markerIndent(content, holding.start, format, page.bodyLine) +\n formatStatement(format, { kind: \"ref\", ids: [opts.id ?? \"\"] });\n const insertAt = offsetOfLine(content, holding.start);\n body = insertStatementBefore(content, insertAt, statement);\n after = insertAt + statement.length;\n markerAt = holding.start;\n }\n const unit = anchoredLines(body, after, format, quote);\n const pin = unit === undefined ? undefined : pinOfLines(splitLines(body), unit);\n if (unit === undefined || pin === undefined) {\n throw new CiteError(`${at} has no paragraph or block for a marker to anchor.`);\n }\n for (const { index, lines: moved } of shifted.frontmatter) {\n body = spliceEntryField(body, format, index, [\"claim\", \"lines\"], moved);\n }\n claimSpan = unit;\n claim = { integrity: pin };\n } else if (pageLines !== undefined) {\n const pin = pinOfLines(lines, pageLines);\n if (pin === undefined) {\n throw new CiteError(`${at} is past the end of the page (${String(lines.length)} lines).`);\n }\n claimSpan = pageLines;\n claim = { lines: lineSpec(toBodyLines(pageLines, page.bodyLine)), integrity: pin };\n elsewhere = otherClaimSpans(lines, pageLines, pin, page.bodyLine);\n }\n\n const mint = (key: string | undefined, encrypt: boolean): Promise<Citation> =>\n mintCitation({\n root,\n src: opts.src,\n ...(opts.id === undefined ? {} : { id: opts.id }),\n ...(claim === undefined ? {} : { claim }),\n ...(quote ? { quote: true } : {}),\n ...(opts.commitSha === false ? { commitSha: false as const } : {}),\n encrypt,\n ...(key === undefined ? {} : { key }),\n gitClient: client,\n sourceIndex,\n });\n\n // Encryption follows the key: an available one encrypts every add, with no\n // flag to remember, and `--encrypt` asks for one when there is none. With a\n // key in hand this mint is the citation written. Without one it is plain,\n // and settles every refusal that needs no key before the question is put,\n // so a refused add never leaves a key behind.\n const needsKey = opts.encrypt === true && run.key === undefined;\n let citation = await mint(run.key, run.key !== undefined);\n\n if (quote && claimSpan !== undefined) {\n // The lines inside the fences are what the source has to match.\n const cited = await citedText(root, sourceIndex, opts.src, run.key);\n const inside = splitLines(body).slice(claimSpan.start, claimSpan.end - 1).join(\"\\n\");\n if (!blockMatches(inside, cited)) {\n throw new CiteError(`The block at ${at} does not reproduce ${opts.src}.`);\n }\n }\n\n if (needsKey) {\n const { key } = await ensureEncryptionKey({\n subject: opts.src,\n cwd,\n file: run.configFile ?? null,\n env: opts.env,\n confirm: opts.confirm,\n notice: (message) => {\n opts.onNotice?.(message);\n },\n toError: (message) => new CiteError(message),\n });\n citation = await mint(key, true);\n }\n\n // The first pinned source line, so the report shows what the range caught\n // and a mis-typed one is visible at write time. A whole file has no first\n // line worth naming, and an encrypted source is never spelled in the open.\n const srcRange = parseSrc(opts.src);\n let sourceLine: string | undefined;\n if (srcRange.start !== undefined && !isEncryptedValue(citation.source.file)) {\n const read = await readSource(root, sourceIndex, srcRange, undefined);\n if (read.kind === \"ok\") sourceLine = splitLines(read.text)[srcRange.start - 1];\n }\n\n // Where the entry goes follows the config, not a flag: a collection whose\n // manifest owns `citations` keeps them there, and the page is left alone\n // but for a marker.\n const manifests = new ManifestSet();\n let placed: AddResult[\"manifest\"];\n /** Which item of the entry's `citations` this run added, for the line report. */\n let index = 0;\n if (owner !== undefined) {\n if (sidecar?.entry === undefined) {\n throw new CiteError(\n `${label} carries no ${owner.join}: value, so its citations cannot be keyed in ${owner.file}.`,\n );\n }\n const existing = (sidecar.citations ?? []).map((input, index) => {\n const moved = shifted.manifest.get(index);\n return moved === undefined ? input.entry : withClaimLines(input.entry, moved);\n });\n const list = [...existing, entryObject(citation)];\n index = list.length - 1;\n const at = await manifests.write(owner, sidecar.entry, list, index);\n const [changed] = manifests.changed();\n placed = {\n file: at.file,\n line: at.line,\n content: changed?.text ?? \"\",\n diff: changed?.diff ?? \"\",\n written: false,\n };\n }\n\n const after = owner === undefined ? appendFrontmatterCitation(body, format, citation, label) : body;\n // The frontmatter append leaves the body's bytes alone, so every body line\n // moves by exactly what the block grew. The marker sits in the body, so the\n // page it was inserted into already has this page's body line. An entry\n // written to a manifest grows no block, so nothing moves.\n const shift = bodyLineOf(after, locateFrontmatter(after)?.closeEnd ?? 0) - page.bodyLine;\n\n const result: AddResult = {\n file: label,\n citation,\n placed: owner === undefined ? \"frontmatter\" : \"manifest\",\n content: after,\n diff: unifiedDiff(label, content, after),\n written: false,\n ...(sourceLine === undefined ? {} : { sourceLine }),\n ...(placed === undefined ? {} : { manifest: placed }),\n };\n if (markerAt !== undefined) result.markerLine = markerAt + shift;\n if (markerJoined) result.markerJoined = true;\n if (claimSpan !== undefined) {\n result.claimLines = { start: claimSpan.start + shift, end: claimSpan.end + shift };\n }\n\n // A manifest entry leaves the page byte for byte as it was, unless a\n // marker went into the body; there is then nothing to write.\n result.written = path !== undefined && opts.dryRun !== true && after !== content;\n if (result.written && path !== undefined) await writeFileAtomic(path, after);\n // The entry goes in under compare-and-swap, so what lands may be a replay\n // onto a manifest another command wrote while this one was running. The\n // report names the bytes and the line that actually landed, not the ones\n // this run spliced from.\n if (result.manifest !== undefined && opts.dryRun !== true) {\n const [settled] = await manifests.commit();\n if (owner !== undefined && sidecar?.entry !== undefined) {\n result.manifest.line = manifests.lineOf(owner, sidecar.entry, index) ?? result.manifest.line;\n }\n if (settled !== undefined) {\n result.manifest.content = settled.text;\n result.manifest.diff = settled.diff;\n }\n result.manifest.written = true;\n }\n // The claim's text repeats, so a later move of it could not be told apart\n // from its copies. Said once the entry is written: it is not a refusal, and\n // the lines it names are the page's own after the write.\n if (elsewhere.length > 0) {\n const named = elsewhere.map((span) => ({ start: span.start + shift, end: span.end + shift }));\n const who = citation.id === undefined ? \"\" : `${citation.id}: `;\n opts.onNotice?.(\n `${who}the claim's text also appears at ${spellElsewhere(named)}, so a move would be ambiguous. Use --marker, or pin more lines.`,\n );\n }\n // A commit was wanted (no --no-commit-sha) and git had none to give. Said\n // once the add has succeeded, so a refused add says nothing about git.\n if (opts.commitSha !== false && !(await client.available())) {\n opts.onNotice?.(GIT_UNAVAILABLE_COMMIT);\n }\n return result;\n}\n","/**\n * `manni cite remove`: take a citation off a page.\n *\n * The inverse of `add`, and it undoes all of what `add` did. The entry goes\n * out of the page's frontmatter, or out of the manifest that owns the page's\n * citations, whichever `add` would have written to. Every marker naming it\n * goes out of the body: the id goes out of the marker list, and the whole\n * line goes when that id was the last one (proposal 0056). The claims below\n * each removed marker line move up with the text they pin, which is the\n * inverse of the shift `add --marker` performs and the same rule\n * (`shiftedEntries`). A marker that only loses a word moves nothing.\n *\n * `--only` is required, one entry per occurrence, and nothing is written\n * until every one of them has been found: a run either removes what it was\n * told to or writes nothing. That is `add`'s contract, and the reason there\n * is no exit 1 here.\n *\n * An id with a marker and no entry removes the marker alone, which is how a\n * `marker-orphan` is cleared.\n */\nimport { resolve } from \"node:path\";\nimport { writeFileAtomic } from \"../../meta/index.js\";\nimport { STDIN_LABEL } from \"../../meta/internal.js\";\nimport { ManifestSet } from \"../core/manifest.js\";\nimport { citationInputs, pickExtractor, readPage } from \"../core/page.js\";\nimport { shiftedEntries, withClaimLines } from \"../core/shift.js\";\nimport { isMarkerLine, respellEdit } from \"../core/statements.js\";\nimport { splitLines } from \"../core/hash.js\";\nimport {\n applyEdits,\n lineRemovals,\n removeFrontmatterCitations,\n spliceEntryField,\n unifiedDiff,\n} from \"../core/write.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n CitationInput,\n InlineStatement,\n ManifestChange,\n Removal,\n RemoveOptions,\n RemovePage,\n RemoveRun,\n TextEdit,\n} from \"../types.js\";\nimport { assertNoOrphanJoins, assertNoOrphans, joinHits, prepareRun, readTarget } from \"./check.js\";\n\n/** How an entry with no id is named: its place in the page's list. */\nconst POINTER = /^\\/citations\\/(0|[1-9][0-9]*)$/;\n\n/** `4 entries`, `1 entry`. */\nfunction entryCount(n: number): string {\n return `${String(n)} ${n === 1 ? \"entry\" : \"entries\"}`;\n}\n\n/** The `id` of a raw entry, whether or not the schema would accept the rest of it. */\nfunction idOf(entry: unknown): string | undefined {\n if (typeof entry !== \"object\" || entry === null || Array.isArray(entry)) return undefined;\n const id: unknown = (entry as Record<string, unknown>).id;\n return typeof id === \"string\" ? id : undefined;\n}\n\n/** What one page's run found, before anything is written. */\ninterface Planned {\n page: RemovePage;\n /** The page as it will be written, when it changed. */\n content?: string;\n /** Absolute path to write it to; absent for the stdin page. */\n path?: string;\n}\n\nexport async function runRemove(opts: RemoveOptions): Promise<RemoveRun> {\n // Repeats collapse, as they do on `--collection`: naming one entry twice\n // asks for one removal, and would otherwise be counted twice.\n const only = [...new Set(opts.only)];\n // Asked before the config is read: it is a usage error, and the answer does\n // not depend on anything on disk.\n if (only.length === 0) {\n throw new CiteError(\"remove needs --only <id>; it never removes every citation on a page.\");\n }\n // Nothing here resolves a source: the run builds no index, and says\n // nothing about where `src:` paths would have come from.\n const prepared = await prepareRun({ ...opts, checkSources: false }, \"removed\", \"remove\", {\n resolve: false,\n });\n const { run, files, usingStdin, forced } = prepared;\n await assertNoOrphans(prepared);\n const hits = joinHits();\n const manifests = new ManifestSet();\n /** Every `--only` value that named something, anywhere in the run. */\n const matched = new Set<string>();\n const pageCount = files.length + (usingStdin ? 1 : 0);\n\n const planned: Planned[] = [];\n const removeOne = async (label: string, content: string, path?: string): Promise<void> => {\n const setup = await prepared.setupFor(label, content);\n if (setup.sidecar !== undefined) hits.record(setup.sidecar, label);\n const owner = setup.sidecar?.owner;\n const page = readPage(label, content, {\n ...(forced === undefined ? {} : { format: forced.name }),\n ...(setup.options.citations === undefined ? {} : { citations: setup.options.citations }),\n ...(owner === undefined ? {} : { owned: { file: owner.file, collection: owner.collection } }),\n });\n const { format } = page;\n const extractor = pickExtractor(label, forced?.name);\n const inputs: CitationInput[] = citationInputs(\n label,\n extractor.extract(content, label),\n setup.sidecar?.citations,\n );\n const lines = splitLines(content);\n\n /** The entries one `--only` value names on this page. */\n const entriesFor = (value: string): number[] => {\n // The digits of a pointer, or nothing for a value that is an id. Read\n // as a capture rather than through `exec(...) !== null`, so the index\n // is a string the compiler has seen narrowed.\n const [, digits] = POINTER.exec(value) ?? [];\n if (digits === undefined) {\n return inputs.flatMap((input, index) => (idOf(input.entry) === value ? [index] : []));\n }\n const index = Number(digits);\n if (index < inputs.length) return [index];\n // A pointer is a position, so over several pages it means the entry at\n // that position wherever there is one. Against one page there is no\n // other page it could have meant.\n if (pageCount === 1) {\n throw new CiteError(\n `\"${value}\" is past the last entry of ${label} (${entryCount(inputs.length)}).`,\n );\n }\n return [];\n };\n /** The markers naming an id. */\n const markersFor = (id: string | undefined): InlineStatement[] =>\n id === undefined\n ? []\n : page.statements.filter(\n (s) => s.payload.kind === \"ref\" && s.payload.ids.includes(id),\n );\n /** Per marker line, the ids this run takes out of its list. */\n const dropped = new Map<number, { statement: InlineStatement; ids: Set<string> }>();\n const drop = (statement: InlineStatement, id: string): void => {\n const held = dropped.get(statement.line) ?? { statement, ids: new Set<string>() };\n held.ids.add(id);\n dropped.set(statement.line, held);\n };\n\n const removed: Removal[] = [];\n const indices = new Set<number>();\n const markerLines: number[] = [];\n for (const value of only) {\n const found = entriesFor(value);\n for (const index of found) {\n const input = inputs[index];\n const id = idOf(input?.entry);\n const markers = markersFor(id);\n indices.add(index);\n markerLines.push(...markers.map((s) => s.line));\n if (id !== undefined) for (const statement of markers) drop(statement, id);\n removed.push({\n ...(id === undefined ? {} : { id }),\n index,\n ...(input === undefined ? {} : { origin: input.origin }),\n markerLines: markers.map((s) => s.line),\n });\n matched.add(value);\n }\n if (found.length > 0) continue;\n // An id no entry carries, but a marker names: the marker alone.\n const markers = markersFor(value);\n if (markers.length === 0) continue;\n markerLines.push(...markers.map((s) => s.line));\n for (const statement of markers) drop(statement, value);\n removed.push({ id: value, markerLines: markers.map((s) => s.line) });\n matched.add(value);\n }\n const nothing: RemovePage = { file: label, removed: [], diff: \"\", written: false };\n if (removed.length === 0) {\n // The stdin page is printed whatever the run did to it.\n if (path === undefined) nothing.content = content;\n planned.push({ page: nothing, ...(path === undefined ? {} : { path }) });\n return;\n }\n\n // A marker sharing its line with text anchors that text, so the line is\n // not the tool's to delete. The refusal is a property of the line rather\n // than of the payload, so it holds however many ids the marker names.\n const touched = [...new Set(markerLines)].sort((a, b) => a - b);\n for (const line of touched) {\n if (!isMarkerLine(lines[line - 1] ?? \"\", format)) {\n const id = page.statements.find((s) => s.line === line)?.payload;\n const named = id?.kind === \"ref\" ? ` ${id.ids.join(\" \")}` : \"\";\n throw new CiteError(\n `the marker${named} at ${label}:${String(line)} shares its line with text; remove it by hand.`,\n );\n }\n }\n // A marker that keeps an id keeps its line: the word goes out of the list\n // and nothing below it moves. Only a marker that loses its last id is a\n // line to delete (proposal 0056).\n const kept = new Map<number, [string, ...string[]]>();\n const ordered: number[] = [];\n for (const line of touched) {\n const held = dropped.get(line);\n // Destructured rather than cast: a marker that keeps nothing is a line\n // to delete, and the head is what tells the two apart.\n const [head, ...rest] =\n held === undefined || held.statement.payload.kind !== \"ref\"\n ? []\n : held.statement.payload.ids.filter((id) => !held.ids.has(id));\n if (head === undefined) ordered.push(line);\n else kept.set(line, [head, ...rest]);\n }\n\n // What stays, moved up by the marker lines going out above it.\n const survivors = page.citations.filter((c) => !indices.has(c.origin.index));\n const shifted = shiftedEntries({\n citations: survivors,\n at: ordered,\n delta: -1,\n bodyLine: page.bodyLine,\n label,\n });\n\n // One parse, one pass.\n //\n // Every position the body rewrite reads -- a statement's byte offsets, a\n // marker's line number -- is read against `content`, the page as it was\n // parsed, and the edits are collected as spans and applied together. So no\n // offset is used after the text it indexes has changed, and no writer has\n // to run before or after another to be correct. The ordering contract this\n // carried is gone rather than satisfied: it was got wrong three times, in\n // three review rounds, and each time silently -- the edit lands nowhere,\n // the entry leaves the frontmatter, and the marker still names the id\n // until some later `cite check` reports a `marker-orphan` with nothing to\n // explain it.\n const edits: TextEdit[] = [];\n for (const [line, ids] of kept) {\n const held = dropped.get(line);\n if (held === undefined) continue;\n const edit = respellEdit(content, held.statement, ids);\n // `content` is the text the statement was parsed from, so the payload is\n // where the statement says it is. A miss would mean the parse and the\n // page disagree, which is worth stopping for rather than writing a page\n // whose marker still names an id no entry has.\n if (edit === undefined) {\n throw new CiteError(\n `manni cannot read the marker at ${label}:${String(line)} to rewrite it; remove it by hand.`,\n );\n }\n edits.push(edit);\n }\n // The marker lines that lost their last id, taken out with their\n // terminators. Neighbours merge into one span, so no two of them reach for\n // the same break.\n edits.push(...lineRemovals(content, ordered));\n let after = applyEdits(content, edits);\n // Then the frontmatter. Both of its writers re-derive their own position\n // from the text they are handed -- `spliceEntryField` by re-extracting,\n // `removeFrontmatterCitations` by re-reading the list -- so neither reads\n // anything out of the parse above and neither cares what the body pass\n // did. The splice still runs before the removal, but for a different\n // reason: its `index` counts the entries the page has now, and the removal\n // is what renumbers them.\n for (const { index, lines: moved } of shifted.frontmatter) {\n after = spliceEntryField(after, format, index, [\"claim\", \"lines\"], moved);\n }\n if (owner === undefined) {\n after = removeFrontmatterCitations(after, format, indices, label);\n } else {\n if (setup.sidecar?.entry === undefined) {\n throw new CiteError(\n `${label} carries no ${owner.join}: value, so its citations cannot be keyed in ${owner.file}.`,\n );\n }\n const kept = inputs\n .map((input, index) => {\n const moved = shifted.manifest.get(index);\n return moved === undefined ? input.entry : withClaimLines(input.entry, moved);\n })\n .filter((_entry, index) => !indices.has(index));\n if (kept.length === 0) await manifests.remove(owner, setup.sidecar.entry);\n // The line a written entry sits on is what `add` reports; a removal\n // reports the line the entry sat on before, from its origin. So the\n // answer is dropped here, and the index it is measured from is any\n // index at all.\n else void (await manifests.write(owner, setup.sidecar.entry, kept, 0));\n }\n\n const out: RemovePage = {\n file: label,\n removed,\n diff: after === content ? \"\" : unifiedDiff(label, content, after),\n written: false,\n };\n // The stdin page has nowhere to be written; the caller prints it instead.\n if (path === undefined) out.content = after;\n planned.push({ page: out, ...(after === content ? {} : { content: after }), ...(path === undefined ? {} : { path }) });\n };\n\n if (usingStdin) await removeOne(STDIN_LABEL, opts.stdinContent ?? \"\");\n for (const file of files) {\n await removeOne(file, await readTarget(run, file), resolve(run.base, file));\n }\n assertNoOrphanJoins(prepared, hits);\n\n // Every name has to have been found somewhere before a byte is written.\n const missing = only.find((value) => !matched.has(value));\n if (missing !== undefined) {\n const where =\n pageCount === 1\n ? `${planned[0]?.page.file ?? \"the page\"} has no`\n : `none of ${String(pageCount)} pages has an`;\n const what = POINTER.test(missing) ? `entry ${missing}` : `entry or marker ${missing}`;\n throw new CiteError(`${where} ${what}.`);\n }\n\n const write = opts.dryRun !== true;\n for (const item of planned) {\n if (item.content === undefined || item.path === undefined) continue;\n if (write) await writeFileAtomic(item.path, item.content);\n item.page.written = write;\n }\n const rewritten: ManifestChange[] = [];\n const record = (changed: { file: string; diff: string }): void => {\n rewritten.push({ file: changed.file, diff: changed.diff, written: write });\n };\n if (write) await manifests.commit({ after: record });\n else for (const changed of manifests.changed()) record(changed);\n\n const pages = planned.map((item) => item.page);\n return {\n pages,\n removed: pages.reduce((n, page) => n + page.removed.length, 0),\n ...(rewritten.length > 0 ? { manifests: rewritten } : {}),\n };\n}\n","/**\n * `manni cite update`: repair what moved; with `--accept`, re-pin what changed.\n *\n * A moved end gets its `lines` spliced where it stands, so comments and\n * quoting are untouched: `claim.lines` for a claim found verbatim elsewhere on\n * the page, `source.lines` for a source found elsewhere in its file. A moved\n * source is re-minted over the range it moved to, so its `commit-sha` names a\n * commit its new lines are true at. A marker never moves, because it travels\n * with its own text.\n *\n * `--accept` re-pins a changed end. A claim is re-pinned over the paragraph,\n * fenced block or table rows now at its first line, and the report prints that\n * text, so the log shows exactly what was accepted. A paragraph grows with the\n * sentence it gained; a table keeps the number of rows the claim was minted\n * over, because a row is a statement of its own. A claim it cannot re-pin is\n * skipped with the reason named, and a sentence that was reworded *and* moved\n * is an `add` again. A source is re-minted at HEAD, with a new `commit-sha`\n * where the entry records one.\n *\n * Every finding the run did not resolve is reported as skipped, and an\n * error-severity one is work left undone: exit 1, as `fill` has it. Writes by\n * default (0025).\n */\nimport { resolve } from \"node:path\";\nimport { writeFileAtomic } from \"../../meta/index.js\";\nimport { STDIN_LABEL } from \"../../meta/internal.js\";\nimport { checkCitations } from \"../core/check-page.js\";\nimport {\n noUnitAt,\n normalizeWhitespace,\n otherClaimSpans,\n pinOfLines,\n spellElsewhere,\n toBodyLines,\n toFileLines,\n unitAt,\n type ClaimUnit,\n type NoUnit,\n} from \"../core/claims.js\";\nimport { historyOf } from \"../core/classify.js\";\nimport { GIT_UNAVAILABLE_COMMIT, SHALLOW_RECOMMIT } from \"../core/git.js\";\nimport { splitLines } from \"../core/hash.js\";\nimport { claimWords, sharesSentence, wordShare } from \"../core/history.js\";\nimport { mintCitation } from \"../core/mint.js\";\nimport { ManifestSet } from \"../core/manifest.js\";\nimport { readPage } from \"../core/page.js\";\nimport {\n formatSrc,\n lineSpec,\n parseLines,\n parseSrc,\n sourceRange,\n spellLines,\n tooWide,\n} from \"../core/range.js\";\nimport {\n applyMarkerMoves,\n misplacedMarkers,\n type MisplacedMarker,\n} from \"../core/reanchor.js\";\nimport { resolveSeverity } from \"../core/severity.js\";\nimport { listOf, spellAt } from \"../core/spell.js\";\nimport { anchoredLines, markerIndent, offsetOfLine } from \"../core/statements.js\";\nimport { spliceEntryField, unifiedDiff } from \"../core/write.js\";\nimport { CiteError } from \"../errors.js\";\nimport type {\n Citation,\n CitationResult,\n CiteRule,\n ClaimEnd,\n LineSpec,\n ManifestChange,\n PageCitation,\n PageCitationReport,\n PageCitations,\n PageLines,\n RecommitReason,\n UpdateOptions,\n UpdatePage,\n UpdateRewrite,\n UpdateRun,\n} from \"../types.js\";\nimport {\n assertNoOrphanJoins,\n assertNoOrphans,\n joinHits,\n prepareRun,\n readTarget,\n sayNotices,\n} from \"./check.js\";\n\ntype Plan =\n | { kind: \"claim-moved\"; result: CitationResult; lines: LineSpec; from: string; to: string }\n /**\n * The pinned lines sit elsewhere in the file now. The entry is re-minted\n * over them, so its `lines`, its `integrity` and its `commit-sha` are three\n * parts of one reading rather than two new ones and a stale third.\n */\n | {\n kind: \"source-moved\";\n result: CitationResult;\n /** The new `source.lines`; absent for a whole-file pin, which has none. */\n lines?: LineSpec;\n /**\n * The new `source.file`, when the pin followed its text into another\n * file. The entry's own `commit-sha` is then left alone: the pin was\n * minted at that commit and still holds, so HEAD would record a mint\n * that never happened (proposal 0055).\n */\n file?: string;\n /** The pin the entry carries afterwards. */\n pin: string;\n /** The commit to advance to, for a move inside the entry's own file. */\n commitSha?: string;\n to: string;\n }\n | {\n kind: \"claim-accepted\";\n result: CitationResult;\n unit: ClaimUnit;\n pin: string;\n lines?: LineSpec;\n /**\n * The line held wholly other text and `--only` named the entry, so the\n * accept stands. The report says so rather than reading as an edit.\n */\n replaced?: true;\n /** The marker's line on the page this run leaves, where one anchors. */\n markerLine?: number;\n }\n /**\n * A changed source, re-pinned at HEAD. Where the in-range search found the\n * old first and last line, the re-mint covers the span they bracket rather\n * than the recorded range, and `source.lines` follows it (proposal 0055).\n */\n | {\n kind: \"source-accepted\";\n result: CitationResult;\n minted: Citation;\n /** The span accepted, when it is not the range the entry records. */\n span?: { lines: LineSpec; from: string; to: string };\n }\n /**\n * The source holds, but the commit it is recorded against does not contain\n * the pinned lines, or is not in the history of HEAD. Only `commit-sha`\n * moves; the pin itself is untouched.\n */\n | {\n kind: \"source-recommitted\";\n result: CitationResult;\n /** The commit the entry records now, and cannot support. */\n from: string;\n /** HEAD, which was checked to contain the lines before this was planned. */\n commitSha: string;\n because: RecommitReason;\n }\n | { kind: \"marker-moved\"; result: CitationResult; from: number; to: number }\n | {\n kind: \"claim-reanchored\";\n result: CitationResult;\n pin: string;\n /** The span that held, in file lines, and the span now pinned. */\n held: string;\n now: string;\n }\n | {\n kind: \"claim-shifted\";\n result: CitationResult;\n lines: LineSpec;\n from: string;\n to: string;\n }\n /**\n * The words the pin covered are unchanged and only the layout moved\n * (proposal 0053). A plain `update` re-pins it, and rewrites its `lines:`\n * when the entry has them.\n */\n | {\n kind: \"claim-words-held\";\n result: CitationResult;\n pin: string;\n /** The file line of the claim's first body line, after any marker move. */\n at: number;\n /** The stored span and the span now pinned, in file lines. */\n fromLines: string;\n toLines: string;\n commitSha?: string;\n lines?: LineSpec;\n }\n /**\n * A changed claim `--accept` refused to re-pin: the line now holds text\n * sharing no sentence with the claim at its baseline, or too few of its\n * words. Nothing is written.\n */\n | {\n kind: \"claim-replaced\";\n result: CitationResult;\n at: number;\n commitSha: string;\n /** The share of the claim's words held, when overlap is what refused it. */\n wordShare?: number;\n /** The pin that stands, and the one that was not written. */\n pin: string;\n would: string;\n };\n\n/**\n * Why one repair was declined, and the rule whose finding says so. One entry\n * can carry findings about both ends, so the reason names which it is about.\n */\ninterface Declined {\n rule: string;\n why: string;\n}\n\n/**\n * Why `--accept` re-pinned nothing at the claim's line, said plainly. Each\n * reason is a different problem: a blank line lost the sentence, a claim that\n * runs out of its fenced block covers a fence rather than code, a line that\n * starts no paragraph is a heading underline or an unclosed fence, a line\n * outside the body is a range the page no longer reaches, a short table lost\n * rows the claim was minted over, and a marker or a table rule is a line that\n * holds no claim text at all.\n */\nfunction sayNoUnit(reason: NoUnit): string {\n switch (reason) {\n case \"outside\":\n return \"the line is outside the page body\";\n case \"blank\":\n return \"the line is blank\";\n case \"fence-crossed\":\n return \"the claim's lines are not all inside one fenced block\";\n case \"marker\":\n return \"that line now holds a cite marker, not claim text\";\n case \"not-a-paragraph\":\n return \"the line does not start a paragraph\";\n case \"table-short\":\n return \"the table no longer holds every row the claim covers\";\n case \"table-rule\":\n return \"that line is a table rule, not claim text\";\n }\n}\n\n/** A unit named in a refusal. `fenced-lines` is a span of code, not a block. */\nfunction unitNoun(kind: ClaimUnit[\"kind\"]): string {\n return kind === \"fenced-lines\" ? \"fenced text\" : kind;\n}\n\n/** The rule a plan settles, so its finding is not also reported as skipped. */\nfunction settles(plan: Plan): string {\n switch (plan.kind) {\n case \"claim-moved\":\n return \"claim-moved\";\n case \"source-moved\":\n return \"source-moved\";\n case \"claim-accepted\":\n return \"claim-changed\";\n case \"source-accepted\":\n return plan.result.source.status === \"never-true\" ? \"source-never-true\" : \"source-changed\";\n case \"marker-moved\":\n return \"marker-misplaced\";\n case \"claim-reanchored\":\n return \"claim-moved\";\n case \"claim-words-held\":\n return \"claim-reanchored\";\n // A refused claim leaves nothing written, but its finding is the row the\n // refusal prints, so it is not also reported as skipped.\n case \"claim-replaced\":\n return \"claim-changed\";\n // A shifted entry was `current`, so it had no finding to settle. A\n // re-committed one was `current` too: `check` never reported it, which is\n // why the repair is asked for rather than offered.\n case \"claim-shifted\":\n case \"source-recommitted\":\n return \"\";\n }\n}\n\nfunction apply(content: string, format: string, plan: Plan): string {\n const index = plan.result.origin.index;\n switch (plan.kind) {\n case \"claim-moved\":\n case \"claim-shifted\":\n return spliceEntryField(content, format, index, [\"claim\", \"lines\"], plan.lines);\n case \"claim-reanchored\":\n return spliceEntryField(content, format, index, [\"claim\", \"integrity\"], plan.pin);\n case \"claim-words-held\": {\n let out = spliceEntryField(content, format, index, [\"claim\", \"integrity\"], plan.pin);\n if (plan.lines !== undefined) {\n out = spliceEntryField(out, format, index, [\"claim\", \"lines\"], plan.lines);\n }\n return out;\n }\n // Nothing is written for a refused claim; the report is the whole of it.\n case \"claim-replaced\":\n // The move is a page rewrite, applied to the whole page before any splice.\n case \"marker-moved\":\n return content;\n case \"source-moved\": {\n let out = content;\n if (plan.file !== undefined) {\n out = spliceEntryField(out, format, index, [\"source\", \"file\"], plan.file);\n }\n if (plan.lines !== undefined) {\n out = spliceEntryField(out, format, index, [\"source\", \"lines\"], plan.lines);\n }\n out = spliceEntryField(out, format, index, [\"source\", \"integrity\"], plan.pin);\n // As on a re-mint: HEAD is written only where the entry already records\n // a commit, because the splice replaces a scalar and never adds a key.\n if (plan.commitSha !== undefined) {\n out = spliceEntryField(out, format, index, [\"source\", \"commit-sha\"], plan.commitSha);\n }\n return out;\n }\n case \"source-recommitted\":\n return spliceEntryField(content, format, index, [\"source\", \"commit-sha\"], plan.commitSha);\n case \"claim-accepted\": {\n let out = spliceEntryField(content, format, index, [\"claim\", \"integrity\"], plan.pin);\n if (plan.lines !== undefined) {\n out = spliceEntryField(out, format, index, [\"claim\", \"lines\"], plan.lines);\n }\n return out;\n }\n case \"source-accepted\": {\n let out = content;\n if (plan.span !== undefined) {\n out = spliceEntryField(out, format, index, [\"source\", \"lines\"], plan.span.lines);\n }\n out = spliceEntryField(\n out,\n format,\n index,\n [\"source\", \"integrity\"],\n plan.minted.source.integrity,\n );\n const commit = plan.minted.source[\"commit-sha\"];\n // An entry with no `commit-sha:` line of its own keeps none: the splice\n // replaces a scalar, it does not add a key.\n if (commit !== undefined) {\n out = spliceEntryField(out, format, index, [\"source\", \"commit-sha\"], commit);\n }\n return out;\n }\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The same repair, against an entry that lives in a manifest. The page's\n * whole `citations` value is written back at the end of the run, so a repair\n * here is an edit to the parsed entry rather than a splice of one scalar.\n * An entry the writer cannot reach — a list item that is not a mapping —\n * leaves its finding reported.\n */\nfunction applyToEntry(entry: unknown, plan: Plan): boolean {\n if (!isRecord(entry)) return false;\n const end = (name: \"claim\" | \"source\"): Record<string, unknown> | undefined =>\n isRecord(entry[name]) ? entry[name] : undefined;\n switch (plan.kind) {\n case \"claim-moved\":\n case \"claim-shifted\": {\n const claim = end(\"claim\");\n if (claim === undefined) return false;\n claim.lines = plan.lines;\n return true;\n }\n case \"claim-reanchored\": {\n const claim = end(\"claim\");\n if (claim === undefined) return false;\n claim.integrity = plan.pin;\n return true;\n }\n case \"claim-words-held\": {\n const claim = end(\"claim\");\n if (claim === undefined) return false;\n claim.integrity = plan.pin;\n if (plan.lines !== undefined) claim.lines = plan.lines;\n return true;\n }\n // Nothing is written for a refused claim.\n case \"claim-replaced\":\n // The page holds the marker, so the manifest has nothing to change.\n case \"marker-moved\":\n return true;\n case \"source-moved\": {\n const source = end(\"source\");\n if (source === undefined) return false;\n if (plan.file !== undefined) source.file = plan.file;\n if (plan.lines !== undefined) source.lines = plan.lines;\n source.integrity = plan.pin;\n if (plan.commitSha !== undefined) source[\"commit-sha\"] = plan.commitSha;\n return true;\n }\n case \"source-recommitted\": {\n const source = end(\"source\");\n if (source === undefined) return false;\n source[\"commit-sha\"] = plan.commitSha;\n return true;\n }\n case \"claim-accepted\": {\n const claim = end(\"claim\");\n if (claim === undefined) return false;\n claim.integrity = plan.pin;\n if (plan.lines !== undefined) claim.lines = plan.lines;\n return true;\n }\n case \"source-accepted\": {\n const source = end(\"source\");\n if (source === undefined) return false;\n if (plan.span !== undefined) source.lines = plan.span.lines;\n source.integrity = plan.minted.source.integrity;\n const commit = plan.minted.source[\"commit-sha\"];\n // As on a page: a re-mint records a commit only where the entry\n // already recorded one, so this never adds the key.\n if (commit !== undefined) source[\"commit-sha\"] = commit;\n return true;\n }\n }\n}\n\nfunction rewriteOf(plan: Plan): UpdateRewrite {\n const { citation, origin, source } = plan.result;\n const base: Pick<UpdateRewrite, \"id\" | \"index\" | \"line\"> = { index: origin.index };\n if (citation.id !== undefined) base.id = citation.id;\n if (origin.line !== undefined) base.line = origin.line;\n\n switch (plan.kind) {\n case \"claim-moved\":\n return {\n ...base,\n end: \"claim\",\n reason: \"moved\",\n status: \"moved\",\n from: plan.from,\n to: plan.to,\n fromLines: plan.from,\n toLines: plan.to,\n };\n case \"marker-moved\": {\n const from = String(plan.from);\n const to = String(plan.to);\n return {\n ...base,\n end: \"marker\",\n reason: \"re-anchored\",\n status: \"misplaced\",\n from,\n to,\n fromLines: from,\n toLines: to,\n };\n }\n case \"claim-reanchored\": {\n const was = citation.claim?.integrity ?? \"\";\n return {\n ...base,\n end: \"claim\",\n reason: \"re-anchored\",\n status: \"moved\",\n from: was,\n to: plan.pin,\n fromPin: was,\n toPin: plan.pin,\n lines: plan.held,\n newLines: plan.now,\n };\n }\n case \"claim-words-held\": {\n const was = citation.claim?.integrity ?? \"\";\n const out: UpdateRewrite = {\n ...base,\n end: \"claim\",\n reason: \"re-anchored\",\n status: \"reanchored\",\n from: was,\n to: plan.pin,\n fromPin: was,\n toPin: plan.pin,\n fromLines: plan.fromLines,\n toLines: plan.toLines,\n at: plan.at,\n };\n if (plan.commitSha !== undefined) out.commitSha = plan.commitSha;\n return out;\n }\n case \"claim-replaced\":\n return {\n ...base,\n end: \"claim\",\n reason: \"replaced\",\n status: \"changed\",\n from: plan.pin,\n to: plan.would,\n fromPin: plan.pin,\n toPin: plan.would,\n at: plan.at,\n commitSha: plan.commitSha,\n ...(plan.wordShare === undefined ? {} : { wordShare: plan.wordShare }),\n };\n case \"claim-shifted\":\n return {\n ...base,\n end: \"claim\",\n reason: \"shifted\",\n status: \"current\",\n from: plan.from,\n to: plan.to,\n fromLines: plan.from,\n toLines: plan.to,\n };\n case \"source-moved\":\n return {\n ...base,\n end: \"source\",\n reason: \"moved\",\n status: \"moved\",\n from: source.src,\n to: plan.to,\n };\n case \"source-recommitted\":\n return {\n ...base,\n end: \"source\",\n reason: \"recommitted\",\n // The source itself held. Only its date was wrong.\n status: \"current\",\n because: plan.because,\n from: plan.from,\n to: plan.commitSha,\n fromCommit: plan.from,\n toCommit: plan.commitSha,\n src: source.src,\n };\n case \"claim-accepted\": {\n const was = citation.claim?.integrity ?? \"\";\n const out: UpdateRewrite = {\n ...base,\n end: \"claim\",\n reason: \"accepted\",\n // A bypassed guard reads `replaced`, so the log shows that the line\n // held other text and a named accept took it anyway.\n status: plan.replaced === true ? \"replaced\" : \"changed\",\n from: was,\n to: plan.pin,\n fromPin: was,\n toPin: plan.pin,\n at: plan.unit.lines.start,\n text: quoted(plan.unit.text),\n };\n // A re-pin over a unit wider than the stored lines names both spans.\n const stored = plan.result.claim?.fileLines;\n const now = spellLines(plan.unit.lines);\n if (stored !== undefined && stored !== now) {\n out.fromLines = stored;\n out.toLines = now;\n }\n // Where the report says the claim is: its marker, when one anchors it.\n // A marker this run moved reads at the line it now sits on, so the row\n // and the move above it name one line rather than two.\n const markerLine =\n plan.markerLine ?? (plan.result.anchor === \"marker\" ? plan.result.markerLine : undefined);\n if (markerLine !== undefined) out.markerLine = markerLine;\n return out;\n }\n case \"source-accepted\": {\n const out: UpdateRewrite = {\n ...base,\n end: \"source\",\n reason: \"accepted\",\n status: source.status === \"never-true\" ? \"never-true\" : \"changed\",\n from: citation.source.integrity,\n to: plan.minted.source.integrity,\n fromPin: citation.source.integrity,\n toPin: plan.minted.source.integrity,\n src: source.src,\n };\n // A re-mint over the span the old first and last line now bracket names\n // both ranges, so the acceptance says which lines it accepted.\n if (plan.span !== undefined) {\n out.fromLines = plan.span.from;\n out.toLines = plan.span.to;\n }\n const commit = plan.minted.source[\"commit-sha\"];\n if (commit !== undefined) out.commitSha = commit;\n return out;\n }\n }\n}\n\n/**\n * How much of the claim's words its line must still hold for a blanket\n * `--accept` to re-pin it, as `wordShare` measures it.\n *\n * A replay of 65 proposed `--accept` re-pins over this repository's own\n * corpus, every one with a baseline to read, put the seven wrong re-pins at\n * 0.38 and below and every safe one at 0.74 and above. Each of the seven had\n * drifted onto a neighbouring table row, and the sentence test below let all\n * seven through. Nothing measured landed between the two bands, so the number\n * is fixed here. A config key would be a knob over a gap no corpus fills.\n */\nconst CLAIM_WORD_SHARE = 0.5;\n\n/** Why a re-pin was refused: the baseline, and the share when overlap is what fired. */\ninterface Replacement {\n /** The baseline the claim's words were read against. */\n commit: string;\n /** Set only when the overlap test fired: the share of the claim's words held. */\n share?: number;\n}\n\n/**\n * Why a re-pin over `text` would bless a line that no longer carries the\n * claim: a neighbouring table row after a shift, or a block inserted under a\n * marker. `undefined` lets the accept stand, which is also what happens with\n * no baseline to read the claim against.\n *\n * Two tests, either of which refuses. The first is sentence intersection: a\n * claim whose paragraph was edited still shares a sentence with what it said\n * at the baseline, and one whose line was replaced outright shares none. The\n * second is word overlap, for the drift the first misses. Two rows of one\n * table end alike often enough to share a sentence while saying different\n * things, so a line holding less than `CLAIM_WORD_SHARE` of the claim's words\n * is refused too, and the report names the share.\n *\n * The guard only asks about an entry the run did not name. Naming an id with\n * `--only` is the human judgement the guard exists to demand, so a reviewer\n * who has read the claim and its source re-pins a reworded sentence without a\n * remove and an add. What the guard is for is a blanket `--accept` quietly\n * re-pinning a hundred claims, one of which now holds a neighbouring table\n * row. A bypass is reported rather than hidden.\n */\nfunction replacementAt(\n claim: ClaimEnd,\n text: readonly string[],\n format: string,\n): Replacement | undefined {\n const was = claim.baselineText;\n const commit = claim.commitSha;\n if (was === undefined || commit === undefined) return undefined;\n const before = claimWords(was, format);\n const now = claimWords(text, format);\n if (!sharesSentence(before, now)) return { commit };\n const share = wordShare(before, now);\n if (share < CLAIM_WORD_SHARE) return { commit, share };\n return undefined;\n}\n\n/** How many characters of re-pinned text the report quotes before it elides. */\nconst QUOTE_CAP = 200;\n\n/**\n * The text a re-pin quotes: whitespace collapsed, and capped, because the\n * unit may be a whole paragraph and the report is one line per rewrite.\n */\nfunction quoted(text: readonly string[]): string {\n const all = normalizeWhitespace(text.join(\"\\n\"));\n return all.length <= QUOTE_CAP ? all : `${all.slice(0, QUOTE_CAP)}…`;\n}\n\n/** `<id>: <text>`, or the text alone for an entry with no id. */\nfunction named(id: string | undefined, text: string): string {\n return id === undefined ? text : `${id}: ${text}`;\n}\n\n/** One misplaced marker `update` left where it is, and the rule its line reads at. */\ninterface MarkerStay {\n line: number;\n rule: CiteRule;\n message: string;\n}\n\n/** What `update` will do to a page's misplaced markers. */\ninterface MarkerDecisions {\n moves: { result: CitationResult; entry: PageCitation; misplaced: MisplacedMarker }[];\n stays: MarkerStay[];\n}\n\n/**\n * A claim-lines entry the move would change: one whose range holds the\n * marker's line, or starts above the unit and reaches the place the marker\n * goes. Moving the marker would rewrite that entry's pinned text.\n */\nfunction crossing(\n page: PageCitations,\n misplaced: MisplacedMarker,\n): string | undefined {\n for (const other of page.citations) {\n const spec = other.citation.claim?.lines;\n const recorded = spec === undefined ? undefined : parseLines(spec);\n if (recorded === undefined) continue;\n const file = toFileLines(recorded, page.bodyLine);\n const holdsMarker = file.start <= misplaced.line && misplaced.line <= file.end;\n const holdsPlace = file.start < misplaced.place && misplaced.place <= file.end;\n if (!holdsMarker && !holdsPlace) continue;\n return other.citation.id === undefined\n ? `the claim at ${spellAt(file)}`\n : `the claim of ${other.citation.id} (${spellAt(file)})`;\n }\n return undefined;\n}\n\n/**\n * Which of a page's misplaced markers move, and why each of the rest stays.\n * Every decision is taken against the page as it was read, before any write.\n */\nfunction decideMarkers(input: {\n page: PageCitations;\n report: PageCitationReport;\n lines: readonly string[];\n accept: boolean;\n only?: Set<string>;\n}): MarkerDecisions {\n const { page, report, lines, accept, only } = input;\n const out: MarkerDecisions = { moves: [], stays: [] };\n for (const misplaced of misplacedMarkers(page, lines)) {\n const entry = misplaced.entry;\n const line = misplaced.line;\n const stay = (rule: CiteRule, message: string): void => {\n out.stays.push({ line, rule, message });\n };\n // An orphan, repeated or invalid marker names no entry that can be\n // checked, and `--only` selects entries, so it selects their markers.\n if (entry === undefined) {\n if (only !== undefined) continue;\n const own = report.findings.find(\n (finding) => finding.line === line && finding.rule.startsWith(\"marker-\") && finding.rule !== \"marker-misplaced\",\n );\n stay(\n own?.rule ?? \"marker-orphan\",\n `the marker at line ${String(line)} stays, because it names no entry update can check.`,\n );\n continue;\n }\n const id = entry.citation.id;\n if (only !== undefined && (id === undefined || !only.has(id))) continue;\n const result = report.citations.find((r) => r.origin.index === entry.origin.index);\n if (result === undefined) continue;\n // Claim lines and a marker both: neither anchor can be trusted.\n if (entry.citation.claim?.lines !== undefined) {\n stay(\n \"anchor-invalid\",\n named(id, `the marker at line ${String(line)} stays, because the entry also has claim lines. Keep one.`),\n );\n continue;\n }\n const across = crossing(page, misplaced);\n if (across !== undefined) {\n stay(\n \"marker-misplaced\",\n named(id, `the marker at line ${String(line)} stays, because moving it would change ${across}.`),\n );\n continue;\n }\n if (result.claim !== null && result.claim.status === \"changed\" && !accept) {\n stay(\n \"marker-misplaced\",\n named(\n id,\n `the marker at line ${String(line)} stays, because its claim changed since it was pinned. update --accept moves it and re-pins.`,\n ),\n );\n continue;\n }\n out.moves.push({ result, entry, misplaced });\n }\n return out;\n}\n\n/**\n * The lines the span an entry's marker anchors covers on the page as it now\n * stands, and the pin over them.\n */\nfunction anchoredNow(\n content: string,\n format: string,\n lines: readonly string[],\n markerLine: number,\n quote: boolean,\n): { span: PageLines; pin: string } | undefined {\n const at = offsetOfLine(content, markerLine) + (lines[markerLine - 1]?.length ?? 0);\n const span = anchoredLines(content, at, format, quote);\n if (span === undefined) return undefined;\n const pin = pinOfLines(lines, span);\n return pin === undefined ? undefined : { span, pin };\n}\n\n/** The errno a failed write carries, when it carries one. */\nfunction codeOf(error: unknown): string | undefined {\n if (typeof error !== \"object\" || error === null || !(\"code\" in error)) return undefined;\n const code: unknown = error.code;\n return typeof code === \"string\" ? code : undefined;\n}\n\n/**\n * A run writes a page and the manifest that keys it, and a marker move needs\n * both to land. So every file this run wrote, page and manifest alike, keeps\n * its original text until the run is done, and a failed write puts them back.\n * A manifest left pinned to text its page no longer holds would read as drift\n * that never happened.\n */\nclass WrittenFiles {\n private readonly before = new Map<string, string>();\n private readonly labels = new Map<string, string>();\n\n /** Remember what `path` held before this run wrote it. */\n record(path: string, label: string, content: string): void {\n if (!this.before.has(path)) {\n this.before.set(path, content);\n this.labels.set(path, label);\n }\n }\n\n /**\n * Put every file back, and say what happened: `<file> could not be written\n * (<code>). <pages> was restored.`\n */\n async restore(file: string, error: unknown): Promise<CiteError> {\n const restored: string[] = [];\n const failed: string[] = [];\n for (const [path, content] of this.before) {\n const label = this.labels.get(path) ?? path;\n try {\n await writeFileAtomic(path, content);\n restored.push(label);\n } catch {\n failed.push(label);\n }\n }\n const code = codeOf(error);\n const why = code === undefined ? \"\" : ` (${code})`;\n const parts = [`${file} could not be written${why}.`];\n if (restored.length > 0) {\n parts.push(`${listOf(restored)} ${restored.length === 1 ? \"was\" : \"were\"} restored.`);\n }\n if (failed.length > 0) {\n parts.push(\n `${listOf(failed)} could not be restored, and ${failed.length === 1 ? \"holds\" : \"hold\"} an intermediate state.`,\n );\n }\n return new CiteError(parts.join(\" \"));\n }\n}\n\n/**\n * Citations counted as a summary counts them: an entry whose marker moved and\n * whose claim was re-pinned is one citation, not two.\n */\nfunction citationsIn(rows: readonly UpdateRewrite[]): number {\n const withMarker = new Set(rows.filter((row) => row.end === \"marker\").map((row) => row.index));\n return withMarker.size + rows.filter((row) => !withMarker.has(row.index)).length;\n}\n\nexport async function runUpdate(opts: UpdateOptions): Promise<UpdateRun> {\n const prepared = await prepareRun(opts, \"updated\", \"update\", { require: true });\n const { run, files, usingStdin, forced, pageOptions, git } = prepared;\n await assertNoOrphans(prepared);\n const hits = joinHits();\n // Each manifest is read once and written once, however many of its pages\n // the run repairs.\n const manifests = new ManifestSet();\n // What every file this run wrote held before, so a failed write is undone.\n const writes = new WrittenFiles();\n const only = opts.only !== undefined && opts.only.length > 0 ? new Set(opts.only) : undefined;\n const accept = opts.accept === true;\n const recommit = opts.recommit === true;\n if (recommit && !(await git.available())) {\n throw new CiteError(\n \"--recommit needs git to verify recorded commits, and git is not available here.\",\n );\n }\n\n /**\n * Whether `commit` is outside the history of `head`. Only a client that can\n * answer both questions, in a clone that is not shallow, says yes. A shallow\n * clone lacks commits that are in the history, so it cannot tell them from\n * a squash merge's orphans.\n */\n const outsideHistory = async (commit: string, head: string): Promise<boolean> => {\n if (git.shallow === undefined || git.isAncestor === undefined) return false;\n if (await git.shallow()) return false;\n return !(await git.isAncestor(commit, head));\n };\n\n /**\n * The commit to record for an entry whose recorded one cannot stand, and\n * why, or `undefined` to leave the entry alone.\n *\n * Three questions. First, is the recorded commit in the history of HEAD? A\n * squash merge leaves a branch commit that main never took, and it may well\n * hold the lines. Second, for a commit in the history, does it contain the\n * lines? It counts as containing them wherever in the file they sit,\n * because `update` follows a move and keeps `commit`, so line drift inside\n * one commit is the tool working rather than damage. Only a pin found\n * nowhere there is unsupported. Third, does HEAD contain them? The entry is\n * `current`, so the working tree does, but an uncommitted edit means HEAD\n * may not, and there is then no commit worth recording. The two questions\n * about lines are asked through `historyOf`, which is what `check` uses, so\n * the answers agree.\n *\n * In a full clone, a commit git cannot read fails the first question, so it\n * is re-recorded. A shallow clone cannot ask the first question. There such\n * a commit answers the second with neither yes nor no, and is left alone.\n */\n const recommitFor = async (\n result: CitationResult,\n ): Promise<{ commit: string; because: RecommitReason } | undefined> => {\n const recorded = result.citation.source[\"commit-sha\"];\n const path = result.source.resolvedPath;\n if (recorded === undefined || path === undefined) return undefined;\n const head = await git.head();\n if (head === null || head === recorded) return undefined;\n const range = sourceRange(result.citation.source);\n const pin = result.citation.source.integrity;\n const key = range.encrypted ? run.key : undefined;\n // History first. It is one memoized `merge-base` per commit, where\n // containment is one `git show` per commit and path. A commit outside the\n // history is re-recorded whatever it holds, so its file is never read.\n let because: RecommitReason;\n if (await outsideHistory(recorded, head)) because = \"not-in-history\";\n else {\n const was = await historyOf(git, recorded, path, range, pin, key, undefined);\n if (was.kind !== \"never-true\") return undefined;\n because = \"not-contained\";\n }\n // `original` means HEAD holds the pinned bytes, at the recorded lines or\n // anywhere else in the file. That is the same reading as question one, so\n // the two answers are comparable.\n const now = await historyOf(git, head, path, range, pin, key, undefined);\n return now.kind === \"original\" ? { commit: head, because } : undefined;\n };\n\n /** What this citation needs, in the order the repairs are worth trying. */\n const plansFor = async (\n result: CitationResult,\n entry: PageCitation | undefined,\n page: PageCitations,\n lines: readonly string[],\n lineNow: (line: number) => number,\n declined: Map<number, Declined>,\n ): Promise<Plan[]> => {\n const out: Plan[] = [];\n const claim = result.claim;\n // A marker-anchored claim has no `lines:` to splice; its repair is a\n // re-pin over the span the marker anchors, planned by the caller.\n if (\n result.anchor !== \"marker\" &&\n claim !== null &&\n claim.status === \"moved\" &&\n claim.newLines !== undefined\n ) {\n const at = parseLines(claim.newLines);\n // A marker that moved shifted the page under the window the search\n // found, so the lines it reported are read through the move.\n const shifted =\n at === undefined\n ? undefined\n : (() => {\n const file = toFileLines(at, page.bodyLine);\n const to = { start: lineNow(file.start), end: lineNow(file.end) };\n return to.end - to.start === file.end - file.start\n ? toBodyLines(to, page.bodyLine)\n : undefined;\n })();\n if (at !== undefined && shifted !== undefined) {\n out.push({\n kind: \"claim-moved\",\n result,\n lines: lineSpec(shifted),\n from: claim.fileLines ?? \"\",\n to: spellLines(toFileLines(shifted, page.bodyLine)),\n });\n }\n }\n // The words the pin covered are unchanged, and the run they sit in moved.\n // A plain `update` re-pins it and rewrites the entry's lines (0053).\n if (\n result.anchor !== \"marker\" &&\n claim !== null &&\n claim.status === \"reanchored\" &&\n claim.newLines !== undefined\n ) {\n const at = parseLines(claim.newLines);\n const file = at === undefined ? undefined : toFileLines(at, page.bodyLine);\n const pin = file === undefined ? undefined : pinOfLines(lines, file);\n const to =\n file === undefined ? undefined : { start: lineNow(file.start), end: lineNow(file.end) };\n if (\n file !== undefined &&\n to !== undefined &&\n pin !== undefined &&\n to.end - to.start === file.end - file.start\n ) {\n const plan: Plan = {\n kind: \"claim-words-held\",\n result,\n pin,\n at: to.start,\n fromLines: claim.fileLines ?? \"\",\n toLines: spellLines(to),\n lines: lineSpec(toBodyLines(to, page.bodyLine)),\n };\n if (claim.commitSha !== undefined) plan.commitSha = claim.commitSha;\n out.push(plan);\n }\n }\n if (result.source.status === \"moved\" && result.source.newSrc !== undefined) {\n const to = result.source.newSrc;\n const recorded = result.citation.source[\"commit-sha\"];\n const at = result.source.newLines === undefined ? undefined : parseLines(result.source.newLines);\n // The path the pin followed its text to, when that is another file. The\n // entry's own `commit-sha` then stands: the pin was minted there and\n // still holds, so HEAD would record a mint that never happened.\n const went = parseSrc(to).path;\n const crossFile = went !== result.citation.source.file;\n if (at !== undefined || result.citation.source.lines === undefined) {\n try {\n if (crossFile) {\n // Nothing to re-mint: the window hashed to the pin the entry\n // already carries, so only the stale halves of the record move.\n out.push({\n kind: \"source-moved\",\n result,\n to,\n file: went,\n pin: result.citation.source.integrity,\n ...(at === undefined ? {} : { lines: lineSpec(at) }),\n });\n } else if (at !== undefined) {\n // Re-minted over the range it moved to, not just re-pointed at it.\n // A pin whose `lines` were rewritten under an older `commit-sha`\n // names a range that commit may not even reach, and the next\n // command to ask for history reads it as a claim that never held.\n const minted = await mintCitation({\n root: run.root,\n src: to,\n ...(run.key === undefined ? {} : { key: run.key }),\n ...(recorded === undefined ? { commitSha: false as const } : {}),\n gitClient: git,\n ...(pageOptions.sourceIndex === undefined\n ? {}\n : { sourceIndex: pageOptions.sourceIndex }),\n });\n const commit = minted.source[\"commit-sha\"];\n // An entry that records a commit needs one to advance to. Without\n // git there is none, and writing the new lines alone would leave the\n // entry naming a range its own commit cannot hold, which is the\n // state this re-mint exists to prevent. So nothing is written: a\n // whole stale entry is one a later run repairs, and a half-written\n // one is not. An entry that records no commit has nothing to keep in\n // step, and is rewritten as before.\n if (recorded !== undefined && commit === undefined) {\n declined.set(result.origin.index, {\n rule: \"source-moved\",\n why: \"Not rewritten: git is not available here, so the entry's commit-sha cannot advance with its lines.\",\n });\n } else {\n out.push({\n kind: \"source-moved\",\n result,\n lines: lineSpec(at),\n to,\n pin: minted.source.integrity,\n ...(commit === undefined ? {} : { commitSha: commit }),\n });\n }\n }\n } catch (error) {\n // A range the re-mint cannot read leaves its finding reported, as a\n // source `--accept` could not re-mint does, and the finding says why\n // rather than reading as a repair that silently did nothing.\n if (!(error instanceof CiteError)) throw error;\n declined.set(result.origin.index, {\n rule: \"source-moved\",\n why: `Not rewritten: ${error.message}`,\n });\n }\n }\n }\n // Asked for, not offered: the entry is `current`, so `check` reported\n // nothing to repair here.\n if (recommit && result.source.status === \"current\") {\n const to = await recommitFor(result);\n if (to !== undefined) {\n out.push({\n kind: \"source-recommitted\",\n result,\n from: result.citation.source[\"commit-sha\"] ?? \"\",\n commitSha: to.commit,\n because: to.because,\n });\n }\n }\n if (!accept) return out;\n\n // A marker-anchored claim is re-pinned against the page the move left,\n // so the caller plans that one.\n if (claim !== null && claim.status === \"changed\" && entry !== undefined && result.anchor !== \"marker\") {\n // The paragraph, block or row now at the claim's first line. Anything\n // else is left for a fresh `cite add`, and says why.\n // The span the claim holds now, and the line it starts on. A table keeps\n // the span: the author chose how many rows the claim covers, and\n // `--accept` re-mints, never redesigns.\n //\n // Both are set for every claim that reaches here. `claimEnd` fills\n // `fileLines` only on the `claim.lines` branch, and the marker branch is\n // already excluded above, so the `undefined` arms below are the types\n // being honest rather than a case a run can land in.\n const held = claim.fileLines === undefined ? undefined : parseLines(claim.fileLines);\n const at = held?.start;\n // Naming an id is the operator saying they have read the line, so the\n // refusals that ask whether it can be claim text at all stand down.\n const named = only !== undefined;\n const unit: ClaimUnit | undefined =\n at === undefined ? undefined : unitAt(page, at, lines, held, named);\n const wantsBlock = entry.citation.quote === true;\n const pin = unit === undefined ? undefined : pinOfLines(lines, unit.lines);\n // A unit past the range limit would pin more than a citation may hold.\n const wide = unit === undefined ? undefined : tooWide(unit.lines);\n if (unit !== undefined && wide !== undefined) {\n declined.set(result.origin.index, {\n rule: \"claim-changed\",\n why: `Not re-pinned: the ${unitNoun(unit.kind)} ${wide}.`,\n });\n } else if (unit === undefined) {\n const why = at === undefined ? undefined : noUnitAt(page, at, lines, held, named);\n if (why !== undefined) {\n declined.set(result.origin.index, {\n rule: \"claim-changed\",\n why: `Not re-pinned: ${sayNoUnit(why)}.`,\n });\n }\n } else if (wantsBlock && unit.kind !== \"block\") {\n // A `quote: true` entry's claim lines are a whole fenced block, fences\n // included; `check` reads anything else as `anchor-invalid`. So a\n // quote whose first line drifted into prose, or into the middle of a\n // block, is left for a fresh `cite add` and says so.\n declined.set(result.origin.index, {\n rule: \"claim-changed\",\n why: \"Not re-pinned: quote: true, and the line no longer opens a fenced block.\",\n });\n } else if (pin !== undefined) {\n // Where else the same text sits. A pin cannot tell two copies apart,\n // so re-pinning over one of them writes a claim that is\n // `moved-ambiguous` the moment anything above it shifts. `add` refuses\n // the same pin for the same reason, before it is ever written.\n const elsewhere = named ? [] : otherClaimSpans(lines, unit.lines, pin, page.bodyLine);\n const replaced = replacementAt(claim, unit.text, page.format);\n // The order of these two matters, and it is the baseline that goes\n // first. Both refusals stop the same re-pin, but they do not carry the\n // same weight. The one the baseline earns says the line no longer\n // holds the claim, which is work left undone, and it exits 1. The\n // uniqueness refusal only reads the line as it stands and exits 0. So\n // a claim that trips both has to keep the stronger signal, or a\n // repeated line would quietly turn a failing run green.\n if (replaced !== undefined && only === undefined) {\n // `plansFor` runs only for a selected entry, so a run with `only`\n // set has named this one. `selected` says which repairs run; the\n // bypass says which entries `--accept` may re-pin, and both hold\n // here.\n out.push({\n kind: \"claim-replaced\",\n result,\n at: unit.lines.start,\n commitSha: replaced.commit,\n ...(replaced.share === undefined ? {} : { wordShare: replaced.share }),\n pin: entry.citation.claim?.integrity ?? \"\",\n would: pin,\n });\n } else if (elsewhere.length > 0) {\n // `--only` takes an id, so an entry without one has no way to say\n // \"accept it anyway\"; the advice is left off rather than made up.\n const id = result.citation.id;\n const anyway = id === undefined ? \"\" : ` Re-run with --only ${id} to accept it anyway.`;\n declined.set(result.origin.index, {\n rule: \"claim-changed\",\n why: `Not re-pinned: the text there also appears at ${spellElsewhere(elsewhere)}, so a pin cannot identify it.${anyway}`,\n });\n } else {\n const plan: Plan = { kind: \"claim-accepted\", result, unit, pin };\n if (replaced !== undefined) plan.replaced = true;\n // A paragraph that grew or shrank moves the claim's last line too.\n if (entry.citation.claim?.lines !== undefined) {\n const body = toBodyLines(unit.lines, page.bodyLine);\n const recorded = parseLines(entry.citation.claim.lines);\n if (\n recorded === undefined ||\n recorded.start !== body.start ||\n recorded.end !== body.end\n ) {\n plan.lines = lineSpec(body);\n }\n }\n out.push(plan);\n }\n }\n }\n if (result.source.status === \"changed\" || result.source.status === \"never-true\") {\n // Where the in-range search found the old first and last line. Accepting\n // the recorded range instead would hash a span the sentence never rested\n // on: an insertion inside a cited range pushes its end out of it.\n const stored = parseSrc(result.source.src);\n const span =\n result.source.newLines === undefined ? undefined : parseLines(result.source.newLines);\n const at =\n span === undefined || (span.start === stored.start && span.end === stored.end)\n ? undefined\n : { ...stored, start: span.start, end: span.end };\n try {\n // The source as the entry spells it: an encrypted one stays encrypted,\n // under the key it decrypted with, and mint keys the pin accordingly.\n // HEAD is recorded only where the entry already records a commit.\n const minted = await mintCitation({\n root: run.root,\n src: at === undefined ? result.source.src : formatSrc(at),\n ...(run.key === undefined ? {} : { key: run.key }),\n ...(result.citation.source[\"commit-sha\"] === undefined\n ? { commitSha: false as const }\n : {}),\n gitClient: git,\n ...(pageOptions.sourceIndex === undefined\n ? {}\n : { sourceIndex: pageOptions.sourceIndex }),\n });\n out.push({\n kind: \"source-accepted\",\n result,\n minted,\n ...(at === undefined || span === undefined\n ? {}\n : {\n span: {\n lines: lineSpec(span),\n from: spellLines({ start: stored.start ?? 1, end: stored.end ?? stored.start ?? 1 }),\n to: spellLines(span),\n },\n }),\n });\n } catch (error) {\n // A range the file no longer reaches cannot be re-minted; its finding stays reported.\n if (!(error instanceof CiteError)) throw error;\n }\n }\n return out;\n };\n\n const pages: UpdatePage[] = [];\n const updateOne = async (\n label: string,\n content: string,\n path?: string,\n ): Promise<PageCitationReport> => {\n const setup = await prepared.setupFor(label, content);\n if (setup.sidecar !== undefined) hits.record(setup.sidecar, label);\n const report = await checkCitations({ file: label, content, format: forced?.name }, setup.options);\n const { format } = report;\n const severity = resolveSeverity(setup.options.severity);\n const page = readPage(label, content, {\n ...(forced === undefined ? {} : { format: forced.name }),\n ...(setup.options.citations === undefined ? {} : { citations: setup.options.citations }),\n ...(setup.options.owned === undefined ? {} : { owned: setup.options.owned }),\n });\n const lines = splitLines(content);\n const rewritten: UpdateRewrite[] = [];\n const refused: UpdateRewrite[] = [];\n /** `<index>\\0<rule>` of every finding a rewrite settled. */\n const settled = new Set<string>();\n /**\n * Why a repair was declined, by entry index, said with the skipped\n * finding it concerns. The rule is carried so the reason lands on that\n * finding and not on another one about the same entry.\n */\n const declined = new Map<number, Declined>();\n\n // Misplaced markers first: the page is rewritten once, with every movable\n // marker relocated, and every pin below is taken against that page.\n const markers = decideMarkers({ page, report, lines, accept, only });\n const movedPage =\n markers.moves.length === 0\n ? undefined\n : applyMarkerMoves(\n content,\n markers.moves.map(({ misplaced }) => ({\n from: misplaced.line,\n place: misplaced.place,\n })),\n (line) => markerIndent(content, line, format, page.bodyLine),\n );\n let after = movedPage?.content ?? content;\n const afterLines = movedPage === undefined ? lines : splitLines(after);\n const movedIndexes = new Set(markers.moves.map(({ entry }) => entry.origin.index));\n const lineNow = (line: number): number => movedPage?.line(line) ?? line;\n // The manifest's entries for this page, edited in memory and written\n // back as one value once the page is done.\n const owner = setup.sidecar?.owner;\n const entries: unknown[] | undefined =\n setup.sidecar?.citations === undefined\n ? undefined\n : (JSON.parse(JSON.stringify(setup.sidecar.citations.map((c) => c.entry))) as unknown[]);\n let manifestDirty = false;\n for (const result of report.citations) {\n // `--only` selects the repairs to make. It does not select the shift a\n // marker move forces on the entries below it, which is planned for\n // every entry further down.\n const selected =\n only === undefined ||\n (result.citation.id !== undefined && only.has(result.citation.id));\n const entry = page.citations.find((c) => c.origin.index === result.origin.index);\n const plans: Plan[] = [];\n\n const move = selected\n ? markers.moves.find((m) => m.entry.origin.index === result.origin.index)\n : undefined;\n if (move !== undefined) {\n plans.push({\n kind: \"marker-moved\",\n result,\n from: move.misplaced.line,\n to: lineNow(move.misplaced.line),\n });\n }\n // The pin a marker anchors is taken against the page the moves left, so\n // the next check reads it as current however the run split.\n const marker = entry?.marker;\n const recorded = entry?.citation.claim?.integrity;\n if (\n selected &&\n result.anchor === \"marker\" &&\n marker !== undefined &&\n recorded !== undefined &&\n result.claim !== null\n ) {\n const quote = entry?.citation.quote === true;\n const now = anchoredNow(after, format, afterLines, lineNow(marker.line), quote);\n const status = result.claim.status;\n if (now !== undefined && now.pin !== recorded) {\n // A `current` claim already covers the unit the marker belongs to,\n // so only a move that split its run can leave it needing a pin.\n const unitText = afterLines.slice(now.span.start - 1, now.span.end);\n if (status === \"moved\" || (status === \"current\" && move !== undefined)) {\n plans.push({\n kind: \"claim-reanchored\",\n result,\n pin: now.pin,\n held: result.claim.fileLines ?? \"\",\n now: spellLines(now.span),\n });\n } else if (status === \"reanchored\") {\n // The marker travels with its text, so nothing moves but the pin.\n const held: Plan = {\n kind: \"claim-words-held\",\n result,\n pin: now.pin,\n at: now.span.start,\n fromLines: result.claim.fileLines ?? \"\",\n toLines: spellLines(now.span),\n };\n if (result.claim.commitSha !== undefined) held.commitSha = result.claim.commitSha;\n plans.push(held);\n } else if (status === \"changed\" && accept) {\n const kind = quote ? \"block\" : \"paragraph\";\n // A marker pins everything it anchors, so the range limit applies\n // to that, exactly as it does to a claim-lines re-pin.\n const wide = tooWide(now.span);\n if (wide !== undefined) {\n declined.set(result.origin.index, {\n rule: \"claim-changed\",\n why: `Not re-pinned: the ${kind} ${wide}.`,\n });\n } else {\n const replaced = replacementAt(result.claim, unitText, format);\n // `--only` naming the entry is the judgement the guard demands,\n // so a named accept stands and says `replaced` in the log.\n plans.push(\n replaced === undefined || only !== undefined\n ? {\n kind: \"claim-accepted\",\n result,\n pin: now.pin,\n markerLine: lineNow(marker.line),\n unit: { lines: now.span, kind, text: unitText },\n ...(replaced === undefined ? {} : { replaced: true as const }),\n }\n : {\n kind: \"claim-replaced\",\n result,\n at: now.span.start,\n commitSha: replaced.commit,\n ...(replaced.share === undefined ? {} : { wordShare: replaced.share }),\n pin: recorded,\n would: now.pin,\n },\n );\n }\n }\n }\n }\n\n if (selected) {\n plans.push(...(await plansFor(result, entry, page, lines, lineNow, declined)));\n }\n\n // A claim-lines entry the moves pushed along keeps its pinned text, so\n // its lines are rewritten in the same write. This one runs outside\n // `--only`: the page has already moved under the entry, so leaving its\n // lines behind would need a second run to put right.\n const spec = entry?.citation.claim?.lines;\n // A claim whose text moved is repaired by `claim-moved`, which finds\n // where the text went. Shifting its lines by the marker's delta would\n // point them somewhere else again, so the shift leaves it alone.\n const wentElsewhere = result.claim?.status === \"moved\";\n if (\n movedPage !== undefined &&\n spec !== undefined &&\n !wentElsewhere &&\n !plans.some((p) => p.kind === \"claim-moved\")\n ) {\n const at = parseLines(spec);\n const file = at === undefined ? undefined : toFileLines(at, page.bodyLine);\n const to =\n file === undefined ? undefined : { start: lineNow(file.start), end: lineNow(file.end) };\n if (\n file !== undefined &&\n to !== undefined &&\n to.end - to.start === file.end - file.start &&\n (to.start !== file.start || to.end !== file.end)\n ) {\n plans.push({\n kind: \"claim-shifted\",\n result,\n lines: lineSpec(toBodyLines(to, page.bodyLine)),\n from: spellLines(file),\n to: spellLines(to),\n });\n }\n }\n\n for (const plan of plans) {\n // A refused claim writes nothing, in either channel; its row is the\n // whole of it, and it keeps the finding from being reported twice.\n if (plan.kind === \"claim-replaced\") {\n refused.push(rewriteOf(plan));\n settled.add(`${String(result.origin.index)}\\0${settles(plan)}`);\n continue;\n }\n if (plan.kind === \"marker-moved\") {\n // The page already carries the move.\n } else if (result.origin.kind === \"manifest\") {\n // The manifest's entry list is shorter than the report's index, so\n // there is nothing to splice. Said rather than dropped: a silent\n // skip would report the check's own message and no reason.\n const held = entries?.[result.origin.index];\n if (held === undefined) {\n declined.set(result.origin.index, {\n rule: settles(plan),\n why: `Not rewritten: ${owner?.file ?? \"the manifest\"} has no entry at index ${String(result.origin.index)}.`,\n });\n continue;\n }\n if (!applyToEntry(held, plan)) continue;\n manifestDirty = true;\n } else {\n after = apply(after, format, plan);\n }\n rewritten.push(rewriteOf(plan));\n settled.add(`${String(result.origin.index)}\\0${settles(plan)}`);\n }\n }\n // A marker that moved settles its finding even where the entry is out of\n // the loop's reach, and a stacked run that split keeps the rest reported.\n for (const index of movedIndexes) settled.add(`${String(index)}\\0marker-misplaced`);\n if (manifestDirty && owner !== undefined && entries !== undefined) {\n if (setup.sidecar?.entry === undefined) {\n throw new CiteError(\n `${label} carries no ${owner.join}: value, so its citations cannot be keyed in ${owner.file}.`,\n );\n }\n await manifests.write(owner, setup.sidecar.entry, entries, 0);\n }\n // A marker that stays says so in place of the check's wording, at the\n // severity of the rule that kept it there. An accept this run declined\n // says why beside the finding that kept its work undone.\n const stayAt = new Map(markers.stays.map((stay) => [stay.line, stay]));\n const skipped = report.findings\n .filter(\n (finding) =>\n (only === undefined || (finding.id !== undefined && only.has(finding.id))) &&\n !settled.has(`${String(finding.index ?? -1)}\\0${finding.rule}`),\n )\n .map((finding) => {\n if (finding.rule === \"marker-misplaced\") {\n const stay = stayAt.get(finding.line ?? -1);\n if (stay === undefined) return finding;\n const level = severity[stay.rule];\n return {\n ...finding,\n message: stay.message,\n ...(level === \"off\" ? {} : { severity: level }),\n };\n }\n const turned = finding.index === undefined ? undefined : declined.get(finding.index);\n const why = turned?.rule === finding.rule ? turned.why : undefined;\n return why === undefined ? finding : { ...finding, message: `${finding.message} ${why}` };\n });\n const diff = after === content ? \"\" : unifiedDiff(label, content, after);\n const written = after !== content && path !== undefined && opts.dryRun !== true;\n if (written) {\n try {\n await writeFileAtomic(path, after);\n } catch (error) {\n throw await writes.restore(label, error);\n }\n writes.record(path, label, content);\n }\n const out: UpdatePage = { file: label, rewritten, refused, skipped, diff, written };\n // The stdin page has nowhere to be written; the caller prints it instead.\n if (path === undefined) out.content = after;\n pages.push(out);\n return report;\n };\n\n const reports: PageCitationReport[] = [];\n if (usingStdin) reports.push(await updateOne(STDIN_LABEL, opts.stdinContent ?? \"\"));\n for (const file of files) {\n reports.push(await updateOne(file, await readTarget(run, file), resolve(run.base, file)));\n }\n assertNoOrphanJoins(prepared, hits);\n\n // One write per manifest, after every page that touches it is settled.\n const write = opts.dryRun !== true;\n const rewrittenManifests: ManifestChange[] = [];\n const record = (changed: { file: string; diff: string }): void => {\n rewrittenManifests.push({ file: changed.file, diff: changed.diff, written: write });\n };\n if (write) {\n await manifests.commit({\n // A manifest joins the run's written files the moment it lands, so a\n // later manifest's failure puts this one back with the pages. Without\n // it the tree would keep pins no page content matches.\n after: (changed) => {\n writes.record(changed.path, changed.file, changed.before);\n record(changed);\n },\n onError: async (changed, error) => {\n throw await writes.restore(changed.file, error);\n },\n });\n } else for (const changed of manifests.changed()) record(changed);\n // A re-mint records HEAD when git has one. Where git is not there the entry\n // is re-pinned without a commit, and the run says so once.\n const reminted = pages.some((page) =>\n page.rewritten.some((r) => r.reason === \"accepted\" && r.end === \"source\"),\n );\n const also: string[] = [];\n if (reminted && !(await git.available())) also.push(GIT_UNAVAILABLE_COMMIT);\n // A shallow clone ran only the containment test, and says so whatever it\n // found, because what it could not check is the point. The guard is the\n // one `outsideHistory` uses, so the notice fires exactly when that test\n // would have run and could not.\n if (recommit && git.shallow !== undefined && git.isAncestor !== undefined && (await git.shallow())) {\n also.push(SHALLOW_RECOMMIT);\n }\n sayNotices(reports, opts.onNotice, also);\n\n const rewritten = pages.reduce((n, page) => n + citationsIn(page.rewritten), 0);\n // A refused claim counts as skipped: `--accept` was asked for it and the\n // run left it undone, which is what the summary's second number means.\n const skipped = pages.reduce((n, page) => n + page.skipped.length + page.refused.length, 0);\n const undone = pages.some(\n (page) =>\n page.refused.length > 0 || page.skipped.some((finding) => finding.severity === \"error\"),\n );\n return {\n pages,\n rewritten,\n skipped,\n ...(rewrittenManifests.length > 0 ? { manifests: rewrittenManifests } : {}),\n exitCode: undone ? 1 : 0,\n };\n}\n","/**\n * `reencryptCitations`: re-encrypt one page's encrypted citations under a new\n * key, for `manni key rotate` (proposal 0045). It reads sources and never\n * writes: the caller gets the rewritten page back, and writes it only once\n * every page in the run could be re-encrypted.\n *\n * A citation counts as done only when its `source.file` decrypts under the\n * new key *and* its pin holds under the new key. Either alone is a half\n * rotation, and a rerun has to finish it rather than declare it done. Meta's\n * walker cannot leave one today, because it skips the whole `citations` key\n * and cite encrypts in its own `cite-src` context; an interrupted run, a hand\n * edit, or a second writer of the same manifest can.\n *\n * The path must be tracked, and the pin must hold under the old key, over the\n * lines as they are today or, with git, as they were at the entry's\n * `commit-sha` (the classifier's history search). Then `file` becomes the\n * path's ciphertext under the new key, its lines kept, and `integrity` the\n * keyed pin under it, so a `changed` citation stays exactly as changed. A pin\n * that holds nowhere is skipped, with `update --accept` named as the repair.\n * No message names a path.\n */\nimport type {\n Citation,\n CitationInput,\n CitationOrigin,\n GitClient,\n ReencryptCitationsResult,\n ReencryptedCitation,\n SourceIndex,\n SourceRange,\n} from \"../types.js\";\nimport { historyOf } from \"./classify.js\";\nimport { gitClient } from \"./git.js\";\nimport { hashLines, sliceLines, splitLines } from \"./hash.js\";\nimport { readPage } from \"./page.js\";\nimport { formatSrc, sourceRange, spellSource } from \"./range.js\";\nimport { buildSourceIndex, decryptSourcePath, encryptSourcePath, readSource } from \"./sources.js\";\nimport { spliceEntryField } from \"./write.js\";\n\nconst UNDECRYPTABLE = \"does not decrypt under the current key\";\nconst MISSING = \"missing (no tracked file matches)\";\nconst CHANGED = \"changed; run `manni cite update --accept` before rotating\";\n\ntype Where = Pick<ReencryptedCitation, \"id\" | \"index\" | \"line\">;\n\n/** The fields a report row carries to name the entry: its id, or where it sits. */\nfunction whereOf(citation: Citation, origin: CitationOrigin): Where {\n const where: Where = { index: origin.index };\n if (citation.id !== undefined) where.id = citation.id;\n if (origin.line !== undefined) where.line = origin.line;\n return where;\n}\n\ninterface Context {\n root: string;\n index: SourceIndex;\n git: GitClient;\n}\n\n/**\n * The lines the pin was taken over, joined: today's when the pin holds there\n * under `key`, else the lines at the entry's commit when git can show them;\n * else why neither.\n */\nasync function pinnedLines(\n ctx: Context,\n citation: Citation,\n range: SourceRange,\n path: string,\n key: string,\n): Promise<{ joined: string } | { skip: string }> {\n const source = await readSource(ctx.root, ctx.index, { ...range, path, encrypted: false });\n if (source.kind === \"missing\") return { skip: MISSING };\n const pin = citation.source.integrity;\n let joined: string | undefined;\n try {\n joined = sliceLines(splitLines(source.text), range);\n } catch {\n // The range runs past the end of the file as it is now.\n joined = undefined;\n }\n if (joined !== undefined && hashLines(joined, key) === pin) return { joined };\n\n const commit = citation.source[\"commit-sha\"];\n if (commit !== undefined && (await ctx.git.available())) {\n const history = await historyOf(ctx.git, commit, path, range, pin, key, undefined);\n if (history.kind === \"original\") return { joined: history.lines.join(\"\\n\") };\n }\n return { skip: CHANGED };\n}\n\n/** What one citation needs: nothing, a new pair of values, or a reason it cannot be done. */\ntype Verdict =\n | { kind: \"done\" }\n | { kind: \"skip\"; message: string }\n | { kind: \"write\"; file: string; integrity: string; to: string };\n\n/** Options every re-encryption takes, whichever channel the entry lives in. */\nexport interface ReencryptOptions {\n root: string;\n fromKey: string;\n toKey: string;\n /** History and the source index are read through it; defaults to one over the root. */\n gitClient?: GitClient;\n sourceIndex?: SourceIndex;\n}\n\n/**\n * One citation's verdict: whether it is already under the new key, what its\n * `source.file` and `source.integrity` become, or why neither. The rule is\n * the same wherever the entry is kept, so the page splicer and the manifest\n * writer both go through here.\n */\nasync function verdictFor(\n ctx: Context,\n citation: Citation,\n opts: Pick<ReencryptOptions, \"fromKey\" | \"toKey\">,\n): Promise<Verdict> {\n const range = sourceRange(citation.source);\n const underNew = decryptSourcePath(range.path, opts.toKey);\n // Done only when both halves are under the new key; a file that is and a\n // pin that is not is the half rotation this finishes.\n if (underNew !== undefined) {\n const held = await pinnedLines(ctx, citation, range, underNew, opts.toKey);\n if (\"joined\" in held) return { kind: \"done\" };\n }\n const path = underNew ?? decryptSourcePath(range.path, opts.fromKey);\n if (path === undefined) return { kind: \"skip\", message: UNDECRYPTABLE };\n const lines = await pinnedLines(ctx, citation, range, path, opts.fromKey);\n if (\"skip\" in lines) return { kind: \"skip\", message: lines.skip };\n const file = underNew === undefined ? encryptSourcePath(path, opts.toKey) : range.path;\n return {\n kind: \"write\",\n file,\n integrity: hashLines(lines.joined, opts.toKey),\n to: formatSrc({ ...range, path: file }),\n };\n}\n\n/** The git client and source index a run shares, built once per page at most. */\nasync function contextFor(opts: ReencryptOptions): Promise<Context> {\n const git = opts.gitClient ?? gitClient(opts.root);\n const index = opts.sourceIndex ?? (await buildSourceIndex(opts.root, { gitClient: git }));\n return { root: opts.root, index, git };\n}\n\nexport async function reencryptCitations(\n page: { file: string; content: string; format?: string },\n opts: ReencryptOptions,\n): Promise<ReencryptCitationsResult> {\n const read = readPage(page.file, page.content, page.format === undefined ? undefined : { format: page.format });\n const result: ReencryptCitationsResult = { content: page.content, rewritten: [], skipped: [] };\n const encrypted = read.citations.filter(({ citation }) => sourceRange(citation.source).encrypted);\n // A page with nothing encrypted costs no index and no git.\n if (encrypted.length === 0) return result;\n\n const ctx = await contextFor(opts);\n let after = page.content;\n for (const { citation, origin } of encrypted) {\n const range = sourceRange(citation.source);\n const where = whereOf(citation, origin);\n const verdict = await verdictFor(ctx, citation, opts);\n if (verdict.kind === \"done\") continue;\n if (verdict.kind === \"skip\") {\n result.skipped.push({ ...where, message: verdict.message });\n continue;\n }\n if (verdict.file !== range.path) {\n after = spliceEntryField(after, read.format, origin.index, [\"source\", \"file\"], verdict.file);\n }\n after = spliceEntryField(\n after,\n read.format,\n origin.index,\n [\"source\", \"integrity\"],\n verdict.integrity,\n );\n result.rewritten.push({ ...where, from: spellSource(citation.source), to: verdict.to });\n }\n result.content = after;\n return result;\n}\n\n/** What `reencryptCitationEntries` did to one page's manifest entries. */\nexport interface ReencryptEntriesResult {\n /** The entries as they should now be written, a copy of what came in. */\n entries: unknown[];\n /** Whether any of them changed. */\n changed: boolean;\n rewritten: ReencryptedCitation[];\n skipped: { id?: string; index?: number; line?: number; message: string }[];\n}\n\n/**\n * The same rotation, for a page whose citations live in a manifest.\n *\n * The entries come from meta's merge, so they are plain values; each one is\n * validated as `readPage` validates a frontmatter entry, and an encrypted\n * source's `file` and `integrity` are rewritten in place. The caller writes\n * the whole list back with one splice, once every page of the run could be\n * re-encrypted.\n */\nexport async function reencryptCitationEntries(\n page: { file: string; content: string; format?: string; citations: readonly CitationInput[] },\n opts: ReencryptOptions,\n): Promise<ReencryptEntriesResult> {\n const entries: unknown[] = JSON.parse(\n JSON.stringify(page.citations.map((input) => input.entry)),\n ) as unknown[];\n const out: ReencryptEntriesResult = { entries, changed: false, rewritten: [], skipped: [] };\n\n const read = readPage(page.file, page.content, {\n ...(page.format === undefined ? {} : { format: page.format }),\n citations: page.citations,\n });\n const encrypted = read.citations.filter(({ citation }) => sourceRange(citation.source).encrypted);\n if (encrypted.length === 0) return out;\n\n const ctx = await contextFor(opts);\n for (const { citation, origin } of encrypted) {\n const where = whereOf(citation, origin);\n const verdict = await verdictFor(ctx, citation, opts);\n if (verdict.kind === \"done\") continue;\n if (verdict.kind === \"skip\") {\n out.skipped.push({ ...where, message: verdict.message });\n continue;\n }\n const entry: unknown = entries[origin.index];\n const source =\n typeof entry === \"object\" && entry !== null && !Array.isArray(entry)\n ? (entry as Record<string, unknown>).source\n : undefined;\n if (typeof source !== \"object\" || source === null || Array.isArray(source)) {\n out.skipped.push({ ...where, message: UNDECRYPTABLE });\n continue;\n }\n const fields = source as Record<string, unknown>;\n fields.file = verdict.file;\n fields.integrity = verdict.integrity;\n out.changed = true;\n out.rewritten.push({ ...where, from: spellSource(citation.source), to: verdict.to });\n }\n return out;\n}\n","/**\n * Pretty output for `check` and `update`.\n *\n * A citation is one row: its name, its claim end, its source end, and, when a\n * manifest owns the entry, where that is. Both ends read in file lines, the\n * only lines a person sees. Marks: ✓ current, ✗ error, ↕ warning, ℹ notice,\n * · skipped or baselined; a file line is ✓, ✗ (an error), ⚠ (a warning, no\n * error) or ℹ (notices only). Diffs, commit subjects and a changed claim's\n * current lines print only under `showDiff`; a decrypted path only under\n * `reveal`. Colour via `shouldColor`; never under `--no-color`/`NO_COLOR`.\n */\nimport type { ValidationResult } from \"../../meta/index.js\";\nimport { palette } from \"../../shared/color.js\";\nimport { errorSite, messageFor } from \"../core/adapt.js\";\nimport { parseSrc } from \"../core/range.js\";\nimport { shortCommit, shortPin, shortSrc, spellAt } from \"../core/spell.js\";\nimport type {\n CheckRun,\n CitationFinding,\n CitationResult,\n PageCitationReport,\n RecommitReason,\n Removal,\n RemoveRun,\n UpdateRewrite,\n UpdateRun,\n} from \"../types.js\";\n\nexport interface PrettyOptions {\n color: boolean;\n quiet?: boolean;\n showDiff?: boolean;\n reveal?: boolean;\n /** `remove --dry-run`: the footer says what the run would have removed. */\n dryRun?: boolean;\n}\n\n/** Diff lines printed under a `changed` row before the rest is elided. */\nexport const DIFF_LINE_CAP = 60;\n\nconst plural = (n: number, one: string, many = `${one}s`): string =>\n `${String(n)} ${n === 1 ? one : many}`;\n\n/** A finding's mark, by severity: ✗ error, ↕ warning, ℹ notice. */\nfunction severityMark(severity: CitationFinding[\"severity\"], c: ReturnType<typeof palette>): string {\n switch (severity) {\n case \"error\":\n return c.red(\"✗\");\n case \"warning\":\n return c.yellow(\"↕\");\n case \"notice\":\n return c.dim(\"ℹ\");\n }\n}\n\n/** A page's findings, split into the ones the baseline let through and the ones it forgave. */\nexport interface SplitFindings {\n reported: CitationFinding[];\n baselined: CitationFinding[];\n}\n\n/**\n * Which of a page's findings the run actually reported.\n *\n * The baseline works on the adapted `ValidationResult`: a forgiven finding is\n * removed from `errors` and counted in `baselined`, while `pages[].findings`\n * keeps every finding the check produced. So a finding is baselined exactly\n * when no error in the adapted result is left to account for it. Each error\n * is consumed once, so two identical findings need two identical errors.\n */\nexport function splitBaselined(\n page: PageCitationReport,\n result: ValidationResult | undefined,\n): SplitFindings {\n if (result === undefined) return { reported: [...page.findings], baselined: [] };\n const pool = [...result.errors];\n const out: SplitFindings = { reported: [], baselined: [] };\n for (const finding of page.findings) {\n const instancePath =\n finding.index === undefined ? \"\" : `/citations/${String(finding.index)}`;\n // A finding that sits on a manifest carries that file's line, and one\n // whose manifest lies outside the tree carries no line at all.\n const line = errorSite(finding).line;\n const at = pool.findIndex(\n (e) =>\n e.keyword === finding.rule &&\n e.instancePath === instancePath &&\n e.message === finding.message &&\n (e.line ?? null) === (line ?? null),\n );\n if (at === -1) {\n out.baselined.push(finding);\n } else {\n pool.splice(at, 1);\n out.reported.push(finding);\n }\n }\n return out;\n}\n\n/** The adapted result for a page: same position first, then by file label. */\nexport function resultFor(run: CheckRun, index: number): ValidationResult | undefined {\n const page = run.pages[index];\n if (page === undefined) return undefined;\n const aligned = run.results[index];\n if (aligned !== undefined && aligned.file === page.file) return aligned;\n return run.results.find((r) => r.file === page.file);\n}\n\n/** Whether a finding is about this citation. Every entry has an index, in either channel. */\nfunction belongsTo(finding: CitationFinding, result: CitationResult): boolean {\n return finding.index !== undefined && finding.index === result.origin.index;\n}\n\n/** `<id>`, else nothing: the ends say which entry it is. */\nfunction labelOf(result: CitationResult): string {\n return result.citation.id ?? \"\";\n}\n\n/** A page-level finding's label: its id, its index, or the source it names. */\nfunction labelOfFinding(finding: CitationFinding): string {\n if (finding.id !== undefined) return finding.id;\n if (finding.index !== undefined) return `#${String(finding.index)}`;\n return finding.src ?? \"page\";\n}\n\n/** Whether the entry spelled this source encrypted. */\nfunction citesEncrypted(src: string): boolean {\n try {\n return parseSrc(src).encrypted;\n } catch {\n return false;\n }\n}\n\n/**\n * The claim end column: where it is, in file lines, and how it reads. A marker\n * says where it is and, when it is misplaced, where it belongs. Its claim\n * status reads bare: the marker's own line is what a reader acts on.\n */\nfunction claimColumn(result: CitationResult): string {\n const { claim, marker } = result;\n const anchoredByMarker = result.anchor === \"marker\" && result.markerLine !== undefined;\n const moves = marker?.misplaced === undefined ? \"\" : ` -> :${String(marker.misplaced.to)}`;\n const where = anchoredByMarker\n ? `marker :${String(result.markerLine ?? 0)}${moves}`\n : claim?.fileLines === undefined\n ? \"\"\n : `:${claim.fileLines}`;\n if (claim === null) return where;\n let status: string;\n switch (claim.status) {\n case \"moved\":\n status = anchoredByMarker ? \"moved\" : `moved -> :${claim.newFileLines ?? \"?\"}`;\n break;\n case \"moved-ambiguous\": {\n const at = (claim.candidateFileLines ?? []).map((lines) => `:${lines}`);\n status = `moved, ${plural(at.length, \"candidate\")} (${at.join(\", \")})`;\n break;\n }\n case \"reanchored\": {\n const since = claim.commitSha === undefined ? \"\" : ` since ${shortCommit(claim.commitSha)}`;\n const to = claim.newFileLines === undefined ? \"\" : ` -> :${claim.newFileLines}`;\n status = `reanchored${since}${to}`;\n break;\n }\n case \"changed\":\n status = changedText(claim);\n break;\n default:\n status = claim.status;\n }\n return where === \"\" ? status : `${where} ${status}`;\n}\n\n/** How a changed claim's column says since when, as the source column does. */\nfunction changedText(claim: NonNullable<CitationResult[\"claim\"]>): string {\n if (claim.historyAvailable === false) return \"changed (history unavailable; fetch-depth: 0)\";\n if (claim.commitSha === undefined) return \"changed\";\n const since = claim.commitsSince ?? [];\n const count = since.length === 0 ? \"uncommitted\" : plural(since.length, \"commit\");\n return `changed since ${shortCommit(claim.commitSha)}, ${count}`;\n}\n\n/**\n * The source end column: the source as the entry spelled it, plus the\n * decrypted path only under `reveal`, and only beside an encrypted source,\n * the one spelling that hides it.\n */\nfunction sourceColumn(\n result: CitationResult,\n opts: PrettyOptions,\n dim: (s: string) => string,\n): string {\n const { source } = result;\n const src = shortSrc(source.src);\n const encrypted = citesEncrypted(source.src);\n const reveal = (path: string | undefined): string =>\n opts.reveal === true && path !== undefined && encrypted ? ` ${dim(`(${path})`)}` : \"\";\n // A source that followed its text to another file has a second ciphertext\n // in the message, and `--reveal` is the one place either is a path.\n return `${src}${reveal(source.resolvedPath)} ${messageFor(source)}${reveal(source.resolvedNewPath)}`;\n}\n\n/** The subjects and diff under a changed source, dim, the diff capped. */\nfunction diffLines(result: CitationResult, dim: (s: string) => string): string[] {\n const out: string[] = [];\n for (const subject of result.source.commitsSince ?? []) out.push(dim(` ${subject}`));\n const diff = result.source.diff;\n if (diff === undefined || diff === \"\") return out;\n const lines = diff.split(/\\r?\\n/);\n while (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n const shown = lines.slice(0, DIFF_LINE_CAP);\n for (const line of shown) out.push(dim(` ${line}`));\n const more = lines.length - shown.length;\n if (more > 0) out.push(dim(` … (${plural(more, \"more line\")})`));\n return out;\n}\n\n/**\n * What `--show-diff` adds under a claim row: the page's commit subjects since\n * the baseline and the claim's own diff. With no baseline there is no diff to\n * print, so a changed claim shows the lines it covers now instead.\n */\nfunction claimLines(result: CitationResult, dim: (s: string) => string): string[] {\n const claim = result.claim;\n const diff = claim?.diff;\n if (claim === null || diff === undefined || diff === \"\") {\n return capped(claim?.text ?? [], dim);\n }\n const out: string[] = [];\n for (const subject of claim.commitsSince ?? []) out.push(dim(` ${subject}`));\n return [...out, ...capped(diff.split(/\\r?\\n/), dim)];\n}\n\n/** Lines under a row, dim and capped, with a count of the ones left out. */\nfunction capped(lines: readonly string[], dim: (s: string) => string): string[] {\n const shown = lines.slice(0, DIFF_LINE_CAP);\n const out = shown.map((line) => dim(` ${line}`));\n const more = lines.length - shown.length;\n if (more > 0) out.push(dim(` … (${plural(more, \"more line\")})`));\n return out;\n}\n\n/**\n * The line a row sorts on: the marker's line for a marker-anchored entry,\n * else the claim's first file line. That is the line the row opens with, so\n * the claim column climbs down the page. A bare pin anchors nowhere and has\n * none.\n */\nfunction anchorSortLine(result: CitationResult): number | undefined {\n if (result.anchor === \"marker\" && result.markerLine !== undefined) return result.markerLine;\n const first = result.claim?.fileLines?.split(\"-\")[0];\n if (first === undefined) return undefined;\n const line = Number.parseInt(first, 10);\n return Number.isNaN(line) ? undefined : line;\n}\n\n/**\n * A page's citations in the order their rows print: by anchor line, with the\n * bare pins after them in the order the page keeps them. The entries\n * themselves are left alone, so json and the findings keep frontmatter order.\n */\nfunction rowOrder(citations: readonly CitationResult[]): CitationResult[] {\n return [...citations].sort((a, b) => {\n const left = anchorSortLine(a);\n const right = anchorSortLine(b);\n if (left === undefined) return right === undefined ? 0 : 1;\n if (right === undefined) return -1;\n return left - right;\n });\n}\n\n/** One row of a page's citation table, before the columns are padded. */\ninterface Row {\n mark: string;\n label: string;\n claim: string;\n source: string;\n where: string;\n /** Lines printed under the row: findings that are not an end, and diffs. */\n under: string[];\n}\n\n/**\n * The one manifest every citation of a page came from, or `undefined` when\n * the page has none, or when its rows come from more than one place (a\n * frontmatter entry among them counts as another place).\n */\nfunction oneManifest(citations: readonly CitationResult[]): string | undefined {\n const files = new Set(\n citations.map((result) => (result.origin.kind === \"manifest\" ? result.origin.file : undefined)),\n );\n const [only, ...rest] = [...files];\n return rest.length === 0 ? only : undefined;\n}\n\nfunction padTo(text: string, width: number, plain: number): string {\n // Colour codes are not width, so the visible length is passed in.\n return width <= plain ? text : text + \" \".repeat(width - plain);\n}\n\nexport function renderCheckPretty(run: CheckRun, opts: PrettyOptions): string {\n const c = palette(opts.color);\n const lines: string[] = [];\n const quiet = opts.quiet ?? false;\n // A finding about an entry a manifest owns names the manifest, because\n // its line is a line of that file and not of the page above it.\n const location = (finding: CitationFinding): string => {\n const { file, line } = errorSite(finding);\n if (line === undefined) return \"\";\n if (file === undefined) return c.dim(` (line ${String(line)})`);\n return c.dim(` (${file}:${String(line)})`);\n };\n\n run.pages.forEach((page, index) => {\n const { reported, baselined } = splitBaselined(page, resultFor(run, index));\n const errors = reported.filter((f) => f.severity === \"error\").length;\n const warned = reported.some((f) => f.severity === \"warning\");\n // \"baselined\" is a participle, not a noun: 1 baselined, 2 baselined.\n const forgiven =\n baselined.length > 0 ? c.dim(` (${String(baselined.length)} baselined)`) : \"\";\n // Every row names one manifest: a page's own under `{page}` (proposal\n // 0058), or a shared one. Said once on the page's line, not on each row.\n const manifest = oneManifest(page.citations);\n const heading = manifest === undefined ? page.file : `${page.file} ${c.dim(manifest)}`;\n\n if (reported.length === 0) {\n if (quiet) return;\n lines.push(`${c.green(\"✓\")} ${heading}${forgiven}`);\n } else {\n // The most severe finding marks the file. Only ✗ is a failure.\n const mark = errors > 0 ? c.red(\"✗\") : warned ? c.yellow(\"⚠\") : c.dim(\"ℹ\");\n lines.push(`${mark} ${heading}${forgiven}`);\n }\n\n const isBaselined = new Set(baselined);\n const placed = new Set<CitationFinding>();\n const rows: Row[] = [];\n\n for (const result of rowOrder(page.citations)) {\n const own = page.findings.filter((f) => belongsTo(f, result) && !placed.has(f));\n for (const finding of own) placed.add(finding);\n const live = own.filter((f) => !isBaselined.has(f));\n if (own.length === 0 && quiet) continue;\n const worst =\n live.find((f) => f.severity === \"error\") ??\n live.find((f) => f.severity === \"warning\") ??\n live[0];\n const mark =\n worst !== undefined\n ? severityMark(worst.severity, c)\n : own.length > 0\n ? c.dim(\"·\")\n : result.source.status === \"skipped\" && result.claim === null\n ? c.dim(\"·\")\n : c.green(\"✓\");\n\n // The ends are the row; anything else about the entry is a line under\n // it. A misplaced marker is part of the row too: it reads there as\n // `marker :<line> -> :<place>`.\n const endRules = new Set([\"claim-\", \"source-\", \"marker-misplaced\"]);\n const under: string[] = [];\n for (const finding of own) {\n const isEnd = [...endRules].some((prefix) => finding.rule.startsWith(prefix));\n if (isEnd) continue;\n const text = isBaselined.has(finding)\n ? c.dim(`${finding.message} (baselined)`)\n : finding.message;\n under.push(` ${severityMark(finding.severity, c)} ${text}${location(finding)}`);\n }\n if (opts.showDiff) {\n if (own.some((f) => f.rule === \"source-changed\")) under.push(...diffLines(result, c.dim));\n if (own.some((f) => f.rule === \"claim-changed\" || f.rule === \"claim-reanchored\")) {\n under.push(...claimLines(result, c.dim));\n }\n }\n const forgivenEnd = own.length > 0 && live.length === 0 ? c.dim(\" (baselined)\") : \"\";\n rows.push({\n mark,\n label: labelOf(result),\n claim: claimColumn(result),\n source: `${sourceColumn(result, opts, c.dim)}${forgivenEnd}`,\n where:\n result.origin.kind === \"manifest\" && manifest === undefined\n ? `${result.origin.file}${result.origin.line === undefined ? \"\" : `:${String(result.origin.line)}`}`\n : \"\",\n under,\n });\n }\n\n // Columns are as wide as this page needs them, and no wider.\n const width = (pick: (row: Row) => string): number =>\n rows.reduce((n, row) => Math.max(n, pick(row).length), 0);\n const labelWidth = width((row) => row.label);\n const claimWidth = width((row) => row.claim);\n const anyWhere = rows.some((row) => row.where !== \"\");\n const sourceWidth = anyWhere ? width((row) => row.source) : 0;\n for (const row of rows) {\n const label = padTo(c.cyan(row.label), labelWidth, row.label.length);\n const source = padTo(row.source, sourceWidth, row.source.length);\n const text = ` ${row.mark} ${label} ${padTo(row.claim, claimWidth, row.claim.length)} ${source}${row.where === \"\" ? \"\" : ` ${c.dim(row.where)}`}`;\n lines.push(text.replace(/\\s+$/, \"\"));\n lines.push(...row.under);\n }\n\n // Findings about no entry: a marker naming nothing, a reserved page key.\n for (const finding of page.findings) {\n if (placed.has(finding)) continue;\n const label = c.cyan(labelOfFinding(finding));\n lines.push(\n isBaselined.has(finding)\n ? ` ${c.dim(\"·\")} ${label} ${c.dim(`${finding.message} (baselined)`)}${location(finding)}`\n : ` ${severityMark(finding.severity, c)} ${label} ${finding.message}${location(finding)}`,\n );\n }\n });\n\n const { summary } = run;\n const warnings = summary.warnings ?? 0;\n const notices = summary.notices ?? 0;\n const baselined = summary.baseline?.suppressed ?? 0;\n const findings = summary.errors + warnings + notices + baselined;\n const parts = [plural(findings, \"finding\")];\n if (warnings > 0) parts.push(`(${plural(warnings, \"warning\")})`);\n if (notices > 0) parts.push(`(${plural(notices, \"notice\")})`);\n if (baselined > 0) parts.push(`(${String(baselined)} baselined)`);\n const summaryText = `${plural(summary.files, \"file\")} checked, ${String(summary.passed)} passed, ${String(summary.failed)} failed, ${parts.join(\" \")}`;\n if (lines.length > 0) lines.push(\"\");\n lines.push(summary.failed > 0 ? c.red(summaryText) : c.green(summaryText));\n if (summary.baseline?.written) {\n lines.push(c.dim(`Baseline written to ${summary.baseline.path}`));\n }\n return lines.join(\"\\n\");\n}\n\n/** `line 9`, or `lines 9-12`, from a line spec. */\nfunction spellAtSpec(spec: string): string {\n const span = spanOf(spec);\n return span === undefined ? `lines ${spec}` : spellAt(span);\n}\n\n/** A line spec as numbers, or undefined when it does not read as one. */\nfunction spanOf(spec: string): { start: number; end: number } | undefined {\n const [first, second] = spec.split(\"-\");\n const start = Number(first);\n const end = second === undefined ? start : Number(second);\n if (!Number.isFinite(start) || !Number.isFinite(end)) return undefined;\n return { start, end };\n}\n\n/**\n * What a re-pin over the unit newly covers, so the widening is in the log as\n * well as in the diff. A span that only lost marker lines gains nothing, and\n * says that instead.\n */\nfunction widening(held: string, now: string): string {\n const was = spanOf(held);\n const is = spanOf(now);\n if (was === undefined || is === undefined) return \"\";\n const parts: string[] = [];\n if (is.start < was.start) {\n parts.push(spellAt({ start: is.start, end: Math.min(was.start - 1, is.end) }));\n }\n if (is.end > was.end) {\n parts.push(spellAt({ start: Math.max(was.end + 1, is.start), end: is.end }));\n }\n if (parts.length === 0) return \", which held a marker line\";\n return `, ${parts.join(\" and \")} newly pinned`;\n}\n\n/** Whether a re-pin covered a span other than the stored one. */\nfunction widened(rewrite: UpdateRewrite): boolean {\n return (\n rewrite.fromLines !== undefined &&\n rewrite.toLines !== undefined &&\n rewrite.fromLines !== rewrite.toLines\n );\n}\n\n/** `lines 9 -> 9-12` for a re-pin that moved, `at line 9` for one that did not. */\nfunction movedSpan(rewrite: UpdateRewrite): string {\n if (widened(rewrite)) return `lines ${rewrite.fromLines ?? \"\"} -> ${rewrite.toLines ?? \"\"}`;\n const at = rewrite.toLines ?? rewrite.fromLines ?? String(rewrite.at ?? 0);\n return `at ${spellAtSpec(at)}`;\n}\n\n/**\n * What one claim `--accept` refused to re-pin says, and what to do about it.\n * The line names which test refused it: the share is printed when overlap is\n * what fired, and the text is called different when no sentence was shared.\n */\nexport function refusalLine(rewrite: UpdateRewrite): string {\n const at = shortCommit(rewrite.commitSha ?? \"\");\n const where = `claim at ${spellAtSpec(String(rewrite.at ?? 0))} skipped:`;\n if (rewrite.wordShare !== undefined) {\n const share = Math.round(rewrite.wordShare * 100);\n return `${where} that line now holds text sharing ${String(share)}% of the claim's words at ${at}. Re-add it with cite add.`;\n }\n return `${where} that line now holds different text than the claim at ${at}. Re-add it with cite add.`;\n}\n\n/**\n * Why a pin was re-committed, as its row says it. Exhaustive, so a new reason\n * is a type error here rather than a row that quietly reads as the old one. No\n * reason at all is the containment case, which is all `--recommit` once knew.\n */\nfunction recommitWhy(because: RecommitReason | undefined): string {\n switch (because) {\n case \"not-in-history\":\n return \"not in this branch's history\";\n case \"not-contained\":\n case undefined:\n return \"did not contain the pinned lines\";\n }\n}\n\n/** What one rewritten end says it did. */\nexport function rewriteLine(rewrite: UpdateRewrite): string {\n const word = rewrite.from.includes(\"-\") ? \"lines\" : \"line\";\n const status = rewrite.status === \"never-true\" ? \"never true\" : rewrite.status;\n if (rewrite.end === \"marker\") {\n return `marker line ${rewrite.from} -> ${rewrite.to} (misplaced)`;\n }\n // The pin held; only its date was wrong. The row names both commits, so the\n // log says what the entry claimed before it was corrected.\n if (rewrite.reason === \"recommitted\") {\n const from = shortCommit(rewrite.fromCommit ?? \"\");\n const to = shortCommit(rewrite.toCommit ?? \"\");\n return `source ${shortSrc(rewrite.src ?? \"\")} commit ${from} -> ${to} (${recommitWhy(rewrite.because)})`;\n }\n if (rewrite.reason === \"shifted\") {\n return `claim ${word} ${rewrite.from} -> ${rewrite.to} (shifted by a marker)`;\n }\n // The words held while the anchor moved (0053). A claim-lines entry moved\n // onto its new run, so the row names both spans.\n if (rewrite.reason === \"re-anchored\" && rewrite.status === \"reanchored\") {\n const since = rewrite.commitSha === undefined ? \"\" : ` since ${shortCommit(rewrite.commitSha)}`;\n return `claim ${movedSpan(rewrite)} re-pinned (reanchored; words unchanged${since})`;\n }\n if (rewrite.reason === \"re-anchored\") {\n const held = rewrite.lines ?? \"\";\n const now = rewrite.newLines ?? \"\";\n return `claim re-pinned over ${spellAtSpec(now)} (moved; was ${spellAtSpec(held)}${widening(held, now)})`;\n }\n if (rewrite.reason === \"moved\") {\n return rewrite.end === \"claim\"\n ? `claim ${word} ${rewrite.from} -> ${rewrite.to} (moved)`\n : `source ${shortSrc(rewrite.from)} -> ${shortSrc(rewrite.to)} (moved)`;\n }\n if (rewrite.end === \"claim\") {\n // A re-pin over a unit wider than the stored lines names both spans, so\n // the widening is in the log as well as in the diff.\n if (widened(rewrite)) {\n return `claim ${movedSpan(rewrite)} re-pinned (${status}; now \"${rewrite.text ?? \"\"}\")`;\n }\n // A marker anchors its claim, so the marker's line is where the entry is,\n // as `check` reports it. A claim-lines entry reads at the claim.\n const where =\n rewrite.markerLine === undefined\n ? `line ${String(rewrite.at ?? 0)}`\n : `marker line ${String(rewrite.markerLine)}`;\n return `claim at ${where} re-pinned (${status}; now \"${rewrite.text ?? \"\"}\")`;\n }\n const at = rewrite.commitSha === undefined ? \"\" : ` at ${shortCommit(rewrite.commitSha)}`;\n const src = shortSrc(rewrite.src ?? \"\");\n // A re-mint over the span the old first and last line now bracket names both\n // ranges, so the log says which lines were accepted.\n const where = rewrite.toLines === undefined ? src : `${src} -> ${atLines(src, rewrite.toLines)}`;\n return `source ${where} re-pinned${at} (${status}; ${shortPin(rewrite.from)} -> ${shortPin(rewrite.to)})`;\n}\n\n/** The same source spelled at other lines: `path:200-212` and `\"200-215\"` read `path:200-215`. */\nfunction atLines(src: string, lines: string): string {\n const colon = src.lastIndexOf(\":\");\n return `${colon === -1 ? src : src.slice(0, colon)}:${lines}`;\n}\n\nexport function renderUpdatePretty(run: UpdateRun, opts: PrettyOptions): string {\n const c = palette(opts.color);\n const lines: string[] = [];\n let files = 0;\n for (const page of run.pages) {\n if (page.rewritten.length > 0) files += 1;\n if (opts.showDiff && page.diff !== \"\") {\n for (const line of page.diff.split(/\\r?\\n/)) {\n if (line !== \"\") lines.push(c.dim(line));\n }\n }\n for (const rewrite of page.rewritten) {\n const label = rewrite.id ?? `#${String(rewrite.index)}`;\n lines.push(`${page.file}: ${c.cyan(label)} ${rewriteLine(rewrite)}`);\n }\n // A claim `--accept` refused reads beside the rewrites, because it is the\n // one row `--accept` was asked for and did not write.\n for (const rewrite of page.refused) {\n const label = rewrite.id ?? `#${String(rewrite.index)}`;\n lines.push(`${page.file}: ${c.cyan(label)} ${refusalLine(rewrite)}`);\n }\n for (const finding of page.skipped) {\n const mark = severityMark(finding.severity, c);\n lines.push(\n `${page.file}: ${c.cyan(labelOfFinding(finding))} ${mark} skipped: ${finding.message}`,\n );\n }\n }\n // The manifests, after the pages: a dry run owes the diff of every file it\n // would have written, and an entry a manifest owns is written there.\n if (opts.showDiff) {\n for (const manifest of run.manifests ?? []) {\n for (const line of manifest.diff.split(/\\r?\\n/)) {\n if (line !== \"\") lines.push(c.dim(line));\n }\n }\n }\n const summary = `${plural(run.rewritten, \"citation\")} rewritten in ${plural(files, \"file\")}, ${String(run.skipped)} skipped`;\n lines.push(run.exitCode === 0 ? c.green(summary) : c.red(summary));\n return lines.join(\"\\n\");\n}\n\n/** `line 30`, or `lines 30 and 42` for several, as a sentence reads them. */\nfunction spellLineList(at: readonly number[], noun: string): string {\n // No lines is the noun alone. Every caller has at least one, and a\n // sentence reading \"lines and \" would be the only sign that one did not.\n if (at.length === 0) return noun;\n const spelled = at.map((line) => String(line));\n if (spelled.length === 1) return `${noun} ${spelled[0] ?? \"\"}`;\n const last = spelled[spelled.length - 1] ?? \"\";\n return `${noun}s ${spelled.slice(0, -1).join(\", \")} and ${last}`;\n}\n\n/** What one removal says it did: the entry, where it was kept, and its markers. */\nexport function removalLine(removal: Removal, c: ReturnType<typeof palette>): string {\n const markers = spellLineList(removal.markerLines, \"line\");\n if (removal.origin === undefined) {\n // A marker naming no entry: there is nothing else to report about it.\n const named = removal.markerLines.length === 1 ? \"the marker\" : \"the markers\";\n return `removed ${named} ${c.cyan(removal.id ?? \"\")} at ${markers}, which named no entry`;\n }\n const name = removal.id ?? `/citations/${String(removal.index ?? 0)}`;\n const where =\n removal.origin.kind === \"manifest\"\n ? `${removal.origin.file}${removal.origin.line === undefined ? \"\" : `:${String(removal.origin.line)}`}`\n : \"frontmatter\";\n const also =\n removal.markerLines.length === 0\n ? \"\"\n : `, and ${removal.markerLines.length === 1 ? \"its marker\" : \"its markers\"} at ${markers}`;\n return `removed ${c.cyan(name)} from ${where}${also}`;\n}\n\nexport function renderRemovePretty(run: RemoveRun, opts: PrettyOptions): string {\n const c = palette(opts.color);\n const lines: string[] = [];\n let files = 0;\n for (const page of run.pages) {\n if (page.removed.length > 0) files += 1;\n if (opts.showDiff && page.diff !== \"\") {\n for (const line of page.diff.split(/\\r?\\n/)) {\n if (line !== \"\") lines.push(c.dim(line));\n }\n }\n for (const removal of page.removed) {\n lines.push(`${page.file}: ${removalLine(removal, c)}`);\n }\n }\n // The manifests, after the pages, as `update` prints them.\n if (opts.showDiff) {\n for (const manifest of run.manifests ?? []) {\n for (const line of manifest.diff.split(/\\r?\\n/)) {\n if (line !== \"\") lines.push(c.dim(line));\n }\n }\n }\n const verb = opts.dryRun === true ? \"would be removed\" : \"removed\";\n lines.push(c.green(`${plural(run.removed, \"citation\")} ${verb} from ${plural(files, \"file\")}`));\n return lines.join(\"\\n\");\n}\n","/**\n * JSON output. `{ summary, pages }` for check; the run itself for update and\n * remove.\n *\n * A citation prints its two ends and how they are anchored. `resolvedPath`,\n * `diff`, `commitsSince` and a changed claim's current lines are left out of\n * every citation: output never says more than the page did. It is an\n * allowlist rather than a strip, so a field added to the result stays private\n * until someone decides here that it is safe to print.\n */\nimport type {\n CheckRun,\n CitationAnchor,\n CitationResult,\n MarkerEnd,\n OriginKind,\n PageCitationReport,\n RemoveRun,\n UpdateRewrite,\n UpdateRun,\n} from \"../types.js\";\n\nexport interface PublicClaimEnd {\n lines?: string;\n fileLines?: string;\n status: string;\n newLines?: string;\n candidates?: string[];\n /** The baseline the claim was read against: the page's own history says it. */\n commitSha?: string;\n historyAvailable?: boolean;\n}\n\nexport interface PublicSourceEnd {\n src: string;\n status: string;\n newLines?: string;\n newSrc?: string;\n candidates?: string[];\n commitSha?: string;\n historyAvailable?: boolean;\n truncatedSearch?: boolean;\n}\n\nexport interface PublicCitationResult {\n id?: string;\n origin: { kind: OriginKind; file: string; line?: number };\n anchor: CitationAnchor;\n /** The marker that names the entry: its line, and its misplacement when it has one. */\n marker?: MarkerEnd;\n claim: PublicClaimEnd | null;\n source: PublicSourceEnd;\n}\n\nexport function publicCitation(result: CitationResult): PublicCitationResult {\n const origin: PublicCitationResult[\"origin\"] = {\n kind: result.origin.kind,\n file: result.origin.file,\n };\n if (result.origin.line !== undefined) origin.line = result.origin.line;\n\n const source: PublicSourceEnd = { src: result.source.src, status: result.source.status };\n if (result.source.newLines !== undefined) source.newLines = result.source.newLines;\n if (result.source.newSrc !== undefined) source.newSrc = result.source.newSrc;\n if (result.source.candidates !== undefined) source.candidates = result.source.candidates;\n if (result.source.commitSha !== undefined) source.commitSha = result.source.commitSha;\n if (result.source.historyAvailable !== undefined) {\n source.historyAvailable = result.source.historyAvailable;\n }\n if (result.source.truncatedSearch !== undefined) {\n source.truncatedSearch = result.source.truncatedSearch;\n }\n\n let claim: PublicClaimEnd | null = null;\n if (result.claim !== null) {\n claim = { status: result.claim.status };\n if (result.claim.lines !== undefined) claim.lines = result.claim.lines;\n if (result.claim.fileLines !== undefined) claim.fileLines = result.claim.fileLines;\n if (result.claim.newLines !== undefined) claim.newLines = result.claim.newLines;\n if (result.claim.candidates !== undefined) claim.candidates = result.claim.candidates;\n if (result.claim.commitSha !== undefined) claim.commitSha = result.claim.commitSha;\n if (result.claim.historyAvailable !== undefined) {\n claim.historyAvailable = result.claim.historyAvailable;\n }\n }\n\n // Key order is the order the plan spells a citation in: what it is called,\n // where it is kept, what anchors it, then its two ends.\n return {\n ...(result.citation.id === undefined ? {} : { id: result.citation.id }),\n origin,\n anchor: result.anchor,\n ...(result.marker === undefined ? {} : { marker: result.marker }),\n claim,\n source,\n };\n}\n\nexport interface PublicPageReport extends Omit<PageCitationReport, \"citations\"> {\n citations: PublicCitationResult[];\n}\n\nexport function publicPage(page: PageCitationReport): PublicPageReport {\n return { ...page, citations: page.citations.map(publicCitation) };\n}\n\nexport function renderCheckJson(run: CheckRun): string {\n return JSON.stringify({ summary: run.summary, pages: run.pages.map(publicPage) }, null, 2);\n}\n\nexport function renderRemoveJson(run: RemoveRun): string {\n // The whole run, with nothing stripped: `RemoveRun` carries no\n // pretty-only field, as `UpdateRewrite.markerLine` is below. A field added\n // to it for the terminal alone is stripped here, as that one is.\n return JSON.stringify(run, null, 2);\n}\n\nexport function renderUpdateJson(run: UpdateRun): string {\n // `markerLine` is the pretty report's line for a marker-anchored claim.\n // `at` is the claim's own first file line, which is what data says.\n const strip = (rows: readonly UpdateRewrite[]): Omit<UpdateRewrite, \"markerLine\">[] =>\n rows.map(({ markerLine: _pretty, ...rewrite }) => rewrite);\n const pages = run.pages.map((page) => ({\n ...page,\n rewritten: strip(page.rewritten),\n refused: strip(page.refused),\n }));\n return JSON.stringify({ ...run, pages }, null, 2);\n}\n","/**\n * GitHub workflow commands, one per finding:\n * `::error file=<file>,line=<n>,title=<ruleId>::<id or src> (<src>): <message>`\n * with `::warning` and `::notice` for the lower levels: the family scale is\n * GitHub's, so the level is the severity. Uses meta's escapes. A baselined\n * finding is not an annotation; a clean run is the empty string.\n */\nimport {\n escapeWorkflowCommandMessage,\n escapeWorkflowCommandProperty,\n} from \"../../meta/internal.js\";\nimport { errorSite } from \"../core/adapt.js\";\nimport type { CheckRun, CitationFinding, CiteRule } from \"../types.js\";\nimport { resultFor, splitBaselined } from \"./pretty.js\";\n\n/**\n * The rules whose message already names what it is about: every claim,\n * marker and anchor message is written as a sentence about the entry, so\n * prefixing it with the subject again would say the name twice. Exported so\n * a test asserting the composed messages reads this set rather than a copy.\n */\nexport const NAMES_ITS_SUBJECT = new Set<CiteRule>([\n \"claim-moved\",\n \"claim-moved-ambiguous\",\n \"claim-changed\",\n \"marker-orphan\",\n \"marker-invalid\",\n \"marker-repeated\",\n \"anchor-invalid\",\n]);\n\n/**\n * `<id> (<src>): <message>`, or `<src>: <message>` when the entry has no id.\n * A message that names its own subject, by its rule or by opening with the\n * id (an `entry-invalid` about a pin prefix does), is left to say it once.\n * SARIF and JUnit carry the same message.\n */\nexport function findingMessage(finding: CitationFinding): string {\n const subject = finding.id ?? finding.src;\n if (subject === undefined) return finding.message;\n if (NAMES_ITS_SUBJECT.has(finding.rule)) return finding.message;\n if (finding.id !== undefined && finding.message.startsWith(finding.id)) return finding.message;\n const where = finding.id !== undefined && finding.src !== undefined ? ` (${finding.src})` : \"\";\n return `${subject}${where}: ${finding.message}`;\n}\n\nexport function renderCheckGithub(run: CheckRun): string {\n const lines: string[] = [];\n run.pages.forEach((page, index) => {\n const { reported } = splitBaselined(page, resultFor(run, index));\n for (const finding of reported) {\n // A finding about an entry a manifest owns is annotated on the\n // manifest, unless that manifest is outside the tree, where an\n // annotation would land nowhere: then the page carries it.\n const site = errorSite(finding);\n const params = [`file=${escapeWorkflowCommandProperty(site.file ?? page.file)}`];\n if (site.line !== undefined) params.push(`line=${String(site.line)}`);\n params.push(`title=${escapeWorkflowCommandProperty(finding.ruleId)}`);\n lines.push(\n `::${finding.severity} ${params.join(\",\")}::${escapeWorkflowCommandMessage(findingMessage(finding))}`,\n );\n }\n });\n return lines.join(\"\\n\");\n}\n","import { ToolError } from \"../shared/errors.js\";\n\n/** An operational or usage error in the key domain: exit 2. */\nexport class KeyError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"KeyError\";\n }\n}\n","/**\n * `manni key rotate [paths...]`: re-encrypt every encrypted value under a new\n * key, then write the key (proposal 0045).\n *\n * Values are found by their ciphertext, never through schema marks: meta's\n * `reencryptMetadata` takes every string of the ciphertext shape in a page's\n * metadata, and cite's `reencryptCitations` every encrypted `source.file` with its\n * keyed pin. A value already under the new key counts as done, so a run can\n * always be repeated.\n *\n * A value does not have to sit in a page. An external-metadata manifest\n * (proposal 0037) holds the private half of the same documents, which is\n * where an encrypted value most often lives, so the local manifests of the\n * collections a run covers are re-encrypted with the pages. See\n * `planManifests`.\n *\n * Input resolution is `cite check`'s: positional paths from `cwd`, else the\n * selected collections' `paths:` from the config's directory, `--exclude`\n * added to a collection's own `exclude:`, and zero files an error unless\n * `--allow-empty`.\n *\n * Every page and manifest is re-encrypted in memory first. One skip and\n * nothing is written (exit 1). Otherwise a whole run whose key comes from the\n * config writes in three steps, so that an interruption at any point leaves\n * every value readable by the next run:\n *\n * 1. the config: `encryptionKey:` the new key, `encryptionKeyPrevious:` the\n * old one, in one atomic write;\n * 2. the pages, then the manifests;\n * 3. the config again, without `encryptionKeyPrevious:`.\n *\n * A run that finds `encryptionKeyPrevious:` finishes that rotation: from the\n * previous key to the current one. A narrowed run (paths or `--collection`)\n * and a run whose key comes from `MANNI_ENCRYPTION_KEY` write pages and\n * manifests and never the config. `--dry-run` writes nothing at all.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport {\n DEFAULT_CITE_BASELINE_PATH,\n GIT_UNAVAILABLE_HISTORY,\n ManifestSet,\n buildSourceIndex,\n gitClient,\n loadCitationSidecars,\n parseCiteConfig,\n readPage,\n sourceRange,\n reencryptCitationEntries,\n reencryptCitations,\n type CiteConfig,\n type CitationSidecars,\n type GitClient,\n type ReencryptCitationsResult,\n type SourceIndex,\n} from \"../../cite/index.js\";\nimport {\n PATH_JOIN,\n classifyRef,\n externalMetadataJoin,\n loadExternalMetadata,\n reencryptMetadata,\n supportedExtensions,\n writeFileAtomic,\n type ExternalMetadataEntry,\n type ExternalMetadataIndex,\n type ExternalMetadataValue,\n} from \"../../meta/index.js\";\nimport {\n STDIN_TOKEN,\n assertNonEmpty,\n configMarks,\n extractorByName,\n gitignoreOptions,\n reencryptData,\n resolveTargetSet,\n spliceManifestValue,\n} from \"../../meta/internal.js\";\nimport { isMember, selectCollections, type CollectionConfig } from \"../../shared/collections.js\";\nimport type { ConfigFile } from \"../../shared/config-file.js\";\nimport { resolveEncryptionKey, writeEncryptionKey } from \"../../shared/encryption-key.js\";\nimport { generateEncryptionKey, isValidEncryptionKey } from \"../../shared/encryption.js\";\nimport { findGitRoot } from \"../../shared/git-root.js\";\nimport {\n findPageManifests,\n hasPagePlaceholder,\n pageManifestPath,\n} from \"../../shared/page-manifest.js\";\nimport { readRotateConfig, toKeyError, unfinishedRotation } from \"../core/config.js\";\nimport { KeyError } from \"../errors.js\";\nimport type {\n KeyRotateOptions,\n KeyRotateResult,\n RotateManifest,\n RotateOutcome,\n RotatePage,\n RotatedValue,\n SkippedValue,\n} from \"../types.js\";\n\nconst BAD_TO = \"--to must be at least 32 hex or base64url characters.\";\nconst NO_STDIN =\n \"key rotate reads and writes files, so it takes no stdin (`-`). Name the files instead.\";\nconst WITH_PATHS =\n \"--collection selects a configured collection; it cannot be combined with paths.\";\nconst NEEDS_CONFIG = \"--collection needs a config file to select from.\";\nconst NO_KEY =\n \"No encryption key is available, so nothing can be re-encrypted. Run `manni key set` first.\";\nconst ENV_NEEDS_TO =\n \"The key comes from MANNI_ENCRYPTION_KEY; pass --to <value>, re-encrypt with it, then update the secret. Nothing is written to config.\";\nconst NARROWED_NEEDS_TO = \"A run over part of the family needs --to, and never writes the key.\";\nconst NO_FILES =\n \"No files to re-encrypt. Pass paths/globs, or declare a collection under `collections:` in manni.config.yaml.\";\n\n/**\n * Any ciphertext at all. A page without one has nothing to rotate, so it costs\n * no parse; with one, the page is parsed and the tag decides.\n */\nconst ANY_CIPHERTEXT = /~[A-Za-z0-9_-]{82,}/;\n\n/** The `cite:` section of the file, for `root:` and `baseline:`; `{}` without one. */\nfunction citeSection(file: ConfigFile | null): CiteConfig {\n if (file === null) return {};\n const doc: unknown = parseYaml(file.text);\n if (typeof doc !== \"object\" || doc === null || !(\"cite\" in doc)) return {};\n return parseCiteConfig(doc.cite, file.source);\n}\n\n/**\n * Where cited sources resolve from, as `cite` resolves it: `--root` (cwd\n * relative) > `cite.root` (config relative) > the git root > `cwd`.\n */\nfunction rootFor(\n flag: string | undefined,\n cite: CiteConfig,\n file: ConfigFile | null,\n cwd: string,\n): { root: string; fellBack: boolean } {\n if (flag !== undefined) return { root: resolve(cwd, flag), fellBack: false };\n if (file !== null && cite.root !== undefined) {\n return { root: resolve(file.dir, cite.root), fellBack: false };\n }\n const gitRoot = findGitRoot(cwd);\n return gitRoot === null ? { root: cwd, fellBack: true } : { root: gitRoot, fellBack: false };\n}\n\nfunction isEnoent(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nasync function indexFor(root: string, client: GitClient): Promise<SourceIndex> {\n try {\n return await buildSourceIndex(root, { gitClient: client });\n } catch (error) {\n if (isEnoent(error)) throw new KeyError(`Root directory not found: ${root}.`);\n throw error;\n }\n}\n\n/**\n * The page's encrypted citations, the only ones a rotation reads sources\n * for: whether it has any, and whether one carries a commit (its own or the\n * page's), which is when history would be read.\n */\nfunction encryptedCitations(\n file: string,\n content: string,\n format: string | undefined,\n): { any: boolean; withCommit: boolean } {\n const read = readPage(file, content, format === undefined ? undefined : { format });\n const encrypted = read.citations.filter(({ citation }) => sourceRange(citation.source).encrypted);\n return {\n any: encrypted.length > 0,\n withCommit: encrypted.some(({ citation }) => citation.source[\"commit-sha\"] !== undefined),\n };\n}\n\ninterface Planned {\n page: RotatePage;\n path: string;\n content: string;\n changed: boolean;\n}\n\n/**\n * The citations of one page that a manifest owns (proposal 0044). They are\n * re-encrypted exactly as a page's own are — a citation counts as done only\n * when its `source.file` decrypts under the new key *and* its pin holds —\n * and written back as one value per page, each manifest written once.\n *\n * Kept in its own function, and reached from one place in the loop below, so\n * nothing about how *meta* values are rotated changes.\n */\nasync function rotateManifestCitations(\n sidecars: CitationSidecars | null,\n manifests: ManifestSet,\n page: { file: string; content: string; format?: string },\n opts: {\n root: string;\n fromKey: string;\n toKey: string;\n gitClient: GitClient;\n sourceIndex: () => Promise<SourceIndex>;\n },\n): Promise<{ rewritten: RotatedValue[]; skipped: SkippedValue[]; wantsHistory: boolean }> {\n const none = { rewritten: [], skipped: [], wantsHistory: false };\n if (sidecars === null) return none;\n const sidecar = await sidecars.forPage(page.file, page.content, page.format);\n const owner = sidecar.owner;\n if (owner === undefined || sidecar.citations === undefined) return none;\n // Only a manifest entry that actually holds a ciphertext costs an index.\n if (!sidecar.citations.some((input) => ANY_CIPHERTEXT.test(JSON.stringify(input.entry)))) {\n return none;\n }\n const result = await reencryptCitationEntries(\n { ...page, citations: sidecar.citations },\n {\n root: opts.root,\n fromKey: opts.fromKey,\n toKey: opts.toKey,\n gitClient: opts.gitClient,\n sourceIndex: await opts.sourceIndex(),\n },\n );\n if (result.changed && sidecar.entry !== undefined) {\n await manifests.write(owner, sidecar.entry, result.entries, 0);\n }\n return {\n rewritten: result.rewritten.map((r) => ({ kind: \"citation\" as const, ...r })),\n skipped: result.skipped.map((s) => ({ kind: \"citation\" as const, ...s })),\n // A pin that no longer holds is re-keyed from the lines at its commit.\n wantsHistory: sidecar.citations.some((input) =>\n /\"commit-sha\"\\s*:/.test(JSON.stringify(input.entry)),\n ),\n };\n}\n\ninterface PlannedManifest {\n manifest: RotateManifest;\n path: string;\n /** The manifest's text, with every rewritten value spliced into it. */\n text: string;\n changed: boolean;\n}\n\n/** How a run spells a manifest: relative to its base, like every file label. */\nfunction reportedPath(abs: string, base: string): string {\n const rel = relative(base, abs);\n return rel === \"\" ? \".\" : rel.split(sep).join(\"/\");\n}\n\n/**\n * The collections whose manifests this run covers. A run over every\n * collection, and one narrowed by `--collection`, covers the collections it\n * selected. A run over positional paths covers the collections those files\n * belong to, so the private half of a page a run re-encrypts moves with it.\n */\nfunction manifestCollections(\n collections: readonly CollectionConfig[],\n opts: {\n fromCollections: boolean;\n files: readonly string[];\n base: string;\n configDir: string;\n },\n): CollectionConfig[] {\n if (opts.fromCollections) return [...collections];\n const rels = opts.files.map((rel) =>\n reportedPath(resolve(opts.base, rel), opts.configDir),\n );\n return collections.filter((c) => rels.some((rel) => isMember(c, rel)));\n}\n\n/** The owned values one manifest entry supplies, or an empty map. */\nfunction valuesOf(\n index: ExternalMetadataIndex,\n entry: ExternalMetadataEntry,\n): ReadonlyMap<string, ExternalMetadataValue> {\n const empty = new Map<string, ExternalMetadataValue>();\n if (entry.join === PATH_JOIN) {\n return entry.abs === undefined ? empty : (index.byPath.get(entry.abs) ?? empty);\n }\n return index.byField.get(entry.join)?.get(entry.spelled) ?? empty;\n}\n\n/**\n * Re-encrypt the metadata values that live in the selected collections' local\n * manifests (proposals 0037, 0039 and 0041).\n *\n * A manifest is private by construction, so it is where an encrypted value is\n * most likely to sit. Rotation would otherwise leave it under the old key and\n * `meta validate` would report `encrypted:unreadable` on every page the\n * manifest feeds.\n *\n * Two things are left alone. A URL manifest is somebody else's file and\n * read-only (0038), so it is never loaded, and a rotation reaches no network.\n * The `citations` key is cite's: it re-keys a citation's source together with\n * its pin, under its own context, and re-encrypting the source alone would\n * break the pin. `reencryptData` skips it for the same reason\n * `reencryptMetadata` does on a page.\n *\n * Text in, text out. Each value is spliced into the manifest by\n * `spliceManifestValue`, which replaces that value's range and keeps every\n * other byte: the comments, the key order, the quoting and the line endings.\n * Nothing is written here; the caller writes when every value could be\n * re-encrypted.\n */\nasync function planManifests(opts: {\n collections: readonly CollectionConfig[];\n configDir: string;\n base: string;\n fromKey: string;\n toKey: string;\n /** The run's pages, as absolute paths, which a `{page}` manifest (0058) is read for. */\n pages: readonly string[];\n /** A run over the whole family: no paths and no `--collection`. */\n whole: boolean;\n}): Promise<PlannedManifest[]> {\n const local = opts.collections\n .map((c) => ({\n ...c,\n externalMetadata: c.externalMetadata.filter(\n (m) => classifyRef(m.file).kind !== \"url\",\n ),\n }))\n .filter((c) => c.externalMetadata.length > 0);\n if (local.length === 0) return [];\n\n // A `{page}` entry (proposal 0058) is one manifest per page, so its files\n // are enumerated rather than named: each page of the run resolves its own,\n // and a whole run adds every file the pattern's glob finds, so a manifest\n // whose page is gone is re-encrypted too (0058 stress test 12). The pages\n // those files name are handed to the loader like the run's own.\n const pages = new Set(opts.pages);\n if (opts.whole) {\n for (const c of local) {\n for (const m of c.externalMetadata) {\n if (!hasPagePlaceholder(m.file)) continue;\n for (const found of findPageManifests(m.file, opts.configDir, (rel) => isMember(c, rel))) {\n for (const entry of found.entries) pages.add(entry.pageAbs);\n }\n }\n }\n }\n\n const index = await loadExternalMetadata(local, {\n configDir: opts.configDir,\n base: opts.base,\n pages: [...pages],\n });\n if (index === null) return [];\n\n // One plan per manifest file, so a manifest two collections declare is read\n // once and spliced once. Its reported path and collection identify it the\n // way `index.entries` does. A plan is made when an entry first names its\n // file, and only a plan with a value to report is kept.\n const plans = new Map<string, PlannedManifest>();\n const located = new Map<string, { abs: string; collection: string }>();\n const locate = (collection: string, abs: string, join: string): void => {\n located.set(`${collection}\\u0000${reportedPath(abs, opts.base)}\\u0000${join}`, { abs, collection });\n };\n for (const c of local) {\n for (const m of c.externalMetadata) {\n const join = externalMetadataJoin(m);\n if (!hasPagePlaceholder(m.file)) {\n locate(c.name, isAbsolute(m.file) ? m.file : resolve(opts.configDir, m.file), join);\n continue;\n }\n for (const page of pages) {\n const resolved = pageManifestPath(m.file, opts.configDir, page);\n if (!(\"outside\" in resolved)) locate(c.name, resolved.abs, join);\n }\n }\n }\n const planFor = async (key: string): Promise<PlannedManifest | undefined> => {\n const where = located.get(key);\n if (where === undefined) return undefined;\n const known = plans.get(where.abs);\n if (known !== undefined) return known;\n const plan: PlannedManifest = {\n manifest: {\n file: reportedPath(where.abs, opts.base),\n collection: where.collection,\n rewritten: [],\n skipped: [],\n written: false,\n },\n path: where.abs,\n text: await readFile(where.abs, \"utf8\"),\n changed: false,\n };\n plans.set(where.abs, plan);\n return plan;\n };\n\n for (const entry of index.entries) {\n const plan = await planFor(`${entry.collection}\\u0000${entry.file}\\u0000${entry.join}`);\n if (plan === undefined) continue;\n const data: Record<string, unknown> = {};\n for (const [key, supplied] of valuesOf(index, entry)) {\n if (supplied.file === entry.file && supplied.collection === entry.collection) {\n data[key] = supplied.value;\n }\n }\n const done = reencryptData(data, { fromKey: opts.fromKey, toKey: opts.toKey });\n for (const r of done.rewritten) {\n plan.manifest.rewritten.push({ entry: entry.spelled, ...r });\n }\n for (const s of done.skipped) {\n plan.manifest.skipped.push({ entry: entry.spelled, ...s });\n }\n for (const key of done.keys) {\n plan.text = spliceManifestValue(plan.text, {\n entry: entry.spelled,\n key,\n value: done.data[key],\n join: entry.join,\n file: plan.manifest.file,\n }).text;\n plan.changed = true;\n }\n }\n\n return [...plans.values()].filter(\n (p) => p.manifest.rewritten.length > 0 || p.manifest.skipped.length > 0,\n );\n}\n\nexport async function runKeyRotate(opts: KeyRotateOptions): Promise<KeyRotateResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const env = opts.env ?? process.env;\n if (opts.to !== undefined && !isValidEncryptionKey(opts.to)) throw new KeyError(BAD_TO);\n if (opts.inputs.includes(STDIN_TOKEN)) throw new KeyError(NO_STDIN);\n const wanted = opts.collection ?? [];\n if (wanted.length > 0 && opts.inputs.length > 0) throw new KeyError(WITH_PATHS);\n\n const file = await readRotateConfig(opts.configPath, cwd);\n if (wanted.length > 0 && file === null) throw new KeyError(NEEDS_CONFIG);\n const { key: current, source: keySource } = resolveEncryptionKey({\n env,\n file,\n toError: toKeyError,\n });\n if (current === undefined) throw new KeyError(NO_KEY);\n const narrowed = opts.inputs.length > 0 || wanted.length > 0;\n\n // Only a key from the config has a config a rotation can be finished in.\n const keyFile = keySource === \"config\" ? file : null;\n const previous = keyFile?.encryptionKeyPrevious;\n if (\n keyFile !== null &&\n previous !== undefined &&\n (narrowed || (opts.to !== undefined && opts.to !== current))\n ) {\n throw new KeyError(unfinishedRotation(keyFile.source));\n }\n if (keySource === \"env\" && opts.to === undefined) throw new KeyError(ENV_NEEDS_TO);\n if (narrowed && opts.to === undefined) throw new KeyError(NARROWED_NEEDS_TO);\n\n // Finishing an interrupted rotation goes from the key it replaced to the one\n // the config already holds; otherwise from the current key to the new one.\n const fromKey = previous ?? current;\n const toKey = previous === undefined ? (opts.to ?? generateEncryptionKey()) : current;\n\n const collections =\n file === null ? [] : selectCollections(file.collections, wanted, file.source, toKeyError);\n const fromCollections = opts.inputs.length === 0;\n const inputs = fromCollections ? collections.flatMap((c) => c.paths) : opts.inputs;\n if (inputs.length === 0) throw new KeyError(NO_FILES);\n // One base per run, as in cite and meta: typed paths from cwd, a\n // collection's `paths:` from the config's directory.\n const base = fromCollections && file !== null ? file.dir : cwd;\n\n const forced = opts.as === undefined ? undefined : extractorByName(opts.as);\n if (opts.as !== undefined && forced === undefined) {\n throw new KeyError(\n `Unknown format \"${opts.as}\". Supported extensions: ${supportedExtensions().join(\", \")}.`,\n );\n }\n const format = forced?.name;\n const exts = opts.exts ?? forced?.extensions;\n const exclude = [\n ...new Set([\n ...(opts.exclude ?? []),\n ...(fromCollections ? collections.flatMap((c) => c.exclude) : []),\n ]),\n ];\n const { files, gitignoreSkipped } = await resolveTargetSet({\n inputs,\n exts,\n exclude,\n cwd: base,\n allowEmpty: opts.allowEmpty,\n ...gitignoreOptions({ flag: opts.respectGitignore, onNotice: opts.onNotice }),\n });\n assertNonEmpty({\n files,\n inputs,\n usingStdin: false,\n allowEmpty: opts.allowEmpty,\n exclude,\n exts,\n gitignoreSkipped,\n action: \"re-encrypted\",\n });\n\n const cite = citeSection(file);\n const { root, fellBack } = rootFor(opts.root, cite, file, cwd);\n const client = opts.gitClient ?? gitClient(root);\n // Built once, and only when a page cites an encrypted source.\n let index: Promise<SourceIndex> | undefined;\n const sourceIndex = (): Promise<SourceIndex> => {\n if (index === undefined) {\n if (fellBack) opts.onNotice?.(`No git root found; resolving src: paths from ${cwd}`);\n index = indexFor(root, client);\n }\n return index;\n };\n\n // The manifests that own `citations` (proposal 0044): a page whose entries\n // live in one carries no ciphertext of its own, so they are read for every\n // page of the run, not only the ones the shortcut below lets through.\n const sidecars =\n file === null\n ? null\n : await loadCitationSidecars({\n collections: file.collections,\n configDir: file.dir,\n base,\n configSource: file.source,\n key: current,\n toError: toKeyError,\n // A keyless manifest (proposal 0068) keeps what a page's schemas mark.\n marks: () => configMarks(file.path, file.dir),\n // A `{page}` manifest (0058) is read for exactly the pages rotated.\n pages: files.map((rel) => resolve(base, rel)),\n });\n const manifests = new ManifestSet();\n\n const planned: Planned[] = [];\n let wantsHistory = false;\n for (const rel of files) {\n const path = resolve(base, rel);\n const before = await readFile(path, \"utf8\");\n const page = { file: rel, content: before, ...(format === undefined ? {} : { format }) };\n // A page's own values first, then the entries its manifest holds.\n const sidecarWork = await rotateManifestCitations(sidecars, manifests, page, {\n root,\n fromKey,\n toKey,\n gitClient: client,\n sourceIndex,\n });\n if (sidecarWork.wantsHistory) wantsHistory = true;\n if (!ANY_CIPHERTEXT.test(before)) {\n if (sidecarWork.rewritten.length === 0 && sidecarWork.skipped.length === 0) continue;\n planned.push({\n page: { file: rel, rewritten: sidecarWork.rewritten, skipped: sidecarWork.skipped, written: false },\n path,\n content: before,\n changed: false,\n });\n continue;\n }\n const meta = reencryptMetadata(page, { fromKey, toKey });\n const encrypted = encryptedCitations(rel, meta.content, format);\n if (encrypted.withCommit) wantsHistory = true;\n const cited: ReencryptCitationsResult = encrypted.any\n ? await reencryptCitations(\n { ...page, content: meta.content },\n { root, fromKey, toKey, gitClient: client, sourceIndex: await sourceIndex() },\n )\n : { content: meta.content, rewritten: [], skipped: [] };\n const rewritten: RotatedValue[] = [\n ...meta.rewritten.map((r) => ({ kind: \"metadata\" as const, ...r })),\n ...cited.rewritten.map((r) => ({ kind: \"citation\" as const, ...r })),\n ...sidecarWork.rewritten,\n ];\n const skipped: SkippedValue[] = [\n ...meta.skipped.map((s) => ({ kind: \"metadata\" as const, ...s })),\n ...cited.skipped.map((s) => ({ kind: \"citation\" as const, ...s })),\n ...sidecarWork.skipped,\n ];\n if (rewritten.length === 0 && skipped.length === 0) continue;\n planned.push({\n page: { file: rel, rewritten, skipped, written: false },\n path,\n content: cited.content,\n changed: cited.content !== before,\n });\n }\n\n // A pin that no longer holds is re-keyed from the lines at its commit, so a\n // citation with one wants git. Where git is not there, said once.\n if (wantsHistory && !(await client.available())) opts.onNotice?.(GIT_UNAVAILABLE_HISTORY);\n\n // The private half of the same documents: every local manifest of the\n // collections this run covers. Planned in memory like the pages, and\n // counted with them, so one unreadable value anywhere stops the whole run.\n const valueManifests =\n file === null\n ? []\n : await planManifests({\n collections: manifestCollections(collections, {\n fromCollections,\n files,\n base,\n configDir: file.dir,\n }),\n configDir: file.dir,\n base,\n fromKey,\n toKey,\n pages: files.map((rel) => resolve(base, rel)),\n whole: !narrowed,\n });\n\n const reencrypted =\n planned.reduce((n, p) => n + p.page.rewritten.length, 0) +\n valueManifests.reduce((n, m) => n + m.manifest.rewritten.length, 0);\n const skipped =\n planned.reduce((n, p) => n + p.page.skipped.length, 0) +\n valueManifests.reduce((n, m) => n + m.manifest.skipped.length, 0);\n const writePage = opts.writePage ?? ((path: string, content: string) => writeFileAtomic(path, content));\n\n let outcome: RotateOutcome;\n if (skipped > 0) {\n // The new key is never written beside a value it cannot decrypt, and no\n // page is written without the key: nothing at all.\n outcome = \"skipped\";\n } else if (opts.dryRun === true) {\n outcome = \"dry-run\";\n } else {\n const writesKey = !narrowed && keyFile !== null;\n // (1) The new key, with the old one beside it. A rotation being finished\n // already has both.\n if (!narrowed && keyFile !== null && previous === undefined) {\n await writeEncryptionKey({ file: keyFile, key: toKey, previous: fromKey, cwd, toError: toKeyError });\n }\n // (2) The pages, then the manifests: the citations one owns, and the\n // encrypted values another holds. Each manifest is written once,\n // however many pages it keeps entries for.\n for (const p of planned) {\n if (!p.changed) continue;\n await writePage(p.path, p.content);\n p.page.written = true;\n }\n for (const changed of manifests.changed()) await writePage(changed.path, changed.text);\n for (const m of valueManifests) {\n if (!m.changed) continue;\n await writePage(m.path, m.text);\n m.manifest.written = true;\n }\n // (3) The old key goes, now that nothing is under it.\n if (!narrowed && keyFile !== null) {\n await writeEncryptionKey({ file: keyFile, key: toKey, previous: null, cwd, toError: toKeyError });\n }\n if (narrowed) outcome = \"narrowed\";\n else if (!writesKey) outcome = \"env\";\n else outcome = previous === undefined ? \"written\" : \"finished\";\n }\n\n const wrote = outcome !== \"skipped\" && outcome !== \"dry-run\";\n const baseline =\n file !== null && cite.baseline !== undefined\n ? resolve(file.dir, cite.baseline)\n : join(file?.dir ?? cwd, DEFAULT_CITE_BASELINE_PATH);\n\n return {\n pages: planned.map((p) => p.page),\n manifests: valueManifests.map((m) => m.manifest),\n reencrypted,\n skipped,\n keyWritten: outcome === \"written\" || outcome === \"finished\",\n outcome,\n ...(keyFile === null ? {} : { configSource: keyFile.source }),\n baselineStale: wrote && existsSync(baseline),\n exitCode: skipped > 0 ? 1 : 0,\n };\n}\n","/**\n * Which config file `manni key` reads and writes. `key` has no section of its\n * own (proposal 0045): the key it manages sits at the top of the family file,\n * beside `collections:`.\n *\n * - `set` writes the nearest family file whatever it carries, or the one `-c`\n * names, read as a family file (`findFamilyConfigFile`,\n * `readFamilyConfigFile`).\n * - `rotate` reads its key and collections from the file every sibling\n * without a section there would read them from: the nearest family file\n * carrying `collections:` or `encryptionKey:`. That is discovery with a\n * section name nothing uses.\n */\nimport {\n findConfigFile,\n findFamilyConfigFile,\n readConfigFile,\n readFamilyConfigFile,\n type ConfigFile,\n type ConfigFileOptions,\n} from \"../../shared/config-file.js\";\nimport { KeyError } from \"../errors.js\";\n\nexport const toKeyError = (message: string): KeyError => new KeyError(message);\n\nconst KEY_CONFIG: ConfigFileOptions = {\n section: \"key\",\n // The key never had a file of its own.\n legacyNames: [],\n toError: toKeyError,\n};\n\n/** The config `rotate` reads the current key and the collections from. */\nexport function readRotateConfig(\n configPath: string | undefined,\n cwd: string,\n): Promise<ConfigFile | null> {\n return configPath === undefined\n ? findConfigFile(cwd, KEY_CONFIG)\n : readConfigFile(configPath, cwd, KEY_CONFIG);\n}\n\n/** The config `set` writes to; `null` when discovery finds no family file. */\nexport function readSetConfig(\n configPath: string | undefined,\n cwd: string,\n): Promise<ConfigFile | null> {\n return configPath === undefined\n ? findFamilyConfigFile(cwd, toKeyError)\n : readFamilyConfigFile(configPath, cwd, toKeyError);\n}\n\n/** The refusal while `encryptionKeyPrevious:` says a rotation is unfinished. */\nexport const unfinishedRotation = (source: string): string =>\n `A rotation is unfinished in ${source}. Run \\`manni key rotate\\` with no --to to finish it.`;\n","/**\n * `manni key set [value]`: write the family encryption key (proposal 0045).\n *\n * Refusals, each exit 2 and none echoing a value: a value of the wrong shape;\n * `MANNI_ENCRYPTION_KEY` set, because it wins and the written key would never\n * be read; a rotation left unfinished; a key already configured, because\n * replacing one in place strands every value encrypted under it (`rotate` is\n * what replaces a key); and a new `manni.config.yaml` beside a legacy\n * `docmeta.config.yaml`, which the new file would hide from `manni meta`.\n *\n * It warns, and still writes, when git would publish the file.\n */\nimport { existsSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { LEGACY_CONFIG_NAMES } from \"../../meta/internal.js\";\nimport {\n ENCRYPTION_KEY_ENV,\n committedKeyWarning,\n isIgnoredByGit,\n writeEncryptionKey,\n} from \"../../shared/encryption-key.js\";\nimport { generateEncryptionKey, isValidEncryptionKey } from \"../../shared/encryption.js\";\nimport { readSetConfig, toKeyError, unfinishedRotation } from \"../core/config.js\";\nimport { KeyError } from \"../errors.js\";\nimport type { KeySetOptions, KeySetResult } from \"../types.js\";\n\nconst BAD_VALUE =\n \"The key must be at least 32 hex or base64url characters. Run `manni key set` with no value to generate one.\";\nconst ENV_SET = `${ENCRYPTION_KEY_ENV} is set, so a key written to config would never be read. Unset it, or keep the key in the secret.`;\n\nconst alreadyConfigured = (source: string): string =>\n `An encryption key is already configured in ${source}. Run \\`manni key rotate\\` to replace it and re-encrypt every value.`;\n\n/**\n * A new family file beside a legacy per-tool file hides it: discovery reads\n * the family file first in a directory, and one holding only a key is every\n * tool's config, so `manni meta` would stop reading the options it had.\n */\nfunction refuseBesideLegacy(path: string, cwd: string): void {\n const dir = dirname(path);\n const name = basename(path);\n for (const legacy of LEGACY_CONFIG_NAMES) {\n const found = join(dir, legacy);\n if (!existsSync(found)) continue;\n const source = relative(cwd, found).replace(/\\\\/g, \"/\");\n throw new KeyError(\n `${source} is a single-tool config; a ${name} beside it would hide it. Move its keys under meta: in ${name} first.`,\n );\n }\n}\n\nexport async function runKeySet(opts: KeySetOptions): Promise<KeySetResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const env = opts.env ?? process.env;\n if (opts.value !== undefined && !isValidEncryptionKey(opts.value)) {\n throw new KeyError(BAD_VALUE);\n }\n // Empty counts as unset, as `resolveEncryptionKey` has it.\n const fromEnv = env[ENCRYPTION_KEY_ENV];\n if (fromEnv !== undefined && fromEnv !== \"\") throw new KeyError(ENV_SET);\n\n const file = await readSetConfig(opts.configPath, cwd);\n if (file?.encryptionKeyPrevious !== undefined) {\n throw new KeyError(unfinishedRotation(file.source));\n }\n if (file?.encryptionKey !== undefined) {\n throw new KeyError(alreadyConfigured(file.source));\n }\n\n const generated = opts.value === undefined;\n const key = opts.value ?? generateEncryptionKey();\n const dryRun = opts.dryRun === true;\n // Name the target before writing to it: the legacy check and the git\n // warning are both about the file the key is about to land in.\n const target = await writeEncryptionKey({ file, key, cwd, toError: toKeyError, dryRun: true });\n if (target.created) refuseBesideLegacy(target.path, cwd);\n if (isIgnoredByGit(target.path) === false) {\n opts.onNotice?.(committedKeyWarning(target.source));\n }\n if (!dryRun) await writeEncryptionKey({ file, key, cwd, toError: toKeyError });\n return { path: target.path, source: target.source, created: target.created, generated, dryRun };\n}\n","/**\n * The contract every other module is written against.\n *\n * Two shapes matter. `DocumentTree` is what a parser owes the rest of the tool:\n * a nested section tree with real source positions, in a vocabulary that has\n * nothing to do with Markdown. `Finding` is what the tool owes its caller.\n * Everything between the two - matching, rules, reporting - touches neither\n * mdast nor Asciidoctor nor parse5, which is what lets a new input format be\n * one file plus a line in the parser registry.\n */\n\nimport { ToolError } from \"../shared/errors.js\";\nimport type { Severity } from \"../shared/severity.js\";\n\n/**\n * Operational/usage failure. Exits 2; never used for lint findings.\n *\n * Extends the umbrella's `ToolError`, which is what the shared bin runner\n * matches on; the subclass stays so this tool's tests and library callers can\n * match on it by name. Named for its domain, as `A11yError`, `CiteError` and\n * `KeyError` are.\n */\nexport class LintError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"LintError\";\n }\n}\n\n/** A point in a source file. Line and column are 1-based, offset 0-based. */\nexport interface Point {\n line: number;\n column: number;\n offset: number;\n}\n\n/** A half-open source span, `start` inclusive and `end` exclusive. */\nexport interface Position {\n start: Point;\n end: Point;\n}\n\n/**\n * Content kinds a section can hold, named generically so a rule written once\n * works on every format. Each parser maps its own AST onto these: mdast\n * `paragraph`/`code`/`list`, Asciidoctor `paragraph`/`listing`/`ulist`|`olist`,\n * HTML `<p>`/`<pre>`/`<ul>` - all three onto `paragraph`/`codeBlock`/`list`.\n *\n * The vocabulary is wider than any one parser emits today. `table`,\n * `admonition`, `image`, `blockquote`, `definitionList`, and `element` are\n * declared here, and in each `DocumentParser.kinds`, only once a parser\n * actually produces them - see `src/lint/parsers/index.ts`.\n */\nexport type ContentKind =\n | \"paragraph\"\n | \"codeBlock\"\n | \"list\"\n | \"listItem\"\n | \"table\"\n | \"tableRow\"\n | \"tableCell\"\n | \"admonition\"\n | \"image\"\n | \"blockquote\"\n | \"definitionList\"\n | \"definitionItem\"\n | \"element\";\n\nexport interface ContentNodeBase {\n kind: ContentKind;\n position: Position;\n /** Plain-text rendering, used by pattern rules. */\n text: string;\n}\n\nexport interface ParagraphNode extends ContentNodeBase {\n kind: \"paragraph\";\n}\n\nexport interface CodeNode extends ContentNodeBase {\n kind: \"codeBlock\";\n /** Language, when the format carries one. */\n language?: string;\n /** The info-string tail after the language, when the format carries one. */\n fenceInfo?: string;\n}\n\nexport interface ListItemNode {\n kind: \"listItem\";\n position: Position;\n text: string;\n /** Nested content, so item-level paragraph/code/list rules can run. */\n children: ContentNode[];\n}\n\nexport interface ListNode extends ContentNodeBase {\n kind: \"list\";\n ordered: boolean;\n items: ListItemNode[];\n}\n\nexport interface TableCellNode extends ContentNodeBase {\n kind: \"tableCell\";\n children: ContentNode[];\n}\n\nexport interface TableRowNode extends ContentNodeBase {\n kind: \"tableRow\";\n header: boolean;\n children: TableCellNode[];\n}\n\nexport interface TableNode extends ContentNodeBase {\n kind: \"table\";\n children: TableRowNode[];\n}\n\n/**\n * A callout, and the flavor the source gave it.\n *\n * `variant` is optional because not every format names one this vocabulary\n * has. reStructuredText has `hint`, `attention`, `error` and a generic\n * `admonition` directive, and a bare HTML `<aside>` says nothing at all. Those\n * produce an admonition with no variant rather than an invented equivalence:\n * mapping `hint` onto `tip` would make `variant: tip` pass on a page that\n * never said tip. A `variant:` rule reports such a node as a mismatch, and a\n * plain count rule still counts it.\n */\nexport interface AdmonitionNode extends ContentNodeBase {\n kind: \"admonition\";\n variant?: \"note\" | \"tip\" | \"important\" | \"caution\" | \"warning\" | \"danger\";\n children: ContentNode[];\n}\n\nexport interface ImageNode extends ContentNodeBase {\n kind: \"image\";\n url: string;\n alt: string;\n title?: string;\n}\n\nexport interface BlockquoteNode extends ContentNodeBase {\n kind: \"blockquote\";\n children: ContentNode[];\n}\n\nexport interface DefinitionItemNode {\n kind: \"definitionItem\";\n position: Position;\n text: string;\n term: string;\n definition: ContentNode[];\n}\n\nexport interface DefinitionListNode extends ContentNodeBase {\n kind: \"definitionList\";\n children: DefinitionItemNode[];\n}\n\n/**\n * A named wrapper - an MDX/JSX component today, and where HTML and DITA may\n * eventually anchor a custom element. Its children are its own content, never\n * the enclosing section's: a rule reading a section's `children` must not see\n * inside an `<Element>` it did not ask about.\n */\nexport interface ElementNode extends ContentNodeBase {\n kind: \"element\";\n name: string;\n attributes?: Record<string, string | true>;\n children: ContentNode[];\n}\n\nexport type ContentNode =\n | ParagraphNode\n | CodeNode\n | ListNode\n | TableNode\n | AdmonitionNode\n | ImageNode\n | BlockquoteNode\n | DefinitionListNode\n | ElementNode;\n\n/**\n * One section of a document, demarcated by a heading.\n *\n * `slug`/`title`/`level`/`order`/`parentSlug` intentionally match manni kg's\n * `Section` (dockg/src/types.ts), so its graph can be built from this tree.\n *\n * `children` is in document order and is the single source of truth: the\n * paragraph/codeBlock/list counts every rule needs are queries over it, not\n * separately maintained arrays.\n */\nexport interface SectionNode {\n /** Slug of the heading, disambiguated across the document (`install-1`). */\n slug: string;\n /** Heading text, with inline markup flattened. */\n title: string;\n /** Heading level, 1-6. 0 for the implicit lead section before any heading. */\n level: number;\n /** 1-based position among siblings under the same parent. */\n order: number;\n /** Slug of the enclosing section, or null at the top level. */\n parentSlug: string | null;\n /** Span of the title itself. Null for the implicit lead section. */\n titlePosition: Position | null;\n /** Span of the whole section: its heading through the last node before the next sibling heading. */\n position: Position;\n /** Direct content, in document order, excluding anything owned by a subsection. */\n children: ContentNode[];\n /** Nested sections, in document order. */\n sections: SectionNode[];\n}\n\n/** What a parser returns for one file. */\nexport interface DocumentTree {\n /** Name of the parser that produced this (`markdown`, `asciidoc`, ...). */\n format: string;\n /** Path the content came from, for error messages. */\n filePath: string;\n /** Raw frontmatter/metadata values, or null when the file carries none. */\n frontmatter: Record<string, unknown> | null;\n /** Span of the frontmatter block, for anchoring findings about it. */\n frontmatterPosition: Position | null;\n /** Top-level sections, in document order. */\n sections: SectionNode[];\n}\n\n/**\n * A parser for one input format.\n *\n * Shaped after docmeta's `MetadataExtractor` so the two registries read the\n * same way. A format is registered only when its parser reads it, so every\n * registered format is one the tool reads, and an extension no parser claims is\n * skipped by name rather than parsed as Markdown.\n */\nexport interface DocumentParser {\n /** Stable name, also used as `DocumentTree.format`. */\n name: string;\n /** Human-readable label for `manni lint tools`. */\n label: string;\n /**\n * The content kinds this parser actually emits today. A capability\n * declaration, not the full `ContentKind` vocabulary: a kind absent here is\n * one no rule will ever see from this parser's trees, whatever the format\n * could in principle represent.\n */\n kinds: ContentKind[];\n /** Lowercase file extensions this parser handles, incl. dot (e.g. \".md\"). */\n extensions: string[];\n /**\n * Extensions safe to collect from a directory walk. Defaults to\n * `extensions`.\n *\n * The two differ when an extension is a generic container rather than a\n * documentation format. `.xml` is the case: this parser can read a DocBook\n * or DITA document named explicitly, but a docs tree also contains\n * `pom.xml`, `sitemap.xml`, and `.csproj`, and sweeping those in turns a\n * clean run into a failure about files the user never asked to lint.\n */\n walkExtensions?: string[];\n /** Parse raw file content into the generic tree. */\n parse(content: string, filePath: string): DocumentTree;\n}\n\n/**\n * How much a finding weighs, on the one scale every manni tool speaks\n * (`src/shared/severity.ts`): `notice | warning | error`.\n *\n * Almost every structural finding is an `error`, since a template either\n * describes a document or it does not. `unsupported_content_kind` is the\n * exception and is a `warning`: the rule never ran, so the page may still be\n * fine, and a warning never moves the exit code.\n *\n * The scale is the family's and not this tool's private pair, because a flag\n * or config key two domains both have carries the same name *and* the same\n * values. Re-exported so `lint.Severity` names the same type a caller already\n * has.\n */\nexport type { Severity };\n\n/**\n * One structural violation.\n *\n * The field set is pinned by manni docevals' tool adapter, which reads\n * `{ type, heading, message, position }` off the JSON reporter. Additions are\n * safe; renames are not.\n */\nexport interface Finding {\n /** Machine-readable rule id, e.g. `missing_section`. */\n type: string;\n /** Heading of the section the finding is anchored to, if any. */\n heading: string | null;\n message: string;\n position: Position;\n severity: Severity;\n}\n\n/**\n * Why a file was not linted.\n *\n * `unreadable` is the one that is not about the document: the file was found,\n * claimed by a parser, and then could not be opened - a denied permission, a\n * symlink loop, a page a doc build moved between the walk and the read. It is a\n * skip rather than a finding because nothing was checked, and calling it a\n * finding would report the docs as wrong when the filesystem was.\n */\nexport type SkipReason = \"no-template\" | \"unsupported-format\" | \"unreadable\";\n\n/** Result of linting one file. */\nexport interface FileResult {\n file: string;\n /** True when the file was linted and produced no findings. */\n success: boolean;\n findings: Finding[];\n /** Template id/ref applied, or null when skipped. */\n template: string | null;\n /** Set when the file was skipped rather than linted. */\n skipped?: SkipReason;\n}\n","/**\n * Markdown and MDX parsers.\n *\n * They share everything but the unified processor. MDX needs its own, selected\n * by extension rather than by a flag: `remark-mdx` reads `{` as an expression\n * delimiter, so ordinary Markdown prose containing a brace is a syntax error\n * under it. Running one processor for both formats would break either MDX\n * (without the plugin) or plain Markdown (with it).\n */\nimport { unified } from \"unified\";\nimport remarkParse from \"remark-parse\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkFrontmatter from \"remark-frontmatter\";\nimport remarkMdx from \"remark-mdx\";\nimport { extractFrontmatter } from \"../../meta/index.js\";\nimport type { ContentKind, DocumentParser, DocumentTree } from \"../types.js\";\nimport { LintError } from \"../types.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { documentEnd, toFragments } from \"./mdast.js\";\nimport { sectionize } from \"./sectionize.js\";\nimport { fencedPosition as frontmatterPosition, withMetadataTitle as withFrontmatterTitle } from \"./metadata.js\";\n\nconst markdownProcessor = unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkFrontmatter, [\"yaml\", \"toml\"]);\n\nconst mdxProcessor = unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkFrontmatter, [\"yaml\", \"toml\"])\n .use(remarkMdx);\n\n/**\n * Only `parse` is used, and unified's `Processor` generics differ between the\n * plain and MDX pipelines (their tree types are not the same), so the narrow\n * structural type is both sufficient and the one that lets both pass.\n */\ninterface Parseable {\n parse(content: string): unknown;\n}\n\nfunction parseWith(\n processor: Parseable,\n format: string,\n content: string,\n filePath: string,\n): DocumentTree {\n let root: unknown;\n try {\n root = processor.parse(content);\n } catch (err) {\n // MDX raises on malformed expressions; a parse failure is the file's\n // problem, not a crash, so it surfaces as an operational error naming it.\n throw new LintError(\n `${filePath}: could not parse as ${format}: ${errorMessage(err)}`,\n );\n }\n\n const meta = extractFrontmatter(content, format);\n const tree = root as Parameters<typeof toFragments>[0];\n\n const frontmatter = meta.present ? meta.data : null;\n const metaPosition = frontmatterPosition(content);\n\n return {\n format,\n filePath,\n frontmatter,\n frontmatterPosition: metaPosition,\n sections: sectionize(\n withFrontmatterTitle(toFragments(tree), frontmatter, metaPosition),\n documentEnd(tree),\n ),\n };\n}\n\n/**\n * What both formats emit. `element` is MDX's alone: plain Markdown has no JSX,\n * so `<Steps>` is raw HTML to it and no tree it produces carries an element.\n * Declaring one here would report a rule about elements as checked on every\n * `.md` file it silently could not see.\n */\nconst SHARED_KINDS: ContentKind[] = [\n \"paragraph\",\n \"codeBlock\",\n \"list\",\n \"listItem\",\n \"table\",\n \"tableRow\",\n \"tableCell\",\n \"admonition\",\n \"image\",\n \"blockquote\",\n];\n\nexport const markdownParser: DocumentParser = {\n name: \"markdown\",\n label: \"Markdown\",\n kinds: SHARED_KINDS,\n extensions: [\".md\", \".markdown\"],\n parse: (content, filePath) =>\n parseWith(markdownProcessor, \"markdown\", content, filePath),\n};\n\nexport const mdxParser: DocumentParser = {\n name: \"mdx\",\n label: \"MDX\",\n kinds: [...SHARED_KINDS, \"element\"],\n extensions: [\".mdx\"],\n parse: (content, filePath) => parseWith(mdxProcessor, \"mdx\", content, filePath),\n};\n","/**\n * mdast -> generic fragments. Shared by the Markdown and MDX parsers, which\n * differ only in which unified processor produced the tree.\n *\n * The mapping is onto the family content model (proposal 0065), never onto a\n * nearest neighbour: a blockquote is a `blockquote` and a table is a `table`,\n * because counting either as a paragraph would make `paragraphs: {max: 3}`\n * fail documents a reader would say satisfy it. A node type the model has no\n * kind for is still skipped with its subtree rather than approximated.\n *\n * MDX-only node types (`mdxJsxFlowElement`, and the expressions and comments\n * this file deliberately drops) appear only in trees the MDX processor\n * produced. The plain Markdown processor has no `remark-mdx`, so its trees\n * cannot carry them and `markdownParser` neither emits `element` nor declares\n * it. That is why one mapping serves both formats without a mode flag.\n */\nimport { toString as mdastToString } from \"mdast-util-to-string\";\nimport type { Position } from \"../types.js\";\nimport type {\n AdmonitionNode,\n ContentNode,\n ElementNode,\n ImageNode,\n ListItemNode,\n TableCellNode,\n TableRowNode,\n} from \"../types.js\";\nimport type { Fragment } from \"./sectionize.js\";\n\n/** An MDX JSX attribute, as `mdast-util-mdx-jsx` shapes it. */\ninterface MdAttribute {\n type: string;\n name?: string | null;\n /** A string for `a=\"b\"`, null for a bare `a`, an expression node for `a={b}`. */\n value?: string | { type?: string; value?: string } | null;\n}\n\n/** Minimal structural view of an mdast node; avoids depending on @types/mdast shapes. */\ninterface MdNode {\n type: string;\n position?: {\n start: { line: number; column: number; offset?: number };\n end: { line: number; column: number; offset?: number };\n };\n children?: MdNode[];\n depth?: number;\n lang?: string | null;\n ordered?: boolean | null;\n value?: string;\n url?: string;\n alt?: string | null;\n title?: string | null;\n /** MDX JSX only; null on a fragment (`<>`). */\n name?: string | null;\n attributes?: MdAttribute[];\n}\n\nconst ZERO: Position = {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n};\n\n/**\n * unist positions carry `offset` as optional. It is always present on a tree\n * remark parsed from a string, but the type does not say so, and a missing\n * offset would otherwise become `NaN` in a reporter.\n */\nexport function positionOf(node: MdNode): Position {\n const p = node.position;\n if (!p) return { start: { ...ZERO.start }, end: { ...ZERO.end } };\n return {\n start: { line: p.start.line, column: p.start.column, offset: p.start.offset ?? 0 },\n end: { line: p.end.line, column: p.end.column, offset: p.end.offset ?? 0 },\n };\n}\n\nfunction isContentNode(node: ContentNode | null): node is ContentNode {\n return node !== null;\n}\n\nfunction childContent(node: MdNode): ContentNode[] {\n return (node.children ?? []).map(toContentNode).filter(isContentNode);\n}\n\n/**\n * `AdmonitionNode.variant` is optional, for the formats that name a flavor\n * this vocabulary does not carry. A GitHub alert always names one of five, so\n * every admonition this file produces has one, and saying so here is what\n * keeps a missing lookup from being mistaken for a format that named nothing.\n */\ntype AlertVariant = NonNullable<AdmonitionNode[\"variant\"]>;\n\n/**\n * The five alert types GitHub defines. `danger` is in the model's `variant`\n * set but is not one of them, so `> [!DANGER]` renders as an ordinary\n * blockquote and is read as one here: a word outside the source's own set is\n * not an equivalence to invent.\n */\nconst ALERT_VARIANTS = new Map<string, AlertVariant>([\n [\"note\", \"note\"],\n [\"tip\", \"tip\"],\n [\"important\", \"important\"],\n [\"warning\", \"warning\"],\n [\"caution\", \"caution\"],\n]);\n\n/** The marker line, which must be the whole first line of the first paragraph. */\nconst ALERT_MARKER = /^\\[!([A-Za-z]+)\\][^\\S\\n]*$/;\n\n/**\n * The same marker where it sits at the head of a flattened string, with the\n * newline that followed it. `mdast-util-to-string` concatenates block children\n * without a separator, so the marker's paragraph may run straight into the\n * next one and there is no newline to consume.\n */\nconst ALERT_PREFIX = /^\\[!\\w+\\][^\\S\\n]*\\n?/;\n\n/**\n * A GitHub alert, which is a blockquote whose first paragraph opens with a\n * marker line. It is a check on that paragraph's text rather than a plugin,\n * because the marker is ordinary text to every Markdown parser.\n */\nfunction alertVariant(node: MdNode): AlertVariant | null {\n const first = node.children?.[0];\n if (!first || first.type !== \"paragraph\") return null;\n const text = mdastToString(first);\n const newline = text.indexOf(\"\\n\");\n const firstLine = newline === -1 ? text : text.slice(0, newline);\n const match = ALERT_MARKER.exec(firstLine);\n const word = match?.[1];\n // Case-insensitively, as GitHub matches it.\n return word ? (ALERT_VARIANTS.get(word.toLowerCase()) ?? null) : null;\n}\n\nfunction toAdmonition(node: MdNode, variant: AlertVariant): AdmonitionNode {\n const children = childContent(node);\n const first = children[0];\n // The marker is markup, not content, so it is stripped from the admonition's\n // own text and from the paragraph that carried it. A paragraph left holding\n // nothing but the marker is dropped rather than kept as an empty one.\n if (first && first.kind === \"paragraph\") {\n const stripped = first.text.replace(ALERT_PREFIX, \"\");\n if (stripped.length === 0) children.shift();\n else children[0] = { ...first, text: stripped };\n }\n return {\n kind: \"admonition\",\n position: positionOf(node),\n text: mdastToString(node).replace(ALERT_PREFIX, \"\"),\n variant,\n children,\n };\n}\n\n/**\n * The image a paragraph holds, when that is all it holds. An image inside\n * richer prose is part of what the paragraph says: promoting it would take the\n * sentence around it out of the paragraph count.\n */\nfunction soleImage(node: MdNode): MdNode | null {\n const meaningful = (node.children ?? []).filter(\n (child) => !(child.type === \"text\" && (child.value ?? \"\").trim().length === 0),\n );\n const only = meaningful.length === 1 ? meaningful[0] : undefined;\n return only && only.type === \"image\" ? only : null;\n}\n\nfunction toImage(node: MdNode): ImageNode {\n const alt = node.alt ?? \"\";\n return {\n kind: \"image\",\n position: positionOf(node),\n text: alt,\n url: node.url ?? \"\",\n alt,\n ...(node.title ? { title: node.title } : {}),\n };\n}\n\n/**\n * An MDX element's attributes, by their literal values: the string for\n * `a=\"b\"`, `true` for a bare `a`, and the braced source for `a={b}`, so a rule\n * can say \"its value is an expression\" rather than silently not matching a\n * value it cannot know. A spread (`{...rest}`) names no attribute and is\n * dropped, having no key to record it under.\n */\nfunction attributesOf(node: MdNode): Record<string, string | true> | undefined {\n const attributes: Record<string, string | true> = {};\n let any = false;\n for (const attribute of node.attributes ?? []) {\n if (attribute.type !== \"mdxJsxAttribute\") continue;\n const name = attribute.name;\n if (typeof name !== \"string\" || name.length === 0) continue;\n const value = attribute.value;\n if (value === null || value === undefined) attributes[name] = true;\n else if (typeof value === \"string\") attributes[name] = value;\n else attributes[name] = `{${value.value ?? \"\"}}`;\n any = true;\n }\n return any ? attributes : undefined;\n}\n\nfunction toElement(node: MdNode): ElementNode {\n const attributes = attributesOf(node);\n return {\n kind: \"element\",\n position: positionOf(node),\n text: mdastToString(node),\n // A fragment (`<>`) has no tag to name.\n name: node.name ?? \"\",\n ...(attributes ? { attributes } : {}),\n // The element's own children, never the enclosing section's: a section\n // holding one `<Steps>` holds one block, not the four paragraphs inside\n // it (proposal 0065, stress test 4). A heading inside one is dropped with\n // everything else the model has no kind for, which stress test 5 records.\n children: childContent(node),\n };\n}\n\nfunction toTableRow(row: MdNode, header: boolean): TableRowNode {\n return {\n kind: \"tableRow\",\n position: positionOf(row),\n text: mdastToString(row),\n header,\n children: (row.children ?? [])\n .filter((cell) => cell.type === \"tableCell\")\n .map(\n (cell): TableCellNode => ({\n kind: \"tableCell\",\n position: positionOf(cell),\n text: mdastToString(cell),\n // A GFM cell holds inline content only, so this is empty today. It\n // is mapped rather than assumed empty because the model's cell is\n // the one reStructuredText and DITA fill with blocks.\n children: childContent(cell),\n }),\n ),\n };\n}\n\nfunction toContentNode(node: MdNode): ContentNode | null {\n switch (node.type) {\n case \"paragraph\": {\n const image = soleImage(node);\n if (image) return toImage(image);\n return {\n kind: \"paragraph\",\n position: positionOf(node),\n text: mdastToString(node),\n };\n }\n case \"code\":\n return {\n kind: \"codeBlock\",\n position: positionOf(node),\n text: node.value ?? \"\",\n ...(node.lang ? { language: node.lang } : {}),\n };\n case \"list\":\n return {\n kind: \"list\",\n position: positionOf(node),\n text: mdastToString(node),\n ordered: Boolean(node.ordered),\n items: (node.children ?? [])\n .filter((child) => child.type === \"listItem\")\n .map(\n (item): ListItemNode => ({\n kind: \"listItem\",\n position: positionOf(item),\n text: mdastToString(item),\n children: childContent(item),\n }),\n ),\n };\n case \"table\":\n return {\n kind: \"table\",\n position: positionOf(node),\n text: mdastToString(node),\n // GFM guarantees the first row is the header, which is the one format\n // of six where reading it positionally is safe. Everywhere else the\n // format carries a real `thead` and this flag comes from it.\n children: (node.children ?? [])\n .filter((row) => row.type === \"tableRow\")\n .map((row, index) => toTableRow(row, index === 0)),\n };\n case \"blockquote\": {\n const variant = alertVariant(node);\n if (variant) return toAdmonition(node, variant);\n return {\n kind: \"blockquote\",\n position: positionOf(node),\n text: mdastToString(node),\n children: childContent(node),\n };\n }\n case \"mdxJsxFlowElement\":\n return toElement(node);\n default:\n return null;\n }\n}\n\n/**\n * The `{#anchor}` suffix Hugo and Docusaurus write on a heading. It names the\n * rendered id, and a reader never sees it, so a template matches the heading\n * without it.\n */\nconst HEADING_ANCHOR = /\\s*\\{#[^}\\s]*\\}\\s*$/;\n\nfunction headingTitle(node: MdNode): string {\n return mdastToString(node).replace(HEADING_ANCHOR, \"\").trim();\n}\n\n/** Flatten an mdast root's direct children into ordered fragments. */\nexport function toFragments(root: MdNode): Fragment[] {\n const fragments: Fragment[] = [];\n for (const node of root.children ?? []) {\n // Frontmatter is metadata, not body content; the caller reads it separately.\n if (node.type === \"yaml\" || node.type === \"toml\") continue;\n\n if (node.type === \"heading\") {\n fragments.push({\n type: \"heading\",\n level: node.depth ?? 1,\n title: headingTitle(node),\n position: positionOf(node),\n });\n continue;\n }\n\n const content = toContentNode(node);\n if (content) fragments.push({ type: \"content\", node: content });\n }\n return fragments;\n}\n\n/** End of the document, for closing the final sections. */\nexport function documentEnd(root: MdNode): Position[\"end\"] {\n return positionOf(root).end;\n}\n","/**\n * Fold a flat list of fragments into a nested section tree.\n *\n * Every format arrives here as an ordered list of `Fragment`s - a heading, or\n * a piece of content - and leaves as `SectionNode[]`. Keeping the fold in one\n * place is what makes a new format one `toFragments` function rather than a\n * second copy of the nesting, position, and slug logic.\n *\n * Named `Fragment` rather than `Block`, deliberately: \"block\" is the\n * block-level content vocabulary (`ContentKind`'s `table`, `blockquote`, and\n * so on), and this internal pipeline type never leaves `src/lint/parsers/`.\n *\n * Two position rules are deliberate:\n *\n * - A section ends where the *next section at its level or shallower* begins,\n * not at its own last child. A finding about a section therefore spans the\n * trailing blank lines a reader would consider part of it, and adjacent\n * sections tile the document with no gaps.\n * - Content appearing before any heading becomes an implicit lead section at\n * `level: 0`, so a headless document (frontmatter, prose, then `## ...`)\n * still has somewhere to hang its content and its later headings nest under\n * it rather than being dropped.\n */\nimport GithubSlugger from \"github-slugger\";\nimport type { ContentNode, Position, SectionNode } from \"../types.js\";\n\nexport interface HeadingFragment {\n type: \"heading\";\n /** 1-6. */\n level: number;\n title: string;\n position: Position;\n}\n\nexport interface ContentFragment {\n type: \"content\";\n node: ContentNode;\n}\n\nexport type Fragment = HeadingFragment | ContentFragment;\n\n/** Mutable while open; frozen into a `SectionNode` on close. */\ninterface OpenSection {\n node: SectionNode;\n /** End of the last block seen, the fallback when nothing follows. */\n lastEnd: Position[\"end\"];\n}\n\n/**\n * @param fragments Document fragments in source order, frontmatter excluded.\n * @param docEnd End of the document, used to close the final sections.\n */\nexport function sectionize(fragments: Fragment[], docEnd: Position[\"end\"]): SectionNode[] {\n const slugger = new GithubSlugger();\n const roots: SectionNode[] = [];\n const stack: OpenSection[] = [];\n\n /** Close every open section at `level` or deeper, ending it at `end`. */\n const closeTo = (level: number, end: Position[\"end\"]): void => {\n let top = stack.at(-1);\n while (top !== undefined && top.node.level >= level) {\n stack.pop();\n top.node.position.end = { ...end };\n top = stack.at(-1);\n }\n };\n\n /** Pushes `node` onto the stack and hands back the section it opened. */\n const push = (node: SectionNode): OpenSection => {\n const parent = stack[stack.length - 1];\n if (parent) {\n node.parentSlug = parent.node.slug;\n node.order = parent.node.sections.length + 1;\n parent.node.sections.push(node);\n } else {\n node.parentSlug = null;\n node.order = roots.length + 1;\n roots.push(node);\n }\n const open: OpenSection = { node, lastEnd: node.position.end };\n stack.push(open);\n return open;\n };\n\n /**\n * The implicit lead section. `level: 0` is below every real heading, so the\n * headings that follow nest inside it instead of closing it.\n */\n const openLead = (start: Position[\"start\"]): OpenSection =>\n push({\n slug: slugger.slug(\"(lead)\"),\n title: \"\",\n level: 0,\n order: 0,\n parentSlug: null,\n titlePosition: null,\n position: { start: { ...start }, end: { ...start } },\n children: [],\n sections: [],\n });\n\n for (const fragment of fragments) {\n if (fragment.type === \"heading\") {\n closeTo(fragment.level, fragment.position.start);\n push({\n slug: slugger.slug(fragment.title),\n title: fragment.title,\n level: fragment.level,\n order: 0,\n parentSlug: null,\n titlePosition: { ...fragment.position },\n position: { start: { ...fragment.position.start }, end: { ...fragment.position.end } },\n children: [],\n sections: [],\n });\n continue;\n }\n\n const current = stack.at(-1) ?? openLead(fragment.node.position.start);\n current.node.children.push(fragment.node);\n current.lastEnd = fragment.node.position.end;\n // Every enclosing section grows with its descendants, so a parent's span\n // always covers its children even before it is closed.\n for (const open of stack) open.node.position.end = { ...fragment.node.position.end };\n }\n\n closeTo(0, docEnd);\n return roots;\n}\n","/**\n * Metadata helpers shared by every format that has both metadata and headings.\n *\n * Both functions here were independently written four times, once per parser,\n * and were character-identical each time. They are rules about a `DocumentTree`\n * rather than about any one syntax, so they belong in one place: a subtlety\n * duplicated four ways is a subtlety that will be fixed one way.\n */\nimport { locateFrontmatter } from \"../../meta/index.js\";\nimport type { Position } from \"../types.js\";\nimport type { Fragment } from \"./sectionize.js\";\n\n/**\n * Span of a leading fenced metadata block (`--- … ---`, `+++ … +++`,\n * `;;; … ;;;`), or null when the content carries none.\n *\n * docmeta's locator reports character offsets against the original content, so\n * line numbers are recovered by counting newlines rather than by a second\n * parse - exact, because those offsets are byte-for-byte.\n */\nexport function fencedPosition(content: string): Position | null {\n const loc = locateFrontmatter(content);\n if (!loc) return null;\n const before = content.slice(0, loc.openStart);\n const startLine = before.split(\"\\n\").length;\n const lines = content.slice(loc.openStart, loc.closeEnd).split(\"\\n\");\n return {\n start: { line: startLine, column: 1, offset: loc.openStart },\n end: {\n line: startLine + lines.length - 1,\n // Taken from the last line's own length rather than fixed at 1. When the\n // block ends with a newline that line is empty and the column is 1\n // anyway; when the closing fence ends at EOF without one, the half-open\n // end is just past the delimiter - which `offset` already said, so a\n // fixed column contradicted it and pointed a reader's caret at the start\n // of the fence line instead of its end.\n // `split` always yields at least one entry, so the fallback is\n // unreachable; an empty last line is column 1 either way.\n column: (lines.at(-1) ?? \"\").length + 1,\n offset: loc.closeEnd,\n },\n };\n}\n\n/**\n * Treat a metadata `title` as the document's H1 when the body has none.\n *\n * Docusaurus, Hugo, and Starlight all render the page title from frontmatter,\n * so their pages legitimately start at `##`. Read literally, such a page has no\n * top-level section, and every doctype template - which models the title as its\n * outermost rule, because that is how the published templates are written -\n * misaligns against it and reports a cascade. The page is not malformed; the\n * title simply is not written where a naive reading looks for it.\n *\n * So a synthetic heading is prepended, positioned on the metadata that actually\n * carries the title. Everything downstream then sees the document the way a\n * reader sees it rendered.\n *\n * Only when the body has no level-1 heading of its own: prepending one where a\n * real title exists would nest it inside a synthetic parent, which is a\n * different document.\n *\n * See ADR 01006. Formats where the title is always a body element - XML, whose\n * \"metadata\" is the root element's own attributes - do not call this, and\n * should not.\n */\nexport function withMetadataTitle(\n fragments: Fragment[],\n metadata: Record<string, unknown> | null,\n position: Position | null,\n): Fragment[] {\n const declared = metadata?.[\"title\"];\n const title = typeof declared === \"string\" ? declared.trim() : null;\n // Trimmed, not merely non-empty: `title: \" \"` is as absent as no title at\n // all, and admitting it would give the document a synthetic H1 with a blank\n // heading - which every template then reports as the wrong title, naming\n // nothing the author could search for.\n if (title === null || title.length === 0) return fragments;\n if (position === null) return fragments;\n if (fragments.some((b) => b.type === \"heading\" && b.level === 1)) return fragments;\n\n return [{ type: \"heading\", level: 1, title, position }, ...fragments];\n}\n\n/**\n * The content with a leading fenced metadata block removed.\n *\n * docmeta's AsciiDoc and reStructuredText extractors short-circuit: when a\n * fence is present they return it and never look at the format's own metadata.\n * So a page carrying both a `---` fence and a native `:type: how-to` header\n * lost the `type` entirely and was skipped as untyped - while the same page in\n * HTML, whose extractor has no such branch, routed correctly. Running the\n * native extractor over the fence-free remainder is what lets both be read.\n *\n * Only the values are taken from that second read; positions would be shifted\n * by the removal and are not used.\n */\nexport function withoutFence(content: string): string {\n const loc = locateFrontmatter(content);\n return loc ? content.slice(loc.closeEnd) : content;\n}\n","/**\n * HTML parser: parse5's DOM -> generic blocks -> the shared `sectionize` fold.\n *\n * The job is the same one `mdast.ts` does for Markdown - flatten a format's own\n * tree into ordered `Fragment`s - and the same skipping discipline applies\n * where the content model has no kind at all. A `<div>` is not content and a\n * `<figure>` with no image inside it is dropped whole, because counting\n * either would make `paragraphs: {max: 3}` fail a page a reader would say\n * satisfies it. Proposal 0065 widened the model, so `blockquote`, `table`,\n * `figure`, and `dl` are no longer in that group: they map onto real nodes\n * now, alongside `admonition` from `<aside>`/`role=\"note\"` and `image` from\n * `<img>`.\n *\n * `parse` rather than `parseFragment`. Real documentation HTML is a document:\n * `<!DOCTYPE html><html><head>…</head><body>…`, and an HTML page's metadata\n * lives in `<head>`, which `parseFragment` (which parses in a `<body>` context)\n * drops on the floor - `<head>` is an ignored start tag in the \"in body\"\n * insertion mode. `parse` also handles a bare fragment, because HTML5 tree\n * construction synthesizes the missing `<html>`/`<head>`/`<body>` around it; the\n * only cost is that those synthesized elements carry no `sourceCodeLocation`,\n * which `positionOf` already has to tolerate.\n *\n * parse5 never throws on malformed input - HTML5 defines recovery for every\n * error - so unlike the MDX path there is no parse-failure branch here. A\n * document with unclosed tags parses into whatever a browser would build from\n * it, and lints against that.\n */\nimport { defaultTreeAdapter, parse } from \"parse5\";\nimport type { DefaultTreeAdapterTypes } from \"parse5\";\nimport { extractFrontmatter, extractorForExtension } from \"../../meta/index.js\";\nimport type {\n AdmonitionNode,\n BlockquoteNode,\n CodeNode,\n ContentNode,\n DefinitionItemNode,\n DefinitionListNode,\n DocumentParser,\n DocumentTree,\n ImageNode,\n ListItemNode,\n Position,\n TableCellNode,\n TableNode,\n TableRowNode,\n} from \"../types.js\";\nimport type { Fragment } from \"./sectionize.js\";\nimport { sectionize } from \"./sectionize.js\";\nimport { fencedPosition, withMetadataTitle } from \"./metadata.js\";\n\ntype Node = DefaultTreeAdapterTypes.Node;\ntype Element = DefaultTreeAdapterTypes.Element;\ntype ParentNode = DefaultTreeAdapterTypes.ParentNode;\n\n/**\n * What a walk does when it meets an element.\n *\n * - `heading`/`content`: the element *is* a block. It is emitted and never\n * descended into, because its whole subtree has already been folded into the\n * emitted node's text (or, for a container kind, its own `children`).\n * Descending would emit the same prose twice.\n * - `container`: the element is not content but its children may be. Descend\n * without emitting. This is the case that matters: real HTML wraps\n * everything in `<html><body><main><article><div>`, and a heading inside a\n * `<div>` is still a heading.\n * - `opaque`: neither content nor a container. Skip the subtree entirely.\n *\n * `container` is the default, so an unknown element - a web component, a\n * `<my-callout>` - still yields the headings and paragraphs inside it. `opaque`\n * is a short, explicit list, and every entry earns its place the same way: it\n * is metadata/machinery rather than prose, so the generic content model has no\n * kind for it at all.\n */\ntype Role = \"heading\" | \"content\" | \"container\" | \"opaque\";\n\nconst HEADING_LEVELS = new Map<string, number>([\n [\"h1\", 1],\n [\"h2\", 2],\n [\"h3\", 3],\n [\"h4\", 4],\n [\"h5\", 5],\n [\"h6\", 6],\n]);\n\n/**\n * Elements that are a block on their own: emitted as one content node, never\n * descended into. `table`, `blockquote`, `dl`, `img` and `figure` used to sit\n * in `OPAQUE_TAGS` and be dropped whole; proposal 0065 gave each a node shape,\n * so they move here instead. `aside` joins them because it is one of the two\n * HTML sources of `admonition` - the other, `role=\"note\"`, is not a tag and is\n * checked separately in `roleOf`.\n */\nconst CONTENT_TAGS = new Set([\"p\", \"pre\", \"ul\", \"ol\", \"table\", \"blockquote\", \"dl\", \"img\", \"figure\", \"aside\"]);\n\nconst OPAQUE_TAGS = new Set([\n // Metadata and machinery, not prose.\n \"head\",\n \"script\",\n \"style\",\n \"template\",\n \"noscript\",\n \"svg\",\n \"math\",\n]);\n\n/** Elements whose text is not document text, for the flattening helpers. */\nconst NON_TEXT_TAGS = new Set([\"script\", \"style\", \"template\"]);\n\nconst ADMONITION_VARIANTS = new Set([\n \"note\",\n \"tip\",\n \"important\",\n \"caution\",\n \"warning\",\n \"danger\",\n]);\n\nconst ZERO: Position = {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n};\n\nfunction tagOf(el: Element): string {\n return el.tagName.toLowerCase();\n}\n\n/** An element's attribute value, or `undefined` when it does not carry one. */\nfunction attrOf(el: Element, name: string): string | undefined {\n return el.attrs.find((a) => a.name === name)?.value;\n}\n\n/**\n * `admonition`'s two HTML sources: the `<aside>` tag, and `role=\"note\"` on any\n * element. Neither one is enough on its own - `aside` is a tag and `role` is\n * an attribute any element can carry - so this is checked ahead of the\n * tag-keyed `CONTENT_TAGS`/`OPAQUE_TAGS` lookup rather than folded into it.\n */\nfunction isAdmonitionSource(el: Element, tag: string): boolean {\n return tag === \"aside\" || attrOf(el, \"role\") === \"note\";\n}\n\nfunction roleOf(el: Element, tag: string): Role {\n if (HEADING_LEVELS.has(tag)) return \"heading\";\n if (isAdmonitionSource(el, tag)) return \"content\";\n if (CONTENT_TAGS.has(tag)) return \"content\";\n if (OPAQUE_TAGS.has(tag)) return \"opaque\";\n return \"container\";\n}\n\n/**\n * parse5's `sourceCodeLocation` maps onto `Position` one field at a time: its\n * lines and columns are 1-based, its offsets 0-based, and its `end*` is one\n * past the last character - the same half-open span `Position` documents. A\n * `<p>foo</p>` starting at column 1 reports `endCol` 12 for an 11-character\n * element, and `endOffset - startOffset` is its length.\n *\n * A node can carry no location at all: parse5 synthesizes `<html>`, `<head>`,\n * and `<body>` around a fragment, and those have none. Nothing synthesized is\n * ever emitted as a block, but the fallback keeps a missing location from\n * becoming `NaN` in a reporter.\n */\ninterface Located {\n sourceCodeLocation?: {\n startLine: number;\n startCol: number;\n startOffset: number;\n endLine: number;\n endCol: number;\n endOffset: number;\n } | null;\n}\n\nfunction positionOf(node: Located): Position {\n const loc = node.sourceCodeLocation;\n if (!loc) return { start: { ...ZERO.start }, end: { ...ZERO.end } };\n return {\n start: { line: loc.startLine, column: loc.startCol, offset: loc.startOffset },\n end: { line: loc.endLine, column: loc.endCol, offset: loc.endOffset },\n };\n}\n\n/** Concatenated text of a subtree, markup and all, verbatim. */\nfunction rawText(node: Node): string {\n if (defaultTreeAdapter.isTextNode(node)) return node.value;\n if (!defaultTreeAdapter.isElementNode(node)) return \"\";\n if (NON_TEXT_TAGS.has(tagOf(node))) return \"\";\n let out = \"\";\n for (const child of node.childNodes) out += rawText(child);\n return out;\n}\n\n/**\n * Text as a browser renders it: nested `<code>`, `<em>`, and `<a>` contribute\n * their text, and HTML's insignificant whitespace collapses, so a heading\n * written across three indented lines still equals `\"Overview\"` - which is what\n * a template's `heading: {const: Overview}` compares against.\n *\n * This is the HTML side of the bug the Markdown parser had before the rewrite,\n * where a title was built from `children.map(c => c.value)` and every inline\n * element vanished.\n */\nfunction flatText(node: Node): string {\n return rawText(node).replace(/\\s+/g, \" \").trim();\n}\n\n/** `language-x` from a `class`, per the HTML5 convention for code blocks. */\nfunction langOf(el: Element): string | undefined {\n const className = attrOf(el, \"class\");\n if (!className) return undefined;\n for (const token of className.split(/\\s+/)) {\n if (token.startsWith(\"language-\") && token.length > \"language-\".length) {\n return token.slice(\"language-\".length);\n }\n }\n return undefined;\n}\n\n/** `variant`, from `role=\"note\"` or a class naming one of the six - never invented. */\nfunction variantOf(el: Element): AdmonitionNode[\"variant\"] | undefined {\n const className = attrOf(el, \"class\");\n if (className) {\n for (const token of className.split(/\\s+/)) {\n if (ADMONITION_VARIANTS.has(token)) return token as AdmonitionNode[\"variant\"];\n }\n }\n if (attrOf(el, \"role\") === \"note\") return \"note\";\n return undefined;\n}\n\nfunction firstElementChild(el: Element, tag: string): Element | undefined {\n for (const child of el.childNodes) {\n if (defaultTreeAdapter.isElementNode(child) && tagOf(child) === tag) return child;\n }\n return undefined;\n}\n\n/** An element's direct element children, text and comment nodes excluded. */\nfunction elementChildren(el: Element): Element[] {\n const out: Element[] = [];\n for (const child of el.childNodes) {\n if (defaultTreeAdapter.isElementNode(child)) out.push(child);\n }\n return out;\n}\n\n/** The first `<img>` anywhere under `el`, depth-first - for a `<figure>`. */\nfunction findImage(el: Element): Element | undefined {\n for (const child of el.childNodes) {\n if (!defaultTreeAdapter.isElementNode(child)) continue;\n if (tagOf(child) === \"img\") return child;\n const nested = findImage(child);\n if (nested) return nested;\n }\n return undefined;\n}\n\n/**\n * `<pre>` (usually `<pre><code>`) as a code node.\n *\n * Whitespace is significant here, so this is the one place `rawText` is used\n * unnormalized. Two trims are deliberate: a newline directly after `<code>` is\n * an artifact of writing the block over several lines (the HTML parser already\n * drops one directly after `<pre>`, but not one after a nested `<code>`), and\n * dropping trailing whitespace matches mdast's `code.value`, which carries no\n * closing newline.\n */\nfunction codeNode(pre: Element): CodeNode {\n const inner = firstElementChild(pre, \"code\");\n const lang = langOf(pre) ?? (inner ? langOf(inner) : undefined);\n const text = rawText(pre).replace(/^\\r?\\n/, \"\").replace(/\\s+$/, \"\");\n return {\n kind: \"codeBlock\",\n position: positionOf(pre),\n text,\n ...(lang ? { language: lang } : {}),\n };\n}\n\n/**\n * `<img>` as an image node. A bare `<img>` carries no caption of its own; a\n * `<figure>` wrapping one supplies both the position (the whole figure, since\n * that construct - image and caption together - is what the one node stands\n * for) and, when present, its `<figcaption>` as `text`.\n */\nfunction imageNode(img: Element, position: Position, caption: string | null): ImageNode {\n const title = attrOf(img, \"title\");\n return {\n kind: \"image\",\n position,\n text: caption ?? \"\",\n url: attrOf(img, \"src\") ?? \"\",\n alt: attrOf(img, \"alt\") ?? \"\",\n ...(title ? { title } : {}),\n };\n}\n\n/**\n * `<figure>` as a single image node. A figure with no `<img>` anywhere inside\n * it maps to nothing - the same as before 0065, when the whole subtree was\n * opaque - because the content model has no other kind to give it.\n */\nfunction figureNode(figure: Element): ImageNode | null {\n const img = findImage(figure);\n if (!img) return null;\n const caption = firstElementChild(figure, \"figcaption\");\n return imageNode(img, positionOf(figure), caption ? flatText(caption) : null);\n}\n\n/** `<blockquote>` as a blockquote node, its own content mapped recursively. */\nfunction blockquoteNode(el: Element): BlockquoteNode {\n return {\n kind: \"blockquote\",\n position: positionOf(el),\n text: flatText(el),\n children: childContent(el),\n };\n}\n\n/**\n * `<aside>` or `role=\"note\"` as an admonition node. HTML names no admonition\n * type natively, so `variantOf` only ever returns one of the six when the\n * source itself said which - see its own comment. A bare `<aside>` that names\n * neither carries no `variant` at all, per `AdmonitionNode.variant`'s own\n * comment in `src/lint/types.ts`: defaulting it to `note` would make\n * `variant: note` pass on a page that never said note.\n */\nfunction admonitionNode(el: Element): AdmonitionNode {\n const variant = variantOf(el);\n return {\n kind: \"admonition\",\n position: positionOf(el),\n text: flatText(el),\n ...(variant ? { variant } : {}),\n children: childContent(el),\n };\n}\n\n/** One `<td>`/`<th>` as a table cell, its own content mapped recursively. */\nfunction cellNode(cell: Element): TableCellNode {\n return {\n kind: \"tableCell\",\n position: positionOf(cell),\n text: flatText(cell),\n children: childContent(cell),\n };\n}\n\n/**\n * Which grouping a row was found in. `none` is a bare `<tr>` under the table.\n *\n * A footer has to be told apart from a body, rather than both being \"not the\n * head\". `<tfoot><tr><th>Total</th></tr></tfoot>` is an ordinary way to label\n * a totals row, and the every-cell-is-a-`<th>` rule below would otherwise read\n * it as a header.\n */\ntype RowGroup = \"head\" | \"body\" | \"foot\" | \"none\";\n\n/** One `<tr>`. `header` is set from `<thead>` membership, or - failing that - from every cell being a `<th>`. Never inferred from position, and never in a footer. */\nfunction rowNode(tr: Element, group: RowGroup): TableRowNode {\n const cells: TableCellNode[] = [];\n let allHeaderCells = true;\n for (const child of elementChildren(tr)) {\n const tag = tagOf(child);\n if (tag !== \"td\" && tag !== \"th\") continue;\n if (tag !== \"th\") allHeaderCells = false;\n cells.push(cellNode(child));\n }\n return {\n kind: \"tableRow\",\n position: positionOf(tr),\n text: flatText(tr),\n header:\n group === \"head\" || (group !== \"foot\" && cells.length > 0 && allHeaderCells),\n children: cells,\n };\n}\n\n/** Rows from `<thead>`/`<tbody>`/`<tfoot>` or bare `<tr>` children, in document order. */\nfunction collectRows(parent: Element, out: TableRowNode[], group: RowGroup): void {\n for (const child of elementChildren(parent)) {\n const tag = tagOf(child);\n if (tag === \"thead\") {\n collectRows(child, out, \"head\");\n } else if (tag === \"tbody\") {\n collectRows(child, out, \"body\");\n } else if (tag === \"tfoot\") {\n collectRows(child, out, \"foot\");\n } else if (tag === \"tr\") {\n out.push(rowNode(child, group));\n }\n // `<caption>`/`<colgroup>` carry no rows and are not content of their own.\n }\n}\n\n/** `<table>` as a table node. */\nfunction tableNode(table: Element): TableNode {\n const rows: TableRowNode[] = [];\n collectRows(table, rows, \"none\");\n return {\n kind: \"table\",\n position: positionOf(table),\n text: flatText(table),\n children: rows,\n };\n}\n\n/**\n * `<dl>` as a definition list. Each `<dt>` pairs with the `<dd>` elements that\n * immediately follow it - up to the next `<dt>` or the end of the list - and\n * the `<dt>`'s own text becomes the item's `term`. An item's position spans\n * from its `<dt>` through its last `<dd>`, or the `<dt>` alone when it has\n * none.\n */\nfunction definitionListNode(dl: Element): DefinitionListNode {\n const children = elementChildren(dl);\n const items: DefinitionItemNode[] = [];\n\n for (let i = 0; i < children.length; i++) {\n const dt = children[i];\n if (!dt || tagOf(dt) !== \"dt\") continue;\n\n const dds: Element[] = [];\n let j = i + 1;\n while (j < children.length) {\n const next = children[j];\n if (!next || tagOf(next) !== \"dd\") break;\n dds.push(next);\n j++;\n }\n\n const term = flatText(dt);\n const definition = dds.flatMap((dd) => childContent(dd));\n const lastDd = dds.at(-1);\n const end = lastDd ? positionOf(lastDd).end : positionOf(dt).end;\n const text = [term, ...dds.map((dd) => flatText(dd))].filter((t) => t.length > 0).join(\" \");\n\n items.push({\n kind: \"definitionItem\",\n position: { start: positionOf(dt).start, end },\n text,\n term,\n definition,\n });\n }\n\n return {\n kind: \"definitionList\",\n position: positionOf(dl),\n text: flatText(dl),\n children: items,\n };\n}\n\n/**\n * `<li>` children of a list, with their own content mapped recursively.\n */\nfunction listItems(list: Element): ListItemNode[] {\n const items: ListItemNode[] = [];\n for (const child of list.childNodes) {\n if (!defaultTreeAdapter.isElementNode(child)) continue;\n if (tagOf(child) !== \"li\") continue;\n items.push({\n kind: \"listItem\",\n position: positionOf(child),\n text: flatText(child),\n children: childContent(child),\n });\n }\n return items;\n}\n\n/**\n * One container element's content, with its own loose prose kept as a\n * paragraph. Shared by every construct that holds generic content recursively\n * - `<li>`, `<blockquote>`, `<aside>`/`role=\"note\"`, `<td>`/`<th>`, `<dd>` -\n * so the same reconciliation applies everywhere rather than once per kind.\n *\n * An item's text is rarely wrapped in a block element, but mdast puts a list\n * item's principal text in a `paragraph` child regardless, and\n * `lists: {items: {paragraphs: {min: 1}}}` has to count the same thing in\n * every format. So the loose text is gathered into one, in the position it\n * occupies among the container's blocks.\n *\n * Gathering it rather than checking whether the container has any children is\n * what makes the two cases agree. `<li>text</li>` and `<li><p>text</p></li>`\n * were already reconciled; `<li>Parent<ul>…</ul></li>` was not, because the\n * nested list is a child, so the item looked accounted for and `Parent` became\n * a paragraph nothing counted - while its Markdown, AsciiDoc, and reST twins\n * all counted one.\n *\n * A container element that yields no blocks of its own is inline in practice -\n * `<strong>`, `<a>`, `<code>` - so its text joins the prose around it instead\n * of being dropped, which is again what mdast does with the same markup.\n */\nfunction childContent(parent: Element): ContentNode[] {\n const out: ContentNode[] = [];\n let text = \"\";\n let span: Position | null = null;\n\n const extend = (node: Located): void => {\n const at = positionOf(node);\n span = span === null ? at : { start: span.start, end: at.end };\n };\n\n const flush = (): void => {\n const value = text.trim();\n const at = span;\n text = \"\";\n span = null;\n if (value.length === 0) return;\n out.push({ kind: \"paragraph\", position: at ?? positionOf(parent), text: value });\n };\n\n for (const child of parent.childNodes) {\n if (defaultTreeAdapter.isTextNode(child)) {\n text += child.value;\n if (child.value.trim().length > 0) extend(child);\n continue;\n }\n if (!defaultTreeAdapter.isElementNode(child)) continue;\n\n const tag = tagOf(child);\n const role = roleOf(child, tag);\n if (role === \"heading\" || role === \"opaque\") continue;\n\n if (role === \"content\") {\n flush();\n const node = toContentNode(child, tag);\n if (node) out.push(node);\n continue;\n }\n\n const nested = contentIn(child);\n if (nested.length > 0) {\n flush();\n out.push(...nested);\n continue;\n }\n\n const inline = flatText(child);\n text += inline;\n if (inline.trim().length > 0) extend(child);\n }\n\n flush();\n return out;\n}\n\nfunction toContentNode(el: Element, tag: string): ContentNode | null {\n if (isAdmonitionSource(el, tag)) return admonitionNode(el);\n switch (tag) {\n case \"p\":\n return { kind: \"paragraph\", position: positionOf(el), text: flatText(el) };\n case \"pre\":\n return codeNode(el);\n case \"ul\":\n case \"ol\":\n return {\n kind: \"list\",\n position: positionOf(el),\n text: flatText(el),\n ordered: tag === \"ol\",\n items: listItems(el),\n };\n case \"table\":\n return tableNode(el);\n case \"blockquote\":\n return blockquoteNode(el);\n case \"dl\":\n return definitionListNode(el);\n case \"img\":\n return imageNode(el, positionOf(el), null);\n case \"figure\":\n return figureNode(el);\n default:\n return null;\n }\n}\n\n/**\n * Content nodes inside a container that is not itself a block - a wrapper\n * within one, reached from `childContent`. Same descend/skip rule as the\n * document walk, minus headings: a heading inside a list item does not open a\n * section, and mdast drops it the same way.\n */\nfunction contentIn(parent: ParentNode): ContentNode[] {\n const out: ContentNode[] = [];\n for (const child of parent.childNodes) {\n if (!defaultTreeAdapter.isElementNode(child)) continue;\n const tag = tagOf(child);\n const role = roleOf(child, tag);\n if (role === \"heading\" || role === \"opaque\") continue;\n if (role === \"content\") {\n const node = toContentNode(child, tag);\n if (node) out.push(node);\n continue;\n }\n out.push(...contentIn(child));\n }\n return out;\n}\n\n/**\n * Walk the document into ordered blocks.\n *\n * Structure comes from heading *levels* only. Explicit `<section>` nesting is\n * deliberately ignored, and `<section>` is just another container:\n *\n * - `sectionize` already derives nesting from heading level for every format.\n * Honoring `<section>` would mean a second nesting mechanism living in this\n * file, plus a rule for reconciling the two whenever a page's element\n * nesting and its heading levels disagree - which they routinely do, because\n * `<section>` is optional and is as often a layout wrapper\n * (`<section class=\"hero\">`) as a semantic one.\n * - The cross-format promise is that one template produces the same findings\n * on a page and its Markdown, AsciiDoc, or reST twin. Those formats have\n * nothing but heading level, so deriving HTML's structure from anything else\n * would let identical headings nest differently per format.\n * - Where `<section>` nesting agrees with the headings - which is the whole\n * point of writing it - honoring it changes nothing. It could only ever\n * matter when it disagrees, and there the headings are what the reader sees.\n */\nfunction walk(parent: ParentNode, out: Fragment[]): void {\n for (const child of parent.childNodes) {\n if (!defaultTreeAdapter.isElementNode(child)) continue;\n const tag = tagOf(child);\n const role = roleOf(child, tag);\n\n if (role === \"heading\") {\n out.push({\n type: \"heading\",\n level: HEADING_LEVELS.get(tag) ?? 1,\n title: flatText(child),\n position: positionOf(child),\n });\n continue;\n }\n\n if (role === \"content\") {\n const node = toContentNode(child, tag);\n if (node) out.push({ type: \"content\", node });\n continue;\n }\n\n if (role === \"opaque\") continue;\n\n walk(child, out);\n }\n}\n\n/** End of the document, for closing the final sections. */\nfunction documentEnd(content: string): Position[\"end\"] {\n const lines = content.split(\"\\n\");\n const last = lines[lines.length - 1] ?? \"\";\n return { line: lines.length, column: last.length + 1, offset: content.length };\n}\n\n/**\n * An HTML page's metadata, from both places it can be.\n *\n * `extractFrontmatter(content, \"html\")` - the call the Markdown parser makes -\n * turns out to read *only* a fenced `---`/`+++`/`;;;` block; the `format`\n * argument is a label on the result, not a dispatch key. On an ordinary HTML\n * page it returns `{present: false, data: {}}`, which would leave\n * `type: how-to` in a `<meta>` tag invisible and every `.html` file unrouted.\n *\n * The `<meta>` reading lives in docmeta's *extractor* registry instead, reached\n * by extension. So both are asked, and the results merged. That keeps docmeta\n * the single source of truth for metadata - including its `<title>` lift and\n * its YAML-scalar coercion of attribute values, so `content=\"[a, b]\"` is a list\n * here exactly as it would be in frontmatter - rather than growing a second\n * `<meta>` convention in this repository.\n *\n * A fenced block wins on a key collision: it is authored at the top of the\n * source file, and it is what every sibling format reads. The two coexist\n * rarely enough that the tie-break is a formality.\n *\n * The cost is that docmeta parses the document a second time. Re-reading\n * `<meta>` off the tree already in hand would avoid it and duplicate the\n * convention; the ADR's \"docmeta is the single source of truth for frontmatter\"\n * is worth one extra parse of a file we are already reading from disk.\n */\nfunction metadataOf(\n content: string,\n filePath: string,\n doc: DefaultTreeAdapterTypes.Document,\n): { frontmatter: Record<string, unknown> | null; position: Position | null } {\n const fenced = extractFrontmatter(content, \"html\");\n const extractor = extractorForExtension(\".html\");\n const headMeta = extractor\n ? extractor.extract(content, filePath)\n : { present: false, data: {} as Record<string, unknown> };\n\n if (!fenced.present && !headMeta.present) return { frontmatter: null, position: null };\n\n const frontmatter = { ...headMeta.data, ...fenced.data };\n\n // Anchor on whichever block the values actually came from. `<head>` is an\n // HTML document's frontmatter: it is where `<title>` and every `<meta>` sit,\n // and a finding about the page's metadata belongs there.\n if (fenced.present) return { frontmatter, position: fencedPosition(content) };\n\n // A `<head>` parse5 synthesized carries no source location. That happens\n // whenever anything precedes `<html>` - a BOM is the common case - and it\n // used to yield a null position, which silently switched off the synthetic\n // frontmatter title: `withMetadataTitle` bails when the position is null, so\n // the document lost its top-level section and every doctype template\n // misaligned against it. The metadata is real either way, so fall back to the\n // top of the file rather than disowning it.\n const head = findHead(doc);\n return {\n frontmatter,\n position: head?.sourceCodeLocation ? positionOf(head) : origin(),\n };\n}\n\n/** Zero-width span at the top of the file, for metadata with no located block. */\nfunction origin(): Position {\n return {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n };\n}\n\n/** The document's `<head>`, when the source actually wrote one. */\nfunction findHead(doc: DefaultTreeAdapterTypes.Document): Element | undefined {\n for (const child of doc.childNodes) {\n if (!defaultTreeAdapter.isElementNode(child)) continue;\n if (tagOf(child) === \"html\") return firstElementChild(child, \"head\");\n }\n return undefined;\n}\n\nfunction parseHtml(content: string, filePath: string): DocumentTree {\n const doc = parse(content, { sourceCodeLocationInfo: true });\n const fragments: Fragment[] = [];\n walk(doc, fragments);\n\n const { frontmatter, position } = metadataOf(content, filePath, doc);\n\n return {\n format: \"html\",\n filePath,\n frontmatter,\n frontmatterPosition: position,\n sections: sectionize(\n withMetadataTitle(fragments, frontmatter, position),\n documentEnd(content),\n ),\n };\n}\n\nexport const htmlParser: DocumentParser = {\n name: \"html\",\n label: \"HTML\",\n kinds: [\n \"paragraph\",\n \"codeBlock\",\n \"list\",\n \"listItem\",\n \"table\",\n \"tableRow\",\n \"tableCell\",\n \"admonition\",\n \"image\",\n \"blockquote\",\n \"definitionList\",\n \"definitionItem\",\n ],\n extensions: [\".html\", \".htm\"],\n parse: parseHtml,\n};\n","/**\n * reStructuredText -> generic blocks.\n *\n * Unlike its siblings this parser has no AST library under it. There is no\n * usable reStructuredText parser for JavaScript, so this reads the source\n * directly: a line scanner that answers one question - what sections does this\n * document have, and what content is in each - and then hands `sectionize` the\n * same `Fragment[]` every other format produces.\n *\n * ## Section levels\n *\n * RST has no fixed heading hierarchy. A title is a line underlined, and\n * optionally also overlined, by a run of punctuation at least as long as the\n * title. Which *level* an adornment style means is discovered, not fixed:\n *\n * \"Rather than imposing a fixed number and order of section title adornment\n * styles, the order enforced will be the order as encountered.\"\n * - the reStructuredText spec, \"Sections\"\n *\n * So the first style seen is level 1, the next new style level 2, and so on -\n * `===` then `+++` then `---` is a perfectly ordinary document, and a\n * hardcoded character-to-level table would get it wrong. The spec also makes\n * over-and-underlined styles distinct from underline-only ones using the same\n * character, so the style key carries both facts (`over:=` vs `under:=`).\n *\n * Levels are clamped to 6, because `SectionNode.level` is documented 1-6; a\n * document with seven adornment styles is beyond what the templates model.\n *\n * ## What this deliberately does not handle\n *\n * This is a structural scanner, not docutils. It does not implement, and\n * silently ignores:\n *\n * - **Substitutions** (`|name|` definitions and references) - a reference is\n * flattened to its bare name, a definition is skipped with other directives.\n * - **Includes** (`.. include::`) - the referenced file is never read, so\n * sections it would contribute are invisible.\n * - **Transitions** (a lone adornment run between paragraphs) - skipped, like\n * Markdown thematic breaks.\n * - **Option lists** and **line blocks** (`|`) - skipped, not mapped onto\n * anything. **Definition lists** are mapped: a term line followed by an\n * indented definition becomes a `definitionList`/`definitionItem` pair,\n * and consecutive pairs group into one list the way blank-separated bullet\n * items do.\n * - **Doctest blocks** (`>>>`) - recognised so they are not mis-read as prose,\n * but skipped rather than emitted as `codeBlock`.\n * - **Tables** - grid (`+---+`), simple (`=== ===`), `list-table`, and\n * `csv-table` all become `table` nodes. Grid and simple tables take their\n * columns from the border itself, so a spanning cell (a row border that\n * omits one `+`, or a simple-table row that straddles a column gap) is read\n * as if it were not spanned - the rectangular case, not the general grid\n * grammar. A simple table's body is one row per physical line; only its\n * header, if it has one, merges multiple lines into one row. `list-table`\n * and `csv-table` carry a header row only when `:header-rows:` (both) or\n * `:header:` (`csv-table`) says so - without one, the table has real rows\n * and no header, which is the honest answer. A `csv-table`'s external\n * `:file:`/`:url:` source is never read, the same call `include` gets.\n * - **Block quotes** (an indented block with no `::` ahead of it) - mapped to\n * `blockquote`, its own content parsed the same way a list item's is.\n * - **Quoted literal blocks** (an unindented literal block quoted with\n * punctuation) - not recognised; read as prose.\n * - **Enumerator styles beyond `1.`/`1)`/`#.`/`#)`** - alphabetic and Roman\n * enumerators (`a.`, `iv.`) and the parenthesised `(1)` form are read as\n * prose. They are ambiguous without docutils' second-item confirmation:\n * `A. Smith wrote this` is a sentence, not a list.\n * - **Roles and inline markup** beyond a regex flattening - `flattenInline`\n * strips the common constructs; it does not implement inline parsing, does\n * not process `\\` escapes, and leaves trailing reference underscores alone\n * (stripping them would eat `snake_case`).\n * - **Tab expansion** in indentation - a tab counts as one column, where\n * docutils expands to the next multiple of eight.\n * - **East Asian width** - adornment length is compared against the title's\n * code-point count, where the spec compares display columns.\n * - **Document title promotion** - docutils promotes a lone top-level section\n * to the document title. Here it stays a level-1 section, which is what the\n * doctype templates model (a title with its subsections hanging under it).\n * - **Directive options and content semantics beyond what is listed above** -\n * `code-block`/`code`/`sourcecode` become `codeBlock`; `note`, `tip`,\n * `important`, `caution`, `warning`, and `danger` become `admonition` with\n * that word as `variant`; `image` and `figure` become `image`; `list-table`\n * and `csv-table` become `table`. `attention`, `hint`, `error`, and the\n * generic `admonition` directive also become `admonition`, but with no\n * `variant` at all - `AdmonitionNode.variant` has no six-value member for\n * them, and inventing an equivalence (`hint` as `tip`, `error` as `danger`)\n * is exactly what this parser does not do. A plain count rule still counts\n * them; a `variant:` rule reports them as a mismatch instead of a false\n * match. Every other directive is skipped whole.\n * - **Anything an unterminated fenced block would need** - a *complete* fenced\n * front matter block is cut from the body before scanning, because `---`\n * reads as a transition and the YAML under it as prose. An unterminated one\n * is not front matter, and is scanned as the RST it literally is.\n *\n * One judgement call is worth stating plainly. The spec requires an adornment\n * run to extend \"at least as far as the right edge of the title text\", and\n * that is what is enforced here: a shorter run is not a section title, and the\n * line becomes a paragraph. docutils the implementation is more forgiving - it\n * reports \"Title underline too short\" and recovers - but taking the strict\n * reading is what keeps this parser agreeing with `docmeta`'s RST extractor,\n * which applies the same rule to the document title.\n */\nimport { extractFrontmatter, extractorForExtension, locateFrontmatter } from \"../../meta/index.js\";\nimport type {\n AdmonitionNode,\n ContentNode,\n DefinitionItemNode,\n DocumentParser,\n DocumentTree,\n ListItemNode,\n ListNode,\n Point,\n Position,\n TableCellNode,\n TableNode,\n TableRowNode,\n} from \"../types.js\";\nimport type { Fragment } from \"./sectionize.js\";\nimport { sectionize } from \"./sectionize.js\";\nimport {\n fencedPosition,\n withMetadataTitle as withFrontmatterTitle,\n withoutFence,\n} from \"./metadata.js\";\n\n/** Every character the spec allows as title adornment. */\nconst ADORNMENT_CHARS = new Set(\n \"!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\".split(\"\"),\n);\n\n/** Explicit markup: a directive, comment, target, or substitution definition. */\nconst EXPLICIT = /^[ \\t]*\\.\\.(?:[ \\t]|$)/;\n/** A directive with a parseable name, e.g. `.. code-block:: python`. */\nconst DIRECTIVE = /^([ \\t]*)\\.\\.[ \\t]+([\\w.+:-]+)::[ \\t]*(.*)$/;\n/** Directives that carry a literal block, with the language as the argument. */\nconst CODE_DIRECTIVES = new Set([\"code\", \"code-block\", \"sourcecode\"]);\n/** Admonition directives that name one of the six variants directly. */\nconst ADMONITION_VARIANTS = new Map<string, AdmonitionNode[\"variant\"]>([\n [\"note\", \"note\"],\n [\"tip\", \"tip\"],\n [\"important\", \"important\"],\n [\"caution\", \"caution\"],\n [\"warning\", \"warning\"],\n [\"danger\", \"danger\"],\n]);\n/**\n * Every admonition directive this parser reads, variant-naming or not.\n * `attention`, `hint`, `error`, and the generic `admonition` directive still\n * become an `admonition` node - just with no `variant`, since none of the six\n * is honestly theirs. See the file header.\n */\nconst ADMONITION_DIRECTIVES = new Set([\n ...ADMONITION_VARIANTS.keys(),\n \"attention\",\n \"hint\",\n \"error\",\n \"admonition\",\n]);\n/** A field-list entry: `:name:` or `:name: value`. */\nconst FIELD = /^[ \\t]*:[^:\\s][^:]*:(?:[ \\t]|$)/;\n/** A directive option inside a directive body, e.g. `:linenos:`. */\nconst OPTION = /^[ \\t]*:[\\w-]+:(?:[ \\t].*)?$/;\n/** A directive option, capturing its key and value: `:header-rows: 1`. */\nconst OPTION_KV = /^[ \\t]*:([\\w-]+):(?:[ \\t]+(.*))?$/;\n/** A bullet-list item. The marker must be followed by whitespace or nothing. */\nconst BULLET = /^([ \\t]*)([*+-])(?:([ \\t]+)(.*))?$/;\n/** An enumerated-list item, arabic or auto (`#`), with a `.` or `)` suffix. */\nconst ENUM = /^([ \\t]*)(\\d+|#)([.)])(?:([ \\t]+)(.*))?$/;\n/** A doctest block. */\nconst DOCTEST = /^[ \\t]*>>>[ \\t]/;\n/** A grid-table border. */\nconst GRID_TABLE = /^[ \\t]*\\+[-=+]+\\+[ \\t]*$/;\n/** A simple-table border: runs of `=` (or `-`, for column spans) with gaps. */\nconst SIMPLE_TABLE = /^[ \\t]*[-=]+(?:[ \\t]+[-=]+)+[ \\t]*$/;\n\n/**\n * The source, indexed by line.\n *\n * `text` is the array the scanner reads, and it is mutable on purpose: list\n * item markers are blanked out of it *in place, space for space*, so an item's\n * body can be scanned by the same code that scans the document body without\n * re-slicing anything. Every column and offset in `starts` stays exact by\n * construction rather than by bookkeeping.\n *\n * Line terminators are stripped, and CRLF is handled here so nothing below has\n * to know about it.\n */\ninterface Source {\n text: string[];\n /** Offset of the first character of each line. */\n starts: number[];\n /** End of the document, for closing the final sections. */\n end: Point;\n}\n\nfunction indexLines(content: string): Source {\n const text: string[] = [];\n const starts: number[] = [];\n let cursor = 0;\n for (;;) {\n starts.push(cursor);\n const nl = content.indexOf(\"\\n\", cursor);\n if (nl === -1) {\n text.push(content.slice(cursor));\n break;\n }\n const hadCr = nl > cursor && content.charCodeAt(nl - 1) === 13;\n text.push(content.slice(cursor, hadCr ? nl - 1 : nl));\n cursor = nl + 1;\n }\n return {\n text,\n starts,\n end: {\n line: text.length,\n column: (text[text.length - 1] ?? \"\").length + 1,\n offset: content.length,\n },\n };\n}\n\n/** Leading whitespace width. Tabs count as one column; see the header. */\nfunction indentOf(line: string): number {\n let i = 0;\n while (i < line.length && (line[i] === \" \" || line[i] === \"\\t\")) i++;\n return i;\n}\n\nfunction isBlank(line: string | undefined): boolean {\n return (line ?? \"\").trim() === \"\";\n}\n\n/**\n * A run of one repeated adornment character starting at column 1, or null.\n *\n * One character counts. docutils only rejects a run for being short when it is\n * also shorter than the title, so `A` over `=` is a section - and a lone\n * punctuation line that underlines nothing is a too-short transition marker,\n * which docutils drops. Skipping it, which is what the caller does with any\n * adornment that started no title, is the same outcome.\n */\nfunction adornmentOf(line: string | undefined): { char: string; length: number } | null {\n const trimmed = (line ?? \"\").replace(/[ \\t]+$/, \"\");\n const char = trimmed[0];\n if (char === undefined || !ADORNMENT_CHARS.has(char)) return null;\n for (let i = 1; i < trimmed.length; i++) {\n if (trimmed[i] !== char) return null;\n }\n return { char, length: trimmed.length };\n}\n\n/**\n * Strip the inline markup a heading or paragraph is likely to carry, so a title\n * matches a template's `heading.const` and a slug reads like the rendered page.\n * A regex pass, not an inline parser - see the header for what it misses.\n */\nfunction flattenInline(text: string): string {\n return text\n .replace(/``([^`]*)``/g, \"$1\")\n .replace(/:[\\w.+:-]+:`([^`]*)`/g, \"$1\")\n .replace(/`([^`]*?)[ \\t]*<[^<>]*>`__?/g, \"$1\")\n .replace(/`([^`]*)`__?/g, \"$1\")\n .replace(/`([^`]*)`/g, \"$1\")\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\*([^*]+)\\*/g, \"$1\")\n .replace(/\\|([^|\\s][^|]*)\\|/g, \"$1\")\n .trim();\n}\n\n/** Point at the start of `line`'s column `column` (1-based). */\nfunction pointAt(src: Source, line: number, column: number): Point {\n return {\n line: line + 1,\n column,\n offset: (src.starts[line] ?? 0) + column - 1,\n };\n}\n\n/**\n * Span of the source lines `first..last` inclusive, ending just past the last\n * non-whitespace character - the convention mdast uses, so a block's end never\n * runs into the heading that follows it.\n */\nfunction spanOf(src: Source, first: number, last: number, startColumn?: number): Position {\n const firstLine = src.text[first] ?? \"\";\n const lastLine = (src.text[last] ?? \"\").replace(/[ \\t]+$/, \"\");\n return {\n start: pointAt(src, first, startColumn ?? indentOf(firstLine) + 1),\n end: pointAt(src, last, lastLine.length + 1),\n };\n}\n\n/** A section title found at a line, with the adornment style that marked it. */\ninterface TitleHit {\n title: string;\n /** Style key; over-and-underlined is distinct from underline-only. */\n style: string;\n /** First line of the construct (the overline, or the title text). */\n first: number;\n /** Last line of the construct (always the underline). */\n last: number;\n}\n\n/**\n * A section title starting at `line`, or null.\n *\n * Both forms are checked: overline / text / matching underline, and text /\n * underline. The adornment must be at least as long as the title text, and an\n * overline must match its underline in both character and length - what the\n * spec requires, and what `docmeta`'s RST extractor enforces for the doctitle.\n */\nfunction titleAt(src: Source, line: number, limit: number): TitleHit | null {\n const over = adornmentOf(src.text[line]);\n if (over) {\n if (line + 2 >= limit) return null;\n const text = src.text[line + 1] ?? \"\";\n const under = adornmentOf(src.text[line + 2]);\n const title = flattenInline(text);\n if (\n title !== \"\" &&\n adornmentOf(text) === null &&\n under !== null &&\n under.char === over.char &&\n under.length === over.length &&\n over.length >= text.trim().length\n ) {\n return { title, style: `over:${over.char}`, first: line, last: line + 2 };\n }\n // A lone run is a transition, and a mismatched pair is not a title.\n return null;\n }\n\n if (line + 1 >= limit) return null;\n const text = src.text[line] ?? \"\";\n if (text.trim() === \"\" || indentOf(text) > 0) return null;\n const under = adornmentOf(src.text[line + 1]);\n if (under === null || under.length < text.trim().length) return null;\n const title = flattenInline(text);\n if (title === \"\") return null;\n return { title, style: `under:${under.char}`, first: line, last: line + 1 };\n}\n\n/**\n * End of an indented block opened at `from`: the first line at or after `from`\n * whose indent is at or below `base` and which is not blank. Returns the\n * exclusive end, trimmed of trailing blank lines.\n */\nfunction indentedBlockEnd(src: Source, from: number, to: number, base: number): number {\n let i = from;\n let last = from - 1;\n while (i < to) {\n const line = src.text[i] ?? \"\";\n if (isBlank(line)) {\n i++;\n continue;\n }\n if (indentOf(line) <= base) break;\n last = i;\n i++;\n }\n return last + 1;\n}\n\n/** The lines `from..to` with their common indent removed, joined by newlines. */\nfunction dedent(src: Source, from: number, to: number): string {\n let common = Infinity;\n for (let i = from; i < to; i++) {\n const line = src.text[i] ?? \"\";\n if (!isBlank(line)) common = Math.min(common, indentOf(line));\n }\n if (!Number.isFinite(common)) common = 0;\n const out: string[] = [];\n for (let i = from; i < to; i++) {\n const line = src.text[i] ?? \"\";\n out.push(isBlank(line) ? \"\" : line.slice(common).replace(/[ \\t]+$/, \"\"));\n }\n return out.join(\"\\n\").replace(/\\n+$/, \"\");\n}\n\n/** Last non-blank line in `from..to`, or `from - 1` when there is none. */\nfunction lastContentLine(src: Source, from: number, to: number): number {\n for (let i = to - 1; i >= from; i--) {\n if (!isBlank(src.text[i])) return i;\n }\n return from - 1;\n}\n\n/** Scanner state that outlives one range: the adornment styles seen so far. */\ninterface Levels {\n styles: string[];\n}\n\nfunction levelFor(levels: Levels, style: string): number {\n let index = levels.styles.indexOf(style);\n if (index === -1) {\n levels.styles.push(style);\n index = levels.styles.length - 1;\n }\n return Math.min(index + 1, 6);\n}\n\n/** A directive's `:key: value` option block, read up to the first non-option line. */\nfunction readOptions(\n src: Source,\n from: number,\n to: number,\n): { options: Record<string, string>; next: number } {\n const options: Record<string, string> = {};\n let i = from;\n while (i < to) {\n const match = OPTION_KV.exec(src.text[i] ?? \"\");\n if (!match) break;\n const key = (match[1] ?? \"\").toLowerCase();\n options[key] = (match[2] ?? \"\").trim();\n i++;\n }\n return { options, next: i };\n}\n\n/** First content line of a directive body, after its options and any blank lines. */\nfunction directiveContentStart(src: Source, from: number, to: number): number {\n const { next } = readOptions(src, from, to);\n let start = next;\n while (start < to && isBlank(src.text[start])) start++;\n return start;\n}\n\n/** Index of every `+` in a grid-table border line - the table's column edges. */\nfunction gridColumns(border: string): number[] {\n const cols: number[] = [];\n for (let i = 0; i < border.length; i++) {\n if (border[i] === \"+\") cols.push(i);\n }\n return cols;\n}\n\n/** The substrings a grid-table content line holds between `cols`' column edges. */\nfunction gridCells(line: string, cols: number[]): string[] {\n const cells: string[] = [];\n for (let k = 0; k < cols.length - 1; k++) {\n const start = (cols[k] ?? 0) + 1;\n const end = cols[k + 1] ?? line.length;\n cells.push(line.slice(start, end));\n }\n return cells;\n}\n\n/**\n * A grid table (`+---+---+` borders), read from its top border at `from`.\n *\n * Column edges come from the top border alone, so a row whose own border omits\n * a `+` (a spanning cell) is read as if it were not spanned - see the file\n * header. A row is `header: true` when the border that closes it carries `=`.\n */\nfunction parseGridTable(src: Source, from: number, to: number): { node: TableNode; next: number } {\n let end = from;\n while (end < to && !isBlank(src.text[end])) end++;\n\n const cols = gridColumns(src.text[from] ?? \"\");\n const rows: TableRowNode[] = [];\n let current: number[] = [];\n\n const flush = (header: boolean): void => {\n if (current.length === 0) return;\n const first = current[0] ?? from;\n const last = current[current.length - 1] ?? first;\n const perColumn: string[][] = cols.slice(0, -1).map(() => []);\n for (const lineIdx of current) {\n const cells = gridCells(src.text[lineIdx] ?? \"\", cols);\n cells.forEach((text, idx) => perColumn[idx]?.push(text));\n }\n const cellNodes: TableCellNode[] = perColumn.map((lines) => {\n const text = flattenInline(lines.join(\" \").trim());\n return {\n kind: \"tableCell\",\n position: spanOf(src, first, last),\n text,\n children: text === \"\" ? [] : [{ kind: \"paragraph\", position: spanOf(src, first, last), text }],\n };\n });\n rows.push({\n kind: \"tableRow\",\n header,\n position: spanOf(src, first, last),\n text: cellNodes.map((c) => c.text).join(\" | \"),\n children: cellNodes,\n });\n current = [];\n };\n\n for (let i = from + 1; i < end; i++) {\n const line = src.text[i] ?? \"\";\n if (GRID_TABLE.test(line)) {\n flush(/=/.test(line));\n continue;\n }\n current.push(i);\n }\n flush(false);\n\n const last = lastContentLine(src, from, end);\n return {\n node: {\n kind: \"table\",\n position: spanOf(src, from, Math.max(last, from)),\n text: rows.map((r) => r.text).join(\"\\n\"),\n children: rows,\n },\n next: end,\n };\n}\n\n/** Column spans (`[start, end)`) from a simple-table border's `=`/`-` runs. */\nfunction simpleColumns(border: string): [number, number][] {\n const spans: [number, number][] = [];\n const re = /[-=]+/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(border)) !== null) {\n spans.push([match.index, match.index + match[0].length]);\n }\n return spans;\n}\n\n/** One simple-table row, built from one or more physical lines over `spans`. */\nfunction simpleRow(\n src: Source,\n lines: number[],\n spans: [number, number][],\n header: boolean,\n): TableRowNode {\n const first = lines[0] ?? 0;\n const last = lines[lines.length - 1] ?? first;\n const perColumn: string[][] = spans.map(() => []);\n for (const lineIdx of lines) {\n const raw = src.text[lineIdx] ?? \"\";\n spans.forEach(([start, endCol], idx) => {\n const isLast = idx === spans.length - 1;\n perColumn[idx]?.push(raw.slice(start, isLast ? raw.length : endCol));\n });\n }\n const cells: TableCellNode[] = perColumn.map((columnLines) => {\n const text = flattenInline(columnLines.join(\" \").trim());\n return {\n kind: \"tableCell\",\n position: spanOf(src, first, last),\n text,\n children: text === \"\" ? [] : [{ kind: \"paragraph\", position: spanOf(src, first, last), text }],\n };\n });\n return {\n kind: \"tableRow\",\n header,\n position: spanOf(src, first, last),\n text: cells.map((c) => c.text).join(\" | \"),\n children: cells,\n };\n}\n\n/**\n * A simple table (`=== ===` rules), read from its top border at `from`.\n *\n * One physical line is one row, with one exception: every line between the\n * top border and the header separator, if there is one, merges into a single\n * multi-line header row. Without a header separator, the table has no header.\n */\nfunction parseSimpleTable(src: Source, from: number, to: number): { node: TableNode; next: number } {\n let end = from;\n while (end < to && !isBlank(src.text[end])) end++;\n\n const spans = simpleColumns(src.text[from] ?? \"\");\n const borders: number[] = [];\n for (let i = from; i < end; i++) {\n if (SIMPLE_TABLE.test(src.text[i] ?? \"\")) borders.push(i);\n }\n const top = borders[0] ?? from;\n const bottom = borders[borders.length - 1] ?? end - 1;\n const interior = borders.filter((idx) => idx !== top && idx !== bottom);\n const headerSep = interior[0];\n\n const headerLines: number[] = [];\n const bodyLines: number[] = [];\n for (let i = top + 1; i < bottom; i++) {\n if (interior.includes(i)) continue;\n if (headerSep !== undefined && i < headerSep) headerLines.push(i);\n else bodyLines.push(i);\n }\n\n const rows: TableRowNode[] = [];\n if (headerLines.length > 0) rows.push(simpleRow(src, headerLines, spans, true));\n for (const lineIdx of bodyLines) rows.push(simpleRow(src, [lineIdx], spans, false));\n\n const last = lastContentLine(src, from, end);\n return {\n node: {\n kind: \"table\",\n position: spanOf(src, from, Math.max(last, from)),\n text: rows.map((r) => r.text).join(\"\\n\"),\n children: rows,\n },\n next: end,\n };\n}\n\n/**\n * A `csv-table`'s own naive split: comma-delimited, `\"`-quoted fields with\n * `\"\"` as an escaped quote. Not the general CSV grammar, just enough for the\n * directive's inline rows.\n */\nfunction splitCsvLine(line: string): string[] {\n const fields: string[] = [];\n let field = \"\";\n let quoted = false;\n let i = 0;\n while (i < line.length) {\n const ch = line[i];\n // `i < line.length` already guarantees this, but `noUncheckedIndexedAccess`\n // cannot see it, and a `?? \"\"` fallback would silently swallow a real\n // bounds bug instead of ending the scan.\n if (ch === undefined) break;\n if (quoted) {\n if (ch === '\"') {\n if (line[i + 1] === '\"') {\n field += '\"';\n i += 2;\n continue;\n }\n quoted = false;\n i++;\n continue;\n }\n field += ch;\n i++;\n continue;\n }\n if (ch === '\"' && field.trim() === \"\") {\n quoted = true;\n i++;\n continue;\n }\n if (ch === \",\") {\n fields.push(field.trim());\n field = \"\";\n i++;\n continue;\n }\n field += ch;\n i++;\n }\n fields.push(field.trim());\n return fields;\n}\n\n/** One `csv-table` row, from already-split fields. */\nfunction csvRow(src: Source, lineIdx: number, fields: string[], header: boolean): TableRowNode {\n const cells: TableCellNode[] = fields.map((field) => {\n const text = flattenInline(field);\n return {\n kind: \"tableCell\",\n position: spanOf(src, lineIdx, lineIdx),\n text,\n children: text === \"\" ? [] : [{ kind: \"paragraph\", position: spanOf(src, lineIdx, lineIdx), text }],\n };\n });\n return {\n kind: \"tableRow\",\n header,\n position: spanOf(src, lineIdx, lineIdx),\n text: cells.map((c) => c.text).join(\" | \"),\n children: cells,\n };\n}\n\n/**\n * Scan `from..to` at indent `base` into ordered blocks.\n *\n * `headings` is false inside a list item: RST section titles only occur at the\n * document's own indent, and a heading emitted from inside an item would break\n * the fold.\n */\nfunction scanRange(\n src: Source,\n levels: Levels,\n from: number,\n to: number,\n base: number,\n headings: boolean,\n): Fragment[] {\n const fragments: Fragment[] = [];\n const content = (node: ContentNode): void => {\n fragments.push({ type: \"content\", node });\n };\n let i = from;\n\n while (i < to) {\n const line = src.text[i] ?? \"\";\n\n if (isBlank(line)) {\n i++;\n continue;\n }\n\n if (headings) {\n const hit = titleAt(src, i, to);\n if (hit) {\n fragments.push({\n type: \"heading\",\n level: levelFor(levels, hit.style),\n title: hit.title,\n position: spanOf(src, hit.first, hit.last),\n });\n i = hit.last + 1;\n continue;\n }\n }\n\n // `::` alone is the expanded form of the literal-block marker, and it also\n // reads as a two-character run of `:`. The marker wins: an adornment of\n // colons could only ever underline a title one or two characters wide.\n if (line.trim() === \"::\") {\n i = readParagraph(src, levels, fragments, i, to, base, headings);\n continue;\n }\n\n // A run of adornment that did not start a title is a transition, or the\n // stray underline of something that was not one. Either way, not content.\n if (adornmentOf(line) !== null) {\n i++;\n continue;\n }\n\n const lineIndent = indentOf(line);\n\n // Explicit markup: a directive, a comment, a target, or a substitution\n // definition. Some directives become a node of their own; every other\n // directive, comment, target, and substitution definition is skipped\n // whole - see the file header for exactly which.\n if (EXPLICIT.test(line)) {\n const bodyEnd = indentedBlockEnd(src, i + 1, to, lineIndent);\n const directive = DIRECTIVE.exec(line);\n const name = directive?.[2]?.toLowerCase();\n\n if (name && CODE_DIRECTIVES.has(name)) {\n const lang = (directive?.[3] ?? \"\").trim();\n // Drop the directive's own options (`:linenos:` and friends) before the\n // body; they are configuration, not code.\n let codeStart = i + 1;\n while (codeStart < bodyEnd && OPTION.test(src.text[codeStart] ?? \"\")) codeStart++;\n while (codeStart < bodyEnd && isBlank(src.text[codeStart])) codeStart++;\n const codeEnd = lastContentLine(src, codeStart, bodyEnd) + 1;\n content({\n kind: \"codeBlock\",\n position: spanOf(src, i, Math.max(codeEnd - 1, i)),\n text: codeStart < codeEnd ? dedent(src, codeStart, codeEnd) : \"\",\n ...(lang ? { language: lang } : {}),\n });\n } else if (name && ADMONITION_DIRECTIVES.has(name)) {\n const variant = ADMONITION_VARIANTS.get(name);\n const start = directiveContentStart(src, i + 1, bodyEnd);\n const children =\n start < bodyEnd\n ? scanRange(src, levels, start, bodyEnd, indentOf(src.text[start] ?? \"\"), false)\n .filter((f): f is Extract<Fragment, { type: \"content\" }> => f.type === \"content\")\n .map((f) => f.node)\n : [];\n const last = lastContentLine(src, i, bodyEnd);\n content({\n kind: \"admonition\",\n position: spanOf(src, i, Math.max(last, i)),\n text: children.map((c) => c.text).join(\"\\n\"),\n ...(variant ? { variant } : {}),\n children,\n });\n } else if (name === \"image\" || name === \"figure\") {\n const url = (directive?.[3] ?? \"\").trim();\n if (url) {\n const { options } = readOptions(src, i + 1, bodyEnd);\n const alt = options[\"alt\"] ?? \"\";\n const last = lastContentLine(src, i, bodyEnd);\n content({\n kind: \"image\",\n position: spanOf(src, i, Math.max(last, i)),\n text: alt,\n url,\n alt,\n });\n }\n } else if (name === \"list-table\") {\n const start = directiveContentStart(src, i + 1, bodyEnd);\n if (start < bodyEnd) {\n const { options } = readOptions(src, i + 1, bodyEnd);\n const headerRows = Number.parseInt(options[\"header-rows\"] ?? \"\", 10) || 0;\n const rowsFragment = scanRange(\n src,\n levels,\n start,\n bodyEnd,\n indentOf(src.text[start] ?? \"\"),\n false,\n ).find(\n (f): f is Extract<Fragment, { type: \"content\" }> =>\n f.type === \"content\" && f.node.kind === \"list\",\n );\n if (rowsFragment && rowsFragment.node.kind === \"list\") {\n const rows: TableRowNode[] = rowsFragment.node.items.map((item, index) => {\n const cellsList = item.children.find((c): c is ListNode => c.kind === \"list\");\n const cells: TableCellNode[] = (cellsList?.items ?? []).map((cellItem) => ({\n kind: \"tableCell\",\n position: cellItem.position,\n text: cellItem.text,\n children: cellItem.children,\n }));\n return {\n kind: \"tableRow\",\n header: index < headerRows,\n position: item.position,\n text: cells.map((c) => c.text).join(\" | \"),\n children: cells,\n };\n });\n const last = lastContentLine(src, i, bodyEnd);\n content({\n kind: \"table\",\n position: spanOf(src, i, Math.max(last, i)),\n text: rows.map((r) => r.text).join(\"\\n\"),\n children: rows,\n });\n }\n }\n } else if (name === \"csv-table\") {\n const { options } = readOptions(src, i + 1, bodyEnd);\n const bodyStart = directiveContentStart(src, i + 1, bodyEnd);\n const rowLines: number[] = [];\n for (let li = bodyStart; li < bodyEnd; li++) {\n if (!isBlank(src.text[li])) rowLines.push(li);\n }\n const headerOption = options[\"header\"];\n if (rowLines.length > 0 || headerOption !== undefined) {\n const headerRows = Number.parseInt(options[\"header-rows\"] ?? \"\", 10) || 0;\n const rows: TableRowNode[] = [];\n if (headerOption !== undefined) {\n rows.push(csvRow(src, i, splitCsvLine(headerOption), true));\n }\n rowLines.forEach((lineIdx, index) => {\n rows.push(csvRow(src, lineIdx, splitCsvLine(src.text[lineIdx] ?? \"\"), index < headerRows));\n });\n const last = lastContentLine(src, i, bodyEnd);\n content({\n kind: \"table\",\n position: spanOf(src, i, Math.max(last, i)),\n text: rows.map((r) => r.text).join(\"\\n\"),\n children: rows,\n });\n }\n }\n i = Math.max(bodyEnd, i + 1);\n continue;\n }\n\n // Field lists (docinfo, and bibliographic fields) are metadata, read\n // separately by `readMetadata`. Never body content.\n if (FIELD.test(line) && lineIndent === base) {\n i = Math.max(indentedBlockEnd(src, i + 1, to, lineIndent), i + 1);\n while (i < to && FIELD.test(src.text[i] ?? \"\") && indentOf(src.text[i] ?? \"\") === base) {\n i = Math.max(indentedBlockEnd(src, i + 1, to, lineIndent), i + 1);\n }\n continue;\n }\n\n if (DOCTEST.test(line)) {\n // Consume the run of non-blank lines the construct occupies.\n let end = i;\n while (end < to && !isBlank(src.text[end])) end++;\n i = end;\n continue;\n }\n\n if (GRID_TABLE.test(line)) {\n const table = parseGridTable(src, i, to);\n content(table.node);\n i = table.next;\n continue;\n }\n\n if (SIMPLE_TABLE.test(line)) {\n const table = parseSimpleTable(src, i, to);\n content(table.node);\n i = table.next;\n continue;\n }\n\n // An indented block with no `::` ahead of it is a block quote. Its own\n // content is parsed the same way a list item's body is.\n if (lineIndent > base) {\n const bqEnd = indentedBlockEnd(src, i, to, base);\n const children = scanRange(src, levels, i, bqEnd, lineIndent, false)\n .filter((f): f is Extract<Fragment, { type: \"content\" }> => f.type === \"content\")\n .map((f) => f.node);\n const last = lastContentLine(src, i, bqEnd);\n content({\n kind: \"blockquote\",\n position: spanOf(src, i, Math.max(last, i)),\n text: children.map((c) => c.text).join(\"\\n\"),\n children,\n });\n i = Math.max(bqEnd, i + 1);\n continue;\n }\n\n const bullet = BULLET.exec(line);\n if (bullet && indentOf(line) === base && bulletHasBody(bullet, src, i, to, base)) {\n const list = parseList(src, levels, i, to, base, false);\n content(list.node);\n i = list.next;\n continue;\n }\n\n const enumerated = ENUM.exec(line);\n if (enumerated && indentOf(line) === base && bulletHasBody(enumerated, src, i, to, base)) {\n const list = parseList(src, levels, i, to, base, true);\n content(list.node);\n i = list.next;\n continue;\n }\n\n // A term whose next line is indented is a definition list, not a paragraph\n // followed by a block quote.\n const next = src.text[i + 1];\n if (i + 1 < to && !isBlank(next) && indentOf(next ?? \"\") > base) {\n const dl = parseDefinitionList(src, levels, i, to, base);\n content(dl.node);\n i = dl.next;\n continue;\n }\n\n i = readParagraph(src, levels, fragments, i, to, base, headings);\n }\n\n return fragments;\n}\n\n/**\n * Does a matched list marker actually open an item?\n *\n * A marker with text after it always does. A bare marker opens one only when an\n * indented block follows, which is what separates an empty list item from a\n * line that merely starts with a hyphen.\n */\nfunction bulletHasBody(\n match: RegExpExecArray,\n src: Source,\n line: number,\n to: number,\n base: number,\n): boolean {\n // The content group is 4 for `BULLET` and 5 for `ENUM`, which has the extra\n // suffix group. Checking both is cheaper than threading the pattern's shape\n // through: only one of the two is ever a content group, and the other is\n // whitespace or undefined.\n if ((match[4] ?? \"\").trim() !== \"\" || (match[5] ?? \"\").trim() !== \"\") return true;\n for (let i = line + 1; i < to; i++) {\n const next = src.text[i] ?? \"\";\n if (isBlank(next)) continue;\n return indentOf(next) > base;\n }\n return false;\n}\n\n/** The marker text and the column its content starts at, for one item line. */\ninterface Marker {\n /** Width of the marker plus the whitespace after it. */\n width: number;\n /** Indent the item's body sits at. */\n contentIndent: number;\n}\n\nfunction markerOf(match: RegExpExecArray, ordered: boolean): Marker {\n const indent = (match[1] ?? \"\").length;\n const marker = ordered ? `${match[2] ?? \"\"}${match[3] ?? \"\"}` : (match[2] ?? \"\");\n const gap = (ordered ? match[4] : match[3]) ?? \" \";\n return { width: marker.length + gap.length, contentIndent: indent + marker.length + gap.length };\n}\n\n/**\n * Parse the run of list items starting at `from`.\n *\n * Each item's marker is blanked out of `src.text` - replaced by exactly as many\n * spaces - so the item body is an ordinary indented block that `scanRange` can\n * read with no special case. Offsets and columns are untouched by construction.\n */\nfunction parseList(\n src: Source,\n levels: Levels,\n from: number,\n to: number,\n base: number,\n ordered: boolean,\n): { node: ContentNode; next: number } {\n const pattern = ordered ? ENUM : BULLET;\n // `parseList` is only entered on a line that already matched, so the miss\n // falls through to the same defaults a matched line with no marker group\n // would have taken.\n const firstMatch = pattern.exec(src.text[from] ?? \"\");\n const markerChar = ordered ? (firstMatch?.[3] ?? \".\") : (firstMatch?.[2] ?? \"*\");\n const items: ListItemNode[] = [];\n // Where the list ends, excluding the blank lines between items - those belong\n // to whatever follows, so a list before a heading does not swallow the gap.\n let end = from;\n let i = from;\n\n while (i < to) {\n // Items may be separated by blank lines; the list ends at the first\n // non-blank line that is not another item at this indent.\n let start = i;\n while (start < to && isBlank(src.text[start])) start++;\n if (start >= to) break;\n\n const line = src.text[start] ?? \"\";\n if (indentOf(line) !== base) break;\n const match = pattern.exec(line);\n if (!match) break;\n // docutils ends a list when the marker style changes; so do we. The\n // defaults match `markerChar`'s above: a different fallback here would end\n // the list after its first item rather than read the style as unchanged.\n const thisChar = ordered ? (match[3] ?? \".\") : (match[2] ?? \"*\");\n if (thisChar !== markerChar) break;\n if (!bulletHasBody(match, src, start, to, base)) break;\n\n const marker = markerOf(match, ordered);\n // Blank the marker in place. Same length, so `starts` stays exact.\n src.text[start] = \" \".repeat(marker.contentIndent) + line.slice(marker.contentIndent);\n\n const bodyEnd = Math.max(indentedBlockEnd(src, start + 1, to, base), start + 1);\n const last = lastContentLine(src, start, bodyEnd);\n const children = scanRange(src, levels, start, bodyEnd, marker.contentIndent, false)\n .filter((b): b is Extract<Fragment, { type: \"content\" }> => b.type === \"content\")\n .map((b) => b.node);\n\n items.push({\n kind: \"listItem\",\n position: spanOf(src, start, Math.max(last, start), base + 1),\n text: children.map((c) => c.text).join(\"\\n\"),\n children,\n });\n i = bodyEnd;\n end = bodyEnd;\n }\n\n const last = lastContentLine(src, from, end);\n return {\n node: {\n kind: \"list\",\n position: spanOf(src, from, Math.max(last, from), base + 1),\n text: items.map((item) => item.text).join(\"\\n\"),\n ordered,\n items,\n },\n next: Math.max(i, from + 1),\n };\n}\n\n/**\n * A run of term/definition pairs starting at `from`: an unindented term line\n * immediately followed by an indented definition. Items may be separated by\n * blank lines, the same tolerance `parseList` gives bulleted items.\n */\nfunction parseDefinitionList(\n src: Source,\n levels: Levels,\n from: number,\n to: number,\n base: number,\n): { node: ContentNode; next: number } {\n const items: DefinitionItemNode[] = [];\n let i = from;\n let end = from;\n\n while (i < to) {\n let start = i;\n while (start < to && isBlank(src.text[start])) start++;\n if (start >= to) break;\n\n const line = src.text[start] ?? \"\";\n if (indentOf(line) !== base) break;\n const next = src.text[start + 1];\n if (start + 1 >= to || isBlank(next) || indentOf(next ?? \"\") <= base) break;\n\n const term = flattenInline(line.trim());\n const defStart = start + 1;\n const defIndent = indentOf(next ?? \"\");\n const defEnd = Math.max(indentedBlockEnd(src, defStart, to, base), defStart);\n const last = lastContentLine(src, start, defEnd);\n const definition = scanRange(src, levels, defStart, defEnd, defIndent, false)\n .filter((f): f is Extract<Fragment, { type: \"content\" }> => f.type === \"content\")\n .map((f) => f.node);\n\n items.push({\n kind: \"definitionItem\",\n position: spanOf(src, start, Math.max(last, start)),\n text: [term, ...definition.map((d) => d.text)].join(\"\\n\"),\n term,\n definition,\n });\n i = defEnd;\n end = defEnd;\n }\n\n const last = lastContentLine(src, from, end);\n return {\n node: {\n kind: \"definitionList\",\n position: spanOf(src, from, Math.max(last, from)),\n text: items.map((item) => item.text).join(\"\\n\"),\n children: items,\n },\n next: Math.max(i, from + 1),\n };\n}\n\n/**\n * Read one paragraph, and the literal block it may introduce.\n *\n * A paragraph ending in `::` opens a literal block: the indented block after\n * it becomes `code`, and the `::` is stripped from the paragraph's own text the\n * way docutils strips it - removed entirely when the paragraph is only `::` or\n * when whitespace precedes it, and collapsed to one colon otherwise.\n */\nfunction readParagraph(\n src: Source,\n levels: Levels,\n fragments: Fragment[],\n from: number,\n to: number,\n base: number,\n headings: boolean,\n): number {\n let end = from;\n while (end < to) {\n const line = src.text[end] ?? \"\";\n if (isBlank(line)) break;\n if (end > from) {\n // A line whose successor underlines it ends the paragraph and starts a\n // section, and a construct of any other kind ends it too.\n if (headings && titleAt(src, end, to)) break;\n if (adornmentOf(line) !== null) break;\n if (EXPLICIT.test(line)) break;\n if (indentOf(line) !== base) break;\n if (GRID_TABLE.test(line) || SIMPLE_TABLE.test(line) || DOCTEST.test(line)) break;\n }\n end++;\n }\n\n const rawText = flattenInline(\n src.text\n .slice(from, end)\n .map((l) => l.trim())\n .join(\"\\n\"),\n );\n const literal = /::$/.test(rawText);\n const text = !literal\n ? rawText\n : rawText === \"::\"\n ? \"\" // A paragraph that is only `::` is the marker, and nothing else.\n : rawText.replace(/(\\s*)::$/, (_m, space: string) => (space === \"\" ? \":\" : \"\"));\n\n if (text.trim() !== \"\") {\n fragments.push({\n type: \"content\",\n node: { kind: \"paragraph\", position: spanOf(src, from, end - 1), text },\n });\n }\n\n if (!literal) return end;\n\n // The literal block is the next indented block, after any blank lines.\n let start = end;\n while (start < to && isBlank(src.text[start])) start++;\n if (start >= to || indentOf(src.text[start] ?? \"\") <= base) return end;\n\n const blockEnd = indentedBlockEnd(src, start, to, base);\n const last = lastContentLine(src, start, blockEnd);\n fragments.push({\n type: \"content\",\n node: {\n kind: \"codeBlock\",\n position: spanOf(src, start, Math.max(last, start)),\n text: dedent(src, start, blockEnd),\n },\n });\n return Math.max(blockEnd, end);\n}\n\n/**\n * Span of the native docinfo block: the leading field list, or - when a page\n * carries only a title - the title line docmeta read it from.\n *\n * docmeta reports the block's start line but not its extent, and we are already\n * holding a line index, so the span is cheaper to recover here than to ask for.\n */\nfunction docinfoPosition(src: Source): Position | null {\n const limit = src.text.length;\n let i = 0;\n while (i < limit && isBlank(src.text[i])) i++;\n\n const hit = titleAt(src, i, limit);\n if (hit) i = hit.last + 1;\n while (i < limit && isBlank(src.text[i])) i++;\n\n const fieldStart = i;\n while (i < limit && FIELD.test(src.text[i] ?? \"\") && indentOf(src.text[i] ?? \"\") === 0) {\n i = Math.max(indentedBlockEnd(src, i + 1, limit, 0), i + 1);\n }\n if (i > fieldStart) return spanOf(src, fieldStart, i - 1);\n if (hit) return spanOf(src, hit.first, hit.last);\n return null;\n}\n\ninterface Metadata {\n frontmatter: Record<string, unknown> | null;\n position: Position | null;\n /**\n * First body line, 0-based. Non-zero only for a fenced block, whose lines\n * would otherwise be scanned as prose - `---` as a transition and the YAML\n * under it as a paragraph, which opens an implicit lead section and hands the\n * template's top-level slot the wrong thing. A docinfo field list needs no\n * such cut: it is inside the body, and the scanner skips field lists.\n */\n bodyStart: number;\n}\n\n/**\n * Read the page's metadata, from both places an RST page can put it.\n *\n * `extractFrontmatter(content, \"rst\")` - the call `markdown.ts` makes - reads\n * only a *fenced* block; its format argument is a label copied onto the result,\n * not a dispatch. On its own it would leave every page using the native docinfo\n * field list unrouted, and that field list is how RST authors actually declare\n * `:type: how-to`. The RST-aware reading lives in docmeta's extractor registry,\n * so both are read and merged.\n *\n * A fenced block wins a key collision: it is the author being deliberate about\n * metadata, where a docinfo `title` is often just the document's own heading\n * read a second time. `present` is the OR of the two - the same shape the HTML\n * parser landed on, so the formats stay consistent.\n *\n * That docinfo `title` is worth knowing about. In RST the page title genuinely\n * *is* the first section title, so a page with a title and no fields comes back\n * with non-null `frontmatter` holding just that. Nothing downstream is misled -\n * routing reads `type` and `$template` - and taking docmeta's answer verbatim\n * keeps one source of truth for what a format's metadata is.\n */\nfunction readMetadata(content: string, filePath: string, src: Source): Metadata {\n const fenced = extractFrontmatter(content, \"rst\");\n // Read the docinfo field list from the fence-free remainder: docmeta's reST\n // extractor returns the fence and stops when one is present, so asking it\n // about the whole file would discard `:type:` on any page that has both.\n const native = extractorForExtension(\".rst\")?.extract(\n fenced.present ? withoutFence(content) : content,\n filePath,\n );\n\n if (!fenced.present && !native?.present) {\n return { frontmatter: null, position: null, bodyStart: 0 };\n }\n\n const loc = fenced.present ? locateFrontmatter(content) : null;\n return {\n frontmatter: {\n ...(native?.present ? native.data : {}),\n ...(fenced.present ? fenced.data : {}),\n },\n position: fenced.present ? fencedPosition(content) : docinfoPosition(src),\n // `findIndex` returns -1 when no line starts at or after the closing fence,\n // i.e. the fence is the last thing in the file. `Math.max(-1, 0)` used to\n // launder that into line 0, restarting the scan inside the frontmatter and\n // reading the YAML as body prose - the exact thing `bodyStart` exists to\n // prevent. There is no body in that case, so start past the last line.\n bodyStart: loc\n ? (() => {\n const i = src.starts.findIndex((start) => start >= loc.closeEnd);\n return i === -1 ? src.starts.length : i;\n })()\n : 0,\n };\n}\n\nexport const rstParser: DocumentParser = {\n name: \"rst\",\n label: \"reStructuredText\",\n kinds: [\n \"paragraph\",\n \"codeBlock\",\n \"list\",\n \"listItem\",\n \"table\",\n \"tableRow\",\n \"tableCell\",\n \"admonition\",\n \"image\",\n \"blockquote\",\n \"definitionList\",\n \"definitionItem\",\n ],\n extensions: [\".rst\"],\n parse(content, filePath): DocumentTree {\n const src = indexLines(content);\n // Order is load-bearing: `readMetadata` must run before `scanRange`.\n // `scanRange` blanks consumed list lines in `src.text` in place so a later\n // pass cannot re-read them, and `docinfoPosition` inside `readMetadata`\n // reads those same lines to place the metadata span. Swapped, the docinfo\n // field list is already blank and every metadata position collapses.\n const { frontmatter, position, bodyStart } = readMetadata(content, filePath, src);\n const fragments = scanRange(\n src,\n { styles: [] },\n Math.max(bodyStart, 0),\n src.text.length,\n 0,\n true,\n );\n\n return {\n format: \"rst\",\n filePath,\n frontmatter,\n frontmatterPosition: position,\n sections: sectionize(\n withFrontmatterTitle(fragments, frontmatter, position),\n src.end,\n ),\n };\n },\n};\n","/**\n * XML -> generic blocks, through a declarative vocabulary mapping.\n *\n * ADR 01001 puts XML last \"because structure comes from the document's own\n * element nesting and needs a small per-vocabulary mapping\". This is that\n * mapping, and the reason it exists: XML has no headings. Markdown says `##`,\n * AsciiDoc says `==`, HTML says `<h2>` - one universal rule each. XML says\n * whatever its schema says. DITA nests `<topic>`/`<section>` and titles them\n * with `<title>`; DocBook nests `<chapter>`/`<section>`/`<sect1>` and titles\n * them with `<title>` too, but calls a paragraph `<para>` where DITA calls it\n * `<p>`; a house schema calls them something else again. Hardcoding DITA would\n * make \"the XML parser\" a lie.\n *\n * ## The mapping\n *\n * An `XmlVocabulary` sorts element names into four buckets and says nothing\n * about anything else:\n *\n * - `sections` open a section, titled by the first `titles` element among\n * their children (or inside a `titleWrappers` child, which is\n * how DocBook 5 hides `<title>` in `<info>`).\n * - `transparent` are structural wrappers with no meaning of their own -\n * DITA's `<body>`, `<taskbody>`, `<context>`. The walk passes\n * straight through them at the same level.\n * - `paragraphs` / `code` / `unorderedLists` / `orderedLists` / `listItems` /\n * `tables` / `admonitions` / `images` / `blockquotes` /\n * `definitionLists` are the format-neutral content kinds of\n * `types.ts`. The last five are optional buckets: a vocabulary\n * that leaves one out never emits that kind, same as leaving\n * an entry out of `kinds`.\n * - everything else is **skipped, with its subtree**, exactly as the Markdown\n * parser skips a blockquote. A DITA `<related-links>` is not a paragraph,\n * and its contents must not be counted as one, or `paragraphs: {max: 3}`\n * fails documents a reader would say satisfy it.\n *\n * That last rule is why `transparent` has to exist as its own bucket: without\n * it, skipping the unmapped `<body>` would skip the whole topic.\n *\n * ## Titles that are not elements, and sections that carry none\n *\n * Two more fields, both earned by a DITA map:\n *\n * - `titleAttributes` names attributes that title a section, for the schemas\n * that spell a title as one (`<topicref navtitle=\"Install\"/>`). An attribute\n * has no position of its own, so the heading ends where the start tag does.\n * - `untitledSections` says a `sections` element opens a section even with no\n * title at all. Off by default, because an untitled DITA `<section>` is\n * prose belonging to the topic around it. On for a map, where an entry names\n * its target by `@keyref` or `@href` and lets the referenced topic supply\n * the title, so untitled is the normal case and dropping those entries would\n * flatten the whole table of contents.\n *\n * ## Extending it for a bespoke schema\n *\n * Add one entry to `XML_VOCABULARIES` (or pass your own array to `parseXml`):\n *\n * { name: \"acme\", label: \"Acme Docs\",\n * namespaces: [\"https://acme.example/docs\"], roots: [\"manual\"],\n * sections: [\"manual\", \"chapter\"], titles: [\"heading\"],\n * titleWrappers: [], transparent: [\"content\"],\n * paragraphs: [\"text\"], code: [\"sample\"], codeLangAttributes: [\"lang\"],\n * unorderedLists: [\"bullets\"], orderedLists: [\"steps\"],\n * listItems: [\"item\"] }\n *\n * Tables, admonitions, images, blockquotes and definition lists are five more\n * buckets, all optional - a schema that never names one simply never emits\n * that kind. See each field's own doc comment below for the shape it expects.\n *\n * Nothing else changes: the walk, the levels, the positions, and the fold are\n * vocabulary-independent. This is deliberately not wired to `manni.config.yaml`\n * yet - the shape is the commitment, the config surface is a later decision.\n *\n * ## Which vocabulary a document is in\n *\n * Scored, not guessed: a declared namespace is decisive, then elements only\n * one candidate claims, then the root element name, then the elements they\n * share. That ordering is what settles the ambiguous cases - `<section>`,\n * `<title>` and `<reference>` belong to both built-ins, so a `<section>`-rooted\n * file is decided by whether its prose is in `<p>` or `<para>`. Nothing\n * recognized at all is an error, not an empty tree: see `chooseVocabulary`.\n *\n * ## Levels\n *\n * `sectionize` folds by heading *level*, so nesting is expressed as one: the\n * level is the number of enclosing elements that actually opened a section,\n * plus one. Transparent wrappers do not count, and neither does a section\n * element with no title - an untitled DITA `<section>` is legal, and the honest\n * reading is that it adds no heading and so no level, its content belonging to\n * the section that encloses it. Levels clamp at 6, the range `SectionNode`\n * declares.\n *\n * ## Positions\n *\n * `@xmldom/xmldom` records `lineNumber` (1-based, despite its `index.d.ts`\n * saying \"zero based\") and `columnNumber` (1-based) on every node, pointing at\n * the `<` of an element's start tag and at the first character of a text node.\n * There is no end position. But *every* node carries a start, including the\n * whitespace text nodes between elements, so the exclusive end of an element is\n * the start of the next node in document order - for indented XML that is the\n * character right after `</tag>`, exactly. Only when a node is last all the way\n * up to the root does that fall back to the end of the document, per the\n * house rule for formats whose parser reports no end.\n */\nimport { DOMParser } from \"@xmldom/xmldom\";\nimport type { Element as XmlElement, Node as XmlNode } from \"@xmldom/xmldom\";\nimport { extractorForExtension } from \"../../meta/index.js\";\nimport type {\n AdmonitionNode,\n ContentNode,\n DefinitionItemNode,\n DefinitionListNode,\n DocumentParser,\n DocumentTree,\n ImageNode,\n ListItemNode,\n Point,\n Position,\n TableCellNode,\n TableNode,\n TableRowNode,\n} from \"../types.js\";\nimport { LintError } from \"../types.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport type { Fragment } from \"./sectionize.js\";\nimport { sectionize } from \"./sectionize.js\";\n\n/**\n * One schema's answer to \"what is a section, and what is content?\".\n *\n * Every list is of lowercased local names - the prefix and namespace of an\n * element are not part of the match, so a document that binds DocBook to `db:`\n * maps the same as one that uses the default namespace.\n */\nexport interface XmlVocabulary {\n /** Stable id, used in error messages. */\n name: string;\n /** Human-readable label. */\n label: string;\n /** Namespace URIs that identify this vocabulary outright. */\n namespaces: readonly string[];\n /** Root element names that identify it. */\n roots: readonly string[];\n /** Elements that open a section when they carry a title. */\n sections: readonly string[];\n /** Elements that carry a section's title. */\n titles: readonly string[];\n /**\n * Attributes that carry a section's title when no `titles` element does,\n * first one present wins. A DITA map spells one `<topicref navtitle=\"...\">`.\n */\n titleAttributes?: readonly string[];\n /**\n * Whether a `sections` element with no title of any kind still opens a\n * section. Default false: an untitled container adds no heading, and its\n * content belongs to the section that encloses it.\n */\n untitledSections?: boolean;\n /** Children to look inside for a title (DocBook's `<info>`). */\n titleWrappers: readonly string[];\n /** Structural wrappers: no section, no content, walk through. */\n transparent: readonly string[];\n /** Elements that are one paragraph. */\n paragraphs: readonly string[];\n /** Elements that are one code block. */\n code: readonly string[];\n /** Attributes carrying a code block's language, first one present wins. */\n codeLangAttributes: readonly string[];\n /** Elements that are an unordered list. */\n unorderedLists: readonly string[];\n /** Elements that are an ordered list. */\n orderedLists: readonly string[];\n /** Elements that are one item of a list. */\n listItems: readonly string[];\n\n /** Elements that are a table, CALS-shaped or simple. */\n tables?: readonly string[];\n /** Elements whose direct children are cells: a header row or a body row. */\n tableRows?: readonly string[];\n /** Elements that are one cell of a row. */\n tableCells?: readonly string[];\n /** Wrapper elements whose descendant rows are all header rows (CALS `<thead>`). */\n tableHeaderWrappers?: readonly string[];\n /** Row elements that are inherently a header row on their own (DITA `<sthead>`). */\n tableHeaderRows?: readonly string[];\n\n /** Elements that may be an admonition. */\n admonitions?: readonly string[];\n /**\n * Attribute naming the admonition's variant (DITA's `<note>` `@type`). When\n * absent, an admonition element's own lowercased name is its variant -\n * DocBook's five admonition elements are themselves named `note`, `tip`,\n * `important`, `caution` and `warning`. Either way, a name outside the six\n * `AdmonitionNode` knows produces an admonition with no `variant` set,\n * rather than an invented equivalence - DITA's `restriction` and `fastpath`\n * are real `@type` values this model does not have a word for.\n */\n admonitionVariantAttribute?: string;\n\n /** Elements that are an image, standing alone or wrapping one. */\n images?: readonly string[];\n /**\n * Element carrying the image's own url attribute - itself, for a\n * self-contained image (DITA's `<image href>`), or a descendant found by\n * name (DocBook's `<imagedata fileref>` inside a `<mediaobject>`).\n */\n imageDataElements?: readonly string[];\n /** Attribute on an `imageDataElements` match that carries the url. */\n imageUrlAttribute?: string;\n /** Direct child of an `imageDataElements` match carrying the alt text. */\n imageAltElements?: readonly string[];\n\n /** Elements that are a block quote. */\n blockquotes?: readonly string[];\n\n /** Elements that are a definition list. */\n definitionLists?: readonly string[];\n /** Elements that are one entry, pairing a term with a definition. */\n definitionItems?: readonly string[];\n /** Elements that carry an entry's term(s); more than one join with \", \". */\n definitionTerms?: readonly string[];\n /** Elements that carry an entry's definition body. */\n definitionBodies?: readonly string[];\n}\n\n/**\n * DITA. No default namespace to detect on (DITA is conventionally\n * namespace-free, with only `ditaarch:` bound on the root), so recognition\n * leans on the topic types and on `<p>`/`<codeblock>`/`<body>`.\n *\n * `<prereq>`, `<context>`, `<result>` and friends are transparent rather than\n * sections: they are untitled parts of a task body that render as continuous\n * prose, so their paragraphs belong to the task. `<related-links>` and\n * `<prolog>` are in no bucket at all, so they and their contents are skipped -\n * the blockquote rule.\n *\n * A CALS `<table>` and an OASIS `<simpletable>` share one row/cell reading:\n * `<row>`/`<entry>` for the former, `<strow>`/`<stentry>` for the latter. A row\n * inside `<thead>` is a header row (the CALS shape); `<sthead>` is a header row\n * on its own, holding `<stentry>` cells directly rather than wrapping a row.\n */\nconst DITA: XmlVocabulary = {\n name: \"dita\",\n label: \"DITA\",\n namespaces: [],\n roots: [\"dita\", \"topic\", \"concept\", \"task\", \"reference\", \"glossentry\"],\n sections: [\n \"topic\",\n \"concept\",\n \"task\",\n \"reference\",\n \"glossentry\",\n \"section\",\n \"example\",\n ],\n // `<glossterm>` is how a `<glossentry>` titles itself. It never carries a\n // `<title>`, so a vocabulary listing `title` alone reads every real glossary\n // topic as untitled and refuses the whole file. DITA-OT's own docset has\n // thirteen of them. `src/term/core/readers/dita.ts` has always read\n // `<glossterm>` as the term, so the two halves of this package disagreed\n // until the vendored corpus made it visible.\n titles: [\"title\", \"glossterm\"],\n titleWrappers: [],\n transparent: [\n \"dita\",\n \"body\",\n \"conbody\",\n \"taskbody\",\n \"refbody\",\n \"glossbody\",\n \"abstract\",\n \"prereq\",\n \"context\",\n \"result\",\n \"postreq\",\n \"div\",\n \"bodydiv\",\n \"sectiondiv\",\n ],\n // `<cmd>` is the imperative line of a `<step>`; treating it as a paragraph is\n // what makes a DITA `<steps>` item shaped like a Markdown list item.\n //\n // `<glossdef>` is the definition, and it holds prose either directly or in\n // `<p>`s. A paragraph rather than a wrapper, because a wrapper would drop the\n // direct-text spelling, which is the common one.\n paragraphs: [\"p\", \"shortdesc\", \"cmd\", \"info\", \"glossdef\"],\n code: [\"codeblock\", \"pre\"],\n codeLangAttributes: [\"outputclass\"],\n unorderedLists: [\"ul\", \"sl\", \"steps-unordered\"],\n orderedLists: [\"ol\", \"steps\", \"substeps\"],\n listItems: [\"li\", \"sli\", \"step\", \"substep\"],\n\n tables: [\"table\", \"simpletable\"],\n tableRows: [\"row\", \"strow\", \"sthead\"],\n tableCells: [\"entry\", \"stentry\"],\n tableHeaderWrappers: [\"thead\"],\n tableHeaderRows: [\"sthead\"],\n\n admonitions: [\"note\"],\n admonitionVariantAttribute: \"type\",\n\n images: [\"image\", \"fig\"],\n imageDataElements: [\"image\"],\n imageUrlAttribute: \"href\",\n imageAltElements: [\"alt\"],\n\n blockquotes: [\"lq\"],\n\n definitionLists: [\"dl\"],\n definitionItems: [\"dlentry\"],\n definitionTerms: [\"dt\"],\n definitionBodies: [\"dd\"],\n};\n\n/**\n * DocBook 5 (and the DocBook 4 `<sectN>`/`<*info>` spellings, which cost two\n * entries and save a whole second vocabulary).\n */\nconst DOCBOOK: XmlVocabulary = {\n name: \"docbook\",\n label: \"DocBook\",\n namespaces: [\"http://docbook.org/ns/docbook\"],\n roots: [\n \"book\",\n \"article\",\n \"chapter\",\n \"section\",\n \"sect1\",\n \"part\",\n \"appendix\",\n \"preface\",\n \"reference\",\n ],\n sections: [\n \"book\",\n \"article\",\n \"part\",\n \"chapter\",\n \"appendix\",\n \"preface\",\n \"section\",\n \"simplesect\",\n \"sect1\",\n \"sect2\",\n \"sect3\",\n \"sect4\",\n \"sect5\",\n ],\n titles: [\"title\"],\n titleWrappers: [\n \"info\",\n \"bookinfo\",\n \"articleinfo\",\n \"chapterinfo\",\n \"sectioninfo\",\n ],\n transparent: [\"formalpara\"],\n paragraphs: [\"para\", \"simpara\"],\n code: [\"programlisting\", \"screen\", \"literallayout\", \"synopsis\"],\n codeLangAttributes: [\"language\"],\n unorderedLists: [\"itemizedlist\", \"simplelist\"],\n orderedLists: [\"orderedlist\", \"procedure\"],\n listItems: [\"listitem\", \"member\", \"step\"],\n\n tables: [\"table\", \"informaltable\"],\n tableRows: [\"row\"],\n tableCells: [\"entry\"],\n tableHeaderWrappers: [\"thead\"],\n tableHeaderRows: [],\n\n // No `admonitionVariantAttribute`: DocBook's five admonition elements are\n // themselves named `note`/`warning`/`caution`/`tip`/`important`.\n admonitions: [\"note\", \"warning\", \"caution\", \"tip\", \"important\"],\n\n images: [\"mediaobject\", \"figure\"],\n imageDataElements: [\"imagedata\"],\n imageUrlAttribute: \"fileref\",\n imageAltElements: [],\n\n blockquotes: [\"blockquote\"],\n\n definitionLists: [\"variablelist\"],\n definitionItems: [\"varlistentry\"],\n definitionTerms: [\"term\"],\n // DocBook reuses `<listitem>` for a variable list's own body, distinct from\n // the `listItems` bucket above which reads it inside `<itemizedlist>`.\n definitionBodies: [\"listitem\"],\n};\n\n/**\n * DITA maps, `<map>` and `<bookmap>`. No namespace to detect on, as with DITA\n * itself, so recognition leans on `<topicref>` and the rest of the navigation\n * vocabulary.\n *\n * A map is a table of contents, which is a tree of titled nodes - and a tree of\n * titled nodes is what a section tree is. `<topicref>` nesting is section\n * nesting. The one thing a map does that a topic never does is leave its nodes\n * untitled: a real entry points by `@keyref` or `@href` and lets the referenced\n * topic supply the title, so `untitledSections` is on and an untitled entry is\n * an untitled section rather than a failure. A titled entry may be titled\n * either way, as `<topicmeta><navtitle>` or as `@navtitle`, so `titles` and\n * `titleAttributes` both name it.\n *\n * `sections` is wide because navigation is. `<glossref>`, `<mapref>`,\n * `<navref>`, `<topicset>` and a bookmap's `<chapter>`/`<part>`/`<appendix>`\n * are all `<topicref>` specializations, and a map that nests its entries in one\n * of them - DITA-OT's own glossary map nests thirteen `<glossref>`s - would\n * otherwise parse to a tree with nothing in it.\n *\n * `<reltable>` and `<keydef>` are in no bucket at all, so they and their\n * contents are skipped, the blockquote rule. A relationship table states which\n * topics relate to each other, and a key definition binds a key to a resource.\n * Neither is navigation, and counting their `<topicref>`s as sections would\n * make every map's shape a lie. A `<glossref>` carrying `@keys` is the case\n * that looks like both, and it is a section: `<keydef>` defaults to\n * `processing-role=\"resource-only\"` and so never appears in a table of\n * contents, while `<glossref>` processes normally and does. That is a fact\n * about DITA, not a preference.\n *\n * `<topicmeta>` is both a title wrapper and transparent. Wrapping is how\n * `<navtitle>` is found; transparency is how the `<shortdesc>` and `<linktext>`\n * beside it are read, since a map has no other prose and they live nowhere\n * else. `<booktitle>` is a wrapper only: a bookmap titles itself\n * `<booktitle><mainbooktitle>`, and the optional `<booklibrary>` beside it\n * names the series rather than the book, so only `<mainbooktitle>` is a title.\n */\nconst DITAMAP: XmlVocabulary = {\n name: \"ditamap\",\n label: \"DITA map\",\n namespaces: [],\n roots: [\"map\", \"bookmap\"],\n sections: [\n \"map\",\n \"bookmap\",\n \"topicref\",\n \"topichead\",\n \"mapref\",\n \"glossref\",\n \"anchorref\",\n \"navref\",\n \"topicset\",\n \"topicsetref\",\n \"chapter\",\n \"part\",\n \"appendix\",\n \"appendices\",\n \"preface\",\n \"notices\",\n \"dedication\",\n \"colophon\",\n \"amendments\",\n ],\n // `navtitle` sits in both buckets on purpose, because DITA spells it either\n // way. The element form wins: `headingOf` asks `titleOf` first, so\n // `@navtitle` is read only when the entry has no `<topicmeta><navtitle>`.\n titles: [\"title\", \"navtitle\", \"mainbooktitle\"],\n titleAttributes: [\"navtitle\"],\n titleWrappers: [\"topicmeta\", \"booktitle\"],\n untitledSections: true,\n transparent: [\n \"topicgroup\",\n \"topicmeta\",\n \"frontmatter\",\n \"backmatter\",\n \"booklists\",\n ],\n paragraphs: [\"shortdesc\", \"linktext\"],\n code: [],\n codeLangAttributes: [],\n unorderedLists: [],\n orderedLists: [],\n listItems: [],\n};\n\n/**\n * The vocabularies tried, in declaration order (which breaks scoring ties).\n * Exported so a bespoke schema is an array entry rather than a fork.\n */\nexport const XML_VOCABULARIES: readonly XmlVocabulary[] = [\n DITA,\n DOCBOOK,\n DITAMAP,\n];\n\n/** Precomputed lookups for one vocabulary. */\ninterface Compiled {\n vocab: XmlVocabulary;\n sections: Set<string>;\n titles: Set<string>;\n titleWrappers: Set<string>;\n transparent: Set<string>;\n paragraphs: Set<string>;\n code: Set<string>;\n unordered: Set<string>;\n ordered: Set<string>;\n items: Set<string>;\n tables: Set<string>;\n tableRows: Set<string>;\n tableCells: Set<string>;\n tableHeaderWrappers: Set<string>;\n tableHeaderRows: Set<string>;\n admonitions: Set<string>;\n images: Set<string>;\n imageDataElements: Set<string>;\n imageAltElements: Set<string>;\n blockquotes: Set<string>;\n definitionLists: Set<string>;\n definitionItems: Set<string>;\n definitionTerms: Set<string>;\n definitionBodies: Set<string>;\n /** Every name the vocabulary claims, for scoring. */\n known: Set<string>;\n}\n\nconst lower = (names: readonly string[] = []): Set<string> =>\n new Set(names.map((n) => n.toLowerCase()));\n\nfunction compile(vocab: XmlVocabulary): Compiled {\n const c: Compiled = {\n vocab,\n sections: lower(vocab.sections),\n titles: lower(vocab.titles),\n titleWrappers: lower(vocab.titleWrappers),\n transparent: lower(vocab.transparent),\n paragraphs: lower(vocab.paragraphs),\n code: lower(vocab.code),\n unordered: lower(vocab.unorderedLists),\n ordered: lower(vocab.orderedLists),\n items: lower(vocab.listItems),\n tables: lower(vocab.tables),\n tableRows: lower(vocab.tableRows),\n tableCells: lower(vocab.tableCells),\n tableHeaderWrappers: lower(vocab.tableHeaderWrappers),\n tableHeaderRows: lower(vocab.tableHeaderRows),\n admonitions: lower(vocab.admonitions),\n images: lower(vocab.images),\n imageDataElements: lower(vocab.imageDataElements),\n imageAltElements: lower(vocab.imageAltElements),\n blockquotes: lower(vocab.blockquotes),\n definitionLists: lower(vocab.definitionLists),\n definitionItems: lower(vocab.definitionItems),\n definitionTerms: lower(vocab.definitionTerms),\n definitionBodies: lower(vocab.definitionBodies),\n known: new Set(),\n };\n for (const set of [\n c.sections,\n c.titles,\n c.titleWrappers,\n c.transparent,\n c.paragraphs,\n c.code,\n c.unordered,\n c.ordered,\n c.items,\n c.tables,\n c.tableRows,\n c.tableCells,\n c.tableHeaderWrappers,\n c.tableHeaderRows,\n c.admonitions,\n c.images,\n c.imageDataElements,\n c.imageAltElements,\n c.blockquotes,\n c.definitionLists,\n c.definitionItems,\n c.definitionTerms,\n c.definitionBodies,\n ]) {\n for (const name of set) c.known.add(name);\n }\n return c;\n}\n\nconst ELEMENT_NODE = 1;\n\n/** Lowercased local name, prefix and namespace discarded. */\nfunction localName(node: XmlNode): string {\n const el = node as XmlElement;\n const name = el.localName ?? node.nodeName.split(\":\").pop() ?? node.nodeName;\n return name.toLowerCase();\n}\n\nfunction* elementChildren(el: XmlNode): Generator<XmlElement> {\n for (let child = el.firstChild; child; child = child.nextSibling) {\n if (child.nodeType === ELEMENT_NODE) yield child as XmlElement;\n }\n}\n\n/** First direct child matching one of `names`, or null. */\nfunction findDirectChild(el: XmlElement, names: Set<string>): XmlElement | null {\n for (const child of elementChildren(el)) {\n if (names.has(localName(child))) return child;\n }\n return null;\n}\n\n/** First descendant matching one of `names`, in document order, or null. */\nfunction findDescendant(el: XmlElement, names: Set<string>): XmlElement | null {\n for (const child of elementChildren(el)) {\n if (names.has(localName(child))) return child;\n const nested = findDescendant(child, names);\n if (nested) return nested;\n }\n return null;\n}\n\n/** Collapse XML's indentation whitespace into the single spaces a reader sees. */\nfunction flatten(text: string | null): string {\n return (text ?? \"\").replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * A code block's text, minus the layout the source added around it: the newline\n * that follows the start tag when the code is on its own line, and the\n * indentation before the end tag. Everything between is significant and is left\n * exactly as written, which is what mdast does with a fenced block's value.\n */\nfunction codeText(text: string | null): string {\n return (text ?? \"\").replace(/^[^\\S\\n]*\\n/, \"\").replace(/\\n[^\\S\\n]*$/, \"\");\n}\n\n/** The six variants `AdmonitionNode` knows. A name outside this set names no variant. */\ntype Variant = Exclude<AdmonitionNode[\"variant\"], undefined>;\nconst ADMONITION_VARIANTS = new Set<Variant>([\n \"note\",\n \"tip\",\n \"important\",\n \"caution\",\n \"warning\",\n \"danger\",\n]);\n\nfunction isAdmonitionVariant(name: string): name is Variant {\n return (ADMONITION_VARIANTS as ReadonlySet<string>).has(name);\n}\n\n/** Weights for `chooseVocabulary`, in the order they are meant to dominate. */\nconst NAMESPACE_MATCH = 1000;\nconst EXCLUSIVE_ELEMENT = 10;\nconst ROOT_NAME = 5;\nconst SHARED_ELEMENT = 1;\n\n/**\n * Score every vocabulary against the document and take the best.\n *\n * A namespace match on the root is decisive: a document that declares its\n * namespace has already said what it is. Failing that, what counts is elements\n * only one candidate claims - `<para>` and `<programlisting>` are DocBook's\n * alone, `<p>` and `<taskbody>` DITA's - because those are the ones whose\n * presence is an argument. Elements the candidates share (`<section>`,\n * `<title>`) are worth a point as a tiebreak and no more, since they are\n * evidence for everyone and therefore for no one.\n *\n * The root element name is weaker still, and deliberately weaker than a single\n * exclusive element. `<section>` is a DocBook root, so a bare `<section>` whose\n * prose is in `<p>` would otherwise be read as DocBook - and every `<p>` in it\n * would then be an unmapped element, silently skipped, leaving a titled section\n * with no content and no complaint. One `<p>` is better evidence about what a\n * file is than the name of its outermost tag.\n */\nfunction chooseVocabulary(\n root: XmlElement,\n compiled: Compiled[],\n): { best: Compiled; score: number } {\n const counts = new Map<string, number>();\n const tally = (node: XmlNode): void => {\n for (const child of elementChildren(node)) {\n const name = localName(child);\n counts.set(name, (counts.get(name) ?? 0) + 1);\n tally(child);\n }\n };\n counts.set(localName(root), 1);\n tally(root);\n\n /** How many candidates claim each name; 1 means the name is decisive. */\n const claims = new Map<string, number>();\n for (const c of compiled) {\n for (const name of c.known) claims.set(name, (claims.get(name) ?? 0) + 1);\n }\n\n const ns = (root.namespaceURI ?? \"\").toLowerCase();\n const rootName = localName(root);\n\n let best: Compiled | undefined;\n let bestScore = -1;\n for (const c of compiled) {\n let score = 0;\n if (ns && c.vocab.namespaces.some((u) => u.toLowerCase() === ns)) {\n score += NAMESPACE_MATCH;\n }\n if (lower(c.vocab.roots).has(rootName)) score += ROOT_NAME;\n for (const [name, n] of counts) {\n if (!c.known.has(name)) continue;\n score += n * (claims.get(name) === 1 ? EXCLUSIVE_ELEMENT : SHARED_ELEMENT);\n }\n if (score > bestScore) {\n best = c;\n bestScore = score;\n }\n }\n if (!best) {\n // The vocabulary list is the registry's own and is never empty; the loop\n // assigns on its first pass, because every score beats the -1 it starts\n // from. Saying so out loud beats returning a vocabulary nobody chose.\n throw new LintError(\"No XML vocabularies are registered.\");\n }\n return { best, score: bestScore };\n}\n\n/**\n * Line/column -> offset, over the content as it was read.\n *\n * xmldom normalizes line endings before parsing, so its line and column are\n * against a LF-only copy. Line *numbers* survive that normalization unchanged\n * and CRLF only ever differs at a line terminator, so indexing the original\n * content's line starts with xmldom's (line, column) lands on the same\n * character - which is what keeps `offset` an index into the file the reporter\n * will quote, not into a normalized copy of it.\n */\nclass SourceMap {\n private readonly lineStarts: number[] = [0];\n /** Byte-order mark length, added back to every offset. */\n private readonly bom: number;\n private readonly body: string;\n readonly docEnd: Point;\n\n constructor(content: string) {\n this.bom = content.charCodeAt(0) === 0xfeff ? 1 : 0;\n this.body = content.slice(this.bom);\n for (let i = 0; i < this.body.length; i++) {\n const ch = this.body[i];\n if (ch === \"\\n\") this.lineStarts.push(i + 1);\n else if (ch === \"\\r\") {\n if (this.body[i + 1] === \"\\n\") i++;\n this.lineStarts.push(i + 1);\n }\n }\n // `lineStarts` opens with 0 and is only ever appended to, so the fallback\n // is unreachable - and it is the start of the one and only line anyway.\n const lastStart = this.lineStarts.at(-1) ?? 0;\n this.docEnd = {\n line: this.lineStarts.length,\n column: this.body.length - lastStart + 1,\n offset: content.length,\n };\n }\n\n /** The source text, for the parser to hand to xmldom without the BOM. */\n get text(): string {\n return this.body;\n }\n\n /** Start point of a node, or null when the locator recorded none. */\n point(node: XmlNode | null | undefined): Point | null {\n if (!node) return null;\n const line = node.lineNumber;\n const column = node.columnNumber;\n if (typeof line !== \"number\" || typeof column !== \"number\") return null;\n const start = this.lineStarts[line - 1];\n if (start === undefined) return null;\n const offset = Math.min(start + column - 1, this.body.length) + this.bom;\n return { line, column, offset };\n }\n\n /** End of the line a point sits on, exclusive of its terminator. */\n endOfLine(line: number): Point {\n const start = this.lineStarts[line - 1];\n if (start === undefined) return { ...this.docEnd };\n const next = this.lineStarts[line];\n const end = next === undefined ? this.body.length : next - 1;\n return { line, column: end - start + 1, offset: end + this.bom };\n }\n}\n\n/**\n * The exclusive end of an element: where the next node in document order\n * starts. Whitespace text nodes carry positions too, so for indented XML that\n * is the character immediately after `</tag>`.\n */\nfunction nextInDocumentOrder(el: XmlNode): XmlNode | null {\n let node: XmlNode = el;\n for (;;) {\n if (node.nextSibling) return node.nextSibling;\n const parent: XmlNode | null = node.parentNode;\n if (!parent || parent.nodeType !== ELEMENT_NODE) return null;\n node = parent;\n }\n}\n\n/** Flattens one document into ordered fragments under one vocabulary. */\nclass Flattener {\n readonly fragments: Fragment[] = [];\n\n constructor(\n private readonly c: Compiled,\n private readonly map: SourceMap,\n ) {}\n\n private span(el: XmlNode): Position {\n const start = this.map.point(el) ?? { ...this.map.docEnd };\n const end =\n this.map.point(nextInDocumentOrder(el)) ?? { ...this.map.docEnd };\n // A malformed locator (or an element that ends the document) must never\n // produce a backwards span; rules sort findings by offset.\n return end.offset < start.offset ? { start, end: { ...start } } : { start, end };\n }\n\n /** The title element of a section container, direct or inside a wrapper. */\n private titleOf(el: XmlElement): XmlElement | null {\n for (const child of elementChildren(el)) {\n if (this.c.titles.has(localName(child))) return child;\n }\n for (const child of elementChildren(el)) {\n if (!this.c.titleWrappers.has(localName(child))) continue;\n for (const inner of elementChildren(child)) {\n if (this.c.titles.has(localName(inner))) return inner;\n }\n }\n return null;\n }\n\n /**\n * The exclusive end of an element's start tag: where its first child begins,\n * which for indented XML is the character right after `>`. A childless\n * element has no such node and falls back to the end of the element, which\n * for `<topicref keyref=\"a\"/>` is the same character anyway.\n */\n private startTagEnd(el: XmlElement): Point {\n return this.map.point(el.firstChild) ?? this.span(el).end;\n }\n\n /**\n * The heading a section container carries: its text, and where the heading\n * ends. A `titles` element ends it at its own end. An attribute title and an\n * absent one both end it at the end of the start tag, since neither has a\n * position and anything further would swallow a nested section's heading.\n * Null when the vocabulary says an untitled container is not a section.\n */\n private headingOf(el: XmlElement): { title: string; end: Point } | null {\n const title = this.titleOf(el);\n if (title) {\n return { title: flatten(title.textContent), end: this.span(title).end };\n }\n for (const attr of this.c.vocab.titleAttributes ?? []) {\n const value = el.getAttribute(attr);\n if (value) return { title: flatten(value), end: this.startTagEnd(el) };\n }\n if (this.c.vocab.untitledSections) {\n return { title: \"\", end: this.startTagEnd(el) };\n }\n return null;\n }\n\n /** Walk one element: section, wrapper, content, or skipped subtree. */\n visit(el: XmlElement, level: number): void {\n const name = localName(el);\n\n if (this.c.sections.has(name)) {\n const heading = this.headingOf(el);\n if (!heading) {\n // An untitled section container adds no heading, so it adds no level\n // either; its content belongs to the section that encloses it.\n this.walkChildren(el, level);\n return;\n }\n const next = Math.min(level + 1, 6);\n this.fragments.push({\n type: \"heading\",\n level: next,\n title: heading.title,\n // From the container's start tag through the end of its title: the\n // container is the section, so a section that began at its `<title>`\n // would leave its own opening tag outside itself and stop adjacent\n // sections from tiling the document.\n position: { start: this.span(el).start, end: heading.end },\n });\n this.walkChildren(el, next);\n return;\n }\n\n if (this.c.transparent.has(name)) {\n this.walkChildren(el, level);\n return;\n }\n\n const node = this.content(el);\n if (node) this.fragments.push({ type: \"content\", node });\n // Unmapped: skipped with its subtree, like a Markdown blockquote.\n }\n\n private walkChildren(el: XmlElement, level: number): void {\n for (const child of elementChildren(el)) this.visit(child, level);\n }\n\n /** One element as a content node, or null when it is not one. */\n private content(el: XmlElement): ContentNode | null {\n const name = localName(el);\n const position = this.span(el);\n\n if (this.c.paragraphs.has(name)) {\n return { kind: \"paragraph\", position, text: flatten(el.textContent) };\n }\n\n if (this.c.code.has(name)) {\n const lang = this.langOf(el);\n return {\n kind: \"codeBlock\",\n position,\n text: codeText(el.textContent),\n ...(lang ? { language: lang } : {}),\n };\n }\n\n const ordered = this.c.ordered.has(name);\n if (ordered || this.c.unordered.has(name)) {\n return {\n kind: \"list\",\n position,\n text: flatten(el.textContent),\n ordered,\n items: [...elementChildren(el)]\n .filter((item) => this.c.items.has(localName(item)))\n .map((item): ListItemNode => ({\n kind: \"listItem\",\n position: this.span(item),\n text: flatten(item.textContent),\n children: this.blockContent(item),\n })),\n };\n }\n\n if (this.c.tables.has(name)) return this.tableNode(el, position);\n\n if (this.c.admonitions.has(name)) {\n const variant = this.admonitionVariantOf(el, name);\n return {\n kind: \"admonition\",\n position,\n text: flatten(el.textContent),\n // A `@type`/name outside the six variants `AdmonitionNode` knows\n // leaves `variant` unset, rather than inventing an equivalence.\n ...(variant ? { variant } : {}),\n children: this.blockContent(el),\n };\n }\n\n if (this.c.images.has(name)) return this.imageNode(el, position);\n\n if (this.c.blockquotes.has(name)) {\n return {\n kind: \"blockquote\",\n position,\n text: flatten(el.textContent),\n children: this.blockContent(el),\n };\n }\n\n if (this.c.definitionLists.has(name)) return this.definitionListNode(el, position);\n\n return null;\n }\n\n /** A table's rows, from any of its CALS wrappers (`tgroup`, `tbody`, `thead`). */\n private tableNode(el: XmlElement, position: Position): TableNode {\n return {\n kind: \"table\",\n position,\n text: flatten(el.textContent),\n children: this.tableRowsOf(el, false),\n };\n }\n\n /**\n * Rows found anywhere under `el`, recursing through every wrapper - `tgroup`,\n * `tbody`, `thead` and the like - regardless of whether it is known\n * elsewhere. A table's internal grouping elements carry no content of their\n * own; only the rows and cells inside them do.\n *\n * `inheritedHeader` tracks whether an enclosing `tableHeaderWrappers` element\n * (CALS's `<thead>`) has been entered; `tableHeaderRows` (DITA's `<sthead>`)\n * marks a row as a header on its own, without a wrapper.\n */\n private tableRowsOf(el: XmlElement, inheritedHeader: boolean): TableRowNode[] {\n const rows: TableRowNode[] = [];\n for (const child of elementChildren(el)) {\n const name = localName(child);\n if (this.c.tableRows.has(name)) {\n rows.push(this.tableRow(child, inheritedHeader || this.c.tableHeaderRows.has(name)));\n continue;\n }\n rows.push(\n ...this.tableRowsOf(child, inheritedHeader || this.c.tableHeaderWrappers.has(name)),\n );\n }\n return rows;\n }\n\n private tableRow(el: XmlElement, header: boolean): TableRowNode {\n const cells: TableCellNode[] = [];\n for (const child of elementChildren(el)) {\n if (!this.c.tableCells.has(localName(child))) continue;\n cells.push({\n kind: \"tableCell\",\n position: this.span(child),\n text: flatten(child.textContent),\n children: this.blockContent(child),\n });\n }\n return {\n kind: \"tableRow\",\n position: this.span(el),\n text: flatten(el.textContent),\n header,\n children: cells,\n };\n }\n\n /**\n * An admonition's variant: the value of `admonitionVariantAttribute` when the\n * vocabulary names one (DITA's `<note type>`, defaulting to `note` when the\n * attribute is absent - DITA's own default), or the element's own lowercased\n * name otherwise (DocBook's `<warning>`, `<tip>`, and so on). Undefined when\n * neither names one of the six variants `AdmonitionNode` knows.\n */\n private admonitionVariantOf(el: XmlElement, name: string): Variant | undefined {\n const attr = this.c.vocab.admonitionVariantAttribute;\n const raw = (attr ? el.getAttribute(attr) : \"\") || name;\n const variant = raw.toLowerCase();\n return isAdmonitionVariant(variant) ? variant : undefined;\n }\n\n /**\n * An image, standing alone or wrapping one. `imageDataElements` names the\n * element carrying the url - `el` itself for a self-contained image (DITA's\n * `<image href>`), or a descendant found by name otherwise (DocBook's\n * `<imagedata fileref>` inside a `<mediaobject>`/`<figure>`). The caption\n * reuses `titleOf`, the same lookup a section uses for its heading - DITA's\n * `<fig><title>` and DocBook's `<figure><title>` are both a direct `<title>`\n * child.\n */\n private imageNode(el: XmlElement, position: Position): ImageNode {\n const name = localName(el);\n const dataEl = this.c.imageDataElements.has(name)\n ? el\n : findDescendant(el, this.c.imageDataElements);\n const attr = this.c.vocab.imageUrlAttribute;\n const url = (dataEl && attr ? dataEl.getAttribute(attr) : \"\") || \"\";\n const altEl = dataEl ? findDirectChild(dataEl, this.c.imageAltElements) : null;\n const title = this.titleOf(el);\n return {\n kind: \"image\",\n position,\n text: flatten(el.textContent),\n url,\n alt: altEl ? flatten(altEl.textContent) : \"\",\n ...(title ? { title: flatten(title.textContent) } : {}),\n };\n }\n\n private definitionListNode(el: XmlElement, position: Position): DefinitionListNode {\n const children: DefinitionItemNode[] = [];\n for (const child of elementChildren(el)) {\n if (this.c.definitionItems.has(localName(child))) {\n children.push(this.definitionItem(child));\n }\n }\n return {\n kind: \"definitionList\",\n position,\n text: flatten(el.textContent),\n children,\n };\n }\n\n /** One entry, pairing its term(s) - joined with \", \" when more than one - with its definition body. */\n private definitionItem(el: XmlElement): DefinitionItemNode {\n const terms: string[] = [];\n let body: XmlElement | null = null;\n for (const child of elementChildren(el)) {\n const name = localName(child);\n if (this.c.definitionTerms.has(name)) {\n terms.push(flatten(child.textContent));\n } else if (body === null && this.c.definitionBodies.has(name)) {\n body = child;\n }\n }\n return {\n kind: \"definitionItem\",\n position: this.span(el),\n text: flatten(el.textContent),\n term: terms.join(\", \"),\n definition: body ? this.blockContent(body) : [],\n };\n }\n\n /**\n * One container's content, with its own loose prose kept as a paragraph.\n * Shared by list items, table cells, admonitions, block quotes, and a\n * definition's body - anywhere the content model asks for a container's\n * `children` rather than a single block.\n *\n * mdast puts a list item's principal text in a `paragraph` child regardless\n * of markup, and `lists: {items: {paragraphs: {min: 1}}}` has to count the\n * same thing in every format. So the loose text is gathered into one, in the\n * position it occupies among the container's blocks.\n *\n * Gathering it rather than checking whether the container has any children is\n * what makes the two cases agree. `<li>bare text</li>` was already\n * reconciled; `<li>Parent<ul>…</ul></li>` was not, because the nested list is\n * a child, so the item looked accounted for and `Parent` became prose\n * nothing counted - while its Markdown, HTML, AsciiDoc, and reST twins all\n * counted one. This is the same fix `html.ts` carries, and the two should\n * stay in step.\n *\n * Unmapped elements contribute their text rather than being skipped, which is\n * what the old whole-item `textContent` did: inside a container they are\n * inline markup - DITA's `<b>`, `<xref>` - not structure worth dropping.\n */\n private blockContent(container: XmlElement): ContentNode[] {\n const out: ContentNode[] = [];\n let text = \"\";\n\n const flush = (): void => {\n const value = flatten(text);\n text = \"\";\n if (value.length === 0) return;\n out.push({ kind: \"paragraph\", position: this.span(container), text: value });\n };\n\n for (let child = container.firstChild; child; child = child.nextSibling) {\n if (child.nodeType !== ELEMENT_NODE) {\n text += child.nodeValue ?? \"\";\n continue;\n }\n\n const el = child as XmlElement;\n const nested = this.c.transparent.has(localName(el))\n ? this.contentChildren(el)\n : [this.content(el)].filter((n): n is ContentNode => n !== null);\n\n if (nested.length > 0) {\n flush();\n out.push(...nested);\n continue;\n }\n text += el.textContent ?? \"\";\n }\n\n flush();\n return out;\n }\n\n private contentChildren(el: XmlElement): ContentNode[] {\n const out: ContentNode[] = [];\n for (const child of elementChildren(el)) {\n if (this.c.transparent.has(localName(child))) {\n out.push(...this.contentChildren(child));\n continue;\n }\n const node = this.content(child);\n if (node) out.push(node);\n }\n return out;\n }\n\n /** A code block's language, with a `language-` prefix stripped. */\n private langOf(el: XmlElement): string | undefined {\n for (const attr of this.c.vocab.codeLangAttributes) {\n const value = el.getAttribute(attr);\n if (value) return value.replace(/^language-/, \"\");\n }\n return undefined;\n }\n}\n\n/**\n * Parse, refusing anything xmldom had to guess at.\n *\n * xmldom is lenient: it throws only on a `fatalError`, and reports `error` and\n * `warning` through the handler while carrying on with a repaired tree. The\n * line between them is drawn at `error` because in XML the element tree *is*\n * the structure - there is no second signal like a `##` to fall back on - so\n * linting a tree xmldom guessed at reports on a document nobody wrote. A\n * mismatched end tag or a stray `<` puts every following element at the wrong\n * depth, and the findings would be confident nonsense. `warning` is left alone:\n * xmldom recovers from an unquoted attribute value without changing the element\n * tree at all, and attributes here are metadata, not structure.\n *\n * This is also the line docmeta's XML extractor draws, so a file manni lint\n * lints is exactly a file docmeta will read metadata from.\n */\nfunction parseDocument(source: string, filePath: string): XmlElement {\n const problems: string[] = [];\n let doc;\n try {\n doc = new DOMParser({\n onError: (level, message) => {\n if (level === \"error\" || level === \"fatalError\") problems.push(message);\n },\n }).parseFromString(source, \"text/xml\");\n } catch (err) {\n const detail = problems[0] ?? errorMessage(err);\n throw new LintError(\n `${filePath}: could not parse as XML: ${firstLine(detail)}`,\n );\n }\n\n const [firstProblem] = problems;\n if (firstProblem !== undefined) {\n throw new LintError(\n `${filePath}: could not parse as XML: ${firstLine(firstProblem)}`,\n );\n }\n\n const root = doc.documentElement;\n if (!root) {\n throw new LintError(`${filePath}: could not parse as XML: no root element`);\n }\n return root;\n}\n\n/** xmldom appends the offending source to some messages; one line is enough. */\nfunction firstLine(message: string): string {\n const [first] = message.split(\"\\n\");\n return (first ?? message).trim();\n}\n\n/**\n * Metadata for routing, from docmeta.\n *\n * **Not `extractFrontmatter`.** `src/parsers/markdown.ts` calls it because for\n * Markdown it is the whole story, but in docmeta that function is specifically\n * the *fenced* `---` block reader (\"core front matter extraction shared by the\n * markdown, mdx, adoc, rst formats\"). An XML file has no fenced block, so\n * `extractFrontmatter(content, \"xml\")` returns `{ data: {}, present: false }`\n * for every XML document ever written, and `type:` routing for `.xml` would\n * silently never fire. docmeta's *registry* is the right door: its XML\n * extractor reads the root element's attributes (`<task type=\"how-to\">` ->\n * `{ type: \"how-to\" }`, minus `xmlns*`, with values parsed as YAML scalars)\n * plus the text of simple direct children as dotted keys (`task.title`). That\n * is a real `type`, so an `.xml` page does route.\n *\n * The HTML parser merges a fenced block with its native reading, fenced\n * winning a collision. This one does not, because an `.xml` file cannot carry a\n * fenced block and still be XML: a leading `---` is character data outside the\n * root element, which xmldom reports as an error and `parseDocument` refuses\n * before metadata is ever read. (HTML has no such rule - a comment or stray\n * text before `<html>` parses fine - which is why the merge is right there and\n * would be unreachable code here.)\n *\n * It throws on malformed XML, the same line `parseDocument` draws, but it is\n * called after the parse so in practice it cannot be the one to complain.\n */\nfunction readMetadata(\n content: string,\n filePath: string,\n): Record<string, unknown> | null {\n const extractor = extractorForExtension(\".xml\");\n if (!extractor) return null;\n try {\n const meta = extractor.extract(content, filePath);\n return meta.present ? meta.data : null;\n } catch (err) {\n throw new LintError(\n `${filePath}: could not read XML metadata: ${firstLine(errorMessage(err))}`,\n );\n }\n}\n\n/**\n * Note on the frontmatter-title rule.\n *\n * `withFrontmatterTitle` in the Markdown parser synthesizes an H1 from\n * `title:` when the body has none, because Docusaurus and Hugo render the page\n * title from frontmatter and their pages legitimately start at `##`. That\n * reasoning does not carry to XML and the rule is deliberately not applied\n * here. An XML document's title is an element - `<title>` - in the body, in\n * document order, exactly where the section fold already looks for it; there is\n * no publishing convention that moves it out. And what docmeta calls this\n * document's \"frontmatter\" is the *root element's own attributes*, so a `title`\n * attribute would be a second title on the very element that already carries\n * the real one: synthesizing a section from it would nest the document's actual\n * title underneath a duplicate of itself. A document with no title element at\n * all is not a page missing its H1, it is a document with no structure to lint,\n * and `parseXml` says so.\n */\n\n/**\n * Parse XML into the generic tree.\n *\n * @param vocabularies Overrides the built-ins; the extension point for a\n * bespoke schema until there is a config surface for it.\n */\nexport function parseXml(\n content: string,\n filePath: string,\n vocabularies: readonly XmlVocabulary[] = XML_VOCABULARIES,\n): DocumentTree {\n const map = new SourceMap(content);\n const root = parseDocument(map.text, filePath);\n\n const compiled = vocabularies.map(compile);\n if (compiled.length === 0) {\n throw new LintError(`${filePath}: no XML vocabularies are configured.`);\n }\n\n const { best, score } = chooseVocabulary(root, compiled);\n const names = compiled.map((c) => c.vocab.label).join(\", \");\n\n // Nothing recognized is an error rather than an empty tree. An empty tree\n // would lint as a document that is missing every section its template asks\n // for - a cascade of findings that says nothing about the page and points\n // nowhere useful. The gap is in the mapping, and this is where to say so.\n if (score <= 0) {\n throw new LintError(\n `${filePath}: no known XML vocabulary matched <${localName(root)}>. ` +\n `manni lint understands ${names}; add an entry to XML_VOCABULARIES ` +\n `in src/parsers/xml.ts to describe another schema.`,\n );\n }\n\n const flattener = new Flattener(best, map);\n flattener.visit(root, 0);\n const fragments = flattener.fragments;\n\n if (!fragments.some((b) => b.type === \"heading\")) {\n throw new LintError(\n `${filePath}: read as ${best.vocab.label}, but no titled section was found. ` +\n `A ${best.vocab.label} section is one of <${best.vocab.sections.join(\">, <\")}> ` +\n `carrying a <${best.vocab.titles.join(\">/<\")}>; without one the document has ` +\n `no structure to check.`,\n );\n }\n\n const frontmatter = readMetadata(content, filePath);\n\n return {\n format: \"xml\",\n filePath,\n frontmatter,\n // The metadata block is the root element's start tag: from its `<` to the\n // character after its `>`, which is where its first child begins.\n frontmatterPosition: frontmatter\n ? {\n start: map.point(root) ?? { ...map.docEnd },\n end:\n map.point(root.firstChild) ??\n map.endOfLine(map.point(root)?.line ?? 1),\n }\n : null,\n sections: sectionize(fragments, map.docEnd),\n };\n}\n\nexport const xmlParser: DocumentParser = {\n name: \"xml\",\n label: \"XML\",\n kinds: [\n \"paragraph\",\n \"codeBlock\",\n \"list\",\n \"listItem\",\n \"table\",\n \"tableRow\",\n \"tableCell\",\n \"admonition\",\n \"image\",\n \"blockquote\",\n \"definitionList\",\n \"definitionItem\",\n ],\n /**\n * `.dita` and `.ditamap` as well as `.xml`, because that is what a DITA topic\n * and a DITA map are actually called on disk and docmeta registers both — a\n * docset whose topics this parser was written for would otherwise be walked\n * past entirely.\n *\n * A map carries no prose, but it is a tree of navigation entries, and that is\n * the same thing a section tree is: `<topicref>` nesting is section nesting.\n * A docset of maps with no map template matches nothing and is skipped as\n * `no-template`, exactly as an untyped Markdown page is.\n */\n extensions: [\".xml\", \".dita\", \".ditamap\"],\n /**\n * A directory walk collects `.dita` and `.ditamap` but not `.xml`. Both of\n * those are documentation by definition; `.xml` is a container a repository\n * uses for build files, sitemaps, and project metadata, none of which match a\n * documentation vocabulary. Sweeping those in made one `pom.xml` fail an\n * otherwise clean tree. Naming an `.xml` file explicitly still parses it.\n */\n walkExtensions: [\".dita\", \".ditamap\"],\n parse: (content, filePath) => parseXml(content, filePath),\n};\n","/**\n * AsciiDoc parser.\n *\n * Asciidoctor already hands back a nested block tree, so the work here is the\n * same as `mdast.ts`'s: flatten it into ordered `Fragment`s and let `sectionize`\n * rebuild the nesting. `table`, `admonition`, `image`, `quote` and `dlist`\n * contexts map onto the shared content model (proposal 0065); a context that\n * still has no kind there - `sidebar`, a thematic break, `verse`, `example`,\n * and so on - is skipped whole rather than mapped to a nearest neighbour, for\n * the reason the Markdown parser skips a construct it does not model: a\n * sidebar is not a paragraph, and counting one as such would make\n * `paragraphs: {max: 3}` fail a document a reader would say satisfies it.\n *\n * Two things about Asciidoctor shape this file:\n *\n * - **Positions come from line numbers, and only line numbers.** `load()` is\n * given `sourcemap: true` so every block carries `getLineNumber()`; nothing\n * reports where a block *ends*, and there are no columns or offsets at all.\n * Those are derived from a line-start index built once over the content.\n * The pre-rewrite `parsers/asciidoc.js` instead reconstructed a `=== Title`\n * marker and ran `content.indexOf()` on it, which mismatches on attribute\n * lines, duplicate titles, and any non-canonical heading syntax.\n * - **Metadata arrives two ways.** AsciiDoc's own is the document header -\n * `= Title` plus `:key: value` entries - and that is how a real page says\n * `:type: how-to`. Some toolchains prepend a Markdown-style `---` fence\n * instead, which is a thematic break to Asciidoctor, so `skip-front-matter`\n * consumes it rather than letting it parse as body content; line numbering\n * is unaffected, so the body still indexes the original file. Both readings\n * run, and the results merge.\n */\nimport asciidoctor from \"@asciidoctor/core\";\nimport { extractFrontmatter, extractorForExtension } from \"../../meta/index.js\";\nimport type {\n AdmonitionNode,\n ContentNode,\n DefinitionItemNode,\n DocumentParser,\n DocumentTree,\n ListItemNode,\n Point,\n Position,\n TableCellNode,\n TableRowNode,\n} from \"../types.js\";\nimport { LintError } from \"../types.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport type { Fragment } from \"./sectionize.js\";\nimport { sectionize } from \"./sectionize.js\";\nimport {\n fencedPosition,\n withMetadataTitle as withFrontmatterTitle,\n withoutFence,\n} from \"./metadata.js\";\n\n/**\n * `@asciidoctor/core`, not the `asciidoctor` meta-package.\n *\n * Only the parser is wanted here. The meta-package adds `@asciidoctor/cli`\n * (and yargs) plus the ejs, nunjucks and pug template engines, none of which\n * this file can reach - 63 lockfile entries that installed with manni so that\n * one `.adoc` file could be read. The core is the same Asciidoctor at the same\n * version, published as a real ESM module, so the default import is the\n * factory with no CJS interop to undo.\n *\n * Stay on 3.x. `@asciidoctor/core@4` is a rewrite whose `load()` returns a\n * promise, and `DocumentParser.parse` is synchronous for every format. Moving\n * to it would also drop `@asciidoctor/opal-runtime` and with it the deprecated\n * `glob`/`inflight` pair, which 3.x still brings in on its own.\n */\nconst processor = asciidoctor();\n\n/**\n * Minimal structural view of an Asciidoctor node.\n *\n * `getBlocks()` is typed `any[]` upstream and is not even homogeneous - a\n * description list returns `[[terms], description]` tuples rather than nodes -\n * so everything is read back through `asNode`, which checks for the one method\n * every real block has.\n */\ninterface AdocNode {\n getContext(): string;\n getLineNumber?(): number | undefined;\n getBlocks?(): unknown[];\n getLevel?(): number;\n getTitle?(): string | undefined;\n getSource?(): string;\n getContent?(): string;\n getAttribute?(name: string): unknown;\n getItems?(): unknown[];\n getRows?(): AdocRows;\n}\n\n/** A list item. Its principal text is not among its blocks. */\ninterface AdocItem {\n getLineNumber?(): number | undefined;\n getText(): string;\n getBlocks(): unknown[];\n}\n\n/** A table cell, from either a head, body or foot row. */\ninterface AdocCell {\n getLineNumber?(): number | undefined;\n getText(): string;\n}\n\n/** `Table#getRows()`'s own shape: the three row groups, each an array of cell rows. */\ninterface AdocRows {\n getHead(): AdocCell[][];\n getBody(): AdocCell[][];\n getFoot(): AdocCell[][];\n}\n\ninterface AdocDocument extends AdocNode {\n hasHeader(): boolean;\n getHeader(): unknown;\n}\n\nfunction asNode(value: unknown): AdocNode | null {\n const node = value as AdocNode | null;\n return node && typeof node.getContext === \"function\" ? node : null;\n}\n\nfunction asItem(value: unknown): AdocItem | null {\n const item = value as AdocItem | null;\n return item && typeof item.getText === \"function\" ? item : null;\n}\n\n/** Blocks of a container, filtered down to the ones that really are nodes. */\nfunction childrenOf(node: AdocNode): AdocNode[] {\n const blocks = node.getBlocks?.() ?? [];\n return blocks.map(asNode).filter((n): n is AdocNode => n !== null);\n}\n\nfunction lineOf(node: { getLineNumber?(): number | undefined }): number {\n return node.getLineNumber?.() ?? 1;\n}\n\n// ---------------------------------------------------------------------------\n// Positions\n// ---------------------------------------------------------------------------\n\n/**\n * Line numbers to `Point`s.\n *\n * The offsets a reporter prints, and the offsets `validateDocument` sorts\n * findings by, do not exist anywhere in Asciidoctor's output. They are all\n * recovered from one pass over the content that records where each line\n * starts, so a lookup is an array index rather than a search through the text.\n */\ninterface LineIndex {\n /** Column 1 of `line`. */\n start(line: number): Point;\n /** Just past the last character of `line`, before its line break. */\n endOfLine(line: number): Point;\n /** End of the document, for closing the final sections. */\n documentEnd(): Point;\n}\n\nfunction lineIndex(content: string): LineIndex {\n const starts: number[] = [0];\n for (let i = 0; i < content.length; i++) {\n if (content[i] === \"\\n\") starts.push(i + 1);\n }\n\n /** Line numbers come from a third-party tree; keep them inside the file. */\n const clamp = (line: number): number =>\n Math.min(Math.max(Math.trunc(line) || 1, 1), starts.length);\n\n /**\n * Offset of column 1 of a clamped line. `starts` opens with 0 and `clamp`\n * keeps the index inside it, so the fallback is unreachable - and 0 is where\n * a line clamped to 1 starts anyway.\n */\n const startOf = (n: number): number => starts[n - 1] ?? 0;\n\n return {\n start(line) {\n const n = clamp(line);\n return { line: n, column: 1, offset: startOf(n) };\n },\n endOfLine(line) {\n const n = clamp(line);\n const from = startOf(n);\n const next = starts[n];\n let stop = next === undefined ? content.length : next - 1;\n if (stop > from && content[stop - 1] === \"\\r\") stop -= 1;\n return { line: n, column: stop - from + 1, offset: stop };\n },\n documentEnd() {\n return {\n line: starts.length,\n column: content.length - startOf(starts.length) + 1,\n offset: content.length,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inline text\n// ---------------------------------------------------------------------------\n\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \" \",\n};\n\n/**\n * Asciidoctor's plain-text rendering, flattened.\n *\n * `getTitle()`, `getContent()`, and `ListItem#getText()` all return inline\n * *HTML*: a heading written with backtick-quoted `lint` comes back as\n * `Use the <code>lint</code> command`. Stripping the tags and decoding the\n * entities is this format's equivalent of `mdast-util-to-string`, and it is\n * what makes `heading: {const: \"Overview\"}` mean the same thing here as it does\n * in Markdown.\n *\n * The one place it is lossy is Asciidoctor's `replacements` substitution, which\n * fires before we ever see the string: a straight apostrophe arrives as\n * `&#8217;` and flattens to a curly one, where Markdown would leave it alone.\n * That is Asciidoctor's conversion, not ours, and it exposes no way to ask for\n * a title with quotes substituted but replacements skipped.\n */\nfunction flattenInline(html: string | undefined): string {\n if (!html) return \"\";\n return html\n .replace(/<[^>]*>/g, \"\")\n .replace(/&#(\\d+);/g, (_, dec: string) => String.fromCodePoint(Number(dec)))\n .replace(/&#x([0-9a-f]+);/gi, (_, hex: string) =>\n String.fromCodePoint(Number.parseInt(hex, 16)),\n )\n .replace(\n /&([a-z]+);/gi,\n (whole: string, name: string) => NAMED_ENTITIES[name.toLowerCase()] ?? whole,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Asciidoctor's tree -> drafts\n// ---------------------------------------------------------------------------\n\n/**\n * A block with a start line but no span yet.\n *\n * The walk cannot assign spans as it goes, because a block's end is the start\n * of whatever comes after it - which is only known once the whole document is\n * flat. So the walk emits drafts and `place` closes them.\n */\ntype Draft =\n | { kind: \"heading\"; line: number; level: number; title: string }\n | { kind: \"paragraph\"; line: number; text: string }\n | { kind: \"codeBlock\"; line: number; text: string; language?: string }\n | { kind: \"list\"; line: number; ordered: boolean; items: DraftItem[] }\n | { kind: \"table\"; line: number; rows: DraftRow[] }\n | {\n kind: \"admonition\";\n line: number;\n variant: AdmonitionNode[\"variant\"];\n children: Draft[];\n }\n | { kind: \"image\"; line: number; url: string; alt: string; title?: string }\n | { kind: \"blockquote\"; line: number; children: Draft[] }\n | { kind: \"definitionList\"; line: number; items: DraftDefinitionItem[] };\n\n/** Every draft but a heading, which is the only kind that is not content. */\ntype ContentDraft = Exclude<Draft, { kind: \"heading\" }>;\n\ninterface DraftItem {\n line: number;\n text: string;\n children: Draft[];\n}\n\ninterface DraftCell {\n line: number;\n text: string;\n}\n\ninterface DraftRow {\n line: number;\n header: boolean;\n cells: DraftCell[];\n}\n\ninterface DraftDefinitionItem {\n line: number;\n term: string;\n children: Draft[];\n}\n\nfunction stringAttribute(node: AdocNode, name: string): string | undefined {\n const value = node.getAttribute?.(name);\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction draftList(node: AdocNode, ordered: boolean): Draft {\n const items: DraftItem[] = [];\n\n for (const raw of node.getItems?.() ?? []) {\n const item = asItem(raw);\n if (!item) continue;\n\n const line = lineOf(item);\n const text = flattenInline(item.getText());\n const children: Draft[] = [];\n\n // An item's principal text is not one of its blocks, but mdast puts it in\n // a paragraph child - so `lists: {items: {paragraphs: {min: 1}}}` counts\n // the same thing in both formats only if we put it there too.\n if (text.length > 0) children.push({ kind: \"paragraph\", line, text });\n collect(\n item.getBlocks().map(asNode).filter((n): n is AdocNode => n !== null),\n children,\n );\n\n items.push({ line, text, children });\n }\n\n return { kind: \"list\", line: lineOf(node), ordered, items };\n}\n\n/**\n * A block's own children, recursively drafted - the same walk `collect` does\n * at document level, reused for a container whose content is content in its\n * own right (an admonition, a blockquote) rather than a section's directly.\n */\nfunction draftChildren(node: AdocNode): Draft[] {\n const children: Draft[] = [];\n collect(childrenOf(node), children);\n return children;\n}\n\n/**\n * AsciiDoc's own admonition vocabulary is closed - `NOTE`, `TIP`, `IMPORTANT`,\n * `CAUTION`, `WARNING`, and nothing else; there is no `DANGER`. So unlike a\n * format with free-form admonition naming, every real admonition here maps\n * cleanly onto the shared vocabulary, and only a node whose `name` attribute\n * is missing or unrecognised - which real AsciiDoc input cannot produce -\n * fails to.\n */\nconst ADMONITION_VARIANTS = new Set<string>([\n \"note\",\n \"tip\",\n \"important\",\n \"caution\",\n \"warning\",\n]);\n\nfunction admonitionVariant(node: AdocNode): AdmonitionNode[\"variant\"] | null {\n const name = stringAttribute(node, \"name\")?.toLowerCase();\n return name && ADMONITION_VARIANTS.has(name)\n ? (name as AdmonitionNode[\"variant\"])\n : null;\n}\n\n/**\n * An admonition's content, whichever of the two forms it took.\n *\n * A compound admonition (`[TIP]\\n====\\n...\\n====`) has real blocks, and\n * `getContent()` on it returns their *rendered* concatenation - using both\n * would double the content. A simple one (`NOTE: text`) has no blocks at all;\n * its only content is `getContent()`, exactly as a paragraph's is.\n */\nfunction draftAdmonition(node: AdocNode, variant: AdmonitionNode[\"variant\"]): Draft {\n const children = draftChildren(node);\n if (children.length === 0) {\n const text = flattenInline(node.getContent?.());\n if (text.length > 0) children.push({ kind: \"paragraph\", line: lineOf(node), text });\n }\n return { kind: \"admonition\", line: lineOf(node), variant, children };\n}\n\n/** A quote block's content, by the same two-form rule as an admonition's. */\nfunction draftBlockquote(node: AdocNode): Draft {\n const children = draftChildren(node);\n if (children.length === 0) {\n const text = flattenInline(node.getContent?.());\n if (text.length > 0) children.push({ kind: \"paragraph\", line: lineOf(node), text });\n }\n return { kind: \"blockquote\", line: lineOf(node), children };\n}\n\nfunction draftTable(node: AdocNode): Draft {\n const rows = node.getRows?.();\n const toRow = (header: boolean) => (cells: AdocCell[]): DraftRow => ({\n line: cells[0]?.getLineNumber?.() ?? lineOf(node),\n header,\n cells: cells.map((cell) => ({\n line: cell.getLineNumber?.() ?? lineOf(node),\n text: flattenInline(cell.getText()),\n })),\n });\n return {\n kind: \"table\",\n line: lineOf(node),\n rows: [\n ...(rows?.getHead().map(toRow(true)) ?? []),\n ...(rows?.getBody().map(toRow(false)) ?? []),\n ...(rows?.getFoot().map(toRow(false)) ?? []),\n ],\n };\n}\n\n/**\n * A description list's items.\n *\n * `getItems()` does not hand back `ListItem`s for a `dlist` the way it does\n * for a `ulist`/`olist`; each entry is a `[terms, description]` tuple, and a\n * missing description arrives as AsciiDoctor's own `nil`, which is a real\n * object in the JS bridge rather than `null` or `undefined` - `asItem` rejects\n * it the same way it rejects anything else with no `getText`.\n */\nfunction draftDefinitionList(node: AdocNode): Draft {\n const items: DraftDefinitionItem[] = [];\n\n for (const entry of node.getItems?.() ?? []) {\n if (!Array.isArray(entry)) continue;\n const [rawTerms, rawDesc] = entry as [unknown, unknown];\n const terms = (Array.isArray(rawTerms) ? rawTerms : [])\n .map(asItem)\n .filter((t): t is AdocItem => t !== null);\n const first = terms[0];\n if (!first) continue;\n\n const children: Draft[] = [];\n const desc = asItem(rawDesc);\n if (desc) {\n const text = flattenInline(desc.getText());\n if (text.length > 0) children.push({ kind: \"paragraph\", line: lineOf(desc), text });\n collect(\n desc.getBlocks().map(asNode).filter((n): n is AdocNode => n !== null),\n children,\n );\n }\n\n items.push({\n line: lineOf(first),\n term: terms.map((t) => flattenInline(t.getText())).join(\", \"),\n children,\n });\n }\n\n return { kind: \"definitionList\", line: lineOf(node), items };\n}\n\n/** One block, or null when the content model has no kind for it. */\nfunction draftOf(node: AdocNode): Draft | null {\n switch (node.getContext()) {\n case \"paragraph\":\n return {\n kind: \"paragraph\",\n line: lineOf(node),\n text: flattenInline(node.getContent?.()),\n };\n case \"listing\":\n case \"literal\": {\n const lang = stringAttribute(node, \"language\");\n return {\n kind: \"codeBlock\",\n line: lineOf(node),\n // Raw, not converted: a code block's text is its source, and\n // `getContent()` would escape every `<` in it.\n text: node.getSource?.() ?? \"\",\n ...(lang ? { language: lang } : {}),\n };\n }\n case \"ulist\":\n return draftList(node, false);\n case \"olist\":\n return draftList(node, true);\n case \"table\":\n return draftTable(node);\n case \"admonition\": {\n const variant = admonitionVariant(node);\n return variant ? draftAdmonition(node, variant) : null;\n }\n case \"image\": {\n const url = stringAttribute(node, \"target\");\n if (!url) return null;\n const title = flattenInline(node.getTitle?.());\n return {\n kind: \"image\",\n line: lineOf(node),\n url,\n alt: stringAttribute(node, \"alt\") ?? \"\",\n ...(title.length > 0 ? { title } : {}),\n };\n }\n case \"quote\":\n return draftBlockquote(node);\n case \"dlist\":\n return draftDefinitionList(node);\n default:\n // Sidebars, thematic breaks, verses, and the rest the content model\n // does not name. Skipped whole: their children are not the section's\n // content either.\n return null;\n }\n}\n\n/**\n * Flatten a container's children into drafts, in document order.\n *\n * `section` contributes a heading and then its own children as siblings, which\n * is what turns Asciidoctor's nesting back into the flat stream `sectionize`\n * folds.\n *\n * Two containers are transparent - recursed through, contributing nothing of\n * their own - because neither is a construct the author meant as content:\n *\n * - `preamble`, a wrapper Asciidoctor inserts between a document title and the\n * first section. Skipping it would swallow the lead prose.\n * - `open` (`--`). That is how an author attaches several blocks to one list\n * item, so skipping it would make a numbered step's whole body invisible to\n * a template. The constructs a `--` block can be *turned into* do not arrive\n * here at all: `[NOTE]` becomes an `admonition`, `[quote]` a `quote`,\n * `[sidebar]` a `sidebar`, each with its own context and each skipped by the\n * default branch, which is the line mdast draws around a blockquote. So a\n * node still reporting `open` is the bare attach-blocks form by elimination.\n */\nfunction collect(nodes: AdocNode[], out: Draft[]): void {\n for (const node of nodes) {\n const context = node.getContext();\n\n if (context === \"section\") {\n out.push({\n kind: \"heading\",\n line: lineOf(node),\n // Asciidoctor's `=` title is level 0, so every level is one shallower\n // than the heading level the rest of the tool speaks in.\n level: (node.getLevel?.() ?? 0) + 1,\n title: flattenInline(node.getTitle?.()),\n });\n collect(childrenOf(node), out);\n continue;\n }\n\n if (context === \"preamble\" || context === \"open\") {\n collect(childrenOf(node), out);\n continue;\n }\n\n const draft = draftOf(node);\n if (draft) out.push(draft);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Drafts -> blocks\n// ---------------------------------------------------------------------------\n\n/**\n * Give every draft a span.\n *\n * A heading spans its own title line, the way an mdast heading spans its `#`\n * line. Everything else ends where the next block begins, and the last block at\n * `end` - the convention `sectionize` already uses for sections, applied one\n * level down because Asciidoctor reports where a block starts and nothing at\n * all about where it stops.\n */\nfunction place(drafts: Draft[], end: Point, index: LineIndex): Fragment[] {\n return drafts.map((draft, i): Fragment => {\n const next = drafts[i + 1];\n const boundary = next ? index.start(next.line) : end;\n\n if (draft.kind === \"heading\") {\n return {\n type: \"heading\",\n level: draft.level,\n title: draft.title,\n position: {\n start: index.start(draft.line),\n end: index.endOfLine(draft.line),\n },\n };\n }\n\n return {\n type: \"content\",\n node: contentNode(\n draft,\n { start: index.start(draft.line), end: boundary },\n index,\n ),\n };\n });\n}\n\n/** `place`, for content that cannot contain a heading. */\nfunction placeContent(drafts: Draft[], end: Point, index: LineIndex): ContentNode[] {\n return place(drafts, end, index).flatMap((fragment) =>\n fragment.type === \"content\" ? [fragment.node] : [],\n );\n}\n\nfunction placeItems(items: DraftItem[], end: Point, index: LineIndex): ListItemNode[] {\n return items.map((item, i) => {\n const next = items[i + 1];\n const boundary = next ? index.start(next.line) : end;\n return {\n kind: \"listItem\",\n position: { start: index.start(item.line), end: boundary },\n text: item.text,\n children: placeContent(item.children, boundary, index),\n };\n });\n}\n\n/**\n * A table cell's own span: its starting line only.\n *\n * Asciidoctor reports a line per cell, but several cells on one row commonly\n * share a single source line, so there is no line-based boundary between\n * them the way there is between rows or list items. A cell spans just the\n * line it starts on, the way a heading spans its own title line.\n */\nfunction placeCells(cells: DraftCell[], index: LineIndex): TableCellNode[] {\n return cells.map((cell) => ({\n kind: \"tableCell\",\n position: { start: index.start(cell.line), end: index.endOfLine(cell.line) },\n text: cell.text,\n children: [],\n }));\n}\n\nfunction placeRows(rows: DraftRow[], end: Point, index: LineIndex): TableRowNode[] {\n return rows.map((row, i) => {\n const next = rows[i + 1];\n const boundary = next ? index.start(next.line) : end;\n const cells = placeCells(row.cells, index);\n return {\n kind: \"tableRow\",\n position: { start: index.start(row.line), end: boundary },\n text: cells.map((cell) => cell.text).join(\" | \"),\n header: row.header,\n children: cells,\n };\n });\n}\n\nfunction placeDefinitionItems(\n items: DraftDefinitionItem[],\n end: Point,\n index: LineIndex,\n): DefinitionItemNode[] {\n return items.map((item, i) => {\n const next = items[i + 1];\n const boundary = next ? index.start(next.line) : end;\n const definition = placeContent(item.children, boundary, index);\n const definitionText = definition.map((node) => node.text).join(\" \");\n return {\n kind: \"definitionItem\",\n position: { start: index.start(item.line), end: boundary },\n text: definitionText.length > 0 ? `${item.term}: ${definitionText}` : item.term,\n term: item.term,\n definition,\n };\n });\n}\n\nfunction contentNode(\n draft: ContentDraft,\n position: Position,\n index: LineIndex,\n): ContentNode {\n switch (draft.kind) {\n case \"paragraph\":\n return { kind: \"paragraph\", position, text: draft.text };\n case \"codeBlock\":\n return {\n kind: \"codeBlock\",\n position,\n text: draft.text,\n ...(draft.language ? { language: draft.language } : {}),\n };\n case \"list\":\n return {\n kind: \"list\",\n position,\n // Informational only - no rule reads a list's own text - so the items\n // are joined one per line rather than run together the way\n // `mdast-util-to-string` concatenates them.\n text: draft.items.map((item) => item.text).join(\"\\n\"),\n ordered: draft.ordered,\n items: placeItems(draft.items, position.end, index),\n };\n case \"table\": {\n const rows = placeRows(draft.rows, position.end, index);\n return {\n kind: \"table\",\n position,\n text: rows.map((row) => row.text).join(\"\\n\"),\n children: rows,\n };\n }\n case \"admonition\": {\n const children = placeContent(draft.children, position.end, index);\n return {\n kind: \"admonition\",\n position,\n text: children.map((node) => node.text).join(\"\\n\\n\"),\n variant: draft.variant,\n children,\n };\n }\n case \"image\":\n return {\n kind: \"image\",\n position,\n text: draft.alt,\n url: draft.url,\n alt: draft.alt,\n ...(draft.title ? { title: draft.title } : {}),\n };\n case \"blockquote\": {\n const children = placeContent(draft.children, position.end, index);\n return {\n kind: \"blockquote\",\n position,\n text: children.map((node) => node.text).join(\"\\n\\n\"),\n children,\n };\n }\n case \"definitionList\": {\n const children = placeDefinitionItems(draft.items, position.end, index);\n return {\n kind: \"definitionList\",\n position,\n // `item.text`, which is `\"term: definition\"`, not `item.term`. A\n // node's `text` is its flattened rendering, so dropping the definition\n // bodies here would make a pattern rule find a word in every format\n // except this one.\n text: children.map((item) => item.text).join(\"\\n\"),\n children,\n };\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Document metadata\n// ---------------------------------------------------------------------------\n\n/**\n * The AsciiDoc-aware reader, which the plain `extractFrontmatter` is not.\n *\n * `extractFrontmatter(content, \"asciidoc\")` reads only the fenced `--- ... ---`\n * block some toolchains prepend - its format argument is a label copied onto\n * the result, not a parser selector. AsciiDoc's own metadata is the document\n * header: the `= Title` line plus `:key: value` attribute entries, up to the\n * first blank line. That is how a real page declares `:type: how-to`, and\n * reading it is what makes type routing work for `.adoc` at all.\n */\nconst nativeExtractor = extractorForExtension(\".adoc\");\n\ninterface Metadata {\n data: Record<string, unknown> | null;\n position: Position | null;\n}\n\n/**\n * Span of the native header: the run of lines before the first blank one,\n * which is exactly the range docmeta's extractor reads attributes from.\n */\nfunction headerPosition(content: string, index: LineIndex): Position | null {\n let last = 0;\n for (const [i, line] of content.split(/\\r?\\n/).entries()) {\n if (line.trim() === \"\") break;\n last = i + 1;\n }\n if (last === 0) return null;\n return { start: index.start(1), end: index.endOfLine(last) };\n}\n\n/**\n * Both metadata styles, merged, with the fenced block winning a key collision:\n * a file carrying a fence has chosen it as its metadata of record. `present` is\n * the OR of the two, so a page with only `:type: how-to` still reports\n * frontmatter and still routes.\n */\nfunction metadata(content: string, filePath: string, index: LineIndex): Metadata {\n const fenced = extractFrontmatter(content, \"asciidoc\");\n // Read the native header from the fence-free remainder: docmeta's AsciiDoc\n // extractor returns the fence and stops when one is present, so asking it\n // about the whole file would discard `:type:` on any page that has both.\n const native = nativeExtractor?.extract(\n fenced.present ? withoutFence(content) : content,\n filePath,\n );\n\n if (!fenced.present && !native?.present) return { data: null, position: null };\n\n return {\n data: { ...(native?.data ?? {}), ...(fenced.present ? fenced.data : {}) },\n position:\n (fenced.present ? fencedPosition(content) : null) ??\n headerPosition(content, index),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Parser\n// ---------------------------------------------------------------------------\n\nfunction load(content: string, filePath: string): AdocDocument {\n try {\n return processor.load(content, {\n // Without this every block's `getLineNumber()` is undefined and there are\n // no positions to derive at all.\n sourcemap: true,\n // A leading `---` fence is a thematic break in AsciiDoc; this consumes it\n // as metadata instead, without disturbing line numbering.\n attributes: { \"skip-front-matter\": true },\n }) as unknown as AdocDocument;\n } catch (err) {\n // Asciidoctor recovers from malformed *documents* - it warns about an\n // unterminated block and carries on - so this fires when the loader itself\n // refuses the input. Either way it is the file's problem, not a crash.\n throw new LintError(\n `${filePath}: could not parse as asciidoc: ${errorMessage(err)}`,\n );\n }\n}\n\n/**\n * The document title, as a heading block.\n *\n * `= Title` is not a block: Asciidoctor keeps it as the document header, and\n * `getDocumentTitle()` lies about it - with no header at all it falls back to\n * the first section's title - so this goes through `hasHeader()`. A header made\n * only of attribute entries has no title to contribute, and emitting an empty\n * heading for it would both invent a section and block the frontmatter title\n * those attributes may be carrying.\n */\nfunction headerDraft(doc: AdocDocument): Draft | null {\n if (!doc.hasHeader()) return null;\n const header = asNode(doc.getHeader());\n if (!header) return null;\n const title = flattenInline(header.getTitle?.());\n if (title.length === 0) return null;\n return {\n kind: \"heading\",\n line: lineOf(header),\n level: (header.getLevel?.() ?? 0) + 1,\n title,\n };\n}\n\nfunction parse(content: string, filePath: string): DocumentTree {\n const doc = load(content, filePath);\n const index = lineIndex(content);\n\n const drafts: Draft[] = [];\n const header = headerDraft(doc);\n if (header) drafts.push(header);\n collect(childrenOf(doc), drafts);\n\n const meta = metadata(content, filePath, index);\n const end = index.documentEnd();\n\n return {\n format: \"asciidoc\",\n filePath,\n frontmatter: meta.data,\n frontmatterPosition: meta.position,\n sections: sectionize(\n withFrontmatterTitle(place(drafts, end, index), meta.data, meta.position),\n end,\n ),\n };\n}\n\nexport const asciidocParser: DocumentParser = {\n name: \"asciidoc\",\n label: \"AsciiDoc\",\n kinds: [\n \"paragraph\",\n \"codeBlock\",\n \"list\",\n \"listItem\",\n \"table\",\n \"tableRow\",\n \"tableCell\",\n \"admonition\",\n \"image\",\n \"blockquote\",\n \"definitionList\",\n \"definitionItem\",\n ],\n extensions: [\".adoc\", \".asciidoc\"],\n parse,\n};\n","/**\n * Parser registry. Maps file extensions to parsers and resolves a parser by\n * name for the `--as` override.\n *\n * Shaped after docmeta's extractor registry, and for the same reason:\n * everything downstream of `parse()` operates on the generic `DocumentTree`, so\n * adding a format is one file plus one line here - no change to matching,\n * rules, templates, or reporting.\n *\n * A format is registered here when, and only when, a parser reads it. That is\n * what `manni lint tools` lists and what `--as` accepts, so neither can name a\n * format the tool does not read. An extension no parser claims is skipped by\n * name, never parsed as Markdown the way the pre-rewrite `inferFileType` did.\n */\nimport type { ContentKind, DocumentParser } from \"../types.js\";\nimport { markdownParser, mdxParser } from \"./markdown.js\";\nimport { htmlParser } from \"./html.js\";\nimport { rstParser } from \"./rst.js\";\nimport { xmlParser } from \"./xml.js\";\nimport { asciidocParser } from \"./asciidoc.js\";\n\nexport const PARSERS: DocumentParser[] = [\n markdownParser,\n mdxParser,\n htmlParser,\n asciidocParser,\n rstParser,\n xmlParser,\n];\n\nconst byExtension = new Map<string, DocumentParser>();\nconst byName = new Map<string, DocumentParser>();\nfor (const parser of PARSERS) {\n byName.set(parser.name, parser);\n for (const ext of parser.extensions) byExtension.set(ext.toLowerCase(), parser);\n}\n\n/** Resolve a parser for a file extension (including the dot). */\nexport function parserForExtension(ext: string): DocumentParser | undefined {\n return byExtension.get(ext.toLowerCase());\n}\n\n/** Resolve a parser by its `--as` name. */\nexport function parserByName(name: string): DocumentParser | undefined {\n return byName.get(name.toLowerCase());\n}\n\n/** Extensions collected from a directory walk. */\nexport function supportedExtensions(): string[] {\n return PARSERS.flatMap((p) => p.walkExtensions ?? p.extensions);\n}\n\n/** Every format the tool reads, for `manni lint tools`. */\nexport function listFormats(): {\n name: string;\n label: string;\n extensions: string[];\n kinds: ContentKind[];\n}[] {\n return PARSERS.map((p) => ({\n name: p.name,\n label: p.label,\n extensions: p.extensions,\n kinds: p.kinds,\n }));\n}\n","/**\n * `heading:` - the section's title against a string, a one-of list, a\n * `{ pattern }`, or `false` for \"no heading of its own\".\n *\n * One finding type, `heading_error`, covers all four forms; the message\n * names which form failed. v1 split this into `heading_const_error` and\n * `heading_pattern_error`, each of which could fire independently for the\n * same section. v2's `heading:` is one value, so it fires at most once.\n */\n\nimport type { Finding, SectionNode } from \"../types.js\";\nimport { compilePattern, type HeadingRule } from \"./index.js\";\n\n/**\n * A section's own title, in the vocabulary `heading:` speaks: `null` when the\n * section has no heading of its own (the implicit lead section), the title\n * text otherwise.\n *\n * `SectionNode.title` is `\"\"` rather than `null` for that section - `null` is\n * reserved for \"no heading\" so `headingMatches`-style checks elsewhere don't\n * have to special-case the empty string. This bridges the two.\n */\nfunction ownTitle(section: SectionNode): string | null {\n return section.titlePosition === null ? null : section.title;\n}\n\n/** Checks a section's title against the template's `heading:` rule. */\nexport function checkHeading(\n section: SectionNode,\n rule: HeadingRule | undefined,\n): Finding[] {\n if (rule === undefined) return [];\n\n // The heading itself is the offending node when it has a span of its own;\n // the implicit lead section has none, so fall back to the section.\n const position = section.titlePosition ?? section.position;\n const title = ownTitle(section);\n const found = title === null ? \"no heading\" : `\"${title}\"`;\n\n const fail = (message: string): Finding[] => [\n {\n type: \"heading_error\",\n // `|| null`, as `sectionContext` and `match.ts`'s `anchor` both do. A\n // headless section's title is `\"\"`, and the JSON reporter's `heading` is\n // a wire key `manni docevals` parses rather than validates, so two\n // spellings of \"no heading\" would reach it as two different facts.\n heading: section.title || null,\n message,\n position,\n severity: \"error\",\n },\n ];\n\n if (rule === false) {\n return title === null ? [] : fail(`Expected no heading of its own, but found ${found}`);\n }\n\n if (typeof rule === \"string\") {\n return title === rule ? [] : fail(`Expected title \"${rule}\", but found ${found}`);\n }\n\n if (Array.isArray(rule)) {\n if (title !== null && rule.includes(title)) return [];\n return fail(`Expected one of ${rule.map((option) => `\"${option}\"`).join(\", \")}, but found ${found}`);\n }\n\n // { pattern }\n if (title !== null && compilePattern(rule.pattern).test(title)) return [];\n return fail(`Expected title matching /${rule.pattern}/, but found ${found}`);\n}\n","/**\n * `paragraphs:` - paragraph counts and a per-paragraph pattern.\n *\n * v1 took a cycling `patterns: string[]`; v2 simplifies to one `pattern`\n * every paragraph in the run must match, per proposal 0061's block-rule\n * vocabulary.\n */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n compilePattern,\n paragraphsOf,\n sectionContext,\n type ParagraphsRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the paragraphs a section holds directly. */\nexport function checkParagraphs(\n section: SectionNode,\n rule: ParagraphsRule | undefined,\n): Finding[] {\n return checkParagraphsIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks the paragraphs in any ordered content list.\n *\n * Used for a section's own content, for a list item's `children`, and for one\n * run of a `sequence`. `ctx` says where count findings land and what heading\n * they carry.\n */\nexport function checkParagraphsIn(\n content: ContentNode[],\n rule: ParagraphsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const paragraphs = paragraphsOf(content);\n const findings = checkCount(\n paragraphs.length,\n rule,\n \"paragraph\",\n \"paragraphs_count_error\",\n ctx,\n );\n\n const pattern = rule.pattern;\n if (pattern) {\n const regex = compilePattern(pattern);\n paragraphs.forEach((paragraph, index) => {\n if (!regex.test(paragraph.text)) {\n findings.push({\n type: \"paragraphs_pattern_error\",\n heading: ctx.heading,\n message: `Paragraph ${index + 1} does not match /${pattern}/`,\n position: paragraph.position,\n severity: \"error\",\n });\n }\n });\n }\n\n return findings;\n}\n","/**\n * `codeBlocks:` - code block counts, the language(s) every block must\n * declare, and a `fenceInfo` filter over the info-string tail.\n *\n * `language` reports per offending block (every code block must declare one\n * of the accepted languages), the same way v1 reported nothing about\n * language at all - this is new in v2. `fenceInfo` has no message form of its\n * own in proposal 0061's table, so it narrows which blocks count toward\n * `min`/`max` instead, the way `elements.tag` does.\n */\n\nimport type { CodeNode, ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n codeBlocksOf,\n compilePattern,\n sectionContext,\n type CodeBlocksRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the code blocks a section holds directly. */\nexport function checkCodeBlocks(\n section: SectionNode,\n rule: CodeBlocksRule | undefined,\n): Finding[] {\n return checkCodeBlocksIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks the code blocks in any ordered content list -\n * a section's content, a list item's `children`, or one run of a `sequence`.\n */\nexport function checkCodeBlocksIn(\n content: ContentNode[],\n rule: CodeBlocksRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const codeBlocks = codeBlocksOf(content);\n const counted = rule.fenceInfo\n ? codeBlocks.filter((block) => matchesFenceInfo(block, rule.fenceInfo as string))\n : codeBlocks;\n\n const findings = checkCount(\n counted.length,\n rule,\n \"code block\",\n \"code_blocks_count_error\",\n ctx,\n );\n\n if (rule.language) {\n findings.push(...checkLanguages(codeBlocks, rule.language, ctx));\n }\n\n return findings;\n}\n\nfunction matchesFenceInfo(block: CodeNode, pattern: string): boolean {\n return compilePattern(pattern).test(block.fenceInfo ?? \"\");\n}\n\n/** Every code block in the run must declare one of the accepted languages. */\nfunction checkLanguages(\n codeBlocks: CodeNode[],\n language: string | string[],\n ctx: RuleContext,\n): Finding[] {\n const languages = Array.isArray(language) ? language : [language];\n const only = languages[0];\n if (languages.length === 0 || only === undefined) return [];\n\n const label =\n languages.length === 1\n ? `\"${only}\"`\n : `one of ${languages.map((lang) => `\"${lang}\"`).join(\", \")}`;\n\n const findings: Finding[] = [];\n codeBlocks.forEach((block, index) => {\n if (block.language !== undefined && languages.includes(block.language)) return;\n\n const found = block.language ? `but found \"${block.language}\"` : \"but found no language\";\n findings.push({\n type: \"code_blocks_language_error\",\n heading: ctx.heading,\n message: `Expected code block ${index + 1} to declare ${label}, ${found}`,\n position: block.position,\n severity: \"error\",\n });\n });\n\n return findings;\n}\n","/**\n * `tables:` - table counts and the header cells every table must carry.\n *\n * `columns` is diagnostic, not a count filter: every table in the run counts\n * toward `min`/`max` whether or not its columns match, and a mismatch is\n * reported once per offending table (the same treatment `codeBlocks.language`\n * and `admonitions.variant` get, and unlike `codeBlocks.fenceInfo`, which has\n * no message form and narrows the count instead).\n */\n\nimport type { ContentNode, Finding, SectionNode, TableNode } from \"../types.js\";\nimport {\n checkCount,\n quoteList,\n sectionContext,\n tablesOf,\n type RuleContext,\n type TablesRule,\n} from \"./index.js\";\n\n/** Checks the tables a section holds directly. */\nexport function checkTables(\n section: SectionNode,\n rule: TablesRule | undefined,\n): Finding[] {\n return checkTablesIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the tables in any ordered content list. */\nexport function checkTablesIn(\n content: ContentNode[],\n rule: TablesRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const tables = tablesOf(content);\n const findings = checkCount(tables.length, rule, \"table\", \"tables_count_error\", ctx);\n\n if (rule.columns) {\n for (const table of tables) {\n const actual = headerCells(table);\n if (!sameColumns(actual, rule.columns)) {\n findings.push({\n type: \"tables_columns_error\",\n heading: ctx.heading,\n message: `Expected table columns ${quoteList(rule.columns)}, but found ${quoteList(actual)}`,\n position: table.position,\n severity: \"error\",\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction headerCells(table: TableNode): string[] {\n const header = table.children.find((row) => row.header);\n return header ? header.children.map((cell) => cell.text) : [];\n}\n\nfunction sameColumns(actual: string[], expected: string[]): boolean {\n return actual.length === expected.length && actual.every((cell, index) => cell === expected[index]);\n}\n","/**\n * `admonitions:` - admonition counts and the variant every admonition must\n * carry.\n *\n * `variant` is diagnostic, not a count filter, for the same reason\n * `tables.columns` is: every admonition counts toward `min`/`max` regardless,\n * and a mismatch is reported once per offending admonition.\n */\n\nimport type { AdmonitionNode, ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n admonitionsOf,\n checkCount,\n sectionContext,\n type AdmonitionsRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the admonitions a section holds directly. */\nexport function checkAdmonitions(\n section: SectionNode,\n rule: AdmonitionsRule | undefined,\n): Finding[] {\n return checkAdmonitionsIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the admonitions in any ordered content list. */\nexport function checkAdmonitionsIn(\n content: ContentNode[],\n rule: AdmonitionsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const admonitions = admonitionsOf(content);\n const findings = checkCount(\n admonitions.length,\n rule,\n \"admonition\",\n \"admonitions_count_error\",\n ctx,\n );\n\n if (rule.variant) {\n findings.push(...checkVariant(admonitions, rule.variant, ctx));\n }\n\n return findings;\n}\n\nfunction checkVariant(\n admonitions: AdmonitionNode[],\n variant: NonNullable<AdmonitionsRule[\"variant\"]>,\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n for (const admonition of admonitions) {\n if (admonition.variant !== variant) {\n // A format may name a flavor this vocabulary does not have, or none at\n // all: reStructuredText's `hint`, a bare HTML `<aside>`. The node then\n // carries no variant, and saying \"found a undefined\" would be worse\n // than saying what is true.\n const found = admonition.variant\n ? `but found a ${admonition.variant}`\n : \"but found one with no type\";\n findings.push({\n type: \"admonitions_variant_error\",\n heading: ctx.heading,\n message: `Expected a ${variant} admonition, ${found}`,\n position: admonition.position,\n severity: \"error\",\n });\n }\n }\n return findings;\n}\n","/**\n * `images:` - how many images, filtered by `url`, `alt`, and `attributes`.\n *\n * All three narrow the counted set rather than reporting their own finding -\n * proposal 0061's message table gives `images` only `images_count_error`, no\n * per-field diagnostic the way `elements.attributes` gets one. `attributes`\n * in particular can never match: `ImageNode` carries no `attributes` of its\n * own (the node model gave that field to `element` only), so any non-empty\n * `attributes` requirement here excludes every image, same as an image whose\n * `url` or `alt` does not match.\n */\n\nimport type { ContentNode, Finding, ImageNode, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n imagesOf,\n sectionContext,\n type ImagesRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the images a section holds directly. */\nexport function checkImages(\n section: SectionNode,\n rule: ImagesRule | undefined,\n): Finding[] {\n return checkImagesIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the images in any ordered content list. */\nexport function checkImagesIn(\n content: ContentNode[],\n rule: ImagesRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const matching = imagesOf(content).filter((image) => matches(image, rule));\n return checkCount(matching.length, rule, \"image\", \"images_count_error\", ctx);\n}\n\nfunction matches(image: ImageNode, rule: ImagesRule): boolean {\n if (rule.url !== undefined && image.url !== rule.url) return false;\n if (rule.alt !== undefined && image.alt !== rule.alt) return false;\n if (rule.attributes && Object.keys(rule.attributes).length > 0) return false;\n return true;\n}\n","/** `blockquotes:` - a plain count, the schema's `counted` shape. */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport { blockquotesOf, checkCount, sectionContext, type Occurrences, type RuleContext } from \"./index.js\";\n\n/** Checks the blockquotes a section holds directly. */\nexport function checkBlockquotes(\n section: SectionNode,\n rule: Occurrences | undefined,\n): Finding[] {\n return checkBlockquotesIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the blockquotes in any ordered content list. */\nexport function checkBlockquotesIn(\n content: ContentNode[],\n rule: Occurrences | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n return checkCount(blockquotesOf(content).length, rule, \"blockquote\", \"blockquotes_count_error\", ctx);\n}\n","/** `definitionLists:` - a plain count, the schema's `counted` shape. */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n definitionListsOf,\n sectionContext,\n type Occurrences,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the definition lists a section holds directly. */\nexport function checkDefinitionLists(\n section: SectionNode,\n rule: Occurrences | undefined,\n): Finding[] {\n return checkDefinitionListsIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the definition lists in any ordered content list. */\nexport function checkDefinitionListsIn(\n content: ContentNode[],\n rule: Occurrences | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n return checkCount(\n definitionListsOf(content).length,\n rule,\n \"definition list\",\n \"definition_lists_count_error\",\n ctx,\n );\n}\n","/**\n * `sequence:` - the ordered runs of content a section (or an element's or\n * list item's own content) must hold.\n *\n * Content arrives flat and in document order, so consecutive nodes of the\n * same kind are first grouped into runs: `[p, p, code, table]` becomes three\n * runs (paragraph, codeBlock, table). Those runs are then matched\n * positionally against the template's sequence, and each run is handed to\n * `checkContainsIn` for its one set key.\n *\n * v1 reported a length mismatch and an order mismatch as two finding types,\n * `sequence_length_error` and `sequence_order_error`. v2 collapses both into\n * one `content_order_error`: the message states the full expected and actual\n * kind lists, which communicates a length difference as plainly as an order\n * one, and a template widening from three kinds to nine does not need a\n * matching widening of finding types. The bail-on-mismatch behavior stays -\n * once the runs are the wrong shape, per-run findings are noise about\n * content the author has not arranged yet.\n */\n\nimport type { ContentKind, ContentNode, Finding, Position, SectionNode } from \"../types.js\";\nimport { BLOCK_KINDS, sectionContext, type BlockKind, type BlockRule, type RuleContext } from \"./index.js\";\nimport { checkContainsIn } from \"./contains.js\";\n\n/** A maximal stretch of consecutive content nodes sharing one kind. */\nexport interface ContentRun {\n kind: ContentKind;\n nodes: ContentNode[];\n /** First node's start through last node's end. */\n position: Position;\n}\n\n/** Groups consecutive same-kind nodes into runs, preserving document order. */\nexport function groupRuns(content: ContentNode[]): ContentRun[] {\n const runs: ContentRun[] = [];\n\n for (const node of content) {\n const current = runs[runs.length - 1];\n if (current && current.kind === node.kind) {\n current.nodes.push(node);\n current.position = {\n start: current.position.start,\n end: node.position.end,\n };\n } else {\n runs.push({\n kind: node.kind,\n nodes: [node],\n position: { start: node.position.start, end: node.position.end },\n });\n }\n }\n\n return runs;\n}\n\n/** The content kind a block-rule key names, e.g. `codeBlocks` -> `codeBlock`. */\nconst KIND_OF_BLOCK: Record<BlockKind, ContentKind> = {\n paragraphs: \"paragraph\",\n codeBlocks: \"codeBlock\",\n lists: \"list\",\n tables: \"table\",\n admonitions: \"admonition\",\n images: \"image\",\n blockquotes: \"blockquote\",\n definitionLists: \"definitionList\",\n elements: \"element\",\n};\n\n/** The short noun a `content_order_error` message uses for one kind. */\nfunction sequenceLabel(kind: ContentKind): string {\n switch (kind) {\n case \"paragraph\":\n return \"paragraph\";\n case \"codeBlock\":\n return \"code\";\n case \"list\":\n return \"list\";\n case \"table\":\n return \"table\";\n case \"admonition\":\n return \"admonition\";\n case \"image\":\n return \"image\";\n case \"blockquote\":\n return \"blockquote\";\n case \"definitionList\":\n return \"definition list\";\n case \"element\":\n return \"element\";\n default:\n // tableRow/tableCell/definitionItem/listItem never appear as a top-level\n // ContentNode.kind; groupRuns only ever sees the nine kinds above.\n return kind;\n }\n}\n\n/** The one key set on a `sequence:` entry, or `null` for a malformed one. */\nfunction keyOf(entry: BlockRule): BlockKind | null {\n for (const kind of BLOCK_KINDS) {\n if (entry[kind] !== undefined) return kind;\n }\n return null;\n}\n\n/** Checks a section's own content against a `sequence:` rule. */\nexport function checkSequence(\n section: SectionNode,\n rule: BlockRule[] | undefined,\n): Finding[] {\n return checkSequenceIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks any ordered content list against a `sequence:`\n * rule - a section's content, a list item's `children`, or an element's own\n * `children`.\n */\nexport function checkSequenceIn(\n content: ContentNode[],\n rule: BlockRule[] | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const runs = groupRuns(content);\n const expectedKinds = rule.map((entry) => {\n const key = keyOf(entry);\n return key ? KIND_OF_BLOCK[key] : null;\n });\n const actualKinds = runs.map((run) => run.kind);\n\n const matches =\n expectedKinds.length === actualKinds.length &&\n expectedKinds.every((kind, index) => kind === actualKinds[index]);\n\n if (!matches) {\n const expected = expectedKinds.map((kind) => (kind ? sequenceLabel(kind) : \"?\"));\n const found = actualKinds.length > 0 ? actualKinds.map(sequenceLabel) : [\"nothing\"];\n return [\n {\n type: \"content_order_error\",\n heading: ctx.heading,\n message: `Expected ${expected.join(\" then \")}, but found ${found.join(\" then \")}`,\n position: ctx.position,\n severity: \"error\",\n },\n ];\n }\n\n const findings: Finding[] = [];\n runs.forEach((run, index) => {\n const entry = rule[index];\n if (!entry) return;\n const runCtx: RuleContext = { heading: ctx.heading, position: run.position };\n // A run holds one kind, so `checkContainsIn` sees exactly the nodes in\n // this stretch, not the section's other content of the same kind - the\n // entry has only that one key set, so every other dispatch is a no-op.\n findings.push(...checkContainsIn(run.nodes, entry, runCtx));\n });\n\n return findings;\n}\n","/**\n * `elements:` - named-wrapper counts, filtered and labeled by `tag`, the\n * literal `attributes` a matched element must carry, and what it holds via\n * `sequence` | `contains` recursing into the element's own `children` -\n * never the enclosing section's, per proposal 0065 stress test 4.\n *\n * `tag` narrows the counted set the way `codeBlocks.fenceInfo` and\n * `images.url`/`alt` do, and also names the noun in count messages: `elements:\n * { tag: \"Steps\", min: 1 }` reports `Expected at least 1 \"Steps\" element, but\n * found 0`, not the generic `\"element\"`. `attributes` is diagnostic instead,\n * checked per matched element and reported once per offending attribute.\n */\n\nimport type { ContentNode, ElementNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n elementsOf,\n sectionContext,\n type AttributesRule,\n type ElementsRule,\n type RuleContext,\n} from \"./index.js\";\nimport { checkContainsIn } from \"./contains.js\";\nimport { checkSequenceIn } from \"./sequence.js\";\n\n/** Checks the elements a section holds directly. */\nexport function checkElements(\n section: SectionNode,\n rule: ElementsRule | undefined,\n): Finding[] {\n return checkElementsIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the elements in any ordered content list. */\nexport function checkElementsIn(\n content: ContentNode[],\n rule: ElementsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const tags = rule.tag === undefined ? undefined : Array.isArray(rule.tag) ? rule.tag : [rule.tag];\n const matching = tags ? elementsOf(content).filter((element) => tags.includes(element.name)) : elementsOf(content);\n\n // \"or\", not a comma list: the count applies to one combined label, so\n // `\"Note\", \"Tip\" element` reads as two nouns with a singular verb where\n // `\"Note\" or \"Tip\" element` reads as the one thing being counted.\n const noun = tags\n ? `${tags.map((tag) => `\"${tag}\"`).join(\" or \")} element`\n : \"element\";\n const findings = checkCount(matching.length, rule, noun, \"elements_count_error\", ctx);\n\n if (rule.attributes) {\n for (const element of matching) {\n findings.push(...checkAttributes(element, rule.attributes, ctx));\n }\n }\n\n // Both, unconditionally, as `validator.ts` runs them against a section. Each\n // no-ops on an absent rule, and the schema refuses a rule that writes both\n // (`oneOfSequenceOrContains`), so only one can ever fire. Writing it as a\n // choice made this file's behaviour depend on a constraint declared in\n // another, which reads like a silent drop whether or not it is one.\n if (rule.sequence || rule.contains) {\n for (const element of matching) {\n const elementCtx: RuleContext = { heading: ctx.heading, position: element.position };\n findings.push(...checkSequenceIn(element.children, rule.sequence, elementCtx));\n findings.push(...checkContainsIn(element.children, rule.contains, elementCtx));\n }\n }\n\n return findings;\n}\n\n/**\n * `true` requires presence (any value); `false` requires absence; a string\n * is the required literal value. An element's own `attributes` map values a\n * dynamic (JSX-expression) attribute as `true` too, since its literal value\n * cannot be known statically - `checkOne` tells that apart from \"absent\" by\n * checking membership before comparing values.\n */\nfunction checkAttributes(\n element: ElementNode,\n rule: AttributesRule,\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n for (const [key, expected] of Object.entries(rule)) {\n const finding = checkOne(element, key, expected, ctx);\n if (finding) findings.push(finding);\n }\n return findings;\n}\n\nfunction checkOne(\n element: ElementNode,\n key: string,\n expected: string | boolean,\n ctx: RuleContext,\n): Finding | null {\n const attributes = element.attributes ?? {};\n const present = key in attributes;\n const actual = attributes[key];\n\n const fail = (want: string, detail: string): Finding => ({\n type: \"elements_attribute_error\",\n heading: ctx.heading,\n message: `Expected the \"${element.name}\" element ${want}, but ${detail}`,\n position: element.position,\n severity: \"error\",\n });\n\n if (expected === false) {\n if (!present) return null;\n const found = actual === true ? `an expression` : `${key}=\"${String(actual)}\"`;\n return fail(`not to carry ${key}`, `found ${found}`);\n }\n\n if (!present) return fail(attributeWant(key, expected), `it carries no ${key}`);\n if (expected === true) return null;\n if (actual === true) return fail(attributeWant(key, expected), `its ${key} is an expression`);\n if (actual !== expected) return fail(attributeWant(key, expected), `found ${key}=\"${String(actual)}\"`);\n return null;\n}\n\nfunction attributeWant(key: string, expected: string | true): string {\n return expected === true ? `to carry ${key}` : `to carry ${key}=\"${expected}\"`;\n}\n","/**\n * `contains:` - what a section (or an element's or list item's own content)\n * holds, in any order. Each listed kind dispatches to that kind's own check.\n */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport { BLOCK_KINDS, sectionContext, type BlockRule, type RuleContext } from \"./index.js\";\nimport { checkParagraphsIn } from \"./paragraphs.js\";\nimport { checkCodeBlocksIn } from \"./code-blocks.js\";\nimport { checkListsIn } from \"./lists.js\";\nimport { checkTablesIn } from \"./tables.js\";\nimport { checkAdmonitionsIn } from \"./admonitions.js\";\nimport { checkImagesIn } from \"./images.js\";\nimport { checkBlockquotesIn } from \"./blockquotes.js\";\nimport { checkDefinitionListsIn } from \"./definition-lists.js\";\nimport { checkElementsIn } from \"./elements.js\";\n\n/** Checks a section's own content against a `contains:` rule. */\nexport function checkContains(\n section: SectionNode,\n rule: BlockRule | undefined,\n): Finding[] {\n return checkContainsIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks any ordered content list against a `contains:`\n * rule - a section's content, a list item's `children`, an element's own\n * `children`, or one run of a `sequence` (which carries exactly one key).\n *\n * `BLOCK_KINDS` drives the dispatch so a ninth kind is one line here, not a\n * rewritten `if` chain.\n */\nexport function checkContainsIn(\n content: ContentNode[],\n rule: BlockRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const findings: Finding[] = [];\n for (const kind of BLOCK_KINDS) {\n switch (kind) {\n case \"paragraphs\":\n findings.push(...checkParagraphsIn(content, rule.paragraphs, ctx));\n break;\n case \"codeBlocks\":\n findings.push(...checkCodeBlocksIn(content, rule.codeBlocks, ctx));\n break;\n case \"lists\":\n findings.push(...checkListsIn(content, rule.lists, ctx));\n break;\n case \"tables\":\n findings.push(...checkTablesIn(content, rule.tables, ctx));\n break;\n case \"admonitions\":\n findings.push(...checkAdmonitionsIn(content, rule.admonitions, ctx));\n break;\n case \"images\":\n findings.push(...checkImagesIn(content, rule.images, ctx));\n break;\n case \"blockquotes\":\n findings.push(...checkBlockquotesIn(content, rule.blockquotes, ctx));\n break;\n case \"definitionLists\":\n findings.push(...checkDefinitionListsIn(content, rule.definitionLists, ctx));\n break;\n case \"elements\":\n findings.push(...checkElementsIn(content, rule.elements, ctx));\n break;\n }\n }\n return findings;\n}\n","/**\n * `lists:` - list counts, whether they are ordered, item counts, and what\n * each item holds.\n *\n * v1's `items` took its own flat `paragraphs`/`code_blocks`/`lists` keys. v2\n * replaces that split with the same `sequence` | `contains` every other\n * container uses (proposal 0061), so item-level rules recurse through the\n * same two functions as everything else instead of a third, list-shaped one.\n */\n\nimport type { ContentNode, Finding, ListNode, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n listsOf,\n sectionContext,\n type ListsRule,\n type RuleContext,\n} from \"./index.js\";\nimport { checkContainsIn } from \"./contains.js\";\nimport { checkSequenceIn } from \"./sequence.js\";\n\n/** Checks the lists a section holds directly. */\nexport function checkLists(\n section: SectionNode,\n rule: ListsRule | undefined,\n): Finding[] {\n return checkListsIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks the lists in any ordered content list.\n *\n * `rule.items` recurses - a list item's children are a `ContentNode[]` like\n * any other, so item-level `sequence`/`contains` rules run through the same\n * functions, arbitrarily deep.\n */\nexport function checkListsIn(\n content: ContentNode[],\n rule: ListsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const lists = listsOf(content);\n const findings = checkCount(lists.length, rule, \"list\", \"lists_count_error\", ctx);\n\n if (rule.ordered !== undefined) {\n findings.push(...checkOrdered(lists, rule.ordered, ctx));\n }\n\n const items = rule.items;\n if (!items) return findings;\n\n findings.push(...checkItemCounts(lists, items, ctx));\n\n if (!items.sequence && !items.contains) return findings;\n\n for (const list of lists) {\n for (const item of list.items) {\n const itemCtx: RuleContext = { heading: ctx.heading, position: item.position };\n if (items.sequence) {\n findings.push(...checkSequenceIn(item.children, items.sequence, itemCtx));\n } else if (items.contains) {\n findings.push(...checkContainsIn(item.children, items.contains, itemCtx));\n }\n }\n }\n\n return findings;\n}\n\nfunction checkOrdered(lists: ListNode[], ordered: boolean, ctx: RuleContext): Finding[] {\n const findings: Finding[] = [];\n for (const list of lists) {\n if (list.ordered !== ordered) {\n findings.push({\n type: \"lists_ordered_error\",\n heading: ctx.heading,\n message: ordered\n ? \"Expected a numbered list, but found a bulleted list\"\n : \"Expected a bulleted list, but found a numbered list\",\n position: list.position,\n severity: \"error\",\n });\n }\n }\n return findings;\n}\n\n/**\n * Item counts report once per bound, anchored at the first list that breaks\n * it. `min` defaults to 1 like every other count, which is a harmless no-op\n * here: a list always has at least one item structurally, so only an\n * explicit `min` above 1 (or a rule that also forbids via `max`) ever fires.\n */\nfunction checkItemCounts(\n lists: ListNode[],\n items: { min?: number; max?: number },\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n const min = items.min ?? (items.max === 0 ? 0 : 1);\n const max = items.max ?? null;\n\n if (max !== null) {\n const offender = lists.find((list) => list.items.length > max);\n if (offender) {\n findings.push({\n type: \"lists_items_count_error\",\n heading: ctx.heading,\n message: `Expected at most ${max} items in a list, but found ${offender.items.length}`,\n position: offender.position,\n severity: \"error\",\n });\n }\n }\n\n if (min > 0) {\n const offender = lists.find((list) => list.items.length < min);\n if (offender) {\n findings.push({\n type: \"lists_items_count_error\",\n heading: ctx.heading,\n message: `Expected at least ${min} items in a list, but found ${offender.items.length}`,\n position: offender.position,\n severity: \"error\",\n });\n }\n }\n\n return findings;\n}\n","/**\n * Content rules: the checks that run against a single section's own content.\n *\n * A rule is a pure, synchronous function of one `SectionNode` (or one ordered\n * `ContentNode[]` slice of it) and its slice of a template, returning\n * `Finding[]`. Rules never touch a parser AST and never await anything.\n *\n * The content model is format-neutral and flat: a section carries one ordered\n * `children: ContentNode[]`, and the per-kind \"buckets\" every rule needs are\n * queries over it (`paragraphsOf`, `codeBlocksOf`, ...) rather than separately\n * maintained arrays. The same queries work unchanged on a list item's\n * `children` or an element's own `children`, which is why `lists.items` and\n * `elements` can recurse.\n *\n * This module is deliberately independent of `../core/template.ts`. That file\n * is the DSL the v2 loader and schema agree on; this one is the DSL the rules\n * are written against. Where the two diverge - see `CodeBlocksRule.language`\n * and `ElementsRule.tag` below, which this chunk's task widened to `string |\n * string[]` while `core/template.ts` still types them as a bare `string` -\n * the validator chunk that wires the two together needs to reconcile it. That\n * mirrors the v1 shape of this file, whose own rule interfaces mirrored\n * `template-v1.ts` rather than importing it.\n */\n\nimport { LintError } from \"../types.js\";\nimport type {\n AdmonitionNode,\n BlockquoteNode,\n CodeNode,\n ContentNode,\n DefinitionListNode,\n ElementNode,\n Finding,\n ImageNode,\n ListNode,\n ParagraphNode,\n Position,\n SectionNode,\n TableNode,\n} from \"../types.js\";\n\n/* -------------------------------------------------------------------------- *\n * Template rule shapes\n *\n * These mirror the v2 template DSL's block-rule vocabulary (proposal 0065 /\n * 0061): a block rule is keyed by a plural content kind and carries `min`\n * (default 1), `max` (absent unbounded, `0` forbids), plus per-kind keys.\n * -------------------------------------------------------------------------- */\n\n/** Shared by every counted rule: how many of the thing there must be. */\nexport interface Occurrences {\n /** Fewest occurrences. Absent means one - see `checkCount` for the one\n * exception, where an explicit `max: 0` with no `min` defaults `min` to 0\n * too, so \"forbid this kind\" is satisfiable by finding none of it. */\n min?: number;\n /** Most occurrences. Absent is unbounded; `0` forbids. */\n max?: number;\n}\n\n/**\n * What a rule's `heading` may say.\n *\n * `undefined` (the key absent) matches any heading or none. A string is exact\n * text, a list is one-of, `{ pattern }` is an unanchored regular expression,\n * and `false` means the section has no heading of its own.\n */\nexport type HeadingRule = string | string[] | { pattern: string } | false;\n\n/** Attributes a node must carry. `true` requires presence; `false` requires absence. */\nexport type AttributesRule = Record<string, string | boolean>;\n\n/** `paragraphs:` - how many paragraphs, and what they must look like. */\nexport interface ParagraphsRule extends Occurrences {\n /** Unanchored regular expression every paragraph in the run must match. */\n pattern?: string;\n}\n\n/** `codeBlocks:` - how many code blocks, and how they are tagged. */\nexport interface CodeBlocksRule extends Occurrences {\n /** Language(s) every code block must declare one of. */\n language?: string | string[];\n /** Info-string tail after the language; narrows which blocks count. */\n fenceInfo?: string;\n}\n\n/** `lists.items:` - how many items per list, and what each item holds. */\nexport interface ListItemsRule extends Occurrences {\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/** `lists:` - how many lists, whether they are ordered, and item rules. */\nexport interface ListsRule extends Occurrences {\n ordered?: boolean;\n items?: ListItemsRule;\n}\n\n/** `tables:` - how many tables, and the header cells in order. */\nexport interface TablesRule extends Occurrences {\n columns?: string[];\n}\n\n/** `admonitions:` - how many, and of which variant. */\nexport interface AdmonitionsRule extends Occurrences {\n variant?: \"note\" | \"tip\" | \"important\" | \"caution\" | \"warning\" | \"danger\";\n}\n\n/** `images:` - how many, and what they point at. */\nexport interface ImagesRule extends Occurrences {\n /** Narrows which images count: only images at this url are counted. */\n url?: string;\n /** Narrows which images count: only images with this alt text are counted. */\n alt?: string;\n /**\n * Narrows which images count. `ImageNode` carries no `attributes` of its\n * own (the node model gave that field to `element` only), so any non-empty\n * requirement here matches no image - see `images.ts`.\n */\n attributes?: AttributesRule;\n}\n\n/** `elements:` - how many named wrappers, and what they hold. */\nexport interface ElementsRule extends Occurrences {\n /** Narrows which elements count, and names the noun in count messages. */\n tag?: string | string[];\n attributes?: AttributesRule;\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/**\n * What a section (or an element's or list item's own content) holds, keyed by\n * content kind.\n *\n * One of these is a whole `contains:`. As an entry of `sequence:` exactly one\n * key is set, and it names the kind expected at that position.\n */\nexport interface BlockRule {\n paragraphs?: ParagraphsRule;\n codeBlocks?: CodeBlocksRule;\n lists?: ListsRule;\n tables?: TablesRule;\n admonitions?: AdmonitionsRule;\n images?: ImagesRule;\n blockquotes?: Occurrences;\n definitionLists?: Occurrences;\n elements?: ElementsRule;\n}\n\n/** `sequence:` - the ordered runs of content a section must contain. */\nexport type SequenceRule = BlockRule[];\n\n/** One block-rule key: a content kind, spelled plural. */\nexport type BlockKind = keyof BlockRule;\n\n/** Every block-rule key, in the order the schema declares them. */\nexport const BLOCK_KINDS: readonly BlockKind[] = [\n \"paragraphs\",\n \"codeBlocks\",\n \"lists\",\n \"tables\",\n \"admonitions\",\n \"images\",\n \"blockquotes\",\n \"definitionLists\",\n \"elements\",\n];\n\n/* -------------------------------------------------------------------------- *\n * Finding anchoring\n * -------------------------------------------------------------------------- */\n\n/**\n * Where findings land when a rule runs over content that is not a whole\n * section - a list item's `children`, an element's `children`, or one run\n * inside a `sequence`.\n */\nexport interface RuleContext {\n /** Stamped onto every finding as `Finding.heading`. */\n heading: string | null;\n /** Used when the offending thing is a count rather than a single node. */\n position: Position;\n}\n\n/**\n * The context for rules run against a section's own content.\n *\n * The heading is normalised to `null` when there is none, as `match.ts` and\n * `validator.ts` both do. A headless section carries `title: \"\"`, and the JSON\n * reporter's `heading` is a wire key `manni docevals` parses rather than\n * validates, so `\"\"` and `null` would reach it as two spellings of one fact.\n */\nexport function sectionContext(section: SectionNode): RuleContext {\n return { heading: section.title || null, position: section.position };\n}\n\n/* -------------------------------------------------------------------------- *\n * Content queries\n *\n * The single place the flat content array is bucketed by kind. Rules call\n * these; they never filter inline.\n * -------------------------------------------------------------------------- */\n\nexport function paragraphsOf(content: ContentNode[]): ParagraphNode[] {\n return content.filter((node): node is ParagraphNode => node.kind === \"paragraph\");\n}\n\nexport function codeBlocksOf(content: ContentNode[]): CodeNode[] {\n return content.filter((node): node is CodeNode => node.kind === \"codeBlock\");\n}\n\nexport function listsOf(content: ContentNode[]): ListNode[] {\n return content.filter((node): node is ListNode => node.kind === \"list\");\n}\n\nexport function tablesOf(content: ContentNode[]): TableNode[] {\n return content.filter((node): node is TableNode => node.kind === \"table\");\n}\n\nexport function admonitionsOf(content: ContentNode[]): AdmonitionNode[] {\n return content.filter((node): node is AdmonitionNode => node.kind === \"admonition\");\n}\n\nexport function imagesOf(content: ContentNode[]): ImageNode[] {\n return content.filter((node): node is ImageNode => node.kind === \"image\");\n}\n\nexport function blockquotesOf(content: ContentNode[]): BlockquoteNode[] {\n return content.filter((node): node is BlockquoteNode => node.kind === \"blockquote\");\n}\n\nexport function definitionListsOf(content: ContentNode[]): DefinitionListNode[] {\n return content.filter((node): node is DefinitionListNode => node.kind === \"definitionList\");\n}\n\nexport function elementsOf(content: ContentNode[]): ElementNode[] {\n return content.filter((node): node is ElementNode => node.kind === \"element\");\n}\n\n/* -------------------------------------------------------------------------- *\n * Shared message helpers\n * -------------------------------------------------------------------------- */\n\n/** `\"paragraph\"`/1 -> `\"paragraph\"`; `\"paragraph\"`/2 -> `\"paragraphs\"`. */\nfunction plural(noun: string, count: number): string {\n return count === 1 ? noun : `${noun}s`;\n}\n\n/** `[\"Field\", \"Type\"]` -> `\"Field\", \"Type\"`. */\nexport function quoteList(items: string[]): string {\n return items.map((item) => `\"${item}\"`).join(\", \");\n}\n\n/**\n * The count half of every block rule: `min` (default 1) and `max` (default\n * unbounded), against one already-computed count.\n *\n * One default is not the naive `rule.min ?? 1`. The schema documents `max: 0`\n * as how a template forbids a kind outright, and that has to be satisfiable\n * by a section that truly has none of it. A blanket \"min defaults to 1\" would\n * make `{ max: 0 }` alone unsatisfiable - it would demand at least one and\n * permit at most zero. So `min` defaults to 0 exactly when `max` is written\n * as `0` and `min` itself is not, and to 1 otherwise. `min: 0` and `max: 0`\n * are each still tested explicitly; this is what makes both mean something\n * at once.\n */\nexport function checkCount(\n count: number,\n rule: Occurrences,\n noun: string,\n type: string,\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n const min = rule.min ?? (rule.max === 0 ? 0 : 1);\n const max = rule.max ?? null;\n\n if (count < min) {\n findings.push({\n type,\n heading: ctx.heading,\n message: `Expected at least ${min} ${plural(noun, min)}, but found ${count}`,\n position: ctx.position,\n severity: \"error\",\n });\n }\n\n if (max !== null && count > max) {\n findings.push({\n type,\n heading: ctx.heading,\n message: `Expected at most ${max} ${plural(noun, max)}, but found ${count}`,\n position: ctx.position,\n severity: \"error\",\n });\n }\n\n return findings;\n}\n\n/* -------------------------------------------------------------------------- *\n * The rules\n * -------------------------------------------------------------------------- */\n\nexport { checkHeading } from \"./heading.js\";\nexport { checkParagraphs, checkParagraphsIn } from \"./paragraphs.js\";\nexport { checkCodeBlocks, checkCodeBlocksIn } from \"./code-blocks.js\";\nexport { checkLists, checkListsIn } from \"./lists.js\";\nexport { checkTables, checkTablesIn } from \"./tables.js\";\nexport { checkAdmonitions, checkAdmonitionsIn } from \"./admonitions.js\";\nexport { checkImages, checkImagesIn } from \"./images.js\";\nexport { checkBlockquotes, checkBlockquotesIn } from \"./blockquotes.js\";\nexport { checkDefinitionLists, checkDefinitionListsIn } from \"./definition-lists.js\";\nexport { checkElements, checkElementsIn } from \"./elements.js\";\nexport { checkContains, checkContainsIn } from \"./contains.js\";\nexport { checkSequence, checkSequenceIn, groupRuns } from \"./sequence.js\";\nexport type { ContentRun } from \"./sequence.js\";\n\n/**\n * Compile an author-supplied pattern, or say which one is broken.\n *\n * A pattern comes from a template, so a bad one is a broken template rather\n * than a lint finding - and the raw `SyntaxError` names the regex but not the\n * template, the section, or the file. Every caller must route the result\n * through the same containment a template load failure gets, or one bad\n * pattern takes the whole run down with it.\n *\n * ## A pattern that compiles can still hang\n *\n * This checks syntax, and syntax is all it checks. `(a+)+b$` is a valid regex\n * that backtracks catastrophically against a heading it cannot match, and\n * `loadTemplateFile` will fetch a template over HTTP, so an untrusted template\n * can supply one.\n *\n * Capping the input length is not the answer, however cheap it looks. The\n * blow-up is exponential in the length of the input, so a cap generous enough\n * for a real heading is already far past the point of hanging: `(a+)+b$` needs\n * on the order of 2^n steps, and n of 64 is out of reach. Any cap that\n * actually bounded the work would reject headings people legitimately write.\n *\n * The boundary that does hold is the one proposal 0015 drew for schemas: a\n * template from a URL is a trust decision made when the URL is configured, not\n * something this function can take back. Validating patterns for backtracking\n * safety at load time is the fix if that decision is ever delegated, and it is\n * a dependency and a proposal rather than a line here.\n */\nconst compiled = new Map<string, RegExp>();\n\nexport function compilePattern(pattern: string): RegExp {\n // Memoized because heading matching is quadratic by nature: the matcher asks\n // every rule about every section, so a template with ten pattern rules against\n // a twenty-section page compiled the same ten regexes two hundred times.\n //\n // Safe to share one instance: these are built with no flags, and `lastIndex`\n // is only carried between calls by `g` and `y`. Adding either to this\n // construction would make the cached regex stateful across sections.\n const hit = compiled.get(pattern);\n if (hit) return hit;\n try {\n const regex = new RegExp(pattern);\n compiled.set(pattern, regex);\n return regex;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new LintError(`Invalid pattern \"${pattern}\": ${reason}`);\n }\n}\n\n/** Drop the compiled-pattern memo. See `clearCaches` in the package root. */\nexport function clearPatternCache(): void {\n compiled.clear();\n}\n","/**\n * The template DSL, as TypeScript. `schemas/lint/template.json` is the\n * authority that user input is validated against; this is the shape the rest of\n * the code reads once that validation has passed.\n *\n * Two things are worth knowing before reading it.\n *\n * A template *is* a rule. It describes the page, so it takes every rule key,\n * plus `title`, `types` and `extends`. It may not take `min` or `max`, because\n * a page is one page, and the loader refuses those two by hand.\n *\n * A rule's children are a **list**, not a map. The v1 format keyed section\n * rules by name and let YAML key order carry the grammar, which made the order\n * invisible to the schema and unspeakable in `extends`. A rule names itself\n * with `id` instead, and that is what `extends` targets.\n *\n * The block-rule keys are plural where the node model is singular. That is\n * deliberate: the node model names one node (`codeBlock`), while a template key\n * carries a count (`codeBlocks: { min: 1 }`).\n */\nimport type { ContentKind } from \"../types.js\";\nimport { compilePattern } from \"../rules/index.js\";\n\n/** Shared by every counted rule: how many of the thing there must be. */\nexport interface Occurrences {\n /** Fewest occurrences. Absent means one. */\n min?: number;\n /** Most occurrences. Absent is unbounded; `0` forbids. */\n max?: number;\n}\n\n/**\n * What a rule's `heading` may say.\n *\n * `undefined` (the key absent) matches any heading or none. A string is exact\n * text, a list is one-of, `{ pattern }` is an unanchored regular expression,\n * and `false` means the section has no heading of its own.\n */\nexport type HeadingRule = string | string[] | { pattern: string } | false;\n\n/**\n * Attributes a node must carry. A string is the required value, `true`\n * requires the attribute's presence, and `false` requires its absence.\n */\nexport type AttributesRule = Record<string, string | boolean>;\n\n/** `paragraphs:` - how many paragraphs, and what each must look like. */\nexport interface ParagraphsRule extends Occurrences {\n /** Unanchored regular expression every paragraph in the run must match. */\n pattern?: string;\n}\n\n/** `codeBlocks:` - how many code blocks, and how they are tagged. */\nexport interface CodeBlocksRule extends Occurrences {\n /** Language, or languages, every code block must declare one of. */\n language?: string | string[];\n /** Info-string tail after the language; narrows which blocks count. */\n fenceInfo?: string;\n}\n\n/** `lists.items:` - how many items per list, and what each item holds. */\nexport interface ListItemsRule extends Occurrences {\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/** `lists:` - how many lists, whether they are ordered, and item rules. */\nexport interface ListsRule extends Occurrences {\n ordered?: boolean;\n items?: ListItemsRule;\n}\n\n/** `tables:` - how many tables, and the header cells in order. */\nexport interface TablesRule extends Occurrences {\n columns?: string[];\n}\n\n/** `admonitions:` - how many, and of which variant. */\nexport interface AdmonitionsRule extends Occurrences {\n variant?: \"note\" | \"tip\" | \"important\" | \"caution\" | \"warning\" | \"danger\";\n}\n\n/** `images:` - how many, and what they point at. */\nexport interface ImagesRule extends Occurrences {\n url?: string;\n alt?: string;\n attributes?: AttributesRule;\n}\n\n/** `elements:` - how many named wrappers, and what they hold. */\nexport interface ElementsRule extends Occurrences {\n /** Name, or names, an element must carry to be counted by this rule. */\n tag?: string | string[];\n attributes?: AttributesRule;\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/**\n * What a section holds, keyed by content kind.\n *\n * One of these is a whole `contains:`. As an entry of `sequence:` exactly one\n * key is set, and it names the kind expected at that position.\n */\nexport interface BlockRule {\n paragraphs?: ParagraphsRule;\n codeBlocks?: CodeBlocksRule;\n lists?: ListsRule;\n tables?: TablesRule;\n admonitions?: AdmonitionsRule;\n images?: ImagesRule;\n blockquotes?: Occurrences;\n definitionLists?: Occurrences;\n elements?: ElementsRule;\n}\n\n/** One block-rule key: a content kind, spelled plural. */\nexport type BlockKind = keyof BlockRule;\n\n/** Every block-rule key, in the order the schema declares them. */\nexport const BLOCK_KINDS: readonly BlockKind[] = [\n \"paragraphs\",\n \"codeBlocks\",\n \"lists\",\n \"tables\",\n \"admonitions\",\n \"images\",\n \"blockquotes\",\n \"definitionLists\",\n \"elements\",\n];\n\n/**\n * The node a block-rule key counts: `codeBlocks` counts `codeBlock` nodes.\n *\n * It is what lets the validator ask a parser whether a rule can run at all -\n * a parser declares the kinds it emits, and a rule about a kind absent from\n * that list is reported rather than silently passing.\n *\n * `rules/sequence.ts` holds the same map, written against the rules' own copy\n * of the DSL. The duplication is the one this file's header describes: the two\n * vocabularies are kept apart deliberately, and this is the copy the loader and\n * the validator read.\n */\nexport const BLOCK_KIND_NODE: Record<BlockKind, ContentKind> = {\n paragraphs: \"paragraph\",\n codeBlocks: \"codeBlock\",\n lists: \"list\",\n tables: \"table\",\n admonitions: \"admonition\",\n images: \"image\",\n blockquotes: \"blockquote\",\n definitionLists: \"definitionList\",\n elements: \"element\",\n};\n\n/** One rule: a section of the page, or a repeated run of sections. */\nexport interface Rule extends Occurrences {\n /** Handle, unique among siblings. `extends` targets it. */\n id?: string;\n /** Prose description of what the rule is for. Never checked. */\n description?: string;\n heading?: HeadingRule;\n /** Rules matched in order as one unit, repeated by this rule's `min`/`max`. */\n repeat?: Rule[];\n /** What the section holds, in order. Not combinable with `contains`. */\n sequence?: BlockRule[];\n /** What the section holds, in any order. Not combinable with `sequence`. */\n contains?: BlockRule;\n /** Rules for the subsections, in document order. */\n sections?: Rule[];\n}\n\n/** One doctype template: the rule that describes a whole page. */\nexport interface Template extends Rule {\n /** Human-readable name, shown by `manni lint templates`. */\n title?: string;\n /** Doctypes this template serves, matched against a page's `type`. */\n types?: string[];\n /** Built-in id, path, or URL to inherit from. */\n extends?: string;\n}\n\n/** A template file: named templates plus reusable `$ref` targets. */\nexport interface TemplateFile {\n /** Published schema URL, for editors. Ignored by the linter. */\n $schema?: string;\n templates?: Record<string, Template>;\n components?: Record<string, unknown>;\n info?: Record<string, unknown>;\n}\n\n/**\n * A rule is a wildcard when it says nothing about its heading.\n *\n * It then matches any heading, and matches a section with none. `heading:\n * false` is not a wildcard: it states that the section has no heading of its\n * own, which is as specific as naming one.\n */\nexport function isWildcard(rule: Rule): boolean {\n return rule.heading === undefined;\n}\n\n/**\n * How many sections a rule claims: `min` defaulting to one, and `max` as\n * written, with `null` for unbounded.\n *\n * The defaults live here rather than in the schema. A default written into the\n * data by Ajv is indistinguishable from a value the author typed, so it wins\n * the `extends` merge against the parent's real value.\n *\n * One default is not the naive `min ?? 1`. `max: 0` is how the format forbids\n * a thing outright, and a bare `max: 0` has to be satisfiable by a page that\n * truly has none of it. A blanket \"min defaults to 1\" makes it unsatisfiable -\n * at least one demanded, at most zero permitted - so `min` defaults to 0\n * exactly when `max` is written as `0` and `min` itself is not, and to 1\n * otherwise. `checkCount` in `rules/index.ts` states the same rule for the\n * content counts; the two agree deliberately.\n */\nexport function occurrenceRange(rule: Occurrences): {\n min: number;\n max: number | null;\n} {\n return { min: rule.min ?? (rule.max === 0 ? 0 : 1), max: rule.max ?? null };\n}\n\n/** Whether a section's title satisfies a rule's `heading`. */\nexport function headingMatches(\n heading: HeadingRule | undefined,\n title: string | null,\n): boolean {\n if (heading === undefined) return true;\n if (heading === false) return title === null;\n if (title === null) return false;\n if (typeof heading === \"string\") return title === heading;\n if (Array.isArray(heading)) return heading.includes(title);\n return compilePattern(heading.pattern).test(title);\n}\n","/**\n * Source of truth for templates. Holds the built-in doctype templates\n * (addressed by `vendor:name:version`-style ids) and knows how to load any\n * template reference - a built-in id, a local `.yaml`/`.yml`/`.json` path, or\n * an `http(s)` URL, optionally naming one template inside a file with a `#`\n * fragment (`./templates.yaml#how-to`).\n *\n * Two ordering decisions are load-bearing:\n *\n * - A file is dereferenced *before* it is validated. `$ref` is how a template\n * file shares one section rule between templates, and a section rule is\n * `additionalProperties: false`, so any `$ref` still standing at validation\n * time would be reported as an unexpected key.\n * - `instructions` is looked for by hand *before* Ajv runs. The schema rejects\n * it too (`not: {required: [\"instructions\"]}`), but a raw schema error says\n * nothing useful about where the feature went; scanning the parsed data\n * directly is both more reliable than reverse-engineering which Ajv error\n * came from the `not` keyword and the only way to quote the author's own\n * instruction back at them in the migration snippet.\n *\n * `extends` is deliberately *not* resolved by `loadTemplate`. Inheritance needs\n * a resolver that knows what a relative ref is relative to, which only the\n * caller knows, so `resolveExtends` takes that resolver as an argument.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve as resolvePath } from \"node:path\";\nimport { packageRoot } from \"../../shared/package-root.js\";\nimport { parse as parseYaml } from \"yaml\";\nimport { dereference } from \"@apidevtools/json-schema-ref-parser\";\nimport * as AjvNs from \"ajv\";\nimport type { ErrorObject, SchemaObject, ValidateFunction } from \"ajv\";\nimport { LintError } from \"../types.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { warn } from \"../../shared/warn.js\";\nimport { BLOCK_KINDS, isWildcard, occurrenceRange } from \"./template.js\";\nimport type {\n BlockRule,\n ListItemsRule,\n Occurrences,\n Rule,\n Template,\n TemplateFile,\n} from \"./template.js\";\nimport templateFileSchema from \"../../../schemas/lint/template.json\" with { type: \"json\" };\nimport tgdpManifest from \"../../../templates/lint/tgdp/manifest.json\" with { type: \"json\" };\n\n// ajv is CommonJS with a default export; under NodeNext the constructable\n// value lives on `.default`. Cast through the named default type so tsc sees a\n// constructor.\ntype AjvCtor = typeof import(\"ajv\").default;\nconst Ajv = AjvNs.default as unknown as AjvCtor;\n\n/**\n * Options for both `dereference` calls, named so the two cannot drift apart.\n *\n * `resolve.external: false` confines `$ref` to the file it is written in. A\n * template file is untrusted input - `loadTemplateFile` will fetch one over\n * `http(s)`, and a local one is only as trustworthy as whoever wrote it, who is\n * not necessarily whoever runs the lint. The dereferencer resolves a `$ref` by\n * reading the file or making the request it names, from the linting host and\n * with its privileges. Left on, `$ref: /etc/passwd` or\n * `$ref: http://169.254.169.254/latest/meta-data/` in a template turned a lint\n * run into an arbitrary read, and a remote template into one that reports back\n * what it found.\n *\n * Nothing in the template DSL wants it. `$ref` is documented as how one file\n * shares a section rule between its own templates, and reuse *across* files is\n * what `extends` is for - which goes through `loadTemplate`, is re-based against\n * the declaring file, and is cycle-checked. Same-document (`#/...`) pointers are\n * untouched; an external one is left standing instead, and the schema then\n * rejects it as an unexpected `$ref` key rather than following it.\n */\nconst DEREFERENCE_OPTIONS = { resolve: { external: false } };\n\nexport interface BuiltinInfo {\n id: string;\n title: string;\n types: string[];\n}\n\n/**\n * Built-in doctype templates.\n *\n * The manifest is a JSON import, so it is bundled and `listBuiltins()` stays\n * synchronous. The templates themselves are YAML files beside it, read on\n * demand: they are meant to be opened, read, and copied by anyone writing their\n * own template, and YAML is the format that survives that. They ship at the\n * package root as `templates/lint/**`, listed in `files`, and are found by\n * walking up from this module to `package.json`, which works identically from\n * source and from the built package.\n */\ninterface ManifestEntry {\n id: string;\n file: string;\n title: string;\n types: string[];\n /** Upstream file this was derived from, for provenance. */\n source?: string;\n}\n\ninterface Manifest {\n vendor: string;\n upstream: string;\n pin: string;\n templates: ManifestEntry[];\n}\n\nconst MANIFESTS: Manifest[] = [tgdpManifest];\n\nconst BUILTINS = new Map<string, ManifestEntry>();\nfor (const manifest of MANIFESTS) {\n for (const entry of manifest.templates) BUILTINS.set(entry.id, entry);\n}\n\n/** Parsed built-ins, keyed by id. Populated on first load. */\nconst builtinCache = new Map<string, Template>();\n\nexport function listBuiltins(): BuiltinInfo[] {\n return [...BUILTINS.values()].map((entry) => ({\n id: entry.id,\n title: entry.title,\n types: entry.types,\n }));\n}\n\n/**\n * Locate a built-in's YAML at the package root.\n *\n * The templates ship as `templates/lint/**` beside `package.json`. Resolving\n * from the package root rather than from `import.meta.url` is what keeps one\n * path correct both in the repo, where this module sits under\n * `src/lint/core/`, and in the bundle, where it sits in `dist/`.\n */\nasync function readBuiltinFile(id: string, file: string): Promise<string> {\n const path = join(packageRoot(import.meta.url), \"templates\", \"lint\", file);\n try {\n return await readFile(path, \"utf8\");\n } catch (err) {\n throw new LintError(\n `Built-in template \"${id}\" is registered but its file could not be read (${path}): ${errorMessage(err)}`,\n );\n }\n}\n\n/**\n * Read, validate, and cache one built-in.\n *\n * Built-ins go through exactly the same schema validation as a user's file. A\n * template we ship is not more trustworthy than one you write - it is only\n * better tested - and a shipped template that violates its own schema should\n * fail loudly here rather than behave strangely during matching.\n */\nasync function loadBuiltin(id: string): Promise<Template> {\n const cached = builtinCache.get(id);\n if (cached) return cached;\n\n // Every caller checks `BUILTINS.has` first, so this is an internal\n // invariant rather than a user error - but it fails loudly all the same,\n // because the alternative is a `TypeError` several lines later on a field\n // of `undefined`.\n const entry = BUILTINS.get(id);\n if (!entry) {\n throw new LintError(`No built-in template is registered under \"${id}\".`);\n }\n const raw = await readBuiltinFile(id, entry.file);\n\n // The same guard `loadTemplateFile` applies to an outside file. A built-in\n // is ours and should never fail it, which is the point: if one ever does,\n // this says which file and what it held, rather than letting `dereference`\n // report something opaque about a value it did not expect.\n const parsed: unknown = parseYaml(raw);\n if (!isRecord(parsed)) {\n throw new LintError(\n `Built-in template \"${id}\" (${entry.file}) is not a template file: ` +\n `expected an object at the top level, got ${\n parsed === null ? \"null\" : Array.isArray(parsed) ? \"an array\" : typeof parsed\n }.`,\n );\n }\n\n const file = validateTemplateFile(\n await dereference<Record<string, unknown>>(parsed, DEREFERENCE_OPTIONS),\n entry.file,\n );\n const names = Object.keys(file.templates ?? {});\n const template = file.templates?.[names[0] ?? \"\"];\n if (!template || names.length !== 1) {\n throw new LintError(\n `Built-in template \"${id}\" must define exactly one template, found ${names.length}.`,\n );\n }\n\n // `types` lives in the manifest so the type map can be built without reading\n // every YAML file; mirror it onto the template so both agree.\n const resolved: Template = { types: entry.types, ...template };\n builtinCache.set(id, resolved);\n return resolved;\n}\n\nexport type RefKind = \"builtin\" | \"file\" | \"url\";\n\n/**\n * A built-in id looks like `seg(:seg)+` using only [a-z0-9._-] segments, with\n * no path separators and no template-file extension. This deliberately\n * excludes Windows paths (`C:\\...`), URLs, and `.yaml`/`.yml`/`.json` files so\n * a typo'd built-in is reported as an unknown id rather than silently treated\n * as a missing file.\n */\nconst BUILTIN_ID = /^[a-z0-9][a-z0-9._-]*(?::[a-z0-9][a-z0-9._-]*)+$/i;\n\nconst FILE_EXTENSIONS = [\".yaml\", \".yml\", \".json\"];\n\nexport function classifyRef(ref: string): { kind: RefKind; ref: string } {\n if (/^https?:\\/\\//i.test(ref)) return { kind: \"url\", ref };\n const lower = ref.toLowerCase();\n if (\n !ref.includes(\"/\") &&\n !ref.includes(\"\\\\\") &&\n !FILE_EXTENSIONS.some((ext) => lower.endsWith(ext)) &&\n BUILTIN_ID.test(ref)\n ) {\n return { kind: \"builtin\", ref };\n }\n return { kind: \"file\", ref };\n}\n\n/** Default network timeout for fetching a remote (`http(s)`) template file. */\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport interface LoadTemplateOptions {\n /** Abort a remote fetch after this many ms (default 10_000). */\n timeoutMs?: number;\n}\n\n/* -------------------------------------------------------------------------- *\n * Validation\n * -------------------------------------------------------------------------- */\n\n// `useDefaults` is deliberately off, and the schema declares no `default`\n// anywhere. A default Ajv writes into the data is indistinguishable from a\n// value the author typed, so it beats the parent's real value in an `extends`\n// merge. Every default in this format lives in the code that reads it\n// (`occurrenceRange`), where an absent key stays absent.\nconst ajv = new Ajv();\n\nlet compiled: ValidateFunction | null = null;\n\nfunction fileValidator(): ValidateFunction {\n compiled ??= ajv.compile(templateFileSchema as SchemaObject);\n return compiled;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** One `instructions` key found in a template file, and where it lives. */\ninterface InstructionsHit {\n /** Dotted path to the rule carrying it, e.g. `templates.how-to.sections.title`. */\n path: string;\n /** Suggested eval name, kebab-cased from the path. */\n name: string;\n /** The instruction strings, verbatim. */\n values: string[];\n}\n\n/** The strings in an `instructions:` value, whatever shape it was written in. */\nfunction stringsOf(value: unknown): string[] {\n if (typeof value === \"string\") return [value];\n if (Array.isArray(value)) return value.filter((v): v is string => typeof v === \"string\");\n return [];\n}\n\n/**\n * Name for the suggested eval: the path with the structural keys (`templates`,\n * `sections`) dropped, kebab-cased. `templates.how-to.sections.title` becomes\n * `how-to-title`.\n */\nfunction suggestEvalName(segments: string[]): string {\n const name = segments\n .filter((segment) => segment !== \"templates\" && segment !== \"sections\")\n .join(\"-\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return name || \"section-instructions\";\n}\n\n/**\n * First `instructions` key anywhere in a parsed template file.\n *\n * Dereferencing can make two rules share one object, and a self-referential\n * `$ref` can make the tree cyclic, hence the `seen` set.\n */\nfunction findInstructions(\n node: unknown,\n segments: string[] = [],\n seen = new WeakSet(),\n): InstructionsHit | null {\n if (typeof node !== \"object\" || node === null) return null;\n if (seen.has(node)) return null;\n seen.add(node);\n\n if (Array.isArray(node)) {\n for (const [index, item] of node.entries()) {\n const hit = findInstructions(item, [...segments, String(index)], seen);\n if (hit) return hit;\n }\n return null;\n }\n\n const record = node as Record<string, unknown>;\n\n // Only a section's own `instructions` *property* is the legacy key. Inside a\n // `sections:` map the keys are section names the author chose, and a section\n // legitimately called \"instructions\" - TGDP's README doctype wants one - must\n // not be mistaken for it. So descend into a `sections` map without testing\n // its keys, and test the property everywhere else.\n const insideSectionsMap = segments.at(-1) === \"sections\";\n if (!insideSectionsMap && \"instructions\" in record) {\n return {\n path: segments.join(\".\"),\n name: suggestEvalName(segments),\n values: stringsOf(record.instructions),\n };\n }\n for (const [key, value] of Object.entries(record)) {\n const hit = findInstructions(value, [...segments, key], seen);\n if (hit) return hit;\n }\n return null;\n}\n\n/**\n * The message a template still carrying `instructions` gets: what replaced the\n * feature, and the config to paste, with the author's own instruction in it.\n */\nfunction instructionsMessage(source: string, hit: InstructionsHit): string {\n const assertion = hit.values[0] ?? \"\";\n return [\n `${source}: \"${hit.path}\" uses \\`instructions\\`, which manni lint no longer evaluates — structure checking is deterministic. Move it to a manni docevals assertion eval in manni.config.yaml:`,\n \"\",\n \" docevals:\",\n \" evals:\",\n ` ${hit.name}:`,\n ` assertion: ${assertion}`,\n \" grader: ai\",\n ].join(\"\\n\");\n}\n\n/* -------------------------------------------------------------------------- *\n * Refusing a v1 file\n *\n * v1 never shipped, so there is no migration mode and no alias. What there is\n * instead is a sentence per key naming the v2 spelling, because a v1 file is\n * what anyone who tried the format early still has on disk. Left to the schema\n * these all read as \"must NOT have additional properties\", which says nothing\n * about where the key went.\n *\n * The scan runs before Ajv, for the same reason the `instructions` scan does.\n * -------------------------------------------------------------------------- */\n\n/** v1 keys that are gone outright, and what to write instead. */\nconst V1_KEYS: Record<string, string> = {\n required: '\"required\" is not a template key. A rule is optional with \"min: 0\".',\n additionalSections:\n '\"additionalSections\" is not a template key. v2 has no equivalent, so drop it.',\n code_blocks: '\"code_blocks\" is not a template key. The v2 spelling is \"codeBlocks\".',\n};\n\nconst V1_SECTIONS_MAP =\n '\"sections\" is a list of rules, not a map. Name each rule with \"id\" and list them in order.';\n\nconst V1_REPEAT_BOOLEAN =\n '\"repeat\" is a list of rules, not a boolean. A rule repeats through \"min\" and \"max\".';\n\nconst V1_PARAGRAPH_PATTERNS =\n '\"patterns\" is not a paragraphs key. The v2 spelling is \"pattern\", one regular expression.';\n\n/**\n * The first v1 key anywhere under `templates` or `components`.\n *\n * `info` is skipped: it is free-form by contract, so a key of one of these\n * names in it is the author's own metadata rather than a template rule.\n *\n * A node carrying a `sections` *map* returns before its children are walked.\n * Inside such a map the keys are section names the author chose, and a v1\n * template with a section named `required` must not be reported as using the\n * `required` key.\n */\nfunction findV1Key(node: unknown, seen = new WeakSet()): string | null {\n if (typeof node !== \"object\" || node === null) return null;\n if (seen.has(node)) return null;\n seen.add(node);\n\n if (Array.isArray(node)) {\n for (const item of node) {\n const hit = findV1Key(item, seen);\n if (hit) return hit;\n }\n return null;\n }\n\n const record = node as Record<string, unknown>;\n for (const [key, message] of Object.entries(V1_KEYS)) {\n if (key in record) return message;\n }\n if (isRecord(record.sections)) return V1_SECTIONS_MAP;\n if (typeof record.repeat === \"boolean\") return V1_REPEAT_BOOLEAN;\n if (isRecord(record.paragraphs) && \"patterns\" in record.paragraphs) {\n return V1_PARAGRAPH_PATTERNS;\n }\n\n for (const value of Object.values(record)) {\n const hit = findV1Key(value, seen);\n if (hit) return hit;\n }\n return null;\n}\n\nfunction findV1File(data: unknown): string | null {\n if (!isRecord(data)) return null;\n return findV1Key(data.templates) ?? findV1Key(data.components);\n}\n\n/* -------------------------------------------------------------------------- *\n * Checks JSON Schema cannot express\n *\n * Three of these compare two siblings, which draft-07 has no keyword for, and\n * one compiles a regular expression, which it has no opinion about. The fifth\n * is a warning rather than an error: the template is legal, and only its author\n * can say whether the ambiguity is intended.\n * -------------------------------------------------------------------------- */\n\n/** How a rule is named in a message: its id where it has one, else its path. */\nfunction ruleLabel(rule: Rule, path: string): string {\n return rule.id === undefined ? path : `\"${rule.id}\"`;\n}\n\n/**\n * `max` below `min`, where the author wrote both.\n *\n * Only where both are written. `min` defaults to one, so comparing against the\n * default would refuse `max: 0`, which is how the format spells \"none of\n * these\".\n */\nfunction checkRange(range: Occurrences, source: string, label: string): void {\n const { min, max } = range;\n if (min !== undefined && max !== undefined && max < min) {\n throw new LintError(`${source}: rule ${label} sets max ${max} below min ${min}.`);\n }\n}\n\n/**\n * Whether two rules claim the same occurrence range, the one comparison the\n * ambiguity warning below needs. Compares what `occurrenceRange` resolves\n * `min`/`max` to, not the raw (possibly absent) fields, so a written `min: 1`\n * and an absent `min` - both one occurrence by default - count as the same.\n */\nfunction sameOccurrenceRange(a: Occurrences, b: Occurrences): boolean {\n const rangeA = occurrenceRange(a);\n const rangeB = occurrenceRange(b);\n return rangeA.min === rangeB.min && rangeA.max === rangeB.max;\n}\n\n/**\n * Compile an author's pattern here, so a broken one names the file it is in.\n *\n * \"Broken\" means it does not compile. A pattern that compiles can still hang\n * the run by backtracking, and this does not catch that; `compilePattern` in\n * `../rules/index.ts` carries the full note, including why a length cap is not\n * the mitigation it looks like.\n */\nfunction checkPattern(pattern: string | undefined, source: string): void {\n if (pattern === undefined) return;\n try {\n new RegExp(pattern);\n } catch (err) {\n throw new LintError(\n `Invalid pattern \"${pattern}\" in ${source}: ${errorMessage(err)}.`,\n );\n }\n}\n\nfunction checkListItems(items: ListItemsRule, source: string, path: string): void {\n checkRange(items, source, path);\n if (items.contains) checkBlockRule(items.contains, source, `${path}.contains`);\n items.sequence?.forEach((entry, index) => {\n checkBlockRule(entry, source, `${path}.sequence[${index}]`);\n });\n}\n\nfunction checkBlockRule(block: BlockRule, source: string, path: string): void {\n for (const kind of BLOCK_KINDS) {\n const counted: Occurrences | undefined = block[kind];\n if (counted) checkRange(counted, source, `${path}.${kind}`);\n }\n checkPattern(block.paragraphs?.pattern, source);\n if (block.lists?.items) {\n checkListItems(block.lists.items, source, `${path}.lists.items`);\n }\n const element = block.elements;\n if (element?.contains) {\n checkBlockRule(element.contains, source, `${path}.elements.contains`);\n }\n element?.sequence?.forEach((entry, index) => {\n checkBlockRule(entry, source, `${path}.elements.sequence[${index}]`);\n });\n}\n\n/** Everything a rule and a template share. A template is a rule. */\nfunction checkRuleBody(rule: Rule, source: string, path: string): void {\n const heading = rule.heading;\n if (typeof heading === \"object\" && !Array.isArray(heading)) {\n checkPattern(heading.pattern, source);\n }\n if (rule.contains) checkBlockRule(rule.contains, source, `${path}.contains`);\n rule.sequence?.forEach((entry, index) => {\n checkBlockRule(entry, source, `${path}.sequence[${index}]`);\n });\n checkRuleList(rule.repeat, source, `${path}.repeat`);\n checkRuleList(rule.sections, source, `${path}.sections`);\n}\n\n/**\n * One list of sibling rules: their ids, their ranges, and whether two\n * neighbours are told apart by nothing but their order.\n */\nfunction checkRuleList(rules: Rule[] | undefined, source: string, path: string): void {\n if (!rules) return;\n\n const ids = new Set<string>();\n for (const [index, rule] of rules.entries()) {\n const here = `${path}[${index}]`;\n if (rule.id !== undefined) {\n if (ids.has(rule.id)) {\n throw new LintError(`${source}: two sibling rules share the id \"${rule.id}\".`);\n }\n ids.add(rule.id);\n }\n checkRange(rule, source, ruleLabel(rule, here));\n checkRuleBody(rule, source, here);\n }\n\n // A warning, not an error. Two adjacent wildcards are how TGDP's \"{Task\n // name}\" then \"{Next task}\" is written, and that is legal. It is also how a\n // template accidentally describes one section twice, and nothing in the file\n // distinguishes the two cases - unless their occurrence ranges differ, in\n // which case the matcher can still tell them apart: one claims a fixed count\n // of sections and the other claims however many are left. That is\n // `reference-description` (`max: 1`) next to `structured-entry` (`min: 0`,\n // no `max`) in tgdp:reference - legal and unambiguous, so only a shared range\n // is flagged.\n for (const [index, rule] of rules.entries()) {\n const next = rules[index + 1];\n if (!next) break;\n if (\n isWildcard(rule) &&\n rule.repeat === undefined &&\n isWildcard(next) &&\n next.repeat === undefined &&\n sameOccurrenceRange(rule, next)\n ) {\n warn(\n `${source}: two adjacent rules have no heading and no repeat; only rule order tells them apart.`,\n );\n break;\n }\n }\n}\n\n/** The checks that run over a validated file, template by template. */\nfunction checkTemplateFile(file: TemplateFile, source: string): void {\n for (const [name, template] of Object.entries(file.templates ?? {})) {\n if (template.min !== undefined || template.max !== undefined) {\n throw new LintError(\n `${source}: a template may not set min or max; a page is one page.`,\n );\n }\n checkRuleBody(template, source, `templates.${name}`);\n }\n}\n\n/**\n * What each `not` constraint means, in the words its author needs.\n *\n * Ajv renders every `not` as \"must NOT be valid\", which names the path and\n * then says nothing whatsoever about what is wrong with it. The schema carries\n * a `description` on each of these; the sentence lives here instead because it\n * is user-facing text, and every other message in this file does too.\n */\nconst NOT_CONSTRAINTS: Record<string, string> = {\n oneOfSequenceOrContains:\n \"sets both sequence and contains; a rule says what it holds in order, or in any order, never both\",\n noHeadingOnRepeat:\n \"sets both heading and repeat; a repeat group has no heading of its own, so put the heading on the first rule inside it\",\n noInstructions: \"carries an instructions key, which this tool does not read\",\n};\n\n/** `/templates/how-to/sections/title must NOT have additional properties (foo)`. */\nfunction describeError(error: ErrorObject): string {\n const where = error.instancePath || \"/\";\n\n if (error.keyword === \"not\") {\n for (const [name, why] of Object.entries(NOT_CONSTRAINTS)) {\n if (error.schemaPath.includes(name)) return `${where} ${why}`;\n }\n }\n\n const params = error.params as { additionalProperty?: unknown };\n const extra =\n typeof params.additionalProperty === \"string\" ? ` (\"${params.additionalProperty}\")` : \"\";\n return `${where} ${error.message ?? \"is invalid\"}${extra}`;\n}\n\n/**\n * Validate a parsed, dereferenced template file, filling in rule defaults.\n *\n * Throws `LintError` naming `source` and the offending instance path. The\n * pre-rewrite loader threw a bare \"Template is invalid\" and passed the real\n * detail as `new Error(msg, {message: ...})` - an options bag that only\n * understands `cause` - so every schema error reached the user as four words.\n */\nexport function validateTemplateFile(data: unknown, source: string): TemplateFile {\n const instructions = findInstructions(data);\n if (instructions) throw new LintError(instructionsMessage(source, instructions));\n\n // Before Ajv, so a v1 file is told where its keys went rather than that it\n // has additional properties.\n const v1 = findV1File(data);\n if (v1) throw new LintError(`${source}: ${v1}`);\n\n const validate = fileValidator();\n if (!validate(data)) {\n const errors = validate.errors ?? [];\n const detail = errors.map(describeError).join(\"; \") || \"does not match the template schema\";\n throw new LintError(`${source} is not a valid template file: ${detail}.`);\n }\n const file = data as TemplateFile;\n checkTemplateFile(file, source);\n return file;\n}\n\n/* -------------------------------------------------------------------------- *\n * Loading\n * -------------------------------------------------------------------------- */\n\n/** Split `./templates.yaml#how-to` into its file part and template name. */\nfunction splitFragment(ref: string): { base: string; fragment: string | null } {\n const hash = ref.lastIndexOf(\"#\");\n if (hash === -1) return { base: ref, fragment: null };\n return { base: ref.slice(0, hash), fragment: ref.slice(hash + 1) || null };\n}\n\n/** The part of a ref an extension should be read off - a URL's path, not its query. */\nfunction extensionSource(ref: string, kind: RefKind): string {\n if (kind !== \"url\") return ref;\n try {\n return new URL(ref).pathname;\n } catch {\n return ref;\n }\n}\n\n/**\n * Parse a template file by extension. Anything unrecognized is parsed as YAML,\n * which is a superset of JSON, so an extensionless URL still loads.\n */\nfunction parseTemplateFile(raw: string, source: string, kind: RefKind): unknown {\n const lower = extensionSource(source, kind).toLowerCase();\n if (lower.endsWith(\".json\")) {\n try {\n return JSON.parse(raw) as unknown;\n } catch (err) {\n throw new LintError(`${source} is not valid JSON: ${errorMessage(err)}`);\n }\n }\n try {\n return parseYaml(raw) as unknown;\n } catch (err) {\n throw new LintError(`${source} is not valid YAML: ${errorMessage(err)}`);\n }\n}\n\n/**\n * Read a local template file, saying which way the read failed.\n *\n * Every failure used to be reported as \"not found\", which is the one wording\n * that contradicts `ls -la`: a directory named `templates.yaml` (EISDIR), a\n * file the user cannot open (EACCES), and a process out of descriptors\n * (EMFILE) are three different problems with three different fixes, and the\n * reader was sent after a path that is plainly there. Only ENOENT is a missing\n * file; anything else keeps the OS's own message.\n */\nasync function readText(ref: string): Promise<string> {\n try {\n return await readFile(ref, \"utf8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code === \"ENOENT\") {\n throw new LintError(`Template file not found: \"${ref}\".`);\n }\n throw new LintError(\n `Template file \"${ref}\" could not be read: ${errorMessage(err)}`,\n );\n }\n}\n\nconst urlCache = new Map<string, TemplateFile>();\n\n/**\n * Drop the parsed-template caches.\n *\n * Nothing in the CLI needs this: a process lints one docset and exits, and the\n * caches are what keep a tree of one doctype from re-reading and re-validating\n * the same template per page. It exists for the other caller - a long-lived\n * process using this as a library - where the two behave differently: the\n * memory grows with the number of distinct refs seen, and a `urlCache` entry\n * for a remote template is served for the life of the process, so a template\n * republished upstream is never picked up.\n */\nexport function clearTemplateCaches(): void {\n builtinCache.clear();\n urlCache.clear();\n}\n\nasync function fetchText(ref: string, timeoutMs: number): Promise<string> {\n let res: Response;\n try {\n res = await fetch(ref, { signal: AbortSignal.timeout(timeoutMs) });\n } catch (err) {\n const e = err as Error;\n if (e.name === \"TimeoutError\" || e.name === \"AbortError\") {\n throw new LintError(\n `Failed to fetch template file \"${ref}\": timed out after ${timeoutMs}ms.`,\n );\n }\n throw new LintError(`Failed to fetch template file \"${ref}\": ${e.message}`);\n }\n if (!res.ok) {\n throw new LintError(`Failed to fetch template file \"${ref}\": HTTP ${res.status}.`);\n }\n return await res.text();\n}\n\n/** Resolve every `$ref` in place, so validation never sees one. */\nasync function dereferenceTemplates(\n data: Record<string, unknown>,\n source: string,\n): Promise<Record<string, unknown>> {\n try {\n return await dereference<Record<string, unknown>>(data, DEREFERENCE_OPTIONS);\n } catch (err) {\n throw new LintError(`${source}: could not resolve a \"$ref\": ${errorMessage(err)}`);\n }\n}\n\n/** Load, dereference, and validate a whole template file. */\nexport async function loadTemplateFile(\n ref: string,\n options: LoadTemplateOptions = {},\n): Promise<TemplateFile> {\n const { kind } = classifyRef(ref);\n if (kind === \"builtin\") {\n throw new LintError(\n `\"${ref}\" is a built-in template id, not a template file. Load it with loadTemplate().`,\n );\n }\n\n const cached = kind === \"url\" ? urlCache.get(ref) : undefined;\n if (cached) return cached;\n\n const raw =\n kind === \"url\"\n ? await fetchText(ref, options.timeoutMs ?? DEFAULT_TIMEOUT_MS)\n : await readText(ref);\n\n const parsed = parseTemplateFile(raw, ref, kind);\n if (!isRecord(parsed)) {\n throw new LintError(\n `${ref} is not a template file: expected an object at the top level, got ${\n parsed === null ? \"null\" : Array.isArray(parsed) ? \"an array\" : typeof parsed\n }.`,\n );\n }\n\n const file = validateTemplateFile(await dereferenceTemplates(parsed, ref), ref);\n if (kind === \"url\") urlCache.set(ref, file);\n return file;\n}\n\n/**\n * Resolve a single template.\n *\n * A built-in id names one directly. A file or URL may name one inside itself\n * with a `#` fragment; without a fragment a single-template file resolves\n * unambiguously and anything else is an error listing what is on offer.\n *\n * `extends` is left unresolved - see `resolveExtends`.\n */\nexport async function loadTemplate(\n ref: string,\n options: LoadTemplateOptions = {},\n): Promise<Template> {\n const { base, fragment } = splitFragment(ref);\n const { kind } = classifyRef(base);\n\n if (kind === \"builtin\") {\n // A fragment here was silently dropped, so `tgdp:how-to:1.6#typo` loaded\n // `tgdp:how-to:1.6` and succeeded - the same quiet-wrong-answer as the\n // prototype lookup below, where a configuration error selects a different\n // template than the author wrote and nothing says so. A built-in id names\n // exactly one template, so there is nothing a fragment could select.\n if (fragment !== null) {\n throw new LintError(\n `\"${ref}\" adds a \"#${fragment}\" fragment to a built-in template id. ` +\n `A built-in id names one template on its own - drop the fragment and ` +\n `use \"${base}\". Fragments name a template inside a file, as in ` +\n `\"./templates.yaml#how-to\".`,\n );\n }\n if (!BUILTINS.has(base)) {\n const available = [...BUILTINS.keys()].join(\", \");\n throw new LintError(\n `Unknown built-in template \"${base}\". Available: ${available || \"(none)\"}.`,\n );\n }\n return loadBuiltin(base);\n }\n\n const file = await loadTemplateFile(base, options);\n const templates = file.templates ?? {};\n const names = Object.keys(templates);\n\n if (fragment !== null) {\n // An own-property check, not a truthiness test on the lookup. `templates`\n // is a plain object parsed from YAML, so `#constructor` and `#toString`\n // name members it inherits from `Object.prototype`. Those are truthy, so\n // such a fragment sailed past this guard and a function came back as a\n // template - one with no `sections`, which checks the document against\n // nothing. The bad fragment therefore produced silence rather than an\n // error: the page was reported as passing, not as naming a template that\n // does not exist.\n const named = Object.hasOwn(templates, fragment)\n ? templates[fragment]\n : undefined;\n if (named === undefined) {\n throw new LintError(\n `${base} has no template named \"${fragment}\". Available: ${names.join(\", \") || \"(none)\"}.`,\n );\n }\n return named;\n }\n\n const [only] = Object.values(templates);\n if (names.length === 1 && only !== undefined) return only;\n if (names.length === 0) throw new LintError(`${base} defines no templates.`);\n // Past both branches above, `names.length` is at least two, so `names[0]` is\n // there and the example fragment is never empty. The `?? \"\"` is\n // `noUncheckedIndexedAccess` paperwork rather than a case to look for.\n throw new LintError(\n `${base} defines ${names.length} templates; name one with a \"#\" fragment ` +\n `(e.g. \"${base}#${names[0] ?? \"\"}\"). Available: ${names.join(\", \")}.`,\n );\n}\n\n/* -------------------------------------------------------------------------- *\n * Inheritance\n * -------------------------------------------------------------------------- */\n\n/** How `resolveExtends` turns an `extends` ref into a template. */\nexport type TemplateResolver = (ref: string) => Promise<Template>;\n\n/**\n * Merge a child template onto its parent.\n *\n * Recursion follows `sections` and stops there. A rule's own keys are units:\n * overriding `contains` means replacing it, not merging a child's `min` into\n * the parent's `max` and hoping the pair still means something. But `sections`\n * is a container, not a rule. Replacing it wholesale would mean that tightening\n * one nested rule silently discards every sibling the parent declared, which is\n * the opposite of what `extends` is for.\n *\n * `sections` is a list in v2, so \"merges by key\" now means \"merges by `id`\". A\n * child rule carrying an id the parent also uses replaces that rule where the\n * parent had it, keeping the parent's order. A child rule with no id, or with\n * an id the parent does not use, is appended. Every other key the child sets\n * replaces the parent's outright, `repeat` included: a repeated run is one\n * unit, and merging two of them by position would be guesswork.\n */\nfunction mergeRuleLists(\n parent: Rule[] | undefined,\n child: Rule[] | undefined,\n): Rule[] | undefined {\n if (!parent) return child;\n if (!child) return parent;\n\n // Parent order first, so inherited rules keep the document order the parent\n // declared and child-only additions land at the end.\n const merged: Rule[] = [...parent];\n for (const childRule of child) {\n const id = childRule.id;\n const index =\n id === undefined ? -1 : merged.findIndex((rule) => rule.id === id);\n const target = index === -1 ? undefined : merged[index];\n if (target === undefined) merged.push(childRule);\n else merged[index] = mergeRules(target, childRule);\n }\n return merged;\n}\n\nfunction mergeRules(parent: Rule, child: Rule): Rule {\n // `sections` is dropped from both spreads and merged on its own. Every other\n // key replaces outright, which is what a spread does; sections merge by `id`,\n // which it cannot. Leaving the child's raw array in the spread and then\n // overwriting it worked, but it read as though the spread were the whole\n // answer.\n const sections = mergeRuleLists(parent.sections, child.sections);\n const { sections: _parentSections, ...parentRest } = parent;\n const { sections: _childSections, ...childRest } = child;\n const merged: Rule = { ...parentRest, ...childRest };\n // `!== undefined` rather than truthiness. The two are equivalent here, since\n // `mergeRuleLists` returns `Rule[] | undefined` and an empty array is truthy\n // in any case - but a rule may legitimately carry `sections: []`, meaning it\n // allows none, and a reader should not have to know that `[]` survives a\n // truthiness test to be sure that case is kept.\n if (sections !== undefined) merged.sections = sections;\n return merged;\n}\n\nfunction mergeTemplates(parent: Template, child: Template): Template {\n // Shaped like `mergeRules` above, and for the same reasons: merge first,\n // drop `sections` from both spreads, and test for `undefined` rather than\n // truthiness.\n const sections = mergeRuleLists(parent.sections, child.sections);\n const { sections: _parentSections, ...parentRest } = parent;\n const { sections: _childSections, ...childRest } = child;\n const merged: Template = { ...parentRest, ...childRest };\n if (sections !== undefined) merged.sections = sections;\n // The chain is resolved; leaving `extends` on would invite resolving twice.\n delete merged.extends;\n return merged;\n}\n\n/**\n * Resolve a template's `extends` chain, innermost first.\n *\n * `load` is injected because a relative `extends` is relative to the file the\n * child came from, which this function has no way to know. `chain` is internal\n * bookkeeping for cycle detection.\n */\nexport async function resolveExtends(\n template: Template,\n load: TemplateResolver = loadTemplate,\n chain: string[] = [],\n): Promise<Template> {\n const parentRef = template.extends;\n if (parentRef === undefined) return template;\n\n if (chain.includes(parentRef)) {\n throw new LintError(\n `Template \"extends\" cycle: ${[...chain, parentRef].join(\" -> \")}.`,\n );\n }\n\n const parent = await resolveExtends(await load(parentRef), load, [...chain, parentRef]);\n return mergeTemplates(parent, template);\n}\n\n/* -------------------------------------------------------------------------- *\n * Resolution relative to the declaring file\n * -------------------------------------------------------------------------- */\n\n/**\n * Re-base a ref against the file that declared it.\n *\n * A built-in id, a URL, and an absolute path all name themselves and are\n * returned unchanged. A relative path means \"beside the file I am written in\",\n * which is the one reading `loadTemplate` cannot produce on its own - it reads\n * against the process working directory, so `extends: ./base.yaml` in\n * `tpl/house.yaml` looked for `./base.yaml` at the cwd and found either nothing\n * or, worse, an unrelated file of that name.\n */\nexport function refRelativeTo(baseRef: string, ref: string): string {\n const { base, fragment } = splitFragment(ref);\n if (classifyRef(base).kind !== \"file\" || isAbsolute(base)) return ref;\n\n const { base: fromBase } = splitFragment(baseRef);\n const from = classifyRef(fromBase).kind;\n\n // A template fetched over HTTP names its neighbours the same way a local one\n // does, and `./base.yaml` beside it is a URL, not a path. Resolved as a path\n // it became a read of the process working directory - a local file quietly\n // standing in for the remote one, or a \"file not found\" naming a path that\n // appears nowhere in the template.\n if (from === \"url\") {\n const rebased = new URL(base, fromBase).href;\n return fragment === null ? rebased : `${rebased}#${fragment}`;\n }\n\n if (from !== \"file\") return ref;\n\n const rebased = resolvePath(dirname(fromBase), base);\n return fragment === null ? rebased : `${rebased}#${fragment}`;\n}\n\n/**\n * Load a template with its `extends` chain resolved, re-basing each relative\n * ref against the file that declared it.\n *\n * This is what a caller should use. `resolveExtends` stays exported for callers\n * that supply their own resolver, but its default is the cwd-relative\n * `loadTemplate`, and reaching that default silently is the bug this exists to\n * avoid - `.then(resolveExtends)` passes one argument, so the default is\n * exactly what you get.\n */\nexport async function loadResolvedTemplate(\n ref: string,\n options: LoadTemplateOptions = {},\n chain: string[] = [],\n): Promise<Template> {\n // Seeded with this ref when the caller started here, so the reported cycle\n // starts where the reader did. Chained from the parent only, `a -> b -> a`\n // was reported as `b -> a -> b`: the file the run was pointed at never\n // appeared in the cycle it was said to be part of, which is the one name in\n // the message the reader can act on.\n const seen = chain.length === 0 ? [ref] : chain;\n const template = await loadTemplate(ref, options);\n const parentRef = template.extends;\n if (parentRef === undefined) return template;\n\n const absolute = refRelativeTo(ref, parentRef);\n if (seen.includes(absolute)) {\n throw new LintError(\n `Template \"extends\" cycle: ${[...seen, absolute].join(\" -> \")}.`,\n );\n }\n\n const parent = await loadResolvedTemplate(absolute, options, [\n ...seen,\n absolute,\n ]);\n return mergeTemplates(parent, template);\n}\n","/**\n * The package root, for assets that ship beside the code.\n *\n * Some files are read by path at runtime rather than imported: a JSON Schema a\n * validator is pointed at, a template a linter loads. They live at the package\n * root (`schemas/<tool>/…`), listed in `files`, and are reached by walking up\n * from the calling module until a `package.json` appears. That is the one\n * rule that holds both in the source tree, where a module sits two or three\n * directories down, and in the bundle, where it sits in `dist/`.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ToolError } from \"./errors.js\";\n\nexport function packageRoot(moduleUrl: string): string {\n let dir = dirname(fileURLToPath(moduleUrl));\n for (;;) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) {\n // A `ToolError`, not a bare one: the bin runner renders anything else as\n // \"Unexpected error:\" with a stack trace, which is what it says about a\n // bug. A package whose files did not ship is an operational failure and\n // reads as one line and exit 2, like every other.\n throw new ToolError(`No package.json above ${fileURLToPath(moduleUrl)}`);\n }\n dir = parent;\n }\n}\n","{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"manni-lint:template:2\",\n \"title\": \"manni lint template file\",\n \"description\": \"A template file: named doctype templates, plus the reusable fragments they point at with `$ref`. Validated after dereferencing, so no `$ref` survives to be seen here. A template is itself a rule: it describes the page, and it takes every rule key plus `title`, `types` and `extends`.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"templates\"],\n \"properties\": {\n \"$schema\": {\n \"description\": \"URL of this schema, so an editor can offer completion. Read by editors, never by the linter.\",\n \"type\": \"string\"\n },\n \"info\": {\n \"description\": \"Free-form metadata about the file (title, version, author). Never read by the linter; declared so a file that carries it is not rejected.\",\n \"type\": \"object\"\n },\n \"templates\": {\n \"description\": \"The doctype templates this file defines, keyed by name.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"patternProperties\": {\n \"^[A-Za-z][A-Za-z0-9-_]*$\": { \"$ref\": \"#/definitions/template\" }\n }\n },\n \"components\": {\n \"description\": \"Reusable fragments, targeted by `$ref` from elsewhere in the file. Left unconstrained: a fragment is validated where it is inlined, not where it is declared.\",\n \"type\": \"object\"\n }\n },\n \"definitions\": {\n \"min\": {\n \"description\": \"Fewest occurrences. Absent means one. Deliberately carries no JSON Schema `default`, and neither does any other key in this file: Ajv's `useDefaults` would write one in at load time, and a written-in value is indistinguishable from a value the author typed, so it wins the `extends` merge against the parent's real value. The code reads `undefined` instead.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max\": {\n \"description\": \"Most occurrences. Absent is unbounded, so write `max: 1` for exactly once and `max: 0` to forbid. Must be at least `min` where both are written; the loader checks that, because JSON Schema cannot compare two siblings.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"id\": {\n \"description\": \"Handle for this rule, unique among its siblings. It appears in messages, and `extends` targets it to replace one inherited rule in place.\",\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z][A-Za-z0-9-_]*$\"\n },\n \"description\": {\n \"description\": \"Prose description of what the rule is for. Never checked.\",\n \"type\": \"string\"\n },\n \"heading\": {\n \"description\": \"The heading of the section this rule describes. Absent means any heading, or none. A string is exact text, a list is one-of, `{ pattern }` is an unanchored regular expression, and `false` means the section has no heading of its own.\",\n \"oneOf\": [\n { \"type\": \"string\", \"minLength\": 1 },\n {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"type\": \"string\", \"minLength\": 1 }\n },\n {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"pattern\"],\n \"properties\": {\n \"pattern\": { \"type\": \"string\", \"minLength\": 1 }\n }\n },\n { \"const\": false }\n ]\n },\n \"attributes\": {\n \"description\": \"Literal attributes the node must carry. A string is the required value; `true` requires the attribute to be present, and `false` requires it to be absent.\",\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [{ \"type\": \"string\" }, { \"type\": \"boolean\" }]\n }\n },\n \"oneOfSequenceOrContains\": {\n \"description\": \"A rule says what it holds in order (`sequence`) or in any order (`contains`), never both.\",\n \"type\": \"object\",\n \"not\": { \"required\": [\"sequence\", \"contains\"] }\n },\n \"noHeadingOnRepeat\": {\n \"description\": \"`repeat` groups sibling rules into one repeated unit, so the group has no heading of its own. Put the heading on the first rule inside it.\",\n \"type\": \"object\",\n \"not\": { \"required\": [\"heading\", \"repeat\"] }\n },\n \"noInstructions\": {\n \"description\": \"`instructions` was the language-model hook of doc-structure-lint. manni lint is deterministic and has no model, so a template carrying it is rejected outright rather than silently ignored; the loader turns this into a migration message pointing at manni docevals.\",\n \"type\": \"object\",\n \"not\": { \"required\": [\"instructions\"] }\n },\n \"template\": {\n \"description\": \"One doctype template. A template is a rule describing the page itself, so it takes every rule key, plus `title`, `types` and `extends`.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"allOf\": [\n { \"$ref\": \"#/definitions/noInstructions\" },\n { \"$ref\": \"#/definitions/oneOfSequenceOrContains\" },\n { \"$ref\": \"#/definitions/noHeadingOnRepeat\" }\n ],\n \"properties\": {\n \"title\": {\n \"description\": \"Human-readable name for the template, shown by `manni lint templates`.\",\n \"type\": \"string\"\n },\n \"types\": {\n \"description\": \"Doctypes this template serves, matched against a page's `type` frontmatter.\",\n \"type\": \"array\",\n \"items\": { \"type\": \"string\", \"minLength\": 1 }\n },\n \"extends\": {\n \"description\": \"Template reference (built-in id, path, or URL, optionally with a `#name` fragment) whose rules this template inherits.\",\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"id\": { \"$ref\": \"#/definitions/id\" },\n \"description\": { \"$ref\": \"#/definitions/description\" },\n \"heading\": { \"$ref\": \"#/definitions/heading\" },\n \"repeat\": { \"$ref\": \"#/definitions/repeat\" },\n \"min\": {\n \"description\": \"Refused on a template: a page is one page. Declared here only so the loader can say that in a sentence, rather than leaving Ajv to report an unexpected key.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"max\": {\n \"description\": \"Refused on a template, for the same reason as `min`.\",\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"sequence\": { \"$ref\": \"#/definitions/sequence\" },\n \"contains\": { \"$ref\": \"#/definitions/blockRules\" },\n \"sections\": { \"$ref\": \"#/definitions/rules\" }\n }\n },\n \"rule\": {\n \"description\": \"One rule. It describes a section of the page, or, with `repeat`, a run of sections matched as one unit.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"allOf\": [\n { \"$ref\": \"#/definitions/noInstructions\" },\n { \"$ref\": \"#/definitions/oneOfSequenceOrContains\" },\n { \"$ref\": \"#/definitions/noHeadingOnRepeat\" }\n ],\n \"properties\": {\n \"id\": { \"$ref\": \"#/definitions/id\" },\n \"description\": { \"$ref\": \"#/definitions/description\" },\n \"heading\": { \"$ref\": \"#/definitions/heading\" },\n \"repeat\": { \"$ref\": \"#/definitions/repeat\" },\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"sequence\": { \"$ref\": \"#/definitions/sequence\" },\n \"contains\": { \"$ref\": \"#/definitions/blockRules\" },\n \"sections\": { \"$ref\": \"#/definitions/rules\" }\n }\n },\n \"rules\": {\n \"description\": \"Rules for the subsections, in document order.\",\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/definitions/rule\" }\n },\n \"repeat\": {\n \"description\": \"Rules matched in order as one unit, repeated by this rule's `min` and `max`.\",\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/definitions/rule\" }\n },\n \"sequence\": {\n \"description\": \"What the section holds, in order. Each entry is one run of one content kind.\",\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": {\n \"allOf\": [\n { \"$ref\": \"#/definitions/blockRules\" },\n { \"type\": \"object\", \"maxProperties\": 1 }\n ]\n }\n },\n \"blockRules\": {\n \"description\": \"Block rules, keyed by content kind. The key is plural because it carries a count: the node model says `codeBlock`, a template says `codeBlocks: { min: 1 }`.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"minProperties\": 1,\n \"properties\": {\n \"paragraphs\": { \"$ref\": \"#/definitions/paragraphs\" },\n \"codeBlocks\": { \"$ref\": \"#/definitions/codeBlocks\" },\n \"lists\": { \"$ref\": \"#/definitions/lists\" },\n \"tables\": { \"$ref\": \"#/definitions/tables\" },\n \"admonitions\": { \"$ref\": \"#/definitions/admonitions\" },\n \"images\": { \"$ref\": \"#/definitions/images\" },\n \"blockquotes\": { \"$ref\": \"#/definitions/counted\" },\n \"definitionLists\": { \"$ref\": \"#/definitions/counted\" },\n \"elements\": { \"$ref\": \"#/definitions/elements\" }\n }\n },\n \"counted\": {\n \"description\": \"A block rule that only counts.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" }\n }\n },\n \"paragraphs\": {\n \"description\": \"Paragraph requirements.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"pattern\": {\n \"description\": \"Unanchored regular expression every paragraph in the run must match.\",\n \"type\": \"string\",\n \"minLength\": 1\n }\n }\n },\n \"codeBlocks\": {\n \"description\": \"Code block requirements.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"language\": {\n \"description\": \"Language every code block must be tagged with, as the node model spells it. A list is one-of: the block must declare one of them.\",\n \"oneOf\": [\n { \"type\": \"string\", \"minLength\": 1 },\n {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"type\": \"string\", \"minLength\": 1 }\n }\n ]\n },\n \"fenceInfo\": {\n \"description\": \"Info-string tail after the language, where the format carries one.\",\n \"type\": \"string\"\n }\n }\n },\n \"lists\": {\n \"description\": \"List requirements.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"ordered\": {\n \"description\": \"Whether the list must be ordered. Absent accepts either.\",\n \"type\": \"boolean\"\n },\n \"items\": { \"$ref\": \"#/definitions/listItems\" }\n }\n },\n \"listItems\": {\n \"description\": \"Requirements applied to every item of every list in the run. Recurses arbitrarily deep.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"allOf\": [{ \"$ref\": \"#/definitions/oneOfSequenceOrContains\" }],\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"sequence\": { \"$ref\": \"#/definitions/sequence\" },\n \"contains\": { \"$ref\": \"#/definitions/blockRules\" }\n }\n },\n \"tables\": {\n \"description\": \"Table requirements.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"columns\": {\n \"description\": \"The header cells, in order.\",\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" }\n }\n }\n },\n \"admonitions\": {\n \"description\": \"Admonition requirements.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"variant\": {\n \"description\": \"Which flavor of admonition. The node model's `variant`, not any one format's spelling.\",\n \"enum\": [\n \"note\",\n \"tip\",\n \"important\",\n \"caution\",\n \"warning\",\n \"danger\"\n ]\n }\n }\n },\n \"images\": {\n \"description\": \"Image requirements.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"url\": {\n \"description\": \"Where the image must point.\",\n \"type\": \"string\"\n },\n \"alt\": {\n \"description\": \"Alternative text the image must carry.\",\n \"type\": \"string\"\n },\n \"attributes\": { \"$ref\": \"#/definitions/attributes\" }\n }\n },\n \"elements\": {\n \"description\": \"Named-wrapper requirements. `sequence` and `contains` here describe what the element holds, which is never the enclosing section's content.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"allOf\": [{ \"$ref\": \"#/definitions/oneOfSequenceOrContains\" }],\n \"properties\": {\n \"min\": { \"$ref\": \"#/definitions/min\" },\n \"max\": { \"$ref\": \"#/definitions/max\" },\n \"tag\": {\n \"description\": \"The element's name, as an author of the format would write it. A list is one-of: an element counts when it carries any of them.\",\n \"oneOf\": [\n { \"type\": \"string\", \"minLength\": 1 },\n {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"type\": \"string\", \"minLength\": 1 }\n }\n ]\n },\n \"attributes\": { \"$ref\": \"#/definitions/attributes\" },\n \"sequence\": { \"$ref\": \"#/definitions/sequence\" },\n \"contains\": { \"$ref\": \"#/definitions/blockRules\" }\n }\n }\n }\n}\n","{\n \"$comment\": \"Built-in doctype templates derived from The Good Docs Project templates, pinned to release v1.6.0 (\\\"Iron\\\"): https://gitlab.com/tgdp/templates/-/tree/v1.6.0. Each entry's `file` is a YAML template beside this manifest; `source` is the upstream Markdown it was derived from, vendored under test/lint/fixtures/tgdp/ and linted against the derived template so the two cannot drift. Run `npm run check:tgdp-pin` to see whether upstream has moved past the pin.\",\n \"vendor\": \"tgdp\",\n \"upstream\": \"https://gitlab.com/tgdp/templates\",\n \"pin\": \"v1.6.0\",\n \"templates\": [\n {\n \"id\": \"tgdp:how-to:1.6\",\n \"file\": \"tgdp/how-to.yaml\",\n \"title\": \"How-to guide (The Good Docs Project)\",\n \"types\": [\"how-to\"],\n \"source\": \"how-to/template_how-to.md\"\n },\n {\n \"id\": \"tgdp:tutorial:1.6\",\n \"file\": \"tgdp/tutorial.yaml\",\n \"title\": \"Tutorial (The Good Docs Project)\",\n \"types\": [\"tutorial\"],\n \"source\": \"tutorial/template_tutorial.md\"\n },\n {\n \"id\": \"tgdp:reference:1.6\",\n \"file\": \"tgdp/reference.yaml\",\n \"title\": \"Reference (The Good Docs Project)\",\n \"types\": [\"reference\"],\n \"source\": \"reference/template_reference.md\"\n },\n {\n \"id\": \"tgdp:concept:1.6\",\n \"file\": \"tgdp/concept.yaml\",\n \"title\": \"Concept (The Good Docs Project)\",\n \"types\": [\"concept\", \"explanation\"],\n \"source\": \"concept/template_concept.md\"\n },\n {\n \"id\": \"tgdp:troubleshooting:1.6\",\n \"file\": \"tgdp/troubleshooting.yaml\",\n \"title\": \"Troubleshooting (The Good Docs Project)\",\n \"types\": [\"troubleshooting\"],\n \"source\": \"troubleshooting/template_troubleshooting.md\"\n },\n {\n \"id\": \"tgdp:release-notes:1.6\",\n \"file\": \"tgdp/release-notes.yaml\",\n \"title\": \"Release notes (The Good Docs Project)\",\n \"types\": [\"release-notes\"],\n \"source\": \"release-notes/template_release-notes.md\"\n },\n {\n \"id\": \"tgdp:readme:1.6\",\n \"file\": \"tgdp/readme.yaml\",\n \"title\": \"README (The Good Docs Project)\",\n \"types\": [\"readme\"],\n \"source\": \"readme/template_readme.md\"\n }\n ]\n}\n","/**\n * Decide which template describes a given page.\n *\n * The headline case is the last one: a page declares what it is in its\n * frontmatter (`type: how-to`), and the template follows from that. It is the\n * same key `manni meta`'s OKF, Diataxis, and TGDP schemas validate, so a repo\n * that already types its pages gets routing for free, and one run can lint a\n * whole tree with each page checked against the doctype it claims.\n *\n * The precedence chain mirrors docmeta's `resolveSchemaSet`: an explicit\n * instruction beats a per-page declaration, which beats repo policy, which\n * beats the page's own vocabulary, which beats a blanket default.\n *\n * 1. `--template` an operator overriding everything, for one run\n * 2. `$template` this page, specifically, is an exception\n * 3. config override repo policy: \"everything under docs/api is a reference\"\n * 4. `type` what the page says it is\n * 5. config default what to assume when a page says nothing\n *\n * Every step is recorded, because \"why was this page linted with that\n * template?\" is otherwise a question only the source can answer. `--explain`\n * prints the record.\n */\nimport picomatch from \"picomatch\";\nimport type { Template, TemplateFile } from \"./template.js\";\n\n/** Where a resolution came from, in precedence order. */\nexport type ResolutionStage =\n | \"cli\"\n | \"frontmatter-template\"\n | \"config-override\"\n | \"type\"\n | \"config-default\";\n\nexport type SkipCause = \"no-type\" | \"unknown-type\";\n\nexport interface ResolutionStep {\n stage: ResolutionStage;\n /** What the stage found, or null when it had nothing to say. */\n ref: string | null;\n /** Human-readable account of what the stage saw. */\n detail: string;\n}\n\nexport interface Resolution {\n /** The template ref to lint with, or null when the page is not linted. */\n ref: string | null;\n /** Which stage decided, when one did. */\n stage: ResolutionStage | null;\n /** Why no template was found. Only set when `ref` is null. */\n cause?: SkipCause;\n /**\n * The `type` the page declared but that resolved to nothing. Set only for\n * `unknown-type`, so the caller can name it and suggest near misses.\n */\n unknownType?: string;\n /** Near-miss doctypes, for an unknown-type message. */\n suggestions?: string[];\n /**\n * Every doctype something serves, for an unknown-type message with no near\n * miss to offer. Carried on the resolution rather than looked up by each\n * reporter, because the type index does not reach them - which is how the\n * pretty reporter came to print the list and `--explain` came to print\n * nothing, for the same page.\n */\n knownTypes?: string[];\n /** The full chain, for `--explain`. */\n steps: ResolutionStep[];\n}\n\n/** Per-glob repo policy, from `manni.config.yaml`'s `lint.overrides`. */\nexport interface TemplateOverride {\n files: string;\n template: string;\n}\n\nexport interface TypeIndexEntry {\n /** Ref that `loadTemplate` understands. */\n ref: string;\n /** Where the mapping came from; later sources outrank earlier ones. */\n source: \"builtin\" | \"user\" | \"config\";\n}\n\n/** The frontmatter key a page uses to override its doctype's template. */\nexport const FILE_TEMPLATE_KEY = \"$template\";\n/** The frontmatter key a page uses to declare its doctype. */\nexport const TYPE_KEY = \"type\";\n\n/**\n * Build the doctype -> template map.\n *\n * Built-ins go in first and user templates overwrite them, so overriding\n * `how-to` for a repo is one file with `types: [how-to]` in it - no config, no\n * flag. Within each source, a later entry wins, which makes the last\n * `--templates` file the one that decides.\n */\nexport function buildTypeIndex(params: {\n builtins?: { id: string; types: string[] }[];\n /** User template files, in the order they were supplied. */\n userFiles?: { ref: string; file: TemplateFile }[];\n /**\n * The config's explicit `types:` map. Highest precedence of the three, because\n * it is the only one where someone wrote down this exact pairing on purpose -\n * `types:` on a template says what that template is for, while this says what\n * this repo does about a doctype.\n */\n explicitTypes?: Record<string, string>;\n}): Map<string, TypeIndexEntry> {\n const index = new Map<string, TypeIndexEntry>();\n\n for (const builtin of params.builtins ?? []) {\n for (const type of builtin.types) {\n index.set(type, { ref: builtin.id, source: \"builtin\" });\n }\n }\n\n for (const { ref, file } of params.userFiles ?? []) {\n for (const [name, template] of Object.entries(file.templates ?? {})) {\n for (const type of template.types ?? []) {\n index.set(type, { ref: `${ref}#${name}`, source: \"user\" });\n }\n }\n }\n\n for (const [type, ref] of Object.entries(params.explicitTypes ?? {})) {\n index.set(type, { ref, source: \"config\" });\n }\n\n return index;\n}\n\nconst matcherCache = new Map<string, (p: string) => boolean>();\n\n/** Drop the compiled override-glob matchers. See `clearCaches`. */\nexport function clearMatcherCache(): void {\n matcherCache.clear();\n}\n\nfunction matchesGlob(glob: string, filePath: string): boolean {\n let m = matcherCache.get(glob);\n if (!m) {\n m = picomatch(glob, { dot: true });\n matcherCache.set(glob, m);\n }\n // Globs are written with forward slashes whatever the platform uses.\n return m(filePath.replace(/\\\\/g, \"/\"));\n}\n\n/**\n * Doctypes close enough to a typo to be worth naming. Edit distance of one or\n * two on short strings, or a shared prefix - enough to catch `how-two` and\n * `refernce` without listing the whole vocabulary at someone.\n */\nfunction suggestTypes(unknown: string, known: Iterable<string>): string[] {\n const target = unknown.toLowerCase();\n const scored: { type: string; distance: number }[] = [];\n\n for (const type of known) {\n const distance = editDistance(target, type.toLowerCase());\n const threshold = target.length <= 4 ? 1 : 3;\n if (distance <= threshold) scored.push({ type, distance });\n }\n\n return scored\n .sort((a, b) => a.distance - b.distance || a.type.localeCompare(b.type))\n .slice(0, 3)\n .map((s) => s.type);\n}\n\n/**\n * Levenshtein, two rows. Inputs here are doctype slugs, so size is not a\n * concern.\n *\n * Each cell needs three neighbours: the one to its left, the one above, and\n * the one above-left. Only the one above is read out of the previous row; the\n * other two are carried in locals from the cell just written and the previous\n * `above`. So the loop reads no array slot back by a computed index, which is\n * what `noUncheckedIndexedAccess` cannot prove is filled.\n *\n * The characters are compared as code units for the same reason: `a[i]` is\n * typed `string | undefined`, so comparing the two would either need an\n * assertion or a guard for a case the loop bounds already rule out.\n * `charCodeAt` returns `NaN` past the end and `NaN !== NaN`, so an index that\n * did escape its bounds costs an edit rather than matching by accident - the\n * invariant expressed rather than asserted.\n */\nfunction editDistance(a: string, b: string): number {\n if (a === b) return 0;\n let prev = Array.from({ length: b.length + 1 }, (_, i) => i);\n // The answer when `a` is empty: every character of `b` is an insertion.\n let last = b.length;\n for (let i = 0; i < a.length; i++) {\n const row = [i + 1];\n let left = i + 1;\n let diagonal = i;\n for (const [j, above] of prev.slice(1).entries()) {\n const cost = a.charCodeAt(i) === b.charCodeAt(j) ? 0 : 1;\n const cell = Math.min(left + 1, above + 1, diagonal + cost);\n row.push(cell);\n diagonal = above;\n left = cell;\n }\n prev = row;\n last = left;\n }\n return last;\n}\n\n/** A frontmatter value that should be a template ref. Non-strings are ignored. */\nfunction refFromFrontmatter(\n frontmatter: Record<string, unknown> | null,\n key: string,\n): string | null {\n const value = frontmatter?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nexport interface ResolveParams {\n /** Path used for override glob matching. */\n filePath: string;\n /**\n * Absolute path of the same file, matched as a fallback.\n *\n * `overrides[].files` globs are written relative to the config file, while\n * `filePath` is relative to the working directory. Those agree only when the\n * tool is run from the config's own directory; anywhere else the glob matched\n * nothing, the page fell through to its own `type`, and the run exited 0 with\n * the repo's policy silently unapplied. The CLI now rebases the globs to\n * absolute, so matching the absolute path too is what makes them land.\n */\n absolutePath?: string;\n /** The page's frontmatter, or null when it carries none. */\n frontmatter: Record<string, unknown> | null;\n /** `--template`: applies to every file in the run. */\n cliTemplate?: string;\n /** Repo policy, first match wins. */\n overrides?: TemplateOverride[];\n /** Doctype -> template, from `buildTypeIndex`. */\n typeIndex?: Map<string, TypeIndexEntry>;\n /** Applied when a page declares no doctype and nothing else matches. */\n defaultTemplate?: string;\n}\n\nexport function resolveTemplateRef(params: ResolveParams): Resolution {\n const steps: ResolutionStep[] = [];\n const typeIndex = params.typeIndex ?? new Map<string, TypeIndexEntry>();\n\n const decide = (stage: ResolutionStage, ref: string): Resolution => ({\n ref,\n stage,\n steps,\n });\n\n if (params.cliTemplate) {\n steps.push({ stage: \"cli\", ref: params.cliTemplate, detail: \"--template\" });\n return decide(\"cli\", params.cliTemplate);\n }\n steps.push({ stage: \"cli\", ref: null, detail: \"--template not given\" });\n\n const fileTemplate = refFromFrontmatter(params.frontmatter, FILE_TEMPLATE_KEY);\n if (fileTemplate) {\n steps.push({\n stage: \"frontmatter-template\",\n ref: fileTemplate,\n detail: `${FILE_TEMPLATE_KEY} in frontmatter`,\n });\n return decide(\"frontmatter-template\", fileTemplate);\n }\n steps.push({\n stage: \"frontmatter-template\",\n ref: null,\n detail: `no ${FILE_TEMPLATE_KEY} in frontmatter`,\n });\n\n for (const override of params.overrides ?? []) {\n if (\n matchesGlob(override.files, params.filePath) ||\n (params.absolutePath !== undefined &&\n matchesGlob(override.files, params.absolutePath))\n ) {\n steps.push({\n stage: \"config-override\",\n ref: override.template,\n detail: `matched override \"${override.files}\"`,\n });\n return decide(\"config-override\", override.template);\n }\n }\n steps.push({\n stage: \"config-override\",\n ref: null,\n detail: (params.overrides ?? []).length\n ? \"no override glob matched\"\n : \"no overrides configured\",\n });\n\n const type = refFromFrontmatter(params.frontmatter, TYPE_KEY);\n if (type) {\n const entry = typeIndex.get(type);\n if (entry) {\n steps.push({\n stage: \"type\",\n ref: entry.ref,\n detail: `type: ${type} -> ${entry.source} template`,\n });\n return decide(\"type\", entry.ref);\n }\n\n // A declared type that resolves to nothing is a typo or a gap, and either\n // way silently not checking the page is the wrong answer.\n steps.push({\n stage: \"type\",\n ref: null,\n detail: `type: ${type} matches no template`,\n });\n return {\n ref: null,\n stage: null,\n cause: \"unknown-type\",\n unknownType: type,\n suggestions: suggestTypes(type, typeIndex.keys()),\n knownTypes: knownTypes(typeIndex),\n steps,\n };\n }\n steps.push({ stage: \"type\", ref: null, detail: \"no type in frontmatter\" });\n\n if (params.defaultTemplate) {\n steps.push({\n stage: \"config-default\",\n ref: params.defaultTemplate,\n detail: \"config default\",\n });\n return decide(\"config-default\", params.defaultTemplate);\n }\n steps.push({ stage: \"config-default\", ref: null, detail: \"no default configured\" });\n\n // An untyped page is manni meta's complaint, not this tool's: its OKF schema\n // already requires `type`. Skipping rather than failing is what lets you\n // point manni lint at a whole tree on day one.\n return { ref: null, stage: null, cause: \"no-type\", steps };\n}\n\n/** The doctypes a resolved index can serve, sorted, for error messages. */\nexport function knownTypes(index: Map<string, TypeIndexEntry>): string[] {\n return [...index.keys()].sort();\n}\n\nexport type { Template };\n","/**\n * Decide which rule describes which section, by alignment.\n *\n * A rule list is a regular expression over section predicates, and a document's\n * sibling sections are the string. The matcher compiles the first and aligns\n * the second against it at minimum cost:\n *\n * 1. Each rule contributes one predicate on a heading. `min`/`max` is counted\n * repetition, and `repeat:` is a parenthesised subexpression.\n * 2. Bounded counts expand into copies; an absent `max` becomes a self-loop.\n * 3. Four edits close the gap between rules and sections: a *match* (the\n * predicate holds), a *coercion* (a rule claiming one section takes a\n * section its heading rejects), a *skipped rule* (a required occurrence\n * consumes nothing) and a *skipped section* (no rule consumes it).\n * 4. Viterbi over a (sections + 1) x states lattice finds the cheapest edit\n * sequence. Deletions can form zero-consuming cycles, so each column is\n * closed with Dijkstra rather than a topological sweep; all weights are\n * non-negative.\n * 5. Skipped rules become `missing_section` (or one `missing_group` for a\n * `repeat` copy that is absent whole), skipped sections become\n * `unexpected_section`, and every match is handed to the content rules.\n *\n * The predecessor of this file walked the rules left to right with no\n * backtracking, and each of its eight hand-written behaviours is now a\n * consequence of a weight or a tie-break instead of a special case. The two it\n * could not express are what forced the change: a rule list with counted\n * repetition is not a sequence of one-shot decisions, and a greedy walk has to\n * guess which of two rules wants a section before it has seen the rest.\n *\n * Heading mismatches are deliberately not reported here. This module pairs; the\n * content rules report `heading_error` on the pair it produced. `validator.ts`\n * explains why the two are separate.\n */\nimport { LintError } from \"../types.js\";\nimport type { Finding, Position, SectionNode } from \"../types.js\";\nimport { headingMatches, isWildcard, occurrenceRange } from \"./template.js\";\nimport type { Rule } from \"./template.js\";\n\n/* -------------------------------------------------------------------------- *\n * The cost model, which is interface\n * -------------------------------------------------------------------------- */\n\n/**\n * What each edit costs, in the units the alignment minimises.\n *\n * These weights are **interface, not implementation**. They decide which\n * findings a document produces, so changing one changes the report for\n * documents nobody edited - the same class of change as renaming a flag.\n * `test/lint/unit/match.test.ts` pins them, and the templates reference prints\n * them.\n *\n * Skipping an occurrence at or above its rule's `min` is free; only a required\n * occurrence pays `skipRule`.\n *\n * Coercion is open only to a *required* occurrence of a rule whose `max` is 1.\n * Both halves of that earn their place. Without the `max: 1` half a repeating\n * rule adopts any stray section for 1 rather than letting it report as\n * unexpected for 2. Without the \"required\" half an optional rule does the same\n * thing for the same reason, and there it is plainly wrong: standing aside\n * costs an optional rule nothing, so coercing trades a clean report for a\n * heading error about a section the template never insisted on.\n */\nexport const ALIGNMENT_COSTS = {\n match: 0,\n coerce: 1,\n skipRule: 2,\n skipSection: 2,\n} as const;\n\n/**\n * How equal-cost alignments are settled, in order, after the total cost.\n *\n * Also interface: two of these decide real reports, and all three are stated in\n * words so the docs page and the code cannot drift apart.\n */\nexport const TIE_BREAKS = [\n \"a rule that names its heading beats a wildcard taking the same section\",\n \"a repeating rule prefers its sections adjacent\",\n \"earliest rule, then the smallest edit sequence under match < coerce < skip-rule < skip-section\",\n] as const;\n\n/**\n * Most states a compiled rule list may expand to.\n *\n * Counted repetition is expanded into copies, so `max: 100000` on a rule with\n * five subsections is a hundred thousand copies of five states and a lattice\n * nobody asked for. The cap turns that into a template error naming the file,\n * rather than a lint run that appears to hang.\n */\nexport const STATE_LIMIT = 2000;\n\n/* -------------------------------------------------------------------------- *\n * What the matcher hands on\n * -------------------------------------------------------------------------- */\n\n/** One rule paired with the section it claimed. */\nexport interface Match {\n /** The rule itself - a `repeat` group's member, never the group. */\n rule: Rule;\n section: SectionNode;\n /**\n * True when the rule was paired with a section whose heading does not\n * satisfy it, because nothing else could claim that section. Keeps the\n * precise \"Expected title X, but found Y\" report for the common one-for-one\n * case instead of degrading it into missing + unexpected.\n */\n coerced: boolean;\n}\n\nexport interface MatchResult {\n matches: Match[];\n findings: Finding[];\n}\n\nexport interface MatchOptions {\n /** Section these are the subsections of, for anchoring a trailing gap. */\n parent?: SectionNode | null;\n /** File the rules came from. Used only to name the state-cap failure. */\n source?: string;\n /** Template within that file. Used only to name the state-cap failure. */\n template?: string;\n}\n\n/* -------------------------------------------------------------------------- *\n * Compilation\n * -------------------------------------------------------------------------- */\n\n/**\n * One copy of a `repeat` group, and every leaf occurrence inside it.\n *\n * It exists so an absent copy can report once for the group. A copy whose\n * leaves were *all* skipped is a group that is not there at all, which reads\n * as one finding; a copy that matched some of them is a group that is there and\n * incomplete, whose absent members read better one by one.\n */\ninterface GroupCopy {\n rule: Rule;\n members: Occurrence[];\n}\n\n/** One occurrence of one rule: the chance to consume exactly one section. */\ninterface Occurrence {\n rule: Rule;\n /** Below the rule's `min`, so skipping it costs rather than being free. */\n required: boolean;\n /** Required and `max: 1`, so it may take a section its heading rejects. */\n coercible: boolean;\n /** Says nothing about its heading, so it loses ties to a rule that does. */\n wildcard: boolean;\n /** Enclosing `repeat` copies, outermost first. */\n groups: GroupCopy[];\n}\n\ninterface Eps {\n from: number;\n to: number;\n cost: number;\n rank: number;\n /** Set when this edge is a rule being skipped rather than structure. */\n occ: Occurrence | null;\n}\n\ninterface Automaton {\n states: number;\n start: number;\n accept: number;\n /** The occurrence a state may consume a section through, if any. */\n consume: (Occurrence | null)[];\n /** Where that consumption lands. */\n consumeTo: number[];\n epsOut: Eps[][];\n epsIn: Eps[][];\n /** States strictly inside a repetition, where a skipped section breaks a run. */\n inRepeat: boolean[];\n}\n\n/**\n * Edit ranks, used only to settle a tie the costs and the two structural\n * tie-breaks left open. Structural epsilons - entering, repeating and leaving a\n * self-loop - rank with `match`, because they are not edits at all and a path\n * must be free to leave a loop before it starts skipping the rules inside it.\n */\nconst RANK = {\n match: 0,\n structure: 0,\n coerce: 1,\n skipRule: 2,\n skipSection: 3,\n} as const;\n\nconst NO_EPS: Eps[] = [];\n\n/**\n * States the rule list expands to, counted without building anything.\n *\n * Checked before compilation so a template with an absurd `max` fails on its\n * own terms rather than by exhausting memory. The two extra states per\n * unbounded rule are its self-loop's entry and exit.\n */\nfunction expandedStates(rules: Rule[]): number {\n let total = 1;\n for (const rule of rules) total += ruleStates(rule);\n return total;\n}\n\nfunction ruleStates(rule: Rule): number {\n let unit = 1;\n if (rule.repeat) {\n unit = 0;\n for (const member of rule.repeat) unit += ruleStates(member);\n }\n const { min, max } = occurrenceRange(rule);\n if (max === null) return unit * (Math.max(min, 0) + 1) + 2;\n return unit * Math.max(0, max);\n}\n\nfunction listAt<T>(lists: T[][], index: number): T[] {\n const list = lists[index];\n if (list) return list;\n const created: T[] = [];\n lists[index] = created;\n return created;\n}\n\n/**\n * Compile a rule list into an automaton over section predicates.\n *\n * Bounded repetition is unrolled: `min: 1, max: 3` is three copies, the first\n * required and the rest free to skip. An unbounded `max` is a self-loop after\n * the required copies, which is the only construct here that can consume\n * nothing and return to where it started - hence the Dijkstra in the alignment.\n */\nfunction compile(rules: Rule[]): Automaton {\n const consume: (Occurrence | null)[] = [];\n const consumeTo: number[] = [];\n const epsOut: Eps[][] = [];\n const epsIn: Eps[][] = [];\n const inRepeat: boolean[] = [];\n\n const newState = (): number => {\n consume.push(null);\n consumeTo.push(-1);\n epsOut.push([]);\n epsIn.push([]);\n inRepeat.push(false);\n return consume.length - 1;\n };\n\n const eps = (\n from: number,\n to: number,\n cost: number,\n rank: number,\n occ: Occurrence | null,\n ): void => {\n const edge: Eps = { from, to, cost, rank, occ };\n listAt(epsOut, from).push(edge);\n listAt(epsIn, to).push(edge);\n };\n\n const leaf = (from: number, occ: Occurrence): number => {\n const to = newState();\n consume[from] = occ;\n consumeTo[from] = to;\n // Skipping the occurrence: free when the rule can do without it.\n eps(from, to, occ.required ? ALIGNMENT_COSTS.skipRule : 0, RANK.skipRule, occ);\n return to;\n };\n\n /** One copy of a rule's unit: its members, or the rule's own occurrence. */\n const buildCopy = (\n rule: Rule,\n from: number,\n groups: GroupCopy[],\n required: boolean,\n ): number => {\n if (rule.repeat) {\n const copy: GroupCopy = { rule, members: [] };\n const nested = [...groups, copy];\n let cursor = from;\n for (const member of rule.repeat) {\n cursor = buildRule(member, cursor, nested, required);\n }\n return cursor;\n }\n const { max } = occurrenceRange(rule);\n const occ: Occurrence = {\n rule,\n required,\n coercible: required && max === 1,\n wildcard: isWildcard(rule),\n groups,\n };\n for (const group of groups) group.members.push(occ);\n return leaf(from, occ);\n };\n\n function buildRule(\n rule: Rule,\n from: number,\n groups: GroupCopy[],\n context: boolean,\n ): number {\n const { min, max } = occurrenceRange(rule);\n // `max` below `min` is refused by the loader where both are written; a bare\n // `max: 0` still reaches here against the default `min: 1`, and means none.\n const floor = max === null ? Math.max(min, 0) : Math.min(Math.max(min, 0), max);\n const copies = max === null ? floor : Math.max(0, max);\n const first = consume.length;\n\n let cursor = from;\n for (let copy = 0; copy < copies; copy++) {\n cursor = buildCopy(rule, cursor, groups, context && copy < floor);\n }\n\n let end = cursor;\n if (max === null) {\n const loop = newState();\n eps(cursor, loop, 0, RANK.structure, null);\n const back = buildCopy(rule, loop, groups, false);\n eps(back, loop, 0, RANK.structure, null);\n end = newState();\n eps(loop, end, 0, RANK.structure, null);\n }\n\n // A skipped section inside a repetition breaks the run it is inside, which\n // tie-break 2 charges for. The repetition's own boundaries are not inside\n // it: a section skipped before the first copy or after the last one sits\n // beside the run rather than in the middle of it.\n if (copies > 1 || max === null) {\n for (let state = first; state < consume.length; state++) {\n if (state !== end) inRepeat[state] = true;\n }\n }\n return end;\n }\n\n const start = newState();\n let cursor = start;\n for (const rule of rules) cursor = buildRule(rule, cursor, [], true);\n\n return {\n states: consume.length,\n start,\n accept: cursor,\n consume,\n consumeTo,\n epsOut,\n epsIn,\n inRepeat,\n };\n}\n\n/**\n * Compiled rule lists, keyed by the array the template holds.\n *\n * A template is loaded once and applied to every page of its doctype, and every\n * level of every page re-enters this module. The automaton is immutable once\n * built, so one compilation serves them all.\n */\nconst compiled = new WeakMap<Rule[], Automaton>();\n\nfunction automatonFor(rules: Rule[], options: MatchOptions): Automaton {\n const hit = compiled.get(rules);\n if (hit) return hit;\n\n const states = expandedStates(rules);\n if (states > STATE_LIMIT) {\n const source = options.source ?? \"template\";\n // A template is referred to as `./templates.yaml#how-to` everywhere else,\n // so a named template fragment joins the source the same way here. Absent\n // a name - the file failed to compile a rule list outside any named\n // template - there is nothing to put after a `#`, so the sentence falls\n // back to its old, colon-joined phrasing.\n const label =\n options.template != null ? `${source}#${options.template}` : `${source}: the rule list`;\n throw new LintError(\n `${label} expands to ${states} states; the limit is ${STATE_LIMIT}. ` +\n `Cap a max, or split the template.`,\n );\n }\n\n const built = compile(rules);\n compiled.set(rules, built);\n return built;\n}\n\n/* -------------------------------------------------------------------------- *\n * Alignment\n * -------------------------------------------------------------------------- */\n\ntype StepKind = \"match\" | \"coerce\" | \"skip-rule\" | \"skip-section\";\n\n/** One candidate edge out of a lattice node, during the forward walk. */\ninterface Move {\n kind: StepKind;\n /** State it lands in. */\n to: number;\n /** Section index it lands in - the same one unless a section was consumed. */\n column: number;\n occ: Occurrence | null;\n /** This edge plus the cheapest completion from where it lands. */\n total: number;\n rank: number;\n}\n\ninterface Step {\n kind: StepKind;\n /** Section consumed, or where the cursor stood when a rule was skipped. */\n index: number;\n occ: Occurrence | null;\n}\n\n/** A section's heading, or `null` when it has none of its own. */\nfunction titleOf(section: SectionNode): string | null {\n return section.titlePosition === null ? null : section.title;\n}\n\n/** Binary heap over (cost, state), smallest cost first. */\nclass Heap {\n private readonly costs: number[] = [];\n private readonly items: number[] = [];\n\n get size(): number {\n return this.items.length;\n }\n\n /*\n * Every `?? 0` in this class is unreachable, and is here only because\n * `noUncheckedIndexedAccess` cannot see the bounds the arithmetic already\n * guarantees. `costs` and `items` are pushed and popped together and so\n * always have the same length; `child` is the index just pushed, and\n * `parent = (child - 1) >> 1` is in bounds whenever `child > 0`; `left` and\n * `right` are compared against `length` before they are read.\n *\n * Worth stating rather than leaving to inference: were an index ever out of\n * bounds, the fallback would read as cost 0, quietly inverting the heap\n * order rather than throwing. It is a type-checker concession, not a\n * defensive default.\n */\n push(cost: number, item: number): void {\n this.costs.push(cost);\n this.items.push(item);\n let child = this.items.length - 1;\n while (child > 0) {\n const parent = (child - 1) >> 1;\n if ((this.costs[parent] ?? 0) <= (this.costs[child] ?? 0)) break;\n this.swap(parent, child);\n child = parent;\n }\n }\n\n pop(): { cost: number; item: number } {\n const cost = this.costs[0] ?? 0;\n const item = this.items[0] ?? 0;\n const lastCost = this.costs.pop();\n const lastItem = this.items.pop();\n if (this.items.length > 0 && lastCost !== undefined && lastItem !== undefined) {\n this.costs[0] = lastCost;\n this.items[0] = lastItem;\n let parent = 0;\n for (;;) {\n const left = parent * 2 + 1;\n const right = left + 1;\n let smallest = parent;\n if (left < this.items.length && (this.costs[left] ?? 0) < (this.costs[smallest] ?? 0)) {\n smallest = left;\n }\n if (right < this.items.length && (this.costs[right] ?? 0) < (this.costs[smallest] ?? 0)) {\n smallest = right;\n }\n if (smallest === parent) break;\n this.swap(parent, smallest);\n parent = smallest;\n }\n }\n return { cost, item };\n }\n\n private swap(a: number, b: number): void {\n const cost = this.costs[a] ?? 0;\n const item = this.items[a] ?? 0;\n this.costs[a] = this.costs[b] ?? 0;\n this.items[a] = this.items[b] ?? 0;\n this.costs[b] = cost;\n this.items[b] = item;\n }\n}\n\n/**\n * The cheapest edit sequence turning the rule list into the section list.\n *\n * Costs are packed into one integer so the lattice can be a typed array:\n * `((primary * radix) + wildcards) * radix + brokenRuns`, compared as one\n * number, which is lexicographic because no component can reach the radix.\n *\n * The lattice is filled backwards, from the end of the document to the start,\n * and the path is then walked forwards. That order is what makes tie-break 3\n * expressible: with the cost of every remaining suffix already known, the walk\n * can take the lowest-ranked optimal edit at each step, which is exactly\n * \"earliest rule, then the smallest edit sequence\".\n */\nfunction align(sections: SectionNode[], nfa: Automaton): Step[] {\n const n = sections.length;\n const states = nfa.states;\n const radix = 2 * (n + states) + 2;\n const weigh = (primary: number, wildcards: number, brokenRuns: number): number =>\n (primary * radix + wildcards) * radix + brokenRuns;\n\n const SKIP_SECTION = weigh(ALIGNMENT_COSTS.skipSection, 0, 0);\n const SKIP_SECTION_IN_RUN = weigh(ALIGNMENT_COSTS.skipSection, 0, 1);\n const MATCH = weigh(ALIGNMENT_COSTS.match, 0, 0);\n const MATCH_WILDCARD = weigh(ALIGNMENT_COSTS.match, 1, 0);\n const COERCE = weigh(ALIGNMENT_COSTS.coerce, 0, 0);\n\n /** What a state's consuming edge costs against one section, or null. */\n const consumeCost = (\n state: number,\n index: number,\n ): { cost: number; rank: number; to: number; occ: Occurrence } | null => {\n const occ = nfa.consume[state];\n const section = sections[index];\n const to = nfa.consumeTo[state];\n if (!occ || !section || to === undefined || to < 0) return null;\n if (headingMatches(occ.rule.heading, titleOf(section))) {\n const cost = occ.wildcard ? MATCH_WILDCARD : MATCH;\n return { cost, rank: RANK.match, to, occ };\n }\n if (occ.coercible) return { cost: COERCE, rank: RANK.coerce, to, occ };\n return null;\n };\n\n const skipSectionCost = (state: number): number =>\n nfa.inRepeat[state] === true ? SKIP_SECTION_IN_RUN : SKIP_SECTION;\n\n // dist[i * states + s]: cheapest way from (section i, state s) to the end.\n const dist = new Float64Array((n + 1) * states).fill(Infinity);\n const distAt = (slot: number): number => dist[slot] ?? Infinity;\n\n for (let index = n; index >= 0; index--) {\n const base = index * states;\n const next = base + states;\n const heap = new Heap();\n\n for (let state = 0; state < states; state++) {\n let best = Infinity;\n if (index === n) {\n if (state === nfa.accept) best = 0;\n } else {\n const step = consumeCost(state, index);\n if (step) best = step.cost + distAt(next + step.to);\n const skipped = skipSectionCost(state) + distAt(next + state);\n if (skipped < best) best = skipped;\n }\n dist[base + state] = best;\n if (best < Infinity) heap.push(best, state);\n }\n\n // Close the column under epsilon edges. They can form zero-consuming\n // cycles - a `repeat` with `min: 0` and no `max` - so this is Dijkstra on\n // the reversed epsilon graph rather than a sweep in state order.\n const done = new Uint8Array(states);\n while (heap.size > 0) {\n const { cost, item } = heap.pop();\n if (done[item] === 1 || cost > distAt(base + item)) continue;\n done[item] = 1;\n for (const edge of nfa.epsIn[item] ?? NO_EPS) {\n const candidate = cost + edge.cost;\n if (candidate < distAt(base + edge.from)) {\n dist[base + edge.from] = candidate;\n heap.push(candidate, edge.from);\n }\n }\n }\n }\n\n if (distAt(nfa.start) === Infinity) {\n // Every state has a skip-section edge and every occurrence a skip edge, so\n // the accept state is always reachable. Reaching this would be a\n // construction bug, not a template the user can fix.\n throw new LintError(\"internal: no alignment exists for this rule list.\");\n }\n\n const steps: Step[] = [];\n let index = 0;\n let state = nfa.start;\n let seen = new Set<number>([state]);\n\n while (!(index === n && state === nfa.accept)) {\n const moves: Move[] = [];\n\n const offer = (\n cost: number,\n rank: number,\n to: number,\n column: number,\n kind: StepKind,\n occ: Occurrence | null,\n ): void => {\n const total = cost + distAt(column * states + to);\n if (total === Infinity) return;\n moves.push({ kind, to, column, occ, total, rank });\n };\n\n if (index < n) {\n const step = consumeCost(state, index);\n if (step) {\n offer(\n step.cost,\n step.rank,\n step.to,\n index + 1,\n step.rank === RANK.coerce ? \"coerce\" : \"match\",\n step.occ,\n );\n }\n offer(skipSectionCost(state), RANK.skipSection, state, index + 1, \"skip-section\", null);\n }\n for (const edge of nfa.epsOut[state] ?? NO_EPS) {\n if (seen.has(edge.to)) continue;\n offer(edge.cost, edge.rank, edge.to, index, \"skip-rule\", edge.occ);\n }\n\n // Cheapest first; then the lowest-ranked edit, which is tie-break 3; then\n // the earliest state, so the walk is reproducible to the edge.\n let move: Move | undefined;\n for (const candidate of moves) {\n if (\n move === undefined ||\n candidate.total < move.total ||\n (candidate.total === move.total && candidate.rank < move.rank) ||\n (candidate.total === move.total &&\n candidate.rank === move.rank &&\n candidate.to < move.to)\n ) {\n move = candidate;\n }\n }\n if (move === undefined) {\n throw new LintError(\"internal: the alignment could not be reconstructed.\");\n }\n\n if (move.kind !== \"skip-rule\" || move.occ !== null) {\n steps.push({ kind: move.kind, index, occ: move.occ });\n }\n if (move.column !== index) {\n index = move.column;\n seen = new Set<number>();\n }\n state = move.to;\n seen.add(state);\n }\n\n return steps;\n}\n\n/* -------------------------------------------------------------------------- *\n * Findings\n * -------------------------------------------------------------------------- */\n\nfunction collapse(point: Position[\"end\"]): Position {\n return { start: { ...point }, end: { ...point } };\n}\n\n/**\n * Where a finding about the cursor position lands.\n *\n * A gap in the middle of a document anchors on the section standing where the\n * missing one should be. A gap at the *end* has no such section, and anchoring\n * on the parent - which is what the previous matcher did - spans the parent's\n * whole subtree, so the finding starts at the parent's heading and sorts to the\n * top of a report about the bottom of the file. It anchors at the parent's end\n * instead, which is where the section would have gone.\n */\nfunction anchor(\n index: number,\n sections: SectionNode[],\n parent: SectionNode | null,\n): { heading: string | null; position: Position } {\n const section = sections[index];\n if (section) {\n return { heading: section.title || null, position: section.position };\n }\n if (parent) {\n return { heading: parent.title || null, position: collapse(parent.position.end) };\n }\n const last = sections[sections.length - 1];\n if (last) return { heading: null, position: collapse(last.position.end) };\n return { heading: null, position: collapse({ line: 1, column: 1, offset: 0 }) };\n}\n\n/** How a rule's heading reads inside a longer sentence. */\nfunction describeHeading(rule: Rule): string {\n const heading = rule.heading;\n if (typeof heading === \"string\") return `\"${heading}\"`;\n if (Array.isArray(heading)) return heading.map((text) => `\"${text}\"`).join(\", \");\n if (heading === false) return \"a section with no heading\";\n if (heading !== undefined) return `/${heading.pattern}/`;\n return rule.id === undefined ? \"any section\" : `\"${rule.id}\"`;\n}\n\n/**\n * What an absent occurrence is called.\n *\n * A rule names itself by its heading where it has one, because that is the text\n * the reader will type into the document. A wildcard has only its `id`, which\n * is why one is worth writing.\n */\nfunction missingMessage(rule: Rule): string {\n const heading = rule.heading;\n if (typeof heading === \"string\") return `Missing section \"${heading}\"`;\n if (Array.isArray(heading)) {\n return `Missing one of ${heading.map((text) => `\"${text}\"`).join(\", \")}`;\n }\n if (heading === false) return \"Missing section without a heading\";\n if (heading !== undefined) return `Missing section matching /${heading.pattern}/`;\n return rule.id === undefined ? \"Missing section\" : `Missing section \"${rule.id}\"`;\n}\n\nfunction missingGroupMessage(copy: GroupCopy): string {\n const members = (copy.rule.repeat ?? []).map(describeHeading).join(\" followed by \");\n const name = copy.rule.id === undefined ? \"\" : ` \"${copy.rule.id}\"`;\n return `Missing group${name}: expected ${members}`;\n}\n\nfunction unexpectedMessage(section: SectionNode): string {\n const what =\n section.titlePosition === null\n ? \"Unexpected section without a heading\"\n : `Unexpected section \"${section.title}\"`;\n return `${what}. Add a trailing rule with min: 0 to allow sections the template does not describe.`;\n}\n\n/* -------------------------------------------------------------------------- *\n * The entry point\n * -------------------------------------------------------------------------- */\n\n/**\n * Align `sections` against `rules` and say what is missing, what is extra, and\n * which rule describes which section.\n *\n * `rules` being absent means the template says nothing about this level, which\n * is silence rather than \"no sections allowed\". An empty list is the other\n * thing: a rule list that describes no sections, so every section is\n * unexpected.\n */\nexport function matchSections(\n sections: SectionNode[],\n rules: Rule[] | undefined,\n options: MatchOptions = {},\n): MatchResult {\n const matches: Match[] = [];\n const findings: Finding[] = [];\n if (!rules) return { matches, findings };\n\n const parent = options.parent ?? null;\n const nfa = automatonFor(rules, options);\n const steps = align(sections, nfa);\n\n const taken = new Set<Occurrence>();\n for (const step of steps) {\n if ((step.kind === \"match\" || step.kind === \"coerce\") && step.occ) {\n taken.add(step.occ);\n }\n }\n\n /** The outermost enclosing `repeat` copy that is absent whole, if any. */\n const absentGroup = (occ: Occurrence): GroupCopy | null => {\n for (const group of occ.groups) {\n if (group.members.every((member) => !taken.has(member))) return group;\n }\n return null;\n };\n\n const reported = new Set<GroupCopy>();\n\n for (const step of steps) {\n const section = sections[step.index];\n if ((step.kind === \"match\" || step.kind === \"coerce\") && step.occ && section) {\n matches.push({\n rule: step.occ.rule,\n section,\n coerced: step.kind === \"coerce\",\n });\n continue;\n }\n\n if (step.kind === \"skip-section\" && section) {\n findings.push({\n type: \"unexpected_section\",\n heading: section.title || null,\n message: unexpectedMessage(section),\n position: section.position,\n severity: \"error\",\n });\n continue;\n }\n\n if (step.kind !== \"skip-rule\" || !step.occ || !step.occ.required) continue;\n\n const where = anchor(step.index, sections, parent);\n const group = absentGroup(step.occ);\n if (group) {\n if (reported.has(group)) continue;\n reported.add(group);\n findings.push({\n type: \"missing_group\",\n heading: where.heading,\n message: missingGroupMessage(group),\n position: where.position,\n severity: \"error\",\n });\n continue;\n }\n\n findings.push({\n type: \"missing_section\",\n heading: where.heading,\n message: missingMessage(step.occ.rule),\n position: where.position,\n severity: \"error\",\n });\n }\n\n return { matches, findings };\n}\n","/**\n * Run a template over a parsed document.\n *\n * Matching and checking are deliberately separate: `match.ts` decides which\n * section each rule is talking about, and this module asks the content rules\n * about the pairs it produced. The old code fused the two - it inferred which\n * section a rule meant by running the rules and seeing whether they passed -\n * which made \"does this section match?\" and \"is this section valid?\" the same\n * question, so a section could never be both matched and wrong.\n *\n * Everything here is synchronous. It was async only to await a language model,\n * which this tool no longer has.\n *\n * Two things beyond that wiring live here, and both are about the document as a\n * whole rather than about any one section.\n *\n * **A template is a rule, and its subject is the page.** Its `heading`\n * constrains the page's own title, its `sequence`/`contains` describe what sits\n * before the first heading, and its `sections` describe what follows. See\n * `pageSection` for which section that makes the subject.\n *\n * **A rule the format cannot answer is said out loud.** A parser declares the\n * content kinds it emits (proposal 0065), and a rule about a kind absent from\n * that list is dropped and reported as a `warning` rather than silently passing\n * - or, worse, failing a document for holding none of something its format\n * cannot express.\n */\nimport type {\n ContentKind,\n DocumentTree,\n Finding,\n Position,\n SectionNode,\n} from \"../types.js\";\nimport {\n checkContains,\n checkContainsIn,\n checkHeading,\n checkSequence,\n checkSequenceIn,\n type RuleContext,\n} from \"../rules/index.js\";\nimport { parserByName } from \"../parsers/index.js\";\nimport { matchSections, type MatchOptions } from \"./match.js\";\nimport { BLOCK_KINDS, BLOCK_KIND_NODE } from \"./template.js\";\nimport type {\n BlockKind,\n BlockRule,\n ElementsRule,\n ListItemsRule,\n ListsRule,\n Rule,\n TablesRule,\n Template,\n} from \"./template.js\";\n\n/** What a caller can tell the validator beyond the tree and the template. */\nexport interface ValidateOptions {\n /** Template file the rules came from. Names the state-cap failure. */\n source?: string;\n /** Template within that file. Named in messages about the template. */\n template?: string;\n /**\n * Content kinds the parser that produced this tree emits. Defaults to what\n * the registry declares for `tree.format`, which is what the CLI wants; a\n * caller holding a tree from somewhere else passes its own.\n */\n kinds?: ContentKind[];\n}\n\n/* -------------------------------------------------------------------------- *\n * The page as the template's subject\n * -------------------------------------------------------------------------- */\n\n/** A zero-width span at the top of a file, for a document with no sections. */\nfunction origin(): Position {\n return {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n };\n}\n\n/** First section's start through the last one's end. */\nfunction span(sections: SectionNode[]): Position {\n const first = sections[0];\n const last = sections[sections.length - 1];\n if (!first || !last) return origin();\n return { start: { ...first.position.start }, end: { ...last.position.end } };\n}\n\n/**\n * The section the template describes: the page itself.\n *\n * A page whose body is one `# Title` with everything nested under it *is* that\n * section, and a page whose content starts before any heading is the implicit\n * lead section `sectionize` opens for it - which has no heading of its own, so\n * `heading: false` matches it and `heading: \"Overview\"` does not.\n *\n * Anything else - several top-level headings, or a body that starts at `##`,\n * which is what a page whose title lives in frontmatter looks like - has no one\n * section standing for the page, so one is synthesised. It has no heading and\n * no content of its own: content before the first heading always opens a lead\n * section, so a document that reaches this branch has none.\n */\nfunction pageSection(tree: DocumentTree): SectionNode {\n const [only] = tree.sections;\n if (tree.sections.length === 1 && only && only.level <= 1) return only;\n return {\n slug: \"\",\n title: \"\",\n level: 0,\n order: 0,\n parentSlug: null,\n titlePosition: null,\n position: span(tree.sections),\n children: [],\n sections: tree.sections,\n };\n}\n\n/* -------------------------------------------------------------------------- *\n * Rules the format cannot answer\n * -------------------------------------------------------------------------- */\n\n/** One rule that will not run here, and what the parser does not report. */\ninterface UncheckedRule {\n /** The template key, as the author wrote it. */\n rule: string;\n /** What is missing, in words: `tables`, `table columns`, `list items`. */\n noun: string;\n}\n\n/** What each block-rule key asks about, as a message says it. */\nconst BLOCK_NOUNS: Record<BlockKind, string> = {\n paragraphs: \"paragraphs\",\n codeBlocks: \"code blocks\",\n lists: \"lists\",\n tables: \"tables\",\n admonitions: \"admonitions\",\n images: \"images\",\n blockquotes: \"blockquotes\",\n definitionLists: \"definition lists\",\n elements: \"elements\",\n};\n\n/**\n * A template with the rules this format cannot answer removed, and the list of\n * what was removed.\n *\n * Removing them is the point, not a side effect. A `tables: { min: 1 }` left\n * standing against a parser that never emits a table counts zero tables and\n * fails the page, which is a verdict on the format rather than on the document\n * - and it would contradict, in the same report, the warning saying the rule\n * was not checked.\n */\nclass Pruner {\n private readonly emitted: Set<ContentKind>;\n /** Keyed by message, so one rule asked twice is reported once. */\n private readonly missing = new Map<string, UncheckedRule>();\n\n constructor(kinds: ContentKind[]) {\n this.emitted = new Set(kinds);\n }\n\n get gaps(): UncheckedRule[] {\n return [...this.missing.values()];\n }\n\n private emits(kind: ContentKind): boolean {\n return this.emitted.has(kind);\n }\n\n private drop(rule: string, noun: string): void {\n this.missing.set(`${rule}: ${noun}`, { rule, noun });\n }\n\n /** A table rule without its `columns`, when the parser reports no cells. */\n private tables(rule: TablesRule): TablesRule {\n if (rule.columns === undefined || this.emits(\"tableCell\")) return rule;\n this.drop(\"columns\", \"table columns\");\n const { columns: _columns, ...kept } = rule;\n return kept;\n }\n\n /**\n * A list rule with its `items` pruned.\n *\n * `items` has no capability of its own to check. A parser that reports a\n * list reports its items, since `ListNode.items` is not optional, and\n * `listItem` is not one of the `BLOCK_KINDS` a block rule can target. So\n * the `lists` gap covers the whole rule, and only what the items *hold* can\n * go unchecked.\n *\n * `listItem` is a `ContentKind` and parsers do declare it. That is a fact\n * about the node model rather than about this pruner: a template names\n * `lists`, and reaches an item only through `items`, so there is no rule\n * whose capability would be `listItem` on its own.\n */\n private lists(rule: ListsRule): ListsRule {\n const items = rule.items;\n if (items === undefined) return rule;\n const pruned = this.listItems(items);\n return pruned === items ? rule : { ...rule, items: pruned };\n }\n\n private listItems(rule: ListItemsRule): ListItemsRule {\n return this.holder(rule);\n }\n\n private elements(rule: ElementsRule): ElementsRule {\n return this.holder(rule);\n }\n\n /** The `sequence`/`contains` pair every content holder carries. */\n private holder<T extends { sequence?: BlockRule[]; contains?: BlockRule }>(\n rule: T,\n ): T {\n const kept = { ...rule };\n let changed = false;\n\n if (rule.sequence) {\n const sequence = this.sequence(rule.sequence);\n if (sequence === undefined) {\n delete kept.sequence;\n changed = true;\n } else if (sequence !== rule.sequence) {\n kept.sequence = sequence;\n changed = true;\n }\n }\n\n if (rule.contains) {\n const contains = this.block(rule.contains);\n if (contains === undefined) {\n delete kept.contains;\n changed = true;\n } else if (contains !== rule.contains) {\n kept.contains = contains;\n changed = true;\n }\n }\n\n return changed ? kept : rule;\n }\n\n /**\n * One `sequence`, with the runs this format cannot see taken out.\n *\n * Taking the entry out rather than leaving it empty is what keeps the rest of\n * the sequence meaningful: a run of a kind the parser never emits can never\n * appear among the actual runs, so an entry left standing would report an\n * order error on every file of that format. `undefined` means the key goes.\n */\n private sequence(entries: BlockRule[]): BlockRule[] | undefined {\n const kept: BlockRule[] = [];\n let changed = false;\n for (const entry of entries) {\n const pruned = this.block(entry);\n if (pruned === undefined) {\n changed = true;\n continue;\n }\n if (pruned !== entry) changed = true;\n kept.push(pruned);\n }\n if (!changed) return entries;\n return kept.length > 0 ? kept : undefined;\n }\n\n /** One block rule, or `undefined` when nothing in it can be checked. */\n private block(block: BlockRule): BlockRule | undefined {\n const kept: BlockRule = { ...block };\n let changed = false;\n\n for (const key of BLOCK_KINDS) {\n if (kept[key] === undefined) continue;\n if (this.emits(BLOCK_KIND_NODE[key])) continue;\n this.drop(key, BLOCK_NOUNS[key]);\n // Cleared rather than deleted. A computed `delete` is banned here, and\n // nothing that reads a block rule asks whether the key is present - every\n // one of them tests the value against `undefined`.\n Object.assign(kept, { [key]: undefined });\n changed = true;\n }\n\n const tables = kept.tables;\n if (tables) {\n const pruned = this.tables(tables);\n if (pruned !== tables) {\n kept.tables = pruned;\n changed = true;\n }\n }\n\n const lists = kept.lists;\n if (lists) {\n const pruned = this.lists(lists);\n if (pruned !== lists) {\n kept.lists = pruned;\n changed = true;\n }\n }\n\n const elements = kept.elements;\n if (elements) {\n const pruned = this.elements(elements);\n if (pruned !== elements) {\n kept.elements = pruned;\n changed = true;\n }\n }\n\n if (!changed) return block;\n return BLOCK_KINDS.some((key) => kept[key] !== undefined) ? kept : undefined;\n }\n\n private rules(rules: Rule[]): Rule[] {\n const kept: Rule[] = [];\n let changed = false;\n for (const rule of rules) {\n const pruned = this.rule(rule);\n if (pruned !== rule) changed = true;\n kept.push(pruned);\n }\n return changed ? kept : rules;\n }\n\n rule<T extends Rule>(rule: T): T {\n const kept = this.holder(rule);\n let changed = kept !== rule;\n const out = changed ? kept : { ...rule };\n\n if (rule.repeat) {\n const repeat = this.rules(rule.repeat);\n if (repeat !== rule.repeat) {\n out.repeat = repeat;\n changed = true;\n }\n }\n\n if (rule.sections) {\n const sections = this.rules(rule.sections);\n if (sections !== rule.sections) {\n out.sections = sections;\n changed = true;\n }\n }\n\n return changed ? out : rule;\n }\n}\n\n/** A pruned template and what pruning it took out. */\ninterface Pruned {\n template: Template;\n gaps: UncheckedRule[];\n}\n\n/**\n * Pruned templates, keyed by the template and the format's kinds.\n *\n * The identity matters as much as the saving. `match.ts` caches one compiled\n * automaton per rule *array*, so a fresh copy of `sections` per file would\n * recompile the template for every page of a docset. A template that needs no\n * pruning is therefore returned as-is, and one that does is pruned once per\n * format.\n */\nconst pruneCache = new WeakMap<Template, Map<string, Pruned>>();\n\nfunction prune(template: Template, kinds: ContentKind[]): Pruned {\n const key = [...kinds].sort().join(\",\");\n let byKinds = pruneCache.get(template);\n if (!byKinds) {\n byKinds = new Map<string, Pruned>();\n pruneCache.set(template, byKinds);\n }\n const hit = byKinds.get(key);\n if (hit) return hit;\n\n const pruner = new Pruner(kinds);\n const pruned: Pruned = { template: pruner.rule(template), gaps: pruner.gaps };\n byKinds.set(key, pruned);\n return pruned;\n}\n\n/** The warning one unchecked rule gets, anchored at the top of the file. */\nfunction uncheckedFinding(\n format: string,\n name: string,\n gap: UncheckedRule,\n): Finding {\n return {\n type: \"unsupported_content_kind\",\n heading: null,\n message:\n `The ${format} parser does not report ${gap.noun}, so the ` +\n `\"${gap.rule}\" rule in template \"${name}\" is not checked for this file.`,\n position: origin(),\n // A warning, because nothing about the document is wrong: the rule asks\n // about something this format cannot express. It never changes the exit\n // code - `runLint` counts a file as failed only on an error-severity\n // finding - so a docset of mixed formats stays green while still saying\n // which rules went unchecked, and where.\n severity: \"warning\",\n };\n}\n\n/* -------------------------------------------------------------------------- *\n * The walk\n * -------------------------------------------------------------------------- */\n\n/** Content and heading rules for one matched pair, without recursion. */\nfunction checkSection(section: SectionNode, rule: Rule): Finding[] {\n return [\n ...checkHeading(section, rule.heading),\n ...checkSequence(section, rule.sequence),\n ...checkContains(section, rule.contains),\n ];\n}\n\n/** Match one level of sections, check each pair, then recurse. */\nexport function validateSections(\n sections: SectionNode[],\n rules: Rule[] | undefined,\n options: MatchOptions = {},\n): Finding[] {\n const { matches, findings } = matchSections(sections, rules, options);\n const all = [...findings];\n\n for (const match of matches) {\n all.push(...checkSection(match.section, match.rule));\n all.push(\n ...validateSections(match.section.sections, match.rule.sections, {\n ...options,\n parent: match.section,\n }),\n );\n }\n\n return all;\n}\n\n/** Findings for one document against one template, in document order. */\nexport function validateDocument(\n tree: DocumentTree,\n template: Template,\n options: ValidateOptions = {},\n): Finding[] {\n // An unrecognised format falls back to *no* kinds rather than to no pruning.\n // Every tree the CLI builds carries a registered parser's own name, so this\n // is only reachable through the exported API, with a tree somebody else\n // parsed. Such a format has promised nothing, so no content rule can be said\n // to have run against it, and the alternative is the one 0065 rules out:\n // applying every rule to a format that may answer none of them, which makes\n // a green run mean two different things.\n const kinds = options.kinds ?? parserByName(tree.format)?.kinds ?? [];\n const pruned = prune(template, kinds);\n const rules = pruned.template;\n // The template's own name, for the messages that have to say which template\n // asked. The caller knows it; `title` is the next best thing a file carries.\n const name = options.template ?? template.title ?? \"unnamed\";\n\n const findings: Finding[] = pruned.gaps.map((gap) =>\n uncheckedFinding(tree.format, name, gap),\n );\n\n // The page is the template's subject. Its content is checked through the\n // `*In` rules rather than the section-shaped ones so that a finding about a\n // page with no heading of its own carries no heading either, instead of the\n // empty string a headless section's title is.\n const page = pageSection(tree);\n const ctx: RuleContext = {\n heading: page.title || null,\n position: page.position,\n };\n findings.push(...checkHeading(page, rules.heading));\n findings.push(...checkSequenceIn(page.children, rules.sequence, ctx));\n findings.push(...checkContainsIn(page.children, rules.contains, ctx));\n findings.push(\n ...validateSections(page.sections, rules.sections, {\n parent: page,\n source: options.source,\n template: options.template,\n }),\n );\n\n // Rules fire in rule order, which is not necessarily document order once a\n // template mixes optional sections and subsections. Readers scan a report top\n // to bottom against the file, so sort by where the finding actually is.\n return findings.sort(\n (a, b) => a.position.start.offset - b.position.start.offset,\n );\n}\n","/**\n * The `lint:` section of `manni.config.yaml`.\n *\n * The file is shared across the manni family - manni docevals, manni meta and\n * this tool all read one file per repo, each taking its own top-level key. So\n * the root is a mapping of tool name to that tool's settings, and manni lint\n * reads `lint:` and nothing else: sibling keys are neither read nor validated,\n * which is what keeps the family decoupled - no registry of known tools, no\n * coordination, no version coupling. See agentevals ADR 01009.\n *\n * Finding the file is the family's job (`src/shared/config-file.ts`): it walks\n * up from the working directory to the repository root, reads the `lint:` key\n * of the first family file that has one, and hands this module the slice. What\n * the slice may contain is decided here. The pre-family\n * `doc-structure-lint.config.yaml` is no longer discovered: its whole document\n * was a `lint:` section written in keys this one no longer takes, so reading it\n * could only produce the moved-key refusal from a file the author is not\n * looking at.\n *\n * The document set is not a `lint:` key. Proposal 0041 declares it once for\n * every tool, under the family-level `collections:`, which the shared loader\n * parses and `resolveLintRun` selects from; `paths:` and `exclude:` under\n * `lint:` are refused by name.\n *\n * That leaves the root unvalidatable by any single tool, so the two ways an\n * author can lose a whole config to this convention are caught by shape\n * instead: keys left at the top level, and a wrapper differing only in case. A\n * wrapper misspelled any other way (`lnt:`) is indistinguishable from another\n * tool's section and still yields defaults - the accepted cost of having no\n * registry.\n *\n * Inside the section, `config.json` is the authority and `additionalProperties`\n * is false at every level, so a typo'd key is a loud failure rather than a\n * silent default. Defaults themselves live with the consumers, not here: this\n * returns exactly what the author wrote.\n */\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport * as AjvNs from \"ajv\";\nimport type { ErrorObject, SchemaObject, ValidateFunction } from \"ajv\";\nimport configSchema from \"../../../schemas/lint/config.json\" with { type: \"json\" };\nimport { selectCollections, type CollectionConfig } from \"../../shared/collections.js\";\nimport {\n FAMILY_CONFIG_NAMES,\n findConfigFile,\n readConfigFile,\n type ConfigFile,\n type ConfigFileOptions,\n} from \"../../shared/config-file.js\";\nimport { LintError } from \"../types.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport type { ToolsConfig } from \"../../shared/tools.js\";\nimport type { TemplateOverride } from \"./resolve-template.js\";\nimport { refRelativeTo } from \"./template-registry.js\";\n\n// ajv is CommonJS with a default export; under NodeNext the constructable\n// value is on `.default`, which the namespace import reaches without the\n// esModuleInterop-only call signature TypeScript otherwise complains about.\ntype AjvCtor = typeof import(\"ajv\").default;\nconst Ajv = AjvNs.default as unknown as AjvCtor;\n\n/**\n * Everything the `lint:` section can carry. Every key is optional, and an\n * absent one means \"the consumer's default\", never a value written in here.\n *\n * `overrides[].template` and the `types` values are template refs, left as the\n * strings they were written as: `resolve-template.ts` owns what a ref means.\n */\nexport interface LintConfig {\n /** Zero matched files is a success, not an operational error. */\n allowEmpty?: boolean;\n /** The structure job: what `lint structure` runs and `lint check` includes. */\n structure?: LintJobConfig;\n /** Template files to load; their `types:` join the routing table. */\n templates?: string[];\n /** Template for a page that declares no doctype. */\n template?: string;\n /** Explicit doctype -> template ref map. */\n types?: Record<string, string>;\n /** Repo policy, first matching glob wins. */\n overrides?: TemplateOverride[];\n}\n\nexport type { TemplateOverride };\n\n/** One job's settings. The tool that performs it is all a job configures. */\nexport interface LintJobConfig {\n tool?: LintTool;\n}\n\n/**\n * The tools that can perform a lint job: manni's own engine, and DITA Open\n * Toolkit for a DITA docset.\n */\nexport const LINT_TOOLS = [\"manni\", \"dita-ot\"] as const;\nexport type LintTool = (typeof LINT_TOOLS)[number];\n\n/** The jobs `lint check` runs: `structure`. */\nexport const LINT_JOBS = [\"structure\"] as const;\nexport type LintJob = (typeof LINT_JOBS)[number];\n\n/** The tools each job accepts, in the order its message lists them. */\nexport const TOOLS_BY_JOB: Readonly<Record<LintJob, readonly LintTool[]>> = {\n structure: [\"manni\", \"dita-ot\"],\n};\n\nexport function isLintTool(value: string): value is LintTool {\n return (LINT_TOOLS as readonly string[]).includes(value);\n}\n\n/** The top-level key manni lint owns inside the shared manni config. */\nexport const SECTION_KEY = \"lint\";\n\n/** The family filenames discovery accepts, in the order it tries them. */\nexport const CONFIG_FILENAMES: readonly string[] = FAMILY_CONFIG_NAMES;\n\n/**\n * How the family loader finds and slices this tool's config.\n *\n * `legacyNames` is empty on purpose. `doc-structure-lint.config.yaml` was this\n * tool's file before the family file, and its whole document was the `lint:`\n * section - written in `paths:` and `exclude:`, which the section no longer\n * takes. Reading one now could only refuse it, from a file the author is not\n * looking at, so discovery no longer knows the name at all.\n */\nconst CONFIG_FILE: ConfigFileOptions = {\n section: SECTION_KEY,\n legacyNames: [],\n toError: (message) => new LintError(message),\n};\n\n/**\n * The keys this tool owns, read off the schema rather than restated here.\n *\n * Finding any of them at the root of a manni config means the file was never\n * nested under `lint:`. Deriving the list from `config.json` is what stops it\n * drifting from the real key set the next time a key is added - a restated\n * list that fell behind would let exactly the un-nested config it exists to\n * catch fall through to defaults instead.\n */\nconst SECTION_KEYS: readonly string[] = Object.keys(configSchema.properties);\n\n/** The keys one job takes. Read off the schema for the same reason. */\nconst STRUCTURE_KEYS: readonly string[] = Object.keys(\n configSchema.properties.structure.properties,\n);\n\n/**\n * Where the metadata tool's configuration reference documents `collections:`.\n * The literal cite's `config.ts` carries, repeated for the same reason: that\n * module is meta's own, and sibling tools import only its public and family\n * barrels.\n */\nconst CONFIG_REF = \"https://hawkeyexl.github.io/manni/meta/reference/configuration/\";\n\n/**\n * The two keys proposal 0041 moved out of `lint:` and up to the family level.\n * Refused rather than aliased, as meta and cite refuse them: an alias would be\n * a second place to declare a document set that is meant to be declared once.\n */\nconst MOVED_KEYS: readonly string[] = [\"paths\", \"exclude\"];\n\n/**\n * Refuse a moved key before the unknown-key check, which would otherwise call\n * `paths` a typo. Same sentence as meta's and cite's, with the section renamed.\n */\nfunction assertNoMovedKeys(raw: Record<string, unknown>, source: string): void {\n for (const key of MOVED_KEYS) {\n if (Object.hasOwn(raw, key)) {\n throw new LintError(\n `${source}: \"${key}\" is no longer a ${SECTION_KEY} key. Document sets are declared once for every tool, under a top-level collections: list. See ${CONFIG_REF}#collections`,\n );\n }\n }\n}\n\n/**\n * A key the parser does not know is a typo, not a no-op. Naming every key the\n * mapping takes is what turns `allowEmtpy: true` from a line that reads as\n * configured and does nothing into a failure the author can act on. `where` is\n * the mapping as the user spells it: `lint` or `lint.structure`.\n */\nfunction rejectUnknownKeys(\n obj: Record<string, unknown>,\n allowed: readonly string[],\n where: string,\n source: string,\n): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.includes(key)) {\n throw new LintError(\n `Unknown key \"${key}\" under ${where}: in ${source}. Supported keys: ${allowed.join(\", \")}.`,\n );\n }\n }\n}\n\n/**\n * The job mappings, checked before Ajv so the messages name the key set and\n * the tool list rather than restating a schema keyword. A tool nobody\n * implements is refused by name: silently falling back to manni's engine would\n * make `tool: vale` read as configured and lint with something else.\n */\nfunction checkJobs(section: Record<string, unknown>, source: string): void {\n for (const job of LINT_JOBS) {\n const value = section[job];\n if (value == null || !isRecord(value)) continue;\n rejectUnknownKeys(value, STRUCTURE_KEYS, `${SECTION_KEY}.${job}`, source);\n const tool = value.tool;\n if (tool === undefined) continue;\n if (typeof tool !== \"string\" || !TOOLS_BY_JOB[job].includes(tool as LintTool)) {\n throw new LintError(\n `${source}: ${SECTION_KEY}.${job}.tool must be one of: ${TOOLS_BY_JOB[job].join(\", \")}.`,\n );\n }\n }\n}\n\n// No `useDefaults`: the schema declares no defaults, deliberately. A default\n// written into the parsed object is indistinguishable from a value the author\n// wrote, which is the trap `template.json` documents on its `required` key.\nconst ajv = new Ajv({ allErrors: true });\n\nlet compiled: ValidateFunction<LintConfig> | null = null;\n\nfunction sectionValidator(): ValidateFunction<LintConfig> {\n compiled ??= ajv.compile<LintConfig>(configSchema as SchemaObject);\n return compiled;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * One Ajv error, as a path an author can find in their file.\n *\n * Ajv's `instancePath` is relative to the section, so it is prefixed back to\n * `lint`: a bare `/overrides/0/files` names a path that is not in the file.\n */\nfunction describeError(error: ErrorObject): string {\n const params = error.params as { additionalProperty?: unknown };\n const extra =\n typeof params.additionalProperty === \"string\"\n ? ` (\"${params.additionalProperty}\")`\n : \"\";\n return `${SECTION_KEY}${error.instancePath} ${error.message ?? \"is invalid\"}${extra}`;\n}\n\n/** The un-nested config: our own keys at the root, with no `lint:` wrapper. */\nfunction rejectUnNested(root: Record<string, unknown>, source: string): void {\n const stray = SECTION_KEYS.filter((key) => key in root);\n if (stray.length === 0) return;\n // The convention is named after the shared file, but the message must\n // describe the file the user actually passed: telling someone who ran\n // `-c my-custom.yaml` about `manni.config.yaml` reads as a complaint about a\n // file they never mentioned, and sends them looking for the wrong one.\n throw new LintError(\n `${source}: found ${stray.map((key) => `\"${key}:\"`).join(\", \")} at the top level, ` +\n `but no \"${SECTION_KEY}:\" key. This file is shared across the manni family, ` +\n `so every manni lint setting belongs under a top-level \"${SECTION_KEY}:\" key. ` +\n `Indent the file's contents one level and add that key.`,\n );\n}\n\n/**\n * The miscased wrapper: `Lint:`, which the stray-key check cannot see, because\n * the keys under it are nested rather than at the top level.\n */\nfunction rejectMiscasedWrapper(\n root: Record<string, unknown>,\n source: string,\n): void {\n const miscased = Object.keys(root).find(\n (key) => key !== SECTION_KEY && key.toLowerCase() === SECTION_KEY,\n );\n if (miscased === undefined) return;\n throw new LintError(\n `${source}: found \"${miscased}:\" at the top level, but the key is case-sensitive ` +\n `and manni lint reads \"${SECTION_KEY}:\" exactly. Rename \"${miscased}:\" to \"${SECTION_KEY}:\".`,\n );\n}\n\n/**\n * Validate the `lint:` section itself, whatever file it came from.\n *\n * `source` names the file in every message. `null` is the section written\n * with nothing under it, which an author means as \"defaults\"; it is not a\n * broken section.\n */\nexport function parseConfigSection(section: unknown, source: string): LintConfig {\n if (section == null) return {};\n\n // Before Ajv, which would call a moved key an additional property and an\n // unknown one a schema keyword. Both messages have to name what to do.\n if (isRecord(section)) {\n assertNoMovedKeys(section, source);\n rejectUnknownKeys(section, SECTION_KEYS, SECTION_KEY, source);\n checkJobs(section, source);\n }\n\n const validate = sectionValidator();\n if (!validate(section)) {\n const detail =\n (validate.errors ?? []).map(describeError).join(\"; \") ||\n `does not match the ${SECTION_KEY} config schema`;\n throw new LintError(\n `${source}: invalid \"${SECTION_KEY}\" section: ${detail}.`,\n );\n }\n return section;\n}\n\n/**\n * Parse a whole `manni.config.yaml` and return its `lint:` section.\n *\n * `source` names the file in every message. A file that is empty, or that\n * carries only other tools' sections, returns `{}` rather than throwing - that\n * is the case that keeps one shared file usable by a project which has not\n * adopted this tool yet.\n */\nexport function parseConfig(text: string, source: string): LintConfig {\n let raw: unknown;\n try {\n raw = parseYaml(text);\n } catch (err) {\n throw new LintError(\n `${source}: invalid YAML: ${errorMessage(err)}`,\n );\n }\n\n // An empty file configures nothing; it is not a broken one.\n if (raw == null) return {};\n if (!isRecord(raw)) {\n throw new LintError(\n `${source}: top level must be a mapping of tool name to that tool's settings, ` +\n `with manni lint's under \"${SECTION_KEY}:\".`,\n );\n }\n\n if (!(SECTION_KEY in raw)) {\n rejectUnNested(raw, source);\n rejectMiscasedWrapper(raw, source);\n // Every remaining root key belongs to a sibling tool. Reading none of them\n // is the whole point of the convention.\n return {};\n }\n\n return parseConfigSection(raw[SECTION_KEY], source);\n}\n\n/**\n * Load the config from an explicit path, or by walking up from `cwd`.\n *\n * Discovery is the family's: the nearest `manni.config.yaml` with a `lint:`\n * key or a family key wins, and a family file with neither belongs to a\n * sibling and is passed over. An explicit path skips discovery and errors if\n * it is missing; its `lint:` key is unwrapped when present and the whole\n * document is the section otherwise, so a file passed by hand may be called\n * anything.\n *\n * A wrapper differing from `lint:` only in case is still caught on an\n * un-wrapped document: nothing else in the section's schema would name it.\n *\n * Returns null when discovery finds no config, which is not an error - a repo\n * whose pages all declare their `type` needs no config at all.\n */\nexport async function loadConfig(\n explicitPath?: string,\n cwd: string = process.cwd(),\n): Promise<{ config: LintConfig; path: string } | null> {\n const file = await readLintConfigFile(explicitPath, cwd);\n if (file === null) return null;\n return { config: sectionOf(file), path: file.path };\n}\n\n/** The family file itself, found or named, before its `lint:` slice is read. */\nfunction readLintConfigFile(\n explicitPath: string | undefined,\n cwd: string,\n): Promise<ConfigFile | null> {\n return explicitPath\n ? readConfigFile(explicitPath, cwd, CONFIG_FILE)\n : findConfigFile(cwd, CONFIG_FILE);\n}\n\n/** One found file's `lint:` section, parsed, with the shape checks a file gets. */\nfunction sectionOf(file: ConfigFile): LintConfig {\n if (!file.wrapped && isRecord(file.value)) {\n rejectMiscasedWrapper(file.value, file.source);\n }\n return parseConfigSection(file.value, file.source);\n}\n\n/**\n * Re-base everything a config declares against the config file's own\n * directory.\n *\n * `loadConfig` returns the file's `path` precisely so this can happen, and\n * discarding it made the same config mean different things depending on where\n * the tool was invoked from. Running from a subdirectory turned `templates:`\n * into \"file not found\" - and turned `overrides:` into nothing at all,\n * silently: the glob stopped matching, every page fell through to its own\n * `type`, and the run exited 0 having applied none of the repo's policy.\n *\n * Refs go through `refRelativeTo`, which leaves built-in ids, URLs, and\n * absolute paths alone. Globs become absolute, which is what the run matches\n * them against. Every non-absolute glob is relative to the config, `**\\/*.md`\n * included: exempting a leading `**` left the original bug half-open, because\n * from a subdirectory that pattern expanded against the working directory.\n */\nexport function rebaseConfig(\n found: { config: LintConfig; path: string } | null,\n): LintConfig {\n if (!found) return {};\n const dir = dirname(resolve(found.path));\n const config = found.config;\n\n const ref = (value: string): string => refRelativeTo(found.path, value);\n const glob = (value: string): string =>\n isAbsolute(value) ? value : resolve(dir, value).replace(/\\\\/g, \"/\");\n\n return {\n ...config,\n ...(config.templates ? { templates: config.templates.map(ref) } : {}),\n ...(config.template ? { template: ref(config.template) } : {}),\n ...(config.types\n ? {\n types: Object.fromEntries(\n Object.entries(config.types).map(([type, value]) => [type, ref(value)]),\n ),\n }\n : {}),\n ...(config.overrides\n ? {\n overrides: config.overrides.map((o) => ({\n files: glob(o.files),\n template: ref(o.template),\n })),\n }\n : {}),\n };\n}\n\n/** The stdin token, repeated so this module does not depend on the file loader. */\nconst STDIN = \"-\";\n\nexport interface LintRunOptions {\n cwd: string;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /** Positional inputs; empty means fall back to the selected collections' `paths:`. */\n inputs: string[];\n /**\n * `--collection <name>`, repeatable: the collections this run covers. Empty\n * or absent means every declared one, the same thing, because commander's\n * collector hands `[]` over when the flag was never typed.\n */\n collection?: string[];\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n}\n\n/** What every lint command settles before it touches a file. */\nexport interface ResolvedLintRun {\n /** The `lint:` section, rebased against the config's directory. */\n config: LintConfig;\n /** What to resolve: the positional inputs, or the collections' `paths:`. */\n inputs: string[];\n /** The directory `inputs` resolve from. */\n base: string;\n /** The collections this run covers; `[]` with no config. */\n collections: CollectionConfig[];\n /** Whether `inputs` came from the collections rather than the command line. */\n fromCollections: boolean;\n /**\n * The document's top-level `tools:`, an outside tool's settings (proposal\n * 0052). `{}` with no config. It is not part of the `lint:` section and is\n * not rebased here: a path in it is resolved against `configDir` by the run\n * that needs it, through the helpers in `src/shared/tools.ts`.\n */\n tools: ToolsConfig;\n configDir?: string;\n configPath?: string;\n configSource?: string;\n}\n\n/**\n * Settle which config governs the run and what it covers. The same shape cite\n * uses, for the same reason: positional inputs are typed from a shell and stay\n * cwd-relative, while a collection's `paths:` was written next to the config\n * and resolves there, so one run has exactly one base.\n */\nexport async function resolveLintRun(\n opts: LintRunOptions,\n): Promise<ResolvedLintRun> {\n const cwd = resolve(opts.cwd);\n\n // `--collection` names something only a config can define, and selects a set\n // the operator did not type, so it composes with neither positional paths\n // nor `--no-config`. The same two sentences meta, a11y and cite use. Stdin\n // is one more input rather than a path, so it rides beside the flag.\n const wanted = opts.collection ?? [];\n if (wanted.length > 0 && opts.inputs.some((input) => input !== STDIN)) {\n throw new LintError(\n \"--collection selects a configured collection; it cannot be combined with paths.\",\n );\n }\n\n const file = opts.noConfig ? null : await readLintConfigFile(opts.configPath, cwd);\n if (wanted.length > 0 && file === null) {\n throw new LintError(\"--collection needs a config file to select from.\");\n }\n if (file !== null) opts.onConfigLoaded?.({ path: file.path, dir: file.dir });\n\n const config = rebaseConfig(\n file === null ? null : { config: sectionOf(file), path: file.path },\n );\n // Selected whatever the inputs are: a typed file is still a member of the\n // collections that contain it. An unknown name is the shared helper's error.\n const collections =\n file === null\n ? []\n : selectCollections(\n file.collections,\n wanted,\n file.source,\n (message) => new LintError(message),\n );\n\n // `--collection` is a request the run has to honour, as in cite and meta:\n // the named collection's pages are resolved even when stdin rides beside the\n // flag. Counting `-` as a path made `lint check - --as markdown --collection\n // guides` lint the piped document, open not one file of `guides`, and exit 0\n // over a docset nothing read. The implicit fallback is not a request, and a\n // lone `-` cancels it: a piped page is a run of its own.\n const fromCollections = wanted.length > 0 || opts.inputs.length === 0;\n const collectionPaths = fromCollections ? collections.flatMap((c) => c.paths) : [];\n // Stdin keeps its typed position; the globs follow it in declaration order.\n const inputs = fromCollections ? [...opts.inputs, ...collectionPaths] : opts.inputs;\n // Only a path needs a base, so it follows the globs when they contributed\n // and stays at the working directory otherwise, stdin included.\n const base = collectionPaths.length > 0 && file ? file.dir : cwd;\n\n return {\n config,\n inputs,\n base,\n collections,\n fromCollections,\n tools: file?.tools ?? {},\n ...(file === null\n ? {}\n : { configDir: file.dir, configPath: file.path, configSource: file.source }),\n };\n}\n","{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"manni-lint:config:1\",\n \"title\": \"manni lint config section\",\n \"description\": \"The `lint:` section of a shared `manni.config.yaml`. The file's root is a mapping of tool name to that tool's settings, so this schema describes the section only - never the file. The document set is not here: proposal 0041 declares it once for every tool, under the family-level `collections:` key, and `paths`/`exclude` under `lint:` are refused by name. Every key is optional: a repo that configures no manni lint at all is a legitimate config, and so is one that carries only a sibling tool's section. `additionalProperties: false` applies at every level below `lint:`, which is what turns a typo'd key into a loud failure instead of a silent default.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"allowEmpty\": {\n \"description\": \"Treat a run that matched zero files as a success rather than an operational error. The same key, with the same meaning, as `cite.allowEmpty`: for a shared CI template or a pre-commit hook whose file list may legitimately be empty. `--allow-empty` on the command line sets it for one run.\",\n \"type\": \"boolean\"\n },\n \"overrides\": {\n \"description\": \"Repo policy: everything under a glob is linted with one template, whatever the pages say they are. First matching entry wins, and an override outranks a page's own `type`.\",\n \"type\": \"array\",\n \"items\": {\n \"description\": \"One policy entry. Both keys are required: an entry naming no template, or no files, is a line that silently does nothing.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"files\", \"template\"],\n \"properties\": {\n \"files\": {\n \"description\": \"Glob matched against each file's path, written with forward slashes whatever the platform uses.\",\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"template\": {\n \"description\": \"Template ref applied to the files this entry matches.\",\n \"type\": \"string\",\n \"minLength\": 1\n }\n }\n }\n },\n \"structure\": {\n \"description\": \"The structure job, which `manni lint structure` and `manni lint check` both run. Declaring it with no keys is how a repo says the job applies. Its one setting is the tool that performs it.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"tool\": {\n \"description\": \"Which tool performs the job. `manni` is manni's own template-structure engine; `dita-ot` is DITA Open Toolkit, which validates a DITA map and the topics it reaches and is located through the top-level `tools.dita-ot.home`. `--tool <name>` on the command line names the same thing.\",\n \"type\": \"string\",\n \"enum\": [\"manni\", \"dita-ot\"]\n }\n }\n },\n \"template\": {\n \"description\": \"Template ref applied to a page that declares no doctype and matches no override. The last stage of the resolution chain, not an override: `--template`, a page's `$template`, an `overrides` entry, and the page's own `type` all outrank it.\",\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"templates\": {\n \"description\": \"Template files to load. Their templates' `types:` join the doctype routing table, outranking the built-ins, so adopting a repo's own how-to shape is one entry here and no flag.\",\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1\n }\n },\n \"types\": {\n \"description\": \"Explicit doctype -> template ref map, for a doctype no template file claims with its own `types:`. Keys are the vocabulary a page's `type` frontmatter is written in, so they are the author's names rather than this schema's - constrained only to the shape a doctype slug takes, not to a fixed set.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"patternProperties\": {\n \"^[A-Za-z0-9._:-]+$\": {\n \"description\": \"A template ref: a built-in id, a path, or a URL, optionally with a `#name` fragment.\",\n \"type\": \"string\",\n \"minLength\": 1\n }\n }\n }\n }\n}\n","/**\n * The DITA Open Toolkit process seam: the only module that starts `dita`.\n *\n * Written in the shape `src/term/core/vale.ts` set, for the same reasons. The\n * launcher is started with an argv and never a shell string, the buffer is\n * raised because a build log is not small, and what comes back is validated\n * here, because it crosses a process boundary.\n *\n * **The test suite starts no DITA-OT, and needs no JVM.** Every unit test\n * injects a stub spawn. What the parser is fed is real output, though: the\n * logs under `test/lint/fixtures/dita-ot/logs/` are captures of DITA-OT 4.4.1\n * runs over the fixtures beside them, with only absolute paths rewritten.\n * Their README records what each one holds and where each field name comes\n * from.\n *\n * The verdict is the log, not the exit code: DITA-OT publishes no exit-code\n * contract, so a non-zero exit with a parseable log is findings, and only a\n * log that is missing or unreadable *and* a non-zero exit is a failure to run.\n */\nimport { execFile } from \"node:child_process\";\nimport { mkdtemp, readFile, rm, stat } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { delimiter, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Severity } from \"../../shared/severity.js\";\nimport { ditaOtHome } from \"../../shared/tools.js\";\nimport { LintError } from \"../types.js\";\n// Type-only, and erased at runtime: `./index.js` imports this module to put the\n// descriptor in its initial map, so a value import here would be a cycle.\nimport type { FormatInfo } from \"../commands/tools.js\";\nimport type { StructureToolDescriptor, ToolProbe, ToolProbeContext } from \"./index.js\";\n\n/** What the launcher did. `code` is null when a signal ended it. */\nexport interface DitaOtProcessResult {\n code: number | null;\n /**\n * The signal that ended it, when one did, and `code` is then null. Optional\n * because absent means what it says: the run was not killed.\n */\n signal?: string | null;\n stdout: string;\n stderr: string;\n}\n\n/**\n * Start `launcher` with `args` and wait for it. Resolves for any exit; rejects\n * when the process could not start, with an error whose `code` is `ENOENT`\n * when there is no such launcher. Tests inject a stub.\n */\nexport type DitaOtSpawn = (\n launcher: string,\n args: string[],\n opts: { cwd?: string },\n) => Promise<DitaOtProcessResult>;\n\nconst MAX_BUFFER = 64 * 1024 * 1024;\n\n/** The two refusals a user reads, worded once. */\nconst NOT_ON_PATH =\n \"dita is not on PATH. Install DITA Open Toolkit to lint structure, or set tools.dita-ot.home.\";\n\nconst noLauncher = (home: string): string =>\n `no DITA Open Toolkit at \"${home}\". tools.dita-ot.home must be a DITA-OT installation directory.`;\n\n/**\n * `<home>/bin/dita`, or the bare name for the one on PATH. Windows has its own\n * launcher, `dita.bat`, which is what makes `ditaOtCommandLine` necessary.\n *\n * `platform` is a parameter so the mapping can be tested on either host.\n */\nexport function ditaOtLauncher(\n home: string | undefined,\n platform: NodeJS.Platform = process.platform,\n): string {\n const name = platform === \"win32\" ? \"dita.bat\" : \"dita\";\n return home === undefined ? name : join(home, \"bin\", name);\n}\n\n/** How a launcher is actually started. */\nexport interface DitaOtCommandLine {\n command: string;\n argv: string[];\n /** Windows: the argv is already one quoted string and must not be re-quoted. */\n verbatim: boolean;\n}\n\nfunction isBatch(launcher: string): boolean {\n const lower = launcher.toLowerCase();\n return lower.endsWith(\".bat\") || lower.endsWith(\".cmd\");\n}\n\n/**\n * Quote one token for `cmd.exe`. A `\"` inside a Windows path is impossible -\n * the character is not legal in a filename - so a value carrying one is a\n * shape this cannot quote safely, and it is refused rather than passed on.\n */\nfunction quoteForCmd(value: string): string {\n if (value.includes('\"')) {\n throw new LintError(\n `DITA Open Toolkit cannot be given an argument containing a quote: ${value}`,\n );\n }\n return `\"${value}\"`;\n}\n\n/**\n * How to start `launcher`, given what it is.\n *\n * Node refuses to `execFile` a `.bat` or `.cmd` without a shell, and\n * `shell: true` joins the argv into one string **with no quoting at all**. Our\n * argv carries user-supplied paths, so that is a command-injection hole, not a\n * convenience. The documented alternative is this one: run `cmd.exe` directly,\n * do the quoting here, and pass the whole command as one verbatim argument.\n * `/s` then strips exactly the outer pair of quotes, which is why the string\n * is wrapped a second time. The next reader will find `shell: true` simpler;\n * it is also the version with the hole in it.\n */\nexport function ditaOtCommandLine(\n launcher: string,\n args: string[],\n): DitaOtCommandLine {\n if (!isBatch(launcher)) {\n return { command: launcher, argv: args, verbatim: false };\n }\n const line = [launcher, ...args].map(quoteForCmd).join(\" \");\n return {\n command: process.env[\"COMSPEC\"] ?? \"cmd.exe\",\n argv: [\"/d\", \"/s\", \"/c\", `\"${line}\"`],\n verbatim: true,\n };\n}\n\nexport const spawnDitaOt: DitaOtSpawn = (launcher, args, opts) =>\n new Promise((settle, reject) => {\n const line = ditaOtCommandLine(launcher, args);\n execFile(\n line.command,\n line.argv,\n {\n cwd: opts.cwd,\n windowsHide: true,\n windowsVerbatimArguments: line.verbatim,\n maxBuffer: MAX_BUFFER,\n encoding: \"utf8\",\n },\n (error, stdout, stderr) => {\n if (!error) {\n settle({ code: 0, stdout, stderr });\n return;\n }\n if (typeof error.code === \"number\") {\n settle({ code: error.code, stdout, stderr });\n return;\n }\n // Killed by a signal. Node reports the exit code as **null** here, not\n // as undefined, so testing for undefined never matched and a killed\n // run rejected as though the launcher had failed to start. The log is\n // still read: a run cut short may have written findings before it died.\n if (error.code == null && typeof error.signal === \"string\") {\n settle({ code: null, signal: error.signal, stdout, stderr });\n return;\n }\n // A start failure (ENOENT) or an output over the buffer.\n const failure: Error = error;\n reject(failure);\n },\n );\n });\n\nfunction isEnoent(err: unknown): boolean {\n return (\n typeof err === \"object\" &&\n err !== null &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n );\n}\n\nfunction isMapping(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nasync function isFile(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Whether a bare launcher name resolves to a file on `PATH`.\n *\n * Asked only after a failure, and only to choose the message. On Windows the\n * launcher is a `.bat` started through `cmd.exe`, so a missing one comes back\n * as cmd's own non-zero exit rather than as an `ENOENT` - and the advice a\n * reader needs is \"install DITA-OT\", not cmd's sentence about a command it did\n * not recognize.\n */\nasync function isOnPath(name: string): Promise<boolean> {\n for (const dir of (process.env[\"PATH\"] ?? \"\").split(delimiter)) {\n if (dir === \"\") continue;\n if (await isFile(join(dir, name))) return true;\n }\n return false;\n}\n\n/**\n * DITA-OT's `MessageBean.Type` onto the family's three-value scale, as\n * `foldValeSeverity` does for Vale's.\n *\n * `null` is \"not a finding\": `DEBUG` and `TRACE` are build chatter even when\n * they carry a code, and a level this does not know is dropped rather than\n * promoted to something it might not be.\n */\nexport function foldDitaOtSeverity(level: string): Severity | null {\n switch (level.toUpperCase()) {\n case \"FATAL\":\n case \"ERROR\":\n return \"error\";\n case \"WARN\":\n return \"warning\";\n case \"INFO\":\n return \"notice\";\n default:\n return null;\n }\n}\n\n/** One diagnostic DITA-OT reported, in the vocabulary the lint branch reads. */\nexport interface DitaOtMessage {\n /** DITA-OT's own message id, e.g. `DOTX010E`. Becomes the finding's `type`. */\n code: string;\n severity: Severity;\n message: string;\n /** The path its `location` URI named, absent when it named none. */\n file?: string;\n line?: number;\n /** The **column**. See `readMessage` for why the log calls it `row`. */\n column?: number;\n}\n\n/**\n * The path a `location` names.\n *\n * DITA-OT writes `file:/x`, one slash and no authority. `new URL` normalizes\n * that to the three-slash form, so the quirk costs nothing. What does cost\n * something is a POSIX-rooted URI read on Windows: `fileURLToPath` refuses\n * `file:///repo/a.dita` outright there, with `ERR_INVALID_FILE_URL_PATH`, and\n * a log written on a Linux CI runner is full of exactly those. The decoded\n * pathname is the answer in that case.\n */\nfunction pathFromFileUri(location: string): string {\n let url: URL;\n try {\n url = new URL(location);\n } catch {\n // Not a URI at all: DITA-OT named a bare path, so it is the path.\n return location;\n }\n if (url.protocol !== \"file:\") return location;\n try {\n return fileURLToPath(url);\n } catch {\n return decodeURIComponent(url.pathname);\n }\n}\n\n/**\n * One log object as a finding, or `null` when it is not one.\n *\n * `code` is the marker. DITA-OT writes hundreds of `INFO` lines that are\n * progress rather than diagnostics, and it is its own account of which is\n * which, so an object without a code is chatter whatever its level.\n */\nfunction readMessage(raw: unknown): DitaOtMessage | null {\n if (!isMapping(raw)) return null;\n const code = raw[\"code\"];\n if (typeof code !== \"string\" || code === \"\") return null;\n const level = raw[\"level\"];\n const severity =\n typeof level === \"string\" ? foldDitaOtSeverity(level) : null;\n if (severity === null) return null;\n\n const msg = raw[\"msg\"];\n const location = raw[\"location\"];\n const line = raw[\"line\"];\n // `row` is the column. The name is the logger's: its regex takes group 2 as\n // the line and group 3 as the column, then writes the column out under this\n // name. Read as a row it puts every finding on the wrong line, so do not\n // \"fix\" it to `line`.\n const row = raw[\"row\"];\n\n return {\n code,\n severity,\n // A coded message with no text is still a finding; the code says what it is.\n message: typeof msg === \"string\" && msg !== \"\" ? msg : code,\n ...(typeof location === \"string\" && location !== \"\"\n ? { file: pathFromFileUri(location) }\n : {}),\n ...(typeof line === \"number\" ? { line } : {}),\n ...(typeof row === \"number\" ? { column: row } : {}),\n };\n}\n\n/**\n * The findings in a `--logger=json` log, or `null` when the text is not one.\n *\n * Null rather than an empty list, because the caller treats the two\n * differently: no findings is a clean target, while no log at all is only a\n * failure when the launcher also exited non-zero.\n */\nexport function parseDitaOtLog(text: string): DitaOtMessage[] | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text) as unknown;\n } catch {\n return null;\n }\n if (!Array.isArray(parsed)) return null;\n const messages: DitaOtMessage[] = [];\n for (const raw of parsed as unknown[]) {\n const message = readMessage(raw);\n if (message !== null) messages.push(message);\n }\n return messages;\n}\n\n/** The first version-shaped number in what the launcher printed. */\nexport function parseDitaOtVersion(output: string): string | null {\n const match = /\\b(\\d+(?:\\.\\d+)+(?:[-.][0-9A-Za-z]+)*)/.exec(output);\n return match?.[1] ?? null;\n}\n\n/** What one invocation of DITA-OT had to say about one target. */\nexport interface DitaOtTargetResult {\n /** The absolute path this invocation was given as `--input`. */\n target: string;\n messages: DitaOtMessage[];\n}\n\nexport interface DitaOtRunOptions {\n /** Absolute paths. One invocation each: DITA-OT takes one `--input`. */\n targets: string[];\n /** The directory the run resolves from, and where the launcher is started. */\n cwd: string;\n /** `tools.dita-ot.home`, already resolved to an absolute directory. */\n home?: string;\n spawn?: DitaOtSpawn;\n}\n\n/** The message a failure to run reports, which is the launcher's own. */\nfunction failureText(result: DitaOtProcessResult): string {\n const stderr = result.stderr.trim();\n if (stderr !== \"\") return stderr;\n // \"exit code null\" says nothing a reader can act on, and a signal is the one\n // ending that reliably leaves no message behind.\n if (result.signal != null) return `killed by ${result.signal}`;\n return `exit code ${String(result.code)}`;\n}\n\nasync function readLog(path: string): Promise<DitaOtMessage[] | null> {\n let text: string;\n try {\n text = await readFile(path, \"utf8\");\n } catch {\n return null;\n }\n return parseDitaOtLog(text);\n}\n\n/**\n * DITA-OT over each target, and what its log said.\n *\n * ## Why this is not `dita validate`\n *\n * Because `dita validate` does not answer the question this tool exists for.\n * Run against a map whose topic conrefs an id that is not there, it exits 0 and\n * prints nothing. It parses and checks grammar, and it resolves no references.\n * Its own `--help` lists neither `--logger` nor `--logfile` nor `--temp`, so\n * the obvious invocation is silently accepted and silently useless.\n *\n * `--format=dita` is the DITA-to-DITA transformation. It runs the whole\n * preprocessing chain, which is where conref, keyref and link resolution\n * happen, and it reports what those stages find. Measured against the fixtures\n * beside this file, it catches everything `validate` catches and the references\n * as well: a grammar error is `DOTJ088E` with a line and a column, a missing\n * conref target is `DOTX010E`, an unreadable link target is `DOTX008E`.\n *\n * The cost is that a transformation writes output. It goes to the scratch\n * directory with the logs and the temp trees, and the whole scratch is removed\n * however the run ends, so nothing of ours lands in the user's tree.\n *\n * ## Why verbose\n *\n * Because DITA-OT reports an undefined key reference (`DOTJ047I`) at `INFO`,\n * and the default verbosity drops it. Verbose turns one run of a four-file map\n * into roughly 135 log entries, of which one carries a `code`. That is what\n * makes the `code` filter in `parseDitaOtLog` load-bearing rather than tidy.\n */\nexport async function runDitaOtValidate(\n opts: DitaOtRunOptions,\n): Promise<DitaOtTargetResult[]> {\n const spawn = opts.spawn ?? spawnDitaOt;\n const launcher = ditaOtLauncher(opts.home);\n // A home that holds no launcher is a configuration mistake, and saying so\n // before anything is started names the thing the user can fix.\n if (opts.home !== undefined && !(await isFile(launcher))) {\n throw new LintError(noLauncher(opts.home));\n }\n\n const scratch = await mkdtemp(join(tmpdir(), \"manni-dita-ot-\"));\n try {\n const results: DitaOtTargetResult[] = [];\n for (const [index, target] of opts.targets.entries()) {\n const logfile = join(scratch, `${String(index)}.json`);\n const args = [\n `--input=${target}`,\n \"--format=dita\",\n `--output=${join(scratch, `out-${String(index)}`)}`,\n `--temp=${join(scratch, `temp-${String(index)}`)}`,\n \"--logger=json\",\n `--logfile=${logfile}`,\n \"--verbose\",\n ];\n\n let result: DitaOtProcessResult;\n try {\n result = await spawn(launcher, args, { cwd: opts.cwd });\n } catch (err) {\n if (isEnoent(err)) {\n throw new LintError(\n opts.home === undefined ? NOT_ON_PATH : noLauncher(opts.home),\n );\n }\n throw err;\n }\n\n const messages = await readLog(logfile);\n\n /**\n * A non-zero exit has to be accounted for by something we are going to\n * report. Otherwise the run failed for a reason this log does not hold,\n * and saying \"no findings\" would be inventing a clean bill of health.\n *\n * The asymmetry is DITA-OT's. It exits **0** while logging `DOTX010E`\n * for a broken conref, so a zero exit proves nothing and the log is the\n * verdict. It also exits **1** on a map that is not well-formed, having\n * already written a perfectly readable log whose only coded entries are\n * `DOTJ030I` at `INFO`, with the fatal parse error in neither the log\n * nor stdout nor stderr. Trusting the parse of that log reported the\n * file as passing, which is the false green this guard exists for.\n */\n // Only an `error` accounts for it. A warning or a notice is something\n // DITA-OT says while finishing the job, and it exits 0 having said it,\n // so a non-zero exit alongside nothing worse than `DOTJ047I` is still a\n // failure this log does not explain.\n const explained =\n messages !== null && messages.some((m) => m.severity === \"error\");\n\n if (result.code !== 0 && !explained) {\n if (opts.home === undefined && !(await isOnPath(launcher))) {\n throw new LintError(NOT_ON_PATH);\n }\n throw new LintError(\n `DITA Open Toolkit failed on ${target}: ${failureText(result)}. ` +\n `Run it directly on that file to see why.`,\n );\n }\n\n results.push({ target, messages: messages ?? [] });\n }\n return results;\n } finally {\n await rm(scratch, { recursive: true, force: true });\n }\n}\n\n/**\n * Whether DITA-OT can run here, and at what version.\n *\n * Never throws: reporting what cannot run is `manni lint tools`' job, and a\n * probe that threw would take the whole table down with it. So a launcher\n * that fails to start for any reason (`ENOENT`, but also `EACCES` or `EPERM`)\n * is unavailable. A non-zero exit counts as unavailable too, because on\n * Windows a missing `dita.bat` is cmd.exe's exit code rather than an `ENOENT`.\n */\nexport async function probeDitaOt(\n ctx: ToolProbeContext,\n spawn: DitaOtSpawn = spawnDitaOt,\n): Promise<ToolProbe> {\n const home =\n ctx.tools === undefined\n ? undefined\n : ditaOtHome(ctx.tools, ctx.configDir ?? ctx.cwd);\n const launcher = ditaOtLauncher(home);\n if (home !== undefined && !(await isFile(launcher))) {\n return { available: false, version: null };\n }\n\n let result: DitaOtProcessResult;\n try {\n result = await spawn(launcher, [\"--version\"], { cwd: ctx.cwd });\n } catch {\n return { available: false, version: null };\n }\n if (result.code !== 0) return { available: false, version: null };\n return {\n available: true,\n // Both channels, because which one carries the banner is not fixed: the\n // shell launcher prints it on stdout, and the Windows `.bat` run through\n // `cmd.exe` has been seen to put it on stderr. Reading one would report a\n // toolkit that is plainly there as versionless on the other platform.\n version: parseDitaOtVersion(`${result.stdout}\\n${result.stderr}`),\n };\n}\n\n/**\n * DITA's one format row.\n *\n * `kinds` is empty and that is correct: DITA-OT does not parse into manni's\n * content model, and the column exists to say what a template rule can ask\n * about. `.xml` is listed because a DITA topic is often named that way; the\n * walk set is narrower on purpose - see `walkExtensions`.\n */\nconst DITA_FORMAT: FormatInfo = {\n name: \"dita\",\n label: \"DITA\",\n extensions: [\".ditamap\", \".dita\", \".xml\"],\n kinds: [],\n};\n\nexport const ditaOt: StructureToolDescriptor = {\n name: \"dita-ot\",\n label: \"DITA Open Toolkit\",\n formats: () => [{ ...DITA_FORMAT }],\n // Maps only. DITA-OT takes one `--input` per invocation, so walking\n // every topic in a docset would pay a JVM start per topic. Naming a `.dita`\n // explicitly still works: a named file bypasses the extension filter.\n walkExtensions: () => [\".ditamap\"],\n probe: (ctx) => probeDitaOt(ctx),\n // None. Every option manni owns is refused under this tool, stdin included.\n ownedOptions: [],\n};\n","/**\n * The tools that can perform a lint job, one descriptor each.\n *\n * Deliberately **not** a unified `run()` interface. The tools take completely\n * different inputs: manni's engine needs the templates, the doctype index and\n * the parser registry, and a tool outside the package needs none of them. A\n * lowest-common-denominator `run(files, options)` would either lie about what\n * it accepts or grow a passthrough blob nobody can type. `src/shared/tools.ts`\n * records the same decision for `tools:`, and for the same reason.\n *\n * What the tools genuinely share is what the *command* has to know before it\n * dispatches: the formats to list, the extensions a directory walk collects,\n * whether the tool can run here, and which options belong to the tool rather\n * than to the job. That is this table, and nothing more. Running a tool stays\n * with the branch that runs it.\n */\nimport pkg from \"../../../package.json\" with { type: \"json\" };\nimport { listFormats, supportedExtensions } from \"../parsers/index.js\";\nimport type { FormatInfo } from \"../commands/tools.js\";\nimport { TOOLS_BY_JOB, type LintTool } from \"../core/config.js\";\nimport type { ToolsConfig } from \"../../shared/tools.js\";\nimport { LintError } from \"../types.js\";\nimport { ditaOt } from \"./dita-ot.js\";\n\n/** What a probe is allowed to look at. A tool outside the package shells out. */\nexport interface ToolProbeContext {\n /** The directory the run resolves from. */\n cwd: string;\n /**\n * The family's top-level `tools:`, when a config declared one.\n *\n * A tool outside the package is found where its own `tools.<tool>` says it\n * is, so a probe that could not read it would report \"not available\" over an\n * installation the run itself goes on to use. manni's own probe ignores it.\n */\n tools?: ToolsConfig;\n /** The directory the config that declared `tools:` sits in. */\n configDir?: string;\n}\n\n/** Whether a tool can run here, and at what version. */\nexport interface ToolProbe {\n available: boolean;\n /** The version the tool reported, or null when it reported none. */\n version: string | null;\n}\n\nexport interface StructureToolDescriptor {\n name: LintTool;\n label: string;\n /** Formats for `manni lint tools`' formats column. */\n formats: () => FormatInfo[];\n /** Extensions a directory walk collects when this tool runs. */\n walkExtensions: () => string[];\n /** Whether this tool can run here, and at what version. */\n probe: (ctx: ToolProbeContext) => Promise<ToolProbe>;\n /**\n * Options that belong to this tool alone, spelled as a user types them.\n *\n * `-` is in the list because stdin is one of them: a tool that reads a\n * document off a pipe is answering the same question as one that reads\n * `--template`, and deriving both from one list is what keeps the next tool\n * from having to remember to refuse either.\n */\n ownedOptions: readonly string[];\n}\n\n/**\n * manni's own engine, which ships in this package.\n *\n * `formats` and `walkExtensions` forward to the parser registry rather than\n * restating it: a format added there is listed and walked here the moment it\n * is registered, which is the property `parsers/index.ts` exists to have.\n */\nconst manni: StructureToolDescriptor = {\n name: \"manni\",\n label: \"manni's own structure engine\",\n formats: () => listFormats(),\n walkExtensions: () => supportedExtensions(),\n // Nothing to look for: the engine is this package, so it is available\n // wherever the CLI is. A tool that shells out answers this by looking.\n probe: () => Promise.resolve({ available: true, version: pkg.version }),\n // `-` is stdin, and it is in this list so the derivation in `lint.ts` has\n // one place to learn that manni owns it. The refusal itself is not shaped\n // like the others, because \"option\" is the wrong word for a positional:\n // `assertOptionsOwned` special-cases it to say \"cannot read stdin\" instead.\n // A tool that copies this list without reading that guard gets the right\n // ownership and the wrong sentence.\n ownedOptions: [\"--template\", \"--templates\", \"--explain\", \"--as\", \"-\"],\n};\n\n/**\n * Registered statically rather than through `registerStructureTool` at import\n * time, so the table and `LINT_TOOLS` agree whatever order the modules load\n * in: a name in `LINT_TOOLS` with no descriptor is a `--tool` value the config\n * validates and the run cannot dispatch.\n */\nconst descriptors = new Map<string, StructureToolDescriptor>([\n [manni.name, manni],\n [ditaOt.name, ditaOt],\n]);\n\n/**\n * Add a descriptor, and hand back the undo.\n *\n * The registry is mutable so a second tool can be stood up without a name\n * being added to `LINT_TOOLS` first. A name there is a `--tool` value the CLI\n * accepts and the config validates, so adding one for a tool that cannot run\n * is the silent green this seam exists to prevent.\n */\nexport function registerStructureTool(\n descriptor: StructureToolDescriptor,\n): () => void {\n const previous = descriptors.get(descriptor.name);\n descriptors.set(descriptor.name, descriptor);\n return () => {\n if (previous === undefined) descriptors.delete(descriptor.name);\n else descriptors.set(descriptor.name, previous);\n };\n}\n\n/** The descriptor registered under `name`, if there is one. */\nexport function structureTool(\n name: string,\n): StructureToolDescriptor | undefined {\n return descriptors.get(name);\n}\n\n/** Every registered descriptor, in registration order. */\nexport function structureTools(): StructureToolDescriptor[] {\n return [...descriptors.values()];\n}\n\n/**\n * The descriptor for a named tool, or the refusal a user reads.\n *\n * The message is the one the CLI's own `--tool` guard produced before the\n * registry existed, because `runLint` is exported from `src/index.ts` and\n * called in process: a caller that never touches commander owes the same\n * sentence.\n */\nexport function resolveStructureTool(name: string): StructureToolDescriptor {\n const descriptor = descriptors.get(name);\n if (descriptor) return descriptor;\n throw new LintError(\n `Unknown --tool \"${name}\" for structure. Use ${TOOLS_BY_JOB.structure.join(\", \")}.`,\n );\n}\n","/**\n * `lint` command core. Resolves targets, picks a parser per file, resolves a\n * template per file, and returns structured results. Free of CLI/IO plumbing so\n * it can be driven directly from tests and from the programmatic API.\n *\n * Template selection is per file, not per run: a page declares what it is\n * (`type: how-to`) and the template follows. `--template` still exists and\n * still overrides everything, but it is no longer required, which is what lets\n * one invocation lint a whole tree of mixed doctypes.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { extname, relative, resolve } from \"node:path\";\nimport { errorMessage, ToolError } from \"../../shared/errors.js\";\nimport {\n LintError,\n type DocumentParser,\n type DocumentTree,\n type FileResult,\n type Finding,\n type Position,\n} from \"../types.js\";\nimport {\n parserByName,\n parserForExtension,\n supportedExtensions,\n} from \"../parsers/index.js\";\nimport type { Template, TemplateFile } from \"../core/template.js\";\nimport {\n classifyRef,\n refRelativeTo,\n listBuiltins,\n loadResolvedTemplate,\n loadTemplateFile,\n} from \"../core/template-registry.js\";\nimport {\n buildTypeIndex,\n knownTypes,\n resolveTemplateRef,\n FILE_TEMPLATE_KEY,\n type Resolution,\n type TemplateOverride,\n type TypeIndexEntry,\n} from \"../core/resolve-template.js\";\nimport { validateDocument } from \"../core/validator.js\";\nimport {\n resolveStructureTool,\n structureTools,\n type StructureToolDescriptor,\n} from \"../tools/index.js\";\nimport {\n ditaOt,\n runDitaOtValidate,\n type DitaOtMessage,\n} from \"../tools/dita-ot.js\";\nimport { ditaOtHome } from \"../../shared/tools.js\";\nimport {\n assertNonEmpty,\n gitignoreOptions,\n resolveTargetSet,\n STDIN_TOKEN,\n} from \"../../meta/internal.js\";\nimport { isErrorSeverity } from \"../../meta/index.js\";\nimport { resolveLintRun, type LintConfig } from \"../core/config.js\";\n\n/** File label used for a document read from stdin. */\nexport const STDIN_LABEL = \"<stdin>\";\n\nexport interface LintOptions {\n /**\n * Positional inputs: files, directories, or globs. `-` reads stdin. Empty\n * falls back to the `collections:` the config declares (proposal 0041).\n */\n inputs: string[];\n /** `--collection <name>`, repeatable: the collections this run covers. */\n collection?: string[];\n /**\n * `--tool`: which tool performs the structure job. Overrides the config's\n * own `lint.structure.tool`, and defaults to manni's engine.\n */\n tool?: string;\n /** `--template`: a built-in id, a path, or a name inside `templates`. */\n template?: string;\n /**\n * `--templates`: template files whose `types:` join the routing table. A bare\n * `--template <name>` is resolved as a name inside the *last* of them, which\n * is the pairing the manni docevals adapter invokes. Last, not first, to\n * agree with `buildTypeIndex`: a later file overrides an earlier one there,\n * so resolving a bare name against the first would make one name mean two\n * different templates depending on how it was written.\n */\n templates?: string | string[];\n /** `--as`: force an input format, by parser name. */\n as?: string;\n /** `--ext`: extensions kept during directory and glob expansion. */\n exts?: string[];\n /** `--exclude`: globs removed from directory/glob expansion. */\n exclude?: string[];\n cwd?: string;\n /** Content for the `-` input, injected by the CLI and by tests. */\n stdinContent?: string;\n /** `--explain`: record how each file's template was chosen. */\n explain?: boolean;\n /** Repo policy: first matching glob wins. Overrides the config's own. */\n overrides?: TemplateOverride[];\n /** Applied when a page declares no doctype. Overrides the config's own. */\n defaultTemplate?: string;\n /** Explicit doctype -> template ref map. Overrides the config's own. */\n types?: Record<string, string>;\n /** `--allow-empty`: zero matched files is a success, not an error. */\n allowEmpty?: boolean;\n /** `--no-gitignore`: only an explicit `false` travels, so config can decide. */\n respectGitignore?: boolean;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /** Told which config governed the run, and where it came from. */\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n /** Told what the run had to say beside its findings. */\n onNotice?: (message: string) => void;\n /**\n * The DITA-OT seam, injected by tests, as `term lint` injects Vale's.\n *\n * There is no JVM and no DITA-OT on a CI runner of ours, so the only way to\n * exercise this branch end to end is to hand it the process boundary. The\n * shipped default is the real one.\n */\n runDitaOt?: typeof runDitaOtValidate;\n}\n\n/** Extensions that make a bare `--template` value a filename, not a name. */\nconst TEMPLATE_FILE_EXTENSIONS = [\".yaml\", \".yml\", \".json\"];\n\n/**\n * Run a family helper, rethrowing the error it raises as this tool's.\n *\n * The walker and its guards are meta's, and they throw `DocmetaError` - a\n * sibling of `LintError`, not a parent of it. `runLint` is exported from\n * `src/index.ts` and called in process by manni docevals, so a caller doing\n * the documented thing, `catch (err) { if (err instanceof LintError) … }`,\n * missed the two most ordinary operational failures there are: a mistyped path\n * and a pattern matching nothing. The message is the walker's own, which is\n * the part the user reads; only the class changes.\n */\nasync function asLintError<T>(run: () => T | Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (err) {\n if (err instanceof LintError) throw err;\n // A `ToolError` from any sibling is operational and already worded for a\n // user. Anything else is a bug and keeps its class and its stack.\n if (err instanceof ToolError) throw new LintError(err.message);\n throw err;\n }\n}\n\n/** `--templates` accepts one path or several; normalize to a list. */\nfunction templateFiles(value: string | string[] | undefined): string[] {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value];\n}\n\n/**\n * The options a tool can own, in the order the guard reports them, each paired\n * with how to tell that the caller passed it.\n *\n * `--templates` reads `opts` alone. A `templates:` key in the config describes\n * the repo rather than the invocation, so a repo that has written one must not\n * be refused the moment it points a different tool at the same tree.\n */\nconst TOOL_OPTIONS: {\n spelling: string;\n given: (opts: LintOptions) => boolean;\n}[] = [\n { spelling: \"--template\", given: (o) => o.template !== undefined },\n {\n spelling: \"--templates\",\n given: (o) => templateFiles(o.templates).length > 0,\n },\n { spelling: \"--explain\", given: (o) => o.explain === true },\n { spelling: \"--as\", given: (o) => o.as !== undefined },\n];\n\n/**\n * The options some other registered tool owns and this one does not, each with\n * the tool that does own it.\n *\n * Derived rather than written out per tool, because a hand-written chain is a\n * list the next tool has to remember to join - and the failure mode of\n * forgetting is a silently ignored option, which is a run that reports success\n * having done something other than what was asked.\n */\nfunction foreignOptions(\n tool: StructureToolDescriptor,\n): Map<string, StructureToolDescriptor> {\n const foreign = new Map<string, StructureToolDescriptor>();\n for (const other of structureTools()) {\n // By identity, not by name: the registry holds one descriptor per name, so\n // the tool this run resolved *is* its entry, and comparing the names is a\n // tautology to the compiler while `LintTool` carries one of them.\n if (other === tool) continue;\n for (const spelling of other.ownedOptions) {\n if (tool.ownedOptions.includes(spelling)) continue;\n if (!foreign.has(spelling)) foreign.set(spelling, other);\n }\n }\n return foreign;\n}\n\n/**\n * Refuse an option that belongs to a tool this run is not performing the job\n * with. One message, naming the first offending option.\n *\n * Ignoring it instead would be the quietest kind of wrong answer: the flag\n * reads as applied, the run exits 0, and nothing says the template, the format\n * override or the explanation was dropped on the floor.\n */\nfunction assertOptionsOwned(\n opts: LintOptions,\n tool: StructureToolDescriptor,\n usingStdin: boolean,\n): void {\n const foreign = foreignOptions(tool);\n if (foreign.size === 0) return;\n\n for (const { spelling, given } of TOOL_OPTIONS) {\n const owner = foreign.get(spelling);\n if (owner === undefined || !given(opts)) continue;\n throw new LintError(\n `${spelling} is an option of the ${owner.name} tool; ` +\n `the structure job's tool is ${tool.name}.`,\n );\n }\n\n // Stdin last, and in its own words: \"option\" is the wrong noun for a pipe,\n // and the advice a reader needs is what to pass instead.\n if (usingStdin && foreign.has(STDIN_TOKEN)) {\n throw new LintError(`${tool.name} cannot read stdin. Name files or a map.`);\n }\n}\n\nexport interface LintSummary {\n /** Files actually linted. Always `passed + failed`; skips are counted apart. */\n checked: number;\n passed: number;\n failed: number;\n skipped: number;\n}\n\n/**\n * A `FileResult` plus the human-readable reason a file was skipped.\n *\n * `types.ts` pins the fields manni docevals reads off the JSON reporter, so\n * this diagnostic lives here instead: it exists for pretty output, and the\n * JSON reporter never emits it.\n */\nexport interface LintFileResult extends FileResult {\n /** Why the file was skipped, in words. Set only alongside `skipped`. */\n reason?: string;\n /** How the template was chosen. Present when `--explain` asked for it. */\n resolution?: Resolution;\n /**\n * What the alignment block is rendered from. Present when `--explain` asked\n * for it, and only for a file that routed to a template.\n *\n * Nested rather than flat, because `FileResult.template` is already taken by\n * the template's *ref* - the string a reader sees on the routing line. A\n * loaded `Template` beside it under the same name would be two things called\n * one thing, and the reporter would read whichever it got.\n */\n alignment?: { tree: DocumentTree; template: Template };\n}\n\nexport interface LintRun {\n results: LintFileResult[];\n summary: LintSummary;\n}\n\n/** Zero-width span at the top of a file, for findings with nowhere better. */\nfunction origin(): Position {\n return {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n };\n}\n\nfunction skip(\n file: string,\n reason: string,\n cause: FileResult[\"skipped\"] = \"unsupported-format\",\n): LintFileResult {\n return {\n file,\n // `success` means \"linted and produced no findings\". A file that was never\n // linted is neither passing nor failing, and calling it a pass would hide\n // the gap from anyone reading CI output.\n success: false,\n findings: [],\n template: null,\n skipped: cause,\n reason,\n };\n}\n\nfunction parseFinding(message: string): Finding {\n return {\n type: \"parse_error\",\n heading: null,\n message,\n position: origin(),\n severity: \"error\",\n };\n}\n\n/**\n * A template ref, loaded once per run however many pages route to it.\n *\n * The registry deliberately leaves `extends` unresolved, so the merge happens\n * here. Skipping it would make inheritance silently inert: a template that\n * inherits every one of its sections would check nothing and report a clean\n * pass. `resolveExtends` is a no-op on a template without `extends`.\n */\nfunction templateLoader(): (ref: string) => Promise<Template> {\n const cache = new Map<string, Promise<Template>>();\n return (ref) => {\n let pending = cache.get(ref);\n if (!pending) {\n pending = loadResolvedTemplate(ref);\n cache.set(ref, pending);\n }\n return pending;\n };\n}\n\n/**\n * Normalize `--template` into a ref the registry understands.\n *\n * `--templates t.yaml --template how-to` is the pairing the manni docevals\n * adapter invokes, and it means \"the template named how-to inside t.yaml\".\n * A ref that already names a file, a URL, or a built-in is passed through.\n */\nfunction cliTemplateRef(\n template: string | undefined,\n templatePaths: string[],\n): string | undefined {\n if (!template) return undefined;\n // A ref that names itself is passed through. Sniffing for `#`, `/` and `\\`\n // missed built-in ids, which contain none of them, so `-t tgdp:how-to:1.6`\n // silently became a lookup for a template of that name inside the first\n // `--templates` file the moment one was given.\n if (template.includes(\"#\")) return template;\n if (classifyRef(template).kind !== \"file\") return template;\n if (template.includes(\"/\") || template.includes(\"\\\\\")) return template;\n // A bare filename names a file even without a separator: `--template\n // custom.yaml` means that file, not a template called \"custom.yaml\" inside\n // some other one.\n if (TEMPLATE_FILE_EXTENSIONS.some((e) => template.toLowerCase().endsWith(e))) {\n return template;\n }\n if (templatePaths.length === 0) return template;\n\n // A bare name is a name inside a `--templates` file. Search them last-first,\n // matching `buildTypeIndex`, so the file that wins routing also wins here.\n return `${templatePaths[templatePaths.length - 1] ?? \"\"}#${template}`;\n}\n\n/**\n * Which file a template came from and what it is called there.\n *\n * The validator and the matcher both name the template in messages - the\n * state-cap failure, and the warning about a rule a format cannot answer - and\n * neither can work either out from a `Template` object, which carries no\n * record of where it was loaded from. The ref does: `./templates.yaml#how-to`\n * is a file and a name, and a built-in id is both at once.\n */\nfunction templateIdentity(ref: string): { source: string; template: string } {\n const hash = ref.lastIndexOf(\"#\");\n if (hash === -1) return { source: ref, template: ref };\n return { source: ref.slice(0, hash), template: ref.slice(hash + 1) };\n}\n\n/** The finding a page gets when it declares a doctype nothing serves. */\nfunction unknownTypeFinding(\n resolution: Resolution,\n typeIndex: Map<string, TypeIndexEntry>,\n position: Position,\n): Finding {\n const suggestions = resolution.suggestions ?? [];\n const known = resolution.knownTypes ?? knownTypes(typeIndex);\n const hint = suggestions.length\n ? ` Did you mean ${suggestions.map((s) => `\"${s}\"`).join(\", \")}?`\n : ` Known doctypes: ${known.join(\", \") || \"(none)\"}.`;\n // `unknownType` is set whenever the cause is `unknown-type`, but the type\n // says `string | undefined` and only the resolver enforces the pairing. The\n // fallback keeps a future break from printing `type \"undefined\"`, which\n // would send the reader looking for a doctype they never wrote.\n const declared = resolution.unknownType ?? \"(none recorded)\";\n return {\n type: \"unknown_type\",\n heading: null,\n message:\n `No template serves type \"${declared}\".${hint} ` +\n `Declare it on a template with \"types:\", then pass that file with --templates.`,\n position,\n severity: \"error\",\n };\n}\n\ninterface LintContext {\n getTemplate: (ref: string) => Promise<Template>;\n /** Absolute, forward-slashed form of a display path, for override globs. */\n absoluteOf?: (file: string) => string;\n typeIndex: Map<string, TypeIndexEntry>;\n cliTemplate?: string;\n overrides?: TemplateOverride[];\n defaultTemplate?: string;\n explain: boolean;\n}\n\nasync function lintOne(\n label: string,\n content: string,\n parser: DocumentParser,\n ctx: LintContext,\n): Promise<LintFileResult> {\n let tree: DocumentTree;\n try {\n tree = parser.parse(content, label);\n } catch (err) {\n // A file that will not parse is that file's problem, not the run's: it is\n // reported and the run continues, so one broken page cannot hide the\n // findings in the other 199.\n return {\n file: label,\n success: false,\n findings: [parseFinding(errorMessage(err))],\n template: null,\n };\n }\n\n // Routing needs the frontmatter, so it happens after the parse rather than\n // before the read - which is also what makes `--explain` able to say what the\n // page actually declared.\n const resolution = resolveTemplateRef({\n filePath: label,\n absolutePath: ctx.absoluteOf?.(label),\n frontmatter: tree.frontmatter,\n cliTemplate: ctx.cliTemplate,\n overrides: ctx.overrides,\n typeIndex: ctx.typeIndex,\n defaultTemplate: ctx.defaultTemplate,\n });\n const withResolution = <T extends LintFileResult>(result: T): T =>\n ctx.explain ? { ...result, resolution } : result;\n\n // Anchor anything said about the frontmatter at the frontmatter.\n const metaPosition = tree.frontmatterPosition ?? origin();\n\n if (resolution.ref === null) {\n if (resolution.cause === \"unknown-type\") {\n // A declared type that resolves to nothing is a typo or a gap. Skipping\n // would mean a page silently stops being checked, which is the one\n // outcome worse than a false positive.\n return withResolution({\n file: label,\n success: false,\n findings: [unknownTypeFinding(resolution, ctx.typeIndex, metaPosition)],\n template: null,\n });\n }\n // An untyped page is manni meta's complaint, not this tool's - its OKF\n // schema already requires `type`. Skipping is what lets manni lint be\n // pointed at a whole tree on day one.\n return withResolution(\n skip(\n label,\n \"no type in frontmatter and no template resolved\",\n \"no-template\",\n ),\n );\n }\n\n /** A broken template, reported against this page rather than thrown. */\n const brokenTemplate = (err: unknown): LintFileResult =>\n withResolution({\n file: label,\n success: false,\n findings: [\n {\n type: \"template_error\",\n heading: null,\n message: errorMessage(err),\n position: metaPosition,\n severity: \"error\",\n },\n ],\n template: resolution.ref,\n });\n\n // A page may not send the linter to a URL of its own choosing.\n //\n // `type` comes out of the document too, but it only *selects* from the\n // routing table the operator assembled - a page can ask for a template on\n // offer, not introduce one. `$template` names a reference directly, which\n // makes it the one stage where a document says where a template comes from,\n // and documents are exactly what this tool is pointed at untrusted: a docset\n // from a fork, a contributor's branch, a vendored copy.\n // Left open, one line of frontmatter makes the linting host issue an\n // arbitrary request, which on CI means from inside the build network. The\n // `$ref` hole this mirrors was closed in the template loader; this is the\n // same hole one level up, where the ref itself is attacker-chosen.\n //\n // Refused rather than ignored, because silently falling through to `type`\n // would lint the page against something other than what it asked for and say\n // nothing. An operator who does want a remote template still has every other\n // stage: name it in `templates:`, map it under `types:`, or pass --template.\n if (\n resolution.stage === \"frontmatter-template\" &&\n classifyRef(resolution.ref).kind === \"url\"\n ) {\n return brokenTemplate(\n new LintError(\n `${FILE_TEMPLATE_KEY} may not name a URL (\"${resolution.ref}\"): a document ` +\n `must not choose what the linter fetches. Declare it in manni.config.yaml ` +\n `under \"templates:\" or \"types:\", or pass it with --template.`,\n ),\n );\n }\n\n // A relative `$template` means \"beside this page\", not \"beside wherever the\n // tool happened to be invoked from\". `extends` already follows that rule, and\n // for the same reason: resolved against the process cwd, `$template:\n // ./house.yaml` in `docs/guide.md` found the file only when the run started\n // in `docs/` - so the page routed correctly from one directory and reported\n // \"Template file not found\" from every other, including from CI.\n const ref =\n resolution.stage === \"frontmatter-template\"\n ? refRelativeTo(ctx.absoluteOf?.(label) ?? label, resolution.ref)\n : resolution.ref;\n\n let template: Template;\n try {\n template = await ctx.getTemplate(ref);\n } catch (err) {\n // One unloadable template must not abort a run over a whole tree; it is\n // reported against the pages that route to it.\n return brokenTemplate(err);\n }\n\n // `--explain` stops here, having promised to \"lint nothing\".\n //\n // The line is drawn after loading rather than before it, because loading is\n // part of the answer the flag exists to give: \"which template, and why\" is\n // not answered by naming a ref that does not resolve, and a broken\n // `--templates` path is exactly the surprise someone runs `--explain` to\n // find. Loading is also cheap in the way validation is not - templates are\n // cached, so a tree of one doctype loads once, while `validateDocument` runs\n // per file and its findings are then discarded unrendered.\n if (ctx.explain) {\n return withResolution({\n file: label,\n success: true,\n findings: [],\n template: resolution.ref,\n // The tree and the loaded template, for the alignment block. Both are\n // already in hand here, and neither survives this function otherwise.\n alignment: { tree, template },\n });\n }\n\n let findings: Finding[];\n try {\n findings = validateDocument(tree, template, {\n ...templateIdentity(ref),\n kinds: parser.kinds,\n });\n } catch (err) {\n // Validation can raise for the same reason loading can: a template the\n // author got wrong - an uncompilable `heading.pattern` is the live case.\n // Without this the raise escapes `runLint` and kills the run, so one bad\n // pattern hides the findings in every other page, which is the outcome the\n // load path above exists to prevent.\n if (err instanceof LintError) return brokenTemplate(err);\n throw err;\n }\n\n return withResolution({\n file: label,\n // \"Linted and found nothing wrong\", which is not the same as \"produced no\n // findings\". A `warning` - today, a rule this file's format cannot answer -\n // says something about the run rather than about the document, and the\n // exit code follows `success`, so counting it as a failure would turn a\n // docset of mixed formats permanently red. The family's rule, and the one\n // meta and cite already apply: `ok` is \"no error-severity finding\".\n success: !findings.some(isErrorSeverity),\n findings,\n template: resolution.ref,\n });\n}\n\n/** Everything manni's branch needs, settled once by the shared prefix. */\ninterface ManniRun {\n opts: LintOptions;\n config: LintConfig;\n /** The directory the resolved files are relative to. */\n cwd: string;\n /** The files the shared target resolution produced. */\n files: string[];\n /** The parser `--as` forced, when it did. */\n forcedParser?: DocumentParser;\n /** Whether `-` rode among the inputs. */\n usingStdin: boolean;\n}\n\n/**\n * Lint with manni's own engine.\n *\n * Everything below this line is manni's and nobody else's: the template files,\n * the doctype index, the parser registry, and the guard that fires when a run\n * checks nothing. The loading in particular has to sit here rather than in the\n * shared prefix, because it is file I/O a tool that reads no templates must\n * not be made to pay - and a missing `templates:` entry is then the loader's\n * error under manni and nothing at all under anybody else.\n */\nasync function lintWithManni(run: ManniRun): Promise<LintFileResult[]> {\n const { opts, config, cwd, files, forcedParser, usingStdin } = run;\n\n // The doctype -> template map. Built-ins go in first and user templates\n // overwrite them, so overriding `how-to` for a repo is one file with\n // `types: [how-to]` in it - no config entry, no flag.\n const templatePaths = templateFiles(opts.templates ?? config.templates);\n const getTemplate = templateLoader();\n\n const userFiles: { ref: string; file: TemplateFile }[] = [];\n for (const ref of templatePaths) {\n const file = await loadTemplateFile(ref);\n // `extends` is resolved before `types` is read. A template that inherits\n // its doctypes declares none of its own, so reading the raw file routes\n // nothing to it - the override loads, merges, and is silently inert while\n // the page goes to the built-in it meant to replace. The loader is cached,\n // so this costs nothing the lint would not already pay.\n const templates: Record<string, Template> = {};\n for (const name of Object.keys(file.templates ?? {})) {\n templates[name] = await getTemplate(`${ref}#${name}`);\n }\n userFiles.push({ ref, file: { ...file, templates } });\n }\n\n const typeIndex = buildTypeIndex({\n builtins: listBuiltins(),\n userFiles,\n explicitTypes: opts.types ?? config.types,\n });\n\n const ctx: LintContext = {\n getTemplate,\n absoluteOf: (file) => resolve(cwd, file).replace(/\\\\/g, \"/\"),\n typeIndex,\n cliTemplate: cliTemplateRef(opts.template, templatePaths),\n overrides: opts.overrides ?? config.overrides,\n // `template:` in config is the default for a page that declares no type -\n // the bottom of the chain, not the top. `--template` is the top.\n defaultTemplate: opts.defaultTemplate ?? config.template,\n explain: opts.explain === true,\n };\n\n // `--template` applies to every file, so a ref that will not load is bad\n // usage, not a property of any page. Resolved before a single page is linted\n // so it exits 2 with one message, rather than becoming an identical\n // `template_error` finding on all 200 pages and exiting 1 - which reads to\n // CI as \"the docs are wrong\".\n if (ctx.cliTemplate != null) await getTemplate(ctx.cliTemplate);\n\n const results: LintFileResult[] = [];\n\n // `forcedParser` is set whenever `usingStdin` is - the shared prefix refused\n // the run otherwise - but only that guard knows it, so the pair is tested\n // rather than asserted.\n if (usingStdin && forcedParser) {\n results.push(\n await lintOne(STDIN_LABEL, opts.stdinContent ?? \"\", forcedParser, ctx),\n );\n }\n\n for (const file of files) {\n const ext = extname(file);\n const parser = forcedParser ?? parserForExtension(ext);\n // The parser is chosen before the read, not after, because a file nothing\n // can parse must not depend on being readable to be reported. Reading\n // first pulls every skipped file into memory for nothing, and an\n // unreadable one - a denied permission, a file a doc build moved mid-run -\n // throws out of this loop, so a `.xyz` nobody asked us to parse takes the\n // whole run down with it: exit 2 and no verdict for any of the pages after\n // it, instead of one skip line and a report.\n if (!parser) {\n results.push(\n skip(\n file,\n `no parser is registered for \"${ext || file}\". Supported extensions: ${supportedExtensions().join(\", \")}. Use --as to override.`,\n ),\n );\n continue;\n }\n let content: string;\n try {\n content = await readFile(resolve(cwd, file), \"utf8\");\n } catch (err) {\n // The read is the other thing that can fail per file, and it failed out\n // of the loop: a denied permission, a symlink loop, or a page a doc\n // build moved between `resolveTargetSet` and here threw straight through\n // `runLint` to `fail()`. Exit 2, no report, and every result already\n // gathered discarded - which is exactly what moving the parser lookup\n // before the read was meant to prevent, one step further along.\n //\n // The OS message travels verbatim: \"permission denied\" and \"no such\n // file\" send the reader to different places, and this code cannot tell\n // which it was.\n results.push(\n skip(file, `could not be read: ${errorMessage(err)}`, \"unreadable\"),\n );\n continue;\n }\n results.push(await lintOne(file, content, parser, ctx));\n }\n\n return results;\n}\n\n/** Everything the DITA-OT branch needs, and nothing else. */\ninterface DitaOtRun {\n /** The directory the resolved files are relative to. */\n cwd: string;\n /** The files the shared target resolution produced, as it spelled them. */\n files: string[];\n /** `tools.dita-ot.home`, resolved; undefined means the `dita` on PATH. */\n home?: string;\n onNotice?: (message: string) => void;\n /** The seam. The shipped default starts the real launcher. */\n validate: typeof runDitaOtValidate;\n}\n\n/** One DITA-OT message as a finding. */\nfunction ditaOtFinding(message: DitaOtMessage): Finding {\n // The code is the finding's `type`, so `ruleId` yields\n // `manni:lint/structure/DOTX010E` and the JSON reporter publishes the code\n // DITA-OT's own message reference is indexed by.\n const point =\n message.line === undefined\n ? null\n : {\n line: message.line,\n // The log calls the column `row`; see `readMessage` in the seam.\n column: message.column ?? 1,\n // DITA-OT reports no byte offset, and nothing downstream needs one.\n offset: 0,\n };\n return {\n type: message.code,\n heading: null,\n message: message.message,\n position: point === null ? origin() : { start: point, end: point },\n severity: message.severity,\n };\n}\n\n/**\n * Lint with DITA Open Toolkit.\n *\n * One invocation per target, and the log is the verdict. A map's log speaks\n * about the topics it reached, so the findings are grouped by the file each\n * message named rather than by the file the run was pointed at - which is how\n * one map target produces a result per topic.\n */\nasync function lintWithDitaOt(run: DitaOtRun): Promise<LintFileResult[]> {\n const { cwd, files, onNotice } = run;\n\n /**\n * Only the formats this tool says it reads are handed to it.\n *\n * `manni lint tools` prints that list, and the rule the registry documents\n * is that a listed format is one that is read. Passing anything else on and\n * reporting whatever came back meant a `notes.md` named on the command line\n * came out as a clean pass, because DITA-OT shrugged and logged nothing to\n * disagree with. The manni branch skips a format no parser claims; this is\n * the same answer for the same reason.\n */\n const readable = ditaOt.formats().flatMap((format) => format.extensions);\n const reads = new Set(readable.map((ext) => ext.toLowerCase()));\n const targets: string[] = [];\n const unsupported: LintFileResult[] = [];\n for (const file of files) {\n if (reads.has(extname(file).toLowerCase())) targets.push(file);\n else {\n unsupported.push(\n skip(\n file,\n `dita-ot does not read \"${extname(file) || file}\". It reads ${readable.join(\", \")}.`,\n ),\n );\n }\n }\n\n // The label the run resolved is what the report says, whatever spelling the\n // absolute path comes back with.\n /**\n * One entry per absolute path, first spelling wins.\n *\n * **Defensive, not a fix for anything reachable today.** `resolveTargetSet`\n * normalizes every input to a cwd-relative posix path and holds them in a\n * `Set`, so two spellings of one file cannot arrive here. Review raised the\n * collision as a hazard and it is a real one in isolation: built naively the\n * later label replaces the earlier, `byFile` keeps both, and findings reach\n * only the survivor while the other reports as a clean pass.\n *\n * Kept because this function starts a JVM per target, so being correct on\n * its own terms rather than on its caller's is worth eight lines. Do not\n * write a test that claims to prove the collision: it cannot be reached\n * from `runLint`, and a test that passes either way proves nothing.\n */\n const labels = new Map<string, string>();\n for (const file of targets) {\n const absolute = resolve(cwd, file);\n if (!labels.has(absolute)) labels.set(absolute, file);\n }\n const unique = [...labels.values()];\n const labelOf = (absolute: string): string => {\n const known = labels.get(absolute);\n if (known !== undefined) return known;\n const near = relative(cwd, absolute).replace(/\\\\/g, \"/\");\n return near === \"\" ? absolute : near;\n };\n\n for (const file of unique) {\n // Checked, not skipped: a topic on its own is validated, it just resolves\n // fewer references than the same topic reached through its map. Calling it\n // a skip would say nothing was checked, which is false.\n if (extname(file).toLowerCase() !== \".ditamap\") {\n onNotice?.(\n `checked ${file} without a map; references outside it are not resolved.`,\n );\n }\n }\n\n // Nothing this tool can read is not a run: starting a JVM per target for an\n // empty list would be work with no answer at the end of it.\n if (unique.length === 0) return unsupported;\n\n const results = await run.validate({\n targets: [...labels.keys()],\n cwd,\n ...(run.home === undefined ? {} : { home: run.home }),\n });\n\n // Seeded with the targets, so a target DITA-OT had nothing to say about is a\n // result that passed rather than a file missing from the report.\n const byFile = new Map<string, Finding[]>(unique.map((file) => [file, []]));\n const findingsFor = (file: string): Finding[] => {\n let list = byFile.get(file);\n if (list === undefined) {\n list = [];\n byFile.set(file, list);\n }\n return list;\n };\n\n // A topic DITA-OT names that nobody targeted becomes a result of its own, so\n // `checked` can exceed the number of paths the user typed. That is the\n // answer, not an inflation of it: pointing at a map is how you ask about the\n // topics it gathers, and a finding against `topic.dita` has to be reported\n // against `topic.dita` for anyone to fix it. One map in, two files checked.\n for (const { target, messages } of results) {\n const invoked = labelOf(target);\n for (const message of messages) {\n // A message with no location belongs to the target the run was invoked\n // on, at a zero-width origin: DITA-OT's semantic messages routinely\n // carry no file, and discarding them would drop real errors.\n const file =\n message.file === undefined\n ? invoked\n : labelOf(resolve(cwd, message.file));\n findingsFor(file).push(ditaOtFinding(message));\n }\n }\n\n return [\n ...unsupported,\n ...[...byFile].map(([file, findings]) => ({\n file,\n // The family's rule, as manni's branch applies it: `ok` is \"no\n // error-severity finding\", so a warning-only file stays green.\n success: !findings.some(isErrorSeverity),\n findings,\n template: null,\n })),\n ];\n}\n\n/**\n * A run that found files and checked none of them is the worst thing this tool\n * can do quietly: it exits 0 and reads as a clean bill of health for a docset\n * nothing looked at. A repo that adopts manni lint in CI before backfilling\n * `type:` keys would get a permanently green job.\n *\n * This replaces a guard that tested `typeIndex.size === 0` before any file was\n * read. That could never fire - the index is always seeded with the built-ins\n * - so it protected nothing. Counting the outcome does.\n *\n * `--explain` is exempt: showing why nothing routed is exactly its job.\n */\nfunction assertSomethingWasChecked(\n results: LintFileResult[],\n explain: boolean,\n tool: StructureToolDescriptor,\n): void {\n const skipped = results.filter((r) => r.skipped != null).length;\n const checked = results.length - skipped;\n if (explain || checked > 0 || skipped === 0) return;\n\n // The advice has to follow the cause. The guard fires on any skip, but it\n // used to describe routing only - so a run over files no parser claims was\n // told to add a `type:` key, which changes nothing about an extension the\n // tool cannot read. Advice the reader cannot act on is only half a guard.\n const unrouted = results.filter((r) => r.skipped === \"no-template\").length;\n const unsupported = results.filter(\n (r) => r.skipped === \"unsupported-format\",\n ).length;\n const unreadable = results.filter((r) => r.skipped === \"unreadable\").length;\n const advice = [\n unrouted > 0\n ? `${unrouted} had no template: give a page a \"type:\" that a template ` +\n `serves, pass -t/--template <ref>, or set \"lint.template\" as a default.`\n : null,\n unsupported > 0\n ? // `--as` belongs to manni's engine, so offering it to someone running\n // another tool is advice that answers with a usage error. The formats\n // line is true for every tool, because every tool declares one.\n `${unsupported} ${unsupported === 1 ? \"is\" : \"are\"} in a format ` +\n `${tool.name} does not read: ` +\n (tool.ownedOptions.includes(\"--as\")\n ? `pass --as <format> to force one, or target files in a format `\n : `target files in a format `) +\n `\"manni lint tools\" lists.`\n : null,\n unreadable > 0\n ? `${unreadable} could not be read: check the permissions on those ` +\n `paths, or drop them from the run with --exclude <glob>.`\n : null,\n ]\n .filter((line): line is string => line !== null)\n .join(\" \");\n\n throw new LintError(\n `Nothing was checked: all ${skipped} file(s) were skipped. ${advice} ` +\n `Run \"manni lint structure <paths> --explain\" to see how each file resolved.`,\n );\n}\n\nexport async function runLint(opts: LintOptions): Promise<LintRun> {\n // Which config governs the run, and what it covers: positional paths, or\n // the `collections:` the family file declares. One base per run, so a\n // collection's globs resolve beside the config that wrote them.\n const run = await resolveLintRun({\n cwd: opts.cwd ?? process.cwd(),\n configPath: opts.configPath,\n noConfig: opts.noConfig,\n inputs: opts.inputs,\n collection: opts.collection,\n onConfigLoaded: opts.onConfigLoaded,\n });\n const config: LintConfig = run.config;\n const cwd = run.base;\n\n if (run.inputs.length === 0) {\n throw new LintError(\n \"No files to check. Pass paths/globs, or declare a collection under `collections:` in manni.config.yaml.\",\n );\n }\n\n // Which tool performs the structure job: `--tool` first, then the config's\n // `lint.structure.tool`, then manni's own engine. Settled before anything is\n // read, because it decides what \"anything\" even is - the extensions a walk\n // collects, and which of the options below the run may carry at all.\n const tool = resolveStructureTool(\n opts.tool ?? config.structure?.tool ?? \"manni\",\n );\n\n const usingStdin = run.inputs.includes(STDIN_TOKEN);\n assertOptionsOwned(opts, tool, usingStdin);\n\n // Resolve `--as` before anything is read: a typo should fail immediately,\n // not after walking a tree of files it was going to mis-parse anyway.\n //\n // A name no parser answers to is unknown, whatever it is meant to name: the\n // formats `manni lint tools` lists are exactly the ones `--as` accepts.\n const forcedParser = opts.as != null ? parserByName(opts.as) : undefined;\n if (opts.as != null && !forcedParser) {\n throw new LintError(\n `Unknown format \"${opts.as}\". Run \"manni lint tools\" to see the formats manni lint reads.`,\n );\n }\n\n // Before the targets are resolved, as cite does: a mistyped path beside `-`\n // was reported as \"File not found\", which names the wrong mistake when the\n // run could not have read stdin either way.\n if (usingStdin && !forcedParser) {\n throw new LintError(\n \"Reading from stdin (-) requires --as <format> to choose a parser.\",\n );\n }\n\n const fileInputs = run.inputs.filter((input) => input !== STDIN_TOKEN);\n // The resolved tool's own walk set is the default, not the walker's. Left\n // undefined, the family walker falls back to the *metadata* tool's extractor\n // extensions, which sweep in every format that tool reads - `.xml` among\n // them, where manni lint's registry honours `walkExtensions` and\n // deliberately walks `.dita` and not `.xml`, so an ordinary `pom.xml` cannot\n // fail a clean tree. Read off the descriptor rather than off that registry\n // directly, so a tool with input formats of its own walks for those.\n // Resolved here rather than at the walk, so `assertNonEmpty` names the same\n // set it filtered with.\n const exts = opts.exts ?? forcedParser?.extensions ?? tool.walkExtensions();\n const allowEmpty = opts.allowEmpty ?? config.allowEmpty;\n // A collection's `exclude:` shapes the collection, so it applies when the\n // inputs came from the collections and never to a path the operator typed.\n // `--exclude` filters either way; the union is deduplicated.\n const exclude = [\n ...new Set([\n ...(opts.exclude ?? []),\n ...(run.fromCollections ? run.collections.flatMap((c) => c.exclude) : []),\n ]),\n ];\n const { files, gitignoreSkipped } = await asLintError(() =>\n resolveTargetSet({\n inputs: fileInputs,\n exts,\n exclude,\n cwd,\n allowEmpty,\n ...gitignoreOptions({\n flag: opts.respectGitignore,\n onNotice: opts.onNotice,\n }),\n }),\n );\n // Resolving zero files is an operational error, not a pass: with no files\n // there is no verdict, and exit 0 would read as a clean bill of health.\n await asLintError(() => {\n assertNonEmpty({\n files,\n inputs: fileInputs,\n usingStdin,\n allowEmpty,\n exclude,\n exts,\n gitignoreSkipped,\n action: \"linted\",\n });\n });\n\n // The branch per tool. Reaching the refusal is an internal fault rather than\n // user error - every name the registry does not carry was refused by\n // `resolveStructureTool` above - and it is a `LintError` for that reason: a\n // bare `Error` escapes the bin runner and exits 1, the code that means \"the\n // documents have findings\".\n const name: string = tool.name;\n let results: LintFileResult[];\n if (name === \"manni\") {\n results = await lintWithManni({\n opts,\n config,\n cwd,\n files,\n forcedParser,\n usingStdin,\n });\n } else if (name === \"dita-ot\") {\n // `tools:` is the family's key, not the `lint:` section's, so the home is\n // resolved against the directory of the config that declared it.\n const home = ditaOtHome(run.tools, run.configDir ?? cwd);\n results = await lintWithDitaOt({\n cwd,\n files,\n ...(home === undefined ? {} : { home }),\n ...(opts.onNotice === undefined ? {} : { onNotice: opts.onNotice }),\n validate: opts.runDitaOt ?? runDitaOtValidate,\n });\n } else {\n throw new LintError(`No implementation is registered for the ${name} tool.`);\n }\n\n // Every tool, not just manni's. A run that resolved files and checked none\n // of them exits 0 and reads as a clean bill of health, which is the worst\n // thing this command can do quietly. It sat inside the manni branch until\n // `dita-ot` started skipping the formats it does not read, at which point\n // `manni lint structure notes.md` reported \"0 files checked, 1 skipped\" and\n // exited 0. One call here is one the next tool cannot forget to make.\n assertSomethingWasChecked(results, opts.explain === true, tool);\n\n const skipped = results.filter((r) => r.skipped != null).length;\n const failed = results.filter((r) => r.skipped == null && !r.success).length;\n const checked = results.length - skipped;\n\n return {\n results,\n summary: { checked, passed: checked - failed, failed, skipped },\n };\n}\n","/**\n * Write a first template from a page that already has the shape its author\n * wants.\n *\n * The format is strict by default: every rule is one occurrence, and a section\n * no rule describes is a finding. A new author's first run against a\n * hand-written template is therefore a screen of unexpected sections, and this\n * is the escape. Proposal 0061's stress test 5 records it, and says the two\n * ship together.\n *\n * Two rules govern everything here.\n *\n * **The output must lint its input clean.** That is the whole contract, and it\n * is why each inference below is the weakest claim that still describes the\n * page. `contains:` lists only the kinds that are there, at `min: 1`, so a\n * section holding more of something still passes. A table's `columns:` is\n * claimed only where every table in that section agrees about them, and a code\n * block's `language:` only where every block in that section declares one -\n * both rules report per offending node, so a claim drawn from one node would\n * fail on its neighbour. A template that fails the page it was inferred from is\n * worse than no template: it hands a new author findings about the very\n * document they pointed at.\n *\n * **Nothing is optional and nothing repeats.** One page cannot show what\n * varies, so no `min: 0`, no `max`, no `repeat` and no `pattern` is invented.\n * Two sections with one heading are two rules. Loosening a heading into a list\n * or a pattern, marking a rule optional, and adding a trailing wildcard are the\n * author's edits, and the reference page says so.\n */\nimport { stringify as stringifyYaml } from \"yaml\";\nimport { LintError } from \"../types.js\";\nimport type {\n CodeNode,\n ContentKind,\n ContentNode,\n DocumentTree,\n Position,\n SectionNode,\n TableNode,\n} from \"../types.js\";\nimport { BLOCK_KINDS, BLOCK_KIND_NODE } from \"./template.js\";\nimport type {\n BlockKind,\n BlockRule,\n HeadingRule,\n Rule,\n Template,\n TemplateFile,\n} from \"./template.js\";\n\n/** How an inferred template is written out. */\nexport const INFER_FORMATS = [\"yaml\", \"json\"] as const;\nexport type InferFormat = (typeof INFER_FORMATS)[number];\n\nexport function isInferFormat(value: string): value is InferFormat {\n return (INFER_FORMATS as readonly string[]).includes(value);\n}\n\n/**\n * Template names the schema's `templates` map accepts.\n *\n * Checked here rather than left to Ajv. `templates` is `additionalProperties:\n * false` beside a `patternProperties` key, so a name outside the pattern is\n * reported as an unexpected property - which names the offending key and says\n * nothing whatsoever about what is wrong with it.\n */\nconst TEMPLATE_NAME = /^[A-Za-z][A-Za-z0-9\\-_]*$/;\n\n/** The node each block-rule key counts, inverted: `codeBlock` -> `codeBlocks`. */\nconst KIND_KEY = new Map<ContentKind, BlockKind>(\n BLOCK_KINDS.map((key) => [BLOCK_KIND_NODE[key], key]),\n);\n\n/* -------------------------------------------------------------------------- *\n * The page as the template's subject\n * -------------------------------------------------------------------------- */\n\n/** A zero-width span at the top of a file, for a document with no sections. */\nfunction origin(): Position {\n return {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n };\n}\n\n/** First section's start through the last one's end. */\nfunction span(sections: SectionNode[]): Position {\n const first = sections[0];\n const last = sections[sections.length - 1];\n if (!first || !last) return origin();\n return { start: { ...first.position.start }, end: { ...last.position.end } };\n}\n\n/**\n * The section the template describes: the page itself.\n *\n * Deliberately the same reading `validator.ts` applies, because the template\n * this produces is checked by that one. A page whose body is a single `# Title`\n * *is* that section; anything else - several top-level headings, or a body that\n * starts at `##` with no lead content - has no section standing for the page,\n * so one is synthesised with no heading of its own. The duplication is small\n * and the alternative is worse: an inference that read the page differently\n * from the checker would produce templates that fail their own source.\n */\nfunction pageSection(tree: DocumentTree): SectionNode {\n const [only] = tree.sections;\n if (tree.sections.length === 1 && only && only.level <= 1) return only;\n return {\n slug: \"\",\n title: \"\",\n level: 0,\n order: 0,\n parentSlug: null,\n titlePosition: null,\n position: span(tree.sections),\n children: [],\n sections: tree.sections,\n };\n}\n\n/* -------------------------------------------------------------------------- *\n * Content\n * -------------------------------------------------------------------------- */\n\n/** The header row's cells, in order, or none where the table has no header. */\nfunction headerCells(table: TableNode): string[] {\n const header = table.children.find((row) => row.header);\n return header ? header.children.map((cell) => cell.text) : [];\n}\n\n/**\n * `columns:` for a run of tables, where they all agree about it.\n *\n * `tables.columns` reports once per table whose header differs, so a claim\n * taken from the first of two unlike tables fails on the second - in the very\n * page it was drawn from. Where the tables disagree, or any of them has no\n * header row, the count alone is what the page can honestly be said to show.\n */\nfunction columnsOf(tables: TableNode[]): { columns?: string[] } {\n const headers = tables.map(headerCells);\n const [first] = headers;\n if (first === undefined || first.length === 0) return {};\n const same = (cells: string[]): boolean =>\n cells.length === first.length && cells.every((c, i) => c === first[i]);\n return headers.every(same) ? { columns: [...first] } : {};\n}\n\n/**\n * `language:` for a run of code blocks, where every one of them declares one.\n *\n * `codeBlocks.language` holds every block in the run to the accepted set, so a\n * section mixing a tagged fence with a bare one can claim nothing: the bare one\n * would fail. Where the tags differ the list form says what the page shows,\n * which is what \"one of these\" is for.\n */\nfunction languageOf(blocks: CodeNode[]): { language?: string | string[] } {\n const declared: string[] = [];\n for (const block of blocks) {\n if (block.language === undefined || block.language.length === 0) return {};\n declared.push(block.language);\n }\n const distinct = [...new Set(declared)];\n const [only] = distinct;\n if (only === undefined) return {};\n return { language: distinct.length === 1 ? only : distinct };\n}\n\n/**\n * What a section holds, as a `contains:` rule, or nothing where it holds none\n * of the kinds a template can count.\n *\n * `contains` rather than `sequence`: the page shows one order, and asserting it\n * would make moving a paragraph below a list a finding. Order is a claim its\n * author makes deliberately.\n */\nfunction inferContains(children: ContentNode[]): BlockRule | undefined {\n const byKey = new Map<BlockKind, ContentNode[]>();\n for (const node of children) {\n const key = KIND_KEY.get(node.kind);\n if (key === undefined) continue;\n const bucket = byKey.get(key);\n if (bucket) bucket.push(node);\n else byKey.set(key, [node]);\n }\n\n const rule: BlockRule = {};\n let any = false;\n // In `BLOCK_KINDS` order, not the order the page happens to put them in, so\n // two pages holding the same kinds produce byte-identical rules.\n for (const key of BLOCK_KINDS) {\n const nodes = byKey.get(key);\n if (nodes === undefined) continue;\n any = true;\n if (key === \"tables\") {\n rule.tables = { min: 1, ...columnsOf(nodes as TableNode[]) };\n } else if (key === \"codeBlocks\") {\n rule.codeBlocks = { min: 1, ...languageOf(nodes as CodeNode[]) };\n } else {\n // A computed key, as `validator.ts` does it: every other block rule is a\n // bare count, and nine near-identical branches would say less.\n Object.assign(rule, { [key]: { min: 1 } });\n }\n }\n return any ? rule : undefined;\n}\n\n/* -------------------------------------------------------------------------- *\n * Rules\n * -------------------------------------------------------------------------- */\n\n/**\n * A section's heading, as a rule about it.\n *\n * Exact text, because that is what the page shows; a one-of list or a pattern\n * is a generalisation only its author can make. `false` for a section with no\n * heading of its own - the implicit lead section, and the synthesised page -\n * because that is as specific a claim as naming one.\n *\n * An empty title is the one case with no spelling: the schema's `heading`\n * requires a non-empty string, and `false` would be a lie about a section that\n * does have a heading. The key is omitted, which matches any heading.\n */\nfunction inferHeading(section: SectionNode): HeadingRule | undefined {\n if (section.titlePosition === null) return false;\n return section.title.length > 0 ? section.title : undefined;\n}\n\n/** One section, and every section under it. */\nfunction inferRule(section: SectionNode): Rule {\n const rule: Rule = {};\n const heading = inferHeading(section);\n if (heading !== undefined) rule.heading = heading;\n const contains = inferContains(section.children);\n if (contains) rule.contains = contains;\n // Omitted, never `[]`. An absent `sections:` says nothing about the\n // subsections; an empty list says none are permitted.\n if (section.sections.length > 0) {\n rule.sections = section.sections.map(inferRule);\n }\n return rule;\n}\n\n/** The template one page describes: the page rule, with its sections under it. */\nexport function inferTemplate(tree: DocumentTree): Template {\n return inferRule(pageSection(tree));\n}\n\n/* -------------------------------------------------------------------------- *\n * The file\n * -------------------------------------------------------------------------- */\n\n/** Refuse a name the `templates` map cannot hold, in words that name the rule. */\nexport function assertTemplateName(name: string): string {\n if (TEMPLATE_NAME.test(name)) return name;\n throw new LintError(\n `\"${name}\" is not a usable template name. A name starts with a letter and ` +\n `holds only letters, digits, \"-\" and \"_\". Pass --name <name>.`,\n );\n}\n\n/** A one-template file, ready to serialize. */\nexport function inferTemplateFile(\n tree: DocumentTree,\n name: string,\n): TemplateFile {\n return { templates: { [assertTemplateName(name)]: inferTemplate(tree) } };\n}\n\n/**\n * Serialize a template file.\n *\n * `lineWidth: 0` turns off YAML's folding. A folded heading still parses back\n * to the same string, but a template is read and edited by hand, and a heading\n * broken across two lines is the one thing in this output a reader would\n * mistrust.\n */\nexport function renderTemplateFile(\n file: TemplateFile,\n format: InferFormat,\n): string {\n const text =\n format === \"json\"\n ? JSON.stringify(file, null, 2)\n : stringifyYaml(file, { lineWidth: 0 });\n return text.endsWith(\"\\n\") ? text : `${text}\\n`;\n}\n","/**\n * `templates` command cores.\n *\n * `runTemplates` reports the templates a run could resolve: the built-ins, plus\n * the named templates in any files given by `--templates` or by\n * `lint.templates` in the config, with the doctypes each serves.\n *\n * The `types` column is the part worth printing. It is what frontmatter\n * routing will match a page against, so seeing it is how someone works out\n * which `type:` value to write in a page - or that no template claims the one\n * they already wrote.\n *\n * `runTemplatesInfer` writes a first template from a page that already has the\n * shape its author wants. The inference itself is `../core/infer.ts`; what\n * lives here is the plumbing around it - which parser reads the page, what the\n * template is called, and where the file goes.\n *\n * Both return data; `src/lint/reporters/index.ts` renders the listing, and an\n * inferred template is already the text it will be written as.\n */\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport { basename, dirname, extname, resolve } from \"node:path\";\nimport { errorMessage, ToolError } from \"../../shared/errors.js\";\nimport { writeTextAtomic } from \"../../shared/write-file.js\";\nimport { LintError } from \"../types.js\";\nimport type { DocumentParser, DocumentTree } from \"../types.js\";\nimport {\n parserByName,\n parserForExtension,\n supportedExtensions,\n} from \"../parsers/index.js\";\nimport {\n assertTemplateName,\n inferTemplateFile,\n isInferFormat,\n renderTemplateFile,\n type InferFormat,\n} from \"../core/infer.js\";\nimport type { TemplateFile } from \"../core/template.js\";\nimport { resolveLintRun } from \"../core/config.js\";\nimport {\n listBuiltins,\n loadTemplateFile,\n} from \"../core/template-registry.js\";\n\n/** `TemplateInfo.source` for a template that ships with the tool. */\nexport const BUILTIN_SOURCE = \"builtin\";\n\nexport interface TemplateInfo {\n /** The ref to pass to `--template`. */\n id: string;\n /**\n * Human-readable title. Empty for templates read from a user file: the\n * template DSL has no title field, only the built-in registry carries one.\n */\n title: string;\n /** Doctypes the template serves, matched against a page `type`. */\n types: string[];\n /** `builtin`, or the template file this entry came from. */\n source: string;\n}\n\nexport interface TemplatesInfo {\n templates: TemplateInfo[];\n}\n\nexport interface TemplatesOptions {\n /** Template files whose entries join the built-ins. */\n templates?: string | string[];\n}\n\nexport async function runTemplates(\n opts: TemplatesOptions = {},\n): Promise<TemplatesInfo> {\n const templates: TemplateInfo[] = listBuiltins().map((builtin) => ({\n id: builtin.id,\n title: builtin.title,\n types: builtin.types,\n source: BUILTIN_SOURCE,\n }));\n\n // Listed after the built-ins, in the order supplied - the same order\n // `buildTypeIndex` applies them in, so a later entry claiming the same\n // doctype is the one that would win.\n const paths =\n opts.templates == null\n ? []\n : Array.isArray(opts.templates)\n ? opts.templates\n : [opts.templates];\n\n for (const path of paths) {\n const file = await loadTemplateFile(path);\n for (const [id, template] of Object.entries(file.templates ?? {})) {\n templates.push({\n id,\n title: \"\",\n types: template.types ?? [],\n source: path,\n });\n }\n }\n\n return { templates };\n}\n\n/* -------------------------------------------------------------------------- *\n * infer\n * -------------------------------------------------------------------------- */\n\n/** The token that means stdin, in every command of the family. */\nconst STDIN = \"-\";\n\n/** What a page read from stdin is called when nothing else names it. */\nconst STDIN_NAME = \"stdin\";\n\nexport interface TemplatesInferOptions {\n /** The one page to infer from: a path, or `-` for stdin. */\n page: string;\n /** `--as`: force an input format, by parser name. */\n as?: string;\n /** `--name`: what to call the template. Defaults to the page's own doctype. */\n name?: string;\n /** `-f/--format`: how the file is written. Defaults to `yaml`. */\n format?: InferFormat;\n /** `-o/--out`: write here instead of returning text for stdout. */\n out?: string;\n /** `--force`: replace an existing `--out`. */\n force?: boolean;\n cwd?: string;\n /** Content for the `-` page, injected by the CLI and by tests. */\n stdinContent?: string;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: skip discovery. */\n noConfig?: boolean;\n /** Told which config governed the run, and where it came from. */\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n}\n\nexport interface TemplatesInferResult {\n /** The name the template was written under. */\n name: string;\n /** The inferred file, for a caller that wants the data rather than the text. */\n file: TemplateFile;\n /** The serialized template file, exactly as written. */\n text: string;\n /** Where it was written. Absent without `--out`. */\n written?: string;\n}\n\n/**\n * The parser that reads this page.\n *\n * Resolved before anything is read, as `runLint` does it: a typo in `--as`\n * should fail immediately rather than after a file was opened it was going to\n * mis-parse anyway. A name no parser answers to is unknown whatever it was\n * meant to name, so the message points at the one command that lists them.\n */\nfunction parserFor(page: string, as: string | undefined): DocumentParser {\n if (as !== undefined) {\n const forced = parserByName(as);\n if (forced) return forced;\n throw new LintError(\n `Unknown format \"${as}\". Run \"manni lint tools\" to see the formats manni lint reads.`,\n );\n }\n if (page === STDIN) {\n throw new LintError(\n \"Reading from stdin (-) requires --as <format> to choose a parser.\",\n );\n }\n const ext = extname(page);\n const parser = parserForExtension(ext);\n if (parser) return parser;\n throw new LintError(\n `no parser is registered for \"${ext || page}\". Supported extensions: ` +\n `${supportedExtensions().join(\", \")}. Use --as to override.`,\n );\n}\n\n/**\n * What the template is called: `--name`, else the page's own doctype, else the\n * file's stem.\n *\n * The doctype first because that is the handle the page already carries, and\n * the one `types:` will route on once the author adds it. A file read from\n * stdin has no stem, so it falls back to a word rather than to `-`.\n */\nfunction defaultName(tree: DocumentTree, page: string): string {\n const declared = tree.frontmatter?.[\"type\"];\n if (typeof declared === \"string\" && declared.trim().length > 0) {\n return declared.trim();\n }\n if (page === STDIN) return STDIN_NAME;\n return basename(page, extname(page)) || STDIN_NAME;\n}\n\n/**\n * Infer a template from one page.\n *\n * One page, never a set. A template is a generalisation, and this makes exactly\n * the generalisation one exemplar supports; inferring from several would mean\n * deciding which differences are variation and which are mistakes, which is the\n * author's judgment and not the tool's.\n */\nexport async function runTemplatesInfer(\n opts: TemplatesInferOptions,\n): Promise<TemplatesInferResult> {\n const format = opts.format ?? \"yaml\";\n if (!isInferFormat(format)) {\n throw new LintError(\n `Unknown --format \"${String(format)}\". Use yaml or json.`,\n );\n }\n\n // Which config governs the run, said once, the way every other lint verb\n // says it. With a page typed on the command line the base stays the working\n // directory, so the path means what it looked like it meant.\n const run = await resolveLintRun({\n cwd: opts.cwd ?? process.cwd(),\n ...(opts.configPath === undefined ? {} : { configPath: opts.configPath }),\n ...(opts.noConfig === undefined ? {} : { noConfig: opts.noConfig }),\n inputs: [opts.page],\n ...(opts.onConfigLoaded === undefined\n ? {}\n : { onConfigLoaded: opts.onConfigLoaded }),\n });\n const cwd = run.base;\n\n const parser = parserFor(opts.page, opts.as);\n // A name the schema cannot hold is refused before the page is read, beside\n // the other refusals: a run that is going to fail should leave the working\n // tree, and the reader's terminal, exactly as it found them.\n if (opts.name !== undefined) assertTemplateName(opts.name);\n\n // Every refusal happens before the write, and the `--out` guard happens\n // before the read - the ordering `meta schemas infer` established. The path\n // is echoed as it was typed, because that is the string the reader will edit.\n let absOut: string | undefined;\n if (opts.out !== undefined) {\n absOut = resolve(cwd, opts.out);\n if (opts.force !== true && existsSync(absOut)) {\n throw new LintError(`${opts.out} exists. Pass --force to overwrite it.`);\n }\n }\n\n let content: string;\n if (opts.page === STDIN) {\n content = opts.stdinContent ?? \"\";\n } else {\n try {\n content = await readFile(resolve(cwd, opts.page), \"utf8\");\n } catch (err) {\n // The OS message travels verbatim: \"permission denied\" and \"no such\n // file\" send the reader to different places, and this cannot tell which.\n throw new LintError(\n `\"${opts.page}\" could not be read: ${errorMessage(err)}`,\n );\n }\n }\n\n let tree: DocumentTree;\n try {\n tree = parser.parse(content, opts.page === STDIN ? \"<stdin>\" : opts.page);\n } catch (err) {\n // A page that will not parse has no shape to infer, and the parser's own\n // message already names the file and the syntax it choked on.\n if (err instanceof ToolError) throw new LintError(err.message);\n throw err;\n }\n\n const name = opts.name ?? defaultName(tree, opts.page);\n const file = inferTemplateFile(tree, name);\n const text = renderTemplateFile(file, format);\n\n if (absOut === undefined) return { name, file, text };\n\n await mkdir(dirname(absOut), { recursive: true });\n await writeTextAtomic(absOut, text);\n return { name, file, text, written: opts.out };\n}\n","/**\n * `tools` command core. One row per lint job: which tool performs it, whether\n * this checkout can run it, what it read its settings from, and the input\n * formats it understands.\n *\n * It replaces `formats`, which reported the parser registry alone. Proposal\n * 0050 records the rename. The registry is here as one column of the job that\n * reads it, because the formats belong to the tool performing that job.\n *\n * The column lists exactly the formats the tool reads, so a row carries no\n * state: a listed format is one that is read, and `--as` accepts every name in\n * it.\n *\n * Returns data; `src/lint/reporters/index.ts` renders it.\n */\nimport type { ContentKind } from \"../types.js\";\nimport { BLOCK_KIND_NODE } from \"../core/template.js\";\nimport { resolveStructureTool } from \"../tools/index.js\";\nimport {\n LINT_JOBS,\n resolveLintRun,\n type LintConfig,\n type LintJob,\n type LintTool,\n} from \"../core/config.js\";\n\n/**\n * The content kinds a template rule can actually name - `BLOCK_KIND_NODE`'s\n * values, the nine block-rule keys map onto. `manni lint tools` lists this\n * column to answer \"can my rule run against this format\", and a rule can\n * never ask about `listItem`, `tableRow`, `tableCell`, or `definitionItem`:\n * those are structural kinds a parser reports so the content model can\n * describe a list's items or a table's cells, not kinds a `sections:` rule\n * counts on its own. What a parser *declares* (`DocumentParser.kinds`, read by\n * the pruner in `validator.ts`) is untouched - this is a display decision, so\n * it belongs here rather than trimming the declaration itself.\n */\nconst REPORTABLE_KINDS = new Set<ContentKind>(Object.values(BLOCK_KIND_NODE));\n\nexport interface FormatInfo {\n /** Parser name, also what `--as` accepts. */\n name: string;\n label: string;\n extensions: string[];\n /** The content kinds this format's parser actually emits today. */\n kinds: ContentKind[];\n}\n\n/** One job, and the tool that would perform it on this run. */\nexport interface ToolInfo {\n job: LintJob;\n tool: LintTool;\n /** Whether the config declares this job, or anything the job's tool reads. */\n configured: boolean;\n /** Whether the tool can run here, as its own probe reported it. */\n available: boolean;\n /**\n * The version the probe reported, or null when it reported none.\n *\n * Null rather than a placeholder string, because this is the shape\n * `-f json` emits: a consumer can test for an absent version, where a dash\n * would be a value it has to know to recognize. The pretty reporter renders\n * the dash.\n */\n version: string | null;\n /** Where the tool read its settings: the config file, or the defaults. */\n config: string;\n /** The input formats the tool reads. */\n formats: FormatInfo[];\n}\n\nexport interface ToolsOptions {\n cwd?: string;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: ignore any discovered config file. */\n noConfig?: boolean;\n}\n\n/** What a run with no config file to read reports in the `config` column. */\nexport const BUILT_IN_DEFAULTS = \"built-in defaults\";\n\n/**\n * Whether the config says anything about this job.\n *\n * The job's own mapping counts, and so does every key its tool reads: a repo\n * that has written `templates:` and `overrides:` has configured the structure\n * job whether or not it also spelled `structure:` out. Saying otherwise would\n * report \"not configured\" beside a run those keys visibly govern.\n */\nfunction isConfigured(job: LintJob, config: LintConfig): boolean {\n if (config[job] !== undefined) return true;\n return (\n config.templates !== undefined ||\n config.template !== undefined ||\n config.types !== undefined ||\n config.overrides !== undefined\n );\n}\n\nexport async function runTools(opts: ToolsOptions = {}): Promise<ToolInfo[]> {\n // The same resolution every other command does, so a config this command\n // cannot read is the same exit 2 with the same message, rather than a row\n // saying \"built-in defaults\" over a file that is really there and broken.\n const cwd = opts.cwd ?? process.cwd();\n const run = await resolveLintRun({\n cwd,\n configPath: opts.configPath,\n noConfig: opts.noConfig,\n inputs: [],\n });\n\n return await Promise.all(\n LINT_JOBS.map(async (job) => {\n const tool: LintTool = run.config[job]?.tool ?? \"manni\";\n // The row is the tool's own answer about itself. It used to be two\n // literals that happened to be right while manni was the only tool:\n // \"available\" was hard-coded true, and the version was this package's\n // whatever performed the job.\n const descriptor = resolveStructureTool(tool);\n // The family's `tools:` travels with the probe: a tool outside the\n // package is found where its own `tools.<tool>` says it is, so probing\n // without it would report \"not available\" over the very installation the\n // run would go on to use.\n const probed = await descriptor.probe({\n cwd,\n tools: run.tools,\n ...(run.configDir === undefined ? {} : { configDir: run.configDir }),\n });\n return {\n job,\n tool,\n configured: isConfigured(job, run.config),\n available: probed.available,\n version: probed.version,\n config: run.configSource ?? BUILT_IN_DEFAULTS,\n formats: descriptor.formats().map((format) => ({\n ...format,\n kinds: format.kinds.filter((kind) => REPORTABLE_KINDS.has(kind)),\n })),\n };\n }),\n );\n}\n","/**\n * A finding's **rule identity**: `manni:lint/<job>/<rule>`.\n *\n * One id, in one place, for every consumer that files or correlates findings -\n * the SARIF `ruleId`, the JUnit `<failure type>`, the GitHub annotation's\n * `title`, and the `ruleId` the JSON reporter carries beside `type`. A rule id\n * is durable by contract: rename one and every historical alert in a\n * dashboard closes, then reopens as new.\n *\n * Three segments rather than cite's two. The job is what makes a second lint\n * tool possible without collisions: a prose job will report\n * `manni:lint/prose/Google.Passive`, keeping Vale's own rule name because that\n * is the name Vale's documentation uses, and nothing about it can be confused\n * with a structure rule. Proposal 0050 records the shape, and warns that\n * anything parsing family rule ids must not assume two segments.\n *\n * The rule half is derived from the finding's `type` rather than authored\n * beside it. `type` is already the machine-readable name the JSON reporter\n * publishes - manni docevals' grader reads it - so a hand-maintained second\n * table would be one more thing to keep in step, and the derivation cannot\n * drift. `_error` is dropped because it says only that a finding is a finding;\n * `heading_pattern_error` is the rule \"heading-pattern\".\n */\nimport type { LintJob } from \"./config.js\";\n\n/** Every lint rule id starts here. */\nexport const RULE_ID_PREFIX = \"manni:lint\";\n\n/** The tool that performs the structure job, reported beside every finding. */\nexport const TOOL_NAME = \"manni\";\n\n/** The job every finding in this pipeline reports under. */\nexport const STRUCTURE_JOB: LintJob = \"structure\";\n\n/**\n * `heading_pattern_error` -> `heading-pattern`; `parse_error` -> `parse`.\n *\n * Only a trailing `_error` is dropped, so a rule that is genuinely *about*\n * errors keeps the word.\n */\nexport function ruleName(type: string): string {\n return type.replace(/_error$/, \"\").replace(/_/g, \"-\");\n}\n\n/** `manni:lint/<job>/<rule>` for one finding `type`. */\nexport function ruleId(type: string, job: LintJob = STRUCTURE_JOB): string {\n return `${RULE_ID_PREFIX}/${job}/${ruleName(type)}`;\n}\n","/**\n * JUnit XML, rendered through **meta's** writer rather than a second one.\n *\n * There is no authoritative JUnit schema, and the escaping is the part a\n * hand-rolled writer gets wrong - XML 1.0 forbids characters that sit quite\n * happily in a JavaScript string, and one of them makes the whole document\n * unparseable rather than merely mis-rendered. That work is done once, in\n * `src/meta/reporters/junit.ts`, and cite already rides it. So does lint:\n * adapt the run onto meta's `ValidationResult`, hand it to that writer, and\n * the family ships one XML writer, one escaping rule, and one\n * testcase-per-file convention.\n *\n * What is lint's is the two strings that identify the findings as lint's:\n * the `classname` on every `<testcase>`, and the `<failure type>`, which is\n * the namespaced rule id.\n */\nimport {\n isErrorSeverity,\n renderJunit as renderJunitXml,\n type FieldError,\n type ValidationResult,\n} from \"../../meta/index.js\";\nimport { RULE_ID_PREFIX, ruleName, STRUCTURE_JOB } from \"../core/rule-id.js\";\nimport type { LintRun } from \"../commands/lint.js\";\n\n/** JUnit `classname` for this tool's findings, as cite's is `manni.cite`. */\nconst JUNIT_CLASSNAME = \"manni.lint\";\n\n/**\n * One finding as a `FieldError`.\n *\n * `schema` and `keyword` are split where they are because meta's `ruleIdFor`\n * joins them with a `/`, and the id it has to produce is\n * `manni:lint/<job>/<rule>`. The prefix is the schema half and stays one\n * segment, which is what keeps it a built-in-shaped ref: a ref containing a\n * slash classifies as a local file, and a caller that passed a path frame\n * would see it rewritten into a relative path. The job and the rule travel\n * together as the keyword.\n *\n * `instancePath` is `\"\"`, the whole document. A structural finding is about a\n * document's shape and not about a pointer into its metadata, so there is no\n * honest pointer to give; meta spells that `(root)`, as it does for its own\n * parse failures. The section the finding is anchored to is already in the\n * message.\n */\nfunction toFieldError(\n finding: LintRun[\"results\"][number][\"findings\"][number],\n): FieldError {\n return {\n schema: RULE_ID_PREFIX,\n instancePath: \"\",\n message:\n finding.heading != null\n ? `${finding.heading}: ${finding.message}`\n : finding.message,\n keyword: `${STRUCTURE_JOB}/${ruleName(finding.type)}`,\n severity: finding.severity,\n line: finding.position.start.line,\n col: finding.position.start.column,\n };\n}\n\n/**\n * The files this run actually checked, as meta's results.\n *\n * The skipped ones are **not** here, and that is the one place this reporter\n * parts company with the others. A skip has to be reported, or a file nothing\n * looked at is indistinguishable from a file that passed - so pretty says so\n * in words and SARIF files a `toolExecutionNotification`. JUnit has neither:\n * meta's writer emits a testcase or a testcase with a failure, so a skipped\n * file can only arrive as a green test. That is worse than absent. It claims a\n * pass on evidence nobody gathered, and it puts the suite's `tests` count three\n * above the `2 files checked, 3 skipped` the same run prints.\n *\n * So the count here is the run's `checked`, by construction: one testcase per\n * file that was linted.\n */\nexport function toValidationResults(run: LintRun): ValidationResult[] {\n return run.results\n .filter((result) => result.skipped == null)\n .map((result) => ({\n file: result.file,\n // meta's `format` is the extractor that read the file. A lint result does\n // not carry the parser that produced its tree, and no reporter reached\n // through here reads the field, so it names the domain rather than\n // inventing a format the run never recorded.\n format: \"lint\",\n // meta's invariant, not a count: `ok` is \"no error-severity finding\".\n // Read as \"no findings at all\", a file whose only finding is a warning\n // renders as a `✗` through meta's own pretty reporter - which is a\n // legitimate consumer, since this function is exported - while lint's\n // exit code says the run passed.\n ok: !result.findings.some(isErrorSeverity),\n schemas: [RULE_ID_PREFIX],\n errors: result.findings.map(toFieldError),\n }));\n}\n\n/**\n * Straight to meta's JUnit writer rather than through its `render`, which\n * takes a `RunSummary` its junit branch does not forward. Building one here\n * only to have it dropped read as though the suite's counts came from the run,\n * and they do not: they are the length of the list above and how much of it\n * carries an error-severity finding.\n */\nexport function renderJunit(run: LintRun): string {\n return renderJunitXml(toValidationResults(run), {\n classname: JUNIT_CLASSNAME,\n });\n}\n","/**\n * SARIF 2.1.0, the format GitHub code scanning ingests.\n *\n * `github` annotations live and die with one check run: no history, nothing to\n * query, and nothing outside GitHub Actions reads them at all. SARIF is the\n * same findings as a durable artifact - uploaded once, tracked across commits,\n * and understood by every dashboard that speaks the standard.\n *\n * The format's failure mode is silence. A SARIF file with a malformed URI, or\n * with results whose `ruleId` names no declared rule, uploads successfully and\n * then annotates nothing: a green check and an empty dashboard. So the two\n * things most likely to be wrong are the two things this module is most\n * careful about - rule descriptors, and URIs.\n */\nimport type { Finding, Position, Severity, SkipReason } from \"../types.js\";\nimport type { LintFileResult, LintRun } from \"../commands/lint.js\";\nimport { ruleId, ruleName } from \"../core/rule-id.js\";\nimport pkg from \"../../../package.json\" with { type: \"json\" };\n\nconst SARIF_VERSION = \"2.1.0\";\nconst SARIF_SCHEMA =\n \"https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json\";\n/**\n * Where code scanning sends someone who clicks \"more information\" on an alert.\n *\n * Deliberately the post-rename URL, which 404s until `doc-structure-lint` is\n * renamed on GitHub - a manual step outside this repo. Pointing it at the\n * current name instead would mean every SARIF report published from the day of\n * the rename onward links somewhere that has moved, and reports outlive the\n * rename; a link that is briefly wrong beats one that is permanently wrong.\n * `package.json`'s `repository` and `bugs` URLs are forward-looking for the\n * same reason, so all three flip together or not at all.\n */\nconst INFORMATION_URI = \"https://github.com/hawkeyexl/manni\";\n\n/** The base every relative artifact URI in this report resolves against. */\nconst URI_BASE_ID = \"SRCROOT\";\n\ntype SarifLevel = \"error\" | \"warning\" | \"note\" | \"none\";\n\ninterface SarifMessage {\n text: string;\n}\n\ninterface ReportingDescriptor {\n id: string;\n name: string;\n shortDescription: SarifMessage;\n defaultConfiguration?: { level: SarifLevel };\n}\n\ninterface ArtifactLocation {\n uri: string;\n uriBaseId?: string;\n}\n\ninterface Region {\n startLine: number;\n startColumn: number;\n endLine: number;\n endColumn: number;\n}\n\ninterface SarifLocation {\n physicalLocation: { artifactLocation: ArtifactLocation; region?: Region };\n}\n\ninterface SarifResult {\n ruleId: string;\n ruleIndex?: number;\n level: SarifLevel;\n message: SarifMessage;\n locations: SarifLocation[];\n properties?: { heading: string };\n}\n\ninterface SarifNotification {\n descriptor: { id: string; index: number };\n level: SarifLevel;\n message: SarifMessage;\n locations: SarifLocation[];\n}\n\ninterface SarifInvocation {\n executionSuccessful: boolean;\n toolExecutionNotifications?: SarifNotification[];\n}\n\ninterface SarifDriver {\n name: string;\n informationUri: string;\n version: string;\n rules: ReportingDescriptor[];\n notifications?: ReportingDescriptor[];\n}\n\ninterface SarifLog {\n $schema: string;\n version: string;\n runs: {\n tool: { driver: SarifDriver };\n originalUriBaseIds: Record<string, { uri: string }>;\n invocations: SarifInvocation[];\n results: SarifResult[];\n }[];\n}\n\nexport interface SarifOptions {\n /**\n * Directory the relative paths in `LintRun` are relative to - the lint run's\n * `cwd`. Defaults to the process cwd, which is what `runLint` itself\n * defaults to. It is a parameter rather than a bare read of `process.cwd()`\n * so the URI mapping, the part most likely to be silently wrong, is testable\n * without moving the whole process into a fixture directory.\n */\n root?: string;\n}\n\n/**\n * The family scale -> SARIF `level`. A total map rather than a ternary, so a\n * fourth severity fails to compile here instead of quietly becoming `error`.\n *\n * The family's three values were chosen to be GitHub's, and SARIF agrees on\n * two of them; it spells the lowest one `note`. meta's reporter folds\n * `notice` onto `note` the same way, so a repository uploading both tools'\n * reports sees one scale. SARIF's `none` has no `Severity` that means it.\n */\nconst LEVELS: Record<Severity, SarifLevel> = {\n notice: \"note\",\n warning: \"warning\",\n error: \"error\",\n};\n\n/**\n * Why a file went unlinted, in words. `Record<SkipReason, ...>` on purpose: a\n * new skip reason should fail to compile until someone has decided what the\n * report says about it.\n */\nconst SKIP_DESCRIPTIONS: Record<SkipReason, string> = {\n \"no-template\": \"File was not linted: no template resolved for it.\",\n \"unsupported-format\": \"File was not linted: no parser handles its format.\",\n unreadable: \"File was not linted: it could not be read.\",\n};\n\n/** Matches a Windows drive prefix on an already-forward-slashed path. */\nconst DRIVE = /^[A-Za-z]:\\//;\n\nfunction toPosix(p: string): string {\n return p.replace(/\\\\/g, \"/\");\n}\n\n/**\n * Path handling here is string-level rather than `node:path`, deliberately.\n *\n * `node:path` is platform-bound: on Linux, `isAbsolute(\"C:\\\\repo\\\\a.md\")` is\n * false and `relative()` treats the whole thing as one filename. That would\n * make this reporter's most important behaviour differ between the two CI\n * runners, and differ in the direction that fails silently - a Windows path\n * emitted verbatim as a URI resolves to no file in the repository. Doing the\n * work on strings makes the mapping identical everywhere.\n */\nfunction isAbsolutePath(posix: string): boolean {\n return posix.startsWith(\"/\") || DRIVE.test(posix);\n}\n\n/**\n * A path Windows resolves, and therefore compares without regard to case:\n * either a drive path or a UNC share. `//` is how `fileUri` recognises a share\n * too, so both places agree on what one looks like.\n */\nfunction isWindowsPath(posix: string): boolean {\n return DRIVE.test(posix) || posix.startsWith(\"//\");\n}\n\n/** `/repo/` + `/repo/docs/a.md` -> `docs/a.md`; null when not underneath. */\nfunction underRoot(posix: string, root: string): string | null {\n if (posix.startsWith(root)) return posix.slice(root.length);\n // Windows paths are case-insensitive: `C:/Repo` and `c:/repo` are one\n // directory, and so are `//server/Share` and `//SERVER/share` - a checkout on\n // a network share must relativize as readily as one on a drive, or its\n // findings upload as absolute URIs and attach to nothing. Retry this way only\n // when both sides are Windows-shaped - anywhere else, two paths differing in\n // case are two different files.\n if (isWindowsPath(posix) && isWindowsPath(root)) {\n // The comparison case-folds but the slice does not, which reads like a bug\n // and is not: case folding leaves length unchanged, so `root.length` still\n // indexes the same boundary, and slicing the original is what keeps the\n // reported path in the casing the author actually used.\n if (posix.toLowerCase().startsWith(root.toLowerCase())) {\n return posix.slice(root.length);\n }\n }\n return null;\n}\n\n/**\n * Percent-encode what a URI cannot carry raw. `encodeURI` leaves `/` and `:`\n * alone, which is what a path needs, but it also leaves `#` and `?` alone, and\n * either of those would be read as a fragment or a query rather than as part\n * of the name.\n *\n * This also covers labels that are not paths at all: the stdin document is\n * `<stdin>`, and `<`/`>` are not legal in a URI. It will not resolve to a file\n * anywhere, but an invalid URI can sink an entire upload, whereas a valid one\n * that resolves to nothing only sinks its own annotation.\n */\nfunction encodePath(p: string): string {\n return encodeURI(p).replace(/#/g, \"%23\").replace(/\\?/g, \"%3F\");\n}\n\n/** An absolute forward-slashed path as a `file:` URI. */\nfunction fileUri(posix: string): string {\n const encoded = encodePath(posix);\n if (posix.startsWith(\"//\")) return `file:${encoded}`; // UNC: file://host/share\n if (posix.startsWith(\"/\")) return `file://${encoded}`; // POSIX: file:///etc\n return `file:///${encoded}`; // Drive: file:///C:/repo\n}\n\n/** A relative path that climbs out of the directory it is relative to. */\nfunction escapesRoot(posix: string): boolean {\n return posix === \"..\" || posix.startsWith(\"../\");\n}\n\n/**\n * `C:/repo/` + `../sibling/a.md` -> `C:/sibling/a.md`.\n *\n * String-level, like everything else here, and one step per `..` rather than a\n * single strip: `../a.md` and `../../a.md` name two different files, and a\n * reporter that collapsed them would point an alert at the wrong one. The first\n * segment is never popped - it is the drive, the empty segment before a posix\n * root, or the first half of a UNC share - so a path cannot climb past the\n * filesystem root.\n */\nfunction resolveFromRoot(root: string, rel: string): string {\n const parts = root.replace(/\\/+$/, \"\").split(\"/\");\n for (const segment of rel.split(\"/\")) {\n if (segment === \"\" || segment === \".\") continue;\n if (segment === \"..\") {\n if (parts.length > 1) parts.pop();\n continue;\n }\n parts.push(segment);\n }\n const joined = parts.join(\"/\");\n return joined === \"\" ? \"/\" : joined;\n}\n\n/**\n * Forward-slashed with exactly one trailing slash, so a prefix match on it can\n * only ever land on a segment boundary.\n */\nfunction normalizeRoot(root: string): string {\n const posix = toPosix(root);\n return posix.endsWith(\"/\") ? posix : `${posix}/`;\n}\n\n/**\n * The artifact URI, which is the single most breakable thing in this file.\n *\n * SARIF URIs are URI references, not native paths. Relative plus `uriBaseId`\n * is what GitHub resolves against the checkout, so that is the default; a\n * backslashed path, or a bare absolute one, uploads fine and matches no file.\n *\n * A target outside the run root arrives as a **relative** path too - a `../`\n * chain, which is how `resolveTargets` reports it - and that is the one shape\n * a `uriBaseId` cannot carry. `SRCROOT` is the checkout, and code scanning\n * will not resolve above it: `../sibling/docs/a.md` uploads and annotates\n * nothing, which is this format's whole failure mode. So it is resolved\n * against the root and emitted the way the genuinely-absolute case below is,\n * with no base to resolve against.\n */\nfunction artifactLocation(file: string, root: string): ArtifactLocation {\n const posix = toPosix(file);\n if (!isAbsolutePath(posix)) {\n if (escapesRoot(posix)) return { uri: fileUri(resolveFromRoot(root, posix)) };\n return { uri: encodePath(posix), uriBaseId: URI_BASE_ID };\n }\n const rel = underRoot(posix, root);\n if (rel !== null) return { uri: encodePath(rel), uriBaseId: URI_BASE_ID };\n // Genuinely outside the run root. No relative URI reaches it, so say so with\n // an absolute `file:` URI rather than inventing a `../` chain that resolves\n // to nothing on the machine reading the report.\n return { uri: fileUri(posix) };\n}\n\n/**\n * Positions map straight across, with no arithmetic.\n *\n * Both sides are 1-based in line and column. Both also treat the end column as\n * exclusive: SARIF defines `endColumn` as \"the column number of the character\n * following the end of the region\", and `Position` in types.ts is documented\n * as a half-open span with `end` exclusive. Checked against what the parser\n * actually emits rather than taken on trust - remark gives `# Hi`, four\n * characters on line 1, an `end.column` of 5, one past the last character,\n * which is precisely SARIF's convention. So no +1 and no -1 in either\n * direction. A zero-width span (`origin()`, used by findings with nowhere\n * better to point) becomes a zero-length region, which SARIF allows.\n */\nfunction region(position: Position): Region {\n return {\n startLine: position.start.line,\n startColumn: position.start.column,\n endLine: position.end.line,\n endColumn: position.end.column,\n };\n}\n\nfunction location(\n file: string,\n root: string,\n position?: Position,\n): SarifLocation {\n return {\n physicalLocation: {\n artifactLocation: artifactLocation(file, root),\n region: position ? region(position) : undefined,\n },\n };\n}\n\n/**\n * The heading goes in the message *and* in `properties`.\n *\n * In the message because most SARIF viewers show the message and nothing else\n * beside the line: \"Expected at least 2 paragraphs, found 1\" is a different\n * sentence depending on which section it is about, and dropping the heading\n * would make the SARIF annotation less informative than the `github` one for\n * the very same finding. In `properties.heading` because a message is prose\n * and nothing can group or filter on it - a consumer asking for \"every finding\n * under Prerequisites\" should not have to parse English back out.\n *\n * Unlike `renderGithub`, newlines are left intact. A workflow command is one\n * line by definition; a SARIF message is a JSON string with no such limit.\n */\nfunction messageText(finding: Finding): string {\n return finding.heading != null\n ? `${finding.heading}: ${finding.message}`\n : finding.message;\n}\n\nfunction words(id: string): string[] {\n return id.split(/[^A-Za-z0-9]+/).filter(Boolean);\n}\n\n/**\n * `missing_section` -> `MissingSection`. SARIF asks a descriptor `name` to be\n * a single Pascal-case identifier, and GitHub shows it in the rule list.\n */\nfunction pascalCase(id: string): string {\n return words(id)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\"\");\n}\n\n/**\n * `missing_section` -> `Missing section`. Derived from the id, not authored:\n * there is no rule catalog to draw a real description from, and the first\n * finding's message describes one occurrence rather than the rule. Restating\n * the id in prose says nothing new, but it beats an empty column in GitHub's\n * rule list and it can never drift out of step with the rule it describes.\n */\nfunction humanize(id: string): string {\n const text = words(id).join(\" \");\n return text.charAt(0).toUpperCase() + text.slice(1);\n}\n\ninterface RuleIndex {\n descriptors: ReportingDescriptor[];\n indexOf: Map<string, number>;\n}\n\n/**\n * One `reportingDescriptor` per distinct finding type, in order of first\n * appearance.\n *\n * This is not optional decoration. A result carrying a `ruleId` that matches\n * no descriptor is accepted by GitHub code scanning and then rendered without\n * a rule name, a description, or a working filter - the alert arrives stripped\n * of everything that makes a dashboard usable, and with no error to explain\n * why.\n */\nfunction buildRules(run: LintRun): RuleIndex {\n const indexOf = new Map<string, number>();\n const order: string[] = [];\n const severities = new Map<string, Set<Severity>>();\n\n for (const result of run.results) {\n for (const finding of result.findings) {\n let seen = severities.get(finding.type);\n if (!seen) {\n seen = new Set<Severity>();\n severities.set(finding.type, seen);\n indexOf.set(finding.type, order.length);\n order.push(finding.type);\n }\n seen.add(finding.severity);\n }\n }\n\n const descriptors = order.map((type) => {\n // The descriptor id is the **family** rule id, not the internal `type`:\n // it is what an alert is filed and de-duplicated under, and it has to be\n // the string every other reporter uses for the same finding. `name` and\n // `shortDescription` are derived from the rule half alone, so GitHub's\n // rule list reads \"MissingSection\", not \"ManniLintStructureMissingSection\".\n const rule = ruleName(type);\n const descriptor: ReportingDescriptor = {\n id: ruleId(type),\n name: pascalCase(rule),\n shortDescription: { text: humanize(rule) },\n };\n // Only when every finding of this type agreed on a severity. Severity is\n // per finding, not per rule, so a type that appeared as both an error and\n // a warning has no honest default - and every result states its own\n // `level` regardless, which is what a consumer actually reads.\n const [only, ...rest] = [...(severities.get(type) ?? [])];\n if (only !== undefined && rest.length === 0) {\n descriptor.defaultConfiguration = { level: LEVELS[only] };\n }\n return descriptor;\n });\n\n return { descriptors, indexOf };\n}\n\nfunction toResult(\n finding: Finding,\n file: string,\n rules: RuleIndex,\n root: string,\n): SarifResult {\n return {\n ruleId: ruleId(finding.type),\n // Always populated in practice, since the index is built from these same\n // findings. Omitted rather than faked if it ever is not: a wrong index\n // points the alert at somebody else's rule, which is worse than none.\n ruleIndex: rules.indexOf.get(finding.type),\n level: LEVELS[finding.severity],\n message: { text: messageText(finding) },\n locations: [location(file, root, finding.position)],\n properties:\n finding.heading != null ? { heading: finding.heading } : undefined,\n };\n}\n\ninterface SkipReport {\n descriptors: ReportingDescriptor[];\n notifications: SarifNotification[];\n}\n\n/**\n * Skipped files become `toolExecutionNotifications`, not results.\n *\n * They cannot simply be dropped - the pretty reporter's rule applies here too:\n * a file that leaves no trace in the report is indistinguishable from a file\n * that passed, and a docset mid-onboarding is mostly unrouted pages. Reading\n * that as a clean bill of health is the exact failure this format exists to\n * prevent.\n *\n * They are not results either. A result is a statement about the content of a\n * document; a skip is a statement about the tool, which declined to look. As\n * results they would open code-scanning alerts against files nothing has\n * examined, and each of those would then have to be triaged and dismissed by\n * hand. `toolExecutionNotifications` is the slot SARIF defines for \"the tool\n * has something to say about its own execution\", which is what a skip is.\n *\n * Level `note` rather than SARIF's default of `warning`: on a repository that\n * has not adopted doctypes yet nearly every page is skipped, and a warning\n * stream that long is one nobody reads.\n */\nfunction buildSkips(run: LintRun, root: string): SkipReport {\n const indexOf = new Map<string, number>();\n const descriptors: ReportingDescriptor[] = [];\n const notifications: SarifNotification[] = [];\n\n for (const result of run.results) {\n const reason = result.skipped;\n if (reason == null) continue;\n\n let index = indexOf.get(reason);\n if (index === undefined) {\n index = descriptors.length;\n indexOf.set(reason, index);\n descriptors.push({\n id: reason,\n name: pascalCase(reason),\n shortDescription: { text: SKIP_DESCRIPTIONS[reason] },\n });\n }\n\n notifications.push({\n // Declared in `tool.driver.notifications` and referenced by id *and*\n // index, for the same reason results reference their rules both ways.\n descriptor: { id: reason, index },\n level: \"note\",\n message: { text: skipMessage(result, reason) },\n locations: [location(result.file, root)],\n });\n }\n\n return { descriptors, notifications };\n}\n\n/** The specific reason when the run recorded one, the generic one otherwise. */\nfunction skipMessage(result: LintFileResult, reason: SkipReason): string {\n return result.reason ?? SKIP_DESCRIPTIONS[reason];\n}\n\nexport function renderSarif(run: LintRun, opts: SarifOptions = {}): string {\n const root = normalizeRoot(opts.root ?? process.cwd());\n const rules = buildRules(run);\n const skips = buildSkips(run, root);\n\n const results = run.results.flatMap((result) =>\n result.findings.map((finding) =>\n toResult(finding, result.file, rules, root),\n ),\n );\n\n const driver: SarifDriver = {\n name: \"manni-lint\",\n informationUri: INFORMATION_URI,\n version: pkg.version,\n // Emitted even when empty: results point into this array, so a consumer\n // always looks here, and a stable shape is cheaper than a special case.\n rules: rules.descriptors,\n notifications: skips.descriptors.length > 0 ? skips.descriptors : undefined,\n };\n\n const invocation: SarifInvocation = {\n // Findings are the tool doing its job, not failing at it. This would only\n // be false if manni lint itself could not run, and that path exits 2\n // before any report is rendered.\n executionSuccessful: true,\n toolExecutionNotifications:\n skips.notifications.length > 0 ? skips.notifications : undefined,\n };\n\n const log: SarifLog = {\n $schema: SARIF_SCHEMA,\n version: SARIF_VERSION,\n runs: [\n {\n tool: { driver },\n // Declared unconditionally: it is what makes every relative `uri` in\n // this report mean anything, and a reader should not have to infer the\n // base from whether some result happened to use it.\n originalUriBaseIds: { [URI_BASE_ID]: { uri: fileUri(root) } },\n invocations: [invocation],\n results,\n },\n ],\n };\n\n return JSON.stringify(log, null, 2);\n}\n","/**\n * The alignment block `--explain` prints under each routed file: which rule\n * claimed which section, and why. It is lint's answer to \"why did it say\n * that\" for the matcher in `core/match.ts` - proposal 0061's stress test 3\n * names this as the cost of an alignment matcher over a left-to-right one: a\n * tie is invisible unless something prints the pairing it chose.\n *\n * This module recomputes the alignment itself by calling the matcher's own,\n * already-exported `matchSections` - it does not reach into `align()`'s\n * internal step sequence, which is module-private. That has one visible\n * consequence: this file has no way to know the *document position* a missing\n * rule or an unexpected section falls at relative to the other, so a missing\n * rule is placed among the sections that did match using rule order alone\n * (`insertMissing` below), which is exact whenever - as in every template this\n * repository ships - the missing rule is not sandwiched between two unexpected\n * sections with nothing matched between them. `core/match.ts` is read-only\n * from here; exporting the step sequence, if this ever needs to be exact, is a\n * change to that file rather than to this one.\n *\n * The other thing this module cannot get from an export: which key in a\n * page's frontmatter is its title. It assumes `title`, the same key\n * `manni meta`'s own schemas require, and re-reads `tree.frontmatter`\n * directly rather than asking a caller to resolve it, so the assumption lives\n * in exactly one place.\n *\n * **The seam this depends on.** `commands/lint.ts` parses every file and\n * loads its template before `--explain` returns - both already exist at that\n * point in `lintOne` - but neither is currently attached to the\n * `LintFileResult` it returns. `render()` (`reporters/index.ts`) reads them\n * off a result through `ExplainSource`, structurally: a result carrying\n * `tree` and `template` gets an alignment block, and one that does not is\n * printed exactly as before. Wiring `commands/lint.ts` to attach them is\n * outside this chunk's files (`src/lint/commands/lint.ts` is not among them).\n */\nimport { LintError, type DocumentTree, type SectionNode } from \"../types.js\";\nimport { matchSections, type Match } from \"../core/match.js\";\nimport { occurrenceRange, type Rule, type Template } from \"../core/template.js\";\n\n/** What a caller must attach to a `LintFileResult` for the block to render. */\nexport interface ExplainSource {\n tree: DocumentTree;\n template: Template;\n}\n\n/** One line of the block, before indentation is joined on. */\nexport interface AlignmentRow {\n depth: number;\n text: string;\n}\n\nconst LABEL_WIDTH = 22;\nconst ARROW = \"←\"; // ←\nconst ELLIPSIS = \"…\"; // …\nconst TIMES = \"×\"; // ×\n\nfunction pad(label: string): string {\n return label.length >= LABEL_WIDTH ? `${label} ` : label.padEnd(LABEL_WIDTH + 1);\n}\n\n/** A section's title, quoted, or `(no heading)` for one that has none. */\nfunction titleText(title: string | null): string {\n return title === null ? \"(no heading)\" : `\"${title}\"`;\n}\n\n/**\n * A rule's display name: its `id` where it has one, else a literal string\n * `heading`, else `(any)` for anything else - an array, a `{ pattern }`,\n * `heading: false`, or a bare wildcard. Mirrors the priority `--explain`'s\n * spec states, which is not the same order `missingMessage` in `match.ts`\n * uses for its prose: that picks the heading first because it is read as a\n * sentence, and this picks the id first because it is a column header.\n */\nfunction ruleLabel(rule: Rule): string {\n if (rule.id !== undefined) return rule.id;\n if (typeof rule.heading === \"string\") return rule.heading;\n return \"(any)\";\n}\n\n/**\n * The page's own heading, and the note explaining where it came from.\n *\n * Mirrors `validator.ts`'s private `pageSection`: a lone top-level heading\n * *is* the page. Most of the time that heading is not literal, though - every\n * parser with both frontmatter and headings (`parsers/metadata.ts`'s\n * `withMetadataTitle`) already synthesizes an H1 from `frontmatter.title` when\n * the body has none, positioned on the frontmatter block itself, precisely so\n * a template written against \"the page's title is its outermost rule\" does\n * not have to know the difference. By the time a tree reaches here that\n * difference is gone from the section's own fields - so it is recovered the\n * same way `titlePosition` was set: a synthesized heading's position is\n * `tree.frontmatterPosition`, verbatim.\n *\n * `frontmatter.title` is read directly only as a fallback, for a tree a\n * caller built by some other means - the programmatic API accepts one from\n * anywhere - where no such synthesis ran at all.\n */\nfunction pageHeading(tree: DocumentTree): { text: string | null; note: string | null } {\n const [only] = tree.sections;\n if (tree.sections.length === 1 && only && only.level <= 1) {\n const text = only.title || null;\n if (text === null) return { text: null, note: \"no heading\" };\n const synthesized =\n only.titlePosition !== null &&\n tree.frontmatterPosition !== null &&\n only.titlePosition.start.offset === tree.frontmatterPosition.start.offset &&\n only.titlePosition.end.offset === tree.frontmatterPosition.end.offset;\n return { text, note: synthesized ? \"synthesized from frontmatter\" : null };\n }\n const raw = tree.frontmatter?.[\"title\"];\n const text = typeof raw === \"string\" && raw !== \"\" ? raw : null;\n return { text, note: text === null ? \"no heading\" : \"synthesized from frontmatter\" };\n}\n\n/** The sections a template's `sections:` rules describe - `pageSection`'s subject. */\nfunction pageSections(tree: DocumentTree): SectionNode[] {\n const [only] = tree.sections;\n if (tree.sections.length === 1 && only && only.level <= 1) return only.sections;\n return tree.sections;\n}\n\n/**\n * One matched or collapsed run of matches, rendered as a single row.\n *\n * Both call sites build `run` by pushing one already-known `Match` before\n * ever calling this, so it is never empty; the guard below exists to let the\n * checker see that rather than to handle a real empty-run case.\n */\nfunction matchedRow(depth: number, run: Match[]): AlignmentRow {\n const head = run[0];\n if (!head) return { depth, text: `${pad(\"(empty run)\")}${ARROW} (missing)` };\n const rule = head.rule;\n const first = head.section;\n const last = (run[run.length - 1] ?? head).section;\n const label = run.length === 1 ? ruleLabel(rule) : `${ruleLabel(rule)} ${TIMES}${run.length}`;\n // Coercion can only ever land on a run of length 1: `ALIGNMENT_COSTS.coerce`\n // is open only to a required occurrence whose `max` is 1 (`match.ts`'s\n // header explains why), and a rule with `max: 1` can never contribute a\n // second match to a run.\n const coerced = run.length === 1 && head.coerced ? \" (coerced)\" : \"\";\n const arrow =\n run.length === 1\n ? `${titleText(first.title || null)}${coerced}`\n : `${titleText(first.title || null)} ${ELLIPSIS} ${titleText(last.title || null)}`;\n return { depth, text: `${pad(label)}${ARROW} ${arrow}` };\n}\n\n/**\n * What an absent rule is called.\n *\n * `(missing)` means exactly what produces a `missing_section` finding, so it\n * is reserved for a rule that had to appear. An optional rule that took\n * nothing is `(none)`: absent, and fine. Sharing one word made a page that\n * lints clean print a row saying something was missing from it, which is the\n * opposite of what `--explain` is for.\n */\nfunction absentLabel(rule: Rule): string {\n return occurrenceRange(rule).min > 0 ? \"(missing)\" : \"(none)\";\n}\n\n/** A rule with nothing to show, or a `repeat` group with nothing at all. */\nfunction missingRows(depth: number, rule: Rule): AlignmentRow[] {\n if (!rule.repeat) {\n return [{ depth, text: `${pad(ruleLabel(rule))}${ARROW} ${absentLabel(rule)}` }];\n }\n // A group's members inherit the group's own occurrence: a member of an\n // optional group is not missing when the whole group never ran.\n const label = absentLabel(rule);\n const rows: AlignmentRow[] = [{ depth, text: pad(rule.id ?? \"(repeat)\").trimEnd() }];\n for (const member of rule.repeat) {\n rows.push({ depth: depth + 1, text: `${pad(ruleLabel(member))}${ARROW} ${label}` });\n }\n return rows;\n}\n\n/**\n * Insert `missing`, each tagged with the index of the rule it is about, among\n * `matched` entries tagged the same way (`null` for one that has no rule -\n * an unexpected section). A missing rule never displaces an unexpected\n * section: only a matched entry's index gates it, so an unexpected section is\n * carried along in whichever position document order already put it in.\n */\nfunction insertMissing(\n matched: { index: number | null; rows: AlignmentRow[] }[],\n missing: { index: number; rows: AlignmentRow[] }[],\n): AlignmentRow[] {\n const out: AlignmentRow[] = [];\n let mi = 0;\n for (const entry of matched) {\n while (mi < missing.length) {\n // `mi < missing.length` just guarded this, so `next` is always here;\n // the check only lets the type checker see the invariant the loop\n // bound already established.\n const next = missing[mi];\n if (!next || (entry.index !== null && next.index >= entry.index)) break;\n out.push(...next.rows);\n mi++;\n }\n out.push(...entry.rows);\n }\n while (mi < missing.length) {\n const next = missing[mi];\n if (!next) break;\n out.push(...next.rows);\n mi++;\n }\n return out;\n}\n\n/**\n * One level: `rules` against `sections`, and every matched pair's own\n * subsections.\n *\n * A `repeat` member's `Match.rule` is the member itself, never the group\n * (`match.ts`'s `compile` only ever assigns an occurrence to a leaf rule), so\n * a group is never a key in `matches`. `rootOf` recovers \"which top-level\n * rule is this a member of\" - itself, for a rule with no group - which is\n * what lets a group be judged matched or missing as one thing while still\n * naming which of its members carried the section.\n */\nfunction alignLevel(\n rules: Rule[] | undefined,\n sections: SectionNode[],\n parent: SectionNode | null,\n depth: number,\n): AlignmentRow[] {\n // `undefined` is the template saying nothing about this level - silence,\n // not \"no sections allowed\" - so there is nothing to align and nothing to\n // print. `matchSections` draws the same line; this mirrors it rather than\n // passing `[]` through, which would turn silence into every section here\n // reading as unexpected.\n if (rules === undefined) return [];\n\n const { matches } = matchSections(sections, rules, { parent });\n const ruleIndex = new Map<Rule, number>(rules.map((r, i) => [r, i]));\n const rootOf = new Map<Rule, Rule>();\n for (const rule of rules) {\n if (rule.repeat) for (const member of rule.repeat) rootOf.set(member, rule);\n else rootOf.set(rule, rule);\n }\n const rootOfRule = (rule: Rule): Rule => rootOf.get(rule) ?? rule;\n const matchedRoots = new Set(matches.map((m) => rootOfRule(m.rule)));\n const bySection = new Map<SectionNode, Match>(matches.map((m) => [m.section, m]));\n\n const matched: { index: number | null; rows: AlignmentRow[] }[] = [];\n let i = 0;\n while (i < sections.length) {\n // `i < sections.length` just guarded this; `section` always exists.\n const section = sections[i];\n if (!section) break;\n const match = bySection.get(section);\n if (!match) {\n matched.push({\n index: null,\n rows: [{ depth, text: `(unexpected) ${titleText(section.title || null)}` }],\n });\n i++;\n continue;\n }\n\n const root = rootOfRule(match.rule);\n if (root.repeat) {\n // Every section, in this run, that belongs to this same group - by\n // whichever member took it, not necessarily the same one twice.\n const taken: Match[] = [];\n while (i < sections.length) {\n const here = sections[i];\n if (!here) break;\n const next = bySection.get(here);\n if (!next || rootOfRule(next.rule) !== root) break;\n taken.push(next);\n i++;\n }\n const rows: AlignmentRow[] = [{ depth, text: pad(root.id ?? \"(repeat)\").trimEnd() }];\n let run: Match[] = [];\n const flushMember = (): void => {\n if (run.length === 0) return;\n rows.push(matchedRow(depth + 1, run));\n for (const m of run) {\n rows.push(...alignLevel(m.rule.sections, m.section.sections, m.section, depth + 2));\n }\n run = [];\n };\n for (const m of taken) {\n const first = run[0];\n if (first && first.rule !== m.rule) flushMember();\n run.push(m);\n }\n flushMember();\n // A member this occurrence never reached prints missing beside the\n // members it did, the same information `missingRows` gives a group with\n // nothing at all.\n const takenMembers = new Set(taken.map((m) => m.rule));\n for (const member of root.repeat) {\n if (takenMembers.has(member)) continue;\n rows.push({ depth: depth + 1, text: `${pad(ruleLabel(member))}${ARROW} (missing)` });\n }\n matched.push({ index: ruleIndex.get(root) ?? null, rows });\n continue;\n }\n\n // A plain rule: gather the run of consecutive sections it claimed.\n const run: Match[] = [match];\n i++;\n while (i < sections.length) {\n const here = sections[i];\n if (!here) break;\n const next = bySection.get(here);\n if (!next || next.rule !== match.rule) break;\n run.push(next);\n i++;\n }\n const rows = [matchedRow(depth, run)];\n for (const m of run) {\n rows.push(...alignLevel(m.rule.sections, m.section.sections, m.section, depth + 1));\n }\n matched.push({ index: ruleIndex.get(match.rule) ?? null, rows });\n }\n\n const missing = rules\n .filter((rule) => !matchedRoots.has(rule))\n .map((rule) => {\n const index = ruleIndex.get(rule);\n if (index === undefined) {\n // `ruleIndex` is built from this exact `rules` array above, so every\n // rule reached here (it came from filtering `rules` itself) has an\n // entry; this is unreachable.\n //\n // `LintError` rather than `Error` even so. Everything this tool throws\n // is caught by the bin runner and exits 2, an operational error; a bare\n // `Error` would escape that and exit 1, which means \"the documents have\n // findings\". An internal fault must never be reported as a lint result.\n throw new LintError(\"alignLevel: rule missing from its own index\");\n }\n return { index, rows: missingRows(depth, rule) };\n });\n\n return insertMissing(matched, missing);\n}\n\n/** The full alignment block for one file: the page row, then its sections. */\nexport function explainAlignment(tree: DocumentTree, template: Template): AlignmentRow[] {\n const heading = pageHeading(tree);\n const arrow =\n heading.text !== null\n ? `${titleText(heading.text)}${heading.note ? ` (${heading.note})` : \"\"}`\n : `(${heading.note ?? \"no heading\"})`;\n const rows: AlignmentRow[] = [{ depth: 0, text: `${pad(\"(page)\")}${ARROW} ${arrow}` }];\n rows.push(...alignLevel(template.sections, pageSections(tree), null, 1));\n return rows;\n}\n\n/** `AlignmentRow[]` as the indented text `renderExplain` prints, two spaces per depth. */\nexport function formatAlignment(rows: AlignmentRow[]): string[] {\n return rows.map((row) => `${\" \".repeat(row.depth)}${row.text}`);\n}\n","/**\n * Reporters render a run to a string. The CLI writes the result to stdout;\n * diagnostics go to stderr separately, so a report is never interleaved with\n * anything a consumer has to parse around.\n */\nimport { LintError, type Finding } from \"../types.js\";\nimport type { LintFileResult, LintRun } from \"../commands/lint.js\";\nimport type { FormatInfo, ToolInfo } from \"../commands/tools.js\";\nimport type { TemplateInfo, TemplatesInfo } from \"../commands/templates.js\";\nimport { palette, type Colors } from \"../../shared/color.js\";\nimport {\n escapeWorkflowCommandMessage,\n escapeWorkflowCommandProperty,\n} from \"../../shared/github.js\";\nimport type { ReportFormat as FamilyFormat } from \"../../meta/index.js\";\nimport { REPORT_FORMAT_LIST } from \"../../meta/internal.js\";\nimport { ruleId, TOOL_NAME } from \"../core/rule-id.js\";\nimport { renderJunit } from \"./junit.js\";\nimport { renderSarif } from \"./sarif.js\";\nimport { explainAlignment, formatAlignment, type ExplainSource } from \"./alignment.js\";\n\nexport { renderJunit, toValidationResults } from \"./junit.js\";\n\n/**\n * Every `-f` value, plus `--explain`.\n *\n * The findings formats are the family's, taken from meta rather than restated,\n * so a format added there is available here the moment lint's `render` grows a\n * case for it - and a value lint does not handle is a compile error instead of\n * a silent fall-through to pretty. `explain` is lint's own: it is reachable\n * through `--explain` and never through `-f`, because it reports on\n * configuration rather than on documents.\n */\nexport type ReportFormat = FamilyFormat | \"explain\";\n\n/** Listing commands have nothing to annotate, so they offer no `github`. */\nexport type ListFormat = \"pretty\" | \"json\";\n\nexport interface ReportOptions {\n color?: boolean;\n /**\n * Directory the run's relative paths are relative to, forwarded to the SARIF\n * reporter and ignored by the others. Defaults to the process cwd, which is\n * right for the CLI because `runLint` defaults its `cwd` the same way.\n *\n * It is here rather than only on `renderSarif` because `render` is the entry\n * point a library caller reaches for, and without it that caller was pinned\n * to the process cwd with no way out short of bypassing `render` entirely -\n * for the one reporter whose whole output is paths.\n */\n root?: string;\n}\n\nfunction plural(n: number, word: string): string {\n return `${n} ${word}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** `line:column` of a finding, the anchor an editor can jump to. */\nfunction locate(finding: Finding): string {\n return `${finding.position.start.line}:${finding.position.start.column}`;\n}\n\n/** A finding as prose: the heading it is about, then what is wrong with it. */\nfunction describeFinding(finding: Finding): string {\n return finding.heading != null\n ? `${finding.heading}: ${finding.message}`\n : finding.message;\n}\n\n/**\n * A finding's level prefix, meta's shape: nothing for an error, since the\n * `✗`/`✓` mark already says that; the word itself, coloured, for anything\n * milder. Keeps a passing file's warning from reading as just another\n * anonymous line once it is printed beside real errors on a failing one.\n */\nfunction levelPrefix(c: Colors, severity: Finding[\"severity\"]): string {\n if (severity === \"error\") return \"\";\n return `${severity === \"notice\" ? c.dim(\"notice\") : c.yellow(\"warning\")} `;\n}\n\nexport function renderPretty(run: LintRun, opts: ReportOptions = {}): string {\n const c = palette(opts.color ?? false);\n const lines: string[] = [];\n let warnings = 0;\n let notices = 0;\n\n for (const result of run.results) {\n // A skip is reported, never silently dropped: an unreadable format that\n // leaves no trace is indistinguishable from a file that passed.\n if (result.skipped != null) {\n const why = result.reason ?? result.skipped;\n lines.push(`${c.yellow(\"-\")} ${result.file} ${c.dim(`skipped: ${why}`)}`);\n continue;\n }\n if (result.success && result.findings.length === 0) {\n lines.push(`${c.green(\"✓\")} ${result.file}`);\n continue;\n }\n // `success` means \"no error-severity finding\", not \"no findings\" - a\n // passing file can still hold a warning, such as\n // `unsupported_content_kind`. Reusing `✓` for it would hide the warning\n // behind the same glyph a clean file gets; reusing `✗` would fail a file\n // nothing actually failed. `⚠` (meta's and cite's mark for the same case)\n // says \"passing, but read this\" without claiming either extreme.\n const mark = result.success ? c.yellow(\"⚠\") : c.red(\"✗\");\n lines.push(`${mark} ${result.file}`);\n for (const finding of result.findings) {\n // Counted apart, because they are not the same thing to a reader. Every\n // structure finding used to be an `error` or the occasional `warning`,\n // so \"not an error\" and \"a warning\" were the same set. DITA-OT reports an\n // undefined key reference at `notice`, and calling that a warning on the\n // summary line overstates it.\n if (finding.severity === \"warning\") warnings++;\n else if (finding.severity === \"notice\") notices++;\n // The namespaced id rather than the bare `type`: it is what SARIF,\n // JUnit and the GitHub annotation file the finding under, so the string\n // a reader copies out of the terminal is the one they can search for.\n lines.push(\n ` ${c.dim(locate(finding))} ${c.cyan(ruleId(finding.type))} ` +\n `${levelPrefix(c, finding.severity)}${describeFinding(finding)}`,\n );\n }\n }\n\n const { checked, passed, failed, skipped } = run.summary;\n // Named only when there are any, as meta and cite do: every run against a\n // format that reports every content kind has none.\n const warningsText = warnings > 0 ? `, ${plural(warnings, \"warning\")}` : \"\";\n const noticesText = notices > 0 ? `, ${plural(notices, \"notice\")}` : \"\";\n const summary = `${plural(checked, \"file\")} checked, ${passed} passed, ${failed} failed, ${skipped} skipped${warningsText}${noticesText}`;\n if (lines.length > 0) lines.push(\"\");\n lines.push(failed > 0 ? c.red(summary) : c.green(summary));\n return lines.join(\"\\n\");\n}\n\n/**\n * The published JSON shape, and the reason this builds objects by hand rather\n * than stringifying `run.results` directly.\n *\n * manni docevals reads `[{ file, success, errors: [{ type, heading, message,\n * position: { start: { line, column } } }] }]` off stdout, and it parses\n * rather than validates - a renamed key produces zero findings, not an error.\n * So: a bare array at the top level, and `errors`, even though the internal\n * field is `findings`. Adding keys is safe; renaming or nesting is not.\n */\nexport function renderJson(run: LintRun): string {\n const results = run.results.map((result) => ({\n file: result.file,\n success: result.success,\n errors: result.findings.map((finding) => ({\n type: finding.type,\n // Additive, and deliberately beside `type` rather than instead of it.\n // `ruleId` is the family id every other reporter files this finding\n // under; `tool` names which tool produced it, the question a second\n // lint job makes worth asking.\n ruleId: ruleId(finding.type),\n tool: TOOL_NAME,\n heading: finding.heading,\n message: finding.message,\n position: finding.position,\n // Additive too, and the reason it has to be: `success: true` beside a\n // non-empty `errors` array is exactly what a warning-only file looks\n // like now that `success` means \"no error-severity finding\" rather than\n // \"no findings\". Without this key a consumer has no way to tell that\n // apart from an error the JSON shape simply forgot to fail on.\n severity: finding.severity,\n })),\n // Additive, and the one thing this shape could not say. A skipped file is\n // `{success: false, errors: []}`, which is also what a failure whose\n // finding vanished looks like - so a consumer counting failures counted a\n // file nothing read as a file that was read and found wanting. Null rather\n // than absent, because a key that comes and goes makes \"not skipped\" and\n // \"an older manni\" the same observation. The prose `reason` stays off the\n // wire; it is a diagnostic for the pretty and SARIF reports.\n skipped: result.skipped ?? null,\n }));\n return JSON.stringify(results, null, 2);\n}\n\n/**\n * GitHub workflow commands: one annotation per finding, shaped as cite's are -\n * `::<severity> file=…,line=…,col=…,title=<ruleId>::<message>`.\n *\n * The rule id is a `title=` property rather than a `[type]` prefix inside the\n * message. GitHub renders the title as the alert's own heading, so the prefix\n * spelled the rule's name a second time; and `title` is the field a reader can\n * group and filter on, which prose can never be.\n *\n * The level is the severity, not a constant `error`. The family scale was\n * chosen to be GitHub's for exactly this: `::warning` and `::notice` render\n * inline like `::error` but do not fail the check, which is the severity\n * invariant in GitHub's terms, and it is load-bearing rather than theoretical:\n * `unsupported_content_kind` is a `warning`, so it annotates the file without\n * failing the job.\n *\n * Line breaks are escaped rather than collapsed to spaces, as this once did.\n * `%0A` is the format's own answer and GitHub renders it as a multi-line\n * annotation, so the message arrives whole; collapsing threw away the author's\n * line breaks to solve a problem the escape already solves, and its `\\r?\\n`\n * pattern let a bare carriage return through into the command untouched.\n *\n * The escaping itself is the family's, from `src/shared/github.ts`. It lives\n * there precisely so a second renderer cannot re-derive it: the replacements\n * are order-dependent (`%` first, or the escape sequences get escaped again),\n * and a local copy that got the order wrong would look identical in review and\n * only show itself on a message carrying a literal `%`.\n */\nexport function renderGithub(run: LintRun): string {\n const lines: string[] = [];\n for (const result of run.results) {\n for (const finding of result.findings) {\n const params = [\n `file=${escapeWorkflowCommandProperty(result.file)}`,\n `line=${finding.position.start.line}`,\n `col=${finding.position.start.column}`,\n `title=${escapeWorkflowCommandProperty(ruleId(finding.type))}`,\n ];\n const message = escapeWorkflowCommandMessage(describeFinding(finding));\n lines.push(`::${finding.severity} ${params.join(\",\")}::${message}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * `--explain`: the resolution chain per file, rather than findings.\n *\n * Printing every stage, including the ones that had nothing to say, is the\n * point. \"Which template linted this page?\" is usually asked because the answer\n * was surprising, and the surprising part is almost always a stage the reader\n * forgot applies - a stray `$template`, an override glob matching more than\n * intended. A report that showed only the winning stage would hide exactly the\n * thing being looked for.\n */\n/**\n * The alignment block riding on a result. `commands/lint.ts` attaches the tree\n * and the loaded template under `alignment` when `--explain` asked for them,\n * and only for a file that routed; a result without it prints as it always did.\n *\n * It is a nested key rather than two flat ones because `template` at the top\n * level is already the template's *ref*, the string the routing line shows.\n */\nfunction alignmentFor(result: LintFileResult): string[] | null {\n const source: ExplainSource | undefined = result.alignment;\n if (!source) return null;\n return formatAlignment(explainAlignment(source.tree, source.template));\n}\n\nexport function renderExplain(run: LintRun, opts: ReportOptions = {}): string {\n const c = palette(opts.color ?? false);\n const lines: string[] = [];\n\n for (const result of run.results) {\n // Not the pass/fail glyphs: `--explain` reports whether a page was routed,\n // and a routed page may still be full of findings. Reusing the tick would\n // read as a clean bill of health for a document nothing has looked at yet.\n const chosen = result.template;\n lines.push(`${chosen ? c.cyan(\"▸\") : c.dim(\"-\")} ${c.bold(result.file)}`);\n\n const steps = result.resolution?.steps ?? [];\n if (steps.length === 0) {\n lines.push(` ${c.dim(\"(no resolution recorded)\")}`);\n }\n for (const step of steps) {\n const mark = step.ref ? c.green(\"→\") : c.dim(\"·\");\n const label = step.ref ? c.bold(step.ref) : c.dim(step.detail);\n const suffix = step.ref ? ` ${c.dim(step.detail)}` : \"\";\n lines.push(` ${mark} ${step.stage.padEnd(20)} ${label}${suffix}`);\n }\n\n const alignment = chosen ? alignmentFor(result) : null;\n if (alignment && alignment.length > 0) {\n lines.push(` ${c.dim(\"alignment\")}`);\n for (const row of alignment) lines.push(` ${row}`);\n }\n\n const cause = result.resolution?.cause;\n if (cause === \"unknown-type\") {\n const type = result.resolution?.unknownType ?? \"(none recorded)\";\n const near = result.resolution?.suggestions ?? [];\n const known = result.resolution?.knownTypes ?? [];\n // The same fallback the pretty reporter gives. Without it a typo with no\n // near miss - which is most of them, since a near miss needs the typo to\n // be close - printed the failure and nothing to act on, while the plain\n // lint output for that page listed every doctype available.\n const hint = near.length\n ? `; did you mean ${near.join(\", \")}?`\n : known.length\n ? `; known doctypes: ${known.join(\", \")}`\n : \"\";\n lines.push(` ${c.red(\"✗\")} no template serves type \"${type}\"${hint}`);\n } else if (cause === \"no-type\") {\n lines.push(` ${c.dim(\"skipped: the page declares no type\")}`);\n }\n lines.push(\"\");\n }\n\n const routed = run.results.filter((r) => r.template != null).length;\n lines.push(\n `${run.results.length} file${run.results.length === 1 ? \"\" : \"s\"}, ` +\n `${routed} routed, ${run.results.length - routed} unrouted`,\n );\n return lines.join(\"\\n\");\n}\n\nexport function render(\n run: LintRun,\n format: ReportFormat,\n opts: ReportOptions = {},\n): string {\n switch (format) {\n case \"json\":\n return renderJson(run);\n case \"github\":\n return renderGithub(run);\n case \"sarif\":\n return renderSarif(run, opts.root === undefined ? {} : { root: opts.root });\n case \"junit\":\n return renderJunit(run);\n case \"explain\":\n return renderExplain(run, opts);\n case \"pretty\":\n return renderPretty(run, opts);\n default: {\n // Exhaustive, and the guard is what makes the claim true: sharing an arm\n // with `pretty` narrowed nothing, so a format added to meta's\n // `REPORT_FORMATS` - which is what the CLI validates `-f` against - was\n // accepted here and silently rendered as a human report. Now it is a\n // compile error, and this is its runtime half for library callers.\n const unreachable: never = format;\n throw new LintError(\n `Unknown report format ${JSON.stringify(unreachable)}. Use ${REPORT_FORMAT_LIST}.`,\n );\n }\n }\n}\n\n/** One template per line: the ref to pass, its title, and the types it serves. */\nfunction templateLine(c: Colors, entry: TemplateInfo): string {\n const title = entry.title !== \"\" ? ` ${c.dim(\"—\")} ${entry.title}` : \"\";\n const types =\n entry.types.length > 0 ? entry.types.join(\", \") : \"(no types declared)\";\n return ` ${c.cyan(entry.id)}${title} ${c.dim(`types: ${types}`)} ${c.dim(`[${entry.source}]`)}`;\n}\n\nexport function renderTemplates(\n info: TemplatesInfo,\n format: ListFormat,\n opts: ReportOptions = {},\n): string {\n if (format === \"json\") return JSON.stringify(info, null, 2);\n\n const c = palette(opts.color ?? false);\n const lines: string[] = [c.bold(\"Templates:\")];\n if (info.templates.length === 0) {\n lines.push(c.dim(\" (none)\"));\n } else {\n for (const entry of info.templates) lines.push(templateLine(c, entry));\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * One input format as `markdown Markdown (.md, .markdown) kinds: paragraph,\n * codeBlock, list`.\n *\n * The kinds are left out entirely when there are none, rather than printed as\n * an empty list. A tool outside the package answers the job without parsing\n * into the content model, so it has no kinds to report, and a bare `kinds:`\n * label reads as a rendering fault rather than as the answer.\n */\nfunction formatLine(c: Colors, entry: FormatInfo): string {\n const head = ` ${c.cyan(entry.name)} ${entry.label} (${entry.extensions.join(\", \")})`;\n if (entry.kinds.length === 0) return head;\n return `${head} ${c.dim(`kinds: ${entry.kinds.join(\", \")}`)}`;\n}\n\n/**\n * `manni lint tools`: one block per job. Every column is printed for every\n * job, the negatives included - \"not configured\" beside a job that still runs\n * on defaults is the answer someone ran this command to get.\n */\nexport function renderTools(\n tools: ToolInfo[],\n format: ListFormat,\n opts: ReportOptions = {},\n): string {\n if (format === \"json\") return JSON.stringify(tools, null, 2);\n\n const c = palette(opts.color ?? false);\n const lines: string[] = [c.bold(\"Jobs:\")];\n for (const entry of tools) {\n const state = [\n entry.configured ? \"configured\" : \"not configured\",\n entry.available ? \"available\" : \"unavailable\",\n ].join(\", \");\n // A tool that is not here has no version to report, and the row still\n // prints: \"unavailable\" beside a blank cell reads as a rendering fault\n // rather than as the answer. The dash is a cell standing in for a missing\n // value, which is why it is an em dash in a house style that bans them in\n // prose.\n const version = entry.version ?? \"—\";\n lines.push(\n ` ${c.cyan(entry.job)} tool: ${c.bold(entry.tool)} ${version} [${state}]`,\n );\n lines.push(` config: ${c.dim(entry.config)}`);\n lines.push(` ${c.dim(\"formats:\")}`);\n for (const info of entry.formats) lines.push(formatLine(c, info));\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":["walk","content","apply","CITATIONS_KEY","hashRange","sliceLines","sliceLines","hashRange","extname","fenceFor","words","at","pad","line","ajv","extname","origin","quoted","run","at","span","pre43","at","span","named","run","resolve","at","at","words","span","pinOf","held","now","w1","sliceLines","candidates","spanOf","at","spellAt","span","at","origin","sep","CITATIONS_KEY","sep","candidates","at","run","readFile","at","run","isRecord","i","j","CONTEXT","readFile","CITATIONS_KEY","at","join","isAbsolute","candidates","span","at","named","place","finding","rule","isAbsolute","byLine","finding","at","sliceLines","named","span","readOptions","emptyIndex","sliceLines","resolve","resolve","existsSync","readFile","resolve","join","resolve","run","sidecars","readFile","checkOne","existsSync","readFile","relative","resolve","ID","toPosix","isEnoent","readFile","sliceLines","at","span","resolve","run","relative","sidecars","markerAt","after","index","named","resolve","run","index","markers","named","kept","resolve","resolve","apply","isRecord","origin","named","finding","at","span","run","rewritten","unitText","skipped","resolve","origin","sliceLines","plural","finding","at","run","citesEncrypted","location","baselined","span","spanOf","where","named","origin","run","finding","run","existsSync","readFile","isAbsolute","join","relative","resolve","sep","resolve","isEnoent","sidecars","reportedPath","relative","sep","locate","join","isAbsolute","readFile","skipped","existsSync","existsSync","join","relative","resolve","join","existsSync","relative","resolve","firstLine","metadata","processor","ZERO","positionOf","childContent","span","at","toContentNode","documentEnd","ADMONITION_VARIANTS","indentOf","spanOf","firstLine","text","under","title","last","quoted","rawText","elementChildren","ADMONITION_VARIANTS","compiled","parseDocument","readMetadata","flattenInline","ADMONITION_VARIANTS","parse","supportedExtensions","listFormats","run","matches","finding","plural","BLOCK_KINDS","readFile","dirname","isAbsolute","join","existsSync","dirname","join","dirname","existsSync","join","parseYaml","listBuiltins","join","readFile","parseYaml","isRecord","classifyRef","lower","compiled","BLOCK_KINDS","named","load","isAbsolute","rebased","dirname","compile","cursor","compiled","state","index","missingMessage","matches","origin","BLOCK_KINDS","matches","dirname","isAbsolute","resolve","parseYaml","AjvNs","Ajv","CONFIG_FILE","CONFIG_REF","MOVED_KEYS","assertNoMovedKeys","rejectUnknownKeys","isRecord","ajv","Ajv","compiled","describeError","parseConfig","parseYaml","loadConfig","dirname","resolve","isAbsolute","STDIN","execFile","readFile","join","fileURLToPath","MAX_BUFFER","join","lower","settle","execFile","isEnoent","isMapping","location","fileURLToPath","readFile","listFormats","supportedExtensions","readFile","extname","relative","resolve","STDIN_LABEL","run","origin","classifyRef","listBuiltins","resolve","extname","supportedExtensions","readFile","labelOf","relative","findingsFor","BLOCK_KINDS","origin","span","pageSection","headerCells","existsSync","readFile","basename","dirname","extname","resolve","listBuiltins","STDIN","extname","supportedExtensions","basename","run","resolve","existsSync","readFile","dirname","run","RULE_ID_PREFIX","ruleId","finding","RULE_ID_PREFIX","run","renderJunit","toPosix","posix","finding","run","descriptors","ruleId","renderSarif","ruleLabel","text","run","matches","i","rows","plural","finding","run","ruleId","render","renderSarif","renderJunit"]}