chaffjs 0.29.0 → 0.31.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 (681) hide show
  1. package/dist/announced-count.d.ts +2 -0
  2. package/dist/announced-count.d.ts.map +1 -1
  3. package/dist/announced-count.js +4 -3
  4. package/dist/announced-count.js.map +1 -1
  5. package/dist/contacts/addresses.d.ts +21 -0
  6. package/dist/contacts/addresses.d.ts.map +1 -0
  7. package/dist/contacts/addresses.js +144 -0
  8. package/dist/contacts/addresses.js.map +1 -0
  9. package/dist/contacts/emails.d.ts +11 -0
  10. package/dist/contacts/emails.d.ts.map +1 -0
  11. package/dist/contacts/emails.js +51 -0
  12. package/dist/contacts/emails.js.map +1 -0
  13. package/dist/contacts/variants.d.ts +14 -0
  14. package/dist/contacts/variants.d.ts.map +1 -0
  15. package/dist/contacts/variants.js +25 -0
  16. package/dist/contacts/variants.js.map +1 -0
  17. package/dist/derived/battery-runtime.d.ts +85 -0
  18. package/dist/derived/battery-runtime.d.ts.map +1 -0
  19. package/dist/derived/battery-runtime.js +217 -0
  20. package/dist/derived/battery-runtime.js.map +1 -0
  21. package/dist/derived/period-counts.d.ts +48 -0
  22. package/dist/derived/period-counts.d.ts.map +1 -0
  23. package/dist/derived/period-counts.js +128 -0
  24. package/dist/derived/period-counts.js.map +1 -0
  25. package/dist/derived/session-hours.d.ts +26 -0
  26. package/dist/derived/session-hours.d.ts.map +1 -0
  27. package/dist/derived/session-hours.js +29 -0
  28. package/dist/derived/session-hours.js.map +1 -0
  29. package/dist/derived/time-lengths.d.ts +37 -0
  30. package/dist/derived/time-lengths.d.ts.map +1 -0
  31. package/dist/derived/time-lengths.js +171 -0
  32. package/dist/derived/time-lengths.js.map +1 -0
  33. package/dist/derived/unit-counts.d.ts +7 -0
  34. package/dist/derived/unit-counts.d.ts.map +1 -0
  35. package/dist/derived/unit-counts.js +13 -0
  36. package/dist/derived/unit-counts.js.map +1 -0
  37. package/dist/derived/use-interval.d.ts +33 -0
  38. package/dist/derived/use-interval.d.ts.map +1 -0
  39. package/dist/derived/use-interval.js +93 -0
  40. package/dist/derived/use-interval.js.map +1 -0
  41. package/dist/derived/working-hours.d.ts +36 -0
  42. package/dist/derived/working-hours.d.ts.map +1 -0
  43. package/dist/derived/working-hours.js +55 -0
  44. package/dist/derived/working-hours.js.map +1 -0
  45. package/dist/detectors/acronym-expansion.d.ts +1 -1
  46. package/dist/detectors/acronym-expansion.d.ts.map +1 -1
  47. package/dist/detectors/acronym-expansion.js +46 -2
  48. package/dist/detectors/acronym-expansion.js.map +1 -1
  49. package/dist/detectors/announced-count.d.ts.map +1 -1
  50. package/dist/detectors/announced-count.js +1 -0
  51. package/dist/detectors/announced-count.js.map +1 -1
  52. package/dist/detectors/capacity-runtime.d.ts +7 -0
  53. package/dist/detectors/capacity-runtime.d.ts.map +1 -0
  54. package/dist/detectors/capacity-runtime.js +98 -0
  55. package/dist/detectors/capacity-runtime.js.map +1 -0
  56. package/dist/detectors/capitalised-term.d.ts +44 -0
  57. package/dist/detectors/capitalised-term.d.ts.map +1 -0
  58. package/dist/detectors/capitalised-term.js +101 -0
  59. package/dist/detectors/capitalised-term.js.map +1 -0
  60. package/dist/detectors/contact-variant.d.ts +3 -0
  61. package/dist/detectors/contact-variant.d.ts.map +1 -0
  62. package/dist/detectors/contact-variant.js +21 -0
  63. package/dist/detectors/contact-variant.js.map +1 -0
  64. package/dist/detectors/count-over-capacity.d.ts +4 -0
  65. package/dist/detectors/count-over-capacity.d.ts.map +1 -0
  66. package/dist/detectors/count-over-capacity.js +26 -0
  67. package/dist/detectors/count-over-capacity.js.map +1 -0
  68. package/dist/detectors/date-outside-period.d.ts.map +1 -1
  69. package/dist/detectors/date-outside-period.js +5 -1
  70. package/dist/detectors/date-outside-period.js.map +1 -1
  71. package/dist/detectors/date-stamp-order.d.ts +3 -0
  72. package/dist/detectors/date-stamp-order.d.ts.map +1 -0
  73. package/dist/detectors/date-stamp-order.js +24 -0
  74. package/dist/detectors/date-stamp-order.js.map +1 -0
  75. package/dist/detectors/defined-term-form.d.ts.map +1 -1
  76. package/dist/detectors/defined-term-form.js +57 -7
  77. package/dist/detectors/defined-term-form.js.map +1 -1
  78. package/dist/detectors/definition-use.d.ts +1 -1
  79. package/dist/detectors/definition-use.d.ts.map +1 -1
  80. package/dist/detectors/definition-use.js +4 -2
  81. package/dist/detectors/definition-use.js.map +1 -1
  82. package/dist/detectors/derived-numbers.d.ts +11 -1
  83. package/dist/detectors/derived-numbers.d.ts.map +1 -1
  84. package/dist/detectors/derived-numbers.js +74 -20
  85. package/dist/detectors/derived-numbers.js.map +1 -1
  86. package/dist/detectors/due-date.d.ts.map +1 -1
  87. package/dist/detectors/due-date.js +6 -0
  88. package/dist/detectors/due-date.js.map +1 -1
  89. package/dist/detectors/en-shape.d.ts.map +1 -1
  90. package/dist/detectors/en-shape.js +7 -4
  91. package/dist/detectors/en-shape.js.map +1 -1
  92. package/dist/detectors/event-deadline.d.ts +3 -0
  93. package/dist/detectors/event-deadline.d.ts.map +1 -0
  94. package/dist/detectors/event-deadline.js +24 -0
  95. package/dist/detectors/event-deadline.js.map +1 -0
  96. package/dist/detectors/fact-consistency.d.ts +1 -1
  97. package/dist/detectors/fact-consistency.d.ts.map +1 -1
  98. package/dist/detectors/fact-consistency.js +52 -3
  99. package/dist/detectors/fact-consistency.js.map +1 -1
  100. package/dist/detectors/heading-case.d.ts +5 -2
  101. package/dist/detectors/heading-case.d.ts.map +1 -1
  102. package/dist/detectors/heading-case.js +12 -4
  103. package/dist/detectors/heading-case.js.map +1 -1
  104. package/dist/detectors/heading-echo.d.ts +5 -0
  105. package/dist/detectors/heading-echo.d.ts.map +1 -1
  106. package/dist/detectors/heading-echo.js +14 -1
  107. package/dist/detectors/heading-echo.js.map +1 -1
  108. package/dist/detectors/layout-code.d.ts +5 -0
  109. package/dist/detectors/layout-code.d.ts.map +1 -0
  110. package/dist/detectors/layout-code.js +124 -0
  111. package/dist/detectors/layout-code.js.map +1 -0
  112. package/dist/detectors/measured-facts.d.ts +8 -0
  113. package/dist/detectors/measured-facts.d.ts.map +1 -0
  114. package/dist/detectors/measured-facts.js +18 -0
  115. package/dist/detectors/measured-facts.js.map +1 -0
  116. package/dist/detectors/name-variant-model-codes.d.ts +11 -0
  117. package/dist/detectors/name-variant-model-codes.d.ts.map +1 -0
  118. package/dist/detectors/name-variant-model-codes.js +21 -0
  119. package/dist/detectors/name-variant-model-codes.js.map +1 -0
  120. package/dist/detectors/name-variant.d.ts.map +1 -1
  121. package/dist/detectors/name-variant.js +78 -10
  122. package/dist/detectors/name-variant.js.map +1 -1
  123. package/dist/detectors/orthographic-variant.d.ts.map +1 -1
  124. package/dist/detectors/orthographic-variant.js +62 -7
  125. package/dist/detectors/orthographic-variant.js.map +1 -1
  126. package/dist/detectors/orthography.d.ts.map +1 -1
  127. package/dist/detectors/orthography.js +12 -6
  128. package/dist/detectors/orthography.js.map +1 -1
  129. package/dist/detectors/party-order.d.ts +3 -0
  130. package/dist/detectors/party-order.d.ts.map +1 -0
  131. package/dist/detectors/party-order.js +46 -0
  132. package/dist/detectors/party-order.js.map +1 -0
  133. package/dist/detectors/quantity-range.d.ts +3 -0
  134. package/dist/detectors/quantity-range.d.ts.map +1 -0
  135. package/dist/detectors/quantity-range.js +35 -0
  136. package/dist/detectors/quantity-range.js.map +1 -0
  137. package/dist/detectors/range-band.d.ts +5 -0
  138. package/dist/detectors/range-band.d.ts.map +1 -0
  139. package/dist/detectors/range-band.js +80 -0
  140. package/dist/detectors/range-band.js.map +1 -0
  141. package/dist/detectors/registry/capacity-runtime-mismatch.d.ts +3 -0
  142. package/dist/detectors/registry/capacity-runtime-mismatch.d.ts.map +1 -0
  143. package/dist/detectors/registry/capacity-runtime-mismatch.js +3 -0
  144. package/dist/detectors/registry/capacity-runtime-mismatch.js.map +1 -0
  145. package/dist/detectors/registry/connection-time-short.d.ts +3 -0
  146. package/dist/detectors/registry/connection-time-short.d.ts.map +1 -0
  147. package/dist/detectors/registry/connection-time-short.js +3 -0
  148. package/dist/detectors/registry/connection-time-short.js.map +1 -0
  149. package/dist/detectors/registry/contact-variant.d.ts +3 -0
  150. package/dist/detectors/registry/contact-variant.d.ts.map +1 -0
  151. package/dist/detectors/registry/contact-variant.js +3 -0
  152. package/dist/detectors/registry/contact-variant.js.map +1 -0
  153. package/dist/detectors/registry/count-over-capacity.d.ts +3 -0
  154. package/dist/detectors/registry/count-over-capacity.d.ts.map +1 -0
  155. package/dist/detectors/registry/count-over-capacity.js +3 -0
  156. package/dist/detectors/registry/count-over-capacity.js.map +1 -0
  157. package/dist/detectors/registry/date-stamp-order.d.ts +3 -0
  158. package/dist/detectors/registry/date-stamp-order.d.ts.map +1 -0
  159. package/dist/detectors/registry/date-stamp-order.js +3 -0
  160. package/dist/detectors/registry/date-stamp-order.js.map +1 -0
  161. package/dist/detectors/registry/duration-product-mismatch.d.ts +3 -0
  162. package/dist/detectors/registry/duration-product-mismatch.d.ts.map +1 -0
  163. package/dist/detectors/registry/duration-product-mismatch.js +3 -0
  164. package/dist/detectors/registry/duration-product-mismatch.js.map +1 -0
  165. package/dist/detectors/registry/event-deadline.d.ts +3 -0
  166. package/dist/detectors/registry/event-deadline.d.ts.map +1 -0
  167. package/dist/detectors/registry/event-deadline.js +3 -0
  168. package/dist/detectors/registry/event-deadline.js.map +1 -0
  169. package/dist/detectors/registry/interval-count-mismatch.d.ts +3 -0
  170. package/dist/detectors/registry/interval-count-mismatch.d.ts.map +1 -0
  171. package/dist/detectors/registry/interval-count-mismatch.js +3 -0
  172. package/dist/detectors/registry/interval-count-mismatch.js.map +1 -0
  173. package/dist/detectors/registry/layout-code-mismatch.d.ts +3 -0
  174. package/dist/detectors/registry/layout-code-mismatch.d.ts.map +1 -0
  175. package/dist/detectors/registry/layout-code-mismatch.js +3 -0
  176. package/dist/detectors/registry/layout-code-mismatch.js.map +1 -0
  177. package/dist/detectors/registry/party-order.d.ts +3 -0
  178. package/dist/detectors/registry/party-order.d.ts.map +1 -0
  179. package/dist/detectors/registry/party-order.js +3 -0
  180. package/dist/detectors/registry/party-order.js.map +1 -0
  181. package/dist/detectors/registry/quantity-range.d.ts +3 -0
  182. package/dist/detectors/registry/quantity-range.d.ts.map +1 -0
  183. package/dist/detectors/registry/quantity-range.js +3 -0
  184. package/dist/detectors/registry/quantity-range.js.map +1 -0
  185. package/dist/detectors/registry/range-band-mismatch.d.ts +3 -0
  186. package/dist/detectors/registry/range-band-mismatch.d.ts.map +1 -0
  187. package/dist/detectors/registry/range-band-mismatch.js +3 -0
  188. package/dist/detectors/registry/range-band-mismatch.js.map +1 -0
  189. package/dist/detectors/registry/rent-multiple-mismatch.d.ts +3 -0
  190. package/dist/detectors/registry/rent-multiple-mismatch.d.ts.map +1 -0
  191. package/dist/detectors/registry/rent-multiple-mismatch.js +3 -0
  192. package/dist/detectors/registry/rent-multiple-mismatch.js.map +1 -0
  193. package/dist/detectors/registry/requirement-lists.d.ts +3 -0
  194. package/dist/detectors/registry/requirement-lists.d.ts.map +1 -0
  195. package/dist/detectors/registry/requirement-lists.js +3 -0
  196. package/dist/detectors/registry/requirement-lists.js.map +1 -0
  197. package/dist/detectors/registry/return-type.d.ts +3 -0
  198. package/dist/detectors/registry/return-type.d.ts.map +1 -0
  199. package/dist/detectors/registry/return-type.js +3 -0
  200. package/dist/detectors/registry/return-type.js.map +1 -0
  201. package/dist/detectors/registry/scaled-quantity-mismatch.d.ts +3 -0
  202. package/dist/detectors/registry/scaled-quantity-mismatch.d.ts.map +1 -0
  203. package/dist/detectors/registry/scaled-quantity-mismatch.js +3 -0
  204. package/dist/detectors/registry/scaled-quantity-mismatch.js.map +1 -0
  205. package/dist/detectors/registry/step-time-sum-mismatch.d.ts +3 -0
  206. package/dist/detectors/registry/step-time-sum-mismatch.d.ts.map +1 -0
  207. package/dist/detectors/registry/step-time-sum-mismatch.js +3 -0
  208. package/dist/detectors/registry/step-time-sum-mismatch.js.map +1 -0
  209. package/dist/detectors/registry/time-range-reversed.d.ts +3 -0
  210. package/dist/detectors/registry/time-range-reversed.d.ts.map +1 -0
  211. package/dist/detectors/registry/time-range-reversed.js +3 -0
  212. package/dist/detectors/registry/time-range-reversed.js.map +1 -0
  213. package/dist/detectors/registry/unlisted-item-used.d.ts +3 -0
  214. package/dist/detectors/registry/unlisted-item-used.d.ts.map +1 -0
  215. package/dist/detectors/registry/unlisted-item-used.js +3 -0
  216. package/dist/detectors/registry/unlisted-item-used.js.map +1 -0
  217. package/dist/detectors/registry/walk-time-distance-mismatch.d.ts +3 -0
  218. package/dist/detectors/registry/walk-time-distance-mismatch.d.ts.map +1 -0
  219. package/dist/detectors/registry/walk-time-distance-mismatch.js +3 -0
  220. package/dist/detectors/registry/walk-time-distance-mismatch.js.map +1 -0
  221. package/dist/detectors/rent-multiple-mismatch.d.ts +3 -0
  222. package/dist/detectors/rent-multiple-mismatch.d.ts.map +1 -0
  223. package/dist/detectors/rent-multiple-mismatch.js +39 -0
  224. package/dist/detectors/rent-multiple-mismatch.js.map +1 -0
  225. package/dist/detectors/requirement-lists.d.ts +3 -0
  226. package/dist/detectors/requirement-lists.d.ts.map +1 -0
  227. package/dist/detectors/requirement-lists.js +46 -0
  228. package/dist/detectors/requirement-lists.js.map +1 -0
  229. package/dist/detectors/return-type.d.ts +3 -0
  230. package/dist/detectors/return-type.d.ts.map +1 -0
  231. package/dist/detectors/return-type.js +24 -0
  232. package/dist/detectors/return-type.js.map +1 -0
  233. package/dist/detectors/scaled-quantity.d.ts +3 -0
  234. package/dist/detectors/scaled-quantity.d.ts.map +1 -0
  235. package/dist/detectors/scaled-quantity.js +37 -0
  236. package/dist/detectors/scaled-quantity.js.map +1 -0
  237. package/dist/detectors/signals.d.ts.map +1 -1
  238. package/dist/detectors/signals.js +3 -1
  239. package/dist/detectors/signals.js.map +1 -1
  240. package/dist/detectors/step-time-sum.d.ts +3 -0
  241. package/dist/detectors/step-time-sum.d.ts.map +1 -0
  242. package/dist/detectors/step-time-sum.js +46 -0
  243. package/dist/detectors/step-time-sum.js.map +1 -0
  244. package/dist/detectors/structure-tree.d.ts +2 -0
  245. package/dist/detectors/structure-tree.d.ts.map +1 -1
  246. package/dist/detectors/structure-tree.js +31 -6
  247. package/dist/detectors/structure-tree.js.map +1 -1
  248. package/dist/detectors/structure.js +1 -1
  249. package/dist/detectors/structure.js.map +1 -1
  250. package/dist/detectors/technical-docs.d.ts +5 -0
  251. package/dist/detectors/technical-docs.d.ts.map +1 -1
  252. package/dist/detectors/technical-docs.js +12 -0
  253. package/dist/detectors/technical-docs.js.map +1 -1
  254. package/dist/detectors/time-order.d.ts +2 -0
  255. package/dist/detectors/time-order.d.ts.map +1 -1
  256. package/dist/detectors/time-order.js +33 -5
  257. package/dist/detectors/time-order.js.map +1 -1
  258. package/dist/detectors/undefined-term.d.ts.map +1 -1
  259. package/dist/detectors/undefined-term.js +19 -3
  260. package/dist/detectors/undefined-term.js.map +1 -1
  261. package/dist/detectors/unit-consistency.d.ts +1 -1
  262. package/dist/detectors/unit-consistency.d.ts.map +1 -1
  263. package/dist/detectors/unit-consistency.js +46 -38
  264. package/dist/detectors/unit-consistency.js.map +1 -1
  265. package/dist/detectors/unlisted-items.d.ts +3 -0
  266. package/dist/detectors/unlisted-items.d.ts.map +1 -0
  267. package/dist/detectors/unlisted-items.js +57 -0
  268. package/dist/detectors/unlisted-items.js.map +1 -0
  269. package/dist/detectors/use-count-words.d.ts +8 -0
  270. package/dist/detectors/use-count-words.d.ts.map +1 -0
  271. package/dist/detectors/use-count-words.js +20 -0
  272. package/dist/detectors/use-count-words.js.map +1 -0
  273. package/dist/detectors/use-interval.d.ts +3 -0
  274. package/dist/detectors/use-interval.d.ts.map +1 -0
  275. package/dist/detectors/use-interval.js +39 -0
  276. package/dist/detectors/use-interval.js.map +1 -0
  277. package/dist/detectors/walk-time-distance-mismatch.d.ts +4 -0
  278. package/dist/detectors/walk-time-distance-mismatch.d.ts.map +1 -0
  279. package/dist/detectors/walk-time-distance-mismatch.js +38 -0
  280. package/dist/detectors/walk-time-distance-mismatch.js.map +1 -0
  281. package/dist/document.d.ts.map +1 -1
  282. package/dist/document.js +4 -1
  283. package/dist/document.js.map +1 -1
  284. package/dist/facts/approximate-tolerance.d.ts +7 -0
  285. package/dist/facts/approximate-tolerance.d.ts.map +1 -0
  286. package/dist/facts/approximate-tolerance.js +16 -0
  287. package/dist/facts/approximate-tolerance.js.map +1 -0
  288. package/dist/facts/item-amounts.d.ts +18 -0
  289. package/dist/facts/item-amounts.d.ts.map +1 -0
  290. package/dist/facts/item-amounts.js +67 -0
  291. package/dist/facts/item-amounts.js.map +1 -0
  292. package/dist/facts/labelled-facts.d.ts +4 -0
  293. package/dist/facts/labelled-facts.d.ts.map +1 -1
  294. package/dist/facts/labelled-facts.js +21 -6
  295. package/dist/facts/labelled-facts.js.map +1 -1
  296. package/dist/facts/measure-units.d.ts +5 -0
  297. package/dist/facts/measure-units.d.ts.map +1 -0
  298. package/dist/facts/measure-units.js +28 -0
  299. package/dist/facts/measure-units.js.map +1 -0
  300. package/dist/facts/measures.d.ts +23 -4
  301. package/dist/facts/measures.d.ts.map +1 -1
  302. package/dist/facts/measures.js +68 -19
  303. package/dist/facts/measures.js.map +1 -1
  304. package/dist/facts/retention-periods.d.ts +51 -0
  305. package/dist/facts/retention-periods.d.ts.map +1 -0
  306. package/dist/facts/retention-periods.js +148 -0
  307. package/dist/facts/retention-periods.js.map +1 -0
  308. package/dist/facts/table-facts.d.ts +2 -0
  309. package/dist/facts/table-facts.d.ts.map +1 -1
  310. package/dist/facts/table-facts.js +2 -0
  311. package/dist/facts/table-facts.js.map +1 -1
  312. package/dist/facts/unit-conflicts.d.ts +3 -2
  313. package/dist/facts/unit-conflicts.d.ts.map +1 -1
  314. package/dist/facts/unit-conflicts.js +15 -7
  315. package/dist/facts/unit-conflicts.js.map +1 -1
  316. package/dist/facts/unit-equivalents.d.ts +13 -0
  317. package/dist/facts/unit-equivalents.d.ts.map +1 -0
  318. package/dist/facts/unit-equivalents.js +56 -0
  319. package/dist/facts/unit-equivalents.js.map +1 -0
  320. package/dist/facts/unit-tolerance.d.ts +4 -0
  321. package/dist/facts/unit-tolerance.d.ts.map +1 -0
  322. package/dist/facts/unit-tolerance.js +13 -0
  323. package/dist/facts/unit-tolerance.js.map +1 -0
  324. package/dist/facts/unit-word.d.ts +8 -0
  325. package/dist/facts/unit-word.d.ts.map +1 -0
  326. package/dist/facts/unit-word.js +34 -0
  327. package/dist/facts/unit-word.js.map +1 -0
  328. package/dist/facts/written-precision.d.ts +10 -0
  329. package/dist/facts/written-precision.d.ts.map +1 -0
  330. package/dist/facts/written-precision.js +20 -0
  331. package/dist/facts/written-precision.js.map +1 -0
  332. package/dist/kana-spelling.d.ts +12 -0
  333. package/dist/kana-spelling.d.ts.map +1 -1
  334. package/dist/kana-spelling.js +23 -0
  335. package/dist/kana-spelling.js.map +1 -1
  336. package/dist/model-codes.d.ts +23 -0
  337. package/dist/model-codes.d.ts.map +1 -0
  338. package/dist/model-codes.js +81 -0
  339. package/dist/model-codes.js.map +1 -0
  340. package/dist/name-spelling-chars.d.ts +16 -0
  341. package/dist/name-spelling-chars.d.ts.map +1 -0
  342. package/dist/name-spelling-chars.js +14 -0
  343. package/dist/name-spelling-chars.js.map +1 -0
  344. package/dist/name-variants.d.ts +8 -2
  345. package/dist/name-variants.d.ts.map +1 -1
  346. package/dist/name-variants.js +72 -7
  347. package/dist/name-variants.js.map +1 -1
  348. package/dist/name-word-order.d.ts +49 -0
  349. package/dist/name-word-order.d.ts.map +1 -0
  350. package/dist/name-word-order.js +114 -0
  351. package/dist/name-word-order.js.map +1 -0
  352. package/dist/phone-numbers.d.ts.map +1 -1
  353. package/dist/phone-numbers.js +22 -5
  354. package/dist/phone-numbers.js.map +1 -1
  355. package/dist/place-names.d.ts +12 -5
  356. package/dist/place-names.d.ts.map +1 -1
  357. package/dist/place-names.js +34 -14
  358. package/dist/place-names.js.map +1 -1
  359. package/dist/plugin.d.ts +12 -0
  360. package/dist/plugin.d.ts.map +1 -1
  361. package/dist/preamble-paragraphs.d.ts +2 -1
  362. package/dist/preamble-paragraphs.d.ts.map +1 -1
  363. package/dist/preamble-paragraphs.js +16 -1
  364. package/dist/preamble-paragraphs.js.map +1 -1
  365. package/dist/profile/parse.d.ts.map +1 -1
  366. package/dist/profile/parse.js +11 -0
  367. package/dist/profile/parse.js.map +1 -1
  368. package/dist/return-type.d.ts +33 -0
  369. package/dist/return-type.d.ts.map +1 -0
  370. package/dist/return-type.js +302 -0
  371. package/dist/return-type.js.map +1 -0
  372. package/dist/spacing-code.d.ts +6 -0
  373. package/dist/spacing-code.d.ts.map +1 -0
  374. package/dist/spacing-code.js +16 -0
  375. package/dist/spacing-code.js.map +1 -0
  376. package/dist/structure/amount-range.d.ts +2 -2
  377. package/dist/structure/amount-range.d.ts.map +1 -1
  378. package/dist/structure/amount-range.js +12 -5
  379. package/dist/structure/amount-range.js.map +1 -1
  380. package/dist/structure/capacity-count.d.ts +59 -0
  381. package/dist/structure/capacity-count.d.ts.map +1 -0
  382. package/dist/structure/capacity-count.js +118 -0
  383. package/dist/structure/capacity-count.js.map +1 -0
  384. package/dist/structure/connection-times.d.ts +56 -0
  385. package/dist/structure/connection-times.d.ts.map +1 -0
  386. package/dist/structure/connection-times.js +165 -0
  387. package/dist/structure/connection-times.js.map +1 -0
  388. package/dist/structure/counted-amounts.d.ts +6 -0
  389. package/dist/structure/counted-amounts.d.ts.map +1 -1
  390. package/dist/structure/counted-amounts.js +4 -4
  391. package/dist/structure/counted-amounts.js.map +1 -1
  392. package/dist/structure/date-order-tie.d.ts +13 -0
  393. package/dist/structure/date-order-tie.d.ts.map +1 -0
  394. package/dist/structure/date-order-tie.js +61 -0
  395. package/dist/structure/date-order-tie.js.map +1 -0
  396. package/dist/structure/date-order.d.ts +2 -2
  397. package/dist/structure/date-order.d.ts.map +1 -1
  398. package/dist/structure/date-order.js +26 -9
  399. package/dist/structure/date-order.js.map +1 -1
  400. package/dist/structure/date-outside-period.d.ts +8 -0
  401. package/dist/structure/date-outside-period.d.ts.map +1 -1
  402. package/dist/structure/date-outside-period.js +52 -3
  403. package/dist/structure/date-outside-period.js.map +1 -1
  404. package/dist/structure/date-range.d.ts +6 -2
  405. package/dist/structure/date-range.d.ts.map +1 -1
  406. package/dist/structure/date-range.js +37 -9
  407. package/dist/structure/date-range.js.map +1 -1
  408. package/dist/structure/deadline-after-event.d.ts +23 -0
  409. package/dist/structure/deadline-after-event.d.ts.map +1 -0
  410. package/dist/structure/deadline-after-event.js +42 -0
  411. package/dist/structure/deadline-after-event.js.map +1 -0
  412. package/dist/structure/definition-use.d.ts +1 -1
  413. package/dist/structure/definition-use.d.ts.map +1 -1
  414. package/dist/structure/definition-use.js +55 -2
  415. package/dist/structure/definition-use.js.map +1 -1
  416. package/dist/structure/due-date.d.ts.map +1 -1
  417. package/dist/structure/due-date.js +5 -27
  418. package/dist/structure/due-date.js.map +1 -1
  419. package/dist/structure/labelled-date-order.d.ts +38 -0
  420. package/dist/structure/labelled-date-order.d.ts.map +1 -0
  421. package/dist/structure/labelled-date-order.js +41 -0
  422. package/dist/structure/labelled-date-order.js.map +1 -0
  423. package/dist/structure/layout-codes.d.ts +68 -0
  424. package/dist/structure/layout-codes.d.ts.map +1 -0
  425. package/dist/structure/layout-codes.js +161 -0
  426. package/dist/structure/layout-codes.js.map +1 -0
  427. package/dist/structure/leg-times.d.ts +2 -0
  428. package/dist/structure/leg-times.d.ts.map +1 -1
  429. package/dist/structure/leg-times.js +13 -0
  430. package/dist/structure/leg-times.js.map +1 -1
  431. package/dist/structure/measured-amounts.d.ts +17 -0
  432. package/dist/structure/measured-amounts.d.ts.map +1 -0
  433. package/dist/structure/measured-amounts.js +110 -0
  434. package/dist/structure/measured-amounts.js.map +1 -0
  435. package/dist/structure/party-order.d.ts +33 -0
  436. package/dist/structure/party-order.d.ts.map +1 -0
  437. package/dist/structure/party-order.js +79 -0
  438. package/dist/structure/party-order.js.map +1 -0
  439. package/dist/structure/quantity-range.d.ts +8 -0
  440. package/dist/structure/quantity-range.d.ts.map +1 -0
  441. package/dist/structure/quantity-range.js +36 -0
  442. package/dist/structure/quantity-range.js.map +1 -0
  443. package/dist/structure/range-bands.d.ts +75 -0
  444. package/dist/structure/range-bands.d.ts.map +1 -0
  445. package/dist/structure/range-bands.js +244 -0
  446. package/dist/structure/range-bands.js.map +1 -0
  447. package/dist/structure/rent-multiple.d.ts +76 -0
  448. package/dist/structure/rent-multiple.d.ts.map +1 -0
  449. package/dist/structure/rent-multiple.js +186 -0
  450. package/dist/structure/rent-multiple.js.map +1 -0
  451. package/dist/structure/requirement-lists.d.ts +37 -0
  452. package/dist/structure/requirement-lists.d.ts.map +1 -0
  453. package/dist/structure/requirement-lists.js +89 -0
  454. package/dist/structure/requirement-lists.js.map +1 -0
  455. package/dist/structure/scaled-quantities.d.ts +50 -0
  456. package/dist/structure/scaled-quantities.d.ts.map +1 -0
  457. package/dist/structure/scaled-quantities.js +153 -0
  458. package/dist/structure/scaled-quantities.js.map +1 -0
  459. package/dist/structure/stamp-order.d.ts +16 -0
  460. package/dist/structure/stamp-order.d.ts.map +1 -0
  461. package/dist/structure/stamp-order.js +78 -0
  462. package/dist/structure/stamp-order.js.map +1 -0
  463. package/dist/structure/step-times.d.ts +49 -0
  464. package/dist/structure/step-times.d.ts.map +1 -0
  465. package/dist/structure/step-times.js +128 -0
  466. package/dist/structure/step-times.js.map +1 -0
  467. package/dist/structure/term-deadline.d.ts +19 -0
  468. package/dist/structure/term-deadline.d.ts.map +1 -0
  469. package/dist/structure/term-deadline.js +28 -0
  470. package/dist/structure/term-deadline.js.map +1 -0
  471. package/dist/structure/time-order.d.ts +21 -0
  472. package/dist/structure/time-order.d.ts.map +1 -1
  473. package/dist/structure/time-order.js +5 -6
  474. package/dist/structure/time-order.js.map +1 -1
  475. package/dist/structure/time-range.d.ts +16 -0
  476. package/dist/structure/time-range.d.ts.map +1 -0
  477. package/dist/structure/time-range.js +57 -0
  478. package/dist/structure/time-range.js.map +1 -0
  479. package/dist/structure/total-line.d.ts +16 -0
  480. package/dist/structure/total-line.d.ts.map +1 -0
  481. package/dist/structure/total-line.js +44 -0
  482. package/dist/structure/total-line.js.map +1 -0
  483. package/dist/structure/total.d.ts +7 -1
  484. package/dist/structure/total.d.ts.map +1 -1
  485. package/dist/structure/total.js +28 -5
  486. package/dist/structure/total.js.map +1 -1
  487. package/dist/structure/unlisted-items.d.ts +70 -0
  488. package/dist/structure/unlisted-items.d.ts.map +1 -0
  489. package/dist/structure/unlisted-items.js +152 -0
  490. package/dist/structure/unlisted-items.js.map +1 -0
  491. package/dist/structure/version-order.d.ts +2 -0
  492. package/dist/structure/version-order.d.ts.map +1 -1
  493. package/dist/structure/version-order.js +10 -0
  494. package/dist/structure/version-order.js.map +1 -1
  495. package/dist/structure/walk-time.d.ts +87 -0
  496. package/dist/structure/walk-time.d.ts.map +1 -0
  497. package/dist/structure/walk-time.js +195 -0
  498. package/dist/structure/walk-time.js.map +1 -0
  499. package/dist/surname-near.d.ts +6 -0
  500. package/dist/surname-near.d.ts.map +1 -0
  501. package/dist/surname-near.js +31 -0
  502. package/dist/surname-near.js.map +1 -0
  503. package/dist/table-cells.d.ts +13 -0
  504. package/dist/table-cells.d.ts.map +1 -0
  505. package/dist/table-cells.js +36 -0
  506. package/dist/table-cells.js.map +1 -0
  507. package/dist/table-names.d.ts +42 -0
  508. package/dist/table-names.d.ts.map +1 -0
  509. package/dist/table-names.js +94 -0
  510. package/dist/table-names.js.map +1 -0
  511. package/package.json +3 -3
  512. package/profiles/listing.yaml +20 -0
  513. package/rules/announced-count-mismatch.yaml +2 -2
  514. package/rules/capacity-runtime-mismatch.yaml +66 -0
  515. package/rules/connection-time-short.yaml +52 -0
  516. package/rules/contact-variant.yaml +76 -0
  517. package/rules/count-over-capacity.yaml +55 -0
  518. package/rules/date-outside-period.yaml +4 -4
  519. package/rules/date-stamp-order.yaml +82 -0
  520. package/rules/deadline-after-event.yaml +67 -0
  521. package/rules/defined-name-repeated.yaml +2 -2
  522. package/rules/due-before-issue.yaml +11 -7
  523. package/rules/duration-mismatch.yaml +7 -4
  524. package/rules/duration-product-mismatch.yaml +73 -0
  525. package/rules/fact-conflict.yaml +9 -4
  526. package/rules/heading-echo.yaml +2 -2
  527. package/rules/interval-count-mismatch.yaml +54 -0
  528. package/rules/latin-spacing.yaml +2 -2
  529. package/rules/layout-code-mismatch.yaml +68 -0
  530. package/rules/name-variant.yaml +14 -2
  531. package/rules/no-em-dash.yaml +2 -2
  532. package/rules/party-order.yaml +84 -0
  533. package/rules/preamble-length.yaml +2 -2
  534. package/rules/quantity-range-reversed.yaml +53 -0
  535. package/rules/range-band-mismatch.yaml +70 -0
  536. package/rules/rent-multiple-mismatch.yaml +61 -0
  537. package/rules/required-listed-as-preferred.yaml +102 -0
  538. package/rules/return-type-mismatch.yaml +79 -0
  539. package/rules/scaled-quantity-mismatch.yaml +69 -0
  540. package/rules/step-time-sum-mismatch.yaml +65 -0
  541. package/rules/time-range-reversed.yaml +48 -0
  542. package/rules/title-case-consistency.yaml +2 -2
  543. package/rules/total-mismatch.yaml +2 -2
  544. package/rules/undefined-term.yaml +21 -7
  545. package/rules/unit-mismatch.yaml +12 -4
  546. package/rules/unlisted-item-used.yaml +90 -0
  547. package/rules/unused-definition.yaml +2 -2
  548. package/rules/use-before-definition.yaml +2 -2
  549. package/rules/walk-time-distance-mismatch.yaml +55 -0
  550. package/src/announced-count.ts +6 -3
  551. package/src/contacts/addresses.ts +179 -0
  552. package/src/contacts/emails.ts +63 -0
  553. package/src/contacts/variants.ts +33 -0
  554. package/src/derived/battery-runtime.ts +284 -0
  555. package/src/derived/period-counts.ts +178 -0
  556. package/src/derived/session-hours.ts +62 -0
  557. package/src/derived/time-lengths.ts +229 -0
  558. package/src/derived/unit-counts.ts +18 -0
  559. package/src/derived/use-interval.ts +151 -0
  560. package/src/derived/working-hours.ts +97 -0
  561. package/src/detectors/acronym-expansion.ts +57 -2
  562. package/src/detectors/announced-count.ts +1 -0
  563. package/src/detectors/capacity-runtime.ts +128 -0
  564. package/src/detectors/capitalised-term.ts +147 -0
  565. package/src/detectors/contact-variant.ts +24 -0
  566. package/src/detectors/count-over-capacity.ts +37 -0
  567. package/src/detectors/date-outside-period.ts +5 -1
  568. package/src/detectors/date-stamp-order.ts +28 -0
  569. package/src/detectors/defined-term-form.ts +63 -7
  570. package/src/detectors/definition-use.ts +6 -2
  571. package/src/detectors/derived-numbers.ts +97 -24
  572. package/src/detectors/due-date.ts +10 -2
  573. package/src/detectors/en-shape.ts +11 -4
  574. package/src/detectors/event-deadline.ts +29 -0
  575. package/src/detectors/fact-consistency.ts +64 -3
  576. package/src/detectors/heading-case.ts +13 -4
  577. package/src/detectors/heading-echo.ts +17 -1
  578. package/src/detectors/layout-code.ts +174 -0
  579. package/src/detectors/measured-facts.ts +20 -0
  580. package/src/detectors/name-variant-model-codes.ts +27 -0
  581. package/src/detectors/name-variant.ts +99 -15
  582. package/src/detectors/orthographic-variant.ts +78 -9
  583. package/src/detectors/orthography.ts +16 -6
  584. package/src/detectors/party-order.ts +50 -0
  585. package/src/detectors/quantity-range.ts +47 -0
  586. package/src/detectors/range-band.ts +125 -0
  587. package/src/detectors/registry/capacity-runtime-mismatch.ts +4 -0
  588. package/src/detectors/registry/connection-time-short.ts +4 -0
  589. package/src/detectors/registry/contact-variant.ts +4 -0
  590. package/src/detectors/registry/count-over-capacity.ts +4 -0
  591. package/src/detectors/registry/date-stamp-order.ts +4 -0
  592. package/src/detectors/registry/duration-product-mismatch.ts +4 -0
  593. package/src/detectors/registry/event-deadline.ts +4 -0
  594. package/src/detectors/registry/interval-count-mismatch.ts +4 -0
  595. package/src/detectors/registry/layout-code-mismatch.ts +4 -0
  596. package/src/detectors/registry/party-order.ts +4 -0
  597. package/src/detectors/registry/quantity-range.ts +4 -0
  598. package/src/detectors/registry/range-band-mismatch.ts +4 -0
  599. package/src/detectors/registry/rent-multiple-mismatch.ts +4 -0
  600. package/src/detectors/registry/requirement-lists.ts +4 -0
  601. package/src/detectors/registry/return-type.ts +4 -0
  602. package/src/detectors/registry/scaled-quantity-mismatch.ts +4 -0
  603. package/src/detectors/registry/step-time-sum-mismatch.ts +4 -0
  604. package/src/detectors/registry/time-range-reversed.ts +4 -0
  605. package/src/detectors/registry/unlisted-item-used.ts +4 -0
  606. package/src/detectors/registry/walk-time-distance-mismatch.ts +4 -0
  607. package/src/detectors/rent-multiple-mismatch.ts +56 -0
  608. package/src/detectors/requirement-lists.ts +65 -0
  609. package/src/detectors/return-type.ts +30 -0
  610. package/src/detectors/scaled-quantity.ts +49 -0
  611. package/src/detectors/signals.ts +3 -1
  612. package/src/detectors/step-time-sum.ts +55 -0
  613. package/src/detectors/structure-tree.ts +42 -6
  614. package/src/detectors/structure.ts +1 -1
  615. package/src/detectors/technical-docs.ts +12 -0
  616. package/src/detectors/time-order.ts +45 -6
  617. package/src/detectors/undefined-term.ts +20 -3
  618. package/src/detectors/unit-consistency.ts +50 -38
  619. package/src/detectors/unlisted-items.ts +72 -0
  620. package/src/detectors/use-count-words.ts +32 -0
  621. package/src/detectors/use-interval.ts +51 -0
  622. package/src/detectors/walk-time-distance-mismatch.ts +45 -0
  623. package/src/document.ts +4 -1
  624. package/src/facts/approximate-tolerance.ts +19 -0
  625. package/src/facts/item-amounts.ts +94 -0
  626. package/src/facts/labelled-facts.ts +29 -7
  627. package/src/facts/measure-units.ts +31 -0
  628. package/src/facts/measures.ts +113 -25
  629. package/src/facts/retention-periods.ts +216 -0
  630. package/src/facts/table-facts.ts +3 -0
  631. package/src/facts/unit-conflicts.ts +22 -9
  632. package/src/facts/unit-equivalents.ts +70 -0
  633. package/src/facts/unit-tolerance.ts +17 -0
  634. package/src/facts/unit-word.ts +35 -0
  635. package/src/facts/written-precision.ts +23 -0
  636. package/src/kana-spelling.ts +25 -0
  637. package/src/model-codes.ts +104 -0
  638. package/src/name-spelling-chars.ts +34 -0
  639. package/src/name-variants.ts +83 -7
  640. package/src/name-word-order.ts +149 -0
  641. package/src/phone-numbers.ts +26 -6
  642. package/src/place-names.ts +53 -14
  643. package/src/plugin.ts +7 -0
  644. package/src/preamble-paragraphs.ts +21 -2
  645. package/src/profile/parse.ts +10 -0
  646. package/src/return-type.ts +361 -0
  647. package/src/spacing-code.ts +26 -0
  648. package/src/structure/amount-range.ts +16 -7
  649. package/src/structure/capacity-count.ts +196 -0
  650. package/src/structure/connection-times.ts +226 -0
  651. package/src/structure/counted-amounts.ts +5 -4
  652. package/src/structure/date-order-tie.ts +86 -0
  653. package/src/structure/date-order.ts +41 -14
  654. package/src/structure/date-outside-period.ts +77 -7
  655. package/src/structure/date-range.ts +45 -9
  656. package/src/structure/deadline-after-event.ts +67 -0
  657. package/src/structure/definition-use.ts +59 -2
  658. package/src/structure/due-date.ts +8 -32
  659. package/src/structure/labelled-date-order.ts +84 -0
  660. package/src/structure/layout-codes.ts +210 -0
  661. package/src/structure/leg-times.ts +15 -0
  662. package/src/structure/measured-amounts.ts +138 -0
  663. package/src/structure/party-order.ts +115 -0
  664. package/src/structure/quantity-range.ts +54 -0
  665. package/src/structure/range-bands.ts +316 -0
  666. package/src/structure/rent-multiple.ts +277 -0
  667. package/src/structure/requirement-lists.ts +145 -0
  668. package/src/structure/scaled-quantities.ts +225 -0
  669. package/src/structure/stamp-order.ts +100 -0
  670. package/src/structure/step-times.ts +169 -0
  671. package/src/structure/term-deadline.ts +35 -0
  672. package/src/structure/time-order.ts +8 -7
  673. package/src/structure/time-range.ts +64 -0
  674. package/src/structure/total-line.ts +63 -0
  675. package/src/structure/total.ts +41 -6
  676. package/src/structure/unlisted-items.ts +207 -0
  677. package/src/structure/version-order.ts +10 -0
  678. package/src/structure/walk-time.ts +285 -0
  679. package/src/surname-near.ts +31 -0
  680. package/src/table-cells.ts +41 -0
  681. package/src/table-names.ts +113 -0
@@ -23,8 +23,8 @@ const finding = (doc: ProseDocument, rule: string, offset: number, variant: stri
23
23
 
24
24
  const OPENING_QUOTES = new Set(["「", "『", '"', "“"]);
25
25
  const CLOSING_QUOTES = new Set(["」", "』", '"', "”"]);
26
- /** A quoted term right before these is defined again (「X」とは, "X" means), which duplicate-definition reads. */
27
- const DEFINING_AFTER = /^(?:とは|という|\s+(?:means|shall mean|refers to|has the meaning))/u;
26
+ /** A quoted term right before these is defined again (「X」とは, 「X」といいます, "X" means), which duplicate-definition reads. */
27
+ const DEFINING_AFTER = /^(?:とは|という|といい(?:ます)?(?=[。、,))\s]|$)|\s+(?:means|shall mean|refers to|has the meaning))/u;
28
28
  /** The ending a use may carry past the term: a plural or a possessive (Services, Service's). */
29
29
  const WORD_ENDING = /^(?:e?s|['’]s?)/u;
30
30
 
@@ -238,14 +238,69 @@ const bracketBefore = (source: string, definition: Span): number => {
238
238
 
239
239
  export type RepeatedName = { readonly offset: number; readonly name: string; readonly term: string; readonly line: number };
240
240
 
241
- /** A line that holds the short name too (甲 株式会社みなと) or little else than the long name: a signature block names both. */
242
- const isNameLine = (source: string, offset: number, name: string, term: string): boolean => {
241
+ /** How many characters a line may add to the long name and still be a line that only names the party. */
242
+ const SLACK = 12;
243
+
244
+ /** A field label on its own line, after a list marker (Attention:, 宛先:): short, and not a sentence. */
245
+ const FIELD_LABEL = /^(?:[-*+]\s+)?[^::。.]{1,20}[::]\s*/u;
246
+ /**
247
+ * What may follow the name in an address field: nothing, a comma and the next part (, Member Support), or a space and a part
248
+ * that does not go on in lower case (株式会社みなと 総務部). A particle or a verb (は支払う, shall pay) makes the line a sentence.
249
+ */
250
+ const NEXT_PART = /^\.?(?:$|\s*[,、,]|\s+(?!\p{Ll}))/u;
251
+ const CLOSES_SENTENCE = /[.。!?!?]$/u;
252
+
253
+ /** A field whose value is the name and a little more, not a sentence (Attention: Hibari Lab Inc., Member Support). */
254
+ const isNameField = (line: string, name: string): boolean => {
255
+ const label = FIELD_LABEL.exec(line);
256
+ const value = label === null ? "" : line.slice(label[0].length);
257
+ const rest = value.slice(name.length);
258
+ return value.startsWith(name) && NEXT_PART.test(rest) && [...rest].length <= SLACK * 2 && !CLOSES_SENTENCE.test(rest.slice(1));
259
+ };
260
+
261
+ /** A contact field's label: after a bullet or a number (1. 連絡先:), and as long as a label in English runs (Privacy Contact:). */
262
+ const CONTACT_LABEL = /^(?:(?:[-*+]|\d+[.)])\s+)?([^::。.]{1,40})[::]\s*/u;
263
+ const LABEL_MARKS = /[*_\s]+/gu;
264
+ /** After the name in a contact field, the next part after a space or a comma (, Tokyo), or the bracket that holds it (お問い合わせ窓口(株式会社みなと)). */
265
+ const NEXT_CONTACT_PART = /^\.?(?:$|[))]|\s*,?\s+(?!\p{Ll}))/u;
266
+ /** A comma that goes on in lower case or 、 may also start a clause (, which may; 株式会社みなと、平日に受け付ける): the address field's bound. */
267
+ const COMMA_PART = /^\.?\s*[,、,]/u;
268
+
269
+ const endsWithContactLabel = (label: string, contactLabels: readonly string[]): boolean => {
270
+ const bare = label.replaceAll(LABEL_MARKS, "").toLowerCase();
271
+ return contactLabels.some((contact) => contact !== "" && bare.endsWith(contact.toLowerCase()));
272
+ };
273
+
274
+ /**
275
+ * A field whose label ends with a contact label (窓口:, Attention:): the value names the party in full however long it is and
276
+ * wherever the name sits in it, unless the name goes on as a sentence (連絡先:株式会社みなとは、…).
277
+ */
278
+ const isContactField = (line: string, name: string, contactLabels: readonly string[]): boolean => {
279
+ const label = CONTACT_LABEL.exec(line);
280
+ if (label === null || !endsWithContactLabel(label[1] ?? "", contactLabels)) return false;
281
+ const value = line.slice(label[0].length);
282
+ const at = value.indexOf(name);
283
+ if (at === -1) return false;
284
+ const rest = value.slice(at + name.length);
285
+ const continues = NEXT_CONTACT_PART.test(rest) || (COMMA_PART.test(rest) && [...rest].length <= SLACK * 2);
286
+ return continues && !CLOSES_SENTENCE.test(rest.slice(1));
287
+ };
288
+
289
+ /**
290
+ * A line that holds the short name too (甲 株式会社みなと), little else than the long name (a signature block names both),
291
+ * or a field whose value is the name (Attention: …, 宛先:…): an address gives the name in full.
292
+ */
293
+ const isNameLine = (source: string, offset: number, name: string, term: string, contactLabels: readonly string[]): boolean => {
243
294
  const start = source.lastIndexOf("\n", offset - 1) + 1;
244
295
  const end = source.indexOf("\n", offset);
245
296
  const line = source.slice(start, end === -1 ? source.length : end).trim();
246
- const SLACK = 12;
247
297
  // The short name inside the long one ("Pinecone" in "Pinecone Software Ltd") is not the short name written beside it.
248
- return line.replaceAll(name, "").includes(term) || [...line].length <= [...name].length + SLACK;
298
+ return (
299
+ line.replaceAll(name, "").includes(term) ||
300
+ [...line].length <= [...name].length + SLACK ||
301
+ isNameField(line, name) ||
302
+ isContactField(line, name, contactLabels)
303
+ );
249
304
  };
250
305
 
251
306
  /** A name inside a longer word (東京大学 in 東京大学大学院, Acme in Acmeware) is part of another name. */
@@ -267,6 +322,7 @@ export const standsAlone = (source: string, offset: number, name: string, joiner
267
322
  export const repeatedNames = (doc: ProseDocument, terms: readonly DefinedTerm[]): RepeatedName[] => {
268
323
  const defined = new Set(terms.map((term) => term.term));
269
324
  const joiners = (doc.lexicons["enumeration-joiner"] ?? []).map((entry) => entry.pattern);
325
+ const contactLabels = (doc.lexicons["contact-label"] ?? []).map((entry) => entry.pattern);
270
326
  return terms
271
327
  .filter((term) => term.inline)
272
328
  .flatMap((term) => {
@@ -278,7 +334,7 @@ export const repeatedNames = (doc: ProseDocument, terms: readonly DefinedTerm[])
278
334
  return doc.sentences
279
335
  .filter((later) => later.span.start > term.span.end)
280
336
  .flatMap((later) => [...later.text.matchAll(pattern)].map((match) => later.span.start + match.index))
281
- .filter((offset) => standsAlone(doc.source, offset, name, joiners) && !isNameLine(doc.source, offset, name, term.term))
337
+ .filter((offset) => standsAlone(doc.source, offset, name, joiners) && !isNameLine(doc.source, offset, name, term.term, contactLabels))
282
338
  .map((offset) => ({ offset, name, term: term.term, line: term.line }));
283
339
  });
284
340
  };
@@ -22,11 +22,15 @@ const findingAt = (doc: ProseDocument, offset: number, values: Readonly<Record<s
22
22
  values: { ...values, offset },
23
23
  });
24
24
 
25
- /** 定義したのに、定義の外で一度も使っていない語。 */
25
+ /** Markdown の見出し。文には入らないが、見出しで語を使っても、その語は文書で使われている。 */
26
+ const headingsOf = (doc: ProseDocument): BodyText[] =>
27
+ (doc.markup?.headings ?? []).map((heading) => ({ start: heading.start, text: doc.source.slice(heading.start, heading.end) }));
28
+
29
+ /** 定義したのに、定義の外(文と見出し)で一度も使っていない語。 */
26
30
  export const unusedDefinition: Detector = (doc): Finding[] =>
27
31
  doc.structure === undefined
28
32
  ? []
29
- : unusedDefinitions(definedTerms(doc.structure), bodyOf(doc), mentionedIn(doc)).map((defined) =>
33
+ : unusedDefinitions(definedTerms(doc.structure), [...bodyOf(doc), ...headingsOf(doc)], mentionedIn(doc)).map((defined) =>
30
34
  findingAt(doc, defined.span.start, { term: defined.term }),
31
35
  );
32
36
 
@@ -15,19 +15,24 @@ import {
15
15
  type NightsMismatch,
16
16
  type StayColumnWords,
17
17
  } from "../derived/stays.ts";
18
- import { escapeRegExp } from "../orthography.ts";
18
+ import { numeralCounts } from "../derived/unit-counts.ts";
19
+ import { timeLengths, type LengthWords, type TimeLength } from "../derived/time-lengths.ts";
20
+ import { workingHoursMismatches, type WorkingHoursMismatch } from "../derived/working-hours.ts";
21
+ import { sessionHoursMismatches } from "../derived/session-hours.ts";
22
+ import { clockTimes } from "../compare/clock-time.ts";
23
+ import { secondsOf, type Mark } from "../structure/time-marks.ts";
19
24
  import { proseAndTablesOf } from "../table-text.ts";
20
25
  import { quoteAt } from "./structure-tree.ts";
21
26
 
22
27
  /** 期間の単位の語彙表。木の数量の単位がどれかに入れば、その単位の期間。 */
23
- const DURATION_LEXICONS: readonly (readonly [string, DurationUnit])[] = [
28
+ export const DURATION_LEXICONS: readonly (readonly [string, DurationUnit])[] = [
24
29
  ["duration-day", "day"],
25
30
  ["duration-week", "week"],
26
31
  ["duration-month", "month"],
27
32
  ["duration-year", "year"],
28
33
  ];
29
34
 
30
- type Quantity = Span & { readonly amount: number; readonly unit: string };
35
+ export type Quantity = Span & { readonly amount: number; readonly unit: string };
31
36
 
32
37
  const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
33
38
 
@@ -57,7 +62,7 @@ const withWordsAround = (source: string, start: number, end: number, unit: strin
57
62
  return wordStart === undefined ? { start, end: endWithUnit(source, end, unit) } : { start: wordStart, end: endWithUnit(source, end + 1, unit) };
58
63
  };
59
64
 
60
- const quantitiesOf = (tree: StructureNode, source: string): Quantity[] =>
65
+ export const quantitiesOf = (tree: StructureNode, source: string): Quantity[] =>
61
66
  inDocumentOrder(tree).flatMap((node): Quantity[] => {
62
67
  if (node.kind !== "quantity") return [];
63
68
  const unit = String(node.attrs["unit"] ?? "");
@@ -93,29 +98,18 @@ const durationsOf = (doc: ProseDocument, quantities: readonly Quantity[]): Durat
93
98
 
94
99
  const sentencesOf = (doc: ProseDocument): Span[] => doc.sentences.map((sentence) => sentence.span);
95
100
 
96
- const LATIN_UNIT = /^[a-z]+$/iu;
97
-
98
- /** 数字と泊数の単位(3泊、3 nights)。英字の単位は語の切れ目まで。 */
99
- const digitNights = (text: string, units: readonly string[]): Count[] =>
100
- units.flatMap((unit) => {
101
- const tail = LATIN_UNIT.test(unit) ? "(?![\\p{L}\\p{N}])" : "";
102
- const pattern = new RegExp(`(?<![\\p{N}.,])(\\p{Nd}+)\\s?${escapeRegExp(unit)}${tail}`, "giu");
103
- return [...text.matchAll(pattern)].map((match) => ({
104
- start: match.index,
105
- end: match.index + match[0].length,
106
- amount: Number((match[1] ?? "").normalize("NFKC")),
107
- }));
108
- });
109
-
110
101
  /** 泊数(3泊、3 nights、three nights)。text は地の文と表(リンク先や code は読まない)。目安の泊数(最大3泊)は除く。 */
111
- const nightsOf = (doc: ProseDocument, text: string): Count[] => {
112
- const units = patternsOf(doc, "stay-night");
113
- const digits = digitNights(text, units);
114
- const taken = spanIndex(digits);
102
+ /** 数と単位(3泊、15 sessions、three nights)。 */
103
+ const unitCountsOf = (doc: ProseDocument, text: string, units: readonly string[]): Count[] => {
104
+ const numerals = numeralCounts(text, units);
105
+ const taken = spanIndex(numerals);
115
106
  const worded = numberWordCounts(text, patternsOf(doc, "count-number"), units).filter((count) => !overlapsAny(taken, count));
116
- return [...digits, ...worded].filter((count) => !isApproximate(doc, count)).toSorted((left, right) => left.start - right.start);
107
+ return [...numerals, ...worded].toSorted((left, right) => left.start - right.start);
117
108
  };
118
109
 
110
+ const nightsOf = (doc: ProseDocument, text: string): Count[] =>
111
+ unitCountsOf(doc, text, patternsOf(doc, "stay-night")).filter((count) => !isApproximate(doc, count));
112
+
119
113
  const finding = (doc: ProseDocument, offset: number, values: Record<string, string | number>, variant?: string): Finding => ({
120
114
  rule: "duration-mismatch",
121
115
  severity: "warning",
@@ -143,6 +137,57 @@ const stayColumnWords = (doc: ProseDocument): StayColumnWords => ({
143
137
  units: patternsOf(doc, "stay-night"),
144
138
  });
145
139
 
140
+ const marksOf = (doc: ProseDocument, id: string): Mark[] =>
141
+ (doc.lexicons[id] ?? []).map((entry) => ({ pattern: entry.pattern, position: entry.position, group: entry.group }));
142
+
143
+ const SECONDS_PER_HOUR = 3600;
144
+ const SECONDS_PER_MINUTE = 60;
145
+
146
+ /** The hour and minute units of unit-time, told apart by their weight in seconds. */
147
+ const unitsWeighing = (doc: ProseDocument, seconds: number): string[] =>
148
+ (doc.lexicons["unit-time"] ?? []).filter((entry) => entry.weight === seconds).map((entry) => entry.pattern);
149
+
150
+ const lengthWords = (doc: ProseDocument): LengthWords => ({
151
+ hourUnits: unitsWeighing(doc, SECONDS_PER_HOUR),
152
+ minuteUnits: unitsWeighing(doc, SECONDS_PER_MINUTE),
153
+ halves: patternsOf(doc, "length-half"),
154
+ numberWords: patternsOf(doc, "count-number"),
155
+ });
156
+
157
+ const lengthsOf = (doc: ProseDocument, text: string): TimeLength[] => timeLengths(text, lengthWords(doc));
158
+
159
+ const MINUTES_PER_HOUR = 60;
160
+ const HOUR_DECIMALS = 100;
161
+
162
+ const hoursOf = (minutes: number): number => Math.round((minutes / MINUTES_PER_HOUR) * HOUR_DECIMALS) / HOUR_DECIMALS;
163
+
164
+ const workingHoursFinding = (doc: ProseDocument, mismatch: WorkingHoursMismatch): Finding =>
165
+ finding(
166
+ doc,
167
+ mismatch.total.start,
168
+ {
169
+ start: written(doc, mismatch.start),
170
+ end: written(doc, mismatch.end),
171
+ break: written(doc, mismatch.break),
172
+ total: written(doc, mismatch.total),
173
+ expected: hoursOf(mismatch.expected),
174
+ },
175
+ "working-hours",
176
+ );
177
+
178
+ /** 始業から終業まで、休憩を除いた時間が、書いた実働と合わない。 */
179
+ const workingHoursOf = (doc: ProseDocument, text: string): Finding[] => {
180
+ const times = clockTimes(text).map((time) => ({ start: time.start, end: time.end, seconds: secondsOf(time.key) }));
181
+ const words = {
182
+ joiners: patternsOf(doc, "clock-range-joiner"),
183
+ dayShifts: marksOf(doc, "day-shift-mark"),
184
+ breaks: marksOf(doc, "working-hours-break"),
185
+ totals: marksOf(doc, "working-hours-total"),
186
+ approximate: marksOf(doc, "approximate-marker"),
187
+ };
188
+ return workingHoursMismatches(text, doc.source, sentencesOf(doc), times, lengthsOf(doc, text), words).map((mismatch) => workingHoursFinding(doc, mismatch));
189
+ };
190
+
146
191
  /** 始まり + 期間 ≠ 終わり。泊数が二つの日付の差と合わない。「2泊3日」の日数が泊数より一つ多くない。 */
147
192
  export const durationMismatch: Detector = (doc): Finding[] => {
148
193
  if (doc.structure === undefined) return [];
@@ -173,7 +218,35 @@ export const durationMismatch: Detector = (doc): Finding[] => {
173
218
  const nightsDays = nightsDaysMismatches(pairs).map((mismatch) =>
174
219
  finding(doc, mismatch.days.start, { nights: written(doc, mismatch.nights), days: written(doc, mismatch.days), expected: mismatch.expected }, "nights-days"),
175
220
  );
176
- return [...lengths, ...stays.map((mismatch) => nightsFinding(doc, mismatch)), ...nightsDays];
221
+ return [...lengths, ...stays.map((mismatch) => nightsFinding(doc, mismatch)), ...nightsDays, ...workingHoursOf(doc, proseAndTables)];
222
+ };
223
+
224
+ /** 番号の書き方(ordinal-frame)の頭の語のすぐ後ろの数。「第15回」は15番目の回で、15回ではない。 */
225
+ const isOrdinal = (doc: ProseDocument, text: string, count: Span): boolean =>
226
+ patternsOf(doc, "ordinal-frame").some((frame) => {
227
+ const head = frame.split("{n}")[0] ?? "";
228
+ return head !== "" && text.slice(Math.max(0, count.start - head.length), count.start).toLowerCase() === head.toLowerCase();
229
+ });
230
+
231
+ /** 回数 × 1回の長さが、書いた合計と合わない(90分×15回(計24時間))。 */
232
+ export const durationProductMismatch: Detector = (doc): Finding[] => {
233
+ const text = proseAndTablesOf(doc);
234
+ const counts = unitCountsOf(doc, text, patternsOf(doc, "session-count-unit")).filter((count) => !isOrdinal(doc, text, count));
235
+ const words = { totals: marksOf(doc, "session-total"), approximate: marksOf(doc, "approximate-marker") };
236
+ return sessionHoursMismatches(text, doc.source, sentencesOf(doc), counts, lengthsOf(doc, text), words).map((mismatch) => ({
237
+ rule: "duration-product-mismatch",
238
+ severity: "warning",
239
+ line: 0,
240
+ column: 0,
241
+ quote: quoteAt(doc.source, mismatch.total.start),
242
+ values: {
243
+ count: written(doc, mismatch.count),
244
+ length: written(doc, mismatch.length),
245
+ total: written(doc, mismatch.total),
246
+ expected: hoursOf(mismatch.expected),
247
+ offset: mismatch.total.start,
248
+ },
249
+ }));
177
250
  };
178
251
 
179
252
  /** 四桁の年。木が日付と読まなかった英語の年(founded in 2015、born 1980)もここで読む。 */
@@ -1,14 +1,18 @@
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
- // action-section-heading, earlier-section-word, action-due-label, item-done-word); the dates are the structure tree's, and the
4
- // lines are read with code masked.
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); the dates are the structure tree's, and the lines are read with code masked.
5
5
  import type { Detector, Finding, ProseDocument } from "../plugin.ts";
6
6
  import { actionDueBeforeMeeting, type ActionWords } from "../structure/action-due.ts";
7
+ import { pairedDatesOutOfOrder } from "../structure/labelled-date-order.ts";
7
8
  import { dueBeforeIssue, type DueWords } from "../structure/due-date.ts";
8
9
  import type { StructureIssue } from "../structure/issues.ts";
9
10
  import { proseAndTablesOf } from "../table-text.ts";
10
11
  import { datedPoints, quoteAt } from "./structure-tree.ts";
11
12
 
13
+ /** A record's facts table can sit well below its header date (a listing date above the table holding the move-in date). */
14
+ const MAX_RECORD_LINE_GAP = 40;
15
+
12
16
  const patternsOf = (doc: ProseDocument, lexicon: string): string[] => (doc.lexicons[lexicon] ?? []).map((entry) => entry.pattern);
13
17
 
14
18
  const wordsOf = (doc: ProseDocument): DueWords => ({
@@ -26,6 +30,8 @@ const actionWordsOf = (doc: ProseDocument): ActionWords => ({
26
30
  minutes: patternsOf(doc, "minutes-title-word"),
27
31
  });
28
32
 
33
+ const orderAsidesOf = (doc: ProseDocument): string[] => [...patternsOf(doc, "deadline-passed-word"), ...patternsOf(doc, "date-now-word")];
34
+
29
35
  const findingOf = (doc: ProseDocument, issue: StructureIssue, variant?: string): Finding => ({
30
36
  rule: "due-before-issue",
31
37
  severity: "error",
@@ -40,8 +46,10 @@ export const dueDate: Detector = (doc): Finding[] => {
40
46
  if (doc.structure === undefined) return [];
41
47
  const text = proseAndTablesOf(doc);
42
48
  const dates = datedPoints(doc.structure);
49
+ const pairs = doc.lexicons["dated-pair-label"] ?? [];
43
50
  return [
44
51
  ...dueBeforeIssue(text, dates, wordsOf(doc)).map((issue) => findingOf(doc, issue)),
52
+ ...pairedDatesOutOfOrder(text, dates, pairs, orderAsidesOf(doc), MAX_RECORD_LINE_GAP).map((issue) => findingOf(doc, issue, "order")),
45
53
  ...actionDueBeforeMeeting(text, dates, doc.markup?.headings ?? [], actionWordsOf(doc)).map((issue) => findingOf(doc, issue, "meeting")),
46
54
  ];
47
55
  };
@@ -123,9 +123,12 @@ export const conjunctionRun: Detector = (doc, options): Finding[] => {
123
123
  });
124
124
  };
125
125
 
126
- const headingsOf = (sections: readonly Section[]): { readonly section: Section; readonly title: boolean }[] =>
126
+ /** Weekday and month names, capitalised in either style (the list leaves out May, March and August, also ordinary words). */
127
+ const FIXED_CASE_LISTS = ["calendar-name"] as const;
128
+
129
+ const headingsOf = (sections: readonly Section[], fixedCase: ReadonlySet<string>): { readonly section: Section; readonly title: boolean }[] =>
127
130
  sections.flatMap((section) => {
128
- const title = isTitleCase(section.heading);
131
+ const title = isTitleCase(section.heading, fixedCase);
129
132
  return title === undefined ? [] : [{ section, title }];
130
133
  });
131
134
 
@@ -134,10 +137,14 @@ const headingsOf = (sections: readonly Section[]): { readonly section: Section;
134
137
  * 見るのは文書の中で揃っているかだけで、少数派のほうを指摘する。題名は指摘しない(minorityCase)。
135
138
  */
136
139
  export const titleCaseMix: Detector = (doc, options): Finding[] => {
140
+ const fixedCase = new Set(FIXED_CASE_LISTS.flatMap((id) => (doc.lexicons[id] ?? []).map((entry) => entry.pattern)));
137
141
  const pageTitle = pageTitleOf(doc.sections);
138
- const judged = headingsOf(doc.sections.filter((section) => section !== pageTitle));
142
+ const judged = headingsOf(
143
+ doc.sections.filter((section) => section !== pageTitle),
144
+ fixedCase,
145
+ );
139
146
  const titleCase = judged.filter((entry) => entry.title).length;
140
- const pageTitleCase = pageTitle === undefined ? undefined : isTitleCase(pageTitle.heading);
147
+ const pageTitleCase = pageTitle === undefined ? undefined : isTitleCase(pageTitle.heading, fixedCase);
141
148
  const minorityIsTitle = minorityCase({ titleCase, sentenceCase: judged.length - titleCase }, pageTitleCase);
142
149
  const few = minorityIsTitle === undefined ? [] : judged.filter((entry) => entry.title === minorityIsTitle);
143
150
  if (few.length > options.limit) return [];
@@ -0,0 +1,29 @@
1
+ // deadline-after-event: the reading half. The event-date, registration, deadline and follow-up words come from the language's
2
+ // lexicons (event-date-label, event-registration-word, event-deadline-word, event-aside); the dates are the structure tree's,
3
+ // and the lines are read with code masked.
4
+ import type { Detector, Finding, ProseDocument } from "../plugin.ts";
5
+ import { deadlinesAfterEvent, type EventDeadlineWords } from "../structure/deadline-after-event.ts";
6
+ import { proseAndTablesOf } from "../table-text.ts";
7
+ import { datedPoints, quoteAt } from "./structure-tree.ts";
8
+
9
+ const patternsOf = (doc: ProseDocument, lexicon: string): string[] => (doc.lexicons[lexicon] ?? []).map((entry) => entry.pattern);
10
+
11
+ const wordsOf = (doc: ProseDocument): EventDeadlineWords => ({
12
+ events: patternsOf(doc, "event-date-label"),
13
+ registrations: patternsOf(doc, "event-registration-word"),
14
+ deadlines: patternsOf(doc, "event-deadline-word"),
15
+ asides: patternsOf(doc, "event-aside"),
16
+ });
17
+
18
+ export const eventDeadline: Detector = (doc): Finding[] => {
19
+ if (doc.structure === undefined) return [];
20
+ const sentences = doc.sentences.map((sentence) => sentence.span);
21
+ return deadlinesAfterEvent(proseAndTablesOf(doc), datedPoints(doc.structure), sentences, wordsOf(doc)).map((issue) => ({
22
+ rule: "deadline-after-event",
23
+ severity: "error",
24
+ line: 0,
25
+ column: 0,
26
+ quote: quoteAt(doc.source, issue.offset),
27
+ values: { ...issue.values, offset: issue.offset },
28
+ }));
29
+ };
@@ -8,7 +8,11 @@ import { partsAt, scopedFacts, type ScopedFact } from "../facts/fact-scope.ts";
8
8
  import { conditionPairConflicts, type ChangeSentence, type ChangeWords, type ConditionWord, type PairConflict, type WordAt } from "../facts/condition-pairs.ts";
9
9
  import { scopeConflicts, summaryConflicts, type FactConflict } from "../facts/fact-conflicts.ts";
10
10
  import { eventDateConflicts, type EventDateConflict, type EventWord } from "../facts/event-dates.ts";
11
+ import { retentionConflicts, type LengthMark, type RetentionLength, type RetentionVerb, type RetentionWords } from "../facts/retention-periods.ts";
12
+ import type { DurationUnit } from "../derived/date-arithmetic.ts";
13
+ import { DURATION_LEXICONS, quantitiesOf, type Quantity } from "./derived-numbers.ts";
11
14
  import { quoteAt } from "./structure-tree.ts";
15
+ import { measuredOf, valuesWith } from "./measured-facts.ts";
12
16
 
13
17
  const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
14
18
 
@@ -23,8 +27,9 @@ export const factWordsOf = (doc: ProseDocument): FactWords => ({
23
27
 
24
28
  const factsByDocument = new WeakMap<ProseDocument, readonly ScopedFact[]>();
25
29
 
30
+ /** 単位の語彙表の量(410 g、1.2 kg)も値として読む。木が単位を読まない量は、数だけでは升や文の値にならない。 */
26
31
  const readFacts = (doc: ProseDocument, tree: StructureNode): ScopedFact[] => {
27
- const values = factValues(tree, doc.source, nameSpans(doc));
32
+ const values = valuesWith(tree, doc, measuredOf(doc));
28
33
  const facts = [...labelledFacts(doc.source, values, factWordsOf(doc)), ...tableFacts(doc.source, values)];
29
34
  return scopedFacts(facts, tree, doc.source, patternsOf(doc, "summary-heading"));
30
35
  };
@@ -51,8 +56,64 @@ const findingOf =
51
56
  values: { label: conflict.fact.label, value: shown(doc, conflict.fact.value), other: shown(doc, conflict.other), offset: conflict.fact.value.start },
52
57
  });
53
58
 
54
- /** 同じ節で、同じ名前に二通りの値(締切:10月5日 と 締切:10月7日)。 */
55
- export const factConflict: Detector = (doc): Finding[] => scopeConflicts(factsOf(doc)).map(findingOf("fact-conflict", doc));
59
+ const UNITS: readonly DurationUnit[] = ["day", "week", "month", "year"];
60
+
61
+ const isDurationUnit = (group: string | undefined): group is DurationUnit => UNITS.some((unit) => unit === group);
62
+
63
+ const retentionUnitOf = (doc: ProseDocument, unit: string): DurationUnit | undefined => {
64
+ const listed = DURATION_LEXICONS.find(([id]) => patternsOf(doc, id).some((pattern) => pattern.normalize("NFKC") === unit))?.[1];
65
+ const extra = (doc.lexicons["retention-unit"] ?? []).find((entry) => entry.pattern.normalize("NFKC") === unit)?.group;
66
+ return listed ?? (isDurationUnit(extra) ? extra : undefined);
67
+ };
68
+
69
+ /** 単位の語彙表に、書いた単位より長い形(か月 に対する か月間)があれば、そこまで。木の数量は か月 で終わる。 */
70
+ const endWithLongerUnit = (doc: ProseDocument, quantity: Quantity): number => {
71
+ const unitStart = quantity.end - quantity.unit.length;
72
+ const longer = DURATION_LEXICONS.flatMap(([id]) => patternsOf(doc, id))
73
+ .filter((pattern) => pattern.length > quantity.unit.length && pattern.startsWith(quantity.unit) && doc.source.startsWith(pattern, unitStart))
74
+ .reduce((longest, pattern) => Math.max(longest, pattern.length), quantity.unit.length);
75
+ return unitStart + longer;
76
+ };
77
+
78
+ const retentionLengthsOf = (doc: ProseDocument, tree: StructureNode): RetentionLength[] =>
79
+ quantitiesOf(tree, doc.source).flatMap((quantity) => {
80
+ const unit = retentionUnitOf(doc, quantity.unit);
81
+ return unit === undefined ? [] : [{ start: quantity.start, end: endWithLongerUnit(doc, quantity), amount: quantity.amount, unit }];
82
+ });
83
+
84
+ const retentionVerbsOf = (doc: ProseDocument): RetentionVerb[] =>
85
+ (doc.lexicons["retention-verb"] ?? []).map((entry) => ({ pattern: entry.pattern, group: entry.group ?? "", position: entry.position ?? "before" }));
86
+
87
+ const lengthMarksOf = (doc: ProseDocument): LengthMark[] =>
88
+ (doc.lexicons["retention-length-mark"] ?? []).map((entry) => ({ pattern: entry.pattern, group: entry.group ?? "", position: entry.position ?? "before" }));
89
+
90
+ const retentionWordsOf = (doc: ProseDocument): RetentionWords => ({
91
+ verbs: retentionVerbsOf(doc),
92
+ marks: lengthMarksOf(doc),
93
+ modifiers: patternsOf(doc, "retention-length-modifier"),
94
+ bounds: [...wordsAt(doc, "approximate-marker"), ...wordsAt(doc, "retention-bound")],
95
+ joiners: patternsOf(doc, "fact-name-joiner"),
96
+ objectMarks: patternsOf(doc, "retention-object-mark"),
97
+ });
98
+
99
+ /** 文書のどこかで、同じものの保存期間が二通り(1年間保存 と 3年間を経過したら削除)。 */
100
+ const retentionFindings = (doc: ProseDocument): Finding[] => {
101
+ const tree = doc.structure;
102
+ if (tree === undefined) return [];
103
+ const sentences = doc.sentences.map((sentence) => ({ ...sentence.span, tokens: sentence.tokens ?? [] }));
104
+ return retentionConflicts(doc.source, sentences, retentionLengthsOf(doc, tree), retentionWordsOf(doc)).map(({ object, value, other }): Finding => ({
105
+ rule: "fact-conflict",
106
+ severity: "warning",
107
+ line: 0,
108
+ column: 0,
109
+ quote: quoteAt(doc.source, value.start),
110
+ variant: "retention",
111
+ values: { label: object, value: doc.source.slice(value.start, value.end), other: doc.source.slice(other.start, other.end), offset: value.start },
112
+ }));
113
+ };
114
+
115
+ /** 同じ節で、同じ名前に二通りの値(締切:10月5日 と 締切:10月7日)。文書のどこでも、同じものに二通りの保存期間。 */
116
+ export const factConflict: Detector = (doc): Finding[] => [...scopeConflicts(factsOf(doc)).map(findingOf("fact-conflict", doc)), ...retentionFindings(doc)];
56
117
 
57
118
  const countedPhrasesOf = (doc: ProseDocument): CountedPhrase[] =>
58
119
  doc.sentences.flatMap((sentence) => {
@@ -34,11 +34,20 @@ const ACRONYM = /^[A-Z]{2,}s?$/u;
34
34
 
35
35
  const TITLE_DEPTH = 1;
36
36
 
37
- /** 見出しが Title Case か。判定できなければ undefined。 */
38
- export const isTitleCase = (heading: string): boolean | undefined => {
39
- const words = [...withoutCodeWords(straightApostrophes(heading)).matchAll(WORD)]
37
+ /**
38
+ * 見出しの頭の番号の札(Section 3. / Day 1: / Part II:)。札の語は流儀によらず大文字で始まり、続く題の語数にも数えない。
39
+ * 番号は 3 桁までで、後ろに「.」「:」「)」か ダッシュがあるものだけ(Windows 11 Setup も Budget 2026: も札ではない)。
40
+ */
41
+ const LEADING_LABEL = /^\s*\p{Lu}\p{Ll}+\s+(?:\d{1,3}(?:\.\d{1,3})*|[IVXLC]+)\s*[.:)\-\u2013\u2014]\s+/u;
42
+
43
+ /**
44
+ * 見出しが Title Case か。判定できなければ undefined。fixedCase は流儀によらず大文字で書く語(曜日・月の名)で、
45
+ * どちらの流儀の証拠にもならないので数えない。
46
+ */
47
+ export const isTitleCase = (heading: string, fixedCase: ReadonlySet<string> = new Set()): boolean | undefined => {
48
+ const words = [...withoutCodeWords(straightApostrophes(heading.replace(LEADING_LABEL, ""))).matchAll(WORD)]
40
49
  .map((match) => match[0])
41
- .filter((word) => !MINOR_WORDS.has(word.toLowerCase()) && !ACRONYM.test(word));
50
+ .filter((word) => !MINOR_WORDS.has(word.toLowerCase()) && !ACRONYM.test(word) && !fixedCase.has(word));
42
51
  // 1 語の見出しは、どちらの流儀でも先頭が大文字になる。判定できない。
43
52
  if (words.length < 2) return undefined;
44
53
  const capitalized = words.filter((word) => word[0] === word[0]?.toUpperCase()).length;
@@ -65,6 +65,22 @@ const pointsElsewhere = (doc: ProseDocument, section: Section): boolean => {
65
65
  return first !== undefined && (holdsLink(doc.source, first.span, doc.links) || namesLocation(doc.source.slice(first.span.start, first.span.end)));
66
66
  };
67
67
 
68
+ /** A figure, with its thousands separators (1,320,000), compared without them. */
69
+ const FIGURE = /\p{Nd}+(?:[,,]\p{Nd}{3})*/gu;
70
+ /** Note marks are not figures: [^1], ※1, <sup>1</sup>. */
71
+ const NOTE_MARK = /\[\^[^\]]*\]|※\p{Nd}+|<sup>[^<]*<\/sup>/gu;
72
+
73
+ const figuresOf = (text: string): string[] => (text.replace(NOTE_MARK, "").match(FIGURE) ?? []).map((figure) => figure.replace(/[,,]/gu, ""));
74
+
75
+ /**
76
+ * 最初の文が、見出しに無い数(金額・番号・日付)を述べている。見出しが約束した中身そのもので(## 見積金額 → 見積金額は1,320,000円です。
77
+ * Invoice → Invoice number: INV-2026-0318)、語が重なっても読者は何かを受け取る。
78
+ */
79
+ export const statesFigure = (heading: string, sentence: string): boolean => {
80
+ const inHeading = new Set(figuresOf(heading));
81
+ return figuresOf(sentence).some((figure) => !inHeading.has(figure));
82
+ };
83
+
68
84
  /** 見出しとの重なりを測る文。用語集や表記の手引きは見出しの語の別の書き方を引用する(Not “datacentre”)ので、それは数えない。 */
69
85
  const echoedText = (section: Section): string => withoutQuotedVariants(section.firstSentence?.text ?? "", measuredHeading(section));
70
86
 
@@ -72,7 +88,7 @@ export const headingEcho: Detector = (doc, options): Finding[] => {
72
88
  const leadIns = (doc.lexicons["lead-in"] ?? []).map((entry) => entry.pattern);
73
89
  return doc.sections
74
90
  .filter((section) => section.heading.length > 0 && section.firstSentence !== undefined && addsLittle(section, doc.lengthUnit))
75
- .filter((section) => !leadsIn(doc, section, leadIns) && !pointsElsewhere(doc, section))
91
+ .filter((section) => !leadsIn(doc, section, leadIns) && !pointsElsewhere(doc, section) && !statesFigure(section.heading, section.firstSentence?.text ?? ""))
76
92
  .map((section) => ({ section, overlap: Math.round(containment(trigrams(measuredHeading(section)), trigrams(echoedText(section))) * 100) }))
77
93
  .filter(({ overlap }) => overlap >= options.limit)
78
94
  .map(({ section, overlap }) => ({