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
@@ -15,21 +15,32 @@ const chainAtEnd = (preceding: readonly Token[]): readonly Token[] => {
15
15
  return preceding.slice(Math.max(head, 0));
16
16
  };
17
17
 
18
+ /** 語彙表 neutral-ending の語(「こと」)か。書いた形か原形で照らす。 */
19
+ const isNeutralWord = (token: Token | undefined, neutral: readonly LexiconEntry[]): boolean =>
20
+ token !== undefined && neutral.some((entry) => token.surface === entry.pattern || token.lemma === entry.pattern);
21
+
18
22
  /**
19
- * 非自立名詞で終わる文末は、手前の述語の連なりまで見る。「予約できること。」「おかけしましたこと。」は手前の述語が調子を持つ。
20
- * 要件や規程のである調は「〜こと。」で書く。「以下のとおり。」は手前も述語でないので、調子を持たないまま。
23
+ * 非自立名詞で終わる文末は、手前の述語の連なりまで見る。「使っているのかな?」は手前の述語が調子を持つ。
24
+ * 「以下のとおり。」は手前も述語でないので、調子を持たないまま。
25
+ * 語彙表 neutral-ending の語(「こと」)で終わる文末は手前を見ない。「〜を保持すること。」は体言止めで、要件や規程の箇条書きは
26
+ * ですます調の文書でもである調の文書でもこの形で書く。
21
27
  */
22
- const withPreceding = (ending: readonly Token[], preceding: readonly Token[]): readonly Token[] =>
23
- isDependent(ending[0]) ? [...chainAtEnd(preceding), ...ending] : ending;
28
+ const withPreceding = (ending: readonly Token[], preceding: readonly Token[], neutral: readonly LexiconEntry[]): readonly Token[] =>
29
+ isDependent(ending[0]) && !isNeutralWord(ending[0], neutral) ? [...chainAtEnd(preceding), ...ending] : ending;
24
30
 
25
31
  /**
26
- * 文末の語の調子。preceding は文末の語より前の語。
32
+ * 文末の語の調子。preceding は文末の語より前の語。neutral は調子を持たない文末の語(語彙表 neutral-ending)。
27
33
  * 文末に述語(動詞・形容詞・助動詞)が無ければ、ですます調でもである調でもないので undefined。
28
34
  * 「以下の通り。」「円錐形の麦わら帽子。」のような名詞で終わる文を数えると、そのままである調の少数派になっていた。
29
35
  * 書いた形でも原形でも読みでも当てる(polite-word.ts)。「ください」の原形は「くださる」で、原形だけを見ると丁寧な文末を見落とす。
30
36
  */
31
- export const registerOf = (ending: readonly Token[], preceding: readonly Token[], polite: readonly LexiconEntry[]): Register | undefined => {
32
- const judged = withPreceding(ending, preceding);
37
+ export const registerOf = (
38
+ ending: readonly Token[],
39
+ preceding: readonly Token[],
40
+ polite: readonly LexiconEntry[],
41
+ neutral: readonly LexiconEntry[] = [],
42
+ ): Register | undefined => {
43
+ const judged = withPreceding(ending, preceding, neutral);
33
44
  if (!judged.some(isPredicate)) return undefined;
34
45
  return judged.some((token) => isPoliteWord(token, polite)) ? "polite" : "plain";
35
46
  };
@@ -56,21 +67,36 @@ export const groupOf = (offset: number, lists: readonly Span[], runs: readonly S
56
67
  /** group: 文が入っているまとまり(groupOf の値)。本文なら undefined。 */
57
68
  export type Judged = { readonly register: Register; readonly group: number | undefined };
58
69
 
59
- /** 混ざった文と、その文が属する本文または箇条書きの中の少数派の数。 */
70
+ /** 混ざった文と、その文が属するまとまり(本文、または箇条書き 1 つ)の中の少数派の数。文書全体の数ではない。 */
60
71
  export type Slip<T extends Judged> = { readonly entry: T; readonly count: number };
61
72
 
62
73
  const countIn = (judged: readonly Judged[], register: Register): number => judged.filter((entry) => entry.register === register).length;
63
74
 
75
+ /** 多いほう。同数なら undefined。 */
76
+ export const majorityOf = (judged: readonly Judged[]): Register | undefined => {
77
+ const difference = countIn(judged, "polite") - countIn(judged, "plain");
78
+ if (difference === 0) return undefined;
79
+ return difference > 0 ? "polite" : "plain";
80
+ };
81
+
64
82
  /** 少ないほう。同数なら文書全体で少ないほう、それも同数なら丁寧体。 */
65
83
  const minorityOf = (group: readonly Judged[], whole: readonly Judged[]): Register => {
66
- const difference = countIn(group, "polite") - countIn(group, "plain");
67
- if (difference !== 0) return difference < 0 ? "polite" : "plain";
84
+ const majority = majorityOf(group);
85
+ if (majority !== undefined) return majority === "polite" ? "plain" : "polite";
68
86
  return countIn(whole, "polite") <= countIn(whole, "plain") ? "polite" : "plain";
69
87
  };
70
88
 
89
+ /**
90
+ * 箇条書きの中の少数派が、文書全体では多数派か。それなら箇条書きの中で文書の調子に寄せた側なので、直す側ではない。
91
+ * 常体の多い箇条書きにですます調の文が混ざっても、ですます調の文書なら「多いほうに揃えて」は文書の少数派へ揃えることになる。
92
+ */
93
+ export const followsDocument = (group: number | undefined, minority: Register, whole: readonly Judged[]): boolean =>
94
+ group !== undefined && majorityOf(whole) === minority;
95
+
71
96
  const slipsInGroup = <T extends Judged>(judged: readonly T[], group: number | undefined, limit: number): Slip<T>[] => {
72
97
  const members = judged.filter((entry) => entry.group === group);
73
98
  const minority = minorityOf(members, judged);
99
+ if (followsDocument(group, minority, judged)) return [];
74
100
  const slips = members.filter((entry) => entry.register === minority);
75
101
  // 片方しか無ければ揃っている。少数派が閾値を超えて多ければ、混在ではなく別の文体。
76
102
  if (slips.length === 0 || slips.length > limit) return [];
@@ -80,6 +106,7 @@ const slipsInGroup = <T extends Judged>(judged: readonly T[], group: number | un
80
106
  /**
81
107
  * 調子が混ざった文を、judged の順で。本文は本文どうし、箇条書きと番号で始まる段落の並びは 1 つずつ、その中で揃っているかを見る。
82
108
  * ですます調の本文に常体の箇条書きを置くのはよくある書き方で、箇条書きが丸ごと揃っていれば混在ではない。
109
+ * 箇条書きの中で混ざっていても、少数派が文書全体の多数派なら指さない(followsDocument)。
83
110
  */
84
111
  export const slipsOf = <T extends Judged>(judged: readonly T[], limit: number): Slip<T>[] => {
85
112
  const slips = [...new Set(judged.map((entry) => entry.group))].flatMap((group) => slipsInGroup(judged, group, limit));
@@ -3,3 +3,6 @@
3
3
  * 各桁が省けるので空文字にも当たる。1 文字目があることを先読みで求める。
4
4
  */
5
5
  export const ROMAN_NUMERAL = "(?=[MDCLXVI])M{0,4}(?:CM|CD|D?C{0,3})(?:XC|XL|L?X{0,3})(?:IX|IV|V?I{0,3})";
6
+
7
+ /** ハイフンかダッシュで繋いだ数字の範囲(II-VI、I–III)も、一つの番号として読む。 */
8
+ export const romanRangeOf = (numeral: string): string => `${numeral}(?:[-–]${numeral})?`;
@@ -12,11 +12,11 @@ import type { Detector, Finding, LexiconEntry, ProseDocument, Sentence, Span } f
12
12
  */
13
13
  type Entry = { readonly sentence: Sentence; readonly register: Register; readonly group: number | undefined };
14
14
 
15
- const registerOfSentence = (sentence: Sentence, polite: readonly LexiconEntry[]): Register | undefined => {
15
+ const registerOfSentence = (sentence: Sentence, polite: readonly LexiconEntry[], neutral: readonly LexiconEntry[]): Register | undefined => {
16
16
  const ending = endingTokens(sentence);
17
17
  const tokens = sentence.tokens ?? [];
18
18
  const head = ending[0] === undefined ? -1 : tokens.indexOf(ending[0]);
19
- return registerOf(ending, head > 0 ? tokens.slice(0, head) : [], polite);
19
+ return registerOf(ending, head > 0 ? tokens.slice(0, head) : [], polite, neutral);
20
20
  };
21
21
 
22
22
  /** 番号で始まる段落の並び。木を組むのは高いので、調子が一つだけの文書(混ざりようがない)では組まない。 */
@@ -30,25 +30,32 @@ const runsOf = (doc: ProseDocument, registers: readonly Register[]): Span[] => {
30
30
  );
31
31
  };
32
32
 
33
- export const sentenceEnding: Detector = (doc, options): Finding[] => {
34
- const polite = options.lexicon ?? [];
33
+ /** 調子を持つ文と、比べ合うまとまり(groupOf)。polite は語彙表 polite-ending。 */
34
+ export const judgedSentences = (doc: ProseDocument, polite: readonly LexiconEntry[]): Entry[] => {
35
+ const neutral = doc.lexicons["neutral-ending"] ?? [];
35
36
  const lists = doc.lists.map((list) => list.span);
36
37
  const found = doc.sentences.flatMap((sentence, index): { sentence: Sentence; register: Register }[] => {
37
38
  if (!isClosed(sentence) || continuesInto(sentence, doc.sentences[index + 1])) return [];
38
- const register = registerOfSentence(sentence, polite);
39
+ const register = registerOfSentence(sentence, polite, neutral);
39
40
  return register === undefined ? [] : [{ sentence, register }];
40
41
  });
41
42
  const runs = runsOf(
42
43
  doc,
43
44
  found.map((entry) => entry.register),
44
45
  );
45
- const judged = found.map((entry): Entry => ({ ...entry, group: groupOf(entry.sentence.span.start, lists, runs) }));
46
- return slipsOf(judged, options.limit).map(({ entry: { sentence }, count }) => ({
46
+ return found.map((entry): Entry => ({ ...entry, group: groupOf(entry.sentence.span.start, lists, runs) }));
47
+ };
48
+
49
+ export const sentenceEnding: Detector = (doc, options): Finding[] => {
50
+ const judged = judgedSentences(doc, options.lexicon ?? []);
51
+ // 数えたのは文が属するまとまりの中なので、文言もそのまとまりを名指す(本文の中で / この箇条書きの中で)。
52
+ return slipsOf(judged, options.limit).map(({ entry: { sentence, group }, count }) => ({
47
53
  rule: "no-mixed-desumasu",
48
54
  severity: "warning",
49
55
  line: 0,
50
56
  column: 0,
51
57
  quote: sentence.text.trim(),
58
+ ...(group === undefined ? {} : { variant: "list" }),
52
59
  values: { count, limit: options.limit, offset: sentence.span.start },
53
60
  }));
54
61
  };
@@ -1,15 +1,26 @@
1
1
  import { lengthOf, proseText } from "../measure.ts";
2
- import type { Detector, Finding } from "../plugin.ts";
2
+ import type { Detector, DetectorOptions, Finding, LengthUnit, Sentence } from "../plugin.ts";
3
+
4
+ type Measure = { readonly size: number; readonly limit: number; readonly variant?: string };
5
+
6
+ /** 文書と違う言語の文(和文の中の英文)は、その言語の単位と上限で測る。rule がその言語の段を持たなければ文書のもので。 */
7
+ const measureOf = (sentence: Sentence, unit: LengthUnit, options: DetectorOptions): Measure => {
8
+ const embedded = sentence.embeddedLanguage;
9
+ const limit = embedded === undefined ? undefined : options.embeddedLimits?.[embedded.id];
10
+ if (embedded === undefined || limit === undefined) return { size: lengthOf(sentence, unit), limit: options.limit };
11
+ return { size: lengthOf(sentence, embedded.lengthUnit), limit, variant: `embedded-${embedded.id}` };
12
+ };
3
13
 
4
14
  export const sentenceLength: Detector = (doc, options): Finding[] =>
5
15
  doc.sentences
6
- .map((sentence) => ({ sentence, size: lengthOf(sentence, doc.lengthUnit) }))
7
- .filter(({ size }) => size > options.limit)
8
- .map(({ sentence, size }) => ({
16
+ .map((sentence) => ({ sentence, measure: measureOf(sentence, doc.lengthUnit, options) }))
17
+ .filter(({ measure }) => measure.size > measure.limit)
18
+ .map(({ sentence, measure }) => ({
9
19
  rule: "max-sentence-length",
10
20
  severity: "warning",
11
21
  line: 0,
12
22
  column: 0,
13
23
  quote: proseText(sentence),
14
- values: { count: size, limit: options.limit, offset: sentence.span.start },
24
+ values: { count: measure.size, limit: measure.limit, offset: sentence.span.start },
25
+ ...(measure.variant === undefined ? {} : { variant: measure.variant }),
15
26
  }));
@@ -1,8 +1,10 @@
1
1
  import { proseText } from "../measure.ts";
2
2
  import { dateSpans, wordsOf } from "./structure.ts";
3
- import { compacted, placeOf } from "./gram-place.ts";
3
+ import { compacted, placeAt, type Compacted } from "./gram-place.ts";
4
+ import { charWindows, wordWindows } from "./gram-windows.ts";
5
+ import { furnitureMask, isFurniture } from "./gram-furniture.ts";
4
6
  import { notAcronymSpansOf, type NotAcronymSpans } from "./acronym-context.ts";
5
- import { expansionAt, termEntryAcronyms, type ExpandedAt } from "./acronym-expansion.ts";
7
+ import { abbreviates, expansionAt, termEntryAcronyms, type ExpandedAt } from "./acronym-expansion.ts";
6
8
  import { isExplained } from "./acronym-compound.ts";
7
9
  import { conjugatedForms } from "./conjugated-form.ts";
8
10
  import { evidenceSpans, hasNumeral, startsWithin } from "./concrete-evidence.ts";
@@ -17,7 +19,7 @@ const PER = 1000;
17
19
  * これより短い文書では密度が暴れる。1 個で「1000 あたり 100」になる。
18
20
  * 単位は言語で違うので、床も分ける。英語の 200 語と日本語の 200 文字では長さが桁で違う。
19
21
  */
20
- const FLOOR = { word: 200, char: 500 };
22
+ export const MIN_DOCUMENT_LENGTH = { word: 200, char: 500 };
21
23
 
22
24
  const bodyOf = (doc: ProseDocument): string => doc.sentences.map(proseText).join(" ");
23
25
 
@@ -41,7 +43,7 @@ export const emojiDensity: Detector = (doc, options): Finding[] => {
41
43
  const hits = findIn(doc, EMOJI);
42
44
  const first = hits[0];
43
45
  const rate = density(doc, hits.length);
44
- if (wordsOf(doc) < FLOOR[doc.lengthUnit] || first === undefined || rate <= options.limit) return [];
46
+ if (wordsOf(doc) < MIN_DOCUMENT_LENGTH[doc.lengthUnit] || first === undefined || rate <= options.limit) return [];
45
47
  return [
46
48
  {
47
49
  rule: "emoji-density",
@@ -55,26 +57,17 @@ export const emojiDensity: Detector = (doc, options): Finding[] => {
55
57
  };
56
58
 
57
59
  /**
58
- * 同じ言い回しの繰り返し。character n-gram で見るので、語の区切りが要らない。
60
+ * 同じ言い回しの繰り返し。文字の並びで見るので、adapter の語の区切り(wordSplit)が要らない。英語の窓は空白で語の切れ目にそろえる。
59
61
  * spec §10 が n-gram を選んだのはこのためで、新しい言語でそのまま動く。
60
62
  */
61
63
  /**
62
64
  * 窓の幅は単位で分ける。同じ 8 文字でも、日本語では 4〜5 形態素だが英語では 1 語半にしかならない。
63
- * 実文書(英語 11 本)で 8 文字にしたら、上位は " generat"(generate)のような**語の断片**だった。
65
+ * 英語の窓は語の切れ目にそろえ、18 文字に届くまで語を足す。文字で切ると " generat" のような語の断片が上位に来る。
66
+ * 18 は、文字で切っていた頃の 20 文字の窓から前後の空白を除いた長さ(" juxtaposed to said ")。
64
67
  */
65
- const GRAM = { char: 8, word: 20 };
66
-
67
- /** 並べた名前にかかる語句は数えない。名前が繰り返されれば、その前後(「the …」)も一緒に繰り返されるのは当たり前。 */
68
- const countGrams = (text: string, width: number, names: readonly string[]): Map<string, number> => {
69
- const counts = new Map<string, number>();
70
- const named = nameSpans(text, names);
71
- Array.from({ length: Math.max(0, text.length - width + 1) }).forEach((_, index) => {
72
- if (touchesAny(named, index, index + width)) return;
73
- const gram = text.slice(index, index + width);
74
- counts.set(gram, (counts.get(gram) ?? 0) + 1);
75
- });
76
- return counts;
77
- };
68
+ const GRAM = { char: 8, word: 18 };
69
+
70
+ const windowsOf = (text: string, unit: ProseDocument["lengthUnit"]): Span[] => (unit === "char" ? charWindows(text, GRAM.char) : wordWindows(text, GRAM.word));
78
71
 
79
72
  /**
80
73
  * 名前ではなく言い回しだけを数える。実文書で測ったら、上位は
@@ -93,49 +86,80 @@ const CONNECTIVE = { char: /[ぁ-ゖ].*[ぁ-ゖ].*[ぁ-ゖ]/u, word: /\S \S.*\S
93
86
 
94
87
  const isPhrasing = (gram: string, unit: ProseDocument["lengthUnit"]): boolean => CONNECTIVE[unit].test(gram);
95
88
 
96
- /** 文をまたいで数えない。文の終わりと次の文の始まりが繋がると、固有名詞が言い回しに見える。 */
97
- const gramsOf = (doc: ProseDocument): Map<string, number> => {
98
- const counts = new Map<string, number>();
99
- doc.sentences.forEach((sentence) => {
100
- const text = doc.lengthUnit === "char" ? proseText(sentence).replace(/\s+/gu, "") : proseText(sentence);
101
- const names = doc.lengthUnit === "char" ? (doc.names ?? []).map((name) => name.replace(/\s+/gu, "")) : (doc.names ?? []);
102
- countGrams(text, GRAM[doc.lengthUnit], names).forEach((count, gram) => counts.set(gram, (counts.get(gram) ?? 0) + count));
103
- });
104
- return counts;
89
+ /** 語句が最初に数えられた所。書かれたままの語句と、文と、文の中の範囲(sentence.text の位置)。 */
90
+ type FirstSeen = { readonly gram: string; readonly sentence: Sentence; readonly place: Span };
91
+
92
+ type Tally = { readonly counts: Map<string, number>; readonly first: Map<string, FirstSeen> };
93
+
94
+ /** 詰めた文の index 番目の文字が、リンクの文字か。 */
95
+ const linkedIn = (doc: ProseDocument, sentence: Sentence, source: Compacted): ((index: number) => boolean) => {
96
+ const links = doc.links.filter((link) => link.start < sentence.span.end && sentence.span.start < link.end);
97
+ return (index) => {
98
+ const at = sentence.span.start + (source.offsets[index] ?? -1);
99
+ return links.some((link) => link.start <= at && at < link.end);
100
+ };
101
+ };
102
+
103
+ /** 英語は大文字と小文字を区別せずに数える。文頭の "Proposals submitted via" も文中の "proposals submitted via" も同じ言い回し。 */
104
+ const keyOf = (gram: string, unit: ProseDocument["lengthUnit"]): string => (unit === "word" ? gram.toLowerCase() : gram);
105
+
106
+ const namesOf = (doc: ProseDocument): readonly string[] =>
107
+ doc.lengthUnit === "char" ? (doc.names ?? []).map((name) => name.replace(/\s+/gu, "")) : (doc.names ?? []);
108
+
109
+ /**
110
+ * 文をまたいで数えない。文の終わりと次の文の始まりが繋がると、固有名詞が言い回しに見える。
111
+ * 並べた名前にかかる語句も数えない。名前が繰り返されれば、その前後(「the …」)も一緒に繰り返されるのは当たり前。
112
+ * 一覧の飾り(gram-furniture.ts)も数えない。項目ごとに繰り返すのはひな形で、書き手ではない。
113
+ */
114
+ const tallySentence = (doc: ProseDocument, sentence: Sentence, tally: Tally): void => {
115
+ const source = compacted(sentence.text, doc.lengthUnit);
116
+ const named = nameSpans(source.text, namesOf(doc));
117
+ const mask = furnitureMask(source.text, linkedIn(doc, sentence, source));
118
+ windowsOf(source.text, doc.lengthUnit)
119
+ .filter((window) => !touchesAny(named, window.start, window.end) && !isFurniture(source.text, mask, window))
120
+ .forEach((window) => {
121
+ const gram = source.text.slice(window.start, window.end);
122
+ const key = keyOf(gram, doc.lengthUnit);
123
+ tally.counts.set(key, (tally.counts.get(key) ?? 0) + 1);
124
+ const place = placeAt(source, window);
125
+ if (!tally.first.has(key) && place !== undefined) tally.first.set(key, { gram, sentence, place });
126
+ });
105
127
  };
106
128
 
107
- /** 数えたときと同じ形の文。char 単位では空白を詰めてから数えている。 */
108
- const gramText = (sentence: Sentence, unit: ProseDocument["lengthUnit"]): string => compacted(sentence.text, unit).text;
129
+ const gramsOf = (doc: ProseDocument): Tally => {
130
+ const tally: Tally = { counts: new Map(), first: new Map() };
131
+ doc.sentences.forEach((sentence) => tallySentence(doc, sentence, tally));
132
+ return tally;
133
+ };
109
134
 
110
135
  /**
111
136
  * 語句が文の中で占める範囲に、述語になる動詞か助動詞があるか(gram-predicate.ts)。
112
137
  * 品詞が無ければ見分けられないので、これまでどおり言い回しとして数える。
113
138
  */
114
- const hasPredicate = (gram: string, sentence: Sentence, unit: ProseDocument["lengthUnit"]): boolean => {
115
- if (sentence.tokens === undefined) return true;
116
- const place = placeOf(compacted(sentence.text, unit), gram);
117
- if (place === undefined) return true;
118
- return hasPredicateIn(sentence.tokens, { start: sentence.span.start + place.start, end: sentence.span.start + place.end }, unit);
139
+ const hasPredicate = (at: FirstSeen | undefined, unit: ProseDocument["lengthUnit"]): boolean => {
140
+ if (at?.sentence.tokens === undefined) return true;
141
+ const start = at.sentence.span.start;
142
+ return hasPredicateIn(at.sentence.tokens, { start: start + at.place.start, end: start + at.place.end }, unit);
119
143
  };
120
144
 
121
145
  export const ngramRepetition: Detector = (doc, options): Finding[] => {
122
- if (wordsOf(doc) < FLOOR[doc.lengthUnit]) return [];
123
- const sentenceWith = (gram: string): Sentence | undefined => doc.sentences.find((sentence) => gramText(sentence, doc.lengthUnit).includes(gram));
124
- const worst = [...gramsOf(doc).entries()]
125
- .filter(([gram, count]) => count > options.limit && isPhrasing(gram, doc.lengthUnit))
146
+ if (wordsOf(doc) < MIN_DOCUMENT_LENGTH[doc.lengthUnit]) return [];
147
+ const tally = gramsOf(doc);
148
+ const worst = [...tally.counts.entries()]
149
+ .filter(([key, count]) => count > options.limit && isPhrasing(key, doc.lengthUnit))
126
150
  .toSorted(([, left], [, right]) => right - left)
127
- .map(([gram, count]) => ({ gram, count, at: sentenceWith(gram) }))
128
- .find(({ gram, at }) => at === undefined || hasPredicate(gram, at, doc.lengthUnit));
151
+ .map(([key, count]) => ({ key, count, at: tally.first.get(key) }))
152
+ .find(({ at }) => hasPredicate(at, doc.lengthUnit));
129
153
  if (worst === undefined) return [];
130
- const at = worst.at;
154
+ const at = worst.at?.sentence;
131
155
  return [
132
156
  {
133
157
  rule: "ngram-repetition",
134
158
  severity: "info",
135
159
  line: 0,
136
160
  column: 0,
137
- quote: at?.text.trim() ?? worst.gram,
138
- values: { word: worst.gram, count: worst.count, limit: options.limit, offset: at?.span.start ?? 0 },
161
+ quote: at?.text.trim() ?? worst.key,
162
+ values: { word: worst.at?.gram ?? worst.key, count: worst.count, limit: options.limit, offset: at?.span.start ?? 0 },
139
163
  },
140
164
  ];
141
165
  };
@@ -237,6 +261,13 @@ const outsideDates = (hits: readonly AcronymHit[], dates: readonly Span[]): Acro
237
261
  const isExpanded = (body: string, acronym: string, expandedAt: ExpandedAt): boolean =>
238
262
  [...body.matchAll(new RegExp(`${EDGE_BEFORE}${acronym}${EDGE_AFTER}`, "gu"))].some((match) => expandedAt(body, acronym, match.index));
239
263
 
264
+ /**
265
+ * 見出しは文にならないので、見出しの中の展開(Maximum Envelope of Water (MEOW) runs)は見出しの文字列で探す。
266
+ * 見出しの括弧は添え書き(Your Own AI (LLM)、(Beta))にも使うので、見出しの語から略語の文字が順に拾えるときだけ認める。
267
+ */
268
+ const expandsInHeading = (heading: string, acronym: string, expandedAt: ExpandedAt): boolean =>
269
+ isExpanded(heading, acronym, expandedAt) && abbreviates(heading.replaceAll(acronym, " "), acronym);
270
+
240
271
  const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
241
272
 
242
273
  const notationOf = (doc: ProseDocument): NotAcronymSpans =>
@@ -247,6 +278,7 @@ const notationOf = (doc: ProseDocument): NotAcronymSpans =>
247
278
  usStates: patternsOf(doc, "us-state-code"),
248
279
  emphasis: patternsOf(doc, "emphasis-word"),
249
280
  divisions: patternsOf(doc, "numbered-division"),
281
+ abbreviatedLabels: patternsOf(doc, "abbreviated-label"),
250
282
  honorifics: patternsOf(doc, "honorific"),
251
283
  titles: patternsOf(doc, "name-title"),
252
284
  dateTimeUnits: patternsOf(doc, "date-time-unit"),
@@ -265,7 +297,9 @@ export const undefinedAcronym: Detector = (doc, options): Finding[] => {
265
297
  const common = new Set([...(options.lexicon ?? []).map((entry) => entry.pattern), ...patternsOf(doc, "http-method"), ...(doc.names ?? [])]);
266
298
  const expandedAt = expansionAt({ markers: patternsOf(doc, "definition-marker"), verbs: definitionVerbsOf(doc) });
267
299
  const entries = termEntryAcronyms(doc.source);
268
- const explainedAlone = (word: string): boolean => common.has(word) || entries.has(word) || isExpanded(body, word, expandedAt);
300
+ const headings = doc.sections.map((section) => section.heading);
301
+ const explainedAlone = (word: string): boolean =>
302
+ common.has(word) || entries.has(word) || isExpanded(body, word, expandedAt) || headings.some((heading) => expandsInHeading(heading, word, expandedAt));
269
303
  const hits = acronymsOf(doc, notationOf(doc));
270
304
  const unexplained = new Set([...firstHits(hits).keys()].filter((acronym) => !isExplained(acronym, explainedAlone)));
271
305
  // 日付を読むには文書の木を作る。上限に届かない文書では作らない。
@@ -339,7 +373,7 @@ export const dashDensity: Detector = (doc, options): Finding[] => {
339
373
  const hits = findIn(doc, DASH);
340
374
  const first = hits[0];
341
375
  const rate = density(doc, hits.length);
342
- if (wordsOf(doc) < FLOOR[doc.lengthUnit] || first === undefined || rate <= options.limit) return [];
376
+ if (wordsOf(doc) < MIN_DOCUMENT_LENGTH[doc.lengthUnit] || first === undefined || rate <= options.limit) return [];
343
377
  return [
344
378
  {
345
379
  rule: "no-em-dash",
@@ -4,11 +4,13 @@ import { numberingBreaks } from "../structure/numbering.ts";
4
4
  import { weekdayMismatches } from "../structure/weekday.ts";
5
5
  import { dateOrderBreaks } from "../structure/date-order.ts";
6
6
  import { totalMismatches, type Amount } from "../structure/total.ts";
7
+ import { reversedRanges, type DatedSpan, type RangeWords } from "../structure/date-range.ts";
8
+ import { percentSumMismatches, type ShareWords } from "../structure/percent-sum.ts";
7
9
 
8
10
  const QUOTE_LENGTH = 80;
9
11
 
10
12
  /** 指摘の位置から行末までを引用する。条の見出しや参照を含む一行が、読み手の探す手がかりになる。 */
11
- const quoteAt = (source: string, offset: number): string => {
13
+ export const quoteAt = (source: string, offset: number): string => {
12
14
  const end = source.indexOf("\n", offset);
13
15
  return source
14
16
  .slice(offset, end === -1 ? source.length : end)
@@ -96,3 +98,45 @@ export const totalMismatch: Detector = (doc): Finding[] =>
96
98
  quote: quoteAt(doc.source, issue.offset),
97
99
  values: { ...issue.values, offset: issue.offset },
98
100
  }));
101
+
102
+ const datedSpans = (tree: NonNullable<ProseDocument["structure"]>): DatedSpan[] =>
103
+ inDocumentOrder(tree).flatMap((node) => (node.kind === "date" ? [{ offset: node.span.start, end: node.span.end, value: String(node.attrs["value"]) }] : []));
104
+
105
+ const rangeWordsOf = (doc: ProseDocument): RangeWords => ({
106
+ connectors: (doc.lexicons["range-connector"] ?? []).map((entry) => entry.pattern),
107
+ openers: (doc.lexicons["range-opener"] ?? []).map((entry) => entry.pattern),
108
+ closers: (doc.lexicons["range-closer"] ?? []).map((entry) => entry.pattern),
109
+ });
110
+
111
+ /** 期間の終わりが始まりより前。範囲の記号と語は言語パッケージの語彙表(range-connector、range-opener、range-closer)から取る。 */
112
+ export const dateRangeReversed: Detector = (doc): Finding[] =>
113
+ doc.structure === undefined
114
+ ? []
115
+ : reversedRanges(doc.source, datedSpans(doc.structure), rangeWordsOf(doc)).map((issue) => ({
116
+ rule: "date-range-reversed",
117
+ severity: "warning",
118
+ line: 0,
119
+ column: 0,
120
+ quote: quoteAt(doc.source, issue.offset),
121
+ values: { ...issue.values, offset: issue.offset },
122
+ }));
123
+
124
+ const shareWordsOf = (doc: ProseDocument): ShareWords => ({
125
+ labels: (doc.lexicons["share-label"] ?? []).map((entry) => entry.pattern),
126
+ exceptions: (doc.lexicons["share-exception"] ?? []).map((entry) => entry.pattern),
127
+ units: (doc.lexicons["percent-unit"] ?? []).map((entry) => entry.pattern),
128
+ totalLabels: (doc.lexicons["total-label"] ?? []).map((entry) => entry.pattern),
129
+ });
130
+
131
+ /** 構成比や内訳の百分率の和が 100% にならない。割合の語と百分率の単位は言語パッケージの語彙表から取る。 */
132
+ export const percentSumMismatch: Detector = (doc): Finding[] =>
133
+ doc.structure === undefined
134
+ ? []
135
+ : percentSumMismatches(doc.source, amountsOf(doc.structure), shareWordsOf(doc)).map((issue) => ({
136
+ rule: "percent-sum-mismatch",
137
+ severity: "warning",
138
+ line: 0,
139
+ column: 0,
140
+ quote: quoteAt(doc.source, issue.offset),
141
+ values: { ...issue.values, offset: issue.offset },
142
+ }));
@@ -4,6 +4,7 @@ import { dateStampIndexes, stampCandidates } from "../date-stamp.ts";
4
4
  import { inDocumentOrder } from "../structure/issues.ts";
5
5
  import { preambleParagraphs } from "../preamble-paragraphs.ts";
6
6
  import { isTooLongParagraph } from "../paragraph-length.ts";
7
+ import { bodySectionOf } from "../body-section.ts";
7
8
 
8
9
  /**
9
10
  * ばらつきは変動係数(標準偏差 ÷ 平均)で測る。
@@ -118,12 +119,10 @@ const withoutDateStamps = (doc: ProseDocument, paragraphs: readonly Paragraph[])
118
119
 
119
120
  /**
120
121
  * 本題に入るまでが長い。業務文書では、読み手は結論を探しに来ている。
121
- *
122
- * 「本題」は最初の中見出し(深さ 2 以上)とする。表題(深さ 1)の直後から数えると、
123
- * 表題しか無い文書で全文が前置きになる。中見出しが無い文書では何も言わない。
122
+ * 「本題」は最初の中見出し。中見出しが無い文書では、rule が requires の headings で動かず、動かなかった理由が出る。
124
123
  */
125
124
  export const preambleLength: Detector = (doc, options): Finding[] => {
126
- const body = doc.sections.find((section) => section.depth >= 2);
125
+ const body = bodySectionOf(doc.sections);
127
126
  if (body === undefined) return [];
128
127
  const all = preambleParagraphs(doc.paragraphs, body.span.start);
129
128
  if (all.length <= options.limit) return [];
@@ -9,10 +9,13 @@ const joinsAsNoun = (previous: Token, token: Token | undefined): token is Token
9
9
 
10
10
  /** 空白も助詞も挟まずに続く名詞の連なり(最大|瞬間|風速)の最後の語。連なりが無ければ undefined。 */
11
11
  const lastJoined = (tokens: readonly Token[], at: number): Token | undefined => {
12
- const previous = tokens[at - 1];
13
- const token = tokens[at];
14
- if (previous === undefined || !joinsAsNoun(previous, token)) return undefined;
15
- return lastJoined(tokens, at + 1) ?? token;
12
+ let last: Token | undefined;
13
+ for (let index = at; ; index += 1) {
14
+ const previous = tokens[index - 1];
15
+ const token = tokens[index];
16
+ if (previous === undefined || !joinsAsNoun(previous, token)) return last;
17
+ last = token;
18
+ }
16
19
  };
17
20
 
18
21
  const measures = (noun: Token, quantities: Lexicon): boolean => quantities.some((entry) => entry.pattern === noun.surface);
@@ -48,9 +48,14 @@ const namedBefore = (tokens: readonly Token[], range: TokenRange, markers: Lexic
48
48
 
49
49
  /** 最上級に続く名詞句の終わり。名詞が出るまでは修飾を、出た後は名詞の連なりを読む。 */
50
50
  export const phraseEnd = (tokens: readonly Token[], at: number, nounSeen = false): number => {
51
- const token = tokens[at];
52
- if (token === undefined || !(nounSeen ? NOUN_RUN : PREMODIFIER).has(token.pos)) return at;
53
- return phraseEnd(tokens, at + 1, nounSeen || NOMINAL.has(token.pos));
51
+ let end = at;
52
+ let seen = nounSeen;
53
+ for (;;) {
54
+ const token = tokens[end];
55
+ if (token === undefined || !(seen ? NOUN_RUN : PREMODIFIER).has(token.pos)) return end;
56
+ seen ||= NOMINAL.has(token.pos);
57
+ end += 1;
58
+ }
54
59
  };
55
60
 
56
61
  /** 最上級 + 名詞句 + 範囲の語 + 名詞句(the best pizza in Chicago・the most famous of the sculptures)。 */