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
@@ -0,0 +1,226 @@
1
+ import type { StructureIssue } from "./issues.ts";
2
+ import { lineNumberAt, linesOf, type Line } from "./lines.ts";
3
+ import { runsOf } from "./runs.ts";
4
+ import type { Stop } from "./time-order.ts";
5
+ import {
6
+ crossesZones,
7
+ dayShiftOf,
8
+ markBefore,
9
+ markSoonAfter,
10
+ wordOffsets,
11
+ zonesIn,
12
+ type DateSpan,
13
+ type Mark,
14
+ type TimeSpan,
15
+ type TimeWords,
16
+ } from "./time-marks.ts";
17
+
18
+ /**
19
+ * 乗り継ぎの間が、文書に書いた移動の時間より短い所。移動の時間は、移動の語(移動、徒歩、地下鉄、by Metro、coach。語彙表
20
+ * travel-time-word)と同じ文に書いた長さ(約10分、about 40 minutes)だけを使う。実際にかかる時間は推し量らない。
21
+ * 移動の始まりと終わりの時刻は二通りに読む。
22
+ * - 移動そのものを書いた予定(「10:00 京都駅から貸切バスで清水寺へ(約30分)」)は、その時刻に発ち、同じ日の次の予定までに着く。
23
+ * - 予定に添えた移動の時間(「09:55 博多駅で合流(福岡空港から地下鉄で約10分)」)や、時刻の無い移動の文に続けて書いた時刻は、
24
+ * すぐ前の着の時刻(「福岡 09:50着」、表の到着の列)から移動して、その時刻に間に合う。
25
+ * 日付が違う、翌日の印がある、時刻が戻る(夜をまたぐ)、時間帯の印が違う所は比べない。
26
+ */
27
+
28
+ /** 移動の時間として読む長さ。minutes は分。 */
29
+ export type TravelLength = { readonly start: number; readonly end: number; readonly minutes: number };
30
+
31
+ /** cues は移動を言う語、bounds は長さを上限として言う語(以内、within)。上限の長さは、それより早く着けるので使わない。 */
32
+ export type TravelWords = { readonly cues: readonly Mark[]; readonly bounds: readonly Mark[] };
33
+
34
+ export type ConnectionInputs = {
35
+ readonly source: string;
36
+ readonly times: readonly TimeSpan[];
37
+ readonly dates: readonly DateSpan[];
38
+ readonly words: TimeWords;
39
+ readonly travel: TravelWords;
40
+ readonly lengths: readonly TravelLength[];
41
+ readonly arrivals: ReadonlySet<number>;
42
+ readonly days: readonly (readonly Stop[])[];
43
+ };
44
+
45
+ const SECONDS_PER_MINUTE = 60;
46
+
47
+ /** 文の切れ目。leg-times.ts と同じ。 */
48
+ const BREAK = /[。.;;!?!?]|\.\s/gu;
49
+ /** 括弧書き。中に括弧を入れ子にしたものは、内側から一つずつ外す。 */
50
+ const BRACKETED = /[((][^()()]*[))]/gu;
51
+ /** 「within 10 minutes」の within と長さの間に挟んでよい字の数。 */
52
+ const BOUND_GAP = 1;
53
+
54
+ /** 発ってから着くまでの間が、書いた移動の時間より短いか。間が負なら(時刻が戻る)、夜をまたいだのか書き間違いか決められないので言わない。 */
55
+ export const isTooShort = (gapSeconds: number, travelMinutes: number): boolean => gapSeconds >= 0 && gapSeconds < travelMinutes * SECONDS_PER_MINUTE;
56
+
57
+ /** 二つの時刻に書いた日付が比べられるか。両方に無いか、同じ書き方で同じ日付なら同じ日。 */
58
+ export const isSameDate = (left: string | undefined, right: string | undefined): boolean => left === right;
59
+
60
+ /** 時間帯の印を見て、二つの行の時刻をそのまま比べられるか。どちらかが時間帯をまたぐか、印が違えば比べない。 */
61
+ export const isSameZone = (left: string, right: string, words: TimeWords): boolean => {
62
+ const [leftZones, rightZones] = [zonesIn(left, words), zonesIn(right, words)];
63
+ if (crossesZones(leftZones) || crossesZones(rightZones)) return false;
64
+ return (leftZones[0]?.text ?? "") === (rightZones[0]?.text ?? "");
65
+ };
66
+
67
+ /** 括弧書きを外した残り。 */
68
+ export const outsideBrackets = (text: string): string => {
69
+ const stripped = text.replace(BRACKETED, " ");
70
+ return stripped === text ? text : outsideBrackets(stripped);
71
+ };
72
+
73
+ /** text に移動の語が一語として書かれているか。大文字と小文字は区別しない。 */
74
+ export const mentionsTravel = (text: string, cues: readonly Mark[]): boolean => {
75
+ const lower = text.toLowerCase();
76
+ return cues.some((cue) => wordOffsets(lower, cue.pattern.toLowerCase()).length > 0);
77
+ };
78
+
79
+ /** 行の中で、at から to までを含む文の範囲(行の頭からの位置)。 */
80
+ export const sentenceAround = (text: string, at: number, to: number): { start: number; end: number } => {
81
+ const breaks = [...text.matchAll(BREAK)].map((match) => ({ start: match.index, end: match.index + match[0].length }));
82
+ const start = breaks.filter((cut) => cut.end <= at).at(-1)?.end ?? 0;
83
+ const end = breaks.find((cut) => cut.start >= to)?.start ?? text.length;
84
+ return { start, end };
85
+ };
86
+
87
+ const lineAt = (lines: readonly Line[], offset: number): Line | undefined => {
88
+ const number = lineNumberAt(lines, offset);
89
+ return number === undefined ? undefined : lines[number - 1];
90
+ };
91
+
92
+ /** 長さが上限として書かれている(10分以内、within 10 minutes)か。 */
93
+ const isBound = (inputs: ConnectionInputs, line: Line, length: TravelLength): boolean => {
94
+ const head = inputs.source.slice(line.start, length.start).toLowerCase();
95
+ return markSoonAfter(inputs.source, length.end, inputs.travel.bounds, []) !== undefined || markBefore(head, inputs.travel.bounds, BOUND_GAP) !== undefined;
96
+ };
97
+
98
+ /** 移動の時間を書いた長さか。同じ文に移動の語があり、上限として書いたものではない。 */
99
+ const isTravel = (inputs: ConnectionInputs, line: Line, length: TravelLength): boolean => {
100
+ const sentence = sentenceAround(line.text, length.start - line.start, length.end - line.start);
101
+ return mentionsTravel(line.text.slice(sentence.start, sentence.end), inputs.travel.cues) && !isBound(inputs, line, length);
102
+ };
103
+
104
+ /** 時刻の前の、同じ行に書いた最後の日付。 */
105
+ const dateOf = (inputs: ConnectionInputs, line: Line, time: TimeSpan): string | undefined =>
106
+ inputs.dates.filter((date) => date.start >= line.start && date.end <= time.start).at(-1)?.value;
107
+
108
+ const shiftOf = (inputs: ConnectionInputs, line: Line, time: TimeSpan): number =>
109
+ dayShiftOf(inputs.source.slice(line.start, time.start), inputs.source, time.end, inputs.words);
110
+
111
+ const written = (inputs: ConnectionInputs, span: { start: number; end: number }): string => inputs.source.slice(span.start, span.end);
112
+
113
+ type Leg = { readonly from: TimeSpan; readonly to: TimeSpan };
114
+
115
+ const issueOf = (inputs: ConnectionInputs, leg: Leg, length: TravelLength): StructureIssue => ({
116
+ offset: leg.to.start,
117
+ values: {
118
+ time: written(inputs, leg.to),
119
+ from: written(inputs, leg.from),
120
+ gap: Math.round((leg.to.seconds - leg.from.seconds) / SECONDS_PER_MINUTE),
121
+ travel: written(inputs, length),
122
+ },
123
+ });
124
+
125
+ const dayOf = (inputs: ConnectionInputs, line: Line): readonly Stop[] | undefined =>
126
+ inputs.days.find((stops) => stops.some((stop) => stop.offset >= line.start && stop.offset <= line.start + line.text.length));
127
+
128
+ const OPENERS = new Set(["(", "("]);
129
+ const CLOSERS = new Set([")", ")"]);
130
+
131
+ /** at から to までを囲む一番内側の括弧の中身の範囲(行の頭からの位置)。囲む括弧が無ければ undefined。 */
132
+ export const bracketAround = (text: string, at: number, to: number): { start: number; end: number } | undefined => {
133
+ const open = text
134
+ .slice(0, at)
135
+ .split("")
136
+ .reduceRight<{ depth: number; found: number | undefined }>(
137
+ (scan, char, index) => {
138
+ if (scan.found !== undefined) return scan;
139
+ if (CLOSERS.has(char)) return { ...scan, depth: scan.depth + 1 };
140
+ if (!OPENERS.has(char)) return scan;
141
+ return scan.depth === 0 ? { ...scan, found: index } : { ...scan, depth: scan.depth - 1 };
142
+ },
143
+ { depth: 0, found: undefined },
144
+ ).found;
145
+ if (open === undefined) return undefined;
146
+ const close = text
147
+ .slice(to)
148
+ .split("")
149
+ .findIndex((char) => CLOSERS.has(char));
150
+ return close === -1 ? undefined : { start: open + 1, end: to + close };
151
+ };
152
+
153
+ /**
154
+ * 移動そのものを書いた予定か。頭に時刻を書いた予定で、移動の語が括弧の外(行の本文)にある。長さを囲む括弧の中に移動の語が
155
+ * あれば(「(福岡空港から地下鉄で約10分)」)、その括弧はこの予定までの移動を添えたもので、予定は移動ではない。
156
+ */
157
+ const isMoveLine = (inputs: ConnectionInputs, line: Line, length: TravelLength): boolean => {
158
+ const aside = bracketAround(line.text, length.start - line.start, length.end - line.start);
159
+ if (aside !== undefined && mentionsTravel(line.text.slice(aside.start, aside.end), inputs.travel.cues)) return false;
160
+ return dayOf(inputs, line) !== undefined && mentionsTravel(outsideBrackets(line.text), inputs.travel.cues);
161
+ };
162
+
163
+ /** 移動そのものを書いた予定の時刻と、同じ日の次の予定の時刻。 */
164
+ const scheduledLeg = (inputs: ConnectionInputs, line: Line): Leg | undefined => {
165
+ const day = dayOf(inputs, line);
166
+ const index = day?.findIndex((stop) => stop.offset >= line.start) ?? -1;
167
+ const [start, next] = [day?.[index], day?.[index + 1]];
168
+ if (start === undefined || next === undefined || start.shift !== 0 || next.shift !== 0 || start.zone.startsWith("local:")) return undefined;
169
+ const timeAt = (offset: number): TimeSpan | undefined => inputs.times.find((time) => time.start === offset);
170
+ const [from, to] = [timeAt(start.offset), timeAt(next.offset)];
171
+ return from === undefined || to === undefined ? undefined : { from, to };
172
+ };
173
+
174
+ /** 時刻と同じ並び(続いた箇条書きや表の行)か同じ行にある、その時刻より前の時刻。 */
175
+ const timesBeside = (inputs: ConnectionInputs, line: Line, to: TimeSpan): TimeSpan[] => {
176
+ const run = runsOf(inputs.source).find((lines) => lines.some((row) => row.start === line.start));
177
+ const inScope = (time: TimeSpan): boolean =>
178
+ (time.start >= line.start && time.end <= to.start) || (run?.some((row) => time.start >= row.start && time.end <= row.end) ?? false);
179
+ return inputs.times.filter((time) => time.end <= to.start && inScope(time));
180
+ };
181
+
182
+ /** 日付を書いた時刻なら、文書のそれより前の同じ日付の時刻。日付が無ければ、同じ並びか同じ行の、日付の無い前の時刻。 */
183
+ const timesBefore = (inputs: ConnectionInputs, lines: readonly Line[], line: Line, to: TimeSpan): TimeSpan[] => {
184
+ const date = dateOf(inputs, line, to);
185
+ const candidates = date === undefined ? timesBeside(inputs, line, to) : inputs.times.filter((time) => time.end <= to.start);
186
+ return candidates.filter((time) => {
187
+ const own = lineAt(lines, time.start);
188
+ return own !== undefined && isSameDate(dateOf(inputs, own, time), date);
189
+ });
190
+ };
191
+
192
+ /**
193
+ * 移動の時間を添えた時刻。予定の行ならその頭の時刻、文なら移動の文の中かその後ろの、最初の着でない時刻。
194
+ * 移動の文より前の時刻は、移動の前の予定で、移動して着く先ではない。
195
+ */
196
+ const arrivalTarget = (inputs: ConnectionInputs, line: Line, length: TravelLength): TimeSpan | undefined => {
197
+ const stop = dayOf(inputs, line)?.find((candidate) => candidate.offset >= line.start && candidate.offset <= line.start + line.text.length);
198
+ if (stop !== undefined) return inputs.times.find((time) => time.start === stop.offset);
199
+ const sentenceStart = line.start + sentenceAround(line.text, length.start - line.start, length.end - line.start).start;
200
+ return inputs.times.find((time) => time.start >= sentenceStart && time.end <= line.start + line.text.length && !inputs.arrivals.has(time.start));
201
+ };
202
+
203
+ /** 移動の時間を添えた時刻と、そのすぐ前の着の時刻。すぐ前の時刻が着でなければ、どこから移動したのか分からない。 */
204
+ const arrivingLeg = (inputs: ConnectionInputs, lines: readonly Line[], line: Line, length: TravelLength): Leg | undefined => {
205
+ const to = arrivalTarget(inputs, line, length);
206
+ if (to === undefined) return undefined;
207
+ const from = timesBefore(inputs, lines, line, to).at(-1);
208
+ const fromLine = from === undefined ? undefined : lineAt(lines, from.start);
209
+ if (from === undefined || fromLine === undefined || !inputs.arrivals.has(from.start)) return undefined;
210
+ if (shiftOf(inputs, fromLine, from) !== 0 || shiftOf(inputs, line, to) !== 0 || !isSameZone(fromLine.text, line.text, inputs.words)) return undefined;
211
+ return { from, to };
212
+ };
213
+
214
+ /** 移動の時間を書いた長さごとに、間の足りない乗り継ぎ。同じ時刻は一度だけ言う。 */
215
+ export const shortConnections = (inputs: ConnectionInputs): StructureIssue[] => {
216
+ const lines = linesOf(inputs.source);
217
+ const issues = inputs.lengths.flatMap((length) => {
218
+ const line = lineAt(lines, length.start);
219
+ if (line === undefined || !isTravel(inputs, line, length)) return [];
220
+ const leg = isMoveLine(inputs, line, length) ? scheduledLeg(inputs, line) : arrivingLeg(inputs, lines, line, length);
221
+ return leg !== undefined && isTooShort(leg.to.seconds - leg.from.seconds, length.minutes) ? [issueOf(inputs, leg, length)] : [];
222
+ });
223
+ return issues
224
+ .filter((issue, index) => issues.findIndex((other) => other.offset === issue.offset) === index)
225
+ .toSorted((left, right) => left.offset - right.offset);
226
+ };
@@ -7,10 +7,10 @@ import type { Amount } from "./total.ts";
7
7
  export type SummedCounter = { readonly pattern: string; readonly unit: string };
8
8
 
9
9
  /** 前に英字や数や小数点が続く数(v2、A4、1.2.3 の 2)は読まない。日本語は数の前に空白を置かないので、仮名や漢字の後ろはよい。 */
10
- const NUMBER = /(?<![\p{Script=Latin}\p{N}.,.,])[0-90-9]+(?:[,,][0-90-9]{3})*(?:[..][0-90-9]+)?/gu;
10
+ export const NUMBER = /(?<![\p{Script=Latin}\p{N}.,.,])[0-90-9]+(?:[,,][0-90-9]{3})*(?:[..][0-90-9]+)?/gu;
11
11
 
12
12
  /** 助数詞に文字や数、つなぎの - _ が詰めて続くもの(3単位目、4コマ漫画、3 unit-priced)は、別の語の一部。 */
13
- const CONTINUES_WORD = /^[\p{L}\p{N}_-]/u;
13
+ export const CONTINUES_WORD = /^[\p{L}\p{N}_-]/u;
14
14
 
15
15
  /** 序数の印(第3回)。 */
16
16
  const ORDINAL_MARK = "第";
@@ -18,7 +18,7 @@ const ORDINAL_MARK = "第";
18
18
  /** 助数詞を探す長さ。どの助数詞よりも長い。 */
19
19
  const LOOKAHEAD = 32;
20
20
 
21
- const valueOf = (written: string): number => Number(written.normalize("NFKC").replace(/,/gu, ""));
21
+ export const valueOf = (written: string): number => Number(written.normalize("NFKC").replace(/,/gu, ""));
22
22
 
23
23
  /** 数のすぐ後ろ(空白一つまで)の助数詞。長い語から試す。大文字小文字は区別しない(4 Credits)。 */
24
24
  const counterAfter = (source: string, end: number, counters: readonly SummedCounter[]): { unit: string; end: number } | undefined => {
@@ -28,7 +28,8 @@ const counterAfter = (source: string, end: number, counters: readonly SummedCoun
28
28
  return counter === undefined ? undefined : { unit: counter.unit, end: end + gap + counter.pattern.length };
29
29
  };
30
30
 
31
- const overlapsAny = (start: number, end: number, amounts: readonly Amount[]): boolean => amounts.some((amount) => start < amount.end && amount.offset < end);
31
+ export const overlapsAny = (start: number, end: number, amounts: readonly Amount[]): boolean =>
32
+ amounts.some((amount) => start < amount.end && amount.offset < end);
32
33
 
33
34
  /** 文書の中の、足してよい助数詞の付いた数。木がすでに数量として読んだもの(known)とは重ねない。 */
34
35
  export const countedAmounts = (source: string, counters: readonly SummedCounter[], known: readonly Amount[]): Amount[] => {
@@ -0,0 +1,86 @@
1
+ import { versionsAlong } from "./version-order.ts";
2
+
3
+ /**
4
+ * 隣どうしの二つの日付が入れ替わったように見えて、どちらを取り除いても同じだけ揃う(引き分け)とき、同じ項目の手がかりで決める。
5
+ * 項目がみな版を持ち、版が向きに沿って並ぶなら、並びの位置は版が裏付ける。位置に照らして逆らう相手の多い日付を指す。
6
+ * 版が無いか、版も乱れているなら、二つだけが入れ替わった並びに限り、外側の隣(前の日付の前、後ろの日付の後ろ)から遠いほうを指す。書き間違えた日付は隣から跳ぶ。
7
+ * どちらでも決まらなければ undefined(呼ぶ側はこれまでどおり後ろを指す)。
8
+ */
9
+ export type TieEntry = { readonly value: string; readonly version: string | undefined };
10
+
11
+ const DAY_MS = 86_400_000;
12
+ const MONTHS_PER_YEAR = 12;
13
+ /** 年の無い月日(09-14)を日数にするための、閏年の仮の年。 */
14
+ const LEAP_YEAR = 2000;
15
+
16
+ /** 同じ書き方の日付どうしで差をとれる数。年月日と月日は日数、年月は月数。 */
17
+ const pointOf = (value: string): number | undefined => {
18
+ const full = /^(\d{4})-(\d{2})-(\d{2})$/u.exec(value);
19
+ if (full !== null) return Date.UTC(Number(full[1]), Number(full[2]) - 1, Number(full[3])) / DAY_MS;
20
+ const month = /^(\d{4})-(\d{2})$/u.exec(value);
21
+ if (month !== null) return Number(month[1]) * MONTHS_PER_YEAR + Number(month[2]);
22
+ const day = /^(\d{2})-(\d{2})$/u.exec(value);
23
+ return day === null ? undefined : Date.UTC(LEAP_YEAR, Number(day[1]) - 1, Number(day[2])) / DAY_MS;
24
+ };
25
+
26
+ /** 位置に照らして向きに逆らう相手の数。 */
27
+ const disagreements = (values: readonly string[], index: number, direction: number): number =>
28
+ values.filter((other, at) => {
29
+ if (at === index) return false;
30
+ const [earlier, later] = at < index ? [other, values[index] ?? ""] : [values[index] ?? "", other];
31
+ return Math.sign(later.localeCompare(earlier)) === -direction;
32
+ }).length;
33
+
34
+ /** 多いほうを指す。同じなら決めない。 */
35
+ const larger = (before: number, after: number, scores: readonly [number, number]): number | undefined => {
36
+ if (scores[0] === scores[1]) return undefined;
37
+ return scores[0] > scores[1] ? before : after;
38
+ };
39
+
40
+ const byVersion = (entries: readonly TieEntry[], before: number, after: number, direction: number): number | undefined => {
41
+ if (
42
+ !versionsAlong(
43
+ entries.map((entry) => entry.version),
44
+ direction,
45
+ )
46
+ )
47
+ return undefined;
48
+ const values = entries.map((entry) => entry.value);
49
+ return larger(before, after, [disagreements(values, before, direction), disagreements(values, after, direction)]);
50
+ };
51
+
52
+ const distance = (entries: readonly TieEntry[], from: number, to: number): number | undefined => {
53
+ const start = pointOf(entries[from]?.value ?? "");
54
+ const end = pointOf(entries[to]?.value ?? "");
55
+ return start === undefined || end === undefined ? undefined : Math.abs(end - start);
56
+ };
57
+
58
+ /** from から to へ、向きに逆らわない(等しくてもよい)。 */
59
+ const along = (from: string, to: string, direction: number): boolean => Math.sign(to.localeCompare(from)) !== -direction;
60
+
61
+ /** 隣どうしの入れ替わりだけ: 外側の二つが向きに沿い、入れ替わった二つがどちらもその間に収まる。乱れが広い並びでは、外側の隣も当てにならない。 */
62
+ const isSwap = (values: readonly string[], before: number, after: number, direction: number): boolean => {
63
+ const [outerBefore, outerAfter] = [values[before - 1], values[after + 1]];
64
+ if (outerBefore === undefined || outerAfter === undefined) return false;
65
+ return [values[before] ?? "", values[after] ?? ""].every((value) => along(outerBefore, value, direction) && along(value, outerAfter, direction));
66
+ };
67
+
68
+ const byGap = (entries: readonly TieEntry[], before: number, after: number, direction: number): number | undefined => {
69
+ if (
70
+ !isSwap(
71
+ entries.map((entry) => entry.value),
72
+ before,
73
+ after,
74
+ direction,
75
+ )
76
+ )
77
+ return undefined;
78
+ const outerBefore = distance(entries, before - 1, before);
79
+ const outerAfter = distance(entries, after, after + 1);
80
+ if (outerBefore === undefined || outerAfter === undefined) return undefined;
81
+ return larger(before, after, [outerBefore, outerAfter]);
82
+ };
83
+
84
+ /** 引き分けの二つ(before = at - 1、after = at)のうち外れたほう。決まらなければ undefined。 */
85
+ export const breakDateTie = (entries: readonly TieEntry[], before: number, after: number, direction: number): number | undefined =>
86
+ byVersion(entries, before, after, direction) ?? byGap(entries, before, after, direction);
@@ -1,6 +1,8 @@
1
1
  import type { StructureIssue } from "./issues.ts";
2
2
  import { siblingHeadingRunsOf } from "./heading-runs.ts";
3
3
  import { runsOf } from "./runs.ts";
4
+ import { breakDateTie, type TieEntry } from "./date-order-tie.ts";
5
+ import { leadingVersion } from "./version-order.ts";
4
6
 
5
7
  /**
6
8
  * 日程として並べた日付の順番。箇条書きの続いた項目、表の続いた行、同じ親の下で同じ深さに並ぶ見出しで、
@@ -32,17 +34,30 @@ const onlyDateIn = (line: Span, points: readonly DatedPoint[]): DatedPoint | und
32
34
  return inside.length === 1 ? inside[0] : undefined;
33
35
  };
34
36
 
35
- const datedLines = (run: readonly Span[], points: readonly DatedPoint[]): DatedPoint[] =>
37
+ /** 日付を一つ持つ一行。行が版で始まれば(「## 3.1.1 - 2026-05-08」「- 3.1.0 (2026-06-02)」)その版を添える。 */
38
+ type DatedEntry = DatedPoint & Pick<TieEntry, "version">;
39
+
40
+ /** 見出しの #、箇条書きの記号、表の最初の |。 */
41
+ const LINE_MARKER = /^[ \t]*(?:#{1,6}|[-*+]|\d{1,3}[.)]|\|)?[ \t]*/u;
42
+
43
+ const entryOf = (source: string, line: Span, points: readonly DatedPoint[]): DatedEntry | undefined => {
44
+ const date = onlyDateIn(line, points);
45
+ if (date === undefined) return undefined;
46
+ const text = source.slice(line.start, line.end);
47
+ return { ...date, version: leadingVersion(text.slice(LINE_MARKER.exec(text)?.[0].length ?? 0)) };
48
+ };
49
+
50
+ const datedLines = (source: string, run: readonly Span[], points: readonly DatedPoint[]): DatedEntry[] =>
36
51
  run.flatMap((line) => {
37
- const date = onlyDateIn(line, points);
38
- return date === undefined ? [] : [date];
52
+ const entry = entryOf(source, line, points);
53
+ return entry === undefined ? [] : [entry];
39
54
  });
40
55
 
41
56
  /** 見出しの並びは、日付を一つ持つ見出しが続くあいだだけ。日付の無い見出しが混じる並び(問いに更新日を添えた FAQ)は、日付で並べたものではない。 */
42
- const datedStretches = (run: readonly Span[], points: readonly DatedPoint[]): DatedPoint[][] =>
43
- run.reduce<DatedPoint[][]>(
57
+ const datedStretches = (source: string, run: readonly Span[], points: readonly DatedPoint[]): DatedEntry[][] =>
58
+ run.reduce<DatedEntry[][]>(
44
59
  (stretches, heading) => {
45
- const date = onlyDateIn(heading, points);
60
+ const date = entryOf(source, heading, points);
46
61
  if (date === undefined) return [...stretches, []];
47
62
  return [...stretches.slice(0, -1), [...(stretches.at(-1) ?? []), date]];
48
63
  },
@@ -71,10 +86,19 @@ const without = (values: readonly string[], index: number): string[] => values.f
71
86
 
72
87
  /**
73
88
  * 向きに逆らう一歩(at - 1 から at)のうち、並びから外れているほう。取り除いたとき残りが長く揃うほうを指す。
74
- * 前を取っても後ろを取っても同じだけ揃う(隣どうしの入れ替わり)なら、どちらとも決められないので後ろを指す。
89
+ * 前を取っても後ろを取っても同じだけ揃う(隣どうしの入れ替わり)なら、tieBreak が決めたほう、決まらなければ後ろを指す。
75
90
  */
76
- export const outOfPlace = (values: readonly string[], at: number, direction: number): number =>
77
- longestInOrder(without(values, at - 1), direction) > longestInOrder(without(values, at), direction) ? at - 1 : at;
91
+ export const outOfPlace = (
92
+ values: readonly string[],
93
+ at: number,
94
+ direction: number,
95
+ tieBreak: (before: number, after: number) => number | undefined = () => undefined,
96
+ ): number => {
97
+ const withoutBefore = longestInOrder(without(values, at - 1), direction);
98
+ const withoutAfter = longestInOrder(without(values, at), direction);
99
+ if (withoutBefore === withoutAfter) return tieBreak(at - 1, at) ?? at;
100
+ return withoutBefore > withoutAfter ? at - 1 : at;
101
+ };
78
102
 
79
103
  /** 外れた日付に、前の日付を添える。先頭の日付には前が無いので、次の日付を添える。 */
80
104
  const issueAt = (dated: readonly DatedPoint[], at: number): StructureIssue[] => {
@@ -85,18 +109,21 @@ const issueAt = (dated: readonly DatedPoint[], at: number): StructureIssue[] =>
85
109
  };
86
110
 
87
111
  /** 多いほうの向きに逆らう一歩ごとに、並びから外れた日付を指す。 */
88
- const againstMajority = (dated: readonly DatedPoint[]): StructureIssue[] => {
112
+ const againstMajority = (dated: readonly DatedEntry[]): StructureIssue[] => {
89
113
  const values = dated.map((point) => point.value);
90
114
  const signs = values.slice(1).map((value, index) => Math.sign(value.localeCompare(values[index] ?? "")));
91
115
  const majority = majorityOf(signs.filter((sign) => sign > 0).length, signs.filter((sign) => sign < 0).length);
92
116
  if (majority === 0 || !mostlyInOrder(values, majority)) return [];
93
117
  return signs.flatMap((sign, index) => {
94
118
  if (sign !== -majority) return [];
95
- return issueAt(dated, outOfPlace(values, index + 1, majority));
119
+ return issueAt(
120
+ dated,
121
+ outOfPlace(values, index + 1, majority, (before, after) => breakDateTie(dated, before, after, majority)),
122
+ );
96
123
  });
97
124
  };
98
125
 
99
- const breaksIn = (dated: readonly DatedPoint[]): StructureIssue[] => (samePrecision(dated) ? againstMajority(dated) : []);
126
+ const breaksIn = (dated: readonly DatedEntry[]): StructureIssue[] => (samePrecision(dated) ? againstMajority(dated) : []);
100
127
 
101
128
  /** 見出しを箇条書きの中に書けば(「- ## 3.1.0 - 2026-10-02」)、同じ日付が両方の並びに入る。一度だけ言う。 */
102
129
  const oncePerOffset = (issues: readonly StructureIssue[]): StructureIssue[] =>
@@ -104,6 +131,6 @@ const oncePerOffset = (issues: readonly StructureIssue[]): StructureIssue[] =>
104
131
 
105
132
  export const dateOrderBreaks = (source: string, points: readonly DatedPoint[], headings: readonly HeadingSpan[] = []): StructureIssue[] =>
106
133
  oncePerOffset([
107
- ...runsOf(source).flatMap((run) => breaksIn(datedLines(run, points))),
108
- ...siblingHeadingRuns(headings).flatMap((run) => datedStretches(run, points).flatMap(breaksIn)),
134
+ ...runsOf(source).flatMap((run) => breaksIn(datedLines(source, run, points))),
135
+ ...siblingHeadingRuns(headings).flatMap((run) => datedStretches(source, run, points).flatMap(breaksIn)),
109
136
  ]);
@@ -1,6 +1,7 @@
1
1
  import { escapeRegExp } from "../orthography.ts";
2
2
  import type { StructureIssue } from "./issues.ts";
3
3
  import { TABLE_ROW } from "./runs.ts";
4
+ import { deadlineVerdict } from "./term-deadline.ts";
4
5
  import { statedPeriod, type DateMention, type Period, type PeriodWords } from "./stated-period.ts";
5
6
 
6
7
  /**
@@ -8,11 +9,21 @@ import { statedPeriod, type DateMention, type Period, type PeriodWords } from ".
8
9
  * 地の文の日付は、年の無いもの(2月12日(金)の午前は…)だけを比べる。年のある日付は、過去の回や別の年の出来事を挙げることが多い。
9
10
  * 期間の前後に置く予定(前泊、follow-up)、締め切りや予約の日、過去の回を言う語(period-aside)が、その行、文、節の見出しにあれば比べない。
10
11
  * 年の無い期間(12月28日〜1月4日)は年をまたいで読む。
12
+ * 文書の仕事の期間(開講期間:…)を文書の頭か概要の節で書いたものは文書全体の期間で、後ろのどの節でも、締め切りの語(period-deadline)のある項目や文の、
13
+ * 期間の終わりより後の日付を指す(課題の提出が学期の後)。年の無い日付は、期間が一つの年に収まるときだけその年と読む。成績発表や再試験の語(period-after-term)のある日付は比べない。期間の前の締め切り(申込締切)と、旅行期間のように後に締め切りが来てよい期間は比べない。
11
14
  */
12
15
  export type HeadingSpan = { readonly start: number; readonly end: number; readonly depth: number };
13
16
  type Span = { readonly start: number; readonly end: number };
14
17
 
15
- export type OutsideWords = PeriodWords & { readonly asides: readonly string[] };
18
+ export type OutsideWords = PeriodWords & {
19
+ readonly asides: readonly string[];
20
+ /** 文書の仕事がその中で済む期間の語(開講期間、Term)。この期間は締め切りとだけ比べる。 */
21
+ readonly terms: readonly string[];
22
+ readonly deadlines: readonly string[];
23
+ readonly overviews: readonly string[];
24
+ /** 期間の後に来てよい仕事の語(成績発表、再試験)。この語のある締め切りは期間と比べない。 */
25
+ readonly afterTerm: readonly string[];
26
+ };
16
27
 
17
28
  const LIST_ITEM = /^[ \t]{0,12}(?:[-*+]|\d{1,3}[.)])[ \t]/u;
18
29
  const DAY_VALUE = /^(?:\d{4}-)?\d{2}-\d{2}$/u;
@@ -46,7 +57,7 @@ export const mentions = (text: string, words: readonly string[]): boolean => {
46
57
  });
47
58
  };
48
59
 
49
- type Stated = Period & { readonly scopeStart: number; readonly scopeEnd: number };
60
+ type Stated = Period & { readonly line: Span; readonly scopeStart: number; readonly scopeEnd: number; readonly nextPeriod: number };
50
61
 
51
62
  /**
52
63
  * 期間の及ぶ範囲の始まり: 期間の行の後ろ。期間の行が箇条書きの項目なら、その箇条書きの後ろ。
@@ -84,6 +95,8 @@ const statedPeriods = (
84
95
  });
85
96
  return found.map(({ period, line }, index) => ({
86
97
  ...period,
98
+ line,
99
+ nextPeriod: found[index + 1]?.line.start ?? source.length,
87
100
  scopeStart: scopeStart(source, lines, line),
88
101
  scopeEnd: scopeEnd(line, found[index + 1]?.line.start ?? source.length, headings, source.length),
89
102
  }));
@@ -110,6 +123,65 @@ const outsideOne = (date: DateMention, period: Stated, context: Context, asides:
110
123
  return !surroundings(date, line, item, context).some((text) => mentions(text, asides));
111
124
  };
112
125
 
126
+ const boundaryPattern = (word: string): RegExp => {
127
+ const target = escapeRegExp(word.toLowerCase());
128
+ return /[a-z]/u.test(word.toLowerCase()) ? new RegExp(`(?<![a-z])${target}(?![a-z])`, "gu") : new RegExp(target, "gu");
129
+ };
130
+
131
+ /** 締め切りの語を除いた文。「提出期限」の「期限」、「submit by」の「submit」は、期間の外に置く語として読まない。 */
132
+ const withoutWords = (text: string, words: readonly string[]): string =>
133
+ words.toSorted((left, right) => right.length - left.length).reduce((rest, word) => rest.replace(boundaryPattern(word), " "), text.toLowerCase());
134
+
135
+ /** 節の見出しの並び(その行の見出しと、それを囲む浅い見出し)。 */
136
+ const enclosingHeadings = (offset: number, headings: readonly HeadingSpan[]): HeadingSpan[] =>
137
+ headings
138
+ .filter((heading) => heading.start < offset)
139
+ .toReversed()
140
+ .reduce<HeadingSpan[]>((chain, heading) => (heading.depth < (chain.at(-1)?.depth ?? Infinity) ? [...chain, heading] : chain), []);
141
+
142
+ /** 文書の仕事の期間か: 表題(文書の頭の # の見出し)のほかの見出しより前か、概要の節(period-overview-heading)の行。 */
143
+ const isDocumentTerm = (period: Stated, context: Context, overviews: readonly string[]): boolean => {
144
+ const sections = context.headings.filter((heading, index) => heading.start < period.line.start && !(index === 0 && heading.depth === 1));
145
+ if (sections.length === 0) return true;
146
+ return enclosingHeadings(period.line.start, context.headings).some((heading) => mentions(context.source.slice(heading.start, heading.end), overviews));
147
+ };
148
+
149
+ const lateDeadline = (date: DateMention, period: Stated, context: Context, words: OutsideWords): boolean => {
150
+ if (!DAY_VALUE.test(date.value)) return false;
151
+ const line = containing(context.lines, date.offset);
152
+ if (line === undefined) return false;
153
+ const texts = surroundings(date, line, isItem(context.source.slice(line.start, line.end), line, context.headings), context);
154
+ const marks = {
155
+ deadline: mentions(texts[0] ?? "", words.deadlines),
156
+ aside: texts.some((text) => mentions(withoutWords(text, words.deadlines), words.asides)),
157
+ afterTerm: mentions(texts[0] ?? "", words.afterTerm),
158
+ };
159
+ return deadlineVerdict(date.value, period, marks) === "late";
160
+ };
161
+
162
+ const issueOf = (source: string, date: DateMention, period: Stated): StructureIssue => ({
163
+ offset: date.offset,
164
+ values: { date: source.slice(date.offset, date.end), period: period.written },
165
+ });
166
+
167
+ /** 期間の行の後ろ、同じ節の日程の日付で、期間の外のもの。 */
168
+ const outsideInSection = (dates: readonly DateMention[], context: Context, words: OutsideWords): StructureIssue[] =>
169
+ statedPeriods(context.source, context.lines, dates, context.headings, words).flatMap((period) =>
170
+ dates
171
+ .filter((date) => date.offset > period.scopeStart && date.offset < period.scopeEnd && outsideOne(date, period, context, words.asides))
172
+ .map((date) => issueOf(context.source, date, period)),
173
+ );
174
+
175
+ /** 文書の仕事の期間の行の後ろ、次の仕事の期間の行までの、期間の終わりより後の締め切り。 */
176
+ const lateDeadlines = (dates: readonly DateMention[], context: Context, words: OutsideWords): StructureIssue[] =>
177
+ statedPeriods(context.source, context.lines, dates, context.headings, { ...words, labels: words.terms })
178
+ .filter((period) => isDocumentTerm(period, context, words.overviews))
179
+ .flatMap((period) =>
180
+ dates
181
+ .filter((date) => date.offset > period.line.end && date.offset < period.nextPeriod && lateDeadline(date, period, context, words))
182
+ .map((date) => issueOf(context.source, date, period)),
183
+ );
184
+
113
185
  export const datesOutsidePeriod = (
114
186
  source: string,
115
187
  dates: readonly DateMention[],
@@ -119,9 +191,7 @@ export const datesOutsidePeriod = (
119
191
  ): StructureIssue[] => {
120
192
  const lines = linesOf(source);
121
193
  const context: Context = { source, lines, headings, sentences };
122
- return statedPeriods(source, lines, dates, headings, words).flatMap((period) =>
123
- dates
124
- .filter((date) => date.offset > period.scopeStart && date.offset < period.scopeEnd && outsideOne(date, period, context, words.asides))
125
- .map((date) => ({ offset: date.offset, values: { date: source.slice(date.offset, date.end), period: period.written } })),
126
- );
194
+ const inSection = outsideInSection(dates, context, words);
195
+ const reported = new Set(inSection.map((issue) => issue.offset));
196
+ return [...inSection, ...lateDeadlines(dates, context, words).filter((issue) => !reported.has(issue.offset))];
127
197
  };