@descent-vtt/spec-graph 0.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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +627 -0
  3. package/bin/spec-graph.js +24 -0
  4. package/dist/baseline.d.ts +93 -0
  5. package/dist/baseline.js +187 -0
  6. package/dist/baseline.js.map +1 -0
  7. package/dist/cli.d.ts +66 -0
  8. package/dist/cli.js +565 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/config.d.ts +66 -0
  11. package/dist/config.js +183 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/directives.d.ts +56 -0
  14. package/dist/directives.js +125 -0
  15. package/dist/directives.js.map +1 -0
  16. package/dist/extract.d.ts +116 -0
  17. package/dist/extract.js +1043 -0
  18. package/dist/extract.js.map +1 -0
  19. package/dist/glob.d.ts +73 -0
  20. package/dist/glob.js +284 -0
  21. package/dist/glob.js.map +1 -0
  22. package/dist/graph.d.ts +55 -0
  23. package/dist/graph.js +201 -0
  24. package/dist/graph.js.map +1 -0
  25. package/dist/identity.d.ts +87 -0
  26. package/dist/identity.js +294 -0
  27. package/dist/identity.js.map +1 -0
  28. package/dist/index.d.ts +63 -0
  29. package/dist/index.js +45 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/lifecycle.d.ts +57 -0
  32. package/dist/lifecycle.js +258 -0
  33. package/dist/lifecycle.js.map +1 -0
  34. package/dist/markdown.d.ts +152 -0
  35. package/dist/markdown.js +820 -0
  36. package/dist/markdown.js.map +1 -0
  37. package/dist/paths.d.ts +22 -0
  38. package/dist/paths.js +58 -0
  39. package/dist/paths.js.map +1 -0
  40. package/dist/report.d.ts +89 -0
  41. package/dist/report.js +326 -0
  42. package/dist/report.js.map +1 -0
  43. package/dist/resolve.d.ts +61 -0
  44. package/dist/resolve.js +340 -0
  45. package/dist/resolve.js.map +1 -0
  46. package/dist/rules.d.ts +61 -0
  47. package/dist/rules.js +557 -0
  48. package/dist/rules.js.map +1 -0
  49. package/dist/runner.d.ts +108 -0
  50. package/dist/runner.js +186 -0
  51. package/dist/runner.js.map +1 -0
  52. package/dist/sections.d.ts +94 -0
  53. package/dist/sections.js +372 -0
  54. package/dist/sections.js.map +1 -0
  55. package/dist/select.d.ts +96 -0
  56. package/dist/select.js +413 -0
  57. package/dist/select.js.map +1 -0
  58. package/dist/source.d.ts +43 -0
  59. package/dist/source.js +109 -0
  60. package/dist/source.js.map +1 -0
  61. package/dist/state.d.ts +45 -0
  62. package/dist/state.js +330 -0
  63. package/dist/state.js.map +1 -0
  64. package/dist/types.d.ts +294 -0
  65. package/dist/types.js +52 -0
  66. package/dist/types.js.map +1 -0
  67. package/dist/yaml.d.ts +37 -0
  68. package/dist/yaml.js +240 -0
  69. package/dist/yaml.js.map +1 -0
  70. package/package.json +71 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A structural Markdown scanner.\n *\n * This is deliberately **not** a CommonMark implementation. spec-graph needs six\n * things from a document - front matter, headings, list items with their\n * continuations, HTML comments, links, and a reliable map of what is code - and\n * a full parser would cost a dependency tree, an AST walk, and a position\n * mapping layer to get back the offsets we want in the first place.\n *\n * What the scanner does guarantee is the part that makes regex-based spec\n * linters lie:\n *\n * - **Code never counts.** Fenced blocks, indented blocks and inline spans are\n * masked before a single link is extracted, so an example in a code sample\n * never becomes a graph edge.\n * - **Items are blocks, not lines.** A list item owns its wrapped continuation\n * lines and its nested content, so a resolution written on the second line of\n * a bullet is found instead of missed.\n * - **Everything carries absolute offsets.** No re-scanning, no drift between\n * the text a rule matched and the position it reports.\n */\n\nimport { createLineIndex, type LineIndex } from './source.js';\n\n/* -------------------------------------------------------------------------- */\n/* Shapes */\n/* -------------------------------------------------------------------------- */\n\nexport interface Range {\n readonly start: number;\n readonly end: number;\n}\n\nexport interface FrontMatter {\n /** The body between the delimiters, exclusive. */\n readonly raw: string;\n /** Offset of the first character of `raw`. */\n readonly start: number;\n readonly end: number;\n /** Offset just past the closing delimiter line. */\n readonly bodyStart: number;\n}\n\nexport interface ScannedLine {\n /** 1-based. */\n readonly line: number;\n /** Offset of the raw line start. */\n readonly start: number;\n /** Offset just past the line, excluding its terminator. */\n readonly end: number;\n /** Offset of the first character after any block-quote markers. */\n readonly contentStart: number;\n /** Line text after block-quote markers, indentation intact. */\n readonly content: string;\n /** Indentation of `content`, tabs counted as four columns. */\n readonly indent: number;\n readonly blank: boolean;\n readonly quoteDepth: number;\n /** Inside a fenced or indented code block, fence delimiters included. */\n readonly code: boolean;\n}\n\nexport interface Heading {\n readonly level: number;\n readonly text: string;\n /** GitHub-compatible anchor slug. */\n readonly slug: string;\n readonly start: number;\n readonly end: number;\n readonly line: number;\n}\n\nexport interface ListItem {\n /** The whole block: marker line plus continuations and nested content. */\n readonly start: number;\n readonly end: number;\n /** Offset of the list marker itself. */\n readonly markerStart: number;\n readonly marker: string;\n /** Offset where the item text begins, after marker and any checkbox. */\n readonly textStart: number;\n /** The character inside `[ ]`, or `null` when the item has no checkbox. */\n readonly checkbox: string | null;\n readonly checkboxStart: number | null;\n /** First line of item text, trimmed. */\n readonly firstLine: string;\n /** Full item text including continuations and nested content. */\n readonly body: string;\n /**\n * `body` with code and comments blanked out, same length and offsets.\n *\n * Anything that searches item text for meaning - resolution markers above\n * all - must read this rather than `body`, or a fenced example nested under\n * the item will close it.\n */\n readonly maskedBody: string;\n readonly line: number;\n /** How many list items enclose this one. Top-level items are `0`. */\n readonly depth: number;\n readonly indent: number;\n}\n\nexport interface HtmlComment {\n readonly start: number;\n readonly end: number;\n /** Text between `<!--` and `-->`. */\n readonly inner: string;\n readonly innerStart: number;\n readonly line: number;\n}\n\nexport type LinkForm = 'inline' | 'reference' | 'shortcut' | 'autolink' | 'wiki' | 'definition';\n\nexport interface Link {\n /** Visible label. Empty for autolinks and definitions. */\n readonly text: string;\n /** Destination as written: a path, a URL, or a reference label. */\n readonly target: string;\n /** Offset of the whole construct. */\n readonly start: number;\n readonly end: number;\n /** Offset of `target` inside the source, for precise diagnostics. */\n readonly targetStart: number;\n readonly form: LinkForm;\n readonly line: number;\n}\n\nexport interface TableCell {\n /** Cell text as written, trimmed. */\n readonly text: string;\n /** Offset of the trimmed text, so a finding can point at the cell itself. */\n readonly start: number;\n readonly end: number;\n}\n\nexport interface TableRow {\n readonly cells: readonly TableCell[];\n readonly start: number;\n readonly end: number;\n readonly line: number;\n}\n\nexport interface Table {\n readonly start: number;\n readonly end: number;\n /** Header cells, trimmed. A table without a header row is not a table. */\n readonly headers: readonly TableCell[];\n readonly rows: readonly TableRow[];\n}\n\nexport interface ScannedDocument {\n readonly text: string;\n readonly index: LineIndex;\n readonly frontMatter: FrontMatter | null;\n /** Offset where the body starts, after any front matter. */\n readonly bodyStart: number;\n readonly lines: readonly ScannedLine[];\n readonly headings: readonly Heading[];\n readonly listItems: readonly ListItem[];\n readonly comments: readonly HtmlComment[];\n readonly links: readonly Link[];\n readonly tables: readonly Table[];\n /** Code and comments blanked out, offsets and line breaks preserved. */\n readonly masked: string;\n /** True when the offset falls inside code, a comment, or front matter. */\n isMasked(offset: number): boolean;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Entry point */\n/* -------------------------------------------------------------------------- */\n\nexport function scanMarkdown(source: string): ScannedDocument {\n const text = source.charCodeAt(0) === 0xfeff ? source.slice(1) : source;\n const index = createLineIndex(text);\n const frontMatter = readFrontMatter(text, index);\n const bodyStart = frontMatter ? frontMatter.bodyStart : 0;\n\n const lines = scanLines(text, index, bodyStart);\n const codeRanges = collectCodeRanges(lines, bodyStart);\n const comments = scanComments(text, index, bodyStart, codeRanges);\n\n const inlineCode = scanInlineCode(text, bodyStart, codeRanges, comments);\n const maskRanges = [\n ...(frontMatter ? [{ start: 0, end: frontMatter.bodyStart }] : []),\n ...codeRanges,\n ...inlineCode,\n ...comments.map((c) => ({ start: c.start, end: c.end })),\n ];\n const masked = applyMask(text, maskRanges);\n const sortedMask = mergeRanges(maskRanges);\n\n const headings = scanHeadings(lines);\n const listItems = scanListItems(lines, text, masked);\n const links = scanLinks(masked, text, index);\n const tables = scanTables(lines, text, masked);\n\n return {\n text,\n index,\n frontMatter,\n bodyStart,\n lines,\n headings,\n listItems,\n comments,\n links,\n tables,\n masked,\n isMasked: (offset) => containsOffset(sortedMask, offset),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Front matter */\n/* -------------------------------------------------------------------------- */\n\nconst FENCE_FM = /^(-{3,}|\\+{3,})[ \\t]*$/;\n\nfunction readFrontMatter(text: string, index: LineIndex): FrontMatter | null {\n if (index.lineCount === 0) return null;\n const first = index.lineText(1);\n const open = FENCE_FM.exec(first);\n if (!open) return null;\n const closer = (open[1] as string).startsWith('-') ? /^(-{3,}|\\.{3,})[ \\t]*$/ : /^\\+{3,}[ \\t]*$/;\n\n for (let line = 2; line <= index.lineCount; line += 1) {\n if (closer.test(index.lineText(line))) {\n const start = index.lineStart(2);\n const end = index.lineStart(line);\n const bodyStart = line < index.lineCount ? index.lineStart(line + 1) : text.length;\n return { raw: text.slice(start, end), start, end, bodyStart };\n }\n }\n // An unterminated opener is a horizontal rule, not front matter.\n return null;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Line classification */\n/* -------------------------------------------------------------------------- */\n\nconst LIST_MARKER = /^([ \\t]*)([-*+]|\\d{1,9}[.)])([ \\t]+|$)/;\nconst ATX_HEADING = /^ {0,3}(#{1,6})(?:[ \\t]+(.*?))?[ \\t]*(?:#+[ \\t]*)?$/;\nconst SETEXT_UNDERLINE = /^ {0,3}(=+|-+)[ \\t]*$/;\nconst THEMATIC_BREAK = /^ {0,3}(?:(?:\\*[ \\t]*){3,}|(?:-[ \\t]*){3,}|(?:_[ \\t]*){3,})$/;\nconst FENCE_OPEN = /^([ \\t]*)(`{3,}|~{3,})(.*)$/;\n\n/** Counts indentation in columns, expanding tabs to the next multiple of four. */\nfunction measureIndent(line: string): number {\n let width = 0;\n for (const ch of line) {\n if (ch === ' ') width += 1;\n else if (ch === '\\t') width += 4 - (width % 4);\n else break;\n }\n return width;\n}\n\n/** Strips `>` block-quote markers, returning the offset and text of the content. */\nfunction stripQuotes(raw: string, lineStart: number): { contentStart: number; content: string; depth: number } {\n let i = 0;\n let depth = 0;\n for (;;) {\n let j = i;\n let spaces = 0;\n while (j < raw.length && (raw[j] === ' ' || raw[j] === '\\t') && spaces < 3) {\n spaces += 1;\n j += 1;\n }\n if (raw[j] !== '>') break;\n j += 1;\n if (raw[j] === ' ') j += 1;\n depth += 1;\n i = j;\n }\n return { contentStart: lineStart + i, content: raw.slice(i), depth };\n}\n\nfunction scanLines(text: string, index: LineIndex, bodyStart: number): ScannedLine[] {\n const out: ScannedLine[] = [];\n const firstLine = index.positionAt(bodyStart).line;\n\n let fence: { char: string; length: number; indent: number } | null = null;\n let inList = false;\n let listIndent = 0;\n let previousBlank = true;\n let indentedCode = false;\n\n for (let line = firstLine; line <= index.lineCount; line += 1) {\n const start = index.lineStart(line);\n const end = index.lineEnd(line);\n if (end < bodyStart) continue;\n const raw = text.slice(start, end);\n const { contentStart, content, depth } = stripQuotes(raw, start);\n const indent = measureIndent(content);\n const blank = content.trim().length === 0;\n\n let code = false;\n\n if (fence) {\n code = true;\n const close = FENCE_OPEN.exec(content);\n if (\n close &&\n (close[2] as string)[0] === fence.char &&\n (close[2] as string).length >= fence.length &&\n (close[3] as string).trim().length === 0 &&\n measureIndent(close[1] as string) <= fence.indent + 3\n ) {\n fence = null;\n }\n } else {\n const open = FENCE_OPEN.exec(content);\n if (open && (open[3] as string).indexOf('`') === -1) {\n fence = {\n char: (open[2] as string)[0] as string,\n length: (open[2] as string).length,\n indent: measureIndent(open[1] as string),\n };\n code = true;\n indentedCode = false;\n } else if (blank) {\n code = indentedCode;\n } else {\n // Indented code is only recognised outside list containers. Inside a\n // list, four-space indentation is ordinary continuation far more often\n // than it is a code block, and masking a continuation would silently\n // drop the links and resolutions written there.\n if (!inList && indent >= 4 && (previousBlank || indentedCode)) {\n code = true;\n indentedCode = true;\n } else {\n indentedCode = false;\n }\n }\n }\n\n if (!code && !blank) {\n const marker = LIST_MARKER.exec(content);\n if (marker) {\n inList = true;\n listIndent = indent;\n } else if (inList && indent === 0 && previousBlank) {\n inList = false;\n listIndent = 0;\n } else if (inList && indent <= listIndent && previousBlank && ATX_HEADING.test(content)) {\n inList = false;\n listIndent = 0;\n }\n if (ATX_HEADING.test(content) && indent < 4) {\n inList = false;\n listIndent = 0;\n }\n }\n\n out.push({ line, start, end, contentStart, content, indent, blank, quoteDepth: depth, code });\n previousBlank = blank;\n }\n\n return out;\n}\n\nfunction collectCodeRanges(lines: readonly ScannedLine[], bodyStart: number): Range[] {\n const ranges: Range[] = [];\n let open: { start: number; end: number } | null = null;\n for (const line of lines) {\n if (line.code) {\n const start = Math.max(line.start, bodyStart);\n if (open && open.end >= line.start - 2) open.end = line.end;\n else {\n if (open) ranges.push(open);\n open = { start, end: line.end };\n }\n } else if (open) {\n ranges.push(open);\n open = null;\n }\n }\n if (open) ranges.push(open);\n return ranges;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Headings */\n/* -------------------------------------------------------------------------- */\n\nexport function slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[`*_~[\\]()<>#!|]/g, '')\n .replace(/[^\\p{L}\\p{N}\\s-]/gu, '')\n .trim()\n // GitHub hyphenates every whitespace character, so a run of two spaces left\n // behind by stripped punctuation becomes two hyphens, not one.\n .replace(/\\s/g, '-');\n}\n\nfunction scanHeadings(lines: readonly ScannedLine[]): Heading[] {\n const out: Heading[] = [];\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i] as ScannedLine;\n if (line.code || line.blank) continue;\n\n const atx = ATX_HEADING.exec(line.content);\n if (atx && line.indent < 4) {\n const body = (atx[2] ?? '').trim();\n out.push({\n level: (atx[1] as string).length,\n text: body,\n slug: slugify(body),\n start: line.contentStart,\n end: line.end,\n line: line.line,\n });\n continue;\n }\n\n // Setext: an underline of `=` or `-` directly below a paragraph line. The\n // preceding line must not itself be a heading, a list item or a fence.\n const next = lines[i + 1];\n if (!next || next.code || next.blank) continue;\n const under = SETEXT_UNDERLINE.exec(next.content);\n if (!under) continue;\n if (LIST_MARKER.test(line.content) || THEMATIC_BREAK.test(line.content)) continue;\n if (line.indent >= 4) continue;\n const body = line.content.trim();\n if (body.length === 0) continue;\n out.push({\n level: (under[1] as string)[0] === '=' ? 1 : 2,\n text: body,\n slug: slugify(body),\n start: line.contentStart,\n end: next.end,\n line: line.line,\n });\n }\n return out;\n}\n\n/* -------------------------------------------------------------------------- */\n/* List items */\n/* -------------------------------------------------------------------------- */\n\nconst CHECKBOX = /^\\[([ xX~\\-?!*/+])\\](?=[ \\t]|$)/;\n\nfunction scanListItems(lines: readonly ScannedLine[], text: string, masked: string): ListItem[] {\n const out: ListItem[] = [];\n // Indents of the list items currently enclosing the cursor, outermost first.\n const stack: number[] = [];\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i] as ScannedLine;\n if (line.code || line.blank) continue;\n const marker = LIST_MARKER.exec(line.content);\n if (!marker) continue;\n\n const indent = measureIndent(marker[1] as string);\n while (stack.length > 0 && indent <= (stack[stack.length - 1] as number)) stack.pop();\n const depth = stack.length;\n stack.push(indent);\n\n const markerStart = line.contentStart + (marker[1] as string).length;\n let textStart = markerStart + (marker[2] as string).length + (marker[3] as string).length;\n\n const rest = text.slice(textStart, line.end);\n const box = CHECKBOX.exec(rest);\n let checkbox: string | null = null;\n let checkboxStart: number | null = null;\n if (box) {\n checkbox = box[1] as string;\n checkboxStart = textStart;\n textStart += (box[0] as string).length;\n while (text[textStart] === ' ' || text[textStart] === '\\t') textStart += 1;\n }\n\n const end = findItemEnd(lines, i, indent);\n const firstLine = text.slice(textStart, line.end).trim();\n const body = text.slice(textStart, end);\n\n out.push({\n start: line.contentStart,\n end,\n markerStart,\n marker: marker[2] as string,\n textStart,\n checkbox,\n checkboxStart,\n firstLine,\n body,\n maskedBody: masked.slice(textStart, end),\n line: line.line,\n depth,\n indent,\n });\n }\n\n return out;\n}\n\n/**\n * Finds where a list item block ends.\n *\n * The item owns its wrapped continuation lines and everything nested under it.\n * It gives up ownership at the next sibling or shallower marker, at any\n * heading, and at the first non-indented line after a blank one.\n */\nfunction findItemEnd(lines: readonly ScannedLine[], startIndex: number, indent: number): number {\n let end = (lines[startIndex] as ScannedLine).end;\n let sawBlank = false;\n\n for (let i = startIndex + 1; i < lines.length; i += 1) {\n const line = lines[i] as ScannedLine;\n if (line.blank) {\n sawBlank = true;\n continue;\n }\n if (!line.code) {\n if (line.indent < 4 && ATX_HEADING.test(line.content)) break;\n if (line.indent <= indent) {\n if (sawBlank) break;\n if (LIST_MARKER.test(line.content)) break;\n if (THEMATIC_BREAK.test(line.content)) break;\n }\n }\n if (line.indent <= indent && sawBlank) break;\n end = line.end;\n sawBlank = false;\n }\n\n return end;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Tables */\n/* -------------------------------------------------------------------------- */\n\n/** `| :--- | ---: | :-: |` - the row that makes the line above it a header. */\nconst TABLE_DELIMITER = /^\\|?(?:\\s*:?-+:?\\s*\\|)+\\s*:?-*:?\\s*\\|?$/;\n\n/**\n * Finds pipe tables, with an offset for every cell.\n *\n * Cell offsets are the point: a register kept as a table needs findings that\n * name the cell declaring the relation, not the row and not the file.\n *\n * Splitting happens on the masked copy so a pipe inside inline code cannot\n * invent a column, while the text comes from the original.\n */\nfunction scanTables(lines: readonly ScannedLine[], text: string, masked: string): Table[] {\n const out: Table[] = [];\n\n for (let i = 0; i < lines.length - 1; i += 1) {\n const header = lines[i] as ScannedLine;\n const delimiter = lines[i + 1] as ScannedLine;\n if (header.code || header.blank || delimiter.code) continue;\n if (!header.content.includes('|')) continue;\n if (!TABLE_DELIMITER.test(delimiter.content.trim())) continue;\n\n const headers = splitRow(header, text, masked);\n if (headers.length === 0) continue;\n\n const rows: TableRow[] = [];\n let end = delimiter.end;\n for (let j = i + 2; j < lines.length; j += 1) {\n const line = lines[j] as ScannedLine;\n if (line.blank || line.code || !line.content.includes('|')) break;\n const cells = splitRow(line, text, masked);\n if (cells.length === 0) break;\n rows.push({ cells, start: line.contentStart, end: line.end, line: line.line });\n end = line.end;\n }\n\n out.push({ start: header.contentStart, end, headers, rows });\n i += rows.length + 1;\n }\n\n return out;\n}\n\n/** Splits one row into cells, keeping each cell's offset in the source. */\nfunction splitRow(line: ScannedLine, text: string, masked: string): TableCell[] {\n const from = line.contentStart;\n const to = line.end;\n const bounds: number[] = [];\n for (let i = from; i < to; i += 1) {\n if (masked[i] !== '|') continue;\n // A pipe escaped with a backslash is content, not a column edge.\n if (i > from && text[i - 1] === '\\\\') continue;\n bounds.push(i);\n }\n if (bounds.length === 0) return [];\n\n const cells: TableCell[] = [];\n // A leading pipe opens the first cell; without one the row starts at `from`.\n let cursor = (bounds[0] as number) === from ? from + 1 : from;\n for (const bound of bounds) {\n if (bound < cursor) continue;\n cells.push(makeCell(text, cursor, bound));\n cursor = bound + 1;\n }\n // Trailing content after the last pipe is a final cell unless the row ended\n // with a border pipe.\n if (cursor < to && text.slice(cursor, to).trim().length > 0) cells.push(makeCell(text, cursor, to));\n\n return cells;\n}\n\nfunction makeCell(text: string, start: number, end: number): TableCell {\n const raw = text.slice(start, end);\n const leading = raw.length - raw.trimStart().length;\n const trimmed = raw.trim();\n return { text: trimmed, start: start + leading, end: start + leading + trimmed.length };\n}\n\n/* -------------------------------------------------------------------------- */\n/* HTML comments */\n/* -------------------------------------------------------------------------- */\n\nfunction scanComments(text: string, index: LineIndex, bodyStart: number, code: readonly Range[]): HtmlComment[] {\n const out: HtmlComment[] = [];\n const merged = mergeRanges(code);\n let from = bodyStart;\n for (;;) {\n const open = text.indexOf('<!--', from);\n if (open === -1) break;\n if (containsOffset(merged, open)) {\n from = open + 4;\n continue;\n }\n const close = text.indexOf('-->', open + 4);\n if (close === -1) break;\n out.push({\n start: open,\n end: close + 3,\n inner: text.slice(open + 4, close),\n innerStart: open + 4,\n line: index.positionAt(open).line,\n });\n from = close + 3;\n }\n return out;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Inline code */\n/* -------------------------------------------------------------------------- */\n\nfunction scanInlineCode(\n text: string,\n bodyStart: number,\n code: readonly Range[],\n comments: readonly HtmlComment[],\n): Range[] {\n const blocked = mergeRanges([...code, ...comments.map((c) => ({ start: c.start, end: c.end }))]);\n const out: Range[] = [];\n let i = bodyStart;\n\n while (i < text.length) {\n if (text[i] !== '`') {\n i += 1;\n continue;\n }\n if (containsOffset(blocked, i)) {\n i += 1;\n continue;\n }\n let runStart = i;\n while (text[i] === '`') i += 1;\n const runLength = i - runStart;\n // An escaped backtick does not open a span.\n if (runStart > 0 && text[runStart - 1] === '\\\\') continue;\n\n let j = i;\n let closed = -1;\n while (j < text.length) {\n if (text[j] !== '`') {\n j += 1;\n continue;\n }\n const closeStart = j;\n while (text[j] === '`') j += 1;\n if (j - closeStart === runLength && !containsOffset(blocked, closeStart)) {\n closed = j;\n break;\n }\n }\n if (closed === -1) continue;\n out.push({ start: runStart, end: closed });\n i = closed;\n }\n\n return out;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Masking */\n/* -------------------------------------------------------------------------- */\n\nfunction mergeRanges(ranges: readonly Range[]): Range[] {\n if (ranges.length === 0) return [];\n const sorted = [...ranges].sort((a, b) => a.start - b.start || a.end - b.end);\n const out: Range[] = [{ ...(sorted[0] as Range) }];\n for (let i = 1; i < sorted.length; i += 1) {\n const next = sorted[i] as Range;\n const last = out[out.length - 1] as { start: number; end: number };\n if (next.start <= last.end) last.end = Math.max(last.end, next.end);\n else out.push({ ...next });\n }\n return out;\n}\n\nfunction containsOffset(sorted: readonly Range[], offset: number): boolean {\n let lo = 0;\n let hi = sorted.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >> 1;\n const range = sorted[mid] as Range;\n if (offset < range.start) hi = mid - 1;\n else if (offset >= range.end) lo = mid + 1;\n else return true;\n }\n return false;\n}\n\n/**\n * Blanks out the given ranges.\n *\n * Line terminators survive so every offset, line and column in the masked copy\n * still matches the original. Callers slice the original text for content and\n * search the masked copy for structure.\n */\nfunction applyMask(text: string, ranges: readonly Range[]): string {\n const merged = mergeRanges(ranges);\n if (merged.length === 0) return text;\n\n // Built from slices rather than a per-character array. Masking runs over every\n // byte of every document, and a `split('')`/`join('')` round trip allocates an\n // array entry per character - on a large corpus that was the single most\n // expensive thing the scanner did.\n let out = '';\n let cursor = 0;\n for (const range of merged) {\n const start = Math.max(range.start, cursor);\n const end = Math.min(range.end, text.length);\n if (end <= start) continue;\n out += text.slice(cursor, start);\n // The character class is deliberately not Unicode-aware: a surrogate pair\n // must become two spaces so that every later offset still lines up.\n out += text.slice(start, end).replace(NON_TERMINATOR, ' ');\n cursor = end;\n }\n return out + text.slice(cursor);\n}\n\nconst NON_TERMINATOR = /[^\\n\\r]/g;\n\n/* -------------------------------------------------------------------------- */\n/* Links */\n/* -------------------------------------------------------------------------- */\n\nconst DEFINITION = /^ {0,3}\\[([^\\]\\n]+)\\]:[ \\t]*(<[^>\\n]*>|\\S+)/;\nconst AUTOLINK = /<((?:https?|ftp|mailto):[^>\\s]+)>/g;\n\n/** How far a bracket construct may run before we call it unbalanced prose. */\nconst MAX_LINK_SPAN = 4096;\n\nfunction scanLinks(masked: string, text: string, index: LineIndex): Link[] {\n const out: Link[] = [];\n const definitions = new Set<string>();\n const definitionRanges: Range[] = [];\n\n // Pass 1: reference definitions, which also make shortcut links resolvable.\n for (let line = 1; line <= index.lineCount; line += 1) {\n const start = index.lineStart(line);\n const content = masked.slice(start, index.lineEnd(line));\n const match = DEFINITION.exec(content);\n if (!match) continue;\n const label = (match[1] as string).trim().toLowerCase();\n definitions.add(label);\n const rawTarget = match[2] as string;\n const targetStart = start + content.indexOf(rawTarget, (match[1] as string).length);\n definitionRanges.push({ start, end: start + (match[0] as string).length });\n out.push({\n text: (match[1] as string).trim(),\n target: unwrapAngle(rawTarget),\n start,\n end: start + (match[0] as string).length,\n targetStart,\n form: 'definition',\n line,\n });\n }\n\n // Pass 2: autolinks.\n AUTOLINK.lastIndex = 0;\n for (let m = AUTOLINK.exec(masked); m !== null; m = AUTOLINK.exec(masked)) {\n const start = m.index;\n out.push({\n text: '',\n target: m[1] as string,\n start,\n end: start + (m[0] as string).length,\n targetStart: start + 1,\n form: 'autolink',\n line: index.positionAt(start).line,\n });\n }\n\n // Pass 3: bracket constructs, left to right.\n const definedAt = mergeRanges(definitionRanges);\n let i = 0;\n while (i < masked.length) {\n const ch = masked[i];\n if (ch !== '[') {\n i += 1;\n continue;\n }\n // The label of a definition is not itself a shortcut link to anything.\n if (containsOffset(definedAt, i)) {\n i += 1;\n continue;\n }\n const isImage = i > 0 && masked[i - 1] === '!';\n\n if (masked[i + 1] === '[') {\n const close = masked.indexOf(']]', i + 2);\n if (close !== -1 && close - i <= MAX_LINK_SPAN && masked.slice(i + 2, close).indexOf('\\n') === -1) {\n const target = text.slice(i + 2, close).trim();\n if (target.length > 0) {\n out.push({\n text: target,\n target: wikiTarget(target),\n start: i,\n end: close + 2,\n targetStart: i + 2,\n form: 'wiki',\n line: index.positionAt(i).line,\n });\n i = close + 2;\n continue;\n }\n }\n }\n\n const labelEnd = matchBracket(masked, i);\n if (labelEnd === -1) {\n i += 1;\n continue;\n }\n const label = text.slice(i + 1, labelEnd);\n const after = masked[labelEnd + 1];\n\n if (after === '(') {\n const dest = readDestination(masked, labelEnd + 2);\n if (dest) {\n if (!isImage) {\n out.push({\n text: label.trim(),\n target: unwrapAngle(text.slice(dest.start, dest.end).trim()),\n start: isImage ? i - 1 : i,\n end: dest.close + 1,\n targetStart: dest.start,\n form: 'inline',\n line: index.positionAt(i).line,\n });\n }\n i = dest.close + 1;\n continue;\n }\n } else if (after === '[') {\n const refEnd = matchBracket(masked, labelEnd + 1);\n if (refEnd !== -1) {\n const ref = text.slice(labelEnd + 2, refEnd).trim();\n const resolved = ref.length > 0 ? ref : label.trim();\n if (!isImage) {\n out.push({\n text: label.trim(),\n target: resolved,\n start: isImage ? i - 1 : i,\n end: refEnd + 1,\n targetStart: ref.length > 0 ? labelEnd + 2 : i + 1,\n form: 'reference',\n line: index.positionAt(i).line,\n });\n }\n i = refEnd + 1;\n continue;\n }\n } else if (!isImage && definitions.has(label.trim().toLowerCase())) {\n out.push({\n text: label.trim(),\n target: label.trim(),\n start: i,\n end: labelEnd + 1,\n targetStart: i + 1,\n form: 'shortcut',\n line: index.positionAt(i).line,\n });\n i = labelEnd + 1;\n continue;\n }\n\n i = labelEnd + 1;\n }\n\n out.sort((a, b) => a.start - b.start);\n return out;\n}\n\n/** Finds the `]` matching the `[` at `open`, honouring nesting and escapes. */\nfunction matchBracket(text: string, open: number): number {\n let depth = 0;\n const limit = Math.min(text.length, open + MAX_LINK_SPAN);\n for (let i = open; i < limit; i += 1) {\n const ch = text[i];\n if (ch === '\\\\') {\n i += 1;\n continue;\n }\n if (ch === '\\n' && text[i + 1] === '\\n') return -1;\n if (ch === '[') depth += 1;\n else if (ch === ']') {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/** Reads a link destination starting just after `(`. */\nfunction readDestination(text: string, from: number): { start: number; end: number; close: number } | null {\n let i = from;\n const limit = Math.min(text.length, from + MAX_LINK_SPAN);\n while (i < limit && (text[i] === ' ' || text[i] === '\\t' || text[i] === '\\n')) i += 1;\n\n const start = i;\n if (text[i] === '<') {\n const close = text.indexOf('>', i + 1);\n if (close === -1 || close > limit) return null;\n const paren = text.indexOf(')', close);\n if (paren === -1 || paren > limit) return null;\n return { start, end: close + 1, close: paren };\n }\n\n let depth = 0;\n while (i < limit) {\n const ch = text[i];\n if (ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === '(') depth += 1;\n else if (ch === ')') {\n if (depth === 0) break;\n depth -= 1;\n } else if (ch === ' ' || ch === '\\t' || ch === '\\n') break;\n i += 1;\n }\n const end = i;\n // Skip an optional title, then require the closing paren.\n let j = i;\n while (j < limit && text[j] !== ')') {\n if (text[j] === '\\n' && text[j + 1] === '\\n') return null;\n j += 1;\n }\n if (j >= limit || text[j] !== ')') return null;\n if (end === start) return null;\n return { start, end, close: j };\n}\n\nfunction unwrapAngle(value: string): string {\n return value.startsWith('<') && value.endsWith('>') ? value.slice(1, -1) : value;\n}\n\n/** `[[0007-thing|Display]]` and `[[0007-thing]]` both target `0007-thing`. */\nfunction wikiTarget(raw: string): string {\n const pipe = raw.indexOf('|');\n return (pipe === -1 ? raw : raw.slice(0, pipe)).trim();\n}\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * POSIX path arithmetic, independent of the host platform.
3
+ *
4
+ * Every path inside spec-graph is a repository-relative POSIX path, on Windows
5
+ * as much as on Linux. Node's `path` module would happily produce
6
+ * `docs\adr\0007.md` on one machine and `docs/adr/0007.md` on another, and a
7
+ * graph whose node identities depend on which laptop built it is not a graph.
8
+ */
9
+ /** Converts a host path to POSIX form. */
10
+ export declare function toPosix(value: string): string;
11
+ /** Removes `.` and `..` segments. Leading `..` are preserved. */
12
+ export declare function normalisePosix(value: string): string;
13
+ /** The directory containing `value`, or `''` at the root. */
14
+ export declare function dirnamePosix(value: string): string;
15
+ /** The final segment of `value`. */
16
+ export declare function basenamePosix(value: string): string;
17
+ /** Joins segments and normalises the result. */
18
+ export declare function joinPosix(...segments: readonly string[]): string;
19
+ /** Resolves `target` against the directory holding `from`. */
20
+ export declare function resolveFrom(from: string, target: string): string;
21
+ /** The extension including the dot, lower-cased, or `''`. */
22
+ export declare function extnamePosix(value: string): string;
package/dist/paths.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * POSIX path arithmetic, independent of the host platform.
3
+ *
4
+ * Every path inside spec-graph is a repository-relative POSIX path, on Windows
5
+ * as much as on Linux. Node's `path` module would happily produce
6
+ * `docs\adr\0007.md` on one machine and `docs/adr/0007.md` on another, and a
7
+ * graph whose node identities depend on which laptop built it is not a graph.
8
+ */
9
+ /** Converts a host path to POSIX form. */
10
+ export function toPosix(value) {
11
+ return value.replace(/\\/g, '/');
12
+ }
13
+ /** Removes `.` and `..` segments. Leading `..` are preserved. */
14
+ export function normalisePosix(value) {
15
+ const absolute = value.startsWith('/');
16
+ const out = [];
17
+ for (const segment of value.split('/')) {
18
+ if (segment === '' || segment === '.')
19
+ continue;
20
+ if (segment === '..') {
21
+ const last = out[out.length - 1];
22
+ if (out.length > 0 && last !== '..')
23
+ out.pop();
24
+ else if (!absolute)
25
+ out.push('..');
26
+ continue;
27
+ }
28
+ out.push(segment);
29
+ }
30
+ const joined = out.join('/');
31
+ return absolute ? `/${joined}` : joined;
32
+ }
33
+ /** The directory containing `value`, or `''` at the root. */
34
+ export function dirnamePosix(value) {
35
+ const slash = value.lastIndexOf('/');
36
+ return slash === -1 ? '' : value.slice(0, slash);
37
+ }
38
+ /** The final segment of `value`. */
39
+ export function basenamePosix(value) {
40
+ return value.slice(value.lastIndexOf('/') + 1);
41
+ }
42
+ /** Joins segments and normalises the result. */
43
+ export function joinPosix(...segments) {
44
+ return normalisePosix(segments.filter((segment) => segment.length > 0).join('/'));
45
+ }
46
+ /** Resolves `target` against the directory holding `from`. */
47
+ export function resolveFrom(from, target) {
48
+ if (target.startsWith('/'))
49
+ return normalisePosix(target);
50
+ return joinPosix(dirnamePosix(from), target);
51
+ }
52
+ /** The extension including the dot, lower-cased, or `''`. */
53
+ export function extnamePosix(value) {
54
+ const base = basenamePosix(value);
55
+ const dot = base.lastIndexOf('.');
56
+ return dot <= 0 ? '' : base.slice(dot).toLowerCase();
57
+ }
58
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0CAA0C;AAC1C,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACnC,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG;YAAE,SAAS;QAChD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACjC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,IAAI;gBAAE,GAAG,CAAC,GAAG,EAAE,CAAC;iBAC1C,IAAI,CAAC,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AAC1C,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACrC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,SAAS,CAAC,GAAG,QAA2B;IACtD,OAAO,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,MAAc;IACtD,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;IAC1D,OAAO,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AACvD,CAAC","sourcesContent":["/**\n * POSIX path arithmetic, independent of the host platform.\n *\n * Every path inside spec-graph is a repository-relative POSIX path, on Windows\n * as much as on Linux. Node's `path` module would happily produce\n * `docs\\adr\\0007.md` on one machine and `docs/adr/0007.md` on another, and a\n * graph whose node identities depend on which laptop built it is not a graph.\n */\n\n/** Converts a host path to POSIX form. */\nexport function toPosix(value: string): string {\n return value.replace(/\\\\/g, '/');\n}\n\n/** Removes `.` and `..` segments. Leading `..` are preserved. */\nexport function normalisePosix(value: string): string {\n const absolute = value.startsWith('/');\n const out: string[] = [];\n for (const segment of value.split('/')) {\n if (segment === '' || segment === '.') continue;\n if (segment === '..') {\n const last = out[out.length - 1];\n if (out.length > 0 && last !== '..') out.pop();\n else if (!absolute) out.push('..');\n continue;\n }\n out.push(segment);\n }\n const joined = out.join('/');\n return absolute ? `/${joined}` : joined;\n}\n\n/** The directory containing `value`, or `''` at the root. */\nexport function dirnamePosix(value: string): string {\n const slash = value.lastIndexOf('/');\n return slash === -1 ? '' : value.slice(0, slash);\n}\n\n/** The final segment of `value`. */\nexport function basenamePosix(value: string): string {\n return value.slice(value.lastIndexOf('/') + 1);\n}\n\n/** Joins segments and normalises the result. */\nexport function joinPosix(...segments: readonly string[]): string {\n return normalisePosix(segments.filter((segment) => segment.length > 0).join('/'));\n}\n\n/** Resolves `target` against the directory holding `from`. */\nexport function resolveFrom(from: string, target: string): string {\n if (target.startsWith('/')) return normalisePosix(target);\n return joinPosix(dirnamePosix(from), target);\n}\n\n/** The extension including the dot, lower-cased, or `''`. */\nexport function extnamePosix(value: string): string {\n const base = basenamePosix(value);\n const dot = base.lastIndexOf('.');\n return dot <= 0 ? '' : base.slice(dot).toLowerCase();\n}\n"]}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Output formatting.
3
+ *
4
+ * Two audiences, one set of facts. In a terminal the report leads with the file
5
+ * and line so an editor can jump there, indents the supporting evidence, and
6
+ * ends with a concrete next action - because a finding a reader cannot act on
7
+ * is a finding they will learn to scroll past. In CI it emits JSON with every
8
+ * position intact, so a bot can annotate a diff.
9
+ *
10
+ * Colour is opt-out and auto-detected, and the glyphs degrade to ASCII when the
11
+ * terminal cannot render them.
12
+ */
13
+ import type { SpecGraph } from './graph.js';
14
+ import type { AnalysisResult } from './runner.js';
15
+ import type { RuleId } from './types.js';
16
+ export interface ReporterOptions {
17
+ readonly color?: boolean | undefined;
18
+ readonly ascii?: boolean | undefined;
19
+ readonly verbose?: boolean | undefined;
20
+ /** Stop after this many findings. `0` means no limit. */
21
+ readonly max?: number | undefined;
22
+ /**
23
+ * Rules whose severity `--strict` raised.
24
+ *
25
+ * A finding that only became an error because of a flag has to say so, or the
26
+ * reader cannot tell what would happen without it.
27
+ */
28
+ readonly escalated?: ReadonlySet<RuleId> | undefined;
29
+ /**
30
+ * What a baseline accounted for on this run.
31
+ *
32
+ * Reported as counts rather than as a list: the point of accepted debt is
33
+ * that nobody has to read it every time. `stale` is the ratchet - debt that
34
+ * has been paid and can be struck from the file.
35
+ */
36
+ readonly baseline?: {
37
+ readonly source: string;
38
+ readonly suppressed: number;
39
+ readonly stale: number;
40
+ } | undefined;
41
+ }
42
+ export interface ColorEnvironment {
43
+ readonly isTTY?: boolean | undefined;
44
+ readonly env?: Readonly<Record<string, string | undefined>> | undefined;
45
+ /**
46
+ * Host platform, defaulting to the real one.
47
+ *
48
+ * Injected for the same reason `env` is: without it half of
49
+ * {@link shouldUseAscii} is unreachable from a test, and a rule about
50
+ * Windows consoles that only Windows can exercise is a rule that breaks on
51
+ * Windows and nowhere else.
52
+ */
53
+ readonly platform?: NodeJS.Platform | undefined;
54
+ }
55
+ /** Honours `NO_COLOR`, `FORCE_COLOR` and `TERM=dumb` before falling back to TTY. */
56
+ export declare function shouldUseColor(environment?: ColorEnvironment): boolean;
57
+ /** True when the terminal is unlikely to render box-drawing and arrows. */
58
+ export declare function shouldUseAscii(environment?: ColorEnvironment): boolean;
59
+ type Paint = (text: string) => string;
60
+ export interface Painter {
61
+ readonly error: Paint;
62
+ readonly warn: Paint;
63
+ readonly info: Paint;
64
+ readonly dim: Paint;
65
+ readonly bold: Paint;
66
+ readonly hint: Paint;
67
+ readonly location: Paint;
68
+ }
69
+ export declare function createPainter(color: boolean): Painter;
70
+ /** Renders the full terminal report. */
71
+ export declare function formatReport(result: AnalysisResult, options?: ReporterOptions): string;
72
+ /**
73
+ * The machine-readable report.
74
+ *
75
+ * Deliberately flat and versioned: this is the contract a CI annotator or a
76
+ * dashboard builds against, and it must be safe to add fields to it later.
77
+ */
78
+ export declare function formatJson(result: AnalysisResult, options?: {
79
+ escalated?: ReadonlySet<RuleId>;
80
+ baseline?: ReporterOptions['baseline'];
81
+ }): string;
82
+ export type GraphFormat = 'dot' | 'mermaid' | 'json';
83
+ export interface GraphExportOptions {
84
+ /** Leave out `contains` edges and item nodes. */
85
+ readonly documentsOnly?: boolean | undefined;
86
+ }
87
+ /** Serialises the graph for Graphviz, Mermaid, or a downstream tool. */
88
+ export declare function formatGraph(graph: SpecGraph, format: GraphFormat, options?: GraphExportOptions): string;
89
+ export {};
package/dist/report.js ADDED
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Output formatting.
3
+ *
4
+ * Two audiences, one set of facts. In a terminal the report leads with the file
5
+ * and line so an editor can jump there, indents the supporting evidence, and
6
+ * ends with a concrete next action - because a finding a reader cannot act on
7
+ * is a finding they will learn to scroll past. In CI it emits JSON with every
8
+ * position intact, so a bot can annotate a diff.
9
+ *
10
+ * Colour is opt-out and auto-detected, and the glyphs degrade to ASCII when the
11
+ * terminal cannot render them.
12
+ */
13
+ import { formatRef } from './source.js';
14
+ /** Honours `NO_COLOR`, `FORCE_COLOR` and `TERM=dumb` before falling back to TTY. */
15
+ export function shouldUseColor(environment = {}) {
16
+ const env = environment.env ?? process.env;
17
+ if (env['NO_COLOR'] !== undefined && env['NO_COLOR'] !== '')
18
+ return false;
19
+ // `FORCE_COLOR=0` is the conventional way to turn colour off, so it has to
20
+ // win over an attached TTY rather than merely failing to force it on.
21
+ if (env['FORCE_COLOR'] === '0')
22
+ return false;
23
+ if (env['FORCE_COLOR'] !== undefined && env['FORCE_COLOR'] !== '')
24
+ return true;
25
+ if (env['TERM'] === 'dumb')
26
+ return false;
27
+ if (env['CI'] !== undefined && env['CI'] !== '')
28
+ return false;
29
+ return environment.isTTY === true;
30
+ }
31
+ /** True when the terminal is unlikely to render box-drawing and arrows. */
32
+ export function shouldUseAscii(environment = {}) {
33
+ const env = environment.env ?? process.env;
34
+ if (env['SPEC_GRAPH_ASCII'] !== undefined && env['SPEC_GRAPH_ASCII'] !== '')
35
+ return true;
36
+ if ((environment.platform ?? process.platform) !== 'win32')
37
+ return false;
38
+ // Windows Terminal and modern shells set these; the legacy console does not.
39
+ return env['WT_SESSION'] === undefined && env['TERM_PROGRAM'] === undefined;
40
+ }
41
+ const EMPTY_RULES = new Set();
42
+ export function createPainter(color) {
43
+ const wrap = (open) => (text) => (color ? `\u001b[${open}m${text}\u001b[0m` : text);
44
+ return {
45
+ error: wrap('31'),
46
+ warn: wrap('33'),
47
+ info: wrap('36'),
48
+ dim: wrap('2'),
49
+ bold: wrap('1'),
50
+ hint: wrap('32'),
51
+ location: wrap('4'),
52
+ };
53
+ }
54
+ function glyphs(ascii) {
55
+ return ascii
56
+ ? { error: 'x', warn: '!', info: 'i', related: '|', hint: '>', separator: '-' }
57
+ : { error: '\u2716', warn: '\u26a0', info: '\u2139', related: '\u21b3', hint: '\u2192', separator: '\u00b7' };
58
+ }
59
+ /* -------------------------------------------------------------------------- */
60
+ /* Human report */
61
+ /* -------------------------------------------------------------------------- */
62
+ /** Renders the full terminal report. */
63
+ export function formatReport(result, options = {}) {
64
+ const paint = createPainter(options.color ?? false);
65
+ const marks = glyphs(options.ascii ?? false);
66
+ const lines = [];
67
+ const { summary } = result;
68
+ lines.push(`${paint.bold('spec-graph')} ${paint.dim([
69
+ `${summary.documents} ${plural(summary.documents, 'document')}`,
70
+ `${summary.items} ${plural(summary.items, 'item')}`,
71
+ `${summary.edges} ${plural(summary.edges, 'relation')}`,
72
+ `${summary.openObligations} open`,
73
+ ].join(` ${marks.separator} `))}`);
74
+ lines.push('');
75
+ const limit = options.max && options.max > 0 ? options.max : result.diagnostics.length;
76
+ const shown = result.diagnostics.slice(0, limit);
77
+ const escalated = options.escalated ?? EMPTY_RULES;
78
+ for (const diagnostic of shown) {
79
+ lines.push(...formatDiagnostic(diagnostic, paint, marks, escalated));
80
+ lines.push('');
81
+ }
82
+ if (result.diagnostics.length > shown.length) {
83
+ lines.push(paint.dim(` ... and ${result.diagnostics.length - shown.length} more`));
84
+ lines.push('');
85
+ }
86
+ if (options.verbose && result.problems.length > 0) {
87
+ for (const problem of result.problems) {
88
+ lines.push(`${paint.warn(marks.warn)} ${paint.location(formatRef(problem.at))} ${problem.message}`);
89
+ }
90
+ lines.push('');
91
+ }
92
+ const tally = [];
93
+ if (summary.errors > 0)
94
+ tally.push(paint.error(`${summary.errors} ${plural(summary.errors, 'error')}`));
95
+ if (summary.warnings > 0)
96
+ tally.push(paint.warn(`${summary.warnings} ${plural(summary.warnings, 'warning')}`));
97
+ if (summary.infos > 0)
98
+ tally.push(paint.info(`${summary.infos} ${plural(summary.infos, 'note')}`));
99
+ tally.push(paint.dim(`${summary.durationMs}ms`));
100
+ const raised = result.diagnostics.filter((diagnostic) => escalated.has(diagnostic.rule)).length;
101
+ if (raised > 0) {
102
+ tally.push(paint.warn(`${raised} raised by --strict`));
103
+ }
104
+ const baseline = options.baseline;
105
+ if (baseline !== undefined && baseline.suppressed > 0) {
106
+ tally.push(paint.dim(`${baseline.suppressed} accepted by ${baseline.source}`));
107
+ }
108
+ lines.push(tally.join(` ${marks.separator} `));
109
+ if (baseline !== undefined && baseline.stale > 0) {
110
+ lines.push(paint.dim(`${baseline.stale} baseline ${plural(baseline.stale, 'entry', 'entries')} no longer ${baseline.stale === 1 ? 'occurs' : 'occur'} - tighten it: spec-graph check --record-baseline ${baseline.source}`));
111
+ }
112
+ lines.push(result.ok
113
+ ? `${paint.hint(marks.hint === '>' ? 'ok' : '\u2714')} ${summary.errors + summary.warnings === 0
114
+ ? 'the specification graph is consistent'
115
+ : 'no errors - the specification graph holds'}`
116
+ : `${paint.error(marks.error)} the specification graph is inconsistent`);
117
+ return lines.join('\n');
118
+ }
119
+ function formatDiagnostic(diagnostic, paint, marks, escalated) {
120
+ const mark = severityMark(diagnostic.severity, paint, marks);
121
+ const label = escalated.has(diagnostic.rule)
122
+ ? `${diagnostic.rule} ${paint.warn('(strict: warn -> error)')}`
123
+ : diagnostic.rule;
124
+ const lines = [
125
+ `${mark} ${paint.location(formatRef(diagnostic.at))} ${paint.dim(label)}`,
126
+ ` ${diagnostic.message}`,
127
+ ];
128
+ const width = Math.max(0, ...diagnostic.related.map((entry) => formatRef(entry.at).length));
129
+ for (const entry of diagnostic.related) {
130
+ const reference = formatRef(entry.at);
131
+ lines.push(` ${paint.dim(marks.related)} ${paint.dim(reference.padEnd(width))} ${paint.dim(entry.note)}`);
132
+ }
133
+ lines.push(` ${paint.hint(marks.hint)} ${paint.hint(diagnostic.hint)}`);
134
+ return lines;
135
+ }
136
+ function severityMark(severity, paint, marks) {
137
+ switch (severity) {
138
+ case 'error':
139
+ return paint.error(marks.error);
140
+ case 'warn':
141
+ return paint.warn(marks.warn);
142
+ case 'info':
143
+ return paint.info(marks.info);
144
+ }
145
+ }
146
+ function plural(count, word, plural) {
147
+ if (count === 1)
148
+ return word;
149
+ return plural ?? `${word}s`;
150
+ }
151
+ /* -------------------------------------------------------------------------- */
152
+ /* JSON */
153
+ /* -------------------------------------------------------------------------- */
154
+ /**
155
+ * The machine-readable report.
156
+ *
157
+ * Deliberately flat and versioned: this is the contract a CI annotator or a
158
+ * dashboard builds against, and it must be safe to add fields to it later.
159
+ */
160
+ export function formatJson(result, options = {}) {
161
+ const escalated = options.escalated ?? EMPTY_RULES;
162
+ return `${JSON.stringify({
163
+ version: 1,
164
+ ok: result.ok,
165
+ strict: escalated.size > 0,
166
+ ...(options.baseline === undefined ? {} : { baseline: options.baseline }),
167
+ summary: result.summary,
168
+ files: result.files,
169
+ diagnostics: result.diagnostics.map((diagnostic) => ({
170
+ rule: diagnostic.rule,
171
+ severity: diagnostic.severity,
172
+ // True when this finding is only an error because of --strict.
173
+ escalated: escalated.has(diagnostic.rule),
174
+ message: diagnostic.message,
175
+ hint: diagnostic.hint,
176
+ nodes: diagnostic.nodes,
177
+ target: diagnostic.target,
178
+ file: diagnostic.at.file,
179
+ line: diagnostic.at.span.start.line,
180
+ column: diagnostic.at.span.start.column,
181
+ endLine: diagnostic.at.span.end.line,
182
+ endColumn: diagnostic.at.span.end.column,
183
+ related: diagnostic.related.map((entry) => ({
184
+ file: entry.at.file,
185
+ line: entry.at.span.start.line,
186
+ column: entry.at.span.start.column,
187
+ note: entry.note,
188
+ })),
189
+ })),
190
+ problems: result.problems.map((problem) => ({
191
+ message: problem.message,
192
+ file: problem.at.file,
193
+ line: problem.at.span.start.line,
194
+ })),
195
+ }, null, 2)}\n`;
196
+ }
197
+ /** Serialises the graph for Graphviz, Mermaid, or a downstream tool. */
198
+ export function formatGraph(graph, format, options = {}) {
199
+ const skipItems = options.documentsOnly ?? false;
200
+ const nodes = [...graph.nodes.values()].filter((node) => !skipItems || node.kind === 'document');
201
+ const visible = new Set(nodes.map((node) => node.id));
202
+ // Hiding items must not hide what they say. An obligation delegated from an
203
+ // item to a document is lifted onto the item's owner, so the document-level
204
+ // view still shows the handover rather than silently losing it.
205
+ const lifted = skipItems
206
+ ? dedupeEdges(graph.edges
207
+ // Containment of an *item* is what hiding items makes redundant.
208
+ // Containment of a specification by the register that holds it is
209
+ // structure between documents, and is what this view exists to show.
210
+ .filter((edge) => edge.kind !== 'contains' || visible.has(edge.to))
211
+ .map((edge) => {
212
+ const from = graph.owningDocument(edge.from)?.id ?? edge.from;
213
+ const to = graph.owningDocument(edge.to)?.id ?? edge.to;
214
+ return from === edge.from && to === edge.to ? edge : { ...edge, from, to, reflexive: from === to };
215
+ })
216
+ .filter((edge) => !edge.reflexive))
217
+ : graph.edges;
218
+ const edges = lifted.filter((edge) => visible.has(edge.from) && visible.has(edge.to));
219
+ switch (format) {
220
+ case 'dot':
221
+ return toDot(nodes, edges);
222
+ case 'mermaid':
223
+ return toMermaid(nodes, edges);
224
+ case 'json':
225
+ return `${JSON.stringify({
226
+ version: 1,
227
+ nodes: nodes.map(serialiseNode),
228
+ edges: edges.map((edge) => ({
229
+ kind: edge.kind,
230
+ from: edge.from,
231
+ to: edge.to,
232
+ origin: edge.origin,
233
+ declaredIn: edge.declaredIn,
234
+ file: edge.declaredAt.file,
235
+ line: edge.declaredAt.span.start.line,
236
+ })),
237
+ }, null, 2)}\n`;
238
+ }
239
+ }
240
+ /** Collapses duplicate relations produced by lifting item edges onto documents. */
241
+ function dedupeEdges(edges) {
242
+ const seen = new Set();
243
+ const out = [];
244
+ for (const edge of edges) {
245
+ const key = `${edge.kind} ${edge.from} ${edge.to}`;
246
+ if (seen.has(key))
247
+ continue;
248
+ seen.add(key);
249
+ out.push(edge);
250
+ }
251
+ return out;
252
+ }
253
+ function serialiseNode(node) {
254
+ const base = {
255
+ id: node.id,
256
+ kind: node.kind,
257
+ title: node.title,
258
+ file: node.at.file,
259
+ line: node.at.span.start.line,
260
+ };
261
+ return node.kind === 'document'
262
+ ? { ...base, path: node.path, phase: node.phase, status: node.rawStatus, aliases: node.aliases }
263
+ : {
264
+ ...base,
265
+ document: node.document,
266
+ section: node.section,
267
+ disposition: node.disposition,
268
+ openness: node.openness,
269
+ };
270
+ }
271
+ /** Phase colours, chosen to stay legible in both light and dark renderings. */
272
+ const PHASE_FILL = {
273
+ draft: '#e8f0fe',
274
+ active: '#e6f4ea',
275
+ frozen: '#e8eaed',
276
+ retired: '#fce8e6',
277
+ record: '#f3e8fd',
278
+ unknown: '#ffffff',
279
+ };
280
+ function toDot(nodes, edges) {
281
+ const lines = ['digraph spec {', ' rankdir=LR;', ' node [shape=box, style="rounded,filled", fontname="sans"];'];
282
+ for (const node of nodes) {
283
+ const fill = node.kind === 'document' ? (PHASE_FILL[node.phase] ?? '#ffffff') : '#fffbe6';
284
+ const label = node.kind === 'document' ? `${node.id}\\n${escapeDot(node.title)}` : escapeDot(node.text);
285
+ const shape = node.kind === 'document' ? 'box' : 'note';
286
+ lines.push(` "${escapeDot(node.id)}" [label="${label}", fillcolor="${fill}", shape=${shape}];`);
287
+ }
288
+ for (const edge of edges) {
289
+ const style = edge.kind === 'contains' ? ', style=dotted' : '';
290
+ lines.push(` "${escapeDot(edge.from)}" -> "${escapeDot(edge.to)}" [label="${edge.kind}"${style}];`);
291
+ }
292
+ lines.push('}');
293
+ return `${lines.join('\n')}\n`;
294
+ }
295
+ function toMermaid(nodes, edges) {
296
+ const lines = ['graph LR'];
297
+ const alias = new Map();
298
+ nodes.forEach((node, position) => alias.set(node.id, `n${position}`));
299
+ for (const node of nodes) {
300
+ const key = alias.get(node.id);
301
+ const label = escapeMermaid(node.kind === 'document' ? node.id : node.text);
302
+ lines.push(node.kind === 'document' ? ` ${key}["${label}"]` : ` ${key}(["${label}"])`);
303
+ if (node.kind === 'document' && node.phase !== 'unknown')
304
+ lines.push(` class ${key} ${node.phase};`);
305
+ }
306
+ for (const edge of edges) {
307
+ const from = alias.get(edge.from);
308
+ const to = alias.get(edge.to);
309
+ if (!from || !to)
310
+ continue;
311
+ lines.push(` ${from} -->|${edge.kind}| ${to}`);
312
+ }
313
+ for (const [phase, fill] of Object.entries(PHASE_FILL)) {
314
+ if (phase === 'unknown')
315
+ continue;
316
+ lines.push(` classDef ${phase} fill:${fill},stroke:#5f6368;`);
317
+ }
318
+ return `${lines.join('\n')}\n`;
319
+ }
320
+ function escapeDot(value) {
321
+ return value.replace(/["\\]/g, '\\$&').replace(/\n/g, '\\n');
322
+ }
323
+ function escapeMermaid(value) {
324
+ return value.replace(/["#]/g, ' ').replace(/\s+/g, ' ').trim();
325
+ }
326
+ //# sourceMappingURL=report.js.map