chaffjs 0.17.0 → 0.18.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 (840) hide show
  1. package/dist/announced-count.d.ts +26 -0
  2. package/dist/announced-count.d.ts.map +1 -0
  3. package/dist/announced-count.js +104 -0
  4. package/dist/announced-count.js.map +1 -0
  5. package/dist/bare-url.d.ts +14 -0
  6. package/dist/bare-url.d.ts.map +1 -0
  7. package/dist/bare-url.js +28 -0
  8. package/dist/bare-url.js.map +1 -0
  9. package/dist/baseline.d.ts +5 -0
  10. package/dist/baseline.d.ts.map +1 -1
  11. package/dist/baseline.js +16 -1
  12. package/dist/baseline.js.map +1 -1
  13. package/dist/body-section.d.ts +7 -0
  14. package/dist/body-section.d.ts.map +1 -0
  15. package/dist/body-section.js +6 -0
  16. package/dist/body-section.js.map +1 -0
  17. package/dist/calendar-number.d.ts +2 -0
  18. package/dist/calendar-number.d.ts.map +1 -1
  19. package/dist/calendar-number.js +9 -2
  20. package/dist/calendar-number.js.map +1 -1
  21. package/dist/cli-args.d.ts +4 -0
  22. package/dist/cli-args.d.ts.map +1 -1
  23. package/dist/cli-args.js +5 -0
  24. package/dist/cli-args.js.map +1 -1
  25. package/dist/cli-text.d.ts.map +1 -1
  26. package/dist/cli-text.js +8 -4
  27. package/dist/cli-text.js.map +1 -1
  28. package/dist/cli.js +33 -30
  29. package/dist/cli.js.map +1 -1
  30. package/dist/commands/compare.d.ts +8 -0
  31. package/dist/commands/compare.d.ts.map +1 -0
  32. package/dist/commands/compare.js +72 -0
  33. package/dist/commands/compare.js.map +1 -0
  34. package/dist/commands/eval.d.ts.map +1 -1
  35. package/dist/commands/eval.js +17 -9
  36. package/dist/commands/eval.js.map +1 -1
  37. package/dist/commands/feedback.d.ts +5 -2
  38. package/dist/commands/feedback.d.ts.map +1 -1
  39. package/dist/commands/feedback.js +11 -5
  40. package/dist/commands/feedback.js.map +1 -1
  41. package/dist/commands/test.d.ts.map +1 -1
  42. package/dist/commands/test.js +2 -4
  43. package/dist/commands/test.js.map +1 -1
  44. package/dist/commands/tree.d.ts +13 -0
  45. package/dist/commands/tree.d.ts.map +1 -1
  46. package/dist/commands/tree.js +35 -5
  47. package/dist/commands/tree.js.map +1 -1
  48. package/dist/compare/atom.d.ts +31 -0
  49. package/dist/compare/atom.d.ts.map +1 -0
  50. package/dist/compare/atom.js +4 -0
  51. package/dist/compare/atom.js.map +1 -0
  52. package/dist/compare/clock-time.d.ts +8 -0
  53. package/dist/compare/clock-time.d.ts.map +1 -0
  54. package/dist/compare/clock-time.js +65 -0
  55. package/dist/compare/clock-time.js.map +1 -0
  56. package/dist/compare/extract.d.ts +15 -0
  57. package/dist/compare/extract.d.ts.map +1 -0
  58. package/dist/compare/extract.js +58 -0
  59. package/dist/compare/extract.js.map +1 -0
  60. package/dist/compare/fact-text.d.ts +23 -0
  61. package/dist/compare/fact-text.d.ts.map +1 -0
  62. package/dist/compare/fact-text.js +47 -0
  63. package/dist/compare/fact-text.js.map +1 -0
  64. package/dist/compare/markup-atoms.d.ts +11 -0
  65. package/dist/compare/markup-atoms.d.ts.map +1 -0
  66. package/dist/compare/markup-atoms.js +23 -0
  67. package/dist/compare/markup-atoms.js.map +1 -0
  68. package/dist/compare/match.d.ts +19 -0
  69. package/dist/compare/match.d.ts.map +1 -0
  70. package/dist/compare/match.js +84 -0
  71. package/dist/compare/match.js.map +1 -0
  72. package/dist/compare/outcome.d.ts +33 -0
  73. package/dist/compare/outcome.d.ts.map +1 -0
  74. package/dist/compare/outcome.js +40 -0
  75. package/dist/compare/outcome.js.map +1 -0
  76. package/dist/compare/proper-nouns.d.ts +19 -0
  77. package/dist/compare/proper-nouns.d.ts.map +1 -0
  78. package/dist/compare/proper-nouns.js +44 -0
  79. package/dist/compare/proper-nouns.js.map +1 -0
  80. package/dist/compare/render.d.ts +9 -0
  81. package/dist/compare/render.d.ts.map +1 -0
  82. package/dist/compare/render.js +64 -0
  83. package/dist/compare/render.js.map +1 -0
  84. package/dist/compare/spans.d.ts +9 -0
  85. package/dist/compare/spans.d.ts.map +1 -0
  86. package/dist/compare/spans.js +11 -0
  87. package/dist/compare/spans.js.map +1 -0
  88. package/dist/compare/text-atoms.d.ts +24 -0
  89. package/dist/compare/text-atoms.d.ts.map +1 -0
  90. package/dist/compare/text-atoms.js +67 -0
  91. package/dist/compare/text-atoms.js.map +1 -0
  92. package/dist/compare/text.d.ts +24 -0
  93. package/dist/compare/text.d.ts.map +1 -0
  94. package/dist/compare/text.js +90 -0
  95. package/dist/compare/text.js.map +1 -0
  96. package/dist/compare/tree-atoms.d.ts +20 -0
  97. package/dist/compare/tree-atoms.d.ts.map +1 -0
  98. package/dist/compare/tree-atoms.js +58 -0
  99. package/dist/compare/tree-atoms.js.map +1 -0
  100. package/dist/compare/written-names.d.ts +8 -0
  101. package/dist/compare/written-names.d.ts.map +1 -0
  102. package/dist/compare/written-names.js +24 -0
  103. package/dist/compare/written-names.js.map +1 -0
  104. package/dist/config/load.d.ts +15 -0
  105. package/dist/config/load.d.ts.map +1 -1
  106. package/dist/config/load.js +5 -0
  107. package/dist/config/load.js.map +1 -1
  108. package/dist/config/option-problems.d.ts +16 -0
  109. package/dist/config/option-problems.d.ts.map +1 -0
  110. package/dist/config/option-problems.js +58 -0
  111. package/dist/config/option-problems.js.map +1 -0
  112. package/dist/config/read.d.ts +4 -0
  113. package/dist/config/read.d.ts.map +1 -0
  114. package/dist/config/read.js +8 -0
  115. package/dist/config/read.js.map +1 -0
  116. package/dist/config/rule-problems.d.ts +2 -4
  117. package/dist/config/rule-problems.d.ts.map +1 -1
  118. package/dist/config/rule-problems.js +7 -1
  119. package/dist/config/rule-problems.js.map +1 -1
  120. package/dist/config/style.d.ts +16 -0
  121. package/dist/config/style.d.ts.map +1 -0
  122. package/dist/config/style.js +36 -0
  123. package/dist/config/style.js.map +1 -0
  124. package/dist/config/warnings.d.ts +6 -0
  125. package/dist/config/warnings.d.ts.map +1 -0
  126. package/dist/config/warnings.js +10 -0
  127. package/dist/config/warnings.js.map +1 -0
  128. package/dist/config/write.d.ts.map +1 -1
  129. package/dist/config/write.js +17 -4
  130. package/dist/config/write.js.map +1 -1
  131. package/dist/custom/bounded-match.d.ts +15 -0
  132. package/dist/custom/bounded-match.d.ts.map +1 -0
  133. package/dist/custom/bounded-match.js +43 -0
  134. package/dist/custom/bounded-match.js.map +1 -0
  135. package/dist/custom/load.d.ts +8 -0
  136. package/dist/custom/load.d.ts.map +1 -0
  137. package/dist/custom/load.js +11 -0
  138. package/dist/custom/load.js.map +1 -0
  139. package/dist/custom/parse.d.ts +70 -0
  140. package/dist/custom/parse.d.ts.map +1 -0
  141. package/dist/custom/parse.js +215 -0
  142. package/dist/custom/parse.js.map +1 -0
  143. package/dist/custom/problems.d.ts +5 -0
  144. package/dist/custom/problems.d.ts.map +1 -0
  145. package/dist/custom/problems.js +78 -0
  146. package/dist/custom/problems.js.map +1 -0
  147. package/dist/custom/regex-safety.d.ts +11 -0
  148. package/dist/custom/regex-safety.d.ts.map +1 -0
  149. package/dist/custom/regex-safety.js +110 -0
  150. package/dist/custom/regex-safety.js.map +1 -0
  151. package/dist/custom/token-pattern.d.ts +8 -0
  152. package/dist/custom/token-pattern.d.ts.map +1 -0
  153. package/dist/custom/token-pattern.js +75 -0
  154. package/dist/custom/token-pattern.js.map +1 -0
  155. package/dist/detect.d.ts.map +1 -1
  156. package/dist/detect.js +24 -2
  157. package/dist/detect.js.map +1 -1
  158. package/dist/detectors/acronym-context.d.ts +2 -0
  159. package/dist/detectors/acronym-context.d.ts.map +1 -1
  160. package/dist/detectors/acronym-context.js +12 -4
  161. package/dist/detectors/acronym-context.js.map +1 -1
  162. package/dist/detectors/ai-phrasing.d.ts +20 -0
  163. package/dist/detectors/ai-phrasing.d.ts.map +1 -0
  164. package/dist/detectors/ai-phrasing.js +112 -0
  165. package/dist/detectors/ai-phrasing.js.map +1 -0
  166. package/dist/detectors/announced-count.d.ts +4 -0
  167. package/dist/detectors/announced-count.d.ts.map +1 -0
  168. package/dist/detectors/announced-count.js +20 -0
  169. package/dist/detectors/announced-count.js.map +1 -0
  170. package/dist/detectors/broken-link.d.ts +17 -0
  171. package/dist/detectors/broken-link.d.ts.map +1 -0
  172. package/dist/detectors/broken-link.js +66 -0
  173. package/dist/detectors/broken-link.js.map +1 -0
  174. package/dist/detectors/cited-name.d.ts.map +1 -1
  175. package/dist/detectors/cited-name.js +4 -4
  176. package/dist/detectors/cited-name.js.map +1 -1
  177. package/dist/detectors/cited-title.d.ts +11 -0
  178. package/dist/detectors/cited-title.d.ts.map +1 -0
  179. package/dist/detectors/cited-title.js +75 -0
  180. package/dist/detectors/cited-title.js.map +1 -0
  181. package/dist/detectors/concrete-evidence.d.ts +1 -1
  182. package/dist/detectors/concrete-evidence.d.ts.map +1 -1
  183. package/dist/detectors/concrete-evidence.js +2 -1
  184. package/dist/detectors/concrete-evidence.js.map +1 -1
  185. package/dist/detectors/contrast-frame.d.ts +17 -0
  186. package/dist/detectors/contrast-frame.d.ts.map +1 -0
  187. package/dist/detectors/contrast-frame.js +32 -0
  188. package/dist/detectors/contrast-frame.js.map +1 -0
  189. package/dist/detectors/custom.d.ts +8 -0
  190. package/dist/detectors/custom.d.ts.map +1 -0
  191. package/dist/detectors/custom.js +71 -0
  192. package/dist/detectors/custom.js.map +1 -0
  193. package/dist/detectors/dangling-figure.d.ts +4 -0
  194. package/dist/detectors/dangling-figure.d.ts.map +1 -0
  195. package/dist/detectors/dangling-figure.js +18 -0
  196. package/dist/detectors/dangling-figure.js.map +1 -0
  197. package/dist/detectors/doubled-punctuation.d.ts +9 -0
  198. package/dist/detectors/doubled-punctuation.d.ts.map +1 -0
  199. package/dist/detectors/doubled-punctuation.js +33 -0
  200. package/dist/detectors/doubled-punctuation.js.map +1 -0
  201. package/dist/detectors/doubled-word.d.ts +5 -0
  202. package/dist/detectors/doubled-word.d.ts.map +1 -1
  203. package/dist/detectors/doubled-word.js +24 -11
  204. package/dist/detectors/doubled-word.js.map +1 -1
  205. package/dist/detectors/enumerated-runs.d.ts +1 -1
  206. package/dist/detectors/enumerated-runs.d.ts.map +1 -1
  207. package/dist/detectors/enumerated-runs.js +15 -4
  208. package/dist/detectors/enumerated-runs.js.map +1 -1
  209. package/dist/detectors/gram-furniture.d.ts +6 -0
  210. package/dist/detectors/gram-furniture.d.ts.map +1 -0
  211. package/dist/detectors/gram-furniture.js +21 -0
  212. package/dist/detectors/gram-furniture.js.map +1 -0
  213. package/dist/detectors/gram-place.d.ts +2 -0
  214. package/dist/detectors/gram-place.d.ts.map +1 -1
  215. package/dist/detectors/gram-place.js +9 -7
  216. package/dist/detectors/gram-place.js.map +1 -1
  217. package/dist/detectors/gram-windows.d.ts +9 -0
  218. package/dist/detectors/gram-windows.d.ts.map +1 -0
  219. package/dist/detectors/gram-windows.js +27 -0
  220. package/dist/detectors/gram-windows.js.map +1 -0
  221. package/dist/detectors/heading-case.d.ts +2 -0
  222. package/dist/detectors/heading-case.d.ts.map +1 -1
  223. package/dist/detectors/heading-case.js +29 -2
  224. package/dist/detectors/heading-case.js.map +1 -1
  225. package/dist/detectors/heading-code-words.d.ts +6 -0
  226. package/dist/detectors/heading-code-words.d.ts.map +1 -0
  227. package/dist/detectors/heading-code-words.js +29 -0
  228. package/dist/detectors/heading-code-words.js.map +1 -0
  229. package/dist/detectors/heading-echo.d.ts.map +1 -1
  230. package/dist/detectors/heading-echo.js +7 -4
  231. package/dist/detectors/heading-echo.js.map +1 -1
  232. package/dist/detectors/heading-level-skip.d.ts +12 -0
  233. package/dist/detectors/heading-level-skip.d.ts.map +1 -0
  234. package/dist/detectors/heading-level-skip.js +11 -0
  235. package/dist/detectors/heading-level-skip.js.map +1 -0
  236. package/dist/detectors/image-alt-text.d.ts +3 -0
  237. package/dist/detectors/image-alt-text.d.ts.map +1 -0
  238. package/dist/detectors/image-alt-text.js +9 -0
  239. package/dist/detectors/image-alt-text.js.map +1 -0
  240. package/dist/detectors/index.d.ts.map +1 -1
  241. package/dist/detectors/index.js +34 -1
  242. package/dist/detectors/index.js.map +1 -1
  243. package/dist/detectors/kutoten-consistency.d.ts +24 -0
  244. package/dist/detectors/kutoten-consistency.d.ts.map +1 -0
  245. package/dist/detectors/kutoten-consistency.js +77 -0
  246. package/dist/detectors/kutoten-consistency.js.map +1 -0
  247. package/dist/detectors/lead-in.d.ts +1 -0
  248. package/dist/detectors/lead-in.d.ts.map +1 -1
  249. package/dist/detectors/lead-in.js +2 -1
  250. package/dist/detectors/lead-in.js.map +1 -1
  251. package/dist/detectors/lexicon-match.d.ts +4 -0
  252. package/dist/detectors/lexicon-match.d.ts.map +1 -1
  253. package/dist/detectors/lexicon-match.js +7 -2
  254. package/dist/detectors/lexicon-match.js.map +1 -1
  255. package/dist/detectors/list-item.d.ts +45 -0
  256. package/dist/detectors/list-item.d.ts.map +1 -0
  257. package/dist/detectors/list-item.js +88 -0
  258. package/dist/detectors/list-item.js.map +1 -0
  259. package/dist/detectors/list-items.d.ts +31 -0
  260. package/dist/detectors/list-items.d.ts.map +1 -0
  261. package/dist/detectors/list-items.js +113 -0
  262. package/dist/detectors/list-items.js.map +1 -0
  263. package/dist/detectors/list-lead-in.d.ts +7 -0
  264. package/dist/detectors/list-lead-in.d.ts.map +1 -0
  265. package/dist/detectors/list-lead-in.js +28 -0
  266. package/dist/detectors/list-lead-in.js.map +1 -0
  267. package/dist/detectors/list-sentence.d.ts +65 -0
  268. package/dist/detectors/list-sentence.d.ts.map +1 -0
  269. package/dist/detectors/list-sentence.js +105 -0
  270. package/dist/detectors/list-sentence.js.map +1 -0
  271. package/dist/detectors/list-view.d.ts +34 -0
  272. package/dist/detectors/list-view.d.ts.map +1 -0
  273. package/dist/detectors/list-view.js +137 -0
  274. package/dist/detectors/list-view.js.map +1 -0
  275. package/dist/detectors/long-vowel.d.ts +7 -0
  276. package/dist/detectors/long-vowel.d.ts.map +1 -0
  277. package/dist/detectors/long-vowel.js +57 -0
  278. package/dist/detectors/long-vowel.js.map +1 -0
  279. package/dist/detectors/markup-finding.d.ts +6 -0
  280. package/dist/detectors/markup-finding.d.ts.map +1 -0
  281. package/dist/detectors/markup-finding.js +19 -0
  282. package/dist/detectors/markup-finding.js.map +1 -0
  283. package/dist/detectors/name-numeral.d.ts +1 -1
  284. package/dist/detectors/name-numeral.d.ts.map +1 -1
  285. package/dist/detectors/name-numeral.js +2 -7
  286. package/dist/detectors/name-numeral.js.map +1 -1
  287. package/dist/detectors/orthography.d.ts.map +1 -1
  288. package/dist/detectors/orthography.js +14 -10
  289. package/dist/detectors/orthography.js.map +1 -1
  290. package/dist/detectors/oxford-comma.d.ts +7 -1
  291. package/dist/detectors/oxford-comma.d.ts.map +1 -1
  292. package/dist/detectors/oxford-comma.js +135 -229
  293. package/dist/detectors/oxford-comma.js.map +1 -1
  294. package/dist/detectors/place-run.d.ts.map +1 -1
  295. package/dist/detectors/place-run.js +10 -6
  296. package/dist/detectors/place-run.js.map +1 -1
  297. package/dist/detectors/placeholder-text.d.ts +9 -0
  298. package/dist/detectors/placeholder-text.d.ts.map +1 -0
  299. package/dist/detectors/placeholder-text.js +18 -0
  300. package/dist/detectors/placeholder-text.js.map +1 -0
  301. package/dist/detectors/quote-around.d.ts +3 -0
  302. package/dist/detectors/quote-around.d.ts.map +1 -0
  303. package/dist/detectors/quote-around.js +8 -0
  304. package/dist/detectors/quote-around.js.map +1 -0
  305. package/dist/detectors/register.d.ts +11 -3
  306. package/dist/detectors/register.d.ts.map +1 -1
  307. package/dist/detectors/register.js +28 -9
  308. package/dist/detectors/register.js.map +1 -1
  309. package/dist/detectors/roman-numeral.d.ts +2 -0
  310. package/dist/detectors/roman-numeral.d.ts.map +1 -1
  311. package/dist/detectors/roman-numeral.js +2 -0
  312. package/dist/detectors/roman-numeral.js.map +1 -1
  313. package/dist/detectors/sentence-ending.d.ts +17 -1
  314. package/dist/detectors/sentence-ending.d.ts.map +1 -1
  315. package/dist/detectors/sentence-ending.js +13 -7
  316. package/dist/detectors/sentence-ending.js.map +1 -1
  317. package/dist/detectors/sentence-length.d.ts.map +1 -1
  318. package/dist/detectors/sentence-length.js +13 -4
  319. package/dist/detectors/sentence-length.js.map +1 -1
  320. package/dist/detectors/signals.d.ts +8 -0
  321. package/dist/detectors/signals.d.ts.map +1 -1
  322. package/dist/detectors/signals.js +67 -46
  323. package/dist/detectors/signals.js.map +1 -1
  324. package/dist/detectors/structure-tree.d.ts +6 -0
  325. package/dist/detectors/structure-tree.d.ts.map +1 -1
  326. package/dist/detectors/structure-tree.js +37 -1
  327. package/dist/detectors/structure-tree.js.map +1 -1
  328. package/dist/detectors/structure.d.ts +1 -3
  329. package/dist/detectors/structure.d.ts.map +1 -1
  330. package/dist/detectors/structure.js +3 -4
  331. package/dist/detectors/structure.js.map +1 -1
  332. package/dist/detectors/superlative-name.d.ts.map +1 -1
  333. package/dist/detectors/superlative-name.js +8 -5
  334. package/dist/detectors/superlative-name.js.map +1 -1
  335. package/dist/detectors/superlative-scope.d.ts.map +1 -1
  336. package/dist/detectors/superlative-scope.js +9 -4
  337. package/dist/detectors/superlative-scope.js.map +1 -1
  338. package/dist/detectors/token-column.d.ts +46 -0
  339. package/dist/detectors/token-column.d.ts.map +1 -0
  340. package/dist/detectors/token-column.js +95 -0
  341. package/dist/detectors/token-column.js.map +1 -0
  342. package/dist/detectors/unbalanced-bracket.d.ts +22 -0
  343. package/dist/detectors/unbalanced-bracket.d.ts.map +1 -0
  344. package/dist/detectors/unbalanced-bracket.js +119 -0
  345. package/dist/detectors/unbalanced-bracket.js.map +1 -0
  346. package/dist/detectors/url-run-on.d.ts +9 -0
  347. package/dist/detectors/url-run-on.d.ts.map +1 -0
  348. package/dist/detectors/url-run-on.js +19 -0
  349. package/dist/detectors/url-run-on.js.map +1 -0
  350. package/dist/document-sections.d.ts +13 -0
  351. package/dist/document-sections.d.ts.map +1 -0
  352. package/dist/document-sections.js +32 -0
  353. package/dist/document-sections.js.map +1 -0
  354. package/dist/document.d.ts +11 -4
  355. package/dist/document.d.ts.map +1 -1
  356. package/dist/document.js +90 -98
  357. package/dist/document.js.map +1 -1
  358. package/dist/email-parts.d.ts +28 -0
  359. package/dist/email-parts.d.ts.map +1 -0
  360. package/dist/email-parts.js +230 -0
  361. package/dist/email-parts.js.map +1 -0
  362. package/dist/eval.d.ts +2 -1
  363. package/dist/eval.d.ts.map +1 -1
  364. package/dist/eval.js +16 -4
  365. package/dist/eval.js.map +1 -1
  366. package/dist/figure-references.d.ts +30 -0
  367. package/dist/figure-references.d.ts.map +1 -0
  368. package/dist/figure-references.js +76 -0
  369. package/dist/figure-references.js.map +1 -0
  370. package/dist/files.d.ts +2 -0
  371. package/dist/files.d.ts.map +1 -1
  372. package/dist/files.js +4 -0
  373. package/dist/files.js.map +1 -1
  374. package/dist/heading-label.d.ts +22 -0
  375. package/dist/heading-label.d.ts.map +1 -0
  376. package/dist/heading-label.js +50 -0
  377. package/dist/heading-label.js.map +1 -0
  378. package/dist/in-page-nav.d.ts +4 -1
  379. package/dist/in-page-nav.d.ts.map +1 -1
  380. package/dist/in-page-nav.js +53 -18
  381. package/dist/in-page-nav.js.map +1 -1
  382. package/dist/joined-view.d.ts.map +1 -1
  383. package/dist/joined-view.js +1 -0
  384. package/dist/joined-view.js.map +1 -1
  385. package/dist/levels.d.ts +5 -1
  386. package/dist/levels.d.ts.map +1 -1
  387. package/dist/levels.js +9 -0
  388. package/dist/levels.js.map +1 -1
  389. package/dist/line-paragraphs.d.ts +8 -0
  390. package/dist/line-paragraphs.d.ts.map +1 -1
  391. package/dist/line-paragraphs.js +33 -10
  392. package/dist/line-paragraphs.js.map +1 -1
  393. package/dist/long-vowel.d.ts +35 -0
  394. package/dist/long-vowel.d.ts.map +1 -0
  395. package/dist/long-vowel.js +71 -0
  396. package/dist/long-vowel.js.map +1 -0
  397. package/dist/markdown-node.d.ts +19 -0
  398. package/dist/markdown-node.d.ts.map +1 -0
  399. package/dist/markdown-node.js +6 -0
  400. package/dist/markdown-node.js.map +1 -0
  401. package/dist/markdown-read.d.ts +17 -0
  402. package/dist/markdown-read.d.ts.map +1 -0
  403. package/dist/markdown-read.js +37 -0
  404. package/dist/markdown-read.js.map +1 -0
  405. package/dist/markup.d.ts +22 -0
  406. package/dist/markup.d.ts.map +1 -0
  407. package/dist/markup.js +180 -0
  408. package/dist/markup.js.map +1 -0
  409. package/dist/mask.js +8 -5
  410. package/dist/mask.js.map +1 -1
  411. package/dist/number-name.d.ts +21 -5
  412. package/dist/number-name.d.ts.map +1 -1
  413. package/dist/number-name.js +119 -17
  414. package/dist/number-name.js.map +1 -1
  415. package/dist/orthography.d.ts +2 -0
  416. package/dist/orthography.d.ts.map +1 -1
  417. package/dist/orthography.js +9 -4
  418. package/dist/orthography.js.map +1 -1
  419. package/dist/page-furniture.d.ts +5 -2
  420. package/dist/page-furniture.d.ts.map +1 -1
  421. package/dist/page-furniture.js +8 -2
  422. package/dist/page-furniture.js.map +1 -1
  423. package/dist/plain-source.d.ts +1 -0
  424. package/dist/plain-source.d.ts.map +1 -1
  425. package/dist/plain-source.js +2 -1
  426. package/dist/plain-source.js.map +1 -1
  427. package/dist/plugin.d.ts +115 -0
  428. package/dist/plugin.d.ts.map +1 -1
  429. package/dist/profile/for-file.d.ts.map +1 -1
  430. package/dist/profile/for-file.js +3 -1
  431. package/dist/profile/for-file.js.map +1 -1
  432. package/dist/quoted-span.d.ts.map +1 -1
  433. package/dist/quoted-span.js +8 -3
  434. package/dist/quoted-span.js.map +1 -1
  435. package/dist/reasons.d.ts +3 -0
  436. package/dist/reasons.d.ts.map +1 -1
  437. package/dist/reasons.js +6 -0
  438. package/dist/reasons.js.map +1 -1
  439. package/dist/reference-lists.d.ts +3 -0
  440. package/dist/reference-lists.d.ts.map +1 -0
  441. package/dist/reference-lists.js +75 -0
  442. package/dist/reference-lists.js.map +1 -0
  443. package/dist/render/explain.d.ts +7 -1
  444. package/dist/render/explain.d.ts.map +1 -1
  445. package/dist/render/explain.js +36 -12
  446. package/dist/render/explain.js.map +1 -1
  447. package/dist/render/friendly.d.ts.map +1 -1
  448. package/dist/render/friendly.js +19 -9
  449. package/dist/render/friendly.js.map +1 -1
  450. package/dist/render/options.d.ts +7 -0
  451. package/dist/render/options.d.ts.map +1 -0
  452. package/dist/render/options.js +50 -0
  453. package/dist/render/options.js.map +1 -0
  454. package/dist/render/rules-json.d.ts +4 -1
  455. package/dist/render/rules-json.d.ts.map +1 -1
  456. package/dist/render/rules-json.js +102 -12
  457. package/dist/render/rules-json.js.map +1 -1
  458. package/dist/render/rules-table.d.ts +4 -0
  459. package/dist/render/rules-table.d.ts.map +1 -0
  460. package/dist/render/rules-table.js +70 -0
  461. package/dist/render/rules-table.js.map +1 -0
  462. package/dist/render/sarif.js +4 -4
  463. package/dist/render/sarif.js.map +1 -1
  464. package/dist/render/semantic.js +3 -3
  465. package/dist/render/semantic.js.map +1 -1
  466. package/dist/render/severity-name.d.ts +6 -0
  467. package/dist/render/severity-name.d.ts.map +1 -0
  468. package/dist/render/severity-name.js +7 -0
  469. package/dist/render/severity-name.js.map +1 -0
  470. package/dist/render/text.d.ts +7 -2
  471. package/dist/render/text.d.ts.map +1 -1
  472. package/dist/render/text.js +15 -4
  473. package/dist/render/text.js.map +1 -1
  474. package/dist/resolve-genre.d.ts +1 -1
  475. package/dist/resolve-genre.d.ts.map +1 -1
  476. package/dist/resolve-genre.js +4 -1
  477. package/dist/resolve-genre.js.map +1 -1
  478. package/dist/rule-genres.d.ts +24 -0
  479. package/dist/rule-genres.d.ts.map +1 -0
  480. package/dist/rule-genres.js +11 -0
  481. package/dist/rule-genres.js.map +1 -0
  482. package/dist/rule-guide.d.ts +54 -0
  483. package/dist/rule-guide.d.ts.map +1 -0
  484. package/dist/rule-guide.js +81 -0
  485. package/dist/rule-guide.js.map +1 -0
  486. package/dist/rule-load.d.ts.map +1 -1
  487. package/dist/rule-load.js +87 -33
  488. package/dist/rule-load.js.map +1 -1
  489. package/dist/rule-options.d.ts +50 -0
  490. package/dist/rule-options.d.ts.map +1 -0
  491. package/dist/rule-options.js +106 -0
  492. package/dist/rule-options.js.map +1 -0
  493. package/dist/run.d.ts +13 -0
  494. package/dist/run.d.ts.map +1 -1
  495. package/dist/run.js +54 -10
  496. package/dist/run.js.map +1 -1
  497. package/dist/sentence-shape.d.ts.map +1 -1
  498. package/dist/sentence-shape.js +4 -4
  499. package/dist/sentence-shape.js.map +1 -1
  500. package/dist/setting-problems.d.ts +2 -1
  501. package/dist/setting-problems.d.ts.map +1 -1
  502. package/dist/setting-problems.js +6 -1
  503. package/dist/setting-problems.js.map +1 -1
  504. package/dist/span-cut.d.ts +6 -0
  505. package/dist/span-cut.d.ts.map +1 -0
  506. package/dist/span-cut.js +22 -0
  507. package/dist/span-cut.js.map +1 -0
  508. package/dist/structure/aside-depth.d.ts +21 -0
  509. package/dist/structure/aside-depth.d.ts.map +1 -0
  510. package/dist/structure/aside-depth.js +65 -0
  511. package/dist/structure/aside-depth.js.map +1 -0
  512. package/dist/structure/build.d.ts +5 -1
  513. package/dist/structure/build.d.ts.map +1 -1
  514. package/dist/structure/build.js +29 -17
  515. package/dist/structure/build.js.map +1 -1
  516. package/dist/structure/closed-pairs.d.ts +8 -0
  517. package/dist/structure/closed-pairs.d.ts.map +1 -0
  518. package/dist/structure/closed-pairs.js +22 -0
  519. package/dist/structure/closed-pairs.js.map +1 -0
  520. package/dist/structure/date-range.d.ts +21 -0
  521. package/dist/structure/date-range.d.ts.map +1 -0
  522. package/dist/structure/date-range.js +45 -0
  523. package/dist/structure/date-range.js.map +1 -0
  524. package/dist/structure/known-mentions.d.ts +18 -0
  525. package/dist/structure/known-mentions.d.ts.map +1 -0
  526. package/dist/structure/known-mentions.js +78 -0
  527. package/dist/structure/known-mentions.js.map +1 -0
  528. package/dist/structure/numbering.d.ts +1 -0
  529. package/dist/structure/numbering.d.ts.map +1 -1
  530. package/dist/structure/numbering.js +11 -6
  531. package/dist/structure/numbering.js.map +1 -1
  532. package/dist/structure/of.d.ts +3 -1
  533. package/dist/structure/of.d.ts.map +1 -1
  534. package/dist/structure/of.js +5 -1
  535. package/dist/structure/of.js.map +1 -1
  536. package/dist/structure/percent-sum.d.ts +16 -0
  537. package/dist/structure/percent-sum.d.ts.map +1 -0
  538. package/dist/structure/percent-sum.js +104 -0
  539. package/dist/structure/percent-sum.js.map +1 -0
  540. package/dist/structure/quoted-number.d.ts +8 -0
  541. package/dist/structure/quoted-number.d.ts.map +1 -0
  542. package/dist/structure/quoted-number.js +34 -0
  543. package/dist/structure/quoted-number.js.map +1 -0
  544. package/dist/structure/relative-find.d.ts.map +1 -1
  545. package/dist/structure/relative-find.js +34 -46
  546. package/dist/structure/relative-find.js.map +1 -1
  547. package/dist/structure/relative-resolve.d.ts.map +1 -1
  548. package/dist/structure/relative-resolve.js +76 -30
  549. package/dist/structure/relative-resolve.js.map +1 -1
  550. package/dist/structure/runs.d.ts +2 -0
  551. package/dist/structure/runs.d.ts.map +1 -1
  552. package/dist/structure/runs.js +2 -2
  553. package/dist/structure/runs.js.map +1 -1
  554. package/dist/structure/sexp.d.ts +1 -1
  555. package/dist/structure/sexp.d.ts.map +1 -1
  556. package/dist/structure/sexp.js +18 -6
  557. package/dist/structure/sexp.js.map +1 -1
  558. package/dist/structure/total.d.ts +3 -0
  559. package/dist/structure/total.d.ts.map +1 -1
  560. package/dist/structure/total.js +2 -2
  561. package/dist/structure/total.js.map +1 -1
  562. package/dist/structure/universal.d.ts +14 -2
  563. package/dist/structure/universal.d.ts.map +1 -1
  564. package/dist/structure/universal.js +17 -2
  565. package/dist/structure/universal.js.map +1 -1
  566. package/dist/structure/wrapped-tail.d.ts +14 -7
  567. package/dist/structure/wrapped-tail.d.ts.map +1 -1
  568. package/dist/structure/wrapped-tail.js +33 -8
  569. package/dist/structure/wrapped-tail.js.map +1 -1
  570. package/dist/style-load.d.ts +4 -0
  571. package/dist/style-load.d.ts.map +1 -0
  572. package/dist/style-load.js +28 -0
  573. package/dist/style-load.js.map +1 -0
  574. package/dist/style-parse.d.ts +19 -0
  575. package/dist/style-parse.d.ts.map +1 -0
  576. package/dist/style-parse.js +60 -0
  577. package/dist/style-parse.js.map +1 -0
  578. package/dist/subheading-line.d.ts +6 -0
  579. package/dist/subheading-line.d.ts.map +1 -0
  580. package/dist/subheading-line.js +57 -0
  581. package/dist/subheading-line.js.map +1 -0
  582. package/dist/template-syntax.d.ts +17 -0
  583. package/dist/template-syntax.d.ts.map +1 -0
  584. package/dist/template-syntax.js +140 -0
  585. package/dist/template-syntax.js.map +1 -0
  586. package/dist/text-above.d.ts +19 -0
  587. package/dist/text-above.d.ts.map +1 -0
  588. package/dist/text-above.js +43 -0
  589. package/dist/text-above.js.map +1 -0
  590. package/dist/text-figures.d.ts +10 -0
  591. package/dist/text-figures.d.ts.map +1 -0
  592. package/dist/text-figures.js +131 -0
  593. package/dist/text-figures.js.map +1 -0
  594. package/dist/trailing-aside.d.ts +2 -0
  595. package/dist/trailing-aside.d.ts.map +1 -0
  596. package/dist/trailing-aside.js +53 -0
  597. package/dist/trailing-aside.js.map +1 -0
  598. package/dist/tree-walk.d.ts +18 -0
  599. package/dist/tree-walk.d.ts.map +1 -0
  600. package/dist/tree-walk.js +45 -0
  601. package/dist/tree-walk.js.map +1 -0
  602. package/genres.yaml +26 -0
  603. package/package.json +5 -3
  604. package/reference-headings.yaml +17 -0
  605. package/rules/adverb-overuse.yaml +19 -0
  606. package/rules/agentless-passive.yaml +19 -0
  607. package/rules/agreement-slip.yaml +14 -1
  608. package/rules/ai-generated-composite.yaml +102 -0
  609. package/rules/ai-tell.yaml +23 -0
  610. package/rules/announced-count-mismatch.yaml +57 -0
  611. package/rules/announcing-opener.yaml +51 -0
  612. package/rules/assistant-residue.yaml +52 -0
  613. package/rules/bold-density.yaml +31 -0
  614. package/rules/broken-link.yaml +65 -0
  615. package/rules/closing-cliche.yaml +33 -0
  616. package/rules/colon-lead-in.yaml +59 -0
  617. package/rules/concrete-evidence-density.yaml +41 -0
  618. package/rules/contraction-consistency.yaml +18 -0
  619. package/rules/contrast-framing.yaml +57 -0
  620. package/rules/cushion-phrase-density.yaml +25 -0
  621. package/rules/dangling-figure-reference.yaml +61 -0
  622. package/rules/dangling-reference.yaml +53 -1
  623. package/rules/date-order.yaml +33 -1
  624. package/rules/date-range-reversed.yaml +46 -0
  625. package/rules/date-weekday-mismatch.yaml +17 -1
  626. package/rules/double-keigo.yaml +16 -0
  627. package/rules/doubled-punctuation.yaml +45 -0
  628. package/rules/doubled-word.yaml +17 -1
  629. package/rules/duplicate-definition.yaml +59 -1
  630. package/rules/emoji-density.yaml +25 -0
  631. package/rules/empty-conclusion.yaml +28 -0
  632. package/rules/empty-intensifier.yaml +19 -0
  633. package/rules/excessive-hedging.yaml +19 -0
  634. package/rules/expletive-construction.yaml +19 -0
  635. package/rules/heading-echo.yaml +31 -0
  636. package/rules/heading-level-skip.yaml +78 -0
  637. package/rules/hiragana-fukushi.yaml +16 -0
  638. package/rules/image-alt-text.yaml +54 -0
  639. package/rules/internal-jargon.yaml +21 -0
  640. package/rules/katakana-long-vowel.yaml +98 -0
  641. package/rules/kutoten-consistency.yaml +53 -0
  642. package/rules/latin-spacing.yaml +23 -4
  643. package/rules/max-kanji-continuous.yaml +16 -0
  644. package/rules/max-paragraph-length.yaml +33 -0
  645. package/rules/max-sentence-length.yaml +32 -0
  646. package/rules/ngram-repetition.yaml +29 -2
  647. package/rules/no-doubled-joshi.yaml +16 -0
  648. package/rules/no-em-dash.yaml +25 -0
  649. package/rules/no-mixed-desumasu.yaml +27 -2
  650. package/rules/no-nakaguro-parallel.yaml +20 -0
  651. package/rules/numbering-gap.yaml +53 -1
  652. package/rules/oxford-comma-consistency.yaml +18 -0
  653. package/rules/padded-intro.yaml +19 -0
  654. package/rules/paragraph-length-variance.yaml +49 -0
  655. package/rules/percent-sum-mismatch.yaml +58 -0
  656. package/rules/preamble-length.yaml +56 -0
  657. package/rules/preferred-term.yaml +27 -0
  658. package/rules/proper-noun-density.yaml +26 -0
  659. package/rules/repeated-conjunction.yaml +47 -0
  660. package/rules/repeated-sentence-head.yaml +23 -0
  661. package/rules/required-sections.yaml +49 -0
  662. package/rules/risk-disclosure.yaml +22 -0
  663. package/rules/rule-of-three.yaml +97 -0
  664. package/rules/sasete-itadaku.yaml +18 -0
  665. package/rules/section-length-uniformity.yaml +89 -0
  666. package/rules/sentence-initial-conjunction-run.yaml +18 -0
  667. package/rules/sentence-rhythm.yaml +25 -0
  668. package/rules/stock-transition.yaml +55 -0
  669. package/rules/stray-space.yaml +18 -0
  670. package/rules/taigen-dome-in-prose.yaml +19 -0
  671. package/rules/title-case-consistency.yaml +42 -0
  672. package/rules/total-mismatch.yaml +37 -1
  673. package/rules/unbalanced-bracket.yaml +56 -0
  674. package/rules/undefined-acronym.yaml +22 -0
  675. package/rules/unfilled-placeholder.yaml +50 -0
  676. package/rules/unqualified-superlative.yaml +19 -0
  677. package/rules/unsourced-number.yaml +16 -0
  678. package/rules/url-run-on.yaml +45 -0
  679. package/skills/chaff/SKILL.md +70 -0
  680. package/src/announced-count.ts +148 -0
  681. package/src/bare-url.ts +35 -0
  682. package/src/baseline.ts +17 -1
  683. package/src/body-section.ts +7 -0
  684. package/src/calendar-number.ts +18 -4
  685. package/src/cli-args.ts +6 -0
  686. package/src/cli-text.ts +8 -4
  687. package/src/cli.ts +37 -37
  688. package/src/commands/compare.ts +80 -0
  689. package/src/commands/eval.ts +19 -8
  690. package/src/commands/feedback.ts +12 -6
  691. package/src/commands/test.ts +2 -4
  692. package/src/commands/tree.ts +41 -5
  693. package/src/compare/atom.ts +33 -0
  694. package/src/compare/clock-time.ts +86 -0
  695. package/src/compare/extract.ts +78 -0
  696. package/src/compare/fact-text.ts +68 -0
  697. package/src/compare/markup-atoms.ts +29 -0
  698. package/src/compare/match.ts +105 -0
  699. package/src/compare/outcome.ts +70 -0
  700. package/src/compare/proper-nouns.ts +65 -0
  701. package/src/compare/render.ts +102 -0
  702. package/src/compare/spans.ts +17 -0
  703. package/src/compare/text-atoms.ts +95 -0
  704. package/src/compare/text.ts +120 -0
  705. package/src/compare/tree-atoms.ts +80 -0
  706. package/src/compare/written-names.ts +26 -0
  707. package/src/config/load.ts +21 -0
  708. package/src/config/option-problems.ts +70 -0
  709. package/src/config/read.ts +8 -0
  710. package/src/config/rule-problems.ts +12 -2
  711. package/src/config/style.ts +42 -0
  712. package/src/config/warnings.ts +13 -0
  713. package/src/config/write.ts +18 -4
  714. package/src/custom/bounded-match.ts +58 -0
  715. package/src/custom/load.ts +15 -0
  716. package/src/custom/parse.ts +274 -0
  717. package/src/custom/problems.ts +89 -0
  718. package/src/custom/regex-safety.ts +118 -0
  719. package/src/custom/token-pattern.ts +84 -0
  720. package/src/detect.ts +28 -2
  721. package/src/detectors/acronym-context.ts +16 -4
  722. package/src/detectors/ai-phrasing.ts +137 -0
  723. package/src/detectors/announced-count.ts +25 -0
  724. package/src/detectors/broken-link.ts +90 -0
  725. package/src/detectors/cited-name.ts +6 -5
  726. package/src/detectors/cited-title.ts +96 -0
  727. package/src/detectors/concrete-evidence.ts +3 -2
  728. package/src/detectors/contrast-frame.ts +54 -0
  729. package/src/detectors/custom.ts +89 -0
  730. package/src/detectors/dangling-figure.ts +22 -0
  731. package/src/detectors/doubled-punctuation.ts +49 -0
  732. package/src/detectors/doubled-word.ts +19 -4
  733. package/src/detectors/enumerated-runs.ts +13 -4
  734. package/src/detectors/gram-furniture.ts +30 -0
  735. package/src/detectors/gram-place.ts +9 -5
  736. package/src/detectors/gram-windows.ts +31 -0
  737. package/src/detectors/heading-case.ts +30 -2
  738. package/src/detectors/heading-code-words.ts +35 -0
  739. package/src/detectors/heading-echo.ts +8 -4
  740. package/src/detectors/heading-level-skip.ts +19 -0
  741. package/src/detectors/image-alt-text.ts +11 -0
  742. package/src/detectors/index.ts +43 -1
  743. package/src/detectors/kutoten-consistency.ts +96 -0
  744. package/src/detectors/lead-in.ts +3 -1
  745. package/src/detectors/lexicon-match.ts +9 -2
  746. package/src/detectors/list-item.ts +122 -0
  747. package/src/detectors/list-items.ts +163 -0
  748. package/src/detectors/list-lead-in.ts +33 -0
  749. package/src/detectors/list-sentence.ts +157 -0
  750. package/src/detectors/list-view.ts +157 -0
  751. package/src/detectors/long-vowel.ts +66 -0
  752. package/src/detectors/markup-finding.ts +24 -0
  753. package/src/detectors/name-numeral.ts +4 -2
  754. package/src/detectors/orthography.ts +23 -17
  755. package/src/detectors/oxford-comma.ts +178 -283
  756. package/src/detectors/place-run.ts +7 -4
  757. package/src/detectors/placeholder-text.ts +27 -0
  758. package/src/detectors/quote-around.ts +9 -0
  759. package/src/detectors/register.ts +37 -10
  760. package/src/detectors/roman-numeral.ts +3 -0
  761. package/src/detectors/sentence-ending.ts +14 -7
  762. package/src/detectors/sentence-length.ts +16 -5
  763. package/src/detectors/signals.ts +80 -46
  764. package/src/detectors/structure-tree.ts +45 -1
  765. package/src/detectors/structure.ts +3 -4
  766. package/src/detectors/superlative-name.ts +7 -4
  767. package/src/detectors/superlative-scope.ts +8 -3
  768. package/src/detectors/token-column.ts +149 -0
  769. package/src/detectors/unbalanced-bracket.ts +153 -0
  770. package/src/detectors/url-run-on.ts +27 -0
  771. package/src/document-sections.ts +46 -0
  772. package/src/document.ts +106 -138
  773. package/src/email-parts.ts +269 -0
  774. package/src/eval.ts +14 -4
  775. package/src/figure-references.ts +112 -0
  776. package/src/files.ts +5 -0
  777. package/src/heading-label.ts +55 -0
  778. package/src/in-page-nav.ts +48 -19
  779. package/src/joined-view.ts +1 -0
  780. package/src/levels.ts +14 -1
  781. package/src/line-paragraphs.ts +52 -9
  782. package/src/long-vowel.ts +99 -0
  783. package/src/markdown-node.ts +19 -0
  784. package/src/markdown-read.ts +44 -0
  785. package/src/markup.ts +210 -0
  786. package/src/mask.ts +8 -8
  787. package/src/number-name.ts +151 -24
  788. package/src/orthography.ts +10 -3
  789. package/src/page-furniture.ts +11 -2
  790. package/src/plain-source.ts +2 -1
  791. package/src/plugin.ts +101 -1
  792. package/src/profile/for-file.ts +3 -1
  793. package/src/quoted-span.ts +9 -3
  794. package/src/reasons.ts +9 -0
  795. package/src/reference-lists.ts +91 -0
  796. package/src/render/explain.ts +47 -13
  797. package/src/render/friendly.ts +20 -9
  798. package/src/render/options.ts +58 -0
  799. package/src/render/rules-json.ts +130 -14
  800. package/src/render/rules-table.ts +91 -0
  801. package/src/render/sarif.ts +4 -4
  802. package/src/render/semantic.ts +3 -3
  803. package/src/render/severity-name.ts +10 -0
  804. package/src/render/text.ts +21 -7
  805. package/src/resolve-genre.ts +4 -1
  806. package/src/rule-genres.ts +25 -0
  807. package/src/rule-guide.ts +135 -0
  808. package/src/rule-load.ts +91 -34
  809. package/src/rule-options.ts +131 -0
  810. package/src/run.ts +74 -11
  811. package/src/sentence-shape.ts +4 -5
  812. package/src/setting-problems.ts +7 -1
  813. package/src/span-cut.ts +28 -0
  814. package/src/structure/aside-depth.ts +67 -0
  815. package/src/structure/build.ts +38 -19
  816. package/src/structure/closed-pairs.ts +20 -0
  817. package/src/structure/date-range.ts +69 -0
  818. package/src/structure/known-mentions.ts +96 -0
  819. package/src/structure/numbering.ts +9 -5
  820. package/src/structure/of.ts +11 -3
  821. package/src/structure/percent-sum.ts +135 -0
  822. package/src/structure/quoted-number.ts +36 -0
  823. package/src/structure/relative-find.ts +34 -47
  824. package/src/structure/relative-resolve.ts +77 -30
  825. package/src/structure/runs.ts +2 -2
  826. package/src/structure/sexp.ts +17 -5
  827. package/src/structure/total.ts +2 -2
  828. package/src/structure/universal.ts +24 -4
  829. package/src/structure/wrapped-tail.ts +38 -13
  830. package/src/style-load.ts +28 -0
  831. package/src/style-parse.ts +77 -0
  832. package/src/subheading-line.ts +68 -0
  833. package/src/template-syntax.ts +164 -0
  834. package/src/text-above.ts +49 -0
  835. package/src/text-figures.ts +147 -0
  836. package/src/trailing-aside.ts +50 -0
  837. package/src/tree-walk.ts +48 -0
  838. package/styles/bunkacho.yaml +25 -0
  839. package/styles/ieice.yaml +29 -0
  840. package/styles/jis-z8301-2011.yaml +25 -0
@@ -61,6 +61,7 @@ relaxing a rule.
61
61
  existing one is left as it is), and adds `.chaff-cache/` and `.env*` to `.gitignore`.
62
62
  - `npx chaffjs rules --json [--genre <genre>]` prints every rule with its levels, the setting in effect (`now`,
63
63
  the genre's preset included) and why a rule is off. Read it instead of guessing rule names or limits.
64
+ `npx chaffjs rules` shows the same as a table, grouped, with the level each rule runs at now.
64
65
  - A level is `strict` / `normal` / `relaxed` / `off`; when even `relaxed` is too tight, a positive number is the
65
66
  limit itself (`max-sentence-length: 260`).
66
67
  - `prefer:` maps spellings to the team's (`e-mail: email`); `preferred-term: normal` turns the rule on.
@@ -68,6 +69,75 @@ relaxing a rule.
68
69
  - `genre:` sets the kind of document; `by_path` sets one per folder; `--genre` overrides both for one run.
69
70
  `rules:` wins over the genre's preset.
70
71
 
72
+ ## Turn a team's style note into chaff.yaml
73
+
74
+ When the person gives house rules ("polite endings, sentences of at most 80 characters"), do not guess rule
75
+ names or numbers:
76
+
77
+ 1. Read `npx chaffjs rules --json`. Each rule has `summary` (what it finds), `level_meaning` (what a level's
78
+ number means), `levels`, `example`, `not_flagged`, and `genres` (whether it runs in each genre).
79
+ 2. Split the note into single requirements; map each to the rule whose `summary` and `level_meaning` fit. A
80
+ number between levels is written as the number itself (`max-sentence-length: 80`). Spellings go under
81
+ `prefer`, in-house words under `jargon`, required headings under `required_sections`.
82
+ 3. Say plainly what no rule covers. For example, `no-mixed-desumasu` flags a register mixed into a document, but
83
+ does not require a particular one; a document wholly in the other register is not reported.
84
+ 4. Write only what differs from the default, then check before committing: `npx chaffjs explain <rule-id>`, a
85
+ short sample that breaks each requirement (each must be reported), and `npx chaffjs rules` (the table shows the
86
+ level each rule now runs at).
87
+
88
+ ## Adding a team rule
89
+
90
+ Pick the easiest way that can say the requirement:
91
+
92
+ | Requirement | Use |
93
+ | --- | --- |
94
+ | An existing rule covers it | A level, a number, `prefer`, `jargon` or `required_sections` in `chaff.yaml` |
95
+ | A fixed phrase or pattern, with the team's own message | `custom_rules` of type `words` or `pattern` (coming in the next release) |
96
+ | Decided by part of speech or inflection | `custom_rules` of type `tokens` (coming in the next release) |
97
+ | Counting or comparing that the above cannot express | a Node function, `type: module` (a later release) |
98
+
99
+ Test a new team rule the same way: `explain`, then a sample it must report and a sample it must not, before
100
+ committing `chaff.yaml`. The guide page "Adding a rule" covers each way and how to add a rule to chaff itself.
101
+
102
+ ## Making AI-sounding text sound human
103
+
104
+ chaff marks the shapes common in generated text (group "Signs of generated text" in `npx chaffjs rules`: `ai-tell`,
105
+ `contrast-framing`, `stock-transition`, `announcing-opener`, `colon-lead-in` (Japanese only), `assistant-residue`, and the signals
106
+ `ai-generated-composite` reads). Most are experimental: run with `--experimental`. None of them says the text was
107
+ generated. When asked to make a text sound less generated, pick one of two modes and say which.
108
+
109
+ **Light** (only the flagged spots), when the content and structure are fine:
110
+
111
+ 1. `npx chaffjs <file> --experimental` (or with the genre's `--genre`); collect the AI-shape findings.
112
+ 2. Rewrite only those spots. Keep the meaning, numbers, conditions and technical constraints.
113
+ 3. Run chaff again. At most two rewrite passes.
114
+ 4. Show the rewritten text and a short list of what changed and why.
115
+
116
+ **Bold** (section by section), when a light pass still leaves it reading as generated:
117
+
118
+ 1. Run chaff with `--experimental` and note the document-level signals: the `ai-generated-composite` inputs,
119
+ `bold-density`, `contrast-framing`, `stock-transition`, `sentence-rhythm`.
120
+ 2. Rewrite each section toward a human voice: less bold; one-line paragraphs and punchlines folded back into
121
+ paragraphs; no "X ではありません。Y です" / "It's not X. It's Y" frames; lists turned back into sentences where the
122
+ items connect; fewer em dashes; no announcing openers. Each paragraph carries one claim, joined to the last by a
123
+ connective, built around the writer's own experience or numbers where the original has them.
124
+ 3. Run chaff again and report the same signals before and after, from chaff's output.
125
+ 4. Run `npx chaffjs compare <old> <new>` (exit 1 on a dropped or added fact; `--json` to act on it). Restore every
126
+ dropped fact; for one that is not a fact (a number inside a metaphor, the heading of a section you cut), say why it
127
+ stays out. `--allow-dropped <kind>` excludes a kind you cut on purpose. Never leave an added fact.
128
+
129
+ In both modes:
130
+
131
+ - Never add facts, people, numbers or causes the original does not have.
132
+ - Keep a domain term a word rule trips when it is right in context.
133
+ - Prefer a direct statement over a negated contrast. Say who does what.
134
+ - Never loop just to silence a warning; two passes at most, and list what is left with the reason.
135
+ - Per genre: in a tech article, replace metaphors ("静かに壊れる", "silently fails") with what happens and keep steps
136
+ and commands as lists; in a business document, put the conclusion and who does what first and keep tables and
137
+ figures; in an essay, fold punchlines back in and replace big words ("真理", "new possibilities") with the scene.
138
+
139
+ The guide page "Making AI-sounding text sound human" has a worked example with chaff's output before and after.
140
+
71
141
  ## Structured documents
72
142
 
73
143
  - `npx chaffjs tree <file>` shows a contract or specification as a tree of addresses (`3.2` for 第3条第2項 or
@@ -0,0 +1,148 @@
1
+ import { escapeRegExp } from "./orthography.ts";
2
+ import type { BulletList, Span } from "./plugin.ts";
3
+ import { joined, linesAbove, type TextBlock } from "./text-above.ts";
4
+
5
+ /**
6
+ * 箇条書きのすぐ前の文が予告した数(以下の3点、the following three steps)と、箇条書きのいちばん外側の項目の数。
7
+ * 予告と読むのは、文の最後の一文に数がちょうど一つあり、先を指す語がその前にあるか文がコロンで終わるときだけ。
8
+ * 言語の知識(先を指す語、漢数字や数の語、数える語、数を目安や順番にする語)は語彙表から受け取る。
9
+ */
10
+ export type CountWords = {
11
+ /** 以下の、次の、following。 */
12
+ readonly anchors: readonly string[];
13
+ /** 数を字で書いたもの。一から順に並べる。 */
14
+ readonly numbers: readonly string[];
15
+ /** 数のすぐ後ろで並べるものを数える語。点、つ、steps。 */
16
+ readonly counters: readonly string[];
17
+ /** 数のすぐ前にあると予告でなくなる語(約、第、at least)。 */
18
+ readonly hedgesBefore: readonly string[];
19
+ /** 数か数える語のすぐ後ろにあると予告でなくなる語(以上、目、or more)。 */
20
+ readonly hedgesAfter: readonly string[];
21
+ };
22
+
23
+ export type CountMismatch = { readonly offset: number; readonly phrase: string; readonly announced: number; readonly listed: number };
24
+
25
+ /** counted: 数える語が付いている(3点)。付いていない数(the following two:)は、先を指す語のすぐ後ろでだけ予告に読む。 */
26
+ type Phrase = { readonly start: number; readonly numberEnd: number; readonly end: number; readonly announced: number; readonly counted: boolean };
27
+
28
+ /** 予告の文の外側。見出し、表、引用、コードの囲みの行は、すぐ下の箇条書きを予告する文ではない。 */
29
+ const NOT_A_LEAD = /^[ \t]*(?:#|\||>|```|~~~)/u;
30
+
31
+ /** 箇条書きのすぐ前の塊。見出し・表・引用・コードの囲みなら undefined。 */
32
+ const leadBefore = (source: string, listStart: number): TextBlock | undefined => {
33
+ const lines = linesAbove(source, listStart);
34
+ return lines.some((line) => NOT_A_LEAD.test(line.text)) ? undefined : joined(source, lines);
35
+ };
36
+
37
+ /** 文の終わり。英語の「.」は後ろが空白のときだけ(3.5 や e.g. の途中で切らない)。 */
38
+ const SENTENCE_END = /[。!?!?]|\.(?=\s)/gu;
39
+
40
+ /** 塊の最後の一文の始まり(塊の中の位置)。 */
41
+ const lastSentenceStart = (text: string): number => {
42
+ const body = text.trimEnd();
43
+ const ends = [...body.matchAll(SENTENCE_END)].map((match) => match.index + match[0].length).filter((end) => end < body.length);
44
+ return ends.at(-1) ?? 0;
45
+ };
46
+
47
+ const alternation = (words: readonly string[]): string =>
48
+ words
49
+ .toSorted((a, b) => b.length - a.length)
50
+ .map(escapeRegExp)
51
+ .join("|");
52
+
53
+ /**
54
+ * 数と、それが数えるもの。数の前が数字・英字・数の字なら数の途中(十三、23、eleven の中)。
55
+ * 英語は数と数える語の間に語を二つまで置ける(three key steps)。数える語が無くても、文がコロンで終わる直前の数(the following two:)は数に読む。
56
+ */
57
+ const phrasePattern = (words: CountWords): RegExp => {
58
+ const numberChars = escapeRegExp([...new Set(words.numbers.join(""))].join(""));
59
+ const numbers = words.numbers.length === 0 ? "\\p{Nd}+" : `\\p{Nd}+|${alternation(words.numbers)}`;
60
+ const counted = `[ \\t\\u00a0]?(?:\\p{Ll}[\\p{Ll}-]*[ \\t]){0,2}(${alternation(words.counters)})(?![A-Za-z])`;
61
+ return new RegExp(`(?<![\\p{N}A-Za-z${numberChars}])(${numbers})(?:${counted}|(?=[ \\t]?[::][ \\t]*$))`, "giu");
62
+ };
63
+
64
+ const valueOf = (written: string, numbers: readonly string[]): number => {
65
+ const digits = Number(written.normalize("NFKC"));
66
+ if (!Number.isNaN(digits)) return digits;
67
+ return numbers.findIndex((number) => number.toLowerCase() === written.toLowerCase()) + 1;
68
+ };
69
+
70
+ const LATIN_LETTER = /[A-Za-z]/u;
71
+ const isLatin = (char: string | undefined): boolean => LATIN_LETTER.test(char ?? "");
72
+
73
+ /** 英語の語は語の切れ目で照らす(over が moreover に当たらない)。日本語の語は字面どおり。 */
74
+ const endsWithWord = (text: string, word: string): boolean => text.endsWith(word) && !(isLatin(word[0]) && isLatin(text.at(-word.length - 1)));
75
+
76
+ const startsWithWord = (text: string, word: string): boolean => text.startsWith(word) && !(isLatin(word.at(-1)) && isLatin(text[word.length]));
77
+
78
+ const isHedged = (sentence: string, phrase: Phrase, words: CountWords): boolean => {
79
+ const before = sentence.slice(0, phrase.start).trimEnd().toLowerCase();
80
+ const afters = [sentence.slice(phrase.numberEnd), sentence.slice(phrase.end)].map((text) => text.trimStart().toLowerCase());
81
+ return (
82
+ words.hedgesBefore.some((hedge) => endsWithWord(before, hedge.toLowerCase())) ||
83
+ words.hedgesAfter.some((hedge) => afters.some((after) => startsWithWord(after, hedge.toLowerCase())))
84
+ );
85
+ };
86
+
87
+ const COLON_END = /[::][ \t]*$/u;
88
+
89
+ /** 数える語の無い数は、先を指す語のすぐ後ろでだけ(the following two:)。「under $75:」の金額を数に読まない。 */
90
+ const pointsAhead = (sentence: string, phrase: Phrase, anchors: readonly string[]): boolean => {
91
+ const before = sentence.slice(0, phrase.start).toLowerCase();
92
+ const lowered = anchors.map((anchor) => anchor.toLowerCase());
93
+ if (!phrase.counted) return lowered.some((anchor) => endsWithWord(before.trimEnd(), anchor));
94
+ return COLON_END.test(sentence.trimEnd()) || lowered.some((anchor) => before.includes(anchor));
95
+ };
96
+
97
+ /** 最後の一文の予告。数がちょうど一つで、目安や順番でなく、先を指しているときだけ。 */
98
+ const announcedIn = (sentence: string, words: CountWords, pattern: RegExp): Phrase | undefined => {
99
+ const phrases = [...sentence.matchAll(pattern)].map((match) => ({
100
+ start: match.index,
101
+ numberEnd: match.index + (match[1] ?? "").length,
102
+ end: match.index + match[0].length,
103
+ announced: valueOf(match[1] ?? "", words.numbers),
104
+ counted: match[2] !== undefined,
105
+ }));
106
+ const only = phrases.length === 1 ? phrases[0] : undefined;
107
+ if (only === undefined || only.announced < 1 || isHedged(sentence, only, words)) return undefined;
108
+ return pointsAhead(sentence, only, words.anchors) ? only : undefined;
109
+ };
110
+
111
+ /** 位置から空白と改行を読み飛ばした先。 */
112
+ const pastSpace = (source: string, at: number): number => {
113
+ const filled = /[^ \t\r\n]/gu;
114
+ filled.lastIndex = at;
115
+ return filled.exec(source)?.index ?? source.length;
116
+ };
117
+
118
+ /** 箇条書きの終わり(後ろの空白を読み飛ばした先)と始まり。空白だけを挟んで続く二つの箇条書きは、終わりと始まりが同じ位置になる。 */
119
+ type Neighbours = { readonly ends: ReadonlySet<number>; readonly starts: ReadonlySet<number> };
120
+
121
+ const neighboursOf = (source: string, lists: readonly BulletList[]): Neighbours => ({
122
+ ends: new Set(lists.map((list) => pastSpace(source, list.span.end))),
123
+ starts: new Set(lists.map((list) => list.span.start)),
124
+ });
125
+
126
+ /** 空白だけを挟んで前か後ろに別の箇条書きが続く。印が変わって二つに割れた一つの並びかもしれず、数を決められない。 */
127
+ const hasNeighbour = (source: string, list: Span, neighbours: Neighbours): boolean =>
128
+ neighbours.ends.has(list.start) || neighbours.starts.has(pastSpace(source, list.end));
129
+
130
+ type Context = { readonly source: string; readonly words: CountWords; readonly pattern: RegExp; readonly neighbours: Neighbours };
131
+
132
+ const mismatchOf = ({ source, words, pattern, neighbours }: Context, list: BulletList): CountMismatch[] => {
133
+ if (hasNeighbour(source, list.span, neighbours)) return [];
134
+ const lead = leadBefore(source, list.span.start);
135
+ if (lead === undefined) return [];
136
+ const sentenceStart = lastSentenceStart(lead.text);
137
+ const sentence = lead.text.slice(sentenceStart);
138
+ const phrase = announcedIn(sentence, words, pattern);
139
+ if (phrase === undefined || phrase.announced === list.items.length) return [];
140
+ const offset = lead.start + sentenceStart + phrase.start;
141
+ return [{ offset, phrase: sentence.slice(phrase.start, phrase.end).trim(), announced: phrase.announced, listed: list.items.length }];
142
+ };
143
+
144
+ export const announcedCountMismatches = (source: string, lists: readonly BulletList[], words: CountWords): CountMismatch[] => {
145
+ if (words.counters.length === 0) return [];
146
+ const context = { source, words, pattern: phrasePattern(words), neighbours: neighboursOf(source, lists) };
147
+ return lists.flatMap((list) => mismatchOf(context, list));
148
+ };
@@ -0,0 +1,35 @@
1
+ import type { Span } from "./plugin.ts";
2
+
3
+ /**
4
+ * `https://…` をそのまま書いた URL。GFM の autolink 拡張を入れていないので mdast では
5
+ * ただのテキストになり、本文として残る。残すと、見出しと URL の中の識別子が一致して
6
+ * 「見出しの繰り返し」と読まれる。表示される文字も本文ではない。
7
+ * 空白が来るまでを取るので、URL の直後に続けた日本語(「https://example.jp/をご覧ください」の「をご覧ください」)も入る。
8
+ */
9
+ export const BARE_URL = /https?:\/\/[^\s)<>"'\]]+/gu;
10
+
11
+ /** 文の終わりの句読点。URL の最後の字としてはまず書かれず、URL の後ろの文の字。 */
12
+ const PUNCTUATION: ReadonlySet<string> = new Set([".", ",", ";", ":", "!", "?"]);
13
+
14
+ /**
15
+ * そのまま書いた URL に続けた文の始まり: ひらがなと全角の句読点・括弧(「…/をご覧ください」「…/。」)。
16
+ * 漢字やカタカナは道の名前(/東京、/カタログ)にもなるので切らない。
17
+ */
18
+ const SENTENCE_AFTER = /[\p{Script=Hiragana}\u3000-\u303f\uff01-\uff0f\uff1a-\uff20]/u;
19
+
20
+ /** URL として読む長さ。続けた文の手前で切り、後ろの句読点を外す。正規表現の `[…]+$` は句読点の長い並びで後戻りが二乗になる。 */
21
+ const urlLength = (written: string): number => {
22
+ const cut = SENTENCE_AFTER.exec(written)?.index ?? written.length;
23
+ let end = cut;
24
+ while (end > 0 && PUNCTUATION.has(written.charAt(end - 1))) end -= 1;
25
+ return end;
26
+ };
27
+
28
+ export type BareUrl = Span & { readonly url: string };
29
+
30
+ /** text の中の、そのまま書いた URL。続けて書いた日本語と文末の句読点は外す。位置は text の先頭を 0 とする。 */
31
+ export const bareUrls = (text: string): BareUrl[] =>
32
+ [...text.matchAll(BARE_URL)].map((match) => {
33
+ const url = match[0].slice(0, urlLength(match[0]));
34
+ return { start: match.index, end: match.index + url.length, url };
35
+ });
package/src/baseline.ts CHANGED
@@ -13,6 +13,21 @@ export const fingerprint = (path: string, finding: Finding): string => {
13
13
  return createHash("sha256").update(body).digest("hex").slice(0, 16);
14
14
  };
15
15
 
16
+ /**
17
+ * findings の fingerprint を順に。一つの文から出た指摘は同じ文を引くので、文と rule の組ごとに一度だけ計算する。
18
+ * 長い文に指摘が多いと、指摘ごとに文を読み直すのでは指摘数と文の長さの積になる。
19
+ */
20
+ export const fingerprints = (path: string, findings: readonly Finding[]): string[] => {
21
+ const known = new Map<string, Map<string, string>>();
22
+ return findings.map((finding) => {
23
+ const byRule = known.get(finding.quote) ?? new Map<string, string>();
24
+ known.set(finding.quote, byRule);
25
+ const found = byRule.get(finding.rule) ?? fingerprint(path, finding);
26
+ byRule.set(finding.rule, found);
27
+ return found;
28
+ });
29
+ };
30
+
16
31
  export type Baseline = { readonly version: 1; readonly created: string; readonly entries: readonly string[] };
17
32
 
18
33
  const isBaseline = (value: unknown): value is Baseline =>
@@ -40,7 +55,8 @@ export type Split = { readonly fresh: readonly Finding[]; readonly shelved: numb
40
55
  export const splitByBaseline = (path: string, findings: readonly Finding[], baseline: Baseline | undefined): Split => {
41
56
  if (baseline === undefined) return { fresh: findings, shelved: 0 };
42
57
  const known = new Set(baseline.entries);
43
- const fresh = findings.filter((finding) => !known.has(fingerprint(path, finding)));
58
+ const prints = fingerprints(path, findings);
59
+ const fresh = findings.filter((_, index) => !known.has(prints[index] ?? ""));
44
60
  return { fresh, shelved: findings.length - fresh.length };
45
61
  };
46
62
 
@@ -0,0 +1,7 @@
1
+ import type { Section } from "./plugin.ts";
2
+
3
+ /**
4
+ * 本題の始まり: 最初の中見出し(深さ 2 以上)の節。表題(深さ 1)の直後から数えると、表題しか無い文書で全文が前置きになる。
5
+ * 無ければ、本題の前を測る rule は動けない(rule の requires の headings)。
6
+ */
7
+ export const bodySectionOf = (sections: readonly Section[]): Section | undefined => sections.find((section) => section.depth >= 2);
@@ -8,9 +8,15 @@ import type { ProseDocument, Span, Token } from "./plugin.ts";
8
8
  * 単位は語彙表から渡す。chained は日付・時刻の単位を大きい順に(年月日時分秒)。大きい単位の後ろに小さい単位を続けて書けば
9
9
  * 一つの日付・時刻になる。「2008年 2年連続」のように同じ単位や大きい単位が続けば、別のものの始まり。
10
10
  * positional は数の後ろに置くだけで位置を言う単位(月、時)。year は 4 桁の数の後ろで暦の年を言う単位(年、年度)。
11
+ * era は元号(令和)。元号のすぐ後ろ(空白 1 つまで)の数は、単位が何でも暦の上の位置を言う(令和8年、桁が少なくても年数ではない)。
11
12
  * 「5日」「5分」「3年」のように、単位だけでは長さと見分けのつかないものは、位置を言う単位と続けて書いたときだけ日付・時刻と読む。
12
13
  */
13
- export type CalendarUnits = { readonly chained: readonly string[]; readonly positional: ReadonlySet<string>; readonly year: ReadonlySet<string> };
14
+ export type CalendarUnits = {
15
+ readonly chained: readonly string[];
16
+ readonly positional: ReadonlySet<string>;
17
+ readonly year: ReadonlySet<string>;
18
+ readonly era: readonly string[];
19
+ };
14
20
 
15
21
  /** 日付・時刻の数の並び。first は日付の頭の数、inner は前の単位に続く数(2026年9月の 9)。unit は数の後ろの単位(月)。 */
16
22
  export type CalendarRun = { readonly run: Span; readonly place: "first" | "inner"; readonly unit: string };
@@ -38,15 +44,22 @@ const pastSpace = (text: string, at: number): number => (text[at] === " " ? at +
38
44
 
39
45
  const isUnit = (surface: string, units: CalendarUnits): boolean => units.chained.includes(surface) || units.positional.has(surface) || units.year.has(surface);
40
46
 
41
- const isAnchor = (digits: string, surface: string, units: CalendarUnits): boolean =>
42
- units.positional.has(surface) || (units.year.has(surface) && CALENDAR_YEAR.test(digits));
47
+ /** 数 run のすぐ前(空白 1 つまで)が元号か。 */
48
+ const followsEra = (text: string, run: Span, units: CalendarUnits): boolean => {
49
+ const before = text.slice(0, run.start);
50
+ const written = before.endsWith(" ") ? before.slice(0, -1) : before;
51
+ return units.era.some((era) => written.endsWith(era));
52
+ };
53
+
54
+ const isAnchor = (text: string, run: Span, surface: string, units: CalendarUnits): boolean =>
55
+ units.positional.has(surface) || (units.year.has(surface) && CALENDAR_YEAR.test(text.slice(run.start, run.end))) || followsEra(text, run, units);
43
56
 
44
57
  /** 数のすぐ後ろ(空白 1 つまで)の語が日付・時刻の単位なら、その組。語の切れ目が合わなければ組にしない。 */
45
58
  const partOf = (text: string, run: Span, tokens: readonly Token[], base: number, units: CalendarUnits): Part | undefined => {
46
59
  const unit = tokens.find((token) => token.span.start === base + pastSpace(text, run.end));
47
60
  if (unit === undefined || !isUnit(unit.surface, units)) return undefined;
48
61
  const rank = units.chained.indexOf(unit.surface);
49
- return { run, unit: unit.surface, unitEnd: unit.span.end - base, rank, anchored: isAnchor(text.slice(run.start, run.end), unit.surface, units) };
62
+ return { run, unit: unit.surface, unitEnd: unit.span.end - base, rank, anchored: isAnchor(text, run, unit.surface, units) };
50
63
  };
51
64
 
52
65
  /** 前の組の単位のすぐ後ろ(空白 1 つまで)から始まり、単位が前より小さい組か。 */
@@ -81,4 +94,5 @@ export const calendarUnitsOf = (doc: ProseDocument): CalendarUnits => ({
81
94
  chained: patternList(doc, "date-time-unit"),
82
95
  positional: new Set(patternList(doc, "calendar-unit")),
83
96
  year: new Set(patternList(doc, "calendar-year-unit")),
97
+ era: patternList(doc, "calendar-era"),
84
98
  });
package/src/cli-args.ts CHANGED
@@ -7,3 +7,9 @@ const VALUE_FLAGS: ReadonlySet<string> = new Set(["--sarif", "--genre", "--rule"
7
7
  /** The arguments that name what to check: everything that is neither an option nor an option's value. */
8
8
  export const targetsOf = (args: readonly string[]): string[] =>
9
9
  args.filter((arg, index) => !arg.startsWith("--") && !(index > 0 && VALUE_FLAGS.has(args[index - 1] ?? "")));
10
+
11
+ /** The settings with --experimental applied: the command line turns experimental rules on as chaff.yaml can. */
12
+ export const withExperimental = <T extends { readonly experimental: boolean }>(config: T, args: readonly string[]): T => ({
13
+ ...config,
14
+ experimental: config.experimental || args.includes("--experimental"),
15
+ });
package/src/cli-text.ts CHANGED
@@ -21,7 +21,9 @@ const USAGE_JA = `chaff — 文章の読みにくいところを見つけます
21
21
  chaff genres ジャンル(文書の種類)の一覧と、それぞれ何向けか
22
22
  chaff tree <file> [--format sexp|json] 文書を番地の付いた木にする(条・項・定義・参照)
23
23
  chaff cite <原文> <引用.json> 回答の引用(番地と引用文)が原文にあるかを確かめる
24
- chaff rules --json いまの設定を JSON で出す(AI に渡す用)
24
+ chaff compare <前> <後> 書き換えで事実(数・日付・URL・コード・名前・引用…)が落ちても足されてもいないかを確かめる
25
+ chaff rules ルールの一覧を、グループごとに表で出す(いまの段階つき)
26
+ chaff rules --json いまの設定とルールの説明を JSON で出す(AI に渡す用)
25
27
  chaff baseline <dir> いまある指摘を棚上げする(既存の repo に入れるとき)
26
28
  chaff suppressions <dir> stet で黙らせている指摘を数える
27
29
  chaff relax|strict|off <rule> [--why "理由"]
@@ -55,7 +57,9 @@ const USAGE_EN = `chaff — finds what makes writing hard to read. It never rewr
55
57
  chaff genres list the genres (kinds of document) and what each is for
56
58
  chaff tree <file> [--format sexp|json] the document as a tree of addresses (sections, clauses, definitions, references)
57
59
  chaff cite <source> <quotes.json> check that quoted passages (address and text) are in the source
58
- chaff rules --json the current settings as JSON (to give to an AI)
60
+ chaff compare <before> <after> check that a rewrite dropped no fact and added none (numbers, dates, URLs, code, names, quotations…)
61
+ chaff rules the rules as a table, by group, with the level each runs at now
62
+ chaff rules --json the current settings and what each rule is, as JSON (to give to an AI)
59
63
  chaff baseline <dir> shelve today's findings (when adding chaff to an existing repository)
60
64
  chaff suppressions <dir> count the findings silenced with stet
61
65
  chaff relax|strict|off <rule> [--why "reason"]
@@ -137,7 +141,7 @@ export const CLI_TEXT: Texts<CliText> = {
137
141
  unknownProfile: (profile, where, known) =>
138
142
  `文書の種類 "${profile}" はありません(${where})。使えるのは ${known.join("、")} と、種類を使わない none です。`,
139
143
  profileWhere: (where, files) => (where === "config" ? "chaff.yaml の profile" : `chaff.yaml の by_path、files: ${files.join(", ")}`),
140
- unknownRule: (id) => `${id} というルールはありません。npx chaff rules --json で一覧が出ます。`,
144
+ unknownRule: (id) => `${id} というルールはありません。npx chaff rules で一覧が出ます。`,
141
145
  unknownRuleWithList: (id, list) => `${id} というルールはありません。\n一覧:\n${list}`,
142
146
  unnamed: "(名前なし)",
143
147
  sarifWritten: (path, count) => `\n SARIF を書きました: ${path}(${count} 件)`,
@@ -191,7 +195,7 @@ export const CLI_TEXT: Texts<CliText> = {
191
195
  unknownProfile: (profile, where, known) =>
192
196
  `There is no document profile "${profile}" (${where}). The profiles are ${known.join(", ")}; none uses no profile.`,
193
197
  profileWhere: (where, files) => (where === "config" ? "profile in chaff.yaml" : `by_path in chaff.yaml, files: ${files.join(", ")}`),
194
- unknownRule: (id) => `There is no rule named ${id}. npx chaff rules --json lists them.`,
198
+ unknownRule: (id) => `There is no rule named ${id}. npx chaff rules lists them.`,
195
199
  unknownRuleWithList: (id, list) => `There is no rule named ${id}.\nRules:\n${list}`,
196
200
  unnamed: "(no name)",
197
201
  sarifWritten: (path, count) => `\n Wrote SARIF: ${path} (${counted(count, "finding")})`,
package/src/cli.ts CHANGED
@@ -1,15 +1,13 @@
1
- import { readFile } from "node:fs/promises";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
1
+ import { mkdirSync, writeFileSync } from "node:fs";
3
2
  import { dirname, join } from "node:path";
4
3
  import { loadAdapter, packageFor } from "./adapter-load.ts";
5
- import { CONFIG_FILE, EMPTY, loadConfig, type Config } from "./config/load.ts";
4
+ import { CONFIG_FILE, type Config } from "./config/load.ts";
6
5
  import { applyByPath } from "./config/by-path.ts";
7
6
  import { applyLevel } from "./config/write.ts";
8
7
  import { buildDocument, teamRules } from "./document.ts";
9
8
  import { guessLanguage } from "./detect.ts";
10
- import { plainSource } from "./plain-source.ts";
11
- import { collectTargets } from "./files.ts";
12
- import { BASELINE_FILE, fingerprint, readBaseline, splitByBaseline, writeBaseline } from "./baseline.ts";
9
+ import { collectTargets, readDocumentFile } from "./files.ts";
10
+ import { BASELINE_FILE, fingerprints, readBaseline, splitByBaseline, writeBaseline } from "./baseline.ts";
13
11
  import { applySuppressions } from "./stet.ts";
14
12
  import { renderSuppressions, type PerFile } from "./render/suppressions.ts";
15
13
  import { clock, describeChange, snapshotOf, watchPaths, type Snapshot } from "./watch.ts";
@@ -19,8 +17,8 @@ import { GENRES } from "./genre.ts";
19
17
  import { resolveGenre } from "./resolve-genre.ts";
20
18
  import { runInit } from "./init.ts";
21
19
  import { initGenre } from "./commands/init-ask.ts";
22
- import { targetsOf } from "./cli-args.ts";
23
- import { loadRules } from "./rule-load.ts";
20
+ import { targetsOf, withExperimental } from "./cli-args.ts";
21
+ import { rulesOf } from "./custom/load.ts";
24
22
  import { renderCompact } from "./render/compact.ts";
25
23
  import { renderExplain } from "./render/explain.ts";
26
24
  import { renderFriendly } from "./render/friendly.ts";
@@ -28,18 +26,21 @@ import { renderGenres } from "./render/genres.ts";
28
26
  import { loadGenres, presetLevels } from "./genre-load.ts";
29
27
  import { fileHeader } from "./file-header.ts";
30
28
  import { rulesJson } from "./render/rules-json.ts";
29
+ import { rulesTable } from "./render/rules-table.ts";
31
30
  import { renderSarif } from "./render/sarif.ts";
32
31
  import { VERSION, VERSION_LINES } from "./version.ts";
33
32
  import { runTree, treeTargets, type TreeContext } from "./commands/tree.ts";
34
33
  import { citeTargets, runCite } from "./commands/cite.ts";
34
+ import { compareTargets, runCompare } from "./commands/compare.ts";
35
35
  import { runSkill } from "./commands/skill.ts";
36
36
  import { runFeedback, settingsOf } from "./commands/feedback.ts";
37
37
  import { homedir } from "node:os";
38
- import { ruleProblems } from "./config/rule-problems.ts";
39
- import { nameProblems } from "./config/name-problems.ts";
38
+ import { settingWarnings } from "./config/warnings.ts";
39
+ import { readConfigIn } from "./config/read.ts";
40
+ import { optionLayersOf, settingSourcesOf } from "./config/option-problems.ts";
40
41
  import { renderSummary, type FileOutcome } from "./render/summary.ts";
41
- import { neededBy, runRules } from "./run.ts";
42
- import type { Level, RuleDefinition } from "./plugin.ts";
42
+ import { neededBy, runRulesWith } from "./run.ts";
43
+ import type { Finding, Level, RuleDefinition } from "./plugin.ts";
43
44
  import { CLI_TEXT, type CliText, type GenreSource } from "./cli-text.ts";
44
45
  import { hostLanguage, sharedLanguage, uiLanguageOf, type UiLanguage } from "./ui.ts";
45
46
  import { profileFor } from "./profile/for-file.ts";
@@ -48,7 +49,7 @@ import { settingProblems } from "./setting-problems.ts";
48
49
  /** Text for output that is not about one document. */
49
50
  const hostText = (config: Config): CliText => CLI_TEXT[hostLanguage(config.language, process.env)];
50
51
 
51
- const readConfig = (): Config => (existsSync(join(process.cwd(), CONFIG_FILE)) ? loadConfig(join(process.cwd(), CONFIG_FILE)) : EMPTY);
52
+ const readConfig = (): Config => readConfigIn(process.cwd());
52
53
 
53
54
  /** resolveGenre with this run's --genre, for the commands that take it as a dependency. */
54
55
  const genreFrom =
@@ -61,7 +62,7 @@ const findRule = (rules: readonly RuleDefinition[], id: string | undefined): Rul
61
62
  const changeSetting = (command: Level, ruleId: string | undefined, why: string | undefined): number => {
62
63
  const config = readConfig();
63
64
  const language = config.language ?? hostLanguage(undefined, process.env);
64
- const rule = findRule(loadRules(language), ruleId);
65
+ const rule = findRule(rulesOf(language, config), ruleId);
65
66
  if (rule === undefined) {
66
67
  console.error(hostText(config).unknownRule(ruleId ?? hostText(config).unnamed));
67
68
  return 1;
@@ -84,20 +85,21 @@ type Inspected = {
84
85
  readonly genre: string;
85
86
  readonly outcome: FileOutcome;
86
87
  readonly perFile: PerFile;
87
- readonly all: readonly string[];
88
+ /** stet で黙らせたものを除いた、baseline で棚上げする前の指摘。fingerprint は baseline を書くときだけ作る。 */
89
+ readonly kept: readonly Finding[];
88
90
  };
89
91
 
90
92
  const inspect = async (path: string, config: Config, argv: readonly string[]): Promise<Inspected> => {
91
- const source = plainSource(await readFile(path, "utf8"));
93
+ const source = await readDocumentFile(path);
92
94
  const language = applyByPath(config.byPath, config.baseDir, path).language ?? config.language ?? guessLanguage(source).language;
93
95
  const adapter = await loadAdapter(language);
94
96
  const { genre, from, unread } = resolveGenre(path, source, config, flag(argv, "--genre"));
95
97
  if (unread !== undefined) console.error(`chaff: ${CLI_TEXT[uiLanguageOf(language)].unreadFrontMatterGenre(path, unread, GENRES)}`);
96
- const rules = loadRules(language);
98
+ const rules = rulesOf(language, config);
97
99
  const experimental = config.experimental || argv.includes("--experimental");
98
100
  await adapter.prepare?.(neededBy(rules, config.rules, experimental, genre, language));
99
101
  const doc = buildDocument(path, source, adapter, teamRules(config), profileFor(config, path, source, language, genre));
100
- const raw = runRules(doc, rules, config.rules, experimental, genre, config.limits);
102
+ const raw = runRulesWith(doc, rules, { settings: config.rules, experimental, genre, limits: config.limits, optionLayers: optionLayersOf(config) });
101
103
  // 応答は 3 つ。stet で黙らせたものは、ここで落とす。
102
104
  const applied = applySuppressions(
103
105
  source,
@@ -116,7 +118,7 @@ const inspect = async (path: string, config: Config, argv: readonly string[]): P
116
118
  genre,
117
119
  outcome: { path, findings: split.fresh, notRun: raw.skipped.length },
118
120
  perFile: { path, suppressed: applied.suppressed, reasonless: applied.unusedReasonless },
119
- all: applied.kept.map((finding) => fingerprint(path, finding)),
121
+ kept: applied.kept,
120
122
  };
121
123
  };
122
124
 
@@ -137,10 +139,8 @@ const writeSarif = (results: readonly Inspected[], argv: readonly string[]): voi
137
139
  };
138
140
 
139
141
  /** 効いていない設定は、結果の前に一度だけ言う。標準エラーに出すので、JSON や SARIF の出力は汚さない。 */
140
- const warnRuleProblems = (config: Config, language: string): void => {
141
- const ui = hostLanguage(config.language, process.env);
142
- [...ruleProblems(config, loadRules(language), ui), ...nameProblems(config, ui)].forEach((problem) => console.error(`chaff: ${problem}`));
143
- };
142
+ const warnRuleProblems = (config: Config, language: string): void =>
143
+ settingWarnings(config, rulesOf(language, config), hostLanguage(config.language, process.env)).forEach((problem) => console.error(`chaff: ${problem}`));
144
144
 
145
145
  /** Several files end with one summary: in their language when they share one, else the host's. */
146
146
  const summaryLanguage = (results: readonly Inspected[], config: Config): UiLanguage => {
@@ -214,7 +214,7 @@ const explain = (ruleId: string | undefined, genreFlag: string | undefined): num
214
214
  // The rule's limits differ by language (characters for Japanese, words for English): explain in the one being written.
215
215
  const language = config.language ?? hostLanguage(undefined, process.env);
216
216
  const text = CLI_TEXT[uiLanguageOf(language)];
217
- const rules = loadRules(language);
217
+ const rules = rulesOf(language, config);
218
218
  const rule = findRule(rules, ruleId);
219
219
  if (rule === undefined) {
220
220
  const list = rules.map((entry) => ` ${entry.id}`).join("\n");
@@ -223,7 +223,7 @@ const explain = (ruleId: string | undefined, genreFlag: string | undefined): num
223
223
  }
224
224
  const preset = genre === undefined ? {} : presetLevels(genre);
225
225
  const current = config.rules[rule.id] ?? preset[rule.id] ?? (rule.status === "experimental" && !config.experimental ? "off" : "normal");
226
- console.log(renderExplain(rule, current, language, text.unit(rule.id, language), genre));
226
+ console.log(renderExplain(rule, current, language, text.unit(rule.id, language), genre, settingSourcesOf(config, rule.id)));
227
227
  return 0;
228
228
  };
229
229
 
@@ -235,7 +235,7 @@ const runBaseline = async (targets: readonly string[], argv: readonly string[]):
235
235
  return 1;
236
236
  }
237
237
  const results = await Promise.all(paths.map((path) => inspect(path, config, [...argv, "--show-baseline"])));
238
- const entries = results.flatMap((result) => result.all);
238
+ const entries = results.flatMap((result) => fingerprints(result.outcome.path, result.kept));
239
239
  const file = join(process.cwd(), BASELINE_FILE);
240
240
  writeBaseline(file, entries);
241
241
  console.log(hostText(config).baselineDone(paths.length, entries.length, BASELINE_FILE).join("\n"));
@@ -246,12 +246,8 @@ const runSuppressions = async (targets: readonly string[], argv: readonly string
246
246
  const paths = collectTargets(targets.length > 0 ? targets : ["."]);
247
247
  const config = readConfig();
248
248
  const results = await Promise.all(paths.map((path) => inspect(path, config, [...argv, "--show-baseline"])));
249
- console.log(
250
- renderSuppressions(
251
- results.map((result) => result.perFile),
252
- hostLanguage(config.language, process.env),
253
- ),
254
- );
249
+ const perFile = results.map((result) => result.perFile);
250
+ console.log(renderSuppressions(perFile, hostLanguage(config.language, process.env)));
255
251
  return 0;
256
252
  };
257
253
 
@@ -260,11 +256,14 @@ type Handler = (argv: readonly string[]) => number | Promise<number>;
260
256
  /** `--` で始まらない引数。対象のパス。 */
261
257
  const positional = (argv: readonly string[]): string[] => targetsOf(argv.slice(1));
262
258
 
263
- const showRules = (genreFlag: string | undefined): number => {
264
- const config = readConfig();
259
+ /** `rules --json` for an AI to read; `rules` alone, a table for a person. */
260
+ const showRules = (argv: readonly string[]): number => {
261
+ const config = withExperimental(readConfig(), argv);
265
262
  const language = config.language ?? hostLanguage(undefined, process.env);
266
263
  warnRuleProblems(config, language);
267
- console.log(rulesJson(loadRules(language), config, language, genreFlag ?? config.genre ?? "blog/tech"));
264
+ const genre = flag(argv, "--genre") ?? config.genre ?? "blog/tech";
265
+ const rules = rulesOf(language, config);
266
+ console.log(argv.includes("--json") ? rulesJson(rules, config, language, genre, optionLayersOf(config)) : rulesTable(rules, config, language, genre));
268
267
  return 0;
269
268
  };
270
269
 
@@ -294,11 +293,12 @@ const HANDLERS: Readonly<Record<string, Handler>> = {
294
293
  return "error" in chosen ? 1 : 0;
295
294
  },
296
295
  genres: showGenres,
297
- rules: (argv) => showRules(flag(argv, "--genre")),
296
+ rules: showRules,
298
297
  explain: (argv) => explain(argv[1], flag(argv, "--genre")),
299
298
  eval: (argv) => runEval(positional(argv), argv, { ...measureContext(argv), flag }),
300
299
  tree: (argv) => runTree(treeTargets(argv), argv, treeContext()),
301
300
  cite: (argv) => runCite(citeTargets(argv), argv, treeContext()),
301
+ compare: (argv) => runCompare(compareTargets(argv), argv, treeContext()),
302
302
  test: (argv) => runTest(positional(argv), argv, { ...measureContext(argv), inspect }),
303
303
  baseline: (argv) => runBaseline(positional(argv), argv),
304
304
  suppressions: (argv) => runSuppressions(positional(argv), argv),
@@ -338,7 +338,7 @@ export const main = async (argv: readonly string[]): Promise<number> => {
338
338
  }
339
339
  // 知らないジャンルではどの rule も当たらず、知らない文書の種類では種類の知識が外れる。どちらも素通りに見えるので、何かする前に止める。
340
340
  const config = readConfig();
341
- const problems = settingProblems(first, flag(argv, "--genre"), config, hostText(config));
341
+ const problems = settingProblems(first, flag(argv, "--genre"), config, hostText(config), hostLanguage(config.language, process.env));
342
342
  problems.forEach((problem) => console.error(problem));
343
343
  if (problems.length > 0) return 1;
344
344
  const handler = HANDLERS[first];