@hawkeyexl/manni 4.4.0 → 4.5.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 (169) hide show
  1. package/README.md +1 -1
  2. package/dist/{batch-DFRCLY77.js → batch-GOE3UXOD.js} +11 -11
  3. package/dist/{build-Q5C6SX5J.js → build-M7BMEHL2.js} +13 -11
  4. package/dist/{calibrate-XQILKXS3.js → calibrate-6RRAILUY.js} +12 -12
  5. package/dist/{capture-JQMOC3BW.js → capture-RJPQ6B4N.js} +12 -12
  6. package/dist/{check-NFZQLJKN.js → check-BQD64X3N.js} +11 -11
  7. package/dist/{check-HYNGXYJV.js → check-ESNS7ZBC.js} +4 -4
  8. package/dist/{check-U54XV6BP.js → check-RQIIIURI.js} +12 -12
  9. package/dist/{chunk-7QMCHA4N.js → chunk-3R5Y3XOL.js} +3 -3
  10. package/dist/{chunk-K3D6FPV6.js → chunk-3YHAYXBC.js} +2 -2
  11. package/dist/{chunk-JVTNMVYU.js → chunk-527HHQPS.js} +4 -4
  12. package/dist/{chunk-JVTNMVYU.js.map → chunk-527HHQPS.js.map} +1 -1
  13. package/dist/{chunk-6OYEI2VV.js → chunk-52PDIZKV.js} +3 -3
  14. package/dist/{chunk-UZC7LDAQ.js → chunk-6XTQDFGP.js} +2 -2
  15. package/dist/{chunk-UZC7LDAQ.js.map → chunk-6XTQDFGP.js.map} +1 -1
  16. package/dist/{chunk-NWZ2SLYL.js → chunk-7OQAU4EA.js} +5 -5
  17. package/dist/{chunk-5YXBLLAC.js → chunk-7ZUCEMCY.js} +8 -8
  18. package/dist/{chunk-M2JCK5F6.js → chunk-B7XUEQF3.js} +13 -2
  19. package/dist/chunk-B7XUEQF3.js.map +1 -0
  20. package/dist/{chunk-MYMBCTDE.js → chunk-BOIF2XGG.js} +2 -2
  21. package/dist/{chunk-H6FZ66XR.js → chunk-C3KI45RF.js} +8 -6
  22. package/dist/{chunk-H6FZ66XR.js.map → chunk-C3KI45RF.js.map} +1 -1
  23. package/dist/{chunk-3AFUD75K.js → chunk-C6HZ6C5T.js} +2 -2
  24. package/dist/{chunk-XYLUCIKQ.js → chunk-CP4ZM43V.js} +2 -2
  25. package/dist/chunk-DE7JSWXV.js +2462 -0
  26. package/dist/chunk-DE7JSWXV.js.map +1 -0
  27. package/dist/{chunk-YTCZRLTU.js → chunk-DX32P2DT.js} +2 -2
  28. package/dist/{chunk-644JVKJ4.js → chunk-EL2BZTDL.js} +137 -50
  29. package/dist/chunk-EL2BZTDL.js.map +1 -0
  30. package/dist/{chunk-JOHKIAVH.js → chunk-ELZ2IIOF.js} +332 -2522
  31. package/dist/chunk-ELZ2IIOF.js.map +1 -0
  32. package/dist/{chunk-OBFENF3U.js → chunk-F2OVHJNC.js} +10 -10
  33. package/dist/{chunk-5KHIFVD2.js → chunk-FLF6AECQ.js} +7 -7
  34. package/dist/{chunk-77HX34KD.js → chunk-GAZFKZHM.js} +4 -4
  35. package/dist/{chunk-KCGV52AM.js → chunk-HQFVJDEN.js} +7 -7
  36. package/dist/{chunk-RLR4TKUZ.js → chunk-HVFR66GQ.js} +2 -2
  37. package/dist/{chunk-2U3ORT6D.js → chunk-IA7BMIPE.js} +2 -2
  38. package/dist/{chunk-LAKAWRV5.js → chunk-JQU7FHYH.js} +6 -6
  39. package/dist/{chunk-YIL4XLLJ.js → chunk-K3U5F2QT.js} +183 -31
  40. package/dist/chunk-K3U5F2QT.js.map +1 -0
  41. package/dist/{chunk-X3BPBDGQ.js → chunk-MZC62HPZ.js} +2 -2
  42. package/dist/{chunk-V46OILVC.js → chunk-NAZRLJAK.js} +3 -3
  43. package/dist/{chunk-BUXDLRDT.js → chunk-NGK3N6F2.js} +3 -3
  44. package/dist/{chunk-WQE54PNH.js → chunk-NN4ASVTY.js} +3 -3
  45. package/dist/{chunk-PCHZY2I7.js → chunk-OIZ3XMKB.js} +13 -11
  46. package/dist/chunk-OIZ3XMKB.js.map +1 -0
  47. package/dist/{chunk-CYWHFSRT.js → chunk-QCBICNKC.js} +6 -6
  48. package/dist/chunk-QCBICNKC.js.map +1 -0
  49. package/dist/{chunk-YFQBFNQS.js → chunk-QLUMKWQQ.js} +3 -3
  50. package/dist/{chunk-YYBFZLAJ.js → chunk-QY3DOZMS.js} +4 -4
  51. package/dist/{chunk-IEQHSCZG.js → chunk-SJO2FTPG.js} +6 -6
  52. package/dist/{chunk-ERMSO34F.js → chunk-SNEHX4VE.js} +2 -2
  53. package/dist/{chunk-252LNOEG.js → chunk-TA42STP7.js} +4 -4
  54. package/dist/{chunk-CK7SKVHR.js → chunk-TBAMBLF3.js} +3 -12
  55. package/dist/chunk-TBAMBLF3.js.map +1 -0
  56. package/dist/{chunk-C6OH6CNF.js → chunk-TCC737IS.js} +3 -3
  57. package/dist/{chunk-H2DLH2JI.js → chunk-TVIX653Q.js} +3 -3
  58. package/dist/{chunk-G7NJSREW.js → chunk-UK2I3ACY.js} +3 -3
  59. package/dist/{chunk-XSLV76YK.js → chunk-XWFNO5PO.js} +3 -3
  60. package/dist/{chunk-PHF3D7ER.js → chunk-YA63PVWI.js} +5 -5
  61. package/dist/chunk-YGFIQ6Y5.js +17 -0
  62. package/dist/chunk-YGFIQ6Y5.js.map +1 -0
  63. package/dist/{chunk-MYC3O5EJ.js → chunk-ZX43SRZR.js} +3 -3
  64. package/dist/{cli-URZQXL4K.js → cli-6PGVHP7Y.js} +15 -15
  65. package/dist/{cli-2QPR2OZG.js → cli-AAG3N4NB.js} +16 -16
  66. package/dist/{cli-4IOPGZHR.js → cli-E3H6ZP4I.js} +2 -2
  67. package/dist/{cli-OFPZ5MAS.js → cli-HUIMNJT6.js} +20 -15
  68. package/dist/cli-HUIMNJT6.js.map +1 -0
  69. package/dist/{cli-LJLLIQB2.js → cli-MHTYPVOD.js} +16 -16
  70. package/dist/{cli-5FL73WHA.js → cli-PRZHQ3QB.js} +15 -13
  71. package/dist/{cli-5FL73WHA.js.map → cli-PRZHQ3QB.js.map} +1 -1
  72. package/dist/{cli-SRHFUZHA.js → cli-QKIJOXGW.js} +13 -13
  73. package/dist/{cli-C262QOWM.js → cli-TYGOHJOJ.js} +25 -25
  74. package/dist/{cli-SHSMSRQY.js → cli-YW6VWBHX.js} +9 -9
  75. package/dist/cli.js +11 -11
  76. package/dist/docmeta.js +8 -8
  77. package/dist/{github-QXL3VMK2.js → github-3WMSTNTK.js} +13 -13
  78. package/dist/{github-FE6KCNYJ.js → github-OXSJQ4PS.js} +11 -11
  79. package/dist/index.d.ts +30 -8
  80. package/dist/index.js +42 -38
  81. package/dist/index.js.map +1 -1
  82. package/dist/{json-SGZ6ZRFD.js → json-4DCKDGUV.js} +11 -11
  83. package/dist/lint-YDHVVZHT.js +30 -0
  84. package/dist/{list-7BKNYPSB.js → list-3ZO2NIYO.js} +11 -11
  85. package/dist/{list-6BAXTZUM.js → list-EJH6VAOW.js} +11 -11
  86. package/dist/{page-3U2GCFNE.js → page-QEDB7EVU.js} +10 -10
  87. package/dist/{pretty-N6DO4OOL.js → pretty-5DGEBZSV.js} +11 -11
  88. package/dist/{pretty-2H57QVTY.js → pretty-SQX33UM2.js} +12 -12
  89. package/dist/{reporters-N6GHXSS7.js → reporters-OHSI3RMV.js} +12 -11
  90. package/dist/{reporters-UCNEV7PH.js → reporters-YELDDYJD.js} +4 -4
  91. package/dist/{run-XZDAREJE.js → run-IP6NZHAG.js} +11 -11
  92. package/dist/{term-5ICGKPC3.js → term-2WMDZ4PY.js} +15 -15
  93. package/dist/{validate-GQRM77YN.js → validate-G6HH3YXL.js} +5 -5
  94. package/package.json +1 -1
  95. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  96. package/plugin/manni/hooks/hooks.json +21 -4
  97. package/plugin/manni/hooks/manni.mjs +157 -0
  98. package/plugin/manni/skills/check/SKILL.md +3 -3
  99. package/plugin/manni/skills/evals/SKILL.md +2 -2
  100. package/plugin/manni/skills/fix/SKILL.md +3 -3
  101. package/plugin/manni/skills/setup/SKILL.md +3 -3
  102. package/dist/chunk-644JVKJ4.js.map +0 -1
  103. package/dist/chunk-CK7SKVHR.js.map +0 -1
  104. package/dist/chunk-CYWHFSRT.js.map +0 -1
  105. package/dist/chunk-JOHKIAVH.js.map +0 -1
  106. package/dist/chunk-M2JCK5F6.js.map +0 -1
  107. package/dist/chunk-PCHZY2I7.js.map +0 -1
  108. package/dist/chunk-YIL4XLLJ.js.map +0 -1
  109. package/dist/cli-OFPZ5MAS.js.map +0 -1
  110. package/dist/lint-DL4LJRAY.js +0 -28
  111. /package/dist/{batch-DFRCLY77.js.map → batch-GOE3UXOD.js.map} +0 -0
  112. /package/dist/{build-Q5C6SX5J.js.map → build-M7BMEHL2.js.map} +0 -0
  113. /package/dist/{calibrate-XQILKXS3.js.map → calibrate-6RRAILUY.js.map} +0 -0
  114. /package/dist/{capture-JQMOC3BW.js.map → capture-RJPQ6B4N.js.map} +0 -0
  115. /package/dist/{check-HYNGXYJV.js.map → check-BQD64X3N.js.map} +0 -0
  116. /package/dist/{check-NFZQLJKN.js.map → check-ESNS7ZBC.js.map} +0 -0
  117. /package/dist/{check-U54XV6BP.js.map → check-RQIIIURI.js.map} +0 -0
  118. /package/dist/{chunk-7QMCHA4N.js.map → chunk-3R5Y3XOL.js.map} +0 -0
  119. /package/dist/{chunk-K3D6FPV6.js.map → chunk-3YHAYXBC.js.map} +0 -0
  120. /package/dist/{chunk-6OYEI2VV.js.map → chunk-52PDIZKV.js.map} +0 -0
  121. /package/dist/{chunk-NWZ2SLYL.js.map → chunk-7OQAU4EA.js.map} +0 -0
  122. /package/dist/{chunk-5YXBLLAC.js.map → chunk-7ZUCEMCY.js.map} +0 -0
  123. /package/dist/{chunk-MYMBCTDE.js.map → chunk-BOIF2XGG.js.map} +0 -0
  124. /package/dist/{chunk-3AFUD75K.js.map → chunk-C6HZ6C5T.js.map} +0 -0
  125. /package/dist/{chunk-XYLUCIKQ.js.map → chunk-CP4ZM43V.js.map} +0 -0
  126. /package/dist/{chunk-YTCZRLTU.js.map → chunk-DX32P2DT.js.map} +0 -0
  127. /package/dist/{chunk-OBFENF3U.js.map → chunk-F2OVHJNC.js.map} +0 -0
  128. /package/dist/{chunk-5KHIFVD2.js.map → chunk-FLF6AECQ.js.map} +0 -0
  129. /package/dist/{chunk-77HX34KD.js.map → chunk-GAZFKZHM.js.map} +0 -0
  130. /package/dist/{chunk-KCGV52AM.js.map → chunk-HQFVJDEN.js.map} +0 -0
  131. /package/dist/{chunk-RLR4TKUZ.js.map → chunk-HVFR66GQ.js.map} +0 -0
  132. /package/dist/{chunk-2U3ORT6D.js.map → chunk-IA7BMIPE.js.map} +0 -0
  133. /package/dist/{chunk-LAKAWRV5.js.map → chunk-JQU7FHYH.js.map} +0 -0
  134. /package/dist/{chunk-X3BPBDGQ.js.map → chunk-MZC62HPZ.js.map} +0 -0
  135. /package/dist/{chunk-V46OILVC.js.map → chunk-NAZRLJAK.js.map} +0 -0
  136. /package/dist/{chunk-BUXDLRDT.js.map → chunk-NGK3N6F2.js.map} +0 -0
  137. /package/dist/{chunk-WQE54PNH.js.map → chunk-NN4ASVTY.js.map} +0 -0
  138. /package/dist/{chunk-YFQBFNQS.js.map → chunk-QLUMKWQQ.js.map} +0 -0
  139. /package/dist/{chunk-YYBFZLAJ.js.map → chunk-QY3DOZMS.js.map} +0 -0
  140. /package/dist/{chunk-IEQHSCZG.js.map → chunk-SJO2FTPG.js.map} +0 -0
  141. /package/dist/{chunk-ERMSO34F.js.map → chunk-SNEHX4VE.js.map} +0 -0
  142. /package/dist/{chunk-252LNOEG.js.map → chunk-TA42STP7.js.map} +0 -0
  143. /package/dist/{chunk-C6OH6CNF.js.map → chunk-TCC737IS.js.map} +0 -0
  144. /package/dist/{chunk-H2DLH2JI.js.map → chunk-TVIX653Q.js.map} +0 -0
  145. /package/dist/{chunk-G7NJSREW.js.map → chunk-UK2I3ACY.js.map} +0 -0
  146. /package/dist/{chunk-XSLV76YK.js.map → chunk-XWFNO5PO.js.map} +0 -0
  147. /package/dist/{chunk-PHF3D7ER.js.map → chunk-YA63PVWI.js.map} +0 -0
  148. /package/dist/{chunk-MYC3O5EJ.js.map → chunk-ZX43SRZR.js.map} +0 -0
  149. /package/dist/{cli-URZQXL4K.js.map → cli-6PGVHP7Y.js.map} +0 -0
  150. /package/dist/{cli-2QPR2OZG.js.map → cli-AAG3N4NB.js.map} +0 -0
  151. /package/dist/{cli-4IOPGZHR.js.map → cli-E3H6ZP4I.js.map} +0 -0
  152. /package/dist/{cli-LJLLIQB2.js.map → cli-MHTYPVOD.js.map} +0 -0
  153. /package/dist/{cli-SRHFUZHA.js.map → cli-QKIJOXGW.js.map} +0 -0
  154. /package/dist/{cli-C262QOWM.js.map → cli-TYGOHJOJ.js.map} +0 -0
  155. /package/dist/{cli-SHSMSRQY.js.map → cli-YW6VWBHX.js.map} +0 -0
  156. /package/dist/{github-FE6KCNYJ.js.map → github-3WMSTNTK.js.map} +0 -0
  157. /package/dist/{github-QXL3VMK2.js.map → github-OXSJQ4PS.js.map} +0 -0
  158. /package/dist/{json-SGZ6ZRFD.js.map → json-4DCKDGUV.js.map} +0 -0
  159. /package/dist/{lint-DL4LJRAY.js.map → lint-YDHVVZHT.js.map} +0 -0
  160. /package/dist/{list-6BAXTZUM.js.map → list-3ZO2NIYO.js.map} +0 -0
  161. /package/dist/{list-7BKNYPSB.js.map → list-EJH6VAOW.js.map} +0 -0
  162. /package/dist/{page-3U2GCFNE.js.map → page-QEDB7EVU.js.map} +0 -0
  163. /package/dist/{pretty-2H57QVTY.js.map → pretty-5DGEBZSV.js.map} +0 -0
  164. /package/dist/{pretty-N6DO4OOL.js.map → pretty-SQX33UM2.js.map} +0 -0
  165. /package/dist/{reporters-N6GHXSS7.js.map → reporters-OHSI3RMV.js.map} +0 -0
  166. /package/dist/{reporters-UCNEV7PH.js.map → reporters-YELDDYJD.js.map} +0 -0
  167. /package/dist/{run-XZDAREJE.js.map → run-IP6NZHAG.js.map} +0 -0
  168. /package/dist/{term-5ICGKPC3.js.map → term-2WMDZ4PY.js.map} +0 -0
  169. /package/dist/{validate-GQRM77YN.js.map → validate-G6HH3YXL.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../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 * 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\" };\nimport {\n artifactLocation,\n fileUri,\n normalizeRoot,\n URI_BASE_ID,\n type ArtifactLocation,\n} from \"../../shared/sarif-location.js\";\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\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 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/**\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":["renderJunit","text","i","rows","run","renderJunit"]}
1
+ {"version":3,"sources":["../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 * 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\" };\nimport {\n artifactLocation,\n fileUri,\n normalizeRoot,\n URI_BASE_ID,\n type ArtifactLocation,\n} from \"../../shared/sarif-location.js\";\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\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 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/**\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":["renderJunit","text","i","rows","run","renderJunit"]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  displayPath
4
- } from "./chunk-WQE54PNH.js";
4
+ } from "./chunk-NN4ASVTY.js";
5
5
  import {
6
6
  escapeWorkflowCommandMessage,
7
7
  escapeWorkflowCommandProperty
@@ -20,4 +20,4 @@ function renderFindingsGithub(report) {
20
20
  export {
21
21
  renderFindingsGithub
22
22
  };
23
- //# sourceMappingURL=chunk-3AFUD75K.js.map
23
+ //# sourceMappingURL=chunk-C6HZ6C5T.js.map
@@ -5,7 +5,7 @@ import {
5
5
  listInTree,
6
6
  safeRead,
7
7
  segments
8
- } from "./chunk-7QMCHA4N.js";
8
+ } from "./chunk-3R5Y3XOL.js";
9
9
  import {
10
10
  TracevalsError
11
11
  } from "./chunk-UKZNLVJW.js";
@@ -171,4 +171,4 @@ async function discoverArtifacts(options) {
171
171
  export {
172
172
  discoverArtifacts
173
173
  };
174
- //# sourceMappingURL=chunk-XYLUCIKQ.js.map
174
+ //# sourceMappingURL=chunk-CP4ZM43V.js.map