@hawkeyexl/manni 4.12.4 → 4.13.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 (186) hide show
  1. package/README.md +1 -1
  2. package/dist/{batch-UHLVBMYM.js → batch-OB2FXT47.js} +12 -12
  3. package/dist/{build-4RPXBSAO.js → build-4BL24BG3.js} +13 -13
  4. package/dist/{calibrate-POL5DCJ6.js → calibrate-AEDJ7N7G.js} +13 -13
  5. package/dist/{capture-I7ZYG7NZ.js → capture-TP3P4YNL.js} +12 -12
  6. package/dist/{check-6TEG5TM6.js → check-5IYH42KS.js} +14 -14
  7. package/dist/{check-3O2PZ7TZ.js → check-LU5YC3L4.js} +12 -12
  8. package/dist/{check-V7JUDAPS.js → check-NBN2YK2J.js} +13 -13
  9. package/dist/{check-DGOUTC3V.js → check-S55MH66H.js} +11 -11
  10. package/dist/{chunk-6KONPVHQ.js → chunk-3BVDFQ6Y.js} +2 -2
  11. package/dist/{chunk-JAPSZ44X.js → chunk-3HUCB4Z3.js} +4 -4
  12. package/dist/{chunk-LWMB7JRE.js → chunk-3O6U4ICM.js} +2 -2
  13. package/dist/{chunk-3QUCVYNX.js → chunk-3XGTNN3M.js} +3 -3
  14. package/dist/{chunk-AATCO43N.js → chunk-52WO7ESI.js} +3 -3
  15. package/dist/{chunk-TBAMBLF3.js → chunk-6ZFJWUUH.js} +132 -15
  16. package/dist/chunk-6ZFJWUUH.js.map +1 -0
  17. package/dist/{chunk-7TVIFCGT.js → chunk-7JPL3CUC.js} +2 -2
  18. package/dist/{chunk-RLPWXF5R.js → chunk-7RNONVHI.js} +6 -6
  19. package/dist/{chunk-WWKXPPN5.js → chunk-BMBAAPGN.js} +3 -3
  20. package/dist/{chunk-BGRP44SX.js → chunk-BQXY76JB.js} +4 -4
  21. package/dist/{chunk-N5JSOJY6.js → chunk-CODWRUAD.js} +2 -2
  22. package/dist/{chunk-5OKSFNUV.js → chunk-DQOM3DEU.js} +5 -5
  23. package/dist/{chunk-QUG53QGZ.js → chunk-E6BVUDGY.js} +3 -3
  24. package/dist/{chunk-PSPNIAOP.js → chunk-EQ7E6HMG.js} +8 -8
  25. package/dist/{chunk-7JUIJ7Q5.js → chunk-GWI6JPTT.js} +3 -3
  26. package/dist/{chunk-VXU75N5R.js → chunk-HIEGOW7X.js} +3 -3
  27. package/dist/{chunk-GNUZ37L2.js → chunk-HKTGHLBA.js} +2 -2
  28. package/dist/{chunk-GNUZ37L2.js.map → chunk-HKTGHLBA.js.map} +1 -1
  29. package/dist/{chunk-Y4TDIUG6.js → chunk-HY6ROJTH.js} +2 -2
  30. package/dist/{chunk-PP22XDW2.js → chunk-IGQMBHFY.js} +6 -6
  31. package/dist/{chunk-J4ZOTZII.js → chunk-J5NOWIJ3.js} +6 -6
  32. package/dist/{chunk-XEYS3KAZ.js → chunk-JUL2PRQN.js} +4 -4
  33. package/dist/{chunk-NLELGEKL.js → chunk-KE2F7QES.js} +5 -5
  34. package/dist/{chunk-EBZ4QKKX.js → chunk-LNGSE7V2.js} +2 -2
  35. package/dist/{chunk-EU4HDGG4.js → chunk-LSFXNAHU.js} +7 -7
  36. package/dist/{chunk-SSDSV52B.js → chunk-N6A6DJUO.js} +4 -4
  37. package/dist/{chunk-Z42MO7SO.js → chunk-NSAW7U42.js} +2 -2
  38. package/dist/{chunk-KRKNZ3IV.js → chunk-NTEYYYKL.js} +34 -10
  39. package/dist/chunk-NTEYYYKL.js.map +1 -0
  40. package/dist/{chunk-7QH2ZI4F.js → chunk-NWUXRV6N.js} +52 -27
  41. package/dist/chunk-NWUXRV6N.js.map +1 -0
  42. package/dist/{chunk-QWE3WLV4.js → chunk-OBXCJZ6R.js} +5 -5
  43. package/dist/{chunk-VFL3ERMI.js → chunk-OREHJQNN.js} +2 -2
  44. package/dist/{chunk-DTXLFSAB.js → chunk-OUAH7XF2.js} +2 -2
  45. package/dist/{chunk-ZCJUSQM7.js → chunk-OYIWF3B2.js} +10 -10
  46. package/dist/{chunk-HP43LH7E.js → chunk-PA7CMQGD.js} +2 -2
  47. package/dist/{chunk-5NNPEPVM.js → chunk-PCGBXHSE.js} +3 -3
  48. package/dist/{chunk-TR2XFZPR.js → chunk-QKT67PFE.js} +3 -3
  49. package/dist/{chunk-YGFIQ6Y5.js → chunk-SCLXVTFZ.js} +1 -1
  50. package/dist/{chunk-YGFIQ6Y5.js.map → chunk-SCLXVTFZ.js.map} +1 -1
  51. package/dist/{chunk-PNUM6RHR.js → chunk-TDCOKKMI.js} +3 -3
  52. package/dist/{chunk-X4GQ4HPY.js → chunk-TQ3W6RKG.js} +2 -2
  53. package/dist/{chunk-EX6E2P6Z.js → chunk-ULDV2LUI.js} +2 -2
  54. package/dist/{chunk-XP4RNQZL.js → chunk-UQMLCIRX.js} +242 -15
  55. package/dist/chunk-UQMLCIRX.js.map +1 -0
  56. package/dist/{chunk-KQRYW4DN.js → chunk-VNYXK7TM.js} +3 -3
  57. package/dist/{chunk-3FXPIZXL.js → chunk-VOXOBUTX.js} +2 -2
  58. package/dist/{chunk-4IW6FAUN.js → chunk-VYBYUQIP.js} +7 -7
  59. package/dist/{chunk-4TGIGVFO.js → chunk-WVXCN5DS.js} +4 -4
  60. package/dist/{chunk-J67EOBN3.js → chunk-X4MPUD4B.js} +3 -3
  61. package/dist/{chunk-W7EZJPRX.js → chunk-Y6M4JFKG.js} +3 -3
  62. package/dist/{chunk-U4SY2TJS.js → chunk-YZ4TJLZQ.js} +7 -7
  63. package/dist/{cli-USPQURPP.js → cli-4JHQCPHU.js} +2 -2
  64. package/dist/{cli-UL2IFH3R.js → cli-7DETHSNW.js} +15 -15
  65. package/dist/{cli-4ANSKDPD.js → cli-AZKWTCFV.js} +9 -9
  66. package/dist/{cli-2OQKCKRD.js → cli-BW5VOFOZ.js} +8 -8
  67. package/dist/{cli-5QGP6R63.js → cli-DGFLJ2DD.js} +2 -2
  68. package/dist/{cli-SDTXHLCA.js → cli-ECVT4YXR.js} +16 -16
  69. package/dist/{cli-IE3CYYHA.js → cli-G66X7YMP.js} +54 -15
  70. package/dist/cli-G66X7YMP.js.map +1 -0
  71. package/dist/{cli-2Q5FODAX.js → cli-H5LVGOVT.js} +31 -31
  72. package/dist/{cli-RQRMZKKM.js → cli-KYTCJYXK.js} +16 -16
  73. package/dist/{cli-SGSS6FXE.js → cli-L5B2RVV2.js} +19 -19
  74. package/dist/{cli-RQSCBJJY.js → cli-RP5E7XHC.js} +13 -13
  75. package/dist/cli.js +14 -14
  76. package/dist/docmeta.js +8 -8
  77. package/dist/{github-PBIYRH5S.js → github-DJQ4MWNZ.js} +13 -13
  78. package/dist/{github-RJG2MAWB.js → github-UWTDM2J2.js} +11 -11
  79. package/dist/index.d.ts +76 -4
  80. package/dist/index.js +47 -37
  81. package/dist/index.js.map +1 -1
  82. package/dist/{json-PQURAHQ5.js → json-LCVPMEAM.js} +11 -11
  83. package/dist/{labels-FMLO2URZ.js → labels-OQXBVM4A.js} +10 -10
  84. package/dist/{lint-N2CY66JX.js → lint-O7XRHKFP.js} +13 -13
  85. package/dist/{list-VBFNFEXV.js → list-OOOCLOAL.js} +11 -11
  86. package/dist/{list-OMHTVFDY.js → list-OYQ5XPN2.js} +11 -11
  87. package/dist/{page-X3HYSH6D.js → page-XPX5XJZE.js} +10 -10
  88. package/dist/{prepare-IQMB262G.js → prepare-VMBIQYAM.js} +11 -11
  89. package/dist/{pretty-22PXIEOV.js → pretty-KG6TMOEI.js} +12 -12
  90. package/dist/{pretty-K5BOCKBB.js → pretty-KSTZMBUF.js} +11 -11
  91. package/dist/{reporters-324OWH36.js → reporters-AQU4W3KY.js} +4 -4
  92. package/dist/{reporters-5LIYYE6M.js → reporters-FBYLPKD4.js} +12 -12
  93. package/dist/{run-4EKG6EMI.js → run-KUGTU3TT.js} +11 -11
  94. package/dist/{term-2ADSKGZW.js → term-SI3VM6EM.js} +15 -15
  95. package/dist/{validate-LRYUEZLJ.js → validate-NQO7TFSN.js} +5 -5
  96. package/package.json +1 -1
  97. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  98. package/plugin/manni/skills/fix/SKILL.md +4 -2
  99. package/schemas/lint/template.json +6 -1
  100. package/templates/lint/tgdp/concept.yaml +27 -13
  101. package/templates/lint/tgdp/how-to.yaml +35 -21
  102. package/templates/lint/tgdp/readme.yaml +69 -25
  103. package/templates/lint/tgdp/reference.yaml +44 -31
  104. package/templates/lint/tgdp/release-notes.yaml +48 -19
  105. package/templates/lint/tgdp/troubleshooting.yaml +45 -31
  106. package/templates/lint/tgdp/tutorial.yaml +35 -19
  107. package/dist/chunk-7QH2ZI4F.js.map +0 -1
  108. package/dist/chunk-KRKNZ3IV.js.map +0 -1
  109. package/dist/chunk-TBAMBLF3.js.map +0 -1
  110. package/dist/chunk-XP4RNQZL.js.map +0 -1
  111. package/dist/cli-IE3CYYHA.js.map +0 -1
  112. /package/dist/{batch-UHLVBMYM.js.map → batch-OB2FXT47.js.map} +0 -0
  113. /package/dist/{build-4RPXBSAO.js.map → build-4BL24BG3.js.map} +0 -0
  114. /package/dist/{calibrate-POL5DCJ6.js.map → calibrate-AEDJ7N7G.js.map} +0 -0
  115. /package/dist/{capture-I7ZYG7NZ.js.map → capture-TP3P4YNL.js.map} +0 -0
  116. /package/dist/{check-3O2PZ7TZ.js.map → check-5IYH42KS.js.map} +0 -0
  117. /package/dist/{check-6TEG5TM6.js.map → check-LU5YC3L4.js.map} +0 -0
  118. /package/dist/{check-V7JUDAPS.js.map → check-NBN2YK2J.js.map} +0 -0
  119. /package/dist/{check-DGOUTC3V.js.map → check-S55MH66H.js.map} +0 -0
  120. /package/dist/{chunk-6KONPVHQ.js.map → chunk-3BVDFQ6Y.js.map} +0 -0
  121. /package/dist/{chunk-JAPSZ44X.js.map → chunk-3HUCB4Z3.js.map} +0 -0
  122. /package/dist/{chunk-LWMB7JRE.js.map → chunk-3O6U4ICM.js.map} +0 -0
  123. /package/dist/{chunk-3QUCVYNX.js.map → chunk-3XGTNN3M.js.map} +0 -0
  124. /package/dist/{chunk-AATCO43N.js.map → chunk-52WO7ESI.js.map} +0 -0
  125. /package/dist/{chunk-7TVIFCGT.js.map → chunk-7JPL3CUC.js.map} +0 -0
  126. /package/dist/{chunk-RLPWXF5R.js.map → chunk-7RNONVHI.js.map} +0 -0
  127. /package/dist/{chunk-WWKXPPN5.js.map → chunk-BMBAAPGN.js.map} +0 -0
  128. /package/dist/{chunk-BGRP44SX.js.map → chunk-BQXY76JB.js.map} +0 -0
  129. /package/dist/{chunk-N5JSOJY6.js.map → chunk-CODWRUAD.js.map} +0 -0
  130. /package/dist/{chunk-5OKSFNUV.js.map → chunk-DQOM3DEU.js.map} +0 -0
  131. /package/dist/{chunk-QUG53QGZ.js.map → chunk-E6BVUDGY.js.map} +0 -0
  132. /package/dist/{chunk-PSPNIAOP.js.map → chunk-EQ7E6HMG.js.map} +0 -0
  133. /package/dist/{chunk-7JUIJ7Q5.js.map → chunk-GWI6JPTT.js.map} +0 -0
  134. /package/dist/{chunk-VXU75N5R.js.map → chunk-HIEGOW7X.js.map} +0 -0
  135. /package/dist/{chunk-Y4TDIUG6.js.map → chunk-HY6ROJTH.js.map} +0 -0
  136. /package/dist/{chunk-PP22XDW2.js.map → chunk-IGQMBHFY.js.map} +0 -0
  137. /package/dist/{chunk-J4ZOTZII.js.map → chunk-J5NOWIJ3.js.map} +0 -0
  138. /package/dist/{chunk-XEYS3KAZ.js.map → chunk-JUL2PRQN.js.map} +0 -0
  139. /package/dist/{chunk-NLELGEKL.js.map → chunk-KE2F7QES.js.map} +0 -0
  140. /package/dist/{chunk-EBZ4QKKX.js.map → chunk-LNGSE7V2.js.map} +0 -0
  141. /package/dist/{chunk-EU4HDGG4.js.map → chunk-LSFXNAHU.js.map} +0 -0
  142. /package/dist/{chunk-SSDSV52B.js.map → chunk-N6A6DJUO.js.map} +0 -0
  143. /package/dist/{chunk-Z42MO7SO.js.map → chunk-NSAW7U42.js.map} +0 -0
  144. /package/dist/{chunk-QWE3WLV4.js.map → chunk-OBXCJZ6R.js.map} +0 -0
  145. /package/dist/{chunk-VFL3ERMI.js.map → chunk-OREHJQNN.js.map} +0 -0
  146. /package/dist/{chunk-DTXLFSAB.js.map → chunk-OUAH7XF2.js.map} +0 -0
  147. /package/dist/{chunk-ZCJUSQM7.js.map → chunk-OYIWF3B2.js.map} +0 -0
  148. /package/dist/{chunk-HP43LH7E.js.map → chunk-PA7CMQGD.js.map} +0 -0
  149. /package/dist/{chunk-5NNPEPVM.js.map → chunk-PCGBXHSE.js.map} +0 -0
  150. /package/dist/{chunk-TR2XFZPR.js.map → chunk-QKT67PFE.js.map} +0 -0
  151. /package/dist/{chunk-PNUM6RHR.js.map → chunk-TDCOKKMI.js.map} +0 -0
  152. /package/dist/{chunk-X4GQ4HPY.js.map → chunk-TQ3W6RKG.js.map} +0 -0
  153. /package/dist/{chunk-EX6E2P6Z.js.map → chunk-ULDV2LUI.js.map} +0 -0
  154. /package/dist/{chunk-KQRYW4DN.js.map → chunk-VNYXK7TM.js.map} +0 -0
  155. /package/dist/{chunk-3FXPIZXL.js.map → chunk-VOXOBUTX.js.map} +0 -0
  156. /package/dist/{chunk-4IW6FAUN.js.map → chunk-VYBYUQIP.js.map} +0 -0
  157. /package/dist/{chunk-4TGIGVFO.js.map → chunk-WVXCN5DS.js.map} +0 -0
  158. /package/dist/{chunk-J67EOBN3.js.map → chunk-X4MPUD4B.js.map} +0 -0
  159. /package/dist/{chunk-W7EZJPRX.js.map → chunk-Y6M4JFKG.js.map} +0 -0
  160. /package/dist/{chunk-U4SY2TJS.js.map → chunk-YZ4TJLZQ.js.map} +0 -0
  161. /package/dist/{cli-USPQURPP.js.map → cli-4JHQCPHU.js.map} +0 -0
  162. /package/dist/{cli-UL2IFH3R.js.map → cli-7DETHSNW.js.map} +0 -0
  163. /package/dist/{cli-4ANSKDPD.js.map → cli-AZKWTCFV.js.map} +0 -0
  164. /package/dist/{cli-2OQKCKRD.js.map → cli-BW5VOFOZ.js.map} +0 -0
  165. /package/dist/{cli-5QGP6R63.js.map → cli-DGFLJ2DD.js.map} +0 -0
  166. /package/dist/{cli-SDTXHLCA.js.map → cli-ECVT4YXR.js.map} +0 -0
  167. /package/dist/{cli-2Q5FODAX.js.map → cli-H5LVGOVT.js.map} +0 -0
  168. /package/dist/{cli-RQRMZKKM.js.map → cli-KYTCJYXK.js.map} +0 -0
  169. /package/dist/{cli-SGSS6FXE.js.map → cli-L5B2RVV2.js.map} +0 -0
  170. /package/dist/{cli-RQSCBJJY.js.map → cli-RP5E7XHC.js.map} +0 -0
  171. /package/dist/{github-PBIYRH5S.js.map → github-DJQ4MWNZ.js.map} +0 -0
  172. /package/dist/{github-RJG2MAWB.js.map → github-UWTDM2J2.js.map} +0 -0
  173. /package/dist/{json-PQURAHQ5.js.map → json-LCVPMEAM.js.map} +0 -0
  174. /package/dist/{labels-FMLO2URZ.js.map → labels-OQXBVM4A.js.map} +0 -0
  175. /package/dist/{lint-N2CY66JX.js.map → lint-O7XRHKFP.js.map} +0 -0
  176. /package/dist/{list-OMHTVFDY.js.map → list-OOOCLOAL.js.map} +0 -0
  177. /package/dist/{list-VBFNFEXV.js.map → list-OYQ5XPN2.js.map} +0 -0
  178. /package/dist/{page-X3HYSH6D.js.map → page-XPX5XJZE.js.map} +0 -0
  179. /package/dist/{prepare-IQMB262G.js.map → prepare-VMBIQYAM.js.map} +0 -0
  180. /package/dist/{pretty-22PXIEOV.js.map → pretty-KG6TMOEI.js.map} +0 -0
  181. /package/dist/{pretty-K5BOCKBB.js.map → pretty-KSTZMBUF.js.map} +0 -0
  182. /package/dist/{reporters-324OWH36.js.map → reporters-AQU4W3KY.js.map} +0 -0
  183. /package/dist/{reporters-5LIYYE6M.js.map → reporters-FBYLPKD4.js.map} +0 -0
  184. /package/dist/{run-4EKG6EMI.js.map → run-KUGTU3TT.js.map} +0 -0
  185. /package/dist/{term-2ADSKGZW.js.map → term-SI3VM6EM.js.map} +0 -0
  186. /package/dist/{validate-LRYUEZLJ.js.map → validate-NQO7TFSN.js.map} +0 -0
@@ -1 +0,0 @@
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 +0,0 @@
1
- {"version":3,"sources":["../src/lint/rules/paragraphs.ts","../src/lint/rules/code-blocks.ts","../src/lint/rules/tables.ts","../src/lint/rules/admonitions.ts","../src/lint/rules/images.ts","../src/lint/rules/blockquotes.ts","../src/lint/rules/definition-lists.ts","../src/lint/rules/sequence.ts","../src/lint/rules/elements.ts","../src/lint/rules/contains.ts","../src/lint/rules/lists.ts","../src/lint/rules/index.ts","../src/lint/rules/heading.ts","../src/lint/core/template.ts","../src/lint/core/match.ts"],"sourcesContent":["/**\n * `paragraphs:` - paragraph counts and a per-paragraph pattern.\n *\n * v1 took a cycling `patterns: string[]`; v2 simplifies to one `pattern`\n * every paragraph in the run must match, per proposal 0061's block-rule\n * vocabulary.\n */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n compilePattern,\n paragraphsOf,\n sectionContext,\n type ParagraphsRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the paragraphs a section holds directly. */\nexport function checkParagraphs(\n section: SectionNode,\n rule: ParagraphsRule | undefined,\n): Finding[] {\n return checkParagraphsIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks the paragraphs in any ordered content list.\n *\n * Used for a section's own content, for a list item's `children`, and for one\n * run of a `sequence`. `ctx` says where count findings land and what heading\n * they carry.\n */\nexport function checkParagraphsIn(\n content: ContentNode[],\n rule: ParagraphsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const paragraphs = paragraphsOf(content);\n const findings = checkCount(\n paragraphs.length,\n rule,\n \"paragraph\",\n \"paragraphs_count_error\",\n ctx,\n );\n\n const pattern = rule.pattern;\n if (pattern) {\n const regex = compilePattern(pattern);\n paragraphs.forEach((paragraph, index) => {\n if (!regex.test(paragraph.text)) {\n findings.push({\n type: \"paragraphs_pattern_error\",\n heading: ctx.heading,\n message: `Paragraph ${index + 1} does not match /${pattern}/`,\n position: paragraph.position,\n severity: \"error\",\n });\n }\n });\n }\n\n return findings;\n}\n","/**\n * `codeBlocks:` - code block counts, the language(s) every block must\n * declare, and a `fenceInfo` filter over the info-string tail.\n *\n * `language` reports per offending block (every code block must declare one\n * of the accepted languages), the same way v1 reported nothing about\n * language at all - this is new in v2. `fenceInfo` has no message form of its\n * own in proposal 0061's table, so it narrows which blocks count toward\n * `min`/`max` instead, the way `elements.tag` does.\n */\n\nimport type { CodeNode, ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n codeBlocksOf,\n compilePattern,\n sectionContext,\n type CodeBlocksRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the code blocks a section holds directly. */\nexport function checkCodeBlocks(\n section: SectionNode,\n rule: CodeBlocksRule | undefined,\n): Finding[] {\n return checkCodeBlocksIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks the code blocks in any ordered content list -\n * a section's content, a list item's `children`, or one run of a `sequence`.\n */\nexport function checkCodeBlocksIn(\n content: ContentNode[],\n rule: CodeBlocksRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const codeBlocks = codeBlocksOf(content);\n const counted = rule.fenceInfo\n ? codeBlocks.filter((block) => matchesFenceInfo(block, rule.fenceInfo as string))\n : codeBlocks;\n\n const findings = checkCount(\n counted.length,\n rule,\n \"code block\",\n \"code_blocks_count_error\",\n ctx,\n );\n\n if (rule.language) {\n findings.push(...checkLanguages(codeBlocks, rule.language, ctx));\n }\n\n return findings;\n}\n\nfunction matchesFenceInfo(block: CodeNode, pattern: string): boolean {\n return compilePattern(pattern).test(block.fenceInfo ?? \"\");\n}\n\n/** Every code block in the run must declare one of the accepted languages. */\nfunction checkLanguages(\n codeBlocks: CodeNode[],\n language: string | string[],\n ctx: RuleContext,\n): Finding[] {\n const languages = Array.isArray(language) ? language : [language];\n const only = languages[0];\n if (languages.length === 0 || only === undefined) return [];\n\n const label =\n languages.length === 1\n ? `\"${only}\"`\n : `one of ${languages.map((lang) => `\"${lang}\"`).join(\", \")}`;\n\n const findings: Finding[] = [];\n codeBlocks.forEach((block, index) => {\n if (block.language !== undefined && languages.includes(block.language)) return;\n\n const found = block.language ? `but found \"${block.language}\"` : \"but found no language\";\n findings.push({\n type: \"code_blocks_language_error\",\n heading: ctx.heading,\n message: `Expected code block ${index + 1} to declare ${label}, ${found}`,\n position: block.position,\n severity: \"error\",\n });\n });\n\n return findings;\n}\n","/**\n * `tables:` - table counts and the header cells every table must carry.\n *\n * `columns` is diagnostic, not a count filter: every table in the run counts\n * toward `min`/`max` whether or not its columns match, and a mismatch is\n * reported once per offending table (the same treatment `codeBlocks.language`\n * and `admonitions.variant` get, and unlike `codeBlocks.fenceInfo`, which has\n * no message form and narrows the count instead).\n */\n\nimport type { ContentNode, Finding, SectionNode, TableNode } from \"../types.js\";\nimport {\n checkCount,\n quoteList,\n sectionContext,\n tablesOf,\n type RuleContext,\n type TablesRule,\n} from \"./index.js\";\n\n/** Checks the tables a section holds directly. */\nexport function checkTables(\n section: SectionNode,\n rule: TablesRule | undefined,\n): Finding[] {\n return checkTablesIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the tables in any ordered content list. */\nexport function checkTablesIn(\n content: ContentNode[],\n rule: TablesRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const tables = tablesOf(content);\n const findings = checkCount(tables.length, rule, \"table\", \"tables_count_error\", ctx);\n\n if (rule.columns) {\n for (const table of tables) {\n const actual = headerCells(table);\n if (!sameColumns(actual, rule.columns)) {\n findings.push({\n type: \"tables_columns_error\",\n heading: ctx.heading,\n message: `Expected table columns ${quoteList(rule.columns)}, but found ${quoteList(actual)}`,\n position: table.position,\n severity: \"error\",\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction headerCells(table: TableNode): string[] {\n const header = table.children.find((row) => row.header);\n return header ? header.children.map((cell) => cell.text) : [];\n}\n\nfunction sameColumns(actual: string[], expected: string[]): boolean {\n return actual.length === expected.length && actual.every((cell, index) => cell === expected[index]);\n}\n","/**\n * `admonitions:` - admonition counts and the variant every admonition must\n * carry.\n *\n * `variant` is diagnostic, not a count filter, for the same reason\n * `tables.columns` is: every admonition counts toward `min`/`max` regardless,\n * and a mismatch is reported once per offending admonition.\n */\n\nimport type { AdmonitionNode, ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n admonitionsOf,\n checkCount,\n sectionContext,\n type AdmonitionsRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the admonitions a section holds directly. */\nexport function checkAdmonitions(\n section: SectionNode,\n rule: AdmonitionsRule | undefined,\n): Finding[] {\n return checkAdmonitionsIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the admonitions in any ordered content list. */\nexport function checkAdmonitionsIn(\n content: ContentNode[],\n rule: AdmonitionsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const admonitions = admonitionsOf(content);\n const findings = checkCount(\n admonitions.length,\n rule,\n \"admonition\",\n \"admonitions_count_error\",\n ctx,\n );\n\n if (rule.variant) {\n findings.push(...checkVariant(admonitions, rule.variant, ctx));\n }\n\n return findings;\n}\n\nfunction checkVariant(\n admonitions: AdmonitionNode[],\n variant: NonNullable<AdmonitionsRule[\"variant\"]>,\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n for (const admonition of admonitions) {\n if (admonition.variant !== variant) {\n // A format may name a flavor this vocabulary does not have, or none at\n // all: reStructuredText's `hint`, a bare HTML `<aside>`. The node then\n // carries no variant, and saying \"found a undefined\" would be worse\n // than saying what is true.\n const found = admonition.variant\n ? `but found a ${admonition.variant}`\n : \"but found one with no type\";\n findings.push({\n type: \"admonitions_variant_error\",\n heading: ctx.heading,\n message: `Expected a ${variant} admonition, ${found}`,\n position: admonition.position,\n severity: \"error\",\n });\n }\n }\n return findings;\n}\n","/**\n * `images:` - how many images, filtered by `url`, `alt`, and `attributes`.\n *\n * All three narrow the counted set rather than reporting their own finding -\n * proposal 0061's message table gives `images` only `images_count_error`, no\n * per-field diagnostic the way `elements.attributes` gets one. `attributes`\n * in particular can never match: `ImageNode` carries no `attributes` of its\n * own (the node model gave that field to `element` only), so any non-empty\n * `attributes` requirement here excludes every image, same as an image whose\n * `url` or `alt` does not match.\n */\n\nimport type { ContentNode, Finding, ImageNode, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n imagesOf,\n sectionContext,\n type ImagesRule,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the images a section holds directly. */\nexport function checkImages(\n section: SectionNode,\n rule: ImagesRule | undefined,\n): Finding[] {\n return checkImagesIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the images in any ordered content list. */\nexport function checkImagesIn(\n content: ContentNode[],\n rule: ImagesRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const matching = imagesOf(content).filter((image) => matches(image, rule));\n return checkCount(matching.length, rule, \"image\", \"images_count_error\", ctx);\n}\n\nfunction matches(image: ImageNode, rule: ImagesRule): boolean {\n if (rule.url !== undefined && image.url !== rule.url) return false;\n if (rule.alt !== undefined && image.alt !== rule.alt) return false;\n if (rule.attributes && Object.keys(rule.attributes).length > 0) return false;\n return true;\n}\n","/** `blockquotes:` - a plain count, the schema's `counted` shape. */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport { blockquotesOf, checkCount, sectionContext, type Occurrences, type RuleContext } from \"./index.js\";\n\n/** Checks the blockquotes a section holds directly. */\nexport function checkBlockquotes(\n section: SectionNode,\n rule: Occurrences | undefined,\n): Finding[] {\n return checkBlockquotesIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the blockquotes in any ordered content list. */\nexport function checkBlockquotesIn(\n content: ContentNode[],\n rule: Occurrences | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n return checkCount(blockquotesOf(content).length, rule, \"blockquote\", \"blockquotes_count_error\", ctx);\n}\n","/** `definitionLists:` - a plain count, the schema's `counted` shape. */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n definitionListsOf,\n sectionContext,\n type Occurrences,\n type RuleContext,\n} from \"./index.js\";\n\n/** Checks the definition lists a section holds directly. */\nexport function checkDefinitionLists(\n section: SectionNode,\n rule: Occurrences | undefined,\n): Finding[] {\n return checkDefinitionListsIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the definition lists in any ordered content list. */\nexport function checkDefinitionListsIn(\n content: ContentNode[],\n rule: Occurrences | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n return checkCount(\n definitionListsOf(content).length,\n rule,\n \"definition list\",\n \"definition_lists_count_error\",\n ctx,\n );\n}\n","/**\n * `sequence:` - the ordered runs of content a section (or an element's or\n * list item's own content) must hold.\n *\n * Content arrives flat and in document order, so consecutive nodes of the\n * same kind are first grouped into runs: `[p, p, code, table]` becomes three\n * runs (paragraph, codeBlock, table). Those runs are then matched\n * positionally against the template's sequence, and each run is handed to\n * `checkContainsIn` for its one set key.\n *\n * v1 reported a length mismatch and an order mismatch as two finding types,\n * `sequence_length_error` and `sequence_order_error`. v2 collapses both into\n * one `content_order_error`: the message states the full expected and actual\n * kind lists, which communicates a length difference as plainly as an order\n * one, and a template widening from three kinds to nine does not need a\n * matching widening of finding types. The bail-on-mismatch behavior stays -\n * once the runs are the wrong shape, per-run findings are noise about\n * content the author has not arranged yet.\n */\n\nimport type { ContentKind, ContentNode, Finding, Position, SectionNode } from \"../types.js\";\nimport { BLOCK_KINDS, sectionContext, type BlockKind, type BlockRule, type RuleContext } from \"./index.js\";\nimport { checkContainsIn } from \"./contains.js\";\n\n/** A maximal stretch of consecutive content nodes sharing one kind. */\nexport interface ContentRun {\n kind: ContentKind;\n nodes: ContentNode[];\n /** First node's start through last node's end. */\n position: Position;\n}\n\n/** Groups consecutive same-kind nodes into runs, preserving document order. */\nexport function groupRuns(content: ContentNode[]): ContentRun[] {\n const runs: ContentRun[] = [];\n\n for (const node of content) {\n const current = runs[runs.length - 1];\n if (current && current.kind === node.kind) {\n current.nodes.push(node);\n current.position = {\n start: current.position.start,\n end: node.position.end,\n };\n } else {\n runs.push({\n kind: node.kind,\n nodes: [node],\n position: { start: node.position.start, end: node.position.end },\n });\n }\n }\n\n return runs;\n}\n\n/** The content kind a block-rule key names, e.g. `codeBlocks` -> `codeBlock`. */\nconst KIND_OF_BLOCK: Record<BlockKind, ContentKind> = {\n paragraphs: \"paragraph\",\n codeBlocks: \"codeBlock\",\n lists: \"list\",\n tables: \"table\",\n admonitions: \"admonition\",\n images: \"image\",\n blockquotes: \"blockquote\",\n definitionLists: \"definitionList\",\n elements: \"element\",\n};\n\n/** The short noun a `content_order_error` message uses for one kind. */\nfunction sequenceLabel(kind: ContentKind): string {\n switch (kind) {\n case \"paragraph\":\n return \"paragraph\";\n case \"codeBlock\":\n return \"code\";\n case \"list\":\n return \"list\";\n case \"table\":\n return \"table\";\n case \"admonition\":\n return \"admonition\";\n case \"image\":\n return \"image\";\n case \"blockquote\":\n return \"blockquote\";\n case \"definitionList\":\n return \"definition list\";\n case \"element\":\n return \"element\";\n default:\n // tableRow/tableCell/definitionItem/listItem never appear as a top-level\n // ContentNode.kind; groupRuns only ever sees the nine kinds above.\n return kind;\n }\n}\n\n/** The one key set on a `sequence:` entry, or `null` for a malformed one. */\nfunction keyOf(entry: BlockRule): BlockKind | null {\n for (const kind of BLOCK_KINDS) {\n if (entry[kind] !== undefined) return kind;\n }\n return null;\n}\n\n/** Checks a section's own content against a `sequence:` rule. */\nexport function checkSequence(\n section: SectionNode,\n rule: BlockRule[] | undefined,\n): Finding[] {\n return checkSequenceIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks any ordered content list against a `sequence:`\n * rule - a section's content, a list item's `children`, or an element's own\n * `children`.\n */\nexport function checkSequenceIn(\n content: ContentNode[],\n rule: BlockRule[] | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const runs = groupRuns(content);\n const expectedKinds = rule.map((entry) => {\n const key = keyOf(entry);\n return key ? KIND_OF_BLOCK[key] : null;\n });\n const actualKinds = runs.map((run) => run.kind);\n\n const matches =\n expectedKinds.length === actualKinds.length &&\n expectedKinds.every((kind, index) => kind === actualKinds[index]);\n\n if (!matches) {\n const expected = expectedKinds.map((kind) => (kind ? sequenceLabel(kind) : \"?\"));\n const found = actualKinds.length > 0 ? actualKinds.map(sequenceLabel) : [\"nothing\"];\n return [\n {\n type: \"content_order_error\",\n heading: ctx.heading,\n message: `Expected ${expected.join(\" then \")}, but found ${found.join(\" then \")}`,\n position: ctx.position,\n severity: \"error\",\n },\n ];\n }\n\n const findings: Finding[] = [];\n runs.forEach((run, index) => {\n const entry = rule[index];\n if (!entry) return;\n const runCtx: RuleContext = { heading: ctx.heading, position: run.position };\n // A run holds one kind, so `checkContainsIn` sees exactly the nodes in\n // this stretch, not the section's other content of the same kind - the\n // entry has only that one key set, so every other dispatch is a no-op.\n findings.push(...checkContainsIn(run.nodes, entry, runCtx));\n });\n\n return findings;\n}\n","/**\n * `elements:` - named-wrapper counts, filtered and labeled by `tag`, the\n * literal `attributes` a matched element must carry, and what it holds via\n * `sequence` | `contains` recursing into the element's own `children` -\n * never the enclosing section's, per proposal 0065 stress test 4.\n *\n * `tag` narrows the counted set the way `codeBlocks.fenceInfo` and\n * `images.url`/`alt` do, and also names the noun in count messages: `elements:\n * { tag: \"Steps\", min: 1 }` reports `Expected at least 1 \"Steps\" element, but\n * found 0`, not the generic `\"element\"`. `attributes` is diagnostic instead,\n * checked per matched element and reported once per offending attribute.\n */\n\nimport type { ContentNode, ElementNode, Finding, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n elementsOf,\n sectionContext,\n type AttributesRule,\n type ElementsRule,\n type RuleContext,\n} from \"./index.js\";\nimport { checkContainsIn } from \"./contains.js\";\nimport { checkSequenceIn } from \"./sequence.js\";\n\n/** Checks the elements a section holds directly. */\nexport function checkElements(\n section: SectionNode,\n rule: ElementsRule | undefined,\n): Finding[] {\n return checkElementsIn(section.children, rule, sectionContext(section));\n}\n\n/** The reusable core: checks the elements in any ordered content list. */\nexport function checkElementsIn(\n content: ContentNode[],\n rule: ElementsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const tags = rule.tag === undefined ? undefined : Array.isArray(rule.tag) ? rule.tag : [rule.tag];\n const matching = tags ? elementsOf(content).filter((element) => tags.includes(element.name)) : elementsOf(content);\n\n // \"or\", not a comma list: the count applies to one combined label, so\n // `\"Note\", \"Tip\" element` reads as two nouns with a singular verb where\n // `\"Note\" or \"Tip\" element` reads as the one thing being counted.\n const noun = tags\n ? `${tags.map((tag) => `\"${tag}\"`).join(\" or \")} element`\n : \"element\";\n const findings = checkCount(matching.length, rule, noun, \"elements_count_error\", ctx);\n\n if (rule.attributes) {\n for (const element of matching) {\n findings.push(...checkAttributes(element, rule.attributes, ctx));\n }\n }\n\n // Both, unconditionally, as `validator.ts` runs them against a section. Each\n // no-ops on an absent rule, and the schema refuses a rule that writes both\n // (`oneOfSequenceOrContains`), so only one can ever fire. Writing it as a\n // choice made this file's behaviour depend on a constraint declared in\n // another, which reads like a silent drop whether or not it is one.\n if (rule.sequence || rule.contains) {\n for (const element of matching) {\n const elementCtx: RuleContext = { heading: ctx.heading, position: element.position };\n findings.push(...checkSequenceIn(element.children, rule.sequence, elementCtx));\n findings.push(...checkContainsIn(element.children, rule.contains, elementCtx));\n }\n }\n\n return findings;\n}\n\n/**\n * `true` requires presence (any value); `false` requires absence; a string\n * is the required literal value. An element's own `attributes` map values a\n * dynamic (JSX-expression) attribute as `true` too, since its literal value\n * cannot be known statically - `checkOne` tells that apart from \"absent\" by\n * checking membership before comparing values.\n */\nfunction checkAttributes(\n element: ElementNode,\n rule: AttributesRule,\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n for (const [key, expected] of Object.entries(rule)) {\n const finding = checkOne(element, key, expected, ctx);\n if (finding) findings.push(finding);\n }\n return findings;\n}\n\nfunction checkOne(\n element: ElementNode,\n key: string,\n expected: string | boolean,\n ctx: RuleContext,\n): Finding | null {\n const attributes = element.attributes ?? {};\n const present = key in attributes;\n const actual = attributes[key];\n\n const fail = (want: string, detail: string): Finding => ({\n type: \"elements_attribute_error\",\n heading: ctx.heading,\n message: `Expected the \"${element.name}\" element ${want}, but ${detail}`,\n position: element.position,\n severity: \"error\",\n });\n\n if (expected === false) {\n if (!present) return null;\n const found = actual === true ? `an expression` : `${key}=\"${String(actual)}\"`;\n return fail(`not to carry ${key}`, `found ${found}`);\n }\n\n if (!present) return fail(attributeWant(key, expected), `it carries no ${key}`);\n if (expected === true) return null;\n if (actual === true) return fail(attributeWant(key, expected), `its ${key} is an expression`);\n if (actual !== expected) return fail(attributeWant(key, expected), `found ${key}=\"${String(actual)}\"`);\n return null;\n}\n\nfunction attributeWant(key: string, expected: string | true): string {\n return expected === true ? `to carry ${key}` : `to carry ${key}=\"${expected}\"`;\n}\n","/**\n * `contains:` - what a section (or an element's or list item's own content)\n * holds, in any order. Each listed kind dispatches to that kind's own check.\n */\n\nimport type { ContentNode, Finding, SectionNode } from \"../types.js\";\nimport { BLOCK_KINDS, sectionContext, type BlockRule, type RuleContext } from \"./index.js\";\nimport { checkParagraphsIn } from \"./paragraphs.js\";\nimport { checkCodeBlocksIn } from \"./code-blocks.js\";\nimport { checkListsIn } from \"./lists.js\";\nimport { checkTablesIn } from \"./tables.js\";\nimport { checkAdmonitionsIn } from \"./admonitions.js\";\nimport { checkImagesIn } from \"./images.js\";\nimport { checkBlockquotesIn } from \"./blockquotes.js\";\nimport { checkDefinitionListsIn } from \"./definition-lists.js\";\nimport { checkElementsIn } from \"./elements.js\";\n\n/** Checks a section's own content against a `contains:` rule. */\nexport function checkContains(\n section: SectionNode,\n rule: BlockRule | undefined,\n): Finding[] {\n return checkContainsIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks any ordered content list against a `contains:`\n * rule - a section's content, a list item's `children`, an element's own\n * `children`, or one run of a `sequence` (which carries exactly one key).\n *\n * `BLOCK_KINDS` drives the dispatch so a ninth kind is one line here, not a\n * rewritten `if` chain.\n */\nexport function checkContainsIn(\n content: ContentNode[],\n rule: BlockRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const findings: Finding[] = [];\n for (const kind of BLOCK_KINDS) {\n switch (kind) {\n case \"paragraphs\":\n findings.push(...checkParagraphsIn(content, rule.paragraphs, ctx));\n break;\n case \"codeBlocks\":\n findings.push(...checkCodeBlocksIn(content, rule.codeBlocks, ctx));\n break;\n case \"lists\":\n findings.push(...checkListsIn(content, rule.lists, ctx));\n break;\n case \"tables\":\n findings.push(...checkTablesIn(content, rule.tables, ctx));\n break;\n case \"admonitions\":\n findings.push(...checkAdmonitionsIn(content, rule.admonitions, ctx));\n break;\n case \"images\":\n findings.push(...checkImagesIn(content, rule.images, ctx));\n break;\n case \"blockquotes\":\n findings.push(...checkBlockquotesIn(content, rule.blockquotes, ctx));\n break;\n case \"definitionLists\":\n findings.push(...checkDefinitionListsIn(content, rule.definitionLists, ctx));\n break;\n case \"elements\":\n findings.push(...checkElementsIn(content, rule.elements, ctx));\n break;\n }\n }\n return findings;\n}\n","/**\n * `lists:` - list counts, whether they are ordered, item counts, and what\n * each item holds.\n *\n * v1's `items` took its own flat `paragraphs`/`code_blocks`/`lists` keys. v2\n * replaces that split with the same `sequence` | `contains` every other\n * container uses (proposal 0061), so item-level rules recurse through the\n * same two functions as everything else instead of a third, list-shaped one.\n */\n\nimport type { ContentNode, Finding, ListNode, SectionNode } from \"../types.js\";\nimport {\n checkCount,\n listsOf,\n sectionContext,\n type ListsRule,\n type RuleContext,\n} from \"./index.js\";\nimport { checkContainsIn } from \"./contains.js\";\nimport { checkSequenceIn } from \"./sequence.js\";\n\n/** Checks the lists a section holds directly. */\nexport function checkLists(\n section: SectionNode,\n rule: ListsRule | undefined,\n): Finding[] {\n return checkListsIn(section.children, rule, sectionContext(section));\n}\n\n/**\n * The reusable core: checks the lists in any ordered content list.\n *\n * `rule.items` recurses - a list item's children are a `ContentNode[]` like\n * any other, so item-level `sequence`/`contains` rules run through the same\n * functions, arbitrarily deep.\n */\nexport function checkListsIn(\n content: ContentNode[],\n rule: ListsRule | undefined,\n ctx: RuleContext,\n): Finding[] {\n if (!rule) return [];\n\n const lists = listsOf(content);\n const findings = checkCount(lists.length, rule, \"list\", \"lists_count_error\", ctx);\n\n if (rule.ordered !== undefined) {\n findings.push(...checkOrdered(lists, rule.ordered, ctx));\n }\n\n const items = rule.items;\n if (!items) return findings;\n\n findings.push(...checkItemCounts(lists, items, ctx));\n\n if (!items.sequence && !items.contains) return findings;\n\n for (const list of lists) {\n for (const item of list.items) {\n const itemCtx: RuleContext = { heading: ctx.heading, position: item.position };\n if (items.sequence) {\n findings.push(...checkSequenceIn(item.children, items.sequence, itemCtx));\n } else if (items.contains) {\n findings.push(...checkContainsIn(item.children, items.contains, itemCtx));\n }\n }\n }\n\n return findings;\n}\n\nfunction checkOrdered(lists: ListNode[], ordered: boolean, ctx: RuleContext): Finding[] {\n const findings: Finding[] = [];\n for (const list of lists) {\n if (list.ordered !== ordered) {\n findings.push({\n type: \"lists_ordered_error\",\n heading: ctx.heading,\n message: ordered\n ? \"Expected a numbered list, but found a bulleted list\"\n : \"Expected a bulleted list, but found a numbered list\",\n position: list.position,\n severity: \"error\",\n });\n }\n }\n return findings;\n}\n\n/**\n * Item counts report once per bound, anchored at the first list that breaks\n * it. `min` defaults to 1 like every other count, which is a harmless no-op\n * here: a list always has at least one item structurally, so only an\n * explicit `min` above 1 (or a rule that also forbids via `max`) ever fires.\n */\nfunction checkItemCounts(\n lists: ListNode[],\n items: { min?: number; max?: number },\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n const min = items.min ?? (items.max === 0 ? 0 : 1);\n const max = items.max ?? null;\n\n if (max !== null) {\n const offender = lists.find((list) => list.items.length > max);\n if (offender) {\n findings.push({\n type: \"lists_items_count_error\",\n heading: ctx.heading,\n message: `Expected at most ${max} items in a list, but found ${offender.items.length}`,\n position: offender.position,\n severity: \"error\",\n });\n }\n }\n\n if (min > 0) {\n const offender = lists.find((list) => list.items.length < min);\n if (offender) {\n findings.push({\n type: \"lists_items_count_error\",\n heading: ctx.heading,\n message: `Expected at least ${min} items in a list, but found ${offender.items.length}`,\n position: offender.position,\n severity: \"error\",\n });\n }\n }\n\n return findings;\n}\n","/**\n * Content rules: the checks that run against a single section's own content.\n *\n * A rule is a pure, synchronous function of one `SectionNode` (or one ordered\n * `ContentNode[]` slice of it) and its slice of a template, returning\n * `Finding[]`. Rules never touch a parser AST and never await anything.\n *\n * The content model is format-neutral and flat: a section carries one ordered\n * `children: ContentNode[]`, and the per-kind \"buckets\" every rule needs are\n * queries over it (`paragraphsOf`, `codeBlocksOf`, ...) rather than separately\n * maintained arrays. The same queries work unchanged on a list item's\n * `children` or an element's own `children`, which is why `lists.items` and\n * `elements` can recurse.\n *\n * This module is deliberately independent of `../core/template.ts`. That file\n * is the DSL the v2 loader and schema agree on; this one is the DSL the rules\n * are written against. Where the two diverge - see `CodeBlocksRule.language`\n * and `ElementsRule.tag` below, which this chunk's task widened to `string |\n * string[]` while `core/template.ts` still types them as a bare `string` -\n * the validator chunk that wires the two together needs to reconcile it. That\n * mirrors the v1 shape of this file, whose own rule interfaces mirrored\n * `template-v1.ts` rather than importing it.\n */\n\nimport { LintError } from \"../types.js\";\nimport type {\n AdmonitionNode,\n BlockquoteNode,\n CodeNode,\n ContentNode,\n DefinitionListNode,\n ElementNode,\n Finding,\n ImageNode,\n ListNode,\n ParagraphNode,\n Position,\n SectionNode,\n TableNode,\n} from \"../types.js\";\n\n/* -------------------------------------------------------------------------- *\n * Template rule shapes\n *\n * These mirror the v2 template DSL's block-rule vocabulary (proposal 0065 /\n * 0061): a block rule is keyed by a plural content kind and carries `min`\n * (default 1), `max` (absent unbounded, `0` forbids), plus per-kind keys.\n * -------------------------------------------------------------------------- */\n\n/** Shared by every counted rule: how many of the thing there must be. */\nexport interface Occurrences {\n /** Fewest occurrences. Absent means one - see `checkCount` for the one\n * exception, where an explicit `max: 0` with no `min` defaults `min` to 0\n * too, so \"forbid this kind\" is satisfiable by finding none of it. */\n min?: number;\n /** Most occurrences. Absent is unbounded; `0` forbids. */\n max?: number;\n}\n\n/**\n * What a rule's `heading` may say.\n *\n * `undefined` (the key absent) matches any heading or none. A string is exact\n * text, a list is one-of, `{ pattern }` is an unanchored regular expression,\n * and `false` means the section has no heading of its own.\n */\nexport type HeadingRule = string | string[] | { pattern: string } | false;\n\n/** Attributes a node must carry. `true` requires presence; `false` requires absence. */\nexport type AttributesRule = Record<string, string | boolean>;\n\n/** `paragraphs:` - how many paragraphs, and what they must look like. */\nexport interface ParagraphsRule extends Occurrences {\n /** Unanchored regular expression every paragraph in the run must match. */\n pattern?: string;\n}\n\n/** `codeBlocks:` - how many code blocks, and how they are tagged. */\nexport interface CodeBlocksRule extends Occurrences {\n /** Language(s) every code block must declare one of. */\n language?: string | string[];\n /** Info-string tail after the language; narrows which blocks count. */\n fenceInfo?: string;\n}\n\n/** `lists.items:` - how many items per list, and what each item holds. */\nexport interface ListItemsRule extends Occurrences {\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/** `lists:` - how many lists, whether they are ordered, and item rules. */\nexport interface ListsRule extends Occurrences {\n ordered?: boolean;\n items?: ListItemsRule;\n}\n\n/** `tables:` - how many tables, and the header cells in order. */\nexport interface TablesRule extends Occurrences {\n columns?: string[];\n}\n\n/** `admonitions:` - how many, and of which variant. */\nexport interface AdmonitionsRule extends Occurrences {\n variant?: \"note\" | \"tip\" | \"important\" | \"caution\" | \"warning\" | \"danger\";\n}\n\n/** `images:` - how many, and what they point at. */\nexport interface ImagesRule extends Occurrences {\n /** Narrows which images count: only images at this url are counted. */\n url?: string;\n /** Narrows which images count: only images with this alt text are counted. */\n alt?: string;\n /**\n * Narrows which images count. `ImageNode` carries no `attributes` of its\n * own (the node model gave that field to `element` only), so any non-empty\n * requirement here matches no image - see `images.ts`.\n */\n attributes?: AttributesRule;\n}\n\n/** `elements:` - how many named wrappers, and what they hold. */\nexport interface ElementsRule extends Occurrences {\n /** Narrows which elements count, and names the noun in count messages. */\n tag?: string | string[];\n attributes?: AttributesRule;\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/**\n * What a section (or an element's or list item's own content) holds, keyed by\n * content kind.\n *\n * One of these is a whole `contains:`. As an entry of `sequence:` exactly one\n * key is set, and it names the kind expected at that position.\n */\nexport interface BlockRule {\n paragraphs?: ParagraphsRule;\n codeBlocks?: CodeBlocksRule;\n lists?: ListsRule;\n tables?: TablesRule;\n admonitions?: AdmonitionsRule;\n images?: ImagesRule;\n blockquotes?: Occurrences;\n definitionLists?: Occurrences;\n elements?: ElementsRule;\n}\n\n/** `sequence:` - the ordered runs of content a section must contain. */\nexport type SequenceRule = BlockRule[];\n\n/** One block-rule key: a content kind, spelled plural. */\nexport type BlockKind = keyof BlockRule;\n\n/** Every block-rule key, in the order the schema declares them. */\nexport const BLOCK_KINDS: readonly BlockKind[] = [\n \"paragraphs\",\n \"codeBlocks\",\n \"lists\",\n \"tables\",\n \"admonitions\",\n \"images\",\n \"blockquotes\",\n \"definitionLists\",\n \"elements\",\n];\n\n/* -------------------------------------------------------------------------- *\n * Finding anchoring\n * -------------------------------------------------------------------------- */\n\n/**\n * Where findings land when a rule runs over content that is not a whole\n * section - a list item's `children`, an element's `children`, or one run\n * inside a `sequence`.\n */\nexport interface RuleContext {\n /** Stamped onto every finding as `Finding.heading`. */\n heading: string | null;\n /** Used when the offending thing is a count rather than a single node. */\n position: Position;\n}\n\n/**\n * The context for rules run against a section's own content.\n *\n * The heading is normalised to `null` when there is none, as `match.ts` and\n * `validator.ts` both do. A headless section carries `title: \"\"`, and the JSON\n * reporter's `heading` is a wire key `manni docevals` parses rather than\n * validates, so `\"\"` and `null` would reach it as two spellings of one fact.\n */\nexport function sectionContext(section: SectionNode): RuleContext {\n return { heading: section.title || null, position: section.position };\n}\n\n/* -------------------------------------------------------------------------- *\n * Content queries\n *\n * The single place the flat content array is bucketed by kind. Rules call\n * these; they never filter inline.\n * -------------------------------------------------------------------------- */\n\nexport function paragraphsOf(content: ContentNode[]): ParagraphNode[] {\n return content.filter((node): node is ParagraphNode => node.kind === \"paragraph\");\n}\n\nexport function codeBlocksOf(content: ContentNode[]): CodeNode[] {\n return content.filter((node): node is CodeNode => node.kind === \"codeBlock\");\n}\n\nexport function listsOf(content: ContentNode[]): ListNode[] {\n return content.filter((node): node is ListNode => node.kind === \"list\");\n}\n\nexport function tablesOf(content: ContentNode[]): TableNode[] {\n return content.filter((node): node is TableNode => node.kind === \"table\");\n}\n\nexport function admonitionsOf(content: ContentNode[]): AdmonitionNode[] {\n return content.filter((node): node is AdmonitionNode => node.kind === \"admonition\");\n}\n\nexport function imagesOf(content: ContentNode[]): ImageNode[] {\n return content.filter((node): node is ImageNode => node.kind === \"image\");\n}\n\nexport function blockquotesOf(content: ContentNode[]): BlockquoteNode[] {\n return content.filter((node): node is BlockquoteNode => node.kind === \"blockquote\");\n}\n\nexport function definitionListsOf(content: ContentNode[]): DefinitionListNode[] {\n return content.filter((node): node is DefinitionListNode => node.kind === \"definitionList\");\n}\n\nexport function elementsOf(content: ContentNode[]): ElementNode[] {\n return content.filter((node): node is ElementNode => node.kind === \"element\");\n}\n\n/* -------------------------------------------------------------------------- *\n * Shared message helpers\n * -------------------------------------------------------------------------- */\n\n/** `\"paragraph\"`/1 -> `\"paragraph\"`; `\"paragraph\"`/2 -> `\"paragraphs\"`. */\nfunction plural(noun: string, count: number): string {\n return count === 1 ? noun : `${noun}s`;\n}\n\n/** `[\"Field\", \"Type\"]` -> `\"Field\", \"Type\"`. */\nexport function quoteList(items: string[]): string {\n return items.map((item) => `\"${item}\"`).join(\", \");\n}\n\n/**\n * The count half of every block rule: `min` (default 1) and `max` (default\n * unbounded), against one already-computed count.\n *\n * One default is not the naive `rule.min ?? 1`. The schema documents `max: 0`\n * as how a template forbids a kind outright, and that has to be satisfiable\n * by a section that truly has none of it. A blanket \"min defaults to 1\" would\n * make `{ max: 0 }` alone unsatisfiable - it would demand at least one and\n * permit at most zero. So `min` defaults to 0 exactly when `max` is written\n * as `0` and `min` itself is not, and to 1 otherwise. `min: 0` and `max: 0`\n * are each still tested explicitly; this is what makes both mean something\n * at once.\n */\nexport function checkCount(\n count: number,\n rule: Occurrences,\n noun: string,\n type: string,\n ctx: RuleContext,\n): Finding[] {\n const findings: Finding[] = [];\n const min = rule.min ?? (rule.max === 0 ? 0 : 1);\n const max = rule.max ?? null;\n\n if (count < min) {\n findings.push({\n type,\n heading: ctx.heading,\n message: `Expected at least ${min} ${plural(noun, min)}, but found ${count}`,\n position: ctx.position,\n severity: \"error\",\n });\n }\n\n if (max !== null && count > max) {\n findings.push({\n type,\n heading: ctx.heading,\n message: `Expected at most ${max} ${plural(noun, max)}, but found ${count}`,\n position: ctx.position,\n severity: \"error\",\n });\n }\n\n return findings;\n}\n\n/* -------------------------------------------------------------------------- *\n * The rules\n * -------------------------------------------------------------------------- */\n\nexport { checkHeading } from \"./heading.js\";\nexport { checkParagraphs, checkParagraphsIn } from \"./paragraphs.js\";\nexport { checkCodeBlocks, checkCodeBlocksIn } from \"./code-blocks.js\";\nexport { checkLists, checkListsIn } from \"./lists.js\";\nexport { checkTables, checkTablesIn } from \"./tables.js\";\nexport { checkAdmonitions, checkAdmonitionsIn } from \"./admonitions.js\";\nexport { checkImages, checkImagesIn } from \"./images.js\";\nexport { checkBlockquotes, checkBlockquotesIn } from \"./blockquotes.js\";\nexport { checkDefinitionLists, checkDefinitionListsIn } from \"./definition-lists.js\";\nexport { checkElements, checkElementsIn } from \"./elements.js\";\nexport { checkContains, checkContainsIn } from \"./contains.js\";\nexport { checkSequence, checkSequenceIn, groupRuns } from \"./sequence.js\";\nexport type { ContentRun } from \"./sequence.js\";\n\n/**\n * Compile an author-supplied pattern, or say which one is broken.\n *\n * A pattern comes from a template, so a bad one is a broken template rather\n * than a lint finding - and the raw `SyntaxError` names the regex but not the\n * template, the section, or the file. Every caller must route the result\n * through the same containment a template load failure gets, or one bad\n * pattern takes the whole run down with it.\n *\n * ## A pattern that compiles can still hang\n *\n * This checks syntax, and syntax is all it checks. `(a+)+b$` is a valid regex\n * that backtracks catastrophically against a heading it cannot match, and\n * `loadTemplateFile` will fetch a template over HTTP, so an untrusted template\n * can supply one.\n *\n * Capping the input length is not the answer, however cheap it looks. The\n * blow-up is exponential in the length of the input, so a cap generous enough\n * for a real heading is already far past the point of hanging: `(a+)+b$` needs\n * on the order of 2^n steps, and n of 64 is out of reach. Any cap that\n * actually bounded the work would reject headings people legitimately write.\n *\n * The boundary that does hold is the one proposal 0015 drew for schemas: a\n * template from a URL is a trust decision made when the URL is configured, not\n * something this function can take back. Validating patterns for backtracking\n * safety at load time is the fix if that decision is ever delegated, and it is\n * a dependency and a proposal rather than a line here.\n */\nconst compiled = new Map<string, RegExp>();\n\nexport function compilePattern(pattern: string): RegExp {\n // Memoized because heading matching is quadratic by nature: the matcher asks\n // every rule about every section, so a template with ten pattern rules against\n // a twenty-section page compiled the same ten regexes two hundred times.\n //\n // Safe to share one instance: these are built with no flags, and `lastIndex`\n // is only carried between calls by `g` and `y`. Adding either to this\n // construction would make the cached regex stateful across sections.\n const hit = compiled.get(pattern);\n if (hit) return hit;\n try {\n const regex = new RegExp(pattern);\n compiled.set(pattern, regex);\n return regex;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new LintError(`Invalid pattern \"${pattern}\": ${reason}`);\n }\n}\n\n/** Drop the compiled-pattern memo. See `clearCaches` in the package root. */\nexport function clearPatternCache(): void {\n compiled.clear();\n}\n","/**\n * `heading:` - the section's title against a string, a one-of list, a\n * `{ pattern }`, or `false` for \"no heading of its own\".\n *\n * One finding type, `heading_error`, covers all four forms; the message\n * names which form failed. v1 split this into `heading_const_error` and\n * `heading_pattern_error`, each of which could fire independently for the\n * same section. v2's `heading:` is one value, so it fires at most once.\n */\n\nimport type { Finding, SectionNode } from \"../types.js\";\nimport { compilePattern, type HeadingRule } from \"./index.js\";\n\n/**\n * A section's own title, in the vocabulary `heading:` speaks: `null` when the\n * section has no heading of its own (the implicit lead section), the title\n * text otherwise.\n *\n * `SectionNode.title` is `\"\"` rather than `null` for that section - `null` is\n * reserved for \"no heading\" so `headingMatches`-style checks elsewhere don't\n * have to special-case the empty string. This bridges the two.\n */\nfunction ownTitle(section: SectionNode): string | null {\n return section.titlePosition === null ? null : section.title;\n}\n\n/** Checks a section's title against the template's `heading:` rule. */\nexport function checkHeading(\n section: SectionNode,\n rule: HeadingRule | undefined,\n): Finding[] {\n if (rule === undefined) return [];\n\n // The heading itself is the offending node when it has a span of its own;\n // the implicit lead section has none, so fall back to the section.\n const position = section.titlePosition ?? section.position;\n const title = ownTitle(section);\n const found = title === null ? \"no heading\" : `\"${title}\"`;\n\n const fail = (message: string): Finding[] => [\n {\n type: \"heading_error\",\n // `|| null`, as `sectionContext` and `match.ts`'s `anchor` both do. A\n // headless section's title is `\"\"`, and the JSON reporter's `heading` is\n // a wire key `manni docevals` parses rather than validates, so two\n // spellings of \"no heading\" would reach it as two different facts.\n heading: section.title || null,\n message,\n position,\n severity: \"error\",\n },\n ];\n\n if (rule === false) {\n return title === null ? [] : fail(`Expected no heading of its own, but found ${found}`);\n }\n\n if (typeof rule === \"string\") {\n return title === rule ? [] : fail(`Expected title \"${rule}\", but found ${found}`);\n }\n\n if (Array.isArray(rule)) {\n if (title !== null && rule.includes(title)) return [];\n return fail(`Expected one of ${rule.map((option) => `\"${option}\"`).join(\", \")}, but found ${found}`);\n }\n\n // { pattern }\n if (title !== null && compilePattern(rule.pattern).test(title)) return [];\n return fail(`Expected title matching /${rule.pattern}/, but found ${found}`);\n}\n","/**\n * The template DSL, as TypeScript. `schemas/lint/template.json` is the\n * authority that user input is validated against; this is the shape the rest of\n * the code reads once that validation has passed.\n *\n * Two things are worth knowing before reading it.\n *\n * A template *is* a rule. It describes the page, so it takes every rule key,\n * plus `title`, `types` and `extends`. It may not take `min` or `max`, because\n * a page is one page, and the loader refuses those two by hand.\n *\n * A rule's children are a **list**, not a map. The v1 format keyed section\n * rules by name and let YAML key order carry the grammar, which made the order\n * invisible to the schema and unspeakable in `extends`. A rule names itself\n * with `id` instead, and that is what `extends` targets.\n *\n * The block-rule keys are plural where the node model is singular. That is\n * deliberate: the node model names one node (`codeBlock`), while a template key\n * carries a count (`codeBlocks: { min: 1 }`).\n */\nimport type { ContentKind } from \"../types.js\";\nimport { compilePattern } from \"../rules/index.js\";\n\n/** Shared by every counted rule: how many of the thing there must be. */\nexport interface Occurrences {\n /** Fewest occurrences. Absent means one. */\n min?: number;\n /** Most occurrences. Absent is unbounded; `0` forbids. */\n max?: number;\n}\n\n/**\n * What a rule's `heading` may say.\n *\n * `undefined` (the key absent) matches any heading or none. A string is exact\n * text, a list is one-of, `{ pattern }` is an unanchored regular expression,\n * and `false` means the section has no heading of its own.\n */\nexport type HeadingRule = string | string[] | { pattern: string } | false;\n\n/**\n * Attributes a node must carry. A string is the required value, `true`\n * requires the attribute's presence, and `false` requires its absence.\n */\nexport type AttributesRule = Record<string, string | boolean>;\n\n/** `paragraphs:` - how many paragraphs, and what each must look like. */\nexport interface ParagraphsRule extends Occurrences {\n /** Unanchored regular expression every paragraph in the run must match. */\n pattern?: string;\n}\n\n/** `codeBlocks:` - how many code blocks, and how they are tagged. */\nexport interface CodeBlocksRule extends Occurrences {\n /** Language, or languages, every code block must declare one of. */\n language?: string | string[];\n /** Info-string tail after the language; narrows which blocks count. */\n fenceInfo?: string;\n}\n\n/** `lists.items:` - how many items per list, and what each item holds. */\nexport interface ListItemsRule extends Occurrences {\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/** `lists:` - how many lists, whether they are ordered, and item rules. */\nexport interface ListsRule extends Occurrences {\n ordered?: boolean;\n items?: ListItemsRule;\n}\n\n/** `tables:` - how many tables, and the header cells in order. */\nexport interface TablesRule extends Occurrences {\n columns?: string[];\n}\n\n/** `admonitions:` - how many, and of which variant. */\nexport interface AdmonitionsRule extends Occurrences {\n variant?: \"note\" | \"tip\" | \"important\" | \"caution\" | \"warning\" | \"danger\";\n}\n\n/** `images:` - how many, and what they point at. */\nexport interface ImagesRule extends Occurrences {\n url?: string;\n alt?: string;\n attributes?: AttributesRule;\n}\n\n/** `elements:` - how many named wrappers, and what they hold. */\nexport interface ElementsRule extends Occurrences {\n /** Name, or names, an element must carry to be counted by this rule. */\n tag?: string | string[];\n attributes?: AttributesRule;\n sequence?: BlockRule[];\n contains?: BlockRule;\n}\n\n/**\n * What a section holds, keyed by content kind.\n *\n * One of these is a whole `contains:`. As an entry of `sequence:` exactly one\n * key is set, and it names the kind expected at that position.\n */\nexport interface BlockRule {\n paragraphs?: ParagraphsRule;\n codeBlocks?: CodeBlocksRule;\n lists?: ListsRule;\n tables?: TablesRule;\n admonitions?: AdmonitionsRule;\n images?: ImagesRule;\n blockquotes?: Occurrences;\n definitionLists?: Occurrences;\n elements?: ElementsRule;\n}\n\n/** One block-rule key: a content kind, spelled plural. */\nexport type BlockKind = keyof BlockRule;\n\n/** Every block-rule key, in the order the schema declares them. */\nexport const BLOCK_KINDS: readonly BlockKind[] = [\n \"paragraphs\",\n \"codeBlocks\",\n \"lists\",\n \"tables\",\n \"admonitions\",\n \"images\",\n \"blockquotes\",\n \"definitionLists\",\n \"elements\",\n];\n\n/**\n * The node a block-rule key counts: `codeBlocks` counts `codeBlock` nodes.\n *\n * It is what lets the validator ask a parser whether a rule can run at all -\n * a parser declares the kinds it emits, and a rule about a kind absent from\n * that list is reported rather than silently passing.\n *\n * `rules/sequence.ts` holds the same map, written against the rules' own copy\n * of the DSL. The duplication is the one this file's header describes: the two\n * vocabularies are kept apart deliberately, and this is the copy the loader and\n * the validator read.\n */\nexport const BLOCK_KIND_NODE: Record<BlockKind, ContentKind> = {\n paragraphs: \"paragraph\",\n codeBlocks: \"codeBlock\",\n lists: \"list\",\n tables: \"table\",\n admonitions: \"admonition\",\n images: \"image\",\n blockquotes: \"blockquote\",\n definitionLists: \"definitionList\",\n elements: \"element\",\n};\n\n/** One rule: a section of the page, or a repeated run of sections. */\nexport interface Rule extends Occurrences {\n /** Handle, unique among siblings. `extends` targets it. */\n id?: string;\n /** Prose description of what the rule is for. Never checked. */\n description?: string;\n heading?: HeadingRule;\n /** Rules matched in order as one unit, repeated by this rule's `min`/`max`. */\n repeat?: Rule[];\n /** What the section holds, in order. Not combinable with `contains`. */\n sequence?: BlockRule[];\n /** What the section holds, in any order. Not combinable with `sequence`. */\n contains?: BlockRule;\n /** Rules for the subsections, in document order. */\n sections?: Rule[];\n}\n\n/** One doctype template: the rule that describes a whole page. */\nexport interface Template extends Rule {\n /** Human-readable name, shown by `manni lint templates`. */\n title?: string;\n /** Doctypes this template serves, matched against a page's `type`. */\n types?: string[];\n /** Built-in id, path, or URL to inherit from. */\n extends?: string;\n}\n\n/** A template file: named templates plus reusable `$ref` targets. */\nexport interface TemplateFile {\n /** Published schema URL, for editors. Ignored by the linter. */\n $schema?: string;\n templates?: Record<string, Template>;\n components?: Record<string, unknown>;\n info?: Record<string, unknown>;\n}\n\n/**\n * A rule is a wildcard when it says nothing about its heading.\n *\n * It then matches any heading, and matches a section with none. `heading:\n * false` is not a wildcard: it states that the section has no heading of its\n * own, which is as specific as naming one.\n */\nexport function isWildcard(rule: Rule): boolean {\n return rule.heading === undefined;\n}\n\n/**\n * How many sections a rule claims: `min` defaulting to one, and `max` as\n * written, with `null` for unbounded.\n *\n * The defaults live here rather than in the schema. A default written into the\n * data by Ajv is indistinguishable from a value the author typed, so it wins\n * the `extends` merge against the parent's real value.\n *\n * One default is not the naive `min ?? 1`. `max: 0` is how the format forbids\n * a thing outright, and a bare `max: 0` has to be satisfiable by a page that\n * truly has none of it. A blanket \"min defaults to 1\" makes it unsatisfiable -\n * at least one demanded, at most zero permitted - so `min` defaults to 0\n * exactly when `max` is written as `0` and `min` itself is not, and to 1\n * otherwise. `checkCount` in `rules/index.ts` states the same rule for the\n * content counts; the two agree deliberately.\n */\nexport function occurrenceRange(rule: Occurrences): {\n min: number;\n max: number | null;\n} {\n return { min: rule.min ?? (rule.max === 0 ? 0 : 1), max: rule.max ?? null };\n}\n\n/** Whether a section's title satisfies a rule's `heading`. */\nexport function headingMatches(\n heading: HeadingRule | undefined,\n title: string | null,\n): boolean {\n if (heading === undefined) return true;\n if (heading === false) return title === null;\n if (title === null) return false;\n if (typeof heading === \"string\") return title === heading;\n if (Array.isArray(heading)) return heading.includes(title);\n return compilePattern(heading.pattern).test(title);\n}\n","/**\n * Decide which rule describes which section, by alignment.\n *\n * A rule list is a regular expression over section predicates, and a document's\n * sibling sections are the string. The matcher compiles the first and aligns\n * the second against it at minimum cost:\n *\n * 1. Each rule contributes one predicate on a heading. `min`/`max` is counted\n * repetition, and `repeat:` is a parenthesised subexpression.\n * 2. Bounded counts expand into copies; an absent `max` becomes a self-loop.\n * 3. Four edits close the gap between rules and sections: a *match* (the\n * predicate holds), a *coercion* (a rule claiming one section takes a\n * section its heading rejects), a *skipped rule* (a required occurrence\n * consumes nothing) and a *skipped section* (no rule consumes it).\n * 4. Viterbi over a (sections + 1) x states lattice finds the cheapest edit\n * sequence. Deletions can form zero-consuming cycles, so each column is\n * closed with Dijkstra rather than a topological sweep; all weights are\n * non-negative.\n * 5. Skipped rules become `missing_section` (or one `missing_group` for a\n * `repeat` copy that is absent whole), skipped sections become\n * `unexpected_section`, and every match is handed to the content rules.\n *\n * The predecessor of this file walked the rules left to right with no\n * backtracking, and each of its eight hand-written behaviours is now a\n * consequence of a weight or a tie-break instead of a special case. The two it\n * could not express are what forced the change: a rule list with counted\n * repetition is not a sequence of one-shot decisions, and a greedy walk has to\n * guess which of two rules wants a section before it has seen the rest.\n *\n * Heading mismatches are deliberately not reported here. This module pairs; the\n * content rules report `heading_error` on the pair it produced. `validator.ts`\n * explains why the two are separate.\n */\nimport { LintError } from \"../types.js\";\nimport type { Finding, Position, SectionNode } from \"../types.js\";\nimport { headingMatches, isWildcard, occurrenceRange } from \"./template.js\";\nimport type { Rule } from \"./template.js\";\n\n/* -------------------------------------------------------------------------- *\n * The cost model, which is interface\n * -------------------------------------------------------------------------- */\n\n/**\n * What each edit costs, in the units the alignment minimises.\n *\n * These weights are **interface, not implementation**. They decide which\n * findings a document produces, so changing one changes the report for\n * documents nobody edited - the same class of change as renaming a flag.\n * `test/lint/unit/match.test.ts` pins them, and the templates reference prints\n * them.\n *\n * Skipping an occurrence at or above its rule's `min` is free; only a required\n * occurrence pays `skipRule`.\n *\n * Coercion is open only to a *required* occurrence of a rule whose `max` is 1.\n * Both halves of that earn their place. Without the `max: 1` half a repeating\n * rule adopts any stray section for 1 rather than letting it report as\n * unexpected for 2. Without the \"required\" half an optional rule does the same\n * thing for the same reason, and there it is plainly wrong: standing aside\n * costs an optional rule nothing, so coercing trades a clean report for a\n * heading error about a section the template never insisted on.\n */\nexport const ALIGNMENT_COSTS = {\n match: 0,\n coerce: 1,\n skipRule: 2,\n skipSection: 2,\n} as const;\n\n/**\n * How equal-cost alignments are settled, in order, after the total cost.\n *\n * Also interface: two of these decide real reports, and all three are stated in\n * words so the docs page and the code cannot drift apart.\n */\nexport const TIE_BREAKS = [\n \"a rule that names its heading beats a wildcard taking the same section\",\n \"a repeating rule prefers its sections adjacent\",\n \"earliest rule, then the smallest edit sequence under match < coerce < skip-rule < skip-section\",\n] as const;\n\n/**\n * Most states a compiled rule list may expand to.\n *\n * Counted repetition is expanded into copies, so `max: 100000` on a rule with\n * five subsections is a hundred thousand copies of five states and a lattice\n * nobody asked for. The cap turns that into a template error naming the file,\n * rather than a lint run that appears to hang.\n */\nexport const STATE_LIMIT = 2000;\n\n/* -------------------------------------------------------------------------- *\n * What the matcher hands on\n * -------------------------------------------------------------------------- */\n\n/** One rule paired with the section it claimed. */\nexport interface Match {\n /** The rule itself - a `repeat` group's member, never the group. */\n rule: Rule;\n section: SectionNode;\n /**\n * True when the rule was paired with a section whose heading does not\n * satisfy it, because nothing else could claim that section. Keeps the\n * precise \"Expected title X, but found Y\" report for the common one-for-one\n * case instead of degrading it into missing + unexpected.\n */\n coerced: boolean;\n}\n\nexport interface MatchResult {\n matches: Match[];\n findings: Finding[];\n}\n\nexport interface MatchOptions {\n /** Section these are the subsections of, for anchoring a trailing gap. */\n parent?: SectionNode | null;\n /** File the rules came from. Used only to name the state-cap failure. */\n source?: string;\n /** Template within that file. Used only to name the state-cap failure. */\n template?: string;\n}\n\n/* -------------------------------------------------------------------------- *\n * Compilation\n * -------------------------------------------------------------------------- */\n\n/**\n * One copy of a `repeat` group, and every leaf occurrence inside it.\n *\n * It exists so an absent copy can report once for the group. A copy whose\n * leaves were *all* skipped is a group that is not there at all, which reads\n * as one finding; a copy that matched some of them is a group that is there and\n * incomplete, whose absent members read better one by one.\n */\ninterface GroupCopy {\n rule: Rule;\n members: Occurrence[];\n}\n\n/** One occurrence of one rule: the chance to consume exactly one section. */\ninterface Occurrence {\n rule: Rule;\n /** Below the rule's `min`, so skipping it costs rather than being free. */\n required: boolean;\n /** Required and `max: 1`, so it may take a section its heading rejects. */\n coercible: boolean;\n /** Says nothing about its heading, so it loses ties to a rule that does. */\n wildcard: boolean;\n /** Enclosing `repeat` copies, outermost first. */\n groups: GroupCopy[];\n}\n\ninterface Eps {\n from: number;\n to: number;\n cost: number;\n rank: number;\n /** Set when this edge is a rule being skipped rather than structure. */\n occ: Occurrence | null;\n}\n\ninterface Automaton {\n states: number;\n start: number;\n accept: number;\n /** The occurrence a state may consume a section through, if any. */\n consume: (Occurrence | null)[];\n /** Where that consumption lands. */\n consumeTo: number[];\n epsOut: Eps[][];\n epsIn: Eps[][];\n /** States strictly inside a repetition, where a skipped section breaks a run. */\n inRepeat: boolean[];\n}\n\n/**\n * Edit ranks, used only to settle a tie the costs and the two structural\n * tie-breaks left open. Structural epsilons - entering, repeating and leaving a\n * self-loop - rank with `match`, because they are not edits at all and a path\n * must be free to leave a loop before it starts skipping the rules inside it.\n */\nconst RANK = {\n match: 0,\n structure: 0,\n coerce: 1,\n skipRule: 2,\n skipSection: 3,\n} as const;\n\nconst NO_EPS: Eps[] = [];\n\n/**\n * States the rule list expands to, counted without building anything.\n *\n * Checked before compilation so a template with an absurd `max` fails on its\n * own terms rather than by exhausting memory. The two extra states per\n * unbounded rule are its self-loop's entry and exit.\n */\nfunction expandedStates(rules: Rule[]): number {\n let total = 1;\n for (const rule of rules) total += ruleStates(rule);\n return total;\n}\n\nfunction ruleStates(rule: Rule): number {\n let unit = 1;\n if (rule.repeat) {\n unit = 0;\n for (const member of rule.repeat) unit += ruleStates(member);\n }\n const { min, max } = occurrenceRange(rule);\n if (max === null) return unit * (Math.max(min, 0) + 1) + 2;\n return unit * Math.max(0, max);\n}\n\nfunction listAt<T>(lists: T[][], index: number): T[] {\n const list = lists[index];\n if (list) return list;\n const created: T[] = [];\n lists[index] = created;\n return created;\n}\n\n/**\n * Compile a rule list into an automaton over section predicates.\n *\n * Bounded repetition is unrolled: `min: 1, max: 3` is three copies, the first\n * required and the rest free to skip. An unbounded `max` is a self-loop after\n * the required copies, which is the only construct here that can consume\n * nothing and return to where it started - hence the Dijkstra in the alignment.\n */\nfunction compile(rules: Rule[]): Automaton {\n const consume: (Occurrence | null)[] = [];\n const consumeTo: number[] = [];\n const epsOut: Eps[][] = [];\n const epsIn: Eps[][] = [];\n const inRepeat: boolean[] = [];\n\n const newState = (): number => {\n consume.push(null);\n consumeTo.push(-1);\n epsOut.push([]);\n epsIn.push([]);\n inRepeat.push(false);\n return consume.length - 1;\n };\n\n const eps = (\n from: number,\n to: number,\n cost: number,\n rank: number,\n occ: Occurrence | null,\n ): void => {\n const edge: Eps = { from, to, cost, rank, occ };\n listAt(epsOut, from).push(edge);\n listAt(epsIn, to).push(edge);\n };\n\n const leaf = (from: number, occ: Occurrence): number => {\n const to = newState();\n consume[from] = occ;\n consumeTo[from] = to;\n // Skipping the occurrence: free when the rule can do without it.\n eps(from, to, occ.required ? ALIGNMENT_COSTS.skipRule : 0, RANK.skipRule, occ);\n return to;\n };\n\n /** One copy of a rule's unit: its members, or the rule's own occurrence. */\n const buildCopy = (\n rule: Rule,\n from: number,\n groups: GroupCopy[],\n required: boolean,\n ): number => {\n if (rule.repeat) {\n const copy: GroupCopy = { rule, members: [] };\n const nested = [...groups, copy];\n let cursor = from;\n for (const member of rule.repeat) {\n cursor = buildRule(member, cursor, nested, required);\n }\n return cursor;\n }\n const { max } = occurrenceRange(rule);\n const occ: Occurrence = {\n rule,\n required,\n coercible: required && max === 1,\n wildcard: isWildcard(rule),\n groups,\n };\n for (const group of groups) group.members.push(occ);\n return leaf(from, occ);\n };\n\n function buildRule(\n rule: Rule,\n from: number,\n groups: GroupCopy[],\n context: boolean,\n ): number {\n const { min, max } = occurrenceRange(rule);\n // `max` below `min` is refused by the loader where both are written; a bare\n // `max: 0` still reaches here against the default `min: 1`, and means none.\n const floor = max === null ? Math.max(min, 0) : Math.min(Math.max(min, 0), max);\n const copies = max === null ? floor : Math.max(0, max);\n const first = consume.length;\n\n let cursor = from;\n for (let copy = 0; copy < copies; copy++) {\n cursor = buildCopy(rule, cursor, groups, context && copy < floor);\n }\n\n let end = cursor;\n if (max === null) {\n const loop = newState();\n eps(cursor, loop, 0, RANK.structure, null);\n const back = buildCopy(rule, loop, groups, false);\n eps(back, loop, 0, RANK.structure, null);\n end = newState();\n eps(loop, end, 0, RANK.structure, null);\n }\n\n // A skipped section inside a repetition breaks the run it is inside, which\n // tie-break 2 charges for. The repetition's own boundaries are not inside\n // it: a section skipped before the first copy or after the last one sits\n // beside the run rather than in the middle of it.\n if (copies > 1 || max === null) {\n for (let state = first; state < consume.length; state++) {\n if (state !== end) inRepeat[state] = true;\n }\n }\n return end;\n }\n\n const start = newState();\n let cursor = start;\n for (const rule of rules) cursor = buildRule(rule, cursor, [], true);\n\n return {\n states: consume.length,\n start,\n accept: cursor,\n consume,\n consumeTo,\n epsOut,\n epsIn,\n inRepeat,\n };\n}\n\n/**\n * Compiled rule lists, keyed by the array the template holds.\n *\n * A template is loaded once and applied to every page of its doctype, and every\n * level of every page re-enters this module. The automaton is immutable once\n * built, so one compilation serves them all.\n */\nconst compiled = new WeakMap<Rule[], Automaton>();\n\nfunction automatonFor(rules: Rule[], options: MatchOptions): Automaton {\n const hit = compiled.get(rules);\n if (hit) return hit;\n\n const states = expandedStates(rules);\n if (states > STATE_LIMIT) {\n const source = options.source ?? \"template\";\n // A template is referred to as `./templates.yaml#how-to` everywhere else,\n // so a named template fragment joins the source the same way here. Absent\n // a name - the file failed to compile a rule list outside any named\n // template - there is nothing to put after a `#`, so the sentence falls\n // back to its old, colon-joined phrasing.\n const label =\n options.template != null ? `${source}#${options.template}` : `${source}: the rule list`;\n throw new LintError(\n `${label} expands to ${states} states; the limit is ${STATE_LIMIT}. ` +\n `Cap a max, or split the template.`,\n );\n }\n\n const built = compile(rules);\n compiled.set(rules, built);\n return built;\n}\n\n/* -------------------------------------------------------------------------- *\n * Alignment\n * -------------------------------------------------------------------------- */\n\ntype StepKind = \"match\" | \"coerce\" | \"skip-rule\" | \"skip-section\";\n\n/** One candidate edge out of a lattice node, during the forward walk. */\ninterface Move {\n kind: StepKind;\n /** State it lands in. */\n to: number;\n /** Section index it lands in - the same one unless a section was consumed. */\n column: number;\n occ: Occurrence | null;\n /** This edge plus the cheapest completion from where it lands. */\n total: number;\n rank: number;\n}\n\ninterface Step {\n kind: StepKind;\n /** Section consumed, or where the cursor stood when a rule was skipped. */\n index: number;\n occ: Occurrence | null;\n}\n\n/** A section's heading, or `null` when it has none of its own. */\nfunction titleOf(section: SectionNode): string | null {\n return section.titlePosition === null ? null : section.title;\n}\n\n/** Binary heap over (cost, state), smallest cost first. */\nclass Heap {\n private readonly costs: number[] = [];\n private readonly items: number[] = [];\n\n get size(): number {\n return this.items.length;\n }\n\n /*\n * Every `?? 0` in this class is unreachable, and is here only because\n * `noUncheckedIndexedAccess` cannot see the bounds the arithmetic already\n * guarantees. `costs` and `items` are pushed and popped together and so\n * always have the same length; `child` is the index just pushed, and\n * `parent = (child - 1) >> 1` is in bounds whenever `child > 0`; `left` and\n * `right` are compared against `length` before they are read.\n *\n * Worth stating rather than leaving to inference: were an index ever out of\n * bounds, the fallback would read as cost 0, quietly inverting the heap\n * order rather than throwing. It is a type-checker concession, not a\n * defensive default.\n */\n push(cost: number, item: number): void {\n this.costs.push(cost);\n this.items.push(item);\n let child = this.items.length - 1;\n while (child > 0) {\n const parent = (child - 1) >> 1;\n if ((this.costs[parent] ?? 0) <= (this.costs[child] ?? 0)) break;\n this.swap(parent, child);\n child = parent;\n }\n }\n\n pop(): { cost: number; item: number } {\n const cost = this.costs[0] ?? 0;\n const item = this.items[0] ?? 0;\n const lastCost = this.costs.pop();\n const lastItem = this.items.pop();\n if (this.items.length > 0 && lastCost !== undefined && lastItem !== undefined) {\n this.costs[0] = lastCost;\n this.items[0] = lastItem;\n let parent = 0;\n for (;;) {\n const left = parent * 2 + 1;\n const right = left + 1;\n let smallest = parent;\n if (left < this.items.length && (this.costs[left] ?? 0) < (this.costs[smallest] ?? 0)) {\n smallest = left;\n }\n if (right < this.items.length && (this.costs[right] ?? 0) < (this.costs[smallest] ?? 0)) {\n smallest = right;\n }\n if (smallest === parent) break;\n this.swap(parent, smallest);\n parent = smallest;\n }\n }\n return { cost, item };\n }\n\n private swap(a: number, b: number): void {\n const cost = this.costs[a] ?? 0;\n const item = this.items[a] ?? 0;\n this.costs[a] = this.costs[b] ?? 0;\n this.items[a] = this.items[b] ?? 0;\n this.costs[b] = cost;\n this.items[b] = item;\n }\n}\n\n/**\n * The cheapest edit sequence turning the rule list into the section list.\n *\n * Costs are packed into one integer so the lattice can be a typed array:\n * `((primary * radix) + wildcards) * radix + brokenRuns`, compared as one\n * number, which is lexicographic because no component can reach the radix.\n *\n * The lattice is filled backwards, from the end of the document to the start,\n * and the path is then walked forwards. That order is what makes tie-break 3\n * expressible: with the cost of every remaining suffix already known, the walk\n * can take the lowest-ranked optimal edit at each step, which is exactly\n * \"earliest rule, then the smallest edit sequence\".\n */\nfunction align(sections: SectionNode[], nfa: Automaton): Step[] {\n const n = sections.length;\n const states = nfa.states;\n const radix = 2 * (n + states) + 2;\n const weigh = (primary: number, wildcards: number, brokenRuns: number): number =>\n (primary * radix + wildcards) * radix + brokenRuns;\n\n const SKIP_SECTION = weigh(ALIGNMENT_COSTS.skipSection, 0, 0);\n const SKIP_SECTION_IN_RUN = weigh(ALIGNMENT_COSTS.skipSection, 0, 1);\n const MATCH = weigh(ALIGNMENT_COSTS.match, 0, 0);\n const MATCH_WILDCARD = weigh(ALIGNMENT_COSTS.match, 1, 0);\n const COERCE = weigh(ALIGNMENT_COSTS.coerce, 0, 0);\n\n /** What a state's consuming edge costs against one section, or null. */\n const consumeCost = (\n state: number,\n index: number,\n ): { cost: number; rank: number; to: number; occ: Occurrence } | null => {\n const occ = nfa.consume[state];\n const section = sections[index];\n const to = nfa.consumeTo[state];\n if (!occ || !section || to === undefined || to < 0) return null;\n if (headingMatches(occ.rule.heading, titleOf(section))) {\n const cost = occ.wildcard ? MATCH_WILDCARD : MATCH;\n return { cost, rank: RANK.match, to, occ };\n }\n if (occ.coercible) return { cost: COERCE, rank: RANK.coerce, to, occ };\n return null;\n };\n\n const skipSectionCost = (state: number): number =>\n nfa.inRepeat[state] === true ? SKIP_SECTION_IN_RUN : SKIP_SECTION;\n\n // dist[i * states + s]: cheapest way from (section i, state s) to the end.\n const dist = new Float64Array((n + 1) * states).fill(Infinity);\n const distAt = (slot: number): number => dist[slot] ?? Infinity;\n\n for (let index = n; index >= 0; index--) {\n const base = index * states;\n const next = base + states;\n const heap = new Heap();\n\n for (let state = 0; state < states; state++) {\n let best = Infinity;\n if (index === n) {\n if (state === nfa.accept) best = 0;\n } else {\n const step = consumeCost(state, index);\n if (step) best = step.cost + distAt(next + step.to);\n const skipped = skipSectionCost(state) + distAt(next + state);\n if (skipped < best) best = skipped;\n }\n dist[base + state] = best;\n if (best < Infinity) heap.push(best, state);\n }\n\n // Close the column under epsilon edges. They can form zero-consuming\n // cycles - a `repeat` with `min: 0` and no `max` - so this is Dijkstra on\n // the reversed epsilon graph rather than a sweep in state order.\n const done = new Uint8Array(states);\n while (heap.size > 0) {\n const { cost, item } = heap.pop();\n if (done[item] === 1 || cost > distAt(base + item)) continue;\n done[item] = 1;\n for (const edge of nfa.epsIn[item] ?? NO_EPS) {\n const candidate = cost + edge.cost;\n if (candidate < distAt(base + edge.from)) {\n dist[base + edge.from] = candidate;\n heap.push(candidate, edge.from);\n }\n }\n }\n }\n\n if (distAt(nfa.start) === Infinity) {\n // Every state has a skip-section edge and every occurrence a skip edge, so\n // the accept state is always reachable. Reaching this would be a\n // construction bug, not a template the user can fix.\n throw new LintError(\"internal: no alignment exists for this rule list.\");\n }\n\n const steps: Step[] = [];\n let index = 0;\n let state = nfa.start;\n let seen = new Set<number>([state]);\n\n while (!(index === n && state === nfa.accept)) {\n const moves: Move[] = [];\n\n const offer = (\n cost: number,\n rank: number,\n to: number,\n column: number,\n kind: StepKind,\n occ: Occurrence | null,\n ): void => {\n const total = cost + distAt(column * states + to);\n if (total === Infinity) return;\n moves.push({ kind, to, column, occ, total, rank });\n };\n\n if (index < n) {\n const step = consumeCost(state, index);\n if (step) {\n offer(\n step.cost,\n step.rank,\n step.to,\n index + 1,\n step.rank === RANK.coerce ? \"coerce\" : \"match\",\n step.occ,\n );\n }\n offer(skipSectionCost(state), RANK.skipSection, state, index + 1, \"skip-section\", null);\n }\n for (const edge of nfa.epsOut[state] ?? NO_EPS) {\n if (seen.has(edge.to)) continue;\n offer(edge.cost, edge.rank, edge.to, index, \"skip-rule\", edge.occ);\n }\n\n // Cheapest first; then the lowest-ranked edit, which is tie-break 3; then\n // the earliest state, so the walk is reproducible to the edge.\n let move: Move | undefined;\n for (const candidate of moves) {\n if (\n move === undefined ||\n candidate.total < move.total ||\n (candidate.total === move.total && candidate.rank < move.rank) ||\n (candidate.total === move.total &&\n candidate.rank === move.rank &&\n candidate.to < move.to)\n ) {\n move = candidate;\n }\n }\n if (move === undefined) {\n throw new LintError(\"internal: the alignment could not be reconstructed.\");\n }\n\n if (move.kind !== \"skip-rule\" || move.occ !== null) {\n steps.push({ kind: move.kind, index, occ: move.occ });\n }\n if (move.column !== index) {\n index = move.column;\n seen = new Set<number>();\n }\n state = move.to;\n seen.add(state);\n }\n\n return steps;\n}\n\n/* -------------------------------------------------------------------------- *\n * Findings\n * -------------------------------------------------------------------------- */\n\nfunction collapse(point: Position[\"end\"]): Position {\n return { start: { ...point }, end: { ...point } };\n}\n\n/**\n * Where a finding about the cursor position lands.\n *\n * A gap in the middle of a document anchors on the section standing where the\n * missing one should be. A gap at the *end* has no such section, and anchoring\n * on the parent - which is what the previous matcher did - spans the parent's\n * whole subtree, so the finding starts at the parent's heading and sorts to the\n * top of a report about the bottom of the file. It anchors at the parent's end\n * instead, which is where the section would have gone.\n */\nfunction anchor(\n index: number,\n sections: SectionNode[],\n parent: SectionNode | null,\n): { heading: string | null; position: Position } {\n const section = sections[index];\n if (section) {\n return { heading: section.title || null, position: section.position };\n }\n if (parent) {\n return { heading: parent.title || null, position: collapse(parent.position.end) };\n }\n const last = sections[sections.length - 1];\n if (last) return { heading: null, position: collapse(last.position.end) };\n return { heading: null, position: collapse({ line: 1, column: 1, offset: 0 }) };\n}\n\n/** How a rule's heading reads inside a longer sentence. */\nfunction describeHeading(rule: Rule): string {\n const heading = rule.heading;\n if (typeof heading === \"string\") return `\"${heading}\"`;\n if (Array.isArray(heading)) return heading.map((text) => `\"${text}\"`).join(\", \");\n if (heading === false) return \"a section with no heading\";\n if (heading !== undefined) return `/${heading.pattern}/`;\n return rule.id === undefined ? \"any section\" : `\"${rule.id}\"`;\n}\n\n/**\n * What an absent occurrence is called.\n *\n * A rule names itself by its heading where it has one, because that is the text\n * the reader will type into the document. A wildcard has only its `id`, which\n * is why one is worth writing.\n */\nfunction missingMessage(rule: Rule): string {\n const heading = rule.heading;\n if (typeof heading === \"string\") return `Missing section \"${heading}\"`;\n if (Array.isArray(heading)) {\n return `Missing one of ${heading.map((text) => `\"${text}\"`).join(\", \")}`;\n }\n if (heading === false) return \"Missing section without a heading\";\n if (heading !== undefined) return `Missing section matching /${heading.pattern}/`;\n return rule.id === undefined ? \"Missing section\" : `Missing section \"${rule.id}\"`;\n}\n\nfunction missingGroupMessage(copy: GroupCopy): string {\n const members = (copy.rule.repeat ?? []).map(describeHeading).join(\" followed by \");\n const name = copy.rule.id === undefined ? \"\" : ` \"${copy.rule.id}\"`;\n return `Missing group${name}: expected ${members}`;\n}\n\nfunction unexpectedMessage(section: SectionNode): string {\n const what =\n section.titlePosition === null\n ? \"Unexpected section without a heading\"\n : `Unexpected section \"${section.title}\"`;\n return `${what}. Add a trailing rule with min: 0 to allow sections the template does not describe.`;\n}\n\n/* -------------------------------------------------------------------------- *\n * The entry point\n * -------------------------------------------------------------------------- */\n\n/**\n * Align `sections` against `rules` and say what is missing, what is extra, and\n * which rule describes which section.\n *\n * `rules` being absent means the template says nothing about this level, which\n * is silence rather than \"no sections allowed\". An empty list is the other\n * thing: a rule list that describes no sections, so every section is\n * unexpected.\n */\nexport function matchSections(\n sections: SectionNode[],\n rules: Rule[] | undefined,\n options: MatchOptions = {},\n): MatchResult {\n const matches: Match[] = [];\n const findings: Finding[] = [];\n if (!rules) return { matches, findings };\n\n const parent = options.parent ?? null;\n const nfa = automatonFor(rules, options);\n const steps = align(sections, nfa);\n\n const taken = new Set<Occurrence>();\n for (const step of steps) {\n if ((step.kind === \"match\" || step.kind === \"coerce\") && step.occ) {\n taken.add(step.occ);\n }\n }\n\n /** The outermost enclosing `repeat` copy that is absent whole, if any. */\n const absentGroup = (occ: Occurrence): GroupCopy | null => {\n for (const group of occ.groups) {\n if (group.members.every((member) => !taken.has(member))) return group;\n }\n return null;\n };\n\n const reported = new Set<GroupCopy>();\n\n for (const step of steps) {\n const section = sections[step.index];\n if ((step.kind === \"match\" || step.kind === \"coerce\") && step.occ && section) {\n matches.push({\n rule: step.occ.rule,\n section,\n coerced: step.kind === \"coerce\",\n });\n continue;\n }\n\n if (step.kind === \"skip-section\" && section) {\n findings.push({\n type: \"unexpected_section\",\n heading: section.title || null,\n message: unexpectedMessage(section),\n position: section.position,\n severity: \"error\",\n });\n continue;\n }\n\n if (step.kind !== \"skip-rule\" || !step.occ || !step.occ.required) continue;\n\n const where = anchor(step.index, sections, parent);\n const group = absentGroup(step.occ);\n if (group) {\n if (reported.has(group)) continue;\n reported.add(group);\n findings.push({\n type: \"missing_group\",\n heading: where.heading,\n message: missingGroupMessage(group),\n position: where.position,\n severity: \"error\",\n });\n continue;\n }\n\n findings.push({\n type: \"missing_section\",\n heading: where.heading,\n message: missingMessage(step.occ.rule),\n position: where.position,\n severity: \"error\",\n });\n }\n\n return { matches, findings };\n}\n"],"mappings":"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","names":["matches","BLOCK_KINDS","cursor","compiled","state","index","matches"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lint/core/infer.ts","../src/lint/commands/templates.ts","../src/lint/commands/tools.ts"],"sourcesContent":["/**\n * Write a first template from a page that already has the shape its author\n * wants.\n *\n * The format is strict by default: every rule is one occurrence, and a section\n * no rule describes is a finding. A new author's first run against a\n * hand-written template is therefore a screen of unexpected sections, and this\n * is the escape. Proposal 0061's stress test 5 records it, and says the two\n * ship together.\n *\n * Two rules govern everything here.\n *\n * **The output must lint its input clean.** That is the whole contract, and it\n * is why each inference below is the weakest claim that still describes the\n * page. `contains:` lists only the kinds that are there, at `min: 1`, so a\n * section holding more of something still passes. A table's `columns:` is\n * claimed only where every table in that section agrees about them, and a code\n * block's `language:` only where every block in that section declares one -\n * both rules report per offending node, so a claim drawn from one node would\n * fail on its neighbour. A template that fails the page it was inferred from is\n * worse than no template: it hands a new author findings about the very\n * document they pointed at.\n *\n * **Nothing is optional and nothing repeats.** One page cannot show what\n * varies, so no `min: 0`, no `max`, no `repeat` and no `pattern` is invented.\n * Two sections with one heading are two rules. Loosening a heading into a list\n * or a pattern, marking a rule optional, and adding a trailing wildcard are the\n * author's edits, and the reference page says so.\n */\nimport { stringify as stringifyYaml } from \"yaml\";\nimport { LintError } from \"../types.js\";\nimport type {\n CodeNode,\n ContentKind,\n ContentNode,\n DocumentTree,\n Position,\n SectionNode,\n TableNode,\n} from \"../types.js\";\nimport { BLOCK_KINDS, BLOCK_KIND_NODE } from \"./template.js\";\nimport type {\n BlockKind,\n BlockRule,\n HeadingRule,\n Rule,\n Template,\n TemplateFile,\n} from \"./template.js\";\n\n/** How an inferred template is written out. */\nexport const INFER_FORMATS = [\"yaml\", \"json\"] as const;\nexport type InferFormat = (typeof INFER_FORMATS)[number];\n\nexport function isInferFormat(value: string): value is InferFormat {\n return (INFER_FORMATS as readonly string[]).includes(value);\n}\n\n/**\n * Template names the schema's `templates` map accepts.\n *\n * Checked here rather than left to Ajv. `templates` is `additionalProperties:\n * false` beside a `patternProperties` key, so a name outside the pattern is\n * reported as an unexpected property - which names the offending key and says\n * nothing whatsoever about what is wrong with it.\n */\nconst TEMPLATE_NAME = /^[A-Za-z][A-Za-z0-9\\-_]*$/;\n\n/** The node each block-rule key counts, inverted: `codeBlock` -> `codeBlocks`. */\nconst KIND_KEY = new Map<ContentKind, BlockKind>(\n BLOCK_KINDS.map((key) => [BLOCK_KIND_NODE[key], key]),\n);\n\n/* -------------------------------------------------------------------------- *\n * The page as the template's subject\n * -------------------------------------------------------------------------- */\n\n/** A zero-width span at the top of a file, for a document with no sections. */\nfunction origin(): Position {\n return {\n start: { line: 1, column: 1, offset: 0 },\n end: { line: 1, column: 1, offset: 0 },\n };\n}\n\n/** First section's start through the last one's end. */\nfunction span(sections: SectionNode[]): Position {\n const first = sections[0];\n const last = sections[sections.length - 1];\n if (!first || !last) return origin();\n return { start: { ...first.position.start }, end: { ...last.position.end } };\n}\n\n/**\n * The section the template describes: the page itself.\n *\n * Deliberately the same reading `validator.ts` applies, because the template\n * this produces is checked by that one. A page whose body is a single `# Title`\n * *is* that section; anything else - several top-level headings, or a body that\n * starts at `##` with no lead content - has no section standing for the page,\n * so one is synthesised with no heading of its own. The duplication is small\n * and the alternative is worse: an inference that read the page differently\n * from the checker would produce templates that fail their own source.\n */\nfunction pageSection(tree: DocumentTree): SectionNode {\n const [only] = tree.sections;\n if (tree.sections.length === 1 && only && only.level <= 1) return only;\n return {\n slug: \"\",\n title: \"\",\n level: 0,\n order: 0,\n parentSlug: null,\n titlePosition: null,\n position: span(tree.sections),\n children: [],\n sections: tree.sections,\n };\n}\n\n/* -------------------------------------------------------------------------- *\n * Content\n * -------------------------------------------------------------------------- */\n\n/** The header row's cells, in order, or none where the table has no header. */\nfunction headerCells(table: TableNode): string[] {\n const header = table.children.find((row) => row.header);\n return header ? header.children.map((cell) => cell.text) : [];\n}\n\n/**\n * `columns:` for a run of tables, where they all agree about it.\n *\n * `tables.columns` reports once per table whose header differs, so a claim\n * taken from the first of two unlike tables fails on the second - in the very\n * page it was drawn from. Where the tables disagree, or any of them has no\n * header row, the count alone is what the page can honestly be said to show.\n */\nfunction columnsOf(tables: TableNode[]): { columns?: string[] } {\n const headers = tables.map(headerCells);\n const [first] = headers;\n if (first === undefined || first.length === 0) return {};\n const same = (cells: string[]): boolean =>\n cells.length === first.length && cells.every((c, i) => c === first[i]);\n return headers.every(same) ? { columns: [...first] } : {};\n}\n\n/**\n * `language:` for a run of code blocks, where every one of them declares one.\n *\n * `codeBlocks.language` holds every block in the run to the accepted set, so a\n * section mixing a tagged fence with a bare one can claim nothing: the bare one\n * would fail. Where the tags differ the list form says what the page shows,\n * which is what \"one of these\" is for.\n */\nfunction languageOf(blocks: CodeNode[]): { language?: string | string[] } {\n const declared: string[] = [];\n for (const block of blocks) {\n if (block.language === undefined || block.language.length === 0) return {};\n declared.push(block.language);\n }\n const distinct = [...new Set(declared)];\n const [only] = distinct;\n if (only === undefined) return {};\n return { language: distinct.length === 1 ? only : distinct };\n}\n\n/**\n * What a section holds, as a `contains:` rule, or nothing where it holds none\n * of the kinds a template can count.\n *\n * `contains` rather than `sequence`: the page shows one order, and asserting it\n * would make moving a paragraph below a list a finding. Order is a claim its\n * author makes deliberately.\n */\nfunction inferContains(children: ContentNode[]): BlockRule | undefined {\n const byKey = new Map<BlockKind, ContentNode[]>();\n for (const node of children) {\n const key = KIND_KEY.get(node.kind);\n if (key === undefined) continue;\n const bucket = byKey.get(key);\n if (bucket) bucket.push(node);\n else byKey.set(key, [node]);\n }\n\n const rule: BlockRule = {};\n let any = false;\n // In `BLOCK_KINDS` order, not the order the page happens to put them in, so\n // two pages holding the same kinds produce byte-identical rules.\n for (const key of BLOCK_KINDS) {\n const nodes = byKey.get(key);\n if (nodes === undefined) continue;\n any = true;\n if (key === \"tables\") {\n rule.tables = { min: 1, ...columnsOf(nodes as TableNode[]) };\n } else if (key === \"codeBlocks\") {\n rule.codeBlocks = { min: 1, ...languageOf(nodes as CodeNode[]) };\n } else {\n // A computed key, as `validator.ts` does it: every other block rule is a\n // bare count, and nine near-identical branches would say less.\n Object.assign(rule, { [key]: { min: 1 } });\n }\n }\n return any ? rule : undefined;\n}\n\n/* -------------------------------------------------------------------------- *\n * Rules\n * -------------------------------------------------------------------------- */\n\n/**\n * A section's heading, as a rule about it.\n *\n * Exact text, because that is what the page shows; a one-of list or a pattern\n * is a generalisation only its author can make. `false` for a section with no\n * heading of its own - the implicit lead section, and the synthesised page -\n * because that is as specific a claim as naming one.\n *\n * An empty title is the one case with no spelling: the schema's `heading`\n * requires a non-empty string, and `false` would be a lie about a section that\n * does have a heading. The key is omitted, which matches any heading.\n */\nfunction inferHeading(section: SectionNode): HeadingRule | undefined {\n if (section.titlePosition === null) return false;\n return section.title.length > 0 ? section.title : undefined;\n}\n\n/** One section, and every section under it. */\nfunction inferRule(section: SectionNode): Rule {\n const rule: Rule = {};\n const heading = inferHeading(section);\n if (heading !== undefined) rule.heading = heading;\n const contains = inferContains(section.children);\n if (contains) rule.contains = contains;\n // Omitted, never `[]`. An absent `sections:` says nothing about the\n // subsections; an empty list says none are permitted.\n if (section.sections.length > 0) {\n rule.sections = section.sections.map(inferRule);\n }\n return rule;\n}\n\n/** The template one page describes: the page rule, with its sections under it. */\nexport function inferTemplate(tree: DocumentTree): Template {\n return inferRule(pageSection(tree));\n}\n\n/* -------------------------------------------------------------------------- *\n * The file\n * -------------------------------------------------------------------------- */\n\n/** Refuse a name the `templates` map cannot hold, in words that name the rule. */\nexport function assertTemplateName(name: string): string {\n if (TEMPLATE_NAME.test(name)) return name;\n throw new LintError(\n `\"${name}\" is not a usable template name. A name starts with a letter and ` +\n `holds only letters, digits, \"-\" and \"_\". Pass --name <name>.`,\n );\n}\n\n/** A one-template file, ready to serialize. */\nexport function inferTemplateFile(\n tree: DocumentTree,\n name: string,\n): TemplateFile {\n return { templates: { [assertTemplateName(name)]: inferTemplate(tree) } };\n}\n\n/**\n * Serialize a template file.\n *\n * `lineWidth: 0` turns off YAML's folding. A folded heading still parses back\n * to the same string, but a template is read and edited by hand, and a heading\n * broken across two lines is the one thing in this output a reader would\n * mistrust.\n */\nexport function renderTemplateFile(\n file: TemplateFile,\n format: InferFormat,\n): string {\n const text =\n format === \"json\"\n ? JSON.stringify(file, null, 2)\n : stringifyYaml(file, { lineWidth: 0 });\n return text.endsWith(\"\\n\") ? text : `${text}\\n`;\n}\n","/**\n * `templates` command cores.\n *\n * `runTemplates` reports the templates a run could resolve: the built-ins, plus\n * the named templates in any files given by `--templates` or by\n * `lint.templates` in the config, with the doctypes each serves.\n *\n * The `types` column is the part worth printing. It is what frontmatter\n * routing will match a page against, so seeing it is how someone works out\n * which `type:` value to write in a page - or that no template claims the one\n * they already wrote.\n *\n * `runTemplatesInfer` writes a first template from a page that already has the\n * shape its author wants. The inference itself is `../core/infer.ts`; what\n * lives here is the plumbing around it - which parser reads the page, what the\n * template is called, and where the file goes.\n *\n * Both return data; `src/lint/reporters/index.ts` renders the listing, and an\n * inferred template is already the text it will be written as.\n */\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport { basename, dirname, extname, resolve } from \"node:path\";\nimport { errorMessage, ToolError } from \"../../shared/errors.js\";\nimport { writeTextAtomic } from \"../../shared/write-file.js\";\nimport { LintError } from \"../types.js\";\nimport type { DocumentParser, DocumentTree } from \"../types.js\";\nimport {\n parserByName,\n parserForExtension,\n unsupportedFormatMessage,\n} from \"../parsers/index.js\";\nimport {\n assertTemplateName,\n inferTemplateFile,\n isInferFormat,\n renderTemplateFile,\n type InferFormat,\n} from \"../core/infer.js\";\nimport type { TemplateFile } from \"../core/template.js\";\nimport { resolveLintRun } from \"../core/config.js\";\nimport {\n listBuiltins,\n loadTemplateFile,\n} from \"../core/template-registry.js\";\n\n/** `TemplateInfo.source` for a template that ships with the tool. */\nexport const BUILTIN_SOURCE = \"builtin\";\n\nexport interface TemplateInfo {\n /** The ref to pass to `--template`. */\n id: string;\n /**\n * Human-readable title. Empty for templates read from a user file: the\n * template DSL has no title field, only the built-in registry carries one.\n */\n title: string;\n /** Doctypes the template serves, matched against a page `type`. */\n types: string[];\n /** `builtin`, or the template file this entry came from. */\n source: string;\n}\n\nexport interface TemplatesInfo {\n templates: TemplateInfo[];\n}\n\nexport interface TemplatesOptions {\n /** Template files whose entries join the built-ins. */\n templates?: string | string[];\n}\n\nexport async function runTemplates(\n opts: TemplatesOptions = {},\n): Promise<TemplatesInfo> {\n const templates: TemplateInfo[] = listBuiltins().map((builtin) => ({\n id: builtin.id,\n title: builtin.title,\n types: builtin.types,\n source: BUILTIN_SOURCE,\n }));\n\n // Listed after the built-ins, in the order supplied - the same order\n // `buildTypeIndex` applies them in, so a later entry claiming the same\n // doctype is the one that would win.\n const paths =\n opts.templates == null\n ? []\n : Array.isArray(opts.templates)\n ? opts.templates\n : [opts.templates];\n\n for (const path of paths) {\n const file = await loadTemplateFile(path);\n for (const [id, template] of Object.entries(file.templates ?? {})) {\n templates.push({\n id,\n title: \"\",\n types: template.types ?? [],\n source: path,\n });\n }\n }\n\n return { templates };\n}\n\n/* -------------------------------------------------------------------------- *\n * infer\n * -------------------------------------------------------------------------- */\n\n/** The token that means stdin, in every command of the family. */\nconst STDIN = \"-\";\n\n/** What a page read from stdin is called when nothing else names it. */\nconst STDIN_NAME = \"stdin\";\n\nexport interface TemplatesInferOptions {\n /** The one page to infer from: a path, or `-` for stdin. */\n page: string;\n /** `--as`: force an input format, by parser name. */\n as?: string;\n /** `--name`: what to call the template. Defaults to the page's own doctype. */\n name?: string;\n /** `-f/--format`: how the file is written. Defaults to `yaml`. */\n format?: InferFormat;\n /** `-o/--out`: write here instead of returning text for stdout. */\n out?: string;\n /** `--force`: replace an existing `--out`. */\n force?: boolean;\n cwd?: string;\n /** Content for the `-` page, injected by the CLI and by tests. */\n stdinContent?: string;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: skip discovery. */\n noConfig?: boolean;\n /** Told which config governed the run, and where it came from. */\n onConfigLoaded?: (info: { path: string; dir: string }) => void;\n}\n\nexport interface TemplatesInferResult {\n /** The name the template was written under. */\n name: string;\n /** The inferred file, for a caller that wants the data rather than the text. */\n file: TemplateFile;\n /** The serialized template file, exactly as written. */\n text: string;\n /** Where it was written. Absent without `--out`. */\n written?: string;\n}\n\n/**\n * The parser that reads this page.\n *\n * Resolved before anything is read, as `runLint` does it: a typo in `--as`\n * should fail immediately rather than after a file was opened it was going to\n * mis-parse anyway. A name no parser answers to is unknown whatever it was\n * meant to name, so the message points at the one command that lists them.\n */\nfunction parserFor(page: string, as: string | undefined): DocumentParser {\n if (as !== undefined) {\n const forced = parserByName(as);\n if (forced) return forced;\n throw new LintError(\n `Unknown format \"${as}\". Run \"manni lint tools\" to see the formats manni lint reads.`,\n );\n }\n if (page === STDIN) {\n throw new LintError(\n \"Reading from stdin (-) requires --as <format> to choose a parser.\",\n );\n }\n const ext = extname(page);\n const parser = parserForExtension(ext);\n if (parser) return parser;\n throw new LintError(unsupportedFormatMessage(ext || page));\n}\n\n/**\n * What the template is called: `--name`, else the page's own doctype, else the\n * file's stem.\n *\n * The doctype first because that is the handle the page already carries, and\n * the one `types:` will route on once the author adds it. A file read from\n * stdin has no stem, so it falls back to a word rather than to `-`.\n */\nfunction defaultName(tree: DocumentTree, page: string): string {\n const declared = tree.frontmatter?.[\"type\"];\n if (typeof declared === \"string\" && declared.trim().length > 0) {\n return declared.trim();\n }\n if (page === STDIN) return STDIN_NAME;\n return basename(page, extname(page)) || STDIN_NAME;\n}\n\n/**\n * Infer a template from one page.\n *\n * One page, never a set. A template is a generalisation, and this makes exactly\n * the generalisation one exemplar supports; inferring from several would mean\n * deciding which differences are variation and which are mistakes, which is the\n * author's judgment and not the tool's.\n */\nexport async function runTemplatesInfer(\n opts: TemplatesInferOptions,\n): Promise<TemplatesInferResult> {\n const format = opts.format ?? \"yaml\";\n if (!isInferFormat(format)) {\n throw new LintError(\n `Unknown --format \"${String(format)}\". Use yaml or json.`,\n );\n }\n\n // Which config governs the run, said once, the way every other lint verb\n // says it. With a page typed on the command line the base stays the working\n // directory, so the path means what it looked like it meant.\n const run = await resolveLintRun({\n cwd: opts.cwd ?? process.cwd(),\n ...(opts.configPath === undefined ? {} : { configPath: opts.configPath }),\n ...(opts.noConfig === undefined ? {} : { noConfig: opts.noConfig }),\n inputs: [opts.page],\n ...(opts.onConfigLoaded === undefined\n ? {}\n : { onConfigLoaded: opts.onConfigLoaded }),\n });\n const cwd = run.base;\n\n const parser = parserFor(opts.page, opts.as);\n // A name the schema cannot hold is refused before the page is read, beside\n // the other refusals: a run that is going to fail should leave the working\n // tree, and the reader's terminal, exactly as it found them.\n if (opts.name !== undefined) assertTemplateName(opts.name);\n\n // Every refusal happens before the write, and the `--out` guard happens\n // before the read - the ordering `meta schemas infer` established. The path\n // is echoed as it was typed, because that is the string the reader will edit.\n let absOut: string | undefined;\n if (opts.out !== undefined) {\n absOut = resolve(cwd, opts.out);\n if (opts.force !== true && existsSync(absOut)) {\n throw new LintError(`${opts.out} exists. Pass --force to overwrite it.`);\n }\n }\n\n let content: string;\n if (opts.page === STDIN) {\n content = opts.stdinContent ?? \"\";\n } else {\n try {\n content = await readFile(resolve(cwd, opts.page), \"utf8\");\n } catch (err) {\n // The OS message travels verbatim: \"permission denied\" and \"no such\n // file\" send the reader to different places, and this cannot tell which.\n throw new LintError(\n `\"${opts.page}\" could not be read: ${errorMessage(err)}`,\n );\n }\n }\n\n let tree: DocumentTree;\n try {\n tree = parser.parse(content, opts.page === STDIN ? \"<stdin>\" : opts.page);\n } catch (err) {\n // A page that will not parse has no shape to infer, and the parser's own\n // message already names the file and the syntax it choked on.\n if (err instanceof ToolError) throw new LintError(err.message);\n throw err;\n }\n\n const name = opts.name ?? defaultName(tree, opts.page);\n const file = inferTemplateFile(tree, name);\n const text = renderTemplateFile(file, format);\n\n if (absOut === undefined) return { name, file, text };\n\n await mkdir(dirname(absOut), { recursive: true });\n await writeTextAtomic(absOut, text);\n return { name, file, text, written: opts.out };\n}\n","/**\n * `tools` command core. One row per lint job: which tool performs it, whether\n * this checkout can run it, what it read its settings from, and the input\n * formats it understands.\n *\n * It replaces `formats`, which reported the parser registry alone. Proposal\n * 0050 records the rename. The registry is here as one column of the job that\n * reads it, because the formats belong to the tool performing that job.\n *\n * The column lists exactly the formats the tool reads, so a row carries no\n * state: a listed format is one that is read, and `--as` accepts every name in\n * it.\n *\n * Returns data; `src/lint/reporters/index.ts` renders it.\n */\nimport type { ContentKind } from \"../types.js\";\nimport { BLOCK_KIND_NODE } from \"../core/template.js\";\nimport { resolveStructureTool } from \"../tools/index.js\";\nimport {\n LINT_JOBS,\n resolveLintRun,\n type LintConfig,\n type LintJob,\n type LintTool,\n} from \"../core/config.js\";\n\n/**\n * The content kinds a template rule can actually name - `BLOCK_KIND_NODE`'s\n * values, the nine block-rule keys map onto. `manni lint tools` lists this\n * column to answer \"can my rule run against this format\", and a rule can\n * never ask about `listItem`, `tableRow`, `tableCell`, or `definitionItem`:\n * those are structural kinds a parser reports so the content model can\n * describe a list's items or a table's cells, not kinds a `sections:` rule\n * counts on its own. What a parser *declares* (`DocumentParser.kinds`, read by\n * the pruner in `validator.ts`) is untouched - this is a display decision, so\n * it belongs here rather than trimming the declaration itself.\n */\nconst REPORTABLE_KINDS = new Set<ContentKind>(Object.values(BLOCK_KIND_NODE));\n\nexport interface FormatInfo {\n /** Parser name, also what `--as` accepts. */\n name: string;\n label: string;\n extensions: string[];\n /** The content kinds this format's parser actually emits today. */\n kinds: ContentKind[];\n}\n\n/** One job, and the tool that would perform it on this run. */\nexport interface ToolInfo {\n job: LintJob;\n tool: LintTool;\n /** Whether the config declares this job, or anything the job's tool reads. */\n configured: boolean;\n /** Whether the tool can run here, as its own probe reported it. */\n available: boolean;\n /**\n * The version the probe reported, or null when it reported none.\n *\n * Null rather than a placeholder string, because this is the shape\n * `-f json` emits: a consumer can test for an absent version, where a dash\n * would be a value it has to know to recognize. The pretty reporter renders\n * the dash.\n */\n version: string | null;\n /** Where the tool read its settings: the config file, or the defaults. */\n config: string;\n /** The input formats the tool reads. */\n formats: FormatInfo[];\n}\n\nexport interface ToolsOptions {\n cwd?: string;\n /** `-c/--config`. */\n configPath?: string;\n /** `--no-config`: ignore any discovered config file. */\n noConfig?: boolean;\n}\n\n/** What a run with no config file to read reports in the `config` column. */\nexport const BUILT_IN_DEFAULTS = \"built-in defaults\";\n\n/**\n * Whether the config says anything about this job.\n *\n * The job's own mapping counts, and so does every key its tool reads: a repo\n * that has written `templates:` and `overrides:` has configured the structure\n * job whether or not it also spelled `structure:` out. Saying otherwise would\n * report \"not configured\" beside a run those keys visibly govern.\n */\nfunction isConfigured(job: LintJob, config: LintConfig): boolean {\n if (config[job] !== undefined) return true;\n return (\n config.templates !== undefined ||\n config.template !== undefined ||\n config.types !== undefined ||\n config.overrides !== undefined\n );\n}\n\nexport async function runTools(opts: ToolsOptions = {}): Promise<ToolInfo[]> {\n // The same resolution every other command does, so a config this command\n // cannot read is the same exit 2 with the same message, rather than a row\n // saying \"built-in defaults\" over a file that is really there and broken.\n const cwd = opts.cwd ?? process.cwd();\n const run = await resolveLintRun({\n cwd,\n configPath: opts.configPath,\n noConfig: opts.noConfig,\n inputs: [],\n });\n\n return await Promise.all(\n LINT_JOBS.map(async (job) => {\n const tool: LintTool = run.config[job]?.tool ?? \"manni\";\n // The row is the tool's own answer about itself. It used to be two\n // literals that happened to be right while manni was the only tool:\n // \"available\" was hard-coded true, and the version was this package's\n // whatever performed the job.\n const descriptor = resolveStructureTool(tool);\n // The family's `tools:` travels with the probe: a tool outside the\n // package is found where its own `tools.<tool>` says it is, so probing\n // without it would report \"not available\" over the very installation the\n // run would go on to use.\n const probed = await descriptor.probe({\n cwd,\n tools: run.tools,\n ...(run.configDir === undefined ? {} : { configDir: run.configDir }),\n });\n return {\n job,\n tool,\n configured: isConfigured(job, run.config),\n available: probed.available,\n version: probed.version,\n config: run.configSource ?? BUILT_IN_DEFAULTS,\n formats: descriptor.formats().map((format) => ({\n ...format,\n kinds: format.kinds.filter((kind) => REPORTABLE_KINDS.has(kind)),\n })),\n };\n }),\n );\n}\n"],"mappings":"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","names":[]}