chaffjs 0.20.0 → 0.22.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 (762) hide show
  1. package/README.md +7 -5
  2. package/dist/api.d.ts +16 -1
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js.map +1 -1
  5. package/dist/cli-text.d.ts +2 -0
  6. package/dist/cli-text.d.ts.map +1 -1
  7. package/dist/cli-text.js +18 -5
  8. package/dist/cli-text.js.map +1 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +8 -11
  11. package/dist/cli.js.map +1 -1
  12. package/dist/command-help.d.ts +7 -0
  13. package/dist/command-help.d.ts.map +1 -0
  14. package/dist/command-help.js +18 -0
  15. package/dist/command-help.js.map +1 -0
  16. package/dist/commands/eval.js +2 -2
  17. package/dist/commands/eval.js.map +1 -1
  18. package/dist/commands/fix-plan.d.ts.map +1 -1
  19. package/dist/commands/fix-plan.js +11 -1
  20. package/dist/commands/fix-plan.js.map +1 -1
  21. package/dist/commands/help.d.ts +4 -0
  22. package/dist/commands/help.d.ts.map +1 -0
  23. package/dist/commands/help.js +7 -0
  24. package/dist/commands/help.js.map +1 -0
  25. package/dist/commands/init-command.d.ts +4 -0
  26. package/dist/commands/init-command.d.ts.map +1 -0
  27. package/dist/commands/init-command.js +15 -0
  28. package/dist/commands/init-command.js.map +1 -0
  29. package/dist/commands/plugin-init.d.ts +20 -0
  30. package/dist/commands/plugin-init.d.ts.map +1 -0
  31. package/dist/commands/plugin-init.js +129 -0
  32. package/dist/commands/plugin-init.js.map +1 -0
  33. package/dist/commands/plugin-test.d.ts +11 -0
  34. package/dist/commands/plugin-test.d.ts.map +1 -0
  35. package/dist/commands/plugin-test.js +81 -0
  36. package/dist/commands/plugin-test.js.map +1 -0
  37. package/dist/config/load.d.ts +2 -0
  38. package/dist/config/load.d.ts.map +1 -1
  39. package/dist/config/load.js +1 -0
  40. package/dist/config/load.js.map +1 -1
  41. package/dist/config/option-problems.js +2 -2
  42. package/dist/config/option-problems.js.map +1 -1
  43. package/dist/config/rule-problems.js +2 -2
  44. package/dist/config/rule-problems.js.map +1 -1
  45. package/dist/custom/checked.d.ts +9 -0
  46. package/dist/custom/checked.d.ts.map +1 -0
  47. package/dist/custom/checked.js +3 -0
  48. package/dist/custom/checked.js.map +1 -0
  49. package/dist/custom/dsl-fields.d.ts +27 -0
  50. package/dist/custom/dsl-fields.d.ts.map +1 -0
  51. package/dist/custom/dsl-fields.js +86 -0
  52. package/dist/custom/dsl-fields.js.map +1 -0
  53. package/dist/custom/load.d.ts.map +1 -1
  54. package/dist/custom/load.js +2 -0
  55. package/dist/custom/load.js.map +1 -1
  56. package/dist/custom/parse.d.ts +14 -3
  57. package/dist/custom/parse.d.ts.map +1 -1
  58. package/dist/custom/parse.js +44 -40
  59. package/dist/custom/parse.js.map +1 -1
  60. package/dist/custom/problems.d.ts.map +1 -1
  61. package/dist/custom/problems.js +10 -1
  62. package/dist/custom/problems.js.map +1 -1
  63. package/dist/detectors/amount-for-count.d.ts +21 -0
  64. package/dist/detectors/amount-for-count.d.ts.map +1 -0
  65. package/dist/detectors/amount-for-count.js +55 -0
  66. package/dist/detectors/amount-for-count.js.map +1 -0
  67. package/dist/detectors/blank-structure.d.ts.map +1 -1
  68. package/dist/detectors/blank-structure.js +6 -4
  69. package/dist/detectors/blank-structure.js.map +1 -1
  70. package/dist/detectors/clause-shape.d.ts +22 -0
  71. package/dist/detectors/clause-shape.d.ts.map +1 -0
  72. package/dist/detectors/clause-shape.js +149 -0
  73. package/dist/detectors/clause-shape.js.map +1 -0
  74. package/dist/detectors/code-fences.d.ts +34 -0
  75. package/dist/detectors/code-fences.d.ts.map +1 -0
  76. package/dist/detectors/code-fences.js +100 -0
  77. package/dist/detectors/code-fences.js.map +1 -0
  78. package/dist/detectors/cross-definitions.d.ts +4 -0
  79. package/dist/detectors/cross-definitions.d.ts.map +1 -0
  80. package/dist/detectors/cross-definitions.js +43 -0
  81. package/dist/detectors/cross-definitions.js.map +1 -0
  82. package/dist/detectors/cross-facts.d.ts +4 -0
  83. package/dist/detectors/cross-facts.d.ts.map +1 -0
  84. package/dist/detectors/cross-facts.js +53 -0
  85. package/dist/detectors/cross-facts.js.map +1 -0
  86. package/dist/detectors/cross-registry/cross-doc-duplicate-definition.d.ts +3 -0
  87. package/dist/detectors/cross-registry/cross-doc-duplicate-definition.d.ts.map +1 -0
  88. package/dist/detectors/cross-registry/cross-doc-duplicate-definition.js +3 -0
  89. package/dist/detectors/cross-registry/cross-doc-duplicate-definition.js.map +1 -0
  90. package/dist/detectors/cross-registry/cross-doc-fact-conflict.d.ts +3 -0
  91. package/dist/detectors/cross-registry/cross-doc-fact-conflict.d.ts.map +1 -0
  92. package/dist/detectors/cross-registry/cross-doc-fact-conflict.js +3 -0
  93. package/dist/detectors/cross-registry/cross-doc-fact-conflict.js.map +1 -0
  94. package/dist/detectors/currency-notation.d.ts +29 -0
  95. package/dist/detectors/currency-notation.d.ts.map +1 -0
  96. package/dist/detectors/currency-notation.js +58 -0
  97. package/dist/detectors/currency-notation.js.map +1 -0
  98. package/dist/detectors/custom.d.ts.map +1 -1
  99. package/dist/detectors/custom.js +4 -1
  100. package/dist/detectors/custom.js.map +1 -1
  101. package/dist/detectors/dangling-opener.d.ts +14 -0
  102. package/dist/detectors/dangling-opener.d.ts.map +1 -0
  103. package/dist/detectors/dangling-opener.js +55 -0
  104. package/dist/detectors/dangling-opener.js.map +1 -0
  105. package/dist/detectors/defined-term-form.d.ts +25 -0
  106. package/dist/detectors/defined-term-form.d.ts.map +1 -0
  107. package/dist/detectors/defined-term-form.js +170 -0
  108. package/dist/detectors/defined-term-form.js.map +1 -0
  109. package/dist/detectors/email-letter.d.ts +46 -0
  110. package/dist/detectors/email-letter.d.ts.map +1 -0
  111. package/dist/detectors/email-letter.js +234 -0
  112. package/dist/detectors/email-letter.js.map +1 -0
  113. package/dist/detectors/footnote-mismatch.d.ts +11 -0
  114. package/dist/detectors/footnote-mismatch.d.ts.map +1 -0
  115. package/dist/detectors/footnote-mismatch.js +55 -0
  116. package/dist/detectors/footnote-mismatch.js.map +1 -0
  117. package/dist/detectors/form-minority.d.ts +13 -0
  118. package/dist/detectors/form-minority.d.ts.map +1 -0
  119. package/dist/detectors/form-minority.js +19 -0
  120. package/dist/detectors/form-minority.js.map +1 -0
  121. package/dist/detectors/heading-end-mark.d.ts +10 -0
  122. package/dist/detectors/heading-end-mark.d.ts.map +1 -0
  123. package/dist/detectors/heading-end-mark.js +59 -0
  124. package/dist/detectors/heading-end-mark.js.map +1 -0
  125. package/dist/detectors/impossible-date.d.ts +20 -0
  126. package/dist/detectors/impossible-date.d.ts.map +1 -0
  127. package/dist/detectors/impossible-date.js +105 -0
  128. package/dist/detectors/impossible-date.js.map +1 -0
  129. package/dist/detectors/impossible-time.d.ts +18 -0
  130. package/dist/detectors/impossible-time.d.ts.map +1 -0
  131. package/dist/detectors/impossible-time.js +116 -0
  132. package/dist/detectors/impossible-time.js.map +1 -0
  133. package/dist/detectors/link-shape.d.ts +11 -0
  134. package/dist/detectors/link-shape.d.ts.map +1 -0
  135. package/dist/detectors/link-shape.js +56 -0
  136. package/dist/detectors/link-shape.js.map +1 -0
  137. package/dist/detectors/list-marker.d.ts +7 -0
  138. package/dist/detectors/list-marker.d.ts.map +1 -0
  139. package/dist/detectors/list-marker.js +50 -0
  140. package/dist/detectors/list-marker.js.map +1 -0
  141. package/dist/detectors/mark-shape.d.ts +53 -0
  142. package/dist/detectors/mark-shape.d.ts.map +1 -0
  143. package/dist/detectors/mark-shape.js +160 -0
  144. package/dist/detectors/mark-shape.js.map +1 -0
  145. package/dist/detectors/markdown-slip.d.ts +19 -0
  146. package/dist/detectors/markdown-slip.d.ts.map +1 -0
  147. package/dist/detectors/markdown-slip.js +122 -0
  148. package/dist/detectors/markdown-slip.js.map +1 -0
  149. package/dist/detectors/numeral-opener.d.ts +10 -0
  150. package/dist/detectors/numeral-opener.d.ts.map +1 -0
  151. package/dist/detectors/numeral-opener.js +65 -0
  152. package/dist/detectors/numeral-opener.js.map +1 -0
  153. package/dist/detectors/ordinal-suffix.d.ts +12 -0
  154. package/dist/detectors/ordinal-suffix.d.ts.map +1 -0
  155. package/dist/detectors/ordinal-suffix.js +33 -0
  156. package/dist/detectors/ordinal-suffix.js.map +1 -0
  157. package/dist/detectors/range-notation.d.ts +15 -0
  158. package/dist/detectors/range-notation.d.ts.map +1 -0
  159. package/dist/detectors/range-notation.js +58 -0
  160. package/dist/detectors/range-notation.js.map +1 -0
  161. package/dist/detectors/registry/adverb-polarity.d.ts +3 -0
  162. package/dist/detectors/registry/adverb-polarity.d.ts.map +1 -0
  163. package/dist/detectors/registry/adverb-polarity.js +3 -0
  164. package/dist/detectors/registry/adverb-polarity.js.map +1 -0
  165. package/dist/detectors/registry/amount-for-count.d.ts +3 -0
  166. package/dist/detectors/registry/amount-for-count.d.ts.map +1 -0
  167. package/dist/detectors/registry/amount-for-count.js +3 -0
  168. package/dist/detectors/registry/amount-for-count.js.map +1 -0
  169. package/dist/detectors/registry/attachment-missing.d.ts +3 -0
  170. package/dist/detectors/registry/attachment-missing.d.ts.map +1 -0
  171. package/dist/detectors/registry/attachment-missing.js +3 -0
  172. package/dist/detectors/registry/attachment-missing.js.map +1 -0
  173. package/dist/detectors/registry/bare-url-mix.d.ts +3 -0
  174. package/dist/detectors/registry/bare-url-mix.d.ts.map +1 -0
  175. package/dist/detectors/registry/bare-url-mix.js +3 -0
  176. package/dist/detectors/registry/bare-url-mix.js.map +1 -0
  177. package/dist/detectors/registry/caps-shouting.d.ts +3 -0
  178. package/dist/detectors/registry/caps-shouting.d.ts.map +1 -0
  179. package/dist/detectors/registry/caps-shouting.js +3 -0
  180. package/dist/detectors/registry/caps-shouting.js.map +1 -0
  181. package/dist/detectors/registry/code-fence-language.d.ts +3 -0
  182. package/dist/detectors/registry/code-fence-language.d.ts.map +1 -0
  183. package/dist/detectors/registry/code-fence-language.js +3 -0
  184. package/dist/detectors/registry/code-fence-language.js.map +1 -0
  185. package/dist/detectors/registry/currency-notation.d.ts +3 -0
  186. package/dist/detectors/registry/currency-notation.d.ts.map +1 -0
  187. package/dist/detectors/registry/currency-notation.js +3 -0
  188. package/dist/detectors/registry/currency-notation.js.map +1 -0
  189. package/dist/detectors/registry/dangling-opener.d.ts +3 -0
  190. package/dist/detectors/registry/dangling-opener.d.ts.map +1 -0
  191. package/dist/detectors/registry/dangling-opener.js +3 -0
  192. package/dist/detectors/registry/dangling-opener.js.map +1 -0
  193. package/dist/detectors/registry/defined-name-repeated.d.ts +3 -0
  194. package/dist/detectors/registry/defined-name-repeated.d.ts.map +1 -0
  195. package/dist/detectors/registry/defined-name-repeated.js +3 -0
  196. package/dist/detectors/registry/defined-name-repeated.js.map +1 -0
  197. package/dist/detectors/registry/defined-term-form.d.ts +3 -0
  198. package/dist/detectors/registry/defined-term-form.d.ts.map +1 -0
  199. package/dist/detectors/registry/defined-term-form.js +3 -0
  200. package/dist/detectors/registry/defined-term-form.js.map +1 -0
  201. package/dist/detectors/registry/email-frame.d.ts +3 -0
  202. package/dist/detectors/registry/email-frame.d.ts.map +1 -0
  203. package/dist/detectors/registry/email-frame.js +3 -0
  204. package/dist/detectors/registry/email-frame.js.map +1 -0
  205. package/dist/detectors/registry/email-subject.d.ts +3 -0
  206. package/dist/detectors/registry/email-subject.d.ts.map +1 -0
  207. package/dist/detectors/registry/email-subject.js +3 -0
  208. package/dist/detectors/registry/email-subject.js.map +1 -0
  209. package/dist/detectors/registry/ending-run.d.ts +3 -0
  210. package/dist/detectors/registry/ending-run.d.ts.map +1 -0
  211. package/dist/detectors/registry/ending-run.js +3 -0
  212. package/dist/detectors/registry/ending-run.js.map +1 -0
  213. package/dist/detectors/registry/footnote-mismatch.d.ts +3 -0
  214. package/dist/detectors/registry/footnote-mismatch.d.ts.map +1 -0
  215. package/dist/detectors/registry/footnote-mismatch.js +3 -0
  216. package/dist/detectors/registry/footnote-mismatch.js.map +1 -0
  217. package/dist/detectors/registry/heading-command.d.ts +3 -0
  218. package/dist/detectors/registry/heading-command.d.ts.map +1 -0
  219. package/dist/detectors/registry/heading-command.js +3 -0
  220. package/dist/detectors/registry/heading-command.js.map +1 -0
  221. package/dist/detectors/registry/heading-end-punctuation.d.ts +3 -0
  222. package/dist/detectors/registry/heading-end-punctuation.d.ts.map +1 -0
  223. package/dist/detectors/registry/heading-end-punctuation.js +3 -0
  224. package/dist/detectors/registry/heading-end-punctuation.js.map +1 -0
  225. package/dist/detectors/registry/hyphen-dash.d.ts +3 -0
  226. package/dist/detectors/registry/hyphen-dash.d.ts.map +1 -0
  227. package/dist/detectors/registry/hyphen-dash.js +3 -0
  228. package/dist/detectors/registry/hyphen-dash.js.map +1 -0
  229. package/dist/detectors/registry/image-file-name-alt.d.ts +3 -0
  230. package/dist/detectors/registry/image-file-name-alt.d.ts.map +1 -0
  231. package/dist/detectors/registry/image-file-name-alt.js +3 -0
  232. package/dist/detectors/registry/image-file-name-alt.js.map +1 -0
  233. package/dist/detectors/registry/impossible-date.d.ts +3 -0
  234. package/dist/detectors/registry/impossible-date.d.ts.map +1 -0
  235. package/dist/detectors/registry/impossible-date.js +3 -0
  236. package/dist/detectors/registry/impossible-date.js.map +1 -0
  237. package/dist/detectors/registry/impossible-time.d.ts +3 -0
  238. package/dist/detectors/registry/impossible-time.d.ts.map +1 -0
  239. package/dist/detectors/registry/impossible-time.js +3 -0
  240. package/dist/detectors/registry/impossible-time.js.map +1 -0
  241. package/dist/detectors/registry/latin-abbreviation.d.ts +3 -0
  242. package/dist/detectors/registry/latin-abbreviation.d.ts.map +1 -0
  243. package/dist/detectors/registry/latin-abbreviation.js +3 -0
  244. package/dist/detectors/registry/latin-abbreviation.js.map +1 -0
  245. package/dist/detectors/registry/link-text-url-mismatch.d.ts +3 -0
  246. package/dist/detectors/registry/link-text-url-mismatch.d.ts.map +1 -0
  247. package/dist/detectors/registry/link-text-url-mismatch.js +3 -0
  248. package/dist/detectors/registry/link-text-url-mismatch.js.map +1 -0
  249. package/dist/detectors/registry/list-marker.d.ts +3 -0
  250. package/dist/detectors/registry/list-marker.d.ts.map +1 -0
  251. package/dist/detectors/registry/list-marker.js +3 -0
  252. package/dist/detectors/registry/list-marker.js.map +1 -0
  253. package/dist/detectors/registry/mark-consistency.d.ts +3 -0
  254. package/dist/detectors/registry/mark-consistency.d.ts.map +1 -0
  255. package/dist/detectors/registry/mark-consistency.js +3 -0
  256. package/dist/detectors/registry/mark-consistency.js.map +1 -0
  257. package/dist/detectors/registry/numeral-opener.d.ts +3 -0
  258. package/dist/detectors/registry/numeral-opener.d.ts.map +1 -0
  259. package/dist/detectors/registry/numeral-opener.js +3 -0
  260. package/dist/detectors/registry/numeral-opener.js.map +1 -0
  261. package/dist/detectors/registry/ordinal-suffix.d.ts +3 -0
  262. package/dist/detectors/registry/ordinal-suffix.d.ts.map +1 -0
  263. package/dist/detectors/registry/ordinal-suffix.js +3 -0
  264. package/dist/detectors/registry/ordinal-suffix.js.map +1 -0
  265. package/dist/detectors/registry/origin-particle.d.ts +3 -0
  266. package/dist/detectors/registry/origin-particle.d.ts.map +1 -0
  267. package/dist/detectors/registry/origin-particle.js +3 -0
  268. package/dist/detectors/registry/origin-particle.js.map +1 -0
  269. package/dist/detectors/registry/range-notation.d.ts +3 -0
  270. package/dist/detectors/registry/range-notation.d.ts.map +1 -0
  271. package/dist/detectors/registry/range-notation.js +3 -0
  272. package/dist/detectors/registry/range-notation.js.map +1 -0
  273. package/dist/detectors/registry/relative-pronoun-mix.d.ts +3 -0
  274. package/dist/detectors/registry/relative-pronoun-mix.d.ts.map +1 -0
  275. package/dist/detectors/registry/relative-pronoun-mix.js +3 -0
  276. package/dist/detectors/registry/relative-pronoun-mix.js.map +1 -0
  277. package/dist/detectors/registry/request-without-deadline.d.ts +3 -0
  278. package/dist/detectors/registry/request-without-deadline.d.ts.map +1 -0
  279. package/dist/detectors/registry/request-without-deadline.js +3 -0
  280. package/dist/detectors/registry/request-without-deadline.js.map +1 -0
  281. package/dist/detectors/registry/sentence-spacing.d.ts +3 -0
  282. package/dist/detectors/registry/sentence-spacing.d.ts.map +1 -0
  283. package/dist/detectors/registry/sentence-spacing.js +3 -0
  284. package/dist/detectors/registry/sentence-spacing.js.map +1 -0
  285. package/dist/detectors/registry/share-over-hundred.d.ts +3 -0
  286. package/dist/detectors/registry/share-over-hundred.d.ts.map +1 -0
  287. package/dist/detectors/registry/share-over-hundred.js +3 -0
  288. package/dist/detectors/registry/share-over-hundred.js.map +1 -0
  289. package/dist/detectors/registry/shell-prompt.d.ts +3 -0
  290. package/dist/detectors/registry/shell-prompt.d.ts.map +1 -0
  291. package/dist/detectors/registry/shell-prompt.js +3 -0
  292. package/dist/detectors/registry/shell-prompt.js.map +1 -0
  293. package/dist/detectors/registry/step-reference.d.ts +3 -0
  294. package/dist/detectors/registry/step-reference.d.ts.map +1 -0
  295. package/dist/detectors/registry/step-reference.js +3 -0
  296. package/dist/detectors/registry/step-reference.js.map +1 -0
  297. package/dist/detectors/registry/step-statement.d.ts +3 -0
  298. package/dist/detectors/registry/step-statement.d.ts.map +1 -0
  299. package/dist/detectors/registry/step-statement.js +3 -0
  300. package/dist/detectors/registry/step-statement.js.map +1 -0
  301. package/dist/detectors/registry/table-row-overflow.d.ts +3 -0
  302. package/dist/detectors/registry/table-row-overflow.d.ts.map +1 -0
  303. package/dist/detectors/registry/table-row-overflow.js +3 -0
  304. package/dist/detectors/registry/table-row-overflow.js.map +1 -0
  305. package/dist/detectors/registry/toc-heading.d.ts +3 -0
  306. package/dist/detectors/registry/toc-heading.d.ts.map +1 -0
  307. package/dist/detectors/registry/toc-heading.js +3 -0
  308. package/dist/detectors/registry/toc-heading.js.map +1 -0
  309. package/dist/detectors/registry/unclosed-code-fence.d.ts +3 -0
  310. package/dist/detectors/registry/unclosed-code-fence.d.ts.map +1 -0
  311. package/dist/detectors/registry/unclosed-code-fence.js +3 -0
  312. package/dist/detectors/registry/unclosed-code-fence.js.map +1 -0
  313. package/dist/detectors/registry/unpaired-parallel.d.ts +3 -0
  314. package/dist/detectors/registry/unpaired-parallel.d.ts.map +1 -0
  315. package/dist/detectors/registry/unpaired-parallel.js +3 -0
  316. package/dist/detectors/registry/unpaired-parallel.js.map +1 -0
  317. package/dist/detectors/registry/unrendered-emphasis.d.ts +3 -0
  318. package/dist/detectors/registry/unrendered-emphasis.d.ts.map +1 -0
  319. package/dist/detectors/registry/unrendered-emphasis.js +3 -0
  320. package/dist/detectors/registry/unrendered-emphasis.js.map +1 -0
  321. package/dist/detectors/relative-pronoun-mix.d.ts +19 -0
  322. package/dist/detectors/relative-pronoun-mix.d.ts.map +1 -0
  323. package/dist/detectors/relative-pronoun-mix.js +60 -0
  324. package/dist/detectors/relative-pronoun-mix.js.map +1 -0
  325. package/dist/detectors/request-owner.d.ts +23 -0
  326. package/dist/detectors/request-owner.d.ts.map +1 -0
  327. package/dist/detectors/request-owner.js +110 -0
  328. package/dist/detectors/request-owner.js.map +1 -0
  329. package/dist/detectors/share-over-hundred.d.ts +20 -0
  330. package/dist/detectors/share-over-hundred.d.ts.map +1 -0
  331. package/dist/detectors/share-over-hundred.js +55 -0
  332. package/dist/detectors/share-over-hundred.js.map +1 -0
  333. package/dist/detectors/step-reference.d.ts +20 -0
  334. package/dist/detectors/step-reference.d.ts.map +1 -0
  335. package/dist/detectors/step-reference.js +57 -0
  336. package/dist/detectors/step-reference.js.map +1 -0
  337. package/dist/detectors/technical-docs.d.ts +32 -0
  338. package/dist/detectors/technical-docs.d.ts.map +1 -0
  339. package/dist/detectors/technical-docs.js +199 -0
  340. package/dist/detectors/technical-docs.js.map +1 -0
  341. package/dist/detectors/toc-heading.d.ts +10 -0
  342. package/dist/detectors/toc-heading.d.ts.map +1 -0
  343. package/dist/detectors/toc-heading.js +99 -0
  344. package/dist/detectors/toc-heading.js.map +1 -0
  345. package/dist/extension/pack-read.d.ts +21 -0
  346. package/dist/extension/pack-read.d.ts.map +1 -0
  347. package/dist/extension/pack-read.js +117 -0
  348. package/dist/extension/pack-read.js.map +1 -0
  349. package/dist/extension/plugin-load.d.ts.map +1 -1
  350. package/dist/extension/plugin-load.js +44 -10
  351. package/dist/extension/plugin-load.js.map +1 -1
  352. package/dist/extension/plugin-parse.d.ts.map +1 -1
  353. package/dist/extension/plugin-parse.js +10 -3
  354. package/dist/extension/plugin-parse.js.map +1 -1
  355. package/dist/facts/address-values.d.ts +5 -0
  356. package/dist/facts/address-values.d.ts.map +1 -0
  357. package/dist/facts/address-values.js +64 -0
  358. package/dist/facts/address-values.js.map +1 -0
  359. package/dist/facts/cross-facts.d.ts +20 -0
  360. package/dist/facts/cross-facts.d.ts.map +1 -0
  361. package/dist/facts/cross-facts.js +41 -0
  362. package/dist/facts/cross-facts.js.map +1 -0
  363. package/dist/fix-plan/chosen-depth.d.ts +10 -0
  364. package/dist/fix-plan/chosen-depth.d.ts.map +1 -0
  365. package/dist/fix-plan/chosen-depth.js +24 -0
  366. package/dist/fix-plan/chosen-depth.js.map +1 -0
  367. package/dist/fix-plan/mode.d.ts +13 -4
  368. package/dist/fix-plan/mode.d.ts.map +1 -1
  369. package/dist/fix-plan/mode.js +38 -7
  370. package/dist/fix-plan/mode.js.map +1 -1
  371. package/dist/fix-plan/plan.d.ts +20 -0
  372. package/dist/fix-plan/plan.d.ts.map +1 -1
  373. package/dist/fix-plan/plan.js +23 -5
  374. package/dist/fix-plan/plan.js.map +1 -1
  375. package/dist/fix-plan/render.d.ts.map +1 -1
  376. package/dist/fix-plan/render.js +24 -0
  377. package/dist/fix-plan/render.js.map +1 -1
  378. package/dist/fix-plan/text.d.ts +8 -0
  379. package/dist/fix-plan/text.d.ts.map +1 -1
  380. package/dist/fix-plan/text.js +36 -10
  381. package/dist/fix-plan/text.js.map +1 -1
  382. package/dist/genre-load.d.ts +1 -1
  383. package/dist/genre-load.d.ts.map +1 -1
  384. package/dist/genre-load.js +7 -4
  385. package/dist/genre-load.js.map +1 -1
  386. package/dist/genre-parse.d.ts +6 -0
  387. package/dist/genre-parse.d.ts.map +1 -1
  388. package/dist/genre-parse.js +18 -0
  389. package/dist/genre-parse.js.map +1 -1
  390. package/dist/init.js +10 -10
  391. package/dist/init.js.map +1 -1
  392. package/dist/known-genres.d.ts +8 -0
  393. package/dist/known-genres.d.ts.map +1 -0
  394. package/dist/known-genres.js +17 -0
  395. package/dist/known-genres.js.map +1 -0
  396. package/dist/link-shape.d.ts +20 -0
  397. package/dist/link-shape.d.ts.map +1 -0
  398. package/dist/link-shape.js +58 -0
  399. package/dist/link-shape.js.map +1 -0
  400. package/dist/list-marks.d.ts +21 -0
  401. package/dist/list-marks.d.ts.map +1 -0
  402. package/dist/list-marks.js +82 -0
  403. package/dist/list-marks.js.map +1 -0
  404. package/dist/reasons.d.ts.map +1 -1
  405. package/dist/reasons.js +15 -4
  406. package/dist/reasons.js.map +1 -1
  407. package/dist/render/explain.d.ts.map +1 -1
  408. package/dist/render/explain.js +11 -2
  409. package/dist/render/explain.js.map +1 -1
  410. package/dist/render/friendly.js +1 -1
  411. package/dist/render/friendly.js.map +1 -1
  412. package/dist/render/rules-json.d.ts.map +1 -1
  413. package/dist/render/rules-json.js +12 -3
  414. package/dist/render/rules-json.js.map +1 -1
  415. package/dist/render/rules-table.js +6 -6
  416. package/dist/render/rules-table.js.map +1 -1
  417. package/dist/render/semantic.js +2 -2
  418. package/dist/render/semantic.js.map +1 -1
  419. package/dist/render/suppressions.js +2 -2
  420. package/dist/render/suppressions.js.map +1 -1
  421. package/dist/rewrite-depth.d.ts +22 -0
  422. package/dist/rewrite-depth.d.ts.map +1 -0
  423. package/dist/rewrite-depth.js +42 -0
  424. package/dist/rewrite-depth.js.map +1 -0
  425. package/dist/rule-fields.d.ts +28 -0
  426. package/dist/rule-fields.d.ts.map +1 -0
  427. package/dist/rule-fields.js +85 -0
  428. package/dist/rule-fields.js.map +1 -0
  429. package/dist/rule-guide.d.ts +3 -0
  430. package/dist/rule-guide.d.ts.map +1 -1
  431. package/dist/rule-guide.js +6 -0
  432. package/dist/rule-guide.js.map +1 -1
  433. package/dist/rule-load.d.ts.map +1 -1
  434. package/dist/rule-load.js +13 -5
  435. package/dist/rule-load.js.map +1 -1
  436. package/dist/rule-offs.d.ts +14 -0
  437. package/dist/rule-offs.d.ts.map +1 -0
  438. package/dist/rule-offs.js +45 -0
  439. package/dist/rule-offs.js.map +1 -0
  440. package/dist/structure/build.d.ts.map +1 -1
  441. package/dist/structure/build.js +14 -1
  442. package/dist/structure/build.js.map +1 -1
  443. package/dist/structure/cross-definitions.d.ts +23 -0
  444. package/dist/structure/cross-definitions.d.ts.map +1 -0
  445. package/dist/structure/cross-definitions.js +34 -0
  446. package/dist/structure/cross-definitions.js.map +1 -0
  447. package/genres.yaml +14 -313
  448. package/package.json +3 -3
  449. package/rules/absolute-exception.yaml +3 -1
  450. package/rules/abstract-length.yaml +7 -1
  451. package/rules/acronym-expansion-conflict.yaml +2 -1
  452. package/rules/adverb-overuse.yaml +7 -1
  453. package/rules/adverb-without-negation.yaml +60 -0
  454. package/rules/adversative-ga-repeat.yaml +2 -1
  455. package/rules/agentless-passive.yaml +10 -1
  456. package/rules/agreement-slip.yaml +4 -1
  457. package/rules/ai-generated-composite.yaml +6 -1
  458. package/rules/ai-structure.yaml +8 -2
  459. package/rules/ai-tell.yaml +7 -1
  460. package/rules/all-caps-shouting.yaml +61 -0
  461. package/rules/announced-count-mismatch.yaml +3 -1
  462. package/rules/announcing-opener.yaml +7 -1
  463. package/rules/article-sound.yaml +6 -2
  464. package/rules/assistant-residue.yaml +4 -1
  465. package/rules/attachment-not-attached.yaml +112 -0
  466. package/rules/baito-keigo.yaml +64 -0
  467. package/rules/bare-url-mix.yaml +86 -0
  468. package/rules/bold-density.yaml +1 -0
  469. package/rules/bold-label-list.yaml +9 -1
  470. package/rules/bracket-nesting.yaml +2 -1
  471. package/rules/bracket-width-consistency.yaml +64 -0
  472. package/rules/broken-link.yaml +1 -1
  473. package/rules/chat-citation-residue.yaml +2 -1
  474. package/rules/citation-reference-mismatch.yaml +7 -1
  475. package/rules/citation-style-mix.yaml +7 -1
  476. package/rules/clause-chain.yaml +6 -1
  477. package/rules/cliche.yaml +67 -0
  478. package/rules/closing-cliche.yaml +7 -0
  479. package/rules/code-fence-language-mix.yaml +176 -0
  480. package/rules/colloquial-opener.yaml +62 -0
  481. package/rules/colon-lead-in.yaml +7 -1
  482. package/rules/concrete-evidence-density.yaml +6 -0
  483. package/rules/contraction-consistency.yaml +4 -1
  484. package/rules/contrast-framing.yaml +7 -1
  485. package/rules/cross-doc-duplicate-definition.yaml +70 -0
  486. package/rules/cross-doc-fact-conflict.yaml +64 -0
  487. package/rules/currency-notation-consistency.yaml +77 -0
  488. package/rules/cushion-phrase-density.yaml +8 -1
  489. package/rules/dangling-figure-reference.yaml +3 -1
  490. package/rules/dangling-participle.yaml +58 -0
  491. package/rules/dangling-reference.yaml +3 -1
  492. package/rules/date-format-consistency.yaml +3 -2
  493. package/rules/date-order.yaml +3 -1
  494. package/rules/date-range-reversed.yaml +3 -1
  495. package/rules/date-weekday-mismatch.yaml +3 -1
  496. package/rules/date-without-year.yaml +4 -3
  497. package/rules/defined-name-repeated.yaml +97 -0
  498. package/rules/defined-term-form.yaml +113 -0
  499. package/rules/demonstrative-opener-run.yaml +2 -1
  500. package/rules/double-keigo.yaml +6 -1
  501. package/rules/double-negative.yaml +5 -1
  502. package/rules/doubled-nado.yaml +2 -1
  503. package/rules/doubled-punctuation.yaml +1 -1
  504. package/rules/doubled-word.yaml +4 -1
  505. package/rules/duplicate-definition.yaml +3 -1
  506. package/rules/duplicate-heading.yaml +1 -1
  507. package/rules/duration-mismatch.yaml +2 -1
  508. package/rules/elapsed-years-mismatch.yaml +4 -1
  509. package/rules/email-greeting-closing.yaml +122 -0
  510. package/rules/email-subject-length.yaml +112 -0
  511. package/rules/emoji-density.yaml +3 -1
  512. package/rules/emoji-heading.yaml +7 -1
  513. package/rules/empty-intensifier.yaml +4 -0
  514. package/rules/empty-list-item.yaml +2 -1
  515. package/rules/empty-section.yaml +1 -1
  516. package/rules/empty-table-cell.yaml +2 -1
  517. package/rules/excessive-hedging.yaml +7 -1
  518. package/rules/exclamation-width-consistency.yaml +64 -0
  519. package/rules/expletive-construction.yaml +7 -1
  520. package/rules/fact-conflict.yaml +4 -1
  521. package/rules/figure-reference-order.yaml +7 -1
  522. package/rules/footnote-mismatch.yaml +91 -0
  523. package/rules/fullwidth-alnum-consistency.yaml +2 -2
  524. package/rules/hankaku-kana.yaml +1 -1
  525. package/rules/heading-command-missing.yaml +109 -0
  526. package/rules/heading-echo.yaml +6 -1
  527. package/rules/heading-end-punctuation-mix.yaml +158 -0
  528. package/rules/heading-level-skip.yaml +3 -3
  529. package/rules/heading-numbering-mix.yaml +4 -3
  530. package/rules/hiragana-fukushi.yaml +4 -1
  531. package/rules/homophone-slip.yaml +5 -1
  532. package/rules/humble-for-others.yaml +63 -0
  533. package/rules/hyphen-as-dash.yaml +59 -0
  534. package/rules/idiom-misuse.yaml +4 -1
  535. package/rules/image-file-name-alt.yaml +83 -0
  536. package/rules/impossible-date.yaml +79 -0
  537. package/rules/impossible-time.yaml +76 -0
  538. package/rules/internal-jargon.yaml +1 -1
  539. package/rules/invisible-character.yaml +1 -1
  540. package/rules/katakana-density.yaml +2 -1
  541. package/rules/katakana-long-vowel.yaml +1 -1
  542. package/rules/known-misspelling.yaml +2 -1
  543. package/rules/kutoten-consistency.yaml +1 -1
  544. package/rules/latin-abbreviation-form.yaml +58 -0
  545. package/rules/latin-spacing.yaml +6 -2
  546. package/rules/less-for-fewer.yaml +59 -0
  547. package/rules/link-text-url-mismatch.yaml +72 -0
  548. package/rules/list-item-form-mix.yaml +7 -1
  549. package/rules/list-marker-mix.yaml +111 -0
  550. package/rules/max-kanji-continuous.yaml +10 -2
  551. package/rules/max-paragraph-length.yaml +4 -1
  552. package/rules/max-sentence-length.yaml +29 -21
  553. package/rules/max-ten.yaml +4 -1
  554. package/rules/misconversion.yaml +2 -1
  555. package/rules/modal-conflict.yaml +2 -1
  556. package/rules/name-variant.yaml +4 -3
  557. package/rules/ngram-repetition.yaml +5 -0
  558. package/rules/no-doubled-joshi.yaml +5 -1
  559. package/rules/no-em-dash.yaml +4 -1
  560. package/rules/no-lead.yaml +6 -1
  561. package/rules/no-mixed-desumasu.yaml +5 -2
  562. package/rules/no-nakaguro-parallel.yaml +3 -0
  563. package/rules/nominalization.yaml +5 -1
  564. package/rules/nonstandard-word.yaml +80 -0
  565. package/rules/number-style-consistency.yaml +6 -1
  566. package/rules/number-without-unit.yaml +2 -1
  567. package/rules/numbering-gap.yaml +1 -1
  568. package/rules/numeral-sentence-start.yaml +56 -0
  569. package/rules/one-sentence-paragraph-run.yaml +5 -1
  570. package/rules/ordinal-suffix-mismatch.yaml +65 -0
  571. package/rules/orthographic-variant.yaml +4 -1
  572. package/rules/outside-announced-list.yaml +2 -1
  573. package/rules/oxford-comma-consistency.yaml +3 -1
  574. package/rules/padded-intro.yaml +7 -0
  575. package/rules/paragraph-length-variance.yaml +7 -1
  576. package/rules/paragraph-restatement.yaml +6 -1
  577. package/rules/percent-sum-mismatch.yaml +3 -1
  578. package/rules/person-consistency.yaml +4 -1
  579. package/rules/preamble-length.yaml +6 -0
  580. package/rules/preferred-term.yaml +1 -1
  581. package/rules/proper-noun-density.yaml +8 -1
  582. package/rules/quote-style-consistency.yaml +66 -0
  583. package/rules/ra-nuki.yaml +4 -1
  584. package/rules/range-notation-consistency.yaml +73 -0
  585. package/rules/redundant-expression.yaml +4 -1
  586. package/rules/reference-title-mismatch.yaml +4 -3
  587. package/rules/reference-topic-missing.yaml +2 -1
  588. package/rules/relative-date-mismatch.yaml +2 -1
  589. package/rules/repeated-conjunction.yaml +4 -1
  590. package/rules/repeated-sentence-ending.yaml +62 -0
  591. package/rules/repeated-sentence-head.yaml +4 -0
  592. package/rules/request-without-deadline.yaml +92 -0
  593. package/rules/required-sections.yaml +1 -1
  594. package/rules/requirement-modal.yaml +1 -1
  595. package/rules/requirement-smell.yaml +12 -4
  596. package/rules/rule-of-three.yaml +8 -1
  597. package/rules/sasete-itadaku.yaml +7 -1
  598. package/rules/section-length-uniformity.yaml +7 -1
  599. package/rules/sentence-initial-conjunction-run.yaml +5 -1
  600. package/rules/sentence-initial-so.yaml +6 -1
  601. package/rules/sentence-rhythm.yaml +8 -1
  602. package/rules/sentence-spacing-consistency.yaml +63 -0
  603. package/rules/share-over-hundred.yaml +65 -0
  604. package/rules/shell-prompt-mix.yaml +128 -0
  605. package/rules/space-before-punctuation.yaml +1 -1
  606. package/rules/spelling-consistency.yaml +3 -1
  607. package/rules/step-reference-missing.yaml +85 -0
  608. package/rules/step-statement-mix.yaml +76 -0
  609. package/rules/stock-transition.yaml +8 -1
  610. package/rules/stray-space.yaml +2 -2
  611. package/rules/summary-fact-mismatch.yaml +4 -1
  612. package/rules/table-header-variant.yaml +2 -1
  613. package/rules/table-row-overflow.yaml +90 -0
  614. package/rules/taigen-dome-in-prose.yaml +6 -0
  615. package/rules/tari-unpaired.yaml +58 -0
  616. package/rules/teki-overuse.yaml +2 -1
  617. package/rules/title-case-consistency.yaml +1 -1
  618. package/rules/title-length.yaml +7 -1
  619. package/rules/toc-heading-mismatch.yaml +136 -0
  620. package/rules/topic-predicate-distance.yaml +6 -1
  621. package/rules/total-mismatch.yaml +3 -1
  622. package/rules/translationese-density.yaml +4 -1
  623. package/rules/unbalanced-bracket.yaml +3 -3
  624. package/rules/unclosed-code-fence.yaml +107 -0
  625. package/rules/uncomparable-graded.yaml +65 -0
  626. package/rules/undefined-acronym.yaml +8 -1
  627. package/rules/unfilled-placeholder.yaml +1 -1
  628. package/rules/unit-mismatch.yaml +2 -1
  629. package/rules/unknown-word.yaml +4 -1
  630. package/rules/unqualified-superlative.yaml +6 -1
  631. package/rules/unrendered-emphasis.yaml +73 -0
  632. package/rules/unused-definition.yaml +4 -3
  633. package/rules/url-run-on.yaml +1 -1
  634. package/rules/use-before-definition.yaml +4 -3
  635. package/rules/vague-figure-reference.yaml +3 -1
  636. package/rules/vague-link-text.yaml +2 -1
  637. package/rules/vague-word-density.yaml +2 -1
  638. package/rules/very-adjective.yaml +5 -1
  639. package/rules/weasel-word.yaml +6 -1
  640. package/rules/which-that-consistency.yaml +64 -0
  641. package/rules/wordy-phrase.yaml +6 -1
  642. package/rules/yori-as-from.yaml +61 -0
  643. package/skills/chaff/SKILL.md +7 -7
  644. package/src/api.ts +13 -1
  645. package/src/cli-text.ts +22 -7
  646. package/src/cli.ts +8 -9
  647. package/src/command-help.ts +26 -0
  648. package/src/commands/eval.ts +2 -2
  649. package/src/commands/fix-plan.ts +13 -1
  650. package/src/commands/help.ts +8 -0
  651. package/src/commands/init-command.ts +13 -0
  652. package/src/commands/plugin-init.ts +150 -0
  653. package/src/commands/plugin-test.ts +111 -0
  654. package/src/config/load.ts +3 -0
  655. package/src/config/option-problems.ts +2 -2
  656. package/src/config/rule-problems.ts +2 -2
  657. package/src/custom/checked.ts +8 -0
  658. package/src/custom/dsl-fields.ts +102 -0
  659. package/src/custom/load.ts +2 -0
  660. package/src/custom/parse.ts +72 -50
  661. package/src/custom/problems.ts +16 -2
  662. package/src/detectors/amount-for-count.ts +90 -0
  663. package/src/detectors/blank-structure.ts +12 -4
  664. package/src/detectors/clause-shape.ts +199 -0
  665. package/src/detectors/code-fences.ts +113 -0
  666. package/src/detectors/cross-definitions.ts +49 -0
  667. package/src/detectors/cross-facts.ts +60 -0
  668. package/src/detectors/cross-registry/cross-doc-duplicate-definition.ts +4 -0
  669. package/src/detectors/cross-registry/cross-doc-fact-conflict.ts +4 -0
  670. package/src/detectors/currency-notation.ts +90 -0
  671. package/src/detectors/custom.ts +10 -2
  672. package/src/detectors/dangling-opener.ts +74 -0
  673. package/src/detectors/defined-term-form.ts +200 -0
  674. package/src/detectors/email-letter.ts +262 -0
  675. package/src/detectors/footnote-mismatch.ts +72 -0
  676. package/src/detectors/form-minority.ts +21 -0
  677. package/src/detectors/heading-end-mark.ts +82 -0
  678. package/src/detectors/impossible-date.ts +141 -0
  679. package/src/detectors/impossible-time.ts +151 -0
  680. package/src/detectors/link-shape.ts +70 -0
  681. package/src/detectors/list-marker.ts +60 -0
  682. package/src/detectors/mark-shape.ts +202 -0
  683. package/src/detectors/markdown-slip.ts +140 -0
  684. package/src/detectors/numeral-opener.ts +72 -0
  685. package/src/detectors/ordinal-suffix.ts +40 -0
  686. package/src/detectors/range-notation.ts +76 -0
  687. package/src/detectors/registry/adverb-polarity.ts +4 -0
  688. package/src/detectors/registry/amount-for-count.ts +4 -0
  689. package/src/detectors/registry/attachment-missing.ts +4 -0
  690. package/src/detectors/registry/bare-url-mix.ts +4 -0
  691. package/src/detectors/registry/caps-shouting.ts +4 -0
  692. package/src/detectors/registry/code-fence-language.ts +4 -0
  693. package/src/detectors/registry/currency-notation.ts +4 -0
  694. package/src/detectors/registry/dangling-opener.ts +4 -0
  695. package/src/detectors/registry/defined-name-repeated.ts +4 -0
  696. package/src/detectors/registry/defined-term-form.ts +4 -0
  697. package/src/detectors/registry/email-frame.ts +4 -0
  698. package/src/detectors/registry/email-subject.ts +4 -0
  699. package/src/detectors/registry/ending-run.ts +4 -0
  700. package/src/detectors/registry/footnote-mismatch.ts +4 -0
  701. package/src/detectors/registry/heading-command.ts +4 -0
  702. package/src/detectors/registry/heading-end-punctuation.ts +4 -0
  703. package/src/detectors/registry/hyphen-dash.ts +4 -0
  704. package/src/detectors/registry/image-file-name-alt.ts +4 -0
  705. package/src/detectors/registry/impossible-date.ts +4 -0
  706. package/src/detectors/registry/impossible-time.ts +4 -0
  707. package/src/detectors/registry/latin-abbreviation.ts +4 -0
  708. package/src/detectors/registry/link-text-url-mismatch.ts +4 -0
  709. package/src/detectors/registry/list-marker.ts +4 -0
  710. package/src/detectors/registry/mark-consistency.ts +4 -0
  711. package/src/detectors/registry/numeral-opener.ts +4 -0
  712. package/src/detectors/registry/ordinal-suffix.ts +4 -0
  713. package/src/detectors/registry/origin-particle.ts +4 -0
  714. package/src/detectors/registry/range-notation.ts +4 -0
  715. package/src/detectors/registry/relative-pronoun-mix.ts +4 -0
  716. package/src/detectors/registry/request-without-deadline.ts +4 -0
  717. package/src/detectors/registry/sentence-spacing.ts +4 -0
  718. package/src/detectors/registry/share-over-hundred.ts +4 -0
  719. package/src/detectors/registry/shell-prompt.ts +4 -0
  720. package/src/detectors/registry/step-reference.ts +4 -0
  721. package/src/detectors/registry/step-statement.ts +4 -0
  722. package/src/detectors/registry/table-row-overflow.ts +4 -0
  723. package/src/detectors/registry/toc-heading.ts +4 -0
  724. package/src/detectors/registry/unclosed-code-fence.ts +4 -0
  725. package/src/detectors/registry/unpaired-parallel.ts +4 -0
  726. package/src/detectors/registry/unrendered-emphasis.ts +4 -0
  727. package/src/detectors/relative-pronoun-mix.ts +79 -0
  728. package/src/detectors/request-owner.ts +141 -0
  729. package/src/detectors/share-over-hundred.ts +75 -0
  730. package/src/detectors/step-reference.ts +83 -0
  731. package/src/detectors/technical-docs.ts +230 -0
  732. package/src/detectors/toc-heading.ts +125 -0
  733. package/src/extension/pack-read.ts +128 -0
  734. package/src/extension/plugin-load.ts +49 -9
  735. package/src/extension/plugin-parse.ts +10 -3
  736. package/src/facts/address-values.ts +74 -0
  737. package/src/facts/cross-facts.ts +54 -0
  738. package/src/fix-plan/chosen-depth.ts +28 -0
  739. package/src/fix-plan/mode.ts +57 -11
  740. package/src/fix-plan/plan.ts +37 -5
  741. package/src/fix-plan/render.ts +24 -0
  742. package/src/fix-plan/text.ts +47 -10
  743. package/src/genre-load.ts +7 -4
  744. package/src/genre-parse.ts +19 -0
  745. package/src/init.ts +10 -10
  746. package/src/known-genres.ts +19 -0
  747. package/src/link-shape.ts +62 -0
  748. package/src/list-marks.ts +106 -0
  749. package/src/reasons.ts +16 -4
  750. package/src/render/explain.ts +14 -2
  751. package/src/render/friendly.ts +1 -1
  752. package/src/render/rules-json.ts +14 -3
  753. package/src/render/rules-table.ts +6 -6
  754. package/src/render/semantic.ts +2 -2
  755. package/src/render/suppressions.ts +2 -2
  756. package/src/rewrite-depth.ts +60 -0
  757. package/src/rule-fields.ts +123 -0
  758. package/src/rule-guide.ts +9 -0
  759. package/src/rule-load.ts +10 -4
  760. package/src/rule-offs.ts +50 -0
  761. package/src/structure/build.ts +21 -1
  762. package/src/structure/cross-definitions.ts +60 -0
@@ -13,6 +13,7 @@ import { limitsFor, styleLevelSource } from "../config/style.ts";
13
13
  import { loadStyles } from "../style-load.ts";
14
14
  import type { OptionLayer } from "../rule-options.ts";
15
15
  import { CUSTOM_TYPES } from "../custom/parse.ts";
16
+ import { DEFAULT_DEPTH, REWRITE_DEPTHS, depthMeaning } from "../rewrite-depth.ts";
16
17
 
17
18
  const TEXT: Texts<{
18
19
  readonly offBySetting: string;
@@ -39,7 +40,7 @@ const TEXT: Texts<{
39
40
  "決まりごとに、summary と level_meaning が合う rule を選ぶ。数の決まりは levels の数と比べ、合う段階を選ぶか数を直接書く。",
40
41
  "文書の種類が分かれば genre を決める。rules[].genres で、そのジャンルで動くか・止まるかを確かめる。",
41
42
  "表記の決まりは prefer、社内用語は jargon、必須の見出しは required_sections に書く。",
42
- "既定と同じものは書かない。書いたら npx chaff explain <rule-id> と、決まりに沿った短い見本で確かめる。",
43
+ "既定と同じものは書かない。書いたら npx chaffjs explain <rule-id> と、決まりに沿った短い見本で確かめる。",
43
44
  ],
44
45
  },
45
46
  en: {
@@ -56,7 +57,7 @@ const TEXT: Texts<{
56
57
  "For each requirement, pick the rule whose summary and level_meaning match. For a number, compare it with the rule's levels and pick a level, or write the number itself.",
57
58
  "If the kind of document is known, set genre, and check rules[].genres for whether each rule runs or is off in it.",
58
59
  "Put spellings under prefer, in-house words under jargon, and required headings under required_sections.",
59
- "Leave out anything at its default. Then check each rule with npx chaff explain <rule-id> and a short sample that follows the note.",
60
+ "Leave out anything at its default. Then check each rule with npx chaffjs explain <rule-id> and a short sample that follows the note.",
60
61
  ],
61
62
  },
62
63
  };
@@ -146,11 +147,20 @@ const guideOf = (rule: RuleDefinition): Record<string, unknown> => ({
146
147
  example: rule.guide?.examples ?? {},
147
148
  not_flagged: rule.guide?.notFlagged ?? {},
148
149
  level_meaning: rule.guide?.levelMeaning ?? {},
150
+ // The depth chaff fix-plan files the rule's direction under; a rule that does not say is light.
151
+ rewrite_depth: rule.guide?.rewriteDepth ?? DEFAULT_DEPTH,
149
152
  languages: rule.languages ?? READER_LANGUAGES,
150
153
  requires: rule.requires,
151
154
  genres: genresOf(rule),
152
155
  });
153
156
 
157
+ /** Each rewrite depth with what it means, shallowest first: the values of rules[].rewrite_depth and of fix_plan.depth. */
158
+ const depthsOf = (): Record<string, unknown>[] =>
159
+ REWRITE_DEPTHS.map((depth) => ({
160
+ id: depth,
161
+ meaning: Object.fromEntries(READER_LANGUAGES.map((language) => [language, depthMeaning(depth, uiLanguageOf(language))])),
162
+ }));
163
+
154
164
  const groupsOf = (): Record<string, unknown>[] =>
155
165
  RULE_GROUPS.map((group) => ({
156
166
  id: group,
@@ -190,6 +200,7 @@ export const rulesJson = (
190
200
  values_you_can_use: ["strict", "normal", "relaxed", "off"],
191
201
  values_note: text.valuesNote,
192
202
  groups: groupsOf(),
203
+ rewrite_depths: depthsOf(),
193
204
  ...COMING,
194
205
  rules: rules.map((rule) => ({
195
206
  id: rule.id,
@@ -212,7 +223,7 @@ export const rulesJson = (
212
223
  })),
213
224
  how_to_write_settings_from_a_style_note: text.fromStyleNote,
214
225
  how_to_change: {
215
- by_command: ["relax", "strict", "off"].map((command) => `npx chaff ${command} <rule-id> --why "${text.reason}"`),
226
+ by_command: ["relax", "strict", "off"].map((command) => `npx chaffjs ${command} <rule-id> --why "${text.reason}"`),
216
227
  by_file: text.byFile,
217
228
  options_by_file: text.optionsByFile,
218
229
  },
@@ -21,10 +21,10 @@ const TEXT: Texts<{
21
21
  ungrouped: "(グループ未設定)",
22
22
  footer: [
23
23
  "既定: 何も書かなくても動く 試験中: --experimental か chaff.yaml で動く",
24
- "要設定: chaff.yaml に語や見出しを書いたときだけ AI: npx chaff test で動く",
24
+ "要設定: chaff.yaml に語や見出しを書いたときだけ AI: npx chaffjs test で動く",
25
25
  "",
26
- "詳しく: npx chaff explain <rule>",
27
- "AI に渡す: npx chaff rules --json",
26
+ "詳しく: npx chaffjs explain <rule>",
27
+ "AI に渡す: npx chaffjs rules --json",
28
28
  ],
29
29
  },
30
30
  en: {
@@ -33,10 +33,10 @@ const TEXT: Texts<{
33
33
  ungrouped: "(no group yet)",
34
34
  footer: [
35
35
  "default: runs with no settings experimental: runs with --experimental or a level in chaff.yaml",
36
- "needs list: runs only on words or headings listed in chaff.yaml AI: runs with npx chaff test",
36
+ "needs list: runs only on words or headings listed in chaff.yaml AI: runs with npx chaffjs test",
37
37
  "",
38
- "More on one rule: npx chaff explain <rule>",
39
- "For an AI: npx chaff rules --json",
38
+ "More on one rule: npx chaffjs explain <rule>",
39
+ "For an AI: npx chaffjs rules --json",
40
40
  ],
41
41
  },
42
42
  };
@@ -43,7 +43,7 @@ const TEXT: Texts<{
43
43
  confidence: (value) => `確からしさ ${value}`,
44
44
  disagree: [" この指摘が違うと思ったら:"],
45
45
  silence: (rule) => ` この箇所だけ黙らせる <!-- stet: ${rule} — 理由 -->`,
46
- relax: (rule) => ` ルールごとゆるめる npx chaff relax ${rule}`,
46
+ relax: (rule) => ` ルールごとゆるめる npx chaffjs relax ${rule}`,
47
47
  notRunChecks: (count) => ` ${count} 件の検査は、見るところが無いため動いていません。`,
48
48
  byMachine: "機械で絞り込み済み",
49
49
  whole: "絞り込めず全文",
@@ -68,7 +68,7 @@ const TEXT: Texts<{
68
68
  confidence: (value) => `confidence ${value}`,
69
69
  disagree: [" If you think this finding is wrong:"],
70
70
  silence: (rule) => ` Silence this spot only <!-- stet: ${rule} — reason -->`,
71
- relax: (rule) => ` Relax the whole rule npx chaff relax ${rule}`,
71
+ relax: (rule) => ` Relax the whole rule npx chaffjs relax ${rule}`,
72
72
  notRunChecks: (count) => ` ${counted(count, "check")} did not run: there was nothing for ${formFor(count, "it", "them")} to look at.`,
73
73
  byMachine: "narrowed by machine",
74
74
  whole: "not narrowed: the whole text",
@@ -20,7 +20,7 @@ const TEXT: Texts<{
20
20
  more: (n) => ` ほか ${n} ファイル`,
21
21
  count: (n) => `${String(n).padStart(3)} 件`,
22
22
  reasons: (list) => `理由: ${list}`,
23
- relaxAll: (rule) => `ルールごとゆるめる: npx chaff relax ${rule} --why "..."`,
23
+ relaxAll: (rule) => `ルールごとゆるめる: npx chaffjs relax ${rule} --why "..."`,
24
24
  none: "\n 抑制されている指摘はありません。\n",
25
25
  total: (n) => `抑制されている指摘: ${n} 件`,
26
26
  reasonless: (n) => `理由が書かれていない抑制: ${n} 件`,
@@ -32,7 +32,7 @@ const TEXT: Texts<{
32
32
  more: (n) => ` and ${counted(n, "more file")}`,
33
33
  count: (n) => `${String(n).padStart(3)}`,
34
34
  reasons: (list) => `reasons: ${list}`,
35
- relaxAll: (rule) => `relax the whole rule: npx chaff relax ${rule} --why "..."`,
35
+ relaxAll: (rule) => `relax the whole rule: npx chaffjs relax ${rule} --why "..."`,
36
36
  none: "\n No findings are silenced.\n",
37
37
  total: (n) => `Silenced findings: ${n}`,
38
38
  reasonless: (n) => `Silenced without a reason: ${n}`,
@@ -0,0 +1,60 @@
1
+ import type { Texts, UiLanguage } from "./ui.ts";
2
+
3
+ // How deep a rewrite goes, shallowest first. A rule's rewrite block says how deep its direction reaches, and
4
+ // chaff fix-plan --depth (or fix_plan.depth in chaff.yaml) says how deep the rewrite may go. A depth includes the
5
+ // shallower ones: a structure rewrite also fixes words and sentences. Pure.
6
+
7
+ export const REWRITE_DEPTHS = ["light", "structure", "register"] as const;
8
+
9
+ export type RewriteDepth = (typeof REWRITE_DEPTHS)[number];
10
+
11
+ /** A rule without a depth of its own, or without a rewrite block, fixes words and sentences. */
12
+ export const DEFAULT_DEPTH: RewriteDepth = "light";
13
+
14
+ const isRewriteDepth = (value: unknown): value is RewriteDepth => REWRITE_DEPTHS.some((depth) => depth === value);
15
+
16
+ const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
17
+
18
+ const rankOf = (depth: RewriteDepth): number => REWRITE_DEPTHS.indexOf(depth);
19
+
20
+ /** Whether a rewrite that may go as deep as `allowed` covers a rule whose direction reaches `needed`. */
21
+ export const depthIncludes = (allowed: RewriteDepth, needed: RewriteDepth): boolean => rankOf(needed) <= rankOf(allowed);
22
+
23
+ /** A depth as written: none, one chaff knows, or a value to report as it was written. */
24
+ export type DepthRead = { readonly depth: RewriteDepth | undefined } | { readonly unknown: string };
25
+
26
+ /** rewrite.depth, chaff.yaml's fix_plan.depth or --depth as written. Nothing written is no depth; anything else must be a depth. */
27
+ export const readDepth = (written: unknown): DepthRead => {
28
+ if (written === undefined || written === null) return { depth: undefined };
29
+ if (isRewriteDepth(written)) return { depth: written };
30
+ return { unknown: typeof written === "string" ? written : (JSON.stringify(written) ?? typeof written) };
31
+ };
32
+
33
+ /** rewrite.depth of a rule's rewrite block, which is otherwise keyed by language. */
34
+ export const depthOfRewrite = (rewrite: unknown): DepthRead => (isRecord(rewrite) ? readDepth(rewrite["depth"]) : { depth: undefined });
35
+
36
+ const MEANING: Texts<Readonly<Record<RewriteDepth, string>>> = {
37
+ ja: {
38
+ light: "語と文を直す。構成と文体は残す",
39
+ structure: "節・見出し・段落を組み替える",
40
+ register: "文体を変える(です・ます → である、比べる言い方を外す など)",
41
+ },
42
+ en: {
43
+ light: "words and sentences; the structure and the voice stay",
44
+ structure: "sections, headings and paragraphs are reorganised",
45
+ register: "the style is converted: polite to plain endings, comparatives removed and so on",
46
+ },
47
+ };
48
+
49
+ /** What a depth means, in a reader's words. */
50
+ export const depthMeaning = (depth: RewriteDepth, ui: UiLanguage): string => MEANING[ui][depth];
51
+
52
+ /** Every depth with its meaning, shallowest first: "light (…) / structure (…) / register (…)". */
53
+ const depthChoices = (ui: UiLanguage): string =>
54
+ REWRITE_DEPTHS.map((depth) => (ui === "ja" ? `${depth}(${MEANING.ja[depth]})` : `${depth} (${MEANING.en[depth]})`)).join(" / ");
55
+
56
+ /** Why a written depth cannot be read, with every depth chaff knows. where: what was written ("rewrite.depth", "--depth"). */
57
+ export const unknownDepthSentence = (where: string, written: string, ui: UiLanguage): string =>
58
+ ui === "ja"
59
+ ? `${where}: ${written} は書き直しの深さではありません。深さは ${depthChoices("ja")} のどれかで、深いほうは浅いほうを含みます。`
60
+ : `${where}: ${written} is not a rewrite depth. A depth is one of ${depthChoices("en")}; a deeper one includes the shallower.`;
@@ -0,0 +1,123 @@
1
+ import { RULE_GROUPS } from "./rule-guide.ts";
2
+ import { depthOfRewrite, unknownDepthSentence } from "./rewrite-depth.ts";
3
+ import type { Texts, UiLanguage } from "./ui.ts";
4
+
5
+ // The fields a rule has whoever writes it: chaff's own rules/*.yaml, a team's custom_rules and a plugin's rules all
6
+ // read these the same way, and all three refuse the same malformed values with the same sentence. Pure: the genres a
7
+ // use_for entry may name come in.
8
+
9
+ export type FieldProblem =
10
+ | { readonly kind: "bad-depth"; readonly written: string }
11
+ | { readonly kind: "bad-group"; readonly written: string }
12
+ | { readonly kind: "bad-use-for"; readonly written: string }
13
+ | { readonly kind: "bad-summary"; readonly written: string }
14
+ | { readonly kind: "bad-text"; readonly written: string }
15
+ | { readonly kind: "bad-example"; readonly written: string };
16
+
17
+ export type FieldKind = FieldProblem["kind"];
18
+
19
+ /** Every kind, for a caller that reports these among problems of its own. */
20
+ export const FIELD_KINDS: ReadonlySet<string> = new Set<FieldKind>(["bad-depth", "bad-group", "bad-use-for", "bad-summary", "bad-example", "bad-text"]);
21
+
22
+ const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
23
+
24
+ const isText = (value: unknown): value is string => typeof value === "string" && value.trim() !== "";
25
+
26
+ const printed = (value: unknown): string => (typeof value === "string" ? value : (JSON.stringify(value) ?? typeof value));
27
+
28
+ /** A text in every language (one string) or by language ({ ja, en }), with no empty text. */
29
+ const isTextByLanguage = (value: unknown): boolean =>
30
+ isText(value) || (isRecord(value) && Object.values(value).length > 0 && Object.values(value).every(isText));
31
+
32
+ const groupProblems = (group: unknown): FieldProblem[] =>
33
+ group === undefined || RULE_GROUPS.some((known) => known === group) ? [] : [{ kind: "bad-group", written: printed(group) }];
34
+
35
+ /** A use_for entry names a genre or the start of one (business covers business/report). */
36
+ const namesGenre = (entry: unknown, genres: readonly string[]): boolean =>
37
+ isText(entry) && genres.some((genre) => genre === entry || genre.startsWith(`${entry}/`));
38
+
39
+ const useForProblems = (useFor: unknown, genres: readonly string[]): FieldProblem[] => {
40
+ if (useFor === undefined) return [];
41
+ if (!Array.isArray(useFor) || useFor.length === 0) return [{ kind: "bad-use-for", written: printed(useFor) }];
42
+ return useFor.filter((entry: unknown) => !namesGenre(entry, genres)).map((entry: unknown) => ({ kind: "bad-use-for", written: printed(entry) }));
43
+ };
44
+
45
+ const summaryProblems = (summary: unknown): FieldProblem[] =>
46
+ summary === undefined || isTextByLanguage(summary) ? [] : [{ kind: "bad-summary", written: printed(summary) }];
47
+
48
+ /** A language as a key of a text by language: ja, en, pt-br. */
49
+ const LANGUAGE_KEY = /^[a-z]{2,3}(?:-[a-z0-9]+)*$/iu;
50
+
51
+ /** The texts a reader sees. Each may be one string or one per language. */
52
+ const TEXT_FIELDS = ["name", "why", "how_to_fix", "message", "summary"] as const;
53
+
54
+ /**
55
+ * A text by language whose key is not a language, or whose value is not a text. In YAML, { en: Write a date, or a
56
+ * number of days } is two entries, the second keyed " or a number of days": without this, the text is cut silently.
57
+ */
58
+ const textProblems = (raw: Readonly<Record<string, unknown>>): FieldProblem[] =>
59
+ TEXT_FIELDS.flatMap((field) => {
60
+ const value = raw[field];
61
+ if (!isRecord(value)) return [];
62
+ return Object.entries(value)
63
+ .filter(([key, text]) => !LANGUAGE_KEY.test(key) || typeof text !== "string")
64
+ .map(([key]) => ({ kind: "bad-text" as const, written: `${field}: ${JSON.stringify(key)}` }));
65
+ });
66
+
67
+ /** One example: before and after, each a text in every language or by language. */
68
+ const isExamplePair = (value: unknown): boolean => isRecord(value) && isTextByLanguage(value["before"]) && isTextByLanguage(value["after"]);
69
+
70
+ /**
71
+ * example in either form: { before, after } (a team's rule writes it so), or by language, { ja: { before, after }, en: … }
72
+ * (chaff's rules write it so, with config, pad and other beside before and after).
73
+ */
74
+ const exampleProblems = (example: unknown): FieldProblem[] => {
75
+ if (example === undefined) return [];
76
+ if (isRecord(example) && ("before" in example || "after" in example))
77
+ return isExamplePair(example) ? [] : [{ kind: "bad-example", written: printed(example) }];
78
+ if (!isRecord(example) || Object.keys(example).length === 0) return [{ kind: "bad-example", written: printed(example) }];
79
+ return Object.entries(example).flatMap(([language, pair]) => (isExamplePair(pair) ? [] : [{ kind: "bad-example" as const, written: language }]));
80
+ };
81
+
82
+ const depthProblems = (rewrite: unknown): FieldProblem[] => {
83
+ const read = depthOfRewrite(rewrite);
84
+ return "unknown" in read ? [{ kind: "bad-depth", written: read.unknown }] : [];
85
+ };
86
+
87
+ /** What is wrong with the shared fields of one rule as written, in the order the fields are listed here. */
88
+ export const fieldProblems = (raw: Readonly<Record<string, unknown>>, genres: readonly string[]): FieldProblem[] => [
89
+ ...groupProblems(raw["group"]),
90
+ ...summaryProblems(raw["summary"]),
91
+ ...useForProblems(raw["use_for"], genres),
92
+ ...exampleProblems(raw["example"]),
93
+ ...depthProblems(raw["rewrite"]),
94
+ ...textProblems(raw),
95
+ ];
96
+
97
+ const TEXT: Texts<Readonly<Record<FieldKind, (written: string) => string>>> = {
98
+ ja: {
99
+ "bad-depth": (written) => unknownDepthSentence("rewrite.depth", written, "ja"),
100
+ "bad-group": (written) => `group: ${written} は分類の名前ではありません(${RULE_GROUPS.join(" / ")})。`,
101
+ "bad-use-for": (written) =>
102
+ `use_for: ${written} はジャンルではありません。ジャンルかその頭(business、business/report)を並べます。一覧は npx chaffjs genres。`,
103
+ "bad-summary": (written) => `summary: ${written} は読めません。一つの文字列か、言語ごとの文字列({ ja: …, en: … })で書きます。`,
104
+ "bad-text": (written) =>
105
+ `${written} は言語ではありません。{ } の中のカンマは項目の区切りになるので、カンマのある文は引用符で囲みます(en: "Write a date, or a number of days.")。`,
106
+ "bad-example": (written) =>
107
+ `example: ${written} の before と after が揃っていません。{ before, after } か、言語ごとに { ja: { before, after }, en: { before, after } } と書きます。`,
108
+ },
109
+ en: {
110
+ "bad-depth": (written) => unknownDepthSentence("rewrite.depth", written, "en"),
111
+ "bad-group": (written) => `group: ${written} is not a group (${RULE_GROUPS.join(" / ")}).`,
112
+ "bad-use-for": (written) =>
113
+ `use_for: ${written} is not a genre. List genres or their first part (business, business/report); npx chaffjs genres lists them.`,
114
+ "bad-summary": (written) => `summary: cannot read ${written}. Write one string, or one per language ({ ja: …, en: … }).`,
115
+ "bad-text": (written) =>
116
+ `${written} is not a language. Inside { }, a comma separates entries, so quote a text that has one (en: "Write a date, or a number of days.").`,
117
+ "bad-example": (written) =>
118
+ `example: ${written} lacks a before or an after. Write { before, after }, or one per language: { ja: { before, after }, en: { before, after } }.`,
119
+ },
120
+ };
121
+
122
+ /** What is wrong, with the value as written and what would be right. */
123
+ export const fieldProblemSentence = (problem: FieldProblem, ui: UiLanguage): string => TEXT[ui][problem.kind](problem.written);
package/src/rule-guide.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Localized } from "./plugin.ts";
2
+ import { depthOfRewrite, type RewriteDepth } from "./rewrite-depth.ts";
2
3
 
3
4
  /** How the rule reference groups rules for a reader who is not an engineer, in the order it lists them. */
4
5
  export const RULE_GROUPS = ["readability", "wording", "slips", "consistency", "structure", "facts", "ai-tells", "team"] as const;
@@ -111,6 +112,8 @@ export type RuleGuide = {
111
112
  readonly sources: readonly string[];
112
113
  /** By language, optional per rule. */
113
114
  readonly rewrite: Readonly<Record<string, RuleRewrite>>;
115
+ /** rewrite.depth: how deep the block's direction reaches. None when not written or not a depth; the loaders report the latter. */
116
+ readonly rewriteDepth?: RewriteDepth | undefined;
114
117
  };
115
118
 
116
119
  const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -160,6 +163,11 @@ const rewritesOf = (value: unknown): Readonly<Record<string, RuleRewrite>> =>
160
163
  ? Object.fromEntries(Object.entries(value).flatMap(([language, entry]) => (isRecord(entry) ? [[language, rewriteOf(entry)] as const] : [])))
161
164
  : {};
162
165
 
166
+ const rewriteDepthOf = (rewrite: unknown): RewriteDepth | undefined => {
167
+ const read = depthOfRewrite(rewrite);
168
+ return "depth" in read ? read.depth : undefined;
169
+ };
170
+
163
171
  /** A field that is missing or malformed reads as empty; the test on rule files names what a rule lacks. */
164
172
  export const ruleGuideOf = (raw: Readonly<Record<string, unknown>>): RuleGuide => ({
165
173
  group: RULE_GROUPS.find((group) => group === raw["group"]),
@@ -169,6 +177,7 @@ export const ruleGuideOf = (raw: Readonly<Record<string, unknown>>): RuleGuide =
169
177
  levelMeaning: localizedOf(raw["level_meaning"]),
170
178
  sources: textsOf(raw["sources"]),
171
179
  rewrite: rewritesOf(raw["rewrite"]),
180
+ rewriteDepth: rewriteDepthOf(raw["rewrite"]),
172
181
  });
173
182
 
174
183
  /** The rules in each group, in the order the reference lists them. A rule with no group is in none, which the test on rule files reports. */
package/src/rule-load.ts CHANGED
@@ -6,6 +6,8 @@ import type { LanguageLevels, LevelSets, LevelTable, RuleDefinition, Severity }
6
6
  import { rankOfSeverity, severityAt } from "./levels.ts";
7
7
  import { optionsOf } from "./rule-options.ts";
8
8
  import { ruleGuideOf } from "./rule-guide.ts";
9
+ import { fieldProblemSentence, fieldProblems } from "./rule-fields.ts";
10
+ import { genresBeside } from "./known-genres.ts";
9
11
 
10
12
  const RULES_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "rules");
11
13
 
@@ -142,12 +144,14 @@ const checkedSeverity = (rule: RuleDefinition, file: string): RuleDefinition =>
142
144
  throw new Error(`${file}: severity ${rule.severity} が levels の normal(${severityAt(rule, "normal")})と違います`);
143
145
  };
144
146
 
145
- const toRule = (raw: unknown, language: string, file: string): RuleDefinition => {
147
+ const toRule = (raw: unknown, language: string, file: string, genres: readonly string[]): RuleDefinition => {
146
148
  if (!isRecord(raw)) throw new Error(`${file}: rule は object であること`);
147
149
  const levels = flattenLevels(raw["levels"], language);
148
150
  const missing = missingFields(raw, levels);
149
151
  if (missing.length > 0) throw new Error(`${file}: 必須フィールドがありません: ${missing.join(", ")}`);
150
152
  if (levels === undefined) throw new Error(`${file}: levels を解決できません`);
153
+ const [problem] = fieldProblems(raw, genres);
154
+ if (problem !== undefined) throw new Error(`${file}: ${fieldProblemSentence(problem, "ja")}`);
151
155
  return checkedSeverity(ruleOf(raw, levels, levelSetsOf(raw, language, file), language, file), file);
152
156
  };
153
157
 
@@ -193,8 +197,10 @@ const parseRule = (dir: string, file: string): unknown => {
193
197
  }
194
198
  };
195
199
 
196
- export const loadRules = (language: string, dir: string = RULES_DIR): RuleDefinition[] =>
197
- readdirSync(dir)
200
+ export const loadRules = (language: string, dir: string = RULES_DIR): RuleDefinition[] => {
201
+ const genres = genresBeside(dir);
202
+ return readdirSync(dir)
198
203
  .filter((file) => file.endsWith(".yaml"))
199
204
  .toSorted((left, right) => left.localeCompare(right, "en"))
200
- .map((file) => toRule(parseRule(dir, file), language, file));
205
+ .map((file) => toRule(parseRule(dir, file), language, file, genres));
206
+ };
@@ -0,0 +1,50 @@
1
+ import { readFileSync, readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parse } from "yaml";
4
+
5
+ /** One rule a group or genre turns off by default, from the rule file's off_for, with why. */
6
+ export type RuleOff = { readonly rule: string; readonly target: string; readonly reason: string };
7
+
8
+ const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
9
+
10
+ /** A rule file's off_for block: the "off_for:" line and the indented lines under it. */
11
+ const OFF_FOR_BLOCK = /^off_for:\n(?:[ \t]+[^\n]*\n?)*/mu;
12
+ /** Any top-level off_for line, of whatever form. Only the block form is read, the form `yarn rules:measure --apply` edits. */
13
+ const OFF_FOR_LINE = /^off_for:.*$/gmu;
14
+
15
+ /** The off_for map of one rule file (the group or genre, then why), checked; empty when the file has none. */
16
+ export const ruleOffsOf = (rule: string, raw: unknown): RuleOff[] => {
17
+ if (raw === undefined || raw === null) return [];
18
+ if (!isRecord(raw)) throw new Error(`${rule}: off_for must map a group or genre to why it turns the rule off`);
19
+ return Object.entries(raw).map(([target, reason]) => {
20
+ if (typeof reason !== "string" || reason.trim() === "") throw new Error(`${rule}: off_for.${target} needs a reason`);
21
+ return { rule, target, reason };
22
+ });
23
+ };
24
+
25
+ /** The off_for block of one rule file's text, or undefined; a second block or another form stops here. */
26
+ const offForBlock = (rule: string, text: string): string | undefined => {
27
+ const lines = [...text.matchAll(OFF_FOR_LINE)].map((match) => match[0]);
28
+ if (lines.length === 0) return undefined;
29
+ if (lines.length > 1 || lines[0] !== "off_for:")
30
+ throw new Error(`${rule}: write off_for once, as "off_for:" with one indented "<group or genre>: <why>" line under it per off`);
31
+ return OFF_FOR_BLOCK.exec(text)?.[0];
32
+ };
33
+
34
+ /** The offs of one rule file. The rule is named by the file, which is named by the rule's id. */
35
+ const offsInFile = (dir: string, file: string): RuleOff[] => {
36
+ const rule = file.replace(/\.yaml$/u, "");
37
+ const block = offForBlock(rule, readFileSync(join(dir, file), "utf8").replaceAll("\r\n", "\n"));
38
+ const parsed: unknown = block === undefined ? undefined : parse(block);
39
+ return ruleOffsOf(rule, isRecord(parsed) ? parsed["off_for"] : undefined);
40
+ };
41
+
42
+ /**
43
+ * The offs of every rule file in `dir`. Only each file's off_for block is parsed, not the whole rule: genres are read
44
+ * at startup, before any rule is.
45
+ */
46
+ export const loadRuleOffs = (dir: string): RuleOff[] =>
47
+ readdirSync(dir)
48
+ .filter((file) => file.endsWith(".yaml"))
49
+ .toSorted((left, right) => left.localeCompare(right, "en"))
50
+ .flatMap((file) => offsInFile(dir, file));
@@ -286,6 +286,26 @@ const numberedLine = (state: State, patterns: StructurePatterns, text: string, c
286
286
  unnumberedUnit(text, openUnits(state), state.profile?.unnumbered) ??
287
287
  universalNumber(patterns, text, context, state.plainText);
288
288
 
289
+ /** A dotted number alone: what is left of 「### 29.3 `chaff grade`」 once its code is blanked and the line trimmed. */
290
+ const NUMBER_ONLY = /^\d{1,3}(?:\.\d{1,3}){1,5}[..]?$/u;
291
+
292
+ /**
293
+ * A heading whose title is all inline code is numbered as written. Its rest is left empty: the code is not prose to read,
294
+ * and the blanked line has no place for it. A heading that is only a number as written (a changelog's 「## 46.3」) stays unnumbered.
295
+ */
296
+ const codeTitledNumber = (
297
+ state: State,
298
+ patterns: StructurePatterns,
299
+ text: string,
300
+ heading: Heading | undefined,
301
+ context: NumberingContext,
302
+ ): NumberedLine | undefined => {
303
+ const written = heading?.text.trim() ?? "";
304
+ if (!NUMBER_ONLY.test(text) || written === text) return undefined;
305
+ const numbered = numberedLine(state, patterns, written, context);
306
+ return numbered === undefined ? undefined : { ...numbered, rest: "" };
307
+ };
308
+
289
309
  /** 番号の後ろが見出しでなく本文か。前の行から見出しが付く前の、行そのもので決める。 */
290
310
  const carriesBody = (found: NumberedLine | undefined): boolean => found !== undefined && found.heading === "" && found.rest !== "";
291
311
 
@@ -302,7 +322,7 @@ const readLine = (state: State, patterns: StructurePatterns, line: Line, heading
302
322
  const text = heading === undefined ? line.text : headingLineText(line.text);
303
323
  const openNumbers = state.stack.flatMap((frame) => (frame.numbered === undefined ? [] : [frame.numbered]));
304
324
  const context = { open: openNumbers, isHeading: heading !== undefined };
305
- const found = around.inTable ? undefined : numberedLine(state, patterns, text, context);
325
+ const found = around.inTable ? undefined : (numberedLine(state, patterns, text, context) ?? codeTitledNumber(state, patterns, text, heading, context));
306
326
  const numbered = withCaption(state, line, found);
307
327
  const caption = numbered === undefined && heading === undefined ? captionOf(state.profile, text) : undefined;
308
328
  if (caption !== undefined) state.captions.set(line.number, caption);
@@ -0,0 +1,60 @@
1
+ import { tallyVotes, type Vote } from "../cross-votes.ts";
2
+
3
+ // One term defined in two files of one run, in different words. Pure: the definitions come in already read from each file.
4
+
5
+ /** A definition as a file writes it: the term, what follows it up to the end of the sentence, and where it is. */
6
+ export type WrittenDefinition = { readonly term: string; readonly body: string; readonly offset: number };
7
+
8
+ export type FileDefinitions = { readonly path: string; readonly definitions: readonly WrittenDefinition[] };
9
+
10
+ /** A file that defines a term unlike most files that define it, and one file of the usual wording. */
11
+ export type DefinitionOutOfStep = {
12
+ readonly path: string;
13
+ readonly definition: WrittenDefinition;
14
+ readonly usual: Vote<WrittenDefinition>;
15
+ readonly files: number;
16
+ };
17
+
18
+ /** Marks that do not change what a definition says: the punctuation at its two ends. Spaces are evened out apart. */
19
+ const LEADING: ReadonlySet<string> = new Set(["、", ",", ",", ":", ":"]);
20
+ const TRAILING: ReadonlySet<string> = new Set(["。", ".", "."]);
21
+ const SPACE = /\s+/gu;
22
+
23
+ const SPACE_CHAR = /\s/u;
24
+
25
+ /** The text without spaces and the marks of a set at its start, or at its end. */
26
+ const trimStartOf = (text: string, marks: ReadonlySet<string>): string => {
27
+ const first = text.split("").findIndex((char) => !marks.has(char) && !SPACE_CHAR.test(char));
28
+ return first === -1 ? "" : text.slice(first);
29
+ };
30
+
31
+ const trimEndOf = (text: string, marks: ReadonlySet<string>): string =>
32
+ text.slice(0, text.split("").findLastIndex((char) => !marks.has(char) && !SPACE_CHAR.test(char)) + 1);
33
+
34
+ /** The wording compared: width, spaces and the punctuation at the ends evened out. */
35
+ export const definitionKey = (body: string): string =>
36
+ trimEndOf(trimStartOf(body.normalize("NFKC"), LEADING), TRAILING)
37
+ .replace(SPACE, " ")
38
+ .trim();
39
+
40
+ /** A file's vote for a term: its first definition of it (a second one in the same file is duplicate-definition's). */
41
+ const voteOf = (file: FileDefinitions, term: string): Vote<WrittenDefinition>[] => {
42
+ const first = file.definitions.find((definition) => definition.term === term && definitionKey(definition.body) !== "");
43
+ return first === undefined ? [] : [{ path: file.path, value: first }];
44
+ };
45
+
46
+ const sameWording = (left: WrittenDefinition, right: WrittenDefinition): boolean => definitionKey(left.body) === definitionKey(right.body);
47
+
48
+ /** The files that define a term in other words than most files of the run that define it. */
49
+ export const definitionsOutOfStep = (files: readonly FileDefinitions[]): DefinitionOutOfStep[] => {
50
+ const terms = [...new Set(files.flatMap((file) => file.definitions.map((definition) => definition.term)))];
51
+ return terms.flatMap((term) => {
52
+ const tally = tallyVotes(
53
+ files.flatMap((file) => voteOf(file, term)),
54
+ sameWording,
55
+ );
56
+ const [usual] = tally?.usual ?? [];
57
+ if (tally === undefined || usual === undefined) return [];
58
+ return tally.odd.map((vote) => ({ path: vote.path, definition: vote.value, usual, files: tally.usual.length }));
59
+ });
60
+ };