chaffjs 0.33.0 → 0.35.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 (802) hide show
  1. package/dist/api.d.ts +7 -1
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js.map +1 -1
  4. package/dist/capitals-passage.d.ts +3 -0
  5. package/dist/capitals-passage.d.ts.map +1 -0
  6. package/dist/capitals-passage.js +26 -0
  7. package/dist/capitals-passage.js.map +1 -0
  8. package/dist/cli-text.d.ts.map +1 -1
  9. package/dist/cli-text.js +4 -2
  10. package/dist/cli-text.js.map +1 -1
  11. package/dist/coined-hyphen-name.d.ts +13 -0
  12. package/dist/coined-hyphen-name.d.ts.map +1 -0
  13. package/dist/coined-hyphen-name.js +21 -0
  14. package/dist/coined-hyphen-name.js.map +1 -0
  15. package/dist/commands/grade.d.ts.map +1 -1
  16. package/dist/commands/grade.js +66 -21
  17. package/dist/commands/grade.js.map +1 -1
  18. package/dist/company-kana-spelling.d.ts +6 -1
  19. package/dist/company-kana-spelling.d.ts.map +1 -1
  20. package/dist/company-kana-spelling.js +19 -2
  21. package/dist/company-kana-spelling.js.map +1 -1
  22. package/dist/company-name-ending.d.ts +7 -0
  23. package/dist/company-name-ending.d.ts.map +1 -0
  24. package/dist/company-name-ending.js +44 -0
  25. package/dist/company-name-ending.js.map +1 -0
  26. package/dist/company-names.d.ts +17 -4
  27. package/dist/company-names.d.ts.map +1 -1
  28. package/dist/company-names.js +49 -17
  29. package/dist/company-names.js.map +1 -1
  30. package/dist/custom/no-rewrite.d.ts +3 -0
  31. package/dist/custom/no-rewrite.d.ts.map +1 -0
  32. package/dist/custom/no-rewrite.js +3 -0
  33. package/dist/custom/no-rewrite.js.map +1 -0
  34. package/dist/custom/parse.d.ts.map +1 -1
  35. package/dist/custom/parse.js +14 -2
  36. package/dist/custom/parse.js.map +1 -1
  37. package/dist/detectors/acronym-context.d.ts +1 -1
  38. package/dist/detectors/acronym-context.d.ts.map +1 -1
  39. package/dist/detectors/acronym-context.js +4 -4
  40. package/dist/detectors/acronym-context.js.map +1 -1
  41. package/dist/detectors/acronym-definition.d.ts +13 -0
  42. package/dist/detectors/acronym-definition.d.ts.map +1 -0
  43. package/dist/detectors/acronym-definition.js +90 -0
  44. package/dist/detectors/acronym-definition.js.map +1 -0
  45. package/dist/detectors/acronym-lone.d.ts +13 -0
  46. package/dist/detectors/acronym-lone.d.ts.map +1 -0
  47. package/dist/detectors/acronym-lone.js +22 -0
  48. package/dist/detectors/acronym-lone.js.map +1 -0
  49. package/dist/detectors/acronym-name.d.ts +55 -0
  50. package/dist/detectors/acronym-name.d.ts.map +1 -0
  51. package/dist/detectors/acronym-name.js +75 -0
  52. package/dist/detectors/acronym-name.js.map +1 -0
  53. package/dist/detectors/age-words.d.ts +5 -0
  54. package/dist/detectors/age-words.d.ts.map +1 -0
  55. package/dist/detectors/age-words.js +8 -0
  56. package/dist/detectors/age-words.js.map +1 -0
  57. package/dist/detectors/annual-pay-mismatch.d.ts.map +1 -1
  58. package/dist/detectors/annual-pay-mismatch.js +2 -12
  59. package/dist/detectors/annual-pay-mismatch.js.map +1 -1
  60. package/dist/detectors/blank-structure.d.ts.map +1 -1
  61. package/dist/detectors/blank-structure.js +4 -3
  62. package/dist/detectors/blank-structure.js.map +1 -1
  63. package/dist/detectors/capitalised-term.d.ts +14 -2
  64. package/dist/detectors/capitalised-term.d.ts.map +1 -1
  65. package/dist/detectors/capitalised-term.js +115 -4
  66. package/dist/detectors/capitalised-term.js.map +1 -1
  67. package/dist/detectors/caps-caption.d.ts +11 -0
  68. package/dist/detectors/caps-caption.d.ts.map +1 -0
  69. package/dist/detectors/caps-caption.js +51 -0
  70. package/dist/detectors/caps-caption.js.map +1 -0
  71. package/dist/detectors/char-shape.d.ts.map +1 -1
  72. package/dist/detectors/char-shape.js +47 -18
  73. package/dist/detectors/char-shape.js.map +1 -1
  74. package/dist/detectors/clause-shape.d.ts +1 -1
  75. package/dist/detectors/clause-shape.d.ts.map +1 -1
  76. package/dist/detectors/clause-shape.js +9 -4
  77. package/dist/detectors/clause-shape.js.map +1 -1
  78. package/dist/detectors/closing-balance-mismatch.d.ts.map +1 -1
  79. package/dist/detectors/closing-balance-mismatch.js +1 -0
  80. package/dist/detectors/closing-balance-mismatch.js.map +1 -1
  81. package/dist/detectors/code-fences.d.ts +5 -0
  82. package/dist/detectors/code-fences.d.ts.map +1 -1
  83. package/dist/detectors/code-fences.js +9 -0
  84. package/dist/detectors/code-fences.js.map +1 -1
  85. package/dist/detectors/concrete-evidence.d.ts +13 -1
  86. package/dist/detectors/concrete-evidence.d.ts.map +1 -1
  87. package/dist/detectors/concrete-evidence.js +59 -0
  88. package/dist/detectors/concrete-evidence.js.map +1 -1
  89. package/dist/detectors/condition-toki.d.ts +16 -0
  90. package/dist/detectors/condition-toki.d.ts.map +1 -0
  91. package/dist/detectors/condition-toki.js +42 -0
  92. package/dist/detectors/condition-toki.js.map +1 -0
  93. package/dist/detectors/conjugated-entry.d.ts +17 -0
  94. package/dist/detectors/conjugated-entry.d.ts.map +1 -0
  95. package/dist/detectors/conjugated-entry.js +50 -0
  96. package/dist/detectors/conjugated-entry.js.map +1 -0
  97. package/dist/detectors/content-morphemes.d.ts +2 -0
  98. package/dist/detectors/content-morphemes.d.ts.map +1 -1
  99. package/dist/detectors/content-morphemes.js +1 -1
  100. package/dist/detectors/content-morphemes.js.map +1 -1
  101. package/dist/detectors/contraction-minority.d.ts +11 -0
  102. package/dist/detectors/contraction-minority.d.ts.map +1 -0
  103. package/dist/detectors/contraction-minority.js +10 -0
  104. package/dist/detectors/contraction-minority.js.map +1 -0
  105. package/dist/detectors/counter-edge.d.ts +5 -0
  106. package/dist/detectors/counter-edge.d.ts.map +1 -1
  107. package/dist/detectors/counter-edge.js +23 -0
  108. package/dist/detectors/counter-edge.js.map +1 -1
  109. package/dist/detectors/cross-facts.d.ts.map +1 -1
  110. package/dist/detectors/cross-facts.js +2 -1
  111. package/dist/detectors/cross-facts.js.map +1 -1
  112. package/dist/detectors/custom.d.ts.map +1 -1
  113. package/dist/detectors/custom.js +8 -2
  114. package/dist/detectors/custom.js.map +1 -1
  115. package/dist/detectors/date-any-year.d.ts +6 -3
  116. package/dist/detectors/date-any-year.d.ts.map +1 -1
  117. package/dist/detectors/date-any-year.js +47 -10
  118. package/dist/detectors/date-any-year.js.map +1 -1
  119. package/dist/detectors/date-heading-year.d.ts +18 -0
  120. package/dist/detectors/date-heading-year.d.ts.map +1 -0
  121. package/dist/detectors/date-heading-year.js +38 -0
  122. package/dist/detectors/date-heading-year.js.map +1 -0
  123. package/dist/detectors/date-year.d.ts +12 -2
  124. package/dist/detectors/date-year.d.ts.map +1 -1
  125. package/dist/detectors/date-year.js +31 -6
  126. package/dist/detectors/date-year.js.map +1 -1
  127. package/dist/detectors/defined-term-form.d.ts.map +1 -1
  128. package/dist/detectors/defined-term-form.js +26 -5
  129. package/dist/detectors/defined-term-form.js.map +1 -1
  130. package/dist/detectors/document-shape.d.ts.map +1 -1
  131. package/dist/detectors/document-shape.js +6 -0
  132. package/dist/detectors/document-shape.js.map +1 -1
  133. package/dist/detectors/due-date.d.ts.map +1 -1
  134. package/dist/detectors/due-date.js +18 -2
  135. package/dist/detectors/due-date.js.map +1 -1
  136. package/dist/detectors/en-shape.d.ts.map +1 -1
  137. package/dist/detectors/en-shape.js +5 -1
  138. package/dist/detectors/en-shape.js.map +1 -1
  139. package/dist/detectors/fact-consistency.d.ts.map +1 -1
  140. package/dist/detectors/fact-consistency.js +15 -15
  141. package/dist/detectors/fact-consistency.js.map +1 -1
  142. package/dist/detectors/form-line.d.ts +9 -0
  143. package/dist/detectors/form-line.d.ts.map +1 -0
  144. package/dist/detectors/form-line.js +36 -0
  145. package/dist/detectors/form-line.js.map +1 -0
  146. package/dist/detectors/formula-amount.d.ts.map +1 -1
  147. package/dist/detectors/formula-amount.js +2 -12
  148. package/dist/detectors/formula-amount.js.map +1 -1
  149. package/dist/detectors/gram-passages.d.ts +11 -0
  150. package/dist/detectors/gram-passages.d.ts.map +1 -0
  151. package/dist/detectors/gram-passages.js +26 -0
  152. package/dist/detectors/gram-passages.js.map +1 -0
  153. package/dist/detectors/heading-claim.d.ts +14 -0
  154. package/dist/detectors/heading-claim.d.ts.map +1 -0
  155. package/dist/detectors/heading-claim.js +49 -0
  156. package/dist/detectors/heading-claim.js.map +1 -0
  157. package/dist/detectors/heading-echo.d.ts.map +1 -1
  158. package/dist/detectors/heading-echo.js +29 -1
  159. package/dist/detectors/heading-echo.js.map +1 -1
  160. package/dist/detectors/heading-end-mark.d.ts +8 -3
  161. package/dist/detectors/heading-end-mark.d.ts.map +1 -1
  162. package/dist/detectors/heading-end-mark.js +18 -8
  163. package/dist/detectors/heading-end-mark.js.map +1 -1
  164. package/dist/detectors/heading-names.d.ts +7 -0
  165. package/dist/detectors/heading-names.d.ts.map +1 -0
  166. package/dist/detectors/heading-names.js +24 -0
  167. package/dist/detectors/heading-names.js.map +1 -0
  168. package/dist/detectors/heading-numbering.d.ts.map +1 -1
  169. package/dist/detectors/heading-numbering.js +7 -2
  170. package/dist/detectors/heading-numbering.js.map +1 -1
  171. package/dist/detectors/inch-mark.d.ts +10 -0
  172. package/dist/detectors/inch-mark.d.ts.map +1 -0
  173. package/dist/detectors/inch-mark.js +48 -0
  174. package/dist/detectors/inch-mark.js.map +1 -0
  175. package/dist/detectors/installment-total-mismatch.d.ts.map +1 -1
  176. package/dist/detectors/installment-total-mismatch.js +2 -12
  177. package/dist/detectors/installment-total-mismatch.js.map +1 -1
  178. package/dist/detectors/lexicon.d.ts +0 -1
  179. package/dist/detectors/lexicon.d.ts.map +1 -1
  180. package/dist/detectors/lexicon.js +29 -23
  181. package/dist/detectors/lexicon.js.map +1 -1
  182. package/dist/detectors/list-parallel.d.ts +5 -2
  183. package/dist/detectors/list-parallel.d.ts.map +1 -1
  184. package/dist/detectors/list-parallel.js +45 -7
  185. package/dist/detectors/list-parallel.js.map +1 -1
  186. package/dist/detectors/mark-shape.d.ts +6 -3
  187. package/dist/detectors/mark-shape.d.ts.map +1 -1
  188. package/dist/detectors/mark-shape.js +12 -6
  189. package/dist/detectors/mark-shape.js.map +1 -1
  190. package/dist/detectors/name-variant-apart.d.ts +27 -0
  191. package/dist/detectors/name-variant-apart.d.ts.map +1 -0
  192. package/dist/detectors/name-variant-apart.js +51 -0
  193. package/dist/detectors/name-variant-apart.js.map +1 -0
  194. package/dist/detectors/name-variant.d.ts.map +1 -1
  195. package/dist/detectors/name-variant.js +51 -17
  196. package/dist/detectors/name-variant.js.map +1 -1
  197. package/dist/detectors/number-unit.d.ts +10 -0
  198. package/dist/detectors/number-unit.d.ts.map +1 -1
  199. package/dist/detectors/number-unit.js +28 -8
  200. package/dist/detectors/number-unit.js.map +1 -1
  201. package/dist/detectors/numeral-word.d.ts +15 -0
  202. package/dist/detectors/numeral-word.d.ts.map +1 -0
  203. package/dist/detectors/numeral-word.js +26 -0
  204. package/dist/detectors/numeral-word.js.map +1 -0
  205. package/dist/detectors/organisation-run.d.ts +14 -0
  206. package/dist/detectors/organisation-run.d.ts.map +1 -0
  207. package/dist/detectors/organisation-run.js +73 -0
  208. package/dist/detectors/organisation-run.js.map +1 -0
  209. package/dist/detectors/orthographic-variant.d.ts.map +1 -1
  210. package/dist/detectors/orthographic-variant.js +13 -5
  211. package/dist/detectors/orthographic-variant.js.map +1 -1
  212. package/dist/detectors/orthography.d.ts.map +1 -1
  213. package/dist/detectors/orthography.js +16 -7
  214. package/dist/detectors/orthography.js.map +1 -1
  215. package/dist/detectors/outline-label.d.ts +14 -0
  216. package/dist/detectors/outline-label.d.ts.map +1 -0
  217. package/dist/detectors/outline-label.js +32 -0
  218. package/dist/detectors/outline-label.js.map +1 -0
  219. package/dist/detectors/page-marker.d.ts +6 -0
  220. package/dist/detectors/page-marker.d.ts.map +1 -0
  221. package/dist/detectors/page-marker.js +19 -0
  222. package/dist/detectors/page-marker.js.map +1 -0
  223. package/dist/detectors/parallel-definition.d.ts +16 -0
  224. package/dist/detectors/parallel-definition.d.ts.map +1 -0
  225. package/dist/detectors/parallel-definition.js +51 -0
  226. package/dist/detectors/parallel-definition.js.map +1 -0
  227. package/dist/detectors/per-unit-words.d.ts +7 -0
  228. package/dist/detectors/per-unit-words.d.ts.map +1 -0
  229. package/dist/detectors/per-unit-words.js +17 -0
  230. package/dist/detectors/per-unit-words.js.map +1 -0
  231. package/dist/detectors/period-multiple-mismatch.d.ts.map +1 -1
  232. package/dist/detectors/period-multiple-mismatch.js +2 -12
  233. package/dist/detectors/period-multiple-mismatch.js.map +1 -1
  234. package/dist/detectors/reference-number-variant.d.ts.map +1 -1
  235. package/dist/detectors/reference-number-variant.js +21 -3
  236. package/dist/detectors/reference-number-variant.js.map +1 -1
  237. package/dist/detectors/reference-text.d.ts.map +1 -1
  238. package/dist/detectors/reference-text.js +1 -0
  239. package/dist/detectors/reference-text.js.map +1 -1
  240. package/dist/detectors/registry/condition-toki.d.ts +3 -0
  241. package/dist/detectors/registry/condition-toki.d.ts.map +1 -0
  242. package/dist/detectors/registry/condition-toki.js +3 -0
  243. package/dist/detectors/registry/condition-toki.js.map +1 -0
  244. package/dist/detectors/registry/unfilled-placeholder.d.ts.map +1 -1
  245. package/dist/detectors/registry/unfilled-placeholder.js +2 -2
  246. package/dist/detectors/registry/unfilled-placeholder.js.map +1 -1
  247. package/dist/detectors/registry/vague-density.js +1 -1
  248. package/dist/detectors/registry/vague-density.js.map +1 -1
  249. package/dist/detectors/rent-multiple-mismatch.d.ts.map +1 -1
  250. package/dist/detectors/rent-multiple-mismatch.js +2 -12
  251. package/dist/detectors/rent-multiple-mismatch.js.map +1 -1
  252. package/dist/detectors/request-owner.d.ts +6 -2
  253. package/dist/detectors/request-owner.d.ts.map +1 -1
  254. package/dist/detectors/request-owner.js +57 -7
  255. package/dist/detectors/request-owner.js.map +1 -1
  256. package/dist/detectors/requirement-smell.d.ts.map +1 -1
  257. package/dist/detectors/requirement-smell.js +10 -2
  258. package/dist/detectors/requirement-smell.js.map +1 -1
  259. package/dist/detectors/row-sentence-amounts.d.ts.map +1 -1
  260. package/dist/detectors/row-sentence-amounts.js +5 -10
  261. package/dist/detectors/row-sentence-amounts.js.map +1 -1
  262. package/dist/detectors/sentence-length.d.ts.map +1 -1
  263. package/dist/detectors/sentence-length.js +24 -16
  264. package/dist/detectors/sentence-length.js.map +1 -1
  265. package/dist/detectors/sentence-rhythm.d.ts.map +1 -1
  266. package/dist/detectors/sentence-rhythm.js +6 -3
  267. package/dist/detectors/sentence-rhythm.js.map +1 -1
  268. package/dist/detectors/series-label.d.ts +2 -1
  269. package/dist/detectors/series-label.d.ts.map +1 -1
  270. package/dist/detectors/series-label.js +10 -4
  271. package/dist/detectors/series-label.js.map +1 -1
  272. package/dist/detectors/signals.d.ts +4 -0
  273. package/dist/detectors/signals.d.ts.map +1 -1
  274. package/dist/detectors/signals.js +95 -36
  275. package/dist/detectors/signals.js.map +1 -1
  276. package/dist/detectors/stated-amounts.d.ts +4 -0
  277. package/dist/detectors/stated-amounts.d.ts.map +1 -0
  278. package/dist/detectors/stated-amounts.js +12 -0
  279. package/dist/detectors/stated-amounts.js.map +1 -0
  280. package/dist/detectors/step-time-sum.d.ts.map +1 -1
  281. package/dist/detectors/step-time-sum.js +2 -1
  282. package/dist/detectors/step-time-sum.js.map +1 -1
  283. package/dist/detectors/structure-tree.d.ts.map +1 -1
  284. package/dist/detectors/structure-tree.js +11 -7
  285. package/dist/detectors/structure-tree.js.map +1 -1
  286. package/dist/detectors/team.d.ts.map +1 -1
  287. package/dist/detectors/team.js +10 -6
  288. package/dist/detectors/team.js.map +1 -1
  289. package/dist/detectors/template-sections.d.ts +14 -0
  290. package/dist/detectors/template-sections.d.ts.map +1 -0
  291. package/dist/detectors/template-sections.js +25 -0
  292. package/dist/detectors/template-sections.js.map +1 -0
  293. package/dist/detectors/time-order.d.ts.map +1 -1
  294. package/dist/detectors/time-order.js +17 -13
  295. package/dist/detectors/time-order.js.map +1 -1
  296. package/dist/detectors/titled-run.d.ts +22 -0
  297. package/dist/detectors/titled-run.d.ts.map +1 -0
  298. package/dist/detectors/titled-run.js +34 -0
  299. package/dist/detectors/titled-run.js.map +1 -0
  300. package/dist/detectors/unbalanced-bracket.d.ts.map +1 -1
  301. package/dist/detectors/unbalanced-bracket.js +4 -0
  302. package/dist/detectors/unbalanced-bracket.js.map +1 -1
  303. package/dist/detectors/undefined-term.d.ts.map +1 -1
  304. package/dist/detectors/undefined-term.js +8 -0
  305. package/dist/detectors/undefined-term.js.map +1 -1
  306. package/dist/detectors/unfilled-placeholder.d.ts +4 -0
  307. package/dist/detectors/unfilled-placeholder.d.ts.map +1 -0
  308. package/dist/detectors/unfilled-placeholder.js +9 -0
  309. package/dist/detectors/unfilled-placeholder.js.map +1 -0
  310. package/dist/detectors/unknown-word.d.ts +4 -1
  311. package/dist/detectors/unknown-word.d.ts.map +1 -1
  312. package/dist/detectors/unknown-word.js +18 -2
  313. package/dist/detectors/unknown-word.js.map +1 -1
  314. package/dist/detectors/use-interval.d.ts +1 -0
  315. package/dist/detectors/use-interval.d.ts.map +1 -1
  316. package/dist/detectors/use-interval.js +15 -10
  317. package/dist/detectors/use-interval.js.map +1 -1
  318. package/dist/detectors/use-maximum.d.ts.map +1 -1
  319. package/dist/detectors/use-maximum.js +3 -1
  320. package/dist/detectors/use-maximum.js.map +1 -1
  321. package/dist/detectors/vague-density.d.ts +5 -0
  322. package/dist/detectors/vague-density.d.ts.map +1 -0
  323. package/dist/detectors/vague-density.js +52 -0
  324. package/dist/detectors/vague-density.js.map +1 -0
  325. package/dist/extension/document-view.d.ts +2 -2
  326. package/dist/extension/document-view.d.ts.map +1 -1
  327. package/dist/extension/document-view.js +17 -8
  328. package/dist/extension/document-view.js.map +1 -1
  329. package/dist/extension/entry-genres.d.ts +5 -0
  330. package/dist/extension/entry-genres.d.ts.map +1 -0
  331. package/dist/extension/entry-genres.js +13 -0
  332. package/dist/extension/entry-genres.js.map +1 -0
  333. package/dist/extension/module-detector.d.ts.map +1 -1
  334. package/dist/extension/module-detector.js +4 -4
  335. package/dist/extension/module-detector.js.map +1 -1
  336. package/dist/extension/plugin-parse.d.ts +1 -1
  337. package/dist/extension/plugin-parse.d.ts.map +1 -1
  338. package/dist/extension/plugin-parse.js +24 -7
  339. package/dist/extension/plugin-parse.js.map +1 -1
  340. package/dist/extension/problem-text.d.ts.map +1 -1
  341. package/dist/extension/problem-text.js +2 -0
  342. package/dist/extension/problem-text.js.map +1 -1
  343. package/dist/facts/age-values.d.ts.map +1 -1
  344. package/dist/facts/age-values.js +20 -2
  345. package/dist/facts/age-values.js.map +1 -1
  346. package/dist/facts/column-units.d.ts +31 -0
  347. package/dist/facts/column-units.d.ts.map +1 -0
  348. package/dist/facts/column-units.js +37 -0
  349. package/dist/facts/column-units.js.map +1 -0
  350. package/dist/facts/fact-scope.d.ts +10 -1
  351. package/dist/facts/fact-scope.d.ts.map +1 -1
  352. package/dist/facts/fact-scope.js +34 -3
  353. package/dist/facts/fact-scope.js.map +1 -1
  354. package/dist/facts/fact-values.d.ts +4 -0
  355. package/dist/facts/fact-values.d.ts.map +1 -1
  356. package/dist/facts/fact-values.js +3 -1
  357. package/dist/facts/fact-values.js.map +1 -1
  358. package/dist/facts/labelled-facts.d.ts +10 -0
  359. package/dist/facts/labelled-facts.d.ts.map +1 -1
  360. package/dist/facts/labelled-facts.js +6 -1
  361. package/dist/facts/labelled-facts.js.map +1 -1
  362. package/dist/facts/per-unit.d.ts +36 -0
  363. package/dist/facts/per-unit.d.ts.map +1 -0
  364. package/dist/facts/per-unit.js +56 -0
  365. package/dist/facts/per-unit.js.map +1 -0
  366. package/dist/facts/row-sentence-amounts.d.ts +3 -12
  367. package/dist/facts/row-sentence-amounts.d.ts.map +1 -1
  368. package/dist/facts/row-sentence-amounts.js +1 -15
  369. package/dist/facts/row-sentence-amounts.js.map +1 -1
  370. package/dist/facts/table-facts.d.ts +13 -3
  371. package/dist/facts/table-facts.d.ts.map +1 -1
  372. package/dist/facts/table-facts.js +35 -13
  373. package/dist/facts/table-facts.js.map +1 -1
  374. package/dist/facts/term-values.d.ts +13 -1
  375. package/dist/facts/term-values.d.ts.map +1 -1
  376. package/dist/facts/term-values.js +71 -12
  377. package/dist/facts/term-values.js.map +1 -1
  378. package/dist/grade/baseline.d.ts +4 -2
  379. package/dist/grade/baseline.d.ts.map +1 -1
  380. package/dist/grade/baseline.js +13 -11
  381. package/dist/grade/baseline.js.map +1 -1
  382. package/dist/grade/expect-read.d.ts +16 -0
  383. package/dist/grade/expect-read.d.ts.map +1 -0
  384. package/dist/grade/expect-read.js +52 -0
  385. package/dist/grade/expect-read.js.map +1 -0
  386. package/dist/grade/expect.d.ts +50 -0
  387. package/dist/grade/expect.d.ts.map +1 -0
  388. package/dist/grade/expect.js +53 -0
  389. package/dist/grade/expect.js.map +1 -0
  390. package/dist/grade/grade-item.d.ts +1 -1
  391. package/dist/grade/grade-item.d.ts.map +1 -1
  392. package/dist/grade/grade-item.js +13 -3
  393. package/dist/grade/grade-item.js.map +1 -1
  394. package/dist/grade/item.d.ts +9 -1
  395. package/dist/grade/item.d.ts.map +1 -1
  396. package/dist/grade/item.js +32 -7
  397. package/dist/grade/item.js.map +1 -1
  398. package/dist/grade/result.d.ts +5 -0
  399. package/dist/grade/result.d.ts.map +1 -1
  400. package/dist/grade/results-read.d.ts.map +1 -1
  401. package/dist/grade/results-read.js +4 -2
  402. package/dist/grade/results-read.js.map +1 -1
  403. package/dist/grade/rubric-file.d.ts +23 -0
  404. package/dist/grade/rubric-file.d.ts.map +1 -0
  405. package/dist/grade/rubric-file.js +35 -0
  406. package/dist/grade/rubric-file.js.map +1 -0
  407. package/dist/grade/rubric.d.ts +2 -0
  408. package/dist/grade/rubric.d.ts.map +1 -1
  409. package/dist/grade/rubric.js +75 -47
  410. package/dist/grade/rubric.js.map +1 -1
  411. package/dist/grade/setup.d.ts +2 -1
  412. package/dist/grade/setup.d.ts.map +1 -1
  413. package/dist/grade/setup.js +2 -2
  414. package/dist/grade/setup.js.map +1 -1
  415. package/dist/grade/stamp.d.ts +2 -0
  416. package/dist/grade/stamp.d.ts.map +1 -1
  417. package/dist/grade/stamp.js +8 -2
  418. package/dist/grade/stamp.js.map +1 -1
  419. package/dist/grade/task-rubric.d.ts +16 -0
  420. package/dist/grade/task-rubric.d.ts.map +1 -0
  421. package/dist/grade/task-rubric.js +34 -0
  422. package/dist/grade/task-rubric.js.map +1 -0
  423. package/dist/grade/text.d.ts +5 -1
  424. package/dist/grade/text.d.ts.map +1 -1
  425. package/dist/grade/text.js +16 -4
  426. package/dist/grade/text.js.map +1 -1
  427. package/dist/grade-api.d.ts +9 -2
  428. package/dist/grade-api.d.ts.map +1 -1
  429. package/dist/grade-api.js +31 -15
  430. package/dist/grade-api.js.map +1 -1
  431. package/dist/heading-numbering.d.ts +5 -2
  432. package/dist/heading-numbering.d.ts.map +1 -1
  433. package/dist/heading-numbering.js +27 -6
  434. package/dist/heading-numbering.js.map +1 -1
  435. package/dist/name-char-reading.d.ts +5 -0
  436. package/dist/name-char-reading.d.ts.map +1 -1
  437. package/dist/name-char-reading.js +15 -0
  438. package/dist/name-char-reading.js.map +1 -1
  439. package/dist/name-end-letter.d.ts +24 -0
  440. package/dist/name-end-letter.d.ts.map +1 -0
  441. package/dist/name-end-letter.js +45 -0
  442. package/dist/name-end-letter.js.map +1 -0
  443. package/dist/name-given-before.d.ts +15 -0
  444. package/dist/name-given-before.d.ts.map +1 -0
  445. package/dist/name-given-before.js +30 -0
  446. package/dist/name-given-before.js.map +1 -0
  447. package/dist/name-neighbours.d.ts.map +1 -1
  448. package/dist/name-neighbours.js +2 -1
  449. package/dist/name-neighbours.js.map +1 -1
  450. package/dist/name-separator.d.ts +6 -0
  451. package/dist/name-separator.d.ts.map +1 -1
  452. package/dist/name-separator.js +80 -0
  453. package/dist/name-separator.js.map +1 -1
  454. package/dist/name-variants.d.ts +8 -3
  455. package/dist/name-variants.d.ts.map +1 -1
  456. package/dist/name-variants.js +40 -12
  457. package/dist/name-variants.js.map +1 -1
  458. package/dist/name-word-order.d.ts +9 -5
  459. package/dist/name-word-order.d.ts.map +1 -1
  460. package/dist/name-word-order.js +47 -15
  461. package/dist/name-word-order.js.map +1 -1
  462. package/dist/nominal-stem.d.ts +13 -0
  463. package/dist/nominal-stem.d.ts.map +1 -0
  464. package/dist/nominal-stem.js +32 -0
  465. package/dist/nominal-stem.js.map +1 -0
  466. package/dist/number-name.d.ts.map +1 -1
  467. package/dist/number-name.js +11 -2
  468. package/dist/number-name.js.map +1 -1
  469. package/dist/profile/cue-lines.d.ts +6 -0
  470. package/dist/profile/cue-lines.d.ts.map +1 -0
  471. package/dist/profile/cue-lines.js +13 -0
  472. package/dist/profile/cue-lines.js.map +1 -0
  473. package/dist/profile/parse.d.ts +1 -1
  474. package/dist/profile/parse.d.ts.map +1 -1
  475. package/dist/profile/parse.js +3 -2
  476. package/dist/profile/parse.js.map +1 -1
  477. package/dist/reference-numbers.d.ts +2 -0
  478. package/dist/reference-numbers.d.ts.map +1 -1
  479. package/dist/reference-numbers.js +1 -1
  480. package/dist/reference-numbers.js.map +1 -1
  481. package/dist/sentence-load.d.ts +2 -1
  482. package/dist/sentence-load.d.ts.map +1 -1
  483. package/dist/sentence-load.js +6 -2
  484. package/dist/sentence-load.js.map +1 -1
  485. package/dist/spaced-person-name.d.ts.map +1 -1
  486. package/dist/spaced-person-name.js +26 -1
  487. package/dist/spaced-person-name.js.map +1 -1
  488. package/dist/spacing-code.d.ts.map +1 -1
  489. package/dist/spacing-code.js +10 -1
  490. package/dist/spacing-code.js.map +1 -1
  491. package/dist/spacing-minority.d.ts +7 -0
  492. package/dist/spacing-minority.d.ts.map +1 -1
  493. package/dist/spacing-minority.js +14 -0
  494. package/dist/spacing-minority.js.map +1 -1
  495. package/dist/structure/cited-document-section.d.ts +7 -0
  496. package/dist/structure/cited-document-section.d.ts.map +1 -0
  497. package/dist/structure/cited-document-section.js +33 -0
  498. package/dist/structure/cited-document-section.js.map +1 -0
  499. package/dist/structure/closing-balance.d.ts +9 -0
  500. package/dist/structure/closing-balance.d.ts.map +1 -1
  501. package/dist/structure/closing-balance.js +34 -7
  502. package/dist/structure/closing-balance.js.map +1 -1
  503. package/dist/structure/definition-use.d.ts.map +1 -1
  504. package/dist/structure/definition-use.js +20 -1
  505. package/dist/structure/definition-use.js.map +1 -1
  506. package/dist/structure/document-context.d.ts +2 -0
  507. package/dist/structure/document-context.d.ts.map +1 -0
  508. package/dist/structure/document-context.js +42 -0
  509. package/dist/structure/document-context.js.map +1 -0
  510. package/dist/structure/fenced-lines.d.ts +7 -0
  511. package/dist/structure/fenced-lines.d.ts.map +1 -0
  512. package/dist/structure/fenced-lines.js +27 -0
  513. package/dist/structure/fenced-lines.js.map +1 -0
  514. package/dist/structure/html-text-blocks.d.ts +8 -0
  515. package/dist/structure/html-text-blocks.d.ts.map +1 -0
  516. package/dist/structure/html-text-blocks.js +47 -0
  517. package/dist/structure/html-text-blocks.js.map +1 -0
  518. package/dist/structure/issues.d.ts +1 -1
  519. package/dist/structure/issues.d.ts.map +1 -1
  520. package/dist/structure/issues.js +19 -4
  521. package/dist/structure/issues.js.map +1 -1
  522. package/dist/structure/labelled-date-order.d.ts +34 -9
  523. package/dist/structure/labelled-date-order.d.ts.map +1 -1
  524. package/dist/structure/labelled-date-order.js +60 -15
  525. package/dist/structure/labelled-date-order.js.map +1 -1
  526. package/dist/structure/labelled-order.d.ts +10 -1
  527. package/dist/structure/labelled-order.d.ts.map +1 -1
  528. package/dist/structure/labelled-order.js +18 -6
  529. package/dist/structure/labelled-order.js.map +1 -1
  530. package/dist/structure/line-amount-label.d.ts.map +1 -1
  531. package/dist/structure/line-amount-label.js +2 -1
  532. package/dist/structure/line-amount-label.js.map +1 -1
  533. package/dist/structure/line-amount.d.ts +0 -5
  534. package/dist/structure/line-amount.d.ts.map +1 -1
  535. package/dist/structure/line-amount.js +1 -10
  536. package/dist/structure/line-amount.js.map +1 -1
  537. package/dist/structure/list-numbering.d.ts +20 -4
  538. package/dist/structure/list-numbering.d.ts.map +1 -1
  539. package/dist/structure/list-numbering.js +65 -9
  540. package/dist/structure/list-numbering.js.map +1 -1
  541. package/dist/structure/listed-paragraph.d.ts +16 -0
  542. package/dist/structure/listed-paragraph.d.ts.map +1 -0
  543. package/dist/structure/listed-paragraph.js +37 -0
  544. package/dist/structure/listed-paragraph.js.map +1 -0
  545. package/dist/structure/numbering.d.ts +3 -2
  546. package/dist/structure/numbering.d.ts.map +1 -1
  547. package/dist/structure/numbering.js +31 -6
  548. package/dist/structure/numbering.js.map +1 -1
  549. package/dist/structure/prose-total.d.ts +8 -0
  550. package/dist/structure/prose-total.d.ts.map +1 -1
  551. package/dist/structure/prose-total.js +70 -2
  552. package/dist/structure/prose-total.js.map +1 -1
  553. package/dist/structure/reference-text.d.ts +9 -1
  554. package/dist/structure/reference-text.d.ts.map +1 -1
  555. package/dist/structure/reference-text.js +21 -3
  556. package/dist/structure/reference-text.js.map +1 -1
  557. package/dist/structure/runs.d.ts.map +1 -1
  558. package/dist/structure/runs.js +9 -1
  559. package/dist/structure/runs.js.map +1 -1
  560. package/dist/structure/section-names.d.ts +12 -0
  561. package/dist/structure/section-names.d.ts.map +1 -0
  562. package/dist/structure/section-names.js +26 -0
  563. package/dist/structure/section-names.js.map +1 -0
  564. package/dist/structure/signed-date-line.d.ts +15 -0
  565. package/dist/structure/signed-date-line.d.ts.map +1 -0
  566. package/dist/structure/signed-date-line.js +68 -0
  567. package/dist/structure/signed-date-line.js.map +1 -0
  568. package/dist/structure/tax.d.ts.map +1 -1
  569. package/dist/structure/tax.js +5 -3
  570. package/dist/structure/tax.js.map +1 -1
  571. package/dist/structure/total-line.d.ts.map +1 -1
  572. package/dist/structure/total-line.js +10 -6
  573. package/dist/structure/total-line.js.map +1 -1
  574. package/dist/structure/total.d.ts +2 -0
  575. package/dist/structure/total.d.ts.map +1 -1
  576. package/dist/structure/total.js +34 -3
  577. package/dist/structure/total.js.map +1 -1
  578. package/dist/structure/versioned-label.d.ts +16 -0
  579. package/dist/structure/versioned-label.d.ts.map +1 -0
  580. package/dist/structure/versioned-label.js +48 -0
  581. package/dist/structure/versioned-label.js.map +1 -0
  582. package/dist/structure/written-headings.d.ts +31 -0
  583. package/dist/structure/written-headings.d.ts.map +1 -0
  584. package/dist/structure/written-headings.js +119 -0
  585. package/dist/structure/written-headings.js.map +1 -0
  586. package/dist/structure/written-resolve.d.ts +12 -0
  587. package/dist/structure/written-resolve.d.ts.map +1 -0
  588. package/dist/structure/written-resolve.js +49 -0
  589. package/dist/structure/written-resolve.js.map +1 -0
  590. package/dist/subject-codes.d.ts +21 -0
  591. package/dist/subject-codes.d.ts.map +1 -0
  592. package/dist/subject-codes.js +79 -0
  593. package/dist/subject-codes.js.map +1 -0
  594. package/dist/unlabelled-references.d.ts +6 -2
  595. package/dist/unlabelled-references.d.ts.map +1 -1
  596. package/dist/unlabelled-references.js +11 -10
  597. package/dist/unlabelled-references.js.map +1 -1
  598. package/genres.yaml +17 -0
  599. package/package.json +3 -3
  600. package/profiles/listing.yaml +1 -1
  601. package/rules/all-caps-shouting.yaml +2 -2
  602. package/rules/closing-balance-mismatch.yaml +3 -3
  603. package/rules/concrete-evidence-density.yaml +2 -2
  604. package/rules/contraction-consistency.yaml +13 -13
  605. package/rules/dangling-reference.yaml +2 -2
  606. package/rules/date-without-year.yaml +2 -2
  607. package/rules/defined-name-repeated.yaml +2 -2
  608. package/rules/due-before-issue.yaml +9 -5
  609. package/rules/fact-conflict.yaml +2 -2
  610. package/rules/heading-echo.yaml +2 -2
  611. package/rules/heading-end-punctuation-mix.yaml +2 -2
  612. package/rules/heading-numbering-mix.yaml +2 -2
  613. package/rules/internal-jargon.yaml +2 -2
  614. package/rules/latin-spacing.yaml +4 -4
  615. package/rules/list-item-form-mix.yaml +1 -1
  616. package/rules/max-kanji-continuous.yaml +5 -3
  617. package/rules/max-sentence-length.yaml +3 -2
  618. package/rules/name-variant.yaml +5 -2
  619. package/rules/ngram-repetition.yaml +2 -2
  620. package/rules/no-lead.yaml +2 -2
  621. package/rules/number-without-unit.yaml +2 -2
  622. package/rules/numbering-gap.yaml +2 -2
  623. package/rules/orthographic-variant.yaml +2 -2
  624. package/rules/reference-number-variant.yaml +3 -3
  625. package/rules/reference-title-mismatch.yaml +2 -2
  626. package/rules/repeated-sentence-ending.yaml +3 -2
  627. package/rules/request-without-deadline.yaml +2 -2
  628. package/rules/requirement-smell.yaml +2 -2
  629. package/rules/sentence-rhythm.yaml +2 -2
  630. package/rules/title-case-consistency.yaml +2 -2
  631. package/rules/toki-as-condition.yaml +71 -0
  632. package/rules/total-mismatch.yaml +4 -4
  633. package/rules/unbalanced-bracket.yaml +2 -2
  634. package/rules/undefined-acronym.yaml +11 -2
  635. package/rules/undefined-term.yaml +2 -2
  636. package/rules/unfilled-placeholder.yaml +2 -2
  637. package/rules/unknown-word.yaml +2 -2
  638. package/rules/use-before-definition.yaml +2 -2
  639. package/rules/vague-word-density.yaml +2 -2
  640. package/src/api.ts +11 -2
  641. package/src/capitals-passage.ts +31 -0
  642. package/src/cli-text.ts +4 -2
  643. package/src/coined-hyphen-name.ts +27 -0
  644. package/src/commands/grade.ts +75 -23
  645. package/src/company-kana-spelling.ts +22 -2
  646. package/src/company-name-ending.ts +50 -0
  647. package/src/company-names.ts +76 -20
  648. package/src/custom/no-rewrite.ts +2 -0
  649. package/src/custom/parse.ts +18 -2
  650. package/src/detectors/acronym-context.ts +5 -6
  651. package/src/detectors/acronym-definition.ts +123 -0
  652. package/src/detectors/acronym-lone.ts +26 -0
  653. package/src/detectors/acronym-name.ts +117 -0
  654. package/src/detectors/age-words.ts +12 -0
  655. package/src/detectors/annual-pay-mismatch.ts +3 -18
  656. package/src/detectors/blank-structure.ts +4 -3
  657. package/src/detectors/capitalised-term.ts +154 -4
  658. package/src/detectors/caps-caption.ts +61 -0
  659. package/src/detectors/char-shape.ts +74 -22
  660. package/src/detectors/clause-shape.ts +14 -4
  661. package/src/detectors/closing-balance-mismatch.ts +1 -0
  662. package/src/detectors/code-fences.ts +10 -0
  663. package/src/detectors/concrete-evidence.ts +77 -1
  664. package/src/detectors/condition-toki.ts +60 -0
  665. package/src/detectors/conjugated-entry.ts +53 -0
  666. package/src/detectors/content-morphemes.ts +2 -1
  667. package/src/detectors/contraction-minority.ts +11 -0
  668. package/src/detectors/counter-edge.ts +23 -0
  669. package/src/detectors/cross-facts.ts +2 -1
  670. package/src/detectors/custom.ts +9 -2
  671. package/src/detectors/date-any-year.ts +56 -10
  672. package/src/detectors/date-heading-year.ts +55 -0
  673. package/src/detectors/date-year.ts +54 -9
  674. package/src/detectors/defined-term-form.ts +26 -5
  675. package/src/detectors/document-shape.ts +8 -0
  676. package/src/detectors/due-date.ts +26 -7
  677. package/src/detectors/en-shape.ts +5 -1
  678. package/src/detectors/fact-consistency.ts +16 -19
  679. package/src/detectors/form-line.ts +47 -0
  680. package/src/detectors/formula-amount.ts +2 -18
  681. package/src/detectors/gram-passages.ts +36 -0
  682. package/src/detectors/heading-claim.ts +76 -0
  683. package/src/detectors/heading-echo.ts +32 -1
  684. package/src/detectors/heading-end-mark.ts +23 -10
  685. package/src/detectors/heading-names.ts +31 -0
  686. package/src/detectors/heading-numbering.ts +7 -2
  687. package/src/detectors/inch-mark.ts +49 -0
  688. package/src/detectors/installment-total-mismatch.ts +3 -18
  689. package/src/detectors/lexicon.ts +32 -21
  690. package/src/detectors/list-parallel.ts +46 -7
  691. package/src/detectors/mark-shape.ts +12 -6
  692. package/src/detectors/name-variant-apart.ts +63 -0
  693. package/src/detectors/name-variant.ts +73 -18
  694. package/src/detectors/number-unit.ts +35 -9
  695. package/src/detectors/numeral-word.ts +33 -0
  696. package/src/detectors/organisation-run.ts +86 -0
  697. package/src/detectors/orthographic-variant.ts +22 -6
  698. package/src/detectors/orthography.ts +17 -8
  699. package/src/detectors/outline-label.ts +48 -0
  700. package/src/detectors/page-marker.ts +26 -0
  701. package/src/detectors/parallel-definition.ts +64 -0
  702. package/src/detectors/per-unit-words.ts +24 -0
  703. package/src/detectors/period-multiple-mismatch.ts +2 -18
  704. package/src/detectors/reference-number-variant.ts +27 -5
  705. package/src/detectors/reference-text.ts +1 -0
  706. package/src/detectors/registry/condition-toki.ts +4 -0
  707. package/src/detectors/registry/unfilled-placeholder.ts +2 -2
  708. package/src/detectors/registry/vague-density.ts +1 -1
  709. package/src/detectors/rent-multiple-mismatch.ts +2 -18
  710. package/src/detectors/request-owner.ts +71 -8
  711. package/src/detectors/requirement-smell.ts +15 -2
  712. package/src/detectors/row-sentence-amounts.ts +5 -20
  713. package/src/detectors/sentence-length.ts +14 -6
  714. package/src/detectors/sentence-rhythm.ts +8 -4
  715. package/src/detectors/series-label.ts +13 -4
  716. package/src/detectors/signals.ts +94 -26
  717. package/src/detectors/stated-amounts.ts +20 -0
  718. package/src/detectors/step-time-sum.ts +2 -1
  719. package/src/detectors/structure-tree.ts +13 -8
  720. package/src/detectors/team.ts +13 -7
  721. package/src/detectors/template-sections.ts +37 -0
  722. package/src/detectors/time-order.ts +6 -3
  723. package/src/detectors/titled-run.ts +43 -0
  724. package/src/detectors/unbalanced-bracket.ts +3 -0
  725. package/src/detectors/undefined-term.ts +8 -0
  726. package/src/detectors/unfilled-placeholder.ts +10 -0
  727. package/src/detectors/unknown-word.ts +20 -2
  728. package/src/detectors/use-interval.ts +8 -4
  729. package/src/detectors/use-maximum.ts +3 -1
  730. package/src/detectors/vague-density.ts +68 -0
  731. package/src/extension/document-view.ts +18 -9
  732. package/src/extension/entry-genres.ts +15 -0
  733. package/src/extension/module-detector.ts +9 -4
  734. package/src/extension/plugin-parse.ts +29 -7
  735. package/src/extension/problem-text.ts +4 -0
  736. package/src/facts/age-values.ts +24 -2
  737. package/src/facts/column-units.ts +67 -0
  738. package/src/facts/fact-scope.ts +53 -4
  739. package/src/facts/fact-values.ts +11 -1
  740. package/src/facts/labelled-facts.ts +16 -2
  741. package/src/facts/per-unit.ts +105 -0
  742. package/src/facts/row-sentence-amounts.ts +4 -26
  743. package/src/facts/table-facts.ts +50 -10
  744. package/src/facts/term-values.ts +94 -13
  745. package/src/grade/baseline.ts +20 -12
  746. package/src/grade/expect-read.ts +65 -0
  747. package/src/grade/expect.ts +74 -0
  748. package/src/grade/grade-item.ts +14 -3
  749. package/src/grade/item.ts +48 -8
  750. package/src/grade/result.ts +5 -0
  751. package/src/grade/results-read.ts +7 -2
  752. package/src/grade/rubric-file.ts +46 -0
  753. package/src/grade/rubric.ts +77 -47
  754. package/src/grade/setup.ts +3 -3
  755. package/src/grade/stamp.ts +10 -2
  756. package/src/grade/task-rubric.ts +39 -0
  757. package/src/grade/text.ts +27 -5
  758. package/src/grade-api.ts +38 -16
  759. package/src/heading-numbering.ts +35 -8
  760. package/src/name-char-reading.ts +16 -0
  761. package/src/name-end-letter.ts +61 -0
  762. package/src/name-given-before.ts +40 -0
  763. package/src/name-neighbours.ts +2 -1
  764. package/src/name-separator.ts +93 -0
  765. package/src/name-variants.ts +69 -18
  766. package/src/name-word-order.ts +62 -17
  767. package/src/nominal-stem.ts +36 -0
  768. package/src/number-name.ts +12 -3
  769. package/src/profile/cue-lines.ts +14 -0
  770. package/src/profile/parse.ts +3 -2
  771. package/src/reference-numbers.ts +1 -1
  772. package/src/sentence-load.ts +7 -2
  773. package/src/spaced-person-name.ts +27 -2
  774. package/src/spacing-code.ts +13 -2
  775. package/src/spacing-minority.ts +17 -0
  776. package/src/structure/cited-document-section.ts +42 -0
  777. package/src/structure/closing-balance.ts +46 -8
  778. package/src/structure/definition-use.ts +24 -1
  779. package/src/structure/document-context.ts +46 -0
  780. package/src/structure/fenced-lines.ts +28 -0
  781. package/src/structure/html-text-blocks.ts +45 -0
  782. package/src/structure/issues.ts +19 -4
  783. package/src/structure/labelled-date-order.ts +108 -21
  784. package/src/structure/labelled-order.ts +33 -13
  785. package/src/structure/line-amount-label.ts +2 -1
  786. package/src/structure/line-amount.ts +1 -11
  787. package/src/structure/list-numbering.ts +100 -11
  788. package/src/structure/listed-paragraph.ts +45 -0
  789. package/src/structure/numbering.ts +48 -19
  790. package/src/structure/prose-total.ts +81 -2
  791. package/src/structure/reference-text.ts +25 -3
  792. package/src/structure/runs.ts +10 -1
  793. package/src/structure/section-names.ts +32 -0
  794. package/src/structure/signed-date-line.ts +78 -0
  795. package/src/structure/tax.ts +6 -3
  796. package/src/structure/total-line.ts +12 -6
  797. package/src/structure/total.ts +42 -3
  798. package/src/structure/versioned-label.ts +52 -0
  799. package/src/structure/written-headings.ts +137 -0
  800. package/src/structure/written-resolve.ts +57 -0
  801. package/src/subject-codes.ts +105 -0
  802. package/src/unlabelled-references.ts +24 -16
@@ -0,0 +1,68 @@
1
+ // Vague words dense for the document's length (vague-word-density). Each sentence counts the vague words it holds once:
2
+ // a word inside a longer one ("timely" in "in a timely manner") is that longer word, and a word inside a term of art of the
3
+ // document's genre ("reasonably" in a contract, "adequately compensate" as the test for an injunction) is not vague
4
+ // there. The rule speaks once per sentence, about the document's density. Pure: the words come from the language's
5
+ // lexicons vague-word and vague-word-term-of-art, the genre from the options.
6
+ import { entriesForGenre } from "../lexicon-genres.ts";
7
+ import { escapeRegExp } from "../orthography.ts";
8
+ import type { Detector, Finding, Lexicon, LexiconEntry, Sentence } from "../plugin.ts";
9
+ import { comparableText, comparableWords, entryRanges } from "./lexicon-match.ts";
10
+ import { rateOver } from "./lexicon.ts";
11
+
12
+ const TERMS_OF_ART = "vague-word-term-of-art";
13
+
14
+ type Place = { readonly start: number; readonly end: number };
15
+
16
+ type Match = { readonly pattern: string; readonly place: Place };
17
+
18
+ /** Token spans are places in the document and text places are in the sentence, so one sentence uses one kind for every entry. */
19
+ const readsTokens = (sentence: Sentence, entries: Lexicon): boolean =>
20
+ sentence.tokens !== undefined && entries.every((entry) => (entry.tokens?.length ?? 0) > 0);
21
+
22
+ /** Where an entry stands in the sentence, as character spans: its tokens, or the comparable text. */
23
+ const placesOf = (sentence: Sentence, entry: LexiconEntry, byTokens: boolean): Place[] => {
24
+ const tokens = sentence.tokens;
25
+ if (byTokens && tokens !== undefined)
26
+ return entryRanges(sentence, entry).map((range) => ({ start: tokens[range.start]?.span.start ?? 0, end: tokens[range.end - 1]?.span.end ?? 0 }));
27
+ const word = comparableWords(entry.pattern);
28
+ if (word === "") return [];
29
+ return [...comparableText(sentence).matchAll(new RegExp(escapeRegExp(word), "gu"))].map((found) => ({ start: found.index, end: found.index + word.length }));
30
+ };
31
+
32
+ const matchesOf = (sentence: Sentence, lexicon: Lexicon, byTokens: boolean): Match[] =>
33
+ lexicon.flatMap((entry) => placesOf(sentence, entry, byTokens).map((place) => ({ pattern: entry.pattern, place })));
34
+
35
+ const covers = (outer: Place, inner: Place): boolean => outer.start <= inner.start && inner.end <= outer.end;
36
+
37
+ const isLonger = (outer: Match, inner: Match): boolean => outer.place.end - outer.place.start > inner.place.end - inner.place.start;
38
+
39
+ /** The vague words of one sentence, in the order written, each once: none inside a longer vague word or a term of art. */
40
+ export const vagueWordsIn = (sentence: Sentence, vague: Lexicon, termsOfArt: Lexicon): string[] => {
41
+ const byTokens = readsTokens(sentence, [...vague, ...termsOfArt]);
42
+ const matches = matchesOf(sentence, vague, byTokens);
43
+ const terms = matchesOf(sentence, termsOfArt, byTokens);
44
+ const kept = matches.filter(
45
+ (match) => !matches.some((other) => isLonger(other, match) && covers(other.place, match.place)) && !terms.some((term) => covers(term.place, match.place)),
46
+ );
47
+ return [...new Set(kept.toSorted((left, right) => left.place.start - right.place.start).map((match) => match.pattern))];
48
+ };
49
+
50
+ type SentenceHits = { readonly sentence: Sentence; readonly words: readonly string[] };
51
+
52
+ export const vagueDensity: Detector = (doc, options): Finding[] => {
53
+ const termsOfArt = entriesForGenre(doc.lexicons[TERMS_OF_ART] ?? [], options.genre);
54
+ const hits: SentenceHits[] = doc.sentences
55
+ .map((sentence) => ({ sentence, words: vagueWordsIn(sentence, options.lexicon ?? [], termsOfArt) }))
56
+ .filter((hit) => hit.words.length > 0);
57
+ const count = hits.reduce((sum, hit) => sum + hit.words.length, 0);
58
+ const density = rateOver(doc, count, options.limit);
59
+ if (density === undefined) return [];
60
+ return hits.map(({ sentence, words }) => ({
61
+ rule: "vague-word-density",
62
+ severity: "warning",
63
+ line: 0,
64
+ column: 0,
65
+ quote: sentence.text.trim(),
66
+ values: { matched: words[0] ?? "", count, density, limit: options.limit, offset: sentence.span.start },
67
+ }));
68
+ };
@@ -1,5 +1,6 @@
1
1
  import type * as Api from "../api.ts";
2
2
  import type { BulletList, Lexicon, Markup, Paragraph, ProseDocument, Section, Sentence, Span, Token } from "../plugin.ts";
3
+ import { entriesForGenre } from "../lexicon-genres.ts";
3
4
 
4
5
  // The document as the plugin API shows it (api.ts RuleDocument): copies of only the public fields, frozen. A copy, so
5
6
  // chaff's own shapes can change without breaking a plugin; frozen, so a plugin's rule cannot change what the next rule reads.
@@ -55,7 +56,12 @@ const sectionOf = (section: Section, copy: SentenceCopies): Api.Section => ({
55
56
  const listOf = (list: BulletList): Api.List => ({ span: spanOf(list.span), itemLengths: [...list.items] });
56
57
 
57
58
  const lexiconOf = (lexicon: Lexicon): Api.Lexicon =>
58
- lexicon.map((entry) => ({ pattern: entry.pattern, ...(entry.instead_of === undefined ? {} : { instead_of: entry.instead_of }) }));
59
+ lexicon.map((entry) => ({
60
+ pattern: entry.pattern,
61
+ ...(entry.instead_of === undefined ? {} : { instead_of: entry.instead_of }),
62
+ ...(entry.rewrite === undefined ? {} : { rewrite: entry.rewrite }),
63
+ ...(entry.genres === undefined ? {} : { genres: [...entry.genres] }),
64
+ }));
59
65
 
60
66
  const markupOf = (markup: Markup): Api.Markup => ({
61
67
  markdown: markup.markdown,
@@ -68,7 +74,7 @@ const markupOf = (markup: Markup): Api.Markup => ({
68
74
 
69
75
  const EMPTY_MARKUP: Markup = { markdown: false, headings: [], images: [], links: [], ids: new Set(), texts: [] };
70
76
 
71
- const viewOf = (doc: ProseDocument): Api.RuleDocument => {
77
+ const viewOf = (doc: ProseDocument, genre: string | undefined): Api.RuleDocument => {
72
78
  const copy = sentenceCopier();
73
79
  const fields = deepFreeze({
74
80
  path: doc.path,
@@ -81,7 +87,7 @@ const viewOf = (doc: ProseDocument): Api.RuleDocument => {
81
87
  lists: doc.lists.map(listOf),
82
88
  listItems: doc.listSpans.map(spanOf),
83
89
  links: doc.links.map(spanOf),
84
- lexicons: Object.fromEntries(Object.entries(doc.lexicons).map(([name, lexicon]) => [name, lexiconOf(lexicon)])),
90
+ lexicons: Object.fromEntries(Object.entries(doc.lexicons).map(([name, lexicon]) => [name, lexiconOf(entriesForGenre(lexicon, genre))])),
85
91
  });
86
92
  // The markup is read from the Markdown tree only when a rule asks for it, as chaff's own rules do.
87
93
  const markup: { value: Api.Markup | undefined } = { value: undefined };
@@ -97,13 +103,16 @@ const viewOf = (doc: ProseDocument): Api.RuleDocument => {
97
103
  /** A word list as a detector is given it (DetectorOptions.lexicon): public fields only, frozen. */
98
104
  export const frozenLexiconOf = (lexicon: Lexicon): Api.Lexicon => deepFreeze(lexiconOf(lexicon));
99
105
 
100
- const views = new WeakMap<ProseDocument, Api.RuleDocument>();
106
+ // By genre too: the run, not the document, carries the genre, so one document may be run under several.
107
+ const views = new WeakMap<ProseDocument, Map<string | undefined, Api.RuleDocument>>();
101
108
 
102
- /** The document as a plugin's detector sees it. Made once per document, however many plugin rules read it. */
103
- export const ruleDocumentOf = (doc: ProseDocument): Api.RuleDocument => {
104
- const known = views.get(doc);
109
+ /** The document as a plugin's detector sees it in a genre, its word lists holding that genre's entries. Made once per document and genre. */
110
+ export const ruleDocumentOf = (doc: ProseDocument, genre: string | undefined): Api.RuleDocument => {
111
+ const byGenre = views.get(doc) ?? new Map<string | undefined, Api.RuleDocument>();
112
+ views.set(doc, byGenre);
113
+ const known = byGenre.get(genre);
105
114
  if (known !== undefined) return known;
106
- const view = viewOf(doc);
107
- views.set(doc, view);
115
+ const view = viewOf(doc, genre);
116
+ byGenre.set(genre, view);
108
117
  return view;
109
118
  };
@@ -0,0 +1,15 @@
1
+ // A word-list entry's genres as a plugin writes them: a non-empty list of the genres and groups chaff knows (legal,
2
+ // blog/tech). Pure: the known ids come in.
3
+
4
+ const printed = (value: unknown): string => JSON.stringify(value) ?? String(value);
5
+
6
+ /** What cannot be read in genres, printed: the whole value when it is not a non-empty list, else its unknown items. undefined when it reads. */
7
+ export const genresProblemOf = (genres: unknown, known: ReadonlySet<string>): string | undefined => {
8
+ if (!Array.isArray(genres) || genres.length === 0) return printed(genres);
9
+ const unknown = genres.filter((genre: unknown) => typeof genre !== "string" || !known.has(genre));
10
+ return unknown.length === 0 ? undefined : printed(unknown);
11
+ };
12
+
13
+ /** genres when they read, as a list of ids. */
14
+ export const readGenres = (genres: unknown, known: ReadonlySet<string>): string[] | undefined =>
15
+ Array.isArray(genres) && genresProblemOf(genres, known) === undefined ? genres.filter((genre: unknown) => typeof genre === "string") : undefined;
@@ -1,6 +1,7 @@
1
1
  import type * as Api from "../api.ts";
2
2
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
3
3
  import { frozenLexiconOf, ruleDocumentOf } from "./document-view.ts";
4
+ import { entriesForGenre } from "../lexicon-genres.ts";
4
5
  import { returnedFindings, type ShapeProblem } from "./returned-findings.ts";
5
6
 
6
7
  // A detector a team or a plugin wrote, run as one of chaff's. It reads the document through the plugin API, and what it
@@ -38,8 +39,12 @@ const messageOf = (error: unknown): string => {
38
39
  * What the detector returned, as findings, or how it failed. Reading the return can run the plugin's code too (a getter,
39
40
  * a Proxy), so it is checked inside the try. A Promise is a wrong return; its rejection must not end the run later.
40
41
  */
41
- const findingsOf = (detect: UntrustedDetector, doc: ProseDocument, options: Api.DetectorOptions): { findings: Finding[] } | { failure: RuleFailure } => {
42
- const view = ruleDocumentOf(doc);
42
+ const findingsOf = (
43
+ detect: UntrustedDetector,
44
+ view: Api.RuleDocument,
45
+ doc: ProseDocument,
46
+ options: Api.DetectorOptions,
47
+ ): { findings: Finding[] } | { failure: RuleFailure } => {
43
48
  try {
44
49
  const returned: unknown = detect(view, options);
45
50
  if (returned instanceof Promise) returned.catch(() => undefined);
@@ -54,8 +59,8 @@ const findingsOf = (detect: UntrustedDetector, doc: ProseDocument, options: Api.
54
59
  export const moduleDetector =
55
60
  (detect: UntrustedDetector, origin: string): Detector =>
56
61
  (doc, options): Finding[] => {
57
- const lexicon = options.lexicon === undefined ? undefined : frozenLexiconOf(options.lexicon);
58
- const outcome = findingsOf(detect, doc, Object.freeze({ lexicon }));
62
+ const lexicon = options.lexicon === undefined ? undefined : frozenLexiconOf(entriesForGenre(options.lexicon, options.genre));
63
+ const outcome = findingsOf(detect, ruleDocumentOf(doc, options.genre), doc, Object.freeze({ lexicon }));
59
64
  if ("failure" in outcome) throw new PluginRuleFailure(outcome.failure, origin);
60
65
  return outcome.findings;
61
66
  };
@@ -8,6 +8,7 @@ import { describeValue } from "./returned-findings.ts";
8
8
  import { isPluginName } from "./plugin-name.ts";
9
9
  import { knownGenres } from "../known-genres.ts";
10
10
  import { guideLayerOf, type GuideLayer, type GuideProblem } from "../genre-guide/layer.ts";
11
+ import { genresProblemOf, readGenres } from "./entry-genres.ts";
11
12
 
12
13
  // What a plugin package exports (api.ts PluginSpec), read into what chaff runs: its rules with ids under the plugin's
13
14
  // name, their detectors, its word lists and its house styles. A rule is read exactly like a rule in custom_rules, with
@@ -28,6 +29,7 @@ type PluginProblemKind =
28
29
  | "name-mismatch"
29
30
  | "no-detect"
30
31
  | "bad-lexicon"
32
+ | "bad-lexicon-genres"
31
33
  | "bad-style";
32
34
 
33
35
  /** plugin: as chaff.yaml writes it. detail: what was there instead, the name expected, the rule, list or style at fault. */
@@ -137,30 +139,46 @@ const rulesOf = (raw: unknown, context: RulesContext): Rules => {
137
139
 
138
140
  // ───────── word lists ─────────
139
141
 
140
- const lexiconEntryOf = (value: unknown): LexiconEntry | undefined => {
142
+ const lexiconEntryOf = (value: unknown, known: ReadonlySet<string>): LexiconEntry | undefined => {
141
143
  if (typeof value === "string") return value.trim() === "" ? undefined : { pattern: value.trim() };
142
144
  if (!isRecord(value) || typeof value["pattern"] !== "string" || value["pattern"].trim() === "") return undefined;
143
145
  const [insteadOf, rewrite] = [value["instead_of"], value["rewrite"]];
146
+ const genres = readGenres(value["genres"], known);
144
147
  return {
145
148
  pattern: value["pattern"].trim(),
146
149
  ...(typeof insteadOf === "string" && insteadOf.trim() !== "" ? { instead_of: insteadOf.trim() } : {}),
147
150
  ...(typeof rewrite === "string" && rewrite.trim() !== "" ? { rewrite: rewrite.trim() } : {}),
151
+ ...(genres === undefined ? {} : { genres }),
148
152
  };
149
153
  };
150
154
 
151
- const lexiconOf = (words: unknown): Lexicon | undefined => {
152
- const entries = Array.isArray(words) ? words.map(lexiconEntryOf) : [undefined];
155
+ const lexiconOf = (words: unknown, known: ReadonlySet<string>): Lexicon | undefined => {
156
+ const entries = Array.isArray(words) ? words.map((word: unknown) => lexiconEntryOf(word, known)) : [undefined];
153
157
  const readable = entries.flatMap((entry) => (entry === undefined ? [] : [entry]));
154
158
  // An empty list would leave its rules running and finding nothing, which reads as a clean document.
155
159
  return readable.length === entries.length && readable.length > 0 ? readable : undefined;
156
160
  };
157
161
 
162
+ /** An entry's genres that cannot be read, as its list, language and pattern with what is wrong. */
163
+ const entryGenresProblem = (list: string, language: string, word: unknown, known: ReadonlySet<string>): string[] => {
164
+ if (!isRecord(word) || word["genres"] === undefined) return [];
165
+ const wrong = genresProblemOf(word["genres"], known);
166
+ return wrong === undefined ? [] : [`${list} (${language}) ${printed(word["pattern"])}: ${wrong}`];
167
+ };
168
+
169
+ const genresProblemsOf = (list: string, raw: unknown, known: ReadonlySet<string>): string[] =>
170
+ isRecord(raw)
171
+ ? Object.entries(raw).flatMap(([language, words]) =>
172
+ (Array.isArray(words) ? words : []).flatMap((word: unknown) => entryGenresProblem(list, language, word, known)),
173
+ )
174
+ : [];
175
+
158
176
  type ListInLanguage = { readonly language: string; readonly list: string; readonly lexicon: Lexicon };
159
177
 
160
178
  /** One word list in each language it has. undefined when any part of it cannot be read. */
161
- const listOf = (list: string, raw: unknown): ListInLanguage[] | undefined => {
179
+ const listOf = (list: string, raw: unknown, known: ReadonlySet<string>): ListInLanguage[] | undefined => {
162
180
  if (!LOCAL_NAME.test(list) || !isRecord(raw)) return undefined;
163
- const read = Object.entries(raw).map(([language, words]) => ({ language, lexicon: lexiconOf(words) }));
181
+ const read = Object.entries(raw).map(([language, words]) => ({ language, lexicon: lexiconOf(words, known) }));
164
182
  const readable = read.flatMap(({ language, lexicon }) => (lexicon === undefined ? [] : [{ language, list, lexicon }]));
165
183
  return readable.length === read.length ? readable : undefined;
166
184
  };
@@ -178,12 +196,16 @@ const byLanguage = (lists: readonly ListInLanguage[], name: string): Record<stri
178
196
  const lexiconsOf = (raw: unknown, name: string, problem: Problem): Lexicons => {
179
197
  if (raw === undefined) return { lexicons: {}, lists: new Set(), problems: [] };
180
198
  if (!isRecord(raw)) return { lexicons: {}, lists: new Set(), problems: [problem("bad-lexicon", printed(raw))] };
181
- const read = Object.entries(raw).map(([list, words]) => ({ list, inLanguages: listOf(list, words) }));
199
+ const known = new Set(knownGenres());
200
+ const read = Object.entries(raw).map(([list, words]) => ({ list, words, inLanguages: listOf(list, words, known) }));
182
201
  const readable = read.flatMap((entry) => entry.inLanguages ?? []);
183
202
  return {
184
203
  lexicons: byLanguage(readable, name),
185
204
  lists: new Set(readable.map((entry) => entry.list)),
186
- problems: read.filter((entry) => entry.inLanguages === undefined).map((entry) => problem("bad-lexicon", entry.list)),
205
+ problems: [
206
+ ...read.filter((entry) => entry.inLanguages === undefined).map((entry) => problem("bad-lexicon", entry.list)),
207
+ ...read.flatMap((entry) => genresProblemsOf(entry.list, entry.words, known).map((detail) => problem("bad-lexicon-genres", detail))),
208
+ ],
187
209
  };
188
210
  };
189
211
 
@@ -64,6 +64,8 @@ const PLUGIN_TEXT: Texts<PluginText> = {
64
64
  "name-mismatch": (plugin, detail) => `plugins の ${plugin}: name は ${detail} にしてください(パッケージの名前から決まります)`,
65
65
  "no-detect": (plugin, detail) => `plugins の ${plugin}: ルール ${detail} に detect がありません`,
66
66
  "bad-lexicon": (plugin, detail) => `plugins の ${plugin}: 語彙表 ${detail} が読めません(名前: { ja: [語, …], en: [語, …] })`,
67
+ "bad-lexicon-genres": (plugin, detail) =>
68
+ `plugins の ${plugin}: 語彙表 ${detail} の genres が読めません。chaff の知っているジャンルかその組の並び([legal] や [blog/tech])で書いてください。npx chaffjs genres で一覧が出ます`,
67
69
  "bad-style": (plugin, detail) => `plugins の ${plugin}: スタイルが読めません(${detail})`,
68
70
  },
69
71
  },
@@ -87,6 +89,8 @@ const PLUGIN_TEXT: Texts<PluginText> = {
87
89
  "name-mismatch": (plugin, detail) => `plugins ${plugin}: its name must be ${detail}, which the package's name gives`,
88
90
  "no-detect": (plugin, detail) => `plugins ${plugin}: the rule ${detail} has no detect`,
89
91
  "bad-lexicon": (plugin, detail) => `plugins ${plugin}: cannot read the word list ${detail} (name: { ja: [word, …], en: [word, …] })`,
92
+ "bad-lexicon-genres": (plugin, detail) =>
93
+ `plugins ${plugin}: cannot read the genres of the word list entry ${detail}; write a list of genres or groups chaff knows ([legal], [blog/tech]). npx chaffjs genres lists them`,
90
94
  "bad-style": (plugin, detail) => `plugins ${plugin}: cannot read a style (${detail})`,
91
95
  },
92
96
  },
@@ -65,14 +65,36 @@ const endsWithMark = (source: string, value: FactValue, marks: readonly string[]
65
65
  const mayBeAge = (source: string, value: FactValue, after: readonly string[]): boolean =>
66
66
  value.kind === "quantity" && (value.unit === "" || endsWithMark(source, value, after) || after.some((mark) => folded(mark).startsWith(folded(value.unit))));
67
67
 
68
- /** 年齢の印まで延ばした値。印が無ければ marked は false(範囲の片方なら年齢として読む)。 */
68
+ const TABLE_ROW = /^[ \t]*\|/u;
69
+ const NOT_LETTER = /[^\p{L}\p{N}]+/u;
70
+
71
+ const lettersOf = (text: string): string[] =>
72
+ folded(text)
73
+ .split(NOT_LETTER)
74
+ .filter((word) => word !== "");
75
+
76
+ /** 語の並びの中に、印の語の並びがそのまま続いてあるか(満期 の 満 は印ではない)。 */
77
+ const hasWords = (words: readonly string[], mark: readonly string[]): boolean =>
78
+ mark.length > 0 && words.some((_, index) => mark.every((word, offset) => words[index + offset] === word));
79
+
80
+ /** 表の行の見出しの升(最初の升)に年齢の印の語があり、数がそのすぐ後ろの升にある(| Age at entry | 20 to 70 |)。 */
81
+ const underAgeHeading = (source: string, value: FactValue, words: AgeWords): boolean => {
82
+ const line = source.slice(source.lastIndexOf("\n", value.start - 1) + 1, value.start);
83
+ if (value.unit !== "" || !TABLE_ROW.test(line)) return false;
84
+ const [heading, ...before] = line.trim().slice(1).split("|");
85
+ if (heading === undefined || before.length !== 1) return false;
86
+ const headingWords = lettersOf(heading);
87
+ return words.marks.some((mark) => hasWords(headingWords, lettersOf(mark.pattern)));
88
+ };
89
+
90
+ /** 年齢の印まで延ばした値。印が無ければ marked は false(範囲の片方なら年齢として読む)。年齢を見出しにした表の行の数は、印が無くても年齢。 */
69
91
  const markedAge = (source: string, value: FactValue, words: AgeWords): Marked => {
70
92
  const after = at(words.marks, "after");
71
93
  const inside = endsWithMark(source, value, after);
72
94
  const end = inside ? value.end : wordAfter(source, value.end, after);
73
95
  const start = wordBefore(source, value.start, at(words.marks, "before"));
74
96
  const age: FactValue = { ...value, start: start ?? value.start, end: end ?? value.end, unit: "" };
75
- return { age, marked: inside || start !== undefined || end !== undefined };
97
+ return { age, marked: inside || start !== undefined || end !== undefined || underAgeHeading(source, value, words) };
76
98
  };
77
99
 
78
100
  /** 上限の印まで延ばした値。印があれば上の端。 */
@@ -0,0 +1,67 @@
1
+ import type { Span } from "../plugin.ts";
2
+ import { linesOf } from "../structure/lines.ts";
3
+ import { cellsOf, tablesOf } from "./table-facts.ts";
4
+ import { withoutEdgeMarks } from "./trim-marks.ts";
5
+
6
+ /**
7
+ * 表の升の値が、列の見出しで何の値か。単価の列(単価、Unit price、時給)の値は数量を掛けて金額になる値で、同じ行の見出しの金額の列
8
+ * (| りんご | 1,200円 |)とは別の量。見出しが単価の列の語(語彙表 unit-price-column)ならその group、group の無い語は UNIT_PRICE。
9
+ * 見出しが何あたりの句(/日、per day、1日あたり)を含めば、その単位。ほかの列の升は IN_FULL(そのままの値)。表の外の値は見出しを
10
+ * 持たないので、どの列の値とも比べる(文の「りんごは120円です」が単価か金額かは、読まないと分からない)。
11
+ */
12
+ export type HeadingUnit = { readonly pattern: string; readonly group: string };
13
+
14
+ export type HeadingUnitWords = {
15
+ /** 単価の列の見出し。見出しの全体がこの語のとき。 */
16
+ readonly headings: readonly HeadingUnit[];
17
+ /** 何あたりの句。見出しのどこかに、語の途中でなく書いたとき。 */
18
+ readonly phrases: readonly HeadingUnit[];
19
+ };
20
+
21
+ /** 単位を言わない単価の列(単価、Unit price)。二つの単価の列どうしは比べ、金額とは比べない。 */
22
+ export const UNIT_PRICE = "unit-price";
23
+
24
+ /** 見出しが何あたりとも言わない列(金額、Amount、料金)。 */
25
+ export const IN_FULL = "";
26
+
27
+ export type ColumnUnit = Span & { readonly column: string };
28
+
29
+ const LATIN = /[a-z0-9]/iu;
30
+
31
+ const folded = (text: string): string => text.normalize("NFKC").toLowerCase().replace(/\s+/gu, " ").trim();
32
+
33
+ /** 句が text のその位置で、英字の語の途中でない(per day は per days の頭、/h は /hr の頭ではない)。 */
34
+ const isWordAt = (text: string, phrase: string, at: number): boolean => {
35
+ const opensWord = LATIN.test(phrase.charAt(0)) && LATIN.test(text.charAt(at - 1));
36
+ const closesWord = LATIN.test(phrase.charAt(phrase.length - 1)) && LATIN.test(text.charAt(at + phrase.length));
37
+ return !opensWord && !closesWord;
38
+ };
39
+
40
+ const occurrences = (text: string, phrase: string, from = 0): number[] => {
41
+ const at = phrase === "" ? -1 : text.indexOf(phrase, from);
42
+ return at === -1 ? [] : [at, ...occurrences(text, phrase, at + 1)];
43
+ };
44
+
45
+ const standsIn = (text: string, phrase: string): boolean => occurrences(text, phrase).some((at) => isWordAt(text, phrase, at));
46
+
47
+ const longest = (phrases: readonly HeadingUnit[]): HeadingUnit | undefined =>
48
+ phrases.reduce<HeadingUnit | undefined>((best, phrase) => (best === undefined || phrase.pattern.length > best.pattern.length ? phrase : best), undefined);
49
+
50
+ /** 見出しの言う単位。見出しが単価の列の語ならその group。でなければ見出しに書いた句の単位(二つ当たれば長い句)。どちらも無ければ IN_FULL。 */
51
+ export const headingPerUnit = (heading: string, words: HeadingUnitWords): string => {
52
+ const text = folded(withoutEdgeMarks(heading));
53
+ if (text === "") return IN_FULL;
54
+ const named = words.headings.find((word) => folded(word.pattern) === text);
55
+ return named?.group ?? longest(words.phrases.filter((phrase) => standsIn(text, folded(phrase.pattern))))?.group ?? IN_FULL;
56
+ };
57
+
58
+ /** 文書の表すべての本体の升と、その列の見出しの単位。 */
59
+ export const columnUnits = (source: string, words: HeadingUnitWords): ColumnUnit[] =>
60
+ tablesOf(linesOf(source)).flatMap((table) => {
61
+ const units = cellsOf(table.header).map((cell) => headingPerUnit(cell.text, words));
62
+ return table.rows.flatMap((row) => cellsOf(row).map((cell, index): ColumnUnit => ({ start: cell.start, end: cell.end, column: units[index] ?? IN_FULL })));
63
+ });
64
+
65
+ /** 値のある升の列の単位。表の外の値は undefined。 */
66
+ export const columnUnitAt = (columns: readonly ColumnUnit[], value: Span): string | undefined =>
67
+ columns.find((column) => value.start >= column.start && value.end <= column.end)?.column;
@@ -118,20 +118,69 @@ const headCount = (heads: ReadonlyMap<string, readonly number[]>, from: number,
118
118
 
119
119
  type Lines = { readonly lines: readonly Line[]; readonly breakers: readonly number[]; readonly heads: ReadonlyMap<string, readonly number[]> };
120
120
 
121
- const scopeOf = (fact: Fact, innermost: StructureNode | undefined, at: Lines): { scope: string; record: boolean } => {
121
+ /** 表の、見出しを繰り返した何番目の並びの升か(table-facts の columnGroup)。並びごとに別の範囲。 */
122
+ type PlacedFact = Fact & { readonly columnGroup?: number };
123
+
124
+ const scopeOf = (fact: PlacedFact, innermost: StructureNode | undefined, at: Lines): { scope: string; record: boolean } => {
122
125
  const index = lineIndexAt(at.lines, fact.value.start);
123
126
  const from = innermost === undefined ? 0 : lineIndexAt(at.lines, innermost.span.start);
124
127
  const to = innermost === undefined ? at.lines.length : lineIndexAt(at.lines, innermost.span.end - 1) + 1;
125
- const scope = [innermost?.address ?? "doc", (at.breakers[index] ?? 0) - (at.breakers[from] ?? 0), parentItem(at.lines, index)].join("#");
128
+ const place = [innermost?.address ?? "doc", (at.breakers[index] ?? 0) - (at.breakers[from] ?? 0), parentItem(at.lines, index)];
129
+ const scope = [...place, ...(fact.columnGroup === undefined ? [] : [`g${fact.columnGroup}`])].join("#");
126
130
  return { scope, record: headCount(at.heads, from, to, fact.key) >= RECORD_REPEATS };
127
131
  };
128
132
 
133
+ const MAX_PARAGRAPH_HEAD = 40;
134
+ /** 文の終わりか続きの印。これで終わる行は小見出しではない。 */
135
+ const SENTENCE_END = /[.!?。.!?::;;,、,]$/u;
136
+ const NOT_PLAIN_LINE = /^[ \t]*(?:[#>|]|```|~~~)/u;
137
+ /** setext の見出しの下線。上の行は見出しで、節として木が分ける。 */
138
+ const SETEXT_UNDERLINE = /^[ \t]*(?:=+|-+)[ \t]*$/u;
139
+
140
+ /**
141
+ * 段落の頭の、短い名前だけの行(「Example」「Element 1 (standard rated portion)」「例」)。文の終わりの印も値も無く、項目や表の行でもない。
142
+ * 例や場合ごとに名前を付けた段落の頭で、続く値はその例の値。
143
+ */
144
+ const isNameOnly = (line: string): boolean => {
145
+ const text = line.trim();
146
+ if (text === "" || text.length > MAX_PARAGRAPH_HEAD) return false;
147
+ return /\p{L}/u.test(text) && !SENTENCE_END.test(text) && !LIST_ITEM.test(line) && !NOT_PLAIN_LINE.test(line);
148
+ };
149
+
150
+ const isParagraphHead = (lines: readonly Line[], index: number, valueLines: ReadonlySet<number>): boolean => {
151
+ const startsParagraph = (lines[index - 1]?.text.trim() ?? "") === "";
152
+ const isSetextHeading = SETEXT_UNDERLINE.test(lines[index + 1]?.text ?? "");
153
+ return startsParagraph && !isSetextHeading && !valueLines.has(index) && isNameOnly(lines[index]?.text ?? "");
154
+ };
155
+
156
+ /** 小見出しの代わりの行の数に、段落の頭の名前だけの行も数える。 */
157
+ const withParagraphHeads = (lines: readonly Line[], facts: readonly Fact[]): number[] => {
158
+ const valueLines = new Set(facts.map((fact) => lineIndexAt(lines, fact.value.start)));
159
+ return lines.reduce<number[]>(
160
+ (counts, line, index) => {
161
+ counts.push((counts[index] ?? 0) + (isBreaker(line) || isParagraphHead(lines, index, valueLines) ? 1 : 0));
162
+ return counts;
163
+ },
164
+ [0],
165
+ );
166
+ };
167
+
168
+ /** paragraphHeads: 段落の頭の名前だけの行(Example、例)でも範囲を分ける。 */
169
+ export type ScopeReading = { readonly paragraphHeads?: boolean };
170
+
129
171
  /** 事実ごとに、比べてよい範囲と、文書のどの部分かを付ける。 */
130
- export const scopedFacts = (facts: readonly Fact[], tree: StructureNode, source: string, summaryWords: readonly string[]): ScopedFact[] => {
172
+ export const scopedFacts = (
173
+ facts: readonly PlacedFact[],
174
+ tree: StructureNode,
175
+ source: string,
176
+ summaryWords: readonly string[],
177
+ reading: ScopeReading = {},
178
+ ): ScopedFact[] => {
131
179
  if (facts.length === 0) return [];
132
180
  const nodes = inDocumentOrder(tree).filter((node) => CONTAINERS.has(node.kind));
133
181
  const lines = linesOf(source);
134
- const at: Lines = { lines, breakers: breakerCounts(lines), heads: headLines(lines) };
182
+ const breakers = reading.paragraphHeads === true ? withParagraphHeads(lines, facts) : breakerCounts(lines);
183
+ const at: Lines = { lines, breakers, heads: headLines(lines) };
135
184
  return facts
136
185
  .toSorted((left, right) => left.value.start - right.value.start)
137
186
  .map((fact) => {
@@ -12,6 +12,8 @@ export type ValueKind = "quantity" | "date" | "name";
12
12
  /**
13
13
  * bound: upper なら key は上の端(満70歳まで、20 to 70 の 70)。lower は範囲の下の端(満20歳〜満70歳 の 20)。
14
14
  * basis: 率に書いた基準(period:year、kind:fixed)。両方に書いた同じ種類の基準が違えば、別の量として比べない。
15
+ * per: 何あたりの値か(1kmあたり15円 の km、per-unit.ts)。何あたりかの違う値、片方だけ何あたりの値は比べない。
16
+ * column: 表の升の値の、列の見出しの単位(単価の列、column-units.ts)。どちらも表の升で、列の単位が違えば比べない。
15
17
  */
16
18
  export type FactValue = Span & {
17
19
  readonly kind: ValueKind;
@@ -20,6 +22,8 @@ export type FactValue = Span & {
20
22
  readonly bound?: "upper";
21
23
  readonly lower?: string;
22
24
  readonly basis?: RateBasis;
25
+ readonly per?: string;
26
+ readonly column?: string;
23
27
  };
24
28
 
25
29
  const attr = (node: StructureNode, name: string): string => String(node.attrs[name] ?? "");
@@ -124,10 +128,16 @@ const comparableDates = (left: string, right: string): [string, string] | undefi
124
128
  const comparableBounds = (left: FactValue, right: FactValue): boolean =>
125
129
  (left.lower === undefined || right.bound === "upper") && (right.lower === undefined || left.bound === "upper");
126
130
 
131
+ /** 表の外の値は列を持たないので、どの列の値とも比べる。二つの升は、列の見出しの単位が同じときだけ(単価と金額は別の量)。 */
132
+ const sameColumn = (left: FactValue, right: FactValue): boolean => left.column === undefined || right.column === undefined || left.column === right.column;
133
+
127
134
  /** 同じ種類の値で、比べられるもの。数量は同じ単位どうし(単位の違いは別の rule が見る)。 */
128
135
  export const comparable = (left: FactValue, right: FactValue): boolean => {
129
136
  if (left.kind !== right.kind) return false;
130
- if (left.kind === "quantity") return left.unit === right.unit && comparableBounds(left, right) && basesAgree(left.basis, right.basis);
137
+ if (left.kind === "quantity")
138
+ return (
139
+ left.unit === right.unit && left.per === right.per && sameColumn(left, right) && comparableBounds(left, right) && basesAgree(left.basis, right.basis)
140
+ );
131
141
  return left.kind !== "date" || comparableDates(left.key, right.key) !== undefined;
132
142
  };
133
143
 
@@ -10,7 +10,14 @@ import { isRate, joinsNextClause, rateHead, rateTail, type RateBasis, type RateW
10
10
  * 「$300 per person」)、条件の付いた値なので読まない。読点のあとから始まる名前(「大人は、」「For adults, the fee」)も、
11
11
  * 前に条件があるので読まない。言語の知識(区切り、値の終わり、落とす冠詞)は言語パッケージの語彙表から取る。
12
12
  */
13
- export type AttributePhrase = { readonly pattern: string; readonly position: "before" | "after" };
13
+ /** clause: 主語から書いた節(you can apply)。前に読点があれば、読点の前の句は条件(For the basic plan, you can apply)。 */
14
+ export type AttributePhrase = { readonly pattern: string; readonly position: "before" | "after"; readonly clause?: boolean };
15
+
16
+ type AttributeEntry = { readonly pattern: string; readonly group?: string | undefined; readonly position?: "before" | "after" | undefined };
17
+
18
+ /** 語彙表の言い回し。group が clause なら主語から書いた節。 */
19
+ export const attributePhrasesOf = (entries: readonly AttributeEntry[]): AttributePhrase[] =>
20
+ entries.map((entry) => ({ pattern: entry.pattern, position: entry.position ?? "before", clause: entry.group === "clause" }));
14
21
 
15
22
  export type FactWords = {
16
23
  /** 名前と値の区切り(:、は、is)。英字だけの区切りは、前が空白のときだけ。 */
@@ -173,6 +180,9 @@ const labelledFact = (source: string, read: FactValue, words: FactWords): Fact |
173
180
  return undefined;
174
181
  };
175
182
 
183
+ /** 前に置いた言い回しの前に、同じ文の読点がある(For the basic plan, you can apply)。読点の前の句は条件。 */
184
+ const afterCondition = (head: string, phrase: string): boolean => CLAUSE_COMMA.test(afterLastBreak(head.slice(0, head.length - phrase.length)));
185
+
176
186
  /** 属性の言い回しのすぐ前か後ろの値。名前は言い回しそのもの。 */
177
187
  const attributeFact = (source: string, value: FactValue, words: FactWords): Fact | undefined => {
178
188
  const head = trimEndOf(source.slice(lineStartOf(source, value.start), value.start), EDGE_MARKS).toLowerCase();
@@ -183,7 +193,11 @@ const attributeFact = (source: string, value: FactValue, words: FactWords): Fact
183
193
  const found = words.attributes.find((phrase) =>
184
194
  phrase.position === "before" ? head.endsWith(phrase.pattern.toLowerCase()) : tail.startsWith(phrase.pattern.toLowerCase()),
185
195
  );
186
- if (found === undefined || (found.position === "before" && !endsAfter(source, value, words))) return undefined;
196
+ if (
197
+ found === undefined ||
198
+ (found.position === "before" && (!endsAfter(source, value, words) || (found.clause === true && afterCondition(head, found.pattern))))
199
+ )
200
+ return undefined;
187
201
  return { label: found.pattern, key: keyOf(found.pattern, words), value };
188
202
  };
189
203