chaffjs 0.27.1 → 0.29.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 (923) hide show
  1. package/README.md +2 -1
  2. package/dist/ai-score/of-document.d.ts.map +1 -1
  3. package/dist/ai-score/of-document.js +23 -14
  4. package/dist/ai-score/of-document.js.map +1 -1
  5. package/dist/ai-score/render.d.ts.map +1 -1
  6. package/dist/ai-score/render.js +13 -4
  7. package/dist/ai-score/render.js.map +1 -1
  8. package/dist/ai-score/score.d.ts +16 -1
  9. package/dist/ai-score/score.d.ts.map +1 -1
  10. package/dist/ai-score/score.js +15 -3
  11. package/dist/ai-score/score.js.map +1 -1
  12. package/dist/ai-score/signals.d.ts +2 -4
  13. package/dist/ai-score/signals.d.ts.map +1 -1
  14. package/dist/ai-score/signals.js +11 -2
  15. package/dist/ai-score/signals.js.map +1 -1
  16. package/dist/ai-score/text.d.ts +2 -0
  17. package/dist/ai-score/text.d.ts.map +1 -1
  18. package/dist/ai-score/text.js +4 -2
  19. package/dist/ai-score/text.js.map +1 -1
  20. package/dist/announced-count.d.ts +2 -0
  21. package/dist/announced-count.d.ts.map +1 -1
  22. package/dist/announced-count.js +14 -7
  23. package/dist/announced-count.js.map +1 -1
  24. package/dist/check-source.d.ts +3 -1
  25. package/dist/check-source.d.ts.map +1 -1
  26. package/dist/check-source.js +3 -1
  27. package/dist/check-source.js.map +1 -1
  28. package/dist/cli-text.d.ts.map +1 -1
  29. package/dist/cli-text.js +42 -18
  30. package/dist/cli-text.js.map +1 -1
  31. package/dist/cli.d.ts.map +1 -1
  32. package/dist/cli.js +2 -1
  33. package/dist/cli.js.map +1 -1
  34. package/dist/commands/cite-claims.d.ts +36 -0
  35. package/dist/commands/cite-claims.d.ts.map +1 -0
  36. package/dist/commands/cite-claims.js +81 -0
  37. package/dist/commands/cite-claims.js.map +1 -0
  38. package/dist/commands/cite-page.d.ts +14 -0
  39. package/dist/commands/cite-page.d.ts.map +1 -0
  40. package/dist/commands/cite-page.js +47 -0
  41. package/dist/commands/cite-page.js.map +1 -0
  42. package/dist/commands/cite-scaffold.d.ts +16 -0
  43. package/dist/commands/cite-scaffold.d.ts.map +1 -0
  44. package/dist/commands/cite-scaffold.js +21 -0
  45. package/dist/commands/cite-scaffold.js.map +1 -0
  46. package/dist/commands/cite.d.ts +3 -12
  47. package/dist/commands/cite.d.ts.map +1 -1
  48. package/dist/commands/cite.js +110 -51
  49. package/dist/commands/cite.js.map +1 -1
  50. package/dist/company-names.d.ts +34 -0
  51. package/dist/company-names.d.ts.map +1 -0
  52. package/dist/company-names.js +158 -0
  53. package/dist/company-names.js.map +1 -0
  54. package/dist/default-values.d.ts +17 -0
  55. package/dist/default-values.d.ts.map +1 -0
  56. package/dist/default-values.js +134 -0
  57. package/dist/default-values.js.map +1 -0
  58. package/dist/deprecated-use.d.ts +17 -0
  59. package/dist/deprecated-use.d.ts.map +1 -0
  60. package/dist/deprecated-use.js +95 -0
  61. package/dist/deprecated-use.js.map +1 -0
  62. package/dist/derived/number-word-counts.d.ts +10 -0
  63. package/dist/derived/number-word-counts.d.ts.map +1 -0
  64. package/dist/derived/number-word-counts.js +21 -0
  65. package/dist/derived/number-word-counts.js.map +1 -0
  66. package/dist/derived/stays.d.ts +43 -0
  67. package/dist/derived/stays.d.ts.map +1 -0
  68. package/dist/derived/stays.js +105 -0
  69. package/dist/derived/stays.js.map +1 -0
  70. package/dist/detectors/acronym-context.d.ts +2 -2
  71. package/dist/detectors/acronym-context.d.ts.map +1 -1
  72. package/dist/detectors/acronym-context.js +6 -0
  73. package/dist/detectors/acronym-context.js.map +1 -1
  74. package/dist/detectors/address-word.d.ts +3 -0
  75. package/dist/detectors/address-word.d.ts.map +1 -0
  76. package/dist/detectors/address-word.js +7 -0
  77. package/dist/detectors/address-word.js.map +1 -0
  78. package/dist/detectors/agreement-slip.d.ts.map +1 -1
  79. package/dist/detectors/agreement-slip.js +4 -1
  80. package/dist/detectors/agreement-slip.js.map +1 -1
  81. package/dist/detectors/ai-phrasing.d.ts +0 -4
  82. package/dist/detectors/ai-phrasing.d.ts.map +1 -1
  83. package/dist/detectors/ai-phrasing.js +5 -1
  84. package/dist/detectors/ai-phrasing.js.map +1 -1
  85. package/dist/detectors/amount-range.d.ts +3 -0
  86. package/dist/detectors/amount-range.d.ts.map +1 -0
  87. package/dist/detectors/amount-range.js +38 -0
  88. package/dist/detectors/amount-range.js.map +1 -0
  89. package/dist/detectors/amount-scale.d.ts +8 -0
  90. package/dist/detectors/amount-scale.d.ts.map +1 -0
  91. package/dist/detectors/amount-scale.js +74 -0
  92. package/dist/detectors/amount-scale.js.map +1 -0
  93. package/dist/detectors/announced-count.d.ts +1 -1
  94. package/dist/detectors/announced-count.d.ts.map +1 -1
  95. package/dist/detectors/announced-count.js +18 -3
  96. package/dist/detectors/announced-count.js.map +1 -1
  97. package/dist/detectors/bare-comparative.d.ts.map +1 -1
  98. package/dist/detectors/bare-comparative.js +4 -1
  99. package/dist/detectors/bare-comparative.js.map +1 -1
  100. package/dist/detectors/block-quotation.d.ts +13 -0
  101. package/dist/detectors/block-quotation.d.ts.map +1 -0
  102. package/dist/detectors/block-quotation.js +86 -0
  103. package/dist/detectors/block-quotation.js.map +1 -0
  104. package/dist/detectors/bracket-label.d.ts +10 -0
  105. package/dist/detectors/bracket-label.d.ts.map +1 -0
  106. package/dist/detectors/bracket-label.js +51 -0
  107. package/dist/detectors/bracket-label.js.map +1 -0
  108. package/dist/detectors/change-rate.d.ts.map +1 -1
  109. package/dist/detectors/change-rate.js +12 -1
  110. package/dist/detectors/change-rate.js.map +1 -1
  111. package/dist/detectors/citation-entry.d.ts +5 -0
  112. package/dist/detectors/citation-entry.d.ts.map +1 -1
  113. package/dist/detectors/citation-entry.js +19 -5
  114. package/dist/detectors/citation-entry.js.map +1 -1
  115. package/dist/detectors/code-before.d.ts +6 -0
  116. package/dist/detectors/code-before.d.ts.map +1 -0
  117. package/dist/detectors/code-before.js +15 -0
  118. package/dist/detectors/code-before.js.map +1 -0
  119. package/dist/detectors/connective-hierarchy.d.ts +11 -1
  120. package/dist/detectors/connective-hierarchy.d.ts.map +1 -1
  121. package/dist/detectors/connective-hierarchy.js +26 -6
  122. package/dist/detectors/connective-hierarchy.js.map +1 -1
  123. package/dist/detectors/currency-notation.d.ts +3 -1
  124. package/dist/detectors/currency-notation.d.ts.map +1 -1
  125. package/dist/detectors/currency-notation.js +4 -3
  126. package/dist/detectors/currency-notation.js.map +1 -1
  127. package/dist/detectors/date-outside-period.d.ts +4 -0
  128. package/dist/detectors/date-outside-period.d.ts.map +1 -0
  129. package/dist/detectors/date-outside-period.js +34 -0
  130. package/dist/detectors/date-outside-period.js.map +1 -0
  131. package/dist/detectors/default-values.d.ts +3 -0
  132. package/dist/detectors/default-values.d.ts.map +1 -0
  133. package/dist/detectors/default-values.js +14 -0
  134. package/dist/detectors/default-values.js.map +1 -0
  135. package/dist/detectors/defined-term-form.d.ts +6 -2
  136. package/dist/detectors/defined-term-form.d.ts.map +1 -1
  137. package/dist/detectors/defined-term-form.js +72 -12
  138. package/dist/detectors/defined-term-form.js.map +1 -1
  139. package/dist/detectors/definition-use.d.ts.map +1 -1
  140. package/dist/detectors/definition-use.js +8 -1
  141. package/dist/detectors/definition-use.js.map +1 -1
  142. package/dist/detectors/deprecated-use.d.ts +3 -0
  143. package/dist/detectors/deprecated-use.d.ts.map +1 -0
  144. package/dist/detectors/deprecated-use.js +14 -0
  145. package/dist/detectors/deprecated-use.js.map +1 -0
  146. package/dist/detectors/derived-numbers.d.ts +1 -1
  147. package/dist/detectors/derived-numbers.d.ts.map +1 -1
  148. package/dist/detectors/derived-numbers.js +79 -16
  149. package/dist/detectors/derived-numbers.js.map +1 -1
  150. package/dist/detectors/document-shape.d.ts +1 -0
  151. package/dist/detectors/document-shape.d.ts.map +1 -1
  152. package/dist/detectors/document-shape.js +4 -1
  153. package/dist/detectors/document-shape.js.map +1 -1
  154. package/dist/detectors/due-date.d.ts +3 -0
  155. package/dist/detectors/due-date.d.ts.map +1 -0
  156. package/dist/detectors/due-date.js +38 -0
  157. package/dist/detectors/due-date.js.map +1 -0
  158. package/dist/detectors/en-shape.d.ts.map +1 -1
  159. package/dist/detectors/en-shape.js +17 -9
  160. package/dist/detectors/en-shape.js.map +1 -1
  161. package/dist/detectors/fact-consistency.d.ts.map +1 -1
  162. package/dist/detectors/fact-consistency.js +89 -2
  163. package/dist/detectors/fact-consistency.js.map +1 -1
  164. package/dist/detectors/heading-echo.d.ts.map +1 -1
  165. package/dist/detectors/heading-echo.js +10 -1
  166. package/dist/detectors/heading-echo.js.map +1 -1
  167. package/dist/detectors/kana-function-word.d.ts +12 -0
  168. package/dist/detectors/kana-function-word.d.ts.map +1 -0
  169. package/dist/detectors/kana-function-word.js +59 -0
  170. package/dist/detectors/kana-function-word.js.map +1 -0
  171. package/dist/detectors/line-amount.d.ts +3 -0
  172. package/dist/detectors/line-amount.d.ts.map +1 -0
  173. package/dist/detectors/line-amount.js +22 -0
  174. package/dist/detectors/line-amount.js.map +1 -0
  175. package/dist/detectors/location-pointer.d.ts +6 -0
  176. package/dist/detectors/location-pointer.d.ts.map +1 -0
  177. package/dist/detectors/location-pointer.js +22 -0
  178. package/dist/detectors/location-pointer.js.map +1 -0
  179. package/dist/detectors/mark-shape.d.ts.map +1 -1
  180. package/dist/detectors/mark-shape.js +13 -1
  181. package/dist/detectors/mark-shape.js.map +1 -1
  182. package/dist/detectors/nado-closed-list.d.ts +3 -0
  183. package/dist/detectors/nado-closed-list.d.ts.map +1 -0
  184. package/dist/detectors/nado-closed-list.js +21 -0
  185. package/dist/detectors/nado-closed-list.js.map +1 -0
  186. package/dist/detectors/name-variant.d.ts.map +1 -1
  187. package/dist/detectors/name-variant.js +92 -10
  188. package/dist/detectors/name-variant.js.map +1 -1
  189. package/dist/detectors/next-word.d.ts.map +1 -1
  190. package/dist/detectors/next-word.js +41 -8
  191. package/dist/detectors/next-word.js.map +1 -1
  192. package/dist/detectors/number-word-figure.d.ts +5 -0
  193. package/dist/detectors/number-word-figure.d.ts.map +1 -0
  194. package/dist/detectors/number-word-figure.js +32 -0
  195. package/dist/detectors/number-word-figure.js.map +1 -0
  196. package/dist/detectors/obligation-without-deadline.d.ts +39 -0
  197. package/dist/detectors/obligation-without-deadline.d.ts.map +1 -0
  198. package/dist/detectors/obligation-without-deadline.js +148 -0
  199. package/dist/detectors/obligation-without-deadline.js.map +1 -0
  200. package/dist/detectors/open-end-names.d.ts +23 -0
  201. package/dist/detectors/open-end-names.d.ts.map +1 -0
  202. package/dist/detectors/open-end-names.js +95 -0
  203. package/dist/detectors/open-end-names.js.map +1 -0
  204. package/dist/detectors/ordinal-run-gaps.d.ts +8 -0
  205. package/dist/detectors/ordinal-run-gaps.d.ts.map +1 -0
  206. package/dist/detectors/ordinal-run-gaps.js +80 -0
  207. package/dist/detectors/ordinal-run-gaps.js.map +1 -0
  208. package/dist/detectors/orthographic-variant.d.ts.map +1 -1
  209. package/dist/detectors/orthographic-variant.js +26 -9
  210. package/dist/detectors/orthographic-variant.js.map +1 -1
  211. package/dist/detectors/orthography.d.ts.map +1 -1
  212. package/dist/detectors/orthography.js +5 -0
  213. package/dist/detectors/orthography.js.map +1 -1
  214. package/dist/detectors/parameter-table.d.ts +3 -0
  215. package/dist/detectors/parameter-table.d.ts.map +1 -0
  216. package/dist/detectors/parameter-table.js +16 -0
  217. package/dist/detectors/parameter-table.js.map +1 -0
  218. package/dist/detectors/phone-number-variant.d.ts +3 -0
  219. package/dist/detectors/phone-number-variant.d.ts.map +1 -0
  220. package/dist/detectors/phone-number-variant.js +18 -0
  221. package/dist/detectors/phone-number-variant.js.map +1 -0
  222. package/dist/detectors/prerequisite-order.d.ts +3 -0
  223. package/dist/detectors/prerequisite-order.d.ts.map +1 -0
  224. package/dist/detectors/prerequisite-order.js +30 -0
  225. package/dist/detectors/prerequisite-order.js.map +1 -0
  226. package/dist/detectors/quote-unnamed-speaker.d.ts +3 -0
  227. package/dist/detectors/quote-unnamed-speaker.d.ts.map +1 -0
  228. package/dist/detectors/quote-unnamed-speaker.js +18 -0
  229. package/dist/detectors/quote-unnamed-speaker.js.map +1 -0
  230. package/dist/detectors/quote-without-source.d.ts +12 -2
  231. package/dist/detectors/quote-without-source.d.ts.map +1 -1
  232. package/dist/detectors/quote-without-source.js +45 -11
  233. package/dist/detectors/quote-without-source.js.map +1 -1
  234. package/dist/detectors/registry/amount-range.d.ts +3 -0
  235. package/dist/detectors/registry/amount-range.d.ts.map +1 -0
  236. package/dist/detectors/registry/amount-range.js +3 -0
  237. package/dist/detectors/registry/amount-range.js.map +1 -0
  238. package/dist/detectors/registry/amount-scale.d.ts +3 -0
  239. package/dist/detectors/registry/amount-scale.d.ts.map +1 -0
  240. package/dist/detectors/registry/amount-scale.js +3 -0
  241. package/dist/detectors/registry/amount-scale.js.map +1 -0
  242. package/dist/detectors/registry/arrival-before-departure.d.ts +3 -0
  243. package/dist/detectors/registry/arrival-before-departure.d.ts.map +1 -0
  244. package/dist/detectors/registry/arrival-before-departure.js +3 -0
  245. package/dist/detectors/registry/arrival-before-departure.js.map +1 -0
  246. package/dist/detectors/registry/date-outside-period.d.ts +3 -0
  247. package/dist/detectors/registry/date-outside-period.d.ts.map +1 -0
  248. package/dist/detectors/registry/date-outside-period.js +3 -0
  249. package/dist/detectors/registry/date-outside-period.js.map +1 -0
  250. package/dist/detectors/registry/default-values.d.ts +3 -0
  251. package/dist/detectors/registry/default-values.d.ts.map +1 -0
  252. package/dist/detectors/registry/default-values.js +3 -0
  253. package/dist/detectors/registry/default-values.js.map +1 -0
  254. package/dist/detectors/registry/deprecated-use.d.ts +3 -0
  255. package/dist/detectors/registry/deprecated-use.d.ts.map +1 -0
  256. package/dist/detectors/registry/deprecated-use.js +3 -0
  257. package/dist/detectors/registry/deprecated-use.js.map +1 -0
  258. package/dist/detectors/registry/due-date.d.ts +3 -0
  259. package/dist/detectors/registry/due-date.d.ts.map +1 -0
  260. package/dist/detectors/registry/due-date.js +3 -0
  261. package/dist/detectors/registry/due-date.js.map +1 -0
  262. package/dist/detectors/registry/kana-function-word.d.ts +3 -0
  263. package/dist/detectors/registry/kana-function-word.d.ts.map +1 -0
  264. package/dist/detectors/registry/kana-function-word.js +3 -0
  265. package/dist/detectors/registry/kana-function-word.js.map +1 -0
  266. package/dist/detectors/registry/line-amount.d.ts +3 -0
  267. package/dist/detectors/registry/line-amount.d.ts.map +1 -0
  268. package/dist/detectors/registry/line-amount.js +3 -0
  269. package/dist/detectors/registry/line-amount.js.map +1 -0
  270. package/dist/detectors/registry/nado-closed-list.d.ts +3 -0
  271. package/dist/detectors/registry/nado-closed-list.d.ts.map +1 -0
  272. package/dist/detectors/registry/nado-closed-list.js +3 -0
  273. package/dist/detectors/registry/nado-closed-list.js.map +1 -0
  274. package/dist/detectors/registry/number-word-figure.d.ts +3 -0
  275. package/dist/detectors/registry/number-word-figure.d.ts.map +1 -0
  276. package/dist/detectors/registry/number-word-figure.js +3 -0
  277. package/dist/detectors/registry/number-word-figure.js.map +1 -0
  278. package/dist/detectors/registry/obligation-without-deadline.d.ts +3 -0
  279. package/dist/detectors/registry/obligation-without-deadline.d.ts.map +1 -0
  280. package/dist/detectors/registry/obligation-without-deadline.js +3 -0
  281. package/dist/detectors/registry/obligation-without-deadline.js.map +1 -0
  282. package/dist/detectors/registry/parameter-table.d.ts +3 -0
  283. package/dist/detectors/registry/parameter-table.d.ts.map +1 -0
  284. package/dist/detectors/registry/parameter-table.js +3 -0
  285. package/dist/detectors/registry/parameter-table.js.map +1 -0
  286. package/dist/detectors/registry/phone-number-variant.d.ts +3 -0
  287. package/dist/detectors/registry/phone-number-variant.d.ts.map +1 -0
  288. package/dist/detectors/registry/phone-number-variant.js +3 -0
  289. package/dist/detectors/registry/phone-number-variant.js.map +1 -0
  290. package/dist/detectors/registry/prerequisite-order.d.ts +3 -0
  291. package/dist/detectors/registry/prerequisite-order.d.ts.map +1 -0
  292. package/dist/detectors/registry/prerequisite-order.js +3 -0
  293. package/dist/detectors/registry/prerequisite-order.js.map +1 -0
  294. package/dist/detectors/registry/quote-unnamed-speaker.d.ts +3 -0
  295. package/dist/detectors/registry/quote-unnamed-speaker.d.ts.map +1 -0
  296. package/dist/detectors/registry/quote-unnamed-speaker.js +3 -0
  297. package/dist/detectors/registry/quote-unnamed-speaker.js.map +1 -0
  298. package/dist/detectors/registry/tax-amount.d.ts +3 -0
  299. package/dist/detectors/registry/tax-amount.d.ts.map +1 -0
  300. package/dist/detectors/registry/tax-amount.js +3 -0
  301. package/dist/detectors/registry/tax-amount.js.map +1 -0
  302. package/dist/detectors/registry/time-order.d.ts +3 -0
  303. package/dist/detectors/registry/time-order.d.ts.map +1 -0
  304. package/dist/detectors/registry/time-order.js +3 -0
  305. package/dist/detectors/registry/time-order.js.map +1 -0
  306. package/dist/detectors/registry/ui-label.d.ts +3 -0
  307. package/dist/detectors/registry/ui-label.d.ts.map +1 -0
  308. package/dist/detectors/registry/ui-label.js +3 -0
  309. package/dist/detectors/registry/ui-label.js.map +1 -0
  310. package/dist/detectors/registry/undefined-call.d.ts +3 -0
  311. package/dist/detectors/registry/undefined-call.d.ts.map +1 -0
  312. package/dist/detectors/registry/undefined-call.js +3 -0
  313. package/dist/detectors/registry/undefined-call.js.map +1 -0
  314. package/dist/detectors/registry/undefined-term.d.ts +3 -0
  315. package/dist/detectors/registry/undefined-term.d.ts.map +1 -0
  316. package/dist/detectors/registry/undefined-term.js +3 -0
  317. package/dist/detectors/registry/undefined-term.js.map +1 -0
  318. package/dist/detectors/registry/version-order.d.ts +3 -0
  319. package/dist/detectors/registry/version-order.d.ts.map +1 -0
  320. package/dist/detectors/registry/version-order.js +3 -0
  321. package/dist/detectors/registry/version-order.js.map +1 -0
  322. package/dist/detectors/registry/warning-action.d.ts +3 -0
  323. package/dist/detectors/registry/warning-action.d.ts.map +1 -0
  324. package/dist/detectors/registry/warning-action.js +3 -0
  325. package/dist/detectors/registry/warning-action.js.map +1 -0
  326. package/dist/detectors/requirement-smell.d.ts.map +1 -1
  327. package/dist/detectors/requirement-smell.js +25 -8
  328. package/dist/detectors/requirement-smell.js.map +1 -1
  329. package/dist/detectors/structure-tree.d.ts +12 -4
  330. package/dist/detectors/structure-tree.d.ts.map +1 -1
  331. package/dist/detectors/structure-tree.js +31 -14
  332. package/dist/detectors/structure-tree.js.map +1 -1
  333. package/dist/detectors/superlative-scope.d.ts.map +1 -1
  334. package/dist/detectors/superlative-scope.js +11 -1
  335. package/dist/detectors/superlative-scope.js.map +1 -1
  336. package/dist/detectors/tax-amount.d.ts +3 -0
  337. package/dist/detectors/tax-amount.d.ts.map +1 -0
  338. package/dist/detectors/tax-amount.js +19 -0
  339. package/dist/detectors/tax-amount.js.map +1 -0
  340. package/dist/detectors/technical-docs.d.ts.map +1 -1
  341. package/dist/detectors/technical-docs.js +5 -1
  342. package/dist/detectors/technical-docs.js.map +1 -1
  343. package/dist/detectors/term-extension.d.ts +14 -0
  344. package/dist/detectors/term-extension.d.ts.map +1 -0
  345. package/dist/detectors/term-extension.js +67 -0
  346. package/dist/detectors/term-extension.js.map +1 -0
  347. package/dist/detectors/time-order.d.ts +4 -0
  348. package/dist/detectors/time-order.d.ts.map +1 -0
  349. package/dist/detectors/time-order.js +32 -0
  350. package/dist/detectors/time-order.js.map +1 -0
  351. package/dist/detectors/ui-label.d.ts +3 -0
  352. package/dist/detectors/ui-label.d.ts.map +1 -0
  353. package/dist/detectors/ui-label.js +16 -0
  354. package/dist/detectors/ui-label.js.map +1 -0
  355. package/dist/detectors/unbalanced-bracket.d.ts.map +1 -1
  356. package/dist/detectors/unbalanced-bracket.js +8 -13
  357. package/dist/detectors/unbalanced-bracket.js.map +1 -1
  358. package/dist/detectors/undefined-call.d.ts +3 -0
  359. package/dist/detectors/undefined-call.d.ts.map +1 -0
  360. package/dist/detectors/undefined-call.js +18 -0
  361. package/dist/detectors/undefined-call.js.map +1 -0
  362. package/dist/detectors/undefined-term.d.ts +22 -0
  363. package/dist/detectors/undefined-term.d.ts.map +1 -0
  364. package/dist/detectors/undefined-term.js +85 -0
  365. package/dist/detectors/undefined-term.js.map +1 -0
  366. package/dist/detectors/unknown-word.d.ts +1 -1
  367. package/dist/detectors/unknown-word.js +3 -3
  368. package/dist/detectors/unknown-word.js.map +1 -1
  369. package/dist/detectors/vague-deadline.d.ts +4 -0
  370. package/dist/detectors/vague-deadline.d.ts.map +1 -1
  371. package/dist/detectors/vague-deadline.js +3 -3
  372. package/dist/detectors/vague-deadline.js.map +1 -1
  373. package/dist/detectors/version-mismatch.d.ts.map +1 -1
  374. package/dist/detectors/version-mismatch.js +18 -1
  375. package/dist/detectors/version-mismatch.js.map +1 -1
  376. package/dist/detectors/version-order.d.ts +3 -0
  377. package/dist/detectors/version-order.d.ts.map +1 -0
  378. package/dist/detectors/version-order.js +43 -0
  379. package/dist/detectors/version-order.js.map +1 -0
  380. package/dist/detectors/warning-action.d.ts +3 -0
  381. package/dist/detectors/warning-action.d.ts.map +1 -0
  382. package/dist/detectors/warning-action.js +48 -0
  383. package/dist/detectors/warning-action.js.map +1 -0
  384. package/dist/facts/condition-pairs.d.ts +51 -0
  385. package/dist/facts/condition-pairs.d.ts.map +1 -0
  386. package/dist/facts/condition-pairs.js +203 -0
  387. package/dist/facts/condition-pairs.js.map +1 -0
  388. package/dist/facts/counted-facts.d.ts +16 -0
  389. package/dist/facts/counted-facts.d.ts.map +1 -0
  390. package/dist/facts/counted-facts.js +45 -0
  391. package/dist/facts/counted-facts.js.map +1 -0
  392. package/dist/facts/event-dates.d.ts +26 -0
  393. package/dist/facts/event-dates.d.ts.map +1 -0
  394. package/dist/facts/event-dates.js +38 -0
  395. package/dist/facts/event-dates.js.map +1 -0
  396. package/dist/facts/fact-scope.d.ts +2 -0
  397. package/dist/facts/fact-scope.d.ts.map +1 -1
  398. package/dist/facts/fact-scope.js +5 -0
  399. package/dist/facts/fact-scope.js.map +1 -1
  400. package/dist/facts/labelled-facts.d.ts +2 -0
  401. package/dist/facts/labelled-facts.d.ts.map +1 -1
  402. package/dist/facts/labelled-facts.js +9 -1
  403. package/dist/facts/labelled-facts.js.map +1 -1
  404. package/dist/facts/table-facts.d.ts +16 -0
  405. package/dist/facts/table-facts.d.ts.map +1 -1
  406. package/dist/facts/table-facts.js +2 -2
  407. package/dist/facts/table-facts.js.map +1 -1
  408. package/dist/grade/ai-score.d.ts +1 -1
  409. package/dist/grade/ai-score.d.ts.map +1 -1
  410. package/dist/grade/text.js +2 -2
  411. package/dist/grade/text.js.map +1 -1
  412. package/dist/heading-numbering.js +2 -2
  413. package/dist/heading-numbering.js.map +1 -1
  414. package/dist/html/fetch-page.d.ts +20 -0
  415. package/dist/html/fetch-page.d.ts.map +1 -0
  416. package/dist/html/fetch-page.js +51 -0
  417. package/dist/html/fetch-page.js.map +1 -0
  418. package/dist/html/fetched-text.d.ts +5 -0
  419. package/dist/html/fetched-text.d.ts.map +1 -0
  420. package/dist/html/fetched-text.js +25 -0
  421. package/dist/html/fetched-text.js.map +1 -0
  422. package/dist/html/html-content-block.d.ts +6 -0
  423. package/dist/html/html-content-block.d.ts.map +1 -0
  424. package/dist/html/html-content-block.js +86 -0
  425. package/dist/html/html-content-block.js.map +1 -0
  426. package/dist/html/html-elements.d.ts +41 -0
  427. package/dist/html/html-elements.d.ts.map +1 -0
  428. package/dist/html/html-elements.js +91 -0
  429. package/dist/html/html-elements.js.map +1 -0
  430. package/dist/html/html-footnote-marks.d.ts +2 -0
  431. package/dist/html/html-footnote-marks.d.ts.map +1 -0
  432. package/dist/html/html-footnote-marks.js +15 -0
  433. package/dist/html/html-footnote-marks.js.map +1 -0
  434. package/dist/html/html-heading-links.d.ts +6 -0
  435. package/dist/html/html-heading-links.d.ts.map +1 -0
  436. package/dist/html/html-heading-links.js +71 -0
  437. package/dist/html/html-heading-links.js.map +1 -0
  438. package/dist/html/html-lost-tags.d.ts +3 -0
  439. package/dist/html/html-lost-tags.d.ts.map +1 -0
  440. package/dist/html/html-lost-tags.js +11 -0
  441. package/dist/html/html-lost-tags.js.map +1 -0
  442. package/dist/html/html-markdown.d.ts +2 -0
  443. package/dist/html/html-markdown.d.ts.map +1 -0
  444. package/dist/html/html-markdown.js +347 -0
  445. package/dist/html/html-markdown.js.map +1 -0
  446. package/dist/html/html-preformatted.d.ts +17 -0
  447. package/dist/html/html-preformatted.d.ts.map +1 -0
  448. package/dist/html/html-preformatted.js +82 -0
  449. package/dist/html/html-preformatted.js.map +1 -0
  450. package/dist/html/html-reader-only.d.ts +6 -0
  451. package/dist/html/html-reader-only.d.ts.map +1 -0
  452. package/dist/html/html-reader-only.js +63 -0
  453. package/dist/html/html-reader-only.js.map +1 -0
  454. package/dist/html/html-run-in-headings.d.ts +2 -0
  455. package/dist/html/html-run-in-headings.d.ts.map +1 -0
  456. package/dist/html/html-run-in-headings.js +36 -0
  457. package/dist/html/html-run-in-headings.js.map +1 -0
  458. package/dist/html/html-tables.d.ts +3 -0
  459. package/dist/html/html-tables.d.ts.map +1 -0
  460. package/dist/html/html-tables.js +58 -0
  461. package/dist/html/html-tables.js.map +1 -0
  462. package/dist/html/html-widgets.d.ts +3 -0
  463. package/dist/html/html-widgets.d.ts.map +1 -0
  464. package/dist/html/html-widgets.js +71 -0
  465. package/dist/html/html-widgets.js.map +1 -0
  466. package/dist/html/markup-text.d.ts +5 -0
  467. package/dist/html/markup-text.d.ts.map +1 -0
  468. package/dist/html/markup-text.js +32 -0
  469. package/dist/html/markup-text.js.map +1 -0
  470. package/dist/html/page-document.d.ts +9 -0
  471. package/dist/html/page-document.d.ts.map +1 -0
  472. package/dist/html/page-document.js +19 -0
  473. package/dist/html/page-document.js.map +1 -0
  474. package/dist/inline-count.d.ts +19 -0
  475. package/dist/inline-count.d.ts.map +1 -0
  476. package/dist/inline-count.js +109 -0
  477. package/dist/inline-count.js.map +1 -0
  478. package/dist/kana-spelling.d.ts +5 -0
  479. package/dist/kana-spelling.d.ts.map +1 -1
  480. package/dist/kana-spelling.js +5 -0
  481. package/dist/kana-spelling.js.map +1 -1
  482. package/dist/location-part.d.ts +13 -0
  483. package/dist/location-part.d.ts.map +1 -0
  484. package/dist/location-part.js +24 -0
  485. package/dist/location-part.js.map +1 -0
  486. package/dist/nado-closed-list.d.ts +20 -0
  487. package/dist/nado-closed-list.d.ts.map +1 -0
  488. package/dist/nado-closed-list.js +72 -0
  489. package/dist/nado-closed-list.js.map +1 -0
  490. package/dist/name-cue.d.ts +17 -0
  491. package/dist/name-cue.d.ts.map +1 -0
  492. package/dist/name-cue.js +29 -0
  493. package/dist/name-cue.js.map +1 -0
  494. package/dist/name-variants.d.ts +41 -5
  495. package/dist/name-variants.d.ts.map +1 -1
  496. package/dist/name-variants.js +93 -8
  497. package/dist/name-variants.js.map +1 -1
  498. package/dist/paragraph-runs.d.ts +6 -1
  499. package/dist/paragraph-runs.d.ts.map +1 -1
  500. package/dist/paragraph-runs.js +9 -2
  501. package/dist/paragraph-runs.js.map +1 -1
  502. package/dist/parameter-table.d.ts +19 -0
  503. package/dist/parameter-table.d.ts.map +1 -0
  504. package/dist/parameter-table.js +191 -0
  505. package/dist/parameter-table.js.map +1 -0
  506. package/dist/phone-numbers.d.ts +23 -0
  507. package/dist/phone-numbers.d.ts.map +1 -0
  508. package/dist/phone-numbers.js +83 -0
  509. package/dist/phone-numbers.js.map +1 -0
  510. package/dist/place-names.d.ts +55 -0
  511. package/dist/place-names.d.ts.map +1 -0
  512. package/dist/place-names.js +196 -0
  513. package/dist/place-names.js.map +1 -0
  514. package/dist/plugin.d.ts +4 -0
  515. package/dist/plugin.d.ts.map +1 -1
  516. package/dist/prerequisite-order.d.ts +16 -0
  517. package/dist/prerequisite-order.d.ts.map +1 -0
  518. package/dist/prerequisite-order.js +29 -0
  519. package/dist/prerequisite-order.js.map +1 -0
  520. package/dist/profile/parse.d.ts.map +1 -1
  521. package/dist/profile/parse.js +10 -1
  522. package/dist/profile/parse.js.map +1 -1
  523. package/dist/reasons.d.ts +2 -0
  524. package/dist/reasons.d.ts.map +1 -1
  525. package/dist/reasons.js +2 -0
  526. package/dist/reasons.js.map +1 -1
  527. package/dist/render/rules-json.d.ts.map +1 -1
  528. package/dist/render/rules-json.js +4 -0
  529. package/dist/render/rules-json.js.map +1 -1
  530. package/dist/render/rules-table.d.ts.map +1 -1
  531. package/dist/render/rules-table.js +6 -2
  532. package/dist/render/rules-table.js.map +1 -1
  533. package/dist/rule-genres.d.ts +5 -2
  534. package/dist/rule-genres.d.ts.map +1 -1
  535. package/dist/rule-genres.js +2 -0
  536. package/dist/rule-genres.js.map +1 -1
  537. package/dist/rule-load.d.ts.map +1 -1
  538. package/dist/rule-load.js +2 -1
  539. package/dist/rule-load.js.map +1 -1
  540. package/dist/run.d.ts.map +1 -1
  541. package/dist/run.js +5 -1
  542. package/dist/run.js.map +1 -1
  543. package/dist/spelling.d.ts +2 -0
  544. package/dist/spelling.d.ts.map +1 -1
  545. package/dist/spelling.js +6 -0
  546. package/dist/spelling.js.map +1 -1
  547. package/dist/structure/action-due.d.ts +21 -0
  548. package/dist/structure/action-due.d.ts.map +1 -0
  549. package/dist/structure/action-due.js +126 -0
  550. package/dist/structure/action-due.js.map +1 -0
  551. package/dist/structure/amount-range.d.ts +30 -0
  552. package/dist/structure/amount-range.d.ts.map +1 -0
  553. package/dist/structure/amount-range.js +153 -0
  554. package/dist/structure/amount-range.js.map +1 -0
  555. package/dist/structure/amount-scale.d.ts +35 -0
  556. package/dist/structure/amount-scale.d.ts.map +1 -0
  557. package/dist/structure/amount-scale.js +83 -0
  558. package/dist/structure/amount-scale.js.map +1 -0
  559. package/dist/structure/cite.d.ts +5 -2
  560. package/dist/structure/cite.d.ts.map +1 -1
  561. package/dist/structure/cite.js +20 -1
  562. package/dist/structure/cite.js.map +1 -1
  563. package/dist/structure/counted-amounts.d.ts +12 -0
  564. package/dist/structure/counted-amounts.d.ts.map +1 -0
  565. package/dist/structure/counted-amounts.js +30 -0
  566. package/dist/structure/counted-amounts.js.map +1 -0
  567. package/dist/structure/date-order.d.ts +24 -3
  568. package/dist/structure/date-order.d.ts.map +1 -1
  569. package/dist/structure/date-order.js +49 -17
  570. package/dist/structure/date-order.js.map +1 -1
  571. package/dist/structure/date-outside-period.d.ts +27 -0
  572. package/dist/structure/date-outside-period.d.ts.map +1 -0
  573. package/dist/structure/date-outside-period.js +86 -0
  574. package/dist/structure/date-outside-period.js.map +1 -0
  575. package/dist/structure/definition-use.d.ts +5 -2
  576. package/dist/structure/definition-use.d.ts.map +1 -1
  577. package/dist/structure/definition-use.js +11 -3
  578. package/dist/structure/definition-use.js.map +1 -1
  579. package/dist/structure/due-date.d.ts +19 -0
  580. package/dist/structure/due-date.d.ts.map +1 -0
  581. package/dist/structure/due-date.js +30 -0
  582. package/dist/structure/due-date.js.map +1 -0
  583. package/dist/structure/heading-runs.d.ts +9 -0
  584. package/dist/structure/heading-runs.d.ts.map +1 -0
  585. package/dist/structure/heading-runs.js +23 -0
  586. package/dist/structure/heading-runs.js.map +1 -0
  587. package/dist/structure/install-pin.d.ts +46 -0
  588. package/dist/structure/install-pin.d.ts.map +1 -0
  589. package/dist/structure/install-pin.js +85 -0
  590. package/dist/structure/install-pin.js.map +1 -0
  591. package/dist/structure/leg-times.d.ts +34 -0
  592. package/dist/structure/leg-times.d.ts.map +1 -0
  593. package/dist/structure/leg-times.js +135 -0
  594. package/dist/structure/leg-times.js.map +1 -0
  595. package/dist/structure/line-amount-unit.d.ts +24 -0
  596. package/dist/structure/line-amount-unit.d.ts.map +1 -0
  597. package/dist/structure/line-amount-unit.js +24 -0
  598. package/dist/structure/line-amount-unit.js.map +1 -0
  599. package/dist/structure/line-amount.d.ts +40 -0
  600. package/dist/structure/line-amount.d.ts.map +1 -0
  601. package/dist/structure/line-amount.js +118 -0
  602. package/dist/structure/line-amount.js.map +1 -0
  603. package/dist/structure/number-word-figure.d.ts +37 -0
  604. package/dist/structure/number-word-figure.d.ts.map +1 -0
  605. package/dist/structure/number-word-figure.js +151 -0
  606. package/dist/structure/number-word-figure.js.map +1 -0
  607. package/dist/structure/numbering.d.ts +1 -0
  608. package/dist/structure/numbering.d.ts.map +1 -1
  609. package/dist/structure/numbering.js +3 -0
  610. package/dist/structure/numbering.js.map +1 -1
  611. package/dist/structure/ordinal-runs.d.ts +45 -0
  612. package/dist/structure/ordinal-runs.d.ts.map +1 -0
  613. package/dist/structure/ordinal-runs.js +78 -0
  614. package/dist/structure/ordinal-runs.js.map +1 -0
  615. package/dist/structure/percent-sum-prose.d.ts +1 -1
  616. package/dist/structure/percent-sum-prose.d.ts.map +1 -1
  617. package/dist/structure/percent-sum-prose.js +45 -3
  618. package/dist/structure/percent-sum-prose.js.map +1 -1
  619. package/dist/structure/percent-sum.d.ts +8 -0
  620. package/dist/structure/percent-sum.d.ts.map +1 -1
  621. package/dist/structure/percent-sum.js +8 -1
  622. package/dist/structure/percent-sum.js.map +1 -1
  623. package/dist/structure/release-list.d.ts +9 -0
  624. package/dist/structure/release-list.d.ts.map +1 -0
  625. package/dist/structure/release-list.js +46 -0
  626. package/dist/structure/release-list.js.map +1 -0
  627. package/dist/structure/share-column.d.ts +7 -0
  628. package/dist/structure/share-column.d.ts.map +1 -0
  629. package/dist/structure/share-column.js +22 -0
  630. package/dist/structure/share-column.js.map +1 -0
  631. package/dist/structure/stated-period.d.ts +31 -0
  632. package/dist/structure/stated-period.d.ts.map +1 -0
  633. package/dist/structure/stated-period.js +127 -0
  634. package/dist/structure/stated-period.js.map +1 -0
  635. package/dist/structure/subject-change.d.ts +8 -0
  636. package/dist/structure/subject-change.d.ts.map +1 -0
  637. package/dist/structure/subject-change.js +31 -0
  638. package/dist/structure/subject-change.js.map +1 -0
  639. package/dist/structure/tax.d.ts +25 -0
  640. package/dist/structure/tax.d.ts.map +1 -0
  641. package/dist/structure/tax.js +86 -0
  642. package/dist/structure/tax.js.map +1 -0
  643. package/dist/structure/time-marks.d.ts +58 -0
  644. package/dist/structure/time-marks.d.ts.map +1 -0
  645. package/dist/structure/time-marks.js +74 -0
  646. package/dist/structure/time-marks.js.map +1 -0
  647. package/dist/structure/time-order.d.ts +21 -0
  648. package/dist/structure/time-order.d.ts.map +1 -0
  649. package/dist/structure/time-order.js +108 -0
  650. package/dist/structure/time-order.js.map +1 -0
  651. package/dist/structure/title-lines.d.ts +8 -0
  652. package/dist/structure/title-lines.d.ts.map +1 -0
  653. package/dist/structure/title-lines.js +27 -0
  654. package/dist/structure/title-lines.js.map +1 -0
  655. package/dist/structure/total.d.ts.map +1 -1
  656. package/dist/structure/total.js +3 -1
  657. package/dist/structure/total.js.map +1 -1
  658. package/dist/structure/version-mismatch.d.ts +1 -5
  659. package/dist/structure/version-mismatch.d.ts.map +1 -1
  660. package/dist/structure/version-mismatch.js +65 -12
  661. package/dist/structure/version-mismatch.js.map +1 -1
  662. package/dist/structure/version-order.d.ts +23 -0
  663. package/dist/structure/version-order.d.ts.map +1 -0
  664. package/dist/structure/version-order.js +67 -0
  665. package/dist/structure/version-order.js.map +1 -0
  666. package/dist/table-text.d.ts +9 -0
  667. package/dist/table-text.d.ts.map +1 -0
  668. package/dist/table-text.js +36 -0
  669. package/dist/table-text.js.map +1 -0
  670. package/dist/ui-labels.d.ts +16 -0
  671. package/dist/ui-labels.d.ts.map +1 -0
  672. package/dist/ui-labels.js +42 -0
  673. package/dist/ui-labels.js.map +1 -0
  674. package/dist/undefined-call.d.ts +13 -0
  675. package/dist/undefined-call.d.ts.map +1 -0
  676. package/dist/undefined-call.js +55 -0
  677. package/dist/undefined-call.js.map +1 -0
  678. package/dist/unnamed-speaker.d.ts +23 -0
  679. package/dist/unnamed-speaker.d.ts.map +1 -0
  680. package/dist/unnamed-speaker.js +176 -0
  681. package/dist/unnamed-speaker.js.map +1 -0
  682. package/dist/warning-action.d.ts +22 -0
  683. package/dist/warning-action.d.ts.map +1 -0
  684. package/dist/warning-action.js +58 -0
  685. package/dist/warning-action.js.map +1 -0
  686. package/genres.yaml +2 -0
  687. package/package.json +4 -3
  688. package/profiles/statute.yaml +8 -0
  689. package/rules/agreement-slip.yaml +2 -2
  690. package/rules/amount-range-reversed.yaml +52 -0
  691. package/rules/amount-scale-consistency.yaml +74 -0
  692. package/rules/announced-count-mismatch.yaml +9 -4
  693. package/rules/arrival-before-departure.yaml +48 -0
  694. package/rules/change-rate-mismatch.yaml +5 -4
  695. package/rules/connective-hierarchy.yaml +3 -3
  696. package/rules/currency-notation-consistency.yaml +2 -2
  697. package/rules/date-order.yaml +9 -4
  698. package/rules/date-outside-period.yaml +64 -0
  699. package/rules/default-value-mismatch.yaml +79 -0
  700. package/rules/defined-term-form.yaml +9 -7
  701. package/rules/deprecated-option-used.yaml +78 -0
  702. package/rules/doubled-nado.yaml +28 -12
  703. package/rules/due-before-issue.yaml +68 -0
  704. package/rules/duplicate-definition.yaml +2 -2
  705. package/rules/duration-mismatch.yaml +12 -4
  706. package/rules/elapsed-years-mismatch.yaml +2 -2
  707. package/rules/heading-echo.yaml +2 -2
  708. package/rules/hyphen-as-dash.yaml +2 -2
  709. package/rules/kana-function-word.yaml +58 -0
  710. package/rules/latin-spacing.yaml +6 -5
  711. package/rules/line-amount-mismatch.yaml +58 -0
  712. package/rules/nado-closed-list.yaml +77 -0
  713. package/rules/name-variant.yaml +17 -2
  714. package/rules/number-word-figure-mismatch.yaml +76 -0
  715. package/rules/numbering-gap.yaml +2 -2
  716. package/rules/obligation-without-deadline.yaml +95 -0
  717. package/rules/one-sentence-paragraph-run.yaml +2 -3
  718. package/rules/parameter-table-mismatch.yaml +90 -0
  719. package/rules/percent-sum-mismatch.yaml +2 -2
  720. package/rules/phone-number-variant.yaml +68 -0
  721. package/rules/prerequisite-after-step.yaml +78 -0
  722. package/rules/quote-unnamed-speaker.yaml +67 -0
  723. package/rules/quote-without-source.yaml +6 -6
  724. package/rules/requirement-smell.yaml +3 -3
  725. package/rules/sentence-initial-conjunction-run.yaml +13 -7
  726. package/rules/summary-fact-mismatch.yaml +4 -4
  727. package/rules/tax-mismatch.yaml +71 -0
  728. package/rules/time-order.yaml +65 -0
  729. package/rules/title-length.yaml +2 -2
  730. package/rules/ui-label-variant.yaml +70 -0
  731. package/rules/unbalanced-bracket.yaml +4 -4
  732. package/rules/uncomparable-graded.yaml +29 -10
  733. package/rules/undefined-function-call.yaml +77 -0
  734. package/rules/undefined-term.yaml +72 -0
  735. package/rules/unknown-word.yaml +2 -2
  736. package/rules/unqualified-superlative.yaml +2 -2
  737. package/rules/use-before-definition.yaml +2 -2
  738. package/rules/version-mismatch.yaml +12 -4
  739. package/rules/version-order.yaml +85 -0
  740. package/rules/very-adjective.yaml +31 -13
  741. package/rules/warning-without-action.yaml +64 -0
  742. package/rules/wordy-phrase.yaml +27 -9
  743. package/src/ai-score/of-document.ts +19 -9
  744. package/src/ai-score/render.ts +24 -4
  745. package/src/ai-score/score.ts +24 -3
  746. package/src/ai-score/signals.ts +12 -2
  747. package/src/ai-score/text.ts +7 -2
  748. package/src/announced-count.ts +19 -12
  749. package/src/check-source.ts +11 -2
  750. package/src/cli-text.ts +42 -18
  751. package/src/cli.ts +2 -1
  752. package/src/commands/cite-claims.ts +103 -0
  753. package/src/commands/cite-page.ts +61 -0
  754. package/src/commands/cite-scaffold.ts +27 -0
  755. package/src/commands/cite.ts +127 -58
  756. package/src/company-names.ts +202 -0
  757. package/src/default-values.ts +158 -0
  758. package/src/deprecated-use.ts +122 -0
  759. package/src/derived/number-word-counts.ts +28 -0
  760. package/src/derived/stays.ts +145 -0
  761. package/src/detectors/acronym-context.ts +10 -2
  762. package/src/detectors/address-word.ts +9 -0
  763. package/src/detectors/agreement-slip.ts +7 -1
  764. package/src/detectors/ai-phrasing.ts +6 -1
  765. package/src/detectors/amount-range.ts +54 -0
  766. package/src/detectors/amount-scale.ts +96 -0
  767. package/src/detectors/announced-count.ts +29 -11
  768. package/src/detectors/bare-comparative.ts +7 -2
  769. package/src/detectors/block-quotation.ts +95 -0
  770. package/src/detectors/bracket-label.ts +58 -0
  771. package/src/detectors/change-rate.ts +15 -2
  772. package/src/detectors/citation-entry.ts +20 -5
  773. package/src/detectors/code-before.ts +14 -0
  774. package/src/detectors/connective-hierarchy.ts +39 -11
  775. package/src/detectors/currency-notation.ts +4 -3
  776. package/src/detectors/date-outside-period.ts +38 -0
  777. package/src/detectors/default-values.ts +17 -0
  778. package/src/detectors/defined-term-form.ts +84 -15
  779. package/src/detectors/definition-use.ts +10 -2
  780. package/src/detectors/deprecated-use.ts +17 -0
  781. package/src/detectors/derived-numbers.ts +115 -17
  782. package/src/detectors/document-shape.ts +6 -1
  783. package/src/detectors/due-date.ts +47 -0
  784. package/src/detectors/en-shape.ts +27 -11
  785. package/src/detectors/fact-consistency.ts +110 -2
  786. package/src/detectors/heading-echo.ts +11 -1
  787. package/src/detectors/kana-function-word.ts +71 -0
  788. package/src/detectors/line-amount.ts +33 -0
  789. package/src/detectors/location-pointer.ts +30 -0
  790. package/src/detectors/mark-shape.ts +18 -1
  791. package/src/detectors/nado-closed-list.ts +25 -0
  792. package/src/detectors/name-variant.ts +114 -11
  793. package/src/detectors/next-word.ts +56 -9
  794. package/src/detectors/number-word-figure.ts +43 -0
  795. package/src/detectors/obligation-without-deadline.ts +192 -0
  796. package/src/detectors/open-end-names.ts +140 -0
  797. package/src/detectors/ordinal-run-gaps.ts +101 -0
  798. package/src/detectors/orthographic-variant.ts +39 -14
  799. package/src/detectors/orthography.ts +6 -1
  800. package/src/detectors/parameter-table.ts +17 -0
  801. package/src/detectors/phone-number-variant.ts +18 -0
  802. package/src/detectors/prerequisite-order.ts +35 -0
  803. package/src/detectors/quote-unnamed-speaker.ts +19 -0
  804. package/src/detectors/quote-without-source.ts +57 -10
  805. package/src/detectors/registry/amount-range.ts +4 -0
  806. package/src/detectors/registry/amount-scale.ts +4 -0
  807. package/src/detectors/registry/arrival-before-departure.ts +4 -0
  808. package/src/detectors/registry/date-outside-period.ts +4 -0
  809. package/src/detectors/registry/default-values.ts +4 -0
  810. package/src/detectors/registry/deprecated-use.ts +4 -0
  811. package/src/detectors/registry/due-date.ts +4 -0
  812. package/src/detectors/registry/kana-function-word.ts +4 -0
  813. package/src/detectors/registry/line-amount.ts +4 -0
  814. package/src/detectors/registry/nado-closed-list.ts +4 -0
  815. package/src/detectors/registry/number-word-figure.ts +4 -0
  816. package/src/detectors/registry/obligation-without-deadline.ts +4 -0
  817. package/src/detectors/registry/parameter-table.ts +4 -0
  818. package/src/detectors/registry/phone-number-variant.ts +4 -0
  819. package/src/detectors/registry/prerequisite-order.ts +4 -0
  820. package/src/detectors/registry/quote-unnamed-speaker.ts +4 -0
  821. package/src/detectors/registry/tax-amount.ts +4 -0
  822. package/src/detectors/registry/time-order.ts +4 -0
  823. package/src/detectors/registry/ui-label.ts +4 -0
  824. package/src/detectors/registry/undefined-call.ts +4 -0
  825. package/src/detectors/registry/undefined-term.ts +4 -0
  826. package/src/detectors/registry/version-order.ts +4 -0
  827. package/src/detectors/registry/warning-action.ts +4 -0
  828. package/src/detectors/requirement-smell.ts +29 -9
  829. package/src/detectors/structure-tree.ts +43 -21
  830. package/src/detectors/superlative-scope.ts +13 -1
  831. package/src/detectors/tax-amount.ts +25 -0
  832. package/src/detectors/technical-docs.ts +7 -1
  833. package/src/detectors/term-extension.ts +67 -0
  834. package/src/detectors/time-order.ts +49 -0
  835. package/src/detectors/ui-label.ts +17 -0
  836. package/src/detectors/unbalanced-bracket.ts +7 -14
  837. package/src/detectors/undefined-call.ts +19 -0
  838. package/src/detectors/undefined-term.ts +103 -0
  839. package/src/detectors/unknown-word.ts +3 -3
  840. package/src/detectors/vague-deadline.ts +3 -3
  841. package/src/detectors/version-mismatch.ts +26 -5
  842. package/src/detectors/version-order.ts +50 -0
  843. package/src/detectors/warning-action.ts +49 -0
  844. package/src/facts/condition-pairs.ts +289 -0
  845. package/src/facts/counted-facts.ts +59 -0
  846. package/src/facts/event-dates.ts +63 -0
  847. package/src/facts/fact-scope.ts +6 -0
  848. package/src/facts/labelled-facts.ts +13 -1
  849. package/src/facts/table-facts.ts +3 -3
  850. package/src/grade/ai-score.ts +1 -1
  851. package/src/grade/text.ts +2 -2
  852. package/src/heading-numbering.ts +2 -2
  853. package/src/html/fetch-page.ts +64 -0
  854. package/src/html/fetched-text.ts +32 -0
  855. package/src/html/html-content-block.ts +107 -0
  856. package/src/html/html-elements.ts +127 -0
  857. package/src/html/html-footnote-marks.ts +20 -0
  858. package/src/html/html-heading-links.ts +93 -0
  859. package/src/html/html-lost-tags.ts +14 -0
  860. package/src/html/html-markdown.ts +481 -0
  861. package/src/html/html-preformatted.ts +110 -0
  862. package/src/html/html-reader-only.ts +82 -0
  863. package/src/html/html-run-in-headings.ts +43 -0
  864. package/src/html/html-tables.ts +76 -0
  865. package/src/html/html-widgets.ts +114 -0
  866. package/src/html/markup-text.ts +35 -0
  867. package/src/html/page-document.ts +22 -0
  868. package/src/inline-count.ts +146 -0
  869. package/src/kana-spelling.ts +7 -0
  870. package/src/location-part.ts +30 -0
  871. package/src/nado-closed-list.ts +106 -0
  872. package/src/name-cue.ts +35 -0
  873. package/src/name-variants.ts +152 -11
  874. package/src/paragraph-runs.ts +12 -2
  875. package/src/parameter-table.ts +208 -0
  876. package/src/phone-numbers.ts +98 -0
  877. package/src/place-names.ts +248 -0
  878. package/src/plugin.ts +4 -0
  879. package/src/prerequisite-order.ts +39 -0
  880. package/src/profile/parse.ts +10 -1
  881. package/src/reasons.ts +4 -0
  882. package/src/render/rules-json.ts +4 -0
  883. package/src/render/rules-table.ts +6 -3
  884. package/src/rule-genres.ts +5 -2
  885. package/src/rule-load.ts +3 -2
  886. package/src/run.ts +3 -1
  887. package/src/spelling.ts +8 -0
  888. package/src/structure/action-due.ts +179 -0
  889. package/src/structure/amount-range.ts +219 -0
  890. package/src/structure/amount-scale.ts +115 -0
  891. package/src/structure/cite.ts +21 -2
  892. package/src/structure/counted-amounts.ts +42 -0
  893. package/src/structure/date-order.ts +72 -22
  894. package/src/structure/date-outside-period.ts +127 -0
  895. package/src/structure/definition-use.ts +24 -3
  896. package/src/structure/due-date.ts +46 -0
  897. package/src/structure/heading-runs.ts +24 -0
  898. package/src/structure/install-pin.ts +115 -0
  899. package/src/structure/leg-times.ts +198 -0
  900. package/src/structure/line-amount-unit.ts +35 -0
  901. package/src/structure/line-amount.ts +162 -0
  902. package/src/structure/number-word-figure.ts +199 -0
  903. package/src/structure/numbering.ts +3 -0
  904. package/src/structure/ordinal-runs.ts +107 -0
  905. package/src/structure/percent-sum-prose.ts +46 -3
  906. package/src/structure/percent-sum.ts +16 -2
  907. package/src/structure/release-list.ts +69 -0
  908. package/src/structure/share-column.ts +25 -0
  909. package/src/structure/stated-period.ts +161 -0
  910. package/src/structure/subject-change.ts +35 -0
  911. package/src/structure/tax.ts +114 -0
  912. package/src/structure/time-marks.ts +127 -0
  913. package/src/structure/time-order.ts +140 -0
  914. package/src/structure/title-lines.ts +33 -0
  915. package/src/structure/total.ts +5 -1
  916. package/src/structure/version-mismatch.ts +67 -13
  917. package/src/structure/version-order.ts +84 -0
  918. package/src/table-text.ts +39 -0
  919. package/src/ui-labels.ts +55 -0
  920. package/src/undefined-call.ts +65 -0
  921. package/src/unnamed-speaker.ts +224 -0
  922. package/src/warning-action.ts +73 -0
  923. package/styles/koyobun.yaml +7 -4
@@ -0,0 +1,107 @@
1
+ // The numbered runs a schedule writes as 第N回, 第N週, Week N or Session N (lexicon ordinal-frame), in the first cell of
2
+ // table rows, at the start of list items or at the start of lines, and the places where such a run skips or repeats a
3
+ // number. Pure: the frames come from the lexicon, the leads from the caller.
4
+ import type { Lexicon } from "../plugin.ts";
5
+ import type { StructureIssue } from "./issues.ts";
6
+
7
+ /** One frame of the lexicon: the form with its number, and the form's opening followed by a figure. */
8
+ export type OrdinalFrame = { readonly group: string; readonly written: RegExp; readonly opened: RegExp | undefined };
9
+
10
+ /** A lead that carries a frame: its number (or the first and last of a joined 1-2) as written. */
11
+ export type FramedNumber = { readonly group: string; readonly ordinal: number; readonly last: number; readonly label: string };
12
+
13
+ /** A lead that opens a frame (第2, Week 3) without the form being readable (第2・第3回): it ends the group's run. */
14
+ export type UnreadableFrame = { readonly group: string; readonly unreadable: true };
15
+
16
+ /** Where a lead starts and what it reads as. */
17
+ export type Lead = { readonly offset: number; readonly read: readonly (FramedNumber | UnreadableFrame)[] };
18
+
19
+ const PLACEHOLDER = "{n}";
20
+ const FIGURES = "[0-90-9]{1,3}";
21
+ const JOINER = "[ \\t]?[-–—~〜~・,、][ \\t]?";
22
+ const FOLLOWER = "(?=$|[\\s\\u3000::|((.))\\]\\-–—、,*_])";
23
+ const SPACE = /[ \t\u3000]+/gu;
24
+ const FULLWIDTH_ZERO = 0xff10;
25
+
26
+ const escaped = (text: string): string => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&").replace(SPACE, "[ \\t\\u3000]*");
27
+
28
+ const frameOf = (pattern: string, group: string): OrdinalFrame | undefined => {
29
+ const at = pattern.indexOf(PLACEHOLDER);
30
+ if (at === -1) return undefined;
31
+ const opening = escaped(pattern.slice(0, at));
32
+ const closing = escaped(pattern.slice(at + PLACEHOLDER.length));
33
+ const written = new RegExp(`^${opening}(?<first>${FIGURES})(?:${JOINER}(?<last>${FIGURES}))?${closing}${FOLLOWER}`, "iu");
34
+ return { group, written, opened: opening === "" ? undefined : new RegExp(`^${opening}[0-90-9]`, "iu") };
35
+ };
36
+
37
+ /** The lexicon's frames. An entry without {n} or without a group is not a frame. */
38
+ export const ordinalFramesOf = (lexicon: Lexicon): OrdinalFrame[] =>
39
+ lexicon.flatMap((entry) => {
40
+ const frame = entry.group === undefined ? undefined : frameOf(entry.pattern, entry.group);
41
+ return frame === undefined ? [] : [frame];
42
+ });
43
+
44
+ const figureValue = (figures: string): number =>
45
+ Number([...figures].map((char) => (char >= "0" && char <= "9" ? String(char.charCodeAt(0) - FULLWIDTH_ZERO) : char)).join(""));
46
+
47
+ const readFrame = (lead: string, frame: OrdinalFrame): FramedNumber | UnreadableFrame | undefined => {
48
+ const found = frame.written.exec(lead);
49
+ if (found === null) return frame.opened?.test(lead) === true ? { group: frame.group, unreadable: true } : undefined;
50
+ const ordinal = figureValue(found.groups?.["first"] ?? "");
51
+ const last = found.groups?.["last"];
52
+ return { group: frame.group, ordinal, last: last === undefined ? ordinal : figureValue(last), label: found[0].trim() };
53
+ };
54
+
55
+ /** What the text at the start of a lead reads as, under each frame that matches it. */
56
+ export const framesAt = (lead: string, frames: readonly OrdinalFrame[]): Lead["read"] => {
57
+ const read = frames.flatMap((frame) => readFrame(lead, frame) ?? []);
58
+ const groups = new Set(read.filter((each) => !("unreadable" in each)).map((each) => each.group));
59
+ return read.filter((each) => !("unreadable" in each) || !groups.has(each.group));
60
+ };
61
+
62
+ /** One number of a run, and where its lead starts. */
63
+ export type RunNumber = FramedNumber & { readonly offset: number };
64
+
65
+ /**
66
+ * The leads of one block (one table, one list, one section's lines), cut into runs per group. An unreadable lead ends its
67
+ * group's run, and a number 1 starts a new one (a second term counting again).
68
+ */
69
+ export const ordinalRuns = (leads: readonly Lead[]): RunNumber[][] => {
70
+ const runs: RunNumber[][] = [];
71
+ const open = new Map<string, RunNumber[]>();
72
+ leads.forEach((lead) =>
73
+ lead.read.forEach((read) => {
74
+ if ("unreadable" in read) {
75
+ open.delete(read.group);
76
+ return;
77
+ }
78
+ const openRun = open.get(read.group) ?? [];
79
+ const run = read.ordinal === 1 && openRun.length > 0 ? [] : openRun;
80
+ if (run.length === 0) runs.push(run);
81
+ open.set(read.group, run);
82
+ run.push({ ...read, offset: lead.offset });
83
+ }),
84
+ );
85
+ return runs;
86
+ };
87
+
88
+ /** A run shorter than this is too short to tell a numbering from a mention. */
89
+ const SHORTEST_RUN = 3;
90
+
91
+ const followsOn = (current: FramedNumber, previous: FramedNumber): boolean => current.ordinal === previous.last + 1;
92
+
93
+ /**
94
+ * Each number in the run that does not follow the one before it: a skip or a repeat. A run
95
+ * where fewer than half the steps follow on lists chosen numbers (weeks 2, 5, 9), not a sequence, and is not read; so
96
+ * is a run shorter than three, and a run writing one number throughout.
97
+ */
98
+ export const ordinalRunBreaks = (run: readonly RunNumber[]): StructureIssue[] => {
99
+ if (run.length < SHORTEST_RUN || new Set(run.map((item) => item.ordinal)).size < 2) return [];
100
+ const steps = run.slice(1).map((item, index) => ({ item, previous: run[index] ?? item }));
101
+ const breaks = steps.filter(({ item, previous }) => !followsOn(item, previous));
102
+ if (breaks.length * 2 > steps.length) return [];
103
+ return breaks.map(({ item, previous }) => ({
104
+ offset: item.offset,
105
+ values: { previous: previous.label, label: item.label, expected: previous.last + 1, found: item.ordinal },
106
+ }));
107
+ };
@@ -1,5 +1,6 @@
1
1
  // A breakdown written in one sentence (「構成比は、Aが50%、Bが30%、Cが20%」, "By product, A made up 50% of sales, B 30% and
2
2
  // C 20%") whose shares do not add up to 100%. The table and list form is structure/percent-sum.ts; the words are the same.
3
+ import { escapeRegExp } from "../orthography.ts";
3
4
  import type { Span } from "../plugin.ts";
4
5
  import type { StructureIssue } from "./issues.ts";
5
6
  import type { Amount } from "./total.ts";
@@ -35,20 +36,62 @@ const toleranceOf = (source: string, shares: readonly Amount[]): number =>
35
36
 
36
37
  const isBroken = (sum: number, tolerance: number): boolean => Math.abs(sum - WHOLE) > tolerance && Math.abs(sum - WHOLE) <= BAND;
37
38
 
39
+ /** How far before a percentage the word for the rest may stand: 「その他が 」, "and other ". */
40
+ const REST_REACH = 16;
41
+ /** What may stand between the word for the rest and its percentage: a space, a colon, a particle, an opening parenthesis. */
42
+ const REST_GAP = /^[\s::、,がはで((]*$/u;
43
+ const LATIN_START = /^[A-Za-z]/u;
44
+ const LETTER_BEFORE = /\p{L}$/u;
45
+ const LETTER = /\p{L}/u;
46
+
47
+ /** A word in a text; a Latin one as a whole word ("other", not "another"; "up", not "upkeep"). */
48
+ const hasWord = (text: string, word: string): boolean => {
49
+ const lowered = text.toLowerCase();
50
+ const target = word.toLowerCase();
51
+ if (!LATIN_START.test(word)) return lowered.includes(target);
52
+ return [...lowered.matchAll(new RegExp(escapeRegExp(target), "gu"))].some(
53
+ (match) => !LETTER.test(lowered[match.index - 1] ?? "") && !LETTER.test(lowered[match.index + target.length] ?? ""),
54
+ );
55
+ };
56
+
57
+ /** How far from a percentage a word for which way it moved may stand: "grew 45%", 「8%増加」. */
58
+ const CHANGE_REACH = 12;
59
+
60
+ const movesNear = (source: string, sentence: Span, share: Amount, changes: readonly string[]): boolean => {
61
+ const near = source.slice(Math.max(sentence.start, share.offset - CHANGE_REACH), Math.min(sentence.end, share.end + CHANGE_REACH));
62
+ return changes.some((word) => hasWord(near, word));
63
+ };
64
+
65
+ /**
66
+ * The last share is the rest of the whole (その他が 5%, other 5%): only the parts of one whole have a rest, and it is listed
67
+ * last. Percentages next to a word for which way they moved (grew 45%, 8%増加) are changes, whose rest is no part of a whole.
68
+ */
69
+ const namesRest = (source: string, sentence: Span, shares: readonly Amount[], words: ShareWords): boolean => {
70
+ const last = shares.at(-1);
71
+ if (last === undefined || shares.some((share) => movesNear(source, sentence, share, words.changes ?? []))) return false;
72
+ const before = source.slice(Math.max(sentence.start, last.offset - REST_REACH), last.offset).toLowerCase();
73
+ return (words.rests ?? []).some((word) => {
74
+ const at = before.lastIndexOf(word.toLowerCase());
75
+ if (at < 0 || !REST_GAP.test(before.slice(at + word.length))) return false;
76
+ return !(LATIN_START.test(word) && LETTER_BEFORE.test(before.slice(0, at)));
77
+ });
78
+ };
79
+
38
80
  const issueIn = (source: string, sentence: Span, percents: readonly Amount[], words: ShareWords): StructureIssue[] => {
39
81
  const text = source.slice(sentence.start, sentence.end);
40
- if (!includesAny(text, words.labels) || includesAny(text, words.exceptions)) return [];
82
+ if (includesAny(text, words.exceptions)) return [];
41
83
  const shares = percents.filter((amount) => amount.offset >= sentence.start && amount.end <= sentence.end);
42
84
  if (shares.length < MIN_PARTS || shares.some((share) => isSigned(source, share))) return [];
85
+ if (!includesAny(text, words.labels) && !namesRest(source, sentence, shares, words)) return [];
43
86
  const sum = shares.reduce((total, share) => total + share.value, 0);
44
87
  const decimals = Math.max(0, ...shares.map((share) => decimalsOf(source, share)));
45
88
  if (!isBroken(sum, toleranceOf(source, shares))) return [];
46
89
  return [{ offset: shares[0]?.offset ?? sentence.start, values: { sum: `${sum.toFixed(decimals)}${shares[0]?.unit ?? ""}` } }];
47
90
  };
48
91
 
49
- /** Each sentence that names a share word and three or more unsigned percentages whose sum misses 100% by more than rounding, and by no more than BAND. */
92
+ /** Each sentence that names a share word (or names one share as the rest) and three or more unsigned percentages whose sum misses 100% by more than rounding, and by no more than BAND. */
50
93
  export const proseShareMismatches = (source: string, sentences: readonly Span[], amounts: readonly Amount[], words: ShareWords): StructureIssue[] => {
51
- if (words.labels.length === 0) return [];
94
+ if (words.labels.length === 0 && (words.rests ?? []).length === 0) return [];
52
95
  const percents = amounts.filter((amount) => words.units.includes(amount.unit));
53
96
  return sentences.flatMap((sentence) => issueIn(source, sentence, percents, words));
54
97
  };
@@ -3,6 +3,7 @@ import { runsOf, TABLE_ROW, TABLE_RULE, type Line } from "./runs.ts";
3
3
  import { columnOf, isTotalLabel, type Amount } from "./total.ts";
4
4
  import { CELL_SEPARATOR } from "./bare-numbers.ts";
5
5
  import { joined, lineAbove, linesAbove } from "../text-above.ts";
6
+ import { isShareColumn, mentionsAny } from "./share-column.ts";
6
7
 
7
8
  /**
8
9
  * 一つの全体を分けた割合(構成比、内訳、breakdown)の和が 100% にならない。箇条書きの続いた項目か、表の続いた行の百分率を足す。
@@ -11,8 +12,16 @@ import { joined, lineAbove, linesAbove } from "../text-above.ts";
11
12
  */
12
13
  export type ShareWords = {
13
14
  readonly labels: readonly string[];
15
+ /** 表の列の見出しの升がその語だけのとき、全体を分けた割合の列と読む語(割合、Weight)。 */
16
+ readonly columnLabels?: readonly string[];
17
+ /** 行ごとの率を名指す語(前年比、達成率、growth)。表の上の文にあれば、columnLabels の列は足さない。 */
18
+ readonly rates?: readonly string[];
14
19
  /** 足しても 100% にならない集計(複数回答)。 */
15
20
  readonly exceptions: readonly string[];
21
+ /** 全体の残りを名指す語(その他、other)。一つの文の百分率のすぐ前にあれば、その文は内訳。 */
22
+ readonly rests?: readonly string[];
23
+ /** 値の動いた向きの語(伸び、grew)。その文の百分率は変化で、「その他」があっても内訳ではない。 */
24
+ readonly changes?: readonly string[];
16
25
  readonly units: readonly string[];
17
26
  readonly totalLabels: readonly string[];
18
27
  };
@@ -97,12 +106,13 @@ const tolerance = (shares: readonly Share[]): number => Math.max(1, shares.lengt
97
106
  /** 和は、項目のいちばん細かい桁で、最初の項目の単位を付けて見せる。 */
98
107
  const shownSum = (shares: readonly Share[]): string => `${sumOf(shares).toFixed(decimalsOf(shares))}${shares[0]?.unit ?? ""}`;
99
108
 
100
- type Named = { readonly header: readonly string[]; readonly above: string };
109
+ type Named = { readonly header: readonly string[]; readonly above: string; readonly rows: string };
101
110
 
102
111
  /** 列が全体を分けた割合と名指されているか。表は列の見出しか、百分率の列が一つだけの表の上の文。箇条書きは上の文。 */
103
112
  const namesShares = (named: Named, column: number, percentColumns: number, words: ShareWords): boolean => {
104
113
  const header = named.header[column] ?? "";
105
114
  if (named.header.length > 0 && includesAny(header, words.labels)) return true;
115
+ if (isShareColumn(header, words.columnLabels ?? []) && !mentionsAny(`${named.above} ${named.rows}`, words.rates ?? [])) return true;
106
116
  return (named.header.length === 0 || percentColumns === 1) && includesAny(named.above, words.labels);
107
117
  };
108
118
 
@@ -110,7 +120,11 @@ const namesShares = (named: Named, column: number, percentColumns: number, words
110
120
  const isBreakdown = (source: string, run: readonly Line[], totalLabels: readonly string[]): boolean =>
111
121
  run.length >= MIN_PARTS && !run.some((line) => isTotalLabel(source.slice(line.start, line.end), totalLabels));
112
122
 
113
- const namingOf = (source: string, run: readonly Line[], first: Line): Named => ({ header: headerCells(source, first), above: textAbove(source, run) });
123
+ const namingOf = (source: string, run: readonly Line[], first: Line): Named => ({
124
+ header: headerCells(source, first),
125
+ above: textAbove(source, run),
126
+ rows: run.map((line) => source.slice(line.start, line.end)).join("\n"),
127
+ });
114
128
 
115
129
  const mismatchesIn = (source: string, run: readonly Line[], percents: readonly Amount[], words: ShareWords): StructureIssue[] => {
116
130
  const first = run[0];
@@ -0,0 +1,69 @@
1
+ // The releases a document lists: a run of version headings (## 3.2.0 - 2026-09-14), each with its section, or a run of
2
+ // list items that start with a version (- 3.2.0 (2026-09-14): ...). Pure: reads the source, its headings and code fences.
3
+ import type { Span } from "../plugin.ts";
4
+ import type { Release } from "./install-pin.ts";
5
+ import { runsOf, type Line } from "./runs.ts";
6
+ import { isVersionHistory, leadingVersion } from "./version-order.ts";
7
+
8
+ export type Heading = Span & { readonly depth: number; readonly text: string };
9
+
10
+ const BARE = /\d[\w.-]*/u;
11
+
12
+ /** The version as compared: 3.2.0 from [v3.2.0]. */
13
+ const bareVersion = (label: string): string => BARE.exec(label)?.[0] ?? label;
14
+
15
+ type Labelled = Release & { readonly label: string };
16
+
17
+ /** Kept only when its versions read as a history (all versions, newest or oldest first), not as section numbers. */
18
+ const asHistory = (run: readonly Labelled[]): Release[] =>
19
+ isVersionHistory(run.map((release) => release.label)) ? run.map(({ version, start, end }) => ({ version, start, end })) : [];
20
+
21
+ /** A heading's section: up to the next heading of its depth or shallower. */
22
+ const sectionEnd = (headings: readonly Heading[], index: number, length: number): number => {
23
+ const depth = headings[index]?.depth ?? 0;
24
+ return headings.slice(index + 1).find((later) => later.depth <= depth)?.start ?? length;
25
+ };
26
+
27
+ /**
28
+ * Version headings one after another at one depth. A deeper heading (### Added) stays inside the run; any other heading
29
+ * at its depth or shallower (## Install) ends it, so versioned headings spread over a manual are no release list.
30
+ */
31
+ const headingReleases = (headings: readonly Heading[], length: number): Release[] => {
32
+ const runs: Labelled[][] = [];
33
+ const open: { depth: number; run: Labelled[] } = { depth: 0, run: [] };
34
+ headings.forEach((heading, index) => {
35
+ const label = leadingVersion(heading.text);
36
+ const continues = label !== undefined && heading.depth === open.depth;
37
+ if (!continues && (label !== undefined || heading.depth <= open.depth)) {
38
+ open.run = [];
39
+ open.depth = label === undefined ? 0 : heading.depth;
40
+ runs.push(open.run);
41
+ }
42
+ if (label !== undefined) open.run.push({ label, version: bareVersion(label), start: heading.start, end: sectionEnd(headings, index, length) });
43
+ });
44
+ return runs.flatMap(asHistory);
45
+ };
46
+
47
+ const ITEM_MARKER = /^[ \t]*(?:[-*+]|\d{1,3}[.)])[ \t]*/u;
48
+
49
+ const itemReleases = (source: string, run: readonly Line[]): Release[] =>
50
+ asHistory(
51
+ run.flatMap((line) => {
52
+ const text = source.slice(line.start, line.end);
53
+ const marker = ITEM_MARKER.exec(text)?.[0];
54
+ const label = marker === undefined ? undefined : leadingVersion(text.slice(marker.length));
55
+ return label === undefined ? [] : [{ label, version: bareVersion(label), start: line.start, end: line.end }];
56
+ }),
57
+ );
58
+
59
+ /** Every release the document lists, outside code fences (an example changelog in a block is not the document's). */
60
+ export const releasesOf = (source: string, headings: readonly Heading[], fences: readonly Span[]): Release[] => {
61
+ const inFence = (line: Line): boolean => fences.some((fence) => line.start >= fence.start && line.start < fence.end);
62
+ const items = runsOf(source).flatMap((run) =>
63
+ itemReleases(
64
+ source,
65
+ run.filter((line) => line.kind === "list" && !inFence(line)),
66
+ ),
67
+ );
68
+ return [...headingReleases(headings, source.length), ...items].toSorted((left, right) => left.start - right.start);
69
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 表の列の見出しが、それだけで全体を分けた割合の列と名指すか(割合、配点、Weight)。これらの語は文の中では行ごとの率にも使うので、
3
+ * 見出しの升がその語だけ(単位の括弧と % は除く)のときに限る。
4
+ */
5
+
6
+ /** 見出しの升から外す飾り: 括弧に入れた単位((%)、(%)、[%])、% の記号、強調の印。単位でない括弧((達成率))は残す。 */
7
+ const DECORATION = /[(([[](?:\s|[%%]|percent|pct)*[))]\]]|[%%*_]/giu;
8
+ const LATIN = /^\p{ASCII}+$/u;
9
+ const WORD_BREAK = /[^\p{L}\p{N}]+/u;
10
+
11
+ const bareCell = (cell: string): string => cell.replace(DECORATION, "").trim().toLowerCase();
12
+
13
+ export const isShareColumn = (cell: string, columnLabels: readonly string[]): boolean => {
14
+ const bare = bareCell(cell);
15
+ return bare.length > 0 && columnLabels.some((label) => label.toLowerCase() === bare);
16
+ };
17
+
18
+ /** 英字の語は語の切れ目で探す(rate を separate に当てない)。日本語の語は文字列の中で探す。 */
19
+ const mentions = (text: string, word: string): boolean => {
20
+ const lowered = word.toLowerCase();
21
+ if (!LATIN.test(lowered)) return text.includes(word);
22
+ return ` ${text.toLowerCase().split(WORD_BREAK).join(" ")} `.includes(` ${lowered} `);
23
+ };
24
+
25
+ export const mentionsAny = (text: string, words: readonly string[]): boolean => words.some((word) => mentions(text, word));
@@ -0,0 +1,161 @@
1
+ import { escapeRegExp } from "../orthography.ts";
2
+ import { withoutTrailingWeekday } from "./date-range.ts";
3
+
4
+ /**
5
+ * 文書が書いた期間(旅行期間:10月12日〜10月15日、Trip period: Oct 12–15)。期間の語(period-label)で始まる一行だけを読む。
6
+ * 日付は年月日(2026-10-12)か月日(10-12)。片方にだけ年があれば、もう片方にも同じ年を補う。
7
+ * 言語の知識(期間の語、範囲の記号、月の名、曜日の名)は語彙表から受け取る。
8
+ */
9
+ export type DateMention = { readonly offset: number; readonly end: number; readonly value: string };
10
+
11
+ export type PeriodWords = {
12
+ readonly labels: readonly string[];
13
+ /** 二つの日付の間に置いて期間を作る記号と語(〜、–、から、to)。 */
14
+ readonly connectors: readonly string[];
15
+ /** 月の名。頭の 12 個が 1 月から 12 月、略した名はその頭の字で月を決める。 */
16
+ readonly months: readonly string[];
17
+ readonly weekdays: readonly string[];
18
+ };
19
+
20
+ export type Period = { readonly start: string; readonly end: string; readonly written: string };
21
+
22
+ /**
23
+ * 行の頭の印(見出し、箇条書き、引用)と、語を囲む太字や括弧の開き。表の行は読まない。
24
+ * 「| Conference | May 3–5 |」は催しを並べた表の一行で、文書の期間ではない。
25
+ */
26
+ const LINE_MARKS = /^[ \t]*(?:(?:#{1,6}|[-*+>]|\d{1,3}[.)])[ \t]*)*/u;
27
+ const LABEL_OPEN = /^(?:\*\*|__|【|\[)?/u;
28
+ const LABEL_END = /^(?:\*\*|__|】|\])?(?:[ \t]*[::][ \t]*|[ \t\u3000]+)/u;
29
+
30
+ const leadOf = (line: string): number => {
31
+ const marks = LINE_MARKS.exec(line)?.[0].length ?? 0;
32
+ return marks + (LABEL_OPEN.exec(line.slice(marks))?.[0].length ?? 0);
33
+ };
34
+
35
+ /** 期間の語に続く、期間を書いた部分の行の中の位置。期間の語で始まらない行は undefined。 */
36
+ export const afterLabel = (line: string, labels: readonly string[]): number | undefined => {
37
+ const lead = leadOf(line);
38
+ const rest = line.slice(lead);
39
+ const label = labels.find((word) => rest.toLowerCase().startsWith(word.toLowerCase()) && LABEL_END.test(rest.slice(word.length)));
40
+ if (label === undefined) return undefined;
41
+ return lead + label.length + (LABEL_END.exec(rest.slice(label.length))?.[0].length ?? 0);
42
+ };
43
+
44
+ /** 日付に添えた曜日((水))と時刻(10:00)。期間のつなぎ目ではない。 */
45
+ const ASIDES = /[((][^(())\n]{1,6}[))]|\d{1,2}[::]\d{2}/gu;
46
+
47
+ const isJoint = (between: string, words: PeriodWords): boolean => {
48
+ const bare = between
49
+ .replace(ASIDES, "")
50
+ .replace(/^[\s,]+/u, "")
51
+ .trim()
52
+ .toLowerCase();
53
+ const joint = withoutTrailingWeekday(bare, words.weekdays).trim();
54
+ return words.connectors.some((connector) => connector.toLowerCase() === joint);
55
+ };
56
+
57
+ const connectorPattern = (words: PeriodWords): string =>
58
+ words.connectors
59
+ .toSorted((left, right) => right.length - left.length)
60
+ .map(escapeRegExp)
61
+ .join("|");
62
+
63
+ const hasYear = (value: string): boolean => /^\d{4}-/u.test(value);
64
+ const DAY_VALUE = /^(?:\d{4}-)?\d{2}-\d{2}$/u;
65
+
66
+ const withDay = (value: string, day: string): string => `${value.slice(0, -2)}${day.padStart(2, "0")}`;
67
+
68
+ const shiftYear = (value: string, by: number): string => `${String(Number(value.slice(0, 4)) + by)}${value.slice(4)}`;
69
+
70
+ /** 年を片方にだけ書いた期間に、もう片方の年を補う(December 28 – January 4, 2027 は 2026 年の 12 月から)。 */
71
+ const withYears = (start: string, end: string): string[] => {
72
+ if (hasYear(start) === hasYear(end)) return [start, end];
73
+ if (hasYear(start)) {
74
+ const filled = `${start.slice(0, 4)}-${end}`;
75
+ return [start, filled < start ? shiftYear(filled, 1) : filled];
76
+ }
77
+ const filled = `${end.slice(0, 4)}-${start}`;
78
+ return [filled > end ? shiftYear(filled, -1) : filled, end];
79
+ };
80
+
81
+ type Dates = Omit<Period, "written">;
82
+
83
+ const periodOf = (start: string, end: string): Dates | undefined => {
84
+ if (!DAY_VALUE.test(start) || !DAY_VALUE.test(end)) return undefined;
85
+ const [from = start, to = end] = withYears(start, end);
86
+ return hasYear(from) && to < from ? undefined : { start: from, end: to };
87
+ };
88
+
89
+ /** 時刻の範囲の終わり(May 3, 3–5pm)。日の範囲ではない。 */
90
+ const CLOCK = "\\s*[AaPp]\\.?[Mm]\\b";
91
+
92
+ /** 一つ書いた日付の後ろに日だけを書いた終わり(10月12日〜15日、Oct 12–15)。 */
93
+ const dayAfter = (text: string, date: DateMention, lineStart: number, words: PeriodWords): Dates | undefined => {
94
+ const tail = text.slice(date.end - lineStart).replace(ASIDES, "");
95
+ const found = new RegExp(`^\\s*(?:${connectorPattern(words)})\\s*(\\d{1,2})(?:st|nd|rd|th|日)?(?![\\d/:月.]|\\s*\\p{Lu}|${CLOCK})`, "u").exec(tail);
96
+ const day = found?.[1];
97
+ return day === undefined ? undefined : periodOf(date.value, withDay(date.value, day));
98
+ };
99
+
100
+ /** 一つ書いた日付の前に日だけを書いた始まり(3–5 May 2026)。前に月の名がある日(May 3–June 5)は、終わりの月の日ではない。 */
101
+ const dayBefore = (text: string, date: DateMention, lineStart: number, words: PeriodWords): Dates | undefined => {
102
+ const head = text.slice(0, date.offset - lineStart);
103
+ const found = new RegExp(`(?<![\\d/.]|\\p{L}\\.?\\s)(\\d{1,2})\\s*(?:${connectorPattern(words)})\\s*$`, "u").exec(head);
104
+ const day = found?.[1];
105
+ return day === undefined ? undefined : periodOf(withDay(date.value, day), date.value);
106
+ };
107
+
108
+ const MONTHS_IN_YEAR = 12;
109
+ const ABBREVIATION = 3;
110
+
111
+ const monthNumber = (name: string, months: readonly string[]): number => {
112
+ const head = name.slice(0, ABBREVIATION).toLowerCase();
113
+ return months.slice(0, MONTHS_IN_YEAR).findIndex((month) => month.slice(0, ABBREVIATION).toLowerCase() === head) + 1;
114
+ };
115
+
116
+ const monthDay = (name: string, day: string, months: readonly string[]): string | undefined => {
117
+ const month = monthNumber(name, months);
118
+ return month === 0 ? undefined : `${String(month).padStart(2, "0")}-${day.padStart(2, "0")}`;
119
+ };
120
+
121
+ const DAY = "(\\d{1,2})(?:st|nd|rd|th)?";
122
+
123
+ /**
124
+ * 日付として読まれなかった、月の名と日の範囲(May 3–5, 2026、Dec 28–Jan 4, 2027)。英語の日付は、年を終わりにだけ書くと始まりを日付にしない。
125
+ * 年は終わりの日付のもので、始まりには年をまたいで補う。
126
+ */
127
+ const monthRange = (text: string, words: PeriodWords): Dates | undefined => {
128
+ const names = words.months.map(escapeRegExp).join("|");
129
+ if (names === "") return undefined;
130
+ const month = `(${names})\\.?\\s+`;
131
+ const pattern = `(?<!\\p{L})${month}${DAY}\\s*(?:${connectorPattern(words)})\\s*(?:${month})?${DAY}(?![\\d:]|${CLOCK})(?:,?\\s+(\\d{4}))?`;
132
+ const found = new RegExp(pattern, "u").exec(text);
133
+ if (found === null) return undefined;
134
+ const [, startMonth = "", first = "", endMonth, last = "", year] = found;
135
+ const start = monthDay(startMonth, first, words.months);
136
+ const end = monthDay(endMonth ?? startMonth, last, words.months);
137
+ if (start === undefined || end === undefined) return undefined;
138
+ return periodOf(start, year === undefined ? end : `${year}-${end}`);
139
+ };
140
+
141
+ const fromTwo = (text: string, lineStart: number, first: DateMention, second: DateMention, words: PeriodWords): Dates | undefined =>
142
+ isJoint(text.slice(first.end - lineStart, second.offset - lineStart), words) ? periodOf(first.value, second.value) : undefined;
143
+
144
+ const datesOf = (line: string, lineStart: number, from: number, dates: readonly DateMention[], words: PeriodWords): Dates | undefined => {
145
+ const inside = dates.filter((date) => date.offset >= lineStart + from && date.end <= lineStart + line.length);
146
+ const [first, second] = inside;
147
+ if (first !== undefined && second !== undefined) return fromTwo(line, lineStart, first, second, words);
148
+ if (first !== undefined) return dayAfter(line, first, lineStart, words) ?? dayBefore(line, first, lineStart, words) ?? monthRange(line.slice(from), words);
149
+ return monthRange(line.slice(from), words);
150
+ };
151
+
152
+ /**
153
+ * 期間の語で始まる一行の期間。行の中の日付が二つで間が範囲の記号なら、その二つ。一つなら、その前か後ろに日だけを書いた片方を読む。
154
+ * 日付の無い行は、月の名と日の範囲を読む。読めなければ undefined。
155
+ */
156
+ export const statedPeriod = (line: string, lineStart: number, dates: readonly DateMention[], words: PeriodWords): Period | undefined => {
157
+ const from = afterLabel(line, words.labels);
158
+ if (from === undefined) return undefined;
159
+ const found = datesOf(line, lineStart, from, dates, words);
160
+ return found === undefined ? undefined : { ...found, written: line.slice(from).trim() };
161
+ };
@@ -0,0 +1,35 @@
1
+ import type { Token } from "../plugin.ts";
2
+
3
+ // Whether a joining word ("and") starts a clause about another subject: "Revenue was $1,000 in 2025 and costs were $1,500
4
+ // in 2026" joins two subjects, "… in 2025 and $1,500 in 2026" or "… and revenue was $1,500" one. Two words for one thing
5
+ // ("sales" and "revenue") read as two subjects, so the pair is left alone rather than read wrongly. Pure: reads the tagger's
6
+ // parts of speech and lemmas.
7
+
8
+ const NOUN: ReadonlySet<string> = new Set(["NOUN", "PROPN"]);
9
+ /** Words that may stand before the noun that starts the clause ("and the costs", "and our operating costs"). */
10
+ const BEFORE_NOUN: ReadonlySet<string> = new Set(["DET", "ADJ", "PRON"]);
11
+
12
+ const wordOf = (token: Token): string => (token.lemma ?? token.surface).toLowerCase();
13
+
14
+ /** The last noun of the run of nouns at the start of tokens, past determiners and adjectives ("the operating costs" → cost). */
15
+ const leadingNoun = (tokens: readonly Token[]): Token | undefined => {
16
+ const start = tokens.findIndex((token) => !BEFORE_NOUN.has(token.pos));
17
+ if (start < 0) return undefined;
18
+ const end = tokens.slice(start).findIndex((token) => !NOUN.has(token.pos));
19
+ const nouns = tokens.slice(start, end < 0 ? tokens.length : start + end);
20
+ return nouns.at(-1);
21
+ };
22
+
23
+ /**
24
+ * The joining word at index is followed by a noun the sentence has not used before it: "and costs were", "and costs $1,500"
25
+ * after "Revenue was $1,000", where "and revenue was" after "ACME's revenue was $1,000" names the same thing again. A
26
+ * sentence with no noun before the joining word gives nothing to compare with.
27
+ */
28
+ export const startsOtherSubject = (tokens: readonly Token[], index: number): boolean => {
29
+ const next = leadingNoun(tokens.slice(index + 1));
30
+ const before = tokens
31
+ .slice(0, index)
32
+ .filter((token) => NOUN.has(token.pos))
33
+ .map(wordOf);
34
+ return next !== undefined && before.length > 0 && !before.includes(wordOf(next));
35
+ };
@@ -0,0 +1,114 @@
1
+ import type { StructureIssue } from "./issues.ts";
2
+ import { runsOf, type Line } from "./runs.ts";
3
+ import { columnOf, isTotalLabel, shownTotal, type Amount } from "./total.ts";
4
+
5
+ /**
6
+ * 税の行と、その上の金額に率を掛けた額。表か箇条書きの並びで、税の語(消費税・Sales tax)で始まり率(10%)を書いた行の
7
+ * 金額を、上の最後の合計の行(小計)の金額に率を掛けた額と比べる。合計の行が無ければ、上の項目の和に掛ける。
8
+ * 端数は切り捨て・四捨五入・切り上げのどれでもよく、円の位でも銭(セント)の位でもよい。
9
+ * 内税(「うち消費税」)の行と、率の違う税の行が並ぶ並び(軽減税率)は読まない。Pure.
10
+ */
11
+ export type TaxWords = {
12
+ /** 税の行の頭の語(消費税、Sales tax)。 */
13
+ readonly labels: readonly string[];
14
+ /** 合計の行の頭の語(小計、Subtotal)。 */
15
+ readonly totals: readonly string[];
16
+ /** 税の行が内税だと分かる語(うち、included)。 */
17
+ readonly included: readonly string[];
18
+ };
19
+
20
+ const RATE = /(\d{1,2}(?:\.\d{1,2})?)[ \t]?[%%]/u;
21
+ const PERCENT = new Set(["%", "%"]);
22
+ /** A sign or an opening bracket right before an amount (-$200, ▲500, (1,200)): the amount may be negative. */
23
+ const SIGNED = /[-−▲△((][ \t]?(?:[$€£¥¥][ \t]?)?$/u;
24
+ const CENTS = 100;
25
+ const MAX_RATE = 100;
26
+
27
+ type Row = { readonly line: Line; readonly text: string; readonly amounts: readonly Amount[] };
28
+
29
+ const rowsOf = (source: string, run: readonly Line[], amounts: readonly Amount[]): Row[] =>
30
+ run.map((line) => ({
31
+ line,
32
+ text: source.slice(line.start, line.end),
33
+ amounts: amounts.filter((amount) => amount.offset >= line.start && amount.offset <= line.end && !PERCENT.has(amount.unit)),
34
+ }));
35
+
36
+ const rateOf = (text: string): number | undefined => {
37
+ const rate = Number(RATE.exec(text)?.[1]);
38
+ return Number.isFinite(rate) && rate > 0 && rate < MAX_RATE ? rate : undefined;
39
+ };
40
+
41
+ const isTaxRow = (row: Row, words: TaxWords): boolean =>
42
+ isTotalLabel(row.text, words.labels) && !words.included.some((word) => row.text.toLowerCase().includes(word.toLowerCase()));
43
+
44
+ /** The list marker at the start of a line (- $500) is not a sign. */
45
+ const isSigned = (source: string, row: Row, amount: Amount): boolean => {
46
+ const before = source.slice(row.line.start, amount.offset);
47
+ const sign = SIGNED.exec(before);
48
+ return sign !== null && before.slice(0, sign.index).trim().length > 0;
49
+ };
50
+
51
+ /**
52
+ * The one amount of the row in the column and unit of the tax amount, undefined when there is none, more than one, or
53
+ * one that may be negative (a discount is not added as written).
54
+ */
55
+ const amountAt = (source: string, row: Row, column: number, unit: string): Amount | undefined => {
56
+ const matching = row.amounts.filter((amount) => amount.unit === unit && columnOf(source, row.line, amount.offset) === column);
57
+ const [only] = matching;
58
+ return matching.length === 1 && only !== undefined && !isSigned(source, row, only) ? only : undefined;
59
+ };
60
+
61
+ /**
62
+ * The base the tax is on: the last total row above, or the sum of the item rows above when there is no total row. A row
63
+ * with an amount between the total and the tax (a discount, shipping) may or may not be taxed, so there is no base.
64
+ */
65
+ const baseOf = (source: string, above: readonly Row[], tax: Amount, column: number, words: TaxWords): Amount | undefined => {
66
+ const lastTotalIndex = above.findLastIndex((row) => isTotalLabel(row.text, words.totals));
67
+ const lastTotal = above[lastTotalIndex];
68
+ if (lastTotal !== undefined) {
69
+ const between = above.slice(lastTotalIndex + 1);
70
+ return between.some((row) => row.amounts.length > 0) ? undefined : amountAt(source, lastTotal, column, tax.unit);
71
+ }
72
+ const items = above.map((row) => amountAt(source, row, column, tax.unit));
73
+ if (items.length === 0 || items.some((item) => item === undefined)) return undefined;
74
+ const values = items.flatMap((item) => (item === undefined ? [] : [item.value]));
75
+ return { offset: tax.offset, end: tax.end, unit: tax.unit, value: values.reduce((sum, value) => sum + value, 0) };
76
+ };
77
+
78
+ /**
79
+ * Whether a written amount is an exact one rounded down, to nearest or up, to the cent or (when toUnit) to the unit. Both
80
+ * in cents. An amount written with cents ($59.00) is rounded to the cent only.
81
+ */
82
+ export const roundedMatches = (writtenCents: number, exactCents: number, toUnits = true): boolean => {
83
+ const toCent = [Math.floor(exactCents), Math.round(exactCents), Math.ceil(exactCents)];
84
+ const toUnit = toUnits ? [Math.floor, Math.round, Math.ceil].map((round) => round(exactCents / CENTS) * CENTS) : [];
85
+ return [...toCent, ...toUnit].some((candidate) => Math.abs(candidate - writtenCents) < 1);
86
+ };
87
+
88
+ /** Whether the written tax is base × rate, rounded down, to nearest or up, to the unit or to the cent. */
89
+ // base × rate% in cents: base × 100 × rate / 100.
90
+ export const taxMatches = (writtenCents: number, base: number, rate: number): boolean => roundedMatches(writtenCents, base * rate);
91
+
92
+ const issueOf = (source: string, rows: readonly Row[], index: number, rate: number, words: TaxWords): StructureIssue[] => {
93
+ const row = rows[index];
94
+ const tax = row?.amounts.length === 1 ? row.amounts[0] : undefined;
95
+ if (row === undefined || tax === undefined || isSigned(source, row, tax)) return [];
96
+ const column = columnOf(source, row.line, tax.offset);
97
+ const base = baseOf(source, rows.slice(0, index), tax, column, words);
98
+ if (base === undefined || taxMatches(Math.round(tax.value * CENTS), base.value, rate)) return [];
99
+ const expectedCents = Math.round(base.value * rate);
100
+ const shown = shownTotal(source, tax, expectedCents);
101
+ return [{ offset: tax.offset, values: { written: shown.written ?? "", expected: shown.sum ?? "", rate: `${String(rate)}%` } }];
102
+ };
103
+
104
+ const runIssues = (source: string, rows: readonly Row[], words: TaxWords): StructureIssue[] => {
105
+ const taxRows = rows.flatMap((row, index) => {
106
+ const rate = isTaxRow(row, words) ? rateOf(row.text) : undefined;
107
+ return rate === undefined ? [] : [{ index, rate }];
108
+ });
109
+ if (new Set(taxRows.map((row) => row.rate)).size > 1) return [];
110
+ return taxRows.flatMap(({ index, rate }) => issueOf(source, rows, index, rate, words));
111
+ };
112
+
113
+ export const taxMismatches = (source: string, amounts: readonly Amount[], words: TaxWords): StructureIssue[] =>
114
+ words.labels.length === 0 ? [] : runsOf(source).flatMap((run) => runIssues(source, rowsOf(source, run, amounts), words));