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
@@ -135,12 +135,38 @@ export const unitGaps = (values: readonly Measured[]): UnitGap[] => {
135
135
  const unitsOf = (doc: ProseDocument): Set<string> =>
136
136
  new Set(UNIT_LEXICONS.flatMap((name) => (doc.lexicons[name] ?? []).flatMap((entry) => [entry.pattern, entry.pattern.toLowerCase()])));
137
137
 
138
- export const numberWithoutUnit: Detector = (doc: ProseDocument): Finding[] =>
139
- unitGaps(measuredValues(doc.source, doc.prose ?? doc.source, unitsOf(doc))).map((gap) => ({
140
- rule: "number-without-unit",
141
- severity: "warning",
142
- line: 0,
143
- column: 0,
144
- quote: quoteAt(doc.source, gap.value.offset),
145
- values: { value: gap.value.written, name: gap.value.name, unit: gap.unit, offset: gap.value.offset },
146
- }));
138
+ /** Lexicon piece-count-column: the headings of a column that counts whatever its row is, and the units of a hired period. */
139
+ export type PieceCount = { readonly columns: ReadonlySet<string>; readonly periods: ReadonlySet<string> };
140
+
141
+ const WHOLE_NUMBER = /^\d[\d,]*$/u;
142
+ const TABLE_KIND = /^table \d+: /u;
143
+
144
+ /**
145
+ * A bare whole number in a quantity column whose other rows count a hired period (4 days, 2 nights): the count of a
146
+ * piece the row hires or buys (Child seat | 1), which has no unit to lose.
147
+ */
148
+ export const isPieceCount = (gap: UnitGap, count: PieceCount): boolean =>
149
+ TABLE_KIND.test(gap.value.kind) &&
150
+ count.columns.has(gap.value.name.toLowerCase()) &&
151
+ count.periods.has(gap.unit.toLowerCase()) &&
152
+ WHOLE_NUMBER.test(gap.value.written.normalize("NFKC"));
153
+
154
+ const pieceCountOf = (doc: ProseDocument): PieceCount => {
155
+ const entries = doc.lexicons["piece-count-column"] ?? [];
156
+ const patterns = (group: string): Set<string> => new Set(entries.filter((entry) => entry.group === group).map((entry) => entry.pattern.toLowerCase()));
157
+ return { columns: patterns("column"), periods: patterns("period") };
158
+ };
159
+
160
+ export const numberWithoutUnit: Detector = (doc: ProseDocument): Finding[] => {
161
+ const count = pieceCountOf(doc);
162
+ return unitGaps(measuredValues(doc.source, doc.prose ?? doc.source, unitsOf(doc)))
163
+ .filter((gap) => !isPieceCount(gap, count))
164
+ .map((gap) => ({
165
+ rule: "number-without-unit",
166
+ severity: "warning",
167
+ line: 0,
168
+ column: 0,
169
+ quote: quoteAt(doc.source, gap.value.offset),
170
+ values: { value: gap.value.written, name: gap.value.name, unit: gap.unit, offset: gap.value.offset },
171
+ }));
172
+ };
@@ -8,6 +8,7 @@ import { furiganaSpans } from "../furigana.ts";
8
8
  import { acronymsIn, isCapitalsNotSpelling } from "../capitals-with-small.ts";
9
9
  import { isPartOfAddress } from "./address-word.ts";
10
10
  import { wholeWordRuns, type WholeWordRun } from "../whole-word-runs.ts";
11
+ import { entriesForGenre } from "../lexicon-genres.ts";
11
12
 
12
13
  /**
13
14
  * A word found in the document: where it is, which sentence it is in, its key and spelling, how it is written when that differs, and
@@ -41,7 +42,8 @@ const IDIOM = "orthographic-variant-idiom";
41
42
  /** Lexicon: words the tokenizer cuts in one spelling and not the other (お客様, お客 and さま). Each is read whole, keyed by its group. */
42
43
  const WHOLE_WORD = "orthographic-variant-whole-word";
43
44
 
44
- const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
45
+ const patternsOf = (doc: ProseDocument, id: string, genre: string | undefined): string[] =>
46
+ entriesForGenre(doc.lexicons[id] ?? [], genre).map((entry) => entry.pattern);
45
47
 
46
48
  /**
47
49
  * Whether a stretch of the sentence is outside a quotation, the team's names and a reading in brackets (HTTP(えいちてぃーてぃーぴー)):
@@ -300,8 +302,8 @@ const cellPlace = (cell: TableCell, names: readonly string[]): Place => {
300
302
  */
301
303
  export const orthographicVariant: Detector = (doc, options): Finding[] => {
302
304
  const skips: Skips = {
303
- skip: new Set([...patternsOf(doc, DISTINCT), ...patternsOf(doc, FUKUSHI)]),
304
- idioms: new Set(patternsOf(doc, IDIOM)),
305
+ skip: new Set([...patternsOf(doc, DISTINCT, options.genre), ...patternsOf(doc, FUKUSHI, options.genre)]),
306
+ idioms: new Set(patternsOf(doc, IDIOM, options.genre)),
305
307
  wholeWords: new Map((doc.lexicons[WHOLE_WORD] ?? []).map((entry) => [entry.pattern, entry.group ?? entry.pattern])),
306
308
  };
307
309
  const names = doc.names ?? [];
@@ -1,18 +1,26 @@
1
- import type { Detector, Finding, ProseDocument, Sentence, Span } from "../plugin.ts";
1
+ import type { Detector, Finding, LexiconEntry, ProseDocument, Sentence, Span } from "../plugin.ts";
2
+ import { conjugatedStartsOutside } from "./conjugated-entry.ts";
2
3
  import { calendarRuns, calendarUnitsOf, type CalendarUnits } from "../calendar-number.ts";
3
4
  import { escapeRegExp, latinBoundaries, occurrencesOutside, type Boundary, type SpacingKind } from "../orthography.ts";
4
- import { minorityReport } from "../spacing-minority.ts";
5
+ import { minorityReport, withoutSideOnTie } from "../spacing-minority.ts";
5
6
  import { isWithinAny, quotedSpans } from "../quoted-span.ts";
6
7
  import { digitRunAround, endsWithDivisionLabel, isNumberName, sequenceLabelStarts, type NameContext } from "../number-name.ts";
7
8
  import { isSpacedLocationPart, type FloorWords } from "../location-part.ts";
8
- import { isNameSeparator, type OrganizationWords } from "../name-separator.ts";
9
+ import { isFieldSeparator, isNameSeparator, type OrganizationWords } from "../name-separator.ts";
9
10
  import { addressSpans, clockTimeSpans, identifierSpans, isInsideSpan } from "../spacing-code.ts";
10
11
 
12
+ /** 書いた形の出現に、動詞の活用した形(行う → 行います)を足したもの。同じ位置は一度だけ。 */
13
+ const avoidedStarts = (sentence: Sentence, entry: LexiconEntry, use: string): number[] => {
14
+ const written = occurrencesOutside(sentence.text, entry.pattern, use);
15
+ const conjugated = conjugatedStartsOutside(sentence, entry, use).filter((at) => !written.includes(at));
16
+ return [...written, ...conjugated].toSorted((left, right) => left - right);
17
+ };
18
+
11
19
  /** チームが chaff.yaml の prefer に書いた「使わない書き方」。書いていなければ何も言わない。 */
12
20
  export const preferredTerm: Detector = (doc, options): Finding[] => {
13
- const pairs = (options.lexicon ?? []).flatMap((entry) => (entry.instead_of === undefined ? [] : [{ avoid: entry.pattern, use: entry.instead_of }]));
21
+ const pairs = (options.lexicon ?? []).flatMap((entry) => (entry.instead_of === undefined ? [] : [{ entry, avoid: entry.pattern, use: entry.instead_of }]));
14
22
  const hits = doc.sentences.flatMap((sentence) =>
15
- pairs.flatMap((pair) => occurrencesOutside(sentence.text, pair.avoid, pair.use).map((at) => ({ sentence, at, pair }))),
23
+ pairs.flatMap((pair) => avoidedStarts(sentence, pair.entry, pair.use).map((at) => ({ sentence, at, pair }))),
16
24
  );
17
25
  if (hits.length === 0 || hits.length < options.limit) return [];
18
26
  return hits.map((hit) => ({
@@ -91,7 +99,7 @@ type SentenceCodes = {
91
99
  * 日付・時刻は前の境目(「は 9月」「午後3時」「令和 3 年」)も数えない。日付はまとめて一つの書き方で、数量の空け方の票にはしない。コロンで書いた時刻(13:30)も同じ。
92
100
  * メールアドレス・URL の前後の境目も数えない(spacing-code.ts)。「予約番号 MN-48215 を」の番号の前後も、番号を文から区切る空白なので数えない。
93
101
  * 「本社 5階」のように名前の後ろに空白で区切った階・部屋の番号の前の空白も、所在の組の区切りなので数えない(location-part.ts)。
94
- * 「経営企画部 IR担当」のように名前だけを並べた行で、名前と名前を分ける空白も数えない(name-separator.ts)。
102
+ * 「経営企画部 IR担当」のように名前だけを並べた行で、名前と名前を分ける空白も、「所属:経済学科 1年」のように項目の値の組を分ける空白も数えない(name-separator.ts)。
95
103
  */
96
104
  const isCounted = (sentence: Sentence, boundary: Boundary, context: NumberContext, codes: SentenceCodes): boolean => {
97
105
  if (followsItemNumber(sentence.text, boundary, context.itemNumbers) || besideSpan(codes.identifiers, boundary)) return false;
@@ -103,6 +111,7 @@ const isCounted = (sentence: Sentence, boundary: Boundary, context: NumberContex
103
111
  if (run === undefined) return true;
104
112
  if (codes.calendar.has(run.start)) return false;
105
113
  if (boundary.kind === "before-digit" && isSpacedLocationPart(sentence.text, run, sentence.tokens, sentence.span.start, context.floors)) return false;
114
+ if (isFieldSeparator(sentence.text, boundary, sentence.tokens, sentence.span.start)) return false;
106
115
  return !isNumberName(sentence.text, run, sentence.tokens, sentence.span.start, context);
107
116
  };
108
117
 
@@ -135,9 +144,9 @@ const findingAt = (entry: Located, values: Finding["values"], variant?: string):
135
144
  values: { ...values, offset: entry.sentence.span.start + entry.offset },
136
145
  });
137
146
 
138
- /** 一つの種類の境目の指摘。少ないほうを 1 箇所ずつか、書き方が二通りあれば 1 件で(spacing-minority.ts)。 */
147
+ /** 一つの種類の境目の指摘。少ないほうを 1 箇所ずつか、書き方が二通りあれば 1 件で(spacing-minority.ts)。同数ならどちらの側にも立たない。 */
139
148
  const findingsOf = (kind: SpacingKind, ofKind: readonly Located[], limit: number): Finding[] => {
140
- const report = minorityReport(ofKind, limit);
149
+ const report = withoutSideOnTie(minorityReport(ofKind, limit), ofKind);
141
150
  if (report === undefined) return [];
142
151
  if (report.mode === "mixed") {
143
152
  const { first, odd, spaced, touching } = report;
@@ -0,0 +1,24 @@
1
+ import type { ProseDocument, StructureNode } from "../plugin.ts";
2
+ import { withPerUnits, type PerUnitMark, type PerUnitTemplate, type PerUnitWords } from "../facts/per-unit.ts";
3
+ import { factValues, type FactValue } from "../facts/fact-values.ts";
4
+ import { nameSpans } from "../compare/proper-nouns.ts";
5
+
6
+ const marksOf = (doc: ProseDocument, id: string): PerUnitMark[] =>
7
+ (doc.lexicons[id] ?? []).map((entry): PerUnitMark => ({ pattern: entry.pattern, group: entry.group ?? entry.pattern }));
8
+
9
+ /** 何あたりかの語: 決まった印(per-unit-mark)、型(fact-per-unit)、単位の語(rate-unit)、読まない百分率(percent-unit)、単価の列の見出し(unit-price-column)。 */
10
+ const perUnitWordsOf = (doc: ProseDocument): PerUnitWords => ({
11
+ marks: marksOf(doc, "per-unit-mark"),
12
+ templates: (doc.lexicons["fact-per-unit"] ?? []).map((entry): PerUnitTemplate => ({ pattern: entry.pattern, position: entry.position ?? "before" })),
13
+ units: marksOf(doc, "rate-unit"),
14
+ percentUnits: (doc.lexicons["percent-unit"] ?? []).map((entry) => entry.pattern),
15
+ priceHeadings: (doc.lexicons["unit-price-column"] ?? []).map((entry) =>
16
+ entry.group === undefined ? { pattern: entry.pattern } : { pattern: entry.pattern, group: entry.group },
17
+ ),
18
+ });
19
+
20
+ /** 文書の値に、何あたりか(1kmあたり15円 の km)を付ける。 */
21
+ export const perUnitsOf = <T extends FactValue>(doc: ProseDocument, values: readonly T[]): T[] => withPerUnits(doc.source, values, perUnitWordsOf(doc));
22
+
23
+ /** 木の数量と日付と固有名詞(factValues)に、何あたりかを付けたもの。 */
24
+ export const perUnitValues = (doc: ProseDocument, tree: StructureNode): FactValue[] => perUnitsOf(doc, factValues(tree, doc.source, nameSpans(doc)));
@@ -4,11 +4,9 @@
4
4
  // number-word (digit), and a range of counts is joined by range-connector or amount-range-word.
5
5
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
6
6
  import { periodMultipleMismatches, type PeriodMultipleWords } from "../structure/period-multiple.ts";
7
- import type { StatedAmount } from "../structure/stated-multiple.ts";
8
- import { scaledAmountOf, scaleWordsOf } from "./amount-scale.ts";
9
- import { amountsIn, formsOf } from "./currency-notation.ts";
10
7
  import { proseAndTablesOf } from "../table-text.ts";
11
8
  import { quoteAround } from "./quote-around.ts";
9
+ import { statedAmountsOf } from "./stated-amounts.ts";
12
10
 
13
11
  const patternsOf = (doc: ProseDocument, lexicon: string, group?: string): string[] =>
14
12
  (doc.lexicons[lexicon] ?? []).filter((entry) => group === undefined || entry.group === group).map((entry) => entry.pattern);
@@ -27,23 +25,9 @@ const wordsOf = (doc: ProseDocument): PeriodMultipleWords => ({
27
25
  numberWords: numberWordsOf(doc),
28
26
  });
29
27
 
30
- const amountsOf = (text: string, doc: ProseDocument): StatedAmount[] => {
31
- const scales = scaleWordsOf(doc);
32
- return amountsIn(
33
- text,
34
- formsOf(doc),
35
- scales.map((scale) => scale.word),
36
- ).flatMap((amount) => {
37
- const read = scaledAmountOf(text, amount, scales);
38
- return read === undefined
39
- ? []
40
- : [{ offset: read.offset, end: amount.offset + amount.written.length, currency: read.currency, value: read.value, scale: read.unit }];
41
- });
42
- };
43
-
44
28
  export const periodMultipleMismatch: Detector = (doc): Finding[] => {
45
29
  const text = proseAndTablesOf(doc);
46
- return periodMultipleMismatches(text, amountsOf(text, doc), wordsOf(doc)).map((issue) => ({
30
+ return periodMultipleMismatches(text, statedAmountsOf(text, doc), wordsOf(doc)).map((issue) => ({
47
31
  rule: "period-multiple-mismatch",
48
32
  severity: "warning",
49
33
  line: 0,
@@ -1,13 +1,14 @@
1
1
  // reference-number-variant: a document's own reference number written with two neighbouring characters swapped somewhere
2
2
  // else in the document, after a label of the same kind (reference-numbers.ts), or with no label where only one labelled
3
- // code swaps to it (unlabelled-references.ts); and the document's one vehicle plate written
3
+ // code swaps to it (unlabelled-references.ts), or as the one code a product document is about (subject-codes.ts); and the document's one vehicle plate written
4
4
  // once with one character of its serial changed (vehicle-plates.ts).
5
- import { labelledReferenceNumbers, referenceVariants, type ReferenceNumber } from "../reference-numbers.ts";
5
+ import { labelledReferenceNumbers, referenceVariants, type ReferenceNumber, type ReferenceVariant } from "../reference-numbers.ts";
6
6
  import { labelledPlates, plateVariants } from "../vehicle-plates.ts";
7
- import { tableCodes, tableLabelledCodes, unlabelledVariants } from "../unlabelled-references.ts";
7
+ import { isCodeWith, tableCodes, tableLabelledCodes, unlabelledVariants } from "../unlabelled-references.ts";
8
+ import { isSubjectCode, MIN_SUBJECT_DIGITS, subjectCodeVariants } from "../subject-codes.ts";
8
9
  import { proseAndTablesOf } from "../table-text.ts";
9
10
  import { quoteAt } from "./structure-tree.ts";
10
- import type { Detector, Finding, OptionValue } from "../plugin.ts";
11
+ import type { Detector, Finding, OptionValue, ProseDocument } from "../plugin.ts";
11
12
 
12
13
  const PLATE_SHAPES = "vehicle-plate";
13
14
  const SUBSTITUTED = "substituted";
@@ -25,6 +26,18 @@ const finding = (number: ReferenceNumber, other: ReferenceNumber, source: string
25
26
  /** Kinds a document lists many of (item codes): two labelled ones are two things, so only a code with no label is compared with them. */
26
27
  const listedKindsOf = (value: OptionValue | undefined): readonly string[] => (typeof value === "object" ? value : []);
27
28
 
29
+ const TITLE_DEPTH = 1;
30
+
31
+ /** The title as the source writes it, where it starts: the prose masks a heading's line. */
32
+ const titleOf = (doc: ProseDocument): { start: number; text: string } | undefined => {
33
+ const title = doc.markup?.headings.find((heading) => heading.depth === TITLE_DEPTH);
34
+ return title === undefined ? undefined : { start: title.start, text: doc.source.slice(title.start, title.end) };
35
+ };
36
+
37
+ /** One finding per place, the first reading kept: a code may be read both as an unlabelled item code and as the document's own. */
38
+ const firstAtEachOffset = (variants: readonly ReferenceVariant[]): ReferenceVariant[] =>
39
+ variants.filter((variant, index) => variants.findIndex((other) => other.number.offset === variant.number.offset) === index);
40
+
28
41
  export const referenceNumberVariant: Detector = (doc, options): Finding[] => {
29
42
  const labels = options.lexicon ?? [];
30
43
  if (labels.length === 0) return [];
@@ -36,9 +49,18 @@ export const referenceNumberVariant: Detector = (doc, options): Finding[] => {
36
49
  const listed = new Set(listedKindsOf(options.settings?.["listed_kinds"]));
37
50
  const withTables = proseAndTablesOf(doc);
38
51
  const labelled = [...numbers, ...tableLabelledCodes(withTables, labels)];
52
+ const subjectCodes = subjectCodeVariants({
53
+ prose: text,
54
+ title: titleOf(doc),
55
+ labels,
56
+ listed,
57
+ tabled: tableLabelledCodes(withTables, labels, isSubjectCode),
58
+ known: tableCodes(withTables, isCodeWith(MIN_SUBJECT_DIGITS)),
59
+ });
60
+ const unlabelled = firstAtEachOffset([...unlabelledVariants(text, labelled, tableCodes(withTables)), ...subjectCodes]);
39
61
  return [
40
62
  ...referenceVariants(numbers.filter((number) => !listed.has(number.label))).map(({ number, other }) => finding(number, other, doc.source)),
41
- ...unlabelledVariants(text, labelled, tableCodes(withTables)).map(({ number, other }) => finding(number, other, doc.source)),
63
+ ...unlabelled.map(({ number, other }) => finding(number, other, doc.source)),
42
64
  ...plateVariants(plates).map(({ number, other }) => finding(number, other, doc.source, SUBSTITUTED)),
43
65
  ].toSorted((a, b) => Number(a.values["offset"]) - Number(b.values["offset"]));
44
66
  };
@@ -0,0 +1,4 @@
1
+ import type { Detector } from "../../plugin.ts";
2
+ import { conditionToki } from "../condition-toki.ts";
3
+
4
+ export const detector: Detector = conditionToki;
@@ -0,0 +1,4 @@
1
+ import type { Detector } from "../../plugin.ts";
2
+ import { formulaAmount } from "../formula-amount.ts";
3
+
4
+ export const detector: Detector = formulaAmount;
@@ -4,11 +4,9 @@
4
4
  // range of rent is joined by range-connector or amount-range-word.
5
5
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
6
6
  import { rentMultipleMismatches, type RentMultipleWords } from "../structure/rent-multiple.ts";
7
- import type { StatedAmount } from "../structure/stated-multiple.ts";
8
- import { scaledAmountOf, scaleWordsOf } from "./amount-scale.ts";
9
- import { amountsIn, formsOf } from "./currency-notation.ts";
10
7
  import { proseAndTablesOf } from "../table-text.ts";
11
8
  import { quoteAround } from "./quote-around.ts";
9
+ import { statedAmountsOf } from "./stated-amounts.ts";
12
10
 
13
11
  const patternsOf = (doc: ProseDocument, lexicon: string, group?: string): string[] =>
14
12
  (doc.lexicons[lexicon] ?? []).filter((entry) => group === undefined || entry.group === group).map((entry) => entry.pattern);
@@ -30,23 +28,9 @@ const wordsOf = (doc: ProseDocument): RentMultipleWords => ({
30
28
  numberWords: numberWordsOf(doc),
31
29
  });
32
30
 
33
- const amountsOf = (text: string, doc: ProseDocument): StatedAmount[] => {
34
- const scales = scaleWordsOf(doc);
35
- return amountsIn(
36
- text,
37
- formsOf(doc),
38
- scales.map((scale) => scale.word),
39
- ).flatMap((amount) => {
40
- const read = scaledAmountOf(text, amount, scales);
41
- return read === undefined
42
- ? []
43
- : [{ offset: read.offset, end: amount.offset + amount.written.length, currency: read.currency, value: read.value, scale: read.unit }];
44
- });
45
- };
46
-
47
31
  export const rentMultipleMismatch: Detector = (doc): Finding[] => {
48
32
  const text = proseAndTablesOf(doc);
49
- return rentMultipleMismatches(text, amountsOf(text, doc), wordsOf(doc)).map((issue) => ({
33
+ return rentMultipleMismatches(text, statedAmountsOf(text, doc), wordsOf(doc)).map((issue) => ({
50
34
  rule: "rent-multiple-mismatch",
51
35
  severity: "warning",
52
36
  line: 0,
@@ -4,15 +4,8 @@ import { factValues, type FactValue } from "../facts/fact-values.ts";
4
4
  import { cellsOf, tablesOf } from "../facts/table-facts.ts";
5
5
  import { scopedFacts, type ScopedFact } from "../facts/fact-scope.ts";
6
6
  import { withoutEdgeMarks } from "../facts/trim-marks.ts";
7
- import {
8
- periodOf,
9
- rowSentenceConflicts,
10
- type Amount,
11
- type AmountRow,
12
- type PeriodMark,
13
- type SubjectSentence,
14
- type SubjectWords,
15
- } from "../facts/row-sentence-amounts.ts";
7
+ import { rowSentenceConflicts, type Amount, type AmountRow, type SubjectSentence, type SubjectWords } from "../facts/row-sentence-amounts.ts";
8
+ import { perUnitsOf } from "./per-unit-words.ts";
16
9
  import { linesOf, type Line } from "../structure/lines.ts";
17
10
  import { quoteAt } from "./structure-tree.ts";
18
11
 
@@ -57,19 +50,11 @@ const subjectWordsOf = (doc: ProseDocument): SubjectWords => ({
57
50
  conditions: patternsOf(doc, "fact-amount-condition"),
58
51
  });
59
52
 
60
- const periodMarksOf = (doc: ProseDocument): PeriodMark[] =>
61
- (doc.lexicons["per-unit-mark"] ?? []).map((entry): PeriodMark => ({ pattern: entry.pattern, group: entry.group ?? entry.pattern }));
62
-
63
- /** 金額: 通貨の語彙表の印を単位に書いた数量。前後に期間あたりの印があれば、その期間も。 */
53
+ /** 金額: 通貨の語彙表の印を単位に書いた数量。何あたりの金額(日額、1kmあたり)は、その単位も。 */
64
54
  const amountsOf = (doc: ProseDocument, tree: StructureNode): Amount[] => {
65
55
  const currencies = new Set(patternsOf(doc, "currency-notation").map((pattern) => pattern.normalize("NFKC")));
66
- const marks = periodMarksOf(doc);
67
- return factValues(tree, doc.source, nameSpans(doc))
68
- .filter((value) => value.kind === "quantity" && currencies.has(value.unit))
69
- .map((value): Amount => {
70
- const period = periodOf(doc.source, value, marks);
71
- return period === undefined ? value : { ...value, period };
72
- });
56
+ const amounts = factValues(tree, doc.source, nameSpans(doc)).filter((value) => value.kind === "quantity" && currencies.has(value.unit));
57
+ return perUnitsOf(doc, amounts);
73
58
  };
74
59
 
75
60
  /** 表の行の金額と、その行の見出しを主語にした文の金額の食い違い。名前付きの値として読めた文の値は、ほかの読みが比べる。 */
@@ -0,0 +1,20 @@
1
+ // The amounts a document states, as the multiple and total checks read them: currency-notation's written amounts, each
2
+ // read with amount-multiplier's words of scale (1億2,000万円 is one amount), the ones that cannot be read left out.
3
+ import type { ProseDocument } from "../plugin.ts";
4
+ import type { StatedAmount } from "../structure/stated-multiple.ts";
5
+ import { scaledAmountOf, scaleWordsOf } from "./amount-scale.ts";
6
+ import { amountsIn, formsOf } from "./currency-notation.ts";
7
+
8
+ export const statedAmountsOf = (text: string, doc: ProseDocument): StatedAmount[] => {
9
+ const scales = scaleWordsOf(doc);
10
+ return amountsIn(
11
+ text,
12
+ formsOf(doc),
13
+ scales.map((scale) => scale.word),
14
+ ).flatMap((amount) => {
15
+ const read = scaledAmountOf(text, amount, scales);
16
+ return read === undefined
17
+ ? []
18
+ : [{ offset: read.offset, end: amount.offset + amount.written.length, currency: read.currency, value: read.value, scale: read.unit }];
19
+ });
20
+ };
@@ -3,6 +3,7 @@
3
3
  import { stepTimeSlip, type StepTimeWords } from "../structure/step-times.ts";
4
4
  import type { Mark } from "../structure/time-marks.ts";
5
5
  import { quoteAt } from "./structure-tree.ts";
6
+ import { withoutCodeBlocks } from "./code-fences.ts";
6
7
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
7
8
 
8
9
  const SECONDS_PER_HOUR = 3600;
@@ -35,7 +36,7 @@ const wordsOf = (doc: ProseDocument): StepTimeWords => {
35
36
  };
36
37
 
37
38
  export const stepTimeSumMismatch: Detector = (doc): Finding[] => {
38
- const slip = stepTimeSlip(doc.source, wordsOf(doc));
39
+ const slip = stepTimeSlip(withoutCodeBlocks(doc.source), wordsOf(doc));
39
40
  if (slip === undefined) return [];
40
41
  return [
41
42
  {
@@ -14,6 +14,7 @@ import { withCompoundHours } from "../structure/compound-hours.ts";
14
14
  import { timeLengths } from "../derived/time-lengths.ts";
15
15
  import { measureUnitsOf } from "../facts/measure-units.ts";
16
16
  import { rangeFrameOf, reversedRanges, type DatedSpan, type RangeWords } from "../structure/date-range.ts";
17
+ import { isStartEndRange, startEndWordsOf } from "../structure/start-end-range.ts";
17
18
  import { afterLabel } from "../structure/stated-period.ts";
18
19
  import { afterSpanLabel } from "../structure/span-label.ts";
19
20
  import { percentSumMismatches, type ShareWords } from "../structure/percent-sum.ts";
@@ -264,6 +265,9 @@ const totalIssues = (doc: ProseDocument, tree: NonNullable<ProseDocument["struct
264
265
  breakdowns: patternsOf(doc, "breakdown-phrase"),
265
266
  discounts: patternsOf(doc, "discount-word"),
266
267
  joiners: patternsOf(doc, "breakdown-gap-joiner"),
268
+ leads: patternsOf(doc, "total-breakdown-lead"),
269
+ partials: patternsOf(doc, "breakdown-partial-word"),
270
+ backReferences: patternsOf(doc, "total-back-reference"),
267
271
  };
268
272
  const prose = proseTotalMismatches(
269
273
  doc.source,
@@ -310,11 +314,12 @@ const labelledAt =
310
314
  return after !== undefined && offset >= lineStart + after;
311
315
  };
312
316
 
313
- /** 期間の終わりが始まりより前。範囲の記号と語は言語パッケージの語彙表(range-connector、range-opener、range-closer)から取る。 */
317
+ /** 期間の終わりが始まりより前。範囲の記号と語は言語パッケージの語彙表(range-connector、range-opener、range-closer、range-start-end)から取る。 */
314
318
  export const dateRangeReversed: Detector = (doc): Finding[] => {
315
319
  if (doc.structure === undefined) return [];
316
320
  const dates = datedSpans(doc.structure);
317
- return reversedRanges(doc.source, dates, rangeWordsOf(doc), labelledAt(doc))
321
+ const startEnd = startEndWordsOf(doc.lexicons["range-start-end"] ?? [], patternsOf(doc, "weekday"));
322
+ return reversedRanges(doc.source, dates, rangeWordsOf(doc), labelledAt(doc), (start, end) => isStartEndRange(doc.source, start, end, startEnd))
318
323
  .filter((issue) => {
319
324
  const start = dateAt(dates, issue.offset);
320
325
  return !quotedDates(doc, dates[start], dates[start + 1]);
@@ -2,7 +2,8 @@ import { proseText } from "../measure.ts";
2
2
  import { joinWords } from "./word-list.ts";
3
3
  import { wordsOf } from "./structure.ts";
4
4
  import { nameSpans } from "../team-names.ts";
5
- import type { Detector, Finding, ProseDocument, Sentence, Span, Token } from "../plugin.ts";
5
+ import { conjugatedSpans } from "./conjugated-entry.ts";
6
+ import type { Detector, Finding, LexiconEntry, ProseDocument, Sentence, Span, Token } from "../plugin.ts";
6
7
 
7
8
  /**
8
9
  * チームの言葉。社内でしか通じない語を、チームが chaff.yaml に自分で並べる。
@@ -12,19 +13,24 @@ import type { Detector, Finding, ProseDocument, Sentence, Span, Token } from "..
12
13
  */
13
14
  /**
14
15
  * 表層でも原形でも当てる。利用者は辞書形で書く(「握る」)が、本文は活用している(「握った」)。
16
+ * 複合動詞(「巻き取る」)は語に割れるので、語の並びで原形に照らす(「巻き取ります」)。
15
17
  * 品詞解析があれば原形で当たり、無くても表層で当たる。要求はしない。
16
18
  */
17
- const matches = (sentence: Sentence, word: string): boolean => {
19
+ const matches = (sentence: Sentence, entry: LexiconEntry): boolean => {
18
20
  // 大文字小文字は区別しない。英語の文頭の「Circle back」も「circle back」として当てる。
19
- const wanted = word.toLowerCase();
20
- return sentence.text.toLowerCase().includes(wanted) || (sentence.tokens ?? []).some((token) => token.lemma?.toLowerCase() === wanted);
21
+ const wanted = entry.pattern.toLowerCase();
22
+ return (
23
+ sentence.text.toLowerCase().includes(wanted) ||
24
+ (sentence.tokens ?? []).some((token) => token.lemma?.toLowerCase() === wanted) ||
25
+ conjugatedSpans(sentence, entry).length > 0
26
+ );
21
27
  };
22
28
 
23
29
  export const internalJargon: Detector = (doc, options): Finding[] => {
24
- const words = (options.lexicon ?? []).map((entry) => entry.pattern);
25
- if (words.length === 0) return [];
30
+ const entries = options.lexicon ?? [];
31
+ if (entries.length === 0) return [];
26
32
  const hits = doc.sentences.flatMap((sentence) => {
27
- const matched = words.find((word) => matches(sentence, word));
33
+ const matched = entries.find((entry) => matches(sentence, entry))?.pattern;
28
34
  return matched === undefined ? [] : [{ sentence, matched }];
29
35
  });
30
36
  if (hits.length < options.limit) return [];
@@ -11,6 +11,7 @@ import { reversedTimeRanges } from "../structure/time-range.ts";
11
11
  import { cellMinutes, reversedShiftRows, showsOvernightWork } from "../structure/shift-times.ts";
12
12
  import { pairedTimesOutOfOrder } from "../structure/labelled-time-order.ts";
13
13
  import { quoteAt, rangeWordsOf } from "./structure-tree.ts";
14
+ import { withoutCodeBlocks } from "./code-fences.ts";
14
15
 
15
16
  // 一日の予定の時刻の順番と、語の決まった二つの時刻の順番(time-order)、発より前の着(arrival-before-departure)、移動の時間より短い乗り継ぎ(connection-time-short)。時刻は compare/clock-time.ts が読み、
16
17
  // 発着・翌日・時間帯の語は言語パッケージの語彙表(leg-mark、leg-column、day-shift-mark、time-zone、local-time-mark)から取る。
@@ -43,11 +44,12 @@ const variantOf = (issue: StructureIssue, variant: string | undefined): string |
43
44
  return "end_label" in issue.values ? "columns" : undefined;
44
45
  };
45
46
 
46
- /** 表と箇条書きを行のまま読むので、原文を渡す(doc.prose は表を覆う)。 */
47
+ /** 表と箇条書きを行のまま読むので、原文を渡す(doc.prose は表を覆う)。コードブロックは例なので覆う。 */
47
48
  const detectorOf =
48
49
  (rule: string, find: Finder, variant?: string): Detector =>
49
- (doc): Finding[] =>
50
- find(doc.source, timesOf(doc.source), datesOf(doc), timeWordsOf(doc), doc).map((issue) => {
50
+ (doc): Finding[] => {
51
+ const source = withoutCodeBlocks(doc.source);
52
+ return find(source, timesOf(source), datesOf(doc), timeWordsOf(doc), doc).map((issue) => {
51
53
  const named = variantOf(issue, variant);
52
54
  return {
53
55
  rule,
@@ -59,6 +61,7 @@ const detectorOf =
59
61
  ...(named === undefined ? {} : { variant: named }),
60
62
  };
61
63
  });
64
+ };
62
65
 
63
66
  const timeOrderInList: Detector = detectorOf("time-order", timeOrderBreaks);
64
67
  /** 語の決まった二つの時刻(開場と開演)。語は語彙表 timed-pair-label から取る。 */
@@ -1,5 +1,7 @@
1
1
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
2
2
  import { isKnownWord, isSplitWord, suggestionFor, wordsToCheck, type CheckedWord, type Speller } from "../spelling.ts";
3
+ import { parse } from "../markdown-read.ts";
4
+ import { eachPreOrder } from "../tree-walk.ts";
3
5
  import { quoteAt } from "./structure-tree.ts";
4
6
 
5
7
  /** これより短い語は見ない。短い語は一字違いの語が多すぎて言い直しが決まらず(tost は test か toast か)、略した語(impl)も多い。 */
@@ -24,14 +26,30 @@ const usedOnce = (words: readonly CheckedWord[]): CheckedWord[] => {
24
26
  return words.filter(({ word }) => counts.get(word) === 1);
25
27
  };
26
28
 
29
+ const LETTERS = /\p{L}+/gu;
30
+
31
+ /** 文書がコード(コードの区画と `…`)に書いた語。コードに書いた名前(`tidyq check` の tidyq)は、地の文でも打ち間違いではない。 */
32
+ export const codeWordsOf = (source: string): Set<string> => {
33
+ const words = new Set<string>();
34
+ eachPreOrder(parse(source), (node) => {
35
+ if (node.type === "code" || node.type === "inlineCode")
36
+ (node.value ?? "")
37
+ .toLowerCase()
38
+ .match(LETTERS)
39
+ ?.forEach((word) => words.add(word));
40
+ });
41
+ return words;
42
+ };
43
+
27
44
  /**
28
45
  * 辞書に無い英語の語で、一字違いの辞書の語があるもの(recieve → receive)。辞書は adapter が持ち、無い言語では動かない。
29
- * 大文字を含む語(固有名詞・略語)、コード・URL の中、頭の字を分けた語の残り、二度以上使う語、言い直しの無い語は言わない。
46
+ * 大文字を含む語(固有名詞・略語)、コード・URL の中、頭の字を分けた語の残り、二度以上使う語、言い直しの無い語、
47
+ * 文書がコードにも書いた語は言わない。
30
48
  */
31
49
  export const unknownWord: Detector = (doc): Finding[] => {
32
50
  if (doc.dictionary === undefined) return [];
33
51
  const speller = spellerOf(doc, doc.dictionary());
34
- const known = new Set(patternsOf(doc, "known-misspelling"));
52
+ const known = new Set([...patternsOf(doc, "known-misspelling"), ...codeWordsOf(doc.source)]);
35
53
  const words = wordsToCheck(doc.prose ?? doc.source, MIN_LENGTH, MAX_LENGTH).filter(({ offset }) => !isSplitWord(doc.source, offset));
36
54
  const used = new Set(words.map(({ word }) => word).filter((word) => isKnownWord(word, speller)));
37
55
  return usedOnce(words).flatMap(({ offset, word }) => {
@@ -4,6 +4,7 @@ import { paragraphsOf } from "../derived/period-counts.ts";
4
4
  import { timeLengths, type TimeLength } from "../derived/time-lengths.ts";
5
5
  import { limitWordsOf, marksOf, periodCountWordsOf } from "./use-count-words.ts";
6
6
  import { quoteAt } from "./structure-tree.ts";
7
+ import { withoutCodeBlocks } from "./code-fences.ts";
7
8
 
8
9
  // 使う間隔の下限と期間あたりの回数の上限が両立しない、または表の回数と合わない(interval-count-mismatch)。
9
10
  // 語は use-count-word と use-interval-word、長さの単位は unit-time から取る。
@@ -14,8 +15,8 @@ const SECONDS_PER_MINUTE = 60;
14
15
  const patternsOf = (doc: ProseDocument, lexicon: string, weight?: number): string[] =>
15
16
  (doc.lexicons[lexicon] ?? []).filter((entry) => weight === undefined || entry.weight === weight).map((entry) => entry.pattern);
16
17
 
17
- const lengthsOf = (doc: ProseDocument): TimeLength[] =>
18
- timeLengths(doc.source, {
18
+ const lengthsOf = (doc: ProseDocument, text: string): TimeLength[] =>
19
+ timeLengths(text, {
19
20
  hourUnits: patternsOf(doc, "unit-time", SECONDS_PER_HOUR),
20
21
  minuteUnits: patternsOf(doc, "unit-time", SECONDS_PER_MINUTE),
21
22
  halves: patternsOf(doc, "length-half"),
@@ -39,8 +40,10 @@ const valuesOf = (doc: ProseDocument, mismatch: IntervalMismatch): Record<string
39
40
  ? { count: written(doc, mismatch.count), interval: written(doc, mismatch.interval), needed: mismatch.neededHours, hours: mismatch.count.hours }
40
41
  : { count: written(doc, mismatch.count), column: mismatch.column, table: mismatch.tableCount };
41
42
 
42
- export const intervalCountMismatch: Detector = (doc): Finding[] =>
43
- intervalCountMismatches(doc.source, paragraphsOf(doc.source), lengthsOf(doc), wordsOf(doc)).map((mismatch) => ({
43
+ /** コードブロックの中の用法は例なので、覆って読む。 */
44
+ export const intervalCountMismatch: Detector = (doc): Finding[] => {
45
+ const text = withoutCodeBlocks(doc.source);
46
+ return intervalCountMismatches(text, paragraphsOf(text), lengthsOf(doc, text), wordsOf(doc)).map((mismatch) => ({
44
47
  rule: "interval-count-mismatch",
45
48
  severity: "warning",
46
49
  line: 0,
@@ -49,3 +52,4 @@ export const intervalCountMismatch: Detector = (doc): Finding[] =>
49
52
  values: { ...valuesOf(doc, mismatch), offset: mismatch.count.start },
50
53
  ...(mismatch.kind === "table" ? { variant: "table" } : {}),
51
54
  }));
55
+ };
@@ -3,6 +3,7 @@ import { exceededMaxima } from "../derived/use-maximum.ts";
3
3
  import { paragraphsOf } from "../derived/period-counts.ts";
4
4
  import { limitWordsOf, marksOf, periodCountWordsOf } from "./use-count-words.ts";
5
5
  import { quoteAt } from "./structure-tree.ts";
6
+ import { withoutCodeBlocks } from "./code-fences.ts";
6
7
  import { isMoneySpan, type CurrencyMark } from "../derived/money-span.ts";
7
8
 
8
9
  // 1回の量 × 期間あたりの回数が、その期間の上限を超える(product-exceeds-maximum)。語は use-count-word と use-amount-word から取る。
@@ -19,7 +20,8 @@ export const productExceedsMaximum: Detector = (doc): Finding[] => {
19
20
  const marks = currencyMarksOf(doc);
20
21
  const unitOf = (span: Span): string => written(doc, span).replace(LEADING_NUMBER, "");
21
22
  const isMoney = (span: Span): boolean => isMoneySpan(doc.source, span, unitOf(span), marks);
22
- const amounts = exceededMaxima(doc.source, paragraphsOf(doc.source), words).filter((exceeded) => !isMoney(exceeded.maximum) && !isMoney(exceeded.perUse));
23
+ const text = withoutCodeBlocks(doc.source);
24
+ const amounts = exceededMaxima(text, paragraphsOf(text), words).filter((exceeded) => !isMoney(exceeded.maximum) && !isMoney(exceeded.perUse));
23
25
  return amounts.map((exceeded) => ({
24
26
  rule: "product-exceeds-maximum",
25
27
  severity: "warning",
package/src/eval.ts CHANGED
@@ -46,12 +46,12 @@ const candidates = (rule: RuleDefinition, current: number): number[] => {
46
46
  return [...new Set([...fromLevels, ...scaled, current])].toSorted((left, right) => left - right);
47
47
  };
48
48
 
49
- const countAt = (docs: readonly ProseDocument[], rule: RuleDefinition, limit: number, settings: DetectorOptions["settings"]): Point => {
49
+ const countAt = (docs: readonly ProseDocument[], rule: RuleDefinition, limit: number, settings: DetectorOptions["settings"], genre: string): Point => {
50
50
  const detector = DETECTORS[rule.how_to_find];
51
51
  if (detector === undefined) return { limit, findings: 0, documents: 0, per10k: 0 };
52
52
  const perDoc = docs.map((doc) => {
53
53
  const lexicon = rule.word_list === undefined ? undefined : doc.lexicons[rule.word_list];
54
- return detector(doc, { limit, lexicon, where: rule.where, settings }).length;
54
+ return detector(doc, { limit, lexicon, where: rule.where, settings, genre }).length;
55
55
  });
56
56
  const findings = perDoc.reduce((sum, count) => sum + count, 0);
57
57
  const chars = docs.reduce((sum, doc) => sum + doc.sentences.reduce((inner, sentence) => inner + charLength(sentence), 0), 0);
@@ -111,7 +111,7 @@ export const evaluate = (
111
111
  .map((rule) => {
112
112
  const current = limits[rule.id] ?? rule.levels.normal ?? 1;
113
113
  const settings = rule.options === undefined ? undefined : optionValues(settleOptions(rule.id, rule.options, optionLayers));
114
- const sweep = candidates(rule, current).map((limit) => countAt(docs, rule, limit, settings));
114
+ const sweep = candidates(rule, current).map((limit) => countAt(docs, rule, limit, settings, genre));
115
115
  return {
116
116
  rule: rule.id,
117
117
  name: rule.name[language] ?? rule.id,