chaffjs 0.35.0 → 0.37.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 (823) hide show
  1. package/README.ja.md +12 -0
  2. package/README.md +15 -0
  3. package/dist/announced-count.d.ts +2 -0
  4. package/dist/announced-count.d.ts.map +1 -1
  5. package/dist/announced-count.js +29 -7
  6. package/dist/announced-count.js.map +1 -1
  7. package/dist/chronology-rows.d.ts +9 -0
  8. package/dist/chronology-rows.d.ts.map +1 -0
  9. package/dist/chronology-rows.js +79 -0
  10. package/dist/chronology-rows.js.map +1 -0
  11. package/dist/company-name-run.d.ts +8 -0
  12. package/dist/company-name-run.d.ts.map +1 -0
  13. package/dist/company-name-run.js +30 -0
  14. package/dist/company-name-run.js.map +1 -0
  15. package/dist/compound-head.d.ts +7 -0
  16. package/dist/compound-head.d.ts.map +1 -0
  17. package/dist/compound-head.js +19 -0
  18. package/dist/compound-head.js.map +1 -0
  19. package/dist/date-format.d.ts +8 -3
  20. package/dist/date-format.d.ts.map +1 -1
  21. package/dist/date-format.js +36 -3
  22. package/dist/date-format.js.map +1 -1
  23. package/dist/derived/count-per-period.d.ts +23 -0
  24. package/dist/derived/count-per-period.d.ts.map +1 -0
  25. package/dist/derived/count-per-period.js +14 -0
  26. package/dist/derived/count-per-period.js.map +1 -0
  27. package/dist/detectors/acronym-context.d.ts +4 -0
  28. package/dist/detectors/acronym-context.d.ts.map +1 -1
  29. package/dist/detectors/acronym-context.js +29 -1
  30. package/dist/detectors/acronym-context.js.map +1 -1
  31. package/dist/detectors/acronym-expansion.d.ts +5 -1
  32. package/dist/detectors/acronym-expansion.d.ts.map +1 -1
  33. package/dist/detectors/acronym-expansion.js +42 -3
  34. package/dist/detectors/acronym-expansion.js.map +1 -1
  35. package/dist/detectors/acronym-known.d.ts +19 -0
  36. package/dist/detectors/acronym-known.d.ts.map +1 -0
  37. package/dist/detectors/acronym-known.js +32 -0
  38. package/dist/detectors/acronym-known.js.map +1 -0
  39. package/dist/detectors/acronym-link.d.ts +19 -0
  40. package/dist/detectors/acronym-link.d.ts.map +1 -0
  41. package/dist/detectors/acronym-link.js +65 -0
  42. package/dist/detectors/acronym-link.js.map +1 -0
  43. package/dist/detectors/acronym-mention.d.ts +5 -0
  44. package/dist/detectors/acronym-mention.d.ts.map +1 -0
  45. package/dist/detectors/acronym-mention.js +34 -0
  46. package/dist/detectors/acronym-mention.js.map +1 -0
  47. package/dist/detectors/acronym-name.d.ts +8 -1
  48. package/dist/detectors/acronym-name.d.ts.map +1 -1
  49. package/dist/detectors/acronym-name.js +25 -6
  50. package/dist/detectors/acronym-name.js.map +1 -1
  51. package/dist/detectors/addressee-edge.d.ts +13 -0
  52. package/dist/detectors/addressee-edge.d.ts.map +1 -0
  53. package/dist/detectors/addressee-edge.js +13 -0
  54. package/dist/detectors/addressee-edge.js.map +1 -0
  55. package/dist/detectors/addressee-title-edge.d.ts +21 -0
  56. package/dist/detectors/addressee-title-edge.d.ts.map +1 -0
  57. package/dist/detectors/addressee-title-edge.js +22 -0
  58. package/dist/detectors/addressee-title-edge.js.map +1 -0
  59. package/dist/detectors/announced-count.d.ts.map +1 -1
  60. package/dist/detectors/announced-count.js +1 -0
  61. package/dist/detectors/announced-count.js.map +1 -1
  62. package/dist/detectors/bare-comparative.d.ts +4 -0
  63. package/dist/detectors/bare-comparative.d.ts.map +1 -1
  64. package/dist/detectors/bare-comparative.js +28 -3
  65. package/dist/detectors/bare-comparative.js.map +1 -1
  66. package/dist/detectors/blank-structure.d.ts +7 -1
  67. package/dist/detectors/blank-structure.d.ts.map +1 -1
  68. package/dist/detectors/blank-structure.js +13 -8
  69. package/dist/detectors/blank-structure.js.map +1 -1
  70. package/dist/detectors/bracket-specified.d.ts +6 -0
  71. package/dist/detectors/bracket-specified.d.ts.map +1 -0
  72. package/dist/detectors/bracket-specified.js +23 -0
  73. package/dist/detectors/bracket-specified.js.map +1 -0
  74. package/dist/detectors/broken-link.d.ts +6 -0
  75. package/dist/detectors/broken-link.d.ts.map +1 -1
  76. package/dist/detectors/broken-link.js +23 -2
  77. package/dist/detectors/broken-link.js.map +1 -1
  78. package/dist/detectors/capitalised-term.d.ts +4 -0
  79. package/dist/detectors/capitalised-term.d.ts.map +1 -1
  80. package/dist/detectors/capitalised-term.js +18 -1
  81. package/dist/detectors/capitalised-term.js.map +1 -1
  82. package/dist/detectors/caps-caption.d.ts +17 -6
  83. package/dist/detectors/caps-caption.d.ts.map +1 -1
  84. package/dist/detectors/caps-caption.js +65 -0
  85. package/dist/detectors/caps-caption.js.map +1 -1
  86. package/dist/detectors/caps-phrase.d.ts +6 -0
  87. package/dist/detectors/caps-phrase.d.ts.map +1 -0
  88. package/dist/detectors/caps-phrase.js +16 -0
  89. package/dist/detectors/caps-phrase.js.map +1 -0
  90. package/dist/detectors/char-shape.d.ts +1 -0
  91. package/dist/detectors/char-shape.d.ts.map +1 -1
  92. package/dist/detectors/char-shape.js +56 -20
  93. package/dist/detectors/char-shape.js.map +1 -1
  94. package/dist/detectors/citation-sentence.d.ts +8 -0
  95. package/dist/detectors/citation-sentence.d.ts.map +1 -0
  96. package/dist/detectors/citation-sentence.js +40 -0
  97. package/dist/detectors/citation-sentence.js.map +1 -0
  98. package/dist/detectors/cited-title.d.ts +3 -2
  99. package/dist/detectors/cited-title.d.ts.map +1 -1
  100. package/dist/detectors/cited-title.js +14 -3
  101. package/dist/detectors/cited-title.js.map +1 -1
  102. package/dist/detectors/contraction-mention.d.ts +3 -0
  103. package/dist/detectors/contraction-mention.d.ts.map +1 -0
  104. package/dist/detectors/contraction-mention.js +22 -0
  105. package/dist/detectors/contraction-mention.js.map +1 -0
  106. package/dist/detectors/counter-edge.d.ts +2 -1
  107. package/dist/detectors/counter-edge.d.ts.map +1 -1
  108. package/dist/detectors/counter-edge.js +17 -2
  109. package/dist/detectors/counter-edge.js.map +1 -1
  110. package/dist/detectors/dash-break.d.ts +7 -0
  111. package/dist/detectors/dash-break.d.ts.map +1 -0
  112. package/dist/detectors/dash-break.js +30 -0
  113. package/dist/detectors/dash-break.js.map +1 -0
  114. package/dist/detectors/date-any-year.d.ts +7 -3
  115. package/dist/detectors/date-any-year.d.ts.map +1 -1
  116. package/dist/detectors/date-any-year.js +30 -8
  117. package/dist/detectors/date-any-year.js.map +1 -1
  118. package/dist/detectors/date-format.d.ts.map +1 -1
  119. package/dist/detectors/date-format.js +2 -1
  120. package/dist/detectors/date-format.js.map +1 -1
  121. package/dist/detectors/date-year.d.ts +9 -3
  122. package/dist/detectors/date-year.d.ts.map +1 -1
  123. package/dist/detectors/date-year.js +45 -9
  124. package/dist/detectors/date-year.js.map +1 -1
  125. package/dist/detectors/deadline-unit.d.ts +20 -0
  126. package/dist/detectors/deadline-unit.d.ts.map +1 -0
  127. package/dist/detectors/deadline-unit.js +19 -0
  128. package/dist/detectors/deadline-unit.js.map +1 -0
  129. package/dist/detectors/defined-term-form.d.ts.map +1 -1
  130. package/dist/detectors/defined-term-form.js +33 -7
  131. package/dist/detectors/defined-term-form.js.map +1 -1
  132. package/dist/detectors/definition-use.d.ts.map +1 -1
  133. package/dist/detectors/definition-use.js +14 -6
  134. package/dist/detectors/definition-use.js.map +1 -1
  135. package/dist/detectors/derived-numbers.d.ts.map +1 -1
  136. package/dist/detectors/derived-numbers.js +17 -4
  137. package/dist/detectors/derived-numbers.js.map +1 -1
  138. package/dist/detectors/document-shape.d.ts +5 -0
  139. package/dist/detectors/document-shape.d.ts.map +1 -1
  140. package/dist/detectors/document-shape.js +15 -1
  141. package/dist/detectors/document-shape.js.map +1 -1
  142. package/dist/detectors/doubled-across-aside.d.ts +9 -0
  143. package/dist/detectors/doubled-across-aside.d.ts.map +1 -0
  144. package/dist/detectors/doubled-across-aside.js +27 -0
  145. package/dist/detectors/doubled-across-aside.js.map +1 -0
  146. package/dist/detectors/doubled-punctuation.d.ts +3 -3
  147. package/dist/detectors/doubled-punctuation.d.ts.map +1 -1
  148. package/dist/detectors/doubled-punctuation.js +23 -4
  149. package/dist/detectors/doubled-punctuation.js.map +1 -1
  150. package/dist/detectors/doubled-word.d.ts.map +1 -1
  151. package/dist/detectors/doubled-word.js +2 -1
  152. package/dist/detectors/doubled-word.js.map +1 -1
  153. package/dist/detectors/duplicate-heading.d.ts +1 -0
  154. package/dist/detectors/duplicate-heading.d.ts.map +1 -1
  155. package/dist/detectors/duplicate-heading.js +25 -3
  156. package/dist/detectors/duplicate-heading.js.map +1 -1
  157. package/dist/detectors/ellipsis.d.ts.map +1 -1
  158. package/dist/detectors/ellipsis.js +13 -1
  159. package/dist/detectors/ellipsis.js.map +1 -1
  160. package/dist/detectors/email-letter.d.ts +40 -3
  161. package/dist/detectors/email-letter.d.ts.map +1 -1
  162. package/dist/detectors/email-letter.js +110 -17
  163. package/dist/detectors/email-letter.js.map +1 -1
  164. package/dist/detectors/field-label.d.ts +7 -0
  165. package/dist/detectors/field-label.d.ts.map +1 -0
  166. package/dist/detectors/field-label.js +23 -0
  167. package/dist/detectors/field-label.js.map +1 -0
  168. package/dist/detectors/footnote-mismatch.d.ts +6 -1
  169. package/dist/detectors/footnote-mismatch.d.ts.map +1 -1
  170. package/dist/detectors/footnote-mismatch.js +28 -7
  171. package/dist/detectors/footnote-mismatch.js.map +1 -1
  172. package/dist/detectors/fullwidth-alnum.d.ts.map +1 -1
  173. package/dist/detectors/fullwidth-alnum.js +7 -1
  174. package/dist/detectors/fullwidth-alnum.js.map +1 -1
  175. package/dist/detectors/graded-step.d.ts +20 -0
  176. package/dist/detectors/graded-step.d.ts.map +1 -0
  177. package/dist/detectors/graded-step.js +33 -0
  178. package/dist/detectors/graded-step.js.map +1 -0
  179. package/dist/detectors/gram-openers.d.ts +9 -0
  180. package/dist/detectors/gram-openers.d.ts.map +1 -0
  181. package/dist/detectors/gram-openers.js +40 -0
  182. package/dist/detectors/gram-openers.js.map +1 -0
  183. package/dist/detectors/gram-place.d.ts +3 -1
  184. package/dist/detectors/gram-place.d.ts.map +1 -1
  185. package/dist/detectors/gram-place.js +8 -0
  186. package/dist/detectors/gram-place.js.map +1 -1
  187. package/dist/detectors/gram-predicate.d.ts.map +1 -1
  188. package/dist/detectors/gram-predicate.js +37 -3
  189. package/dist/detectors/gram-predicate.js.map +1 -1
  190. package/dist/detectors/heading-echo.d.ts.map +1 -1
  191. package/dist/detectors/heading-echo.js +28 -2
  192. package/dist/detectors/heading-echo.js.map +1 -1
  193. package/dist/detectors/heading-record-rhythm.d.ts +9 -0
  194. package/dist/detectors/heading-record-rhythm.d.ts.map +1 -0
  195. package/dist/detectors/heading-record-rhythm.js +57 -0
  196. package/dist/detectors/heading-record-rhythm.js.map +1 -0
  197. package/dist/detectors/ime-residue.d.ts +1 -1
  198. package/dist/detectors/ime-residue.d.ts.map +1 -1
  199. package/dist/detectors/ime-residue.js +4 -3
  200. package/dist/detectors/ime-residue.js.map +1 -1
  201. package/dist/detectors/kanji-compound-slip.d.ts +3 -0
  202. package/dist/detectors/kanji-compound-slip.d.ts.map +1 -0
  203. package/dist/detectors/kanji-compound-slip.js +50 -0
  204. package/dist/detectors/kanji-compound-slip.js.map +1 -0
  205. package/dist/detectors/kutoten-consistency.d.ts +10 -2
  206. package/dist/detectors/kutoten-consistency.d.ts.map +1 -1
  207. package/dist/detectors/kutoten-consistency.js +83 -12
  208. package/dist/detectors/kutoten-consistency.js.map +1 -1
  209. package/dist/detectors/lexicon.d.ts.map +1 -1
  210. package/dist/detectors/lexicon.js +13 -4
  211. package/dist/detectors/lexicon.js.map +1 -1
  212. package/dist/detectors/link-shape.d.ts.map +1 -1
  213. package/dist/detectors/link-shape.js +9 -3
  214. package/dist/detectors/link-shape.js.map +1 -1
  215. package/dist/detectors/list-item-ending.d.ts +18 -0
  216. package/dist/detectors/list-item-ending.d.ts.map +1 -0
  217. package/dist/detectors/list-item-ending.js +35 -0
  218. package/dist/detectors/list-item-ending.js.map +1 -0
  219. package/dist/detectors/list-parallel.d.ts +18 -5
  220. package/dist/detectors/list-parallel.d.ts.map +1 -1
  221. package/dist/detectors/list-parallel.js +116 -36
  222. package/dist/detectors/list-parallel.js.map +1 -1
  223. package/dist/detectors/list-sentence.d.ts +4 -0
  224. package/dist/detectors/list-sentence.d.ts.map +1 -1
  225. package/dist/detectors/list-sentence.js +1 -1
  226. package/dist/detectors/list-sentence.js.map +1 -1
  227. package/dist/detectors/mark-shape.d.ts +13 -4
  228. package/dist/detectors/mark-shape.d.ts.map +1 -1
  229. package/dist/detectors/mark-shape.js +73 -10
  230. package/dist/detectors/mark-shape.js.map +1 -1
  231. package/dist/detectors/mentioned-phrase.d.ts +9 -0
  232. package/dist/detectors/mentioned-phrase.d.ts.map +1 -0
  233. package/dist/detectors/mentioned-phrase.js +25 -0
  234. package/dist/detectors/mentioned-phrase.js.map +1 -0
  235. package/dist/detectors/middle-dot.d.ts +2 -2
  236. package/dist/detectors/middle-dot.d.ts.map +1 -1
  237. package/dist/detectors/middle-dot.js +4 -2
  238. package/dist/detectors/middle-dot.js.map +1 -1
  239. package/dist/detectors/modal-conflict.d.ts.map +1 -1
  240. package/dist/detectors/modal-conflict.js +5 -2
  241. package/dist/detectors/modal-conflict.js.map +1 -1
  242. package/dist/detectors/name-variant.d.ts.map +1 -1
  243. package/dist/detectors/name-variant.js +6 -0
  244. package/dist/detectors/name-variant.js.map +1 -1
  245. package/dist/detectors/notice-paragraph.d.ts +9 -0
  246. package/dist/detectors/notice-paragraph.d.ts.map +1 -0
  247. package/dist/detectors/notice-paragraph.js +21 -0
  248. package/dist/detectors/notice-paragraph.js.map +1 -0
  249. package/dist/detectors/number-style.d.ts.map +1 -1
  250. package/dist/detectors/number-style.js +15 -2
  251. package/dist/detectors/number-style.js.map +1 -1
  252. package/dist/detectors/number-unit.d.ts.map +1 -1
  253. package/dist/detectors/number-unit.js +24 -1
  254. package/dist/detectors/number-unit.js.map +1 -1
  255. package/dist/detectors/numeral-opener.d.ts +6 -0
  256. package/dist/detectors/numeral-opener.d.ts.map +1 -1
  257. package/dist/detectors/numeral-opener.js +24 -1
  258. package/dist/detectors/numeral-opener.js.map +1 -1
  259. package/dist/detectors/obligation-without-deadline.d.ts +5 -1
  260. package/dist/detectors/obligation-without-deadline.d.ts.map +1 -1
  261. package/dist/detectors/obligation-without-deadline.js +44 -23
  262. package/dist/detectors/obligation-without-deadline.js.map +1 -1
  263. package/dist/detectors/open-end-class.d.ts +16 -0
  264. package/dist/detectors/open-end-class.d.ts.map +1 -0
  265. package/dist/detectors/open-end-class.js +65 -0
  266. package/dist/detectors/open-end-class.js.map +1 -0
  267. package/dist/detectors/open-end-condition.d.ts +7 -0
  268. package/dist/detectors/open-end-condition.d.ts.map +1 -0
  269. package/dist/detectors/open-end-condition.js +35 -0
  270. package/dist/detectors/open-end-condition.js.map +1 -0
  271. package/dist/detectors/open-end-names.d.ts +9 -3
  272. package/dist/detectors/open-end-names.d.ts.map +1 -1
  273. package/dist/detectors/open-end-names.js +5 -2
  274. package/dist/detectors/open-end-names.js.map +1 -1
  275. package/dist/detectors/open-end-question.d.ts +15 -0
  276. package/dist/detectors/open-end-question.d.ts.map +1 -0
  277. package/dist/detectors/open-end-question.js +37 -0
  278. package/dist/detectors/open-end-question.js.map +1 -0
  279. package/dist/detectors/open-end-scope.d.ts +16 -0
  280. package/dist/detectors/open-end-scope.d.ts.map +1 -0
  281. package/dist/detectors/open-end-scope.js +47 -0
  282. package/dist/detectors/open-end-scope.js.map +1 -0
  283. package/dist/detectors/opening-date.d.ts +10 -0
  284. package/dist/detectors/opening-date.d.ts.map +1 -0
  285. package/dist/detectors/opening-date.js +33 -0
  286. package/dist/detectors/opening-date.js.map +1 -0
  287. package/dist/detectors/ordinary-phrase.d.ts +20 -0
  288. package/dist/detectors/ordinary-phrase.d.ts.map +1 -0
  289. package/dist/detectors/ordinary-phrase.js +54 -0
  290. package/dist/detectors/ordinary-phrase.js.map +1 -0
  291. package/dist/detectors/organisation-run.d.ts +5 -7
  292. package/dist/detectors/organisation-run.d.ts.map +1 -1
  293. package/dist/detectors/organisation-run.js +10 -0
  294. package/dist/detectors/organisation-run.js.map +1 -1
  295. package/dist/detectors/orthographic-variant.d.ts.map +1 -1
  296. package/dist/detectors/orthographic-variant.js +85 -20
  297. package/dist/detectors/orthographic-variant.js.map +1 -1
  298. package/dist/detectors/orthography.d.ts.map +1 -1
  299. package/dist/detectors/orthography.js +9 -2
  300. package/dist/detectors/orthography.js.map +1 -1
  301. package/dist/detectors/oxford-comma.d.ts.map +1 -1
  302. package/dist/detectors/oxford-comma.js +70 -3
  303. package/dist/detectors/oxford-comma.js.map +1 -1
  304. package/dist/detectors/person-consistency.d.ts +2 -1
  305. package/dist/detectors/person-consistency.d.ts.map +1 -1
  306. package/dist/detectors/person-consistency.js +5 -3
  307. package/dist/detectors/person-consistency.js.map +1 -1
  308. package/dist/detectors/phrase-match.d.ts +2 -0
  309. package/dist/detectors/phrase-match.d.ts.map +1 -1
  310. package/dist/detectors/phrase-match.js +11 -4
  311. package/dist/detectors/phrase-match.js.map +1 -1
  312. package/dist/detectors/placeholder-text.d.ts.map +1 -1
  313. package/dist/detectors/placeholder-text.js +18 -3
  314. package/dist/detectors/placeholder-text.js.map +1 -1
  315. package/dist/detectors/placeholder.d.ts +3 -1
  316. package/dist/detectors/placeholder.d.ts.map +1 -1
  317. package/dist/detectors/placeholder.js +8 -3
  318. package/dist/detectors/placeholder.js.map +1 -1
  319. package/dist/detectors/postcode-end.d.ts +3 -0
  320. package/dist/detectors/postcode-end.d.ts.map +1 -0
  321. package/dist/detectors/postcode-end.js +15 -0
  322. package/dist/detectors/postcode-end.js.map +1 -0
  323. package/dist/detectors/prose-total-words.d.ts +5 -0
  324. package/dist/detectors/prose-total-words.d.ts.map +1 -0
  325. package/dist/detectors/prose-total-words.js +14 -0
  326. package/dist/detectors/prose-total-words.js.map +1 -0
  327. package/dist/detectors/range-notation.d.ts +2 -2
  328. package/dist/detectors/range-notation.d.ts.map +1 -1
  329. package/dist/detectors/range-notation.js +18 -7
  330. package/dist/detectors/range-notation.js.map +1 -1
  331. package/dist/detectors/registry/kanji-compound-slip.d.ts +3 -0
  332. package/dist/detectors/registry/kanji-compound-slip.d.ts.map +1 -0
  333. package/dist/detectors/registry/kanji-compound-slip.js +3 -0
  334. package/dist/detectors/registry/kanji-compound-slip.js.map +1 -0
  335. package/dist/detectors/registry/phrase-in-use.d.ts +3 -0
  336. package/dist/detectors/registry/phrase-in-use.d.ts.map +1 -0
  337. package/dist/detectors/registry/phrase-in-use.js +3 -0
  338. package/dist/detectors/registry/phrase-in-use.js.map +1 -0
  339. package/dist/detectors/requirement-smell.d.ts.map +1 -1
  340. package/dist/detectors/requirement-smell.js +35 -7
  341. package/dist/detectors/requirement-smell.js.map +1 -1
  342. package/dist/detectors/scaled-figure-unit.d.ts +28 -0
  343. package/dist/detectors/scaled-figure-unit.d.ts.map +1 -0
  344. package/dist/detectors/scaled-figure-unit.js +78 -0
  345. package/dist/detectors/scaled-figure-unit.js.map +1 -0
  346. package/dist/detectors/sentence-counts.d.ts +12 -2
  347. package/dist/detectors/sentence-counts.d.ts.map +1 -1
  348. package/dist/detectors/sentence-counts.js +52 -11
  349. package/dist/detectors/sentence-counts.js.map +1 -1
  350. package/dist/detectors/sentence-ending.d.ts +2 -0
  351. package/dist/detectors/sentence-ending.d.ts.map +1 -1
  352. package/dist/detectors/sentence-ending.js +10 -3
  353. package/dist/detectors/sentence-ending.js.map +1 -1
  354. package/dist/detectors/sentence-length.d.ts.map +1 -1
  355. package/dist/detectors/sentence-length.js +13 -4
  356. package/dist/detectors/sentence-length.js.map +1 -1
  357. package/dist/detectors/sentence-load.d.ts +4 -1
  358. package/dist/detectors/sentence-load.d.ts.map +1 -1
  359. package/dist/detectors/sentence-load.js +9 -2
  360. package/dist/detectors/sentence-load.js.map +1 -1
  361. package/dist/detectors/signals.d.ts.map +1 -1
  362. package/dist/detectors/signals.js +44 -52
  363. package/dist/detectors/signals.js.map +1 -1
  364. package/dist/detectors/structure-tree.d.ts.map +1 -1
  365. package/dist/detectors/structure-tree.js +14 -13
  366. package/dist/detectors/structure-tree.js.map +1 -1
  367. package/dist/detectors/structure.d.ts.map +1 -1
  368. package/dist/detectors/structure.js +2 -1
  369. package/dist/detectors/structure.js.map +1 -1
  370. package/dist/detectors/subject-name-line.d.ts +8 -0
  371. package/dist/detectors/subject-name-line.d.ts.map +1 -0
  372. package/dist/detectors/subject-name-line.js +53 -0
  373. package/dist/detectors/subject-name-line.js.map +1 -0
  374. package/dist/detectors/superlative-name.d.ts +5 -0
  375. package/dist/detectors/superlative-name.d.ts.map +1 -1
  376. package/dist/detectors/superlative-name.js +9 -0
  377. package/dist/detectors/superlative-name.js.map +1 -1
  378. package/dist/detectors/table-header.d.ts.map +1 -1
  379. package/dist/detectors/table-header.js +13 -1
  380. package/dist/detectors/table-header.js.map +1 -1
  381. package/dist/detectors/technical-docs.d.ts.map +1 -1
  382. package/dist/detectors/technical-docs.js +4 -1
  383. package/dist/detectors/technical-docs.js.map +1 -1
  384. package/dist/detectors/term-mention-sentence.d.ts +4 -0
  385. package/dist/detectors/term-mention-sentence.d.ts.map +1 -0
  386. package/dist/detectors/term-mention-sentence.js +28 -0
  387. package/dist/detectors/term-mention-sentence.js.map +1 -0
  388. package/dist/detectors/titled-run.d.ts +2 -1
  389. package/dist/detectors/titled-run.d.ts.map +1 -1
  390. package/dist/detectors/titled-run.js +9 -4
  391. package/dist/detectors/titled-run.js.map +1 -1
  392. package/dist/detectors/token-shape.d.ts.map +1 -1
  393. package/dist/detectors/token-shape.js +15 -5
  394. package/dist/detectors/token-shape.js.map +1 -1
  395. package/dist/detectors/undefined-term.d.ts.map +1 -1
  396. package/dist/detectors/undefined-term.js +5 -0
  397. package/dist/detectors/undefined-term.js.map +1 -1
  398. package/dist/detectors/unknown-word.d.ts +4 -1
  399. package/dist/detectors/unknown-word.d.ts.map +1 -1
  400. package/dist/detectors/unknown-word.js +1 -1
  401. package/dist/detectors/unknown-word.js.map +1 -1
  402. package/dist/detectors/vague-density.d.ts +5 -2
  403. package/dist/detectors/vague-density.d.ts.map +1 -1
  404. package/dist/detectors/vague-density.js +17 -4
  405. package/dist/detectors/vague-density.js.map +1 -1
  406. package/dist/document-paragraphs.d.ts +4 -0
  407. package/dist/document-paragraphs.d.ts.map +1 -0
  408. package/dist/document-paragraphs.js +24 -0
  409. package/dist/document-paragraphs.js.map +1 -0
  410. package/dist/document.d.ts.map +1 -1
  411. package/dist/document.js +2 -19
  412. package/dist/document.js.map +1 -1
  413. package/dist/figure-references.d.ts +3 -0
  414. package/dist/figure-references.d.ts.map +1 -1
  415. package/dist/figure-references.js +6 -2
  416. package/dist/figure-references.js.map +1 -1
  417. package/dist/format-template.d.ts +3 -0
  418. package/dist/format-template.d.ts.map +1 -0
  419. package/dist/format-template.js +13 -0
  420. package/dist/format-template.js.map +1 -0
  421. package/dist/formula-brackets.d.ts +7 -0
  422. package/dist/formula-brackets.d.ts.map +1 -0
  423. package/dist/formula-brackets.js +29 -0
  424. package/dist/formula-brackets.js.map +1 -0
  425. package/dist/html/html-markdown.d.ts.map +1 -1
  426. package/dist/html/html-markdown.js +2 -1
  427. package/dist/html/html-markdown.js.map +1 -1
  428. package/dist/html/html-site-chrome.d.ts +5 -0
  429. package/dist/html/html-site-chrome.d.ts.map +1 -0
  430. package/dist/html/html-site-chrome.js +56 -0
  431. package/dist/html/html-site-chrome.js.map +1 -0
  432. package/dist/joined-view.d.ts.map +1 -1
  433. package/dist/joined-view.js +1 -0
  434. package/dist/joined-view.js.map +1 -1
  435. package/dist/kanji-compound-slip.d.ts +32 -0
  436. package/dist/kanji-compound-slip.d.ts.map +1 -0
  437. package/dist/kanji-compound-slip.js +63 -0
  438. package/dist/kanji-compound-slip.js.map +1 -0
  439. package/dist/latin-company-form.d.ts +6 -0
  440. package/dist/latin-company-form.d.ts.map +1 -0
  441. package/dist/latin-company-form.js +32 -0
  442. package/dist/latin-company-form.js.map +1 -0
  443. package/dist/latin-word-boundary.d.ts +20 -0
  444. package/dist/latin-word-boundary.d.ts.map +1 -0
  445. package/dist/latin-word-boundary.js +57 -0
  446. package/dist/latin-word-boundary.js.map +1 -0
  447. package/dist/leading-label.d.ts +4 -0
  448. package/dist/leading-label.d.ts.map +1 -0
  449. package/dist/leading-label.js +14 -0
  450. package/dist/leading-label.js.map +1 -0
  451. package/dist/lexicon-genres.d.ts +2 -0
  452. package/dist/lexicon-genres.d.ts.map +1 -1
  453. package/dist/lexicon-genres.js +1 -1
  454. package/dist/lexicon-genres.js.map +1 -1
  455. package/dist/link-shape.d.ts +6 -0
  456. package/dist/link-shape.d.ts.map +1 -1
  457. package/dist/link-shape.js +27 -0
  458. package/dist/link-shape.js.map +1 -1
  459. package/dist/link-title.d.ts +4 -0
  460. package/dist/link-title.d.ts.map +1 -0
  461. package/dist/link-title.js +33 -0
  462. package/dist/link-title.js.map +1 -0
  463. package/dist/list-item-paragraphs.d.ts +15 -0
  464. package/dist/list-item-paragraphs.d.ts.map +1 -0
  465. package/dist/list-item-paragraphs.js +19 -0
  466. package/dist/list-item-paragraphs.js.map +1 -0
  467. package/dist/literal-quote.d.ts +12 -0
  468. package/dist/literal-quote.d.ts.map +1 -0
  469. package/dist/literal-quote.js +43 -0
  470. package/dist/literal-quote.js.map +1 -0
  471. package/dist/nado-closed-list.d.ts.map +1 -1
  472. package/dist/nado-closed-list.js +39 -5
  473. package/dist/nado-closed-list.js.map +1 -1
  474. package/dist/name-misspelt-usual.d.ts +5 -0
  475. package/dist/name-misspelt-usual.d.ts.map +1 -0
  476. package/dist/name-misspelt-usual.js +19 -0
  477. package/dist/name-misspelt-usual.js.map +1 -0
  478. package/dist/name-separator.d.ts.map +1 -1
  479. package/dist/name-separator.js +25 -2
  480. package/dist/name-separator.js.map +1 -1
  481. package/dist/nominal-stem.d.ts +14 -1
  482. package/dist/nominal-stem.d.ts.map +1 -1
  483. package/dist/nominal-stem.js +42 -4
  484. package/dist/nominal-stem.js.map +1 -1
  485. package/dist/notice-header.d.ts +19 -0
  486. package/dist/notice-header.d.ts.map +1 -0
  487. package/dist/notice-header.js +31 -0
  488. package/dist/notice-header.js.map +1 -0
  489. package/dist/person-forms.d.ts +8 -0
  490. package/dist/person-forms.d.ts.map +1 -1
  491. package/dist/person-forms.js +12 -0
  492. package/dist/person-forms.js.map +1 -1
  493. package/dist/plugin.d.ts +5 -0
  494. package/dist/plugin.d.ts.map +1 -1
  495. package/dist/preamble-paragraphs.d.ts +3 -2
  496. package/dist/preamble-paragraphs.d.ts.map +1 -1
  497. package/dist/preamble-paragraphs.js +8 -2
  498. package/dist/preamble-paragraphs.js.map +1 -1
  499. package/dist/sentence-load.d.ts +2 -1
  500. package/dist/sentence-load.d.ts.map +1 -1
  501. package/dist/sentence-load.js +11 -3
  502. package/dist/sentence-load.js.map +1 -1
  503. package/dist/spacing-code.d.ts +1 -0
  504. package/dist/spacing-code.d.ts.map +1 -1
  505. package/dist/spacing-code.js +4 -1
  506. package/dist/spacing-code.js.map +1 -1
  507. package/dist/split-noun.d.ts +10 -0
  508. package/dist/split-noun.d.ts.map +1 -0
  509. package/dist/split-noun.js +50 -0
  510. package/dist/split-noun.js.map +1 -0
  511. package/dist/structure/attached-parts.d.ts +12 -0
  512. package/dist/structure/attached-parts.d.ts.map +1 -0
  513. package/dist/structure/attached-parts.js +44 -0
  514. package/dist/structure/attached-parts.js.map +1 -0
  515. package/dist/structure/build.d.ts.map +1 -1
  516. package/dist/structure/build.js +7 -4
  517. package/dist/structure/build.js.map +1 -1
  518. package/dist/structure/contents-lines.d.ts +7 -0
  519. package/dist/structure/contents-lines.d.ts.map +1 -0
  520. package/dist/structure/contents-lines.js +51 -0
  521. package/dist/structure/contents-lines.js.map +1 -0
  522. package/dist/structure/defining-names.d.ts +37 -0
  523. package/dist/structure/defining-names.d.ts.map +1 -0
  524. package/dist/structure/defining-names.js +122 -0
  525. package/dist/structure/defining-names.js.map +1 -0
  526. package/dist/structure/definition-use.d.ts +8 -4
  527. package/dist/structure/definition-use.d.ts.map +1 -1
  528. package/dist/structure/definition-use.js +123 -38
  529. package/dist/structure/definition-use.js.map +1 -1
  530. package/dist/structure/gerund-phrase.d.ts +8 -0
  531. package/dist/structure/gerund-phrase.d.ts.map +1 -0
  532. package/dist/structure/gerund-phrase.js +30 -0
  533. package/dist/structure/gerund-phrase.js.map +1 -0
  534. package/dist/structure/issues.d.ts +4 -1
  535. package/dist/structure/issues.d.ts.map +1 -1
  536. package/dist/structure/issues.js +5 -2
  537. package/dist/structure/issues.js.map +1 -1
  538. package/dist/structure/list-lead-in.d.ts +19 -0
  539. package/dist/structure/list-lead-in.d.ts.map +1 -0
  540. package/dist/structure/list-lead-in.js +85 -0
  541. package/dist/structure/list-lead-in.js.map +1 -0
  542. package/dist/structure/modal-conflict.d.ts +7 -2
  543. package/dist/structure/modal-conflict.d.ts.map +1 -1
  544. package/dist/structure/modal-conflict.js +36 -7
  545. package/dist/structure/modal-conflict.js.map +1 -1
  546. package/dist/structure/negated-act.d.ts +17 -0
  547. package/dist/structure/negated-act.d.ts.map +1 -0
  548. package/dist/structure/negated-act.js +32 -0
  549. package/dist/structure/negated-act.js.map +1 -0
  550. package/dist/structure/numbering.d.ts +3 -1
  551. package/dist/structure/numbering.d.ts.map +1 -1
  552. package/dist/structure/numbering.js +20 -8
  553. package/dist/structure/numbering.js.map +1 -1
  554. package/dist/structure/prose-total.d.ts +4 -0
  555. package/dist/structure/prose-total.d.ts.map +1 -1
  556. package/dist/structure/prose-total.js +16 -6
  557. package/dist/structure/prose-total.js.map +1 -1
  558. package/dist/structure/repeated-number.d.ts +24 -0
  559. package/dist/structure/repeated-number.d.ts.map +1 -0
  560. package/dist/structure/repeated-number.js +89 -0
  561. package/dist/structure/repeated-number.js.map +1 -0
  562. package/dist/structure/rounded-amount.d.ts +8 -0
  563. package/dist/structure/rounded-amount.d.ts.map +1 -0
  564. package/dist/structure/rounded-amount.js +48 -0
  565. package/dist/structure/rounded-amount.js.map +1 -0
  566. package/dist/structure/side-step.d.ts +8 -0
  567. package/dist/structure/side-step.d.ts.map +1 -0
  568. package/dist/structure/side-step.js +21 -0
  569. package/dist/structure/side-step.js.map +1 -0
  570. package/dist/structure/spanned-label-blank.d.ts +8 -0
  571. package/dist/structure/spanned-label-blank.d.ts.map +1 -0
  572. package/dist/structure/spanned-label-blank.js +37 -0
  573. package/dist/structure/spanned-label-blank.js.map +1 -0
  574. package/dist/structure/universal.d.ts +10 -4
  575. package/dist/structure/universal.d.ts.map +1 -1
  576. package/dist/structure/universal.js +26 -7
  577. package/dist/structure/universal.js.map +1 -1
  578. package/dist/structure/unspaced-heading.d.ts +10 -0
  579. package/dist/structure/unspaced-heading.d.ts.map +1 -0
  580. package/dist/structure/unspaced-heading.js +24 -0
  581. package/dist/structure/unspaced-heading.js.map +1 -0
  582. package/dist/structure/written-list-path.d.ts +10 -0
  583. package/dist/structure/written-list-path.d.ts.map +1 -0
  584. package/dist/structure/written-list-path.js +37 -0
  585. package/dist/structure/written-list-path.js.map +1 -0
  586. package/dist/structure/written-resolve.d.ts +1 -1
  587. package/dist/structure/written-resolve.d.ts.map +1 -1
  588. package/dist/structure/written-resolve.js +15 -9
  589. package/dist/structure/written-resolve.js.map +1 -1
  590. package/dist/title-line.d.ts +23 -0
  591. package/dist/title-line.d.ts.map +1 -0
  592. package/dist/title-line.js +28 -0
  593. package/dist/title-line.js.map +1 -0
  594. package/dist/topic-clause.d.ts +7 -0
  595. package/dist/topic-clause.d.ts.map +1 -0
  596. package/dist/topic-clause.js +87 -0
  597. package/dist/topic-clause.js.map +1 -0
  598. package/dist/uncounted-particles.d.ts +18 -0
  599. package/dist/uncounted-particles.d.ts.map +1 -0
  600. package/dist/uncounted-particles.js +47 -0
  601. package/dist/uncounted-particles.js.map +1 -0
  602. package/package.json +3 -3
  603. package/rules/adversative-ga-repeat.yaml +1 -0
  604. package/rules/all-caps-shouting.yaml +2 -2
  605. package/rules/announced-count-mismatch.yaml +2 -2
  606. package/rules/bare-url-mix.yaml +2 -2
  607. package/rules/bracket-nesting.yaml +2 -2
  608. package/rules/bracket-width-consistency.yaml +2 -2
  609. package/rules/broken-link.yaml +2 -2
  610. package/rules/cliche.yaml +4 -3
  611. package/rules/code-fence-language-mix.yaml +2 -2
  612. package/rules/comparative-without-baseline.yaml +2 -2
  613. package/rules/concrete-evidence-density.yaml +1 -0
  614. package/rules/contraction-consistency.yaml +2 -2
  615. package/rules/dangling-figure-reference.yaml +2 -2
  616. package/rules/date-without-year.yaml +10 -2
  617. package/rules/defined-term-form.yaml +2 -2
  618. package/rules/doubled-punctuation.yaml +4 -4
  619. package/rules/doubled-word.yaml +2 -2
  620. package/rules/duplicate-definition.yaml +2 -2
  621. package/rules/duplicate-heading.yaml +2 -2
  622. package/rules/duration-mismatch.yaml +2 -2
  623. package/rules/email-greeting-closing.yaml +2 -2
  624. package/rules/email-subject-length.yaml +2 -2
  625. package/rules/empty-table-cell.yaml +2 -2
  626. package/rules/footnote-mismatch.yaml +2 -2
  627. package/rules/fullwidth-alnum-consistency.yaml +2 -2
  628. package/rules/heading-echo.yaml +2 -2
  629. package/rules/ime-residue.yaml +2 -2
  630. package/rules/kanji-compound-slip.yaml +67 -0
  631. package/rules/kutoten-consistency.yaml +4 -4
  632. package/rules/latin-spacing.yaml +2 -2
  633. package/rules/list-item-form-mix.yaml +2 -2
  634. package/rules/max-kanji-continuous.yaml +6 -4
  635. package/rules/max-sentence-length.yaml +2 -2
  636. package/rules/modal-conflict.yaml +1 -0
  637. package/rules/nado-closed-list.yaml +2 -2
  638. package/rules/ngram-repetition.yaml +2 -2
  639. package/rules/no-doubled-joshi.yaml +2 -2
  640. package/rules/no-mixed-desumasu.yaml +3 -3
  641. package/rules/no-nakaguro-parallel.yaml +2 -0
  642. package/rules/number-without-unit.yaml +9 -4
  643. package/rules/numbering-gap.yaml +7 -2
  644. package/rules/numeral-sentence-start.yaml +2 -2
  645. package/rules/obligation-without-deadline.yaml +2 -2
  646. package/rules/orthographic-variant.yaml +2 -2
  647. package/rules/oxford-comma-consistency.yaml +3 -3
  648. package/rules/preamble-length.yaml +3 -2
  649. package/rules/range-notation-consistency.yaml +2 -2
  650. package/rules/requirement-smell.yaml +3 -3
  651. package/rules/table-header-variant.yaml +2 -2
  652. package/rules/teki-overuse.yaml +3 -2
  653. package/rules/title-length.yaml +2 -2
  654. package/rules/topic-predicate-distance.yaml +2 -2
  655. package/rules/total-mismatch.yaml +2 -2
  656. package/rules/translationese-density.yaml +2 -2
  657. package/rules/undefined-acronym.yaml +5 -2
  658. package/rules/undefined-term.yaml +2 -2
  659. package/rules/unfilled-placeholder.yaml +4 -4
  660. package/rules/unqualified-superlative.yaml +1 -1
  661. package/rules/unused-definition.yaml +2 -2
  662. package/rules/use-before-definition.yaml +2 -2
  663. package/rules/vague-word-density.yaml +2 -2
  664. package/skills/chaff/SKILL.md +7 -1
  665. package/src/announced-count.ts +35 -8
  666. package/src/chronology-rows.ts +86 -0
  667. package/src/company-name-run.ts +37 -0
  668. package/src/compound-head.ts +25 -0
  669. package/src/date-format.ts +43 -4
  670. package/src/derived/count-per-period.ts +28 -0
  671. package/src/detectors/acronym-context.ts +30 -1
  672. package/src/detectors/acronym-expansion.ts +54 -6
  673. package/src/detectors/acronym-known.ts +40 -0
  674. package/src/detectors/acronym-link.ts +75 -0
  675. package/src/detectors/acronym-mention.ts +44 -0
  676. package/src/detectors/acronym-name.ts +29 -6
  677. package/src/detectors/addressee-edge.ts +16 -0
  678. package/src/detectors/addressee-title-edge.ts +39 -0
  679. package/src/detectors/announced-count.ts +1 -0
  680. package/src/detectors/bare-comparative.ts +44 -3
  681. package/src/detectors/blank-structure.ts +21 -10
  682. package/src/detectors/bracket-specified.ts +25 -0
  683. package/src/detectors/broken-link.ts +26 -2
  684. package/src/detectors/capitalised-term.ts +26 -2
  685. package/src/detectors/caps-caption.ts +76 -0
  686. package/src/detectors/caps-phrase.ts +17 -0
  687. package/src/detectors/char-shape.ts +73 -14
  688. package/src/detectors/citation-sentence.ts +44 -0
  689. package/src/detectors/cited-title.ts +15 -3
  690. package/src/detectors/contraction-mention.ts +24 -0
  691. package/src/detectors/counter-edge.ts +17 -2
  692. package/src/detectors/dash-break.ts +45 -0
  693. package/src/detectors/date-any-year.ts +34 -9
  694. package/src/detectors/date-format.ts +2 -1
  695. package/src/detectors/date-year.ts +64 -16
  696. package/src/detectors/deadline-unit.ts +40 -0
  697. package/src/detectors/defined-term-form.ts +32 -12
  698. package/src/detectors/definition-use.ts +17 -9
  699. package/src/detectors/derived-numbers.ts +19 -4
  700. package/src/detectors/document-shape.ts +20 -1
  701. package/src/detectors/doubled-across-aside.ts +36 -0
  702. package/src/detectors/doubled-punctuation.ts +28 -7
  703. package/src/detectors/doubled-word.ts +2 -1
  704. package/src/detectors/duplicate-heading.ts +26 -3
  705. package/src/detectors/ellipsis.ts +16 -1
  706. package/src/detectors/email-letter.ts +142 -23
  707. package/src/detectors/field-label.ts +25 -0
  708. package/src/detectors/footnote-mismatch.ts +39 -7
  709. package/src/detectors/fullwidth-alnum.ts +9 -1
  710. package/src/detectors/graded-step.ts +52 -0
  711. package/src/detectors/gram-openers.ts +50 -0
  712. package/src/detectors/gram-place.ts +10 -1
  713. package/src/detectors/gram-predicate.ts +43 -3
  714. package/src/detectors/heading-echo.ts +31 -3
  715. package/src/detectors/heading-record-rhythm.ts +57 -0
  716. package/src/detectors/ime-residue.ts +4 -3
  717. package/src/detectors/kanji-compound-slip.ts +61 -0
  718. package/src/detectors/kutoten-consistency.ts +102 -14
  719. package/src/detectors/lexicon.ts +18 -5
  720. package/src/detectors/link-shape.ts +10 -3
  721. package/src/detectors/list-item-ending.ts +51 -0
  722. package/src/detectors/list-parallel.ts +158 -33
  723. package/src/detectors/list-sentence.ts +5 -1
  724. package/src/detectors/mark-shape.ts +89 -10
  725. package/src/detectors/mentioned-phrase.ts +38 -0
  726. package/src/detectors/middle-dot.ts +7 -2
  727. package/src/detectors/modal-conflict.ts +5 -2
  728. package/src/detectors/name-variant.ts +6 -0
  729. package/src/detectors/notice-paragraph.ts +33 -0
  730. package/src/detectors/number-style.ts +14 -2
  731. package/src/detectors/number-unit.ts +28 -1
  732. package/src/detectors/numeral-opener.ts +27 -1
  733. package/src/detectors/obligation-without-deadline.ts +29 -4
  734. package/src/detectors/open-end-class.ts +78 -0
  735. package/src/detectors/open-end-condition.ts +40 -0
  736. package/src/detectors/open-end-names.ts +9 -3
  737. package/src/detectors/open-end-question.ts +50 -0
  738. package/src/detectors/open-end-scope.ts +62 -0
  739. package/src/detectors/opening-date.ts +47 -0
  740. package/src/detectors/ordinary-phrase.ts +62 -0
  741. package/src/detectors/organisation-run.ts +18 -2
  742. package/src/detectors/orthographic-variant.ts +124 -25
  743. package/src/detectors/orthography.ts +15 -2
  744. package/src/detectors/oxford-comma.ts +74 -3
  745. package/src/detectors/person-consistency.ts +5 -3
  746. package/src/detectors/phrase-match.ts +16 -5
  747. package/src/detectors/placeholder-text.ts +18 -3
  748. package/src/detectors/placeholder.ts +10 -3
  749. package/src/detectors/postcode-end.ts +16 -0
  750. package/src/detectors/prose-total-words.ts +18 -0
  751. package/src/detectors/range-notation.ts +26 -6
  752. package/src/detectors/registry/kanji-compound-slip.ts +4 -0
  753. package/src/detectors/registry/phrase-in-use.ts +4 -0
  754. package/src/detectors/requirement-smell.ts +45 -8
  755. package/src/detectors/scaled-figure-unit.ts +103 -0
  756. package/src/detectors/sentence-counts.ts +64 -12
  757. package/src/detectors/sentence-ending.ts +12 -3
  758. package/src/detectors/sentence-length.ts +17 -4
  759. package/src/detectors/sentence-load.ts +9 -2
  760. package/src/detectors/signals.ts +50 -53
  761. package/src/detectors/structure-tree.ts +14 -14
  762. package/src/detectors/structure.ts +2 -1
  763. package/src/detectors/subject-name-line.ts +66 -0
  764. package/src/detectors/superlative-name.ts +10 -0
  765. package/src/detectors/table-header.ts +15 -1
  766. package/src/detectors/technical-docs.ts +5 -1
  767. package/src/detectors/term-mention-sentence.ts +31 -0
  768. package/src/detectors/titled-run.ts +9 -4
  769. package/src/detectors/token-shape.ts +16 -5
  770. package/src/detectors/undefined-term.ts +8 -0
  771. package/src/detectors/unknown-word.ts +1 -1
  772. package/src/detectors/vague-density.ts +20 -4
  773. package/src/document-paragraphs.ts +27 -0
  774. package/src/document.ts +3 -23
  775. package/src/figure-references.ts +7 -2
  776. package/src/format-template.ts +15 -0
  777. package/src/formula-brackets.ts +36 -0
  778. package/src/html/html-markdown.ts +2 -1
  779. package/src/html/html-site-chrome.ts +104 -0
  780. package/src/joined-view.ts +1 -0
  781. package/src/kanji-compound-slip.ts +98 -0
  782. package/src/latin-company-form.ts +38 -0
  783. package/src/latin-word-boundary.ts +64 -0
  784. package/src/leading-label.ts +15 -0
  785. package/src/lexicon-genres.ts +1 -1
  786. package/src/link-shape.ts +31 -0
  787. package/src/link-title.ts +38 -0
  788. package/src/list-item-paragraphs.ts +22 -0
  789. package/src/literal-quote.ts +55 -0
  790. package/src/nado-closed-list.ts +48 -5
  791. package/src/name-misspelt-usual.ts +25 -0
  792. package/src/name-separator.ts +27 -2
  793. package/src/nominal-stem.ts +62 -5
  794. package/src/notice-header.ts +57 -0
  795. package/src/person-forms.ts +15 -0
  796. package/src/plugin.ts +5 -0
  797. package/src/preamble-paragraphs.ts +13 -3
  798. package/src/sentence-load.ts +14 -3
  799. package/src/spacing-code.ts +5 -1
  800. package/src/split-noun.ts +63 -0
  801. package/src/structure/attached-parts.ts +47 -0
  802. package/src/structure/build.ts +7 -4
  803. package/src/structure/contents-lines.ts +63 -0
  804. package/src/structure/defining-names.ts +155 -0
  805. package/src/structure/definition-use.ts +149 -32
  806. package/src/structure/gerund-phrase.ts +31 -0
  807. package/src/structure/issues.ts +7 -3
  808. package/src/structure/list-lead-in.ts +94 -0
  809. package/src/structure/modal-conflict.ts +42 -7
  810. package/src/structure/negated-act.ts +49 -0
  811. package/src/structure/numbering.ts +24 -9
  812. package/src/structure/prose-total.ts +20 -6
  813. package/src/structure/repeated-number.ts +110 -0
  814. package/src/structure/rounded-amount.ts +55 -0
  815. package/src/structure/side-step.ts +21 -0
  816. package/src/structure/spanned-label-blank.ts +39 -0
  817. package/src/structure/universal.ts +33 -9
  818. package/src/structure/unspaced-heading.ts +27 -0
  819. package/src/structure/written-list-path.ts +46 -0
  820. package/src/structure/written-resolve.ts +16 -9
  821. package/src/title-line.ts +53 -0
  822. package/src/topic-clause.ts +109 -0
  823. package/src/uncounted-particles.ts +72 -0
@@ -1,17 +1,23 @@
1
- import type { Detector, Finding, ProseDocument, Sentence, TableCell, Token } from "../plugin.ts";
1
+ import type { Detector, Finding, ProseDocument, Sentence, Span, TableCell, Token } from "../plugin.ts";
2
+ import { externalLinkTitleSpans } from "../link-title.ts";
2
3
  import { groupBy, oddSpellings, type KeyedWord, type OddSpelling } from "../spelling-variants.ts";
3
4
  import { dropsOkurigana, kanjiKeyAmong, katakanaKey, lemmaReading } from "../kana-spelling.ts";
4
5
  import { isKatakanaWord, stemOf } from "../long-vowel.ts";
6
+ import { withNounsAfterParticles } from "../nominal-stem.ts";
5
7
  import { QUOTATION_MARKS, isWithinAny, quotedSpans } from "../quoted-span.ts";
6
8
  import { nameSpans, touchesAny } from "../team-names.ts";
7
9
  import { furiganaSpans } from "../furigana.ts";
10
+ import { withCutNounsJoined } from "../split-noun.ts";
11
+ import { japaneseCompanyNameSpans } from "../company-name-run.ts";
8
12
  import { acronymsIn, isCapitalsNotSpelling } from "../capitals-with-small.ts";
9
13
  import { isPartOfAddress } from "./address-word.ts";
10
14
  import { isInCapitalsPassage } from "../capitals-passage.ts";
11
15
  import { withoutCoinedNames } from "../coined-hyphen-name.ts";
12
16
  import { wholeWordRuns, type WholeWordRun } from "../whole-word-runs.ts";
13
17
  import { entriesForGenre } from "../lexicon-genres.ts";
14
- import { asNounWhereNominal } from "../nominal-stem.ts";
18
+ import { asNounWhereNominal, documentNounKeys } from "../nominal-stem.ts";
19
+ import { isCompoundHead } from "../compound-head.ts";
20
+ import { leadingLabelSpans } from "../leading-label.ts";
15
21
 
16
22
  /**
17
23
  * A word found in the document: where it is, which sentence it is in, its key and spelling, how it is written when that differs, and
@@ -42,6 +48,16 @@ const DISTINCT = "orthographic-variant-distinct";
42
48
  const FUKUSHI = "hiragana-fukushi";
43
49
  /** Lexicon: idioms written as noun, particle and verb (気をつける). The verb there is compared apart from the verb on its own. */
44
50
  const IDIOM = "orthographic-variant-idiom";
51
+ /** Lexicon: verbs whose て-form opening a sentence before a comma is a conjunction (あわせて、). */
52
+ const CONJUNCTION = "orthographic-variant-conjunction";
53
+ /** Lexicon: verbs whose judging use (〜とみられる, 増加がみられる) is written in kana while the verb (資料を見る) keeps its kanji. */
54
+ const JUDGING = "orthographic-variant-judging";
55
+ /**
56
+ * Lexicon: words whose kanji is also a person (方 as かた): compared only before が or で (早いほうが, 資料のほうで), where the
57
+ * person is rare; before に, の or は (担当の方に) the kanji is mostly the person.
58
+ */
59
+ const COMPARATIVE = "orthographic-variant-comparative";
60
+ const COMPARATIVE_PARTICLES = new Set(["が", "で"]);
45
61
  /** Lexicon: words the tokenizer cuts in one spelling and not the other (お客様, お客 and さま). Each is read whole, keyed by its group. */
46
62
  const WHOLE_WORD = "orthographic-variant-whole-word";
47
63
  /** Lexicon: suffixes written onto a word that do not make a compound of it (割当て等, 引受け後): the word keeps its okurigana there. */
@@ -51,17 +67,39 @@ const patternsOf = (doc: ProseDocument, id: string, genre: string | undefined):
51
67
  entriesForGenre(doc.lexicons[id] ?? [], genre).map((entry) => entry.pattern);
52
68
 
53
69
  /**
54
- * Whether a stretch of the sentence is outside a quotation, the team's names and a reading in brackets (HTTP(えいちてぃーてぃーぴー)):
55
- * the first two keep their own spelling, and a reading is not a spelling at all.
70
+ * The team's names, the company forms (株式会社, ㈱) a registered company name is written next to, and the links that quote an
71
+ * outside page's title (link-title.ts), placed in the source.
56
72
  */
57
- const isOpenIn = (sentence: Sentence, names: readonly string[]): IsOpen => {
58
- const closed = [...quotedSpans(sentence.text, QUOTATION_MARKS), ...furiganaSpans(sentence.text)];
59
- const named = nameSpans(sentence.text, names);
73
+ type Names = { readonly team: readonly string[]; readonly companyForms: readonly string[]; readonly linkTitles: readonly Span[] };
74
+
75
+ /** Spans placed in the source, placed in a sentence's text instead. */
76
+ const inSentence = (sentence: Sentence, spans: readonly Span[]): Span[] =>
77
+ spans.map((span) => ({ start: span.start - sentence.span.start, end: span.end - sentence.span.start }));
78
+
79
+ /**
80
+ * Whether a stretch of the sentence is outside a quotation, the team's names, a company's name (関東珪曹硝子㈱), a reading in
81
+ * brackets (HTTP(えいちてぃーてぃーぴー)) and a label opening the sentence ((答)): the first three keep their own spelling,
82
+ * a reading is not a spelling at all, and a label is a fixed short form.
83
+ */
84
+ const isOpenIn = (sentence: Sentence, names: Names): IsOpen => {
85
+ const closed = [
86
+ ...quotedSpans(sentence.text, QUOTATION_MARKS),
87
+ ...furiganaSpans(sentence.text),
88
+ ...japaneseCompanyNameSpans(sentence.text, names.companyForms),
89
+ ...inSentence(sentence, names.linkTitles),
90
+ ...leadingLabelSpans(sentence.text),
91
+ ];
92
+ const named = nameSpans(sentence.text, names.team);
60
93
  return (start, end) => !isWithinAny(closed, { start, end }) && !touchesAny(named, start, end);
61
94
  };
62
95
 
63
- /** A word and the two words before it, in its sentence. */
64
- type InContext = { readonly token: Token; readonly previous: Token | undefined; readonly before: Token | undefined };
96
+ /** A word, the two words before it and the two after it, in its sentence. */
97
+ type InContext = {
98
+ readonly token: Token;
99
+ readonly previous: Token | undefined;
100
+ readonly before: Token | undefined;
101
+ readonly following?: readonly Token[];
102
+ };
65
103
 
66
104
  /** A verb's て-form the tokenizer read as a conjunction (追って at the head of a sentence): a kanji stem and て or で. Connectives (そして, それで) are kana. */
67
105
  const TE_FORM_CONJUNCTION = /^\p{Script=Han}.*[てで]$/u;
@@ -99,13 +137,51 @@ const isKanaSuffix = ({ token, previous }: InContext): boolean =>
99
137
  const isIdiomVerb = ({ token, previous, before }: InContext, idioms: ReadonlySet<string>): boolean =>
100
138
  token.pos === "VERB" && previous?.pos === "ADP" && before !== undefined && idioms.has(`${before.surface}${previous.surface}${token.lemma ?? token.surface}`);
101
139
 
140
+ const TE = new Set(["て", "で"]);
141
+ const COMMA = new Set(["、", ",", ","]);
142
+
143
+ /**
144
+ * A listed verb's て-form that opens its sentence and is followed by a comma (あわせて、…): a conjunction ("in addition"), which
145
+ * many guides write in kana while the verb (日程を合わせる) keeps its kanji.
146
+ */
147
+ const isConjunctionUse = ({ token, previous, following }: InContext, conjunctions: ReadonlySet<string>): boolean =>
148
+ token.pos === "VERB" &&
149
+ conjunctions.has(token.lemma ?? "") &&
150
+ (previous === undefined || previous.pos === "PUNCT") &&
151
+ TE.has(following?.[0]?.surface ?? "") &&
152
+ COMMA.has(following?.[1]?.surface ?? "");
153
+
154
+ /** と, or と and は or も (〜ともみられる): the quotative particle before a verb of judging. */
155
+ const QUOTATIVE = "と";
156
+ const QUOTATIVE_TOPIC = new Set(["は", "も"]);
157
+ const PASSIVE = new Set(["られる", "れる"]);
158
+
159
+ const followsQuotative = (previous: Token | undefined, before: Token | undefined): boolean =>
160
+ previous?.pos === "ADP" && (previous.surface === QUOTATIVE || (QUOTATIVE_TOPIC.has(previous.surface) && before?.surface === QUOTATIVE));
161
+
162
+ /** The particles of the subject before an observing られる (増加がみられる, 発生はみられない); after を it is looking (映画を見られる). */
163
+ const OBSERVED_SUBJECT = new Set(["が", "は", "も"]);
164
+
165
+ const isObserved = (previous: Token | undefined, following: readonly Token[] | undefined): boolean =>
166
+ previous?.pos === "ADP" && OBSERVED_SUBJECT.has(previous.surface) && PASSIVE.has(following?.[0]?.lemma ?? "");
167
+
168
+ /** A listed verb after the quotative と (〜とみる) or observing with られる (増加がみられる): judging what is seen, not looking. */
169
+ const isJudgingUse = ({ token, previous, before, following }: InContext, judging: ReadonlySet<string>): boolean =>
170
+ token.pos === "VERB" && judging.has(token.lemma ?? "") && (followsQuotative(previous, before) || isObserved(previous, following));
171
+
172
+ /** The lexicons that set a verb's use apart: idioms (気をつける), conjunctions (あわせて、) and judging (〜とみられる). */
173
+ type Uses = { readonly idioms: ReadonlySet<string>; readonly conjunctions: ReadonlySet<string>; readonly judging: ReadonlySet<string> };
174
+
102
175
  /**
103
176
  * A helper verb or a dependent noun (見て下さい, その事) is written kana by many guides while the full word keeps its kanji (資料を下さい).
104
177
  * The two uses are compared apart, so a document that follows that convention is consistent. A suffix (業務用, 全員ぶん) is a third use:
105
- * it is not the dependent noun of the same reading (このように). The verb of an idiom (気をつける) is a fourth.
178
+ * it is not the dependent noun of the same reading (このように). The verb of an idiom (気をつける) is a fourth, and a
179
+ * て-form used as a conjunction (あわせて、) a fifth, and a verb of judging (〜とみられる) a sixth.
106
180
  */
107
- const useOf = (word: InContext, idioms: ReadonlySet<string>): string => {
181
+ const useOf = (word: InContext, { idioms, conjunctions, judging }: Uses): string => {
108
182
  if (isIdiomVerb(word, idioms)) return "idiom";
183
+ if (isConjunctionUse(word, conjunctions)) return "conjunction";
184
+ if (isJudgingUse(word, judging)) return "judging";
109
185
  if (isKanaSuffix(word)) return "suffix";
110
186
  if (!isHelper(word)) return "free";
111
187
  return word.token.pos === "NOUN" && word.token.features?.["NounType"] !== "Dependent" ? "suffix" : "bound";
@@ -129,17 +205,28 @@ const isCopulaReadAsVerb = ({ token, previous }: InContext): boolean =>
129
205
  type Skips = {
130
206
  readonly skip: ReadonlySet<string>;
131
207
  readonly idioms: ReadonlySet<string>;
208
+ readonly conjunctions: ReadonlySet<string>;
209
+ readonly judging: ReadonlySet<string>;
210
+ readonly comparative: ReadonlySet<string>;
132
211
  readonly wholeWords: ReadonlyMap<string, string>;
133
212
  readonly phraseSuffixes: ReadonlySet<string>;
213
+ /** The document's nouns, as documentNounKeys keys them. */
214
+ readonly nouns: ReadonlySet<string>;
134
215
  };
135
216
 
136
- const readingKeyOf = (word: InContext, { skip, idioms }: Skips): string | undefined => {
217
+ /** A listed word outside the comparative frame (担当の方に): the kanji there may be the person of the same reading. */
218
+ const isOutsideComparative = ({ token, following }: InContext, comparative: ReadonlySet<string>): boolean =>
219
+ comparative.has(token.lemma ?? "") && !COMPARATIVE_PARTICLES.has(following?.[0]?.surface ?? "");
220
+
221
+ const readingKeyOf = (word: InContext, skips: Skips): string | undefined => {
222
+ const { skip } = skips;
137
223
  const { token } = word;
138
224
  const lemma = token.lemma;
139
225
  if (!CONTENT.has(token.pos) || token.reading === undefined || lemma === undefined || !JAPANESE_WORD.test(lemma) || skip.has(lemma)) return undefined;
226
+ if (isOutsideComparative(word, skips.comparative)) return undefined;
140
227
  const reading = lemmaReading(token.surface, lemma, token.reading);
141
228
  if (reading === undefined || [...reading].length < MIN_READING || skip.has(reading) || isCutFromKatakana(word) || isCopulaReadAsVerb(word)) return undefined;
142
- return `${token.pos}|${useOf(word, idioms)}|${reading}`;
229
+ return `${token.pos}|${useOf(word, skips)}|${reading}`;
143
230
  };
144
231
 
145
232
  /**
@@ -160,7 +247,7 @@ const wholeWordOf = (
160
247
 
161
248
  /** Japanese words keyed by part of speech, use and the reading of the dictionary form, spelled as the dictionary form. */
162
249
  const readingWords = (sentence: Sentence, isOpen: IsOpen, skips: Skips): Placed[] => {
163
- const tokens = sentence.tokens ?? [];
250
+ const tokens = withNounsAfterParticles(sentence.tokens ?? []);
164
251
  const runs = wholeWordRuns(tokens, skips.wholeWords);
165
252
  const inRun = new Set(runs.flatMap(({ first, last }) => Array.from({ length: last - first + 1 }, (_, extra) => first + extra)));
166
253
  const whole = runs.flatMap((run) => wholeWordOf(sentence, tokens, run, isOpen, skips.wholeWords));
@@ -169,11 +256,11 @@ const readingWords = (sentence: Sentence, isOpen: IsOpen, skips: Skips): Placed[
169
256
  ...tokens.flatMap((written, at): Placed[] => {
170
257
  if (inRun.has(at)) return [];
171
258
  const next = tokens[at + 1];
172
- const token = asNounWhereNominal(written, next, skips.phraseSuffixes);
173
- const key = readingKeyOf({ token, previous: tokens[at - 1], before: tokens[at - 2] }, skips);
259
+ const token = asNounWhereNominal(written, next, skips.phraseSuffixes, skips.nouns);
260
+ const key = readingKeyOf({ token, previous: tokens[at - 1], before: tokens[at - 2], following: tokens.slice(at + 1, at + 3) }, skips);
174
261
  const local = token.span.start - sentence.span.start;
175
262
  if (key === undefined || token.lemma === undefined || !isOpen(local, local + token.surface.length)) return [];
176
- const compoundHead = token.pos === "NOUN" && next?.pos === "NOUN" && isTouching(token, next) && !skips.phraseSuffixes.has(next.surface);
263
+ const compoundHead = isCompoundHead(token, tokens, at, skips.phraseSuffixes);
177
264
  return [{ key, spelling: token.lemma, sentence, offset: token.span.start, compoundHead }];
178
265
  }),
179
266
  ];
@@ -300,7 +387,7 @@ const LINK_CHROME = /\]\([^)]*\)|\]\[[^\]]*\]|\[/gu;
300
387
  const withoutLinkChrome = (text: string): string => text.replaceAll(LINK_CHROME, (chrome) => " ".repeat(chrome.length));
301
388
 
302
389
  /** A body cell of a table read as a sentence of its own: the prose covers tables, so a cell's words (片栗粉 in a list of ingredients) are not in the sentences. Header rows stay out. */
303
- const cellPlace = (cell: TableCell, names: readonly string[]): Place => {
390
+ const cellPlace = (cell: TableCell, names: Names): Place => {
304
391
  const text = withoutLinkChrome(cell.text);
305
392
  const sentence: Sentence = { span: { start: cell.start, end: cell.end }, text, tokens: cell.tokens ?? [] };
306
393
  return { sentence, isOpen: isOpenIn(sentence, names), readsLatin: !DATA_KEY_CELL.test(text.trim()) };
@@ -312,18 +399,30 @@ const cellPlace = (cell: TableCell, names: readonly string[]): Place => {
312
399
  * document writes less is pointed at. No way is called right; limit is the largest share, in percent, the minority may have.
313
400
  */
314
401
  export const orthographicVariant: Detector = (doc, options): Finding[] => {
315
- const skips: Skips = {
316
- skip: new Set([...patternsOf(doc, DISTINCT, options.genre), ...patternsOf(doc, FUKUSHI, options.genre)]),
317
- idioms: new Set(patternsOf(doc, IDIOM, options.genre)),
318
- wholeWords: new Map((doc.lexicons[WHOLE_WORD] ?? []).map((entry) => [entry.pattern, entry.group ?? entry.pattern])),
319
- phraseSuffixes: new Set(patternsOf(doc, PHRASE_SUFFIX, options.genre)),
402
+ const names: Names = {
403
+ team: doc.names ?? [],
404
+ companyForms: (doc.lexicons["company-form"] ?? []).map((entry) => entry.pattern),
405
+ linkTitles: externalLinkTitleSpans(doc.source, doc.links),
320
406
  };
321
- const names = doc.names ?? [];
322
407
  const placed: Place[] = [
323
408
  ...doc.sentences.map((sentence) => ({ sentence, isOpen: isOpenIn(sentence, names), readsLatin: true })),
324
409
  ...(doc.tableCells?.() ?? []).map((cell) => cellPlace(cell, names)),
325
410
  ];
326
- const reading = byKanji(placed.flatMap(({ sentence, isOpen }) => readingWords(sentence, isOpen, skips)));
411
+ const phraseSuffixes = new Set(patternsOf(doc, PHRASE_SUFFIX, options.genre));
412
+ const skips: Skips = {
413
+ skip: new Set([...patternsOf(doc, DISTINCT, options.genre), ...patternsOf(doc, FUKUSHI, options.genre)]),
414
+ idioms: new Set(patternsOf(doc, IDIOM, options.genre)),
415
+ conjunctions: new Set(patternsOf(doc, CONJUNCTION, options.genre)),
416
+ judging: new Set(patternsOf(doc, JUDGING, options.genre)),
417
+ comparative: new Set(patternsOf(doc, COMPARATIVE, options.genre)),
418
+ wholeWords: new Map((doc.lexicons[WHOLE_WORD] ?? []).map((entry) => [entry.pattern, entry.group ?? entry.pattern])),
419
+ phraseSuffixes,
420
+ nouns: documentNounKeys(
421
+ placed.map(({ sentence }) => sentence.tokens ?? []),
422
+ phraseSuffixes,
423
+ ),
424
+ };
425
+ const reading = byKanji(placed.flatMap(({ sentence, isOpen }) => readingWords(withCutNounsJoined(sentence, skips.nouns), isOpen, skips)));
327
426
  const katakana = placed.flatMap(({ sentence, isOpen }) => katakanaWords(sentence, isOpen));
328
427
  const runs = placed.flatMap(({ sentence, isOpen }) => katakanaRunWords(sentence, isOpen));
329
428
  const dictionary = doc.dictionary?.();
@@ -8,6 +8,7 @@ import { digitRunAround, endsWithDivisionLabel, isNumberName, sequenceLabelStart
8
8
  import { isSpacedLocationPart, type FloorWords } from "../location-part.ts";
9
9
  import { isFieldSeparator, isNameSeparator, type OrganizationWords } from "../name-separator.ts";
10
10
  import { addressSpans, clockTimeSpans, identifierSpans, isInsideSpan } from "../spacing-code.ts";
11
+ import { followsHandle, isBoundSuffix, isJoinerSpace } from "../latin-word-boundary.ts";
11
12
 
12
13
  /** 書いた形の出現に、動詞の活用した形(行う → 行います)を足したもの。同じ位置は一度だけ。 */
13
14
  const avoidedStarts = (sentence: Sentence, entry: LexiconEntry, use: string): number[] => {
@@ -55,6 +56,8 @@ type NumberContext = NameContext & {
55
56
  readonly itemNumbers: ReadonlySet<string>;
56
57
  readonly floors: FloorWords;
57
58
  readonly organizations: OrganizationWords;
59
+ /** 日本語の句をつなぐ英語の語(or、vs.)と、英字の語に付ける接尾の語(版、化)。 */
60
+ readonly latinWords: { readonly joiners: ReadonlySet<string>; readonly boundSuffixes: ReadonlySet<string> };
58
61
  };
59
62
 
60
63
  /** 文頭の項目の番号の後ろと見る境目の位置の上限。番号は短く文の頭にあるので、これより後ろの境目は番号の後ろではない。長い文で文頭からの切り出しを繰り返さない。 */
@@ -101,11 +104,20 @@ type SentenceCodes = {
101
104
  * 「本社 5階」のように名前の後ろに空白で区切った階・部屋の番号の前の空白も、所在の組の区切りなので数えない(location-part.ts)。
102
105
  * 「経営企画部 IR担当」のように名前だけを並べた行で、名前と名前を分ける空白も、「所属:経済学科 1年」のように項目の値の組を分ける空白も数えない(name-separator.ts)。
103
106
  */
107
+ /** 項目の番号・識別子・チャンネルや宛先の名前(#pj_oss-team)の端の境目。どれも名前や番号を閉じる空白で、空け方の好みではない。 */
108
+ const closesName = (sentence: Sentence, boundary: Boundary, context: NumberContext, codes: SentenceCodes): boolean =>
109
+ followsItemNumber(sentence.text, boundary, context.itemNumbers) || besideSpan(codes.identifiers, boundary) || followsHandle(sentence.text, boundary);
110
+
104
111
  const isCounted = (sentence: Sentence, boundary: Boundary, context: NumberContext, codes: SentenceCodes): boolean => {
105
- if (followsItemNumber(sentence.text, boundary, context.itemNumbers) || besideSpan(codes.identifiers, boundary)) return false;
112
+ if (closesName(sentence, boundary, context, codes)) return false;
106
113
  if (boundary.kind !== "after-digit" && endsWithDivisionLabel(sentence.text.slice(0, boundary.offset), context.divisions)) return false;
107
114
  if (boundary.kind === "letter")
108
- return !besideSpan(codes.addresses, boundary) && !isNameSeparator(sentence.text, boundary, sentence.tokens, sentence.span.start, context.organizations);
115
+ return (
116
+ !besideSpan(codes.addresses, boundary) &&
117
+ !isNameSeparator(sentence.text, boundary, sentence.tokens, sentence.span.start, context.organizations) &&
118
+ !isJoinerSpace(sentence.text, boundary, context.latinWords.joiners) &&
119
+ !isBoundSuffix(sentence.text, boundary, sentence.tokens, sentence.span.start, context.latinWords.boundSuffixes)
120
+ );
109
121
  if (isInsideSpan(codes.clockTimes, digitBeside(boundary))) return false;
110
122
  const run = digitRunAround(sentence.text, digitBeside(boundary));
111
123
  if (run === undefined) return true;
@@ -180,6 +192,7 @@ export const latinSpacing: Detector = (doc, options): Finding[] => {
180
192
  itemNumbers: numberedItems(patternList(doc, "item-number"), doc.prose ?? doc.source),
181
193
  floors: { units: patternsOf(doc, "floor-unit"), levels: patternsOf(doc, "floor-level") },
182
194
  organizations: { units: patternsOf(doc, "organization-unit"), forms: patternList(doc, "company-form") },
195
+ latinWords: { joiners: patternsOf(doc, "latin-joiner"), boundSuffixes: patternsOf(doc, "latin-bound-suffix") },
183
196
  };
184
197
  const located: Located[] = doc.sentences.flatMap((sentence) => {
185
198
  const quoted = quotedSpans(sentence.text);
@@ -26,7 +26,7 @@ import {
26
26
  shapeOf,
27
27
  } from "./list-item.ts";
28
28
  import { listReader, type ItemList } from "./list-items.ts";
29
- import { APPOSITIVE_ANCHOR, isListConjunction, listSentenceOf, VERBAL, type ItemScope, type ListWords } from "./list-sentence.ts";
29
+ import { APPOSITIVE_ANCHOR, isListConjunction, listSentenceOf, NOMINAL, VERBAL, type ItemScope, type ListWords } from "./list-sentence.ts";
30
30
  import {
31
31
  after,
32
32
  contentOnlyWith,
@@ -42,9 +42,12 @@ import {
42
42
  some,
43
43
  wholeList,
44
44
  withoutFirst,
45
+ type Member,
45
46
  type View,
46
47
  } from "./list-view.ts";
47
48
  import { lowerBound, type TokenRange } from "./token-column.ts";
49
+ import { followsPostcode } from "./postcode-end.ts";
50
+ import { dashBreaks } from "./dash-break.ts";
48
51
 
49
52
  const EMPTY: TokenRange = { start: 0, end: 0 };
50
53
 
@@ -55,10 +58,35 @@ const commaBefore = (scope: ItemScope, at: number): boolean => scope.sentence.to
55
58
  * 節の最初の項目が前置詞・接続詞・副詞・to・過去分詞で始まり、次の項目と頭の形が違えば外す。
56
59
  * Quickly, quietly and carefully は残る。For managers, engineers and designers, も外れるが、前置詞のあとの名詞を
57
60
  * 項目と読むと、Over this period, the subcommittees and the full committee ... を並びと誤る。こちらのほうが多い。
61
+ * 順番の語(First,)のあとにもう一つ導入の句が続く(First, outside a block, …)ときは、順番の語を外してから確かめる。
58
62
  */
59
63
  const LEAD_POS = new Set(["ADP", "SCONJ", "ADV", "PART"]);
60
64
 
65
+ const isSequenceWord = (scope: ItemScope, token: Token | undefined): boolean => scope.sentence.words.sequence?.has(token?.surface.toLowerCase() ?? "") ?? false;
66
+
67
+ const SENTENCE_MARKS = new Set(["PUNCT", "SYM"]);
68
+
69
+ /**
70
+ * 順番の語と読点(First, / Next,)で始まる最初の項目から、その語を外した並び。解析器は First を形容詞と読み、読点で項目を切らないことがある。
71
+ * 文頭の語だけ。文の途中の first は項目のことがある(We support first, fallback, and legacy modes)。
72
+ * 次の項目も順番の語なら、順番の語の並び(first, second and third)なので外さない。
73
+ */
74
+ const withoutSequenceWord = (view: View): View | undefined => {
75
+ const { scope } = view.list;
76
+ const [first, second] = [firstOf(view), secondOf(view)];
77
+ if (first === undefined || second === undefined) return undefined;
78
+ const at = firstAt(scope, "open", first.item);
79
+ const { tokens } = scope.sentence;
80
+ const opensSentence = tokens.slice(0, at).every((token) => SENTENCE_MARKS.has(token.pos));
81
+ if (!opensSentence || !isSequenceWord(scope, tokens[at]) || tokens[at + 1]?.surface !== "," || isSequenceWord(scope, openingOf(scope, second.item)))
82
+ return undefined;
83
+ const rest = { start: at + 2, end: first.item.end };
84
+ return hasContent(scope, rest) ? { ...withoutFirst(view), pre: rest } : withoutFirst(view);
85
+ };
86
+
61
87
  const withoutLead = (view: View): View => {
88
+ const afterSequence = withoutSequenceWord(view);
89
+ if (afterSequence !== undefined) return withoutLead(afterSequence);
62
90
  const { scope } = view.list;
63
91
  const [first, second] = [firstOf(view), secondOf(view)];
64
92
  const opening = first === undefined ? undefined : openingOf(scope, first.item);
@@ -83,6 +111,31 @@ const afterClosedList = (view: View): View => {
83
111
  return hasContent(scope, rest) ? { ...after(view, closing), pre: rest } : withoutLead(after(view, closing));
84
112
  };
85
113
 
114
+ const opensAsNoun = (scope: ItemScope, item: TokenRange): boolean => {
115
+ const opening = openingOf(scope, item);
116
+ return opening !== undefined && (opening.pos === "DET" || NOMINAL.has(opening.pos));
117
+ };
118
+
119
+ const opensAsPredicate = (scope: ItemScope, item: TokenRange): boolean => {
120
+ const opening = openingOf(scope, item);
121
+ return opening !== undefined && VERBAL.has(opening.pos) && !isParticiple(opening);
122
+ };
123
+
124
+ /**
125
+ * 読点で挟んだ例の句が主語と述語のあいだにある形(Any services not listed above, such as connected services, are excluded and
126
+ * are not authorized)。句は読点の直後から始まり、例は名詞の句で、句の後ろの項目は動詞で始まる。主語も句も並びの項目ではなく、
127
+ * 並びがあるなら句の後ろから(are excluded and are not authorized は 2 つ)。例の中の分詞(connected)は名詞にかかる語で、
128
+ * 述語と同じ形と読まない。句の前は並びの最初の項目で、名詞の句(主語)。動詞で始まれば述語の並びの項目
129
+ * (Review backups, such as daily snapshots, update indexes and archive logs は 3 つ)。
130
+ */
131
+ const isAsideBeforePredicate = (view: View, phrase: Member, examples: TokenRange): boolean => {
132
+ const { scope } = view.list;
133
+ const [subject, next] = [firstOf(view), firstOf(after(view, phrase))];
134
+ if (subject === undefined || next === undefined || subject.j !== phrase.j - 1) return false;
135
+ const opensPhrase = (scope.sentence.exampleEnds[phrase.item.start]?.length ?? 0) > 0;
136
+ return opensPhrase && opensAsNoun(scope, subject.item) && opensAsNoun(scope, examples) && opensAsPredicate(scope, next.item);
137
+ };
138
+
86
139
  /**
87
140
  * 例の句(such as / including / e.g.)のあとが並び。句の前の項目は並びではない(the screen lock on your phone, such as a PIN or
88
141
  * phone-based fingerprint は 2 つ)。句の中の項目の形が揃わなければ句で切らない(materials such as green steel, utilizing ..., and
@@ -95,7 +148,9 @@ const fromExample = (view: View): View => {
95
148
  const { scope } = view.list;
96
149
  const examples = { start: exampleEnd(scope, phrase.item), end: phrase.item.end };
97
150
  if (hasListConjunction(scope, examples)) return view;
98
- const inPhrase = contentOnlyWith(after(view, phrase), examples);
151
+ const rest = after(view, phrase);
152
+ if (isAsideBeforePredicate(view, phrase, examples)) return rest;
153
+ const inPhrase = contentOnlyWith(rest, examples);
99
154
  return sameShapes(inPhrase) ? inPhrase : view;
100
155
  };
101
156
 
@@ -225,6 +280,15 @@ const itemsAgree = (scope: ItemScope, view: View, afterItem: TokenRange, shape:
225
280
  return clausesAgree && (!VERBAL.has(shape) || every(view, "hasVerb"));
226
281
  };
227
282
 
283
+ /** 否定で始まる項目(not cleaner)。 */
284
+ const CONTRAST = new Set(["not", "never"]);
285
+
286
+ /**
287
+ * and / or の前の項目が否定で始まれば、読点の前と対比している(more correct, not cleaner or more elegant)。
288
+ * and / or が結ぶのは否定の中の 2 つで、読点の前の項目と並ぶ 3 つではない。
289
+ */
290
+ const opensContrast = (scope: ItemScope, item: TokenRange): boolean => CONTRAST.has(openingOf(scope, item)?.surface.toLowerCase() ?? "");
291
+
228
292
  /**
229
293
  * 読点で区切った項目が and / or の前に 2 つ以上あり、最後の項目と and の後ろが同じ形のときだけ並列。
230
294
  * 導入の読点(After the review, the team fixed the bug and shipped it.)や、節をつなぐ読点
@@ -237,6 +301,7 @@ const listAt = (list: ItemList, at: number): boolean | undefined => {
237
301
  const items = fromParticiplePhrase(fromExample(afterClosedList(withoutLead(wholeList(list)))), afterItem);
238
302
  if (listContinues(scope, afterItem) || isAppositive(scope, at, items, afterItem) || insideLastItem(scope, at, items, afterItem)) return undefined;
239
303
  const last = lastOf(items);
304
+ if (last !== undefined && opensContrast(scope, last.item)) return undefined;
240
305
  const shape = last === undefined ? undefined : shapeOf(scope, last.item);
241
306
  if (sizeOf(items) < 2 || shape === undefined || shape !== shapeOf(scope, afterItem)) return undefined;
242
307
  return itemsAgree(scope, items, afterItem, shape) ? commaBefore(scope, at) : undefined;
@@ -252,9 +317,13 @@ export const listVerdicts = (tokens: readonly Token[], words: ListWords, source:
252
317
  if (!tokens.some(isJudgedConjunction)) return [];
253
318
  const sentence = listSentenceOf(tokens, words, source);
254
319
  const readItems = listReader(sentence);
320
+ const breaks = dashBreaks(tokens, source);
255
321
  return tokens.flatMap((token, at) => {
256
322
  if (!isJudgedConjunction(token, at)) return [];
257
- return [sentence.inCitedTitle(at) ? undefined : listAt(readItems(at), at)];
323
+ // 郵便番号で終わる住所のあとの and / or は、住所の行を区切る読点のあと。並びの読点ではない。
324
+ // 最後の読点のあとに前後を空けたダッシュがあれば(Washington, DC – The …)、読点はダッシュの前で閉じた日付行や見出しのもの。
325
+ const notList = sentence.inCitedTitle(at) || followsPostcode(source, token.span.start) || breaks[at] === true;
326
+ return [notList ? undefined : listAt(readItems(at), at)];
258
327
  });
259
328
  };
260
329
 
@@ -275,6 +344,8 @@ export const oxfordComma: Detector = (doc, options): Finding[] => {
275
344
  example: doc.lexicons["example-marker"] ?? [],
276
345
  pair: patternsOf(doc.lexicons["pair-opener"]),
277
346
  region: doc.lexicons["place-region"] ?? [],
347
+ titleCue: (doc.lexicons["title-cue"] ?? []).map((entry) => entry.pattern),
348
+ sequence: patternsOf(doc.lexicons["sequence-opener"]),
278
349
  };
279
350
  const judged = doc.sentences.flatMap((sentence) => {
280
351
  const oxford = oxfordIn(sentence.tokens ?? [], words, doc.source);
@@ -1,5 +1,5 @@
1
1
  import type { Detector, Finding, ProseDocument, Sentence } from "../plugin.ts";
2
- import { personMentions, personMinorities, type PersonMention, type PersonWords } from "../person-forms.ts";
2
+ import { personMentions, personMinorities, withoutOtherSenses, type PersonMention, type PersonWords } from "../person-forms.ts";
3
3
 
4
4
  const wordsOf = (doc: ProseDocument, words: PersonWords["words"]): PersonWords => ({
5
5
  words,
@@ -9,14 +9,16 @@ const wordsOf = (doc: ProseDocument, words: PersonWords["words"]): PersonWords =
9
9
 
10
10
  /**
11
11
  * One document naming itself (私たち / 弊社, 私 / 筆者) or its reader (you / one) two ways: the minority form of each slot.
12
- * Sentences in another language than the document's are left out; quotations are left out by personMentions.
12
+ * Sentences in another language than the document's are left out; quotations are left out by personMentions. A form the
13
+ * language package lists in person-other-sense (本社, also the head office) counts only where it is the usual form.
13
14
  */
14
15
  export const personMix: Detector = (doc, options): Finding[] => {
15
16
  const person = wordsOf(doc, options.lexicon ?? []);
16
17
  const entries: { readonly sentence: Sentence; readonly mention: PersonMention }[] = doc.sentences
17
18
  .filter((sentence) => sentence.embeddedLanguage === undefined)
18
19
  .flatMap((sentence) => personMentions(sentence.text, person).map((mention) => ({ sentence, mention })));
19
- return personMinorities(entries, options.limit).flatMap(({ odd, usual, of }) =>
20
+ const otherSenses = new Set((doc.lexicons["person-other-sense"] ?? []).map((entry) => entry.pattern));
21
+ return personMinorities(withoutOtherSenses(entries, otherSenses), options.limit).flatMap(({ odd, usual, of }) =>
20
22
  odd.map(({ sentence, mention }) => ({
21
23
  rule: "",
22
24
  severity: "info" as const,
@@ -1,5 +1,6 @@
1
- import type { Detector, DetectorOptions, Finding, Lexicon, ProseDocument, Sentence } from "../plugin.ts";
1
+ import type { Detector, DetectorOptions, Finding, Lexicon, LexiconEntry, ProseDocument, Sentence } from "../plugin.ts";
2
2
  import { entryEnds, entryIn } from "./lexicon-match.ts";
3
+ import { mentionCuesOf, onlyMentioned } from "./mentioned-phrase.ts";
3
4
  import { closingSentences } from "../closing-paragraph.ts";
4
5
 
5
6
  /** 冒頭は先頭 2 段落ぶん。「どの記事にも当てはまる書き出し」は冒頭にあるときだけ問題。 */
@@ -17,9 +18,12 @@ const inScope = (doc: ProseDocument, where: string | undefined): readonly Senten
17
18
 
18
19
  type Hit = { readonly sentence: Sentence; readonly matched: string };
19
20
 
20
- const hitsIn = (sentences: readonly Sentence[], lexicon: Lexicon): Hit[] =>
21
+ /** Whether the entry's words in the sentence count as a use. phrase-match counts every one. */
22
+ type IsUsed = (sentence: Sentence, entry: LexiconEntry) => boolean;
23
+
24
+ const hitsIn = (sentences: readonly Sentence[], lexicon: Lexicon, isUsed: IsUsed = () => true): Hit[] =>
21
25
  sentences.flatMap((sentence) => {
22
- const matched = lexicon.find((entry) => entryIn(sentence, entry));
26
+ const matched = lexicon.find((entry) => entryIn(sentence, entry) && isUsed(sentence, entry));
23
27
  return matched === undefined ? [] : [{ sentence, matched: matched.pattern }];
24
28
  });
25
29
 
@@ -33,9 +37,9 @@ const findingsOf = (hits: readonly Hit[], limit: number, count = hits.length): F
33
37
  values: { matched: hit.matched, count, limit, offset: hit.sentence.span.start },
34
38
  }));
35
39
 
36
- const phraseHits = (doc: ProseDocument, options: DetectorOptions): Hit[] => {
40
+ const phraseHits = (doc: ProseDocument, options: DetectorOptions, isUsed?: IsUsed): Hit[] => {
37
41
  const lexicon = options.lexicon ?? [];
38
- return lexicon.length === 0 ? [] : hitsIn(inScope(doc, options.where), lexicon);
42
+ return lexicon.length === 0 ? [] : hitsIn(inScope(doc, options.where), lexicon, isUsed);
39
43
  };
40
44
 
41
45
  /**
@@ -47,6 +51,13 @@ export const phraseMatch: Detector = (doc, options): Finding[] => {
47
51
  return hits.length < options.limit ? [] : findingsOf(hits, options.limit);
48
52
  };
49
53
 
54
+ /** phrase-match の、言葉として名指しただけの言い回し(the phrase "…", 「…」という言い方)を数えない版(mentioned-phrase.ts)。 */
55
+ export const phraseInUse: Detector = (doc, options): Finding[] => {
56
+ const cues = mentionCuesOf(doc.lexicons["mention-cue"] ?? []);
57
+ const hits = phraseHits(doc, options, (sentence, entry) => !onlyMentioned(sentence, entry, cues));
58
+ return hits.length < options.limit ? [] : findingsOf(hits, options.limit);
59
+ };
60
+
50
61
  type Uses = { readonly sentence: Sentence; readonly matched: string; readonly count: number };
51
62
 
52
63
  /**
@@ -29,6 +29,7 @@ const withoutClosers = (text: string): string => {
29
29
  /** Lexicon groups of placeholder-word. An entry without a group is a word written inside a template's brackets. */
30
30
  const MARKER = "marker";
31
31
  const INSTRUCTION = "instruction";
32
+ const LABEL = "label";
32
33
 
33
34
  const innerOf = (match: RegExpExecArray): string => (match[1] ?? match[2] ?? match[3] ?? "").trim().toLowerCase();
34
35
 
@@ -64,11 +65,24 @@ const markerSpans = (text: string, markers: Lexicon): Span[] => {
64
65
  return [{ start, end: start + withoutClosers(rest).length }];
65
66
  };
66
67
 
68
+ /**
69
+ * A template's instruction label left in the text ("OPTIONAL: General conclusions"): the label exactly as the lexicon
70
+ * writes it, in capitals, opening the line before a colon and some text. "Optional: bring a jacket" is a note, not a label.
71
+ */
72
+ const labelSpans = (line: string, labels: Lexicon): Span[] => {
73
+ const start = OPENING.exec(line)?.[0].length ?? 0;
74
+ const rest = line.slice(start);
75
+ const label = labels.find((entry) => rest.startsWith(entry.pattern));
76
+ if (label === undefined) return [];
77
+ const after = rest.slice(label.pattern.length);
78
+ return COLON_NEXT.test(after) && withoutClosers(after.replace(COLON_NEXT, "")) !== "" ? [{ start, end: start + rest.trimEnd().length }] : [];
79
+ };
80
+
67
81
  /** Each line of a sentence on its own: values a line apart ("TBD: owner" then "TBD: date") are two blanks, not one. */
68
- const lineMarkerSpans = (text: string, markers: Lexicon): Span[] =>
82
+ const lineMarkerSpans = (text: string, markers: Lexicon, labels: Lexicon): Span[] =>
69
83
  text.split("\n").flatMap((line, index, lines) => {
70
84
  const offset = lines.slice(0, index).reduce((sum, previous) => sum + previous.length + 1, 0);
71
- return markerSpans(line, markers).map((span) => ({ start: span.start + offset, end: span.end + offset }));
85
+ return [...markerSpans(line, markers), ...labelSpans(line, labels)].map((span) => ({ start: span.start + offset, end: span.end + offset }));
72
86
  });
73
87
 
74
88
  /** 文の中の、埋め忘れた雛形の空欄([Your Name]、【会社名】、(ここに会社名を書く)、TBD: …)の範囲。words は placeholder-word の語彙表。 */
@@ -76,9 +90,10 @@ export const placeholderSpans = (text: string, words: Lexicon): Span[] => {
76
90
  const bracketWords = words.filter((word) => word.group === undefined);
77
91
  const instructions = words.filter((word) => word.group === INSTRUCTION);
78
92
  const markers = words.filter((word) => word.group === MARKER);
93
+ const labels = words.filter((word) => word.group === LABEL);
79
94
  return [
80
95
  ...bracketedSpans(text, BRACKETED, (inner) => holdsWord(inner, bracketWords)),
81
96
  ...(instructions.length === 0 ? [] : bracketedSpans(text, PARENTHESIZED, (inner) => opensWith(inner, instructions))),
82
- ...lineMarkerSpans(text, markers),
97
+ ...lineMarkerSpans(text, markers, labels),
83
98
  ].toSorted((left, right) => left.start - right.start);
84
99
  };
@@ -5,6 +5,8 @@ import { escapeRegExp } from "../orthography.ts";
5
5
  * 定型文の書式で、略語ではない。繰り返しの語が、日付・時刻の単位の語(年、月、日)の前にあるか、
6
6
  * 区切り(/、:、-、.)で別の繰り返しの語か数字と繋がっているときだけ認める。単位の語は言語パッケージの語彙表から読む。
7
7
  * AI時代の AI や CI/CD の CD は、同じ文字の繰り返しではないので略語のまま数える。
8
+ * 単位の前には空白 1 つを挟んでもよい(XX 月 XX 日)。ひな形が名前の代わりに書く O か X を 4 つ以上並べた語(OOOO、XXXX)も、
9
+ * 単位が無くても略語ではない。3 つまで(AAA、XXX)は略語にもあり、ほかの文字の繰り返し(IIII、MMMMM)は崩れたローマ数字にもある。
8
10
  */
9
11
 
10
12
  type Span = { readonly start: number; readonly end: number };
@@ -14,6 +16,7 @@ const PART = String.raw`(?:[A-Z]{2,}|\d+)`;
14
16
  const SEPARATOR = "[//::.-]";
15
17
  const JOINED = new RegExp(String.raw`(?<![A-Za-z0-9_&])${PART}(?:${SEPARATOR}${PART})+(?![A-Za-z0-9_&])`, "gu");
16
18
  const CAPITALS = /[A-Z]+/gu;
19
+ const LONG_REPEAT = /(?<![A-Za-z0-9_&])(?<letter>[OX])\k<letter>{3,}(?![A-Za-z0-9_&])/gu;
17
20
 
18
21
  const isRepeated = (word: string): boolean => REPEATED.test(word);
19
22
 
@@ -30,9 +33,13 @@ const joinedSpans = (text: string): Span[] =>
30
33
 
31
34
  const beforeUnitSpans = (text: string, units: readonly string[]): Span[] => {
32
35
  if (units.length === 0) return [];
33
- const pattern = new RegExp(String.raw`(?<![A-Za-z0-9_&])[A-Z]{2,}(?=${units.map(escapeRegExp).join("|")})`, "gu");
36
+ const pattern = new RegExp(String.raw`(?<![A-Za-z0-9_&])[A-Z]{2,}(?= ?(?:${units.map(escapeRegExp).join("|")}))`, "gu");
34
37
  return [...text.matchAll(pattern)].filter((match) => isRepeated(match[0])).map(spanOf);
35
38
  };
36
39
 
37
- /** 文の中の、日付・時刻の書式に置いた大文字の範囲。units は日付・時刻の単位の語。 */
38
- export const placeholderSpans = (text: string, units: readonly string[]): Span[] => [...joinedSpans(text), ...beforeUnitSpans(text, units)];
40
+ /** 文の中の、日付・時刻の書式とひな形の名前に置いた大文字の範囲。units は日付・時刻の単位の語。 */
41
+ export const placeholderSpans = (text: string, units: readonly string[]): Span[] => [
42
+ ...joinedSpans(text),
43
+ ...beforeUnitSpans(text, units),
44
+ ...[...text.matchAll(LONG_REPEAT)].map(spanOf),
45
+ ];
@@ -0,0 +1,16 @@
1
+ // A postal address closed by its postcode right before an and / or ("… Upper Street, Leeds LS1 4AB, or email us"). The
2
+ // commas between the address's lines are the address's, not a list's. Pure.
3
+
4
+ /** UK (LS1 4AB, TW9 4DU, EC1A 1BB), US state and ZIP (IL 62701, DC 20001-1234), Canada (K1A 0B1). */
5
+ const POSTCODE = String.raw`(?:[A-Z]{1,2}\d[A-Z\d]? \d[A-Z]{2}|[A-Z]{2} \d{5}(?:-\d{4})?|[A-Z]\d[A-Z] \d[A-Z]\d)`;
6
+ /**
7
+ * The place the postcode is written after: a town (Leeds, Springfield,) or a province's code (ON). A code after a
8
+ * lower-case word ("model X1 4AB") is a product's, not an address's.
9
+ */
10
+ const PLACE = String.raw`(?<![\w-])(?:[A-Z][a-z]+|[A-Z]{2}),? `;
11
+ const POSTCODE_BEFORE = new RegExp(String.raw`${PLACE}${POSTCODE},?[ \t]*$`, "u");
12
+ /** How far back the place may start: a long town name, the longest postcode and its comma, with room for spacing. */
13
+ const REACH = 48;
14
+
15
+ /** Whether the text before offset ends with a place and its postcode, the comma after it allowed. */
16
+ export const followsPostcode = (source: string, offset: number): boolean => POSTCODE_BEFORE.test(source.slice(Math.max(0, offset - REACH), offset));
@@ -0,0 +1,18 @@
1
+ import type { ProseDocument } from "../plugin.ts";
2
+ import type { TotalWords } from "../structure/prose-total.ts";
3
+
4
+ const patternsOf = (doc: ProseDocument, id: string, group?: string): string[] =>
5
+ (doc.lexicons[id] ?? []).filter((entry) => group === undefined || entry.group === group).map((entry) => entry.pattern);
6
+
7
+ /** total-mismatch が文の中の合計と内訳を読む語。言語パッケージの語彙表から取る。 */
8
+ export const proseTotalWordsOf = (doc: ProseDocument): TotalWords => ({
9
+ totals: patternsOf(doc, "total-phrase"),
10
+ breakdowns: patternsOf(doc, "breakdown-phrase"),
11
+ discounts: patternsOf(doc, "discount-word"),
12
+ joiners: patternsOf(doc, "breakdown-gap-joiner"),
13
+ leads: patternsOf(doc, "total-breakdown-lead"),
14
+ partials: patternsOf(doc, "breakdown-partial-word"),
15
+ mainOnly: patternsOf(doc, "breakdown-partial-word", "main"),
16
+ backReferences: patternsOf(doc, "total-back-reference"),
17
+ roundedUnits: patternsOf(doc, "rounded-amount-unit"),
18
+ });