chaffjs 0.17.0 → 0.18.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 (840) hide show
  1. package/dist/announced-count.d.ts +26 -0
  2. package/dist/announced-count.d.ts.map +1 -0
  3. package/dist/announced-count.js +104 -0
  4. package/dist/announced-count.js.map +1 -0
  5. package/dist/bare-url.d.ts +14 -0
  6. package/dist/bare-url.d.ts.map +1 -0
  7. package/dist/bare-url.js +28 -0
  8. package/dist/bare-url.js.map +1 -0
  9. package/dist/baseline.d.ts +5 -0
  10. package/dist/baseline.d.ts.map +1 -1
  11. package/dist/baseline.js +16 -1
  12. package/dist/baseline.js.map +1 -1
  13. package/dist/body-section.d.ts +7 -0
  14. package/dist/body-section.d.ts.map +1 -0
  15. package/dist/body-section.js +6 -0
  16. package/dist/body-section.js.map +1 -0
  17. package/dist/calendar-number.d.ts +2 -0
  18. package/dist/calendar-number.d.ts.map +1 -1
  19. package/dist/calendar-number.js +9 -2
  20. package/dist/calendar-number.js.map +1 -1
  21. package/dist/cli-args.d.ts +4 -0
  22. package/dist/cli-args.d.ts.map +1 -1
  23. package/dist/cli-args.js +5 -0
  24. package/dist/cli-args.js.map +1 -1
  25. package/dist/cli-text.d.ts.map +1 -1
  26. package/dist/cli-text.js +8 -4
  27. package/dist/cli-text.js.map +1 -1
  28. package/dist/cli.js +33 -30
  29. package/dist/cli.js.map +1 -1
  30. package/dist/commands/compare.d.ts +8 -0
  31. package/dist/commands/compare.d.ts.map +1 -0
  32. package/dist/commands/compare.js +72 -0
  33. package/dist/commands/compare.js.map +1 -0
  34. package/dist/commands/eval.d.ts.map +1 -1
  35. package/dist/commands/eval.js +17 -9
  36. package/dist/commands/eval.js.map +1 -1
  37. package/dist/commands/feedback.d.ts +5 -2
  38. package/dist/commands/feedback.d.ts.map +1 -1
  39. package/dist/commands/feedback.js +11 -5
  40. package/dist/commands/feedback.js.map +1 -1
  41. package/dist/commands/test.d.ts.map +1 -1
  42. package/dist/commands/test.js +2 -4
  43. package/dist/commands/test.js.map +1 -1
  44. package/dist/commands/tree.d.ts +13 -0
  45. package/dist/commands/tree.d.ts.map +1 -1
  46. package/dist/commands/tree.js +35 -5
  47. package/dist/commands/tree.js.map +1 -1
  48. package/dist/compare/atom.d.ts +31 -0
  49. package/dist/compare/atom.d.ts.map +1 -0
  50. package/dist/compare/atom.js +4 -0
  51. package/dist/compare/atom.js.map +1 -0
  52. package/dist/compare/clock-time.d.ts +8 -0
  53. package/dist/compare/clock-time.d.ts.map +1 -0
  54. package/dist/compare/clock-time.js +65 -0
  55. package/dist/compare/clock-time.js.map +1 -0
  56. package/dist/compare/extract.d.ts +15 -0
  57. package/dist/compare/extract.d.ts.map +1 -0
  58. package/dist/compare/extract.js +58 -0
  59. package/dist/compare/extract.js.map +1 -0
  60. package/dist/compare/fact-text.d.ts +23 -0
  61. package/dist/compare/fact-text.d.ts.map +1 -0
  62. package/dist/compare/fact-text.js +47 -0
  63. package/dist/compare/fact-text.js.map +1 -0
  64. package/dist/compare/markup-atoms.d.ts +11 -0
  65. package/dist/compare/markup-atoms.d.ts.map +1 -0
  66. package/dist/compare/markup-atoms.js +23 -0
  67. package/dist/compare/markup-atoms.js.map +1 -0
  68. package/dist/compare/match.d.ts +19 -0
  69. package/dist/compare/match.d.ts.map +1 -0
  70. package/dist/compare/match.js +84 -0
  71. package/dist/compare/match.js.map +1 -0
  72. package/dist/compare/outcome.d.ts +33 -0
  73. package/dist/compare/outcome.d.ts.map +1 -0
  74. package/dist/compare/outcome.js +40 -0
  75. package/dist/compare/outcome.js.map +1 -0
  76. package/dist/compare/proper-nouns.d.ts +19 -0
  77. package/dist/compare/proper-nouns.d.ts.map +1 -0
  78. package/dist/compare/proper-nouns.js +44 -0
  79. package/dist/compare/proper-nouns.js.map +1 -0
  80. package/dist/compare/render.d.ts +9 -0
  81. package/dist/compare/render.d.ts.map +1 -0
  82. package/dist/compare/render.js +64 -0
  83. package/dist/compare/render.js.map +1 -0
  84. package/dist/compare/spans.d.ts +9 -0
  85. package/dist/compare/spans.d.ts.map +1 -0
  86. package/dist/compare/spans.js +11 -0
  87. package/dist/compare/spans.js.map +1 -0
  88. package/dist/compare/text-atoms.d.ts +24 -0
  89. package/dist/compare/text-atoms.d.ts.map +1 -0
  90. package/dist/compare/text-atoms.js +67 -0
  91. package/dist/compare/text-atoms.js.map +1 -0
  92. package/dist/compare/text.d.ts +24 -0
  93. package/dist/compare/text.d.ts.map +1 -0
  94. package/dist/compare/text.js +90 -0
  95. package/dist/compare/text.js.map +1 -0
  96. package/dist/compare/tree-atoms.d.ts +20 -0
  97. package/dist/compare/tree-atoms.d.ts.map +1 -0
  98. package/dist/compare/tree-atoms.js +58 -0
  99. package/dist/compare/tree-atoms.js.map +1 -0
  100. package/dist/compare/written-names.d.ts +8 -0
  101. package/dist/compare/written-names.d.ts.map +1 -0
  102. package/dist/compare/written-names.js +24 -0
  103. package/dist/compare/written-names.js.map +1 -0
  104. package/dist/config/load.d.ts +15 -0
  105. package/dist/config/load.d.ts.map +1 -1
  106. package/dist/config/load.js +5 -0
  107. package/dist/config/load.js.map +1 -1
  108. package/dist/config/option-problems.d.ts +16 -0
  109. package/dist/config/option-problems.d.ts.map +1 -0
  110. package/dist/config/option-problems.js +58 -0
  111. package/dist/config/option-problems.js.map +1 -0
  112. package/dist/config/read.d.ts +4 -0
  113. package/dist/config/read.d.ts.map +1 -0
  114. package/dist/config/read.js +8 -0
  115. package/dist/config/read.js.map +1 -0
  116. package/dist/config/rule-problems.d.ts +2 -4
  117. package/dist/config/rule-problems.d.ts.map +1 -1
  118. package/dist/config/rule-problems.js +7 -1
  119. package/dist/config/rule-problems.js.map +1 -1
  120. package/dist/config/style.d.ts +16 -0
  121. package/dist/config/style.d.ts.map +1 -0
  122. package/dist/config/style.js +36 -0
  123. package/dist/config/style.js.map +1 -0
  124. package/dist/config/warnings.d.ts +6 -0
  125. package/dist/config/warnings.d.ts.map +1 -0
  126. package/dist/config/warnings.js +10 -0
  127. package/dist/config/warnings.js.map +1 -0
  128. package/dist/config/write.d.ts.map +1 -1
  129. package/dist/config/write.js +17 -4
  130. package/dist/config/write.js.map +1 -1
  131. package/dist/custom/bounded-match.d.ts +15 -0
  132. package/dist/custom/bounded-match.d.ts.map +1 -0
  133. package/dist/custom/bounded-match.js +43 -0
  134. package/dist/custom/bounded-match.js.map +1 -0
  135. package/dist/custom/load.d.ts +8 -0
  136. package/dist/custom/load.d.ts.map +1 -0
  137. package/dist/custom/load.js +11 -0
  138. package/dist/custom/load.js.map +1 -0
  139. package/dist/custom/parse.d.ts +70 -0
  140. package/dist/custom/parse.d.ts.map +1 -0
  141. package/dist/custom/parse.js +215 -0
  142. package/dist/custom/parse.js.map +1 -0
  143. package/dist/custom/problems.d.ts +5 -0
  144. package/dist/custom/problems.d.ts.map +1 -0
  145. package/dist/custom/problems.js +78 -0
  146. package/dist/custom/problems.js.map +1 -0
  147. package/dist/custom/regex-safety.d.ts +11 -0
  148. package/dist/custom/regex-safety.d.ts.map +1 -0
  149. package/dist/custom/regex-safety.js +110 -0
  150. package/dist/custom/regex-safety.js.map +1 -0
  151. package/dist/custom/token-pattern.d.ts +8 -0
  152. package/dist/custom/token-pattern.d.ts.map +1 -0
  153. package/dist/custom/token-pattern.js +75 -0
  154. package/dist/custom/token-pattern.js.map +1 -0
  155. package/dist/detect.d.ts.map +1 -1
  156. package/dist/detect.js +24 -2
  157. package/dist/detect.js.map +1 -1
  158. package/dist/detectors/acronym-context.d.ts +2 -0
  159. package/dist/detectors/acronym-context.d.ts.map +1 -1
  160. package/dist/detectors/acronym-context.js +12 -4
  161. package/dist/detectors/acronym-context.js.map +1 -1
  162. package/dist/detectors/ai-phrasing.d.ts +20 -0
  163. package/dist/detectors/ai-phrasing.d.ts.map +1 -0
  164. package/dist/detectors/ai-phrasing.js +112 -0
  165. package/dist/detectors/ai-phrasing.js.map +1 -0
  166. package/dist/detectors/announced-count.d.ts +4 -0
  167. package/dist/detectors/announced-count.d.ts.map +1 -0
  168. package/dist/detectors/announced-count.js +20 -0
  169. package/dist/detectors/announced-count.js.map +1 -0
  170. package/dist/detectors/broken-link.d.ts +17 -0
  171. package/dist/detectors/broken-link.d.ts.map +1 -0
  172. package/dist/detectors/broken-link.js +66 -0
  173. package/dist/detectors/broken-link.js.map +1 -0
  174. package/dist/detectors/cited-name.d.ts.map +1 -1
  175. package/dist/detectors/cited-name.js +4 -4
  176. package/dist/detectors/cited-name.js.map +1 -1
  177. package/dist/detectors/cited-title.d.ts +11 -0
  178. package/dist/detectors/cited-title.d.ts.map +1 -0
  179. package/dist/detectors/cited-title.js +75 -0
  180. package/dist/detectors/cited-title.js.map +1 -0
  181. package/dist/detectors/concrete-evidence.d.ts +1 -1
  182. package/dist/detectors/concrete-evidence.d.ts.map +1 -1
  183. package/dist/detectors/concrete-evidence.js +2 -1
  184. package/dist/detectors/concrete-evidence.js.map +1 -1
  185. package/dist/detectors/contrast-frame.d.ts +17 -0
  186. package/dist/detectors/contrast-frame.d.ts.map +1 -0
  187. package/dist/detectors/contrast-frame.js +32 -0
  188. package/dist/detectors/contrast-frame.js.map +1 -0
  189. package/dist/detectors/custom.d.ts +8 -0
  190. package/dist/detectors/custom.d.ts.map +1 -0
  191. package/dist/detectors/custom.js +71 -0
  192. package/dist/detectors/custom.js.map +1 -0
  193. package/dist/detectors/dangling-figure.d.ts +4 -0
  194. package/dist/detectors/dangling-figure.d.ts.map +1 -0
  195. package/dist/detectors/dangling-figure.js +18 -0
  196. package/dist/detectors/dangling-figure.js.map +1 -0
  197. package/dist/detectors/doubled-punctuation.d.ts +9 -0
  198. package/dist/detectors/doubled-punctuation.d.ts.map +1 -0
  199. package/dist/detectors/doubled-punctuation.js +33 -0
  200. package/dist/detectors/doubled-punctuation.js.map +1 -0
  201. package/dist/detectors/doubled-word.d.ts +5 -0
  202. package/dist/detectors/doubled-word.d.ts.map +1 -1
  203. package/dist/detectors/doubled-word.js +24 -11
  204. package/dist/detectors/doubled-word.js.map +1 -1
  205. package/dist/detectors/enumerated-runs.d.ts +1 -1
  206. package/dist/detectors/enumerated-runs.d.ts.map +1 -1
  207. package/dist/detectors/enumerated-runs.js +15 -4
  208. package/dist/detectors/enumerated-runs.js.map +1 -1
  209. package/dist/detectors/gram-furniture.d.ts +6 -0
  210. package/dist/detectors/gram-furniture.d.ts.map +1 -0
  211. package/dist/detectors/gram-furniture.js +21 -0
  212. package/dist/detectors/gram-furniture.js.map +1 -0
  213. package/dist/detectors/gram-place.d.ts +2 -0
  214. package/dist/detectors/gram-place.d.ts.map +1 -1
  215. package/dist/detectors/gram-place.js +9 -7
  216. package/dist/detectors/gram-place.js.map +1 -1
  217. package/dist/detectors/gram-windows.d.ts +9 -0
  218. package/dist/detectors/gram-windows.d.ts.map +1 -0
  219. package/dist/detectors/gram-windows.js +27 -0
  220. package/dist/detectors/gram-windows.js.map +1 -0
  221. package/dist/detectors/heading-case.d.ts +2 -0
  222. package/dist/detectors/heading-case.d.ts.map +1 -1
  223. package/dist/detectors/heading-case.js +29 -2
  224. package/dist/detectors/heading-case.js.map +1 -1
  225. package/dist/detectors/heading-code-words.d.ts +6 -0
  226. package/dist/detectors/heading-code-words.d.ts.map +1 -0
  227. package/dist/detectors/heading-code-words.js +29 -0
  228. package/dist/detectors/heading-code-words.js.map +1 -0
  229. package/dist/detectors/heading-echo.d.ts.map +1 -1
  230. package/dist/detectors/heading-echo.js +7 -4
  231. package/dist/detectors/heading-echo.js.map +1 -1
  232. package/dist/detectors/heading-level-skip.d.ts +12 -0
  233. package/dist/detectors/heading-level-skip.d.ts.map +1 -0
  234. package/dist/detectors/heading-level-skip.js +11 -0
  235. package/dist/detectors/heading-level-skip.js.map +1 -0
  236. package/dist/detectors/image-alt-text.d.ts +3 -0
  237. package/dist/detectors/image-alt-text.d.ts.map +1 -0
  238. package/dist/detectors/image-alt-text.js +9 -0
  239. package/dist/detectors/image-alt-text.js.map +1 -0
  240. package/dist/detectors/index.d.ts.map +1 -1
  241. package/dist/detectors/index.js +34 -1
  242. package/dist/detectors/index.js.map +1 -1
  243. package/dist/detectors/kutoten-consistency.d.ts +24 -0
  244. package/dist/detectors/kutoten-consistency.d.ts.map +1 -0
  245. package/dist/detectors/kutoten-consistency.js +77 -0
  246. package/dist/detectors/kutoten-consistency.js.map +1 -0
  247. package/dist/detectors/lead-in.d.ts +1 -0
  248. package/dist/detectors/lead-in.d.ts.map +1 -1
  249. package/dist/detectors/lead-in.js +2 -1
  250. package/dist/detectors/lead-in.js.map +1 -1
  251. package/dist/detectors/lexicon-match.d.ts +4 -0
  252. package/dist/detectors/lexicon-match.d.ts.map +1 -1
  253. package/dist/detectors/lexicon-match.js +7 -2
  254. package/dist/detectors/lexicon-match.js.map +1 -1
  255. package/dist/detectors/list-item.d.ts +45 -0
  256. package/dist/detectors/list-item.d.ts.map +1 -0
  257. package/dist/detectors/list-item.js +88 -0
  258. package/dist/detectors/list-item.js.map +1 -0
  259. package/dist/detectors/list-items.d.ts +31 -0
  260. package/dist/detectors/list-items.d.ts.map +1 -0
  261. package/dist/detectors/list-items.js +113 -0
  262. package/dist/detectors/list-items.js.map +1 -0
  263. package/dist/detectors/list-lead-in.d.ts +7 -0
  264. package/dist/detectors/list-lead-in.d.ts.map +1 -0
  265. package/dist/detectors/list-lead-in.js +28 -0
  266. package/dist/detectors/list-lead-in.js.map +1 -0
  267. package/dist/detectors/list-sentence.d.ts +65 -0
  268. package/dist/detectors/list-sentence.d.ts.map +1 -0
  269. package/dist/detectors/list-sentence.js +105 -0
  270. package/dist/detectors/list-sentence.js.map +1 -0
  271. package/dist/detectors/list-view.d.ts +34 -0
  272. package/dist/detectors/list-view.d.ts.map +1 -0
  273. package/dist/detectors/list-view.js +137 -0
  274. package/dist/detectors/list-view.js.map +1 -0
  275. package/dist/detectors/long-vowel.d.ts +7 -0
  276. package/dist/detectors/long-vowel.d.ts.map +1 -0
  277. package/dist/detectors/long-vowel.js +57 -0
  278. package/dist/detectors/long-vowel.js.map +1 -0
  279. package/dist/detectors/markup-finding.d.ts +6 -0
  280. package/dist/detectors/markup-finding.d.ts.map +1 -0
  281. package/dist/detectors/markup-finding.js +19 -0
  282. package/dist/detectors/markup-finding.js.map +1 -0
  283. package/dist/detectors/name-numeral.d.ts +1 -1
  284. package/dist/detectors/name-numeral.d.ts.map +1 -1
  285. package/dist/detectors/name-numeral.js +2 -7
  286. package/dist/detectors/name-numeral.js.map +1 -1
  287. package/dist/detectors/orthography.d.ts.map +1 -1
  288. package/dist/detectors/orthography.js +14 -10
  289. package/dist/detectors/orthography.js.map +1 -1
  290. package/dist/detectors/oxford-comma.d.ts +7 -1
  291. package/dist/detectors/oxford-comma.d.ts.map +1 -1
  292. package/dist/detectors/oxford-comma.js +135 -229
  293. package/dist/detectors/oxford-comma.js.map +1 -1
  294. package/dist/detectors/place-run.d.ts.map +1 -1
  295. package/dist/detectors/place-run.js +10 -6
  296. package/dist/detectors/place-run.js.map +1 -1
  297. package/dist/detectors/placeholder-text.d.ts +9 -0
  298. package/dist/detectors/placeholder-text.d.ts.map +1 -0
  299. package/dist/detectors/placeholder-text.js +18 -0
  300. package/dist/detectors/placeholder-text.js.map +1 -0
  301. package/dist/detectors/quote-around.d.ts +3 -0
  302. package/dist/detectors/quote-around.d.ts.map +1 -0
  303. package/dist/detectors/quote-around.js +8 -0
  304. package/dist/detectors/quote-around.js.map +1 -0
  305. package/dist/detectors/register.d.ts +11 -3
  306. package/dist/detectors/register.d.ts.map +1 -1
  307. package/dist/detectors/register.js +28 -9
  308. package/dist/detectors/register.js.map +1 -1
  309. package/dist/detectors/roman-numeral.d.ts +2 -0
  310. package/dist/detectors/roman-numeral.d.ts.map +1 -1
  311. package/dist/detectors/roman-numeral.js +2 -0
  312. package/dist/detectors/roman-numeral.js.map +1 -1
  313. package/dist/detectors/sentence-ending.d.ts +17 -1
  314. package/dist/detectors/sentence-ending.d.ts.map +1 -1
  315. package/dist/detectors/sentence-ending.js +13 -7
  316. package/dist/detectors/sentence-ending.js.map +1 -1
  317. package/dist/detectors/sentence-length.d.ts.map +1 -1
  318. package/dist/detectors/sentence-length.js +13 -4
  319. package/dist/detectors/sentence-length.js.map +1 -1
  320. package/dist/detectors/signals.d.ts +8 -0
  321. package/dist/detectors/signals.d.ts.map +1 -1
  322. package/dist/detectors/signals.js +67 -46
  323. package/dist/detectors/signals.js.map +1 -1
  324. package/dist/detectors/structure-tree.d.ts +6 -0
  325. package/dist/detectors/structure-tree.d.ts.map +1 -1
  326. package/dist/detectors/structure-tree.js +37 -1
  327. package/dist/detectors/structure-tree.js.map +1 -1
  328. package/dist/detectors/structure.d.ts +1 -3
  329. package/dist/detectors/structure.d.ts.map +1 -1
  330. package/dist/detectors/structure.js +3 -4
  331. package/dist/detectors/structure.js.map +1 -1
  332. package/dist/detectors/superlative-name.d.ts.map +1 -1
  333. package/dist/detectors/superlative-name.js +8 -5
  334. package/dist/detectors/superlative-name.js.map +1 -1
  335. package/dist/detectors/superlative-scope.d.ts.map +1 -1
  336. package/dist/detectors/superlative-scope.js +9 -4
  337. package/dist/detectors/superlative-scope.js.map +1 -1
  338. package/dist/detectors/token-column.d.ts +46 -0
  339. package/dist/detectors/token-column.d.ts.map +1 -0
  340. package/dist/detectors/token-column.js +95 -0
  341. package/dist/detectors/token-column.js.map +1 -0
  342. package/dist/detectors/unbalanced-bracket.d.ts +22 -0
  343. package/dist/detectors/unbalanced-bracket.d.ts.map +1 -0
  344. package/dist/detectors/unbalanced-bracket.js +119 -0
  345. package/dist/detectors/unbalanced-bracket.js.map +1 -0
  346. package/dist/detectors/url-run-on.d.ts +9 -0
  347. package/dist/detectors/url-run-on.d.ts.map +1 -0
  348. package/dist/detectors/url-run-on.js +19 -0
  349. package/dist/detectors/url-run-on.js.map +1 -0
  350. package/dist/document-sections.d.ts +13 -0
  351. package/dist/document-sections.d.ts.map +1 -0
  352. package/dist/document-sections.js +32 -0
  353. package/dist/document-sections.js.map +1 -0
  354. package/dist/document.d.ts +11 -4
  355. package/dist/document.d.ts.map +1 -1
  356. package/dist/document.js +90 -98
  357. package/dist/document.js.map +1 -1
  358. package/dist/email-parts.d.ts +28 -0
  359. package/dist/email-parts.d.ts.map +1 -0
  360. package/dist/email-parts.js +230 -0
  361. package/dist/email-parts.js.map +1 -0
  362. package/dist/eval.d.ts +2 -1
  363. package/dist/eval.d.ts.map +1 -1
  364. package/dist/eval.js +16 -4
  365. package/dist/eval.js.map +1 -1
  366. package/dist/figure-references.d.ts +30 -0
  367. package/dist/figure-references.d.ts.map +1 -0
  368. package/dist/figure-references.js +76 -0
  369. package/dist/figure-references.js.map +1 -0
  370. package/dist/files.d.ts +2 -0
  371. package/dist/files.d.ts.map +1 -1
  372. package/dist/files.js +4 -0
  373. package/dist/files.js.map +1 -1
  374. package/dist/heading-label.d.ts +22 -0
  375. package/dist/heading-label.d.ts.map +1 -0
  376. package/dist/heading-label.js +50 -0
  377. package/dist/heading-label.js.map +1 -0
  378. package/dist/in-page-nav.d.ts +4 -1
  379. package/dist/in-page-nav.d.ts.map +1 -1
  380. package/dist/in-page-nav.js +53 -18
  381. package/dist/in-page-nav.js.map +1 -1
  382. package/dist/joined-view.d.ts.map +1 -1
  383. package/dist/joined-view.js +1 -0
  384. package/dist/joined-view.js.map +1 -1
  385. package/dist/levels.d.ts +5 -1
  386. package/dist/levels.d.ts.map +1 -1
  387. package/dist/levels.js +9 -0
  388. package/dist/levels.js.map +1 -1
  389. package/dist/line-paragraphs.d.ts +8 -0
  390. package/dist/line-paragraphs.d.ts.map +1 -1
  391. package/dist/line-paragraphs.js +33 -10
  392. package/dist/line-paragraphs.js.map +1 -1
  393. package/dist/long-vowel.d.ts +35 -0
  394. package/dist/long-vowel.d.ts.map +1 -0
  395. package/dist/long-vowel.js +71 -0
  396. package/dist/long-vowel.js.map +1 -0
  397. package/dist/markdown-node.d.ts +19 -0
  398. package/dist/markdown-node.d.ts.map +1 -0
  399. package/dist/markdown-node.js +6 -0
  400. package/dist/markdown-node.js.map +1 -0
  401. package/dist/markdown-read.d.ts +17 -0
  402. package/dist/markdown-read.d.ts.map +1 -0
  403. package/dist/markdown-read.js +37 -0
  404. package/dist/markdown-read.js.map +1 -0
  405. package/dist/markup.d.ts +22 -0
  406. package/dist/markup.d.ts.map +1 -0
  407. package/dist/markup.js +180 -0
  408. package/dist/markup.js.map +1 -0
  409. package/dist/mask.js +8 -5
  410. package/dist/mask.js.map +1 -1
  411. package/dist/number-name.d.ts +21 -5
  412. package/dist/number-name.d.ts.map +1 -1
  413. package/dist/number-name.js +119 -17
  414. package/dist/number-name.js.map +1 -1
  415. package/dist/orthography.d.ts +2 -0
  416. package/dist/orthography.d.ts.map +1 -1
  417. package/dist/orthography.js +9 -4
  418. package/dist/orthography.js.map +1 -1
  419. package/dist/page-furniture.d.ts +5 -2
  420. package/dist/page-furniture.d.ts.map +1 -1
  421. package/dist/page-furniture.js +8 -2
  422. package/dist/page-furniture.js.map +1 -1
  423. package/dist/plain-source.d.ts +1 -0
  424. package/dist/plain-source.d.ts.map +1 -1
  425. package/dist/plain-source.js +2 -1
  426. package/dist/plain-source.js.map +1 -1
  427. package/dist/plugin.d.ts +115 -0
  428. package/dist/plugin.d.ts.map +1 -1
  429. package/dist/profile/for-file.d.ts.map +1 -1
  430. package/dist/profile/for-file.js +3 -1
  431. package/dist/profile/for-file.js.map +1 -1
  432. package/dist/quoted-span.d.ts.map +1 -1
  433. package/dist/quoted-span.js +8 -3
  434. package/dist/quoted-span.js.map +1 -1
  435. package/dist/reasons.d.ts +3 -0
  436. package/dist/reasons.d.ts.map +1 -1
  437. package/dist/reasons.js +6 -0
  438. package/dist/reasons.js.map +1 -1
  439. package/dist/reference-lists.d.ts +3 -0
  440. package/dist/reference-lists.d.ts.map +1 -0
  441. package/dist/reference-lists.js +75 -0
  442. package/dist/reference-lists.js.map +1 -0
  443. package/dist/render/explain.d.ts +7 -1
  444. package/dist/render/explain.d.ts.map +1 -1
  445. package/dist/render/explain.js +36 -12
  446. package/dist/render/explain.js.map +1 -1
  447. package/dist/render/friendly.d.ts.map +1 -1
  448. package/dist/render/friendly.js +19 -9
  449. package/dist/render/friendly.js.map +1 -1
  450. package/dist/render/options.d.ts +7 -0
  451. package/dist/render/options.d.ts.map +1 -0
  452. package/dist/render/options.js +50 -0
  453. package/dist/render/options.js.map +1 -0
  454. package/dist/render/rules-json.d.ts +4 -1
  455. package/dist/render/rules-json.d.ts.map +1 -1
  456. package/dist/render/rules-json.js +102 -12
  457. package/dist/render/rules-json.js.map +1 -1
  458. package/dist/render/rules-table.d.ts +4 -0
  459. package/dist/render/rules-table.d.ts.map +1 -0
  460. package/dist/render/rules-table.js +70 -0
  461. package/dist/render/rules-table.js.map +1 -0
  462. package/dist/render/sarif.js +4 -4
  463. package/dist/render/sarif.js.map +1 -1
  464. package/dist/render/semantic.js +3 -3
  465. package/dist/render/semantic.js.map +1 -1
  466. package/dist/render/severity-name.d.ts +6 -0
  467. package/dist/render/severity-name.d.ts.map +1 -0
  468. package/dist/render/severity-name.js +7 -0
  469. package/dist/render/severity-name.js.map +1 -0
  470. package/dist/render/text.d.ts +7 -2
  471. package/dist/render/text.d.ts.map +1 -1
  472. package/dist/render/text.js +15 -4
  473. package/dist/render/text.js.map +1 -1
  474. package/dist/resolve-genre.d.ts +1 -1
  475. package/dist/resolve-genre.d.ts.map +1 -1
  476. package/dist/resolve-genre.js +4 -1
  477. package/dist/resolve-genre.js.map +1 -1
  478. package/dist/rule-genres.d.ts +24 -0
  479. package/dist/rule-genres.d.ts.map +1 -0
  480. package/dist/rule-genres.js +11 -0
  481. package/dist/rule-genres.js.map +1 -0
  482. package/dist/rule-guide.d.ts +54 -0
  483. package/dist/rule-guide.d.ts.map +1 -0
  484. package/dist/rule-guide.js +81 -0
  485. package/dist/rule-guide.js.map +1 -0
  486. package/dist/rule-load.d.ts.map +1 -1
  487. package/dist/rule-load.js +87 -33
  488. package/dist/rule-load.js.map +1 -1
  489. package/dist/rule-options.d.ts +50 -0
  490. package/dist/rule-options.d.ts.map +1 -0
  491. package/dist/rule-options.js +106 -0
  492. package/dist/rule-options.js.map +1 -0
  493. package/dist/run.d.ts +13 -0
  494. package/dist/run.d.ts.map +1 -1
  495. package/dist/run.js +54 -10
  496. package/dist/run.js.map +1 -1
  497. package/dist/sentence-shape.d.ts.map +1 -1
  498. package/dist/sentence-shape.js +4 -4
  499. package/dist/sentence-shape.js.map +1 -1
  500. package/dist/setting-problems.d.ts +2 -1
  501. package/dist/setting-problems.d.ts.map +1 -1
  502. package/dist/setting-problems.js +6 -1
  503. package/dist/setting-problems.js.map +1 -1
  504. package/dist/span-cut.d.ts +6 -0
  505. package/dist/span-cut.d.ts.map +1 -0
  506. package/dist/span-cut.js +22 -0
  507. package/dist/span-cut.js.map +1 -0
  508. package/dist/structure/aside-depth.d.ts +21 -0
  509. package/dist/structure/aside-depth.d.ts.map +1 -0
  510. package/dist/structure/aside-depth.js +65 -0
  511. package/dist/structure/aside-depth.js.map +1 -0
  512. package/dist/structure/build.d.ts +5 -1
  513. package/dist/structure/build.d.ts.map +1 -1
  514. package/dist/structure/build.js +29 -17
  515. package/dist/structure/build.js.map +1 -1
  516. package/dist/structure/closed-pairs.d.ts +8 -0
  517. package/dist/structure/closed-pairs.d.ts.map +1 -0
  518. package/dist/structure/closed-pairs.js +22 -0
  519. package/dist/structure/closed-pairs.js.map +1 -0
  520. package/dist/structure/date-range.d.ts +21 -0
  521. package/dist/structure/date-range.d.ts.map +1 -0
  522. package/dist/structure/date-range.js +45 -0
  523. package/dist/structure/date-range.js.map +1 -0
  524. package/dist/structure/known-mentions.d.ts +18 -0
  525. package/dist/structure/known-mentions.d.ts.map +1 -0
  526. package/dist/structure/known-mentions.js +78 -0
  527. package/dist/structure/known-mentions.js.map +1 -0
  528. package/dist/structure/numbering.d.ts +1 -0
  529. package/dist/structure/numbering.d.ts.map +1 -1
  530. package/dist/structure/numbering.js +11 -6
  531. package/dist/structure/numbering.js.map +1 -1
  532. package/dist/structure/of.d.ts +3 -1
  533. package/dist/structure/of.d.ts.map +1 -1
  534. package/dist/structure/of.js +5 -1
  535. package/dist/structure/of.js.map +1 -1
  536. package/dist/structure/percent-sum.d.ts +16 -0
  537. package/dist/structure/percent-sum.d.ts.map +1 -0
  538. package/dist/structure/percent-sum.js +104 -0
  539. package/dist/structure/percent-sum.js.map +1 -0
  540. package/dist/structure/quoted-number.d.ts +8 -0
  541. package/dist/structure/quoted-number.d.ts.map +1 -0
  542. package/dist/structure/quoted-number.js +34 -0
  543. package/dist/structure/quoted-number.js.map +1 -0
  544. package/dist/structure/relative-find.d.ts.map +1 -1
  545. package/dist/structure/relative-find.js +34 -46
  546. package/dist/structure/relative-find.js.map +1 -1
  547. package/dist/structure/relative-resolve.d.ts.map +1 -1
  548. package/dist/structure/relative-resolve.js +76 -30
  549. package/dist/structure/relative-resolve.js.map +1 -1
  550. package/dist/structure/runs.d.ts +2 -0
  551. package/dist/structure/runs.d.ts.map +1 -1
  552. package/dist/structure/runs.js +2 -2
  553. package/dist/structure/runs.js.map +1 -1
  554. package/dist/structure/sexp.d.ts +1 -1
  555. package/dist/structure/sexp.d.ts.map +1 -1
  556. package/dist/structure/sexp.js +18 -6
  557. package/dist/structure/sexp.js.map +1 -1
  558. package/dist/structure/total.d.ts +3 -0
  559. package/dist/structure/total.d.ts.map +1 -1
  560. package/dist/structure/total.js +2 -2
  561. package/dist/structure/total.js.map +1 -1
  562. package/dist/structure/universal.d.ts +14 -2
  563. package/dist/structure/universal.d.ts.map +1 -1
  564. package/dist/structure/universal.js +17 -2
  565. package/dist/structure/universal.js.map +1 -1
  566. package/dist/structure/wrapped-tail.d.ts +14 -7
  567. package/dist/structure/wrapped-tail.d.ts.map +1 -1
  568. package/dist/structure/wrapped-tail.js +33 -8
  569. package/dist/structure/wrapped-tail.js.map +1 -1
  570. package/dist/style-load.d.ts +4 -0
  571. package/dist/style-load.d.ts.map +1 -0
  572. package/dist/style-load.js +28 -0
  573. package/dist/style-load.js.map +1 -0
  574. package/dist/style-parse.d.ts +19 -0
  575. package/dist/style-parse.d.ts.map +1 -0
  576. package/dist/style-parse.js +60 -0
  577. package/dist/style-parse.js.map +1 -0
  578. package/dist/subheading-line.d.ts +6 -0
  579. package/dist/subheading-line.d.ts.map +1 -0
  580. package/dist/subheading-line.js +57 -0
  581. package/dist/subheading-line.js.map +1 -0
  582. package/dist/template-syntax.d.ts +17 -0
  583. package/dist/template-syntax.d.ts.map +1 -0
  584. package/dist/template-syntax.js +140 -0
  585. package/dist/template-syntax.js.map +1 -0
  586. package/dist/text-above.d.ts +19 -0
  587. package/dist/text-above.d.ts.map +1 -0
  588. package/dist/text-above.js +43 -0
  589. package/dist/text-above.js.map +1 -0
  590. package/dist/text-figures.d.ts +10 -0
  591. package/dist/text-figures.d.ts.map +1 -0
  592. package/dist/text-figures.js +131 -0
  593. package/dist/text-figures.js.map +1 -0
  594. package/dist/trailing-aside.d.ts +2 -0
  595. package/dist/trailing-aside.d.ts.map +1 -0
  596. package/dist/trailing-aside.js +53 -0
  597. package/dist/trailing-aside.js.map +1 -0
  598. package/dist/tree-walk.d.ts +18 -0
  599. package/dist/tree-walk.d.ts.map +1 -0
  600. package/dist/tree-walk.js +45 -0
  601. package/dist/tree-walk.js.map +1 -0
  602. package/genres.yaml +26 -0
  603. package/package.json +5 -3
  604. package/reference-headings.yaml +17 -0
  605. package/rules/adverb-overuse.yaml +19 -0
  606. package/rules/agentless-passive.yaml +19 -0
  607. package/rules/agreement-slip.yaml +14 -1
  608. package/rules/ai-generated-composite.yaml +102 -0
  609. package/rules/ai-tell.yaml +23 -0
  610. package/rules/announced-count-mismatch.yaml +57 -0
  611. package/rules/announcing-opener.yaml +51 -0
  612. package/rules/assistant-residue.yaml +52 -0
  613. package/rules/bold-density.yaml +31 -0
  614. package/rules/broken-link.yaml +65 -0
  615. package/rules/closing-cliche.yaml +33 -0
  616. package/rules/colon-lead-in.yaml +59 -0
  617. package/rules/concrete-evidence-density.yaml +41 -0
  618. package/rules/contraction-consistency.yaml +18 -0
  619. package/rules/contrast-framing.yaml +57 -0
  620. package/rules/cushion-phrase-density.yaml +25 -0
  621. package/rules/dangling-figure-reference.yaml +61 -0
  622. package/rules/dangling-reference.yaml +53 -1
  623. package/rules/date-order.yaml +33 -1
  624. package/rules/date-range-reversed.yaml +46 -0
  625. package/rules/date-weekday-mismatch.yaml +17 -1
  626. package/rules/double-keigo.yaml +16 -0
  627. package/rules/doubled-punctuation.yaml +45 -0
  628. package/rules/doubled-word.yaml +17 -1
  629. package/rules/duplicate-definition.yaml +59 -1
  630. package/rules/emoji-density.yaml +25 -0
  631. package/rules/empty-conclusion.yaml +28 -0
  632. package/rules/empty-intensifier.yaml +19 -0
  633. package/rules/excessive-hedging.yaml +19 -0
  634. package/rules/expletive-construction.yaml +19 -0
  635. package/rules/heading-echo.yaml +31 -0
  636. package/rules/heading-level-skip.yaml +78 -0
  637. package/rules/hiragana-fukushi.yaml +16 -0
  638. package/rules/image-alt-text.yaml +54 -0
  639. package/rules/internal-jargon.yaml +21 -0
  640. package/rules/katakana-long-vowel.yaml +98 -0
  641. package/rules/kutoten-consistency.yaml +53 -0
  642. package/rules/latin-spacing.yaml +23 -4
  643. package/rules/max-kanji-continuous.yaml +16 -0
  644. package/rules/max-paragraph-length.yaml +33 -0
  645. package/rules/max-sentence-length.yaml +32 -0
  646. package/rules/ngram-repetition.yaml +29 -2
  647. package/rules/no-doubled-joshi.yaml +16 -0
  648. package/rules/no-em-dash.yaml +25 -0
  649. package/rules/no-mixed-desumasu.yaml +27 -2
  650. package/rules/no-nakaguro-parallel.yaml +20 -0
  651. package/rules/numbering-gap.yaml +53 -1
  652. package/rules/oxford-comma-consistency.yaml +18 -0
  653. package/rules/padded-intro.yaml +19 -0
  654. package/rules/paragraph-length-variance.yaml +49 -0
  655. package/rules/percent-sum-mismatch.yaml +58 -0
  656. package/rules/preamble-length.yaml +56 -0
  657. package/rules/preferred-term.yaml +27 -0
  658. package/rules/proper-noun-density.yaml +26 -0
  659. package/rules/repeated-conjunction.yaml +47 -0
  660. package/rules/repeated-sentence-head.yaml +23 -0
  661. package/rules/required-sections.yaml +49 -0
  662. package/rules/risk-disclosure.yaml +22 -0
  663. package/rules/rule-of-three.yaml +97 -0
  664. package/rules/sasete-itadaku.yaml +18 -0
  665. package/rules/section-length-uniformity.yaml +89 -0
  666. package/rules/sentence-initial-conjunction-run.yaml +18 -0
  667. package/rules/sentence-rhythm.yaml +25 -0
  668. package/rules/stock-transition.yaml +55 -0
  669. package/rules/stray-space.yaml +18 -0
  670. package/rules/taigen-dome-in-prose.yaml +19 -0
  671. package/rules/title-case-consistency.yaml +42 -0
  672. package/rules/total-mismatch.yaml +37 -1
  673. package/rules/unbalanced-bracket.yaml +56 -0
  674. package/rules/undefined-acronym.yaml +22 -0
  675. package/rules/unfilled-placeholder.yaml +50 -0
  676. package/rules/unqualified-superlative.yaml +19 -0
  677. package/rules/unsourced-number.yaml +16 -0
  678. package/rules/url-run-on.yaml +45 -0
  679. package/skills/chaff/SKILL.md +70 -0
  680. package/src/announced-count.ts +148 -0
  681. package/src/bare-url.ts +35 -0
  682. package/src/baseline.ts +17 -1
  683. package/src/body-section.ts +7 -0
  684. package/src/calendar-number.ts +18 -4
  685. package/src/cli-args.ts +6 -0
  686. package/src/cli-text.ts +8 -4
  687. package/src/cli.ts +37 -37
  688. package/src/commands/compare.ts +80 -0
  689. package/src/commands/eval.ts +19 -8
  690. package/src/commands/feedback.ts +12 -6
  691. package/src/commands/test.ts +2 -4
  692. package/src/commands/tree.ts +41 -5
  693. package/src/compare/atom.ts +33 -0
  694. package/src/compare/clock-time.ts +86 -0
  695. package/src/compare/extract.ts +78 -0
  696. package/src/compare/fact-text.ts +68 -0
  697. package/src/compare/markup-atoms.ts +29 -0
  698. package/src/compare/match.ts +105 -0
  699. package/src/compare/outcome.ts +70 -0
  700. package/src/compare/proper-nouns.ts +65 -0
  701. package/src/compare/render.ts +102 -0
  702. package/src/compare/spans.ts +17 -0
  703. package/src/compare/text-atoms.ts +95 -0
  704. package/src/compare/text.ts +120 -0
  705. package/src/compare/tree-atoms.ts +80 -0
  706. package/src/compare/written-names.ts +26 -0
  707. package/src/config/load.ts +21 -0
  708. package/src/config/option-problems.ts +70 -0
  709. package/src/config/read.ts +8 -0
  710. package/src/config/rule-problems.ts +12 -2
  711. package/src/config/style.ts +42 -0
  712. package/src/config/warnings.ts +13 -0
  713. package/src/config/write.ts +18 -4
  714. package/src/custom/bounded-match.ts +58 -0
  715. package/src/custom/load.ts +15 -0
  716. package/src/custom/parse.ts +274 -0
  717. package/src/custom/problems.ts +89 -0
  718. package/src/custom/regex-safety.ts +118 -0
  719. package/src/custom/token-pattern.ts +84 -0
  720. package/src/detect.ts +28 -2
  721. package/src/detectors/acronym-context.ts +16 -4
  722. package/src/detectors/ai-phrasing.ts +137 -0
  723. package/src/detectors/announced-count.ts +25 -0
  724. package/src/detectors/broken-link.ts +90 -0
  725. package/src/detectors/cited-name.ts +6 -5
  726. package/src/detectors/cited-title.ts +96 -0
  727. package/src/detectors/concrete-evidence.ts +3 -2
  728. package/src/detectors/contrast-frame.ts +54 -0
  729. package/src/detectors/custom.ts +89 -0
  730. package/src/detectors/dangling-figure.ts +22 -0
  731. package/src/detectors/doubled-punctuation.ts +49 -0
  732. package/src/detectors/doubled-word.ts +19 -4
  733. package/src/detectors/enumerated-runs.ts +13 -4
  734. package/src/detectors/gram-furniture.ts +30 -0
  735. package/src/detectors/gram-place.ts +9 -5
  736. package/src/detectors/gram-windows.ts +31 -0
  737. package/src/detectors/heading-case.ts +30 -2
  738. package/src/detectors/heading-code-words.ts +35 -0
  739. package/src/detectors/heading-echo.ts +8 -4
  740. package/src/detectors/heading-level-skip.ts +19 -0
  741. package/src/detectors/image-alt-text.ts +11 -0
  742. package/src/detectors/index.ts +43 -1
  743. package/src/detectors/kutoten-consistency.ts +96 -0
  744. package/src/detectors/lead-in.ts +3 -1
  745. package/src/detectors/lexicon-match.ts +9 -2
  746. package/src/detectors/list-item.ts +122 -0
  747. package/src/detectors/list-items.ts +163 -0
  748. package/src/detectors/list-lead-in.ts +33 -0
  749. package/src/detectors/list-sentence.ts +157 -0
  750. package/src/detectors/list-view.ts +157 -0
  751. package/src/detectors/long-vowel.ts +66 -0
  752. package/src/detectors/markup-finding.ts +24 -0
  753. package/src/detectors/name-numeral.ts +4 -2
  754. package/src/detectors/orthography.ts +23 -17
  755. package/src/detectors/oxford-comma.ts +178 -283
  756. package/src/detectors/place-run.ts +7 -4
  757. package/src/detectors/placeholder-text.ts +27 -0
  758. package/src/detectors/quote-around.ts +9 -0
  759. package/src/detectors/register.ts +37 -10
  760. package/src/detectors/roman-numeral.ts +3 -0
  761. package/src/detectors/sentence-ending.ts +14 -7
  762. package/src/detectors/sentence-length.ts +16 -5
  763. package/src/detectors/signals.ts +80 -46
  764. package/src/detectors/structure-tree.ts +45 -1
  765. package/src/detectors/structure.ts +3 -4
  766. package/src/detectors/superlative-name.ts +7 -4
  767. package/src/detectors/superlative-scope.ts +8 -3
  768. package/src/detectors/token-column.ts +149 -0
  769. package/src/detectors/unbalanced-bracket.ts +153 -0
  770. package/src/detectors/url-run-on.ts +27 -0
  771. package/src/document-sections.ts +46 -0
  772. package/src/document.ts +106 -138
  773. package/src/email-parts.ts +269 -0
  774. package/src/eval.ts +14 -4
  775. package/src/figure-references.ts +112 -0
  776. package/src/files.ts +5 -0
  777. package/src/heading-label.ts +55 -0
  778. package/src/in-page-nav.ts +48 -19
  779. package/src/joined-view.ts +1 -0
  780. package/src/levels.ts +14 -1
  781. package/src/line-paragraphs.ts +52 -9
  782. package/src/long-vowel.ts +99 -0
  783. package/src/markdown-node.ts +19 -0
  784. package/src/markdown-read.ts +44 -0
  785. package/src/markup.ts +210 -0
  786. package/src/mask.ts +8 -8
  787. package/src/number-name.ts +151 -24
  788. package/src/orthography.ts +10 -3
  789. package/src/page-furniture.ts +11 -2
  790. package/src/plain-source.ts +2 -1
  791. package/src/plugin.ts +101 -1
  792. package/src/profile/for-file.ts +3 -1
  793. package/src/quoted-span.ts +9 -3
  794. package/src/reasons.ts +9 -0
  795. package/src/reference-lists.ts +91 -0
  796. package/src/render/explain.ts +47 -13
  797. package/src/render/friendly.ts +20 -9
  798. package/src/render/options.ts +58 -0
  799. package/src/render/rules-json.ts +130 -14
  800. package/src/render/rules-table.ts +91 -0
  801. package/src/render/sarif.ts +4 -4
  802. package/src/render/semantic.ts +3 -3
  803. package/src/render/severity-name.ts +10 -0
  804. package/src/render/text.ts +21 -7
  805. package/src/resolve-genre.ts +4 -1
  806. package/src/rule-genres.ts +25 -0
  807. package/src/rule-guide.ts +135 -0
  808. package/src/rule-load.ts +91 -34
  809. package/src/rule-options.ts +131 -0
  810. package/src/run.ts +74 -11
  811. package/src/sentence-shape.ts +4 -5
  812. package/src/setting-problems.ts +7 -1
  813. package/src/span-cut.ts +28 -0
  814. package/src/structure/aside-depth.ts +67 -0
  815. package/src/structure/build.ts +38 -19
  816. package/src/structure/closed-pairs.ts +20 -0
  817. package/src/structure/date-range.ts +69 -0
  818. package/src/structure/known-mentions.ts +96 -0
  819. package/src/structure/numbering.ts +9 -5
  820. package/src/structure/of.ts +11 -3
  821. package/src/structure/percent-sum.ts +135 -0
  822. package/src/structure/quoted-number.ts +36 -0
  823. package/src/structure/relative-find.ts +34 -47
  824. package/src/structure/relative-resolve.ts +77 -30
  825. package/src/structure/runs.ts +2 -2
  826. package/src/structure/sexp.ts +17 -5
  827. package/src/structure/total.ts +2 -2
  828. package/src/structure/universal.ts +24 -4
  829. package/src/structure/wrapped-tail.ts +38 -13
  830. package/src/style-load.ts +28 -0
  831. package/src/style-parse.ts +77 -0
  832. package/src/subheading-line.ts +68 -0
  833. package/src/template-syntax.ts +164 -0
  834. package/src/text-above.ts +49 -0
  835. package/src/text-figures.ts +147 -0
  836. package/src/trailing-aside.ts +50 -0
  837. package/src/tree-walk.ts +48 -0
  838. package/styles/bunkacho.yaml +25 -0
  839. package/styles/ieice.yaml +29 -0
  840. package/styles/jis-z8301-2011.yaml +25 -0
package/src/eval.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { DETECTORS } from "./detectors/index.ts";
2
2
  import { charLength } from "./measure.ts";
3
- import type { ProseDocument, RuleDefinition } from "./plugin.ts";
3
+ import type { DetectorOptions, ProseDocument, RuleDefinition } from "./plugin.ts";
4
+ import { optionValues, settleOptions, type OptionLayer } from "./rule-options.ts";
4
5
  import { missingList } from "./declared-lists.ts";
6
+ import { bodySectionOf } from "./body-section.ts";
5
7
 
6
8
  /**
7
9
  * 閾値の較正。
@@ -44,12 +46,12 @@ const candidates = (rule: RuleDefinition, current: number): number[] => {
44
46
  return [...new Set([...fromLevels, ...scaled, current])].toSorted((left, right) => left - right);
45
47
  };
46
48
 
47
- const countAt = (docs: readonly ProseDocument[], rule: RuleDefinition, limit: number): Point => {
49
+ const countAt = (docs: readonly ProseDocument[], rule: RuleDefinition, limit: number, settings: DetectorOptions["settings"]): Point => {
48
50
  const detector = DETECTORS[rule.how_to_find];
49
51
  if (detector === undefined) return { limit, findings: 0, documents: 0, per10k: 0 };
50
52
  const perDoc = docs.map((doc) => {
51
53
  const lexicon = rule.word_list === undefined ? undefined : doc.lexicons[rule.word_list];
52
- return detector(doc, { limit, lexicon, where: rule.where }).length;
54
+ return detector(doc, { limit, lexicon, where: rule.where, settings }).length;
53
55
  });
54
56
  const findings = perDoc.reduce((sum, count) => sum + count, 0);
55
57
  const chars = docs.reduce((sum, doc) => sum + doc.sentences.reduce((inner, sentence) => inner + charLength(sentence), 0), 0);
@@ -71,6 +73,10 @@ const meets = (need: string, docs: readonly ProseDocument[]): boolean => {
71
73
  if (need === "lemma") return capabilities?.lemma === true;
72
74
  // 木は adapter が structure を持つときだけ作れる。無いまま測ると、どの閾値でも 0 件になる。
73
75
  if (need === "structure") return docs.length > 0 && docs.every((doc) => doc.structure !== undefined);
76
+ // 見出しの無い文書では lint が動かない。見出しのある文書が 1 つも無ければ、どの閾値でも 0 件になる。
77
+ if (need === "headings") return docs.some((doc) => bodySectionOf(doc.sections) !== undefined);
78
+ // 記法を読む rule は Markdown の文書でしか動かない。
79
+ if (need === "markdown") return docs.some((doc) => doc.markup?.markdown === true);
74
80
  return false;
75
81
  };
76
82
 
@@ -80,6 +86,8 @@ const meets = (need: string, docs: readonly ProseDocument[]): boolean => {
80
86
  */
81
87
  const measurable = (rule: RuleDefinition, docs: readonly ProseDocument[], genre: string, language: string): boolean => {
82
88
  if (rule.layer === "L4" || !rule.use_for.some((target) => genre.startsWith(target))) return false;
89
+ // A rule with nothing to count has no limit to sweep: its levels set severity.
90
+ if (rule.level_sets === "severity") return false;
83
91
  if (rule.languages !== undefined && !rule.languages.includes(language)) return false;
84
92
  if (rule.from.length > 0) return false;
85
93
  if (docs.some((doc) => missingList(rule, doc.lexicons) !== undefined)) return false;
@@ -96,12 +104,14 @@ export const evaluate = (
96
104
  genre: string,
97
105
  language: string,
98
106
  limits: Readonly<Record<string, number>> = {},
107
+ optionLayers: readonly OptionLayer[] = [],
99
108
  ): RuleReport[] =>
100
109
  rules
101
110
  .filter((rule) => measurable(rule, docs, genre, language))
102
111
  .map((rule) => {
103
112
  const current = limits[rule.id] ?? rule.levels.normal ?? 1;
104
- const sweep = candidates(rule, current).map((limit) => countAt(docs, rule, limit));
113
+ const settings = rule.options === undefined ? undefined : optionValues(settleOptions(rule.id, rule.options, optionLayers));
114
+ const sweep = candidates(rule, current).map((limit) => countAt(docs, rule, limit, settings));
105
115
  return {
106
116
  rule: rule.id,
107
117
  name: rule.name[language] ?? rule.id,
@@ -0,0 +1,112 @@
1
+ import { escapeRegExp } from "./orthography.ts";
2
+ import type { Span } from "./plugin.ts";
3
+
4
+ /**
5
+ * 本文で番号を指した図・表・付録(図3、Table 2、Appendix B)と、それを行の頭に書いた所(キャプション、見出し)。
6
+ * 行の頭に一度も書いていない番号を指していれば、参照先が無い。その種類(図、表)を行の頭に一つも書いていない文書は見ない。
7
+ * 図が別の紙にある文書かもしれない。言語の知識(図や表の語、略した書き方、別の文書を指す語)は語彙表から受け取る。
8
+ */
9
+ type LabelWord = {
10
+ readonly word: string;
11
+ /** 同じものを指す書き方をまとめる名前。「Fig.」は Figure。 */
12
+ readonly kind: string;
13
+ };
14
+
15
+ export type LabelWords = {
16
+ readonly labels: readonly LabelWord[];
17
+ /** 番号のすぐ後ろにあると、別の文書の図になる語(of、in)。 */
18
+ readonly elsewhere: readonly string[];
19
+ /** 番号のすぐ後ろにあると、図の数になる語(図3枚)。 */
20
+ readonly counters: readonly string[];
21
+ };
22
+
23
+ export type DanglingFigure = { readonly offset: number; readonly label: string };
24
+
25
+ type Mention = { readonly start: number; readonly end: number; readonly written: string; readonly key: string; readonly kind: string };
26
+
27
+ /** 語の前の字が漢字・カタカナ・英数字なら、長い語の一部(地図3、一覧表2、法別表第二、SubFigure)。 */
28
+ const INSIDE_WORD = "(?<![\\p{Script=Han}\\p{Script=Katakana}\\p{N}A-Za-z])";
29
+ /** 番号。数字(3、3.2、第3)、「第」の後の漢数字(別表第一)、大文字一つかローマ数字(Appendix B、Annex II)。 */
30
+ const NUMBER = "[ \\t\\u00a0]?(?:第?(\\p{Nd}+(?:[.\\--]\\p{Nd}+)*)|第([一二三四五六七八九十百]+)|([IVX]{2,5}|[A-ZA-Z])(?![A-Za-z]))";
31
+
32
+ const forms = (word: string): string[] => [...new Set([word, word.toUpperCase()])];
33
+
34
+ const mentionPattern = (labels: readonly LabelWord[]): RegExp => {
35
+ const words = labels
36
+ .flatMap((label) => forms(label.word))
37
+ .toSorted((a, b) => b.length - a.length)
38
+ .map(escapeRegExp);
39
+ return new RegExp(`${INSIDE_WORD}(${words.join("|")})${NUMBER}`, "gu");
40
+ };
41
+
42
+ const kindOf = (written: string, labels: readonly LabelWord[]): string => labels.find((label) => forms(label.word).includes(written))?.kind ?? written;
43
+
44
+ /** 同じ図は同じ鍵。全角の数字と字は半角に揃える。 */
45
+ const mentionsIn = (text: string, labels: readonly LabelWord[]): Mention[] =>
46
+ [...text.matchAll(mentionPattern(labels))].map((match) => {
47
+ const kind = kindOf(match[1] ?? "", labels);
48
+ const number = (match[2] ?? match[3] ?? match[4] ?? "").normalize("NFKC");
49
+ return { start: match.index, end: match.index + match[0].length, written: match[0].trim(), key: `${kind}\u0000${number}`, kind };
50
+ });
51
+
52
+ type Scan = { readonly depth: number; readonly kept: string; readonly previous: string };
53
+
54
+ /** 開きの括弧。「(」はリンクの行き先([...](...))のときだけ、つまり「]」のすぐ後ろだけ。 */
55
+ const opens = (char: string, previous: string): boolean => char === "[" || char === "<" || (char === "(" && previous === "]");
56
+ const CLOSERS = "])>";
57
+
58
+ const step = (state: Scan, char: string): Scan => {
59
+ if (opens(char, state.previous)) return { depth: state.depth + 1, kept: state.kept, previous: char };
60
+ if (state.depth > 0 && CLOSERS.includes(char)) return { depth: state.depth - 1, kept: state.kept, previous: char };
61
+ return { depth: state.depth, kept: state.depth === 0 ? state.kept + char : state.kept, previous: char };
62
+ };
63
+
64
+ /** 括弧の外の字。リンクと画像の書き方([...](...))と HTML の札(<b>)の中身は、行の頭の飾りとして読み飛ばす。 */
65
+ const outsideMarkup = (text: string): string => [...text].reduce(step, { depth: 0, kept: "", previous: "" }).kept;
66
+ const LETTER = /\p{L}/u;
67
+
68
+ const HEADING = /^[ \t]{0,3}#/u;
69
+
70
+ /**
71
+ * 番号の後ろが題の区切りか。行の終わり、区切りの記号(: . — | 括弧)、または空白のあとの題の書き出し。
72
+ * 空白のあとがひらがなか英語の小文字なら、本文の文(図3の例では、Figure 3 shows)で、キャプションではない。
73
+ */
74
+ const CAPTION_AFTER = /^(?:[ \t]*$|[::..—–\-|()()【】\]*_]|[ \t\u3000]+[^\p{Script=Hiragana}\p{Ll}])/u;
75
+
76
+ /**
77
+ * 行の頭に書いた番号。前にあるのが飾り(#、**、![、|、【、箇条書きの印)だけで、見出しの中か、後ろが題の区切りならキャプション。
78
+ * 行の頭から始まる本文の文(図3の例では、…)は、図の置き場所ではない。
79
+ */
80
+ const isLabelled = (source: string, mention: Mention): boolean => {
81
+ const lineStart = source.lastIndexOf("\n", mention.start - 1) + 1;
82
+ const lineEnd = source.indexOf("\n", mention.end);
83
+ const before = source.slice(lineStart, mention.start);
84
+ if (LETTER.test(outsideMarkup(before))) return false;
85
+ return HEADING.test(before) || CAPTION_AFTER.test(source.slice(mention.end, lineEnd === -1 ? source.length : lineEnd));
86
+ };
87
+
88
+ const LATIN_WORD = /^[A-Za-z]/u;
89
+
90
+ /** 番号のすぐ後ろの語。別の文書の図(Figure 5 of the report)か、図の数(図3枚)なら参照として見ない。 */
91
+ const pointsHere = (text: string, mention: Mention, words: LabelWords): boolean => {
92
+ const after = text.slice(mention.end);
93
+ const trimmed = after.trimStart();
94
+ const elsewhere = words.elsewhere.some((word) => after !== trimmed && trimmed.startsWith(word) && !LATIN_WORD.test(trimmed.slice(word.length)));
95
+ return !elsewhere && !words.counters.some((word) => after.startsWith(word));
96
+ };
97
+
98
+ /**
99
+ * 参照先の無い番号。source は行の頭を読み、prose(コードを覆った本文)は参照を読む。位置は同じ。
100
+ * 番号は、キャプションが 1 と書けば 1a や 1(b) の参照も 1 に当たる(番号の後ろの字は読まない)。
101
+ * リンクの字([Figure 2](figures.md))は、そのリンクが行き先を持つので参照として見ない。
102
+ */
103
+ export const danglingFigures = (source: string, prose: string, words: LabelWords, links: readonly Span[] = []): DanglingFigure[] => {
104
+ if (words.labels.length === 0) return [];
105
+ const labelled = mentionsIn(source, words.labels).filter((mention) => isLabelled(source, mention));
106
+ const labelledKeys = new Set(labelled.map((mention) => mention.key));
107
+ const labelledKinds = new Set(labelled.map((mention) => mention.kind));
108
+ return mentionsIn(prose, words.labels)
109
+ .filter((mention) => labelledKinds.has(mention.kind) && !labelledKeys.has(mention.key))
110
+ .filter((mention) => pointsHere(prose, mention, words) && !links.some((link) => link.start <= mention.start && mention.end <= link.end))
111
+ .map((mention) => ({ offset: mention.start, label: mention.written }));
112
+ };
package/src/files.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { globSync, statSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
2
3
  import { join, relative, sep } from "node:path";
4
+ import { plainSource } from "./plain-source.ts";
5
+
6
+ /** 検査する文書を読む。言語・ジャンル・stet も文書モデルと同じ本文(BOM と CRLF / CR をそろえたもの)で読むため、ここでそろえる。 */
7
+ export const readDocumentFile = async (path: string): Promise<string> => plainSource(await readFile(path, "utf8"));
3
8
 
4
9
  const MARKDOWN = [".md", ".markdown", ".mdx"];
5
10
 
@@ -0,0 +1,55 @@
1
+ import type { Lexicon, NumberingContext, StructurePatterns, Token } from "./plugin.ts";
2
+ import { universalNumber } from "./structure/universal.ts";
3
+
4
+ const ON_HEADING: NumberingContext = { open: [], isHeading: true };
5
+
6
+ /** 木を組むときと同じ読み方(numbering-gap が比べる番号)で読んだ、番号の後ろの題。「第2章 概要」「Chapter 2: Setup」「1. はじめに」。 */
7
+ const numberedTitle = (heading: string, patterns: StructurePatterns): string | undefined => {
8
+ const numbered = patterns.numbered(heading, ON_HEADING) ?? universalNumber(patterns, heading, ON_HEADING, false);
9
+ return numbered === undefined || numbered.heading === "" ? undefined : numbered.heading;
10
+ };
11
+
12
+ const SPECIAL = /[.*+?^${}()|[\]\\]/gu;
13
+
14
+ /**
15
+ * 番号の前に書いて名前を付ける語(語彙表 numbered-label の before: 例・問・Step)と番号と区切りで始まる見出しの、札の部分。
16
+ * 区切りはコロンか空白。札の後ろに題が無ければ当てない。木はこの札を番号として読まない。
17
+ */
18
+ export const labelPatternOf = (labelWords: readonly string[]): RegExp | undefined => {
19
+ if (labelWords.length === 0) return undefined;
20
+ const words = labelWords.map((word) => word.replace(SPECIAL, String.raw`\$&`)).join("|");
21
+ return new RegExp(String.raw`^(?:${words})[ \t\u3000]?[0-90-9]+(?:[..][0-90-9]+)*(?:[ \t\u3000]*[::][ \t\u3000]*|[ \t\u3000]+)(?=\S)`, "u");
22
+ };
23
+
24
+ /**
25
+ * 見出しの頭の番号の札を除いた題。札は本文で繰り返されないので、見出しと文の重なりを測るときは数えない。
26
+ * 番号は木と同じ読み方で読み、木が読まない札(「例 3:」「Step 3:」)は語彙表の語で読む。札が無ければ見出しのまま。
27
+ */
28
+ export const unlabeledHeading = (heading: string, patterns: StructurePatterns | undefined, labelPattern: RegExp | undefined): string => {
29
+ const titled = patterns === undefined ? undefined : numberedTitle(heading, patterns);
30
+ if (titled !== undefined) return titled;
31
+ const label = labelPattern?.exec(heading)?.[0];
32
+ return label === undefined ? heading : heading.slice(label.length);
33
+ };
34
+
35
+ /**
36
+ * 見出しごとに、札を除いた題を読まれたときに一度だけ読む関数。読むのは heading-echo だけなので、ほかの rule には番号を読む代金を払わせない。
37
+ * 札の語は語彙表 numbered-label の before。
38
+ */
39
+ export const unlabeledReader = (patterns: StructurePatterns | undefined, lexicons: Readonly<Record<string, Lexicon>>): ((heading: string) => () => string) => {
40
+ const labelWords = (lexicons["numbered-label"] ?? []).filter((entry) => entry.position === "before").map((entry) => entry.pattern);
41
+ const labelPattern = labelPatternOf(labelWords);
42
+ return (heading) => {
43
+ const memo: { value?: string } = {};
44
+ return () => (memo.value ??= unlabeledHeading(heading, patterns, labelPattern));
45
+ };
46
+ };
47
+
48
+ /**
49
+ * 見出しの語のうち、札より後ろ(題)のもの。tokens の位置は見出しの中の位置。札の語(例・Step)を見出しにある語と数えると、
50
+ * 文が札の語を使っただけ(例として…)で「見出しに無い語を足していない」ことになる。
51
+ */
52
+ export const titleTokens = (heading: string, title: string, tokens: readonly Token[]): readonly Token[] => {
53
+ const titleStart = heading.lastIndexOf(title);
54
+ return tokens.filter((token) => token.span.start >= titleStart);
55
+ };
@@ -1,3 +1,5 @@
1
+ import { eachPreOrder } from "./tree-walk.ts";
2
+
1
3
  /** mdast の節のうち、ページ内の案内かどうかの判定に要る部分だけ。 */
2
4
  export type NavNode = {
3
5
  readonly type: string;
@@ -17,28 +19,44 @@ const WRAPPERS = new Set(["strong", "emphasis", "delete"]);
17
19
 
18
20
  const pointsInPage = (url: string | undefined): boolean => (url ?? "").startsWith("#");
19
21
 
20
- const collectAnchors = (node: NavNode, found: Set<string>): void => {
21
- if (node.type === "definition" && node.identifier !== undefined && pointsInPage(node.url)) found.add(node.identifier);
22
- (node.children ?? []).forEach((child) => collectAnchors(child, found));
23
- };
24
-
25
22
  export const inPageAnchors = (root: NavNode): InPageAnchors => {
26
23
  const found = new Set<string>();
27
- collectAnchors(root, found);
24
+ eachPreOrder(root, (node) => {
25
+ if (node.type === "definition" && node.identifier !== undefined && pointsInPage(node.url)) found.add(node.identifier);
26
+ });
28
27
  return found;
29
28
  };
30
29
 
31
30
  const isInPageLink = (node: NavNode, anchors: InPageAnchors): boolean =>
32
31
  (node.type === "link" && pointsInPage(node.url)) || (node.type === "linkReference" && anchors.has(node.identifier ?? ""));
33
32
 
33
+ /** What must also be a part for this node to be one: nothing for a link or symbols, the children of emphasis. undefined when it is prose. */
34
+ const partsWithin = (node: NavNode, anchors: InPageAnchors): readonly NavNode[] | undefined => {
35
+ if (isInPageLink(node, anchors) || node.type === "break") return [];
36
+ if (node.type === "text") return WORD.test(node.value ?? "") ? undefined : [];
37
+ return WRAPPERS.has(node.type) ? (node.children ?? []) : undefined;
38
+ };
39
+
34
40
  const isNavigationPart = (node: NavNode, anchors: InPageAnchors): boolean => {
35
- if (isInPageLink(node, anchors) || node.type === "break") return true;
36
- if (node.type === "text") return !WORD.test(node.value ?? "");
37
- return WRAPPERS.has(node.type) && (node.children ?? []).every((child) => isNavigationPart(child, anchors));
41
+ const pending: NavNode[] = [node];
42
+ while (pending.length > 0) {
43
+ const next = pending.pop();
44
+ const within = next === undefined ? [] : partsWithin(next, anchors);
45
+ if (within === undefined) return false;
46
+ within.forEach((child) => pending.push(child));
47
+ }
48
+ return true;
38
49
  };
39
50
 
40
- const containsInPageLink = (node: NavNode, anchors: InPageAnchors): boolean =>
41
- isInPageLink(node, anchors) || (node.children ?? []).some((child) => containsInPageLink(child, anchors));
51
+ const containsInPageLink = (node: NavNode, anchors: InPageAnchors): boolean => {
52
+ const pending: NavNode[] = [node];
53
+ while (pending.length > 0) {
54
+ const next = pending.pop();
55
+ if (next !== undefined && isInPageLink(next, anchors)) return true;
56
+ (next?.children ?? []).forEach((child) => pending.push(child));
57
+ }
58
+ return false;
59
+ };
42
60
 
43
61
  /**
44
62
  * 同じページの中へのリンク(`](#…)`)と記号だけでできた段落。「▲ 目次に戻る」や目次の項目で、本文ではなくページの案内。
@@ -53,15 +71,26 @@ export const isInPageNavigation = (paragraph: NavNode, anchors: InPageAnchors =
53
71
  );
54
72
  };
55
73
 
56
- const isNavigationBlock = (node: NavNode, anchors: InPageAnchors): boolean => isInPageNavigation(node, anchors) || isNavigationList(node, anchors);
57
-
58
- const isNavigationItem = (item: NavNode, anchors: InPageAnchors): boolean => {
59
- const children = item.children ?? [];
60
- return item.type === "listItem" && children.length > 0 && children.every((child) => isNavigationBlock(child, anchors));
74
+ /** The blocks inside a list's items, or undefined unless it is a list whose every item holds a block. */
75
+ const itemBlocks = (list: NavNode): readonly NavNode[] | undefined => {
76
+ const items = list.children ?? [];
77
+ if (list.type !== "list" || items.length === 0) return undefined;
78
+ const blocks = items.map((item) => (item.type === "listItem" ? (item.children ?? []) : []));
79
+ return blocks.some((children) => children.length === 0) ? undefined : blocks.flat();
61
80
  };
62
81
 
63
- /** 項目がどれもページの案内(入れ子も含む)の箇条書き。目次の項目の数は節の数で決まり、書いた人が選んだ並べ方ではない。 */
82
+ /**
83
+ * 項目がどれもページの案内(入れ子も含む)の箇条書き。目次の項目の数は節の数で決まり、書いた人が選んだ並べ方ではない。
84
+ * 項目の中の段落はページの案内の段落で、段落でない塊は、それ自身がページの案内の箇条書き。
85
+ */
64
86
  export const isNavigationList = (list: NavNode, anchors: InPageAnchors = new Set()): boolean => {
65
- const items = list.children ?? [];
66
- return list.type === "list" && items.length > 0 && items.every((item) => isNavigationItem(item, anchors));
87
+ const pending: NavNode[] = [list];
88
+ while (pending.length > 0) {
89
+ const next = pending.pop();
90
+ const blocks = next === undefined ? [] : itemBlocks(next);
91
+ if (blocks === undefined) return false;
92
+ if (!blocks.every((block) => block.type !== "paragraph" || isInPageNavigation(block, anchors))) return false;
93
+ blocks.filter((block) => block.type !== "paragraph").forEach((block) => pending.push(block));
94
+ }
95
+ return true;
67
96
  };
@@ -61,6 +61,7 @@ const sentenceInSource =
61
61
  span,
62
62
  text: text.slice(span.start, span.end),
63
63
  ...(sentence.tokens === undefined ? {} : { tokens: sentence.tokens.map(tokenInSource(view)) }),
64
+ ...(sentence.embeddedLanguage === undefined ? {} : { embeddedLanguage: sentence.embeddedLanguage }),
64
65
  };
65
66
  };
66
67
 
package/src/levels.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Level, LevelTable, RuleDefinition } from "./plugin.ts";
1
+ import type { Level, LevelTable, RuleDefinition, Severity } from "./plugin.ts";
2
2
 
3
3
  const LEVELS: readonly Level[] = ["strict", "normal", "relaxed", "off"];
4
4
 
@@ -37,3 +37,16 @@ export const resolve = (rule: RuleDefinition, level: Level, genre?: string): Res
37
37
 
38
38
  /** その rule が実際に区別できる段だけを返す。CLI の案内に使う。 */
39
39
  export const definedLevels = (rule: RuleDefinition): Level[] => LEVELS.filter((level) => level === "off" || rule.levels[level] !== undefined);
40
+
41
+ /** Lightest first: a level table holds info as 1, warning as 2 and error as 3. */
42
+ const SEVERITY_BY_RANK: readonly Severity[] = ["info", "warning", "error"];
43
+
44
+ /** A severity written in a level table, as the number the table holds. */
45
+ export const rankOfSeverity = (value: unknown): number | undefined => {
46
+ const index = SEVERITY_BY_RANK.findIndex((entry) => entry === value);
47
+ return index === -1 ? undefined : index + 1;
48
+ };
49
+
50
+ /** The severity a rule with nothing to count gives its findings at a level. A counting rule keeps its own. */
51
+ export const severityAt = (rule: RuleDefinition, level: Exclude<Level, "off">, genre?: string): Severity =>
52
+ rule.level_sets === "severity" ? (SEVERITY_BY_RANK[resolve(rule, level, genre).limit - 1] ?? rule.severity) : rule.severity;
@@ -10,6 +10,7 @@ import type { Span } from "./plugin.ts";
10
10
  * (議事録は発言者の行と発言の行が交互に来るので、半分ちょうどは割る)。
11
11
  * - 1 行 1 文の書き方(行を意味の切れ目で改める。英語の Markdown に多い)は、段落のつもりではない。
12
12
  * 文の頭で始まり文の終わりで終わる行が 2 文以上を持つことが、段落を 1 行に書いた印。それがたまにしか無ければ割らない。
13
+ * この印は文書全体で数える(documentIsLineShaped)。
13
14
  */
14
15
 
15
16
  /** 2 文以上を持つ行がこれより少なければ、1 行 1 文の書き方にたまに混じる 2 文の行と見分けられない。 */
@@ -69,18 +70,60 @@ const sentencesIn = (group: Span, cores: readonly Span[]): number => firstStarti
69
70
  const wholeMultiSentenceLines = (lines: readonly Line[], closing: readonly boolean[], cores: readonly Span[]): number =>
70
71
  lines.filter((line, index) => (index === 0 || closing[index - 1] === true) && closing[index] === true && sentencesIn(line.span, cores) >= 2).length;
71
72
 
72
- /** 行ごとの段落として読む形か。 */
73
- const isLineShaped = (lines: readonly Line[], closing: readonly boolean[], groups: readonly Span[], cores: readonly Span[]): boolean => {
74
- const closed = closing.filter(Boolean).length;
75
- const multi = wholeMultiSentenceLines(lines, closing, cores);
76
- return closed * 2 >= closing.length && multi >= MIN_MULTI_SENTENCE && multi >= groups.length * MULTI_SENTENCE_SHARE;
73
+ /** 1 つの段落の形: 割るならどこで割るか(groups)と、行ごとの段落と読む手がかり。 */
74
+ type Shape = {
75
+ readonly paragraph: Span;
76
+ readonly groups: readonly Span[];
77
+ readonly lines: number;
78
+ /** 文で終わる行が半分以上。届かなければ固定幅の折り返し。 */
79
+ readonly mostlyClosed: boolean;
80
+ /** 文の頭で始まり文の終わりで終わる、2 文以上の行の数。 */
81
+ readonly multi: number;
77
82
  };
78
83
 
79
- /** paragraph を、書いた人が段落のつもりで改めた行ごとに割る。そう読めなければ paragraph 1 つ。sentences は段落の中の文。 */
80
- export const lineParagraphs = (source: string, paragraph: Span, sentences: readonly Span[]): Span[] => {
84
+ const shapeOf = (source: string, paragraph: Span, sentences: readonly Span[]): Shape => {
81
85
  const lines = linesOf(source, paragraph);
82
86
  const cores = sentences.map((sentence) => coreOf(source, sentence)).filter((core) => core.end > core.start);
83
87
  const closing = lines.map((line) => hasText(source, line) && endsSentence(line, cores));
84
- const groups = groupAt(lines, closing);
85
- return isLineShaped(lines, closing, groups, cores) ? groups : [paragraph];
88
+ return {
89
+ paragraph,
90
+ groups: groupAt(lines, closing),
91
+ lines: lines.length,
92
+ mostlyClosed: closing.filter(Boolean).length * 2 >= closing.length,
93
+ multi: wholeMultiSentenceLines(lines, closing, cores),
94
+ };
95
+ };
96
+
97
+ /** 2 文以上の行が、1 行 1 文の書き方にたまに混じる数より多い。 */
98
+ const enoughMulti = (multi: number, groups: number): boolean => multi >= MIN_MULTI_SENTENCE && multi >= groups * MULTI_SENTENCE_SHARE;
99
+
100
+ /**
101
+ * 文書が 1 行 1 段落で書かれているか。書き方は書き手のもので、段落 1 つずつでは決まらない(見出しごとの短い段落が並ぶ演説)。
102
+ * 手がかりは、2 行以上あって折り返しでない段落だけから集める。1 行だけの段落は空行で区切った普通の段落で、1 行 1 段落の印ではない。
103
+ */
104
+ const documentIsLineShaped = (shapes: readonly Shape[]): boolean => {
105
+ const evidence = shapes.filter((shape) => shape.lines > 1 && shape.mostlyClosed);
106
+ const total = (count: (shape: Shape) => number): number => evidence.reduce((sum, shape) => sum + count(shape), 0);
107
+ return enoughMulti(
108
+ total((shape) => shape.multi),
109
+ total((shape) => shape.groups.length),
110
+ );
86
111
  };
112
+
113
+ /** 割るか: 折り返しでなく、段落だけで、または文書全体で、行ごとの段落と読める。 */
114
+ const splits = (shape: Shape, lineShapedDocument: boolean): boolean =>
115
+ shape.mostlyClosed && (lineShapedDocument || enoughMulti(shape.multi, shape.groups.length));
116
+
117
+ /**
118
+ * 文書の段落(並び順)を、書いた人が段落のつもりで改めた行ごとに割った段落。そう読めない段落はそのまま。
119
+ * sentences は段落の中の文。
120
+ */
121
+ export const documentLineParagraphs = (source: string, paragraphs: readonly { readonly span: Span; readonly sentences: readonly Span[] }[]): Span[] => {
122
+ const shapes = paragraphs.map((paragraph) => shapeOf(source, paragraph.span, paragraph.sentences));
123
+ const lineShaped = documentIsLineShaped(shapes);
124
+ return shapes.flatMap((shape) => (splits(shape, lineShaped) ? shape.groups : [shape.paragraph]));
125
+ };
126
+
127
+ /** paragraph を、書いた人が段落のつもりで改めた行ごとに割る。そう読めなければ paragraph 1 つ。sentences は段落の中の文。 */
128
+ export const lineParagraphs = (source: string, paragraph: Span, sentences: readonly Span[]): Span[] =>
129
+ documentLineParagraphs(source, [{ span: paragraph, sentences }]);
@@ -0,0 +1,99 @@
1
+ // The final long-vowel mark (ー) of katakana loanwords: how long a word is, and which written forms go against the chosen way.
2
+ // Pure: the words come in already picked from the document's tokens.
3
+
4
+ /** Small kana that join the kana before them into one mora (キャ, ファ, ウィ). ッ, ン and ー are morae of their own. */
5
+ const JOINING: ReadonlySet<string> = new Set(Array.from("ァィゥェォャュョヮぁぃぅぇぉゃゅょゎ"));
6
+
7
+ /** The number of morae (音) in a kana word: コンピューター is コ・ン・ピュ・ー・タ・ー, six. */
8
+ export const moraCount = (word: string): number => Array.from(word).filter((char) => !JOINING.has(char)).length;
9
+
10
+ const LONG_VOWEL = "ー";
11
+ const KATAKANA_WORD = /^[ァ-ヺー]+$/u;
12
+
13
+ /** A katakana word without its final ー: the part both ways of writing it share (コンピュータ for コンピューター). */
14
+ export const stemOf = (surface: string): string => {
15
+ const chars = Array.from(surface);
16
+ return chars.slice(0, chars.findLastIndex((char) => char !== LONG_VOWEL) + 1).join("");
17
+ };
18
+
19
+ /** Whether the surface is a katakana word with something besides ー in it. */
20
+ export const isKatakanaWord = (surface: string): boolean => KATAKANA_WORD.test(surface) && stemOf(surface) !== "";
21
+
22
+ /** A katakana word the rule reads: where it is, how it is written, and whether a final ー could be written or dropped. */
23
+ export type KanaWord = {
24
+ readonly surface: string;
25
+ readonly offset: number;
26
+ /** Written with a final ー. */
27
+ readonly long: boolean;
28
+ /** Written without one, and the dictionary knows the form with one (the language adapter's LongVowelEnding=Dropped). */
29
+ readonly dropped: boolean;
30
+ };
31
+
32
+ /** The morae of the word written with its final ー: カー is two, コンピューター six. The guidelines count the word that way. */
33
+ export const longFormMorae = (surface: string): number => moraCount(stemOf(surface)) + 1;
34
+
35
+ export type Ending = "consistent" | "drop" | "keep";
36
+
37
+ export type Odd = {
38
+ readonly word: KanaWord;
39
+ /** How the rule found it: same-word (one word written both ways), drop or keep (against the setting). */
40
+ readonly variant: "same-word" | "drop" | "keep";
41
+ /** The form the rule asks for. */
42
+ readonly preferred: string;
43
+ /** For same-word: how many times the word is written the way this one is, and how many times in all. */
44
+ readonly count: number;
45
+ readonly of: number;
46
+ };
47
+
48
+ const otherForm = (word: KanaWord): string => (word.long ? stemOf(word.surface) : `${word.surface}${LONG_VOWEL}`);
49
+
50
+ /** The side written less; on a tie, the side the document did not use first. undefined when only one side is used. */
51
+ const minorityLong = (words: readonly KanaWord[]): boolean | undefined => {
52
+ const long = words.filter((word) => word.long).length;
53
+ const short = words.length - long;
54
+ if (long === 0 || short === 0) return undefined;
55
+ if (long !== short) return long < short;
56
+ return !(words[0]?.long ?? false);
57
+ };
58
+
59
+ const minorityOf = (words: readonly KanaWord[], variant: Odd["variant"]): Odd[] => {
60
+ const minority = minorityLong(words);
61
+ if (minority === undefined) return [];
62
+ const odd = words.filter((word) => word.long === minority);
63
+ return odd.map((word) => ({ word, variant, preferred: otherForm(word), count: odd.length, of: words.length }));
64
+ };
65
+
66
+ /** The document's words grouped by the part both ways share (コンピュータ with コンピューター). */
67
+ const sameWordGroups = (words: readonly KanaWord[]): KanaWord[][] => {
68
+ const groups = new Map<string, KanaWord[]>();
69
+ words.forEach((word) => {
70
+ const stem = stemOf(word.surface);
71
+ const group = groups.get(stem);
72
+ if (group === undefined) groups.set(stem, [word]);
73
+ else group.push(word);
74
+ });
75
+ return [...groups.values()];
76
+ };
77
+
78
+ /**
79
+ * With no side taken: a word written both ways (コンピュータ and コンピューター), at its fewer form. Different words are not compared:
80
+ * a document may write サーバー and ブラウザ by each word's usual spelling, and no guideline makes that a mistake.
81
+ */
82
+ const inconsistent = (words: readonly KanaWord[]): Odd[] => sameWordGroups(words).flatMap((group) => minorityOf(group, "same-word"));
83
+
84
+ /**
85
+ * The words that go against the chosen way. drop: a word of minMorae or more written with its final ー. keep: a word written
86
+ * without one where the dictionary, or the document itself, has the form with one. consistent: see inconsistent.
87
+ * Words shorter than minMorae are left alone whichever way: the guidelines that drop the ー keep it on them (カー).
88
+ */
89
+ export const oddLongVowels = (words: readonly KanaWord[], ending: Ending, minMorae: number): Odd[] => {
90
+ const counted = words.filter((word) => longFormMorae(word.surface) >= minMorae);
91
+ if (ending === "drop") return counted.filter((word) => word.long).map((word) => ({ word, variant: "drop", preferred: otherForm(word), count: 0, of: 0 }));
92
+ if (ending === "keep") {
93
+ const longStems = new Set(counted.filter((word) => word.long).map((word) => stemOf(word.surface)));
94
+ return counted
95
+ .filter((word) => !word.long && (word.dropped || longStems.has(word.surface)))
96
+ .map((word) => ({ word, variant: "keep", preferred: otherForm(word), count: 0, of: 0 }));
97
+ }
98
+ return inconsistent(counted).toSorted((left, right) => left.word.offset - right.word.offset);
99
+ };
@@ -0,0 +1,19 @@
1
+ import type { Span } from "./plugin.ts";
2
+
3
+ type Place = { readonly offset?: number | undefined };
4
+
5
+ /** The part of an mdast node chaff reads. */
6
+ export type MarkdownNode = {
7
+ readonly type: string;
8
+ readonly url?: string | undefined;
9
+ readonly value?: string | undefined;
10
+ readonly identifier?: string | undefined;
11
+ readonly position?: { readonly start: Place; readonly end: Place } | undefined;
12
+ readonly children?: readonly MarkdownNode[] | undefined;
13
+ };
14
+
15
+ export const spanOf = (node: MarkdownNode): Span | undefined => {
16
+ const start = node.position?.start.offset;
17
+ const end = node.position?.end.offset;
18
+ return start === undefined || end === undefined ? undefined : { start, end };
19
+ };
@@ -0,0 +1,44 @@
1
+ import { fromMarkdown } from "mdast-util-from-markdown";
2
+ import { gfmTable } from "micromark-extension-gfm-table";
3
+ import { gfmTableFromMarkdown } from "mdast-util-gfm-table";
4
+ import { frontmatter } from "micromark-extension-frontmatter";
5
+ import { frontmatterFromMarkdown } from "mdast-util-frontmatter";
6
+ import { maskSpans } from "./mask.ts";
7
+ import { spanOf, type MarkdownNode } from "./markdown-node.ts";
8
+ import { componentLines, moduleBlocks, templateSpans } from "./template-syntax.ts";
9
+ import { eachPreOrder } from "./tree-walk.ts";
10
+ import type { Span } from "./plugin.ts";
11
+
12
+ export const parse = (source: string): MarkdownNode =>
13
+ fromMarkdown(source, { extensions: [gfmTable(), frontmatter(["yaml"])], mdastExtensions: [gfmTableFromMarkdown(), frontmatterFromMarkdown(["yaml"])] });
14
+
15
+ export const spansOfType = (root: MarkdownNode, type: string, keep: (node: MarkdownNode) => boolean = () => true): Span[] => {
16
+ const found: Span[] = [];
17
+ eachPreOrder(root, (node) => {
18
+ if (node.type !== type || !keep(node)) return;
19
+ const span = spanOf(node);
20
+ if (span !== undefined) found.push(span);
21
+ });
22
+ return found;
23
+ };
24
+
25
+ /** 番号を探してはいけない範囲。コードの中の「第3条」は条ではなく、参照でもない。 */
26
+ const OPAQUE = ["code", "inlineCode", "html", "yaml", "toml"];
27
+
28
+ export const opaqueSpans = (root: MarkdownNode): Span[] => OPAQUE.flatMap((type) => spansOfType(root, type));
29
+
30
+ /** Template syntax outside code: a `{{` in backticks is code, and does not open a tag that runs to the next `}}`. */
31
+ const templateOf = (root: MarkdownNode, source: string): Span[] => (source.includes("{") ? templateSpans(maskSpans(source, opaqueSpans(root))) : []);
32
+
33
+ type MarkdownRead = { readonly root: MarkdownNode; readonly syntax: readonly Span[] };
34
+
35
+ /**
36
+ * Markdown as MDX reads it: a line of nothing but JSX tags is a block of its own, not the start of an HTML block.
37
+ * `syntax` is the site generator's markup in it (those lines, MDX's imports and exports, and template tags outside
38
+ * code), which is neither prose nor structure.
39
+ */
40
+ export const readMarkdown = (source: string): MarkdownRead => {
41
+ const components = source.includes("<") ? componentLines(source) : [];
42
+ const root = parse(components.length === 0 ? source : maskSpans(source, components));
43
+ return { root, syntax: [...components, ...moduleBlocks(root, source), ...templateOf(root, source)] };
44
+ };