chaffjs 0.32.0 → 0.34.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 (535) hide show
  1. package/README.md +7 -0
  2. package/dist/api.d.ts +7 -1
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js.map +1 -1
  5. package/dist/cli-text.d.ts.map +1 -1
  6. package/dist/cli-text.js +6 -4
  7. package/dist/cli-text.js.map +1 -1
  8. package/dist/commands/grade.d.ts.map +1 -1
  9. package/dist/commands/grade.js +66 -21
  10. package/dist/commands/grade.js.map +1 -1
  11. package/dist/company-kana-spelling.d.ts +6 -1
  12. package/dist/company-kana-spelling.d.ts.map +1 -1
  13. package/dist/company-kana-spelling.js +19 -2
  14. package/dist/company-kana-spelling.js.map +1 -1
  15. package/dist/company-name-ending.d.ts +7 -0
  16. package/dist/company-name-ending.d.ts.map +1 -0
  17. package/dist/company-name-ending.js +44 -0
  18. package/dist/company-name-ending.js.map +1 -0
  19. package/dist/company-names.d.ts +11 -3
  20. package/dist/company-names.d.ts.map +1 -1
  21. package/dist/company-names.js +27 -14
  22. package/dist/company-names.js.map +1 -1
  23. package/dist/cross-run.d.ts.map +1 -1
  24. package/dist/cross-run.js +1 -0
  25. package/dist/cross-run.js.map +1 -1
  26. package/dist/custom/no-rewrite.d.ts +3 -0
  27. package/dist/custom/no-rewrite.d.ts.map +1 -0
  28. package/dist/custom/no-rewrite.js +3 -0
  29. package/dist/custom/no-rewrite.js.map +1 -0
  30. package/dist/custom/parse.d.ts.map +1 -1
  31. package/dist/custom/parse.js +14 -2
  32. package/dist/custom/parse.js.map +1 -1
  33. package/dist/detectors/age-words.d.ts +5 -0
  34. package/dist/detectors/age-words.d.ts.map +1 -0
  35. package/dist/detectors/age-words.js +8 -0
  36. package/dist/detectors/age-words.js.map +1 -0
  37. package/dist/detectors/agreement-slip.d.ts.map +1 -1
  38. package/dist/detectors/agreement-slip.js +4 -0
  39. package/dist/detectors/agreement-slip.js.map +1 -1
  40. package/dist/detectors/annual-pay-mismatch.d.ts.map +1 -1
  41. package/dist/detectors/annual-pay-mismatch.js +2 -12
  42. package/dist/detectors/annual-pay-mismatch.js.map +1 -1
  43. package/dist/detectors/blank-structure.d.ts.map +1 -1
  44. package/dist/detectors/blank-structure.js +4 -3
  45. package/dist/detectors/blank-structure.js.map +1 -1
  46. package/dist/detectors/closing-balance-mismatch.d.ts.map +1 -1
  47. package/dist/detectors/closing-balance-mismatch.js +1 -0
  48. package/dist/detectors/closing-balance-mismatch.js.map +1 -1
  49. package/dist/detectors/code-fences.d.ts +5 -0
  50. package/dist/detectors/code-fences.d.ts.map +1 -1
  51. package/dist/detectors/code-fences.js +9 -0
  52. package/dist/detectors/code-fences.js.map +1 -1
  53. package/dist/detectors/condition-toki.d.ts +16 -0
  54. package/dist/detectors/condition-toki.d.ts.map +1 -0
  55. package/dist/detectors/condition-toki.js +42 -0
  56. package/dist/detectors/condition-toki.js.map +1 -0
  57. package/dist/detectors/conjugated-entry.d.ts +17 -0
  58. package/dist/detectors/conjugated-entry.d.ts.map +1 -0
  59. package/dist/detectors/conjugated-entry.js +50 -0
  60. package/dist/detectors/conjugated-entry.js.map +1 -0
  61. package/dist/detectors/content-morphemes.d.ts +2 -0
  62. package/dist/detectors/content-morphemes.d.ts.map +1 -1
  63. package/dist/detectors/content-morphemes.js +1 -1
  64. package/dist/detectors/content-morphemes.js.map +1 -1
  65. package/dist/detectors/cross-facts.d.ts.map +1 -1
  66. package/dist/detectors/cross-facts.js +2 -1
  67. package/dist/detectors/cross-facts.js.map +1 -1
  68. package/dist/detectors/custom.d.ts.map +1 -1
  69. package/dist/detectors/custom.js +8 -2
  70. package/dist/detectors/custom.js.map +1 -1
  71. package/dist/detectors/document-shape.d.ts.map +1 -1
  72. package/dist/detectors/document-shape.js +6 -0
  73. package/dist/detectors/document-shape.js.map +1 -1
  74. package/dist/detectors/due-date.d.ts.map +1 -1
  75. package/dist/detectors/due-date.js +12 -2
  76. package/dist/detectors/due-date.js.map +1 -1
  77. package/dist/detectors/fact-consistency.d.ts.map +1 -1
  78. package/dist/detectors/fact-consistency.js +12 -13
  79. package/dist/detectors/fact-consistency.js.map +1 -1
  80. package/dist/detectors/form-line.d.ts +9 -0
  81. package/dist/detectors/form-line.d.ts.map +1 -0
  82. package/dist/detectors/form-line.js +36 -0
  83. package/dist/detectors/form-line.js.map +1 -0
  84. package/dist/detectors/formula-amount.d.ts +3 -0
  85. package/dist/detectors/formula-amount.d.ts.map +1 -0
  86. package/dist/detectors/formula-amount.js +31 -0
  87. package/dist/detectors/formula-amount.js.map +1 -0
  88. package/dist/detectors/heading-claim.d.ts +14 -0
  89. package/dist/detectors/heading-claim.d.ts.map +1 -0
  90. package/dist/detectors/heading-claim.js +49 -0
  91. package/dist/detectors/heading-claim.js.map +1 -0
  92. package/dist/detectors/heading-echo.d.ts.map +1 -1
  93. package/dist/detectors/heading-echo.js +29 -1
  94. package/dist/detectors/heading-echo.js.map +1 -1
  95. package/dist/detectors/installment-total-mismatch.d.ts.map +1 -1
  96. package/dist/detectors/installment-total-mismatch.js +28 -19
  97. package/dist/detectors/installment-total-mismatch.js.map +1 -1
  98. package/dist/detectors/list-parallel.d.ts +5 -2
  99. package/dist/detectors/list-parallel.d.ts.map +1 -1
  100. package/dist/detectors/list-parallel.js +45 -7
  101. package/dist/detectors/list-parallel.js.map +1 -1
  102. package/dist/detectors/name-variant.d.ts.map +1 -1
  103. package/dist/detectors/name-variant.js +34 -7
  104. package/dist/detectors/name-variant.js.map +1 -1
  105. package/dist/detectors/number-unit.d.ts +10 -0
  106. package/dist/detectors/number-unit.d.ts.map +1 -1
  107. package/dist/detectors/number-unit.js +28 -8
  108. package/dist/detectors/number-unit.js.map +1 -1
  109. package/dist/detectors/orthographic-variant.d.ts.map +1 -1
  110. package/dist/detectors/orthographic-variant.js +4 -3
  111. package/dist/detectors/orthographic-variant.js.map +1 -1
  112. package/dist/detectors/orthography.d.ts.map +1 -1
  113. package/dist/detectors/orthography.js +16 -7
  114. package/dist/detectors/orthography.js.map +1 -1
  115. package/dist/detectors/per-unit-words.d.ts +7 -0
  116. package/dist/detectors/per-unit-words.d.ts.map +1 -0
  117. package/dist/detectors/per-unit-words.js +17 -0
  118. package/dist/detectors/per-unit-words.js.map +1 -0
  119. package/dist/detectors/period-multiple-mismatch.d.ts.map +1 -1
  120. package/dist/detectors/period-multiple-mismatch.js +2 -12
  121. package/dist/detectors/period-multiple-mismatch.js.map +1 -1
  122. package/dist/detectors/reference-number-variant.d.ts.map +1 -1
  123. package/dist/detectors/reference-number-variant.js +21 -3
  124. package/dist/detectors/reference-number-variant.js.map +1 -1
  125. package/dist/detectors/registry/condition-toki.d.ts +3 -0
  126. package/dist/detectors/registry/condition-toki.d.ts.map +1 -0
  127. package/dist/detectors/registry/condition-toki.js +3 -0
  128. package/dist/detectors/registry/condition-toki.js.map +1 -0
  129. package/dist/detectors/registry/formula-amount.d.ts +3 -0
  130. package/dist/detectors/registry/formula-amount.d.ts.map +1 -0
  131. package/dist/detectors/registry/formula-amount.js +3 -0
  132. package/dist/detectors/registry/formula-amount.js.map +1 -0
  133. package/dist/detectors/rent-multiple-mismatch.d.ts.map +1 -1
  134. package/dist/detectors/rent-multiple-mismatch.js +2 -12
  135. package/dist/detectors/rent-multiple-mismatch.js.map +1 -1
  136. package/dist/detectors/row-sentence-amounts.d.ts.map +1 -1
  137. package/dist/detectors/row-sentence-amounts.js +5 -10
  138. package/dist/detectors/row-sentence-amounts.js.map +1 -1
  139. package/dist/detectors/stated-amounts.d.ts +4 -0
  140. package/dist/detectors/stated-amounts.d.ts.map +1 -0
  141. package/dist/detectors/stated-amounts.js +12 -0
  142. package/dist/detectors/stated-amounts.js.map +1 -0
  143. package/dist/detectors/step-time-sum.d.ts.map +1 -1
  144. package/dist/detectors/step-time-sum.js +2 -1
  145. package/dist/detectors/step-time-sum.js.map +1 -1
  146. package/dist/detectors/structure-tree.d.ts +1 -1
  147. package/dist/detectors/structure-tree.d.ts.map +1 -1
  148. package/dist/detectors/structure-tree.js +7 -2
  149. package/dist/detectors/structure-tree.js.map +1 -1
  150. package/dist/detectors/team.d.ts.map +1 -1
  151. package/dist/detectors/team.js +10 -6
  152. package/dist/detectors/team.js.map +1 -1
  153. package/dist/detectors/time-order.d.ts.map +1 -1
  154. package/dist/detectors/time-order.js +17 -13
  155. package/dist/detectors/time-order.js.map +1 -1
  156. package/dist/detectors/unknown-word.d.ts +4 -1
  157. package/dist/detectors/unknown-word.d.ts.map +1 -1
  158. package/dist/detectors/unknown-word.js +18 -2
  159. package/dist/detectors/unknown-word.js.map +1 -1
  160. package/dist/detectors/use-interval.d.ts +1 -0
  161. package/dist/detectors/use-interval.d.ts.map +1 -1
  162. package/dist/detectors/use-interval.js +15 -10
  163. package/dist/detectors/use-interval.js.map +1 -1
  164. package/dist/detectors/use-maximum.d.ts.map +1 -1
  165. package/dist/detectors/use-maximum.js +3 -1
  166. package/dist/detectors/use-maximum.js.map +1 -1
  167. package/dist/eval.js +3 -3
  168. package/dist/eval.js.map +1 -1
  169. package/dist/extension/document-view.d.ts +2 -2
  170. package/dist/extension/document-view.d.ts.map +1 -1
  171. package/dist/extension/document-view.js +17 -8
  172. package/dist/extension/document-view.js.map +1 -1
  173. package/dist/extension/entry-genres.d.ts +5 -0
  174. package/dist/extension/entry-genres.d.ts.map +1 -0
  175. package/dist/extension/entry-genres.js +13 -0
  176. package/dist/extension/entry-genres.js.map +1 -0
  177. package/dist/extension/module-detector.d.ts.map +1 -1
  178. package/dist/extension/module-detector.js +4 -4
  179. package/dist/extension/module-detector.js.map +1 -1
  180. package/dist/extension/plugin-parse.d.ts +1 -1
  181. package/dist/extension/plugin-parse.d.ts.map +1 -1
  182. package/dist/extension/plugin-parse.js +24 -7
  183. package/dist/extension/plugin-parse.js.map +1 -1
  184. package/dist/extension/problem-text.d.ts.map +1 -1
  185. package/dist/extension/problem-text.js +2 -0
  186. package/dist/extension/problem-text.js.map +1 -1
  187. package/dist/facts/age-values.d.ts.map +1 -1
  188. package/dist/facts/age-values.js +20 -2
  189. package/dist/facts/age-values.js.map +1 -1
  190. package/dist/facts/column-units.d.ts +31 -0
  191. package/dist/facts/column-units.d.ts.map +1 -0
  192. package/dist/facts/column-units.js +37 -0
  193. package/dist/facts/column-units.js.map +1 -0
  194. package/dist/facts/fact-values.d.ts +4 -0
  195. package/dist/facts/fact-values.d.ts.map +1 -1
  196. package/dist/facts/fact-values.js +3 -1
  197. package/dist/facts/fact-values.js.map +1 -1
  198. package/dist/facts/labelled-facts.d.ts +10 -0
  199. package/dist/facts/labelled-facts.d.ts.map +1 -1
  200. package/dist/facts/labelled-facts.js +6 -1
  201. package/dist/facts/labelled-facts.js.map +1 -1
  202. package/dist/facts/per-unit.d.ts +36 -0
  203. package/dist/facts/per-unit.d.ts.map +1 -0
  204. package/dist/facts/per-unit.js +56 -0
  205. package/dist/facts/per-unit.js.map +1 -0
  206. package/dist/facts/row-sentence-amounts.d.ts +3 -12
  207. package/dist/facts/row-sentence-amounts.d.ts.map +1 -1
  208. package/dist/facts/row-sentence-amounts.js +1 -15
  209. package/dist/facts/row-sentence-amounts.js.map +1 -1
  210. package/dist/facts/table-facts.d.ts +1 -1
  211. package/dist/facts/table-facts.d.ts.map +1 -1
  212. package/dist/facts/table-facts.js +13 -9
  213. package/dist/facts/table-facts.js.map +1 -1
  214. package/dist/facts/term-values.d.ts +13 -1
  215. package/dist/facts/term-values.d.ts.map +1 -1
  216. package/dist/facts/term-values.js +71 -12
  217. package/dist/facts/term-values.js.map +1 -1
  218. package/dist/fix-plan/text.js +2 -2
  219. package/dist/fix-plan/text.js.map +1 -1
  220. package/dist/grade/baseline.d.ts +4 -2
  221. package/dist/grade/baseline.d.ts.map +1 -1
  222. package/dist/grade/baseline.js +13 -11
  223. package/dist/grade/baseline.js.map +1 -1
  224. package/dist/grade/expect-read.d.ts +16 -0
  225. package/dist/grade/expect-read.d.ts.map +1 -0
  226. package/dist/grade/expect-read.js +52 -0
  227. package/dist/grade/expect-read.js.map +1 -0
  228. package/dist/grade/expect.d.ts +50 -0
  229. package/dist/grade/expect.d.ts.map +1 -0
  230. package/dist/grade/expect.js +53 -0
  231. package/dist/grade/expect.js.map +1 -0
  232. package/dist/grade/grade-item.d.ts +1 -1
  233. package/dist/grade/grade-item.d.ts.map +1 -1
  234. package/dist/grade/grade-item.js +13 -3
  235. package/dist/grade/grade-item.js.map +1 -1
  236. package/dist/grade/item.d.ts +9 -1
  237. package/dist/grade/item.d.ts.map +1 -1
  238. package/dist/grade/item.js +32 -7
  239. package/dist/grade/item.js.map +1 -1
  240. package/dist/grade/result.d.ts +5 -0
  241. package/dist/grade/result.d.ts.map +1 -1
  242. package/dist/grade/results-read.d.ts.map +1 -1
  243. package/dist/grade/results-read.js +4 -2
  244. package/dist/grade/results-read.js.map +1 -1
  245. package/dist/grade/rubric-file.d.ts +23 -0
  246. package/dist/grade/rubric-file.d.ts.map +1 -0
  247. package/dist/grade/rubric-file.js +35 -0
  248. package/dist/grade/rubric-file.js.map +1 -0
  249. package/dist/grade/rubric.d.ts +2 -0
  250. package/dist/grade/rubric.d.ts.map +1 -1
  251. package/dist/grade/rubric.js +75 -47
  252. package/dist/grade/rubric.js.map +1 -1
  253. package/dist/grade/setup.d.ts +2 -1
  254. package/dist/grade/setup.d.ts.map +1 -1
  255. package/dist/grade/setup.js +2 -2
  256. package/dist/grade/setup.js.map +1 -1
  257. package/dist/grade/stamp.d.ts +2 -0
  258. package/dist/grade/stamp.d.ts.map +1 -1
  259. package/dist/grade/stamp.js +8 -2
  260. package/dist/grade/stamp.js.map +1 -1
  261. package/dist/grade/task-rubric.d.ts +16 -0
  262. package/dist/grade/task-rubric.d.ts.map +1 -0
  263. package/dist/grade/task-rubric.js +34 -0
  264. package/dist/grade/task-rubric.js.map +1 -0
  265. package/dist/grade/text.d.ts +5 -1
  266. package/dist/grade/text.d.ts.map +1 -1
  267. package/dist/grade/text.js +16 -4
  268. package/dist/grade/text.js.map +1 -1
  269. package/dist/lexicon-genres.d.ts +7 -0
  270. package/dist/lexicon-genres.d.ts.map +1 -0
  271. package/dist/lexicon-genres.js +8 -0
  272. package/dist/lexicon-genres.js.map +1 -0
  273. package/dist/name-char-reading.d.ts +5 -0
  274. package/dist/name-char-reading.d.ts.map +1 -1
  275. package/dist/name-char-reading.js +15 -0
  276. package/dist/name-char-reading.js.map +1 -1
  277. package/dist/name-end-letter.d.ts +19 -0
  278. package/dist/name-end-letter.d.ts.map +1 -0
  279. package/dist/name-end-letter.js +37 -0
  280. package/dist/name-end-letter.js.map +1 -0
  281. package/dist/name-neighbours.d.ts.map +1 -1
  282. package/dist/name-neighbours.js +2 -1
  283. package/dist/name-neighbours.js.map +1 -1
  284. package/dist/name-separator.d.ts +6 -0
  285. package/dist/name-separator.d.ts.map +1 -1
  286. package/dist/name-separator.js +29 -0
  287. package/dist/name-separator.js.map +1 -1
  288. package/dist/name-variants.d.ts +6 -3
  289. package/dist/name-variants.d.ts.map +1 -1
  290. package/dist/name-variants.js +37 -10
  291. package/dist/name-variants.js.map +1 -1
  292. package/dist/number-name.d.ts.map +1 -1
  293. package/dist/number-name.js +11 -2
  294. package/dist/number-name.js.map +1 -1
  295. package/dist/plugin.d.ts +6 -0
  296. package/dist/plugin.d.ts.map +1 -1
  297. package/dist/profile/cue-lines.d.ts +6 -0
  298. package/dist/profile/cue-lines.d.ts.map +1 -0
  299. package/dist/profile/cue-lines.js +13 -0
  300. package/dist/profile/cue-lines.js.map +1 -0
  301. package/dist/profile/parse.d.ts +1 -1
  302. package/dist/profile/parse.d.ts.map +1 -1
  303. package/dist/profile/parse.js +8 -2
  304. package/dist/profile/parse.js.map +1 -1
  305. package/dist/reference-numbers.d.ts +2 -0
  306. package/dist/reference-numbers.d.ts.map +1 -1
  307. package/dist/reference-numbers.js +1 -1
  308. package/dist/reference-numbers.js.map +1 -1
  309. package/dist/run.d.ts.map +1 -1
  310. package/dist/run.js +1 -0
  311. package/dist/run.js.map +1 -1
  312. package/dist/spaced-person-name.d.ts.map +1 -1
  313. package/dist/spaced-person-name.js +26 -1
  314. package/dist/spaced-person-name.js.map +1 -1
  315. package/dist/spacing-code.d.ts.map +1 -1
  316. package/dist/spacing-code.js +10 -1
  317. package/dist/spacing-code.js.map +1 -1
  318. package/dist/spacing-minority.d.ts +7 -0
  319. package/dist/spacing-minority.d.ts.map +1 -1
  320. package/dist/spacing-minority.js +14 -0
  321. package/dist/spacing-minority.js.map +1 -1
  322. package/dist/structure/closing-balance.d.ts +9 -0
  323. package/dist/structure/closing-balance.d.ts.map +1 -1
  324. package/dist/structure/closing-balance.js +34 -7
  325. package/dist/structure/closing-balance.js.map +1 -1
  326. package/dist/structure/date-range.d.ts +3 -2
  327. package/dist/structure/date-range.d.ts.map +1 -1
  328. package/dist/structure/date-range.js +4 -4
  329. package/dist/structure/date-range.js.map +1 -1
  330. package/dist/structure/definition-use.d.ts.map +1 -1
  331. package/dist/structure/definition-use.js +20 -1
  332. package/dist/structure/definition-use.js.map +1 -1
  333. package/dist/structure/document-context.d.ts +2 -0
  334. package/dist/structure/document-context.d.ts.map +1 -0
  335. package/dist/structure/document-context.js +42 -0
  336. package/dist/structure/document-context.js.map +1 -0
  337. package/dist/structure/fenced-lines.d.ts +7 -0
  338. package/dist/structure/fenced-lines.d.ts.map +1 -0
  339. package/dist/structure/fenced-lines.js +27 -0
  340. package/dist/structure/fenced-lines.js.map +1 -0
  341. package/dist/structure/formula-amount.d.ts +38 -0
  342. package/dist/structure/formula-amount.d.ts.map +1 -0
  343. package/dist/structure/formula-amount.js +187 -0
  344. package/dist/structure/formula-amount.js.map +1 -0
  345. package/dist/structure/installment-fee.d.ts +52 -0
  346. package/dist/structure/installment-fee.d.ts.map +1 -0
  347. package/dist/structure/installment-fee.js +110 -0
  348. package/dist/structure/installment-fee.js.map +1 -0
  349. package/dist/structure/installment-total.d.ts +7 -0
  350. package/dist/structure/installment-total.d.ts.map +1 -1
  351. package/dist/structure/installment-total.js +6 -6
  352. package/dist/structure/installment-total.js.map +1 -1
  353. package/dist/structure/labelled-date-order.d.ts +31 -9
  354. package/dist/structure/labelled-date-order.d.ts.map +1 -1
  355. package/dist/structure/labelled-date-order.js +60 -15
  356. package/dist/structure/labelled-date-order.js.map +1 -1
  357. package/dist/structure/labelled-order.d.ts +7 -1
  358. package/dist/structure/labelled-order.d.ts.map +1 -1
  359. package/dist/structure/labelled-order.js +10 -3
  360. package/dist/structure/labelled-order.js.map +1 -1
  361. package/dist/structure/line-amount-label.d.ts.map +1 -1
  362. package/dist/structure/line-amount-label.js +2 -1
  363. package/dist/structure/line-amount-label.js.map +1 -1
  364. package/dist/structure/line-amount.d.ts +0 -5
  365. package/dist/structure/line-amount.d.ts.map +1 -1
  366. package/dist/structure/line-amount.js +1 -10
  367. package/dist/structure/line-amount.js.map +1 -1
  368. package/dist/structure/prose-total.d.ts +8 -0
  369. package/dist/structure/prose-total.d.ts.map +1 -1
  370. package/dist/structure/prose-total.js +70 -2
  371. package/dist/structure/prose-total.js.map +1 -1
  372. package/dist/structure/runs.d.ts.map +1 -1
  373. package/dist/structure/runs.js +9 -1
  374. package/dist/structure/runs.js.map +1 -1
  375. package/dist/structure/signed-date-line.d.ts +15 -0
  376. package/dist/structure/signed-date-line.d.ts.map +1 -0
  377. package/dist/structure/signed-date-line.js +68 -0
  378. package/dist/structure/signed-date-line.js.map +1 -0
  379. package/dist/structure/start-end-range.d.ts +30 -0
  380. package/dist/structure/start-end-range.d.ts.map +1 -0
  381. package/dist/structure/start-end-range.js +79 -0
  382. package/dist/structure/start-end-range.js.map +1 -0
  383. package/dist/structure/tax.d.ts.map +1 -1
  384. package/dist/structure/tax.js +5 -3
  385. package/dist/structure/tax.js.map +1 -1
  386. package/dist/structure/total-line.d.ts.map +1 -1
  387. package/dist/structure/total-line.js +10 -6
  388. package/dist/structure/total-line.js.map +1 -1
  389. package/dist/structure/total.d.ts +2 -0
  390. package/dist/structure/total.d.ts.map +1 -1
  391. package/dist/structure/total.js +34 -3
  392. package/dist/structure/total.js.map +1 -1
  393. package/dist/subject-codes.d.ts +21 -0
  394. package/dist/subject-codes.d.ts.map +1 -0
  395. package/dist/subject-codes.js +79 -0
  396. package/dist/subject-codes.js.map +1 -0
  397. package/dist/unlabelled-references.d.ts +6 -2
  398. package/dist/unlabelled-references.d.ts.map +1 -1
  399. package/dist/unlabelled-references.js +11 -10
  400. package/dist/unlabelled-references.js.map +1 -1
  401. package/genres.yaml +17 -0
  402. package/package.json +4 -4
  403. package/profiles/listing.yaml +1 -1
  404. package/profiles/property-sale.yaml +21 -0
  405. package/rules/closing-balance-mismatch.yaml +3 -3
  406. package/rules/date-range-reversed.yaml +4 -4
  407. package/rules/due-before-issue.yaml +9 -5
  408. package/rules/fact-conflict.yaml +2 -2
  409. package/rules/formula-amount-mismatch.yaml +67 -0
  410. package/rules/heading-echo.yaml +2 -2
  411. package/rules/installment-total-mismatch.yaml +9 -4
  412. package/rules/internal-jargon.yaml +2 -2
  413. package/rules/latin-spacing.yaml +4 -4
  414. package/rules/list-item-form-mix.yaml +1 -1
  415. package/rules/name-variant.yaml +5 -2
  416. package/rules/no-lead.yaml +2 -2
  417. package/rules/number-without-unit.yaml +2 -2
  418. package/rules/orthographic-variant.yaml +3 -3
  419. package/rules/reference-number-variant.yaml +3 -3
  420. package/rules/toki-as-condition.yaml +71 -0
  421. package/rules/total-mismatch.yaml +4 -4
  422. package/rules/unknown-word.yaml +2 -2
  423. package/rules/use-before-definition.yaml +2 -2
  424. package/src/api.ts +11 -2
  425. package/src/cli-text.ts +6 -4
  426. package/src/commands/grade.ts +75 -23
  427. package/src/company-kana-spelling.ts +22 -2
  428. package/src/company-name-ending.ts +50 -0
  429. package/src/company-names.ts +52 -17
  430. package/src/cross-run.ts +1 -0
  431. package/src/custom/no-rewrite.ts +2 -0
  432. package/src/custom/parse.ts +18 -2
  433. package/src/detectors/age-words.ts +12 -0
  434. package/src/detectors/agreement-slip.ts +3 -0
  435. package/src/detectors/annual-pay-mismatch.ts +3 -18
  436. package/src/detectors/blank-structure.ts +4 -3
  437. package/src/detectors/closing-balance-mismatch.ts +1 -0
  438. package/src/detectors/code-fences.ts +10 -0
  439. package/src/detectors/condition-toki.ts +60 -0
  440. package/src/detectors/conjugated-entry.ts +53 -0
  441. package/src/detectors/content-morphemes.ts +2 -1
  442. package/src/detectors/cross-facts.ts +2 -1
  443. package/src/detectors/custom.ts +9 -2
  444. package/src/detectors/document-shape.ts +8 -0
  445. package/src/detectors/due-date.ts +17 -7
  446. package/src/detectors/fact-consistency.ts +13 -17
  447. package/src/detectors/form-line.ts +47 -0
  448. package/src/detectors/formula-amount.ts +43 -0
  449. package/src/detectors/heading-claim.ts +76 -0
  450. package/src/detectors/heading-echo.ts +32 -1
  451. package/src/detectors/installment-total-mismatch.ts +35 -24
  452. package/src/detectors/list-parallel.ts +46 -7
  453. package/src/detectors/name-variant.ts +45 -8
  454. package/src/detectors/number-unit.ts +35 -9
  455. package/src/detectors/orthographic-variant.ts +5 -3
  456. package/src/detectors/orthography.ts +17 -8
  457. package/src/detectors/per-unit-words.ts +24 -0
  458. package/src/detectors/period-multiple-mismatch.ts +2 -18
  459. package/src/detectors/reference-number-variant.ts +27 -5
  460. package/src/detectors/registry/condition-toki.ts +4 -0
  461. package/src/detectors/registry/formula-amount.ts +4 -0
  462. package/src/detectors/rent-multiple-mismatch.ts +2 -18
  463. package/src/detectors/row-sentence-amounts.ts +5 -20
  464. package/src/detectors/stated-amounts.ts +20 -0
  465. package/src/detectors/step-time-sum.ts +2 -1
  466. package/src/detectors/structure-tree.ts +7 -2
  467. package/src/detectors/team.ts +13 -7
  468. package/src/detectors/time-order.ts +6 -3
  469. package/src/detectors/unknown-word.ts +20 -2
  470. package/src/detectors/use-interval.ts +8 -4
  471. package/src/detectors/use-maximum.ts +3 -1
  472. package/src/eval.ts +3 -3
  473. package/src/extension/document-view.ts +18 -9
  474. package/src/extension/entry-genres.ts +15 -0
  475. package/src/extension/module-detector.ts +9 -4
  476. package/src/extension/plugin-parse.ts +29 -7
  477. package/src/extension/problem-text.ts +4 -0
  478. package/src/facts/age-values.ts +24 -2
  479. package/src/facts/column-units.ts +67 -0
  480. package/src/facts/fact-values.ts +11 -1
  481. package/src/facts/labelled-facts.ts +16 -2
  482. package/src/facts/per-unit.ts +105 -0
  483. package/src/facts/row-sentence-amounts.ts +4 -26
  484. package/src/facts/table-facts.ts +7 -4
  485. package/src/facts/term-values.ts +94 -13
  486. package/src/fix-plan/text.ts +2 -2
  487. package/src/grade/baseline.ts +20 -12
  488. package/src/grade/expect-read.ts +65 -0
  489. package/src/grade/expect.ts +74 -0
  490. package/src/grade/grade-item.ts +14 -3
  491. package/src/grade/item.ts +48 -8
  492. package/src/grade/result.ts +5 -0
  493. package/src/grade/results-read.ts +7 -2
  494. package/src/grade/rubric-file.ts +46 -0
  495. package/src/grade/rubric.ts +77 -47
  496. package/src/grade/setup.ts +3 -3
  497. package/src/grade/stamp.ts +10 -2
  498. package/src/grade/task-rubric.ts +39 -0
  499. package/src/grade/text.ts +27 -5
  500. package/src/lexicon-genres.ts +11 -0
  501. package/src/name-char-reading.ts +16 -0
  502. package/src/name-end-letter.ts +52 -0
  503. package/src/name-neighbours.ts +2 -1
  504. package/src/name-separator.ts +32 -0
  505. package/src/name-variants.ts +54 -13
  506. package/src/number-name.ts +12 -3
  507. package/src/plugin.ts +6 -0
  508. package/src/profile/cue-lines.ts +14 -0
  509. package/src/profile/parse.ts +11 -2
  510. package/src/reference-numbers.ts +1 -1
  511. package/src/run.ts +1 -0
  512. package/src/spaced-person-name.ts +27 -2
  513. package/src/spacing-code.ts +13 -2
  514. package/src/spacing-minority.ts +17 -0
  515. package/src/structure/closing-balance.ts +46 -8
  516. package/src/structure/date-range.ts +4 -3
  517. package/src/structure/definition-use.ts +24 -1
  518. package/src/structure/document-context.ts +46 -0
  519. package/src/structure/fenced-lines.ts +28 -0
  520. package/src/structure/formula-amount.ts +236 -0
  521. package/src/structure/installment-fee.ts +201 -0
  522. package/src/structure/installment-total.ts +6 -6
  523. package/src/structure/labelled-date-order.ts +105 -21
  524. package/src/structure/labelled-order.ts +21 -10
  525. package/src/structure/line-amount-label.ts +2 -1
  526. package/src/structure/line-amount.ts +1 -11
  527. package/src/structure/prose-total.ts +81 -2
  528. package/src/structure/runs.ts +10 -1
  529. package/src/structure/signed-date-line.ts +78 -0
  530. package/src/structure/start-end-range.ts +120 -0
  531. package/src/structure/tax.ts +6 -3
  532. package/src/structure/total-line.ts +12 -6
  533. package/src/structure/total.ts +42 -3
  534. package/src/subject-codes.ts +105 -0
  535. package/src/unlabelled-references.ts +24 -16
@@ -1,5 +1,6 @@
1
1
  import { nameKey } from "./name-variants.ts";
2
2
  import { escapeRegExp } from "./orthography.ts";
3
+ import { isNameEndingSlip } from "./company-name-ending.ts";
3
4
 
4
5
  // 会社の名前を、文書の中で二通りに書いた所(株式会社アオバシステム と アオバシステム株式会社、Aoba Systems Inc. と Aoba Systems Ltd.)。
5
6
  // 会社の形の語(株式会社、Inc)は語彙表 company-form が言う。group が同じ語は同じ形(Inc と Incorporated、株式会社 と (株))、
@@ -27,8 +28,11 @@ export type CompanyMention = {
27
28
  readonly foreign?: boolean | undefined;
28
29
  };
29
30
 
30
- /** 二つの書き方の違い。spelling は記号・幅・大小だけ、form は会社の形、position は形の語の側、near は名前の一字違い。 */
31
- type CompanyRelation = "spelling" | "form" | "position" | "near";
31
+ /**
32
+ * 二つの書き方の違い。spelling は記号・幅・大小だけ、form は会社の形、position は形の語の側、near は名前の一字違い、ending は
33
+ * 名前の一語の終わりだけの違い(company-name-ending.ts)。
34
+ */
35
+ type CompanyRelation = "spelling" | "form" | "position" | "near" | "ending";
32
36
 
33
37
  type CompanyVariant = { readonly mention: CompanyMention; readonly usual: string; readonly kind: CompanyRelation };
34
38
 
@@ -82,6 +86,18 @@ const SPACES: ReadonlySet<string> = new Set([" ", "\u3000"]);
82
86
  */
83
87
  export type KanaStops = { readonly particles: readonly string[]; readonly openers: readonly string[]; readonly ends: readonly string[] };
84
88
 
89
+ /**
90
+ * 品詞解析が形容詞・動詞・助動詞と読んだ語の終わり(source の上の位置)。い で終わるひらがな(ながい、しおさい)は、ここで終わる
91
+ * なら名前の頭と読まない(ながい食品 の ながい)。名前の頭の い(しおさい の さい)は名詞と読まれる。
92
+ */
93
+ export type PredicateEnds = ReadonlySet<number>;
94
+
95
+ const NO_PREDICATE_ENDS: PredicateEnds = new Set();
96
+ const PREDICATE_TAIL = "い";
97
+
98
+ /** い で終わる名前の頭が、品詞解析の形容詞・動詞・助動詞の終わりか(ながい食品 の ながい)。 */
99
+ const isPredicateHead = (head: string, end: number, predicateEnds: PredicateEnds): boolean => head.endsWith(PREDICATE_TAIL) && predicateEnds.has(end);
100
+
85
101
  /** ひらがなの前に何があるか。word は語や閉じ括弧(当社はこもれび、)により)、form は会社の形の語(株式会社こもれび)、boundary は句読点や行の頭。 */
86
102
  export type KanaLead = "word" | "form" | "boundary";
87
103
 
@@ -117,26 +133,27 @@ const kanaRunStart = (source: string, end: number): number => {
117
133
  };
118
134
 
119
135
  /** 名前の前に続くひらがなのうち、名前の頭と読む所を足した始まり。 */
120
- const withKanaHead = (source: string, start: number, stops: KanaStops): number => {
136
+ const withKanaHead = (source: string, start: number, stops: KanaStops, predicateEnds: PredicateEnds): number => {
121
137
  const kanaStart = kanaRunStart(source, start);
122
138
  if (kanaStart === start) return start;
123
139
  const lead = GLUED.test(source.charAt(kanaStart - 1)) ? "word" : "boundary";
124
- return start - (kanaHeadOf(source.slice(kanaStart, start), lead, stops)?.length ?? 0);
140
+ const head = kanaHeadOf(source.slice(kanaStart, start), lead, stops);
141
+ return head === undefined || isPredicateHead(head, start, predicateEnds) ? start : start - head.length;
125
142
  };
126
143
 
127
144
  /** 漢字・かなの名前: 形の語の隣の、名前に使う字の続き。形の語との間の空白一つは名前の外。 */
128
- const cjkBaseBefore = (source: string, end: number, stops: KanaStops): Span | undefined => {
145
+ const cjkBaseBefore = (source: string, end: number, stops: KanaStops, predicateEnds: PredicateEnds): Span | undefined => {
129
146
  const stop = SPACES.has(source.charAt(end - 1)) ? end - 1 : end;
130
147
  const match = CJK_BEFORE.exec(source.slice(0, stop));
131
- return match === null ? undefined : { start: withKanaHead(source, match.index, stops), end: stop };
148
+ return match === null ? undefined : { start: withKanaHead(source, match.index, stops, predicateEnds), end: stop };
132
149
  };
133
150
 
134
151
  /** 形の語の後ろの名前。ひらがなで始まる名前(株式会社こもれび珈琲)は、ひらがなの後ろに名前に使う字が続くときだけ。 */
135
- const cjkBaseAfter = (source: string, start: number, stops: KanaStops): Span | undefined => {
152
+ const cjkBaseAfter = (source: string, start: number, stops: KanaStops, predicateEnds: PredicateEnds): Span | undefined => {
136
153
  const from = SPACES.has(source.charAt(start)) ? start + 1 : start;
137
154
  const kana = KANA_AFTER.exec(source.slice(from))?.[0] ?? "";
138
155
  const head = kana === "" ? "" : kanaHeadOf(kana, "form", stops);
139
- if (head === undefined) return undefined;
156
+ if (head === undefined || isPredicateHead(head, from + head.length, predicateEnds)) return undefined;
140
157
  const match = CJK_AFTER.exec(source.slice(from + head.length));
141
158
  return match === null ? undefined : { start: from, end: from + head.length + match[0].length };
142
159
  };
@@ -184,23 +201,36 @@ const foreignMentionAt = (source: string, form: CompanyForm, at: number, words:
184
201
  return { ...mentionOf(source, base, { start: at, end: at + form.pattern.length }, form.group), foreign: true };
185
202
  };
186
203
 
187
- const baseBefore = (source: string, at: number, latin: boolean, isProper: IsProper, stops: KanaStops): Span | undefined =>
188
- latin ? latinBaseBefore(source, at, isProper) : cjkBaseBefore(source, at, stops);
204
+ const baseBefore = (source: string, at: number, latin: boolean, isProper: IsProper, stops: KanaStops, predicateEnds: PredicateEnds): Span | undefined =>
205
+ latin ? latinBaseBefore(source, at, isProper) : cjkBaseBefore(source, at, stops, predicateEnds);
189
206
 
190
207
  /** 形の語の一つの現れから、会社の名前の現れ。名前が前にあればそれを、無ければ後ろを取る。 */
191
- const mentionAt = (source: string, form: CompanyForm, at: number, isProper: IsProper, stops: KanaStops): CompanyMention | undefined => {
208
+ const mentionAt = (
209
+ source: string,
210
+ form: CompanyForm,
211
+ at: number,
212
+ isProper: IsProper,
213
+ stops: KanaStops,
214
+ predicateEnds: PredicateEnds,
215
+ ): CompanyMention | undefined => {
192
216
  if (form.foreign !== undefined) return foreignMentionAt(source, form, at, form.foreign.words);
193
217
  const formSpan = { start: at, end: at + form.pattern.length };
194
218
  const latin = LATIN.test(form.pattern);
195
219
  if (latin && CONTINUED.test(source.slice(formSpan.end))) return undefined;
196
- const before = form.position === "before" ? undefined : baseBefore(source, at, latin, isProper, stops);
220
+ const before = form.position === "before" ? undefined : baseBefore(source, at, latin, isProper, stops, predicateEnds);
197
221
  if (before !== undefined && isNameBase(source, before, isProper)) return mentionOf(source, before, formSpan, form.group);
198
- const after = form.position === "after" || latin ? undefined : cjkBaseAfter(source, formSpan.end, stops);
222
+ const after = form.position === "after" || latin ? undefined : cjkBaseAfter(source, formSpan.end, stops, predicateEnds);
199
223
  return after !== undefined && isNameBase(source, after, isProper) ? mentionOf(source, after, formSpan, form.group) : undefined;
200
224
  };
201
225
 
202
226
  /** 文書の中の会社の名前の現れ。長い形の語(Co., Ltd)を先に取り、その中の短い語(Ltd)は数えない。 */
203
- export const companyMentionsIn = (source: string, forms: readonly CompanyForm[], isProper: IsProper, stops: KanaStops): CompanyMention[] => {
227
+ export const companyMentionsIn = (
228
+ source: string,
229
+ forms: readonly CompanyForm[],
230
+ isProper: IsProper,
231
+ stops: KanaStops,
232
+ predicateEnds: PredicateEnds = NO_PREDICATE_ENDS,
233
+ ): CompanyMention[] => {
204
234
  const taken: Span[] = [];
205
235
  return forms
206
236
  .toSorted((left, right) => right.pattern.length - left.pattern.length)
@@ -209,7 +239,7 @@ export const companyMentionsIn = (source: string, forms: readonly CompanyForm[],
209
239
  const end = at + form.pattern.length;
210
240
  if (!standsAsWord(source, form.pattern, at) || taken.some((span) => span.start < end && at < span.end)) return [];
211
241
  taken.push({ start: at, end });
212
- const mention = mentionAt(source, form, at, isProper, stops);
242
+ const mention = mentionAt(source, form, at, isProper, stops, predicateEnds);
213
243
  return mention === undefined ? [] : [mention];
214
244
  }),
215
245
  )
@@ -316,12 +346,17 @@ const talliesOf = (mentions: readonly CompanyMention[]): Tally[] => {
316
346
  /** 多いほうが先。同数なら先に書いたほう。 */
317
347
  const byUsage = (left: Tally, right: Tally): number => right.count - left.count || left.first.offset - right.first.offset;
318
348
 
319
- /** 短い名前のかなの一字違いは、別の会社のこともあるので、相手が二度以上、こちらが一度だけのときに限る。 */
349
+ /**
350
+ * 短い名前のかなの一字違いと、名前の一語の終わりだけの違い(Brightmoor と Brightmore、Water Utility と Water Utilities)は、別の
351
+ * 会社のこともあるので、形も側も同じで、相手が二度以上、こちらが一度だけのときに限る。
352
+ */
320
353
  const relationBetween = (tally: Tally, other: Tally): CompanyRelation | undefined => {
321
354
  const relation = companyRelation(tally.first, other.first);
322
355
  if (relation !== undefined || tally.count !== 1 || other.count < 2) return relation;
323
356
  const [left, right] = [tally.first, other.first];
324
- return left.form === right.form && left.position === right.position && isKanaWordSlip(nameKey(left.base), nameKey(right.base)) ? "near" : undefined;
357
+ if (left.form !== right.form || left.position !== right.position) return undefined;
358
+ if (isKanaWordSlip(nameKey(left.base), nameKey(right.base))) return "near";
359
+ return isNameEndingSlip(left.base, right.base) ? "ending" : undefined;
325
360
  };
326
361
 
327
362
  /** 同じ会社の、少ないほうの書き方。同じ会社と言える相手のうち一番多いものと比べる。書き方ごとに最初の現れを一つ。 */
package/src/cross-run.ts CHANGED
@@ -40,6 +40,7 @@ const optionsFor = (input: CrossInput, rule: RuleDefinition): DetectorOptions =>
40
40
  lexicon: rule.word_list === undefined ? undefined : input.doc.lexicons[rule.word_list],
41
41
  where: rule.where,
42
42
  ...(rule.options === undefined ? {} : { settings: optionValues(settleOptions(rule.id, rule.options, input.context.optionLayers ?? [])) }),
43
+ genre: input.context.genre,
43
44
  });
44
45
 
45
46
  /** What one rule did to the documents taking part (by path): its findings, or why it did not run after all. */
@@ -0,0 +1,2 @@
1
+ /** The variant of a words rule's finding whose word-list entry has no rewrite, so there is no spelling to offer. */
2
+ export const NO_REWRITE = "no-rewrite";
@@ -5,6 +5,7 @@ import { modulePathOf, type ModulePathRefusal } from "./module-path.ts";
5
5
  import type { FieldProblem } from "../rule-fields.ts";
6
6
  import { failed, ok, type Checked } from "./checked.ts";
7
7
  import { describedOf, exampleSides, levelsOf, type Described, type RuleLevels } from "./dsl-fields.ts";
8
+ import { NO_REWRITE } from "./no-rewrite.ts";
8
9
 
9
10
  // custom_rules in chaff.yaml: a team's own deterministic rules, written without code. Each becomes a RuleDefinition like the
10
11
  // built-in ones, so findings, explain, rules --json, stet, the baseline and SARIF treat it the same. Pure: the YAML comes in parsed.
@@ -198,13 +199,28 @@ const languagesOf = (raw: unknown, at: string): Checked<readonly string[] | unde
198
199
  return list.length > 0 && list.every(nonEmpty) ? ok(list.map((entry: string) => entry.trim())) : failed({ kind: "bad-languages", at });
199
200
  };
200
201
 
202
+ /** The rule's name and what was found: the message for a finding with no spelling to use. */
203
+ const namedMessage = (name: Localized): Localized =>
204
+ Object.fromEntries(Object.entries(name).map(([language, text]) => [language, language === "ja" ? `${text}:「{matched}」` : `${text}: "{matched}"`]));
205
+
201
206
  /** The message when a rule does not write one: the replacement for a word list, else the rule's name and what was found. */
202
207
  const defaultMessage = (spec: CustomSpec, name: Localized): Localized => {
203
208
  if (spec.type === "words" && spec.words.every((pair) => pair.use !== ""))
204
209
  return { ja: "「{matched}」は「{preferred}」と書きます", en: 'Write "{preferred}", not "{matched}"' };
205
- return Object.fromEntries(Object.entries(name).map(([language, text]) => [language, language === "ja" ? `${text}:「{matched}」` : `${text}: "{matched}"`]));
210
+ return namedMessage(name);
211
+ };
212
+
213
+ /** In each language, the rule's own message unless it offers {preferred}, else the named message. */
214
+ const noRewriteMessage = (written: Localized | undefined, name: Localized): Localized => {
215
+ const named = namedMessage(name);
216
+ if (written === undefined) return named;
217
+ return Object.fromEntries(Object.entries(written).map(([language, text]) => [language, text.includes("{preferred}") ? (named[language] ?? text) : text]));
206
218
  };
207
219
 
220
+ /** A word-list entry may have no rewrite: that finding must not offer an empty spelling. */
221
+ const defaultMessages = (spec: CustomSpec, written: Localized | undefined, name: Localized): Readonly<Record<string, Localized>> =>
222
+ spec.type === "words" ? { [NO_REWRITE]: noRewriteMessage(written, name) } : {};
223
+
208
224
  const PLACEHOLDERS: Readonly<Record<string, Localized>> = {
209
225
  matched: { ja: "見つけた語句", en: "the text found" },
210
226
  preferred: { ja: "使う書き方", en: "the spelling to use" },
@@ -249,7 +265,7 @@ const definitionOf = (id: string, raw: Record<string, unknown>, parts: Parts, us
249
265
  why: parts.texts.why,
250
266
  how_to_fix: parts.texts.how_to_fix,
251
267
  message: localizedOf(raw["message"]) ?? defaultMessage(parts.spec, parts.texts.name),
252
- messages: {},
268
+ messages: defaultMessages(parts.spec, localizedOf(raw["message"]), parts.texts.name),
253
269
  placeholders: PLACEHOLDERS,
254
270
  levels: parts.levels.table,
255
271
  level_sets: "severity",
@@ -0,0 +1,12 @@
1
+ import type { ProseDocument } from "../plugin.ts";
2
+ import type { AgeWord, AgeWords } from "../facts/age-values.ts";
3
+
4
+ const ageWordsAt = (doc: ProseDocument, id: string): AgeWord[] =>
5
+ (doc.lexicons[id] ?? []).map((entry): AgeWord => ({ pattern: entry.pattern, position: entry.position ?? "before" }));
6
+
7
+ /** 年齢の語: 印(fact-age-mark)、上限の印(fact-age-limit)、範囲をつなぐ語(fact-age-joiner)。 */
8
+ export const ageWordsOf = (doc: ProseDocument): AgeWords => ({
9
+ marks: ageWordsAt(doc, "fact-age-mark"),
10
+ limits: ageWordsAt(doc, "fact-age-limit"),
11
+ joiners: (doc.lexicons["fact-age-joiner"] ?? []).map((entry) => entry.pattern),
12
+ });
@@ -1,4 +1,5 @@
1
1
  import type { Detector, Finding, Lexicon, Token } from "../plugin.ts";
2
+ import { isPartOfAddress } from "./address-word.ts";
2
3
  import { isPartOfLongerWord } from "./doubled-word.ts";
3
4
 
4
5
  /**
@@ -130,6 +131,8 @@ const numberSlipAt = (source: string, tokens: readonly Token[], at: number, list
130
131
  const nounAt = at + determiner.length + modifiers.length;
131
132
  const noun = tokens[nounAt];
132
133
  if (!isCommonNoun(noun) || !hasOneNumber(noun, lists.invariant) || isPlural(noun) === determiner.plural) return undefined;
134
+ // A file name or a path (a quotes.json, a docs/ folder) is spelled as it must be, not counted.
135
+ if (isPartOfAddress(source, noun.span.start, noun.span.end)) return undefined;
133
136
  if (mayBeVerb(determiner, modifiers, noun, tokens[nounAt + 1], lists.finite)) return undefined;
134
137
  const span = tokens.slice(at, nounAt + 1);
135
138
  if (!endsNounPhrase(tokens[nounAt + 1], lists.finite) || !joinedBySpace(source, span) || isPartOfLongerWord(source, determiner.head, noun)) return undefined;
@@ -3,9 +3,8 @@
3
3
  // are annual-pay-label, the other words annual-pay-word, approximate-marker, duration-month, number-word (digit),
4
4
  // range-connector and amount-range-word.
5
5
  import type { Detector, Finding, Lexicon, ProseDocument } from "../plugin.ts";
6
- import { annualPayMismatches, type AnnualPayWords, type PayAmount, type PositionedWord } from "../structure/annual-pay.ts";
7
- import { scaledAmountOf, scaleWordsOf } from "./amount-scale.ts";
8
- import { amountsIn, formsOf } from "./currency-notation.ts";
6
+ import { annualPayMismatches, type AnnualPayWords, type PositionedWord } from "../structure/annual-pay.ts";
7
+ import { statedAmountsOf } from "./stated-amounts.ts";
9
8
  import { proseAndTablesOf } from "../table-text.ts";
10
9
  import { quoteAround } from "./quote-around.ts";
11
10
 
@@ -44,23 +43,9 @@ const wordsOf = (doc: ProseDocument): AnnualPayWords => ({
44
43
  numberWords: numberWordsOf(doc),
45
44
  });
46
45
 
47
- const amountsOf = (text: string, doc: ProseDocument): PayAmount[] => {
48
- const scales = scaleWordsOf(doc);
49
- return amountsIn(
50
- text,
51
- formsOf(doc),
52
- scales.map((scale) => scale.word),
53
- ).flatMap((amount) => {
54
- const read = scaledAmountOf(text, amount, scales);
55
- return read === undefined
56
- ? []
57
- : [{ offset: read.offset, end: amount.offset + amount.written.length, currency: read.currency, value: read.value, scale: read.unit }];
58
- });
59
- };
60
-
61
46
  export const annualPayMismatch: Detector = (doc): Finding[] => {
62
47
  const text = proseAndTablesOf(doc);
63
- return annualPayMismatches(text, amountsOf(text, doc), wordsOf(doc)).map((issue) => ({
48
+ return annualPayMismatches(text, statedAmountsOf(text, doc), wordsOf(doc)).map((issue) => ({
64
49
  rule: "annual-pay-mismatch",
65
50
  severity: "warning",
66
51
  line: 0,
@@ -7,7 +7,7 @@ import { eachPreOrder, foldPostOrder } from "../tree-walk.ts";
7
7
  import { quoteAt } from "./structure-tree.ts";
8
8
  import { amountColumnOf, isTotalRowGap, type BodyRow } from "../structure/total-row-blank.ts";
9
9
  import { isAmountNameLine, isTotalLine } from "../structure/total-line.ts";
10
- import { isTotalLabel } from "../structure/total.ts";
10
+ import { isTotalLabel, withoutLeadingBlankCells } from "../structure/total.ts";
11
11
 
12
12
  /** Fewer body rows than this, and one blank is as likely a choice as a gap. */
13
13
  const MIN_BODY_ROWS = 3;
@@ -178,7 +178,8 @@ const patternsOf = (doc: ProseDocument, lexicon: string): string[] => (doc.lexic
178
178
 
179
179
  /**
180
180
  * A total row starts with a total word (total-label, with total-label-qualifier or total-period-qualifier: Week total),
181
- * a tax word (tax-label), or is named by a computed amount (net-amount-label: Gross pay, Net pay).
181
+ * a tax word (tax-label), or is named by a computed amount (net-amount-label: Gross pay, Net pay). The word may sit in the
182
+ * first cell that is not blank (| | Total | $1,200 |): the cells before it are left blank on purpose.
182
183
  */
183
184
  const totalRowOf = (doc: ProseDocument): IsTotalRow => {
184
185
  const totals = {
@@ -188,7 +189,7 @@ const totalRowOf = (doc: ProseDocument): IsTotalRow => {
188
189
  amountNames: patternsOf(doc, "net-amount-label"),
189
190
  };
190
191
  const taxes = patternsOf(doc, "tax-label");
191
- return (rowText) => isTotalLine(rowText, totals) || isAmountNameLine(rowText, totals) || isTotalLabel(rowText, taxes);
192
+ return (rowText) => isTotalLine(rowText, totals) || isAmountNameLine(rowText, totals) || isTotalLabel(withoutLeadingBlankCells(rowText), taxes);
192
193
  };
193
194
 
194
195
  export const emptyTableCell: Detector = findingsOf("empty-table-cell", (doc) => tableBlanks(doc.source, doc.replyQuotes ?? [], totalRowOf(doc)));
@@ -20,6 +20,7 @@ const wordsOf = (doc: ProseDocument): BalanceWords => ({
20
20
  outflow: patternsOf(doc, LEXICON, "outflow"),
21
21
  closing: patternsOf(doc, LEXICON, "closing"),
22
22
  },
23
+ asOf: patternsOf(doc, LEXICON, "as-of"),
23
24
  magnitudes: patternsOf(doc, "amount-multiplier"),
24
25
  percentUnits: patternsOf(doc, "percent-unit"),
25
26
  });
@@ -3,6 +3,7 @@
3
3
  import { parse } from "../markdown-read.ts";
4
4
  import { spanOf } from "../markdown-node.ts";
5
5
  import { eachPreOrder } from "../tree-walk.ts";
6
+ import { maskSpans } from "../mask.ts";
6
7
 
7
8
  export type CodeFence = {
8
9
  /** Where the opening fence line starts. */
@@ -79,6 +80,15 @@ export const codeFences = (source: string): readonly CodeFence[] => {
79
80
  return fences;
80
81
  };
81
82
 
83
+ /**
84
+ * The source with every fenced code block blanked, offsets and line breaks kept. A list or a sentence in a code block is an
85
+ * example, not the document's own: a rule that reads values from the source line by line reads this instead.
86
+ */
87
+ export const withoutCodeBlocks = (source: string): string => {
88
+ const fences = codeFences(source);
89
+ return fences.length === 0 ? source : maskSpans(source, fences);
90
+ };
91
+
82
92
  /** Inline code spans in a stretch of text: a run of backticks closed by a run of the same length. */
83
93
  export const codeSpans = (text: string, offset = 0): CodeSpan[] => {
84
94
  const spans: CodeSpan[] = [];
@@ -0,0 +1,60 @@
1
+ import type { Detector, Finding, Lexicon, Sentence, Token } from "../plugin.ts";
2
+ import { isWithinAny, quotedIn } from "../quoted-span.ts";
3
+
4
+ // A noun for a point in time written where the clause states a condition (認定を受けた時は → 認定を受けたときは). One word
5
+ // list gives the noun and its kana form, another the particles that make the clause a condition; this file knows parts of
6
+ // speech. Pure: the sentence and the word lists come in.
7
+
8
+ export type ConditionWords = { readonly nouns: ReadonlyMap<string, string>; readonly followers: ReadonlySet<string> };
9
+
10
+ export type ConditionSpelling = { readonly written: string; readonly preferred: string; readonly offset: number };
11
+
12
+ /** A predicate ends the clause before the noun (受けた時, 過ぎる時, 支払わない時, 必要な時); の, その and ある (事故の時, その時) do not. */
13
+ const PREDICATE_POS: ReadonlySet<string> = new Set(["VERB", "AUX", "ADJ"]);
14
+
15
+ const FOLLOWER_LIST = "condition-follower";
16
+
17
+ /** The nouns with their rewrite (時 → とき), and the particles that follow them in a condition (は, には, も). */
18
+ export const conditionWordsOf = (nouns: Lexicon | undefined, followers: Lexicon | undefined): ConditionWords => ({
19
+ nouns: new Map((nouns ?? []).flatMap((entry): [string, string][] => (entry.rewrite === undefined ? [] : [[entry.pattern, entry.rewrite]]))),
20
+ followers: new Set((followers ?? []).map((entry) => entry.pattern)),
21
+ });
22
+
23
+ /** The follower right after index: one particle (は, も) or two the tagger splits (に + は). */
24
+ const isFollowedByCondition = (tokens: readonly Token[], index: number, followers: ReadonlySet<string>): boolean => {
25
+ const next = tokens[index + 1]?.surface ?? "";
26
+ const pair = `${next}${tokens[index + 2]?.surface ?? ""}`;
27
+ return followers.has(next) || followers.has(pair);
28
+ };
29
+
30
+ const isConditionNoun = (tokens: readonly Token[], index: number, words: ConditionWords): boolean => {
31
+ const token = tokens[index];
32
+ if (token === undefined || !words.nouns.has(token.surface)) return false;
33
+ const previous = tokens[index - 1];
34
+ return previous !== undefined && PREDICATE_POS.has(previous.pos) && isFollowedByCondition(tokens, index, words.followers);
35
+ };
36
+
37
+ /** Each noun in the sentence, outside 「」『』, that ends a predicate and is followed by は, には or も. */
38
+ export const conditionSpellingsIn = (sentence: Sentence, words: ConditionWords): ConditionSpelling[] => {
39
+ const tokens = sentence.tokens ?? [];
40
+ const quoted = quotedIn(sentence);
41
+ return tokens.flatMap((token, index) =>
42
+ isConditionNoun(tokens, index, words) && !isWithinAny(quoted, token.span)
43
+ ? [{ written: token.surface, preferred: words.nouns.get(token.surface) ?? "", offset: token.span.start }]
44
+ : [],
45
+ );
46
+ };
47
+
48
+ export const conditionToki: Detector = (doc, options): Finding[] => {
49
+ const words = conditionWordsOf(options.lexicon, doc.lexicons[FOLLOWER_LIST]);
50
+ return doc.sentences.flatMap((sentence) =>
51
+ conditionSpellingsIn(sentence, words).map((spelling) => ({
52
+ rule: "",
53
+ severity: "info",
54
+ line: 0,
55
+ column: 0,
56
+ quote: sentence.text.trim(),
57
+ values: { matched: spelling.written, preferred: spelling.preferred, offset: spelling.offset },
58
+ })),
59
+ );
60
+ };
@@ -0,0 +1,53 @@
1
+ import type { LexiconEntry, Sentence, Span, Token } from "../plugin.ts";
2
+ import { escapeRegExp } from "../orthography.ts";
3
+ import { entryRanges } from "./lexicon-match.ts";
4
+
5
+ /**
6
+ * チームが辞書形の動詞で書いた語か(巻き取る・握っておく・utilize)。最後の語が動詞の原形のときだけ。
7
+ * 名詞(巻き取り・onboarding)や活用した形(握った)は書いた形のまま照らす。動詞の名詞形まで当てると、チームが並べていない語を指摘する。
8
+ */
9
+ export const isDictionaryVerb = (entry: LexiconEntry): boolean => {
10
+ const last = entry.tokens?.at(-1);
11
+ return last?.pos === "VERB" && last.lemma?.toLowerCase() === last.surface.toLowerCase();
12
+ };
13
+
14
+ /** 直前に動詞が詰めて書いてある(受け|取ります)。そこは別の複合動詞の後ろ半分で、並べた動詞ではない。 */
15
+ const tailOfCompound = (tokens: readonly Token[], start: number): boolean => {
16
+ const before = tokens[start - 1];
17
+ return before?.pos === "VERB" && before.span.end === tokens[start]?.span.start;
18
+ };
19
+
20
+ /**
21
+ * 辞書形の動詞で書いた語が、活用した形で文のどこに出たか(文の中の字の範囲)。複合動詞は語に割れる(巻き/取り)ので、語の並びで照らす。
22
+ * 品詞が無い文書、動詞でない語には何も返さない。字で探す側がそのまま当たる。
23
+ */
24
+ export const conjugatedSpans = (sentence: Sentence, entry: LexiconEntry): Span[] => {
25
+ const tokens = sentence.tokens;
26
+ if (tokens === undefined || !isDictionaryVerb(entry)) return [];
27
+ return entryRanges(sentence, entry).flatMap((range) => {
28
+ const first = tokens[range.start];
29
+ const last = tokens[range.end - 1];
30
+ if (first === undefined || last === undefined || tailOfCompound(tokens, range.start)) return [];
31
+ return [{ start: first.span.start - sentence.span.start, end: last.span.end - sentence.span.start }];
32
+ });
33
+ };
34
+
35
+ const occurrencesOf = (text: string, word: string): Span[] =>
36
+ word === ""
37
+ ? []
38
+ : [...text.matchAll(new RegExp(escapeRegExp(word), "giu"))].map((match) => ({
39
+ start: match.index,
40
+ end: match.index + match[0].length,
41
+ }));
42
+
43
+ /**
44
+ * prefer の「使わない書き方」が動詞のとき、活用した形の始まり(文の中の字の位置)。「使う書き方」の中に出たものは除く。
45
+ * 大文字小文字だけ違う組(Javascript・JavaScript)は語で照らすと区別が消えるので、字で探す側に任せる。
46
+ */
47
+ export const conjugatedStartsOutside = (sentence: Sentence, entry: LexiconEntry, use: string): number[] => {
48
+ if (entry.pattern.toLowerCase() === use.toLowerCase()) return [];
49
+ const covered = occurrencesOf(sentence.text, use);
50
+ return conjugatedSpans(sentence, entry)
51
+ .filter((span) => !covered.some((cover) => cover.start <= span.start && span.end <= cover.end))
52
+ .map((span) => span.start);
53
+ };
@@ -7,7 +7,8 @@ import type { Token } from "../plugin.ts";
7
7
  const CONTENT_POS = new Set(["NOUN", "PROPN", "NUM", "VERB", "ADJ", "ADV"]);
8
8
 
9
9
  /** 接頭詞・接尾・非自立の語(Bound)と、動詞にするだけの「する」(VerbType=Light)は、付いた語が中身を持つ。 */
10
- const isContent = (token: Token): boolean => CONTENT_POS.has(token.pos) && token.features?.["Bound"] !== "Yes" && token.features?.["VerbType"] !== "Light";
10
+ export const isContent = (token: Token): boolean =>
11
+ CONTENT_POS.has(token.pos) && token.features?.["Bound"] !== "Yes" && token.features?.["VerbType"] !== "Light";
11
12
 
12
13
  /** 原形で照らす(変えました → 変える)。原形の無い語は書いた形で。 */
13
14
  const baseForm = (token: Token): string => (token.lemma ?? token.surface).toLowerCase();
@@ -9,6 +9,7 @@ import { scopedFacts, type ScopedFact } from "../facts/fact-scope.ts";
9
9
  import { factsOutOfStep, writtenValue, type FactOutOfStep } from "../facts/cross-facts.ts";
10
10
  import { factWordsOf } from "./fact-consistency.ts";
11
11
  import { quoteAt } from "./structure-tree.ts";
12
+ import { perUnitsOf } from "./per-unit-words.ts";
12
13
 
13
14
  // cross-doc-fact-conflict reads facts as fact-conflict does (fact-consistency.ts), with two more kinds of value that a docs
14
15
  // site repeats from page to page: an email address and a version of three parts or more (2.4.1, v3).
@@ -32,7 +33,7 @@ const COLON_BEFORE = /[::][\s*_]*$/u;
32
33
  const isEntry = (source: string, fact: Fact): boolean => COLON_BEFORE.test(source.slice(source.lastIndexOf("\n", fact.value.start - 1) + 1, fact.value.start));
33
34
 
34
35
  const factsOf = (doc: ProseDocument, tree: StructureNode): ScopedFact[] => {
35
- const values = factValues(tree, doc.source, namedValues(doc));
36
+ const values = perUnitsOf(doc, factValues(tree, doc.source, namedValues(doc)));
36
37
  const entries = labelledFacts(doc.source, values, factWordsOf(doc)).filter((fact) => isEntry(doc.source, fact));
37
38
  return scopedFacts([...entries, ...tableFacts(doc.source, values)], tree, doc.source, summaryHeadings(doc));
38
39
  };
@@ -3,6 +3,8 @@ import { occurrencesOutside } from "../orthography.ts";
3
3
  import { tokenRuns } from "../custom/token-pattern.ts";
4
4
  import { joinedView, type JoinedView } from "../joined-view.ts";
5
5
  import { boundedMatches } from "../custom/bounded-match.ts";
6
+ import { entriesForGenre } from "../lexicon-genres.ts";
7
+ import { NO_REWRITE } from "../custom/no-rewrite.ts";
6
8
 
7
9
  // The detectors behind a team's custom_rules. Each reports every place it finds, at the rule's level; the spec comes from
8
10
  // the rule (DetectorOptions.custom). Positions are the document's, like every other finding.
@@ -18,6 +20,9 @@ const findingOf = (hit: Hit): Finding => ({
18
20
  values: { matched: hit.matched, preferred: hit.preferred, offset: hit.sentence.span.start + hit.offset },
19
21
  });
20
22
 
23
+ /** A words finding: with no spelling to use (a word-list entry without rewrite), its rule's message for that. */
24
+ const wordsFindingOf = (hit: Hit): Finding => ({ ...findingOf(hit), ...(hit.preferred === "" ? { variant: NO_REWRITE } : {}) });
25
+
21
26
  /**
22
27
  * The sentence with the line breaks that fall inside a word taken out (「関\nする」 reads 「関する」), so words and patterns
23
28
  * are found as the reader reads them. Positions found in it go back to the sentence's own.
@@ -48,7 +53,9 @@ const pairsOf = (
48
53
  spec: { readonly words: readonly { readonly avoid: string; readonly use: string }[] },
49
54
  options: DetectorOptions,
50
55
  ): readonly { avoid: string; use: string }[] =>
51
- spec.words.length > 0 ? spec.words : (options.lexicon ?? []).map((entry) => ({ avoid: entry.pattern, use: entry.rewrite ?? "" }));
56
+ spec.words.length > 0
57
+ ? spec.words
58
+ : entriesForGenre(options.lexicon ?? [], options.genre).map((entry) => ({ avoid: entry.pattern, use: entry.rewrite ?? "" }));
52
59
 
53
60
  /** words: each spelling to avoid, outside the spelling to use (「ユーザ」 inside 「ユーザー」 is not reported). */
54
61
  export const customWords: Detector = (doc, options): Finding[] => {
@@ -58,7 +65,7 @@ export const customWords: Detector = (doc, options): Finding[] => {
58
65
  return doc.sentences.flatMap((sentence) => {
59
66
  const view = readAsWritten(sentence);
60
67
  return pairs.flatMap((pair) =>
61
- occurrencesOutside(view.text, pair.avoid, pair.use).map((start) => findingOf(hitAt(sentence, view, start, start + pair.avoid.length, pair.use))),
68
+ occurrencesOutside(view.text, pair.avoid, pair.use).map((start) => wordsFindingOf(hitAt(sentence, view, start, start + pair.avoid.length, pair.use))),
62
69
  );
63
70
  });
64
71
  };
@@ -1,6 +1,7 @@
1
1
  // The shape of a document's top: whether the lead says anything the title does not, and whether a title or heading
2
2
  // runs too long to scan. Pure; both read only the sections, paragraphs and tokens chaff has already built.
3
3
  import { newContentMorphemes } from "./content-morphemes.ts";
4
+ import { formValueTokens, isFormBlock } from "./form-line.ts";
4
5
  import { trigrams } from "./heading-overlap.ts";
5
6
  import { findingAt, writtenHeadings } from "./markup-finding.ts";
6
7
  import type { Detector, Finding, LengthUnit, MarkupHeading, Paragraph, ProseDocument, Section } from "../plugin.ts";
@@ -38,6 +39,13 @@ const leadOf = (doc: ProseDocument): Lead | undefined => {
38
39
  const lead = title === undefined ? undefined : leadParagraphOf(doc, title);
39
40
  if (title === undefined || lead === undefined || title.headingTokens === undefined) return undefined;
40
41
  const leadTokens = lead.sentences.flatMap((sentence) => sentence.tokens ?? []);
42
+ // A form or a letter opens with fields or a letterhead, not a lead (Invoice number: INV-2026-0318). A line that only copies the title is still one.
43
+ const leadSource = doc.source.slice(lead.span.start, lead.span.end);
44
+ if (
45
+ isFormBlock(leadSource, lead.span.start, leadTokens) &&
46
+ newContentMorphemes(title.headingTokens, formValueTokens(leadSource, lead.span.start, leadTokens)) > 0
47
+ )
48
+ return undefined;
41
49
  const leadText = lead.sentences.map((sentence) => sentence.text).join(" ");
42
50
  return { title, lead, fresh: newContentMorphemes(title.headingTokens, leadTokens), echo: echoPercent(title.heading, leadText) };
43
51
  };
@@ -1,13 +1,15 @@
1
1
  // due-before-issue: the reading half. The issue-date and due-date words come from the language's lexicons
2
2
  // (issue-date-label, due-date-label, deadline-passed-word), and so do the words of minutes (minutes-title-word, meeting-date-label,
3
3
  // action-section-heading, earlier-section-word, action-due-label, item-done-word) and the other pairs of dates that must come in
4
- // order (dated-pair-label, date-now-word, and dated-span-label for the words whose line states a period, read up to its end;
5
- // a table whose header names both columns of a pair, from dated-pair-label and the header-only dated-column-label);
4
+ // order (dated-pair-label, date-now-word, and dated-span-label for the words whose line states a period, read up to its end,
5
+ // or from its start in the group a dated-span-label entry names;
6
+ // a table whose header names both columns of a pair, from dated-pair-label and the header-only dated-column-label;
7
+ // a signature line giving a pair's later date, from the role words of dated-signer-label);
6
8
  // the dates are the structure tree's, and the lines are read with code masked.
7
9
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
8
10
  import { actionDueBeforeMeeting, type ActionWords } from "../structure/action-due.ts";
9
11
  import { columnDatesOutOfOrder } from "../structure/column-date-order.ts";
10
- import { pairedDatesOutOfOrder, type OrderDate } from "../structure/labelled-date-order.ts";
12
+ import { pairedDatesOutOfOrder, type OrderDate, type PairedIssue } from "../structure/labelled-date-order.ts";
11
13
  import { dueBeforeIssue, type DueWords } from "../structure/due-date.ts";
12
14
  import { inDocumentOrder, type StructureIssue } from "../structure/issues.ts";
13
15
  import { proseAndTablesOf } from "../table-text.ts";
@@ -50,17 +52,25 @@ const findingOf = (doc: ProseDocument, issue: StructureIssue, variant?: string):
50
52
  ...(variant === undefined ? {} : { variant }),
51
53
  });
52
54
 
55
+ const variantOf = (issue: PairedIssue): string => {
56
+ if (issue.fromStart === true) return "period-start";
57
+ return issue.period ? "period" : "order";
58
+ };
59
+
53
60
  export const dueDate: Detector = (doc): Finding[] => {
54
61
  if (doc.structure === undefined) return [];
55
62
  const text = proseAndTablesOf(doc);
56
63
  const dates = treeDates(doc.structure);
57
64
  const pairs = doc.lexicons["dated-pair-label"] ?? [];
58
- const spans = periodWordsOf(doc, patternsOf(doc, "dated-span-label"));
65
+ const spanEntries = doc.lexicons["dated-span-label"] ?? [];
66
+ const spans = { ...periodWordsOf(doc, [...new Set(spanEntries.map((entry) => entry.pattern))]), entries: spanEntries };
59
67
  return [
60
68
  ...dueBeforeIssue(text, dates, wordsOf(doc)).map((issue) => findingOf(doc, issue)),
61
- ...pairedDatesOutOfOrder(text, dates, pairs, orderAsidesOf(doc), MAX_RECORD_LINE_GAP, spans).map((issue) =>
62
- findingOf(doc, issue, issue.period ? "period" : "order"),
63
- ),
69
+ ...pairedDatesOutOfOrder(text, dates, pairs, orderAsidesOf(doc), MAX_RECORD_LINE_GAP, {
70
+ spans,
71
+ whole: doc.source,
72
+ signers: doc.lexicons["dated-signer-label"] ?? [],
73
+ }).map((issue) => findingOf(doc, issue, variantOf(issue))),
64
74
  ...columnDatesOutOfOrder(text, dates, [...pairs, ...(doc.lexicons["dated-column-label"] ?? [])], orderAsidesOf(doc)).map((issue) =>
65
75
  findingOf(doc, issue, "order"),
66
76
  ),