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
@@ -5,6 +5,7 @@ import { uiLanguageOf } from "../ui.ts";
5
5
  import type { FixPlan, PhraseHint, PlanSpot, RulePlan } from "./plan.ts";
6
6
  import { FIX_PLAN_TEXT, type FixPlanText } from "./text.ts";
7
7
  import { STRUCTURE_TARGET_TEXT } from "./structure-target-text.ts";
8
+ import { DEFAULT_DEPTH, depthMeaning } from "../rewrite-depth.ts";
8
9
 
9
10
  /** A phrase quoted the way the document's language quotes: 「…」 in Japanese, "…" otherwise. */
10
11
  const quoted = (text: string, language: string): string => (language === "ja" ? `「${text}」` : `"${text}"`);
@@ -34,6 +35,7 @@ const rulePlanLines = (rule: RulePlan, text: FixPlanText, language: string): str
34
35
  "",
35
36
  `### \`${rule.rule}\` ${rule.name}`,
36
37
  "",
38
+ ...(rule.depth === DEFAULT_DEPTH ? [] : [`**${text.ruleDepth}**: ${rule.depth}`, ""]),
37
39
  `**${text.direction}**: ${rule.direction}`,
38
40
  ...labelled(text.keep, bullets(rule.keep)),
39
41
  ...labelled(text.avoid, bullets(rule.avoid)),
@@ -48,15 +50,36 @@ const rulePlanLines = (rule: RulePlan, text: FixPlanText, language: string): str
48
50
  ),
49
51
  ];
50
52
 
53
+ const depthLines = (plan: FixPlan, text: FixPlanText): string[] => {
54
+ const { depth } = plan.mode;
55
+ if (depth === undefined) return [];
56
+ const setBy = plan.chosenDepth === undefined ? "" : text.depthSetBy[plan.chosenDepth.from];
57
+ return [text.depthLine(depth, depthMeaning(depth, uiLanguageOf(plan.language)), setBy), ""];
58
+ };
59
+
51
60
  const modeLines = (plan: FixPlan, text: FixPlanText): string[] => [
52
61
  "",
53
62
  `## ${text.modeHeading}: ${text.modeName[plan.mode.mode]}`,
54
63
  "",
55
64
  text.modeReason[plan.mode.reason],
56
65
  "",
66
+ ...depthLines(plan, text),
57
67
  ...bullets(text.modeWays),
58
68
  ];
59
69
 
70
+ /** The rules a chosen depth leaves out, named with their depth, so their findings are not taken for fixed. */
71
+ const deeperLines = (plan: FixPlan, text: FixPlanText): string[] => {
72
+ if (plan.deeper.length === 0 || plan.chosenDepth === undefined) return [];
73
+ return [
74
+ "",
75
+ `## ${text.deeperHeading}`,
76
+ "",
77
+ text.deeperNote(plan.chosenDepth.depth),
78
+ "",
79
+ ...bullets(plan.deeper.map((rule) => `\`${rule.rule}\` ${rule.name}: ${text.deeperLine(rule.depth, rule.spots)}`)),
80
+ ];
81
+ };
82
+
60
83
  const signalLines = (plan: FixPlan, text: FixPlanText): string[] => {
61
84
  const outline = text.outlineLine(shapeMeasures(plan.outline.shape, plan.outline.unit, OUTLINE_TEXT[uiLanguageOf(plan.language)]));
62
85
  const said = plan.signals.length === 0 ? [text.noSignals, ""] : [];
@@ -126,6 +149,7 @@ export const renderFixPlanMarkdown = (plan: FixPlan): string => {
126
149
  ...structureLines(plan),
127
150
  ...(plan.rules.length === 0 ? [] : ["", `## ${text.rulesHeading}`]),
128
151
  ...plan.rules.flatMap((rule) => rulePlanLines(rule, text, plan.language)),
152
+ ...deeperLines(plan, text),
129
153
  ...notRunLines(plan, text),
130
154
  ...checkLines(plan, text),
131
155
  ].join("\n");
@@ -13,6 +13,14 @@ export type FixPlanText = {
13
13
  readonly modeName: Readonly<Record<FixMode, string>>;
14
14
  readonly modeReason: Readonly<Record<ModeReason, string>>;
15
15
  readonly modeWays: readonly string[];
16
+ /** The depth the plan goes to, with what it means, and where it was chosen when it was. */
17
+ readonly depthLine: (depth: string, meaning: string, setBy: string) => string;
18
+ readonly depthSetBy: Readonly<Record<"flag" | "config", string>>;
19
+ /** A rule's own depth, shown when it reaches past light. */
20
+ readonly ruleDepth: string;
21
+ readonly deeperHeading: string;
22
+ readonly deeperNote: (chosen: string) => string;
23
+ readonly deeperLine: (depth: string, spots: number) => string;
16
24
  readonly signalsHeading: string;
17
25
  readonly noSignals: string;
18
26
  readonly outlineLine: (measures: string) => string;
@@ -35,7 +43,7 @@ export type FixPlanText = {
35
43
 
36
44
  export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
37
45
  ja: {
38
- usage: "使い方: chaff fix-plan <file> [--experimental] [--genre <ジャンル>] [--json]",
46
+ usage: "使い方: chaff fix-plan <file> [--depth light|structure|register] [--experimental] [--genre <ジャンル>] [--json]",
39
47
  notFound: (path) => `${path} がありません。`,
40
48
  title: (path) => `直す計画: ${path}`,
41
49
  about: (language, genre) => `言語 ${language}、ジャンル ${genre}`,
@@ -49,9 +57,18 @@ export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
49
57
  "書き直しは 2 回まで。指摘を消すためだけに書き直しを繰り返さない。",
50
58
  ],
51
59
  modeHeading: "勧める直し方",
52
- modeName: { none: "直すところなし", light: "軽く直す(Light)", bold: "大胆に直す(Bold)", full: "全面書き直し(Full)" },
60
+ modeName: {
61
+ none: "直すところなし",
62
+ light: "軽く直す(Light)",
63
+ bold: "大胆に直す(Bold)",
64
+ full: "全面書き直し(Full)",
65
+ register: "文体を変える(Register)",
66
+ },
53
67
  modeReason: {
68
+ chosen: "書き直しの深さが決めてあるので、その深さで直します。",
69
+ "depth-limit": "chaff だけなら構成から書き直すことを勧めますが、決めてある深さが light なので、構成は残します。",
54
70
  "nothing-found": "chaff は何も見つけませんでした。",
71
+ "all-deeper": "指摘はどれも、決めた深さより深く直すルールのものです。この深さで直すところはありません(下の「決めた深さより深いルール」)。",
55
72
  composite: "ai-generated-composite が出ています。文の言い回しを直しても、生成文の骨組みが残ります。",
56
73
  structure: "構成の項目のいくつもが、人の記事の 9 割を超えています(下の「構成の目標」)。文を直しても、見出しの立て方と節の形が残ります。",
57
74
  genre: "ブログやエッセイは、構成から書き直すほうが書き手の望みに合います。",
@@ -59,10 +76,18 @@ export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
59
76
  spots: "指摘は箇所ごとです。指摘された所だけを直します。",
60
77
  },
61
78
  modeWays: [
62
- "軽く直す: 指摘された箇所だけ。",
63
- "大胆に直す: 見出しの構成は残し、節ごとに文を書き直す。",
64
- "全面書き直し: 事実と主張を控えてから、構成から書き直す。頼まれた内容が「全面的に」「一から」なら、これを選ぶ。",
79
+ "軽く直す(深さ light): 指摘された箇所だけ。",
80
+ "大胆に直す(深さ light): 見出しの構成は残し、節ごとに文を書き直す。",
81
+ "全面書き直し(深さ structure): 事実と主張を控えてから、構成から書き直す。頼まれた内容が「全面的に」「一から」なら、これを選ぶ。",
82
+ "文体を変える(深さ register): 全面書き直しに加えて、文体も変える(です・ます → である など)。chaff からは勧めません。--depth register で選びます。",
65
83
  ],
84
+ depthLine: (depth, meaning, setBy) => `書き直しの深さ: ${depth}(${meaning})${setBy}。`,
85
+ depthSetBy: { flag: "。--depth で決めました", config: "。chaff.yaml の fix_plan.depth で決めました" },
86
+ ruleDepth: "深さ",
87
+ deeperHeading: "決めた深さより深いルール",
88
+ deeperNote: (chosen) =>
89
+ `次のルールも指摘を出しましたが、直す方向が深さ ${chosen} より深いので、この計画では直しません。直すときは、そのルールの深さを --depth に渡して計画を出し直してください。`,
90
+ deeperLine: (depth, spots) => `深さ ${depth}、${String(spots)} 箇所`,
66
91
  signalsHeading: "文書全体の目印",
67
92
  noSignals: "文書全体を測るルールは、何も言っていません。",
68
93
  outlineLine: (measures) => `構成: ${measures}`,
@@ -84,7 +109,7 @@ export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
84
109
  "1 つめは書き直した文書の指摘、2 つめは事実が落ちていないか・足されていないか、3 つめは構成の変化です。数は chaff の出力から取り、形容詞で言わないでください。",
85
110
  },
86
111
  en: {
87
- usage: "usage: chaff fix-plan <file> [--experimental] [--genre <genre>] [--json]",
112
+ usage: "usage: chaff fix-plan <file> [--depth light|structure|register] [--experimental] [--genre <genre>] [--json]",
88
113
  notFound: (path) => `${path} does not exist.`,
89
114
  title: (path) => `Fix plan: ${path}`,
90
115
  about: (language, genre) => `language ${language}, genre ${genre}`,
@@ -98,9 +123,13 @@ export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
98
123
  "At most two passes. Do not rewrite again just to silence a finding.",
99
124
  ],
100
125
  modeHeading: "Recommended way",
101
- modeName: { none: "Nothing to fix", light: "Light", bold: "Bold", full: "Full rewrite" },
126
+ modeName: { none: "Nothing to fix", light: "Light", bold: "Bold", full: "Full rewrite", register: "Register change" },
102
127
  modeReason: {
128
+ chosen: "A rewrite depth is set, so the plan goes to that depth.",
129
+ "depth-limit": "On its findings alone chaff would rewrite from the structure up, but the depth set is light, so the structure stays.",
103
130
  "nothing-found": "chaff found nothing.",
131
+ "all-deeper":
132
+ 'Every finding comes from a rule that rewrites deeper than the depth set. There is nothing to fix at this depth (see "Rules deeper than the depth set" below).',
104
133
  composite: "ai-generated-composite fires. Fixing the wording would leave the skeleton of generated text.",
105
134
  structure:
106
135
  'Several structure measures lie past 90% of human articles (see "Structure targets" below). Fixing the sentences would leave the headings and the shape of the sections.',
@@ -109,10 +138,18 @@ export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
109
138
  spots: "The findings are single spots. Rewrite only those.",
110
139
  },
111
140
  modeWays: [
112
- "Light: only the flagged spots.",
113
- "Bold: keep the outline, rewrite the prose of each section.",
114
- 'Full: take an inventory of the facts and claims, then rewrite from the structure up. If the request says "from scratch", choose this.',
141
+ "Light (depth light): only the flagged spots.",
142
+ "Bold (depth light): keep the outline, rewrite the prose of each section.",
143
+ 'Full (depth structure): take an inventory of the facts and claims, then rewrite from the structure up. If the request says "from scratch", choose this.',
144
+ "Register (depth register): a full rewrite that also converts the style (polite to plain endings, and so on). chaff never recommends it; choose it with --depth register.",
115
145
  ],
146
+ depthLine: (depth, meaning, setBy) => `Rewrite depth: ${depth} (${meaning})${setBy}.`,
147
+ depthSetBy: { flag: ", set by --depth", config: ", set by fix_plan.depth in chaff.yaml" },
148
+ ruleDepth: "Depth",
149
+ deeperHeading: "Rules deeper than the depth set",
150
+ deeperNote: (chosen) =>
151
+ `These rules fired too, but their direction goes deeper than ${chosen}, so this plan does not fix them. To fix them, give the rule's depth to --depth and print the plan again.`,
152
+ deeperLine: (depth, spots) => `depth ${depth}, ${String(spots)} ${spots === 1 ? "spot" : "spots"}`,
116
153
  signalsHeading: "Document-level signals",
117
154
  noSignals: "None of the rules that measure the whole document said anything.",
118
155
  outlineLine: (measures) => `Outline: ${measures}`,
package/src/genre-load.ts CHANGED
@@ -2,17 +2,20 @@ import { readFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { parse } from "yaml";
5
- import { parseGenres, presetLevelsOf, presetProfileOf, type GenreData, type PresetLevels } from "./genre-parse.ts";
5
+ import { parseGenres, presetLevelsOf, presetProfileOf, withRuleOffs, type GenreData, type PresetLevels } from "./genre-parse.ts";
6
+ import { loadRuleOffs } from "./rule-offs.ts";
6
7
 
7
- const GENRES_FILE = join(dirname(fileURLToPath(import.meta.url)), "..", "genres.yaml");
8
+ const PACKAGE = join(dirname(fileURLToPath(import.meta.url)), "..");
9
+ const GENRES_FILE = join(PACKAGE, "genres.yaml");
10
+ const RULES_DIR = join(PACKAGE, "rules");
8
11
 
9
12
  const loaded: { value: GenreData | undefined } = { value: undefined };
10
13
 
11
- /** The bundled genres.yaml. Read once. */
14
+ /** The bundled genres.yaml, with the offs the rule files set (off_for). Read once. */
12
15
  export const loadGenres = (): GenreData => {
13
16
  if (loaded.value !== undefined) return loaded.value;
14
17
  try {
15
- loaded.value = parseGenres(parse(readFileSync(GENRES_FILE, "utf8")));
18
+ loaded.value = withRuleOffs(parseGenres(parse(readFileSync(GENRES_FILE, "utf8"))), loadRuleOffs(RULES_DIR));
16
19
  } catch (error) {
17
20
  throw new Error(`cannot read ${GENRES_FILE}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
18
21
  }
@@ -1,5 +1,6 @@
1
1
  import { isLevel } from "./levels.ts";
2
2
  import type { Level, Localized } from "./plugin.ts";
3
+ import type { RuleOff } from "./rule-offs.ts";
3
4
 
4
5
  /** A preset's rules: the level each named rule runs at, under whatever chaff.yaml's rules say. */
5
6
  export type PresetLevels = Readonly<Record<string, Level>>;
@@ -139,6 +140,24 @@ export const parseGenres = (raw: unknown): GenreData => {
139
140
  return { groups, genres };
140
141
  };
141
142
 
143
+ const withOffsFor = <T extends { readonly id: string; readonly rules: PresetLevels }>(entry: T, offs: readonly RuleOff[]): T => {
144
+ const mine = offs.filter((off) => off.target === entry.id);
145
+ const both = mine.find((off) => entry.rules[off.rule] !== undefined);
146
+ if (both !== undefined) throw new Error(`${both.rule}: its off_for and genres.yaml both set its level for ${entry.id}`);
147
+ return mine.length === 0 ? entry : { ...entry, rules: { ...entry.rules, ...Object.fromEntries(mine.map((off) => [off.rule, "off" as const])) } };
148
+ };
149
+
150
+ /**
151
+ * genres.yaml's data with each rule file's off_for merged in. An off for a group joins the group's rules and an off for
152
+ * a genre the genre's own, so a genre's own level still wins over its group's. An off naming no group or genre stops here.
153
+ */
154
+ export const withRuleOffs = (data: GenreData, offs: readonly RuleOff[]): GenreData => {
155
+ const known = new Set([...data.groups, ...data.genres].map((entry) => entry.id));
156
+ const unknown = offs.find((off) => !known.has(off.target));
157
+ if (unknown !== undefined) throw new Error(`${unknown.rule}: off_for names ${unknown.target}, which is no group or genre`);
158
+ return { groups: data.groups.map((group) => withOffsFor(group, offs)), genres: data.genres.map((genre) => withOffsFor(genre, offs)) };
159
+ };
160
+
142
161
  /** The levels a genre's preset sets: its group's, then its own on top. Empty for a genre chaff does not know. */
143
162
  export const presetLevelsOf = (data: GenreData, genre: string): PresetLevels => {
144
163
  const own = data.genres.find((entry) => entry.id === genre);
package/src/init.ts CHANGED
@@ -30,9 +30,9 @@ const TEXT: Texts<{
30
30
  #
31
31
  # コマンドでも変更できます。理由がコメントとして自動で残ります。
32
32
  #
33
- # npx chaff relax bold-density --why "図の説明で太字を多用するため"
34
- # npx chaff explain bold-density そのルールの意図を読む
35
- # npx chaff rules --json AI に設定を書かせるときに渡す
33
+ # npx chaffjs relax bold-density --why "図の説明で太字を多用するため"
34
+ # npx chaffjs explain bold-density そのルールの意図を読む
35
+ # npx chaffjs rules --json AI に設定を書かせるときに渡す
36
36
 
37
37
  # この場所に置く文書の種類(${summary})。ほかの種類: npx chaffjs genres
38
38
  genre: ${genre}
@@ -50,9 +50,9 @@ rules:
50
50
  exists: "chaff.yaml は既にあります。変更していません。",
51
51
  createdHeading: "作成しました:",
52
52
  genreChosen: (genre) => `ジャンルは ${genre} にしました。違う場合は chaff.yaml の genre を直してください。`,
53
- genreList: " 一覧: npx chaff genres",
53
+ genreList: " 一覧: npx chaffjs genres",
54
54
  next: "次:",
55
- nextCheck: " npx chaff . この場所の Markdown を全部見る",
55
+ nextCheck: " npx chaffjs . この場所の Markdown を全部見る",
56
56
  },
57
57
  en: {
58
58
  config: (genre, summary) => `# chaff.yaml — this team's writing rules
@@ -69,9 +69,9 @@ rules:
69
69
  #
70
70
  # Commands change it too, and leave the reason as a comment.
71
71
  #
72
- # npx chaff relax bold-density --why "figure captions use a lot of bold"
73
- # npx chaff explain bold-density read what the rule is for
74
- # npx chaff rules --json give this to an AI that writes the settings
72
+ # npx chaffjs relax bold-density --why "figure captions use a lot of bold"
73
+ # npx chaffjs explain bold-density read what the rule is for
74
+ # npx chaffjs rules --json give this to an AI that writes the settings
75
75
 
76
76
  # The kind of document kept here (${summary}). The others: npx chaffjs genres
77
77
  genre: ${genre}
@@ -89,9 +89,9 @@ rules:
89
89
  exists: "chaff.yaml already exists. Nothing was changed.",
90
90
  createdHeading: "Created:",
91
91
  genreChosen: (genre) => `The genre is ${genre}. If that is wrong, change genre in chaff.yaml.`,
92
- genreList: " List: npx chaff genres",
92
+ genreList: " List: npx chaffjs genres",
93
93
  next: "Next:",
94
- nextCheck: " npx chaff . check every Markdown file here",
94
+ nextCheck: " npx chaffjs . check every Markdown file here",
95
95
  },
96
96
  };
97
97
 
@@ -0,0 +1,19 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parse } from "yaml";
4
+ import { loadGenres } from "./genre-load.ts";
5
+ import { parseGenres, type GenreData } from "./genre-parse.ts";
6
+
7
+ const idsOf = (data: GenreData): string[] => [...data.groups.map((group) => group.id), ...data.genres.map((genre) => genre.id)];
8
+
9
+ /** Every genre and genre group genres.yaml names: what a rule's use_for may list. */
10
+ export const knownGenres = (): string[] => idsOf(loadGenres());
11
+
12
+ /**
13
+ * The genres of the genres.yaml beside a rules folder (packages/chaff/rules → packages/chaff/genres.yaml), else chaff's
14
+ * own. The site reads the rules from the source tree after bundling, where chaff's own file is not where the module is.
15
+ */
16
+ export const genresBeside = (rulesDir: string): string[] => {
17
+ const file = join(rulesDir, "..", "genres.yaml");
18
+ return existsSync(file) ? idsOf(parseGenres(parse(readFileSync(file, "utf8")))) : knownGenres();
19
+ };
@@ -0,0 +1,62 @@
1
+ // What a link's text and an image's alt text look like: a URL, a host, a file name. Pure functions only.
2
+
3
+ /** Link text that reads as an address: it starts with a scheme or with `www.`. A bare `README.md` is a file, not a host. */
4
+ const URL_TEXT = /^(?:https?:\/\/|www\.)[^\s]+$/iu;
5
+
6
+ /** Marks around a link's text that are not part of the address it shows (`**https://…**`, `` `https://…` ``, `<…>`). */
7
+ const LEADING = new Set(" \t\n*_`<「『\"“'");
8
+ const TRAILING = new Set(" \t\n*_`>」』\"”'.。,,、");
9
+
10
+ /** The text as the reader sees the address, without emphasis, code marks, quotes or closing punctuation. */
11
+ export const shownAddress = (text: string): string => {
12
+ const chars = [...text];
13
+ const start = chars.findIndex((char) => !LEADING.has(char));
14
+ return start === -1 ? "" : chars.slice(start, chars.findLastIndex((char) => !TRAILING.has(char)) + 1).join("");
15
+ };
16
+
17
+ /** Whether a link's text is itself an address. */
18
+ export const isUrlText = (text: string): boolean => URL_TEXT.test(shownAddress(text));
19
+
20
+ const WWW = /^www\./iu;
21
+ const WEB_SCHEME = /^https?:\/\//iu;
22
+
23
+ /** The host an address names, lower case and without `www.`; undefined for a relative path, a fragment or a mail address. */
24
+ export const hostOf = (address: string): string | undefined => {
25
+ const written = shownAddress(address);
26
+ const absolute = WWW.test(written) ? `https://${written}` : written;
27
+ if (!WEB_SCHEME.test(absolute)) return undefined;
28
+ try {
29
+ return new URL(absolute).hostname.toLowerCase().replace(WWW, "");
30
+ } catch {
31
+ return undefined;
32
+ }
33
+ };
34
+
35
+ /**
36
+ * The host a link's text shows, when it differs from the host the link goes to. Both must be absolute web addresses;
37
+ * a shortened display of the same host (`github.com/a` for `https://github.com/a/b/tree/main`) is the same host.
38
+ */
39
+ export const mismatchedHost = (text: string, destination: string): { readonly shown: string; readonly target: string } | undefined => {
40
+ if (!isUrlText(text)) return undefined;
41
+ const shown = hostOf(text);
42
+ const target = hostOf(destination);
43
+ return shown === undefined || target === undefined || shown === target ? undefined : { shown, target };
44
+ };
45
+
46
+ /** The extensions of image files. An alt text that ends in one is the file's name. */
47
+ const IMAGE_FILE = /\.(?:png|jpe?g|gif|svg|webp|bmp|tiff?|heic|heif|avif|ico)$/iu;
48
+
49
+ /** After a camera's or a screenshot tool's name: separators, then the number it counts with (`IMG_1234`, `Screenshot 2026-…`). */
50
+ const COUNTER = /^[\s_-]*\d/u;
51
+
52
+ /**
53
+ * Whether an alt text is a file's name rather than a description: it ends in an image extension (`IMG_1234.png`), or it
54
+ * starts with a name a camera or a screenshot tool gives (`prefixes`, from the language's lexicon) followed by its number.
55
+ */
56
+ export const isFileNameAlt = (alt: string, prefixes: readonly string[]): boolean => {
57
+ const written = alt.trim();
58
+ if (written === "") return false;
59
+ if (IMAGE_FILE.test(written)) return true;
60
+ const lowered = written.toLowerCase();
61
+ return prefixes.some((prefix) => lowered.startsWith(prefix.toLowerCase()) && COUNTER.test(written.slice(prefix.length)));
62
+ };
@@ -0,0 +1,106 @@
1
+ // The bullets a document writes its lists with (`-`, `*`, `+`, and `・` typed at a line's start), where each list sits, and
2
+ // the `・` lines Markdown folds into the item above. Pure; reads the source's Markdown tree.
3
+ import { spanOf, type MarkdownNode } from "./markdown-node.ts";
4
+ import type { Span } from "./plugin.ts";
5
+
6
+ /** One bulleted list as the reader meets it: where its first item starts, how deep it sits among lists, and its bullet. */
7
+ export type ListMark = {
8
+ readonly start: number;
9
+ readonly depth: number;
10
+ readonly mark: string;
11
+ /** The list written right before it in the same parent, when there is one: Markdown splits a list where the bullet changes. */
12
+ readonly previous: string | undefined;
13
+ };
14
+
15
+ /** Bullets Markdown reads as a list. */
16
+ const MARKDOWN_BULLETS = new Set(["-", "*", "+"]);
17
+
18
+ /** A bullet a Japanese writer types at a line's start. Markdown does not read it as a list, so the lines run together. */
19
+ const TYPED_BULLET = "・";
20
+
21
+ /** Blocks whose lists are someone else's or are not prose: quotations, code and HTML. */
22
+ const SKIPPED = new Set(["blockquote", "code", "html"]);
23
+
24
+ const bulletOf = (source: string, list: MarkdownNode): { readonly start: number; readonly mark: string } | undefined => {
25
+ const first = list.children?.[0];
26
+ const span = first === undefined ? undefined : spanOf(first);
27
+ const mark = span === undefined ? undefined : source.charAt(span.start);
28
+ return span === undefined || mark === undefined || !MARKDOWN_BULLETS.has(mark) ? undefined : { start: span.start, mark };
29
+ };
30
+
31
+ /** Where each line of a span starts, with the line's text. */
32
+ const linesIn = (source: string, span: Span): { readonly start: number; readonly text: string }[] => {
33
+ const lines = source.slice(span.start, span.end).split("\n");
34
+ const read: { start: number; text: string }[] = [];
35
+ lines.forEach((text) => {
36
+ const previous = read.at(-1);
37
+ read.push({ start: previous === undefined ? span.start : previous.start + previous.text.length + 1, text });
38
+ });
39
+ return read;
40
+ };
41
+
42
+ /** The start of each line after the first that begins with a typed bullet. */
43
+ const typedLineStarts = (source: string, paragraph: Span): number[] =>
44
+ linesIn(source, paragraph).flatMap((line, at) => {
45
+ const indent = line.text.length - line.text.trimStart().length;
46
+ return at > 0 && line.text.trimStart().startsWith(TYPED_BULLET) ? [line.start + indent] : [];
47
+ });
48
+
49
+ /** Lines of a paragraph that start with a typed bullet; two or more in a row are a list the writer typed. */
50
+ const typedListStart = (source: string, paragraph: Span): number | undefined => {
51
+ const lines = linesIn(source, paragraph).filter((line) => line.text.trim() !== "");
52
+ const typed = lines.filter((line) => line.text.trimStart().startsWith(TYPED_BULLET));
53
+ const first = typed[0];
54
+ return typed.length >= 2 && first !== undefined ? first.start + first.text.length - first.text.trimStart().length : undefined;
55
+ };
56
+
57
+ type Frame = { readonly node: MarkdownNode; readonly depth: number; readonly inItem: boolean };
58
+
59
+ export type ListReading = {
60
+ readonly lists: readonly ListMark[];
61
+ /** `・` lines inside a Markdown list item's paragraph: Markdown joins them to the item above. */
62
+ readonly foldedTyped: readonly number[];
63
+ };
64
+
65
+ const listsOf = (source: string, node: MarkdownNode, depth: number): ListMark[] => {
66
+ const children = node.children ?? [];
67
+ return children.flatMap((child, at) => {
68
+ if (child.type !== "list") return [];
69
+ const bullet = bulletOf(source, child);
70
+ const before = children[at - 1];
71
+ const previous = before?.type === "list" ? bulletOf(source, before)?.mark : undefined;
72
+ return bullet === undefined ? [] : [{ ...bullet, depth, previous }];
73
+ });
74
+ };
75
+
76
+ const typedOf = (source: string, node: MarkdownNode, depth: number, inItem: boolean): { lists: ListMark[]; folded: number[] } => {
77
+ const span = spanOf(node);
78
+ if (node.type !== "paragraph" || span === undefined) return { lists: [], folded: [] };
79
+ if (inItem) return { lists: [], folded: typedLineStarts(source, span) };
80
+ const start = typedListStart(source, span);
81
+ return { lists: start === undefined ? [] : [{ start, depth, mark: TYPED_BULLET, previous: undefined }], folded: [] };
82
+ };
83
+
84
+ /**
85
+ * Every bulleted list outside quotations and code, with its depth among lists (a list in a list item is one deeper), in source
86
+ * order. A paragraph with two or more lines that start with `・` counts as a list at the paragraph's depth; the same lines in a
87
+ * list item's paragraph are folded into that item.
88
+ */
89
+ export const readLists = (source: string, root: MarkdownNode): ListReading => {
90
+ const lists: ListMark[] = [];
91
+ const folded: number[] = [];
92
+ const pending: Frame[] = [{ node: root, depth: 0, inItem: false }];
93
+ for (let frame = pending.pop(); frame !== undefined; frame = pending.pop()) {
94
+ const { node, depth, inItem } = frame;
95
+ if (SKIPPED.has(node.type)) continue;
96
+ lists.push(...listsOf(source, node, depth));
97
+ const typed = typedOf(source, node, depth, inItem);
98
+ lists.push(...typed.lists);
99
+ folded.push(...typed.folded);
100
+ const childDepth = node.type === "list" ? depth + 1 : depth;
101
+ const childInItem = node.type === "listItem" || (inItem && node.type !== "list");
102
+ (node.children ?? []).forEach((child) => pending.push({ node: child, depth: childDepth, inItem: childInItem }));
103
+ }
104
+ const byStart = (left: number, right: number): number => left - right;
105
+ return { lists: lists.toSorted((left, right) => byStart(left.start, right.start)), foldedTyped: folded.toSorted(byStart) };
106
+ };
package/src/reasons.ts CHANGED
@@ -22,6 +22,12 @@ export type Reasons = {
22
22
  readonly oneDocument: string;
23
23
  };
24
24
 
25
+ /** A plugin's word list is named <plugin>/<list> (@scope/foo/list too); a language package's has no slash. */
26
+ const pluginListOf = (list: string): { readonly plugin: string; readonly name: string } | undefined => {
27
+ const slash = list.lastIndexOf("/");
28
+ return slash === -1 ? undefined : { plugin: list.slice(0, slash), name: list.slice(slash + 1) };
29
+ };
30
+
25
31
  const CAPABILITY_NAME: Texts<Readonly<Record<string, string>>> = {
26
32
  ja: { pos: "品詞解析", lemma: "原形" },
27
33
  en: { pos: "part-of-speech tagging", lemma: "lemmas" },
@@ -33,7 +39,7 @@ export const REASONS: Texts<Reasons> = {
33
39
  noCapability: (capability) => `この言語では${CAPABILITY_NAME.ja[capability] ?? capability}が使えないため`,
34
40
  noTags: "アダプタが品詞を返さなかったため",
35
41
  unreadTags: "言語のパッケージがこの文書を読めなかったため(品詞の取れない段落があります)",
36
- semantic: "意味を読む検査のため(npx chaff test で動きます)",
42
+ semantic: "意味を読む検査のため(npx chaffjs test で動きます)",
37
43
  experimental: "まだ試験中のため",
38
44
  turnedOff: "設定で止めているため",
39
45
  presetOff: (genre) => `ジャンル ${genre} では見ないため`,
@@ -41,7 +47,10 @@ export const REASONS: Texts<Reasons> = {
41
47
  unreadStructure: (clauses, units) =>
42
48
  `条項の番号が本文に ${String(clauses)} 個あるのに、番号として読めたのは ${String(units)} 個のため(深い字下げや、行が本文につながった文書)`,
43
49
  noDetector: (name) => `検出器 ${name} がないため`,
44
- noLexicon: (language, list) => `${language} の語彙表 ${list} が無いため`,
50
+ noLexicon: (language, list) => {
51
+ const owner = pluginListOf(list);
52
+ return owner === undefined ? `${language} の語彙表 ${list} が無いため` : `プラグイン ${owner.plugin} に ${language} の語彙表 ${owner.name} が無いため`;
53
+ },
45
54
  noHeadings: "表題より下の見出しが無いため",
46
55
  patternTimeout: (budgetMs) => `正規表現が ${String(budgetMs)} ms で終わらなかったため(chaff.yaml の pattern を単純にしてください)`,
47
56
  notMarkdown: "Markdown の文書ではないため",
@@ -52,7 +61,7 @@ export const REASONS: Texts<Reasons> = {
52
61
  noCapability: (capability) => `${CAPABILITY_NAME.en[capability] ?? capability} is not available for this language`,
53
62
  noTags: "the language package returned no parts of speech",
54
63
  unreadTags: "the language package could not read this document (some paragraphs have no parts of speech)",
55
- semantic: "it reads meaning; npx chaff test runs it",
64
+ semantic: "it reads meaning; npx chaffjs test runs it",
56
65
  experimental: "still experimental",
57
66
  turnedOff: "turned off in the settings",
58
67
  presetOff: (genre) => `the ${genre} genre does not check it`,
@@ -60,7 +69,10 @@ export const REASONS: Texts<Reasons> = {
60
69
  unreadStructure: (clauses, units) =>
61
70
  `the text has ${String(clauses)} clause numbers but only ${String(units)} ${formFor(units, "was read as a numbered line", "were read as numbered lines")} (deep indents, or lines run into the text)`,
62
71
  noDetector: (name) => `no detector named ${name}`,
63
- noLexicon: (language, list) => `the ${language} package has no word list ${list}`,
72
+ noLexicon: (language, list) => {
73
+ const owner = pluginListOf(list);
74
+ return owner === undefined ? `the ${language} package has no word list ${list}` : `the plugin ${owner.plugin} has no ${language} word list ${owner.name}`;
75
+ },
64
76
  noHeadings: "the document has no headings below its title",
65
77
  patternTimeout: (budgetMs) => `the pattern did not finish within ${String(budgetMs)} ms (simplify the pattern in chaff.yaml)`,
66
78
  notMarkdown: "the document is not Markdown",
@@ -5,6 +5,7 @@ import { uiLanguageOf, type Texts } from "../ui.ts";
5
5
  import type { Level, RuleDefinition } from "../plugin.ts";
6
6
  import { optionLines } from "./options.ts";
7
7
  import type { OptionLayer } from "../rule-options.ts";
8
+ import { depthMeaning } from "../rewrite-depth.ts";
8
9
 
9
10
  const TEXT: Texts<{
10
11
  readonly off: string;
@@ -13,6 +14,7 @@ const TEXT: Texts<{
13
14
  readonly experimental: string;
14
15
  readonly alone: (id: string) => string;
15
16
  readonly howToFix: string;
17
+ readonly depth: (depth: string, meaning: string) => string;
16
18
  readonly example: string;
17
19
  readonly definedIn: (plugin: string | undefined) => string;
18
20
  readonly values: string;
@@ -30,6 +32,8 @@ const TEXT: Texts<{
30
32
  experimental: "このルールはまだ試験中で、既定では動きません(--experimental で動きます)。",
31
33
  alone: (id) => `このルールだけを動かす: npx chaffjs enable ${id}(chaff.yaml の rules に ${id}: normal と書くのと同じです)`,
32
34
  howToFix: "直しかた",
35
+ depth: (depth, meaning) =>
36
+ `書き直しの深さ: ${depth}(${meaning})。chaff fix-plan --depth でこれより浅い深さを選ぶと、計画はこのルールを直さず、名前だけを挙げます。`,
33
37
  example: "例",
34
38
  definedIn: (plugin) =>
35
39
  plugin === undefined ? "このルールはチームが chaff.yaml の custom_rules で決めたものです。" : `このルールはプラグイン ${plugin} のものです。`,
@@ -39,7 +43,7 @@ const TEXT: Texts<{
39
43
  now: (level) => `いまは ${level} です。`,
40
44
  nowNumber: (limit) => `いまは段階ではなく数です: ${limit}。`,
41
45
  from: (source) => `(${source} で決めています)`,
42
- change: (id) => `変える: npx chaff relax ${id} --why "理由"`,
46
+ change: (id) => `変える: npx chaffjs relax ${id} --why "理由"`,
43
47
  },
44
48
  en: {
45
49
  off: "not checked",
@@ -48,6 +52,7 @@ const TEXT: Texts<{
48
52
  experimental: "This rule is still experimental and does not run by default (--experimental runs it).",
49
53
  alone: (id) => `Turn on this rule alone: npx chaffjs enable ${id} (the same as rules: { ${id}: normal } in chaff.yaml)`,
50
54
  howToFix: "How to fix",
55
+ depth: (depth, meaning) => `Rewrite depth: ${depth} (${meaning}). With a shallower chaff fix-plan --depth, the plan names this rule without fixing it.`,
51
56
  example: "Example",
52
57
  definedIn: (plugin) =>
53
58
  plugin === undefined ? "The team defined this rule under custom_rules in chaff.yaml." : `This rule comes from the plugin ${plugin}.`,
@@ -57,7 +62,7 @@ const TEXT: Texts<{
57
62
  now: (level) => `Now: ${level}.`,
58
63
  nowNumber: (limit) => `Now: ${limit}, set as a number rather than a level.`,
59
64
  from: (source) => ` (set by ${source})`,
60
- change: (id) => `Change it: npx chaff relax ${id} --why "reason"`,
65
+ change: (id) => `Change it: npx chaffjs relax ${id} --why "reason"`,
61
66
  },
62
67
  };
63
68
 
@@ -98,6 +103,12 @@ const exampleLines = (rule: RuleDefinition, language: string, text: (typeof TEXT
98
103
  return ["", ` ${text.example}: ${example.before}`, ` → ${example.after}`, "", ` ${text.definedIn(rule.plugin)}`];
99
104
  };
100
105
 
106
+ /** How deep the rule's rewrite direction reaches, for a rule that has one: what chaff fix-plan --depth compares. */
107
+ const depthLines = (rule: RuleDefinition, language: string, text: (typeof TEXT)["ja"]): string[] => {
108
+ const depth = rule.guide?.rewriteDepth;
109
+ return depth === undefined ? [] : ["", ` ${text.depth(depth, depthMeaning(depth, uiLanguageOf(language)))}`];
110
+ };
111
+
101
112
  /** Where the rule's settings come from: the option layers, strongest first, and the source of its level when a style set it. */
102
113
  /** limit: a number chaff.yaml or its style set for the rule (rules: { id: 80 }, a style's limits), which a level does not show. */
103
114
  export type ExplainSettings = {
@@ -124,6 +135,7 @@ export const renderExplain = (rule: RuleDefinition, current: Level, language: st
124
135
  ` ${readableText(rule, rule.why, language)}`,
125
136
  "",
126
137
  ` ${text.howToFix}: ${readableText(rule, rule.how_to_fix, language)}`,
138
+ ...depthLines(rule, language, text),
127
139
  ...exampleLines(rule, language, text),
128
140
  "",
129
141
  ` ${rule.level_sets === "severity" ? text.severities : text.values}`,
@@ -90,7 +90,7 @@ const block = (finding: Finding, rule: RuleDefinition, language: string, quoted:
90
90
  "",
91
91
  ...indent(`→ ${filledText(rule.how_to_fix, finding, language)}`, " "),
92
92
  "",
93
- ` ${TEXT[uiLanguageOf(language)].relax}: npx chaff relax ${finding.rule}`,
93
+ ` ${TEXT[uiLanguageOf(language)].relax}: npx chaffjs relax ${finding.rule}`,
94
94
  "",
95
95
  ];
96
96