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,94 @@
1
+ import { linesOf, type Line } from "../structure/lines.ts";
2
+ import { sameMeasure, sameUnit, type Measured } from "./measures.ts";
3
+ import { cellsOf, tablesOf, type Cell } from "./table-facts.ts";
4
+ import { withoutEdgeMarks } from "./trim-marks.ts";
5
+ import { toleranceOf } from "./unit-tolerance.ts";
6
+
7
+ /**
8
+ * 表に量を書いた品物(材料の表の「しょうゆ|大さじ1」)を、本文で違う単位の量と一緒に書いた所(しょうゆ30ml、30 ml of soy sauce)。
9
+ * 表の量は、行の最初の量(人数ごとの列があれば、手順が従う最初の列)。本文の量が表の量より多いときだけ言う。本文の名前は、量のすぐ前(空白一つまで)か、つなぐ語(の、of)と
10
+ * 冠詞(the)を挟んで量の後ろ。名前は語の切れ目で始まり終わる(「濃口しょうゆ」の しょうゆ は切れ目で始まるが、「強力粉」の 力粉 は始まらない)。
11
+ */
12
+ export type ItemConflict = { readonly name: string; readonly measured: Measured; readonly other: Measured };
13
+
14
+ export type ItemWords = { readonly links: readonly string[]; readonly determiners: readonly string[] };
15
+
16
+ type ItemAmount = { readonly name: string; readonly key: string; readonly measured: Measured };
17
+
18
+ const LETTER = /\p{L}/u;
19
+ const SCRIPTS = [/\p{Script=Hiragana}/u, /[\p{Script=Katakana}ー]/u, /\p{Script=Han}/u, /\p{Script=Latin}/u];
20
+ const NAME_WINDOW = 80;
21
+
22
+ const keyOf = (text: string): string => text.normalize("NFKC").toLowerCase();
23
+
24
+ const scriptOf = (char: string): number => SCRIPTS.findIndex((script) => script.test(char));
25
+
26
+ /** 二つの字の間が語の切れ目か。字でない側があるか、字の種類(仮名、漢字、英字)が変わる所。英字どうしは続いている。 */
27
+ const isBoundary = (left: string, right: string): boolean =>
28
+ left === "" || right === "" || !LETTER.test(left) || !LETTER.test(right) || scriptOf(left) !== scriptOf(right);
29
+
30
+ const cellValue = (cell: Cell, source: string, measured: readonly Measured[]): Measured | undefined =>
31
+ measured.find((value) => value.start >= cell.start && value.end <= cell.end && source.slice(value.start, value.end) === withoutEdgeMarks(cell.text));
32
+
33
+ /** 表の行の見出しと、その行の最初の量。同じ名前の行が二つあれば最初の行。 */
34
+ const tableAmounts = (source: string, rows: readonly Line[], measured: readonly Measured[]): ItemAmount[] => {
35
+ const amounts = rows.flatMap((row): ItemAmount[] => {
36
+ const [first, ...rest] = cellsOf(row);
37
+ const name = first === undefined ? "" : withoutEdgeMarks(first.text);
38
+ const value = rest.map((cell) => cellValue(cell, source, measured)).find((found) => found !== undefined);
39
+ if (first === undefined || value === undefined || !LETTER.test(name) || cellValue(first, source, measured) !== undefined) return [];
40
+ return [{ name, key: keyOf(name), measured: value }];
41
+ });
42
+ return amounts.filter((amount, index) => amounts.findIndex((other) => other.key === amount.key) === index);
43
+ };
44
+
45
+ /** 量のすぐ前に名前があるか(しょうゆ大さじ1、soy sauce 30 ml)。 */
46
+ const namedBefore = (source: string, value: Measured, key: string): boolean => {
47
+ const end = source.charAt(value.start - 1) === " " ? value.start - 1 : value.start;
48
+ const head = keyOf(source.slice(Math.max(0, end - NAME_WINDOW), end));
49
+ return head.endsWith(key) && isBoundary(head.charAt(head.length - key.length - 1), key.charAt(0));
50
+ };
51
+
52
+ const skipSpace = (text: string): string => (text.startsWith(" ") ? text.slice(1) : text);
53
+
54
+ /** 頭の語を一つ落とす。英字の語は、後ろに空白が要る(of は offer の頭ではない)。 */
55
+ const dropWord = (text: string, words: readonly string[]): string | undefined => {
56
+ const word = words.map(keyOf).find((candidate) => text.startsWith(candidate) && isBoundary(candidate.slice(-1), text.charAt(candidate.length)));
57
+ return word === undefined ? undefined : skipSpace(text.slice(word.length));
58
+ };
59
+
60
+ /** つなぐ語を挟んで、量の後ろに名前があるか(30mlのしょうゆ、30 ml of the soy sauce)。 */
61
+ const namedAfter = (source: string, value: Measured, key: string, words: ItemWords): boolean => {
62
+ const linked = dropWord(skipSpace(keyOf(source.slice(value.end, value.end + NAME_WINDOW))), words.links);
63
+ if (linked === undefined) return false;
64
+ const rest = dropWord(linked, words.determiners) ?? linked;
65
+ return rest.startsWith(key) && isBoundary(key.slice(-1), rest.charAt(key.length));
66
+ };
67
+
68
+ /** 本文の量が、表の量をどう換算しても超えるか。表より少ない量は、その一部を使う所(牛乳の半分を先に)かもしれない。 */
69
+ const exceeds = (value: Measured, listed: Measured): boolean =>
70
+ value.factors.every((a) => listed.factors.every((b) => (value.amount - value.zero) * a > (listed.amount - listed.zero) * b));
71
+
72
+ const inTable = (value: Measured, rows: readonly Line[]): boolean => rows.some((row) => value.start >= row.start && value.end <= row.start + row.text.length);
73
+
74
+ /** 本文の量のうち、表の同じ品物の量と単位が違い、換算すると合わないもの。 */
75
+ export const itemConflicts = (source: string, measured: readonly Measured[], words: ItemWords): ItemConflict[] => {
76
+ const rows = tablesOf(linesOf(source)).flatMap((table) => [table.header, ...table.rows]);
77
+ const amounts = tableAmounts(source, rows, measured);
78
+ if (amounts.length === 0) return [];
79
+ return measured
80
+ .filter((value) => !inTable(value, rows))
81
+ .flatMap((value): ItemConflict[] => {
82
+ const item = amounts.find(
83
+ ({ key, measured: listed }) => listed.dimension === value.dimension && (namedBefore(source, value, key) || namedAfter(source, value, key, words)),
84
+ );
85
+ if (
86
+ item === undefined ||
87
+ sameUnit(item.measured, value) ||
88
+ sameMeasure(item.measured, value, toleranceOf(value.dimension)) ||
89
+ !exceeds(value, item.measured)
90
+ )
91
+ return [];
92
+ return [{ name: item.name, measured: value, other: item.measured }];
93
+ });
94
+ };
@@ -22,9 +22,12 @@ export type FactWords = {
22
22
  /** 名前の前に置かれる決定の前置き(協議の結果、, it was decided that)。読点を含んでも条件ではないので、外してから名前を読む。 */
23
23
  readonly leads: readonly string[];
24
24
  readonly attributes: readonly AttributePhrase[];
25
+ /** 区切りと値のあいだに置ける目安の語(約、about)。あれば値を目安として読む。無ければ、区切りのすぐ後ろの値だけ。 */
26
+ readonly valueLeads?: readonly string[];
25
27
  };
26
28
 
27
- export type Fact = { readonly label: string; readonly key: string; readonly value: FactValue };
29
+ /** approximate: 値の前に目安の語(約、about)があった。 */
30
+ export type Fact = { readonly label: string; readonly key: string; readonly value: FactValue; readonly approximate?: boolean };
28
31
 
29
32
  const MAX_LABEL_LENGTH = 24;
30
33
  const MAX_LABEL_WORDS = 5;
@@ -57,6 +60,15 @@ const beforeSeparator = (head: string, separator: string): string | undefined =>
57
60
  return rest;
58
61
  };
59
62
 
63
+ /** 頭の後ろの目安の語(「重さは約」の約、"is about" の about)を外したもの。英字の語は、前が語の切れ目のときだけ。 */
64
+ const withoutValueLead = (head: string, leads: readonly string[]): string => {
65
+ const lowered = head.toLowerCase();
66
+ const lead = leads.find(
67
+ (word) => lowered.endsWith(word.toLowerCase()) && !(LATIN_LETTER.test(word.charAt(0)) && LATIN_LETTER.test(head.charAt(head.length - word.length - 1))),
68
+ );
69
+ return lead === undefined ? head : trimEndOf(head.slice(0, head.length - lead.length), EDGE_MARKS);
70
+ };
71
+
60
72
  /** 英字の前置きが語の途中で切れているか(「we agreed that」は「we agreed thatching」の頭ではない)。 */
61
73
  const endsInsideWord = (text: string, length: number): boolean => LATIN_LETTER.test(text.charAt(length - 1)) && LATIN_LETTER.test(text.charAt(length));
62
74
 
@@ -75,11 +87,18 @@ const afterLastBreak = (text: string): string => {
75
87
 
76
88
  const wordsOf = (text: string): string[] => text.split(/\s+/u).filter((word) => word !== "");
77
89
 
90
+ /** 語を空白で分けない言語の、名前の頭の前置き(「本体の幅」の 本体の)。前置きだけの名前は落とさない。 */
91
+ const withoutPrefix = (key: string, determiners: readonly string[]): string => {
92
+ const prefix = determiners.find((word) => !LATIN_WORD.test(word) && key.length > word.length && key.startsWith(word));
93
+ return prefix === undefined ? key : key.slice(prefix.length);
94
+ };
95
+
78
96
  /** 名前を一つの書き方に。全角と半角、大文字と小文字、空白の数を揃え、頭の冠詞を落とす。 */
79
97
  const keyOf = (label: string, words: FactWords): string => {
80
98
  const [first, ...rest] = wordsOf(label.normalize("NFKC").toLowerCase());
81
- const determiners = new Set(words.determiners.map((word) => word.toLowerCase()));
82
- return (first !== undefined && determiners.has(first) ? rest : [first ?? "", ...rest]).join(" ");
99
+ const determiners = words.determiners.map((word) => word.normalize("NFKC").toLowerCase());
100
+ const key = (first !== undefined && determiners.includes(first) ? rest : [first ?? "", ...rest]).join(" ");
101
+ return withoutPrefix(key, determiners);
83
102
  };
84
103
 
85
104
  const containsSeparator = (label: string, words: FactWords): boolean =>
@@ -98,14 +117,17 @@ const isLabel = (label: string, key: string, words: FactWords): boolean =>
98
117
  !words.vague.some((word) => word.toLowerCase() === key);
99
118
 
100
119
  /** 値の後ろが文の切れ目か。行の終わり、表の升の終わり、語彙表の終わりの語。 */
120
+ /** 値の後ろが文の切れ目か。行の終わり、表の升の終わり、語彙表の終わりの語。半角の数のまわりに空白を置く書き方(「14 cm です」)もある。 */
101
121
  const endsAfter = (source: string, value: FactValue, words: FactWords): boolean => {
102
- const after = source.slice(value.end, lineEndOf(source, value.end)).replace(MARKS_AFTER_VALUE, "");
103
- if (after.trim() === "" || after.trimStart().startsWith("|")) return true;
122
+ const after = source.slice(value.end, lineEndOf(source, value.end)).replace(MARKS_AFTER_VALUE, "").trimStart();
123
+ if (after === "" || after.startsWith("|")) return true;
104
124
  return words.valueEnds.some((end) => after.startsWith(end));
105
125
  };
106
126
 
107
127
  const labelledFact = (source: string, value: FactValue, words: FactWords): Fact | undefined => {
108
- const head = trimEndOf(source.slice(lineStartOf(source, value.start), value.start), EDGE_MARKS);
128
+ const written = trimEndOf(source.slice(lineStartOf(source, value.start), value.start), EDGE_MARKS);
129
+ const head = withoutValueLead(written, words.valueLeads ?? []);
130
+ const approximate = head.length < written.length ? { approximate: true } : {};
109
131
  for (const separator of words.separators) {
110
132
  const before = beforeSeparator(head, separator);
111
133
  if (before === undefined) continue;
@@ -113,7 +135,7 @@ const labelledFact = (source: string, value: FactValue, words: FactWords): Fact
113
135
  if (CLAUSE_COMMA.test(clause)) return undefined;
114
136
  const label = withoutEdgeMarks(clause);
115
137
  const key = keyOf(label, words);
116
- return isLabel(label, key, words) ? { label, key, value } : undefined;
138
+ return isLabel(label, key, words) ? { label, key, value, ...approximate } : undefined;
117
139
  }
118
140
  return undefined;
119
141
  };
@@ -0,0 +1,31 @@
1
+ import type { ProseDocument } from "../plugin.ts";
2
+ import type { MeasureUnit } from "./measures.ts";
3
+
4
+ /** 量の種類ごとの語彙表。weight が基準の単位への倍率で、同じ単位を二度書けば倍率が二つ(GB の 10^9 と 2^30)。 */
5
+ const MEASURE_DIMENSIONS = ["unit-length", "unit-mass", "unit-time", "unit-volume", "unit-data", "unit-temperature", "unit-pressure", "unit-area"] as const;
6
+
7
+ const unitKey = (pattern: string, before: boolean): string => `${before ? "<" : ">"}${pattern}`;
8
+
9
+ /** 単位ごとの、零点(unit-zero)と、要る文脈の語(unit-context の group がその単位の語)。 */
10
+ export const measureUnitsOf = (doc: ProseDocument): MeasureUnit[] => {
11
+ const zeros = new Map((doc.lexicons["unit-zero"] ?? []).map((entry) => [entry.pattern, entry.weight ?? 0]));
12
+ const contexts = doc.lexicons["unit-context"] ?? [];
13
+ return MEASURE_DIMENSIONS.flatMap((dimension) => {
14
+ const factors = new Map<string, { pattern: string; before: boolean; weights: number[] }>();
15
+ (doc.lexicons[dimension] ?? []).forEach((entry) => {
16
+ if (entry.weight === undefined) return;
17
+ const before = entry.position === "before";
18
+ const key = unitKey(entry.pattern, before);
19
+ const found = factors.get(key) ?? { pattern: entry.pattern, before, weights: [] };
20
+ factors.set(key, { ...found, weights: [...found.weights, entry.weight] });
21
+ });
22
+ return [...factors.values()].map(({ pattern, before, weights }) => ({
23
+ pattern,
24
+ dimension,
25
+ factors: weights,
26
+ zero: zeros.get(pattern) ?? 0,
27
+ before,
28
+ context: contexts.filter((entry) => entry.group === pattern).map((entry) => entry.pattern),
29
+ }));
30
+ });
31
+ };
@@ -1,54 +1,142 @@
1
1
  import type { FactValue } from "./fact-values.ts";
2
+ import { lineHasContext, standsAsUnitWord } from "./unit-word.ts";
2
3
 
3
4
  /**
4
- * 単位の付いた量(5 km、3000 m、1.5時間、2 GB)。単位は言語パッケージの語彙表から取り、量の種類(長さ、重さ…)と、基準の単位への
5
- * 倍率を持つ。倍率が二つある単位(1 GB は 10^9 か 2^30 バイト)は、どちらで数えても合えば合う。
5
+ * 単位の付いた量(5 km、3000 m、1.5時間、2 GB、180℃、大さじ1)。単位は言語パッケージの語彙表から取り、量の種類(長さ、重さ…)と、基準の単位への
6
+ * 倍率を持つ。倍率が二つある単位(1 GB は 10^9 か 2^30 バイト)は、どちらで数えても合えば合う。零点がずれた単位(°F)は zero を引いてから掛ける。
6
7
  */
7
- export type MeasureUnit = { readonly pattern: string; readonly dimension: string; readonly factors: readonly number[] };
8
+ export type MeasureUnit = {
9
+ readonly pattern: string;
10
+ readonly dimension: string;
11
+ readonly factors: readonly number[];
12
+ /** 基準の単位で 0 のときに、この単位で読む値(°F なら 32)。 */
13
+ readonly zero: number;
14
+ /** 数の前に書く単位(大さじ1)。 */
15
+ readonly before: boolean;
16
+ /** 同じ行にどれかが無ければ単位として読まない語(「度」はオーブンの行だけ温度)。空なら要らない。 */
17
+ readonly context: readonly string[];
18
+ };
8
19
 
9
- export type Measured = FactValue & { readonly dimension: string; readonly factors: readonly number[]; readonly amount: number };
20
+ export type Measured = FactValue & {
21
+ readonly dimension: string;
22
+ readonly factors: readonly number[];
23
+ readonly zero: number;
24
+ readonly amount: number;
25
+ /** 書いた小数の桁数(1.20 なら 2)。amount は数なので末尾の 0 を持たない。 */
26
+ readonly decimals: number;
27
+ };
10
28
 
11
- /** 前に英字や数が続く数(v2、A4、1.2.3 の 2)は量ではない。日本語は数の前に空白を置かないので、仮名や漢字の後ろはよい。 */
12
- const NUMBER = /(?<![\p{Script=Latin}\p{N}.,])[0-90-9]+(?:[,,][0-90-9]{3})*(?:[..][0-90-9]+)?/gu;
29
+ /** 換算して合うとみなす差。relative は大きいほうの値に対する割合、absolute は基準の単位での差。どちらかに収まれば合う。 */
30
+ export type Tolerance = { readonly relative: number; readonly absolute: number };
13
31
 
14
32
  /**
15
- * 数のすぐ後ろ(空白一つまで)の単位。長い単位から試す(「5分間」を 分 で切らない、min を m にしない)。
33
+ * 前に英字や数が続く数(v2、A4、1.2.3 の 2)と、分数の分母(1/2 の 2)は量ではない。日本語は数の前に空白を置かないので、仮名や漢字の後ろはよい。
34
+ * 字や数のすぐ後ろでない負の符号は数に含める(-20 °C)。20-25°C の - は範囲の印。
35
+ */
36
+ const NUMBER = /(?<![\p{Script=Latin}\p{N}.,])(?<![0-90-9][//])[0-90-9]+(?:[,,][0-90-9]{3})*(?:[..][0-90-9]+)?/gu;
37
+ const MINUS_SIGNS = new Set(["-", "−", "-"]);
38
+ const BEFORE_SIGN = /[\p{L}\p{N}.,]/u;
39
+
40
+ /** 数の頭の負の符号の位置。符号が無ければ数の頭。 */
41
+ const signedStart = (source: string, start: number): number =>
42
+ MINUS_SIGNS.has(source.charAt(start - 1)) && !BEFORE_SIGN.test(source.charAt(start - 2)) ? start - 1 : start;
43
+
44
+ /** 数のすぐ後ろに分数が続く(大さじ1と1/2、1 1/2 cups、1½)。数だけを読むと量を取り違える。 */
45
+ const FRACTION_AFTER = /^.?[0-90-9]*[//][0-90-9]|^.?[½⅓⅔¼¾⅛]/u;
46
+
47
+ const MAX_UNIT_LENGTH = 20;
48
+
49
+ const lineAt = (source: string, offset: number): string => {
50
+ const end = source.indexOf("\n", offset);
51
+ return source.slice(source.lastIndexOf("\n", offset - 1) + 1, end === -1 ? source.length : end);
52
+ };
53
+
54
+ const inContext = (unit: MeasureUnit, source: string, offset: number): boolean =>
55
+ unit.context.length === 0 || lineHasContext(lineAt(source, offset), unit.context);
56
+
57
+ /** 数と単位のあいだに置ける字。空白一つか、英語の複合語のハイフン(13.3-inch display)。 */
58
+ const GAPS = new Set([" ", "-"]);
59
+
60
+ type Found = { readonly unit: MeasureUnit; readonly start: number; readonly end: number };
61
+
62
+ /**
63
+ * 数のすぐ後ろ(空白かハイフン一つまで)の単位。長い単位から試す(「5分間」を 分 で切らない、min を m にしない)。
16
64
  * 単位の後ろに語が続く(5 miners)ものは、名前付きの値の終わり(fact-value-end)で落ちるので、ここでは見ない。
17
65
  */
18
- const unitAfter = (source: string, end: number, units: readonly MeasureUnit[]): { unit: MeasureUnit; end: number } | undefined => {
19
- const gap = source.charAt(end) === " " ? 1 : 0;
20
- const rest = source.slice(end + gap, end + gap + 16);
21
- const unit = units.find((candidate) => rest.startsWith(candidate.pattern));
22
- return unit === undefined ? undefined : { unit, end: end + gap + unit.pattern.length };
66
+ const unitAfter = (source: string, start: number, end: number, units: readonly MeasureUnit[]): Found | undefined => {
67
+ const gap = GAPS.has(source.charAt(end)) ? 1 : 0;
68
+ const rest = source.slice(end + gap, end + gap + MAX_UNIT_LENGTH);
69
+ const unit = units.find(
70
+ (candidate) =>
71
+ !candidate.before &&
72
+ rest.startsWith(candidate.pattern) &&
73
+ standsAsUnitWord(candidate.pattern, candidate.context.length > 0, source.slice(end + gap + candidate.pattern.length)) &&
74
+ inContext(candidate, source, end),
75
+ );
76
+ return unit === undefined ? undefined : { unit, start, end: end + gap + unit.pattern.length };
77
+ };
78
+
79
+ /** 数のすぐ前(空白一つまで)の単位(大さじ1)。 */
80
+ const unitBefore = (source: string, start: number, end: number, units: readonly MeasureUnit[]): Found | undefined => {
81
+ const gap = source.charAt(start - 1) === " " ? 1 : 0;
82
+ const head = source.slice(Math.max(0, start - gap - MAX_UNIT_LENGTH), start - gap);
83
+ const unit = units.find((candidate) => candidate.before && head.endsWith(candidate.pattern) && inContext(candidate, source, start));
84
+ return unit === undefined ? undefined : { unit, start: start - gap - unit.pattern.length, end };
23
85
  };
24
86
 
25
87
  /** 文書の中の、単位の付いた量。 */
26
88
  export const measuredValues = (source: string, units: readonly MeasureUnit[]): Measured[] => {
27
89
  const longestFirst = units.toSorted((left, right) => right.pattern.length - left.pattern.length);
28
90
  return [...source.matchAll(NUMBER)].flatMap((match): Measured[] => {
29
- const found = unitAfter(source, match.index + match[0].length, longestFirst);
91
+ const end = match.index + match[0].length;
92
+ if (FRACTION_AFTER.test(source.slice(end, end + MAX_UNIT_LENGTH))) return [];
93
+ const start = signedStart(source, match.index);
94
+ const found = unitAfter(source, start, end, longestFirst) ?? unitBefore(source, start, end, longestFirst);
30
95
  if (found === undefined) return [];
31
- const amount = Number(match[0].normalize("NFKC").replace(/,/gu, ""));
96
+ const written = match[0].normalize("NFKC").replace(/,/gu, "");
97
+ const magnitude = Number(written);
98
+ const amount = start < match.index ? -magnitude : magnitude;
99
+ const { unit } = found;
32
100
  return [
33
101
  {
34
- start: match.index,
102
+ start: found.start,
35
103
  end: found.end,
36
104
  kind: "quantity",
37
105
  key: String(amount),
38
- unit: found.unit.pattern,
39
- dimension: found.unit.dimension,
40
- factors: found.unit.factors,
106
+ unit: unit.pattern,
107
+ dimension: unit.dimension,
108
+ factors: unit.factors,
109
+ zero: unit.zero,
41
110
  amount,
111
+ decimals: written.split(".")[1]?.length ?? 0,
42
112
  },
43
113
  ];
44
114
  });
45
115
  };
46
116
 
47
- /** 二つの量が同じ量か。倍率のどの組み合わせかで、基準の単位に直した値の差が大きいほうの tolerance 以内なら同じ。 */
48
- export const sameMeasure = (left: Measured, right: Measured, tolerance: number): boolean =>
49
- left.factors.some((a) =>
50
- right.factors.some((b) => {
51
- const [x, y] = [left.amount * a, right.amount * b];
52
- return Math.abs(x - y) <= Math.max(Math.abs(x), Math.abs(y)) * tolerance;
53
- }),
117
+ /** 二つの量の単位が、書き方だけ違う同じ単位か(mL と ml、tablespoon と tablespoons)。 */
118
+ export const sameUnit = (left: Measured, right: Measured): boolean =>
119
+ left.zero === right.zero && left.factors.length === right.factors.length && left.factors.every((factor, index) => factor === right.factors[index]);
120
+
121
+ const agrees = (x: number, y: number, tolerance: Tolerance): boolean => {
122
+ const difference = Math.abs(x - y);
123
+ return difference <= tolerance.absolute || difference <= Math.max(Math.abs(x), Math.abs(y)) * tolerance.relative;
124
+ };
125
+
126
+ /** 零点のずれた単位で、零点より小さい量(1 °F)。温度の読みより、差(0.5 ℃ の上昇は 0.9 °F)のことが多い。 */
127
+ const couldBeDifference = (value: Measured): boolean => value.zero !== 0 && Math.abs(value.amount) < Math.abs(value.zero);
128
+
129
+ /**
130
+ * 二つの量が同じ量か。倍率のどの組み合わせかで、基準の単位に直した値の差が tolerance に収まれば同じ。零点より小さい °F の量は、差として
131
+ * 零点を引かずに直しても合えば合う(0.5°C (1°F))。180 °F は差としては読まないので、100 °C (180 °F) は合わない。
132
+ */
133
+ export const sameMeasure = (left: Measured, right: Measured, tolerance: Tolerance): boolean => {
134
+ const difference = couldBeDifference(left) || couldBeDifference(right);
135
+ return left.factors.some((a) =>
136
+ right.factors.some(
137
+ (b) =>
138
+ agrees((left.amount - left.zero) * a, (right.amount - right.zero) * b, tolerance) ||
139
+ (difference && agrees(left.amount * a, right.amount * b, tolerance)),
140
+ ),
54
141
  );
142
+ };
@@ -0,0 +1,216 @@
1
+ import type { Span, Token } from "../plugin.ts";
2
+ import type { DurationUnit } from "../derived/date-arithmetic.ts";
3
+
4
+ /**
5
+ * 保存期間。文が、保存の語(保存、keep)か、期間の後に消す語(3年間を経過した…を削除、delete … 3 years after)と、期間を
6
+ * 一つだけ持つとき、その期間を、語の前後の名詞句(個人情報、personal information)の保存期間と読む。文書のどこでも、同じ名詞句に
7
+ * 違う長さが二通り書かれていれば言う。名詞句が違えば別のもの(ログは90日、アカウントの情報は1年)。
8
+ * 上限や下限や目安の長さ(最長、以上、約、up to、at least)は範囲なので比べない。年と月、週と日だけを換算して比べる。
9
+ */
10
+ export type RetentionLength = Span & { readonly amount: number; readonly unit: DurationUnit };
11
+
12
+ /** position: 対象の名詞句が語の前か後ろか。後ろなら、後ろに無いとき前を読む(is retained の受け身)。 */
13
+ export type RetentionVerb = { readonly pattern: string; readonly group: string; readonly position: "before" | "after" };
14
+
15
+ /** その組の語が期間を言うのに、期間の前か後ろに要る語(keep … for、delete … after、経過)。組に語が無ければ要らない。 */
16
+ export type LengthMark = { readonly pattern: string; readonly group: string; readonly position: "before" | "after" };
17
+
18
+ export type WordAt = { readonly pattern: string; readonly position: "before" | "after" };
19
+
20
+ export type RetentionWords = {
21
+ readonly verbs: readonly RetentionVerb[];
22
+ readonly marks: readonly LengthMark[];
23
+ /** 期間のすぐ後ろにあれば、期間が名詞を修飾している(過去3年間の記録)。 */
24
+ readonly modifiers: readonly string[];
25
+ /** 範囲や目安の印(最長、以上、up to)。 */
26
+ readonly bounds: readonly WordAt[];
27
+ /** 名詞句の中で名詞をつなぐ語(お問い合わせの記録 の の)。 */
28
+ readonly joiners: readonly string[];
29
+ /** 名詞句と、前にある保存の語のあいだの語(を、は)。無い言語は名詞句がすぐ前。 */
30
+ readonly objectMarks: readonly string[];
31
+ };
32
+
33
+ export type RetentionSentence = Span & { readonly tokens: readonly Token[] };
34
+
35
+ export type RetentionConflict = { readonly object: string; readonly value: RetentionLength; readonly other: RetentionLength };
36
+
37
+ type Statement = { readonly object: string; readonly length: RetentionLength; readonly base: string; readonly count: number };
38
+
39
+ const NOUN_PHRASE = new Set(["NOUN", "PROPN", "ADJ"]);
40
+ const SKIPPED_BEFORE = new Set(["PUNCT", "AUX", "ADV", "VERB", "PART"]);
41
+ const DROPPED = new Set(["DET", "PRON"]);
42
+
43
+ const MONTHS_PER_YEAR = 12;
44
+ const DAYS_PER_WEEK = 7;
45
+
46
+ const scaled: Readonly<Record<DurationUnit, readonly [string, number]>> = {
47
+ year: ["month", MONTHS_PER_YEAR],
48
+ month: ["month", 1],
49
+ week: ["day", DAYS_PER_WEEK],
50
+ day: ["day", 1],
51
+ };
52
+
53
+ const folded = (text: string): string => text.normalize("NFKC").toLowerCase();
54
+
55
+ const LATIN = /[a-z]/u;
56
+
57
+ /** 英字の語は語として(for は form の頭ではない)。 */
58
+ const isWordAt = (text: string, at: number, word: string): boolean =>
59
+ text.startsWith(word, at) &&
60
+ !(LATIN.test(word.charAt(0)) && LATIN.test(text.charAt(at - 1))) &&
61
+ !(LATIN.test(word.slice(-1)) && LATIN.test(text.charAt(at + word.length)));
62
+
63
+ const NEAR = 24;
64
+
65
+ const before = (source: string, span: Span): string => folded(source.slice(Math.max(0, span.start - NEAR), span.start)).trimEnd();
66
+ const after = (source: string, span: Span): string => folded(source.slice(span.end, span.end + NEAR)).trimStart();
67
+
68
+ const endsWithWord = (text: string, word: string): boolean => {
69
+ const pattern = folded(word);
70
+ return isWordAt(text, text.length - pattern.length, pattern);
71
+ };
72
+
73
+ const startsWithWord = (text: string, word: string): boolean => isWordAt(text, 0, folded(word));
74
+
75
+ const besideLength = (source: string, length: Span, word: WordAt): boolean =>
76
+ word.position === "before" ? endsWithWord(before(source, length), word.pattern) : startsWithWord(after(source, length), word.pattern);
77
+
78
+ const CLAUSE_COMMA = /^[,、,]\s*/u;
79
+
80
+ /** 後ろの印は読点の後でもよい(90 days, or longer)。 */
81
+ const isBounded = (source: string, length: Span, words: RetentionWords): boolean =>
82
+ words.bounds.some(
83
+ (word) =>
84
+ besideLength(source, length, word) || (word.position === "after" && startsWithWord(after(source, length).replace(CLAUSE_COMMA, ""), word.pattern)),
85
+ );
86
+
87
+ /** 期間の後ろの印(3年後に、を経過)の終わり。印の語は名詞句ではないので、名詞句を探すとき期間と一緒に飛ばす。 */
88
+ const endWithMark = (source: string, length: Span, group: string, words: RetentionWords): number => {
89
+ const gap = /^\s*/u.exec(source.slice(length.end, length.end + NEAR))?.[0].length ?? 0;
90
+ const written = words.marks
91
+ .filter((mark) => mark.group === group && mark.position === "after" && besideLength(source, length, mark))
92
+ .reduce((longest, mark) => Math.max(longest, mark.pattern.length), 0);
93
+ return written === 0 ? length.end : length.end + gap + written;
94
+ };
95
+
96
+ const tokenWord = (token: Token): string => folded(token.lemma ?? token.surface);
97
+
98
+ const isVerbToken = (token: Token, verb: RetentionVerb): boolean => tokenWord(token) === folded(verb.pattern) || folded(token.surface) === folded(verb.pattern);
99
+
100
+ /** 組の語に印が要らないか、要る印が期間の前後にある。 */
101
+ const marked = (source: string, length: Span, group: string, words: RetentionWords): boolean => {
102
+ const marks = words.marks.filter((mark) => mark.group === group);
103
+ return marks.length === 0 || marks.some((mark) => besideLength(source, length, mark));
104
+ };
105
+
106
+ type VerbAt = { readonly verb: RetentionVerb; readonly index: number; readonly token: Token };
107
+
108
+ const verbsIn = (tokens: readonly Token[], verbs: readonly RetentionVerb[]): VerbAt[] =>
109
+ tokens.flatMap((token, index) => verbs.filter((verb) => isVerbToken(token, verb)).map((verb) => ({ verb, index, token })));
110
+
111
+ const inside = (outer: Span, inner: Span): boolean => outer.start <= inner.start && inner.end <= outer.end;
112
+ const overlaps = (left: Span, right: Span): boolean => left.start < right.end && right.start < left.end;
113
+
114
+ const isPhraseToken = (token: Token | undefined, length: Span): boolean => token !== undefined && NOUN_PHRASE.has(token.pos) && !overlaps(token.span, length);
115
+
116
+ const isJoiner = (token: Token | undefined, words: RetentionWords): boolean =>
117
+ token !== undefined && words.joiners.some((joiner) => folded(joiner) === folded(token.surface));
118
+
119
+ /** index から前へ、名詞句の始まり。つなぐ語の前の名詞も句に入れる(お問い合わせ の 記録)。 */
120
+ const phraseStart = (tokens: readonly Token[], index: number, length: Span, words: RetentionWords): number => {
121
+ let start = index;
122
+ while (start > 0) {
123
+ const previous = tokens[start - 1];
124
+ if (isPhraseToken(previous, length)) start -= 1;
125
+ else if (isJoiner(previous, words) && isPhraseToken(tokens[start - 2], length)) start -= 2;
126
+ else break;
127
+ }
128
+ return start;
129
+ };
130
+
131
+ /** index から後ろへ、名詞句の終わり(含まない)。 */
132
+ const phraseEnd = (tokens: readonly Token[], index: number, length: Span, words: RetentionWords): number => {
133
+ let end = index;
134
+ while (end < tokens.length) {
135
+ const next = tokens[end];
136
+ if (isPhraseToken(next, length)) end += 1;
137
+ else if (isJoiner(next, words) && isPhraseToken(tokens[end + 1], length)) end += 2;
138
+ else break;
139
+ }
140
+ return end;
141
+ };
142
+
143
+ const phraseKey = (tokens: readonly Token[]): string => tokens.map(tokenWord).join(tokens.some((token) => LATIN.test(folded(token.surface))) ? " " : "");
144
+
145
+ /** 語の後ろの名詞句(keep your personal information)。冠詞や代名詞は飛ばす。 */
146
+ const objectAfter = (tokens: readonly Token[], index: number, length: Span, words: RetentionWords): string => {
147
+ let start = index + 1;
148
+ while (DROPPED.has(tokens[start]?.pos ?? "")) start += 1;
149
+ return phraseKey(tokens.slice(start, phraseEnd(tokens, start, length, words)));
150
+ };
151
+
152
+ const isObjectMark = (token: Token, words: RetentionWords): boolean => words.objectMarks.some((mark) => folded(mark) === folded(token.surface));
153
+
154
+ /** 語の前の名詞句(個人情報を…保存、Account data is retained)。期間と句読点と助動詞は飛ばし、印のある言語は印の前。 */
155
+ const objectBefore = (tokens: readonly Token[], index: number, length: Span, words: RetentionWords): string => {
156
+ let end = index;
157
+ const skipped = (token: Token | undefined): boolean => token !== undefined && (overlaps(token.span, length) || SKIPPED_BEFORE.has(token.pos));
158
+ while (end > 0 && skipped(tokens[end - 1])) end -= 1;
159
+ if (words.objectMarks.length > 0) {
160
+ const mark = tokens[end - 1];
161
+ if (mark === undefined || !isObjectMark(mark, words)) return "";
162
+ end -= 1;
163
+ }
164
+ if (!isPhraseToken(tokens[end - 1], length)) return "";
165
+ return phraseKey(tokens.slice(phraseStart(tokens, end - 1, length, words), end));
166
+ };
167
+
168
+ const objectOf = (tokens: readonly Token[], at: VerbAt, length: Span, words: RetentionWords): string => {
169
+ const following = at.verb.position === "after" ? objectAfter(tokens, at.index, length, words) : "";
170
+ return following === "" ? objectBefore(tokens, at.index, length, words) : following;
171
+ };
172
+
173
+ const distance = (token: Token, length: Span): number => Math.abs(token.span.start - length.start);
174
+
175
+ /** 文の保存期間の言い方。期間がちょうど一つ、印の揃った組がちょうど一つのときだけ。 */
176
+ const statementOf = (source: string, sentence: RetentionSentence, lengths: readonly RetentionLength[], words: RetentionWords): Statement[] => {
177
+ const own = lengths.filter((length) => inside(sentence, length));
178
+ const [length] = own;
179
+ if (own.length !== 1 || length === undefined || isBounded(source, length, words)) return [];
180
+ if (words.modifiers.some((word) => startsWithWord(after(source, length), word))) return [];
181
+ const verbs = verbsIn(sentence.tokens, words.verbs).filter((at) => marked(source, length, at.verb.group, words));
182
+ if (new Set(verbs.map((at) => at.verb.group)).size !== 1) return [];
183
+ const [nearest] = verbs.toSorted((left, right) => distance(left.token, length) - distance(right.token, length));
184
+ if (nearest === undefined) return [];
185
+ const object = objectOf(sentence.tokens, nearest, { start: length.start, end: endWithMark(source, length, nearest.verb.group, words) }, words);
186
+ const [base, factor] = scaled[length.unit];
187
+ return object === "" ? [] : [{ object, length, base, count: length.amount * factor }];
188
+ };
189
+
190
+ const conflictsOf = (statements: readonly Statement[]): RetentionConflict[] => {
191
+ const [first] = statements;
192
+ if (first === undefined) return [];
193
+ const counts = new Set(statements.map((statement) => statement.count));
194
+ if (counts.size !== 2) return [];
195
+ return statements
196
+ .filter((statement) => statement.count !== first.count)
197
+ .map((statement) => ({ object: statement.object, value: statement.length, other: first.length }));
198
+ };
199
+
200
+ const groupedBy = (statements: readonly Statement[]): Statement[][] => [
201
+ ...statements
202
+ .reduce((groups, statement) => {
203
+ const key = `${statement.object}\u0000${statement.base}`;
204
+ groups.set(key, [...(groups.get(key) ?? []), statement]);
205
+ return groups;
206
+ }, new Map<string, Statement[]>())
207
+ .values(),
208
+ ];
209
+
210
+ /** 同じ名詞句の保存期間が二通り。三通り以上は一覧として言わない。lengths は期間の単位を持つ数量だけ。 */
211
+ export const retentionConflicts = (
212
+ source: string,
213
+ sentences: readonly RetentionSentence[],
214
+ lengths: readonly RetentionLength[],
215
+ words: RetentionWords,
216
+ ): RetentionConflict[] => groupedBy(sentences.flatMap((sentence) => statementOf(source, sentence, lengths, words))).flatMap(conflictsOf);
@@ -69,3 +69,6 @@ export const tableFacts = (source: string, values: readonly FactValue[]): Fact[]
69
69
  const headings = cellsOf(table.header).map((cell) => plain(cell.text));
70
70
  return table.rows.flatMap((row) => rowFacts(row, headings, values, source));
71
71
  });
72
+
73
+ /** 文書の表すべての、本体の行の升(見出しの行を除く)。text は書いたまま。 */
74
+ export const tableBodyCells = (source: string): Cell[] => tablesOf(linesOf(source)).flatMap((table) => table.rows.flatMap(cellsOf));