chaffjs 0.16.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 (939) 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 +9 -2
  18. package/dist/calendar-number.d.ts.map +1 -1
  19. package/dist/calendar-number.js +18 -4
  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/closing-numbers.d.ts +20 -0
  31. package/dist/closing-numbers.d.ts.map +1 -0
  32. package/dist/closing-numbers.js +56 -0
  33. package/dist/closing-numbers.js.map +1 -0
  34. package/dist/commands/compare.d.ts +8 -0
  35. package/dist/commands/compare.d.ts.map +1 -0
  36. package/dist/commands/compare.js +72 -0
  37. package/dist/commands/compare.js.map +1 -0
  38. package/dist/commands/eval.d.ts.map +1 -1
  39. package/dist/commands/eval.js +17 -9
  40. package/dist/commands/eval.js.map +1 -1
  41. package/dist/commands/feedback.d.ts +5 -2
  42. package/dist/commands/feedback.d.ts.map +1 -1
  43. package/dist/commands/feedback.js +11 -5
  44. package/dist/commands/feedback.js.map +1 -1
  45. package/dist/commands/test.d.ts.map +1 -1
  46. package/dist/commands/test.js +13 -13
  47. package/dist/commands/test.js.map +1 -1
  48. package/dist/commands/tree.d.ts +13 -0
  49. package/dist/commands/tree.d.ts.map +1 -1
  50. package/dist/commands/tree.js +35 -5
  51. package/dist/commands/tree.js.map +1 -1
  52. package/dist/compare/atom.d.ts +31 -0
  53. package/dist/compare/atom.d.ts.map +1 -0
  54. package/dist/compare/atom.js +4 -0
  55. package/dist/compare/atom.js.map +1 -0
  56. package/dist/compare/clock-time.d.ts +8 -0
  57. package/dist/compare/clock-time.d.ts.map +1 -0
  58. package/dist/compare/clock-time.js +65 -0
  59. package/dist/compare/clock-time.js.map +1 -0
  60. package/dist/compare/extract.d.ts +15 -0
  61. package/dist/compare/extract.d.ts.map +1 -0
  62. package/dist/compare/extract.js +58 -0
  63. package/dist/compare/extract.js.map +1 -0
  64. package/dist/compare/fact-text.d.ts +23 -0
  65. package/dist/compare/fact-text.d.ts.map +1 -0
  66. package/dist/compare/fact-text.js +47 -0
  67. package/dist/compare/fact-text.js.map +1 -0
  68. package/dist/compare/markup-atoms.d.ts +11 -0
  69. package/dist/compare/markup-atoms.d.ts.map +1 -0
  70. package/dist/compare/markup-atoms.js +23 -0
  71. package/dist/compare/markup-atoms.js.map +1 -0
  72. package/dist/compare/match.d.ts +19 -0
  73. package/dist/compare/match.d.ts.map +1 -0
  74. package/dist/compare/match.js +84 -0
  75. package/dist/compare/match.js.map +1 -0
  76. package/dist/compare/outcome.d.ts +33 -0
  77. package/dist/compare/outcome.d.ts.map +1 -0
  78. package/dist/compare/outcome.js +40 -0
  79. package/dist/compare/outcome.js.map +1 -0
  80. package/dist/compare/proper-nouns.d.ts +19 -0
  81. package/dist/compare/proper-nouns.d.ts.map +1 -0
  82. package/dist/compare/proper-nouns.js +44 -0
  83. package/dist/compare/proper-nouns.js.map +1 -0
  84. package/dist/compare/render.d.ts +9 -0
  85. package/dist/compare/render.d.ts.map +1 -0
  86. package/dist/compare/render.js +64 -0
  87. package/dist/compare/render.js.map +1 -0
  88. package/dist/compare/spans.d.ts +9 -0
  89. package/dist/compare/spans.d.ts.map +1 -0
  90. package/dist/compare/spans.js +11 -0
  91. package/dist/compare/spans.js.map +1 -0
  92. package/dist/compare/text-atoms.d.ts +24 -0
  93. package/dist/compare/text-atoms.d.ts.map +1 -0
  94. package/dist/compare/text-atoms.js +67 -0
  95. package/dist/compare/text-atoms.js.map +1 -0
  96. package/dist/compare/text.d.ts +24 -0
  97. package/dist/compare/text.d.ts.map +1 -0
  98. package/dist/compare/text.js +90 -0
  99. package/dist/compare/text.js.map +1 -0
  100. package/dist/compare/tree-atoms.d.ts +20 -0
  101. package/dist/compare/tree-atoms.d.ts.map +1 -0
  102. package/dist/compare/tree-atoms.js +58 -0
  103. package/dist/compare/tree-atoms.js.map +1 -0
  104. package/dist/compare/written-names.d.ts +8 -0
  105. package/dist/compare/written-names.d.ts.map +1 -0
  106. package/dist/compare/written-names.js +24 -0
  107. package/dist/compare/written-names.js.map +1 -0
  108. package/dist/config/load.d.ts +15 -0
  109. package/dist/config/load.d.ts.map +1 -1
  110. package/dist/config/load.js +5 -0
  111. package/dist/config/load.js.map +1 -1
  112. package/dist/config/option-problems.d.ts +16 -0
  113. package/dist/config/option-problems.d.ts.map +1 -0
  114. package/dist/config/option-problems.js +58 -0
  115. package/dist/config/option-problems.js.map +1 -0
  116. package/dist/config/read.d.ts +4 -0
  117. package/dist/config/read.d.ts.map +1 -0
  118. package/dist/config/read.js +8 -0
  119. package/dist/config/read.js.map +1 -0
  120. package/dist/config/rule-problems.d.ts +2 -4
  121. package/dist/config/rule-problems.d.ts.map +1 -1
  122. package/dist/config/rule-problems.js +7 -1
  123. package/dist/config/rule-problems.js.map +1 -1
  124. package/dist/config/style.d.ts +16 -0
  125. package/dist/config/style.d.ts.map +1 -0
  126. package/dist/config/style.js +36 -0
  127. package/dist/config/style.js.map +1 -0
  128. package/dist/config/warnings.d.ts +6 -0
  129. package/dist/config/warnings.d.ts.map +1 -0
  130. package/dist/config/warnings.js +10 -0
  131. package/dist/config/warnings.js.map +1 -0
  132. package/dist/config/write.d.ts.map +1 -1
  133. package/dist/config/write.js +17 -4
  134. package/dist/config/write.js.map +1 -1
  135. package/dist/custom/bounded-match.d.ts +15 -0
  136. package/dist/custom/bounded-match.d.ts.map +1 -0
  137. package/dist/custom/bounded-match.js +43 -0
  138. package/dist/custom/bounded-match.js.map +1 -0
  139. package/dist/custom/load.d.ts +8 -0
  140. package/dist/custom/load.d.ts.map +1 -0
  141. package/dist/custom/load.js +11 -0
  142. package/dist/custom/load.js.map +1 -0
  143. package/dist/custom/parse.d.ts +70 -0
  144. package/dist/custom/parse.d.ts.map +1 -0
  145. package/dist/custom/parse.js +215 -0
  146. package/dist/custom/parse.js.map +1 -0
  147. package/dist/custom/problems.d.ts +5 -0
  148. package/dist/custom/problems.d.ts.map +1 -0
  149. package/dist/custom/problems.js +78 -0
  150. package/dist/custom/problems.js.map +1 -0
  151. package/dist/custom/regex-safety.d.ts +11 -0
  152. package/dist/custom/regex-safety.d.ts.map +1 -0
  153. package/dist/custom/regex-safety.js +110 -0
  154. package/dist/custom/regex-safety.js.map +1 -0
  155. package/dist/custom/token-pattern.d.ts +8 -0
  156. package/dist/custom/token-pattern.d.ts.map +1 -0
  157. package/dist/custom/token-pattern.js +75 -0
  158. package/dist/custom/token-pattern.js.map +1 -0
  159. package/dist/detect.d.ts.map +1 -1
  160. package/dist/detect.js +24 -2
  161. package/dist/detect.js.map +1 -1
  162. package/dist/detectors/acronym-context.d.ts +4 -0
  163. package/dist/detectors/acronym-context.d.ts.map +1 -1
  164. package/dist/detectors/acronym-context.js +25 -4
  165. package/dist/detectors/acronym-context.js.map +1 -1
  166. package/dist/detectors/acronym-expansion.d.ts +2 -0
  167. package/dist/detectors/acronym-expansion.d.ts.map +1 -1
  168. package/dist/detectors/acronym-expansion.js +104 -1
  169. package/dist/detectors/acronym-expansion.js.map +1 -1
  170. package/dist/detectors/agreement-slip.d.ts +32 -0
  171. package/dist/detectors/agreement-slip.d.ts.map +1 -0
  172. package/dist/detectors/agreement-slip.js +137 -0
  173. package/dist/detectors/agreement-slip.js.map +1 -0
  174. package/dist/detectors/ai-phrasing.d.ts +20 -0
  175. package/dist/detectors/ai-phrasing.d.ts.map +1 -0
  176. package/dist/detectors/ai-phrasing.js +112 -0
  177. package/dist/detectors/ai-phrasing.js.map +1 -0
  178. package/dist/detectors/announced-count.d.ts +4 -0
  179. package/dist/detectors/announced-count.d.ts.map +1 -0
  180. package/dist/detectors/announced-count.js +20 -0
  181. package/dist/detectors/announced-count.js.map +1 -0
  182. package/dist/detectors/broken-link.d.ts +17 -0
  183. package/dist/detectors/broken-link.d.ts.map +1 -0
  184. package/dist/detectors/broken-link.js +66 -0
  185. package/dist/detectors/broken-link.js.map +1 -0
  186. package/dist/detectors/cited-name.d.ts.map +1 -1
  187. package/dist/detectors/cited-name.js +4 -4
  188. package/dist/detectors/cited-name.js.map +1 -1
  189. package/dist/detectors/cited-title.d.ts +11 -0
  190. package/dist/detectors/cited-title.d.ts.map +1 -0
  191. package/dist/detectors/cited-title.js +75 -0
  192. package/dist/detectors/cited-title.js.map +1 -0
  193. package/dist/detectors/concrete-evidence.d.ts +1 -1
  194. package/dist/detectors/concrete-evidence.d.ts.map +1 -1
  195. package/dist/detectors/concrete-evidence.js +2 -1
  196. package/dist/detectors/concrete-evidence.js.map +1 -1
  197. package/dist/detectors/content-morphemes.d.ts +4 -0
  198. package/dist/detectors/content-morphemes.d.ts.map +1 -0
  199. package/dist/detectors/content-morphemes.js +12 -0
  200. package/dist/detectors/content-morphemes.js.map +1 -0
  201. package/dist/detectors/contrast-frame.d.ts +17 -0
  202. package/dist/detectors/contrast-frame.d.ts.map +1 -0
  203. package/dist/detectors/contrast-frame.js +32 -0
  204. package/dist/detectors/contrast-frame.js.map +1 -0
  205. package/dist/detectors/custom.d.ts +8 -0
  206. package/dist/detectors/custom.d.ts.map +1 -0
  207. package/dist/detectors/custom.js +71 -0
  208. package/dist/detectors/custom.js.map +1 -0
  209. package/dist/detectors/dangling-figure.d.ts +4 -0
  210. package/dist/detectors/dangling-figure.d.ts.map +1 -0
  211. package/dist/detectors/dangling-figure.js +18 -0
  212. package/dist/detectors/dangling-figure.js.map +1 -0
  213. package/dist/detectors/doubled-punctuation.d.ts +9 -0
  214. package/dist/detectors/doubled-punctuation.d.ts.map +1 -0
  215. package/dist/detectors/doubled-punctuation.js +33 -0
  216. package/dist/detectors/doubled-punctuation.js.map +1 -0
  217. package/dist/detectors/doubled-word.d.ts +5 -0
  218. package/dist/detectors/doubled-word.d.ts.map +1 -1
  219. package/dist/detectors/doubled-word.js +24 -11
  220. package/dist/detectors/doubled-word.js.map +1 -1
  221. package/dist/detectors/en-shape.d.ts +0 -1
  222. package/dist/detectors/en-shape.d.ts.map +1 -1
  223. package/dist/detectors/en-shape.js +0 -235
  224. package/dist/detectors/en-shape.js.map +1 -1
  225. package/dist/detectors/enumerated-runs.d.ts +1 -1
  226. package/dist/detectors/enumerated-runs.d.ts.map +1 -1
  227. package/dist/detectors/enumerated-runs.js +15 -4
  228. package/dist/detectors/enumerated-runs.js.map +1 -1
  229. package/dist/detectors/gram-furniture.d.ts +6 -0
  230. package/dist/detectors/gram-furniture.d.ts.map +1 -0
  231. package/dist/detectors/gram-furniture.js +21 -0
  232. package/dist/detectors/gram-furniture.js.map +1 -0
  233. package/dist/detectors/gram-place.d.ts +2 -0
  234. package/dist/detectors/gram-place.d.ts.map +1 -1
  235. package/dist/detectors/gram-place.js +9 -7
  236. package/dist/detectors/gram-place.js.map +1 -1
  237. package/dist/detectors/gram-windows.d.ts +9 -0
  238. package/dist/detectors/gram-windows.d.ts.map +1 -0
  239. package/dist/detectors/gram-windows.js +27 -0
  240. package/dist/detectors/gram-windows.js.map +1 -0
  241. package/dist/detectors/heading-case.d.ts +2 -0
  242. package/dist/detectors/heading-case.d.ts.map +1 -1
  243. package/dist/detectors/heading-case.js +29 -2
  244. package/dist/detectors/heading-case.js.map +1 -1
  245. package/dist/detectors/heading-code-words.d.ts +6 -0
  246. package/dist/detectors/heading-code-words.d.ts.map +1 -0
  247. package/dist/detectors/heading-code-words.js +29 -0
  248. package/dist/detectors/heading-code-words.js.map +1 -0
  249. package/dist/detectors/heading-echo.d.ts.map +1 -1
  250. package/dist/detectors/heading-echo.js +17 -20
  251. package/dist/detectors/heading-echo.js.map +1 -1
  252. package/dist/detectors/heading-level-skip.d.ts +12 -0
  253. package/dist/detectors/heading-level-skip.d.ts.map +1 -0
  254. package/dist/detectors/heading-level-skip.js +11 -0
  255. package/dist/detectors/heading-level-skip.js.map +1 -0
  256. package/dist/detectors/heading-overlap.d.ts +13 -0
  257. package/dist/detectors/heading-overlap.d.ts.map +1 -0
  258. package/dist/detectors/heading-overlap.js +52 -0
  259. package/dist/detectors/heading-overlap.js.map +1 -0
  260. package/dist/detectors/image-alt-text.d.ts +3 -0
  261. package/dist/detectors/image-alt-text.d.ts.map +1 -0
  262. package/dist/detectors/image-alt-text.js +9 -0
  263. package/dist/detectors/image-alt-text.js.map +1 -0
  264. package/dist/detectors/index.d.ts.map +1 -1
  265. package/dist/detectors/index.js +40 -2
  266. package/dist/detectors/index.js.map +1 -1
  267. package/dist/detectors/kutoten-consistency.d.ts +24 -0
  268. package/dist/detectors/kutoten-consistency.d.ts.map +1 -0
  269. package/dist/detectors/kutoten-consistency.js +77 -0
  270. package/dist/detectors/kutoten-consistency.js.map +1 -0
  271. package/dist/detectors/lead-in.d.ts +1 -0
  272. package/dist/detectors/lead-in.d.ts.map +1 -1
  273. package/dist/detectors/lead-in.js +2 -1
  274. package/dist/detectors/lead-in.js.map +1 -1
  275. package/dist/detectors/letter-joined-name.d.ts +13 -0
  276. package/dist/detectors/letter-joined-name.d.ts.map +1 -0
  277. package/dist/detectors/letter-joined-name.js +11 -0
  278. package/dist/detectors/letter-joined-name.js.map +1 -0
  279. package/dist/detectors/lexicon-match.d.ts +4 -0
  280. package/dist/detectors/lexicon-match.d.ts.map +1 -1
  281. package/dist/detectors/lexicon-match.js +7 -2
  282. package/dist/detectors/lexicon-match.js.map +1 -1
  283. package/dist/detectors/lexicon.d.ts.map +1 -1
  284. package/dist/detectors/lexicon.js +5 -2
  285. package/dist/detectors/lexicon.js.map +1 -1
  286. package/dist/detectors/list-item.d.ts +45 -0
  287. package/dist/detectors/list-item.d.ts.map +1 -0
  288. package/dist/detectors/list-item.js +88 -0
  289. package/dist/detectors/list-item.js.map +1 -0
  290. package/dist/detectors/list-items.d.ts +31 -0
  291. package/dist/detectors/list-items.d.ts.map +1 -0
  292. package/dist/detectors/list-items.js +113 -0
  293. package/dist/detectors/list-items.js.map +1 -0
  294. package/dist/detectors/list-lead-in.d.ts +7 -0
  295. package/dist/detectors/list-lead-in.d.ts.map +1 -0
  296. package/dist/detectors/list-lead-in.js +28 -0
  297. package/dist/detectors/list-lead-in.js.map +1 -0
  298. package/dist/detectors/list-sentence.d.ts +65 -0
  299. package/dist/detectors/list-sentence.d.ts.map +1 -0
  300. package/dist/detectors/list-sentence.js +105 -0
  301. package/dist/detectors/list-sentence.js.map +1 -0
  302. package/dist/detectors/list-view.d.ts +34 -0
  303. package/dist/detectors/list-view.d.ts.map +1 -0
  304. package/dist/detectors/list-view.js +137 -0
  305. package/dist/detectors/list-view.js.map +1 -0
  306. package/dist/detectors/long-vowel.d.ts +7 -0
  307. package/dist/detectors/long-vowel.d.ts.map +1 -0
  308. package/dist/detectors/long-vowel.js +57 -0
  309. package/dist/detectors/long-vowel.js.map +1 -0
  310. package/dist/detectors/markup-finding.d.ts +6 -0
  311. package/dist/detectors/markup-finding.d.ts.map +1 -0
  312. package/dist/detectors/markup-finding.js +19 -0
  313. package/dist/detectors/markup-finding.js.map +1 -0
  314. package/dist/detectors/name-numeral.d.ts +1 -1
  315. package/dist/detectors/name-numeral.d.ts.map +1 -1
  316. package/dist/detectors/name-numeral.js +2 -7
  317. package/dist/detectors/name-numeral.js.map +1 -1
  318. package/dist/detectors/orthography.d.ts.map +1 -1
  319. package/dist/detectors/orthography.js +16 -12
  320. package/dist/detectors/orthography.js.map +1 -1
  321. package/dist/detectors/oxford-comma.d.ts +9 -0
  322. package/dist/detectors/oxford-comma.d.ts.map +1 -0
  323. package/dist/detectors/oxford-comma.js +246 -0
  324. package/dist/detectors/oxford-comma.js.map +1 -0
  325. package/dist/detectors/place-run.d.ts.map +1 -1
  326. package/dist/detectors/place-run.js +10 -6
  327. package/dist/detectors/place-run.js.map +1 -1
  328. package/dist/detectors/placeholder-text.d.ts +9 -0
  329. package/dist/detectors/placeholder-text.d.ts.map +1 -0
  330. package/dist/detectors/placeholder-text.js +18 -0
  331. package/dist/detectors/placeholder-text.js.map +1 -0
  332. package/dist/detectors/quote-around.d.ts +3 -0
  333. package/dist/detectors/quote-around.d.ts.map +1 -0
  334. package/dist/detectors/quote-around.js +8 -0
  335. package/dist/detectors/quote-around.js.map +1 -0
  336. package/dist/detectors/register.d.ts +11 -3
  337. package/dist/detectors/register.d.ts.map +1 -1
  338. package/dist/detectors/register.js +28 -9
  339. package/dist/detectors/register.js.map +1 -1
  340. package/dist/detectors/roman-numeral.d.ts +2 -0
  341. package/dist/detectors/roman-numeral.d.ts.map +1 -1
  342. package/dist/detectors/roman-numeral.js +2 -0
  343. package/dist/detectors/roman-numeral.js.map +1 -1
  344. package/dist/detectors/sentence-ending.d.ts +17 -1
  345. package/dist/detectors/sentence-ending.d.ts.map +1 -1
  346. package/dist/detectors/sentence-ending.js +13 -7
  347. package/dist/detectors/sentence-ending.js.map +1 -1
  348. package/dist/detectors/sentence-length.d.ts.map +1 -1
  349. package/dist/detectors/sentence-length.js +13 -4
  350. package/dist/detectors/sentence-length.js.map +1 -1
  351. package/dist/detectors/signals.d.ts +8 -0
  352. package/dist/detectors/signals.d.ts.map +1 -1
  353. package/dist/detectors/signals.js +94 -54
  354. package/dist/detectors/signals.js.map +1 -1
  355. package/dist/detectors/stacked-hedge.d.ts +0 -7
  356. package/dist/detectors/stacked-hedge.d.ts.map +1 -1
  357. package/dist/detectors/stacked-hedge.js +6 -3
  358. package/dist/detectors/stacked-hedge.js.map +1 -1
  359. package/dist/detectors/stray-space.d.ts +7 -0
  360. package/dist/detectors/stray-space.d.ts.map +1 -0
  361. package/dist/detectors/stray-space.js +34 -0
  362. package/dist/detectors/stray-space.js.map +1 -0
  363. package/dist/detectors/structure-tree.d.ts +6 -0
  364. package/dist/detectors/structure-tree.d.ts.map +1 -1
  365. package/dist/detectors/structure-tree.js +37 -1
  366. package/dist/detectors/structure-tree.js.map +1 -1
  367. package/dist/detectors/structure.d.ts +4 -4
  368. package/dist/detectors/structure.d.ts.map +1 -1
  369. package/dist/detectors/structure.js +7 -6
  370. package/dist/detectors/structure.js.map +1 -1
  371. package/dist/detectors/superlative-name.d.ts.map +1 -1
  372. package/dist/detectors/superlative-name.js +8 -5
  373. package/dist/detectors/superlative-name.js.map +1 -1
  374. package/dist/detectors/superlative-scope.d.ts.map +1 -1
  375. package/dist/detectors/superlative-scope.js +9 -4
  376. package/dist/detectors/superlative-scope.js.map +1 -1
  377. package/dist/detectors/token-column.d.ts +46 -0
  378. package/dist/detectors/token-column.d.ts.map +1 -0
  379. package/dist/detectors/token-column.js +95 -0
  380. package/dist/detectors/token-column.js.map +1 -0
  381. package/dist/detectors/unbalanced-bracket.d.ts +22 -0
  382. package/dist/detectors/unbalanced-bracket.d.ts.map +1 -0
  383. package/dist/detectors/unbalanced-bracket.js +119 -0
  384. package/dist/detectors/unbalanced-bracket.js.map +1 -0
  385. package/dist/detectors/url-run-on.d.ts +9 -0
  386. package/dist/detectors/url-run-on.d.ts.map +1 -0
  387. package/dist/detectors/url-run-on.js +19 -0
  388. package/dist/detectors/url-run-on.js.map +1 -0
  389. package/dist/document-sections.d.ts +13 -0
  390. package/dist/document-sections.d.ts.map +1 -0
  391. package/dist/document-sections.js +32 -0
  392. package/dist/document-sections.js.map +1 -0
  393. package/dist/document.d.ts +11 -4
  394. package/dist/document.d.ts.map +1 -1
  395. package/dist/document.js +99 -95
  396. package/dist/document.js.map +1 -1
  397. package/dist/email-parts.d.ts +28 -0
  398. package/dist/email-parts.d.ts.map +1 -0
  399. package/dist/email-parts.js +230 -0
  400. package/dist/email-parts.js.map +1 -0
  401. package/dist/eval.d.ts +2 -1
  402. package/dist/eval.d.ts.map +1 -1
  403. package/dist/eval.js +16 -4
  404. package/dist/eval.js.map +1 -1
  405. package/dist/figure-references.d.ts +30 -0
  406. package/dist/figure-references.d.ts.map +1 -0
  407. package/dist/figure-references.js +76 -0
  408. package/dist/figure-references.js.map +1 -0
  409. package/dist/files.d.ts +2 -0
  410. package/dist/files.d.ts.map +1 -1
  411. package/dist/files.js +4 -0
  412. package/dist/files.js.map +1 -1
  413. package/dist/genre-parse.d.ts +5 -1
  414. package/dist/genre-parse.d.ts.map +1 -1
  415. package/dist/genre-parse.js +16 -3
  416. package/dist/genre-parse.js.map +1 -1
  417. package/dist/genre-suggest.d.ts.map +1 -1
  418. package/dist/genre-suggest.js +15 -1
  419. package/dist/genre-suggest.js.map +1 -1
  420. package/dist/heading-label.d.ts +22 -0
  421. package/dist/heading-label.d.ts.map +1 -0
  422. package/dist/heading-label.js +50 -0
  423. package/dist/heading-label.js.map +1 -0
  424. package/dist/in-page-nav.d.ts +4 -1
  425. package/dist/in-page-nav.d.ts.map +1 -1
  426. package/dist/in-page-nav.js +53 -18
  427. package/dist/in-page-nav.js.map +1 -1
  428. package/dist/joined-view.d.ts.map +1 -1
  429. package/dist/joined-view.js +1 -0
  430. package/dist/joined-view.js.map +1 -1
  431. package/dist/levels.d.ts +5 -1
  432. package/dist/levels.d.ts.map +1 -1
  433. package/dist/levels.js +9 -0
  434. package/dist/levels.js.map +1 -1
  435. package/dist/line-paragraphs.d.ts +8 -0
  436. package/dist/line-paragraphs.d.ts.map +1 -1
  437. package/dist/line-paragraphs.js +36 -11
  438. package/dist/line-paragraphs.js.map +1 -1
  439. package/dist/long-vowel.d.ts +35 -0
  440. package/dist/long-vowel.d.ts.map +1 -0
  441. package/dist/long-vowel.js +71 -0
  442. package/dist/long-vowel.js.map +1 -0
  443. package/dist/markdown-node.d.ts +19 -0
  444. package/dist/markdown-node.d.ts.map +1 -0
  445. package/dist/markdown-node.js +6 -0
  446. package/dist/markdown-node.js.map +1 -0
  447. package/dist/markdown-read.d.ts +17 -0
  448. package/dist/markdown-read.d.ts.map +1 -0
  449. package/dist/markdown-read.js +37 -0
  450. package/dist/markdown-read.js.map +1 -0
  451. package/dist/markup.d.ts +22 -0
  452. package/dist/markup.d.ts.map +1 -0
  453. package/dist/markup.js +180 -0
  454. package/dist/markup.js.map +1 -0
  455. package/dist/mask.d.ts.map +1 -1
  456. package/dist/mask.js +10 -16
  457. package/dist/mask.js.map +1 -1
  458. package/dist/number-name.d.ts +21 -5
  459. package/dist/number-name.d.ts.map +1 -1
  460. package/dist/number-name.js +120 -18
  461. package/dist/number-name.js.map +1 -1
  462. package/dist/opening-line.d.ts +3 -0
  463. package/dist/opening-line.d.ts.map +1 -0
  464. package/dist/opening-line.js +14 -0
  465. package/dist/opening-line.js.map +1 -0
  466. package/dist/orthography.d.ts +7 -1
  467. package/dist/orthography.d.ts.map +1 -1
  468. package/dist/orthography.js +16 -5
  469. package/dist/orthography.js.map +1 -1
  470. package/dist/page-furniture.d.ts +5 -2
  471. package/dist/page-furniture.d.ts.map +1 -1
  472. package/dist/page-furniture.js +8 -2
  473. package/dist/page-furniture.js.map +1 -1
  474. package/dist/paragraph-length.d.ts +7 -0
  475. package/dist/paragraph-length.d.ts.map +1 -0
  476. package/dist/paragraph-length.js +10 -0
  477. package/dist/paragraph-length.js.map +1 -0
  478. package/dist/plain-source.d.ts +1 -0
  479. package/dist/plain-source.d.ts.map +1 -1
  480. package/dist/plain-source.js +2 -1
  481. package/dist/plain-source.js.map +1 -1
  482. package/dist/plugin.d.ts +121 -0
  483. package/dist/plugin.d.ts.map +1 -1
  484. package/dist/profile/for-file.d.ts.map +1 -1
  485. package/dist/profile/for-file.js +3 -1
  486. package/dist/profile/for-file.js.map +1 -1
  487. package/dist/quoted-span.d.ts +0 -2
  488. package/dist/quoted-span.d.ts.map +1 -1
  489. package/dist/quoted-span.js +9 -4
  490. package/dist/quoted-span.js.map +1 -1
  491. package/dist/reasons.d.ts +3 -0
  492. package/dist/reasons.d.ts.map +1 -1
  493. package/dist/reasons.js +6 -0
  494. package/dist/reasons.js.map +1 -1
  495. package/dist/reference-lists.d.ts +3 -0
  496. package/dist/reference-lists.d.ts.map +1 -0
  497. package/dist/reference-lists.js +75 -0
  498. package/dist/reference-lists.js.map +1 -0
  499. package/dist/render/explain.d.ts +7 -1
  500. package/dist/render/explain.d.ts.map +1 -1
  501. package/dist/render/explain.js +36 -12
  502. package/dist/render/explain.js.map +1 -1
  503. package/dist/render/friendly.d.ts.map +1 -1
  504. package/dist/render/friendly.js +19 -9
  505. package/dist/render/friendly.js.map +1 -1
  506. package/dist/render/options.d.ts +7 -0
  507. package/dist/render/options.d.ts.map +1 -0
  508. package/dist/render/options.js +50 -0
  509. package/dist/render/options.js.map +1 -0
  510. package/dist/render/rules-json.d.ts +4 -1
  511. package/dist/render/rules-json.d.ts.map +1 -1
  512. package/dist/render/rules-json.js +102 -12
  513. package/dist/render/rules-json.js.map +1 -1
  514. package/dist/render/rules-table.d.ts +4 -0
  515. package/dist/render/rules-table.d.ts.map +1 -0
  516. package/dist/render/rules-table.js +70 -0
  517. package/dist/render/rules-table.js.map +1 -0
  518. package/dist/render/sarif.js +4 -4
  519. package/dist/render/sarif.js.map +1 -1
  520. package/dist/render/semantic.js +3 -3
  521. package/dist/render/semantic.js.map +1 -1
  522. package/dist/render/severity-name.d.ts +6 -0
  523. package/dist/render/severity-name.d.ts.map +1 -0
  524. package/dist/render/severity-name.js +7 -0
  525. package/dist/render/severity-name.js.map +1 -0
  526. package/dist/render/text.d.ts +7 -2
  527. package/dist/render/text.d.ts.map +1 -1
  528. package/dist/render/text.js +15 -4
  529. package/dist/render/text.js.map +1 -1
  530. package/dist/resolve-genre.d.ts +1 -1
  531. package/dist/resolve-genre.d.ts.map +1 -1
  532. package/dist/resolve-genre.js +4 -1
  533. package/dist/resolve-genre.js.map +1 -1
  534. package/dist/rule-genres.d.ts +24 -0
  535. package/dist/rule-genres.d.ts.map +1 -0
  536. package/dist/rule-genres.js +11 -0
  537. package/dist/rule-genres.js.map +1 -0
  538. package/dist/rule-guide.d.ts +54 -0
  539. package/dist/rule-guide.d.ts.map +1 -0
  540. package/dist/rule-guide.js +81 -0
  541. package/dist/rule-guide.js.map +1 -0
  542. package/dist/rule-load.d.ts.map +1 -1
  543. package/dist/rule-load.js +94 -32
  544. package/dist/rule-load.js.map +1 -1
  545. package/dist/rule-options.d.ts +50 -0
  546. package/dist/rule-options.d.ts.map +1 -0
  547. package/dist/rule-options.js +106 -0
  548. package/dist/rule-options.js.map +1 -0
  549. package/dist/run-semantic.d.ts +3 -1
  550. package/dist/run-semantic.d.ts.map +1 -1
  551. package/dist/run-semantic.js +8 -3
  552. package/dist/run-semantic.js.map +1 -1
  553. package/dist/run.d.ts +15 -0
  554. package/dist/run.d.ts.map +1 -1
  555. package/dist/run.js +57 -10
  556. package/dist/run.js.map +1 -1
  557. package/dist/semantic.d.ts +1 -1
  558. package/dist/semantic.d.ts.map +1 -1
  559. package/dist/semantic.js +10 -3
  560. package/dist/semantic.js.map +1 -1
  561. package/dist/sentence-shape.d.ts.map +1 -1
  562. package/dist/sentence-shape.js +4 -4
  563. package/dist/sentence-shape.js.map +1 -1
  564. package/dist/setting-problems.d.ts +2 -1
  565. package/dist/setting-problems.d.ts.map +1 -1
  566. package/dist/setting-problems.js +6 -1
  567. package/dist/setting-problems.js.map +1 -1
  568. package/dist/span-cut.d.ts +6 -0
  569. package/dist/span-cut.d.ts.map +1 -0
  570. package/dist/span-cut.js +22 -0
  571. package/dist/span-cut.js.map +1 -0
  572. package/dist/span-merge.d.ts +4 -0
  573. package/dist/span-merge.d.ts.map +1 -0
  574. package/dist/span-merge.js +12 -0
  575. package/dist/span-merge.js.map +1 -0
  576. package/dist/speaker-labels.d.ts +4 -0
  577. package/dist/speaker-labels.d.ts.map +1 -0
  578. package/dist/speaker-labels.js +106 -0
  579. package/dist/speaker-labels.js.map +1 -0
  580. package/dist/stray-space.d.ts +17 -0
  581. package/dist/stray-space.d.ts.map +1 -0
  582. package/dist/stray-space.js +66 -0
  583. package/dist/stray-space.js.map +1 -0
  584. package/dist/structure/aside-depth.d.ts +21 -0
  585. package/dist/structure/aside-depth.d.ts.map +1 -0
  586. package/dist/structure/aside-depth.js +65 -0
  587. package/dist/structure/aside-depth.js.map +1 -0
  588. package/dist/structure/build.d.ts +5 -1
  589. package/dist/structure/build.d.ts.map +1 -1
  590. package/dist/structure/build.js +29 -17
  591. package/dist/structure/build.js.map +1 -1
  592. package/dist/structure/closed-pairs.d.ts +8 -0
  593. package/dist/structure/closed-pairs.d.ts.map +1 -0
  594. package/dist/structure/closed-pairs.js +22 -0
  595. package/dist/structure/closed-pairs.js.map +1 -0
  596. package/dist/structure/date-range.d.ts +21 -0
  597. package/dist/structure/date-range.d.ts.map +1 -0
  598. package/dist/structure/date-range.js +45 -0
  599. package/dist/structure/date-range.js.map +1 -0
  600. package/dist/structure/known-mentions.d.ts +18 -0
  601. package/dist/structure/known-mentions.d.ts.map +1 -0
  602. package/dist/structure/known-mentions.js +78 -0
  603. package/dist/structure/known-mentions.js.map +1 -0
  604. package/dist/structure/numbering.d.ts +1 -0
  605. package/dist/structure/numbering.d.ts.map +1 -1
  606. package/dist/structure/numbering.js +11 -6
  607. package/dist/structure/numbering.js.map +1 -1
  608. package/dist/structure/of.d.ts +3 -1
  609. package/dist/structure/of.d.ts.map +1 -1
  610. package/dist/structure/of.js +5 -1
  611. package/dist/structure/of.js.map +1 -1
  612. package/dist/structure/percent-sum.d.ts +16 -0
  613. package/dist/structure/percent-sum.d.ts.map +1 -0
  614. package/dist/structure/percent-sum.js +104 -0
  615. package/dist/structure/percent-sum.js.map +1 -0
  616. package/dist/structure/quoted-number.d.ts +8 -0
  617. package/dist/structure/quoted-number.d.ts.map +1 -0
  618. package/dist/structure/quoted-number.js +34 -0
  619. package/dist/structure/quoted-number.js.map +1 -0
  620. package/dist/structure/relative-find.d.ts.map +1 -1
  621. package/dist/structure/relative-find.js +34 -46
  622. package/dist/structure/relative-find.js.map +1 -1
  623. package/dist/structure/relative-resolve.d.ts.map +1 -1
  624. package/dist/structure/relative-resolve.js +94 -42
  625. package/dist/structure/relative-resolve.js.map +1 -1
  626. package/dist/structure/runs.d.ts +2 -0
  627. package/dist/structure/runs.d.ts.map +1 -1
  628. package/dist/structure/runs.js +2 -2
  629. package/dist/structure/runs.js.map +1 -1
  630. package/dist/structure/sexp.d.ts +1 -1
  631. package/dist/structure/sexp.d.ts.map +1 -1
  632. package/dist/structure/sexp.js +18 -6
  633. package/dist/structure/sexp.js.map +1 -1
  634. package/dist/structure/total.d.ts +3 -0
  635. package/dist/structure/total.d.ts.map +1 -1
  636. package/dist/structure/total.js +2 -2
  637. package/dist/structure/total.js.map +1 -1
  638. package/dist/structure/universal.d.ts +14 -2
  639. package/dist/structure/universal.d.ts.map +1 -1
  640. package/dist/structure/universal.js +17 -2
  641. package/dist/structure/universal.js.map +1 -1
  642. package/dist/structure/wrapped-tail.d.ts +14 -7
  643. package/dist/structure/wrapped-tail.d.ts.map +1 -1
  644. package/dist/structure/wrapped-tail.js +33 -8
  645. package/dist/structure/wrapped-tail.js.map +1 -1
  646. package/dist/style-load.d.ts +4 -0
  647. package/dist/style-load.d.ts.map +1 -0
  648. package/dist/style-load.js +28 -0
  649. package/dist/style-load.js.map +1 -0
  650. package/dist/style-parse.d.ts +19 -0
  651. package/dist/style-parse.d.ts.map +1 -0
  652. package/dist/style-parse.js +60 -0
  653. package/dist/style-parse.js.map +1 -0
  654. package/dist/subheading-line.d.ts +6 -0
  655. package/dist/subheading-line.d.ts.map +1 -0
  656. package/dist/subheading-line.js +57 -0
  657. package/dist/subheading-line.js.map +1 -0
  658. package/dist/team-names.d.ts.map +1 -1
  659. package/dist/team-names.js +11 -14
  660. package/dist/team-names.js.map +1 -1
  661. package/dist/template-syntax.d.ts +17 -0
  662. package/dist/template-syntax.d.ts.map +1 -0
  663. package/dist/template-syntax.js +140 -0
  664. package/dist/template-syntax.js.map +1 -0
  665. package/dist/text-above.d.ts +19 -0
  666. package/dist/text-above.d.ts.map +1 -0
  667. package/dist/text-above.js +43 -0
  668. package/dist/text-above.js.map +1 -0
  669. package/dist/text-figures.d.ts +10 -0
  670. package/dist/text-figures.d.ts.map +1 -0
  671. package/dist/text-figures.js +131 -0
  672. package/dist/text-figures.js.map +1 -0
  673. package/dist/trailing-aside.d.ts +2 -0
  674. package/dist/trailing-aside.d.ts.map +1 -0
  675. package/dist/trailing-aside.js +53 -0
  676. package/dist/trailing-aside.js.map +1 -0
  677. package/dist/tree-walk.d.ts +18 -0
  678. package/dist/tree-walk.d.ts.map +1 -0
  679. package/dist/tree-walk.js +45 -0
  680. package/dist/tree-walk.js.map +1 -0
  681. package/genres.yaml +60 -2
  682. package/package.json +5 -3
  683. package/reference-headings.yaml +17 -0
  684. package/rules/adverb-overuse.yaml +19 -0
  685. package/rules/agentless-passive.yaml +19 -0
  686. package/rules/agreement-slip.yaml +49 -0
  687. package/rules/ai-generated-composite.yaml +102 -0
  688. package/rules/ai-tell.yaml +23 -0
  689. package/rules/announced-count-mismatch.yaml +57 -0
  690. package/rules/announcing-opener.yaml +51 -0
  691. package/rules/assistant-residue.yaml +52 -0
  692. package/rules/bold-density.yaml +31 -0
  693. package/rules/broken-link.yaml +65 -0
  694. package/rules/closing-cliche.yaml +33 -0
  695. package/rules/colon-lead-in.yaml +59 -0
  696. package/rules/concrete-evidence-density.yaml +41 -0
  697. package/rules/contraction-consistency.yaml +18 -0
  698. package/rules/contrast-framing.yaml +57 -0
  699. package/rules/cushion-phrase-density.yaml +25 -0
  700. package/rules/dangling-figure-reference.yaml +61 -0
  701. package/rules/dangling-reference.yaml +53 -1
  702. package/rules/date-order.yaml +33 -1
  703. package/rules/date-range-reversed.yaml +46 -0
  704. package/rules/date-weekday-mismatch.yaml +17 -1
  705. package/rules/double-keigo.yaml +16 -0
  706. package/rules/doubled-punctuation.yaml +45 -0
  707. package/rules/doubled-word.yaml +17 -1
  708. package/rules/duplicate-definition.yaml +59 -1
  709. package/rules/emoji-density.yaml +25 -0
  710. package/rules/empty-conclusion.yaml +29 -0
  711. package/rules/empty-intensifier.yaml +19 -0
  712. package/rules/excessive-hedging.yaml +19 -0
  713. package/rules/expletive-construction.yaml +19 -0
  714. package/rules/heading-echo.yaml +32 -0
  715. package/rules/heading-level-skip.yaml +78 -0
  716. package/rules/hiragana-fukushi.yaml +16 -0
  717. package/rules/image-alt-text.yaml +54 -0
  718. package/rules/internal-jargon.yaml +21 -0
  719. package/rules/katakana-long-vowel.yaml +98 -0
  720. package/rules/kutoten-consistency.yaml +53 -0
  721. package/rules/latin-spacing.yaml +23 -4
  722. package/rules/max-kanji-continuous.yaml +16 -0
  723. package/rules/max-paragraph-length.yaml +42 -2
  724. package/rules/max-sentence-length.yaml +36 -0
  725. package/rules/ngram-repetition.yaml +29 -2
  726. package/rules/no-doubled-joshi.yaml +16 -0
  727. package/rules/no-em-dash.yaml +25 -0
  728. package/rules/no-mixed-desumasu.yaml +27 -2
  729. package/rules/no-nakaguro-parallel.yaml +20 -0
  730. package/rules/numbering-gap.yaml +53 -1
  731. package/rules/oxford-comma-consistency.yaml +19 -1
  732. package/rules/padded-intro.yaml +19 -0
  733. package/rules/paragraph-length-variance.yaml +49 -0
  734. package/rules/percent-sum-mismatch.yaml +58 -0
  735. package/rules/preamble-length.yaml +56 -0
  736. package/rules/preferred-term.yaml +27 -0
  737. package/rules/proper-noun-density.yaml +26 -0
  738. package/rules/repeated-conjunction.yaml +47 -0
  739. package/rules/repeated-sentence-head.yaml +23 -0
  740. package/rules/required-sections.yaml +49 -0
  741. package/rules/risk-disclosure.yaml +22 -0
  742. package/rules/rule-of-three.yaml +97 -0
  743. package/rules/sasete-itadaku.yaml +18 -0
  744. package/rules/section-length-uniformity.yaml +89 -0
  745. package/rules/sentence-initial-conjunction-run.yaml +18 -0
  746. package/rules/sentence-rhythm.yaml +25 -0
  747. package/rules/stock-transition.yaml +55 -0
  748. package/rules/stray-space.yaml +56 -0
  749. package/rules/taigen-dome-in-prose.yaml +19 -0
  750. package/rules/title-case-consistency.yaml +42 -0
  751. package/rules/total-mismatch.yaml +37 -1
  752. package/rules/unbalanced-bracket.yaml +56 -0
  753. package/rules/undefined-acronym.yaml +23 -0
  754. package/rules/unfilled-placeholder.yaml +50 -0
  755. package/rules/unqualified-superlative.yaml +19 -0
  756. package/rules/unsourced-number.yaml +16 -0
  757. package/rules/url-run-on.yaml +45 -0
  758. package/skills/chaff/SKILL.md +70 -0
  759. package/src/announced-count.ts +148 -0
  760. package/src/bare-url.ts +35 -0
  761. package/src/baseline.ts +17 -1
  762. package/src/body-section.ts +7 -0
  763. package/src/calendar-number.ts +33 -10
  764. package/src/cli-args.ts +6 -0
  765. package/src/cli-text.ts +8 -4
  766. package/src/cli.ts +37 -37
  767. package/src/closing-numbers.ts +72 -0
  768. package/src/commands/compare.ts +80 -0
  769. package/src/commands/eval.ts +19 -8
  770. package/src/commands/feedback.ts +12 -6
  771. package/src/commands/test.ts +20 -17
  772. package/src/commands/tree.ts +41 -5
  773. package/src/compare/atom.ts +33 -0
  774. package/src/compare/clock-time.ts +86 -0
  775. package/src/compare/extract.ts +78 -0
  776. package/src/compare/fact-text.ts +68 -0
  777. package/src/compare/markup-atoms.ts +29 -0
  778. package/src/compare/match.ts +105 -0
  779. package/src/compare/outcome.ts +70 -0
  780. package/src/compare/proper-nouns.ts +65 -0
  781. package/src/compare/render.ts +102 -0
  782. package/src/compare/spans.ts +17 -0
  783. package/src/compare/text-atoms.ts +95 -0
  784. package/src/compare/text.ts +120 -0
  785. package/src/compare/tree-atoms.ts +80 -0
  786. package/src/compare/written-names.ts +26 -0
  787. package/src/config/load.ts +21 -0
  788. package/src/config/option-problems.ts +70 -0
  789. package/src/config/read.ts +8 -0
  790. package/src/config/rule-problems.ts +12 -2
  791. package/src/config/style.ts +42 -0
  792. package/src/config/warnings.ts +13 -0
  793. package/src/config/write.ts +18 -4
  794. package/src/custom/bounded-match.ts +58 -0
  795. package/src/custom/load.ts +15 -0
  796. package/src/custom/parse.ts +274 -0
  797. package/src/custom/problems.ts +89 -0
  798. package/src/custom/regex-safety.ts +118 -0
  799. package/src/custom/token-pattern.ts +84 -0
  800. package/src/detect.ts +28 -2
  801. package/src/detectors/acronym-context.ts +32 -4
  802. package/src/detectors/acronym-expansion.ts +132 -1
  803. package/src/detectors/agreement-slip.ts +191 -0
  804. package/src/detectors/ai-phrasing.ts +137 -0
  805. package/src/detectors/announced-count.ts +25 -0
  806. package/src/detectors/broken-link.ts +90 -0
  807. package/src/detectors/cited-name.ts +6 -5
  808. package/src/detectors/cited-title.ts +96 -0
  809. package/src/detectors/concrete-evidence.ts +3 -2
  810. package/src/detectors/content-morphemes.ts +19 -0
  811. package/src/detectors/contrast-frame.ts +54 -0
  812. package/src/detectors/custom.ts +89 -0
  813. package/src/detectors/dangling-figure.ts +22 -0
  814. package/src/detectors/doubled-punctuation.ts +49 -0
  815. package/src/detectors/doubled-word.ts +19 -4
  816. package/src/detectors/en-shape.ts +0 -269
  817. package/src/detectors/enumerated-runs.ts +13 -4
  818. package/src/detectors/gram-furniture.ts +30 -0
  819. package/src/detectors/gram-place.ts +9 -5
  820. package/src/detectors/gram-windows.ts +31 -0
  821. package/src/detectors/heading-case.ts +30 -2
  822. package/src/detectors/heading-code-words.ts +35 -0
  823. package/src/detectors/heading-echo.ts +18 -22
  824. package/src/detectors/heading-level-skip.ts +19 -0
  825. package/src/detectors/heading-overlap.ts +65 -0
  826. package/src/detectors/image-alt-text.ts +11 -0
  827. package/src/detectors/index.ts +49 -2
  828. package/src/detectors/kutoten-consistency.ts +96 -0
  829. package/src/detectors/lead-in.ts +3 -1
  830. package/src/detectors/letter-joined-name.ts +15 -0
  831. package/src/detectors/lexicon-match.ts +9 -2
  832. package/src/detectors/lexicon.ts +6 -2
  833. package/src/detectors/list-item.ts +122 -0
  834. package/src/detectors/list-items.ts +163 -0
  835. package/src/detectors/list-lead-in.ts +33 -0
  836. package/src/detectors/list-sentence.ts +157 -0
  837. package/src/detectors/list-view.ts +157 -0
  838. package/src/detectors/long-vowel.ts +66 -0
  839. package/src/detectors/markup-finding.ts +24 -0
  840. package/src/detectors/name-numeral.ts +4 -2
  841. package/src/detectors/orthography.ts +24 -18
  842. package/src/detectors/oxford-comma.ts +297 -0
  843. package/src/detectors/place-run.ts +7 -4
  844. package/src/detectors/placeholder-text.ts +27 -0
  845. package/src/detectors/quote-around.ts +9 -0
  846. package/src/detectors/register.ts +37 -10
  847. package/src/detectors/roman-numeral.ts +3 -0
  848. package/src/detectors/sentence-ending.ts +14 -7
  849. package/src/detectors/sentence-length.ts +16 -5
  850. package/src/detectors/signals.ts +110 -53
  851. package/src/detectors/stacked-hedge.ts +6 -3
  852. package/src/detectors/stray-space.ts +40 -0
  853. package/src/detectors/structure-tree.ts +45 -1
  854. package/src/detectors/structure.ts +13 -6
  855. package/src/detectors/superlative-name.ts +7 -4
  856. package/src/detectors/superlative-scope.ts +8 -3
  857. package/src/detectors/token-column.ts +149 -0
  858. package/src/detectors/unbalanced-bracket.ts +153 -0
  859. package/src/detectors/url-run-on.ts +27 -0
  860. package/src/document-sections.ts +46 -0
  861. package/src/document.ts +116 -127
  862. package/src/email-parts.ts +269 -0
  863. package/src/eval.ts +14 -4
  864. package/src/figure-references.ts +112 -0
  865. package/src/files.ts +5 -0
  866. package/src/genre-parse.ts +30 -5
  867. package/src/genre-suggest.ts +15 -2
  868. package/src/heading-label.ts +55 -0
  869. package/src/in-page-nav.ts +48 -19
  870. package/src/joined-view.ts +1 -0
  871. package/src/levels.ts +14 -1
  872. package/src/line-paragraphs.ts +56 -10
  873. package/src/long-vowel.ts +99 -0
  874. package/src/markdown-node.ts +19 -0
  875. package/src/markdown-read.ts +44 -0
  876. package/src/markup.ts +210 -0
  877. package/src/mask.ts +10 -19
  878. package/src/number-name.ts +152 -25
  879. package/src/opening-line.ts +17 -0
  880. package/src/orthography.ts +20 -5
  881. package/src/page-furniture.ts +11 -2
  882. package/src/paragraph-length.ts +9 -0
  883. package/src/plain-source.ts +2 -1
  884. package/src/plugin.ts +107 -1
  885. package/src/profile/for-file.ts +3 -1
  886. package/src/quoted-span.ts +10 -4
  887. package/src/reasons.ts +9 -0
  888. package/src/reference-lists.ts +91 -0
  889. package/src/render/explain.ts +47 -13
  890. package/src/render/friendly.ts +20 -9
  891. package/src/render/options.ts +58 -0
  892. package/src/render/rules-json.ts +130 -14
  893. package/src/render/rules-table.ts +91 -0
  894. package/src/render/sarif.ts +4 -4
  895. package/src/render/semantic.ts +3 -3
  896. package/src/render/severity-name.ts +10 -0
  897. package/src/render/text.ts +21 -7
  898. package/src/resolve-genre.ts +4 -1
  899. package/src/rule-genres.ts +25 -0
  900. package/src/rule-guide.ts +135 -0
  901. package/src/rule-load.ts +98 -33
  902. package/src/rule-options.ts +131 -0
  903. package/src/run-semantic.ts +28 -20
  904. package/src/run.ts +78 -11
  905. package/src/semantic.ts +11 -3
  906. package/src/sentence-shape.ts +4 -5
  907. package/src/setting-problems.ts +7 -1
  908. package/src/span-cut.ts +28 -0
  909. package/src/span-merge.ts +13 -0
  910. package/src/speaker-labels.ts +129 -0
  911. package/src/stray-space.ts +81 -0
  912. package/src/structure/aside-depth.ts +67 -0
  913. package/src/structure/build.ts +38 -19
  914. package/src/structure/closed-pairs.ts +20 -0
  915. package/src/structure/date-range.ts +69 -0
  916. package/src/structure/known-mentions.ts +96 -0
  917. package/src/structure/numbering.ts +9 -5
  918. package/src/structure/of.ts +11 -3
  919. package/src/structure/percent-sum.ts +135 -0
  920. package/src/structure/quoted-number.ts +36 -0
  921. package/src/structure/relative-find.ts +34 -47
  922. package/src/structure/relative-resolve.ts +104 -42
  923. package/src/structure/runs.ts +2 -2
  924. package/src/structure/sexp.ts +17 -5
  925. package/src/structure/total.ts +2 -2
  926. package/src/structure/universal.ts +24 -4
  927. package/src/structure/wrapped-tail.ts +38 -13
  928. package/src/style-load.ts +28 -0
  929. package/src/style-parse.ts +77 -0
  930. package/src/subheading-line.ts +68 -0
  931. package/src/team-names.ts +13 -13
  932. package/src/template-syntax.ts +164 -0
  933. package/src/text-above.ts +49 -0
  934. package/src/text-figures.ts +147 -0
  935. package/src/trailing-aside.ts +50 -0
  936. package/src/tree-walk.ts +48 -0
  937. package/styles/bunkacho.yaml +25 -0
  938. package/styles/ieice.yaml +29 -0
  939. package/styles/jis-z8301-2011.yaml +25 -0
@@ -0,0 +1,42 @@
1
+ import type { Config } from "./load.ts";
2
+ import type { StyleDefinition } from "../style-parse.ts";
3
+ import type { Texts, UiLanguage } from "../ui.ts";
4
+
5
+ /** How a style is named where a setting's source is shown (rules --json, explain). */
6
+ export const styleSource = (id: string): string => `style: ${id}`;
7
+
8
+ /** Where a rule's level came from when the style set it; undefined when chaff.yaml, the genre or the default did. */
9
+ export const styleLevelSource = (config: Pick<Config, "applied">, ruleId: string): string | undefined =>
10
+ config.applied?.levelsFrom.includes(ruleId) === true ? styleSource(config.applied.style) : undefined;
11
+
12
+ /**
13
+ * chaff.yaml with its style applied. A style's levels sit under chaff.yaml's own rules and over the genre's preset, since
14
+ * they join rules (which run.ts already puts over the preset). Its options become a layer under chaff.yaml's options.
15
+ * Without a style, or with one chaff does not have (settingProblems stops the run on that), the config is unchanged.
16
+ */
17
+ export const withStyle = (config: Config, styles: readonly StyleDefinition[]): Config => {
18
+ const style = styles.find((entry) => entry.id === config.style);
19
+ if (style === undefined) return config;
20
+ const fromStyle = Object.keys(style.rules).filter((id) => config.rules[id] === undefined && config.limits[id] === undefined);
21
+ return {
22
+ ...config,
23
+ rules: { ...style.rules, ...config.rules },
24
+ applied: { style: style.id, levelsFrom: fromStyle, options: style.options },
25
+ };
26
+ };
27
+
28
+ const TEXT: Texts<{ readonly unknown: (where: string, style: string, known: string) => string }> = {
29
+ ja: {
30
+ unknown: (where, style, known) => `${where}: style: ${style} というスタイルはありません。使えるのは ${known} です`,
31
+ },
32
+ en: {
33
+ unknown: (where, style, known) => `${where}: there is no style named ${style}. The styles are ${known}`,
34
+ },
35
+ };
36
+
37
+ /** A style chaff does not have. It stops the run, like an unknown genre: running without it would check less than was asked. */
38
+ export const styleProblems = (config: Pick<Config, "style" | "path">, styles: readonly StyleDefinition[], ui: UiLanguage): string[] => {
39
+ const written = config.style;
40
+ if (written === undefined || styles.some((style) => style.id === written)) return [];
41
+ return [`chaff: ${TEXT[ui].unknown(config.path ?? "chaff.yaml", written, styles.map((style) => style.id).join(", "))}`];
42
+ };
@@ -0,0 +1,13 @@
1
+ import type { Config } from "./load.ts";
2
+ import type { RuleDefinition } from "../plugin.ts";
3
+ import type { UiLanguage } from "../ui.ts";
4
+ import { ruleProblems } from "./rule-problems.ts";
5
+ import { nameProblems } from "./name-problems.ts";
6
+ import { configOptionProblems } from "./option-problems.ts";
7
+
8
+ /** Everything in chaff.yaml that has no effect: unknown rules or levels, unreadable names, options that do not apply. Said before the results. */
9
+ export const settingWarnings = (config: Config, rules: readonly RuleDefinition[], ui: UiLanguage): string[] => [
10
+ ...ruleProblems(config, rules, ui),
11
+ ...nameProblems(config, ui),
12
+ ...configOptionProblems(config, rules, ui),
13
+ ];
@@ -1,7 +1,8 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { Scalar, YAMLMap, isMap, isScalar, parseDocument, type Document } from "yaml";
3
- import { definedLevels } from "../levels.ts";
4
- import { localized } from "../render/text.ts";
3
+ import { definedLevels, severityAt } from "../levels.ts";
4
+ import { SEVERITY_NAME, withArticle } from "../render/severity-name.ts";
5
+ import { readableText } from "../render/text.ts";
5
6
  import type { Level, RuleDefinition } from "../plugin.ts";
6
7
  import { uiLanguageOf, type Texts } from "../ui.ts";
7
8
 
@@ -10,6 +11,7 @@ const TEXT: Texts<{
10
11
  readonly noSuchLevel: (id: string, level: string) => string;
11
12
  readonly hasReason: (id: string, previous: string) => string;
12
13
  readonly done: (id: string, level: string, path: string) => string;
14
+ readonly severityMoved: (from: string, to: string) => string;
13
15
  }> = {
14
16
  ja: {
15
17
  template: `# chaff.yaml — このチームの文章規範
@@ -22,6 +24,7 @@ rules:
22
24
  noSuchLevel: (id, level) => `${id} に ${level} はありません。normal と同じ設定です。\n設定は変更しませんでした。`,
23
25
  hasReason: (id, previous) => `${id} には既に理由が書かれています:\n ${previous}\n値を変えるときは --why で新しい理由を書いてください。`,
24
26
  done: (id, level, path) => `${id} を ${level} にしました(${path})`,
27
+ severityMoved: (from, to) => `このルールに数の上限はありません。指摘は消えず、${from} ではなく ${to} として出ます。`,
25
28
  },
26
29
  en: {
27
30
  template: `# chaff.yaml — this team's writing rules
@@ -34,6 +37,7 @@ rules:
34
37
  noSuchLevel: (id, level) => `${id} has no ${level} level; it is the same as normal.\nThe settings were not changed.`,
35
38
  hasReason: (id, previous) => `${id} already has a reason:\n ${previous}\nTo change the level, give a new reason with --why.`,
36
39
  done: (id, level, path) => `Set ${id} to ${level} (${path})`,
40
+ severityMoved: (from, to) => `This rule has no numeric limit: its findings still show, as ${withArticle(to)} instead of ${withArticle(from)}.`,
37
41
  },
38
42
  };
39
43
 
@@ -47,7 +51,8 @@ const reasonOf = (value: unknown): string | undefined => {
47
51
  return text.length === 0 ? undefined : text;
48
52
  };
49
53
 
50
- const ruleComment = (rule: RuleDefinition, language: string): string => ` ${localized(rule.name, language)}\n ${localized(rule.why, language)}`;
54
+ const ruleComment = (rule: RuleDefinition, language: string): string =>
55
+ ` ${readableText(rule, rule.name, language)}\n ${readableText(rule, rule.why, language)}`;
51
56
 
52
57
  const load = (path: string, language: string): Document => parseDocument(existsSync(path) ? readFileSync(path, "utf8") : TEXT[uiLanguageOf(language)].template);
53
58
 
@@ -83,5 +88,14 @@ export const applyLevel = (path: string, rule: RuleDefinition, level: Level, why
83
88
  existing.value = value;
84
89
  }
85
90
  writeFileSync(path, String(doc), "utf8");
86
- return { ok: true, message: text.done(rule.id, level, path) };
91
+ return { ok: true, message: [text.done(rule.id, level, path), ...severityNote(rule, level, language)].join("\n") };
92
+ };
93
+
94
+ /** relax on a rule with nothing to count keeps its findings and lowers them; say so, or the change looks like it did nothing. */
95
+ const severityNote = (rule: RuleDefinition, level: Level, language: string): string[] => {
96
+ if (level === "off") return [];
97
+ const [from, to] = [severityAt(rule, "normal"), severityAt(rule, level)];
98
+ if (from === to) return [];
99
+ const ui = uiLanguageOf(language);
100
+ return [TEXT[ui].severityMoved(SEVERITY_NAME[ui][from], SEVERITY_NAME[ui][to])];
87
101
  };
@@ -0,0 +1,58 @@
1
+ import { createContext, Script } from "node:vm";
2
+
3
+ // A team's regular expression, run with a time limit. regex-safety.ts refuses the shapes known to run away before a pattern
4
+ // is used; no reading of the pattern can prove every shape safe, so this is the backstop. V8 can interrupt a regular
5
+ // expression only through vm's timeout, so the matching runs in a vm context.
6
+
7
+ /** How long one rule's pattern may take over one document. Far above what a sane pattern needs on any real document. */
8
+ export const PATTERN_BUDGET_MS = 1000;
9
+
10
+ /** A pattern that did not finish within its budget. run.ts lists the rule as not run, with this as the reason. */
11
+ export class PatternTimeout extends Error {
12
+ readonly budget_ms: number;
13
+ constructor(budgetMs: number) {
14
+ super(`the pattern did not finish within ${String(budgetMs)} ms`);
15
+ this.name = "PatternTimeout";
16
+ this.budget_ms = budgetMs;
17
+ }
18
+ }
19
+
20
+ /** Each text's matches: where it starts and what it matched. Empty matches are left out. */
21
+ export type TextMatches = readonly (readonly { readonly index: number; readonly text: string }[])[];
22
+
23
+ const SCRIPT = new Script(
24
+ `texts.map((text) => [...text.matchAll(new RegExp(source, flags))].filter((m) => m[0] !== "").map((m) => ({ index: m.index, text: m[0] })))`,
25
+ );
26
+
27
+ const isTimeout = (error: unknown): boolean => typeof error === "object" && error !== null && "code" in error && error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT";
28
+
29
+ const isMatches = (value: unknown): value is TextMatches =>
30
+ Array.isArray(value) &&
31
+ value.every(
32
+ (entry: unknown) =>
33
+ Array.isArray(entry) &&
34
+ entry.every(
35
+ (match: unknown) =>
36
+ typeof match === "object" &&
37
+ match !== null &&
38
+ "index" in match &&
39
+ typeof match.index === "number" &&
40
+ "text" in match &&
41
+ typeof match.text === "string",
42
+ ),
43
+ );
44
+
45
+ /** Every match of the pattern (flags without g) in each text, or PatternTimeout when the whole run takes longer than budgetMs. */
46
+ export const boundedMatches = (source: string, flags: string, texts: readonly string[], budgetMs: number = PATTERN_BUDGET_MS): TextMatches => {
47
+ const context = createContext({ texts: [...texts], source, flags: `g${flags}` });
48
+ try {
49
+ const result: unknown = SCRIPT.runInContext(context, { timeout: budgetMs });
50
+ // The result is built in another context; copy it through JSON so it holds plain values of this one.
51
+ const plain: unknown = JSON.parse(JSON.stringify(result));
52
+ if (!isMatches(plain)) throw new Error("chaff: the pattern's matches came back in an unexpected shape");
53
+ return plain;
54
+ } catch (error) {
55
+ if (isTimeout(error)) throw new PatternTimeout(budgetMs);
56
+ throw error;
57
+ }
58
+ };
@@ -0,0 +1,15 @@
1
+ import type { Config } from "../config/load.ts";
2
+ import type { RuleDefinition } from "../plugin.ts";
3
+ import { loadRules } from "../rule-load.ts";
4
+ import { loadGenres } from "../genre-load.ts";
5
+ import { parseCustomRules, type CustomRules } from "./parse.ts";
6
+
7
+ /** The team's custom_rules as rules, with what could not be read. A team's rule applies to every genre, like the team's words. */
8
+ export const customRulesOf = (config: Pick<Config, "customRules">): CustomRules =>
9
+ parseCustomRules(config.customRules, {
10
+ builtIn: new Set(loadRules("en").map((rule) => rule.id)),
11
+ useFor: loadGenres().groups.map((group) => group.id),
12
+ });
13
+
14
+ /** Every rule a run knows for a language: chaff's own, then the team's. Where the team's cannot be read, settingProblems stops the run. */
15
+ export const rulesOf = (language: string, config: Pick<Config, "customRules">): RuleDefinition[] => [...loadRules(language), ...customRulesOf(config).rules];
@@ -0,0 +1,274 @@
1
+ import type { CustomSpec, LevelTable, Localized, RuleDefinition, Severity, TokenCondition } from "../plugin.ts";
2
+ import { regexRefusal, type RegexRefusal } from "./regex-safety.ts";
3
+ import { posTags } from "./token-pattern.ts";
4
+
5
+ // custom_rules in chaff.yaml: a team's own deterministic rules, written without code. Each becomes a RuleDefinition like the
6
+ // built-in ones, so findings, explain, rules --json, stet, the baseline and SARIF treat it the same. Pure: the YAML comes in parsed.
7
+
8
+ export const CUSTOM_TYPES = ["words", "pattern", "tokens"] as const;
9
+
10
+ /** Reserved for a small Node function a team writes. Refused with its own message until it is supported. */
11
+ const RESERVED_TYPES: readonly string[] = ["module"];
12
+
13
+ export type CustomProblem =
14
+ | { readonly kind: "not-a-list" }
15
+ | { readonly kind: "not-a-map"; readonly at: string }
16
+ | { readonly kind: "bad-id"; readonly at: string }
17
+ | { readonly kind: "duplicate-id"; readonly at: string }
18
+ | { readonly kind: "built-in-id"; readonly at: string }
19
+ | { readonly kind: "unknown-type"; readonly at: string; readonly written: string }
20
+ | { readonly kind: "not-yet"; readonly at: string; readonly written: string }
21
+ | { readonly kind: "missing"; readonly at: string; readonly field: string }
22
+ | { readonly kind: "unpaired-example"; readonly at: string }
23
+ | { readonly kind: "bad-level"; readonly at: string; readonly written: string }
24
+ | { readonly kind: "bad-languages"; readonly at: string }
25
+ | { readonly kind: "no-words"; readonly at: string }
26
+ | { readonly kind: "bad-pattern"; readonly at: string; readonly refusal: RegexRefusal }
27
+ | { readonly kind: "no-tokens"; readonly at: string }
28
+ | { readonly kind: "bad-token"; readonly at: string; readonly index: number }
29
+ | { readonly kind: "unknown-pos"; readonly at: string; readonly written: string };
30
+
31
+ export type CustomRules = { readonly rules: readonly RuleDefinition[]; readonly problems: readonly CustomProblem[] };
32
+
33
+ /** What parsing needs to know: the built-in rule ids (a team's rule may not take one) and the genres a rule applies to. */
34
+ export type CustomContext = { readonly builtIn: ReadonlySet<string>; readonly useFor: readonly string[] };
35
+
36
+ const RULE_ID = /^[a-z][a-z0-9-]*$/u;
37
+ const SEVERITIES: readonly Severity[] = ["info", "warning", "error"];
38
+
39
+ const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
40
+
41
+ const nonEmpty = (value: unknown): value is string => typeof value === "string" && value.trim() !== "";
42
+
43
+ /** Texts by language ({ ja, en } or any language's id). undefined when there is none. */
44
+ const byLanguageOf = (value: unknown): Localized | undefined => {
45
+ if (!isRecord(value)) return undefined;
46
+ const entries = Object.entries(value).filter((entry): entry is [string, string] => nonEmpty(entry[1]));
47
+ return entries.length === 0 ? undefined : Object.fromEntries(entries.map(([language, text]) => [language, text.trim()]));
48
+ };
49
+
50
+ /** A text by language, or one string for ja and en (and, through the "en" fallback, for any other language). */
51
+ const localizedOf = (value: unknown): Localized | undefined => (nonEmpty(value) ? { ja: value.trim(), en: value.trim() } : byLanguageOf(value));
52
+
53
+ /** The key an example side written as one string is kept under: it reads the same in every language. */
54
+ const EVERY_LANGUAGE = "*";
55
+
56
+ const exampleSideOf = (value: unknown): Localized | undefined => (nonEmpty(value) ? { [EVERY_LANGUAGE]: value.trim() } : byLanguageOf(value));
57
+
58
+ /** One rule's own problems, with the rule's id (or its place in the list) as where. */
59
+ type Checked<T> = { readonly value: T | undefined; readonly problems: readonly CustomProblem[] };
60
+
61
+ const ok = <T>(value: T): Checked<T> => ({ value, problems: [] });
62
+ const failed = <T>(...problems: CustomProblem[]): Checked<T> => ({ value: undefined, problems });
63
+
64
+ type Pair = { readonly avoid: string; readonly use: string };
65
+
66
+ /** words as a map (avoid: use) or a list (words to point at, with nothing to use instead). */
67
+ const pairsOf = (raw: unknown): Pair[] => {
68
+ if (Array.isArray(raw)) return raw.filter(nonEmpty).map((avoid) => ({ avoid: avoid.trim(), use: "" }));
69
+ if (!isRecord(raw)) return [];
70
+ return Object.entries(raw).flatMap(([avoid, use]) => (avoid.trim() === "" ? [] : [{ avoid: avoid.trim(), use: nonEmpty(use) ? use.trim() : "" }]));
71
+ };
72
+
73
+ const printed = (value: unknown): string => JSON.stringify(value) ?? "undefined";
74
+
75
+ const wordsOf = (raw: unknown, at: string): Checked<CustomSpec> => {
76
+ const usable = pairsOf(raw).filter((pair) => pair.avoid !== pair.use);
77
+ return usable.length === 0 ? failed({ kind: "no-words", at }) : ok({ type: "words", words: usable });
78
+ };
79
+
80
+ const patternOf = (raw: Record<string, unknown>, at: string): Checked<CustomSpec> => {
81
+ const pattern = raw["pattern"];
82
+ if (!nonEmpty(pattern)) return failed({ kind: "missing", at, field: "pattern" });
83
+ const flags = raw["ignore_case"] === true ? "iu" : "u";
84
+ const refusal = regexRefusal(pattern, flags);
85
+ return refusal === undefined ? ok({ type: "pattern", pattern, flags }) : failed({ kind: "bad-pattern", at, refusal });
86
+ };
87
+
88
+ const posOf = (raw: unknown, at: string): Checked<readonly string[]> => {
89
+ if (raw === undefined) return ok([]);
90
+ const written = (Array.isArray(raw) ? raw : [raw]).map((entry: unknown) => (typeof entry === "string" ? entry : printed(entry)));
91
+ const unknown = written.find((name) => posTags(name) === undefined);
92
+ if (unknown !== undefined) return failed({ kind: "unknown-pos", at, written: unknown });
93
+ return ok([...new Set(written.flatMap((name) => posTags(name) ?? []))]);
94
+ };
95
+
96
+ const conditionOf = (raw: unknown, index: number, at: string): Checked<TokenCondition> => {
97
+ if (!isRecord(raw)) return failed({ kind: "bad-token", at, index });
98
+ const pos = posOf(raw["pos"], at);
99
+ if (pos.value === undefined) return failed(...pos.problems);
100
+ // lemma is the linguists' word for the base form; either may be written.
101
+ const written = raw["base"] ?? raw["lemma"];
102
+ const base = nonEmpty(written) ? written.trim() : undefined;
103
+ const surface = nonEmpty(raw["surface"]) ? raw["surface"].trim() : undefined;
104
+ if (pos.value.length === 0 && base === undefined && surface === undefined) return failed({ kind: "bad-token", at, index });
105
+ return ok({ ...(pos.value.length === 0 ? {} : { pos: pos.value }), ...(base === undefined ? {} : { base }), ...(surface === undefined ? {} : { surface }) });
106
+ };
107
+
108
+ const tokensOf = (raw: unknown, at: string): Checked<CustomSpec> => {
109
+ if (!Array.isArray(raw) || raw.length === 0) return failed({ kind: "no-tokens", at });
110
+ const checked = raw.map((entry: unknown, index) => conditionOf(entry, index + 1, at));
111
+ const problems = checked.flatMap((entry) => entry.problems);
112
+ const tokens = checked.flatMap((entry) => (entry.value === undefined ? [] : [entry.value]));
113
+ return problems.length > 0 ? failed(...problems) : ok({ type: "tokens", tokens });
114
+ };
115
+
116
+ const specOf = (raw: Record<string, unknown>, type: string, at: string): Checked<CustomSpec> => {
117
+ if (type === "words") return wordsOf(raw["words"], at);
118
+ if (type === "pattern") return patternOf(raw, at);
119
+ return tokensOf(raw["tokens"], at);
120
+ };
121
+
122
+ const typeOf = (raw: Record<string, unknown>, at: string): Checked<string> => {
123
+ const type = raw["type"];
124
+ if (!nonEmpty(type)) return failed({ kind: "missing", at, field: "type" });
125
+ if (RESERVED_TYPES.includes(type)) return failed({ kind: "not-yet", at, written: type });
126
+ return CUSTOM_TYPES.some((known) => known === type) ? ok(type) : failed({ kind: "unknown-type", at, written: type });
127
+ };
128
+
129
+ const severityOf = (raw: unknown, at: string): Checked<Severity> => {
130
+ if (raw === undefined) return ok("warning");
131
+ const severity = SEVERITIES.find((entry) => entry === raw);
132
+ return severity === undefined ? failed({ kind: "bad-level", at, written: typeof raw === "string" ? raw : printed(raw) }) : ok(severity);
133
+ };
134
+
135
+ /** The four words as severities: normal is the rule's own level, relaxed one lower, strict one higher, where there is one. */
136
+ const levelsFor = (severity: Severity): LevelTable => {
137
+ const rank = SEVERITIES.indexOf(severity) + 1;
138
+ return { ...(rank < SEVERITIES.length ? { strict: rank + 1 } : {}), normal: rank, ...(rank > 1 ? { relaxed: rank - 1 } : {}) };
139
+ };
140
+
141
+ type Texts = { readonly name: Localized; readonly why: Localized; readonly how_to_fix: Localized; readonly before: Localized; readonly after: Localized };
142
+
143
+ const textsOf = (raw: Record<string, unknown>, at: string): Checked<Texts> => {
144
+ const example = isRecord(raw["example"]) ? raw["example"] : {};
145
+ const found = {
146
+ name: localizedOf(raw["name"]),
147
+ why: localizedOf(raw["why"]),
148
+ how_to_fix: localizedOf(raw["how_to_fix"]),
149
+ before: exampleSideOf(example["before"]),
150
+ after: exampleSideOf(example["after"]),
151
+ };
152
+ const missing = Object.entries(found).flatMap(([field, text]) =>
153
+ text === undefined ? [{ kind: "missing" as const, at, field: field === "before" || field === "after" ? `example.${field}` : field }] : [],
154
+ );
155
+ const { name, why, how_to_fix: howToFix, before, after } = found;
156
+ if (name === undefined || why === undefined || howToFix === undefined || before === undefined || after === undefined) return failed(...missing);
157
+ return ok({ name, why, how_to_fix: howToFix, before, after });
158
+ };
159
+
160
+ const languagesOf = (raw: unknown, at: string): Checked<readonly string[] | undefined> => {
161
+ if (raw === undefined) return ok(undefined);
162
+ const list = Array.isArray(raw) ? raw : [raw];
163
+ return list.length > 0 && list.every(nonEmpty) ? ok(list.map((entry: string) => entry.trim())) : failed({ kind: "bad-languages", at });
164
+ };
165
+
166
+ /** The message when a rule does not write one: the replacement for a word list, else the rule's name and what was found. */
167
+ const defaultMessage = (spec: CustomSpec, name: Localized): Localized => {
168
+ if (spec.type === "words" && spec.words.every((pair) => pair.use !== ""))
169
+ return { ja: "「{matched}」は「{preferred}」と書きます", en: 'Write "{preferred}", not "{matched}"' };
170
+ return Object.fromEntries(Object.entries(name).map(([language, text]) => [language, language === "ja" ? `${text}:「{matched}」` : `${text}: "{matched}"`]));
171
+ };
172
+
173
+ const PLACEHOLDERS: Readonly<Record<string, Localized>> = {
174
+ matched: { ja: "見つけた語句", en: "the text found" },
175
+ preferred: { ja: "使う書き方", en: "the spelling to use" },
176
+ };
177
+
178
+ const HOW_TO_FIND: Readonly<Record<CustomSpec["type"], string>> = { words: "custom-words", pattern: "custom-pattern", tokens: "custom-tokens" };
179
+
180
+ type Example = { readonly before: string; readonly after: string };
181
+
182
+ type Parts = {
183
+ readonly spec: CustomSpec;
184
+ readonly severity: Severity;
185
+ readonly texts: Texts;
186
+ readonly languages: readonly string[] | undefined;
187
+ readonly examples: Readonly<Record<string, Example>>;
188
+ };
189
+
190
+ const READER_LANGUAGES: readonly string[] = ["ja", "en"];
191
+
192
+ /** The example in each language the rule checks, where both before and after are written in it. A string counts for both. */
193
+ const examplesOf = (texts: Texts, languages: readonly string[] | undefined): Record<string, Example> =>
194
+ Object.fromEntries(
195
+ (languages ?? READER_LANGUAGES).flatMap((language) => {
196
+ const [before, after] = [texts.before[language] ?? texts.before[EVERY_LANGUAGE], texts.after[language] ?? texts.after[EVERY_LANGUAGE]];
197
+ return before === undefined || after === undefined ? [] : [[language, { before, after }]];
198
+ }),
199
+ );
200
+
201
+ const definitionOf = (id: string, raw: Record<string, unknown>, parts: Parts, useFor: readonly string[]): RuleDefinition => ({
202
+ id,
203
+ layer: parts.spec.type === "tokens" ? "L3" : "L2",
204
+ status: "stable",
205
+ name: parts.texts.name,
206
+ why: parts.texts.why,
207
+ how_to_fix: parts.texts.how_to_fix,
208
+ message: localizedOf(raw["message"]) ?? defaultMessage(parts.spec, parts.texts.name),
209
+ messages: {},
210
+ placeholders: PLACEHOLDERS,
211
+ levels: levelsFor(parts.severity),
212
+ level_sets: "severity",
213
+ by_genre: {},
214
+ how_to_find: HOW_TO_FIND[parts.spec.type],
215
+ word_list: undefined,
216
+ extra_word_lists: [],
217
+ what_to_check: undefined,
218
+ where: undefined,
219
+ full_sentence: undefined,
220
+ requires: parts.spec.type === "tokens" ? ["pos"] : [],
221
+ uses: [],
222
+ from: [],
223
+ languages: parts.languages,
224
+ use_for: useFor,
225
+ severity: parts.severity,
226
+ custom: parts.spec,
227
+ // The reference and explain read a rule's plain-language fields from guide; a team's rule is listed with the team's words.
228
+ guide: {
229
+ group: "team",
230
+ summary: parts.texts.name,
231
+ examples: parts.examples,
232
+ notFlagged: {},
233
+ levelMeaning: {},
234
+ },
235
+ });
236
+
237
+ const idOf = (raw: Record<string, unknown>, index: number, seen: ReadonlySet<string>, builtIn: ReadonlySet<string>): Checked<string> => {
238
+ const id = raw["id"];
239
+ const at = typeof id === "string" && id !== "" ? id : `#${String(index + 1)}`;
240
+ if (typeof id !== "string" || !RULE_ID.test(id)) return failed({ kind: "bad-id", at });
241
+ if (builtIn.has(id)) return failed({ kind: "built-in-id", at });
242
+ return seen.has(id) ? failed({ kind: "duplicate-id", at }) : ok(id);
243
+ };
244
+
245
+ const ruleOf = (raw: unknown, index: number, seen: ReadonlySet<string>, context: CustomContext): Checked<RuleDefinition> => {
246
+ if (!isRecord(raw)) return failed({ kind: "not-a-map", at: `#${String(index + 1)}` });
247
+ const id = idOf(raw, index, seen, context.builtIn);
248
+ const at = id.value ?? (nonEmpty(raw["id"]) ? raw["id"] : `#${String(index + 1)}`);
249
+ const type = typeOf(raw, at);
250
+ const spec = type.value === undefined ? failed<CustomSpec>() : specOf(raw, type.value, at);
251
+ const severity = severityOf(raw["level"], at);
252
+ const texts = textsOf(raw, at);
253
+ const languages = languagesOf(raw["languages"], at);
254
+ const examples = texts.value === undefined ? {} : examplesOf(texts.value, languages.value);
255
+ const unpaired: CustomProblem[] = texts.value !== undefined && Object.keys(examples).length === 0 ? [{ kind: "unpaired-example", at }] : [];
256
+ const problems = [...[id, type, spec, severity, texts, languages].flatMap((checked) => checked.problems), ...unpaired];
257
+ if (id.value === undefined || spec.value === undefined || severity.value === undefined || texts.value === undefined || problems.length > 0)
258
+ return failed(...problems);
259
+ const parts = { spec: spec.value, severity: severity.value, texts: texts.value, languages: languages.value, examples };
260
+ return ok(definitionOf(id.value, raw, parts, context.useFor));
261
+ };
262
+
263
+ /** custom_rules as written. Every problem is reported; a rule with a problem is left out, and the run is stopped by the caller. */
264
+ export const parseCustomRules = (raw: unknown, context: CustomContext): CustomRules => {
265
+ if (raw === undefined || raw === null) return { rules: [], problems: [] };
266
+ if (!Array.isArray(raw)) return { rules: [], problems: [{ kind: "not-a-list" }] };
267
+ return raw.reduce<{ rules: RuleDefinition[]; problems: CustomProblem[] }>(
268
+ (acc, entry: unknown, index) => {
269
+ const checked = ruleOf(entry, index, new Set(acc.rules.map((rule) => rule.id)), context);
270
+ return { rules: checked.value === undefined ? acc.rules : [...acc.rules, checked.value], problems: [...acc.problems, ...checked.problems] };
271
+ },
272
+ { rules: [], problems: [] },
273
+ );
274
+ };
@@ -0,0 +1,89 @@
1
+ import type { Config } from "../config/load.ts";
2
+ import type { Texts, UiLanguage } from "../ui.ts";
3
+ import type { CustomProblem } from "./parse.ts";
4
+ import { customRulesOf } from "./load.ts";
5
+ import { MAX_PATTERN_LENGTH, MAX_REPEATS, type RegexRefusal } from "./regex-safety.ts";
6
+ import { POS_WRITTEN_NAMES } from "./token-pattern.ts";
7
+
8
+ /** Each problem's sentence, with {at}, {written}, {field}, {index}, {refusal} and {names} filled in from the problem. */
9
+ type Text = { readonly problems: Readonly<Record<CustomProblem["kind"], string>>; readonly refusal: Readonly<Record<RegexRefusal, string>> };
10
+
11
+ const TEXT: Texts<Text> = {
12
+ ja: {
13
+ refusal: {
14
+ "too-long": `${String(MAX_PATTERN_LENGTH)} 字を超えています。いくつかのルールに分けてください`,
15
+ "nested-quantifier": "繰り返しの中に繰り返しがあります((a+)+ のような形)。長い行で止まらなくなるので使えません",
16
+ "too-many-repeats": `回数の決まらない繰り返し(* や + や {1,9})が ${String(MAX_REPEATS)} つを超えています。長い行で止まらなくなることがあります`,
17
+ backreference: "後方参照(\\1)は使えません。長い行で止まらなくなることがあるためです",
18
+ "empty-match": "何も無い所にも当たります。すべての文で指摘が出てしまいます",
19
+ invalid: "正規表現として読めません",
20
+ },
21
+ problems: {
22
+ "not-a-list": "custom_rules はルールの並び(- id: …)で書いてください",
23
+ "not-a-map": "custom_rules の {at}: id や type を持つ項目として書いてください",
24
+ "bad-id": "custom_rules の {at}: id は英小文字で始まり、英小文字・数字・ハイフンだけで書きます(例: team-no-tbd)",
25
+ "duplicate-id": "custom_rules の {at}: 同じ id のルールがもう一つあります",
26
+ "built-in-id": "custom_rules の {at}: chaff のルールと同じ id です。別の id にしてください",
27
+ "unknown-type": "custom_rules の {at}: type: {written} は使えません(words / pattern / tokens)",
28
+ "not-yet": "custom_rules の {at}: type: {written} はまだ使えません(words / pattern / tokens)",
29
+ missing: "custom_rules の {at}: {field} がありません",
30
+ "unpaired-example": "custom_rules の {at}: example の before と after を、ルールが見る言語の同じ言語で書いてください",
31
+ "bad-level": "custom_rules の {at}: level: {written} は読めません(error / warning / info)",
32
+ "bad-languages": "custom_rules の {at}: languages は言語の並びで書いてください([ja] や [ja, en])",
33
+ "no-words": "custom_rules の {at}: words に語がありません(「使わない書き方: 使う書き方」か語の並び)",
34
+ "no-tokens": "custom_rules の {at}: tokens に語の条件がありません(- { pos: 名詞 } のように並べます)",
35
+ "bad-token": "custom_rules の {at}: tokens の {index} 番目に pos・base・surface のどれもありません",
36
+ "unknown-pos": "custom_rules の {at}: 品詞 {written} は知りません({names})",
37
+ "bad-pattern": "custom_rules の {at}: pattern を使えません。{refusal}",
38
+ },
39
+ },
40
+ en: {
41
+ refusal: {
42
+ "too-long": `it is longer than ${String(MAX_PATTERN_LENGTH)} characters; split it into several rules`,
43
+ "nested-quantifier": "it repeats something that repeats (a shape like (a+)+), which can run for minutes on a long line",
44
+ "too-many-repeats": `it has more than ${String(MAX_REPEATS)} repeats of varying count (*, + or {1,9}), which can run for minutes on a long line`,
45
+ backreference: "backreferences (\\1) are not allowed, since they can run for minutes on a long line",
46
+ "empty-match": "it matches an empty string, so it would report every sentence",
47
+ invalid: "it is not a regular expression",
48
+ },
49
+ problems: {
50
+ "not-a-list": "write custom_rules as a list of rules (- id: …)",
51
+ "not-a-map": "custom_rules {at}: write each rule as an entry with id and type",
52
+ "bad-id": "custom_rules {at}: an id starts with a lowercase letter and has only lowercase letters, digits and hyphens (team-no-tbd)",
53
+ "duplicate-id": "custom_rules {at}: another rule has the same id",
54
+ "built-in-id": "custom_rules {at}: chaff has a rule with this id; choose another",
55
+ "unknown-type": "custom_rules {at}: type: {written} is not a type (words / pattern / tokens)",
56
+ "not-yet": "custom_rules {at}: type: {written} is not supported yet (words / pattern / tokens)",
57
+ missing: "custom_rules {at}: {field} is missing",
58
+ "unpaired-example": "custom_rules {at}: write example's before and after in the same language, one the rule checks",
59
+ "bad-level": "custom_rules {at}: cannot read level: {written} (error / warning / info)",
60
+ "bad-languages": "custom_rules {at}: write languages as a list ([en] or [ja, en])",
61
+ "no-words": "custom_rules {at}: words has no words (avoid: use pairs, or a list)",
62
+ "no-tokens": "custom_rules {at}: tokens has no conditions (- { pos: noun } and so on)",
63
+ "bad-token": "custom_rules {at}: token {index} has none of pos, base and surface",
64
+ "unknown-pos": "custom_rules {at}: unknown part of speech {written} ({names})",
65
+ "bad-pattern": "custom_rules {at}: the pattern cannot be used: {refusal}",
66
+ },
67
+ },
68
+ };
69
+
70
+ const PLACEHOLDER = /\{(at|written|field|index|refusal|names)\}/gu;
71
+
72
+ /** The values a problem's sentence names. Each kind carries only some of them. */
73
+ const valuesOf = (problem: CustomProblem, text: Text): Readonly<Record<string, string>> => ({
74
+ at: "at" in problem ? problem.at : "",
75
+ written: "written" in problem ? problem.written : "",
76
+ field: "field" in problem ? problem.field : "",
77
+ index: "index" in problem ? String(problem.index) : "",
78
+ refusal: "refusal" in problem ? text.refusal[problem.refusal] : "",
79
+ names: POS_WRITTEN_NAMES.join(" / "),
80
+ });
81
+
82
+ const sentenceOf = (problem: CustomProblem, text: Text): string => {
83
+ const values = valuesOf(problem, text);
84
+ return text.problems[problem.kind].replace(PLACEHOLDER, (_whole, key: string) => values[key] ?? "");
85
+ };
86
+
87
+ /** What in custom_rules cannot run. Each stops the run: a team's rule that silently does not run looks like a clean document. */
88
+ export const customRuleProblems = (config: Pick<Config, "customRules" | "path">, ui: UiLanguage): string[] =>
89
+ customRulesOf(config).problems.map((problem) => `chaff: ${config.path ?? "chaff.yaml"}: ${sentenceOf(problem, TEXT[ui])}`);