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
package/src/plugin.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  // 言語アダプタと genre pack が依存してよい唯一の面。spec §6。
2
2
  // ここに実装を置かない。型だけを置く。
3
3
 
4
+ import type { RuleGuide } from "./rule-guide.ts";
5
+
4
6
  export type Span = { readonly start: number; readonly end: number };
5
7
 
6
8
  /**
@@ -17,8 +19,15 @@ export type Sentence = {
17
19
  * tokens は全角どうしに挟まれた段落内の改行を除いた文字列から作るので、改行をまたぐ語の span は改行ごと覆い、surface より長い。
18
20
  */
19
21
  readonly wrapBreaks?: readonly Span[];
22
+ /**
23
+ * 文書と違う言語で書いた文(和文の中の英文、英文の中の和文)。adapter が入れる。無ければ文書の言語の文。
24
+ * 長さの rule はこの単位で数え、この言語の上限と比べる。
25
+ */
26
+ readonly embeddedLanguage?: EmbeddedLanguage;
20
27
  };
21
28
 
29
+ export type EmbeddedLanguage = { readonly id: string; readonly lengthUnit: LengthUnit };
30
+
22
31
  /**
23
32
  * 品詞は Universal Dependencies の UPOS に統一する。アダプタ独自の体系を露出させない。
24
33
  * features は UD の FEATS。「受動か」のように品詞だけでは足りず、かつ言語ごとに
@@ -72,7 +81,11 @@ export type AdapterCapabilities = {
72
81
  };
73
82
 
74
83
  /** prepare に渡す要求。動く rule が要らないものの代金を払わせない。 */
75
- export type AdapterNeeds = { readonly pos: boolean };
84
+ export type AdapterNeeds = {
85
+ readonly pos: boolean;
86
+ /** Token features that cost the adapter extra work (LongVowelEnding asks the dictionary about each katakana word). Only the running rules' are asked for. */
87
+ readonly features?: readonly string[];
88
+ };
76
89
 
77
90
  export type LanguageAdapter = {
78
91
  readonly kind: "language";
@@ -206,6 +219,8 @@ export type Section = {
206
219
  readonly heading: string;
207
220
  /** 見出しを文と同じ解析器で語に分けたもの。文が tokens を持つときだけ入る。 */
208
221
  readonly headingTokens?: readonly Token[];
222
+ /** 見出しの頭の番号の札(「例 3:」「1.」「第2章」「Step 3:」)を除いた題。札が無ければ見出しのまま。 */
223
+ readonly unlabeledHeading?: string;
209
224
  readonly span: Span;
210
225
  readonly sentences: readonly Sentence[];
211
226
  /** この節に含まれる強調(Markdown の ** **)の数。 */
@@ -324,6 +339,34 @@ export type ProseDocument = {
324
339
  readonly profile?: DocumentProfile | undefined;
325
340
  /** 本文でないもの(コード・HTML・強調の印)を同じ長さの空白で覆った source。位置は source と同じ。 */
326
341
  readonly prose?: string | undefined;
342
+ /** メールの引用した返信(前置きの行と「> 」の行)。ほかの人の言葉なので、見出しにも木にも入れない。 */
343
+ readonly replyQuotes?: readonly Span[] | undefined;
344
+ /** 記法の手がかり(見出し・画像・リンク)。記法を読む rule だけが触れ、触れたときに作る。 */
345
+ readonly markup?: Markup | undefined;
346
+ };
347
+
348
+ /** 見出し 1 つ。text は属性(`{#id}`)を外した言葉。 */
349
+ export type MarkupHeading = { readonly depth: number; readonly text: string; readonly start: number; readonly end: number };
350
+
351
+ /** 画像 1 つ。alt は代替テキスト。HTML の `<img>` で alt 属性が無ければ undefined。 */
352
+ export type MarkupImage = { readonly alt: string | undefined; readonly start: number; readonly end: number };
353
+
354
+ /** リンクの行き先 1 つ(`[text](url)` と、参照の定義 `[label]: url`)。 */
355
+ export type MarkupLink = { readonly destination: string; readonly start: number; readonly end: number };
356
+
357
+ /**
358
+ * 文書の記法。Markdown でない文書(.txt)は markdown が false で、見出し・画像・リンクを持たず、texts が文書全体。
359
+ * 位置はすべて doc.source の上。
360
+ */
361
+ export type Markup = {
362
+ readonly markdown: boolean;
363
+ readonly headings: readonly MarkupHeading[];
364
+ readonly images: readonly MarkupImage[];
365
+ readonly links: readonly MarkupLink[];
366
+ /** 書き手が付けたページ内の名前(見出しの `{#id}`、HTML の id と name)。 */
367
+ readonly ids: ReadonlySet<string>;
368
+ /** 読み手に字のまま見える範囲(リンクの外のテキスト)。 */
369
+ readonly texts: readonly Span[];
327
370
  };
328
371
 
329
372
  export type Severity = "error" | "warning" | "info";
@@ -350,6 +393,29 @@ export type DetectorOptions = {
350
393
  readonly where?: string | undefined;
351
394
  /** 普通の長さの文 1 つの長さ(adapter の単位)。段落の長さを文の数と一緒に見る rule だけが持つ。 */
352
395
  readonly fullSentence?: number | undefined;
396
+ /** 文書と違う言語で書いた文の上限。その言語の段から解決済み。rule がその言語の段を持たなければ無い。 */
397
+ readonly embeddedLimits?: Readonly<Record<string, number>> | undefined;
398
+ /** The rule's options (RuleDefinition.options), each at the value the settings chose or its default. Only a rule with options has them. */
399
+ readonly settings?: Readonly<Record<string, OptionValue>> | undefined;
400
+ /** A custom rule's spec (RuleDefinition.custom). */
401
+ readonly custom?: CustomSpec | undefined;
402
+ };
403
+
404
+ /** The value of one rule option: a choice, a count, or a list of words. */
405
+ export type OptionValue = string | number | readonly string[];
406
+
407
+ /**
408
+ * One option a rule takes, beyond its level. The rule's YAML declares it; a team sets it under options in chaff.yaml.
409
+ * choice takes one of choices, count a whole number of 1 or more, words a list of words.
410
+ */
411
+ export type RuleOption = {
412
+ readonly kind: "choice" | "count" | "words";
413
+ readonly choices: readonly string[];
414
+ readonly default: OptionValue;
415
+ /** What the option decides, in plain words. */
416
+ readonly about: Localized;
417
+ /** What each choice means, in plain words. Only a choice has them. */
418
+ readonly choiceNames: Readonly<Record<string, Localized>>;
353
419
  };
354
420
 
355
421
  export type Detector = (doc: ProseDocument, options: DetectorOptions) => Finding[];
@@ -360,6 +426,10 @@ export type Level = "strict" | "normal" | "relaxed" | "off";
360
426
 
361
427
  export type LevelTable = Readonly<Partial<Record<Exclude<Level, "off">, number>>>;
362
428
 
429
+ export type LevelSets = "limit" | "severity";
430
+
431
+ export type LanguageLevels = { readonly levels: LevelTable; readonly by_genre: Readonly<Record<string, LevelTable>> };
432
+
363
433
  export type RuleDefinition = {
364
434
  readonly id: string;
365
435
  readonly layer: "L1" | "L2" | "L3" | "L4";
@@ -370,11 +440,17 @@ export type RuleDefinition = {
370
440
  readonly message: Localized;
371
441
  /** 見つけ方ごとの message(Finding の variant で引く)。ほとんどの rule は持たない。 */
372
442
  readonly messages: Readonly<Record<string, Localized>>;
443
+ /** How a placeholder in name, why or how_to_fix reads where no finding fills it (explain, the rule reference). */
444
+ readonly placeholders?: Readonly<Record<string, Localized>>;
373
445
  /** 4 語と数値の対応。2 つ以上。未定義の段は normal に落ちる。spec §18.1。
374
446
  * 言語別の閾値を持つ rule(max-sentence-length)は、読み込み時に言語で平坦化済み。 */
375
447
  readonly levels: LevelTable;
448
+ /** What a level changes: the limit a detector counts to, or, for a rule with nothing to count, the severity of its findings. */
449
+ readonly level_sets: LevelSets;
376
450
  /** ジャンル別の上書き。"business" は business/* 全部に効き、"business/email" が勝つ。spec §9。 */
377
451
  readonly by_genre: Readonly<Record<string, LevelTable>>;
452
+ /** 読み込んだ言語以外の levels と by_genre。文書と違う言語で書いた文(和文の中の英文)の上限に使う。 */
453
+ readonly other_languages?: Readonly<Record<string, LanguageLevels>>;
378
454
  readonly how_to_find: string;
379
455
  readonly word_list: string | undefined;
380
456
  /** word_list のほかに detector が名前で引く語彙表。どれかが無い言語では rule を動かさない。 */
@@ -388,10 +464,34 @@ export type RuleDefinition = {
388
464
  readonly requires: readonly string[];
389
465
  /** 使えるなら用意してほしい capability("pos")。requires と違い、満たせなくても動かす(品詞が無ければ文字だけで見る)。 */
390
466
  readonly uses: readonly string[];
467
+ /** Token features the rule reads that the adapter computes only when asked (AdapterNeeds.features). */
468
+ readonly token_features?: readonly string[];
391
469
  /** 複合シグナル。ここに並べた rule のうち何本が出たかを見る。spec §20.2。 */
392
470
  readonly from: readonly string[];
393
471
  /** 動かす言語。未指定は全言語。「ですます調」のように言語に固有の rule が使う。 */
394
472
  readonly languages: readonly string[] | undefined;
395
473
  readonly use_for: readonly string[];
396
474
  readonly severity: Severity;
475
+ /** Options beyond the level (the direction and length for katakana-long-vowel). Most rules have none. */
476
+ readonly options?: Readonly<Record<string, RuleOption>>;
477
+ /** A rule a team defined under custom_rules in chaff.yaml: what it looks for. Built-in rules have none. */
478
+ readonly custom?: CustomSpec;
479
+ /** What the rule reference tells a reader who is not an engineer: its group, one line, a before and after. */
480
+ readonly guide?: RuleGuide;
481
+ };
482
+
483
+ /** One token's condition in a custom rule's run of tokens. Each part written must hold; pos lists the tags that match. */
484
+ export type TokenCondition = {
485
+ readonly pos?: readonly string[] | undefined;
486
+ readonly base?: string | undefined;
487
+ readonly surface?: string | undefined;
397
488
  };
489
+
490
+ /**
491
+ * What a team's rule looks for. words: spellings to avoid, each with the one to use (or none, to only point at it).
492
+ * pattern: a regular expression, checked before it runs. tokens: a run of tokens from the language adapter.
493
+ */
494
+ export type CustomSpec =
495
+ | { readonly type: "words"; readonly words: readonly { readonly avoid: string; readonly use: string }[] }
496
+ | { readonly type: "pattern"; readonly pattern: string; readonly flags: string }
497
+ | { readonly type: "tokens"; readonly tokens: readonly TokenCondition[] };
@@ -4,6 +4,7 @@ import type { DocumentProfile } from "../plugin.ts";
4
4
  import { presetProfile } from "../genre-load.ts";
5
5
  import { loadProfiles } from "./load.ts";
6
6
  import { chooseProfile } from "./select.ts";
7
+ import { plainSource } from "../plain-source.ts";
7
8
 
8
9
  type ProfileSettings = Pick<Config, "profile" | "byPath" | "baseDir">;
9
10
 
@@ -13,6 +14,7 @@ export const profileFor = (config: ProfileSettings, path: string, source: string
13
14
  byPath: applyByPath(config.byPath, config.baseDir, path).profile,
14
15
  config: config.profile,
15
16
  genre: genre === undefined ? undefined : presetProfile(genre),
16
- source,
17
+ // 行頭で数える検出は、CR だけの改行では 1 行に見える。
18
+ source: plainSource(source),
17
19
  language,
18
20
  })?.profile;
@@ -13,15 +13,21 @@ const KAGI_MARKS: Marks = { "「": "」", "『": "』" };
13
13
  export const QUOTATION_MARKS: Marks = { ...KAGI_MARKS, "“": "”", '"': '"' };
14
14
 
15
15
  type Open = { readonly closer: string; readonly at: number };
16
- type Scan = { readonly open: readonly Open[]; readonly spans: readonly Span[] };
16
+ /** 1 回の読みの中だけで足し引きする。字ごとに配列を作り直すと、括弧が何万もある文で二乗に遅くなる。 */
17
+ type Scan = { readonly open: Open[]; readonly spans: Span[] };
17
18
 
18
19
  const step =
19
20
  (marks: Marks) =>
20
21
  (scan: Scan, char: string, at: number): Scan => {
21
22
  const last = scan.open.at(-1);
22
- if (last !== undefined && last.closer === char) return { open: scan.open.slice(0, -1), spans: [...scan.spans, { start: last.at + 1, end: at }] };
23
+ if (last !== undefined && last.closer === char) {
24
+ scan.open.pop();
25
+ scan.spans.push({ start: last.at + 1, end: at });
26
+ return scan;
27
+ }
23
28
  const closer = marks[char];
24
- return closer === undefined ? scan : { open: [...scan.open, { closer, at }], spans: scan.spans };
29
+ if (closer !== undefined) scan.open.push({ closer, at });
30
+ return scan;
25
31
  };
26
32
 
27
33
  /**
package/src/reasons.ts CHANGED
@@ -14,6 +14,9 @@ export type Reasons = {
14
14
  readonly unreadStructure: (clauses: number, units: number) => string;
15
15
  readonly noDetector: (name: string) => string;
16
16
  readonly noLexicon: (language: string, list: string) => string;
17
+ readonly noHeadings: string;
18
+ readonly patternTimeout: (budgetMs: number) => string;
19
+ readonly notMarkdown: string;
17
20
  };
18
21
 
19
22
  const CAPABILITY_NAME: Texts<Readonly<Record<string, string>>> = {
@@ -35,6 +38,9 @@ export const REASONS: Texts<Reasons> = {
35
38
  `条項の番号が本文に ${String(clauses)} 個あるのに、番号として読めたのは ${String(units)} 個のため(深い字下げや、行が本文につながった文書)`,
36
39
  noDetector: (name) => `検出器 ${name} がないため`,
37
40
  noLexicon: (language, list) => `${language} の語彙表 ${list} が無いため`,
41
+ noHeadings: "表題より下の見出しが無いため",
42
+ patternTimeout: (budgetMs) => `正規表現が ${String(budgetMs)} ms で終わらなかったため(chaff.yaml の pattern を単純にしてください)`,
43
+ notMarkdown: "Markdown の文書ではないため",
38
44
  },
39
45
  en: {
40
46
  otherLanguage: (language) => `not a rule for ${language}`,
@@ -49,5 +55,8 @@ export const REASONS: Texts<Reasons> = {
49
55
  `the text has ${String(clauses)} clause numbers but only ${String(units)} ${formFor(units, "was read as a numbered line", "were read as numbered lines")} (deep indents, or lines run into the text)`,
50
56
  noDetector: (name) => `no detector named ${name}`,
51
57
  noLexicon: (language, list) => `the ${language} package has no word list ${list}`,
58
+ noHeadings: "the document has no headings below its title",
59
+ patternTimeout: (budgetMs) => `the pattern did not finish within ${String(budgetMs)} ms (simplify the pattern in chaff.yaml)`,
60
+ notMarkdown: "the document is not Markdown",
52
61
  },
53
62
  };
@@ -0,0 +1,91 @@
1
+ import type { Span } from "./plugin.ts";
2
+
3
+ /**
4
+ * 文献一覧の範囲。見出しの語(参考文献、References)で見つけ、構造で範囲を決める。
5
+ * Markdown の見出しなら、次の同じ深さか浅い見出しまで。見出しの語だけの段落(HTML から写した文書)なら、すぐ後に続く箇条書きだけ。
6
+ * 箇条書きが続かなければ文献一覧とは言えないので、何も返さない。
7
+ */
8
+ type Line = { readonly text: string; readonly start: number; readonly end: number };
9
+
10
+ const ATX_HEADING = /^ {0,3}(#{1,6})(?:[ \t](.*))?$/u;
11
+ // 文献の番号(- [1]、1.、[1])で始まる行。
12
+ const LIST_ITEM = /^ {0,3}(?:[-*+]|\d{1,4}[.)]|\[\d{1,4}\])[ \t]/u;
13
+ const CONTINUATION = /^[ \t]+\S/u;
14
+ // 見出しの前の節番号(7.、7.1、VII.)、周りの強調、後ろの閉じの # とコロン。
15
+ const SECTION_NUMBER = /^(?:\d+(?:\.\d+)*\.?|[IVXLC]+\.)\s+/u;
16
+ const EMPHASIS_MARKS = ["**", "__"] as const;
17
+ const CLOSING = new Set([" ", "\t", "#", ":", ":"]);
18
+
19
+ const withoutClosing = (text: string): string => {
20
+ const characters = [...text];
21
+ return characters.slice(0, characters.findLastIndex((character) => !CLOSING.has(character)) + 1).join("");
22
+ };
23
+
24
+ const linesOf = (source: string): Line[] =>
25
+ source.split("\n").reduce<Line[]>((lines, text) => {
26
+ const start = (lines.at(-1)?.end ?? -1) + 1;
27
+ lines.push({ text, start, end: start + text.length });
28
+ return lines;
29
+ }, []);
30
+
31
+ const withoutEmphasis = (text: string): string => {
32
+ const mark = EMPHASIS_MARKS.find((candidate) => text.length > candidate.length * 2 && text.startsWith(candidate) && text.endsWith(candidate));
33
+ return mark === undefined ? text : text.slice(mark.length, -mark.length);
34
+ };
35
+
36
+ const isBlank = (line: Line | undefined): boolean => line === undefined || line.text.trim() === "";
37
+
38
+ const headingWord = (text: string): string => {
39
+ const plain = withoutEmphasis(withoutClosing(text).trim());
40
+ return withoutClosing(plain.replace(SECTION_NUMBER, "")).trim().toLowerCase();
41
+ };
42
+
43
+ const levelOf = (line: Line): number | undefined => ATX_HEADING.exec(line.text)?.[1]?.length;
44
+
45
+ /** from 以降で最初に test を満たす行。無ければ lines.length。先頭から数え直すと、見出しの多い文書で行数の 2 乗になる。 */
46
+ const firstFrom = (lines: readonly Line[], from: number, test: (line: Line) => boolean): number => {
47
+ for (let index = from; index < lines.length; index += 1) {
48
+ const line = lines[index];
49
+ if (line !== undefined && test(line)) return index;
50
+ }
51
+ return lines.length;
52
+ };
53
+
54
+ /** Markdown の見出しの節の終わり: 次の同じ深さか浅い見出しの手前。無ければ文書の終わり。 */
55
+ const sectionEnd = (lines: readonly Line[], at: number, level: number): number =>
56
+ firstFrom(lines, at + 1, (line) => (levelOf(line) ?? Number.POSITIVE_INFINITY) <= level);
57
+
58
+ const isOutsideList = (line: Line): boolean => !isBlank(line) && !LIST_ITEM.test(line.text) && !CONTINUATION.test(line.text);
59
+
60
+ /** from の後の最初の中身の行から続く箇条書きの終わり(最後の中身の行の次)。最初の中身が項目でなければ from。 */
61
+ const listEnd = (lines: readonly Line[], from: number): number => {
62
+ const first = firstFrom(lines, from, (line) => !isBlank(line));
63
+ if (!LIST_ITEM.test(lines[first]?.text ?? "")) return from;
64
+ const stop = firstFrom(lines, first + 1, isOutsideList);
65
+ return first + lines.slice(first, stop).findLastIndex((line) => !isBlank(line)) + 1;
66
+ };
67
+
68
+ const standsAlone = (lines: readonly Line[], at: number): boolean => (at === 0 || isBlank(lines[at - 1])) && isBlank(lines[at + 1]);
69
+
70
+ /** 見出しの行 at から、文献一覧の終わりの行(含まない)。文献一覧の見出しでなければ undefined。 */
71
+ const blockEnd = (lines: readonly Line[], at: number, headings: ReadonlySet<string>): number | undefined => {
72
+ const line = lines[at];
73
+ if (line === undefined) return undefined;
74
+ const level = levelOf(line);
75
+ if (level !== undefined) return headings.has(headingWord(ATX_HEADING.exec(line.text)?.[2] ?? "")) ? sectionEnd(lines, at, level) : undefined;
76
+ if (!headings.has(headingWord(line.text)) || !standsAlone(lines, at)) return undefined;
77
+ const end = listEnd(lines, at + 1);
78
+ return end === at + 1 ? undefined : end;
79
+ };
80
+
81
+ export const referenceListSpans = (source: string, headingWords: readonly string[]): Span[] => {
82
+ const headings = new Set(headingWords.map((word) => word.toLowerCase()));
83
+ const lines = linesOf(source);
84
+ const spans: Span[] = [];
85
+ lines.forEach((line, at) => {
86
+ if ((spans.at(-1)?.end ?? -1) >= line.start) return;
87
+ const end = blockEnd(lines, at, headings);
88
+ if (end !== undefined) spans.push({ start: line.start, end: lines[end - 1]?.end ?? line.end });
89
+ });
90
+ return spans;
91
+ };
@@ -1,7 +1,10 @@
1
- import { definedLevels, resolve } from "../levels.ts";
2
- import { localized } from "./text.ts";
3
- import { uiLanguageOf, type Texts } from "../ui.ts";
1
+ import { definedLevels, resolve, severityAt } from "../levels.ts";
2
+ import { readableText } from "./text.ts";
3
+ import { SEVERITY_NAME } from "./severity-name.ts";
4
+ import { uiLanguageOf, type Texts, type UiLanguage } from "../ui.ts";
4
5
  import type { Level, RuleDefinition } from "../plugin.ts";
6
+ import { optionLines } from "./options.ts";
7
+ import type { OptionLayer } from "../rule-options.ts";
5
8
 
6
9
  const TEXT: Texts<{
7
10
  readonly off: string;
@@ -9,8 +12,12 @@ const TEXT: Texts<{
9
12
  readonly genreNote: (genre: string, others: string) => string;
10
13
  readonly experimental: string;
11
14
  readonly howToFix: string;
15
+ readonly example: string;
16
+ readonly definedIn: string;
12
17
  readonly values: (unit: string) => string;
18
+ readonly severities: string;
13
19
  readonly now: (level: string) => string;
20
+ readonly from: (source: string) => string;
14
21
  readonly change: (id: string) => string;
15
22
  }> = {
16
23
  ja: {
@@ -19,8 +26,12 @@ const TEXT: Texts<{
19
26
  genreNote: (genre, others) => `この数字は ${genre} のものです。ほかに ${others} で別の数字を持っています。`,
20
27
  experimental: "このルールはまだ試験中で、既定では動きません(--experimental で動きます)。",
21
28
  howToFix: "直しかた",
29
+ example: "例",
30
+ definedIn: "このルールはチームが chaff.yaml の custom_rules で決めたものです。",
22
31
  values: (unit) => `設定できる値(単位: ${unit}):`,
32
+ severities: "設定できる値(数える上限は無く、指摘の重さが変わります):",
23
33
  now: (level) => `いまは ${level} です。`,
34
+ from: (source) => `(${source} で決めています)`,
24
35
  change: (id) => `変える: npx chaff relax ${id} --why "理由"`,
25
36
  },
26
37
  en: {
@@ -29,16 +40,24 @@ const TEXT: Texts<{
29
40
  genreNote: (genre, others) => `These numbers are for ${genre}. ${others} have numbers of their own.`,
30
41
  experimental: "This rule is still experimental and does not run by default (--experimental runs it).",
31
42
  howToFix: "How to fix",
43
+ example: "Example",
44
+ definedIn: "The team defined this rule under custom_rules in chaff.yaml.",
32
45
  values: (unit) => `Levels (unit: ${unit}):`,
46
+ severities: "Levels (there is no limit to count to; a level sets how a finding is marked):",
33
47
  now: (level) => `Now: ${level}.`,
48
+ from: (source) => ` (set by ${source})`,
34
49
  change: (id) => `Change it: npx chaff relax ${id} --why "reason"`,
35
50
  },
36
51
  };
37
52
 
38
- const levelLine = (rule: RuleDefinition, level: Level, current: Level, genre: string | undefined, off: string): string => {
53
+ /** What a level holds: the limit a detector counts to, or the severity a rule with nothing to count gives. */
54
+ const valueAt = (rule: RuleDefinition, level: Exclude<Level, "off">, genre: string | undefined, ui: UiLanguage): string =>
55
+ rule.level_sets === "severity" ? SEVERITY_NAME[ui][severityAt(rule, level, genre)] : String(resolve(rule, level, genre).limit);
56
+
57
+ const levelLine = (rule: RuleDefinition, level: Level, current: Level, genre: string | undefined, ui: UiLanguage): string => {
39
58
  const mark = level === current ? "→" : " ";
40
59
  const name = level.padEnd(9);
41
- return level === "off" ? ` ${mark} ${name}${off}` : ` ${mark} ${name}${resolve(rule, level, genre).limit}`;
60
+ return level === "off" ? ` ${mark} ${name}${TEXT[ui].off}` : ` ${mark} ${name}${valueAt(rule, level, genre, ui)}`;
42
61
  };
43
62
 
44
63
  /** ジャンルで数字が変わる rule は、それを言わないと「設定したのに効かない」に見える。 */
@@ -48,23 +67,38 @@ const genreNote = (rule: RuleDefinition, genre: string | undefined, text: (typeo
48
67
  return ["", ` ${text.genreNote(genre ?? text.defaultGenre, others.join(" / "))}`];
49
68
  };
50
69
 
70
+ /** A team's rule shows its example, before and after, and says where it was defined. */
71
+ const exampleLines = (rule: RuleDefinition, language: string, text: (typeof TEXT)["ja"]): string[] => {
72
+ const examples = rule.guide?.examples ?? {};
73
+ const example = examples[language] ?? examples["en"] ?? Object.values(examples)[0];
74
+ if (rule.custom === undefined || example === undefined) return [];
75
+ return ["", ` ${text.example}: ${example.before}`, ` → ${example.after}`, "", ` ${text.definedIn}`];
76
+ };
77
+
78
+ /** Where the rule's settings come from: the option layers, strongest first, and the source of its level when a style set it. */
79
+ export type ExplainSettings = { readonly optionLayers?: readonly OptionLayer[]; readonly levelFrom?: string | undefined };
80
+
51
81
  /** rule の意図と根拠を読む。指摘に納得できないときの入口。 */
52
- export const renderExplain = (rule: RuleDefinition, current: Level, language: string, unit: string, genre?: string): string => {
53
- const text = TEXT[uiLanguageOf(language)];
82
+ export const renderExplain = (rule: RuleDefinition, current: Level, language: string, unit: string, genre?: string, settings: ExplainSettings = {}): string => {
83
+ const { optionLayers = [], levelFrom } = settings;
84
+ const ui = uiLanguageOf(language);
85
+ const text = TEXT[ui];
54
86
  const experimental = rule.status === "experimental" ? [` ${text.experimental}`] : [];
55
87
  return [
56
88
  "",
57
- ` ${localized(rule.name, language)} (${rule.id})`,
89
+ ` ${readableText(rule, rule.name, language)} (${rule.id})`,
58
90
  "",
59
- ` ${localized(rule.why, language)}`,
91
+ ` ${readableText(rule, rule.why, language)}`,
60
92
  "",
61
- ` ${text.howToFix}: ${localized(rule.how_to_fix, language)}`,
93
+ ` ${text.howToFix}: ${readableText(rule, rule.how_to_fix, language)}`,
94
+ ...exampleLines(rule, language, text),
62
95
  "",
63
- ` ${text.values(unit)}`,
64
- ...definedLevels(rule).map((level) => levelLine(rule, level, current, genre, text.off)),
96
+ ` ${rule.level_sets === "severity" ? text.severities : text.values(unit)}`,
97
+ ...definedLevels(rule).map((level) => levelLine(rule, level, current, genre, ui)),
65
98
  ...genreNote(rule, genre, text),
99
+ ...optionLines(rule, optionLayers, language),
66
100
  "",
67
- ` ${text.now(current)}`,
101
+ ` ${text.now(current)}${levelFrom === undefined ? "" : text.from(levelFrom)}`,
68
102
  ...experimental,
69
103
  "",
70
104
  ` ${text.change(rule.id)}`,
@@ -1,6 +1,6 @@
1
1
  import type { Finding, RuleDefinition } from "../plugin.ts";
2
2
  import type { RunResult } from "../run.ts";
3
- import { MARK, localized, messageOf } from "./text.ts";
3
+ import { MARK, filledText, messageOf } from "./text.ts";
4
4
  import { tally } from "./summary.ts";
5
5
  import { counted } from "./plural.ts";
6
6
  import { uiLanguageOf, type Texts } from "../ui.ts";
@@ -45,29 +45,39 @@ const QUOTE_LIMIT = 120;
45
45
 
46
46
  const indent = (text: string, pad: string): string[] => text.split("\n").map((line) => `${pad}${line}`);
47
47
 
48
- const quoteOf = (finding: Finding): string[] => {
49
- const text = finding.quote.replace(/\s+/gu, " ").trim();
48
+ const quoteOf = (quote: string): string[] => {
49
+ const text = quote.replace(/\s+/gu, " ").trim();
50
50
  if (text.length === 0) return [];
51
51
  return ["", ...indent(text.length > QUOTE_LIMIT ? `${text.slice(0, QUOTE_LIMIT)}…` : text, " ")];
52
52
  };
53
53
 
54
+ /** 一つの文から出た指摘は同じ文を引く。長い文に指摘が多いとき、指摘ごとに文を整え直さない。 */
55
+ const quotesOf = (): ((quote: string) => readonly string[]) => {
56
+ const known = new Map<string, readonly string[]>();
57
+ return (quote) => {
58
+ const lines = known.get(quote) ?? quoteOf(quote);
59
+ known.set(quote, lines);
60
+ return lines;
61
+ };
62
+ };
63
+
54
64
  /**
55
65
  * 1 件につき 4 つを出す。どれが欠けても、書いた人は動けない。
56
66
  * 引用 / 何が起きているか / なぜ問題か / どう直すか
57
67
  * rule の id は「ゆるめる」コマンドの中にだけ出す。最初に読むのは name。
58
68
  */
59
- const block = (finding: Finding, rule: RuleDefinition, language: string): string[] => [
69
+ const block = (finding: Finding, rule: RuleDefinition, language: string, quoted: readonly string[]): string[] => [
60
70
  "",
61
71
  // "12 行目" and "line 12" take the same width on a terminal, so the rule ends in the same column in both.
62
72
  `─── ${TEXT[uiLanguageOf(language)].line(finding.line)} ${"─".repeat(Math.max(0, RULE - String(finding.line).length - 8))}`,
63
- ...quoteOf(finding),
73
+ ...quoted,
64
74
  "",
65
- ` ${MARK[finding.severity] ?? "·"} ${localized(rule.name, language)}`,
75
+ ` ${MARK[finding.severity] ?? "·"} ${filledText(rule.name, finding, language)}`,
66
76
  "",
67
77
  ...indent(messageOf(rule, finding, language), " "),
68
- ...indent(localized(rule.why, language), " "),
78
+ ...indent(filledText(rule.why, finding, language), " "),
69
79
  "",
70
- ...indent(`→ ${localized(rule.how_to_fix, language)}`, " "),
80
+ ...indent(`→ ${filledText(rule.how_to_fix, finding, language)}`, " "),
71
81
  "",
72
82
  ` ${TEXT[uiLanguageOf(language)].relax}: npx chaff relax ${finding.rule}`,
73
83
  "",
@@ -82,9 +92,10 @@ export const renderFriendly = (
82
92
  notes: readonly string[] = [],
83
93
  ): string => {
84
94
  const byId = new Map(rules.map((rule) => [rule.id, rule]));
95
+ const quoted = quotesOf();
85
96
  const blocks = result.findings.flatMap((finding) => {
86
97
  const rule = byId.get(finding.rule);
87
- return rule === undefined ? [] : block(finding, rule, language);
98
+ return rule === undefined ? [] : block(finding, rule, language, quoted(finding.quote));
88
99
  });
89
100
  const text = TEXT[uiLanguageOf(language)];
90
101
  const closing = [
@@ -0,0 +1,58 @@
1
+ import type { OptionValue, RuleDefinition } from "../plugin.ts";
2
+ import { DEFAULT_SOURCE, settleOptions, type OptionLayer } from "../rule-options.ts";
3
+ import { localized } from "./text.ts";
4
+ import type { Texts } from "../ui.ts";
5
+ import { uiLanguageOf } from "../ui.ts";
6
+
7
+ const printed = (value: OptionValue): string => (Array.isArray(value) ? `[${value.join(", ")}]` : String(value));
8
+
9
+ /** A rule's options for rules --json: what each decides, what it may be, its default, its value now and which setting gave it. */
10
+ export const optionsJson = (rule: RuleDefinition, layers: readonly OptionLayer[]): Record<string, unknown> | undefined => {
11
+ if (rule.options === undefined) return undefined;
12
+ const settled = settleOptions(rule.id, rule.options, layers);
13
+ return Object.fromEntries(
14
+ Object.entries(rule.options).map(([name, option]) => [
15
+ name,
16
+ {
17
+ kind: option.kind,
18
+ about: option.about,
19
+ ...(option.kind === "choice" ? { choices: option.choiceNames } : {}),
20
+ default: option.default,
21
+ now: settled[name]?.value ?? option.default,
22
+ from: settled[name]?.from ?? DEFAULT_SOURCE,
23
+ },
24
+ ]),
25
+ );
26
+ };
27
+
28
+ const TEXT: Texts<{ readonly heading: string; readonly byDefault: string; readonly from: (source: string) => string; readonly howTo: (id: string) => string }> =
29
+ {
30
+ ja: {
31
+ heading: "オプション(chaff.yaml の options で決めます):",
32
+ byDefault: "既定",
33
+ from: (source) => `${source} から`,
34
+ howTo: (id) => `決める: chaff.yaml に options: { ${id}: { <名前>: <値> } } を書く`,
35
+ },
36
+ en: {
37
+ heading: "Options (set under options in chaff.yaml):",
38
+ byDefault: "default",
39
+ from: (source) => `from ${source}`,
40
+ howTo: (id) => `Set one: write options: { ${id}: { <name>: <value> } } in chaff.yaml`,
41
+ },
42
+ };
43
+
44
+ /** A rule's options for explain: each one's value now and where it came from, what it decides, and each choice's meaning. */
45
+ export const optionLines = (rule: RuleDefinition, layers: readonly OptionLayer[], language: string): string[] => {
46
+ if (rule.options === undefined) return [];
47
+ const text = TEXT[uiLanguageOf(language)];
48
+ const settled = settleOptions(rule.id, rule.options, layers);
49
+ const lines = Object.entries(rule.options).flatMap(([name, option]) => {
50
+ const now = settled[name];
51
+ const source = now === undefined || now.from === DEFAULT_SOURCE ? text.byDefault : text.from(now.from);
52
+ const choices = Object.entries(option.choiceNames).map(
53
+ ([choice, meaning]) => ` ${choice === now?.value ? "→" : " "} ${choice.padEnd(11)}${localized(meaning, language)}`,
54
+ );
55
+ return [` ${name}: ${printed(now?.value ?? option.default)} (${source})`, ` ${localized(option.about, language)}`, ...choices];
56
+ });
57
+ return ["", ` ${text.heading}`, ...lines, "", ` ${text.howTo(rule.id)}`];
58
+ };