chaffjs 0.18.0 → 0.19.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 (682) hide show
  1. package/README.md +52 -56
  2. package/bin/chaff.js +17 -2
  3. package/dist/acronym-expansions.d.ts +26 -0
  4. package/dist/acronym-expansions.d.ts.map +1 -0
  5. package/dist/acronym-expansions.js +88 -0
  6. package/dist/acronym-expansions.js.map +1 -0
  7. package/dist/announced-count.d.ts.map +1 -1
  8. package/dist/announced-count.js +44 -10
  9. package/dist/announced-count.js.map +1 -1
  10. package/dist/announced-list.d.ts +30 -0
  11. package/dist/announced-list.d.ts.map +1 -0
  12. package/dist/announced-list.js +95 -0
  13. package/dist/announced-list.js.map +1 -0
  14. package/dist/api.d.ts +168 -0
  15. package/dist/api.d.ts.map +1 -0
  16. package/dist/api.js +10 -0
  17. package/dist/api.js.map +1 -0
  18. package/dist/cli-text.d.ts +0 -1
  19. package/dist/cli-text.d.ts.map +1 -1
  20. package/dist/cli-text.js +6 -14
  21. package/dist/cli-text.js.map +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +58 -62
  24. package/dist/cli.js.map +1 -1
  25. package/dist/closing-paragraph.d.ts +7 -0
  26. package/dist/closing-paragraph.d.ts.map +1 -0
  27. package/dist/closing-paragraph.js +22 -0
  28. package/dist/closing-paragraph.js.map +1 -0
  29. package/dist/commands/compare.d.ts +8 -1
  30. package/dist/commands/compare.d.ts.map +1 -1
  31. package/dist/commands/compare.js +9 -17
  32. package/dist/commands/compare.js.map +1 -1
  33. package/dist/commands/document-commands.d.ts +9 -0
  34. package/dist/commands/document-commands.d.ts.map +1 -0
  35. package/dist/commands/document-commands.js +17 -0
  36. package/dist/commands/document-commands.js.map +1 -0
  37. package/dist/commands/eval.d.ts.map +1 -1
  38. package/dist/commands/eval.js +3 -2
  39. package/dist/commands/eval.js.map +1 -1
  40. package/dist/commands/facts.d.ts +8 -0
  41. package/dist/commands/facts.d.ts.map +1 -0
  42. package/dist/commands/facts.js +30 -0
  43. package/dist/commands/facts.js.map +1 -0
  44. package/dist/commands/feedback.d.ts +10 -0
  45. package/dist/commands/feedback.d.ts.map +1 -1
  46. package/dist/commands/feedback.js +25 -1
  47. package/dist/commands/feedback.js.map +1 -1
  48. package/dist/commands/fix-plan.d.ts +13 -0
  49. package/dist/commands/fix-plan.d.ts.map +1 -0
  50. package/dist/commands/fix-plan.js +44 -0
  51. package/dist/commands/fix-plan.js.map +1 -0
  52. package/dist/commands/outline.d.ts +8 -0
  53. package/dist/commands/outline.d.ts.map +1 -0
  54. package/dist/commands/outline.js +43 -0
  55. package/dist/commands/outline.js.map +1 -0
  56. package/dist/commands/read-document.d.ts +14 -0
  57. package/dist/commands/read-document.d.ts.map +1 -0
  58. package/dist/commands/read-document.js +21 -0
  59. package/dist/commands/read-document.js.map +1 -0
  60. package/dist/commands/suppressions.d.ts +7 -0
  61. package/dist/commands/suppressions.d.ts.map +1 -0
  62. package/dist/commands/suppressions.js +9 -0
  63. package/dist/commands/suppressions.js.map +1 -0
  64. package/dist/commands/test.js +1 -1
  65. package/dist/commands/test.js.map +1 -1
  66. package/dist/compare/clock-time.d.ts.map +1 -1
  67. package/dist/compare/clock-time.js +5 -2
  68. package/dist/compare/clock-time.js.map +1 -1
  69. package/dist/compare/distinct.d.ts +9 -0
  70. package/dist/compare/distinct.d.ts.map +1 -0
  71. package/dist/compare/distinct.js +12 -0
  72. package/dist/compare/distinct.js.map +1 -0
  73. package/dist/compare/extract.d.ts.map +1 -1
  74. package/dist/compare/extract.js +7 -5
  75. package/dist/compare/extract.js.map +1 -1
  76. package/dist/compare/fact-key.d.ts +17 -0
  77. package/dist/compare/fact-key.d.ts.map +1 -0
  78. package/dist/compare/fact-key.js +25 -0
  79. package/dist/compare/fact-key.js.map +1 -0
  80. package/dist/compare/fact-text.d.ts +5 -0
  81. package/dist/compare/fact-text.d.ts.map +1 -1
  82. package/dist/compare/fact-text.js +16 -2
  83. package/dist/compare/fact-text.js.map +1 -1
  84. package/dist/compare/facts-render.d.ts +17 -0
  85. package/dist/compare/facts-render.d.ts.map +1 -0
  86. package/dist/compare/facts-render.js +43 -0
  87. package/dist/compare/facts-render.js.map +1 -0
  88. package/dist/compare/facts-text.d.ts +15 -0
  89. package/dist/compare/facts-text.d.ts.map +1 -0
  90. package/dist/compare/facts-text.js +27 -0
  91. package/dist/compare/facts-text.js.map +1 -0
  92. package/dist/compare/match.d.ts +1 -0
  93. package/dist/compare/match.d.ts.map +1 -1
  94. package/dist/compare/match.js +1 -1
  95. package/dist/compare/match.js.map +1 -1
  96. package/dist/compare/outcome.d.ts +4 -1
  97. package/dist/compare/outcome.d.ts.map +1 -1
  98. package/dist/compare/outcome.js +10 -4
  99. package/dist/compare/outcome.js.map +1 -1
  100. package/dist/compare/proper-nouns.d.ts +3 -3
  101. package/dist/compare/proper-nouns.d.ts.map +1 -1
  102. package/dist/compare/proper-nouns.js +2 -3
  103. package/dist/compare/proper-nouns.js.map +1 -1
  104. package/dist/compare/render.d.ts +4 -0
  105. package/dist/compare/render.d.ts.map +1 -1
  106. package/dist/compare/render.js +2 -2
  107. package/dist/compare/render.js.map +1 -1
  108. package/dist/compare/text-atoms.d.ts +5 -2
  109. package/dist/compare/text-atoms.d.ts.map +1 -1
  110. package/dist/compare/text-atoms.js +7 -5
  111. package/dist/compare/text-atoms.js.map +1 -1
  112. package/dist/compare/text.d.ts.map +1 -1
  113. package/dist/compare/text.js +2 -2
  114. package/dist/compare/text.js.map +1 -1
  115. package/dist/config/load.d.ts +8 -0
  116. package/dist/config/load.d.ts.map +1 -1
  117. package/dist/config/load.js +1 -0
  118. package/dist/config/load.js.map +1 -1
  119. package/dist/config/option-problems.d.ts +3 -2
  120. package/dist/config/option-problems.d.ts.map +1 -1
  121. package/dist/config/option-problems.js +4 -3
  122. package/dist/config/option-problems.js.map +1 -1
  123. package/dist/config/style.d.ts +5 -0
  124. package/dist/config/style.d.ts.map +1 -1
  125. package/dist/config/style.js +13 -1
  126. package/dist/config/style.js.map +1 -1
  127. package/dist/custom/load.d.ts +6 -3
  128. package/dist/custom/load.d.ts.map +1 -1
  129. package/dist/custom/load.js +10 -2
  130. package/dist/custom/load.js.map +1 -1
  131. package/dist/custom/module-path.d.ts +11 -0
  132. package/dist/custom/module-path.d.ts.map +1 -0
  133. package/dist/custom/module-path.js +15 -0
  134. package/dist/custom/module-path.js.map +1 -0
  135. package/dist/custom/parse.d.ts +17 -3
  136. package/dist/custom/parse.d.ts.map +1 -1
  137. package/dist/custom/parse.js +57 -14
  138. package/dist/custom/parse.js.map +1 -1
  139. package/dist/custom/problems.d.ts +4 -1
  140. package/dist/custom/problems.d.ts.map +1 -1
  141. package/dist/custom/problems.js +56 -39
  142. package/dist/custom/problems.js.map +1 -1
  143. package/dist/detect-language.js +1 -1
  144. package/dist/detect.d.ts.map +1 -1
  145. package/dist/detect.js +9 -3
  146. package/dist/detect.js.map +1 -1
  147. package/dist/detectors/ai-phrasing.d.ts +4 -1
  148. package/dist/detectors/ai-phrasing.d.ts.map +1 -1
  149. package/dist/detectors/ai-phrasing.js +6 -2
  150. package/dist/detectors/ai-phrasing.js.map +1 -1
  151. package/dist/detectors/bold-label.d.ts +10 -0
  152. package/dist/detectors/bold-label.d.ts.map +1 -0
  153. package/dist/detectors/bold-label.js +44 -0
  154. package/dist/detectors/bold-label.js.map +1 -0
  155. package/dist/detectors/dangling-figure.d.ts +5 -2
  156. package/dist/detectors/dangling-figure.d.ts.map +1 -1
  157. package/dist/detectors/dangling-figure.js +5 -3
  158. package/dist/detectors/dangling-figure.js.map +1 -1
  159. package/dist/detectors/definition-use.d.ts +8 -0
  160. package/dist/detectors/definition-use.d.ts.map +1 -0
  161. package/dist/detectors/definition-use.js +32 -0
  162. package/dist/detectors/definition-use.js.map +1 -0
  163. package/dist/detectors/doubled-punctuation.d.ts.map +1 -1
  164. package/dist/detectors/doubled-punctuation.js +4 -2
  165. package/dist/detectors/doubled-punctuation.js.map +1 -1
  166. package/dist/detectors/duplicate-heading.d.ts +14 -0
  167. package/dist/detectors/duplicate-heading.d.ts.map +1 -0
  168. package/dist/detectors/duplicate-heading.js +39 -0
  169. package/dist/detectors/duplicate-heading.js.map +1 -0
  170. package/dist/detectors/empty-section.d.ts +8 -0
  171. package/dist/detectors/empty-section.d.ts.map +1 -0
  172. package/dist/detectors/empty-section.js +16 -0
  173. package/dist/detectors/empty-section.js.map +1 -0
  174. package/dist/detectors/fullwidth-alnum.d.ts +24 -0
  175. package/dist/detectors/fullwidth-alnum.d.ts.map +1 -0
  176. package/dist/detectors/fullwidth-alnum.js +88 -0
  177. package/dist/detectors/fullwidth-alnum.js.map +1 -0
  178. package/dist/detectors/hankaku-kana.d.ts +9 -0
  179. package/dist/detectors/hankaku-kana.d.ts.map +1 -0
  180. package/dist/detectors/hankaku-kana.js +27 -0
  181. package/dist/detectors/hankaku-kana.js.map +1 -0
  182. package/dist/detectors/heading-code-words.js +2 -2
  183. package/dist/detectors/heading-code-words.js.map +1 -1
  184. package/dist/detectors/index.d.ts.map +1 -1
  185. package/dist/detectors/index.js +36 -0
  186. package/dist/detectors/index.js.map +1 -1
  187. package/dist/detectors/invisible-character.d.ts +20 -0
  188. package/dist/detectors/invisible-character.d.ts.map +1 -0
  189. package/dist/detectors/invisible-character.js +143 -0
  190. package/dist/detectors/invisible-character.js.map +1 -0
  191. package/dist/detectors/kutoten-consistency.js +2 -2
  192. package/dist/detectors/kutoten-consistency.js.map +1 -1
  193. package/dist/detectors/lexicon-match.d.ts +10 -1
  194. package/dist/detectors/lexicon-match.d.ts.map +1 -1
  195. package/dist/detectors/lexicon-match.js +26 -1
  196. package/dist/detectors/lexicon-match.js.map +1 -1
  197. package/dist/detectors/lexicon.d.ts +6 -1
  198. package/dist/detectors/lexicon.d.ts.map +1 -1
  199. package/dist/detectors/lexicon.js +31 -13
  200. package/dist/detectors/lexicon.js.map +1 -1
  201. package/dist/detectors/list-sentence.d.ts +3 -1
  202. package/dist/detectors/list-sentence.d.ts.map +1 -1
  203. package/dist/detectors/list-sentence.js +26 -1
  204. package/dist/detectors/list-sentence.js.map +1 -1
  205. package/dist/detectors/long-vowel.d.ts.map +1 -1
  206. package/dist/detectors/long-vowel.js +18 -4
  207. package/dist/detectors/long-vowel.js.map +1 -1
  208. package/dist/detectors/markup-finding.d.ts +3 -1
  209. package/dist/detectors/markup-finding.d.ts.map +1 -1
  210. package/dist/detectors/markup-finding.js +10 -0
  211. package/dist/detectors/markup-finding.js.map +1 -1
  212. package/dist/detectors/modal-conflict.d.ts +4 -0
  213. package/dist/detectors/modal-conflict.d.ts.map +1 -0
  214. package/dist/detectors/modal-conflict.js +22 -0
  215. package/dist/detectors/modal-conflict.js.map +1 -0
  216. package/dist/detectors/name-variant.d.ts +4 -0
  217. package/dist/detectors/name-variant.d.ts.map +1 -0
  218. package/dist/detectors/name-variant.js +13 -0
  219. package/dist/detectors/name-variant.js.map +1 -0
  220. package/dist/detectors/nominalization.d.ts +11 -0
  221. package/dist/detectors/nominalization.d.ts.map +1 -0
  222. package/dist/detectors/nominalization.js +56 -0
  223. package/dist/detectors/nominalization.js.map +1 -0
  224. package/dist/detectors/orthography.d.ts.map +1 -1
  225. package/dist/detectors/orthography.js +59 -28
  226. package/dist/detectors/orthography.js.map +1 -1
  227. package/dist/detectors/outside-announced-list.d.ts +4 -0
  228. package/dist/detectors/outside-announced-list.d.ts.map +1 -0
  229. package/dist/detectors/outside-announced-list.js +24 -0
  230. package/dist/detectors/outside-announced-list.js.map +1 -0
  231. package/dist/detectors/oxford-comma.d.ts.map +1 -1
  232. package/dist/detectors/oxford-comma.js +1 -0
  233. package/dist/detectors/oxford-comma.js.map +1 -1
  234. package/dist/detectors/phrase-match.d.ts +4 -1
  235. package/dist/detectors/phrase-match.d.ts.map +1 -1
  236. package/dist/detectors/phrase-match.js +26 -7
  237. package/dist/detectors/phrase-match.js.map +1 -1
  238. package/dist/detectors/ra-nuki.d.ts +9 -0
  239. package/dist/detectors/ra-nuki.d.ts.map +1 -0
  240. package/dist/detectors/ra-nuki.js +30 -0
  241. package/dist/detectors/ra-nuki.js.map +1 -0
  242. package/dist/detectors/requirement-modal.d.ts +5 -0
  243. package/dist/detectors/requirement-modal.d.ts.map +1 -0
  244. package/dist/detectors/requirement-modal.js +54 -0
  245. package/dist/detectors/requirement-modal.js.map +1 -0
  246. package/dist/detectors/requirement-smell.d.ts +4 -0
  247. package/dist/detectors/requirement-smell.d.ts.map +1 -0
  248. package/dist/detectors/requirement-smell.js +41 -0
  249. package/dist/detectors/requirement-smell.js.map +1 -0
  250. package/dist/detectors/space-before-punctuation.d.ts +8 -0
  251. package/dist/detectors/space-before-punctuation.d.ts.map +1 -0
  252. package/dist/detectors/space-before-punctuation.js +24 -0
  253. package/dist/detectors/space-before-punctuation.js.map +1 -0
  254. package/dist/detectors/spelling-variety.d.ts +23 -0
  255. package/dist/detectors/spelling-variety.d.ts.map +1 -0
  256. package/dist/detectors/spelling-variety.js +59 -0
  257. package/dist/detectors/spelling-variety.js.map +1 -0
  258. package/dist/detectors/structure-tree.d.ts.map +1 -1
  259. package/dist/detectors/structure-tree.js +3 -1
  260. package/dist/detectors/structure-tree.js.map +1 -1
  261. package/dist/detectors/structure.d.ts.map +1 -1
  262. package/dist/detectors/structure.js +16 -2
  263. package/dist/detectors/structure.js.map +1 -1
  264. package/dist/detectors/superlative-comparison.d.ts +20 -0
  265. package/dist/detectors/superlative-comparison.d.ts.map +1 -0
  266. package/dist/detectors/superlative-comparison.js +32 -0
  267. package/dist/detectors/superlative-comparison.js.map +1 -0
  268. package/dist/detectors/url-run-on.d.ts.map +1 -1
  269. package/dist/detectors/url-run-on.js +6 -1
  270. package/dist/detectors/url-run-on.js.map +1 -1
  271. package/dist/detectors/vague-figure-pointer.d.ts +10 -0
  272. package/dist/detectors/vague-figure-pointer.d.ts.map +1 -0
  273. package/dist/detectors/vague-figure-pointer.js +46 -0
  274. package/dist/detectors/vague-figure-pointer.js.map +1 -0
  275. package/dist/detectors/word-list.d.ts +2 -0
  276. package/dist/detectors/word-list.d.ts.map +1 -1
  277. package/dist/detectors/word-list.js +4 -1
  278. package/dist/detectors/word-list.js.map +1 -1
  279. package/dist/document.d.ts +9 -3
  280. package/dist/document.d.ts.map +1 -1
  281. package/dist/document.js +55 -32
  282. package/dist/document.js.map +1 -1
  283. package/dist/extension/document-view.d.ts +7 -0
  284. package/dist/extension/document-view.d.ts.map +1 -0
  285. package/dist/extension/document-view.js +91 -0
  286. package/dist/extension/document-view.js.map +1 -0
  287. package/dist/extension/failure-text.d.ts +5 -0
  288. package/dist/extension/failure-text.d.ts.map +1 -0
  289. package/dist/extension/failure-text.js +33 -0
  290. package/dist/extension/failure-text.js.map +1 -0
  291. package/dist/extension/import-default.d.ts +7 -0
  292. package/dist/extension/import-default.d.ts.map +1 -0
  293. package/dist/extension/import-default.js +21 -0
  294. package/dist/extension/import-default.js.map +1 -0
  295. package/dist/extension/load.d.ts +28 -0
  296. package/dist/extension/load.d.ts.map +1 -0
  297. package/dist/extension/load.js +51 -0
  298. package/dist/extension/load.js.map +1 -0
  299. package/dist/extension/module-detector.d.ts +21 -0
  300. package/dist/extension/module-detector.d.ts.map +1 -0
  301. package/dist/extension/module-detector.js +49 -0
  302. package/dist/extension/module-detector.js.map +1 -0
  303. package/dist/extension/plugin-load.d.ts +9 -0
  304. package/dist/extension/plugin-load.d.ts.map +1 -0
  305. package/dist/extension/plugin-load.js +68 -0
  306. package/dist/extension/plugin-load.js.map +1 -0
  307. package/dist/extension/plugin-name.d.ts +8 -0
  308. package/dist/extension/plugin-name.d.ts.map +1 -0
  309. package/dist/extension/plugin-name.js +22 -0
  310. package/dist/extension/plugin-name.js.map +1 -0
  311. package/dist/extension/plugin-parse.d.ts +41 -0
  312. package/dist/extension/plugin-parse.d.ts.map +1 -0
  313. package/dist/extension/plugin-parse.js +156 -0
  314. package/dist/extension/plugin-parse.js.map +1 -0
  315. package/dist/extension/problem-text.d.ts +5 -0
  316. package/dist/extension/problem-text.d.ts.map +1 -0
  317. package/dist/extension/problem-text.js +74 -0
  318. package/dist/extension/problem-text.js.map +1 -0
  319. package/dist/extension/real-path.d.ts +3 -0
  320. package/dist/extension/real-path.d.ts.map +1 -0
  321. package/dist/extension/real-path.js +8 -0
  322. package/dist/extension/real-path.js.map +1 -0
  323. package/dist/extension/returned-findings.d.ts +17 -0
  324. package/dist/extension/returned-findings.d.ts.map +1 -0
  325. package/dist/extension/returned-findings.js +48 -0
  326. package/dist/extension/returned-findings.js.map +1 -0
  327. package/dist/extension/rule-export.d.ts +13 -0
  328. package/dist/extension/rule-export.d.ts.map +1 -0
  329. package/dist/extension/rule-export.js +16 -0
  330. package/dist/extension/rule-export.js.map +1 -0
  331. package/dist/feedback/draft.d.ts +2 -0
  332. package/dist/feedback/draft.d.ts.map +1 -1
  333. package/dist/feedback/draft.js +3 -0
  334. package/dist/feedback/draft.js.map +1 -1
  335. package/dist/figure-references.d.ts +11 -2
  336. package/dist/figure-references.d.ts.map +1 -1
  337. package/dist/figure-references.js +50 -13
  338. package/dist/figure-references.js.map +1 -1
  339. package/dist/finding-order.d.ts +9 -0
  340. package/dist/finding-order.d.ts.map +1 -0
  341. package/dist/finding-order.js +3 -0
  342. package/dist/finding-order.js.map +1 -0
  343. package/dist/fix-plan/mode.d.ts +21 -0
  344. package/dist/fix-plan/mode.d.ts.map +1 -0
  345. package/dist/fix-plan/mode.js +16 -0
  346. package/dist/fix-plan/mode.js.map +1 -0
  347. package/dist/fix-plan/plan.d.ts +77 -0
  348. package/dist/fix-plan/plan.d.ts.map +1 -0
  349. package/dist/fix-plan/plan.js +100 -0
  350. package/dist/fix-plan/plan.js.map +1 -0
  351. package/dist/fix-plan/render.d.ts +6 -0
  352. package/dist/fix-plan/render.d.ts.map +1 -0
  353. package/dist/fix-plan/render.js +101 -0
  354. package/dist/fix-plan/render.js.map +1 -0
  355. package/dist/fix-plan/text.d.ts +35 -0
  356. package/dist/fix-plan/text.d.ts.map +1 -0
  357. package/dist/fix-plan/text.js +95 -0
  358. package/dist/fix-plan/text.js.map +1 -0
  359. package/dist/language-sample.d.ts +2 -0
  360. package/dist/language-sample.d.ts.map +1 -0
  361. package/dist/language-sample.js +41 -0
  362. package/dist/language-sample.js.map +1 -0
  363. package/dist/link-line.d.ts +8 -0
  364. package/dist/link-line.d.ts.map +1 -0
  365. package/dist/link-line.js +12 -0
  366. package/dist/link-line.js.map +1 -0
  367. package/dist/long-vowel.d.ts +9 -6
  368. package/dist/long-vowel.d.ts.map +1 -1
  369. package/dist/long-vowel.js +15 -8
  370. package/dist/long-vowel.js.map +1 -1
  371. package/dist/markup.d.ts.map +1 -1
  372. package/dist/markup.js +4 -2
  373. package/dist/markup.js.map +1 -1
  374. package/dist/name-variants.d.ts +25 -0
  375. package/dist/name-variants.d.ts.map +1 -0
  376. package/dist/name-variants.js +181 -0
  377. package/dist/name-variants.js.map +1 -0
  378. package/dist/node-version.d.ts +7 -0
  379. package/dist/node-version.d.ts.map +1 -0
  380. package/dist/node-version.js +19 -0
  381. package/dist/node-version.js.map +1 -0
  382. package/dist/not-run.d.ts +14 -0
  383. package/dist/not-run.d.ts.map +1 -0
  384. package/dist/not-run.js +12 -0
  385. package/dist/not-run.js.map +1 -0
  386. package/dist/orthography.d.ts +8 -1
  387. package/dist/orthography.d.ts.map +1 -1
  388. package/dist/orthography.js +33 -12
  389. package/dist/orthography.js.map +1 -1
  390. package/dist/outline/render.d.ts +18 -0
  391. package/dist/outline/render.d.ts.map +1 -0
  392. package/dist/outline/render.js +60 -0
  393. package/dist/outline/render.js.map +1 -0
  394. package/dist/outline/shape.d.ts +26 -0
  395. package/dist/outline/shape.d.ts.map +1 -0
  396. package/dist/outline/shape.js +37 -0
  397. package/dist/outline/shape.js.map +1 -0
  398. package/dist/outline/text.d.ts +21 -0
  399. package/dist/outline/text.d.ts.map +1 -0
  400. package/dist/outline/text.js +30 -0
  401. package/dist/outline/text.js.map +1 -0
  402. package/dist/plugin.d.ts +24 -2
  403. package/dist/plugin.d.ts.map +1 -1
  404. package/dist/reasons.d.ts +1 -0
  405. package/dist/reasons.d.ts.map +1 -1
  406. package/dist/reasons.js +2 -0
  407. package/dist/reasons.js.map +1 -1
  408. package/dist/render/compact.d.ts +3 -1
  409. package/dist/render/compact.d.ts.map +1 -1
  410. package/dist/render/compact.js +8 -2
  411. package/dist/render/compact.js.map +1 -1
  412. package/dist/render/explain.d.ts +3 -1
  413. package/dist/render/explain.d.ts.map +1 -1
  414. package/dist/render/explain.js +32 -15
  415. package/dist/render/explain.js.map +1 -1
  416. package/dist/render/rules-json.d.ts.map +1 -1
  417. package/dist/render/rules-json.js +16 -12
  418. package/dist/render/rules-json.js.map +1 -1
  419. package/dist/render/suppressions.d.ts +3 -0
  420. package/dist/render/suppressions.d.ts.map +1 -1
  421. package/dist/render/suppressions.js +20 -1
  422. package/dist/render/suppressions.js.map +1 -1
  423. package/dist/rule-guide.d.ts +19 -0
  424. package/dist/rule-guide.d.ts.map +1 -1
  425. package/dist/rule-guide.js +14 -0
  426. package/dist/rule-guide.js.map +1 -1
  427. package/dist/run-semantic.d.ts.map +1 -1
  428. package/dist/run-semantic.js +2 -1
  429. package/dist/run-semantic.js.map +1 -1
  430. package/dist/run.d.ts +5 -1
  431. package/dist/run.d.ts.map +1 -1
  432. package/dist/run.js +31 -14
  433. package/dist/run.js.map +1 -1
  434. package/dist/setting-problems.d.ts.map +1 -1
  435. package/dist/setting-problems.js +3 -1
  436. package/dist/setting-problems.js.map +1 -1
  437. package/dist/spacing-minority.d.ts +16 -0
  438. package/dist/spacing-minority.d.ts.map +1 -0
  439. package/dist/spacing-minority.js +23 -0
  440. package/dist/spacing-minority.js.map +1 -0
  441. package/dist/stet-block.d.ts +5 -0
  442. package/dist/stet-block.d.ts.map +1 -0
  443. package/dist/stet-block.js +59 -0
  444. package/dist/stet-block.js.map +1 -0
  445. package/dist/stet.d.ts +4 -0
  446. package/dist/stet.d.ts.map +1 -1
  447. package/dist/stet.js +31 -11
  448. package/dist/stet.js.map +1 -1
  449. package/dist/structure/date-range.d.ts +10 -0
  450. package/dist/structure/date-range.d.ts.map +1 -1
  451. package/dist/structure/date-range.js +33 -1
  452. package/dist/structure/date-range.js.map +1 -1
  453. package/dist/structure/definition-use.d.ts +32 -0
  454. package/dist/structure/definition-use.d.ts.map +1 -0
  455. package/dist/structure/definition-use.js +102 -0
  456. package/dist/structure/definition-use.js.map +1 -0
  457. package/dist/structure/lazy-tree.d.ts +8 -0
  458. package/dist/structure/lazy-tree.d.ts.map +1 -0
  459. package/dist/structure/lazy-tree.js +14 -0
  460. package/dist/structure/lazy-tree.js.map +1 -0
  461. package/dist/structure/modal-conflict.d.ts +28 -0
  462. package/dist/structure/modal-conflict.d.ts.map +1 -0
  463. package/dist/structure/modal-conflict.js +74 -0
  464. package/dist/structure/modal-conflict.js.map +1 -0
  465. package/dist/structure/numbered-clauses.d.ts +4 -0
  466. package/dist/structure/numbered-clauses.d.ts.map +1 -0
  467. package/dist/structure/numbered-clauses.js +9 -0
  468. package/dist/structure/numbered-clauses.js.map +1 -0
  469. package/dist/structure/universal.d.ts.map +1 -1
  470. package/dist/structure/universal.js +8 -2
  471. package/dist/structure/universal.js.map +1 -1
  472. package/dist/style-parse.d.ts +6 -0
  473. package/dist/style-parse.d.ts.map +1 -1
  474. package/dist/style-parse.js +32 -4
  475. package/dist/style-parse.js.map +1 -1
  476. package/dist/subheading-line.d.ts +19 -2
  477. package/dist/subheading-line.d.ts.map +1 -1
  478. package/dist/subheading-line.js +39 -11
  479. package/dist/subheading-line.js.map +1 -1
  480. package/dist/tag-coverage.d.ts +8 -0
  481. package/dist/tag-coverage.d.ts.map +1 -0
  482. package/dist/tag-coverage.js +7 -0
  483. package/dist/tag-coverage.js.map +1 -0
  484. package/genres.yaml +42 -0
  485. package/package.json +7 -3
  486. package/rules/acronym-expansion-conflict.yaml +82 -0
  487. package/rules/adverb-overuse.yaml +2 -2
  488. package/rules/agentless-passive.yaml +28 -0
  489. package/rules/ai-tell.yaml +34 -0
  490. package/rules/announced-count-mismatch.yaml +2 -2
  491. package/rules/announcing-opener.yaml +31 -0
  492. package/rules/assistant-residue.yaml +30 -0
  493. package/rules/bold-density.yaml +28 -0
  494. package/rules/bold-label-list.yaml +81 -0
  495. package/rules/closing-cliche.yaml +27 -2
  496. package/rules/colon-lead-in.yaml +28 -4
  497. package/rules/contrast-framing.yaml +33 -2
  498. package/rules/cushion-phrase-density.yaml +32 -5
  499. package/rules/dangling-reference.yaml +1 -0
  500. package/rules/date-order.yaml +1 -0
  501. package/rules/date-range-reversed.yaml +2 -2
  502. package/rules/double-negative.yaml +51 -0
  503. package/rules/doubled-punctuation.yaml +2 -2
  504. package/rules/doubled-word.yaml +2 -2
  505. package/rules/duplicate-heading.yaml +78 -0
  506. package/rules/emoji-density.yaml +5 -4
  507. package/rules/empty-intensifier.yaml +25 -0
  508. package/rules/empty-section.yaml +74 -0
  509. package/rules/excessive-hedging.yaml +32 -4
  510. package/rules/fullwidth-alnum-consistency.yaml +53 -0
  511. package/rules/hankaku-kana.yaml +41 -0
  512. package/rules/image-alt-text.yaml +1 -1
  513. package/rules/invisible-character.yaml +63 -0
  514. package/rules/katakana-long-vowel.yaml +10 -9
  515. package/rules/latin-spacing.yaml +12 -5
  516. package/rules/max-kanji-continuous.yaml +1 -0
  517. package/rules/max-paragraph-length.yaml +1 -0
  518. package/rules/max-sentence-length.yaml +26 -0
  519. package/rules/modal-conflict.yaml +106 -0
  520. package/rules/name-variant.yaml +88 -0
  521. package/rules/no-doubled-joshi.yaml +1 -0
  522. package/rules/no-em-dash.yaml +26 -2
  523. package/rules/no-mixed-desumasu.yaml +1 -0
  524. package/rules/nominalization.yaml +89 -0
  525. package/rules/outside-announced-list.yaml +80 -0
  526. package/rules/padded-intro.yaml +25 -0
  527. package/rules/paragraph-length-variance.yaml +26 -2
  528. package/rules/preferred-term.yaml +1 -0
  529. package/rules/proper-noun-density.yaml +14 -5
  530. package/rules/ra-nuki.yaml +43 -0
  531. package/rules/requirement-modal.yaml +94 -0
  532. package/rules/requirement-smell.yaml +70 -0
  533. package/rules/rule-of-three.yaml +46 -0
  534. package/rules/section-length-uniformity.yaml +26 -2
  535. package/rules/sentence-rhythm.yaml +26 -0
  536. package/rules/space-before-punctuation.yaml +41 -0
  537. package/rules/spelling-consistency.yaml +47 -0
  538. package/rules/stock-transition.yaml +33 -2
  539. package/rules/taigen-dome-in-prose.yaml +14 -0
  540. package/rules/total-mismatch.yaml +1 -0
  541. package/rules/undefined-acronym.yaml +1 -0
  542. package/rules/unqualified-superlative.yaml +5 -4
  543. package/rules/unused-definition.yaml +75 -0
  544. package/rules/use-before-definition.yaml +77 -0
  545. package/rules/vague-figure-reference.yaml +66 -0
  546. package/skills/chaff/SKILL.md +108 -8
  547. package/src/acronym-expansions.ts +106 -0
  548. package/src/announced-count.ts +53 -11
  549. package/src/announced-list.ts +120 -0
  550. package/src/api.ts +154 -0
  551. package/src/cli-text.ts +6 -11
  552. package/src/cli.ts +64 -63
  553. package/src/closing-paragraph.ts +24 -0
  554. package/src/commands/compare.ts +11 -18
  555. package/src/commands/document-commands.ts +19 -0
  556. package/src/commands/eval.ts +3 -2
  557. package/src/commands/facts.ts +33 -0
  558. package/src/commands/feedback.ts +33 -1
  559. package/src/commands/fix-plan.ts +53 -0
  560. package/src/commands/outline.ts +49 -0
  561. package/src/commands/read-document.ts +24 -0
  562. package/src/commands/suppressions.ts +19 -0
  563. package/src/commands/test.ts +1 -1
  564. package/src/compare/clock-time.ts +5 -2
  565. package/src/compare/distinct.ts +13 -0
  566. package/src/compare/extract.ts +7 -5
  567. package/src/compare/fact-key.ts +31 -0
  568. package/src/compare/fact-text.ts +21 -2
  569. package/src/compare/facts-render.ts +63 -0
  570. package/src/compare/facts-text.ts +41 -0
  571. package/src/compare/match.ts +1 -1
  572. package/src/compare/outcome.ts +14 -4
  573. package/src/compare/proper-nouns.ts +4 -4
  574. package/src/compare/render.ts +2 -2
  575. package/src/compare/text-atoms.ts +7 -6
  576. package/src/compare/text.ts +3 -2
  577. package/src/config/load.ts +9 -0
  578. package/src/config/option-problems.ts +6 -4
  579. package/src/config/style.ts +14 -1
  580. package/src/custom/load.ts +11 -3
  581. package/src/custom/module-path.ts +23 -0
  582. package/src/custom/parse.ts +67 -18
  583. package/src/custom/problems.ts +63 -41
  584. package/src/detect-language.ts +1 -1
  585. package/src/detect.ts +10 -3
  586. package/src/detectors/ai-phrasing.ts +6 -2
  587. package/src/detectors/bold-label.ts +55 -0
  588. package/src/detectors/dangling-figure.ts +8 -4
  589. package/src/detectors/definition-use.ts +41 -0
  590. package/src/detectors/doubled-punctuation.ts +5 -2
  591. package/src/detectors/duplicate-heading.ts +47 -0
  592. package/src/detectors/empty-section.ts +21 -0
  593. package/src/detectors/fullwidth-alnum.ts +118 -0
  594. package/src/detectors/hankaku-kana.ts +38 -0
  595. package/src/detectors/heading-code-words.ts +2 -2
  596. package/src/detectors/index.ts +36 -0
  597. package/src/detectors/invisible-character.ts +190 -0
  598. package/src/detectors/kutoten-consistency.ts +2 -2
  599. package/src/detectors/lexicon-match.ts +33 -1
  600. package/src/detectors/lexicon.ts +40 -13
  601. package/src/detectors/list-sentence.ts +45 -4
  602. package/src/detectors/long-vowel.ts +20 -4
  603. package/src/detectors/markup-finding.ts +16 -1
  604. package/src/detectors/modal-conflict.ts +26 -0
  605. package/src/detectors/name-variant.ts +15 -0
  606. package/src/detectors/nominalization.ts +73 -0
  607. package/src/detectors/orthography.ts +77 -27
  608. package/src/detectors/outside-announced-list.ts +25 -0
  609. package/src/detectors/oxford-comma.ts +1 -0
  610. package/src/detectors/phrase-match.ts +27 -7
  611. package/src/detectors/ra-nuki.ts +38 -0
  612. package/src/detectors/requirement-modal.ts +67 -0
  613. package/src/detectors/requirement-smell.ts +52 -0
  614. package/src/detectors/space-before-punctuation.ts +32 -0
  615. package/src/detectors/spelling-variety.ts +81 -0
  616. package/src/detectors/structure-tree.ts +3 -1
  617. package/src/detectors/structure.ts +17 -3
  618. package/src/detectors/superlative-comparison.ts +47 -0
  619. package/src/detectors/url-run-on.ts +7 -1
  620. package/src/detectors/vague-figure-pointer.ts +58 -0
  621. package/src/detectors/word-list.ts +6 -1
  622. package/src/document.ts +88 -41
  623. package/src/extension/document-view.ts +109 -0
  624. package/src/extension/failure-text.ts +46 -0
  625. package/src/extension/import-default.ts +13 -0
  626. package/src/extension/load.ts +97 -0
  627. package/src/extension/module-detector.ts +61 -0
  628. package/src/extension/plugin-load.ts +82 -0
  629. package/src/extension/plugin-name.ts +26 -0
  630. package/src/extension/plugin-parse.ts +229 -0
  631. package/src/extension/problem-text.ts +103 -0
  632. package/src/extension/real-path.ts +10 -0
  633. package/src/extension/returned-findings.ts +62 -0
  634. package/src/extension/rule-export.ts +23 -0
  635. package/src/feedback/draft.ts +6 -0
  636. package/src/figure-references.ts +73 -12
  637. package/src/finding-order.ts +3 -0
  638. package/src/fix-plan/mode.ts +34 -0
  639. package/src/fix-plan/plan.ts +181 -0
  640. package/src/fix-plan/render.ts +128 -0
  641. package/src/fix-plan/text.ts +133 -0
  642. package/src/language-sample.ts +48 -0
  643. package/src/link-line.ts +13 -0
  644. package/src/long-vowel.ts +18 -8
  645. package/src/markup.ts +4 -2
  646. package/src/name-variants.ts +217 -0
  647. package/src/node-version.ts +22 -0
  648. package/src/not-run.ts +16 -0
  649. package/src/orthography.ts +40 -11
  650. package/src/outline/render.ts +85 -0
  651. package/src/outline/shape.ts +72 -0
  652. package/src/outline/text.ts +50 -0
  653. package/src/plugin.ts +21 -4
  654. package/src/reasons.ts +3 -0
  655. package/src/render/compact.ts +13 -3
  656. package/src/render/explain.ts +47 -20
  657. package/src/render/rules-json.ts +18 -12
  658. package/src/render/suppressions.ts +30 -2
  659. package/src/rule-guide.ts +38 -0
  660. package/src/run-semantic.ts +2 -1
  661. package/src/run.ts +37 -17
  662. package/src/setting-problems.ts +3 -1
  663. package/src/spacing-minority.ts +27 -0
  664. package/src/stet-block.ts +60 -0
  665. package/src/stet.ts +41 -15
  666. package/src/structure/date-range.ts +49 -1
  667. package/src/structure/definition-use.ts +130 -0
  668. package/src/structure/lazy-tree.ts +15 -0
  669. package/src/structure/modal-conflict.ts +86 -0
  670. package/src/structure/numbered-clauses.ts +11 -0
  671. package/src/structure/universal.ts +10 -2
  672. package/src/style-parse.ts +38 -3
  673. package/src/subheading-line.ts +51 -13
  674. package/src/tag-coverage.ts +13 -0
  675. package/styles/ieice.yaml +5 -4
  676. package/styles/jis-z8301-2011.yaml +5 -2
  677. package/styles/jis-z8301-2019.yaml +31 -0
  678. package/styles/koyobun.yaml +35 -0
  679. package/dist/legal-address.d.ts +0 -2
  680. package/dist/legal-address.d.ts.map +0 -1
  681. package/dist/legal-address.js +0 -16
  682. package/dist/legal-address.js.map +0 -1
@@ -0,0 +1,181 @@
1
+ import type { Finding, LengthUnit, Lexicon, RuleDefinition } from "../plugin.ts";
2
+ import type { RewritePair } from "../rule-guide.ts";
3
+ import type { Skipped } from "../run.ts";
4
+ import type { Outline, Shape } from "../outline/shape.ts";
5
+ import { localized, messageOf } from "../render/text.ts";
6
+ import { splitWords } from "../detectors/word-list.ts";
7
+ import { COMPOSITE_RULE, recommendMode, type ModeChoice } from "./mode.ts";
8
+
9
+ /** One flagged spot, where it is and what chaff said about it. */
10
+ export type PlanSpot = { readonly line: number; readonly column: number; readonly quote: string; readonly message: string };
11
+
12
+ /** A phrase's own hint from the lexicon ("時間を溶かす" → "時間がかかった(何に、どれだけ)"). */
13
+ export type PhraseHint = { readonly phrase: string; readonly rewrite: string };
14
+
15
+ /** Everything a rewriter needs for one rule: its direction and the spots it flagged. */
16
+ export type RulePlan = {
17
+ readonly rule: string;
18
+ readonly name: string;
19
+ /** The rule's rewrite direction, or its how_to_fix when it has no rewrite block. */
20
+ readonly direction: string;
21
+ readonly keep: readonly string[];
22
+ readonly avoid: readonly string[];
23
+ /** The first of the rule's pairs, to copy the shape from. */
24
+ readonly pair: RewritePair | undefined;
25
+ readonly hints: readonly PhraseHint[];
26
+ readonly spots: readonly PlanSpot[];
27
+ };
28
+
29
+ /** A rule that measures the whole document, with what it said. */
30
+ type DocumentSignal = { readonly rule: string; readonly message: string };
31
+
32
+ export type FixPlan = {
33
+ readonly path: string;
34
+ /** Where the plan suggests saving the rewrite, so the check commands can be pasted as they are. */
35
+ readonly rewrittenPath: string;
36
+ readonly language: string;
37
+ readonly genre: string;
38
+ readonly experimental: boolean;
39
+ readonly mode: ModeChoice;
40
+ readonly signals: readonly DocumentSignal[];
41
+ readonly outline: { readonly unit: LengthUnit; readonly shape: Shape };
42
+ readonly rules: readonly RulePlan[];
43
+ /** The rewrite and signal rules that did not run, and why: silence from them is not "checked and fine". */
44
+ readonly notRun: readonly Skipped[];
45
+ readonly checks: readonly string[];
46
+ };
47
+
48
+ export type PlanInput = {
49
+ readonly path: string;
50
+ readonly language: string;
51
+ readonly genre: string;
52
+ readonly experimental: boolean;
53
+ /** --genre as given on the command line, repeated in the check commands. */
54
+ readonly genreFlag: string | undefined;
55
+ readonly findings: readonly Finding[];
56
+ readonly rules: readonly RuleDefinition[];
57
+ readonly skipped: readonly Skipped[];
58
+ readonly outline: Outline;
59
+ /** The ai-tell lexicon of the document's language, whose entries may carry their own hint. */
60
+ readonly phrases: Lexicon;
61
+ };
62
+
63
+ const BOLD_DENSITY_RULE = "bold-density";
64
+ const AI_TELL_RULE = "ai-tell";
65
+
66
+ /** ai-generated-composite's inputs and bold-density: the rules the guide reads as document-level signals. */
67
+ const signalRulesOf = (rules: readonly RuleDefinition[]): ReadonlySet<string> =>
68
+ new Set([...(rules.find((rule) => rule.id === COMPOSITE_RULE)?.from ?? []), BOLD_DENSITY_RULE]);
69
+
70
+ /** article.md → article.rewritten.md, beside the original. */
71
+ export const rewrittenPathOf = (path: string): string => {
72
+ const dot = path.lastIndexOf(".");
73
+ const slash = path.lastIndexOf("/");
74
+ return dot > slash + 1 ? `${path.slice(0, dot)}.rewritten${path.slice(dot)}` : `${path}.rewritten`;
75
+ };
76
+
77
+ const SHELL_SAFE = /^[\w./-]+$/u;
78
+
79
+ /** A single quote inside single quotes: close, an escaped quote, reopen. */
80
+ const QUOTE_IN_QUOTES = "'\\''";
81
+
82
+ /** A path as a shell reads it: quoted unless every character is plain. */
83
+ export const shellPath = (path: string): string => (SHELL_SAFE.test(path) ? path : `'${path.replaceAll("'", QUOTE_IN_QUOTES)}'`);
84
+
85
+ /** The ai-tell phrases the finding names that carry a hint of their own. */
86
+ export const phraseHintsOf = (finding: Finding, phrases: Lexicon, language: string): PhraseHint[] => {
87
+ const named = new Set(splitWords(String(finding.values["word"] ?? ""), language));
88
+ return phrases.flatMap((entry) =>
89
+ entry.rewrite !== undefined && named.has(entry.pattern.toLowerCase()) ? [{ phrase: entry.pattern, rewrite: entry.rewrite }] : [],
90
+ );
91
+ };
92
+
93
+ const spotOf = (finding: Finding, rule: RuleDefinition, language: string): PlanSpot => ({
94
+ line: finding.line,
95
+ column: finding.column,
96
+ quote: finding.quote,
97
+ message: messageOf(rule, finding, language),
98
+ });
99
+
100
+ const rulePlanOf = (rule: RuleDefinition, findings: readonly Finding[], input: PlanInput): RulePlan => {
101
+ const rewrite = rule.guide?.rewrite[input.language];
102
+ const hints = rule.id === AI_TELL_RULE ? findings.flatMap((finding) => phraseHintsOf(finding, input.phrases, input.language)) : [];
103
+ return {
104
+ rule: rule.id,
105
+ name: localized(rule.name, input.language),
106
+ direction: rewrite?.direction ?? localized(rule.how_to_fix, input.language),
107
+ keep: rewrite?.keep ?? [],
108
+ avoid: rewrite?.avoid ?? [],
109
+ pair: rewrite?.pairs[0],
110
+ hints,
111
+ spots: findings.map((finding) => spotOf(finding, rule, input.language)),
112
+ };
113
+ };
114
+
115
+ /** The rules in the order their first finding appears; the composite has no spot of its own and is a signal only. */
116
+ const rulePlansOf = (input: PlanInput): RulePlan[] => {
117
+ const order = [...new Set(input.findings.map((finding) => finding.rule))].filter((id) => id !== COMPOSITE_RULE);
118
+ return order.flatMap((id) => {
119
+ const rule = input.rules.find((entry) => entry.id === id);
120
+ return rule === undefined
121
+ ? []
122
+ : [
123
+ rulePlanOf(
124
+ rule,
125
+ input.findings.filter((finding) => finding.rule === id),
126
+ input,
127
+ ),
128
+ ];
129
+ });
130
+ };
131
+
132
+ /** The composite first, then each signal rule once, with what its first finding said. */
133
+ const signalsOf = (input: PlanInput, signalRules: ReadonlySet<string>): DocumentSignal[] =>
134
+ [COMPOSITE_RULE, ...signalRules].flatMap((id) => {
135
+ const finding = input.findings.find((entry) => entry.rule === id);
136
+ const rule = input.rules.find((entry) => entry.id === id);
137
+ return finding === undefined || rule === undefined ? [] : [{ rule: id, message: messageOf(rule, finding, input.language) }];
138
+ });
139
+
140
+ const hasRewrite = (rule: RuleDefinition): boolean => Object.keys(rule.guide?.rewrite ?? {}).length > 0;
141
+
142
+ /** A rule written for other languages is not one that failed to run on this document. */
143
+ const checksLanguage = (rule: RuleDefinition, language: string): boolean => rule.languages === undefined || rule.languages.includes(language);
144
+
145
+ const notRunOf = (input: PlanInput, signalRules: ReadonlySet<string>): Skipped[] => {
146
+ const forThisLanguage = input.rules.filter((rule) => checksLanguage(rule, input.language));
147
+ const watched = new Set(forThisLanguage.filter((rule) => hasRewrite(rule) || rule.id === COMPOSITE_RULE || signalRules.has(rule.id)).map((rule) => rule.id));
148
+ return input.skipped.filter((skipped) => watched.has(skipped.rule));
149
+ };
150
+
151
+ /** The commands to run on the rewrite. A full rewrite cuts repeats and rebuilds headings, which compare is told. */
152
+ const checksOf = (input: PlanInput, choice: ModeChoice): string[] => {
153
+ const original = shellPath(input.path);
154
+ const rewritten = shellPath(rewrittenPathOf(input.path));
155
+ const lintFlags = [...(input.experimental ? ["--experimental"] : []), ...(input.genreFlag === undefined ? [] : ["--genre", input.genreFlag])];
156
+ const compareFlags = choice.mode === "full" ? ["--distinct", "--allow-dropped heading", "--allow-added heading"] : [];
157
+ return [
158
+ ["npx chaffjs", rewritten, ...lintFlags].join(" "),
159
+ ["npx chaffjs compare", original, rewritten, ...compareFlags].join(" "),
160
+ ["npx chaffjs outline", original, rewritten].join(" "),
161
+ ];
162
+ };
163
+
164
+ /** The plan for one document: deterministic, from chaff's findings and the rule files alone. */
165
+ export const buildFixPlan = (input: PlanInput): FixPlan => {
166
+ const signalRules = signalRulesOf(input.rules);
167
+ const mode = recommendMode({ genre: input.genre, firedRules: new Set(input.findings.map((finding) => finding.rule)), signalRules });
168
+ return {
169
+ path: input.path,
170
+ rewrittenPath: rewrittenPathOf(input.path),
171
+ language: input.language,
172
+ genre: input.genre,
173
+ experimental: input.experimental,
174
+ mode,
175
+ signals: signalsOf(input, signalRules),
176
+ outline: { unit: input.outline.unit, shape: input.outline.shape },
177
+ rules: rulePlansOf(input),
178
+ notRun: notRunOf(input, signalRules),
179
+ checks: checksOf(input, mode),
180
+ };
181
+ };
@@ -0,0 +1,128 @@
1
+ import type { RewritePair } from "../rule-guide.ts";
2
+ import { shapeMeasures } from "../outline/render.ts";
3
+ import { OUTLINE_TEXT } from "../outline/text.ts";
4
+ import { uiLanguageOf } from "../ui.ts";
5
+ import type { FixPlan, PhraseHint, PlanSpot, RulePlan } from "./plan.ts";
6
+ import { FIX_PLAN_TEXT, type FixPlanText } from "./text.ts";
7
+
8
+ /** A phrase quoted the way the document's language quotes: 「…」 in Japanese, "…" otherwise. */
9
+ const quoted = (text: string, language: string): string => (language === "ja" ? `「${text}」` : `"${text}"`);
10
+
11
+ const bullets = (items: readonly string[]): string[] => items.map((item) => `- ${item}`);
12
+
13
+ /** Each line of a passage as a Markdown quotation, so a list inside it stays a list and does not join the plan's own. */
14
+ const blockquote = (passage: string): string[] =>
15
+ passage
16
+ .trimEnd()
17
+ .split("\n")
18
+ .map((line) => (line === "" ? ">" : `> ${line}`));
19
+
20
+ const labelled = (label: string, lines: readonly string[]): string[] => (lines.length === 0 ? [] : ["", `**${label}**`, "", ...lines]);
21
+
22
+ const pairLines = (pair: RewritePair | undefined, text: FixPlanText): string[] =>
23
+ pair === undefined ? [] : [`${text.before}:`, "", ...blockquote(pair.before), "", `${text.after}:`, "", ...blockquote(pair.after)];
24
+
25
+ const hintLine = (hint: PhraseHint, language: string): string => `- ${quoted(hint.phrase, language)} → ${hint.rewrite}`;
26
+
27
+ const spotLines = (spot: PlanSpot, text: FixPlanText, language: string): string[] => [
28
+ `- ${text.at(spot.line)}: ${quoted(spot.quote, language)}`,
29
+ ` ${spot.message}`,
30
+ ];
31
+
32
+ const rulePlanLines = (rule: RulePlan, text: FixPlanText, language: string): string[] => [
33
+ "",
34
+ `### \`${rule.rule}\` ${rule.name}`,
35
+ "",
36
+ `**${text.direction}**: ${rule.direction}`,
37
+ ...labelled(text.keep, bullets(rule.keep)),
38
+ ...labelled(text.avoid, bullets(rule.avoid)),
39
+ ...labelled(text.example, pairLines(rule.pair, text)),
40
+ ...labelled(
41
+ text.phrases,
42
+ rule.hints.map((hint) => hintLine(hint, language)),
43
+ ),
44
+ ...labelled(
45
+ text.spots,
46
+ rule.spots.flatMap((spot) => spotLines(spot, text, language)),
47
+ ),
48
+ ];
49
+
50
+ const modeLines = (plan: FixPlan, text: FixPlanText): string[] => [
51
+ "",
52
+ `## ${text.modeHeading}: ${text.modeName[plan.mode.mode]}`,
53
+ "",
54
+ text.modeReason[plan.mode.reason],
55
+ "",
56
+ ...bullets(text.modeWays),
57
+ ];
58
+
59
+ const signalLines = (plan: FixPlan, text: FixPlanText): string[] => {
60
+ const outline = text.outlineLine(shapeMeasures(plan.outline.shape, plan.outline.unit, OUTLINE_TEXT[uiLanguageOf(plan.language)]));
61
+ const said = plan.signals.length === 0 ? [text.noSignals, ""] : [];
62
+ return ["", `## ${text.signalsHeading}`, "", ...said, ...bullets([...plan.signals.map((signal) => `\`${signal.rule}\`: ${signal.message}`), outline])];
63
+ };
64
+
65
+ const notRunLines = (plan: FixPlan, text: FixPlanText): string[] => {
66
+ const note = plan.experimental ? [] : [text.notExperimental];
67
+ const listed = plan.notRun;
68
+ if (note.length === 0 && listed.length === 0) return [];
69
+ return [
70
+ "",
71
+ `## ${text.notRunHeading}`,
72
+ "",
73
+ ...note,
74
+ ...(note.length > 0 && listed.length > 0 ? [""] : []),
75
+ ...bullets(listed.map((skipped) => `\`${skipped.rule}\`: ${skipped.why}`)),
76
+ ];
77
+ };
78
+
79
+ const checkLines = (plan: FixPlan, text: FixPlanText): string[] => [
80
+ "",
81
+ `## ${text.checksHeading}`,
82
+ "",
83
+ text.saveAs(plan.rewrittenPath),
84
+ "",
85
+ "```bash",
86
+ ...plan.checks,
87
+ "```",
88
+ "",
89
+ text.checksNote,
90
+ ];
91
+
92
+ const textOf = (plan: FixPlan): FixPlanText => FIX_PLAN_TEXT[uiLanguageOf(plan.language)];
93
+
94
+ /** The plan as Markdown, in the document's language: what an agent reads before rewriting. */
95
+ export const renderFixPlanMarkdown = (plan: FixPlan): string => {
96
+ const text = textOf(plan);
97
+ return [
98
+ `# ${text.title(plan.path)}`,
99
+ "",
100
+ text.about(plan.language, plan.genre),
101
+ "",
102
+ text.intro,
103
+ "",
104
+ `## ${text.constraintsHeading}`,
105
+ "",
106
+ ...text.constraints.map((constraint, index) => `${String(index + 1)}. ${constraint}`),
107
+ ...modeLines(plan, text),
108
+ ...signalLines(plan, text),
109
+ ...(plan.rules.length === 0 ? [] : ["", `## ${text.rulesHeading}`]),
110
+ ...plan.rules.flatMap((rule) => rulePlanLines(rule, text, plan.language)),
111
+ ...notRunLines(plan, text),
112
+ ...checkLines(plan, text),
113
+ ].join("\n");
114
+ };
115
+
116
+ /** The same plan as JSON, with the constraints and the mode's reason in the document's language. */
117
+ export const renderFixPlanJson = (plan: FixPlan): string => {
118
+ const text = textOf(plan);
119
+ return JSON.stringify(
120
+ {
121
+ ...plan,
122
+ constraints: text.constraints,
123
+ mode: { ...plan.mode, name: text.modeName[plan.mode.mode], why: text.modeReason[plan.mode.reason] },
124
+ },
125
+ null,
126
+ 2,
127
+ );
128
+ };
@@ -0,0 +1,133 @@
1
+ import type { Texts } from "../ui.ts";
2
+ import type { FixMode, ModeReason } from "./mode.ts";
3
+
4
+ export type FixPlanText = {
5
+ readonly usage: string;
6
+ readonly notFound: (path: string) => string;
7
+ readonly title: (path: string) => string;
8
+ readonly about: (language: string, genre: string) => string;
9
+ readonly intro: string;
10
+ readonly constraintsHeading: string;
11
+ readonly constraints: readonly string[];
12
+ readonly modeHeading: string;
13
+ readonly modeName: Readonly<Record<FixMode, string>>;
14
+ readonly modeReason: Readonly<Record<ModeReason, string>>;
15
+ readonly modeWays: readonly string[];
16
+ readonly signalsHeading: string;
17
+ readonly noSignals: string;
18
+ readonly outlineLine: (measures: string) => string;
19
+ readonly rulesHeading: string;
20
+ readonly direction: string;
21
+ readonly keep: string;
22
+ readonly avoid: string;
23
+ readonly example: string;
24
+ readonly before: string;
25
+ readonly after: string;
26
+ readonly phrases: string;
27
+ readonly spots: string;
28
+ readonly at: (line: number) => string;
29
+ readonly notRunHeading: string;
30
+ readonly notExperimental: string;
31
+ readonly checksHeading: string;
32
+ readonly saveAs: (path: string) => string;
33
+ readonly checksNote: string;
34
+ };
35
+
36
+ export const FIX_PLAN_TEXT: Texts<FixPlanText> = {
37
+ ja: {
38
+ usage: "使い方: chaff fix-plan <file> [--experimental] [--genre <ジャンル>] [--json]",
39
+ notFound: (path) => `${path} がありません。`,
40
+ title: (path) => `直す計画: ${path}`,
41
+ about: (language, genre) => `言語 ${language}、ジャンル ${genre}`,
42
+ intro:
43
+ "chaff が機械で見つけた箇所と、それぞれの直す方向です。chaff は書き直しません。書き直すのは、この計画を読む人か AI です。直したら、最後の確かめのコマンドを実行してください。",
44
+ constraintsHeading: "守ること",
45
+ constraints: [
46
+ "事実、数、日付、条件、名前を変えない。",
47
+ "元の文書に無い事実、人、数、原因、例を足さない。",
48
+ "直すのに文書に無い具体(誰が、いつ、どれだけ)が要るときは、作らずに[ ]で空けて書き手に聞く。",
49
+ "書き直しは 2 回まで。指摘を消すためだけに書き直しを繰り返さない。",
50
+ ],
51
+ modeHeading: "勧める直し方",
52
+ modeName: { none: "直すところなし", light: "軽く直す(Light)", bold: "大胆に直す(Bold)", full: "全面書き直し(Full)" },
53
+ modeReason: {
54
+ "nothing-found": "chaff は何も見つけませんでした。",
55
+ composite: "ai-generated-composite が出ています。文の言い回しを直しても、生成文の骨組みが残ります。",
56
+ genre: "ブログやエッセイは、構成から書き直すほうが書き手の望みに合います。",
57
+ signals: "文書全体を測るルールが 2 つ以上出ています。見出しの構成は残し、節ごとに文を書き直します。",
58
+ spots: "指摘は箇所ごとです。指摘された所だけを直します。",
59
+ },
60
+ modeWays: [
61
+ "軽く直す: 指摘された箇所だけ。",
62
+ "大胆に直す: 見出しの構成は残し、節ごとに文を書き直す。",
63
+ "全面書き直し: 事実と主張を控えてから、構成から書き直す。頼まれた内容が「全面的に」「一から」なら、これを選ぶ。",
64
+ ],
65
+ signalsHeading: "文書全体の目印",
66
+ noSignals: "文書全体を測るルールは、何も言っていません。",
67
+ outlineLine: (measures) => `構成: ${measures}`,
68
+ rulesHeading: "ルールごとの直し方",
69
+ direction: "直す方向",
70
+ keep: "変えないもの",
71
+ avoid: "やりがちな間違い",
72
+ example: "例",
73
+ before: "前",
74
+ after: "後",
75
+ phrases: "言い回しごとの手がかり",
76
+ spots: "見つけた箇所",
77
+ at: (line) => `${String(line)} 行目`,
78
+ notRunHeading: "動かなかったルール",
79
+ notExperimental: "試験中のルールは動かしていません。AIっぽさのルールの多くは試験中です。--experimental を付けると見ます。",
80
+ checksHeading: "直したあとの確かめ",
81
+ saveAs: (path) => `書き直したものを ${path} に保存して、次を実行します。`,
82
+ checksNote:
83
+ "1 つめは書き直した文書の指摘、2 つめは事実が落ちていないか・足されていないか、3 つめは構成の変化です。数は chaff の出力から取り、形容詞で言わないでください。",
84
+ },
85
+ en: {
86
+ usage: "usage: chaff fix-plan <file> [--experimental] [--genre <genre>] [--json]",
87
+ notFound: (path) => `${path} does not exist.`,
88
+ title: (path) => `Fix plan: ${path}`,
89
+ about: (language, genre) => `language ${language}, genre ${genre}`,
90
+ intro:
91
+ "What chaff found by machine, and how to rewrite each kind of spot. chaff does not rewrite; whoever reads this plan does, a person or an AI. When done, run the checks at the end.",
92
+ constraintsHeading: "Constraints",
93
+ constraints: [
94
+ "Keep every fact, number, date, condition and name.",
95
+ "Add no fact, person, number, cause or example the original does not have.",
96
+ "Where a fix needs a specific the text does not give (who, when, how much), do not invent it: leave [ ] and ask the writer.",
97
+ "At most two passes. Do not rewrite again just to silence a finding.",
98
+ ],
99
+ modeHeading: "Recommended way",
100
+ modeName: { none: "Nothing to fix", light: "Light", bold: "Bold", full: "Full rewrite" },
101
+ modeReason: {
102
+ "nothing-found": "chaff found nothing.",
103
+ composite: "ai-generated-composite fires. Fixing the wording would leave the skeleton of generated text.",
104
+ genre: "For a blog post or an essay, what the writer wants changed is usually the structure.",
105
+ signals: "Two or more rules that measure the whole document fire. Keep the outline and rewrite the prose section by section.",
106
+ spots: "The findings are single spots. Rewrite only those.",
107
+ },
108
+ modeWays: [
109
+ "Light: only the flagged spots.",
110
+ "Bold: keep the outline, rewrite the prose of each section.",
111
+ 'Full: take an inventory of the facts and claims, then rewrite from the structure up. If the request says "from scratch", choose this.',
112
+ ],
113
+ signalsHeading: "Document-level signals",
114
+ noSignals: "None of the rules that measure the whole document said anything.",
115
+ outlineLine: (measures) => `Outline: ${measures}`,
116
+ rulesHeading: "How to rewrite, rule by rule",
117
+ direction: "Direction",
118
+ keep: "Keep",
119
+ avoid: "Avoid",
120
+ example: "Example",
121
+ before: "before",
122
+ after: "after",
123
+ phrases: "Hints for the phrases found",
124
+ spots: "Spots",
125
+ at: (line) => `line ${String(line)}`,
126
+ notRunHeading: "Rules that did not run",
127
+ notExperimental: "The experimental rules did not run, and most rules for generated text are experimental. Add --experimental to run them.",
128
+ checksHeading: "Check after rewriting",
129
+ saveAs: (path) => `Save the rewrite as ${path} and run:`,
130
+ checksNote:
131
+ "The first lists the rewrite's findings, the second checks that no fact was dropped or added, the third shows how the outline moved. Take the numbers from chaff's output, not adjectives.",
132
+ },
133
+ };
@@ -0,0 +1,48 @@
1
+ import { readMarkdown, spansOfType } from "./markdown-read.ts";
2
+ import { spanOf, type MarkdownNode } from "./markdown-node.ts";
3
+ import { maskSpans } from "./mask.ts";
4
+ import type { Span } from "./plugin.ts";
5
+
6
+ /**
7
+ * The text the document's language is guessed from: what the writer wrote in it. Fenced code, inline code, HTML tags
8
+ * and comments, HTML code blocks (`<script>`, `<pre>` and the like), YAML front matter, a site generator's syntax (MDX imports, component lines) and URLs are blanked out.
9
+ * A technical article in Japanese can hold more Latin letters in its code than kana and kanji in its prose. The text
10
+ * between HTML tags is kept: a `<details>` block holds prose. Indented code is kept too: in plain text an indented
11
+ * paragraph is prose, and Markdown would read it as code.
12
+ */
13
+
14
+ const FENCE = /^ {0,3}(?:```|~~~)/u;
15
+ const URL_PATTERN = /\b[a-z][a-z\d+.-]*:\/\/[^\s<>"'`)\]]+/giu;
16
+ const NOT_WRITTEN_IN_IT: readonly string[] = ["inlineCode", "yaml"];
17
+ /** HTML whose content is not prose: a comment, or a block that holds code (CommonMark's raw HTML blocks, and `<code>`). */
18
+ const NOT_PROSE_HTML = /^\s*(?:<!--|<(?:script|style|pre|textarea|code)\b)/iu;
19
+
20
+ const isFenced = (source: string) => (node: MarkdownNode) => {
21
+ const span = spanOf(node);
22
+ return span !== undefined && FENCE.test(source.slice(span.start, span.end));
23
+ };
24
+
25
+ const urlSpans = (source: string): Span[] => [...source.matchAll(URL_PATTERN)].map((match) => ({ start: match.index, end: match.index + match[0].length }));
26
+
27
+ /** The tags in an HTML node (`<…>`), found with indexOf so that a stray `<` costs one scan, not a backtrack. */
28
+ const tagSpans = (source: string, node: Span): Span[] => {
29
+ const spans: Span[] = [];
30
+ let open = source.indexOf("<", node.start);
31
+ while (open !== -1 && open < node.end) {
32
+ const close = source.indexOf(">", open);
33
+ if (close === -1 || close >= node.end) break;
34
+ spans.push({ start: open, end: close + 1 });
35
+ open = source.indexOf("<", close + 1);
36
+ }
37
+ return spans;
38
+ };
39
+
40
+ /** A comment or a code block is blanked whole; any other HTML keeps the text between its tags. */
41
+ const htmlSpans = (source: string, nodes: readonly Span[]): Span[] =>
42
+ nodes.flatMap((node) => (NOT_PROSE_HTML.test(source.slice(node.start, node.end)) ? [node] : tagSpans(source, node)));
43
+
44
+ export const languageSample = (source: string): string => {
45
+ const { root, syntax } = readMarkdown(source);
46
+ const code = [...spansOfType(root, "code", isFenced(source)), ...NOT_WRITTEN_IN_IT.flatMap((type) => spansOfType(root, type))];
47
+ return maskSpans(source, [...code, ...htmlSpans(source, spansOfType(root, "html")), ...syntax, ...urlSpans(source)]);
48
+ };
@@ -0,0 +1,13 @@
1
+ import type { Span } from "./plugin.ts";
2
+
3
+ /**
4
+ * 行が一つのリンクだけか。前後の空白を除いた行が、どれかのリンクの範囲とちょうど重なる。
5
+ * 記事の一覧のようにリンクを 1 行ずつ並べた段落では、句点が無くても行ごとに一つの項目と読まれる。
6
+ * line と links は source の中の位置。
7
+ */
8
+ export const isLinkLine = (source: string, line: Span, links: readonly Span[]): boolean => {
9
+ const text = source.slice(line.start, line.end);
10
+ const start = line.start + text.length - text.trimStart().length;
11
+ const end = line.end - (text.length - text.trimEnd().length);
12
+ return links.some((link) => link.start === start && link.end === end);
13
+ };
package/src/long-vowel.ts CHANGED
@@ -29,8 +29,11 @@ export type KanaWord = {
29
29
  readonly dropped: boolean;
30
30
  };
31
31
 
32
- /** The morae of the word written with its final ー: カー is two, コンピューター six. The guidelines count the word that way. */
33
- export const longFormMorae = (surface: string): number => moraCount(stemOf(surface)) + 1;
32
+ /**
33
+ * The morae of the word before its final ー: カー is one, カバー two, コンピューター five. JIS Z 8301:2011 Table G.3 counts so:
34
+ * カバー is its example of a word of two sounds or fewer, which keeps the ー.
35
+ */
36
+ export const stemMorae = (surface: string): number => moraCount(stemOf(surface));
34
37
 
35
38
  export type Ending = "consistent" | "drop" | "keep";
36
39
 
@@ -81,14 +84,21 @@ const sameWordGroups = (words: readonly KanaWord[]): KanaWord[][] => {
81
84
  */
82
85
  const inconsistent = (words: readonly KanaWord[]): Odd[] => sameWordGroups(words).flatMap((group) => minorityOf(group, "same-word"));
83
86
 
87
+ /** Whether drop reaches the word: its final ー follows one of the kana the guideline drops it after (ア段: -er, -or, -ar). Any, when none are given. */
88
+ const droppable = (word: KanaWord, dropAfter: ReadonlySet<string> | undefined): boolean =>
89
+ dropAfter === undefined || dropAfter.has(Array.from(stemOf(word.surface)).at(-1) ?? "");
90
+
84
91
  /**
85
- * The words that go against the chosen way. drop: a word of minMorae or more written with its final ー. keep: a word written
86
- * without one where the dictionary, or the document itself, has the form with one. consistent: see inconsistent.
87
- * Words shorter than minMorae are left alone whichever way: the guidelines that drop the ー keep it on them (カー).
92
+ * The words that go against the chosen way. drop: a word of minMorae or more written with its final ー after a kana of dropAfter.
93
+ * keep: a word written without one where the dictionary, or the document itself, has the form with one. consistent: see inconsistent.
94
+ * Words shorter than minMorae are left alone whichever way: the guidelines that drop the ー keep it on them (カー, カバー).
88
95
  */
89
- export const oddLongVowels = (words: readonly KanaWord[], ending: Ending, minMorae: number): Odd[] => {
90
- const counted = words.filter((word) => longFormMorae(word.surface) >= minMorae);
91
- if (ending === "drop") return counted.filter((word) => word.long).map((word) => ({ word, variant: "drop", preferred: otherForm(word), count: 0, of: 0 }));
96
+ export const oddLongVowels = (words: readonly KanaWord[], ending: Ending, minMorae: number, dropAfter?: ReadonlySet<string>): Odd[] => {
97
+ const counted = words.filter((word) => stemMorae(word.surface) >= minMorae);
98
+ if (ending === "drop")
99
+ return counted
100
+ .filter((word) => word.long && droppable(word, dropAfter))
101
+ .map((word) => ({ word, variant: "drop", preferred: otherForm(word), count: 0, of: 0 }));
92
102
  if (ending === "keep") {
93
103
  const longStems = new Set(counted.filter((word) => word.long).map((word) => stemOf(word.surface)));
94
104
  return counted
package/src/markup.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { spanOf, type MarkdownNode } from "./markdown-node.ts";
2
- import { headingText } from "./heading-text.ts";
2
+ import { atxHeadingText, headingText } from "./heading-text.ts";
3
3
  import { eachPreOrder } from "./tree-walk.ts";
4
4
  import { alertReader } from "./template-syntax.ts";
5
5
  import { cutSpans } from "./span-cut.ts";
@@ -84,7 +84,9 @@ const readHeading = (node: MarkdownNode, span: Span, source: string, walk: Walk)
84
84
  // 名前は書いたままの行から読む。MDX のコメントの `*` は、解析すると強調の印になって消える。
85
85
  const { id } = namedHeading(firstLineOf(source.slice(span.start, span.end)).replace(ATX_CLOSING, ""));
86
86
  if (id !== undefined && id !== "") walk.ids.add(id);
87
- const text = withoutMdxComment(headingText(plainText(node, source)));
87
+ // ATX(行頭が #)なら閉じの # も外す。`## Install ## {#install}` の言葉は「Install」。
88
+ const read = source.startsWith("#", span.start) ? atxHeadingText : headingText;
89
+ const text = withoutMdxComment(read(plainText(node, source)));
88
90
  walk.headings.push({ depth: numberField(node, "depth") ?? 1, text, start: span.start, end: span.end });
89
91
  };
90
92