@redocly/recheck 0.15.0 → 2.58.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 (1034) hide show
  1. package/README.md +71 -1886
  2. package/examples/appendices/google.appendix.yaml +1 -1
  3. package/examples/appendices/inclusive-language.appendix.yaml +1 -1
  4. package/examples/appendices/microsoft.appendix.yaml +1 -1
  5. package/examples/appendices/plain-language.appendix.yaml +1 -1
  6. package/examples/appendices/technical-english.appendix.yaml +1 -1
  7. package/examples/google.yaml +7 -7
  8. package/examples/inclusive-language.yaml +7 -7
  9. package/examples/microsoft.yaml +7 -7
  10. package/examples/plain-language.yaml +7 -7
  11. package/examples/technical-english.yaml +7 -7
  12. package/lib/actions/baseline.d.ts +15 -0
  13. package/lib/actions/baseline.d.ts.map +1 -0
  14. package/lib/actions/baseline.js +51 -0
  15. package/lib/actions/baseline.js.map +1 -0
  16. package/lib/actions/lint.d.ts +51 -0
  17. package/lib/actions/lint.d.ts.map +1 -0
  18. package/lib/actions/lint.js +123 -0
  19. package/lib/actions/lint.js.map +1 -0
  20. package/lib/actions/markdoc-schema.d.ts +34 -0
  21. package/lib/actions/markdoc-schema.d.ts.map +1 -0
  22. package/lib/actions/markdoc-schema.js +106 -0
  23. package/lib/actions/markdoc-schema.js.map +1 -0
  24. package/lib/actions/readability.d.ts +25 -0
  25. package/lib/actions/readability.d.ts.map +1 -0
  26. package/lib/actions/readability.js +47 -0
  27. package/lib/actions/readability.js.map +1 -0
  28. package/lib/actions/roots.d.ts +7 -0
  29. package/lib/actions/roots.d.ts.map +1 -0
  30. package/lib/actions/roots.js +36 -0
  31. package/lib/actions/roots.js.map +1 -0
  32. package/lib/config/presets/api-descriptions.d.ts +8 -0
  33. package/lib/config/presets/api-descriptions.d.ts.map +1 -0
  34. package/lib/config/presets/api-descriptions.js +24 -0
  35. package/lib/config/presets/api-descriptions.js.map +1 -0
  36. package/lib/config/presets/google.d.ts +3 -0
  37. package/lib/config/presets/google.d.ts.map +1 -0
  38. package/lib/config/presets/google.js +1086 -0
  39. package/lib/config/presets/google.js.map +1 -0
  40. package/lib/config/presets/inclusive-language.d.ts +3 -0
  41. package/lib/config/presets/inclusive-language.d.ts.map +1 -0
  42. package/lib/config/presets/inclusive-language.js +151 -0
  43. package/lib/config/presets/inclusive-language.js.map +1 -0
  44. package/lib/config/presets/index.d.ts +16 -0
  45. package/lib/config/presets/index.d.ts.map +1 -0
  46. package/lib/config/presets/index.js +38 -0
  47. package/lib/config/presets/index.js.map +1 -0
  48. package/lib/config/presets/markdoc.d.ts +3 -0
  49. package/lib/config/presets/markdoc.d.ts.map +1 -0
  50. package/lib/config/presets/markdoc.js +45 -0
  51. package/lib/config/presets/markdoc.js.map +1 -0
  52. package/lib/config/presets/markdown-relaxed.d.ts +3 -0
  53. package/lib/config/presets/markdown-relaxed.d.ts.map +1 -0
  54. package/lib/config/presets/markdown-relaxed.js +34 -0
  55. package/lib/config/presets/markdown-relaxed.js.map +1 -0
  56. package/lib/config/presets/markdown.d.ts +11 -0
  57. package/lib/config/presets/markdown.d.ts.map +1 -0
  58. package/lib/config/presets/markdown.js +73 -0
  59. package/lib/config/presets/markdown.js.map +1 -0
  60. package/lib/config/presets/microsoft.d.ts +3 -0
  61. package/lib/config/presets/microsoft.d.ts.map +1 -0
  62. package/lib/config/presets/microsoft.js +1260 -0
  63. package/lib/config/presets/microsoft.js.map +1 -0
  64. package/lib/config/presets/minimal.d.ts +3 -0
  65. package/lib/config/presets/minimal.d.ts.map +1 -0
  66. package/lib/config/presets/minimal.js +13 -0
  67. package/lib/config/presets/minimal.js.map +1 -0
  68. package/lib/config/presets/plain-language.d.ts +3 -0
  69. package/lib/config/presets/plain-language.d.ts.map +1 -0
  70. package/lib/config/presets/plain-language.js +175 -0
  71. package/lib/config/presets/plain-language.js.map +1 -0
  72. package/lib/config/presets/prose.d.ts +3 -0
  73. package/lib/config/presets/prose.d.ts.map +1 -0
  74. package/lib/config/presets/prose.js +60 -0
  75. package/lib/config/presets/prose.js.map +1 -0
  76. package/lib/config/presets/technical-english.d.ts +22 -0
  77. package/lib/config/presets/technical-english.d.ts.map +1 -0
  78. package/lib/config/presets/technical-english.js +61 -0
  79. package/lib/config/presets/technical-english.js.map +1 -0
  80. package/lib/config/resolve.d.ts +36 -0
  81. package/lib/config/resolve.d.ts.map +1 -0
  82. package/lib/config/resolve.js +106 -0
  83. package/lib/config/resolve.js.map +1 -0
  84. package/lib/config/schema.d.ts +215 -0
  85. package/lib/config/schema.d.ts.map +1 -0
  86. package/lib/config/schema.js +152 -0
  87. package/lib/config/schema.js.map +1 -0
  88. package/lib/config/validate.d.ts +19 -0
  89. package/lib/config/validate.d.ts.map +1 -0
  90. package/lib/config/validate.js +1049 -0
  91. package/lib/config/validate.js.map +1 -0
  92. package/lib/core/auto-fix.d.ts.map +1 -0
  93. package/lib/core/auto-fix.js +94 -0
  94. package/lib/core/auto-fix.js.map +1 -0
  95. package/lib/core/baseline.d.ts +43 -0
  96. package/lib/core/baseline.d.ts.map +1 -0
  97. package/lib/core/baseline.js +142 -0
  98. package/lib/core/baseline.js.map +1 -0
  99. package/lib/core/case-preserve.d.ts +11 -0
  100. package/lib/core/case-preserve.d.ts.map +1 -0
  101. package/lib/core/case-preserve.js +22 -0
  102. package/lib/core/case-preserve.js.map +1 -0
  103. package/lib/core/directives.d.ts.map +1 -0
  104. package/lib/core/directives.js +66 -0
  105. package/lib/core/directives.js.map +1 -0
  106. package/lib/core/files.d.ts +31 -0
  107. package/lib/core/files.d.ts.map +1 -0
  108. package/lib/core/files.js +184 -0
  109. package/lib/core/files.js.map +1 -0
  110. package/lib/core/inline-code.d.ts +33 -0
  111. package/lib/core/inline-code.d.ts.map +1 -0
  112. package/lib/core/inline-code.js +50 -0
  113. package/lib/core/inline-code.js.map +1 -0
  114. package/lib/core/line-endings.d.ts +13 -0
  115. package/lib/core/line-endings.d.ts.map +1 -0
  116. package/lib/core/line-endings.js +39 -0
  117. package/lib/core/line-endings.js.map +1 -0
  118. package/lib/core/markdoc-tags.d.ts +48 -0
  119. package/lib/core/markdoc-tags.d.ts.map +1 -0
  120. package/lib/core/markdoc-tags.js +102 -0
  121. package/lib/core/markdoc-tags.js.map +1 -0
  122. package/lib/core/prose-extract.d.ts +6 -0
  123. package/lib/core/prose-extract.d.ts.map +1 -0
  124. package/lib/core/prose-extract.js +71 -0
  125. package/lib/core/prose-extract.js.map +1 -0
  126. package/lib/core/readability.d.ts +17 -0
  127. package/lib/core/readability.d.ts.map +1 -0
  128. package/lib/core/readability.js +34 -0
  129. package/lib/core/readability.js.map +1 -0
  130. package/lib/core/rule-filters.d.ts +29 -0
  131. package/lib/core/rule-filters.d.ts.map +1 -0
  132. package/lib/core/rule-filters.js +88 -0
  133. package/lib/core/rule-filters.js.map +1 -0
  134. package/lib/core/runner.d.ts +60 -0
  135. package/lib/core/runner.d.ts.map +1 -0
  136. package/lib/core/runner.js +305 -0
  137. package/lib/core/runner.js.map +1 -0
  138. package/lib/core/summary.d.ts +4 -0
  139. package/lib/core/summary.d.ts.map +1 -0
  140. package/lib/core/summary.js +37 -0
  141. package/lib/core/summary.js.map +1 -0
  142. package/lib/core/timing.d.ts +9 -0
  143. package/lib/core/timing.d.ts.map +1 -0
  144. package/lib/core/timing.js +19 -0
  145. package/lib/core/timing.js.map +1 -0
  146. package/lib/data/markdoc-realm-schema.d.ts.map +1 -0
  147. package/lib/data/markdoc-realm-schema.js +782 -0
  148. package/lib/data/markdoc-realm-schema.js.map +1 -0
  149. package/lib/data/proper-nouns.d.ts.map +1 -0
  150. package/lib/data/proper-nouns.js +42 -0
  151. package/lib/data/proper-nouns.js.map +1 -0
  152. package/lib/data/realm-front-matter-schema.d.ts +12 -0
  153. package/lib/data/realm-front-matter-schema.d.ts.map +1 -0
  154. package/lib/data/realm-front-matter-schema.js +51 -0
  155. package/lib/data/realm-front-matter-schema.js.map +1 -0
  156. package/lib/index.d.ts +81 -0
  157. package/lib/index.d.ts.map +1 -0
  158. package/lib/index.js +114 -0
  159. package/lib/index.js.map +1 -0
  160. package/lib/metrics/formulas.d.ts +9 -0
  161. package/lib/metrics/formulas.d.ts.map +1 -0
  162. package/lib/metrics/formulas.js +59 -0
  163. package/lib/metrics/formulas.js.map +1 -0
  164. package/lib/metrics/statistics.d.ts +14 -0
  165. package/lib/metrics/statistics.d.ts.map +1 -0
  166. package/lib/metrics/statistics.js +35 -0
  167. package/lib/metrics/statistics.js.map +1 -0
  168. package/lib/parser/index.d.ts +13 -0
  169. package/lib/parser/index.d.ts.map +1 -0
  170. package/lib/parser/index.js +123 -0
  171. package/lib/parser/index.js.map +1 -0
  172. package/lib/parser/markdoc/extract-statics.d.ts +28 -0
  173. package/lib/parser/markdoc/extract-statics.d.ts.map +1 -0
  174. package/lib/parser/markdoc/extract-statics.js +80 -0
  175. package/lib/parser/markdoc/extract-statics.js.map +1 -0
  176. package/lib/parser/markdoc/pairing.d.ts +38 -0
  177. package/lib/parser/markdoc/pairing.d.ts.map +1 -0
  178. package/lib/parser/markdoc/pairing.js +77 -0
  179. package/lib/parser/markdoc/pairing.js.map +1 -0
  180. package/lib/parser/markdoc/schema.d.ts +56 -0
  181. package/lib/parser/markdoc/schema.d.ts.map +1 -0
  182. package/lib/parser/markdoc/schema.js +60 -0
  183. package/lib/parser/markdoc/schema.js.map +1 -0
  184. package/lib/parser/markdoc/span.d.ts +52 -0
  185. package/lib/parser/markdoc/span.d.ts.map +1 -0
  186. package/lib/parser/markdoc/span.js +577 -0
  187. package/lib/parser/markdoc/span.js.map +1 -0
  188. package/lib/parser/markdoc/structure.d.ts +17 -0
  189. package/lib/parser/markdoc/structure.d.ts.map +1 -0
  190. package/lib/parser/markdoc/structure.js +121 -0
  191. package/lib/parser/markdoc/structure.js.map +1 -0
  192. package/lib/parser/markdoc/syntax.d.ts +17 -0
  193. package/lib/parser/markdoc/syntax.d.ts.map +1 -0
  194. package/lib/parser/markdoc/syntax.js +262 -0
  195. package/lib/parser/markdoc/syntax.js.map +1 -0
  196. package/lib/parser/types.d.ts.map +1 -0
  197. package/lib/presets.d.ts +6 -0
  198. package/lib/presets.d.ts.map +1 -0
  199. package/lib/presets.js +12 -0
  200. package/lib/presets.js.map +1 -0
  201. package/lib/rules/registry.d.ts +13 -0
  202. package/lib/rules/registry.d.ts.map +1 -0
  203. package/lib/rules/registry.js +54 -0
  204. package/lib/rules/registry.js.map +1 -0
  205. package/lib/rules/scope/capitalization.d.ts.map +1 -0
  206. package/lib/rules/scope/capitalization.js +128 -0
  207. package/lib/rules/scope/capitalization.js.map +1 -0
  208. package/lib/rules/scope/conditional.d.ts.map +1 -0
  209. package/lib/rules/scope/conditional.js +93 -0
  210. package/lib/rules/scope/conditional.js.map +1 -0
  211. package/lib/rules/scope/consistency.d.ts.map +1 -0
  212. package/lib/rules/scope/consistency.js +118 -0
  213. package/lib/rules/scope/consistency.js.map +1 -0
  214. package/lib/rules/scope/length.d.ts.map +1 -0
  215. package/lib/rules/scope/length.js +50 -0
  216. package/lib/rules/scope/length.js.map +1 -0
  217. package/lib/rules/scope/max-image-size.d.ts.map +1 -0
  218. package/lib/rules/scope/max-image-size.js +55 -0
  219. package/lib/rules/scope/max-image-size.js.map +1 -0
  220. package/lib/rules/scope/metric.d.ts +3 -0
  221. package/lib/rules/scope/metric.d.ts.map +1 -0
  222. package/lib/rules/scope/metric.js +59 -0
  223. package/lib/rules/scope/metric.js.map +1 -0
  224. package/lib/rules/scope/occurrence.d.ts.map +1 -0
  225. package/lib/rules/scope/occurrence.js +41 -0
  226. package/lib/rules/scope/occurrence.js.map +1 -0
  227. package/lib/rules/scope/pattern.d.ts.map +1 -0
  228. package/lib/rules/scope/pattern.js +58 -0
  229. package/lib/rules/scope/pattern.js.map +1 -0
  230. package/lib/rules/scope/repetition.d.ts.map +1 -0
  231. package/lib/rules/scope/repetition.js +134 -0
  232. package/lib/rules/scope/repetition.js.map +1 -0
  233. package/lib/rules/scope/semantic-line-breaks.d.ts.map +1 -0
  234. package/lib/rules/scope/semantic-line-breaks.js +180 -0
  235. package/lib/rules/scope/semantic-line-breaks.js.map +1 -0
  236. package/lib/rules/scope/spelling.d.ts +11 -0
  237. package/lib/rules/scope/spelling.d.ts.map +1 -0
  238. package/lib/rules/scope/spelling.js +146 -0
  239. package/lib/rules/scope/spelling.js.map +1 -0
  240. package/lib/rules/scope/swap.d.ts.map +1 -0
  241. package/lib/rules/scope/swap.js +111 -0
  242. package/lib/rules/scope/swap.js.map +1 -0
  243. package/lib/rules/scope/title-case.d.ts +24 -0
  244. package/lib/rules/scope/title-case.d.ts.map +1 -0
  245. package/lib/rules/scope/title-case.js +216 -0
  246. package/lib/rules/scope/title-case.js.map +1 -0
  247. package/lib/rules/token/blanks-around-fences.d.ts.map +1 -0
  248. package/lib/rules/token/blanks-around-fences.js.map +1 -0
  249. package/lib/rules/token/blanks-around-headings.d.ts.map +1 -0
  250. package/lib/rules/token/blanks-around-headings.js +96 -0
  251. package/lib/rules/token/blanks-around-headings.js.map +1 -0
  252. package/lib/rules/token/blanks-around-lists.d.ts.map +1 -0
  253. package/lib/rules/token/blanks-around-lists.js +48 -0
  254. package/lib/rules/token/blanks-around-lists.js.map +1 -0
  255. package/lib/rules/token/blanks-around-tables.d.ts.map +1 -0
  256. package/lib/rules/token/blanks-around-tables.js +40 -0
  257. package/lib/rules/token/blanks-around-tables.js.map +1 -0
  258. package/lib/rules/token/code-block-style.d.ts.map +1 -0
  259. package/lib/rules/token/code-block-style.js.map +1 -0
  260. package/lib/rules/token/code-fence-style.d.ts.map +1 -0
  261. package/lib/rules/token/code-fence-style.js.map +1 -0
  262. package/lib/rules/token/commands-show-output.d.ts.map +1 -0
  263. package/lib/rules/token/commands-show-output.js.map +1 -0
  264. package/lib/rules/token/descriptive-link-text.d.ts.map +1 -0
  265. package/lib/rules/token/descriptive-link-text.js +46 -0
  266. package/lib/rules/token/descriptive-link-text.js.map +1 -0
  267. package/lib/rules/token/fenced-code-language.d.ts.map +1 -0
  268. package/lib/rules/token/fenced-code-language.js.map +1 -0
  269. package/lib/rules/token/first-line-h1.d.ts.map +1 -0
  270. package/lib/rules/token/first-line-h1.js +83 -0
  271. package/lib/rules/token/first-line-h1.js.map +1 -0
  272. package/lib/rules/token/front-matter.d.ts.map +1 -0
  273. package/lib/rules/token/front-matter.js +169 -0
  274. package/lib/rules/token/front-matter.js.map +1 -0
  275. package/lib/rules/token/heading-increment.d.ts.map +1 -0
  276. package/lib/rules/token/heading-increment.js +26 -0
  277. package/lib/rules/token/heading-increment.js.map +1 -0
  278. package/lib/rules/token/heading-start-left.d.ts.map +1 -0
  279. package/lib/rules/token/heading-start-left.js.map +1 -0
  280. package/lib/rules/token/heading-style.d.ts.map +1 -0
  281. package/lib/rules/token/heading-style.js.map +1 -0
  282. package/lib/rules/token/helpers.d.ts +115 -0
  283. package/lib/rules/token/helpers.d.ts.map +1 -0
  284. package/lib/rules/token/helpers.js +502 -0
  285. package/lib/rules/token/helpers.js.map +1 -0
  286. package/lib/rules/token/hr-style.d.ts.map +1 -0
  287. package/lib/rules/token/hr-style.js.map +1 -0
  288. package/lib/rules/token/index.d.ts +65 -0
  289. package/lib/rules/token/index.d.ts.map +1 -0
  290. package/lib/rules/token/index.js +157 -0
  291. package/lib/rules/token/index.js.map +1 -0
  292. package/lib/rules/token/line-length.d.ts.map +1 -0
  293. package/lib/rules/token/line-length.js +96 -0
  294. package/lib/rules/token/line-length.js.map +1 -0
  295. package/lib/rules/token/link-fragments.d.ts.map +1 -0
  296. package/lib/rules/token/link-fragments.js +398 -0
  297. package/lib/rules/token/link-fragments.js.map +1 -0
  298. package/lib/rules/token/link-image-reference-definitions.d.ts.map +1 -0
  299. package/lib/rules/token/link-image-reference-definitions.js.map +1 -0
  300. package/lib/rules/token/link-image-style.d.ts.map +1 -0
  301. package/lib/rules/token/link-image-style.js +138 -0
  302. package/lib/rules/token/link-image-style.js.map +1 -0
  303. package/lib/rules/token/list-indent.d.ts.map +1 -0
  304. package/lib/rules/token/list-indent.js.map +1 -0
  305. package/lib/rules/token/list-length.d.ts.map +1 -0
  306. package/lib/rules/token/list-length.js +31 -0
  307. package/lib/rules/token/list-length.js.map +1 -0
  308. package/lib/rules/token/list-marker-space.d.ts.map +1 -0
  309. package/lib/rules/token/list-marker-space.js.map +1 -0
  310. package/lib/rules/token/markdoc-attributes.d.ts.map +1 -0
  311. package/lib/rules/token/markdoc-attributes.js +198 -0
  312. package/lib/rules/token/markdoc-attributes.js.map +1 -0
  313. package/lib/rules/token/markdoc-pairing.d.ts.map +1 -0
  314. package/lib/rules/token/markdoc-pairing.js +65 -0
  315. package/lib/rules/token/markdoc-pairing.js.map +1 -0
  316. package/lib/rules/token/markdoc-syntax.d.ts.map +1 -0
  317. package/lib/rules/token/markdoc-syntax.js +84 -0
  318. package/lib/rules/token/markdoc-syntax.js.map +1 -0
  319. package/lib/rules/token/markdoc-unknown-tag.d.ts.map +1 -0
  320. package/lib/rules/token/markdoc-unknown-tag.js +44 -0
  321. package/lib/rules/token/markdoc-unknown-tag.js.map +1 -0
  322. package/lib/rules/token/no-alt-text.d.ts.map +1 -0
  323. package/lib/rules/token/no-alt-text.js +43 -0
  324. package/lib/rules/token/no-alt-text.js.map +1 -0
  325. package/lib/rules/token/no-bare-urls.d.ts.map +1 -0
  326. package/lib/rules/token/no-bare-urls.js +74 -0
  327. package/lib/rules/token/no-bare-urls.js.map +1 -0
  328. package/lib/rules/token/no-blanks-blockquote.d.ts.map +1 -0
  329. package/lib/rules/token/no-blanks-blockquote.js.map +1 -0
  330. package/lib/rules/token/no-duplicate-heading.d.ts.map +1 -0
  331. package/lib/rules/token/no-duplicate-heading.js +89 -0
  332. package/lib/rules/token/no-duplicate-heading.js.map +1 -0
  333. package/lib/rules/token/no-duplicate-link-destinations.d.ts.map +1 -0
  334. package/lib/rules/token/no-duplicate-link-destinations.js +54 -0
  335. package/lib/rules/token/no-duplicate-link-destinations.js.map +1 -0
  336. package/lib/rules/token/no-emphasis-as-heading.d.ts.map +1 -0
  337. package/lib/rules/token/no-emphasis-as-heading.js +39 -0
  338. package/lib/rules/token/no-emphasis-as-heading.js.map +1 -0
  339. package/lib/rules/token/no-empty-headings.d.ts.map +1 -0
  340. package/lib/rules/token/no-empty-headings.js +21 -0
  341. package/lib/rules/token/no-empty-headings.js.map +1 -0
  342. package/lib/rules/token/no-empty-links.d.ts.map +1 -0
  343. package/lib/rules/token/no-empty-links.js.map +1 -0
  344. package/lib/rules/token/no-hard-tabs.d.ts.map +1 -0
  345. package/lib/rules/token/no-hard-tabs.js.map +1 -0
  346. package/lib/rules/token/no-inline-html.d.ts.map +1 -0
  347. package/lib/rules/token/no-inline-html.js +41 -0
  348. package/lib/rules/token/no-inline-html.js.map +1 -0
  349. package/lib/rules/token/no-multiple-blanks.d.ts.map +1 -0
  350. package/lib/rules/token/no-multiple-blanks.js.map +1 -0
  351. package/lib/rules/token/no-multiple-space-atx.d.ts +9 -0
  352. package/lib/rules/token/no-multiple-space-atx.d.ts.map +1 -0
  353. package/lib/rules/token/no-multiple-space-atx.js +46 -0
  354. package/lib/rules/token/no-multiple-space-atx.js.map +1 -0
  355. package/lib/rules/token/no-multiple-space-closed-atx.d.ts.map +1 -0
  356. package/lib/rules/token/no-multiple-space-closed-atx.js.map +1 -0
  357. package/lib/rules/token/no-reversed-links.d.ts.map +1 -0
  358. package/lib/rules/token/no-reversed-links.js.map +1 -0
  359. package/lib/rules/token/no-space-in-code.d.ts.map +1 -0
  360. package/lib/rules/token/no-space-in-code.js.map +1 -0
  361. package/lib/rules/token/no-space-in-emphasis.d.ts.map +1 -0
  362. package/lib/rules/token/no-space-in-emphasis.js +72 -0
  363. package/lib/rules/token/no-space-in-emphasis.js.map +1 -0
  364. package/lib/rules/token/no-space-in-links.d.ts.map +1 -0
  365. package/lib/rules/token/no-space-in-links.js.map +1 -0
  366. package/lib/rules/token/no-trailing-punctuation.d.ts.map +1 -0
  367. package/lib/rules/token/no-trailing-punctuation.js.map +1 -0
  368. package/lib/rules/token/no-trailing-spaces.d.ts.map +1 -0
  369. package/lib/rules/token/no-trailing-spaces.js.map +1 -0
  370. package/lib/rules/token/ol-prefix.d.ts.map +1 -0
  371. package/lib/rules/token/ol-prefix.js.map +1 -0
  372. package/lib/rules/token/proper-names.d.ts.map +1 -0
  373. package/lib/rules/token/proper-names.js +87 -0
  374. package/lib/rules/token/proper-names.js.map +1 -0
  375. package/lib/rules/token/reference-links-images.d.ts.map +1 -0
  376. package/lib/rules/token/reference-links-images.js.map +1 -0
  377. package/lib/rules/token/required-headings.d.ts.map +1 -0
  378. package/lib/rules/token/required-headings.js +73 -0
  379. package/lib/rules/token/required-headings.js.map +1 -0
  380. package/lib/rules/token/single-h1.d.ts.map +1 -0
  381. package/lib/rules/token/single-h1.js +43 -0
  382. package/lib/rules/token/single-h1.js.map +1 -0
  383. package/lib/rules/token/table-column-count.d.ts.map +1 -0
  384. package/lib/rules/token/table-column-count.js.map +1 -0
  385. package/lib/rules/token/table-column-style.d.ts.map +1 -0
  386. package/lib/rules/token/table-column-style.js +162 -0
  387. package/lib/rules/token/table-column-style.js.map +1 -0
  388. package/lib/rules/token/table-pipe-style.d.ts.map +1 -0
  389. package/lib/rules/token/table-pipe-style.js.map +1 -0
  390. package/lib/rules/token/ul-indent.d.ts.map +1 -0
  391. package/lib/rules/token/ul-indent.js.map +1 -0
  392. package/lib/rules/token/ul-style.d.ts.map +1 -0
  393. package/lib/rules/token/ul-style.js +70 -0
  394. package/lib/rules/token/ul-style.js.map +1 -0
  395. package/lib/rules/types.d.ts +62 -0
  396. package/lib/rules/types.d.ts.map +1 -0
  397. package/lib/rules/utils.d.ts +18 -0
  398. package/lib/rules/utils.d.ts.map +1 -0
  399. package/lib/rules/utils.js +75 -0
  400. package/lib/rules/utils.js.map +1 -0
  401. package/lib/scopes/extractor.d.ts +6 -0
  402. package/lib/scopes/extractor.d.ts.map +1 -0
  403. package/lib/scopes/extractor.js +398 -0
  404. package/lib/scopes/extractor.js.map +1 -0
  405. package/lib/scopes/selector.d.ts +26 -0
  406. package/lib/scopes/selector.d.ts.map +1 -0
  407. package/lib/scopes/selector.js +78 -0
  408. package/lib/scopes/selector.js.map +1 -0
  409. package/lib/scopes/sentences.d.ts +13 -0
  410. package/lib/scopes/sentences.d.ts.map +1 -0
  411. package/lib/scopes/sentences.js +237 -0
  412. package/lib/scopes/sentences.js.map +1 -0
  413. package/lib/scopes/types.d.ts +35 -0
  414. package/lib/scopes/types.d.ts.map +1 -0
  415. package/lib/scopes/vocabulary.d.ts +12 -0
  416. package/lib/scopes/vocabulary.d.ts.map +1 -0
  417. package/lib/scopes/vocabulary.js +56 -0
  418. package/lib/scopes/vocabulary.js.map +1 -0
  419. package/lib/types/assertions.d.ts +97 -0
  420. package/lib/types/assertions.d.ts.map +1 -0
  421. package/lib/types/reporting.d.ts +23 -0
  422. package/lib/types/reporting.d.ts.map +1 -0
  423. package/lib/types/rules.d.ts +53 -0
  424. package/lib/types/rules.d.ts.map +1 -0
  425. package/lib/types/validation.d.ts +5 -0
  426. package/lib/types/validation.d.ts.map +1 -0
  427. package/lib/utils/is-plain-object.d.ts +2 -0
  428. package/lib/utils/is-plain-object.d.ts.map +1 -0
  429. package/lib/utils/is-plain-object.js +5 -0
  430. package/lib/utils/is-plain-object.js.map +1 -0
  431. package/package.json +58 -61
  432. package/presets/google/PROVENANCE.md +217 -221
  433. package/presets/inclusive-language/PROVENANCE.md +20 -19
  434. package/presets/microsoft/PROVENANCE.md +242 -243
  435. package/presets/plain-language/PROVENANCE.md +66 -60
  436. package/presets/technical-english/PROVENANCE.md +5 -5
  437. package/skills/recheck-config/SKILL.md +70 -20
  438. package/skills/recheck-lint/SKILL.md +37 -13
  439. package/dist/cli.d.ts +0 -3
  440. package/dist/cli.d.ts.map +0 -1
  441. package/dist/cli.js +0 -228
  442. package/dist/cli.js.map +0 -1
  443. package/dist/commands/baseline.d.ts +0 -10
  444. package/dist/commands/baseline.d.ts.map +0 -1
  445. package/dist/commands/baseline.js +0 -59
  446. package/dist/commands/baseline.js.map +0 -1
  447. package/dist/commands/markdoc-schema.d.ts +0 -17
  448. package/dist/commands/markdoc-schema.d.ts.map +0 -1
  449. package/dist/commands/markdoc-schema.js +0 -127
  450. package/dist/commands/markdoc-schema.js.map +0 -1
  451. package/dist/commands/readability.d.ts +0 -10
  452. package/dist/commands/readability.d.ts.map +0 -1
  453. package/dist/commands/readability.js +0 -90
  454. package/dist/commands/readability.js.map +0 -1
  455. package/dist/commands/run.d.ts +0 -21
  456. package/dist/commands/run.d.ts.map +0 -1
  457. package/dist/commands/run.js +0 -236
  458. package/dist/commands/run.js.map +0 -1
  459. package/dist/commands/validate.d.ts +0 -8
  460. package/dist/commands/validate.d.ts.map +0 -1
  461. package/dist/commands/validate.js +0 -43
  462. package/dist/commands/validate.js.map +0 -1
  463. package/dist/config/load.d.ts +0 -33
  464. package/dist/config/load.d.ts.map +0 -1
  465. package/dist/config/load.js +0 -98
  466. package/dist/config/load.js.map +0 -1
  467. package/dist/config/presets/api-descriptions.d.ts +0 -8
  468. package/dist/config/presets/api-descriptions.d.ts.map +0 -1
  469. package/dist/config/presets/api-descriptions.js +0 -24
  470. package/dist/config/presets/api-descriptions.js.map +0 -1
  471. package/dist/config/presets/google.d.ts +0 -3
  472. package/dist/config/presets/google.d.ts.map +0 -1
  473. package/dist/config/presets/google.js +0 -1671
  474. package/dist/config/presets/google.js.map +0 -1
  475. package/dist/config/presets/inclusive-language.d.ts +0 -3
  476. package/dist/config/presets/inclusive-language.d.ts.map +0 -1
  477. package/dist/config/presets/inclusive-language.js +0 -321
  478. package/dist/config/presets/inclusive-language.js.map +0 -1
  479. package/dist/config/presets/index.d.ts +0 -67
  480. package/dist/config/presets/index.d.ts.map +0 -1
  481. package/dist/config/presets/index.js +0 -141
  482. package/dist/config/presets/index.js.map +0 -1
  483. package/dist/config/presets/markdoc.d.ts +0 -21
  484. package/dist/config/presets/markdoc.d.ts.map +0 -1
  485. package/dist/config/presets/markdoc.js +0 -101
  486. package/dist/config/presets/markdoc.js.map +0 -1
  487. package/dist/config/presets/markdown-relaxed.d.ts +0 -3
  488. package/dist/config/presets/markdown-relaxed.d.ts.map +0 -1
  489. package/dist/config/presets/markdown-relaxed.js +0 -98
  490. package/dist/config/presets/markdown-relaxed.js.map +0 -1
  491. package/dist/config/presets/markdown.d.ts +0 -43
  492. package/dist/config/presets/markdown.d.ts.map +0 -1
  493. package/dist/config/presets/markdown.js +0 -132
  494. package/dist/config/presets/markdown.js.map +0 -1
  495. package/dist/config/presets/microsoft.d.ts +0 -3
  496. package/dist/config/presets/microsoft.d.ts.map +0 -1
  497. package/dist/config/presets/microsoft.js +0 -2268
  498. package/dist/config/presets/microsoft.js.map +0 -1
  499. package/dist/config/presets/minimal.d.ts +0 -3
  500. package/dist/config/presets/minimal.d.ts.map +0 -1
  501. package/dist/config/presets/minimal.js +0 -21
  502. package/dist/config/presets/minimal.js.map +0 -1
  503. package/dist/config/presets/plain-language.d.ts +0 -3
  504. package/dist/config/presets/plain-language.d.ts.map +0 -1
  505. package/dist/config/presets/plain-language.js +0 -351
  506. package/dist/config/presets/plain-language.js.map +0 -1
  507. package/dist/config/presets/prose.d.ts +0 -52
  508. package/dist/config/presets/prose.d.ts.map +0 -1
  509. package/dist/config/presets/prose.js +0 -138
  510. package/dist/config/presets/prose.js.map +0 -1
  511. package/dist/config/presets/technical-english.d.ts +0 -34
  512. package/dist/config/presets/technical-english.d.ts.map +0 -1
  513. package/dist/config/presets/technical-english.js +0 -79
  514. package/dist/config/presets/technical-english.js.map +0 -1
  515. package/dist/config/schema.d.ts +0 -226
  516. package/dist/config/schema.d.ts.map +0 -1
  517. package/dist/config/schema.js +0 -196
  518. package/dist/config/schema.js.map +0 -1
  519. package/dist/config/validate.d.ts +0 -22
  520. package/dist/config/validate.d.ts.map +0 -1
  521. package/dist/config/validate.js +0 -1315
  522. package/dist/config/validate.js.map +0 -1
  523. package/dist/core/auto-fix.d.ts.map +0 -1
  524. package/dist/core/auto-fix.js +0 -101
  525. package/dist/core/auto-fix.js.map +0 -1
  526. package/dist/core/baseline.d.ts +0 -49
  527. package/dist/core/baseline.d.ts.map +0 -1
  528. package/dist/core/baseline.js +0 -0
  529. package/dist/core/baseline.js.map +0 -1
  530. package/dist/core/case-preserve.d.ts +0 -46
  531. package/dist/core/case-preserve.d.ts.map +0 -1
  532. package/dist/core/case-preserve.js +0 -57
  533. package/dist/core/case-preserve.js.map +0 -1
  534. package/dist/core/directives.d.ts.map +0 -1
  535. package/dist/core/directives.js +0 -73
  536. package/dist/core/directives.js.map +0 -1
  537. package/dist/core/files.d.ts +0 -69
  538. package/dist/core/files.d.ts.map +0 -1
  539. package/dist/core/files.js +0 -260
  540. package/dist/core/files.js.map +0 -1
  541. package/dist/core/inline-code.d.ts +0 -87
  542. package/dist/core/inline-code.d.ts.map +0 -1
  543. package/dist/core/inline-code.js +0 -104
  544. package/dist/core/inline-code.js.map +0 -1
  545. package/dist/core/line-endings.d.ts +0 -32
  546. package/dist/core/line-endings.d.ts.map +0 -1
  547. package/dist/core/line-endings.js +0 -65
  548. package/dist/core/line-endings.js.map +0 -1
  549. package/dist/core/markdoc-tags.d.ts +0 -79
  550. package/dist/core/markdoc-tags.d.ts.map +0 -1
  551. package/dist/core/markdoc-tags.js +0 -131
  552. package/dist/core/markdoc-tags.js.map +0 -1
  553. package/dist/core/prose-extract.d.ts +0 -6
  554. package/dist/core/prose-extract.d.ts.map +0 -1
  555. package/dist/core/prose-extract.js +0 -79
  556. package/dist/core/prose-extract.js.map +0 -1
  557. package/dist/core/readability.d.ts +0 -17
  558. package/dist/core/readability.d.ts.map +0 -1
  559. package/dist/core/readability.js +0 -37
  560. package/dist/core/readability.js.map +0 -1
  561. package/dist/core/rule-filters.d.ts +0 -45
  562. package/dist/core/rule-filters.d.ts.map +0 -1
  563. package/dist/core/rule-filters.js +0 -118
  564. package/dist/core/rule-filters.js.map +0 -1
  565. package/dist/core/runner.d.ts +0 -98
  566. package/dist/core/runner.d.ts.map +0 -1
  567. package/dist/core/runner.js +0 -401
  568. package/dist/core/runner.js.map +0 -1
  569. package/dist/core/timing.d.ts +0 -24
  570. package/dist/core/timing.d.ts.map +0 -1
  571. package/dist/core/timing.js +0 -39
  572. package/dist/core/timing.js.map +0 -1
  573. package/dist/data/markdoc-realm-schema.d.ts.map +0 -1
  574. package/dist/data/markdoc-realm-schema.js +0 -798
  575. package/dist/data/markdoc-realm-schema.js.map +0 -1
  576. package/dist/data/proper-nouns.d.ts.map +0 -1
  577. package/dist/data/proper-nouns.js +0 -47
  578. package/dist/data/proper-nouns.js.map +0 -1
  579. package/dist/data/realm-front-matter-schema.d.ts +0 -28
  580. package/dist/data/realm-front-matter-schema.d.ts.map +0 -1
  581. package/dist/data/realm-front-matter-schema.js +0 -73
  582. package/dist/data/realm-front-matter-schema.js.map +0 -1
  583. package/dist/index.d.ts +0 -90
  584. package/dist/index.d.ts.map +0 -1
  585. package/dist/index.js +0 -152
  586. package/dist/index.js.map +0 -1
  587. package/dist/metrics/formulas.d.ts +0 -17
  588. package/dist/metrics/formulas.d.ts.map +0 -1
  589. package/dist/metrics/formulas.js +0 -70
  590. package/dist/metrics/formulas.js.map +0 -1
  591. package/dist/metrics/statistics.d.ts +0 -27
  592. package/dist/metrics/statistics.d.ts.map +0 -1
  593. package/dist/metrics/statistics.js +0 -56
  594. package/dist/metrics/statistics.js.map +0 -1
  595. package/dist/parser/index.d.ts +0 -19
  596. package/dist/parser/index.d.ts.map +0 -1
  597. package/dist/parser/index.js +0 -174
  598. package/dist/parser/index.js.map +0 -1
  599. package/dist/parser/markdoc/extract-statics.d.ts +0 -45
  600. package/dist/parser/markdoc/extract-statics.d.ts.map +0 -1
  601. package/dist/parser/markdoc/extract-statics.js +0 -139
  602. package/dist/parser/markdoc/extract-statics.js.map +0 -1
  603. package/dist/parser/markdoc/pairing.d.ts +0 -63
  604. package/dist/parser/markdoc/pairing.d.ts.map +0 -1
  605. package/dist/parser/markdoc/pairing.js +0 -94
  606. package/dist/parser/markdoc/pairing.js.map +0 -1
  607. package/dist/parser/markdoc/schema.d.ts +0 -85
  608. package/dist/parser/markdoc/schema.d.ts.map +0 -1
  609. package/dist/parser/markdoc/schema.js +0 -86
  610. package/dist/parser/markdoc/schema.js.map +0 -1
  611. package/dist/parser/markdoc/span.d.ts +0 -64
  612. package/dist/parser/markdoc/span.d.ts.map +0 -1
  613. package/dist/parser/markdoc/span.js +0 -729
  614. package/dist/parser/markdoc/span.js.map +0 -1
  615. package/dist/parser/markdoc/structure.d.ts +0 -28
  616. package/dist/parser/markdoc/structure.d.ts.map +0 -1
  617. package/dist/parser/markdoc/structure.js +0 -153
  618. package/dist/parser/markdoc/structure.js.map +0 -1
  619. package/dist/parser/markdoc/syntax.d.ts +0 -44
  620. package/dist/parser/markdoc/syntax.d.ts.map +0 -1
  621. package/dist/parser/markdoc/syntax.js +0 -317
  622. package/dist/parser/markdoc/syntax.js.map +0 -1
  623. package/dist/parser/types.d.ts.map +0 -1
  624. package/dist/reporter/fixes.d.ts +0 -3
  625. package/dist/reporter/fixes.d.ts.map +0 -1
  626. package/dist/reporter/fixes.js +0 -41
  627. package/dist/reporter/fixes.js.map +0 -1
  628. package/dist/reporter/formats/github-actions.d.ts +0 -6
  629. package/dist/reporter/formats/github-actions.d.ts.map +0 -1
  630. package/dist/reporter/formats/github-actions.js +0 -20
  631. package/dist/reporter/formats/github-actions.js.map +0 -1
  632. package/dist/reporter/formats/json.d.ts +0 -10
  633. package/dist/reporter/formats/json.d.ts.map +0 -1
  634. package/dist/reporter/formats/json.js +0 -25
  635. package/dist/reporter/formats/json.js.map +0 -1
  636. package/dist/reporter/formats/sarif.d.ts +0 -10
  637. package/dist/reporter/formats/sarif.d.ts.map +0 -1
  638. package/dist/reporter/formats/sarif.js +0 -66
  639. package/dist/reporter/formats/sarif.js.map +0 -1
  640. package/dist/reporter/formats/table.d.ts +0 -6
  641. package/dist/reporter/formats/table.d.ts.map +0 -1
  642. package/dist/reporter/formats/table.js +0 -43
  643. package/dist/reporter/formats/table.js.map +0 -1
  644. package/dist/reporter/index.d.ts +0 -10
  645. package/dist/reporter/index.d.ts.map +0 -1
  646. package/dist/reporter/index.js +0 -42
  647. package/dist/reporter/index.js.map +0 -1
  648. package/dist/reporter/prioritize-problems.d.ts +0 -7
  649. package/dist/reporter/prioritize-problems.d.ts.map +0 -1
  650. package/dist/reporter/prioritize-problems.js +0 -29
  651. package/dist/reporter/prioritize-problems.js.map +0 -1
  652. package/dist/reporter/statistics.d.ts +0 -10
  653. package/dist/reporter/statistics.d.ts.map +0 -1
  654. package/dist/reporter/statistics.js +0 -52
  655. package/dist/reporter/statistics.js.map +0 -1
  656. package/dist/reporter/summary.d.ts +0 -10
  657. package/dist/reporter/summary.d.ts.map +0 -1
  658. package/dist/reporter/summary.js +0 -49
  659. package/dist/reporter/summary.js.map +0 -1
  660. package/dist/rules/registry.d.ts +0 -15
  661. package/dist/rules/registry.d.ts.map +0 -1
  662. package/dist/rules/registry.js +0 -81
  663. package/dist/rules/registry.js.map +0 -1
  664. package/dist/rules/scope/capitalization.d.ts.map +0 -1
  665. package/dist/rules/scope/capitalization.js +0 -164
  666. package/dist/rules/scope/capitalization.js.map +0 -1
  667. package/dist/rules/scope/conditional.d.ts.map +0 -1
  668. package/dist/rules/scope/conditional.js +0 -112
  669. package/dist/rules/scope/conditional.js.map +0 -1
  670. package/dist/rules/scope/consistency.d.ts.map +0 -1
  671. package/dist/rules/scope/consistency.js +0 -179
  672. package/dist/rules/scope/consistency.js.map +0 -1
  673. package/dist/rules/scope/length.d.ts.map +0 -1
  674. package/dist/rules/scope/length.js +0 -73
  675. package/dist/rules/scope/length.js.map +0 -1
  676. package/dist/rules/scope/max-image-size.d.ts.map +0 -1
  677. package/dist/rules/scope/max-image-size.js +0 -65
  678. package/dist/rules/scope/max-image-size.js.map +0 -1
  679. package/dist/rules/scope/metric.d.ts +0 -5
  680. package/dist/rules/scope/metric.d.ts.map +0 -1
  681. package/dist/rules/scope/metric.js +0 -74
  682. package/dist/rules/scope/metric.js.map +0 -1
  683. package/dist/rules/scope/occurrence.d.ts.map +0 -1
  684. package/dist/rules/scope/occurrence.js +0 -48
  685. package/dist/rules/scope/occurrence.js.map +0 -1
  686. package/dist/rules/scope/pattern.d.ts.map +0 -1
  687. package/dist/rules/scope/pattern.js +0 -75
  688. package/dist/rules/scope/pattern.js.map +0 -1
  689. package/dist/rules/scope/repetition.d.ts.map +0 -1
  690. package/dist/rules/scope/repetition.js +0 -139
  691. package/dist/rules/scope/repetition.js.map +0 -1
  692. package/dist/rules/scope/semantic-line-breaks.d.ts.map +0 -1
  693. package/dist/rules/scope/semantic-line-breaks.js +0 -236
  694. package/dist/rules/scope/semantic-line-breaks.js.map +0 -1
  695. package/dist/rules/scope/spelling.d.ts +0 -27
  696. package/dist/rules/scope/spelling.d.ts.map +0 -1
  697. package/dist/rules/scope/spelling.js +0 -227
  698. package/dist/rules/scope/spelling.js.map +0 -1
  699. package/dist/rules/scope/swap.d.ts.map +0 -1
  700. package/dist/rules/scope/swap.js +0 -149
  701. package/dist/rules/scope/swap.js.map +0 -1
  702. package/dist/rules/scope/title-case.d.ts +0 -46
  703. package/dist/rules/scope/title-case.d.ts.map +0 -1
  704. package/dist/rules/scope/title-case.js +0 -301
  705. package/dist/rules/scope/title-case.js.map +0 -1
  706. package/dist/rules/token/blanks-around-fences.d.ts.map +0 -1
  707. package/dist/rules/token/blanks-around-fences.js.map +0 -1
  708. package/dist/rules/token/blanks-around-headings.d.ts.map +0 -1
  709. package/dist/rules/token/blanks-around-headings.js +0 -108
  710. package/dist/rules/token/blanks-around-headings.js.map +0 -1
  711. package/dist/rules/token/blanks-around-lists.d.ts.map +0 -1
  712. package/dist/rules/token/blanks-around-lists.js +0 -56
  713. package/dist/rules/token/blanks-around-lists.js.map +0 -1
  714. package/dist/rules/token/blanks-around-tables.d.ts.map +0 -1
  715. package/dist/rules/token/blanks-around-tables.js +0 -42
  716. package/dist/rules/token/blanks-around-tables.js.map +0 -1
  717. package/dist/rules/token/code-block-style.d.ts.map +0 -1
  718. package/dist/rules/token/code-block-style.js.map +0 -1
  719. package/dist/rules/token/code-fence-style.d.ts.map +0 -1
  720. package/dist/rules/token/code-fence-style.js.map +0 -1
  721. package/dist/rules/token/commands-show-output.d.ts.map +0 -1
  722. package/dist/rules/token/commands-show-output.js.map +0 -1
  723. package/dist/rules/token/descriptive-link-text.d.ts.map +0 -1
  724. package/dist/rules/token/descriptive-link-text.js +0 -53
  725. package/dist/rules/token/descriptive-link-text.js.map +0 -1
  726. package/dist/rules/token/fenced-code-language.d.ts.map +0 -1
  727. package/dist/rules/token/fenced-code-language.js.map +0 -1
  728. package/dist/rules/token/first-line-h1.d.ts.map +0 -1
  729. package/dist/rules/token/first-line-h1.js +0 -107
  730. package/dist/rules/token/first-line-h1.js.map +0 -1
  731. package/dist/rules/token/front-matter.d.ts.map +0 -1
  732. package/dist/rules/token/front-matter.js +0 -177
  733. package/dist/rules/token/front-matter.js.map +0 -1
  734. package/dist/rules/token/heading-increment.d.ts.map +0 -1
  735. package/dist/rules/token/heading-increment.js +0 -27
  736. package/dist/rules/token/heading-increment.js.map +0 -1
  737. package/dist/rules/token/heading-start-left.d.ts.map +0 -1
  738. package/dist/rules/token/heading-start-left.js.map +0 -1
  739. package/dist/rules/token/heading-style.d.ts.map +0 -1
  740. package/dist/rules/token/heading-style.js.map +0 -1
  741. package/dist/rules/token/helpers.d.ts +0 -313
  742. package/dist/rules/token/helpers.d.ts.map +0 -1
  743. package/dist/rules/token/helpers.js +0 -746
  744. package/dist/rules/token/helpers.js.map +0 -1
  745. package/dist/rules/token/hr-style.d.ts.map +0 -1
  746. package/dist/rules/token/hr-style.js.map +0 -1
  747. package/dist/rules/token/index.d.ts +0 -76
  748. package/dist/rules/token/index.d.ts.map +0 -1
  749. package/dist/rules/token/index.js +0 -229
  750. package/dist/rules/token/index.js.map +0 -1
  751. package/dist/rules/token/line-length.d.ts.map +0 -1
  752. package/dist/rules/token/line-length.js +0 -120
  753. package/dist/rules/token/line-length.js.map +0 -1
  754. package/dist/rules/token/link-fragments.d.ts.map +0 -1
  755. package/dist/rules/token/link-fragments.js +0 -393
  756. package/dist/rules/token/link-fragments.js.map +0 -1
  757. package/dist/rules/token/link-image-reference-definitions.d.ts.map +0 -1
  758. package/dist/rules/token/link-image-reference-definitions.js.map +0 -1
  759. package/dist/rules/token/link-image-style.d.ts.map +0 -1
  760. package/dist/rules/token/link-image-style.js +0 -131
  761. package/dist/rules/token/link-image-style.js.map +0 -1
  762. package/dist/rules/token/list-indent.d.ts.map +0 -1
  763. package/dist/rules/token/list-indent.js.map +0 -1
  764. package/dist/rules/token/list-length.d.ts.map +0 -1
  765. package/dist/rules/token/list-length.js +0 -55
  766. package/dist/rules/token/list-length.js.map +0 -1
  767. package/dist/rules/token/list-marker-space.d.ts.map +0 -1
  768. package/dist/rules/token/list-marker-space.js.map +0 -1
  769. package/dist/rules/token/markdoc-attributes.d.ts.map +0 -1
  770. package/dist/rules/token/markdoc-attributes.js +0 -269
  771. package/dist/rules/token/markdoc-attributes.js.map +0 -1
  772. package/dist/rules/token/markdoc-pairing.d.ts.map +0 -1
  773. package/dist/rules/token/markdoc-pairing.js +0 -73
  774. package/dist/rules/token/markdoc-pairing.js.map +0 -1
  775. package/dist/rules/token/markdoc-syntax.d.ts.map +0 -1
  776. package/dist/rules/token/markdoc-syntax.js +0 -119
  777. package/dist/rules/token/markdoc-syntax.js.map +0 -1
  778. package/dist/rules/token/markdoc-unknown-tag.d.ts.map +0 -1
  779. package/dist/rules/token/markdoc-unknown-tag.js +0 -64
  780. package/dist/rules/token/markdoc-unknown-tag.js.map +0 -1
  781. package/dist/rules/token/no-alt-text.d.ts.map +0 -1
  782. package/dist/rules/token/no-alt-text.js +0 -47
  783. package/dist/rules/token/no-alt-text.js.map +0 -1
  784. package/dist/rules/token/no-bare-urls.d.ts.map +0 -1
  785. package/dist/rules/token/no-bare-urls.js +0 -88
  786. package/dist/rules/token/no-bare-urls.js.map +0 -1
  787. package/dist/rules/token/no-blanks-blockquote.d.ts.map +0 -1
  788. package/dist/rules/token/no-blanks-blockquote.js.map +0 -1
  789. package/dist/rules/token/no-duplicate-heading.d.ts.map +0 -1
  790. package/dist/rules/token/no-duplicate-heading.js +0 -101
  791. package/dist/rules/token/no-duplicate-heading.js.map +0 -1
  792. package/dist/rules/token/no-duplicate-link-destinations.d.ts.map +0 -1
  793. package/dist/rules/token/no-duplicate-link-destinations.js +0 -65
  794. package/dist/rules/token/no-duplicate-link-destinations.js.map +0 -1
  795. package/dist/rules/token/no-emphasis-as-heading.d.ts.map +0 -1
  796. package/dist/rules/token/no-emphasis-as-heading.js +0 -44
  797. package/dist/rules/token/no-emphasis-as-heading.js.map +0 -1
  798. package/dist/rules/token/no-empty-headings.d.ts.map +0 -1
  799. package/dist/rules/token/no-empty-headings.js +0 -28
  800. package/dist/rules/token/no-empty-headings.js.map +0 -1
  801. package/dist/rules/token/no-empty-links.d.ts.map +0 -1
  802. package/dist/rules/token/no-empty-links.js.map +0 -1
  803. package/dist/rules/token/no-hard-tabs.d.ts.map +0 -1
  804. package/dist/rules/token/no-hard-tabs.js.map +0 -1
  805. package/dist/rules/token/no-inline-html.d.ts.map +0 -1
  806. package/dist/rules/token/no-inline-html.js +0 -45
  807. package/dist/rules/token/no-inline-html.js.map +0 -1
  808. package/dist/rules/token/no-multiple-blanks.d.ts.map +0 -1
  809. package/dist/rules/token/no-multiple-blanks.js.map +0 -1
  810. package/dist/rules/token/no-multiple-space-atx.d.ts +0 -13
  811. package/dist/rules/token/no-multiple-space-atx.d.ts.map +0 -1
  812. package/dist/rules/token/no-multiple-space-atx.js +0 -50
  813. package/dist/rules/token/no-multiple-space-atx.js.map +0 -1
  814. package/dist/rules/token/no-multiple-space-closed-atx.d.ts.map +0 -1
  815. package/dist/rules/token/no-multiple-space-closed-atx.js.map +0 -1
  816. package/dist/rules/token/no-reversed-links.d.ts.map +0 -1
  817. package/dist/rules/token/no-reversed-links.js.map +0 -1
  818. package/dist/rules/token/no-space-in-code.d.ts.map +0 -1
  819. package/dist/rules/token/no-space-in-code.js.map +0 -1
  820. package/dist/rules/token/no-space-in-emphasis.d.ts.map +0 -1
  821. package/dist/rules/token/no-space-in-emphasis.js +0 -79
  822. package/dist/rules/token/no-space-in-emphasis.js.map +0 -1
  823. package/dist/rules/token/no-space-in-links.d.ts.map +0 -1
  824. package/dist/rules/token/no-space-in-links.js.map +0 -1
  825. package/dist/rules/token/no-trailing-punctuation.d.ts.map +0 -1
  826. package/dist/rules/token/no-trailing-punctuation.js.map +0 -1
  827. package/dist/rules/token/no-trailing-spaces.d.ts.map +0 -1
  828. package/dist/rules/token/no-trailing-spaces.js.map +0 -1
  829. package/dist/rules/token/ol-prefix.d.ts.map +0 -1
  830. package/dist/rules/token/ol-prefix.js.map +0 -1
  831. package/dist/rules/token/proper-names.d.ts.map +0 -1
  832. package/dist/rules/token/proper-names.js +0 -93
  833. package/dist/rules/token/proper-names.js.map +0 -1
  834. package/dist/rules/token/reference-links-images.d.ts.map +0 -1
  835. package/dist/rules/token/reference-links-images.js.map +0 -1
  836. package/dist/rules/token/required-headings.d.ts.map +0 -1
  837. package/dist/rules/token/required-headings.js +0 -83
  838. package/dist/rules/token/required-headings.js.map +0 -1
  839. package/dist/rules/token/single-h1.d.ts.map +0 -1
  840. package/dist/rules/token/single-h1.js +0 -56
  841. package/dist/rules/token/single-h1.js.map +0 -1
  842. package/dist/rules/token/table-column-count.d.ts.map +0 -1
  843. package/dist/rules/token/table-column-count.js.map +0 -1
  844. package/dist/rules/token/table-column-style.d.ts.map +0 -1
  845. package/dist/rules/token/table-column-style.js +0 -179
  846. package/dist/rules/token/table-column-style.js.map +0 -1
  847. package/dist/rules/token/table-pipe-style.d.ts.map +0 -1
  848. package/dist/rules/token/table-pipe-style.js.map +0 -1
  849. package/dist/rules/token/ul-indent.d.ts.map +0 -1
  850. package/dist/rules/token/ul-indent.js.map +0 -1
  851. package/dist/rules/token/ul-style.d.ts.map +0 -1
  852. package/dist/rules/token/ul-style.js +0 -80
  853. package/dist/rules/token/ul-style.js.map +0 -1
  854. package/dist/rules/types.d.ts +0 -83
  855. package/dist/rules/types.d.ts.map +0 -1
  856. package/dist/rules/utils.d.ts +0 -31
  857. package/dist/rules/utils.d.ts.map +0 -1
  858. package/dist/rules/utils.js +0 -90
  859. package/dist/rules/utils.js.map +0 -1
  860. package/dist/scopes/extractor.d.ts +0 -7
  861. package/dist/scopes/extractor.d.ts.map +0 -1
  862. package/dist/scopes/extractor.js +0 -536
  863. package/dist/scopes/extractor.js.map +0 -1
  864. package/dist/scopes/selector.d.ts +0 -51
  865. package/dist/scopes/selector.d.ts.map +0 -1
  866. package/dist/scopes/selector.js +0 -121
  867. package/dist/scopes/selector.js.map +0 -1
  868. package/dist/scopes/sentences.d.ts +0 -15
  869. package/dist/scopes/sentences.d.ts.map +0 -1
  870. package/dist/scopes/sentences.js +0 -202
  871. package/dist/scopes/sentences.js.map +0 -1
  872. package/dist/scopes/types.d.ts +0 -46
  873. package/dist/scopes/types.d.ts.map +0 -1
  874. package/dist/scopes/vocabulary.d.ts +0 -16
  875. package/dist/scopes/vocabulary.d.ts.map +0 -1
  876. package/dist/scopes/vocabulary.js +0 -70
  877. package/dist/scopes/vocabulary.js.map +0 -1
  878. package/dist/types/assertions.d.ts +0 -121
  879. package/dist/types/assertions.d.ts.map +0 -1
  880. package/dist/types/reporting.d.ts +0 -32
  881. package/dist/types/reporting.d.ts.map +0 -1
  882. package/dist/types/rules.d.ts +0 -41
  883. package/dist/types/rules.d.ts.map +0 -1
  884. package/dist/types/validation.d.ts +0 -6
  885. package/dist/types/validation.d.ts.map +0 -1
  886. /package/{dist → lib}/core/auto-fix.d.ts +0 -0
  887. /package/{dist → lib}/core/directives.d.ts +0 -0
  888. /package/{dist → lib}/data/markdoc-realm-schema.d.ts +0 -0
  889. /package/{dist → lib}/data/proper-nouns.d.ts +0 -0
  890. /package/{dist → lib}/metrics/index.d.ts +0 -0
  891. /package/{dist → lib}/metrics/index.d.ts.map +0 -0
  892. /package/{dist → lib}/metrics/index.js +0 -0
  893. /package/{dist → lib}/metrics/index.js.map +0 -0
  894. /package/{dist → lib}/parser/types.d.ts +0 -0
  895. /package/{dist → lib}/parser/types.js +0 -0
  896. /package/{dist → lib}/parser/types.js.map +0 -0
  897. /package/{dist → lib}/rules/scope/capitalization.d.ts +0 -0
  898. /package/{dist → lib}/rules/scope/conditional.d.ts +0 -0
  899. /package/{dist → lib}/rules/scope/consistency.d.ts +0 -0
  900. /package/{dist → lib}/rules/scope/length.d.ts +0 -0
  901. /package/{dist → lib}/rules/scope/max-image-size.d.ts +0 -0
  902. /package/{dist → lib}/rules/scope/occurrence.d.ts +0 -0
  903. /package/{dist → lib}/rules/scope/pattern.d.ts +0 -0
  904. /package/{dist → lib}/rules/scope/repetition.d.ts +0 -0
  905. /package/{dist → lib}/rules/scope/semantic-line-breaks.d.ts +0 -0
  906. /package/{dist → lib}/rules/scope/swap.d.ts +0 -0
  907. /package/{dist → lib}/rules/token/blanks-around-fences.d.ts +0 -0
  908. /package/{dist → lib}/rules/token/blanks-around-fences.js +0 -0
  909. /package/{dist → lib}/rules/token/blanks-around-headings.d.ts +0 -0
  910. /package/{dist → lib}/rules/token/blanks-around-lists.d.ts +0 -0
  911. /package/{dist → lib}/rules/token/blanks-around-tables.d.ts +0 -0
  912. /package/{dist → lib}/rules/token/code-block-style.d.ts +0 -0
  913. /package/{dist → lib}/rules/token/code-block-style.js +0 -0
  914. /package/{dist → lib}/rules/token/code-fence-style.d.ts +0 -0
  915. /package/{dist → lib}/rules/token/code-fence-style.js +0 -0
  916. /package/{dist → lib}/rules/token/commands-show-output.d.ts +0 -0
  917. /package/{dist → lib}/rules/token/commands-show-output.js +0 -0
  918. /package/{dist → lib}/rules/token/descriptive-link-text.d.ts +0 -0
  919. /package/{dist → lib}/rules/token/emphasis-style.d.ts +0 -0
  920. /package/{dist → lib}/rules/token/emphasis-style.d.ts.map +0 -0
  921. /package/{dist → lib}/rules/token/emphasis-style.js +0 -0
  922. /package/{dist → lib}/rules/token/emphasis-style.js.map +0 -0
  923. /package/{dist → lib}/rules/token/fenced-code-language.d.ts +0 -0
  924. /package/{dist → lib}/rules/token/fenced-code-language.js +0 -0
  925. /package/{dist → lib}/rules/token/first-line-h1.d.ts +0 -0
  926. /package/{dist → lib}/rules/token/front-matter.d.ts +0 -0
  927. /package/{dist → lib}/rules/token/heading-increment.d.ts +0 -0
  928. /package/{dist → lib}/rules/token/heading-start-left.d.ts +0 -0
  929. /package/{dist → lib}/rules/token/heading-start-left.js +0 -0
  930. /package/{dist → lib}/rules/token/heading-style.d.ts +0 -0
  931. /package/{dist → lib}/rules/token/heading-style.js +0 -0
  932. /package/{dist → lib}/rules/token/hr-style.d.ts +0 -0
  933. /package/{dist → lib}/rules/token/hr-style.js +0 -0
  934. /package/{dist → lib}/rules/token/line-length.d.ts +0 -0
  935. /package/{dist → lib}/rules/token/link-fragments.d.ts +0 -0
  936. /package/{dist → lib}/rules/token/link-image-reference-definitions.d.ts +0 -0
  937. /package/{dist → lib}/rules/token/link-image-reference-definitions.js +0 -0
  938. /package/{dist → lib}/rules/token/link-image-style.d.ts +0 -0
  939. /package/{dist → lib}/rules/token/list-indent.d.ts +0 -0
  940. /package/{dist → lib}/rules/token/list-indent.js +0 -0
  941. /package/{dist → lib}/rules/token/list-length.d.ts +0 -0
  942. /package/{dist → lib}/rules/token/list-marker-space.d.ts +0 -0
  943. /package/{dist → lib}/rules/token/list-marker-space.js +0 -0
  944. /package/{dist → lib}/rules/token/markdoc-attributes.d.ts +0 -0
  945. /package/{dist → lib}/rules/token/markdoc-pairing.d.ts +0 -0
  946. /package/{dist → lib}/rules/token/markdoc-syntax.d.ts +0 -0
  947. /package/{dist → lib}/rules/token/markdoc-unknown-tag.d.ts +0 -0
  948. /package/{dist → lib}/rules/token/messages.d.ts +0 -0
  949. /package/{dist → lib}/rules/token/messages.d.ts.map +0 -0
  950. /package/{dist → lib}/rules/token/messages.js +0 -0
  951. /package/{dist → lib}/rules/token/messages.js.map +0 -0
  952. /package/{dist → lib}/rules/token/no-alt-text.d.ts +0 -0
  953. /package/{dist → lib}/rules/token/no-bare-urls.d.ts +0 -0
  954. /package/{dist → lib}/rules/token/no-blanks-blockquote.d.ts +0 -0
  955. /package/{dist → lib}/rules/token/no-blanks-blockquote.js +0 -0
  956. /package/{dist → lib}/rules/token/no-duplicate-heading.d.ts +0 -0
  957. /package/{dist → lib}/rules/token/no-duplicate-link-destinations.d.ts +0 -0
  958. /package/{dist → lib}/rules/token/no-emphasis-as-heading.d.ts +0 -0
  959. /package/{dist → lib}/rules/token/no-empty-headings.d.ts +0 -0
  960. /package/{dist → lib}/rules/token/no-empty-links.d.ts +0 -0
  961. /package/{dist → lib}/rules/token/no-empty-links.js +0 -0
  962. /package/{dist → lib}/rules/token/no-hard-tabs.d.ts +0 -0
  963. /package/{dist → lib}/rules/token/no-hard-tabs.js +0 -0
  964. /package/{dist → lib}/rules/token/no-inline-html.d.ts +0 -0
  965. /package/{dist → lib}/rules/token/no-missing-space-atx.d.ts +0 -0
  966. /package/{dist → lib}/rules/token/no-missing-space-atx.d.ts.map +0 -0
  967. /package/{dist → lib}/rules/token/no-missing-space-atx.js +0 -0
  968. /package/{dist → lib}/rules/token/no-missing-space-atx.js.map +0 -0
  969. /package/{dist → lib}/rules/token/no-missing-space-closed-atx.d.ts +0 -0
  970. /package/{dist → lib}/rules/token/no-missing-space-closed-atx.d.ts.map +0 -0
  971. /package/{dist → lib}/rules/token/no-missing-space-closed-atx.js +0 -0
  972. /package/{dist → lib}/rules/token/no-missing-space-closed-atx.js.map +0 -0
  973. /package/{dist → lib}/rules/token/no-multiple-blanks.d.ts +0 -0
  974. /package/{dist → lib}/rules/token/no-multiple-blanks.js +0 -0
  975. /package/{dist → lib}/rules/token/no-multiple-space-blockquote.d.ts +0 -0
  976. /package/{dist → lib}/rules/token/no-multiple-space-blockquote.d.ts.map +0 -0
  977. /package/{dist → lib}/rules/token/no-multiple-space-blockquote.js +0 -0
  978. /package/{dist → lib}/rules/token/no-multiple-space-blockquote.js.map +0 -0
  979. /package/{dist → lib}/rules/token/no-multiple-space-closed-atx.d.ts +0 -0
  980. /package/{dist → lib}/rules/token/no-multiple-space-closed-atx.js +0 -0
  981. /package/{dist → lib}/rules/token/no-reversed-links.d.ts +0 -0
  982. /package/{dist → lib}/rules/token/no-reversed-links.js +0 -0
  983. /package/{dist → lib}/rules/token/no-space-in-code.d.ts +0 -0
  984. /package/{dist → lib}/rules/token/no-space-in-code.js +0 -0
  985. /package/{dist → lib}/rules/token/no-space-in-emphasis.d.ts +0 -0
  986. /package/{dist → lib}/rules/token/no-space-in-links.d.ts +0 -0
  987. /package/{dist → lib}/rules/token/no-space-in-links.js +0 -0
  988. /package/{dist → lib}/rules/token/no-trailing-punctuation.d.ts +0 -0
  989. /package/{dist → lib}/rules/token/no-trailing-punctuation.js +0 -0
  990. /package/{dist → lib}/rules/token/no-trailing-spaces.d.ts +0 -0
  991. /package/{dist → lib}/rules/token/no-trailing-spaces.js +0 -0
  992. /package/{dist → lib}/rules/token/ol-prefix.d.ts +0 -0
  993. /package/{dist → lib}/rules/token/ol-prefix.js +0 -0
  994. /package/{dist → lib}/rules/token/proper-names.d.ts +0 -0
  995. /package/{dist → lib}/rules/token/reference-links-images.d.ts +0 -0
  996. /package/{dist → lib}/rules/token/reference-links-images.js +0 -0
  997. /package/{dist → lib}/rules/token/required-headings.d.ts +0 -0
  998. /package/{dist → lib}/rules/token/single-h1.d.ts +0 -0
  999. /package/{dist → lib}/rules/token/single-trailing-newline.d.ts +0 -0
  1000. /package/{dist → lib}/rules/token/single-trailing-newline.d.ts.map +0 -0
  1001. /package/{dist → lib}/rules/token/single-trailing-newline.js +0 -0
  1002. /package/{dist → lib}/rules/token/single-trailing-newline.js.map +0 -0
  1003. /package/{dist → lib}/rules/token/strong-style.d.ts +0 -0
  1004. /package/{dist → lib}/rules/token/strong-style.d.ts.map +0 -0
  1005. /package/{dist → lib}/rules/token/strong-style.js +0 -0
  1006. /package/{dist → lib}/rules/token/strong-style.js.map +0 -0
  1007. /package/{dist → lib}/rules/token/table-column-count.d.ts +0 -0
  1008. /package/{dist → lib}/rules/token/table-column-count.js +0 -0
  1009. /package/{dist → lib}/rules/token/table-column-style.d.ts +0 -0
  1010. /package/{dist → lib}/rules/token/table-pipe-style.d.ts +0 -0
  1011. /package/{dist → lib}/rules/token/table-pipe-style.js +0 -0
  1012. /package/{dist → lib}/rules/token/ul-indent.d.ts +0 -0
  1013. /package/{dist → lib}/rules/token/ul-indent.js +0 -0
  1014. /package/{dist → lib}/rules/token/ul-style.d.ts +0 -0
  1015. /package/{dist → lib}/rules/types.js +0 -0
  1016. /package/{dist → lib}/rules/types.js.map +0 -0
  1017. /package/{dist → lib}/scopes/types.js +0 -0
  1018. /package/{dist → lib}/scopes/types.js.map +0 -0
  1019. /package/{dist → lib}/types/assertions.js +0 -0
  1020. /package/{dist → lib}/types/assertions.js.map +0 -0
  1021. /package/{dist → lib}/types/index.d.ts +0 -0
  1022. /package/{dist → lib}/types/index.d.ts.map +0 -0
  1023. /package/{dist → lib}/types/index.js +0 -0
  1024. /package/{dist → lib}/types/index.js.map +0 -0
  1025. /package/{dist → lib}/types/problems.d.ts +0 -0
  1026. /package/{dist → lib}/types/problems.d.ts.map +0 -0
  1027. /package/{dist → lib}/types/problems.js +0 -0
  1028. /package/{dist → lib}/types/problems.js.map +0 -0
  1029. /package/{dist → lib}/types/reporting.js +0 -0
  1030. /package/{dist → lib}/types/reporting.js.map +0 -0
  1031. /package/{dist → lib}/types/rules.js +0 -0
  1032. /package/{dist → lib}/types/rules.js.map +0 -0
  1033. /package/{dist → lib}/types/validation.js +0 -0
  1034. /package/{dist → lib}/types/validation.js.map +0 -0
@@ -1,1315 +0,0 @@
1
- import * as fs from 'node:fs/promises';
2
- import * as path from 'node:path';
3
- import Ajv from '@redocly/ajv';
4
- import addFormats from 'ajv-formats';
5
- import * as yaml from 'js-yaml';
6
- import { resolveMarkdocConfig } from '../parser/markdoc/schema.js';
7
- import { RECHECK_CONFIG_SCHEMA, MARKDOC_TAG_SCHEMA } from './schema.js';
8
- import { validateScopeSelector } from '../scopes/vocabulary.js';
9
- import { tokenizeSelector, wholeDocumentKeywordProblems } from '../scopes/selector.js';
10
- import { resolveExtends } from './presets/index.js';
11
- import { resolveAssertion } from '../rules/registry.js';
12
- import { resolveDictionaryPaths } from '../rules/scope/spelling.js';
13
- const ajv = new Ajv({
14
- useDefaults: true,
15
- allErrors: true,
16
- verbose: true,
17
- });
18
- addFormats(ajv); // mismatching AJV typing due to fork
19
- ajv.addSchema(RECHECK_CONFIG_SCHEMA, 'recheck-config');
20
- // Compiled once so `markdoc.extend.tagsFile` entries get exactly the same
21
- // per-tag shape check a config's own inline `extend.tags` gets from the
22
- // schema above, without recompiling on every validate() call.
23
- const validateMarkdocTagShape = ajv.compile(MARKDOC_TAG_SCHEMA);
24
- /**
25
- * Validates configuration structure using JSON Schema
26
- */
27
- function validateStructure(config) {
28
- const validate = ajv.getSchema('recheck-config');
29
- if (!validate) {
30
- throw new Error('Schema not loaded');
31
- }
32
- const valid = validate(config);
33
- if (!valid && validate.errors) {
34
- return validate.errors.map((error) => {
35
- // AJV's own `additionalProperties` message ("must NOT have additional
36
- // properties") never names the offending key in `error.message`
37
- // itself — it's only available on `error.params.additionalProperty`.
38
- // Naming it here is what turns a schema-illegal key (e.g. the removed
39
- // `autoFixable`) into an actionable, greppable error rather than a
40
- // "which property?" guessing game.
41
- const extra = error.keyword === 'additionalProperties' && error.params?.additionalProperty
42
- ? ` (unknown property "${error.params.additionalProperty}")`
43
- : '';
44
- return {
45
- message: `${error.instancePath || '/'}: ${error.message}${extra}`,
46
- path: error.instancePath,
47
- value: error.data,
48
- };
49
- });
50
- }
51
- return [];
52
- }
53
- /**
54
- * Validates assertions in a rule
55
- */
56
- function validateAssertions(rule, name, errors) {
57
- if (!rule.assertions || typeof rule.assertions !== 'object') {
58
- errors.push({
59
- message: `Rule "${name}": assertions must be an object`,
60
- path: `${name}.assertions`,
61
- });
62
- return;
63
- }
64
- for (const assertionType of Object.keys(rule.assertions)) {
65
- let resolved;
66
- try {
67
- // Delegates to the same registry runRules() uses to dispatch
68
- // assertions (rules/registry.ts resolveAssertion), rather than a
69
- // hand-maintained list of known assertion ids duplicated here. Every
70
- // scope AND token rule (including every markdownlint-ported rule
71
- // registered via src/rules/token/index.ts) is "known" the moment
72
- // it's registered, so this can't silently drift out of sync the way
73
- // a hardcoded switch/case list did per rule-porting batch.
74
- resolved = resolveAssertion(assertionType);
75
- }
76
- catch {
77
- errors.push({
78
- message: `Rule "${name}": unknown assertion type "${assertionType}"`,
79
- path: `${name}.assertions.${assertionType}`,
80
- });
81
- continue;
82
- }
83
- // Scope-rule assertions (pattern, occurrence, swap, ...) each have their
84
- // own dedicated per-assertion validator below; token rules (the 53
85
- // markdownlint-ported rules) had no option checking at all until now --
86
- // see validateTokenRuleOptions.
87
- if (resolved.kind === 'token') {
88
- validateTokenRuleOptions(rule, name, assertionType, resolved.rule, errors);
89
- }
90
- }
91
- }
92
- // A misspelled option on a ported (token) rule used to validate clean and
93
- // silently no-op -- invisible in a 100-rule style-guide config. Each token
94
- // rule's own `defaults` object is the schema of record: it's the exact set
95
- // of keys the rule reads off `ctx.config` (see e.g. rules/token/line-length.ts
96
- // `defaults: { message, lineLength, codeBlocks, tables, headings, ... }`).
97
- // `message` is always allowed because every token rule's `defaults` includes
98
- // it (verified for all 53 ported rules) -- this is distinct from the
99
- // RULE-level `message`/`severity`/`scope`/`fix`/`link`/`excludes`/
100
- // `appliesTo`/`exceptions`/`assertions` keys, which are not assertion
101
- // options and are validated elsewhere (schema.ts / validateAssertions).
102
- function validateTokenRuleOptions(rule, name, id, tokenRule, errors) {
103
- const optionsObject = requireOptionsObject(rule, name, id, errors);
104
- if (!optionsObject)
105
- return;
106
- const allowed = new Set(Object.keys(tokenRule.defaults));
107
- for (const key of Object.keys(optionsObject)) {
108
- if (!allowed.has(key)) {
109
- errors.push({
110
- message: `Rule "${name}": unknown option "${key}" for assertion "${id}" (accepted: ${[...allowed].sort().join(', ')})`,
111
- path: `${name}.assertions.${id}.${key}`,
112
- value: key,
113
- });
114
- }
115
- }
116
- }
117
- /**
118
- * Shared guard for every per-assertion option validator below: returns the
119
- * assertion's options when they are a plain object, `undefined` when the
120
- * assertion isn't configured on this rule, and pushes an "options must be
121
- * an object" error for anything else. The JSON schema can't catch this
122
- * shape mistake (`assertions` values are `additionalProperties: true`), so
123
- * without it e.g. `occurrence: "oops"` validates cleanly and misbehaves at
124
- * lint time.
125
- */
126
- function requireOptionsObject(rule, name, assertionId, errors) {
127
- const assertions = rule.assertions;
128
- if (!assertions || typeof assertions !== 'object' || !(assertionId in assertions)) {
129
- return undefined;
130
- }
131
- const config = assertions[assertionId];
132
- if (!config || typeof config !== 'object' || Array.isArray(config)) {
133
- errors.push({
134
- message: `Rule "${name}": ${assertionId} assertion options must be an object`,
135
- path: `${name}.assertions.${assertionId}`,
136
- });
137
- return undefined;
138
- }
139
- return config;
140
- }
141
- // `negate` is included here (rather than left to fall through to the
142
- // generic "unknown option" error below) so a config that sets it gets ONE
143
- // specific, actionable message -- see the dedicated check in
144
- // validatePatternOptions, not a redundant generic one alongside it.
145
- const PATTERN_OPTION_KEYS = new Set(['tokens', 'ignoreCase', 'nonword', 'includeCode', 'negate']);
146
- /**
147
- * Rejects the removed `pattern` option `negate`. Git history shows it never
148
- * functioned in ANY version of the engine — the check always sat inside the
149
- * match-iteration loop, so `negate: true` reported nothing, ever, and a
150
- * pattern's ABSENCE never reported either. Rather than silently ignoring a
151
- * config key that reads like it inverts the rule, validation fails loudly;
152
- * existence checks ("flag when a pattern is absent") are planned as a
153
- * Vale-parity feature.
154
- */
155
- function validatePatternOptions(rule, name, errors) {
156
- const patternConfig = requireOptionsObject(rule, name, 'pattern', errors);
157
- if (!patternConfig)
158
- return;
159
- for (const key of Object.keys(patternConfig)) {
160
- if (!PATTERN_OPTION_KEYS.has(key)) {
161
- errors.push({
162
- message: `Rule "${name}": unknown pattern option "${key}"`,
163
- path: `${name}.assertions.pattern.${key}`,
164
- });
165
- }
166
- }
167
- if ('negate' in patternConfig) {
168
- errors.push({
169
- message: `Rule "${name}": pattern option "negate" was removed — it never worked ` +
170
- `(it never reported anything); remove it from the config`,
171
- path: `${name}.assertions.pattern.negate`,
172
- });
173
- }
174
- // `tokens`, `ignoreCase`, and `nonword` used to have no type check at all --
175
- // `tokens: "ab"` (a string, not an array) validated
176
- // clean, then pattern.ts's `for (const token of tokens)` iterated the
177
- // STRING CHARACTER BY CHARACTER ('a' and 'b' each compiled as their own
178
- // regex), and `ignoreCase: "yes"` (any non-empty string is truthy)
179
- // silently flipped case-sensitivity on a typo. `tokens` is required (not
180
- // `tokens?:` -- see PatternAssertion in types/assertions.ts) and, like
181
- // `swap`'s `pairs` and `consistency`'s `either`, an EMPTY tokens array can
182
- // never report anything, so both shape and non-emptiness are checked here
183
- // -- same reasoning as validateSwapOptions/validateConsistencyOptions.
184
- const { tokens, ignoreCase, nonword } = patternConfig;
185
- const isValidTokens = Array.isArray(tokens) &&
186
- tokens.length > 0 &&
187
- tokens.every((token) => typeof token === 'string');
188
- if (!isValidTokens) {
189
- errors.push({
190
- message: `Rule "${name}": pattern requires "tokens" to be a non-empty array of strings`,
191
- path: `${name}.assertions.pattern.tokens`,
192
- });
193
- }
194
- if (ignoreCase !== undefined && typeof ignoreCase !== 'boolean') {
195
- errors.push({
196
- message: `Rule "${name}": pattern option "ignoreCase" must be a boolean`,
197
- path: `${name}.assertions.pattern.ignoreCase`,
198
- });
199
- }
200
- if (nonword !== undefined && typeof nonword !== 'boolean') {
201
- errors.push({
202
- message: `Rule "${name}": pattern option "nonword" must be a boolean`,
203
- path: `${name}.assertions.pattern.nonword`,
204
- });
205
- }
206
- // Default `false`: a match inside inline code is skipped, by range, not
207
- // by masking the text (see rules/scope/pattern.ts), matching swap's
208
- // `includeCode` option.
209
- const includeCode = patternConfig.includeCode;
210
- if (includeCode !== undefined && typeof includeCode !== 'boolean') {
211
- errors.push({
212
- message: `Rule "${name}": pattern option "includeCode" must be a boolean`,
213
- path: `${name}.assertions.pattern.includeCode`,
214
- });
215
- }
216
- }
217
- /**
218
- * Validates the `occurrence` assertion's options. Omitting BOTH `min` and
219
- * `max` is an error — an occurrence assertion with no bound can never
220
- * report anything — and so is an inverted range (`min` > `max`), which no
221
- * count can satisfy.
222
- */
223
- const OCCURRENCE_OPTION_KEYS = new Set(['pattern', 'min', 'max', 'ignoreCase']);
224
- function validateOccurrenceOptions(rule, name, errors) {
225
- const occurrenceConfig = requireOptionsObject(rule, name, 'occurrence', errors);
226
- if (!occurrenceConfig)
227
- return;
228
- for (const key of Object.keys(occurrenceConfig)) {
229
- if (!OCCURRENCE_OPTION_KEYS.has(key)) {
230
- errors.push({
231
- message: `Rule "${name}": unknown occurrence option "${key}"`,
232
- path: `${name}.assertions.occurrence.${key}`,
233
- });
234
- }
235
- }
236
- const { min, max, pattern } = occurrenceConfig;
237
- if (min === undefined && max === undefined) {
238
- errors.push({
239
- message: `Rule "${name}": occurrence requires at least one of "min" or "max"`,
240
- path: `${name}.assertions.occurrence`,
241
- });
242
- }
243
- // `min`/`max` used to have no type check at all --
244
- // `occurrence: { pattern: ",", max: "two" }` used to validate clean, then
245
- // occurrence.ts's `count > "two"` is NaN-false (a number is never `>` a
246
- // non-numeric string), so a max-bounded rule NEVER fires. Every sibling
247
- // numeric validator (`metric`, `length`, `list-length`) already checks
248
- // this; occurrence didn't.
249
- if (min !== undefined && typeof min !== 'number') {
250
- errors.push({
251
- message: `Rule "${name}": occurrence option "min" must be a number`,
252
- path: `${name}.assertions.occurrence.min`,
253
- });
254
- }
255
- if (max !== undefined && typeof max !== 'number') {
256
- errors.push({
257
- message: `Rule "${name}": occurrence option "max" must be a number`,
258
- path: `${name}.assertions.occurrence.max`,
259
- });
260
- }
261
- if (typeof min === 'number' && typeof max === 'number' && min > max) {
262
- errors.push({
263
- message: `Rule "${name}": occurrence "min" (${min}) must not exceed "max" (${max})`,
264
- path: `${name}.assertions.occurrence`,
265
- });
266
- }
267
- // A missing/empty/non-string `pattern` silently compiles to an
268
- // always-matching empty pattern in occurrence.ts's execute() — a
269
- // max-bounded rule then floods every segment with false positives and a
270
- // min-only rule can never fire. Reject loudly instead.
271
- if (typeof pattern !== 'string' || pattern.length === 0) {
272
- errors.push({
273
- message: `Rule "${name}": occurrence requires a non-empty string "pattern"`,
274
- path: `${name}.assertions.occurrence.pattern`,
275
- });
276
- }
277
- }
278
- /**
279
- * Validates the `repetition` assertion's options. Both are optional
280
- * (defaults `\w+` / `true` -- see rules/scope/repetition.ts), but when
281
- * present `pattern` must be a non-empty string (an empty one compiles to an
282
- * always-matching zero-width regex) and `ignoreCase` a boolean.
283
- */
284
- const REPETITION_OPTION_KEYS = new Set(['pattern', 'ignoreCase']);
285
- function validateRepetitionOptions(rule, name, errors) {
286
- const repetitionConfig = requireOptionsObject(rule, name, 'repetition', errors);
287
- if (!repetitionConfig)
288
- return;
289
- for (const key of Object.keys(repetitionConfig)) {
290
- if (!REPETITION_OPTION_KEYS.has(key)) {
291
- errors.push({
292
- message: `Rule "${name}": unknown repetition option "${key}"`,
293
- path: `${name}.assertions.repetition.${key}`,
294
- });
295
- }
296
- }
297
- const { pattern, ignoreCase } = repetitionConfig;
298
- if (pattern !== undefined && (typeof pattern !== 'string' || pattern.length === 0)) {
299
- errors.push({
300
- message: `Rule "${name}": repetition option "pattern" must be a non-empty string`,
301
- path: `${name}.assertions.repetition.pattern`,
302
- });
303
- }
304
- if (ignoreCase !== undefined && typeof ignoreCase !== 'boolean') {
305
- errors.push({
306
- message: `Rule "${name}": repetition option "ignoreCase" must be a boolean`,
307
- path: `${name}.assertions.repetition.ignoreCase`,
308
- });
309
- }
310
- }
311
- /**
312
- * Validates the `consistency` assertion's options. `either` is required and
313
- * must be a non-empty object mapping one non-empty variant string to
314
- * another -- with no pairs the assertion can never report anything, and an
315
- * empty-string key would reach consistency.ts's scan loop as a zero-width
316
- * regex.
317
- */
318
- const CONSISTENCY_OPTION_KEYS = new Set(['either', 'ignoreCase']);
319
- function validateConsistencyOptions(rule, name, errors) {
320
- const consistencyConfig = requireOptionsObject(rule, name, 'consistency', errors);
321
- if (!consistencyConfig)
322
- return;
323
- for (const key of Object.keys(consistencyConfig)) {
324
- if (!CONSISTENCY_OPTION_KEYS.has(key)) {
325
- errors.push({
326
- message: `Rule "${name}": unknown consistency option "${key}"`,
327
- path: `${name}.assertions.consistency.${key}`,
328
- });
329
- }
330
- }
331
- const { either, ignoreCase } = consistencyConfig;
332
- if (!either || typeof either !== 'object' || Array.isArray(either)) {
333
- errors.push({
334
- message: `Rule "${name}": consistency requires "either" to be an object mapping one variant to another (e.g. behavior: behaviour)`,
335
- path: `${name}.assertions.consistency.either`,
336
- });
337
- }
338
- else {
339
- const entries = Object.entries(either);
340
- if (entries.length === 0) {
341
- errors.push({
342
- message: `Rule "${name}": consistency "either" must declare at least one variant pair`,
343
- path: `${name}.assertions.consistency.either`,
344
- });
345
- }
346
- for (const [variant, alternative] of entries) {
347
- if (variant.length === 0) {
348
- errors.push({
349
- message: `Rule "${name}": consistency "either" entry keys must be non-empty strings`,
350
- path: `${name}.assertions.consistency.either`,
351
- });
352
- }
353
- if (typeof alternative !== 'string' || alternative.length === 0) {
354
- errors.push({
355
- message: `Rule "${name}": consistency "either" entry "${variant}" must map to a non-empty string variant`,
356
- path: `${name}.assertions.consistency.either.${variant}`,
357
- });
358
- }
359
- }
360
- }
361
- if (ignoreCase !== undefined && typeof ignoreCase !== 'boolean') {
362
- errors.push({
363
- message: `Rule "${name}": consistency option "ignoreCase" must be a boolean`,
364
- path: `${name}.assertions.consistency.ignoreCase`,
365
- });
366
- }
367
- }
368
- /**
369
- * Validates the `conditional` assertion's options. Both `first` and
370
- * `second` are required, non-empty strings. Deliberately does NOT check
371
- * that they compile as regexes: like `pattern`'s `tokens`, they are raw
372
- * user patterns and an invalid one silently produces zero problems at
373
- * runtime (see conditional.ts).
374
- */
375
- const CONDITIONAL_OPTION_KEYS = new Set(['first', 'second', 'ignoreCase']);
376
- function validateConditionalOptions(rule, name, errors) {
377
- const conditionalConfig = requireOptionsObject(rule, name, 'conditional', errors);
378
- if (!conditionalConfig)
379
- return;
380
- for (const key of Object.keys(conditionalConfig)) {
381
- if (!CONDITIONAL_OPTION_KEYS.has(key)) {
382
- errors.push({
383
- message: `Rule "${name}": unknown conditional option "${key}"`,
384
- path: `${name}.assertions.conditional.${key}`,
385
- });
386
- }
387
- }
388
- const { first, second, ignoreCase } = conditionalConfig;
389
- if (typeof first !== 'string' || first.length === 0) {
390
- errors.push({
391
- message: `Rule "${name}": conditional requires a non-empty string "first"`,
392
- path: `${name}.assertions.conditional.first`,
393
- });
394
- }
395
- if (typeof second !== 'string' || second.length === 0) {
396
- errors.push({
397
- message: `Rule "${name}": conditional requires a non-empty string "second"`,
398
- path: `${name}.assertions.conditional.second`,
399
- });
400
- }
401
- if (ignoreCase !== undefined && typeof ignoreCase !== 'boolean') {
402
- errors.push({
403
- message: `Rule "${name}": conditional option "ignoreCase" must be a boolean`,
404
- path: `${name}.assertions.conditional.ignoreCase`,
405
- });
406
- }
407
- }
408
- /**
409
- * Validates the `capitalization` assertion's options. `match` is required
410
- * and must be a non-empty string (a `$`-style or a custom regex — an
411
- * invalid regex is deliberately NOT rejected here; it silently produces
412
- * zero problems at runtime, like `pattern`'s `tokens`). `style` is accepted
413
- * alongside ANY `match` value, not just `$title` (the only one it affects)
414
- * — setting it elsewhere is a documented harmless no-op. `exceptions`
415
- * entries must be non-empty strings or they'd silently never match in the
416
- * exception lookup. `builtinVocabulary` (default `true`, see
417
- * ../data/proper-nouns.ts) must be a boolean when present.
418
- */
419
- const CAPITALIZATION_OPTION_KEYS = new Set(['match', 'exceptions', 'style', 'builtinVocabulary']);
420
- function validateCapitalizationOptions(rule, name, errors) {
421
- const capitalizationConfig = requireOptionsObject(rule, name, 'capitalization', errors);
422
- if (!capitalizationConfig)
423
- return;
424
- for (const key of Object.keys(capitalizationConfig)) {
425
- if (!CAPITALIZATION_OPTION_KEYS.has(key)) {
426
- errors.push({
427
- message: `Rule "${name}": unknown capitalization option "${key}"`,
428
- path: `${name}.assertions.capitalization.${key}`,
429
- });
430
- }
431
- }
432
- const { match, exceptions, style, builtinVocabulary } = capitalizationConfig;
433
- if (builtinVocabulary !== undefined && typeof builtinVocabulary !== 'boolean') {
434
- errors.push({
435
- message: `Rule "${name}": capitalization option "builtinVocabulary" must be a boolean`,
436
- path: `${name}.assertions.capitalization.builtinVocabulary`,
437
- });
438
- }
439
- if (typeof match !== 'string' || match.length === 0) {
440
- errors.push({
441
- message: `Rule "${name}": capitalization requires a non-empty string "match" ` +
442
- `($title, $sentence, $lower, $upper, or a regex pattern)`,
443
- path: `${name}.assertions.capitalization.match`,
444
- });
445
- }
446
- if (style !== undefined && style !== 'ap' && style !== 'chicago') {
447
- errors.push({
448
- message: `Rule "${name}": capitalization option "style" must be "ap" or "chicago"`,
449
- path: `${name}.assertions.capitalization.style`,
450
- });
451
- }
452
- if (exceptions !== undefined) {
453
- const isValidExceptions = Array.isArray(exceptions) &&
454
- exceptions.every((entry) => typeof entry === 'string' && entry.length > 0);
455
- if (!isValidExceptions) {
456
- errors.push({
457
- message: `Rule "${name}": capitalization option "exceptions" must be an array of non-empty strings`,
458
- path: `${name}.assertions.capitalization.exceptions`,
459
- });
460
- }
461
- }
462
- }
463
- /**
464
- * Validates the `metric` assertion's options. `formula` is required and
465
- * must be one of the six formulas `computeReadability` supports or a size
466
- * formula -- an unrecognized value would otherwise throw at lint time.
467
- * `wordsPerMinute` must be a positive number and only applies to
468
- * `reading-time`; set with another formula it would be a silent no-op. At least one of
469
- * `min`/`max` is required, and an inverted range (`min` > `max`) is an
470
- * error -- same reasoning as `occurrence` above.
471
- */
472
- const METRIC_OPTION_KEYS = new Set(['formula', 'min', 'max', 'wordsPerMinute']);
473
- const METRIC_FORMULAS = new Set([
474
- 'flesch-reading-ease',
475
- 'flesch-kincaid-grade',
476
- 'gunning-fog',
477
- 'smog',
478
- 'coleman-liau',
479
- 'automated-readability',
480
- 'word-count',
481
- 'sentence-count',
482
- 'reading-time',
483
- ]);
484
- function validateMetricOptions(rule, name, errors) {
485
- const metricConfig = requireOptionsObject(rule, name, 'metric', errors);
486
- if (!metricConfig)
487
- return;
488
- for (const key of Object.keys(metricConfig)) {
489
- if (!METRIC_OPTION_KEYS.has(key)) {
490
- errors.push({
491
- message: `Rule "${name}": unknown metric option "${key}"`,
492
- path: `${name}.assertions.metric.${key}`,
493
- });
494
- }
495
- }
496
- const { formula, min, max, wordsPerMinute } = metricConfig;
497
- if (typeof formula !== 'string' || !METRIC_FORMULAS.has(formula)) {
498
- errors.push({
499
- message: `Rule "${name}": metric requires "formula" to be one of ${[...METRIC_FORMULAS].join(', ')}`,
500
- path: `${name}.assertions.metric.formula`,
501
- });
502
- }
503
- if (wordsPerMinute !== undefined) {
504
- if (typeof wordsPerMinute !== 'number' || !(wordsPerMinute > 0)) {
505
- errors.push({
506
- message: `Rule "${name}": metric option "wordsPerMinute" must be a positive number`,
507
- path: `${name}.assertions.metric.wordsPerMinute`,
508
- });
509
- }
510
- else if (formula !== 'reading-time') {
511
- errors.push({
512
- message: `Rule "${name}": metric option "wordsPerMinute" only applies to formula "reading-time"`,
513
- path: `${name}.assertions.metric.wordsPerMinute`,
514
- });
515
- }
516
- }
517
- if (min === undefined && max === undefined) {
518
- errors.push({
519
- message: `Rule "${name}": metric requires at least one of "min" or "max"`,
520
- path: `${name}.assertions.metric`,
521
- });
522
- }
523
- if (min !== undefined && typeof min !== 'number') {
524
- errors.push({
525
- message: `Rule "${name}": metric option "min" must be a number`,
526
- path: `${name}.assertions.metric.min`,
527
- });
528
- }
529
- if (max !== undefined && typeof max !== 'number') {
530
- errors.push({
531
- message: `Rule "${name}": metric option "max" must be a number`,
532
- path: `${name}.assertions.metric.max`,
533
- });
534
- }
535
- if (typeof min === 'number' && typeof max === 'number' && min > max) {
536
- errors.push({
537
- message: `Rule "${name}": metric "min" (${min}) must not exceed "max" (${max})`,
538
- path: `${name}.assertions.metric`,
539
- });
540
- }
541
- }
542
- /**
543
- * Shared `min`/`max` integer-range check for `length` and `list-length`:
544
- * both measure a COUNT
545
- * that can never be negative (characters/words/sentences/list items), so a
546
- * bound of `min: 0` (or any `min <= 0`) can NEVER be violated by a real
547
- * count -- "must have at least 0 words" is vacuously true for every
548
- * document -- and a negative `max` (e.g. `max: -1`) is violated by EVERY
549
- * real count, since no count is ever less than a negative number. Neither is
550
- * a meaningful bound; both are silent no-op/always-fire footguns. `min` must
551
- * therefore be a positive integer and `max` a non-negative integer when
552
- * present (`max: 0` is a real, meaningful "must be empty" bound, unlike a
553
- * negative one). Fractional bounds (`min: 2.5`) are also rejected: both
554
- * assertions always measure whole units, so a fractional bound could never
555
- * be matched exactly either. Only runs when the value is ALREADY a number --
556
- * a wrong-typed value is reported once by the caller's own type check, not
557
- * duplicated here.
558
- */
559
- function validateCountBounds(name, assertionId, min, max, errors) {
560
- if (typeof min === 'number' && (!Number.isInteger(min) || min < 1)) {
561
- errors.push({
562
- message: `Rule "${name}": ${assertionId} option "min" must be a positive integer ` +
563
- `(${min} could never be violated by a real count)`,
564
- path: `${name}.assertions.${assertionId}.min`,
565
- });
566
- }
567
- if (typeof max === 'number' && (!Number.isInteger(max) || max < 0)) {
568
- errors.push({
569
- message: `Rule "${name}": ${assertionId} option "max" must be a non-negative integer ` +
570
- `(${max} would be violated by every real count)`,
571
- path: `${name}.assertions.${assertionId}.max`,
572
- });
573
- }
574
- }
575
- /**
576
- * Validates the `list-length` assertion's options (rules/token/list-length.ts
577
- * -- a Recheck-original TOKEN rule, not a markdownlint port). Unlike the
578
- * scope-assertion validators above (occurrence, metric, ...), the generic
579
- * `validateTokenRuleOptions` already rejects an unknown option name for every
580
- * token rule -- derived from `Object.keys(rule.defaults)`, which declares
581
- * both `min` and `max` (see list-length.ts's doc comment on its `max:
582
- * undefined` default) -- so this only adds the type/range checks that
583
- * mirror validateOccurrenceOptions/validateMetricOptions: `min`/`max` must be
584
- * numbers when present, an inverted range (`min` > `max`) is an error -- no
585
- * item count could ever satisfy it -- and `min`/`max`
586
- * must additionally be a positive/non-negative INTEGER, per
587
- * validateCountBounds above: unlike occurrence/metric, list-length's counts
588
- * can never be negative, so `min: 0` can never fire and `max: -1` always
589
- * fires, neither a meaningful bound. Omitting BOTH `min` and `max` is
590
- * deliberately NOT an error here, unlike occurrence/metric: list-length's own
591
- * `defaults.min` is 2, so an empty `list-length: {}` is already a complete,
592
- * meaningful configuration (flag any list under 2 items), not a no-op
593
- * assertion with nothing to check.
594
- */
595
- function validateListLengthOptions(rule, name, errors) {
596
- const listLengthConfig = requireOptionsObject(rule, name, 'list-length', errors);
597
- if (!listLengthConfig)
598
- return;
599
- const { min, max } = listLengthConfig;
600
- if (min !== undefined && typeof min !== 'number') {
601
- errors.push({
602
- message: `Rule "${name}": list-length option "min" must be a number`,
603
- path: `${name}.assertions.list-length.min`,
604
- });
605
- }
606
- if (max !== undefined && typeof max !== 'number') {
607
- errors.push({
608
- message: `Rule "${name}": list-length option "max" must be a number`,
609
- path: `${name}.assertions.list-length.max`,
610
- });
611
- }
612
- if (typeof min === 'number' && typeof max === 'number' && min > max) {
613
- errors.push({
614
- message: `Rule "${name}": list-length "min" (${min}) must not exceed "max" (${max})`,
615
- path: `${name}.assertions.list-length`,
616
- });
617
- }
618
- validateCountBounds(name, 'list-length', min, max, errors);
619
- }
620
- /**
621
- * Validates the `spelling` assertion's options. All are optional — an
622
- * empty `spelling: {}` is valid (default dictionary). When present,
623
- * `dictionary` must be a non-empty string, and `vocab`/`ignore` arrays of
624
- * non-empty strings — an empty-string `ignore` pattern would compile to an
625
- * always-matching regex, silencing every word. `builtinVocabulary` (default
626
- * `true`, see ../data/proper-nouns.ts) must be a boolean when present.
627
- */
628
- const SPELLING_OPTION_KEYS = new Set(['dictionary', 'vocab', 'ignore', 'builtinVocabulary']);
629
- function validateSpellingOptions(rule, name, errors) {
630
- const spellingConfig = requireOptionsObject(rule, name, 'spelling', errors);
631
- if (!spellingConfig)
632
- return;
633
- for (const key of Object.keys(spellingConfig)) {
634
- if (!SPELLING_OPTION_KEYS.has(key)) {
635
- errors.push({
636
- message: `Rule "${name}": unknown spelling option "${key}"`,
637
- path: `${name}.assertions.spelling.${key}`,
638
- });
639
- }
640
- }
641
- const { dictionary, vocab, ignore, builtinVocabulary } = spellingConfig;
642
- if (builtinVocabulary !== undefined && typeof builtinVocabulary !== 'boolean') {
643
- errors.push({
644
- message: `Rule "${name}": spelling option "builtinVocabulary" must be a boolean`,
645
- path: `${name}.assertions.spelling.builtinVocabulary`,
646
- });
647
- }
648
- if (dictionary !== undefined && (typeof dictionary !== 'string' || dictionary.length === 0)) {
649
- errors.push({
650
- message: `Rule "${name}": spelling option "dictionary" must be a non-empty string`,
651
- path: `${name}.assertions.spelling.dictionary`,
652
- });
653
- }
654
- if (vocab !== undefined) {
655
- const isValidVocab = Array.isArray(vocab) && vocab.every((word) => typeof word === 'string' && word.length > 0);
656
- if (!isValidVocab) {
657
- errors.push({
658
- message: `Rule "${name}": spelling option "vocab" must be an array of non-empty strings`,
659
- path: `${name}.assertions.spelling.vocab`,
660
- });
661
- }
662
- }
663
- if (ignore !== undefined) {
664
- const isValidIgnore = Array.isArray(ignore) && ignore.every((word) => typeof word === 'string' && word.length > 0);
665
- if (!isValidIgnore) {
666
- errors.push({
667
- message: `Rule "${name}": spelling option "ignore" must be an array of non-empty strings`,
668
- path: `${name}.assertions.spelling.ignore`,
669
- });
670
- }
671
- }
672
- }
673
- /**
674
- * Validates the `length` assertion's options. `unit` is required and must be
675
- * one of `'characters' | 'words' | 'sentences'` -- an unrecognized value
676
- * would otherwise reach `length.ts`'s `measure()` and fall through to the
677
- * word-tokenizer branch silently, scoring the wrong thing with no error.
678
- * At least one of `min`/`max` is required, and an inverted range (`min` >
679
- * `max`) is an error -- same reasoning as `occurrence`/`metric` above.
680
- */
681
- const LENGTH_OPTION_KEYS = new Set(['unit', 'min', 'max']);
682
- const LENGTH_UNITS = new Set(['characters', 'words', 'sentences']);
683
- function validateLengthOptions(rule, name, errors) {
684
- const lengthConfig = requireOptionsObject(rule, name, 'length', errors);
685
- if (!lengthConfig)
686
- return;
687
- for (const key of Object.keys(lengthConfig)) {
688
- if (!LENGTH_OPTION_KEYS.has(key)) {
689
- errors.push({
690
- message: `Rule "${name}": unknown length option "${key}"`,
691
- path: `${name}.assertions.length.${key}`,
692
- });
693
- }
694
- }
695
- const { unit, min, max } = lengthConfig;
696
- if (typeof unit !== 'string' || !LENGTH_UNITS.has(unit)) {
697
- errors.push({
698
- message: `Rule "${name}": length requires "unit" to be one of ${[...LENGTH_UNITS].join(', ')}`,
699
- path: `${name}.assertions.length.unit`,
700
- });
701
- }
702
- if (min === undefined && max === undefined) {
703
- errors.push({
704
- message: `Rule "${name}": length requires at least one of "min" or "max"`,
705
- path: `${name}.assertions.length`,
706
- });
707
- }
708
- if (min !== undefined && typeof min !== 'number') {
709
- errors.push({
710
- message: `Rule "${name}": length option "min" must be a number`,
711
- path: `${name}.assertions.length.min`,
712
- });
713
- }
714
- if (max !== undefined && typeof max !== 'number') {
715
- errors.push({
716
- message: `Rule "${name}": length option "max" must be a number`,
717
- path: `${name}.assertions.length.max`,
718
- });
719
- }
720
- if (typeof min === 'number' && typeof max === 'number' && min > max) {
721
- errors.push({
722
- message: `Rule "${name}": length "min" (${min}) must not exceed "max" (${max})`,
723
- path: `${name}.assertions.length`,
724
- });
725
- }
726
- // `min: 0` (never
727
- // violated -- a segment can't have fewer than 0 characters/words/
728
- // sentences) and a negative `max` (always violated) are silent no-op/
729
- // always-fire footguns, same reasoning as list-length's identical check
730
- // above -- see validateCountBounds's doc comment.
731
- validateCountBounds(name, 'length', min, max, errors);
732
- }
733
- /**
734
- * Validates each find -> replace entry under `swap.pairs`: the KEY must be
735
- * a non-empty string (an empty one escapes to a zero-width pattern in
736
- * swap.ts's findMatches, same hazard as consistency's `either` keys); the
737
- * VALUE must be a string, possibly empty -- an empty replacement is a
738
- * legitimate "delete this word" swap.
739
- */
740
- function validateSwapPairEntries(entries, name, path, errors) {
741
- for (const [key, value] of entries) {
742
- const entryPath = `${path}.${key}`;
743
- if (key.length === 0) {
744
- errors.push({
745
- message: `Rule "${name}": swap "pairs" entry keys must be non-empty strings`,
746
- path: entryPath,
747
- });
748
- }
749
- if (typeof value !== 'string') {
750
- errors.push({
751
- message: `Rule "${name}": swap "pairs" entry "${key}" must map to a string replacement`,
752
- path: entryPath,
753
- });
754
- }
755
- }
756
- }
757
- /**
758
- * Validates the `swap` assertion's options. Exactly one shape is accepted
759
- * -- the only one swap.ts's findMatches actually consumes:
760
- *
761
- * `{ ignoreCase?, wordBoundary?, keysAreRegex?, pairs: {find: replace} }`
762
- *
763
- * The legacy "direct" top-level shape (`swap: { he: they }`) is rejected
764
- * with a migration hint: findMatches only ever reads `options.pairs`, so
765
- * direct entries validated fine but were silently inert -- rejecting them
766
- * turns that no-op into an actionable config error.
767
- */
768
- const SWAP_RESERVED_KEYS = new Set([
769
- 'ignoreCase',
770
- 'wordBoundary',
771
- 'keysAreRegex',
772
- 'pairs',
773
- 'includeCode',
774
- ]);
775
- const SWAP_BOOLEAN_OPTION_KEYS = [
776
- 'ignoreCase',
777
- 'wordBoundary',
778
- 'keysAreRegex',
779
- 'includeCode',
780
- ];
781
- function validateSwapOptions(rule, name, errors) {
782
- const swapConfig = requireOptionsObject(rule, name, 'swap', errors);
783
- if (!swapConfig)
784
- return;
785
- for (const key of Object.keys(swapConfig)) {
786
- if (!SWAP_RESERVED_KEYS.has(key)) {
787
- errors.push({
788
- message: `Rule "${name}": unknown swap option "${key}" -- swap does not accept ` +
789
- `find -> replace entries at the top level; move find -> replace entries under "pairs:"`,
790
- path: `${name}.assertions.swap.${key}`,
791
- });
792
- }
793
- }
794
- for (const key of SWAP_BOOLEAN_OPTION_KEYS) {
795
- const value = swapConfig[key];
796
- if (value !== undefined && typeof value !== 'boolean') {
797
- errors.push({
798
- message: `Rule "${name}": swap option "${key}" must be a boolean`,
799
- path: `${name}.assertions.swap.${key}`,
800
- });
801
- }
802
- }
803
- if (!('pairs' in swapConfig)) {
804
- errors.push({
805
- message: `Rule "${name}": swap requires a "pairs" object mapping find -> replace strings`,
806
- path: `${name}.assertions.swap.pairs`,
807
- });
808
- return;
809
- }
810
- const pairs = swapConfig.pairs;
811
- if (!pairs ||
812
- typeof pairs !== 'object' ||
813
- Array.isArray(pairs) ||
814
- Object.keys(pairs).length === 0) {
815
- errors.push({
816
- message: `Rule "${name}": swap option "pairs" must be a non-empty object mapping find -> replace strings`,
817
- path: `${name}.assertions.swap.pairs`,
818
- });
819
- }
820
- else {
821
- validateSwapPairEntries(Object.entries(pairs), name, `${name}.assertions.swap.pairs`, errors);
822
- }
823
- }
824
- /**
825
- * Missing-peer validation for `spelling`: `nspell` and `dictionary-en` are
826
- * OPTIONAL peer dependencies, so a config that enables `spelling` without
827
- * them installed must fail here with an actionable install command rather
828
- * than as a bare "Cannot find module" the first time a file is linted.
829
- * Runs per spelling rule so a mix of default-dictionary and
830
- * custom-dictionary rules gets the right install command for each; a
831
- * config with no `spelling` assertion never reaches an `import()` call at
832
- * all, keeping validate() lazy about the peers.
833
- *
834
- * ALSO validates that a custom `dictionary`
835
- * path actually names a readable `.aff`/`.dic` pair: the check above only
836
- * ever checked whether `nspell` itself imports, never whether the FILES a
837
- * `dictionary` option points at exist — so a missing/unreadable custom
838
- * dictionary used to pass validation cleanly and only fail (silently: see
839
- * spelling.ts's `loadSpeller`/`spellerCache`) the first time a file was
840
- * linted, disabling spelling for the rest of the process. Resolved via
841
- * `resolveDictionaryPaths`, SHARED with spelling.ts's own
842
- * `readCustomDictionary`, so validate() and the runtime can never disagree
843
- * about which files a `dictionary` path names.
844
- */
845
- async function checkSpellingPeerDependencies(rules) {
846
- const errors = [];
847
- const reportedMessages = new Set();
848
- const reportedDictionaryPaths = new Set();
849
- for (const rule of rules) {
850
- const spellingConfig = rule.assertions?.['spelling'];
851
- if (!spellingConfig || typeof spellingConfig !== 'object')
852
- continue;
853
- const dictionaryPath = spellingConfig.dictionary;
854
- const hasCustomDictionary = typeof dictionaryPath === 'string' && dictionaryPath.length > 0;
855
- let missingPeer = false;
856
- try {
857
- await import('nspell');
858
- }
859
- catch {
860
- missingPeer = true;
861
- }
862
- // A custom-dictionary rule never touches `dictionary-en` (see
863
- // spelling.ts's loadDictionary), so its absence must not fail it.
864
- if (!hasCustomDictionary) {
865
- try {
866
- await import('dictionary-en');
867
- }
868
- catch {
869
- missingPeer = true;
870
- }
871
- }
872
- if (missingPeer) {
873
- const installCommand = hasCustomDictionary ? 'npm i nspell' : 'npm i nspell dictionary-en';
874
- const peerNames = hasCustomDictionary ? '"nspell"' : '"nspell" and "dictionary-en"';
875
- const message = `The spelling assertion requires the optional peer dependenc${hasCustomDictionary ? 'y' : 'ies'} ` +
876
- `${peerNames} — run \`${installCommand}\` to enable it.`;
877
- // Each distinct message is reported once, at the first offending
878
- // rule's path; a mixed config still reports both install commands.
879
- if (!reportedMessages.has(message)) {
880
- reportedMessages.add(message);
881
- errors.push({ message, path: `${rule.name}.assertions.spelling` });
882
- }
883
- }
884
- // Independent of the peer-import check above: even when `nspell`
885
- // imports fine, a custom `dictionary` option may still name files that
886
- // don't exist or aren't readable. Dedupe by the raw dictionary path
887
- // string so several rules sharing one bad path only report once.
888
- if (hasCustomDictionary && !reportedDictionaryPaths.has(dictionaryPath)) {
889
- reportedDictionaryPaths.add(dictionaryPath);
890
- const { aff, dic } = resolveDictionaryPaths(dictionaryPath);
891
- const unreadable = [];
892
- for (const filePath of [aff, dic]) {
893
- try {
894
- await fs.access(filePath, fs.constants.R_OK);
895
- }
896
- catch {
897
- unreadable.push(filePath);
898
- }
899
- }
900
- if (unreadable.length > 0) {
901
- errors.push({
902
- message: `Rule "${rule.name}": spelling dictionary file${unreadable.length > 1 ? 's' : ''} ` +
903
- `not found or not readable: ${unreadable.join(', ')}`,
904
- path: `${rule.name}.assertions.spelling.dictionary`,
905
- });
906
- }
907
- }
908
- }
909
- return errors;
910
- }
911
- /**
912
- * Warns about a config that extends the `recheck/markdoc` preset without
913
- * turning markdoc parsing on. The preset's four rules only look at
914
- * `ctx.markdoc`, which the runner populates only when parsing is enabled, so
915
- * such a config ships four rule entries that can never report. That is dead
916
- * weight rather than a broken config, so this goes to `console.warn` (the
917
- * validation result carries only errors, no warnings) and `isValid` stays
918
- * `true`.
919
- *
920
- * Reads the raw, pre-`resolveExtends` `extends` array rather than the merged
921
- * config: post-merge, the four rule keys the preset contributes are
922
- * indistinguishable from a user hand-writing the same `recheck/markdoc-*` keys
923
- * directly, which is a legitimate way to opt into only some of them and is not
924
- * what this warning is about. The literal `"recheck/markdoc"` entry in
925
- * `extends` is the one unambiguous signal that the preset itself was requested.
926
- */
927
- function warnStaleMarkdocPreset(extendsList, markdocEnabled, warnOnce) {
928
- if (markdocEnabled || !Array.isArray(extendsList))
929
- return;
930
- if (!extendsList.includes('recheck/markdoc'))
931
- return;
932
- warnOnce('recheck: config extends "recheck/markdoc" but "markdoc" parsing is off — its four rules ' +
933
- 'can never fire; set "markdoc: true" (or an object form) to enable them.');
934
- }
935
- /**
936
- * Reads, parses, and shape-checks `markdoc.extend.tagsFile`, resolved
937
- * relative to `configDir`. Returns the file's tags (already validated per
938
- * entry against the same `MARKDOC_TAG_SCHEMA` inline `extend.tags` uses) plus
939
- * any config errors; a non-empty error list means the caller must treat
940
- * markdoc as disabled for this call, the same as any other structurally
941
- * invalid markdoc shape.
942
- *
943
- * Deliberately does not touch the filesystem unless `raw` actually names a
944
- * `tagsFile` -- a config with markdoc off, or with only inline `extend.tags`,
945
- * must never probe for a file it never referenced.
946
- */
947
- async function loadMarkdocTagsFile(raw, configDir) {
948
- const tagsFile = raw !== null && typeof raw === 'object' ? raw.extend?.tagsFile : undefined;
949
- if (!tagsFile)
950
- return { errors: [] };
951
- const resolvedPath = path.resolve(configDir, tagsFile);
952
- const errors = [];
953
- let content;
954
- try {
955
- content = await fs.readFile(resolvedPath, 'utf8');
956
- }
957
- catch (error) {
958
- errors.push({
959
- path: '/markdoc/extend/tagsFile',
960
- message: `markdoc.extend.tagsFile: could not read "${resolvedPath}": ${error.message}`,
961
- });
962
- return { errors };
963
- }
964
- let parsed;
965
- try {
966
- parsed = yaml.load(content);
967
- }
968
- catch (error) {
969
- errors.push({
970
- path: '/markdoc/extend/tagsFile',
971
- message: `markdoc.extend.tagsFile: could not parse "${resolvedPath}" as YAML: ${error.message}`,
972
- });
973
- return { errors };
974
- }
975
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
976
- errors.push({
977
- path: '/markdoc/extend/tagsFile',
978
- message: `markdoc.extend.tagsFile: "${resolvedPath}" must be a YAML map of tag name to tag schema, got ${parsed === null ? 'null' : Array.isArray(parsed) ? 'an array' : typeof parsed}`,
979
- });
980
- return { errors };
981
- }
982
- const fileTags = {};
983
- for (const [tagName, tagValue] of Object.entries(parsed)) {
984
- if (!validateMarkdocTagShape(tagValue)) {
985
- const detail = ajv.errorsText(validateMarkdocTagShape.errors, { separator: '; ' });
986
- errors.push({
987
- path: `/markdoc/extend/tagsFile/${tagName}`,
988
- message: `markdoc.extend.tagsFile: "${resolvedPath}" tag "${tagName}" is invalid: ${detail}`,
989
- });
990
- continue;
991
- }
992
- fileTags[tagName] = tagValue;
993
- }
994
- // Any per-tag shape failure invalidates the whole file's contribution --
995
- // partially trusting a file that failed its own shape check would silently
996
- // merge an unvalidated tag into the resolved schema.
997
- if (errors.length > 0)
998
- return { errors };
999
- return { fileTags, errors: [] };
1000
- }
1001
- /**
1002
- * Stale-pattern warning: a `pattern` assertion token that starts
1003
- * with the literal characters `^#` almost always indicates a config
1004
- * written for the pre-AST line-based scope extractor, where segment
1005
- * content still included the raw `#` heading marker. After the AST
1006
- * migration, non-`raw`/non-`all` scopes (e.g. `heading`, `sentence`,
1007
- * `paragraph`) hand `pattern` only the semantic TEXT of the segment — the
1008
- * literal markup is already stripped — so a token anchored on `^#` can
1009
- * never match and the rule silently does nothing. `scope: raw` (and the
1010
- * default `scope: all`, which also sees full raw file content) are exempt:
1011
- * both still see literal markup, so `^#` is a legitimate anchor there.
1012
- * This exact silent-death case was found in the repo's own recheck.yaml
1013
- * after the AST migration.
1014
- */
1015
- function warnStalePatternPrefix(rule, name, warnOnce) {
1016
- const patternConfig = rule.assertions?.['pattern'];
1017
- if (!patternConfig || !Array.isArray(patternConfig.tokens))
1018
- return;
1019
- const scopeEntries = rule.scope === undefined ? [] : Array.isArray(rule.scope) ? rule.scope : [rule.scope];
1020
- // Each scope entry may itself be a `&`-joined selector clause (e.g.
1021
- // '~blockquote & ~heading') — split and check every term, since ANY
1022
- // non-raw/non-all term in the selector means some matched segments will
1023
- // be semantic-text-only. Parsed via the selector module's own tokenizer
1024
- // so this check can't drift from how compileSelector reads the entry.
1025
- const scopeTerms = scopeEntries.flatMap((entry) => typeof entry === 'string' ? tokenizeSelector(entry).map(({ term }) => term) : []);
1026
- const hasRawOrAllScope = scopeEntries.length === 0 || scopeTerms.some((term) => term === 'raw' || term === 'all');
1027
- if (hasRawOrAllScope)
1028
- return;
1029
- for (const token of patternConfig.tokens) {
1030
- if (typeof token === 'string' && token.startsWith('^#')) {
1031
- const scopeDisplay = Array.isArray(rule.scope) ? rule.scope.join(', ') : String(rule.scope);
1032
- warnOnce(`recheck: Rule "${name}": pattern "${token}" starts with '^#' but scope "${scopeDisplay}" matches semantic text without markup — drop the '#' prefix or use scope: raw`);
1033
- }
1034
- }
1035
- }
1036
- /**
1037
- * Vale parity: `metric` rules are ALWAYS summary-scoped — readability is a
1038
- * whole-document score over the document's prose, which is exactly what the
1039
- * `summary` scope segments carry (see scopes/extractor.ts). Any rule whose
1040
- * assertions include `metric` gets `scope: 'summary'` forced here, so the
1041
- * runner hands metric.ts the summary segments and the rule never re-extracts
1042
- * scopes itself. A config that EXPLICITLY set some other scope gets a
1043
- * warning that the scope is ignored — a warning, not an error, because the
1044
- * rule still behaves correctly; ValidationResult has no warning channel
1045
- * (only errors), so this uses console.warn via `warnOnce`, the
1046
- * `warnStalePatternPrefix` precedent above. Explicitness comes from
1047
- * `hasExplicitScope` (captured BEFORE schema validation): AJV `useDefaults`
1048
- * injects `scope: 'all'` onto every rule that omitted it, so post-schema the
1049
- * two cases are indistinguishable.
1050
- */
1051
- function normalizeMetricScope(rule, name, hasExplicitScope, warnOnce) {
1052
- if (!rule.assertions || typeof rule.assertions !== 'object' || !('metric' in rule.assertions)) {
1053
- return rule.scope;
1054
- }
1055
- if (hasExplicitScope) {
1056
- const entries = Array.isArray(rule.scope) ? rule.scope : [rule.scope];
1057
- const isSummary = entries.length === 1 && (entries[0] === 'summary' || entries[0] === 'default');
1058
- if (!isSummary) {
1059
- const scopeDisplay = Array.isArray(rule.scope) ? rule.scope.join(', ') : String(rule.scope);
1060
- warnOnce(`recheck: Rule "${name}": metric is always summary-scoped; ignoring configured scope "${scopeDisplay}"`);
1061
- }
1062
- }
1063
- return 'summary';
1064
- }
1065
- /**
1066
- * Validates a rule's `scope` field against the full scope vocabulary and
1067
- * selector syntax (optional `~` negation, `&`-joined terms). AJV only
1068
- * checks the structural shape (string, or array of strings); this is the
1069
- * term-level check that gives a helpful message naming the bad term.
1070
- */
1071
- function validateScope(rule, name, errors) {
1072
- if (rule.scope === undefined)
1073
- return;
1074
- const entries = Array.isArray(rule.scope) ? rule.scope : [rule.scope];
1075
- for (const entry of entries) {
1076
- if (typeof entry !== 'string')
1077
- continue; // caught by schema
1078
- for (const problem of validateScopeSelector(entry)) {
1079
- errors.push({
1080
- message: `Rule "${name}": invalid scope — ${problem}`,
1081
- path: `${name}.scope`,
1082
- });
1083
- }
1084
- // `all`/`raw` as a TERM inside a compound or negated selector expression
1085
- // (`heading & all`, `~all`, `~code & ~raw`) is the within-entry variant
1086
- // of the array-mixing mistake rejected below: the conjunction form
1087
- // compiles to a predicate that can never match (silently reporting
1088
- // nothing), the negated form to one that matches every segment. The
1089
- // shared helper (scopes/selector.ts) is also what makes compileSelector
1090
- // throw on these shapes, so validation and compilation reject exactly
1091
- // the same inputs.
1092
- for (const problem of wholeDocumentKeywordProblems(entry)) {
1093
- errors.push({
1094
- message: `Rule "${name}": invalid scope — ${problem}`,
1095
- path: `${name}.scope`,
1096
- });
1097
- }
1098
- }
1099
- // `all`/`raw` are whole-document keywords, not segment names — the
1100
- // extractor never emits segments with those scopes, so combining either
1101
- // with any other array entry (e.g. `scope: [all, code]`) can only ever
1102
- // silently match nothing for the `all`/`raw` part. A single-element array
1103
- // (`scope: ['all']`) is fine — compileSelector normalizes it to the bare
1104
- // string's whole-document semantics — but a mix is a config mistake that
1105
- // must fail loudly rather than validate and then report zero findings.
1106
- if (entries.length > 1) {
1107
- for (const entry of entries) {
1108
- if (typeof entry !== 'string')
1109
- continue; // caught by schema
1110
- const term = entry.trim();
1111
- if (term === 'all' || term === 'raw') {
1112
- errors.push({
1113
- message: `Rule "${name}": scope "${term}" covers the whole document and cannot be ` +
1114
- `combined with other scopes — use \`scope: ${term}\` alone`,
1115
- path: `${name}.scope`,
1116
- });
1117
- }
1118
- }
1119
- }
1120
- }
1121
- /**
1122
- * Per-assertion `%s` message-placeholder caps. `metric` passes four values
1123
- * (formula, score, min, max); `length` passes three (size, unit, bound --
1124
- * see rules/scope/length.ts's FALLBACK_MAX/FALLBACK_MIN); every other
1125
- * assertion passes at most two. A rule's cap is the largest among its
1126
- * configured assertions, so a message can never declare more slots than its
1127
- * assertion will ever fill.
1128
- */
1129
- const MESSAGE_PLACEHOLDER_CAPS = {
1130
- metric: 4,
1131
- length: 3,
1132
- };
1133
- const DEFAULT_MESSAGE_PLACEHOLDER_CAP = 2;
1134
- function messagePlaceholderCap(rule) {
1135
- const assertions = rule.assertions;
1136
- const assertionIds = assertions && typeof assertions === 'object' ? Object.keys(assertions) : [];
1137
- return assertionIds.reduce((cap, id) => Math.max(cap, MESSAGE_PLACEHOLDER_CAPS[id] ?? DEFAULT_MESSAGE_PLACEHOLDER_CAP), DEFAULT_MESSAGE_PLACEHOLDER_CAP);
1138
- }
1139
- function validateSemantics(config, rulesWithExplicitScope = new Set()) {
1140
- const errors = [];
1141
- const rules = [];
1142
- // Dedupes the stale-pattern warning below to once per distinct message
1143
- // for this whole validate() call — a config with the same stale pattern
1144
- // shape on more than one rule only warns once per load.
1145
- const warnedMessages = new Set();
1146
- const warnOnce = (message) => {
1147
- if (warnedMessages.has(message))
1148
- return;
1149
- warnedMessages.add(message);
1150
- console.warn(message);
1151
- };
1152
- for (const [key, rule] of Object.entries(config)) {
1153
- try {
1154
- // Derive name and shortName
1155
- const name = key;
1156
- const shortName = key.replace(/^recheck\//, '');
1157
- // Validate message placeholder count against the rule's own
1158
- // per-assertion cap (see MESSAGE_PLACEHOLDER_CAPS above). `rule.message`
1159
- // is required by the JSON schema (see schema.ts `required`) so it is
1160
- // always a string by the time a config passes AJV structural
1161
- // validation; the `?? ''` only satisfies the now-optional
1162
- // NormalizedRule/BaseRule type.
1163
- const placeholderCount = ((rule.message ?? '').match(/%s/g) || []).length;
1164
- const placeholderCap = messagePlaceholderCap(rule);
1165
- if (placeholderCount > placeholderCap) {
1166
- errors.push({
1167
- message: `Rule "${name}": message can have at most ${placeholderCap} %s placeholders, found ${placeholderCount}`,
1168
- path: `${name}.message`,
1169
- });
1170
- }
1171
- // Assertions validation
1172
- validateAssertions(rule, name, errors);
1173
- // Removed `pattern` options (negate) must fail loudly, not no-op
1174
- validatePatternOptions(rule, name, errors);
1175
- validateOccurrenceOptions(rule, name, errors);
1176
- validateRepetitionOptions(rule, name, errors);
1177
- validateConsistencyOptions(rule, name, errors);
1178
- validateConditionalOptions(rule, name, errors);
1179
- validateCapitalizationOptions(rule, name, errors);
1180
- validateMetricOptions(rule, name, errors);
1181
- validateListLengthOptions(rule, name, errors);
1182
- validateSpellingOptions(rule, name, errors);
1183
- validateSwapOptions(rule, name, errors);
1184
- validateLengthOptions(rule, name, errors);
1185
- // Scope vocabulary/selector-syntax validation
1186
- validateScope(rule, name, errors);
1187
- // Stale `^#`-prefixed pattern token vs. non-raw/non-all scope
1188
- warnStalePatternPrefix(rule, name, warnOnce);
1189
- // Create normalized rule. `metric` rules are forced to
1190
- // `scope: summary` (see normalizeMetricScope above).
1191
- const normalizedRule = {
1192
- ...rule,
1193
- scope: normalizeMetricScope(rule, name, rulesWithExplicitScope.has(name), warnOnce),
1194
- name,
1195
- shortName,
1196
- };
1197
- rules.push(normalizedRule);
1198
- }
1199
- catch (error) {
1200
- errors.push({
1201
- message: `Rule "${key}": ${error.message}`,
1202
- path: key,
1203
- });
1204
- }
1205
- }
1206
- return { errors, rules };
1207
- }
1208
- /**
1209
- * Full validation pipeline. `options.configDir` (default `process.cwd()`) is
1210
- * where a relative `markdoc.extend.tagsFile` resolves from -- the directory
1211
- * containing the config file, so a project's `tagsFile: ./tags.yaml` behaves
1212
- * the same regardless of the caller's own working directory.
1213
- */
1214
- export async function validate(config, options) {
1215
- // Resolve `extends` presets before schema validation of rules: the
1216
- // merged (preset + user) config is what gets schema/semantic-validated,
1217
- // so patternProperties only ever sees real `<namespace>/<rule>` rule keys
1218
- // (`recheck/*` and, since the style-guide presets were added, `google/*`,
1219
- // `microsoft/*`, and other preset-namespaced ids -- see schema.ts).
1220
- // `extends` itself is schema-legal at the top level (see schema.ts) but
1221
- // is stripped here — it is not a rule and must not reach rule iteration.
1222
- // `resolveExtends` only fails to merge the UNRESOLVABLE preset name(s) it
1223
- // reports in `extendsErrors` — every other preset and all of the user's
1224
- // own top-level rule keys still land in `resolvedConfig` — so structure
1225
- // and semantic validation below still run against everything that DID
1226
- // resolve, instead of being skipped just because one `extends` entry
1227
- // named an unknown preset. An unknown preset used to short-circuit semantic
1228
- // validation entirely, hiding e.g. an unknown assertion id elsewhere in the
1229
- // same config.
1230
- const hasExtends = config && typeof config === 'object' && 'extends' in config;
1231
- const { config: resolvedConfig, errors: extendsErrors } = hasExtends
1232
- ? resolveExtends(config)
1233
- : { config: config, errors: [] };
1234
- // Which rules carry an EXPLICIT `scope`, recorded before validateStructure
1235
- // runs: AJV `useDefaults` mutates the config in place, injecting
1236
- // `scope: 'all'` onto every rule that omitted it, so this is the only
1237
- // point where "configured" and "defaulted" scopes are distinguishable —
1238
- // normalizeMetricScope needs the distinction to warn only about scopes a
1239
- // user actually wrote.
1240
- const rulesWithExplicitScope = new Set(resolvedConfig && typeof resolvedConfig === 'object'
1241
- ? Object.entries(resolvedConfig)
1242
- .filter(([key, rule]) => key !== 'extends' &&
1243
- key !== 'markdoc' &&
1244
- key !== 'excludes' &&
1245
- key !== 'baseline' &&
1246
- rule !== null &&
1247
- typeof rule === 'object' &&
1248
- 'scope' in rule)
1249
- .map(([key]) => key)
1250
- : []);
1251
- const structureErrors = validateStructure(resolvedConfig);
1252
- // `markdoc`, like `extends`, is an engine-level flag rather than a rule, so
1253
- // it is read here before being stripped from rule iteration below.
1254
- // `resolveMarkdocConfig` is defensive about the shape it is handed, so this
1255
- // is safe to call even when `structureErrors` is about to report the same
1256
- // value as invalid (e.g. `{ schema: 'bogus' }`).
1257
- const rawMarkdoc = resolvedConfig?.markdoc;
1258
- let { enabled: markdocEnabled, schema: markdocSchema } = resolveMarkdocConfig(rawMarkdoc);
1259
- // The stale-preset warning is independent of structure and semantic
1260
- // validity, so it runs here rather than after an error-return path below
1261
- // could short-circuit it. A bare `console.warn` is enough: unlike
1262
- // `warnStalePatternPrefix`, which runs once per rule and needs the deduping
1263
- // `warnOnce`, this fires at most once per `validate()` call.
1264
- warnStaleMarkdocPreset(hasExtends ? config.extends : undefined, markdocEnabled, (message) => console.warn(message));
1265
- if (structureErrors.length > 0) {
1266
- return {
1267
- isValid: false,
1268
- errors: [...extendsErrors, ...structureErrors],
1269
- rules: [],
1270
- markdoc: { enabled: markdocEnabled, schema: markdocSchema },
1271
- };
1272
- }
1273
- // Only reached once structural validation passed, so `rawMarkdoc`'s shape
1274
- // (including `extend.tagsFile`, when present) is already known-good --
1275
- // safe to resolve and read the file now. `loadMarkdocTagsFile` itself
1276
- // never touches the filesystem when there's no `tagsFile` to load.
1277
- const { fileTags, errors: tagsFileErrors } = await loadMarkdocTagsFile(rawMarkdoc, options?.configDir ?? process.cwd());
1278
- if (tagsFileErrors.length > 0) {
1279
- // Degrade exactly like any other invalid markdoc shape: a broken
1280
- // tagsFile leaves no trustworthy schema for markdoc rules to run
1281
- // against for this call.
1282
- markdocEnabled = false;
1283
- markdocSchema = null;
1284
- }
1285
- else if (fileTags) {
1286
- const resolvedExtend = {
1287
- fileTags,
1288
- tags: rawMarkdoc && typeof rawMarkdoc === 'object' ? rawMarkdoc.extend?.tags : undefined,
1289
- };
1290
- ({ enabled: markdocEnabled, schema: markdocSchema } = resolveMarkdocConfig(rawMarkdoc, resolvedExtend));
1291
- }
1292
- // Then validate semantics of everything that resolved successfully.
1293
- // `markdoc` is stripped first, exactly as `extends` is stripped in
1294
- // resolveExtends, so rule iteration in validateSemantics never sees it.
1295
- const { markdoc: _markdoc, excludes: globalExcludes, baseline: baselinePath, ...rulesOnlyConfig } = resolvedConfig;
1296
- const { errors: semanticErrors, rules: validatedRules } = validateSemantics(rulesOnlyConfig, rulesWithExplicitScope);
1297
- // Merged ahead of each rule's own list rather than replacing it: a rule
1298
- // that already excludes a path keeps doing so.
1299
- const rules = globalExcludes?.length
1300
- ? validatedRules.map((rule) => ({
1301
- ...rule,
1302
- excludes: [...globalExcludes, ...(rule.excludes ?? [])],
1303
- }))
1304
- : validatedRules;
1305
- const peerErrors = await checkSpellingPeerDependencies(rules);
1306
- const errors = [...extendsErrors, ...semanticErrors, ...peerErrors, ...tagsFileErrors];
1307
- return {
1308
- isValid: errors.length === 0,
1309
- errors,
1310
- rules,
1311
- markdoc: { enabled: markdocEnabled, schema: markdocSchema },
1312
- baselinePath,
1313
- };
1314
- }
1315
- //# sourceMappingURL=validate.js.map