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
@@ -6,11 +6,11 @@ import { resolveRelative } from "./relative-resolve.ts";
6
6
  import { maskSpans } from "../mask.ts";
7
7
  import type { DocumentProfile, Mention, NumberedLine, NumberingContext, Span, StructureKind, StructureNode, StructurePatterns } from "../plugin.ts";
8
8
  import { lineNumberAt, linesOf, type Line } from "./lines.ts";
9
- import { dottedNumber } from "./universal.ts";
10
- import { numberInSentence } from "./number-in-sentence.ts";
9
+ import { universalNumber } from "./universal.ts";
11
10
  import { unnumberedUnit, type OpenUnit } from "./unnumbered.ts";
12
11
  import { readsOnHeading } from "./heading-leaves.ts";
13
12
  import { onLine, wrappedLine, type WrappedLine } from "./wrapped-tail.ts";
13
+ import { foldPostOrder } from "../tree-walk.ts";
14
14
 
15
15
  /** 組み立て中の節点。できあがったら StructureNode に固める。 */
16
16
  type Draft = {
@@ -151,14 +151,6 @@ const LEAVES: readonly { readonly kind: StructureKind; readonly find: LeafFinder
151
151
  { kind: "date", find: (patterns, text) => patterns.dates?.(text) ?? [] },
152
152
  ];
153
153
 
154
- /** 言語を問わない通し番号。後ろが単位なら数量、本文の文の続きなら文の中の数なので、番号にしない。 */
155
- const universalNumber = (patterns: StructurePatterns, text: string, context: NumberingContext, plainText: boolean): NumberedLine | undefined => {
156
- const dotted = dottedNumber(text, context, plainText);
157
- if (dotted === undefined || patterns.countedAfter?.(dotted.number, dotted.rest) === true) return undefined;
158
- const numbered = { number: dotted.number, rest: dotted.rest, isHeading: context.isHeading };
159
- return numberInSentence(numbered, patterns.continuesSentence) ? undefined : dotted;
160
- };
161
-
162
154
  /** 行の中の定義・参照・義務・数量を、いま開いている最も内側の節点の子にする。 */
163
155
  const enclosingArticle = (state: State): Draft | undefined => state.stack.findLast((frame) => frame.draft.kind === "article")?.draft;
164
156
 
@@ -220,23 +212,28 @@ const extend = (state: State, end: number): void => {
220
212
  });
221
213
  };
222
214
 
223
- const freeze = (draft: Draft): StructureNode => ({
215
+ const frozen = (draft: Draft, children: readonly StructureNode[]): StructureNode => ({
224
216
  kind: draft.kind,
225
217
  address: draft.address,
226
218
  span: { start: draft.start, end: draft.end },
227
219
  line: draft.line,
228
220
  attrs: draft.attrs,
229
- children: draft.children.map(freeze),
221
+ children,
230
222
  ...(draft.ordinal === undefined ? {} : { ordinal: draft.ordinal }),
231
223
  ...(draft.level === undefined ? {} : { level: draft.level }),
232
224
  ...(draft.ordinalTo === undefined ? {} : { ordinalTo: draft.ordinalTo }),
233
225
  ...(draft.numbering === undefined ? {} : { numbering: draft.numbering }),
234
226
  });
235
227
 
236
- /** Markdown から取った手がかり。見出しと、中を読まない範囲(コード)。.txt はどちらも空。 */
237
- export type Outline = { readonly headings: readonly Heading[]; readonly opaque: readonly Span[] };
228
+ const freeze = (root: Draft): StructureNode => foldPostOrder(root, (draft) => draft.children, frozen);
229
+
230
+ /**
231
+ * Markdown から取った手がかり。見出しと、中を読まない範囲(コード)と、表。.txt はどれも空。
232
+ * 表の欄の数(版の番号 3.1.0)は値で、この文書の番号ではない。表の行は番号として読まず、数量や日付は読む。
233
+ */
234
+ export type Outline = { readonly headings: readonly Heading[]; readonly opaque: readonly Span[]; readonly tables: readonly Span[] };
238
235
 
239
- export const NO_OUTLINE: Outline = { headings: [], opaque: [] };
236
+ export const NO_OUTLINE: Outline = { headings: [], opaque: [], tables: [] };
240
237
 
241
238
  export type StructureInput = {
242
239
  readonly path: string;
@@ -298,11 +295,14 @@ const withCaption = (state: State, line: Line, numbered: NumberedLine | undefine
298
295
  return numbered === undefined || caption === undefined ? numbered : { ...numbered, heading: caption };
299
296
  };
300
297
 
301
- const readLine = (state: State, patterns: StructurePatterns, line: Line, heading: Heading | undefined, next: string | undefined): void => {
298
+ /** 行の周り。前の行は、前の行が見出しでなく自分が表の行でないときだけ渡す。表の行は番号として読まない。 */
299
+ type Around = { readonly next: string | undefined; readonly previous: string | undefined; readonly inTable: boolean };
300
+
301
+ const readLine = (state: State, patterns: StructurePatterns, line: Line, heading: Heading | undefined, around: Around): void => {
302
302
  const text = heading === undefined ? line.text : headingLineText(line.text);
303
303
  const openNumbers = state.stack.flatMap((frame) => (frame.numbered === undefined ? [] : [frame.numbered]));
304
304
  const context = { open: openNumbers, isHeading: heading !== undefined };
305
- const found = numberedLine(state, patterns, text, context);
305
+ const found = around.inTable ? undefined : numberedLine(state, patterns, text, context);
306
306
  const numbered = withCaption(state, line, found);
307
307
  const caption = numbered === undefined && heading === undefined ? captionOf(state.profile, text) : undefined;
308
308
  if (caption !== undefined) state.captions.set(line.number, caption);
@@ -315,7 +315,21 @@ const readLine = (state: State, patterns: StructurePatterns, line: Line, heading
315
315
  const scanned = numbered === undefined ? text : numbered.rest;
316
316
  const offset = Math.max(0, line.text.lastIndexOf(scanned));
317
317
  const onHeading = heading !== undefined;
318
- if (scanned !== "") addLeaves(state, patterns, line, wrappedLine(scanned, onHeading, next), offset, onHeading);
318
+ // 番号付きの行は新しいまとまりの始まりなので、前の行の続きとして読まない。
319
+ const previous = numbered === undefined ? around.previous : undefined;
320
+ if (scanned !== "") addLeaves(state, patterns, line, wrappedLine(scanned, onHeading, around.next, previous), offset, onHeading);
321
+ };
322
+
323
+ /** 表の範囲に入る行の番号。表ごとに始まりと終わりの行を引くので、表の数に比例する。 */
324
+ const tableLineNumbers = (lines: readonly Line[], tables: readonly Span[]): Set<number> => {
325
+ const numbers = new Set<number>();
326
+ tables.forEach((table) => {
327
+ const first = lineNumberAt(lines, table.start);
328
+ const last = lineNumberAt(lines, table.end);
329
+ if (first === undefined || last === undefined) return;
330
+ Array.from({ length: last - first + 1 }, (_, index) => numbers.add(first + index));
331
+ });
332
+ return numbers;
319
333
  };
320
334
 
321
335
  /**
@@ -340,8 +354,13 @@ export const buildTree = (input: StructureInput, patterns: StructurePatterns): S
340
354
  captions: new Map(),
341
355
  plainText: !input.markdown,
342
356
  };
357
+ const inTable = tableLineNumbers(lines, outline.tables);
343
358
  lines.forEach((line, index) => {
344
- if (line.text.trim() !== "") readLine(state, patterns, line, headings.get(line.number), lines[index + 1]?.text);
359
+ // 見出しの後ろと表の行は、段落の折り返しではない。表のすぐ後ろの行は(GFM では)表の行になるので、表の中だけ見ればよい。
360
+ const apart = headings.has(line.number - 1) || inTable.has(line.number);
361
+ const previous = apart ? undefined : lines[index - 1]?.text;
362
+ const around = { next: lines[index + 1]?.text, previous, inTable: inTable.has(line.number) };
363
+ if (line.text.trim() !== "") readLine(state, patterns, line, headings.get(line.number), around);
345
364
  // コードの行は覆って読まないが、開いている節の中身ではある。節の最後にコードブロックがあっても、範囲をそこまで伸ばす。
346
365
  else if (input.source.slice(line.start, line.start + line.text.length).trim() !== "") extend(state, line.start + line.text.length);
347
366
  });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 閉じた括弧の組を、中身ごと外す。入れ子は内側から外れる。閉じない開きと、開かない閉じは残す。
3
+ * open と close は 1 字ずつ。同じ字なら、前から順に組になる。「内側の組を外す」を繰り返すと、深さの数だけ本文を読み直すので、1 度だけ読む。
4
+ */
5
+ export const withoutClosedPairs = (text: string, open: string, close: string): string => {
6
+ const kept: string[] = [];
7
+ const opens: number[] = [];
8
+ for (const char of text) {
9
+ const opened = char === close ? opens.pop() : undefined;
10
+ if (opened !== undefined) kept.splice(opened);
11
+ else {
12
+ if (char === open) opens.push(kept.length);
13
+ kept.push(char);
14
+ }
15
+ }
16
+ return kept.join("");
17
+ };
18
+
19
+ /** 1 字(サロゲートの対も 1 字)か。 */
20
+ export const isOneCharacter = (text: string): boolean => [...text].length === 1;
@@ -0,0 +1,69 @@
1
+ import type { StructureIssue } from "./issues.ts";
2
+
3
+ /**
4
+ * 期間の終わりが始まりより前。二つの日付の間が範囲の記号(〜、–、through)だけか、開きの語(から)で終わりの日付に閉じの語(まで)が続くときを期間と読む。
5
+ * 比べるのは、両方が年月日か、両方が年月のときだけ。年の無い期間(12月28日〜1月4日)は年をまたぐかもしれない。
6
+ * 言語の知識(範囲の記号と語)は語彙表から受け取る。
7
+ */
8
+ export type DatedSpan = { readonly offset: number; readonly end: number; readonly value: string };
9
+
10
+ export type RangeWords = {
11
+ /** それだけで期間を作る記号と語。 */
12
+ readonly connectors: readonly string[];
13
+ /** 終わりの日付に閉じの語が続くときだけ期間を作る語(から)。 */
14
+ readonly openers: readonly string[];
15
+ readonly closers: readonly string[];
16
+ };
17
+
18
+ const COMPARABLE = [/^\d{4}-\d{2}-\d{2}$/u, /^\d{4}-\d{2}$/u];
19
+
20
+ const comparable = (start: string, end: string): boolean => COMPARABLE.some((pattern) => pattern.test(start) && pattern.test(end));
21
+
22
+ /** 日付に添えた曜日((水))と時刻(10:00)は、期間のつなぎ目ではないので読み飛ばす。 */
23
+ const ASIDES = /[((][^(())\n]{1,6}[))]|\d{1,2}[::]\d{2}/gu;
24
+
25
+ const bare = (text: string): string => text.replace(ASIDES, "").trim().toLowerCase();
26
+
27
+ const isOneOf = (text: string, words: readonly string[]): boolean => words.some((word) => word.toLowerCase() === text);
28
+
29
+ /** 行の終わりまでの、終わりの日付の後ろ。曜日と時刻を除いてから閉じの語を探す。 */
30
+ const closedAfter = (source: string, end: DatedSpan, closers: readonly string[]): boolean => {
31
+ const lineEnd = source.indexOf("\n", end.end);
32
+ const after = source
33
+ .slice(end.end, lineEnd === -1 ? source.length : lineEnd)
34
+ .replace(ASIDES, "")
35
+ .trimStart();
36
+ return closers.some((closer) => after.startsWith(closer));
37
+ };
38
+
39
+ /**
40
+ * 二つの日付の間のつなぎ。行をまたぐなら、つなぎは前の行の終わりにあり、次の行は終わりの日付から始まるときだけ(期間は2026年4月1日〜↵2026年3月31日)。
41
+ * 次の行の頭の「- 」は箇条書きの印で、範囲の記号ではない(日付を並べた一覧)。
42
+ */
43
+ const jointOf = (source: string, start: DatedSpan, end: DatedSpan): string | undefined => {
44
+ const [first = "", ...next] = source.slice(start.end, end.offset).split("\n");
45
+ return next.every((line) => line.trim() === "") ? bare(first) : undefined;
46
+ };
47
+
48
+ const isRange = (source: string, start: DatedSpan, end: DatedSpan, words: RangeWords): boolean => {
49
+ const joint = jointOf(source, start, end);
50
+ if (joint === undefined) return false;
51
+ return isOneOf(joint, words.connectors) || (isOneOf(joint, words.openers) && closedAfter(source, end, words.closers));
52
+ };
53
+
54
+ /** 書いたままの期間。行をまたいだ期間は一行にする。 */
55
+ const writtenPeriod = (source: string, start: DatedSpan, end: DatedSpan): string =>
56
+ source
57
+ .slice(start.offset, end.end)
58
+ .split("\n")
59
+ .map((part) => part.trim())
60
+ .join(" ");
61
+
62
+ /** 隣り合う二つの日付のうち、期間をなし、終わりが始まりより前のもの。期間の書き出しを指し、書いたままの期間を見せる。 */
63
+ export const reversedRanges = (source: string, dates: readonly DatedSpan[], words: RangeWords): StructureIssue[] =>
64
+ dates.slice(1).flatMap((end, index) => {
65
+ const start = dates[index];
66
+ if (start === undefined || !comparable(start.value, end.value) || end.value >= start.value) return [];
67
+ if (!isRange(source, start, end, words)) return [];
68
+ return [{ offset: start.offset, values: { start: start.value, end: end.value, period: writtenPeriod(source, start, end) } }];
69
+ });
@@ -0,0 +1,96 @@
1
+ import type { Mention } from "../plugin.ts";
2
+
3
+ /**
4
+ * 条を書かない番地を読むときに引く、同じ行の既知の参照。before(名指しの参照)に、見つけた番地を順に足していく。
5
+ * 引くたびに全部をなめると、参照の数の二乗になる。before は並べ替えて二分探索で、足したものは深さごとに最後の一つで引く。
6
+ *
7
+ * 足すものは、正規表現で左から見つけた番地の順に来る。だから足したものの終わりは、次に引く位置より前にあり、並びの順に増える。
8
+ * - overlaps: [start, end) と重なるものがあるか。足したものは引く位置より前で終わるので、重ならない。
9
+ * - previous: 終わりが at 以前で、終わりの深さが depth のもののうち、終わりが最も後ろのもの。同じ終わりなら後から知ったもの。
10
+ * - endingAt: 終わりが at のもののうち、最初に知ったもの。
11
+ */
12
+ export type KnownMentions = {
13
+ readonly overlaps: (start: number, end: number) => boolean;
14
+ readonly previous: (at: number, depth: number) => Mention | undefined;
15
+ readonly endingAt: (at: number) => Mention | undefined;
16
+ readonly add: (mention: Mention, depth: number) => void;
17
+ };
18
+
19
+ /** sorted の中で、pass が偽になる最初の位置。pass は先頭から真が続き、あとは偽。 */
20
+ const firstFailing = <T>(sorted: readonly T[], pass: (item: T) => boolean): number => {
21
+ let [low, high] = [0, sorted.length];
22
+ while (low < high) {
23
+ const middle = Math.floor((low + high) / 2);
24
+ const item = sorted[middle];
25
+ if (item !== undefined && pass(item)) low = middle + 1;
26
+ else high = middle;
27
+ }
28
+ return low;
29
+ };
30
+
31
+ /** 始まりの順に並べ、そこまでの終わりの最大を添える。始まりが end より前のものの、終わりの最大が start より後ろなら重なる。 */
32
+ const overlapIndex = (before: readonly Mention[]): ((start: number, end: number) => boolean) => {
33
+ const byStart = before.filter((mention) => !Number.isNaN(mention.start)).toSorted((left, right) => left.start - right.start);
34
+ let reach = -Infinity;
35
+ const reaches = byStart.map((mention) => {
36
+ reach = Math.max(reach, Number.isNaN(mention.end) ? -Infinity : mention.end);
37
+ return reach;
38
+ });
39
+ return (start, end) => {
40
+ const count = firstFailing(byStart, (mention) => mention.start < end);
41
+ return count > 0 && (reaches[count - 1] ?? -Infinity) > start;
42
+ };
43
+ };
44
+
45
+ type Ranked = { readonly mention: Mention; readonly order: number };
46
+
47
+ const byEndThenOrder = (left: Ranked, right: Ranked): number => {
48
+ if (left.mention.end !== right.mention.end) return left.mention.end < right.mention.end ? -1 : 1;
49
+ return left.order - right.order;
50
+ };
51
+
52
+ /** 深さごとに、終わりの順(同じなら知った順)に並べる。 */
53
+ const previousIndex = (before: readonly Mention[], depthOf: (at: number) => number): ((at: number, depth: number) => Mention | undefined) => {
54
+ const byDepth = new Map<number, Ranked[]>();
55
+ before.forEach((mention, order) => {
56
+ if (Number.isNaN(mention.end)) return;
57
+ const depth = depthOf(mention.end);
58
+ const ranked = byDepth.get(depth) ?? [];
59
+ ranked.push({ mention, order });
60
+ byDepth.set(depth, ranked);
61
+ });
62
+ const sorted = new Map([...byDepth].map(([depth, ranked]) => [depth, ranked.toSorted(byEndThenOrder)]));
63
+ return (at, depth) => {
64
+ const ranked = sorted.get(depth) ?? [];
65
+ return ranked[firstFailing(ranked, (entry) => entry.mention.end <= at) - 1]?.mention;
66
+ };
67
+ };
68
+
69
+ const firstByEnd = (mentions: readonly Mention[]): Map<number, Mention> => {
70
+ const found = new Map<number, Mention>();
71
+ mentions.forEach((mention) => {
72
+ if (!found.has(mention.end)) found.set(mention.end, mention);
73
+ });
74
+ return found;
75
+ };
76
+
77
+ export const knownMentions = (before: readonly Mention[], depthOf: (at: number) => number): KnownMentions => {
78
+ const overlapsBefore = overlapIndex(before);
79
+ const previousBefore = previousIndex(before, depthOf);
80
+ const endsBefore = firstByEnd(before);
81
+ const lastAddedByDepth = new Map<number, Mention>();
82
+ const endsAdded = new Map<number, Mention>();
83
+ return {
84
+ overlaps: overlapsBefore,
85
+ previous: (at, depth) => {
86
+ const known = previousBefore(at, depth);
87
+ const added = lastAddedByDepth.get(depth);
88
+ return added !== undefined && (known === undefined || added.end >= known.end) ? added : known;
89
+ },
90
+ endingAt: (at) => endsBefore.get(at) ?? endsAdded.get(at),
91
+ add: (mention, depth) => {
92
+ lastAddedByDepth.set(depth, mention);
93
+ if (!endsAdded.has(mention.end)) endsAdded.set(mention.end, mention);
94
+ },
95
+ };
96
+ };
@@ -1,5 +1,6 @@
1
1
  import type { StructureNode } from "../plugin.ts";
2
2
  import { inDocumentOrder, type StructureIssue } from "./issues.ts";
3
+ import { numbersQuotedInside } from "./quoted-number.ts";
3
4
 
4
5
  const labelOf = (node: StructureNode): string => String(node.attrs["label"] ?? node.address);
5
6
 
@@ -9,10 +10,10 @@ type Ordered = { readonly node: StructureNode; readonly ordinal: number; readonl
9
10
  * 同じ親の子のうち、番号の付いたものを種類と深さごとに分ける。条と項は別の並び、項と号も別の並び。
10
11
  * 法令の第 1 項は番号が無いので、その号(一、二)と第 2 項(2)は同じ条の直下に並ぶ。深さで分けないと「二の次が2」に見える。
11
12
  */
12
- const sequencesOf = (parent: StructureNode): Ordered[][] => {
13
+ const sequencesOf = (parent: StructureNode, quoting: ReadonlySet<StructureNode>): Ordered[][] => {
13
14
  const groups = new Map<string, Ordered[]>();
14
15
  parent.children.forEach((node) => {
15
- if (node.ordinal === undefined) return;
16
+ if (node.ordinal === undefined || quoting.has(node)) return;
16
17
  const key = `${node.kind}/${String(node.level ?? "")}`;
17
18
  // 配列を作り直さずに足す。条が何千もある法令で二乗にしない。
18
19
  const group = groups.get(key) ?? [];
@@ -41,9 +42,12 @@ const breaksIn = (sequence: readonly Ordered[]): StructureIssue[] =>
41
42
  * 番号の抜けと重なり。比べるのは同じ親の子どうしだけ。英米の法令は章ごとに Section 101、201 と百の位を変えるので、
42
43
  * 文書全体の通し番号として比べると抜けに見える。最初の番号は見ない。日本語の項は 2 から番号を振る。
43
44
  * 1 に戻った番号は新しい並びの始まりとして扱うので、「(a) の後の (a)」の重なりは見逃す。
45
+ * 同じ番号の節を中に持つ節(ほかの文書の条を引いた手本の見出し)は、並びに入れない。
44
46
  */
45
- export const numberingBreaks = (tree: StructureNode): StructureIssue[] =>
46
- inDocumentOrder(tree)
47
- .flatMap(sequencesOf)
47
+ export const numberingBreaks = (tree: StructureNode): StructureIssue[] => {
48
+ const quoting = numbersQuotedInside(tree);
49
+ return inDocumentOrder(tree)
50
+ .flatMap((parent) => sequencesOf(parent, quoting))
48
51
  .flatMap(breaksIn)
49
52
  .toSorted((left, right) => left.offset - right.offset);
53
+ };
@@ -1,7 +1,8 @@
1
1
  import { markdownOutline } from "../document.ts";
2
- import type { DocumentProfile, StructureNode, StructurePatterns } from "../plugin.ts";
3
- import { buildTree } from "./build.ts";
2
+ import type { DocumentProfile, Lexicon, StructureNode, StructurePatterns } from "../plugin.ts";
3
+ import { buildTree, type Outline } from "./build.ts";
4
4
  import { textOutline } from "../page-furniture.ts";
5
+ import { emailParts, emailVocabulary } from "../email-parts.ts";
5
6
 
6
7
  export type SourceInput = {
7
8
  readonly path: string;
@@ -9,8 +10,15 @@ export type SourceInput = {
9
10
  readonly language: string;
10
11
  readonly markdown: boolean;
11
12
  readonly profile?: DocumentProfile | undefined;
13
+ /** 言語パッケージの語彙表。メールの引用した返信を見分けて、木に入れない。無ければ見分けない。 */
14
+ readonly lexicons?: Readonly<Record<string, Lexicon>> | undefined;
12
15
  };
13
16
 
17
+ const outlineOf = (input: SourceInput): Outline =>
18
+ input.markdown
19
+ ? markdownOutline(input.source, input.lexicons)
20
+ : textOutline(input.source, emailParts(input.source, emailVocabulary(input.lexicons ?? {})).replyQuotes);
21
+
14
22
  /**
15
23
  * 文字列から木を作る。Markdown なら見出しとコードの範囲を先に取る。
16
24
  * lint は文書モデルを作るときの解析を使い回すので、ここを通らずに buildTree を呼ぶ。
@@ -21,7 +29,7 @@ export const buildStructure = (input: SourceInput, patterns: StructurePatterns):
21
29
  path: input.path,
22
30
  source: input.source,
23
31
  language: input.language,
24
- outline: input.markdown ? markdownOutline(input.source) : textOutline(input.source),
32
+ outline: outlineOf(input),
25
33
  markdown: input.markdown,
26
34
  profile: input.profile,
27
35
  },
@@ -0,0 +1,135 @@
1
+ import type { StructureIssue } from "./issues.ts";
2
+ import { runsOf, TABLE_ROW, TABLE_RULE, type Line } from "./runs.ts";
3
+ import { columnOf, isTotalLabel, type Amount } from "./total.ts";
4
+ import { CELL_SEPARATOR } from "./bare-numbers.ts";
5
+ import { joined, lineAbove, linesAbove } from "../text-above.ts";
6
+
7
+ /**
8
+ * 一つの全体を分けた割合(構成比、内訳、breakdown)の和が 100% にならない。箇条書きの続いた項目か、表の続いた行の百分率を足す。
9
+ * 全体を分けたものと読むのは、表のその列の見出しか、すぐ上の文や見出しに割合の語があるときだけ。行ごとの率(利用率)は足さない。
10
+ * 丸めの誤差は、項目ごとに最後の桁の半分まで認める(少なくとも 1 ポイント)。合計の行がある並びは total-mismatch に任せる。
11
+ */
12
+ export type ShareWords = {
13
+ readonly labels: readonly string[];
14
+ /** 足しても 100% にならない集計(複数回答)。 */
15
+ readonly exceptions: readonly string[];
16
+ readonly units: readonly string[];
17
+ readonly totalLabels: readonly string[];
18
+ };
19
+
20
+ const WHOLE = 100;
21
+ const MIN_PARTS = 2;
22
+ const HALF = 0.5;
23
+ const DECIMAL_BASE = 10;
24
+
25
+ type Share = Amount & { readonly column: number; readonly decimals: number; readonly signed: boolean };
26
+
27
+ /** 数の前に書いた符号(+3%、-2%、▲2%)。増減の率で、全体の一部ではない。行頭の箇条書きの - は符号にしない。 */
28
+ const SIGNS = "-+−▲△";
29
+
30
+ const isSigned = (source: string, line: Line, offset: number): boolean => {
31
+ const before = source.slice(line.start, offset).trimEnd();
32
+ return SIGNS.includes(before.at(-1) ?? " ") && before.slice(0, -1).trim().length > 0;
33
+ };
34
+ const DECIMALS = /\.(\d+)/u;
35
+
36
+ const includesAny = (text: string, words: readonly string[]): boolean => {
37
+ const lowered = text.toLowerCase();
38
+ return words.some((word) => lowered.includes(word.toLowerCase()));
39
+ };
40
+
41
+ /** 位置の順に並べた百分率のうち、offset 以後の最初のもの。 */
42
+ const firstFrom = (percents: readonly Amount[], offset: number, low = 0, high = percents.length): number => {
43
+ if (low >= high) return low;
44
+ const middle = Math.floor((low + high) / 2);
45
+ return (percents[middle]?.offset ?? 0) < offset ? firstFrom(percents, offset, middle + 1, high) : firstFrom(percents, offset, low, middle);
46
+ };
47
+
48
+ /** 行の中の百分率。百分率は位置の順に並んでいるので、行の頭から探して行の終わりで止める。 */
49
+ const onLine = (percents: readonly Amount[], line: Line): Amount[] => {
50
+ const from = firstFrom(percents, line.start);
51
+ const past = firstFrom(percents, line.end + 1, from);
52
+ return percents.slice(from, past);
53
+ };
54
+
55
+ const sharesIn = (source: string, line: Line, percents: readonly Amount[]): Share[] =>
56
+ onLine(percents, line).map((amount) => ({
57
+ ...amount,
58
+ column: columnOf(source, line, amount.offset),
59
+ signed: isSigned(source, line, amount.offset),
60
+ decimals: DECIMALS.exec(source.slice(amount.offset, amount.end))?.[1]?.length ?? 0,
61
+ }));
62
+
63
+ /** 表の見出しの行の升。区切りの行のすぐ上の行。表でなければ無い。 */
64
+ const headerCells = (source: string, firstRow: Line): string[] => {
65
+ const rule = lineAbove(source, firstRow.start);
66
+ if (rule === undefined || !TABLE_RULE.test(rule.text)) return [];
67
+ const header = lineAbove(source, rule.start);
68
+ return header === undefined ? [] : header.text.split(CELL_SEPARATOR);
69
+ };
70
+
71
+ /** 並びのすぐ上の文か見出し。表なら見出しの行と区切りの行を飛ばして、その上。 */
72
+ const textAbove = (source: string, run: readonly Line[]): string => {
73
+ const first = run[0];
74
+ return first === undefined
75
+ ? ""
76
+ : (joined(
77
+ source,
78
+ linesAbove(source, first.start, (text) => TABLE_ROW.test(text)),
79
+ )?.text ?? "");
80
+ };
81
+
82
+ /** 列の百分率。どの行にもちょうど一つあり、符号の無いときだけ。 */
83
+ const columnShares = (rows: readonly Share[][], column: number): Share[] | undefined => {
84
+ const cells = rows.map((row) => row.filter((share) => share.column === column));
85
+ if (cells.some((cell) => cell.length !== 1)) return undefined;
86
+ const shares = cells.flat();
87
+ return shares.some((share) => share.signed) ? undefined : shares;
88
+ };
89
+
90
+ const sumOf = (shares: readonly Share[]): number => shares.reduce((total, share) => total + share.value, 0);
91
+
92
+ const decimalsOf = (shares: readonly Share[]): number => Math.max(0, ...shares.map((share) => share.decimals));
93
+
94
+ /** 丸めで離れうる幅。項目ごとに最後の桁の半分、少なくとも 1 ポイント。 */
95
+ const tolerance = (shares: readonly Share[]): number => Math.max(1, shares.length * HALF * DECIMAL_BASE ** -decimalsOf(shares));
96
+
97
+ /** 和は、項目のいちばん細かい桁で、最初の項目の単位を付けて見せる。 */
98
+ const shownSum = (shares: readonly Share[]): string => `${sumOf(shares).toFixed(decimalsOf(shares))}${shares[0]?.unit ?? ""}`;
99
+
100
+ type Named = { readonly header: readonly string[]; readonly above: string };
101
+
102
+ /** 列が全体を分けた割合と名指されているか。表は列の見出しか、百分率の列が一つだけの表の上の文。箇条書きは上の文。 */
103
+ const namesShares = (named: Named, column: number, percentColumns: number, words: ShareWords): boolean => {
104
+ const header = named.header[column] ?? "";
105
+ if (named.header.length > 0 && includesAny(header, words.labels)) return true;
106
+ return (named.header.length === 0 || percentColumns === 1) && includesAny(named.above, words.labels);
107
+ };
108
+
109
+ /** 足してよい並び: 二行以上で、合計の行が無い。 */
110
+ const isBreakdown = (source: string, run: readonly Line[], totalLabels: readonly string[]): boolean =>
111
+ run.length >= MIN_PARTS && !run.some((line) => isTotalLabel(source.slice(line.start, line.end), totalLabels));
112
+
113
+ const namingOf = (source: string, run: readonly Line[], first: Line): Named => ({ header: headerCells(source, first), above: textAbove(source, run) });
114
+
115
+ const mismatchesIn = (source: string, run: readonly Line[], percents: readonly Amount[], words: ShareWords): StructureIssue[] => {
116
+ const first = run[0];
117
+ if (first === undefined || !isBreakdown(source, run, words.totalLabels)) return [];
118
+ const rows = run.map((line) => sharesIn(source, line, percents));
119
+ const columns = [...new Set((rows[0] ?? []).map((share) => share.column))];
120
+ if (columns.length === 0) return [];
121
+ const named = namingOf(source, run, first);
122
+ if (includesAny([...named.header, named.above].join(" "), words.exceptions)) return [];
123
+ return columns.flatMap((column) => {
124
+ const shares = columnShares(rows, column);
125
+ if (shares === undefined || !namesShares(named, column, columns.length, words)) return [];
126
+ if (Math.abs(sumOf(shares) - WHOLE) <= tolerance(shares)) return [];
127
+ return [{ offset: shares[0]?.offset ?? first.start, values: { sum: shownSum(shares) } }];
128
+ });
129
+ };
130
+
131
+ export const percentSumMismatches = (source: string, amounts: readonly Amount[], words: ShareWords): StructureIssue[] => {
132
+ if (words.labels.length === 0) return [];
133
+ const percents = amounts.filter((amount) => words.units.includes(amount.unit)).toSorted((a, b) => a.offset - b.offset);
134
+ return runsOf(source).flatMap((run) => mismatchesIn(source, run, percents, words));
135
+ };
@@ -0,0 +1,36 @@
1
+ import type { StructureNode } from "../plugin.ts";
2
+
3
+ type Visit = { readonly node: StructureNode; readonly leaving: boolean };
4
+
5
+ const keyOf = (node: StructureNode): string | undefined => (node.ordinal === undefined || node.address === "" ? undefined : `${node.kind}/${node.address}`);
6
+
7
+ /** 開いた節を番地ごとに積む。同じ番地の節がもう開いていれば、その一番近いものが中に自分の番号を持つ。 */
8
+ const enter = (open: Map<string, StructureNode[]>, key: string, node: StructureNode, quoting: Set<StructureNode>): void => {
9
+ const holders = open.get(key) ?? [];
10
+ const nearest = holders.at(-1);
11
+ if (nearest !== undefined) quoting.add(nearest);
12
+ holders.push(node);
13
+ open.set(key, holders);
14
+ };
15
+
16
+ /**
17
+ * 同じ種類・同じ番地の番号付きの節を中に持つ節。自分の中に自分は無いので、これはこの文書の番号ではなく、
18
+ * 書き方の手本(「§ 163.25」の下に書き直した「§ 163.25」)のように、ほかの文書の条を名前として引いている。
19
+ * 木を一度だけ歩く。一番近い祖先だけに印を付ければ、その外側は内側の祖先が付ける。深い木でも再帰しない。
20
+ */
21
+ export const numbersQuotedInside = (tree: StructureNode): ReadonlySet<StructureNode> => {
22
+ const quoting = new Set<StructureNode>();
23
+ const open = new Map<string, StructureNode[]>();
24
+ const pending: Visit[] = [{ node: tree, leaving: false }];
25
+ for (let visit = pending.pop(); visit !== undefined; visit = pending.pop()) {
26
+ const key = keyOf(visit.node);
27
+ if (visit.leaving) {
28
+ if (key !== undefined) open.get(key)?.pop();
29
+ continue;
30
+ }
31
+ if (key !== undefined) enter(open, key, visit.node, quoting);
32
+ pending.push({ node: visit.node, leaving: true });
33
+ visit.node.children.toReversed().forEach((child) => pending.push({ node: child, leaving: false }));
34
+ }
35
+ return quoting;
36
+ };