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
@@ -0,0 +1,94 @@
1
+ import type { Sentence, Span } from "../plugin.ts";
2
+
3
+ // 箇条書きの項目の文が、どの導入の文の下にあるか。「(3) If … no such resolution is made—\n(a) the Commissioner must issue …」の
4
+ // (a) は (3) の条件の下にあり、(a) だけを読むと条件が落ちる。
5
+
6
+ /** 導入の文の終わり。この後に項目が並ぶ("must include—"、"is made:"、「承認した場合:」)。 */
7
+ const LEAD_IN_END = /[::—–]\s*$/u;
8
+
9
+ /** 空行。そこで段落が改まり、導入はそこを越えて探さない。 */
10
+ const BLANK_LINE = /\n[^\S\n]*\n/u;
11
+
12
+ /** 項目の頭の印: 開き括弧、番号か記号(囲み数字や仮名は 1 字)、閉じ括弧か点。 */
13
+ const MARKER = /^\s*([(([[]?)([0-90-9]+|[a-zA-Za-zA-Z]+|[一二三四五六七八九十]+|\S)([))]\]..]?)/u;
14
+
15
+ /** 1 字のローマ数字。英字の並び((h) の次の (i))でもありうる。 */
16
+ const SINGLE_ROMAN = /^[ivxIVX]$/u;
17
+ const ROMAN = /^(?:[ivxlc]{2,}|[IVXLC]{2,})$/u;
18
+
19
+ const labelClass = (label: string): string => {
20
+ if (/^[0-90-9]+$/u.test(label)) return "1";
21
+ if (ROMAN.test(label) || SINGLE_ROMAN.test(label)) return /[a-z]/u.test(label) ? "i" : "I";
22
+ if (/^[a-za-z]+$/u.test(label)) return "a";
23
+ if (/^[A-ZA-Z]+$/u.test(label)) return "A";
24
+ if (/^[一二三四五六七八九十]+$/u.test(label)) return "一";
25
+ if (/^[\p{Script=Katakana}\p{Script=Hiragana}]$/u.test(label)) return "イ";
26
+ if (/^[①-⑳㉑-㉟㊱-㊿]$/u.test(label)) return "①";
27
+ if (/^[⑴-⒇]$/u.test(label)) return "⑴";
28
+ return label;
29
+ };
30
+
31
+ /** 項目の文の頭の印の範囲("(a)"、"①")。番号は文の中身ではない。項目の文でなければ undefined。 */
32
+ export const itemMarkerSpan = (sentence: Sentence): Span | undefined => {
33
+ const match = sentence.listItem === true ? MARKER.exec(sentence.text) : null;
34
+ return match === null ? undefined : { start: sentence.span.start, end: sentence.span.start + match[0].length };
35
+ };
36
+
37
+ const previousLetter = (label: string): string => String.fromCharCode(label.charCodeAt(0) - 1);
38
+
39
+ /**
40
+ * 項目の印の形("(1)"、"(a)"、"(i)"、"①"、"・")。番号そのものは数えない。
41
+ * 1 字の i・v・x は、同じ括弧の英字の項目がその前の字(h・u・w)で終わっていれば英字、でなければローマ数字。
42
+ */
43
+ export const markerShape = (text: string, lastLetters: ReadonlyMap<string, string>): { readonly shape: string; readonly letter?: string } | undefined => {
44
+ const match = MARKER.exec(text);
45
+ const [, open = "", label, close = ""] = match ?? [];
46
+ if (label === undefined) return undefined;
47
+ const letterShape = `${open}${/[a-z]/u.test(label) ? "a" : "A"}${close}`;
48
+ const continuesLetters = SINGLE_ROMAN.test(label) && lastLetters.get(letterShape) === previousLetter(label);
49
+ const shape = continuesLetters ? letterShape : `${open}${labelClass(label)}${close}`;
50
+ return shape === letterShape ? { shape, letter: label } : { shape };
51
+ };
52
+
53
+ type Entry = { readonly sentence: Sentence; readonly leadIns: readonly Sentence[] };
54
+
55
+ /** 段落の中で、項目の形ごとの最後の項目と、すぐ前の文が導入ならその文。 */
56
+ type Block = {
57
+ readonly lastByShape: Map<string, { readonly at: number; readonly entry: Entry }>;
58
+ readonly lastLetters: Map<string, string>;
59
+ leadIn: { readonly at: number; readonly entry: Entry } | undefined;
60
+ };
61
+
62
+ const newBlock = (): Block => ({ lastByShape: new Map(), lastLetters: new Map(), leadIn: undefined });
63
+
64
+ /** 項目の導入の文: すぐ前の文が導入で、それより後に同じ形の項目(兄弟)が無ければその文とその導入、でなければ兄弟の導入。 */
65
+ const leadInsOf = (block: Block, shape: string): readonly Sentence[] => {
66
+ const sibling = block.lastByShape.get(shape);
67
+ const leadIn = block.leadIn;
68
+ if (sibling !== undefined && (leadIn === undefined || sibling.at >= leadIn.at)) return sibling.entry.leadIns;
69
+ return leadIn === undefined ? [] : [leadIn.entry.sentence, ...leadIn.entry.leadIns];
70
+ };
71
+
72
+ /**
73
+ * 箇条書きの項目の文(listItem)ごとの、導入の文。近い順で、導入が項目なら、その導入も続ける。
74
+ * 導入は、並びの最初の項目のすぐ前の文で、「—」「:」「:」で終わるもの。同じ段落(空行を挟まない)の中で、同じ形の項目どうしは
75
+ * 同じ導入の下にある。
76
+ * sentences は文書の順。source は sentences の span の座標の文字列。
77
+ */
78
+ export const listLeadIns = (source: string, sentences: readonly Sentence[]): Map<Sentence, readonly Sentence[]> => {
79
+ const found = new Map<Sentence, readonly Sentence[]>();
80
+ let block = newBlock();
81
+ sentences.forEach((sentence, at) => {
82
+ const previous = sentences[at - 1];
83
+ if (previous !== undefined && BLANK_LINE.test(source.slice(previous.span.end, sentence.span.start))) block = newBlock();
84
+ const marker = sentence.listItem === true ? markerShape(sentence.text, block.lastLetters) : undefined;
85
+ const entry: Entry = { sentence, leadIns: marker === undefined ? [] : leadInsOf(block, marker.shape) };
86
+ if (marker !== undefined) {
87
+ found.set(sentence, entry.leadIns);
88
+ block.lastByShape.set(marker.shape, { at, entry });
89
+ if (marker.letter !== undefined) block.lastLetters.set(marker.shape, marker.letter.at(-1) ?? "");
90
+ }
91
+ block.leadIn = LEAD_IN_END.test(sentence.text) ? { at, entry } : undefined;
92
+ });
93
+ return found;
94
+ };
@@ -1,4 +1,6 @@
1
+ import { isMarkedNegation, negatedWords } from "./negated-act.ts";
1
2
  import type { Sentence, Span, Token } from "../plugin.ts";
3
+ import { itemMarkerSpan } from "./list-lead-in.ts";
2
4
 
3
5
  // 同じ主語と行為に、逆の様相(しなければならない と してはならない、may と must not)を書いた二つの文。
4
6
  // 主語と行為は、文の中身の語(名詞・固有名詞・動詞・形容詞)の集まりで近似する。様相の語そのものは数えない。
@@ -24,13 +26,21 @@ const OPPOSITE: Readonly<Record<string, readonly string[]>> = {
24
26
 
25
27
  const overlaps = (token: Token, spans: readonly Span[]): boolean => spans.some((span) => token.span.start < span.end && span.start < token.span.end);
26
28
 
27
- /** 文の中身の語を、原形の小文字で、重ねずに並べたもの。様相の語の範囲にかかる語は外す。 */
29
+ /**
30
+ * 文の中身の語を、原形の小文字で、重ねずに並べたもの。様相の語の範囲にかかる語は外す。
31
+ * 打ち消しの印の付いた機能語(negationsMarked)は、近くの中身の語に印を付ける(negatedWords)。様相の語の中の打ち消し(must not)は数えない。
32
+ */
28
33
  export const contentKey = (tokens: readonly Token[], markers: readonly Span[]): string =>
29
34
  [
30
35
  ...new Set(
31
- tokens
32
- .filter((token) => CONTENT.has(token.pos) && !overlaps(token, markers))
33
- .map((token) => (token.lemma !== undefined && token.lemma !== "" ? token.lemma : token.surface).toLowerCase()),
36
+ negatedWords(
37
+ tokens
38
+ .filter((token) => (CONTENT.has(token.pos) || isMarkedNegation(token)) && !overlaps(token, markers))
39
+ .map((token) => ({
40
+ word: (token.lemma !== undefined && token.lemma !== "" ? token.lemma : token.surface).toLowerCase(),
41
+ negation: !CONTENT.has(token.pos),
42
+ })),
43
+ ),
34
44
  ),
35
45
  ]
36
46
  .toSorted((left, right) => left.localeCompare(right, "en"))
@@ -51,11 +61,21 @@ const sentenceAt = (sentences: readonly Sentence[], offset: number): Sentence |
51
61
  return undefined;
52
62
  };
53
63
 
64
+ /** 中身の語の集まりを足し合わせたもの。並べ方は contentKey と同じ。 */
65
+ const joinedKey = (keys: readonly string[]): string =>
66
+ [...new Set(keys.flatMap((key) => (key === "" ? [] : key.split(" "))))].toSorted((left, right) => left.localeCompare(right, "en")).join(" ");
67
+
54
68
  /**
55
69
  * 様相の語を一つだけ持つ文の、様相と中身。二つ以上持つ文(shall do A and shall not do B)は、どの語がどの行為にかかるかが
56
70
  * 中身の語の集まりからは分からないので外す。品詞の無い文も外す。
71
+ * leadIns は箇条書きの項目の文の導入の文(listLeadIns)。項目の中身には導入の中身の語を足す。導入の条件("If … is made—")は
72
+ * 項目の行為の条件なので、違う導入の下の項目どうしは、同じ行為を決めていない。
57
73
  */
58
- export const modalStatements = (obligations: readonly Obligation[], sentences: readonly Sentence[]): ModalStatement[] => {
74
+ export const modalStatements = (
75
+ obligations: readonly Obligation[],
76
+ sentences: readonly Sentence[],
77
+ leadIns: ReadonlyMap<Sentence, readonly Sentence[]> = new Map(),
78
+ ): ModalStatement[] => {
59
79
  const bySentence = new Map<Sentence, Obligation[]>();
60
80
  obligations.forEach((obligation) => {
61
81
  const sentence = sentenceAt(sentences, obligation.start);
@@ -64,11 +84,26 @@ export const modalStatements = (obligations: readonly Obligation[], sentences: r
64
84
  if (found === undefined) bySentence.set(sentence, [obligation]);
65
85
  else found.push(obligation);
66
86
  });
87
+ /** 様相の語と項目の印を除いた中身。 */
88
+ const keyOf = (sentence: Sentence, tokens: readonly Token[], markers: readonly Span[]): string => {
89
+ const item = itemMarkerSpan(sentence);
90
+ return contentKey(tokens, item === undefined ? markers : [...markers, item]);
91
+ };
92
+ const leadInKeys = new Map<Sentence, string>();
93
+ const leadInKey = (sentence: Sentence): string => {
94
+ const known = leadInKeys.get(sentence);
95
+ if (known !== undefined) return known;
96
+ const key = sentence.tokens === undefined ? "" : keyOf(sentence, sentence.tokens, bySentence.get(sentence) ?? []);
97
+ leadInKeys.set(sentence, key);
98
+ return key;
99
+ };
67
100
  return [...bySentence].flatMap(([sentence, found]) => {
68
101
  const [only] = found;
69
102
  if (found.length !== 1 || only === undefined || sentence.tokens === undefined) return [];
70
- const key = contentKey(sentence.tokens, [only]);
71
- return key.split(" ").length < MIN_CONTENT_WORDS ? [] : [{ offset: sentence.span.start, type: only.type, marker: only.marker, key }];
103
+ const own = keyOf(sentence, sentence.tokens, [only]);
104
+ if (own.split(" ").length < MIN_CONTENT_WORDS) return [];
105
+ const key = joinedKey([own, ...(leadIns.get(sentence) ?? []).map(leadInKey)]);
106
+ return [{ offset: sentence.span.start, type: only.type, marker: only.marker, key }];
72
107
  });
73
108
  };
74
109
 
@@ -0,0 +1,49 @@
1
+ import type { Lexicon, Sentence, Token } from "../plugin.ts";
2
+
3
+ // 行為や条件の中の打ち消し("goods that do not conform"、「承認しなかった場合」)。打ち消しの語は中身の語ではないが、
4
+ // 打ち消しだけが違う二つの文は、違うことを決めている。
5
+
6
+ /** 打ち消しの語に付ける印(Token.features の名前)。 */
7
+ const NEGATION_FEATURE = "negation";
8
+
9
+ /** 打ち消しを受けた語の印。語の後ろに付ける。 */
10
+ export const NEGATED = "¬";
11
+
12
+ /** 語彙表の打ち消しの語(group の無いもの。接頭の「不」「未」は語の一部なので見ない)。英語は小文字で照らす。 */
13
+ export const negationWords = (lexicon: Lexicon | undefined): ReadonlySet<string> =>
14
+ new Set((lexicon ?? []).filter((entry) => entry.group === undefined).map((entry) => entry.pattern.toLowerCase()));
15
+
16
+ const isNegation = (token: Token, words: ReadonlySet<string>): boolean =>
17
+ words.has(token.surface.toLowerCase()) || (token.lemma !== undefined && words.has(token.lemma.toLowerCase()));
18
+
19
+ export const isMarkedNegation = (token: Token): boolean => token.features?.[NEGATION_FEATURE] !== undefined;
20
+
21
+ /** 打ち消しの語に印を付けた文。品詞の無い文はそのまま。 */
22
+ export const negationsMarked = (sentences: readonly Sentence[], words: ReadonlySet<string>): Sentence[] =>
23
+ sentences.map((sentence) =>
24
+ sentence.tokens === undefined
25
+ ? sentence
26
+ : {
27
+ ...sentence,
28
+ tokens: sentence.tokens.map((token) => (isNegation(token, words) ? { ...token, features: { ...token.features, [NEGATION_FEATURE]: "yes" } } : token)),
29
+ },
30
+ );
31
+
32
+ type Placed = { readonly out: readonly string[]; readonly pending: boolean };
33
+
34
+ /**
35
+ * 語の並びの打ち消しを、すぐ前の語(文頭なら次の語)に NEGATED として付けたもの。どの語にかかるかは読まない。
36
+ * 打ち消しのある文と無い文を分けるための印で、二つ重なっても一つにする。
37
+ */
38
+ export const negatedWords = (words: readonly { readonly word: string; readonly negation: boolean }[]): string[] =>
39
+ words
40
+ .reduce<Placed>(
41
+ ({ out, pending }, { word, negation }) => {
42
+ if (!negation) return { out: [...out, pending ? `${word}${NEGATED}` : word], pending: false };
43
+ const last = out.at(-1);
44
+ if (last === undefined) return { out, pending: true };
45
+ return { out: last.endsWith(NEGATED) ? out : [...out.slice(0, -1), `${last}${NEGATED}`], pending: false };
46
+ },
47
+ { out: [], pending: false },
48
+ )
49
+ .out.slice();
@@ -2,10 +2,12 @@ import type { Span, StructureNode } from "../plugin.ts";
2
2
  import { inDocumentOrder, type StructureIssue } from "./issues.ts";
3
3
  import { numbersQuotedInside } from "./quoted-number.ts";
4
4
  import { isVersionHistory } from "./version-order.ts";
5
+ import { withRepeatsNamed } from "./repeated-number.ts";
5
6
 
6
7
  const labelOf = (node: StructureNode): string => String(node.attrs["label"] ?? node.address);
7
8
 
8
- type Ordered = { readonly node: StructureNode; readonly ordinal: number; readonly last: number };
9
+ /** sideSteps は、この番号の直前にある番号の無い手順(GOV.UK の「and」)の数。それぞれが番号を一つ使っていてよい。 */
10
+ type Ordered = { readonly node: StructureNode; readonly ordinal: number; readonly last: number; readonly sideSteps: number };
9
11
 
10
12
  const OPENING_BRACKET = /^[([{〔【〈《]/u;
11
13
 
@@ -17,15 +19,21 @@ const isBracketed = (label: string): boolean => OPENING_BRACKET.test(label.norma
17
19
  * 法令の第 1 項は番号が無いので、その号(一、二)と第 2 項(2)は同じ条の直下に並ぶ。深さで分けないと「二の次が2」に見える。
18
20
  * 社内規程は号の(1)(2)と第 2 項の「2」を同じ深さに読むことがあるので、括弧で囲んだ番号は囲まない番号と別の並びにする。
19
21
  */
20
- const sequencesOf = (parent: StructureNode, quoting: ReadonlySet<StructureNode>): Ordered[][] => {
22
+ const sequencesOf = (parent: StructureNode, quoting: ReadonlySet<StructureNode>, isSideStep: (node: StructureNode) => boolean): Ordered[][] => {
21
23
  const groups = new Map<string, Ordered[]>();
24
+ let sideSteps = 0;
22
25
  parent.children.forEach((node) => {
23
- if (node.ordinal === undefined || quoting.has(node)) return;
26
+ if (node.ordinal === undefined) {
27
+ if (isSideStep(node)) sideSteps += 1;
28
+ return;
29
+ }
30
+ if (quoting.has(node)) return;
24
31
  const key = `${node.kind}/${String(node.level ?? "")}/${isBracketed(labelOf(node)) ? "bracketed" : "bare"}`;
25
32
  // 配列を作り直さずに足す。条が何千もある法令で二乗にしない。
26
33
  const group = groups.get(key) ?? [];
27
- group.push({ node, ordinal: node.ordinal, last: node.ordinalTo ?? node.ordinal });
34
+ group.push({ node, ordinal: node.ordinal, last: node.ordinalTo ?? node.ordinal, sideSteps });
28
35
  groups.set(key, group);
36
+ sideSteps = 0;
29
37
  });
30
38
  return [...groups.values()];
31
39
  };
@@ -59,6 +67,7 @@ const breaksIn =
59
67
  // 範囲をまとめた行(第四十三条から第五十五条まで)の次は、範囲の最後から数える。
60
68
  if (previous === undefined || current.ordinal === previous.last + 1 || current.ordinal === 1) return [];
61
69
  if (current.ordinal > previous.last + 1 && unreadBetween(unread, previous, current)) return [];
70
+ if (current.ordinal > previous.last + 1 && current.ordinal <= previous.last + 1 + current.sideSteps) return [];
62
71
  return [
63
72
  {
64
73
  offset: current.node.span.start,
@@ -73,13 +82,19 @@ const breaksIn =
73
82
  * 1 に戻った番号は新しい並びの始まりとして扱うので、「(a) の後の (a)」の重なりは見逃す。
74
83
  * 同じ番号の節を中に持つ節(ほかの文書の条を引いた手本の見出し)は、並びに入れない。
75
84
  * 変更履歴の版の見出し(## 3.1.0)は番号の並びではない。版の順番は version-order が見る。
85
+ * 同じ番号が二度続いて次が飛ぶ(4.1、4.1、4.3)ものは、重なりと抜けに分けず、二つ目で一度だけ言う(repeated-number.ts)。
76
86
  * unread は、読み手には見えるが木に入らない範囲(Markdown の HTML ブロックの中の文字)を、始まりの順に並べたもの。
87
+ * isSideStep は、番号の代わりに「and」と書いた手順(前の手順と並べて行う)。その数だけ、次の番号は飛んでよい。
77
88
  */
78
- export const numberingBreaks = (tree: StructureNode, unread: readonly Span[] = []): StructureIssue[] => {
89
+ export const numberingBreaks = (
90
+ tree: StructureNode,
91
+ unread: readonly Span[] = [],
92
+ isSideStep: (node: StructureNode) => boolean = () => false,
93
+ ): StructureIssue[] => {
79
94
  const quoting = numbersQuotedInside(tree);
80
- return inDocumentOrder(tree)
81
- .flatMap((parent) => sequencesOf(parent, quoting))
95
+ const breaks = inDocumentOrder(tree)
96
+ .flatMap((parent) => sequencesOf(parent, quoting, isSideStep))
82
97
  .filter((sequence) => !isVersionHistory(sequence.map((ordered) => labelOf(ordered.node))))
83
- .flatMap(breaksIn(unread))
84
- .toSorted((left, right) => left.offset - right.offset);
98
+ .flatMap(breaksIn(unread));
99
+ return withRepeatsNamed(tree, quoting, breaks, unread);
85
100
  };
@@ -1,4 +1,5 @@
1
1
  import type { StructureIssue } from "./issues.ts";
2
+ import { coarsestStep, roundingAllowance } from "./rounded-amount.ts";
2
3
  import { shownTotal, type Amount } from "./total.ts";
3
4
 
4
5
  /**
@@ -22,6 +23,10 @@ export type TotalWords = {
22
23
  readonly leads: readonly string[];
23
24
  /** 合計と内訳のあいだにあれば、後ろの金額は合計の内訳のすべてとは限らないと読む語(including、うち、or)。 */
24
25
  readonly partials: readonly string[];
26
+ /** partials のうち、並べた金額が主なものだけだと言う語(主な、mainly)。合計の前に並べた内訳の前に書いても、内訳は合計のすべてではない。 */
27
+ readonly mainOnly: readonly string[];
28
+ /** 丸めた桁で書く金額の単位(百万円、千円、million)。どの金額もこの単位なら、丸めのずれ(内訳の数 − 1 桁まで)は合うとみなす。 */
29
+ readonly roundedUnits: readonly string[];
25
30
  /** 次の文で内訳の語の前に書いて、前の文の合計を指す語(This、It、その)。何も書かなくてもよい。 */
26
31
  readonly backReferences: readonly string[];
27
32
  };
@@ -85,13 +90,15 @@ const signedValues = (source: string, parts: readonly Amount[], from: number, di
85
90
 
86
91
  type Breakdown = { readonly total: Amount; readonly parts: readonly Amount[]; readonly from: number; readonly nearEnd: boolean };
87
92
 
88
- const mismatch = (source: string, breakdown: Breakdown, discounts: readonly string[]): StructureIssue[] => {
93
+ const mismatch = (source: string, breakdown: Breakdown, words: TotalWords): StructureIssue[] => {
89
94
  const { total, from, nearEnd } = breakdown;
90
95
  const parts = breakdown.parts.filter((part) => part.unit === total.unit);
91
96
  if (parts.length < MIN_PARTS) return [];
92
- const values = signedValues(source, parts, from, discounts);
97
+ const values = signedValues(source, parts, from, words.discounts);
93
98
  const written = centsOf(total);
94
- if (nearRuns(values, nearEnd).some((run) => sumOf(run) === written)) return [];
99
+ const step = coarsestStep(source, [total, ...parts], words.roundedUnits) * CENTS;
100
+ const matches = (run: readonly number[]): boolean => Math.abs(sumOf(run) - written) <= Math.round(roundingAllowance(step, run.length));
101
+ if (nearRuns(values, nearEnd).some(matches)) return [];
95
102
  return [{ offset: total.offset, values: shownTotal(source, total, sumOf(values)) }];
96
103
  };
97
104
 
@@ -106,6 +113,10 @@ const breakdownEnd = (source: string, total: Amount, marker: Span, sentence: Spa
106
113
 
107
114
  const inside = (amounts: readonly Amount[], start: number, end: number): Amount[] => amounts.filter((amount) => amount.offset >= start && amount.end <= end);
108
115
 
116
+ /** 内訳の前(start から end まで)に、主なものだけを並べると言う語があるか(「主な設備投資は、…」「主な内訳は」)。 */
117
+ const saysMainOnly = (source: string, start: number, end: number, words: TotalWords): boolean =>
118
+ phraseSpans(source.slice(start, end), start, words.mainOnly).length > 0;
119
+
109
120
  /** 合計の語のすぐ後ろの金額を、その前の内訳と比べる。内訳は、前の合計の語か内訳の語より後ろから。 */
110
121
  const totalsAfterParts = (source: string, sentence: Span, amounts: readonly Amount[], words: TotalWords): StructureIssue[] => {
111
122
  const text = source.slice(sentence.start, sentence.end);
@@ -115,7 +126,9 @@ const totalsAfterParts = (source: string, sentence: Span, amounts: readonly Amou
115
126
  const total = amounts.find((amount) => amount.offset >= marker.end && isTotalGap(gapBefore(source, marker.end, amount)));
116
127
  if (total === undefined) return [];
117
128
  const from = Math.max(sentence.start, markers[index - 1]?.end ?? 0, ...breakdowns.filter((span) => span.end <= marker.start).map((span) => span.end));
118
- return mismatch(source, { total, parts: inside(amounts, from, marker.start), from, nearEnd: true }, words.discounts);
129
+ const parts = inside(amounts, from, marker.start);
130
+ if (saysMainOnly(source, from, parts[0]?.offset ?? from, words)) return [];
131
+ return mismatch(source, { total, parts, from, nearEnd: true }, words);
119
132
  });
120
133
  };
121
134
 
@@ -126,9 +139,10 @@ const totalsBeforeParts = (source: string, sentence: Span, amounts: readonly Amo
126
139
  return phraseSpans(text, sentence.start, words.breakdowns).flatMap((marker) => {
127
140
  const total = amounts.findLast((amount) => amount.end <= marker.start);
128
141
  if (total === undefined || phraseSpans(source.slice(total.end, marker.start), total.end, words.joiners).length > 0) return [];
142
+ if (saysMainOnly(source, total.end, marker.start, words)) return [];
129
143
  const nextTotal = totalMarkers.find((span) => span.start >= marker.end)?.start ?? sentence.end;
130
144
  const parts = inside(amounts, marker.end, Math.min(nextTotal, breakdownEnd(source, total, marker, sentence)));
131
- return mismatch(source, { total, parts, from: marker.end, nearEnd: false }, words.discounts);
145
+ return mismatch(source, { total, parts, from: marker.end, nearEnd: false }, words);
132
146
  });
133
147
  };
134
148
 
@@ -152,7 +166,7 @@ const fullBreakdown = (source: string, total: Amount, listed: readonly Amount[],
152
166
  if (last === undefined || listed.some((part) => part.unit !== total.unit)) return [];
153
167
  const between = source.slice(total.end, last.offset);
154
168
  if (PERCENT.test(between) || phraseSpans(between, total.end, words.partials).length > 0) return [];
155
- return mismatch(source, { total, parts: listed, from, nearEnd: false }, words.discounts);
169
+ return mismatch(source, { total, parts: listed, from, nearEnd: false }, words);
156
170
  };
157
171
 
158
172
  /** 文の中で、合計の語の金額のすぐ後ろに内訳を始める記号や語(": ")があれば、その後ろから文の終わりか次の記号までが内訳。 */
@@ -0,0 +1,110 @@
1
+ import type { Span, StructureNode } from "../plugin.ts";
2
+ import type { StructureIssue } from "./issues.ts";
3
+ import { isVersionHistory } from "./version-order.ts";
4
+
5
+ type Placed = { readonly node: StructureNode; readonly parent: StructureNode; readonly ordinal: number };
6
+
7
+ const labelOf = (node: StructureNode): string => String(node.attrs["label"] ?? node.address);
8
+
9
+ /** 「4.1」「4.1」の、最後の番号より前(「4」)。点で区切った番号でなければ無い。 */
10
+ const DOTTED = /^(.*\d)[..](\d+)$/u;
11
+ const dottedPrefixOf = (label: string): string | undefined => DOTTED.exec(label.normalize("NFKC").trim())?.[1];
12
+
13
+ const OPENING_BRACKET = /^[([{〔【〈《]/u;
14
+
15
+ /**
16
+ * 番号の並びの単位。点で区切った番号(4.1、4.3)は、前の番号(4)が同じものどうしを、親が違っても一つの並びに読む。
17
+ * 番号の無い見出し(## Approved Office Supplies List)が間に入ると、4.3 は 4.1 と別の親の下に入るが、読み手には 4 の続きに見える。
18
+ * それ以外の番号(第3条、(a))は、同じ親の子どうしだけを並べる。
19
+ */
20
+ const familyOf = (placed: Placed, parentIds: ReadonlyMap<StructureNode, number>): string => {
21
+ const label = labelOf(placed.node);
22
+ const shape = `${placed.node.kind}/${String(placed.node.level ?? "")}/${OPENING_BRACKET.test(label.normalize("NFKC")) ? "bracketed" : "bare"}`;
23
+ const prefix = dottedPrefixOf(label);
24
+ return prefix === undefined ? `${shape}/parent:${String(parentIds.get(placed.parent))}` : `${shape}/dotted:${prefix}`;
25
+ };
26
+
27
+ const placedNodes = (tree: StructureNode, quoting: ReadonlySet<StructureNode>): Placed[] => {
28
+ const placed: Placed[] = [];
29
+ const pending: StructureNode[] = [tree];
30
+ for (let parent = pending.pop(); parent !== undefined; parent = pending.pop()) {
31
+ parent.children.forEach((node) => {
32
+ pending.push(node);
33
+ if (node.ordinal !== undefined && node.ordinalTo === undefined && !quoting.has(node)) placed.push({ node, parent, ordinal: node.ordinal });
34
+ });
35
+ }
36
+ return placed.toSorted((left, right) => left.node.span.start - right.node.span.start);
37
+ };
38
+
39
+ const familiesOf = (placed: readonly Placed[]): Placed[][] => {
40
+ const parentIds = new Map<StructureNode, number>();
41
+ placed.forEach(({ parent }) => parentIds.set(parent, parentIds.get(parent) ?? parentIds.size));
42
+ const families = new Map<string, Placed[]>();
43
+ placed.forEach((entry) => {
44
+ const key = familyOf(entry, parentIds);
45
+ const family = families.get(key) ?? [];
46
+ family.push(entry);
47
+ families.set(key, family);
48
+ });
49
+ return [...families.values()];
50
+ };
51
+
52
+ /** 番号の最後の数字を一つ進めた書き方(4.1 → 4.2、Section 2 → Section 3)。数字で書いていなければ、進めた番号だけ。 */
53
+ export const nextLabelOf = (label: string, ordinal: number): string => {
54
+ const normalized = label.normalize("NFKC");
55
+ const digits = [...normalized.matchAll(/\d+/gu)].at(-1);
56
+ if (digits === undefined || Number(digits[0]) !== ordinal) return String(ordinal + 1);
57
+ return `${normalized.slice(0, digits.index)}${String(ordinal + 1)}${normalized.slice(digits.index + digits[0].length)}`;
58
+ };
59
+
60
+ /** explains は、この誤りで説明がつく、並びの指摘の位置(二つ目、同じ親の下なら次の番号)。 */
61
+ export type RepeatedNumber = { readonly explains: readonly number[]; readonly between: Span; readonly issue: StructureIssue };
62
+
63
+ const repeatsIn = (family: readonly Placed[]): RepeatedNumber[] =>
64
+ family.flatMap((first, index) => {
65
+ const second = family[index + 1];
66
+ const next = family[index + 2];
67
+ if (second === undefined || next === undefined || second.parent !== first.parent) return [];
68
+ if (second.ordinal !== first.ordinal || next.ordinal !== first.ordinal + 2) return [];
69
+ const label = labelOf(second.node);
70
+ return [
71
+ {
72
+ between: { start: second.node.span.start, end: next.node.span.start },
73
+ explains: next.parent === second.parent ? [second.node.span.start, next.node.span.start] : [second.node.span.start],
74
+ issue: {
75
+ offset: second.node.span.start,
76
+ variant: "repeated",
77
+ values: { previous: labelOf(first.node), label, expected: first.ordinal + 1, found: second.ordinal, probably: nextLabelOf(label, second.ordinal) },
78
+ },
79
+ },
80
+ ];
81
+ });
82
+
83
+ /**
84
+ * 同じ番号が二度続き、その次が一つ飛ぶ(4.1、4.1、4.3)。二つ目は、振り間違えた 4.2 である見込みが高い。
85
+ * 重なりと抜けの二つに見えるが、誤りは一つなので、二つ目の番号で一度だけ言う。
86
+ * 同じ親の下で隣り合う二つが同じ番号のときだけ。変更履歴の版の見出し(## 3.1.0)は番号の並びではないので見ない。
87
+ * 別の部の 1.1 から振り直した並び(1.1、1.2 の後の 1.1、1.2)は、次が飛ばないので言わない。
88
+ */
89
+ export const repeatedNumbers = (tree: StructureNode, quoting: ReadonlySet<StructureNode>): RepeatedNumber[] =>
90
+ familiesOf(placedNodes(tree, quoting))
91
+ .filter((family) => !isVersionHistory(family.map(({ node }) => labelOf(node))))
92
+ .flatMap(repeatsIn);
93
+
94
+ /**
95
+ * 並びの抜けと重なり(issues)のうち、同じ番号が二度続いたもの(repeatedNumbers)で説明がつくものを、その一つにまとめる。
96
+ * 二つ目と次の番号のあいだに読めなかった範囲(unread)があれば、飛んだ番号はそこにあるかもしれないので、まとめずに元の指摘を残す。
97
+ * 二つ目の番号への指摘は置き換え、次の番号への抜けの指摘は、二つ目と同じ親の下にあるときだけ(二つ目の次として数えたもの)消す。
98
+ */
99
+ export const withRepeatsNamed = (
100
+ tree: StructureNode,
101
+ quoting: ReadonlySet<StructureNode>,
102
+ issues: readonly StructureIssue[],
103
+ unread: readonly Span[] = [],
104
+ ): StructureIssue[] => {
105
+ const repeats = repeatedNumbers(tree, quoting).filter(({ between }) => !unread.some((span) => span.start > between.start && span.start < between.end));
106
+ const explained = new Set(repeats.flatMap(({ explains }) => explains));
107
+ return [...issues.filter((issue) => !explained.has(issue.offset)), ...repeats.map(({ issue }) => issue)].toSorted(
108
+ (left, right) => left.offset - right.offset,
109
+ );
110
+ };
@@ -0,0 +1,55 @@
1
+ import type { Amount } from "./total.ts";
2
+
3
+ /**
4
+ * 丸めた単位(百万円、千円、億円、$3.1 million)で書いた金額の、最後の桁一つ分。丸めて書いた内訳と合計は、
5
+ * 四捨五入でも切り捨てでも切り上げでも、内訳の数 − 1 桁までずれる(3,074百万円 + 2,434百万円 + 1,146百万円 と 総額6,655百万円)。
6
+ * 有効数字が 3 桁以上の金額だけを丸めたと読む。最後の桁一つ分がその金額の 1% 以下になり、1億円 + 2億円 = 4億円 のような
7
+ * 金額と同じ大きさのずれを丸めとは読まない。
8
+ */
9
+
10
+ /** 書いた数(6,655、3.1)。漢数字だけの金額は読まない。 */
11
+ const NUMERAL = /\d[\d,,]*(?:[..]\d+)?/u;
12
+ /** 金額のすぐ後ろに書いた単位の語($3.1 million の million)までのあいだ。 */
13
+ const UNIT_AFTER = /^[ \t]?([A-Za-z]+)/u;
14
+ const DECIMAL_BASE = 10;
15
+ /** 金額の後ろで単位の語を探す長さ。 */
16
+ const UNIT_REACH = 16;
17
+ /** 丸めたと読む金額の、書いた数の有効数字の最小の桁数。 */
18
+ const MIN_SIGNIFICANT_DIGITS = 3;
19
+
20
+ /** 書いた数と、その小数の桁。 */
21
+ type Numeral = { readonly value: number; readonly decimals: number; readonly significant: number };
22
+
23
+ /** 書いた数と、その小数の桁と有効数字の桁数(頭の 0 を除いた数字の数。6,655 なら 4、3.1 なら 2、0.25 なら 2)。 */
24
+ const numeralOf = (written: string): Numeral | undefined => {
25
+ const match = NUMERAL.exec(written.normalize("NFKC"));
26
+ if (match === null) return undefined;
27
+ const [whole = "", fraction = ""] = match[0].replace(/,/gu, "").split(".");
28
+ const significant = `${whole}${fraction}`.replace(/^0+/u, "").length;
29
+ return { value: Number(`${whole}.${fraction || "0"}`), decimals: fraction.length, significant };
30
+ };
31
+
32
+ /** 金額が丸めた単位で書いてあるか。和文の単位は金額の中に(6,655百万円)、英語の単位は金額のすぐ後ろに($5.6 million)ある。 */
33
+ const inRoundedUnit = (written: string, after: string, units: readonly string[]): boolean => {
34
+ const word = UNIT_AFTER.exec(after)?.[1]?.toLowerCase();
35
+ return units.some((unit) => written.includes(unit) || unit.toLowerCase() === word);
36
+ };
37
+
38
+ /** 丸めた単位で書いた金額の最後の桁一つ分を、金額の値の単位で。丸めた単位でないか、有効数字が 3 桁未満なら undefined。 */
39
+ export const displayStep = (source: string, amount: Amount, units: readonly string[]): number | undefined => {
40
+ const written = source.slice(amount.offset, amount.end);
41
+ if (!inRoundedUnit(written, source.slice(amount.end, amount.end + UNIT_REACH), units)) return undefined;
42
+ const numeral = numeralOf(written);
43
+ if (numeral === undefined || numeral.value === 0 || numeral.significant < MIN_SIGNIFICANT_DIGITS) return undefined;
44
+ return (amount.value / numeral.value) * DECIMAL_BASE ** -numeral.decimals;
45
+ };
46
+
47
+ /** 金額のどれもが丸めた単位で書いてあれば、その一番粗い桁一つ分。一つでも丸めた単位でなければ 0(ずれを許さない)。 */
48
+ export const coarsestStep = (source: string, amounts: readonly Amount[], units: readonly string[]): number => {
49
+ const steps = amounts.map((amount) => displayStep(source, amount, units));
50
+ const known = steps.filter((step) => step !== undefined);
51
+ return known.length === steps.length && known.length > 0 ? Math.max(...known) : 0;
52
+ };
53
+
54
+ /** 丸めた桁 step で書いた parts 個の内訳の和が、合計からずれてよい幅。 */
55
+ export const roundingAllowance = (step: number, parts: number): number => step * Math.max(0, parts - 1);
@@ -0,0 +1,21 @@
1
+ import type { StructureNode } from "../plugin.ts";
2
+
3
+ /** The label, then a gap of two or more spaces or a tab (the label column of a step list), then the step's own text. */
4
+ const LABEL_COLUMN = /^(?<word>\S+)(?: {2}|\t)/u;
5
+
6
+ /**
7
+ * A heading labelled with a word (side-step-label: "and", "or") where a step list puts a number: a step done alongside
8
+ * the one before it (GOV.UK's step-by-step pages). The word is matched as written, and must stand in a label column
9
+ * like a step's number does: "and more details" is an ordinary heading.
10
+ */
11
+ export const sideStepReader = (labels: readonly string[]): ((node: StructureNode) => boolean) => {
12
+ const words = new Set(labels);
13
+ return (node) => {
14
+ const heading = node.attrs["heading"];
15
+ if (typeof heading !== "string") return false;
16
+ const label = LABEL_COLUMN.exec(heading);
17
+ const word = label?.groups?.["word"];
18
+ if (label === null || word === undefined) return false;
19
+ return words.has(word) && heading.slice(label[0].length).trim() !== "";
20
+ };
21
+ };
@@ -0,0 +1,39 @@
1
+ // A row label that spans two columns in the table it was converted from (| Total score | | 5 |): Markdown has no column
2
+ // span, so the cell right after the label is left blank and the value follows. Pure; the caller passes the total words.
3
+
4
+ /** A note in parentheses at the end of a label (Total score (count of all "yes" answers above)), dropped before reading it. */
5
+ const TRAILING_NOTE = /[((][^()()]*[))]$/u;
6
+ const EMPHASIS = /[*_]/gu;
7
+ const COLON_END = /[::]$/u;
8
+ const LATIN_LETTER = /\p{Script=Latin}/u;
9
+
10
+ const labelText = (cell: string): string => cell.replace(EMPHASIS, "").trim().replace(TRAILING_NOTE, "").trim();
11
+
12
+ /**
13
+ * Whether `word` stands at the start or the end of `label` as a word of its own: no Latin letter runs on from it. A word of
14
+ * one character (計) must be the whole label, since it starts or ends many words (計画, 設計).
15
+ */
16
+ const startsOrEndsWith = (label: string, word: string): boolean => {
17
+ const lower = label.toLowerCase();
18
+ const target = word.toLowerCase();
19
+ if (Array.from(target).length === 1) return lower === target;
20
+ const after = lower.charAt(target.length);
21
+ const before = lower.charAt(lower.length - target.length - 1);
22
+ return (lower.startsWith(target) && !LATIN_LETTER.test(after)) || (lower.endsWith(target) && !LATIN_LETTER.test(before));
23
+ };
24
+
25
+ /** A label: it ends in a colon (Total:), or a total word starts or ends it (Total score, 得点合計). */
26
+ export const isSpanningLabel = (cell: string, totalWords: readonly string[]): boolean => {
27
+ const label = labelText(cell);
28
+ if (label === "") return false;
29
+ return COLON_END.test(label) || totalWords.some((word) => word !== "" && startsOrEndsWith(label, word));
30
+ };
31
+
32
+ /**
33
+ * Whether the blank at `column` is the second half of a label that spans two columns: the cell before it holds such a label
34
+ * and the cell after it is filled. Cells are undefined when blank.
35
+ */
36
+ export const isSpannedLabelGap = (cells: readonly (string | undefined)[], column: number, totalWords: readonly string[]): boolean => {
37
+ const label = cells[column - 1];
38
+ return cells[column] === undefined && cells[column + 1] !== undefined && label !== undefined && isSpanningLabel(label, totalWords);
39
+ };