@kensio/pinyinjs 1.7.4 → 1.7.6

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 (732) hide show
  1. package/README.md +128 -123
  2. package/data/full.entries +2595 -2595
  3. package/data/manifest.json +5 -5
  4. package/data/script.map +66 -3
  5. package/dist/accuracy/score-case.d.ts +23 -0
  6. package/dist/accuracy/score-case.d.ts.map +1 -0
  7. package/dist/accuracy/score-case.js +63 -0
  8. package/dist/accuracy/score-case.js.map +1 -0
  9. package/dist/accuracy/score.d.ts +1 -8
  10. package/dist/accuracy/score.d.ts.map +1 -1
  11. package/dist/accuracy/score.js +1 -55
  12. package/dist/accuracy/score.js.map +1 -1
  13. package/dist/cli/arguments.d.ts +4 -290
  14. package/dist/cli/arguments.d.ts.map +1 -1
  15. package/dist/cli/arguments.js +5 -357
  16. package/dist/cli/arguments.js.map +1 -1
  17. package/dist/cli/check-command.d.ts +9 -0
  18. package/dist/cli/check-command.d.ts.map +1 -0
  19. package/dist/cli/check-command.js +95 -0
  20. package/dist/cli/check-command.js.map +1 -0
  21. package/dist/cli/cli-input.d.ts +49 -0
  22. package/dist/cli/cli-input.d.ts.map +1 -0
  23. package/dist/cli/cli-input.js +31 -0
  24. package/dist/cli/cli-input.js.map +1 -0
  25. package/dist/cli/command.d.ts +97 -0
  26. package/dist/cli/command.d.ts.map +1 -0
  27. package/dist/cli/command.js +40 -0
  28. package/dist/cli/command.js.map +1 -0
  29. package/dist/cli/commands.d.ts +7 -110
  30. package/dist/cli/commands.d.ts.map +1 -1
  31. package/dist/cli/commands.js +14 -991
  32. package/dist/cli/commands.js.map +1 -1
  33. package/dist/cli/convert-command.d.ts +6 -0
  34. package/dist/cli/convert-command.d.ts.map +1 -0
  35. package/dist/cli/convert-command.js +52 -0
  36. package/dist/cli/convert-command.js.map +1 -0
  37. package/dist/cli/environment.d.ts +1 -1
  38. package/dist/cli/environment.d.ts.map +1 -1
  39. package/dist/cli/explain-command.d.ts +6 -0
  40. package/dist/cli/explain-command.d.ts.map +1 -0
  41. package/dist/cli/explain-command.js +40 -0
  42. package/dist/cli/explain-command.js.map +1 -0
  43. package/dist/cli/explain-syllable.d.ts +10 -0
  44. package/dist/cli/explain-syllable.d.ts.map +1 -0
  45. package/dist/cli/explain-syllable.js +70 -0
  46. package/dist/cli/explain-syllable.js.map +1 -0
  47. package/dist/cli/flag-help.d.ts +18 -0
  48. package/dist/cli/flag-help.d.ts.map +1 -0
  49. package/dist/cli/flag-help.js +78 -0
  50. package/dist/cli/flag-help.js.map +1 -0
  51. package/dist/cli/flag-lists.d.ts +49 -0
  52. package/dist/cli/flag-lists.d.ts.map +1 -0
  53. package/dist/cli/flag-lists.js +58 -0
  54. package/dist/cli/flag-lists.js.map +1 -0
  55. package/dist/cli/flag-values.d.ts +44 -0
  56. package/dist/cli/flag-values.d.ts.map +1 -0
  57. package/dist/cli/flag-values.js +56 -0
  58. package/dist/cli/flag-values.js.map +1 -0
  59. package/dist/cli/flags.d.ts +193 -0
  60. package/dist/cli/flags.d.ts.map +1 -0
  61. package/dist/cli/flags.js +133 -0
  62. package/dist/cli/flags.js.map +1 -0
  63. package/dist/cli/format-options.d.ts +29 -0
  64. package/dist/cli/format-options.d.ts.map +1 -0
  65. package/dist/cli/format-options.js +72 -0
  66. package/dist/cli/format-options.js.map +1 -0
  67. package/dist/cli/global-help.d.ts +23 -0
  68. package/dist/cli/global-help.d.ts.map +1 -0
  69. package/dist/cli/global-help.js +40 -0
  70. package/dist/cli/global-help.js.map +1 -0
  71. package/dist/cli/help.d.ts +1 -1
  72. package/dist/cli/help.d.ts.map +1 -1
  73. package/dist/cli/help.js +5 -99
  74. package/dist/cli/help.js.map +1 -1
  75. package/dist/cli/html-commands.d.ts +13 -0
  76. package/dist/cli/html-commands.d.ts.map +1 -0
  77. package/dist/cli/html-commands.js +49 -0
  78. package/dist/cli/html-commands.js.map +1 -0
  79. package/dist/cli/info-command.d.ts +7 -0
  80. package/dist/cli/info-command.d.ts.map +1 -0
  81. package/dist/cli/info-command.js +39 -0
  82. package/dist/cli/info-command.js.map +1 -0
  83. package/dist/cli/lookup-commands.d.ts +10 -0
  84. package/dist/cli/lookup-commands.d.ts.map +1 -0
  85. package/dist/cli/lookup-commands.js +101 -0
  86. package/dist/cli/lookup-commands.js.map +1 -0
  87. package/dist/cli/match-command.d.ts +11 -0
  88. package/dist/cli/match-command.d.ts.map +1 -0
  89. package/dist/cli/match-command.js +76 -0
  90. package/dist/cli/match-command.js.map +1 -0
  91. package/dist/cli/number-command.d.ts +12 -0
  92. package/dist/cli/number-command.d.ts.map +1 -0
  93. package/dist/cli/number-command.js +89 -0
  94. package/dist/cli/number-command.js.map +1 -0
  95. package/dist/cli/options.d.ts +30 -0
  96. package/dist/cli/options.d.ts.map +1 -0
  97. package/dist/cli/options.js +54 -0
  98. package/dist/cli/options.js.map +1 -0
  99. package/dist/cli/run-command.d.ts +24 -0
  100. package/dist/cli/run-command.d.ts.map +1 -0
  101. package/dist/cli/run-command.js +40 -0
  102. package/dist/cli/run-command.js.map +1 -0
  103. package/dist/cli/run.d.ts +4 -42
  104. package/dist/cli/run.d.ts.map +1 -1
  105. package/dist/cli/run.js +6 -61
  106. package/dist/cli/run.js.map +1 -1
  107. package/dist/cli/script-command.d.ts +10 -0
  108. package/dist/cli/script-command.d.ts.map +1 -0
  109. package/dist/cli/script-command.js +58 -0
  110. package/dist/cli/script-command.js.map +1 -0
  111. package/dist/cli/segment-command.d.ts +11 -0
  112. package/dist/cli/segment-command.d.ts.map +1 -0
  113. package/dist/cli/segment-command.js +53 -0
  114. package/dist/cli/segment-command.js.map +1 -0
  115. package/dist/cli/slug-command.d.ts +10 -0
  116. package/dist/cli/slug-command.d.ts.map +1 -0
  117. package/dist/cli/slug-command.js +28 -0
  118. package/dist/cli/slug-command.js.map +1 -0
  119. package/dist/cli/syllable-command.d.ts +14 -0
  120. package/dist/cli/syllable-command.d.ts.map +1 -0
  121. package/dist/cli/syllable-command.js +82 -0
  122. package/dist/cli/syllable-command.js.map +1 -0
  123. package/dist/cli/system-table.d.ts +12 -0
  124. package/dist/cli/system-table.d.ts.map +1 -0
  125. package/dist/cli/system-table.js +48 -0
  126. package/dist/cli/system-table.js.map +1 -0
  127. package/dist/cli/systems.d.ts +57 -0
  128. package/dist/cli/systems.d.ts.map +1 -0
  129. package/dist/cli/systems.js +27 -0
  130. package/dist/cli/systems.js.map +1 -0
  131. package/dist/cli/transcribe-command.d.ts +18 -0
  132. package/dist/cli/transcribe-command.d.ts.map +1 -0
  133. package/dist/cli/transcribe-command.js +86 -0
  134. package/dist/cli/transcribe-command.js.map +1 -0
  135. package/dist/cli/transcribe-reading.d.ts +15 -0
  136. package/dist/cli/transcribe-reading.d.ts.map +1 -0
  137. package/dist/cli/transcribe-reading.js +90 -0
  138. package/dist/cli/transcribe-reading.js.map +1 -0
  139. package/dist/cli/transcribe-rows.d.ts +26 -0
  140. package/dist/cli/transcribe-rows.d.ts.map +1 -0
  141. package/dist/cli/transcribe-rows.js +30 -0
  142. package/dist/cli/transcribe-rows.js.map +1 -0
  143. package/dist/cli/usage-error.d.ts +9 -0
  144. package/dist/cli/usage-error.d.ts.map +1 -0
  145. package/dist/cli/usage-error.js +9 -0
  146. package/dist/cli/usage-error.js.map +1 -0
  147. package/dist/decode/alternatives.d.ts +16 -0
  148. package/dist/decode/alternatives.d.ts.map +1 -0
  149. package/dist/decode/alternatives.js +31 -0
  150. package/dist/decode/alternatives.js.map +1 -0
  151. package/dist/decode/chang-context.d.ts +27 -0
  152. package/dist/decode/chang-context.d.ts.map +1 -0
  153. package/dist/decode/chang-context.js +66 -0
  154. package/dist/decode/chang-context.js.map +1 -0
  155. package/dist/decode/chang-rule.d.ts +37 -0
  156. package/dist/decode/chang-rule.d.ts.map +1 -0
  157. package/dist/decode/chang-rule.js +169 -0
  158. package/dist/decode/chang-rule.js.map +1 -0
  159. package/dist/decode/confidence.d.ts +11 -3
  160. package/dist/decode/confidence.d.ts.map +1 -1
  161. package/dist/decode/confidence.js +14 -121
  162. package/dist/decode/confidence.js.map +1 -1
  163. package/dist/decode/convert-options.d.ts +116 -0
  164. package/dist/decode/convert-options.d.ts.map +1 -0
  165. package/dist/decode/convert-options.js +2 -0
  166. package/dist/decode/convert-options.js.map +1 -0
  167. package/dist/decode/convert-pipeline.d.ts +18 -0
  168. package/dist/decode/convert-pipeline.d.ts.map +1 -0
  169. package/dist/decode/convert-pipeline.js +67 -0
  170. package/dist/decode/convert-pipeline.js.map +1 -0
  171. package/dist/decode/convert.d.ts +9 -118
  172. package/dist/decode/convert.d.ts.map +1 -1
  173. package/dist/decode/convert.js +5 -453
  174. package/dist/decode/convert.js.map +1 -1
  175. package/dist/decode/de-rule.d.ts +54 -0
  176. package/dist/decode/de-rule.d.ts.map +1 -0
  177. package/dist/decode/de-rule.js +113 -0
  178. package/dist/decode/de-rule.js.map +1 -0
  179. package/dist/decode/decode.d.ts +2 -15
  180. package/dist/decode/decode.d.ts.map +1 -1
  181. package/dist/decode/decode.js +2 -121
  182. package/dist/decode/decode.js.map +1 -1
  183. package/dist/decode/decoders.d.ts +32 -0
  184. package/dist/decode/decoders.d.ts.map +1 -0
  185. package/dist/decode/decoders.js +29 -0
  186. package/dist/decode/decoders.js.map +1 -0
  187. package/dist/decode/edge-context.d.ts +38 -0
  188. package/dist/decode/edge-context.d.ts.map +1 -0
  189. package/dist/decode/edge-context.js +57 -0
  190. package/dist/decode/edge-context.js.map +1 -0
  191. package/dist/decode/hint-lattice.d.ts +45 -0
  192. package/dist/decode/hint-lattice.d.ts.map +1 -0
  193. package/dist/decode/hint-lattice.js +154 -0
  194. package/dist/decode/hint-lattice.js.map +1 -0
  195. package/dist/decode/hints.d.ts +2 -45
  196. package/dist/decode/hints.d.ts.map +1 -1
  197. package/dist/decode/hints.js +1 -139
  198. package/dist/decode/hints.js.map +1 -1
  199. package/dist/decode/jiao-rule.d.ts +64 -0
  200. package/dist/decode/jiao-rule.d.ts.map +1 -0
  201. package/dist/decode/jiao-rule.js +115 -0
  202. package/dist/decode/jiao-rule.js.map +1 -0
  203. package/dist/decode/lattice-costs.d.ts +55 -0
  204. package/dist/decode/lattice-costs.d.ts.map +1 -0
  205. package/dist/decode/lattice-costs.js +90 -0
  206. package/dist/decode/lattice-costs.js.map +1 -0
  207. package/dist/decode/lattice-edges.d.ts +29 -0
  208. package/dist/decode/lattice-edges.d.ts.map +1 -0
  209. package/dist/decode/lattice-edges.js +78 -0
  210. package/dist/decode/lattice-edges.js.map +1 -0
  211. package/dist/decode/lattice-slice.d.ts +37 -0
  212. package/dist/decode/lattice-slice.d.ts.map +1 -0
  213. package/dist/decode/lattice-slice.js +43 -0
  214. package/dist/decode/lattice-slice.js.map +1 -0
  215. package/dist/decode/lattice-types.d.ts +101 -0
  216. package/dist/decode/lattice-types.d.ts.map +1 -0
  217. package/dist/decode/lattice-types.js +63 -0
  218. package/dist/decode/lattice-types.js.map +1 -0
  219. package/dist/decode/lattice.d.ts +2 -59
  220. package/dist/decode/lattice.d.ts.map +1 -1
  221. package/dist/decode/lattice.js +2 -118
  222. package/dist/decode/lattice.js.map +1 -1
  223. package/dist/decode/number-pieces.d.ts +62 -0
  224. package/dist/decode/number-pieces.d.ts.map +1 -0
  225. package/dist/decode/number-pieces.js +106 -0
  226. package/dist/decode/number-pieces.js.map +1 -0
  227. package/dist/decode/numbers.d.ts +53 -0
  228. package/dist/decode/numbers.d.ts.map +1 -0
  229. package/dist/decode/numbers.js +69 -0
  230. package/dist/decode/numbers.js.map +1 -0
  231. package/dist/decode/pieces.d.ts +78 -0
  232. package/dist/decode/pieces.d.ts.map +1 -0
  233. package/dist/decode/pieces.js +136 -0
  234. package/dist/decode/pieces.js.map +1 -0
  235. package/dist/decode/polyphone-rules.d.ts +11 -0
  236. package/dist/decode/polyphone-rules.d.ts.map +1 -0
  237. package/dist/decode/polyphone-rules.js +11 -0
  238. package/dist/decode/polyphone-rules.js.map +1 -0
  239. package/dist/decode/reading-rules.d.ts +3 -126
  240. package/dist/decode/reading-rules.d.ts.map +1 -1
  241. package/dist/decode/reading-rules.js +8 -434
  242. package/dist/decode/reading-rules.js.map +1 -1
  243. package/dist/decode/rules.d.ts +1 -17
  244. package/dist/decode/rules.d.ts.map +1 -1
  245. package/dist/decode/rules.js +1 -43
  246. package/dist/decode/rules.js.map +1 -1
  247. package/dist/decode/run-lattice.d.ts +52 -0
  248. package/dist/decode/run-lattice.d.ts.map +1 -0
  249. package/dist/decode/run-lattice.js +91 -0
  250. package/dist/decode/run-lattice.js.map +1 -0
  251. package/dist/decode/run-words.d.ts +17 -0
  252. package/dist/decode/run-words.d.ts.map +1 -0
  253. package/dist/decode/run-words.js +29 -0
  254. package/dist/decode/run-words.js.map +1 -0
  255. package/dist/decode/sandhi-input.d.ts +30 -0
  256. package/dist/decode/sandhi-input.d.ts.map +1 -0
  257. package/dist/decode/sandhi-input.js +35 -0
  258. package/dist/decode/sandhi-input.js.map +1 -0
  259. package/dist/decode/sandhi-tones.d.ts +97 -0
  260. package/dist/decode/sandhi-tones.d.ts.map +1 -0
  261. package/dist/decode/sandhi-tones.js +139 -0
  262. package/dist/decode/sandhi-tones.js.map +1 -0
  263. package/dist/decode/sandhi.d.ts +10 -7
  264. package/dist/decode/sandhi.d.ts.map +1 -1
  265. package/dist/decode/sandhi.js +11 -88
  266. package/dist/decode/sandhi.js.map +1 -1
  267. package/dist/decode/script-types.d.ts +76 -0
  268. package/dist/decode/script-types.d.ts.map +1 -0
  269. package/dist/decode/script-types.js +35 -0
  270. package/dist/decode/script-types.js.map +1 -0
  271. package/dist/decode/script-words.d.ts +32 -0
  272. package/dist/decode/script-words.d.ts.map +1 -0
  273. package/dist/decode/script-words.js +77 -0
  274. package/dist/decode/script-words.js.map +1 -0
  275. package/dist/decode/script.d.ts +3 -73
  276. package/dist/decode/script.d.ts.map +1 -1
  277. package/dist/decode/script.js +3 -109
  278. package/dist/decode/script.js.map +1 -1
  279. package/dist/decode/tan-rule.d.ts +68 -0
  280. package/dist/decode/tan-rule.d.ts.map +1 -0
  281. package/dist/decode/tan-rule.js +131 -0
  282. package/dist/decode/tan-rule.js.map +1 -0
  283. package/dist/decode/write-run.d.ts +21 -0
  284. package/dist/decode/write-run.d.ts.map +1 -0
  285. package/dist/decode/write-run.js +42 -0
  286. package/dist/decode/write-run.js.map +1 -0
  287. package/dist/dictionary/artifact-claims.d.ts +25 -0
  288. package/dist/dictionary/artifact-claims.d.ts.map +1 -0
  289. package/dist/dictionary/artifact-claims.js +47 -0
  290. package/dist/dictionary/artifact-claims.js.map +1 -0
  291. package/dist/dictionary/artifact-format.d.ts +86 -0
  292. package/dist/dictionary/artifact-format.d.ts.map +1 -0
  293. package/dist/dictionary/artifact-format.js +91 -0
  294. package/dist/dictionary/artifact-format.js.map +1 -0
  295. package/dist/dictionary/artifact-read.d.ts +34 -0
  296. package/dist/dictionary/artifact-read.d.ts.map +1 -0
  297. package/dist/dictionary/artifact-read.js +114 -0
  298. package/dist/dictionary/artifact-read.js.map +1 -0
  299. package/dist/dictionary/artifact.d.ts +4 -63
  300. package/dist/dictionary/artifact.d.ts.map +1 -1
  301. package/dist/dictionary/artifact.js +12 -229
  302. package/dist/dictionary/artifact.js.map +1 -1
  303. package/dist/dictionary/assertions.d.ts +5 -57
  304. package/dist/dictionary/assertions.d.ts.map +1 -1
  305. package/dist/dictionary/assertions.js +4 -317
  306. package/dist/dictionary/assertions.js.map +1 -1
  307. package/dist/dictionary/build-assertions.d.ts +12 -0
  308. package/dist/dictionary/build-assertions.d.ts.map +1 -0
  309. package/dist/dictionary/build-assertions.js +13 -0
  310. package/dist/dictionary/build-assertions.js.map +1 -0
  311. package/dist/dictionary/built-dictionary.d.ts +46 -0
  312. package/dist/dictionary/built-dictionary.d.ts.map +1 -0
  313. package/dist/dictionary/built-dictionary.js +97 -0
  314. package/dist/dictionary/built-dictionary.js.map +1 -0
  315. package/dist/dictionary/cedict-senses.d.ts +87 -0
  316. package/dist/dictionary/cedict-senses.d.ts.map +1 -0
  317. package/dist/dictionary/cedict-senses.js +126 -0
  318. package/dist/dictionary/cedict-senses.js.map +1 -0
  319. package/dist/dictionary/character-defaults.d.ts +26 -0
  320. package/dist/dictionary/character-defaults.d.ts.map +1 -0
  321. package/dist/dictionary/character-defaults.js +67 -0
  322. package/dist/dictionary/character-defaults.js.map +1 -0
  323. package/dist/dictionary/character-readings.d.ts +10 -0
  324. package/dist/dictionary/character-readings.d.ts.map +1 -0
  325. package/dist/dictionary/character-readings.js +25 -0
  326. package/dist/dictionary/character-readings.js.map +1 -0
  327. package/dist/dictionary/constituent-repair.d.ts +36 -0
  328. package/dist/dictionary/constituent-repair.d.ts.map +1 -0
  329. package/dist/dictionary/constituent-repair.js +117 -0
  330. package/dist/dictionary/constituent-repair.js.map +1 -0
  331. package/dist/dictionary/dictionary-entry.d.ts +37 -0
  332. package/dist/dictionary/dictionary-entry.d.ts.map +1 -0
  333. package/dist/dictionary/dictionary-entry.js +41 -0
  334. package/dist/dictionary/dictionary-entry.js.map +1 -0
  335. package/dist/dictionary/dictionary-readings.d.ts +56 -0
  336. package/dist/dictionary/dictionary-readings.d.ts.map +1 -0
  337. package/dist/dictionary/dictionary-readings.js +93 -0
  338. package/dist/dictionary/dictionary-readings.js.map +1 -0
  339. package/dist/dictionary/dictionary.d.ts +6 -60
  340. package/dist/dictionary/dictionary.d.ts.map +1 -1
  341. package/dist/dictionary/dictionary.js +9 -169
  342. package/dist/dictionary/dictionary.js.map +1 -1
  343. package/dist/dictionary/entry-invariants.d.ts +3 -0
  344. package/dist/dictionary/entry-invariants.d.ts.map +1 -0
  345. package/dist/dictionary/entry-invariants.js +67 -0
  346. package/dist/dictionary/entry-invariants.js.map +1 -0
  347. package/dist/dictionary/entry-lines.d.ts +35 -0
  348. package/dist/dictionary/entry-lines.d.ts.map +1 -0
  349. package/dist/dictionary/entry-lines.js +70 -0
  350. package/dist/dictionary/entry-lines.js.map +1 -0
  351. package/dist/dictionary/erhua-repair.d.ts +26 -0
  352. package/dist/dictionary/erhua-repair.d.ts.map +1 -0
  353. package/dist/dictionary/erhua-repair.js +49 -0
  354. package/dist/dictionary/erhua-repair.js.map +1 -0
  355. package/dist/dictionary/frequency-tones.d.ts +74 -0
  356. package/dist/dictionary/frequency-tones.d.ts.map +1 -0
  357. package/dist/dictionary/frequency-tones.js +128 -0
  358. package/dist/dictionary/frequency-tones.js.map +1 -0
  359. package/dist/dictionary/inventory-invariants.d.ts +3 -0
  360. package/dist/dictionary/inventory-invariants.d.ts.map +1 -0
  361. package/dist/dictionary/inventory-invariants.js +54 -0
  362. package/dist/dictionary/inventory-invariants.js.map +1 -0
  363. package/dist/dictionary/locale-candidates.d.ts +40 -0
  364. package/dist/dictionary/locale-candidates.d.ts.map +1 -0
  365. package/dist/dictionary/locale-candidates.js +77 -0
  366. package/dist/dictionary/locale-candidates.js.map +1 -0
  367. package/dist/dictionary/locale-segments.d.ts +47 -0
  368. package/dist/dictionary/locale-segments.d.ts.map +1 -0
  369. package/dist/dictionary/locale-segments.js +141 -0
  370. package/dist/dictionary/locale-segments.js.map +1 -0
  371. package/dist/dictionary/locale.d.ts +1 -21
  372. package/dist/dictionary/locale.d.ts.map +1 -1
  373. package/dist/dictionary/locale.js +9 -198
  374. package/dist/dictionary/locale.js.map +1 -1
  375. package/dist/dictionary/merge-types.d.ts +127 -0
  376. package/dist/dictionary/merge-types.d.ts.map +1 -0
  377. package/dist/dictionary/merge-types.js +35 -0
  378. package/dist/dictionary/merge-types.js.map +1 -0
  379. package/dist/dictionary/merge-walk.d.ts +27 -0
  380. package/dist/dictionary/merge-walk.d.ts.map +1 -0
  381. package/dist/dictionary/merge-walk.js +49 -0
  382. package/dist/dictionary/merge-walk.js.map +1 -0
  383. package/dist/dictionary/merge-word.d.ts +7 -0
  384. package/dist/dictionary/merge-word.d.ts.map +1 -0
  385. package/dist/dictionary/merge-word.js +91 -0
  386. package/dist/dictionary/merge-word.js.map +1 -0
  387. package/dist/dictionary/merge.d.ts +5 -62
  388. package/dist/dictionary/merge.d.ts.map +1 -1
  389. package/dist/dictionary/merge.js +32 -725
  390. package/dist/dictionary/merge.js.map +1 -1
  391. package/dist/dictionary/proper-noun.d.ts +28 -0
  392. package/dist/dictionary/proper-noun.d.ts.map +1 -0
  393. package/dist/dictionary/proper-noun.js +43 -0
  394. package/dist/dictionary/proper-noun.js.map +1 -0
  395. package/dist/dictionary/reading-agreement.d.ts +71 -0
  396. package/dist/dictionary/reading-agreement.d.ts.map +1 -0
  397. package/dist/dictionary/reading-agreement.js +156 -0
  398. package/dist/dictionary/reading-agreement.js.map +1 -0
  399. package/dist/dictionary/script-conversion.d.ts +28 -0
  400. package/dist/dictionary/script-conversion.d.ts.map +1 -0
  401. package/dist/dictionary/script-conversion.js +58 -0
  402. package/dist/dictionary/script-conversion.js.map +1 -0
  403. package/dist/dictionary/script-pairings.d.ts +74 -0
  404. package/dist/dictionary/script-pairings.d.ts.map +1 -0
  405. package/dist/dictionary/script-pairings.js +120 -0
  406. package/dist/dictionary/script-pairings.js.map +1 -0
  407. package/dist/dictionary/script-tables.d.ts.map +1 -1
  408. package/dist/dictionary/script-tables.js +2 -165
  409. package/dist/dictionary/script-tables.js.map +1 -1
  410. package/dist/dictionary/taiwan-reading.d.ts +8 -0
  411. package/dist/dictionary/taiwan-reading.d.ts.map +1 -0
  412. package/dist/dictionary/taiwan-reading.js +38 -0
  413. package/dist/dictionary/taiwan-reading.js.map +1 -0
  414. package/dist/dictionary/tone-invariants.d.ts +3 -0
  415. package/dist/dictionary/tone-invariants.d.ts.map +1 -0
  416. package/dist/dictionary/tone-invariants.js +64 -0
  417. package/dist/dictionary/tone-invariants.js.map +1 -0
  418. package/dist/dictionary/traditional-form.d.ts +21 -0
  419. package/dist/dictionary/traditional-form.d.ts.map +1 -0
  420. package/dist/dictionary/traditional-form.js +59 -0
  421. package/dist/dictionary/traditional-form.js.map +1 -0
  422. package/dist/dictionary/traditional-ranking.d.ts +22 -0
  423. package/dist/dictionary/traditional-ranking.d.ts.map +1 -0
  424. package/dist/dictionary/traditional-ranking.js +74 -0
  425. package/dist/dictionary/traditional-ranking.js.map +1 -0
  426. package/dist/dictionary/traditional-table.d.ts +51 -0
  427. package/dist/dictionary/traditional-table.d.ts.map +1 -0
  428. package/dist/dictionary/traditional-table.js +98 -0
  429. package/dist/dictionary/traditional-table.js.map +1 -0
  430. package/dist/dictionary/traditional.d.ts +3 -56
  431. package/dist/dictionary/traditional.d.ts.map +1 -1
  432. package/dist/dictionary/traditional.js +3 -186
  433. package/dist/dictionary/traditional.js.map +1 -1
  434. package/dist/dictionary/variant-counts.d.ts +39 -0
  435. package/dist/dictionary/variant-counts.d.ts.map +1 -0
  436. package/dist/dictionary/variant-counts.js +38 -0
  437. package/dist/dictionary/variant-counts.js.map +1 -0
  438. package/dist/dictionary/word-reading.d.ts +26 -0
  439. package/dist/dictionary/word-reading.d.ts.map +1 -0
  440. package/dist/dictionary/word-reading.js +76 -0
  441. package/dist/dictionary/word-reading.js.map +1 -0
  442. package/dist/dictionary/word-readings.d.ts +15 -0
  443. package/dist/dictionary/word-readings.d.ts.map +1 -0
  444. package/dist/dictionary/word-readings.js +41 -0
  445. package/dist/dictionary/word-readings.js.map +1 -0
  446. package/dist/format/annotate.d.ts +90 -0
  447. package/dist/format/annotate.d.ts.map +1 -0
  448. package/dist/format/annotate.js +168 -0
  449. package/dist/format/annotate.js.map +1 -0
  450. package/dist/format/html.d.ts +15 -46
  451. package/dist/format/html.d.ts.map +1 -1
  452. package/dist/format/html.js +3 -162
  453. package/dist/format/html.js.map +1 -1
  454. package/dist/format/slug-hash.d.ts +51 -0
  455. package/dist/format/slug-hash.d.ts.map +1 -0
  456. package/dist/format/slug-hash.js +74 -0
  457. package/dist/format/slug-hash.js.map +1 -0
  458. package/dist/format/slug-options.d.ts +98 -0
  459. package/dist/format/slug-options.d.ts.map +1 -0
  460. package/dist/format/slug-options.js +2 -0
  461. package/dist/format/slug-options.js.map +1 -0
  462. package/dist/format/slug-words.d.ts +27 -0
  463. package/dist/format/slug-words.d.ts.map +1 -0
  464. package/dist/format/slug-words.js +0 -0
  465. package/dist/format/slug-words.js.map +1 -0
  466. package/dist/format/slug.d.ts +3 -128
  467. package/dist/format/slug.d.ts.map +1 -1
  468. package/dist/format/slug.js +0 -0
  469. package/dist/format/slug.js.map +1 -1
  470. package/dist/grade/check-readings.d.ts +41 -0
  471. package/dist/grade/check-readings.d.ts.map +1 -0
  472. package/dist/grade/check-readings.js +36 -0
  473. package/dist/grade/check-readings.js.map +1 -0
  474. package/dist/grade/check.d.ts +4 -4
  475. package/dist/grade/check.d.ts.map +1 -1
  476. package/dist/grade/check.js +5 -270
  477. package/dist/grade/check.js.map +1 -1
  478. package/dist/grade/pair-syllables.d.ts +48 -0
  479. package/dist/grade/pair-syllables.d.ts.map +1 -0
  480. package/dist/grade/pair-syllables.js +71 -0
  481. package/dist/grade/pair-syllables.js.map +1 -0
  482. package/dist/grade/reading-syllables.d.ts +62 -0
  483. package/dist/grade/reading-syllables.d.ts.map +1 -0
  484. package/dist/grade/reading-syllables.js +58 -0
  485. package/dist/grade/reading-syllables.js.map +1 -0
  486. package/dist/grade/reading-tolerance.d.ts +72 -0
  487. package/dist/grade/reading-tolerance.d.ts.map +1 -0
  488. package/dist/grade/reading-tolerance.js +107 -0
  489. package/dist/grade/reading-tolerance.js.map +1 -0
  490. package/dist/grade/typed-reading.d.ts +28 -0
  491. package/dist/grade/typed-reading.d.ts.map +1 -0
  492. package/dist/grade/typed-reading.js +36 -0
  493. package/dist/grade/typed-reading.js.map +1 -0
  494. package/dist/index.d.ts +1 -1
  495. package/dist/index.d.ts.map +1 -1
  496. package/dist/index.js +1 -1
  497. package/dist/index.js.map +1 -1
  498. package/dist/numerals/numeral-parse.d.ts +32 -0
  499. package/dist/numerals/numeral-parse.d.ts.map +1 -0
  500. package/dist/numerals/numeral-parse.js +44 -0
  501. package/dist/numerals/numeral-parse.js.map +1 -0
  502. package/dist/numerals/numeral-shapes.d.ts +89 -0
  503. package/dist/numerals/numeral-shapes.d.ts.map +1 -0
  504. package/dist/numerals/numeral-shapes.js +99 -0
  505. package/dist/numerals/numeral-shapes.js.map +1 -0
  506. package/dist/numerals/numerals.d.ts.map +1 -1
  507. package/dist/numerals/numerals.js +2 -36
  508. package/dist/numerals/numerals.js.map +1 -1
  509. package/dist/numerals/read-numeral.d.ts +76 -0
  510. package/dist/numerals/read-numeral.d.ts.map +1 -0
  511. package/dist/numerals/read-numeral.js +88 -0
  512. package/dist/numerals/read-numeral.js.map +1 -0
  513. package/dist/numerals/text.d.ts +3 -37
  514. package/dist/numerals/text.d.ts.map +1 -1
  515. package/dist/numerals/text.js +3 -254
  516. package/dist/numerals/text.js.map +1 -1
  517. package/dist/numerals/time.d.ts +34 -0
  518. package/dist/numerals/time.d.ts.map +1 -0
  519. package/dist/numerals/time.js +93 -0
  520. package/dist/numerals/time.js.map +1 -0
  521. package/dist/orthography/address-grouping.d.ts +34 -0
  522. package/dist/orthography/address-grouping.d.ts.map +1 -0
  523. package/dist/orthography/address-grouping.js +52 -0
  524. package/dist/orthography/address-grouping.js.map +1 -0
  525. package/dist/orthography/grouping.d.ts +3 -87
  526. package/dist/orthography/grouping.d.ts.map +1 -1
  527. package/dist/orthography/grouping.js +4 -270
  528. package/dist/orthography/grouping.js.map +1 -1
  529. package/dist/orthography/place-grouping.d.ts +39 -0
  530. package/dist/orthography/place-grouping.d.ts.map +1 -0
  531. package/dist/orthography/place-grouping.js +83 -0
  532. package/dist/orthography/place-grouping.js.map +1 -0
  533. package/dist/orthography/word-grouping.d.ts +48 -0
  534. package/dist/orthography/word-grouping.d.ts.map +1 -0
  535. package/dist/orthography/word-grouping.js +147 -0
  536. package/dist/orthography/word-grouping.js.map +1 -0
  537. package/dist/script/conversion-format.d.ts +22 -0
  538. package/dist/script/conversion-format.d.ts.map +1 -0
  539. package/dist/script/conversion-format.js +22 -0
  540. package/dist/script/conversion-format.js.map +1 -0
  541. package/dist/script/conversion-read.d.ts +9 -0
  542. package/dist/script/conversion-read.d.ts.map +1 -0
  543. package/dist/script/conversion-read.js +69 -0
  544. package/dist/script/conversion-read.js.map +1 -0
  545. package/dist/script/conversion-write.d.ts +14 -0
  546. package/dist/script/conversion-write.d.ts.map +1 -0
  547. package/dist/script/conversion-write.js +34 -0
  548. package/dist/script/conversion-write.js.map +1 -0
  549. package/dist/script/conversion.d.ts +10 -16
  550. package/dist/script/conversion.d.ts.map +1 -1
  551. package/dist/script/conversion.js +2 -115
  552. package/dist/script/conversion.js.map +1 -1
  553. package/dist/search/candidate-narrowing.d.ts +56 -0
  554. package/dist/search/candidate-narrowing.d.ts.map +1 -0
  555. package/dist/search/candidate-narrowing.js +55 -0
  556. package/dist/search/candidate-narrowing.js.map +1 -0
  557. package/dist/search/candidate-query.d.ts +25 -0
  558. package/dist/search/candidate-query.d.ts.map +1 -0
  559. package/dist/search/candidate-query.js +28 -0
  560. package/dist/search/candidate-query.js.map +1 -0
  561. package/dist/search/candidate-writings.d.ts +24 -0
  562. package/dist/search/candidate-writings.d.ts.map +1 -0
  563. package/dist/search/candidate-writings.js +114 -0
  564. package/dist/search/candidate-writings.js.map +1 -0
  565. package/dist/search/candidates.d.ts +7 -41
  566. package/dist/search/candidates.d.ts.map +1 -1
  567. package/dist/search/candidates.js +10 -164
  568. package/dist/search/candidates.js.map +1 -1
  569. package/dist/search/match-chunks.d.ts +19 -0
  570. package/dist/search/match-chunks.d.ts.map +1 -0
  571. package/dist/search/match-chunks.js +30 -0
  572. package/dist/search/match-chunks.js.map +1 -0
  573. package/dist/search/match-ranking.d.ts +39 -0
  574. package/dist/search/match-ranking.d.ts.map +1 -0
  575. package/dist/search/match-ranking.js +51 -0
  576. package/dist/search/match-ranking.js.map +1 -0
  577. package/dist/search/match-readings.d.ts +43 -0
  578. package/dist/search/match-readings.d.ts.map +1 -0
  579. package/dist/search/match-readings.js +83 -0
  580. package/dist/search/match-readings.js.map +1 -0
  581. package/dist/search/match-scoring.d.ts +146 -0
  582. package/dist/search/match-scoring.d.ts.map +1 -0
  583. package/dist/search/match-scoring.js +114 -0
  584. package/dist/search/match-scoring.js.map +1 -0
  585. package/dist/search/match-search.d.ts +28 -0
  586. package/dist/search/match-search.d.ts.map +1 -0
  587. package/dist/search/match-search.js +128 -0
  588. package/dist/search/match-search.js.map +1 -0
  589. package/dist/search/match.d.ts +5 -36
  590. package/dist/search/match.d.ts.map +1 -1
  591. package/dist/search/match.js +2 -379
  592. package/dist/search/match.js.map +1 -1
  593. package/dist/search/reverse-index-build.d.ts +30 -0
  594. package/dist/search/reverse-index-build.d.ts.map +1 -0
  595. package/dist/search/reverse-index-build.js +72 -0
  596. package/dist/search/reverse-index-build.js.map +1 -0
  597. package/dist/search/reverse-index-format.d.ts +60 -0
  598. package/dist/search/reverse-index-format.d.ts.map +1 -0
  599. package/dist/search/reverse-index-format.js +54 -0
  600. package/dist/search/reverse-index-format.js.map +1 -0
  601. package/dist/search/reverse-index-groups.d.ts +37 -0
  602. package/dist/search/reverse-index-groups.d.ts.map +1 -0
  603. package/dist/search/reverse-index-groups.js +71 -0
  604. package/dist/search/reverse-index-groups.js.map +1 -0
  605. package/dist/search/reverse-index-passes.d.ts +78 -0
  606. package/dist/search/reverse-index-passes.d.ts.map +1 -0
  607. package/dist/search/reverse-index-passes.js +59 -0
  608. package/dist/search/reverse-index-passes.js.map +1 -0
  609. package/dist/search/reverse-index-state.d.ts +36 -0
  610. package/dist/search/reverse-index-state.d.ts.map +1 -0
  611. package/dist/search/reverse-index-state.js +95 -0
  612. package/dist/search/reverse-index-state.js.map +1 -0
  613. package/dist/search/reverse-index.d.ts +8 -67
  614. package/dist/search/reverse-index.d.ts.map +1 -1
  615. package/dist/search/reverse-index.js +4 -255
  616. package/dist/search/reverse-index.js.map +1 -1
  617. package/dist/sources/unihan-readings.d.ts +58 -0
  618. package/dist/sources/unihan-readings.d.ts.map +1 -0
  619. package/dist/sources/unihan-readings.js +95 -0
  620. package/dist/sources/unihan-readings.js.map +1 -0
  621. package/dist/sources/unihan.d.ts +6 -9
  622. package/dist/sources/unihan.d.ts.map +1 -1
  623. package/dist/sources/unihan.js +2 -85
  624. package/dist/sources/unihan.js.map +1 -1
  625. package/dist/syllable/final-tables.d.ts +23 -0
  626. package/dist/syllable/final-tables.d.ts.map +1 -0
  627. package/dist/syllable/final-tables.js +50 -0
  628. package/dist/syllable/final-tables.js.map +1 -0
  629. package/dist/syllable/inventory.d.ts +8 -42
  630. package/dist/syllable/inventory.d.ts.map +1 -1
  631. package/dist/syllable/inventory.js +9 -918
  632. package/dist/syllable/inventory.js.map +1 -1
  633. package/dist/syllable/spellings.d.ts +40 -0
  634. package/dist/syllable/spellings.d.ts.map +1 -0
  635. package/dist/syllable/spellings.js +469 -0
  636. package/dist/syllable/spellings.js.map +1 -0
  637. package/dist/syllable/syllable-parts.d.ts +31 -0
  638. package/dist/syllable/syllable-parts.d.ts.map +1 -0
  639. package/dist/syllable/syllable-parts.js +105 -0
  640. package/dist/syllable/syllable-parts.js.map +1 -0
  641. package/dist/syllable/syllable.d.ts +1 -14
  642. package/dist/syllable/syllable.d.ts.map +1 -1
  643. package/dist/syllable/syllable.js +3 -144
  644. package/dist/syllable/syllable.js.map +1 -1
  645. package/dist/syllable/written-tones.d.ts +6 -0
  646. package/dist/syllable/written-tones.d.ts.map +1 -0
  647. package/dist/syllable/written-tones.js +453 -0
  648. package/dist/syllable/written-tones.js.map +1 -0
  649. package/dist/transcription/bopomofo-parse.d.ts +42 -0
  650. package/dist/transcription/bopomofo-parse.d.ts.map +1 -0
  651. package/dist/transcription/bopomofo-parse.js +92 -0
  652. package/dist/transcription/bopomofo-parse.js.map +1 -0
  653. package/dist/transcription/bopomofo-reverse.d.ts +31 -0
  654. package/dist/transcription/bopomofo-reverse.d.ts.map +1 -0
  655. package/dist/transcription/bopomofo-reverse.js +48 -0
  656. package/dist/transcription/bopomofo-reverse.js.map +1 -0
  657. package/dist/transcription/bopomofo-symbols.d.ts +36 -0
  658. package/dist/transcription/bopomofo-symbols.d.ts.map +1 -0
  659. package/dist/transcription/bopomofo-symbols.js +41 -0
  660. package/dist/transcription/bopomofo-symbols.js.map +1 -0
  661. package/dist/transcription/bopomofo-tables.d.ts +87 -0
  662. package/dist/transcription/bopomofo-tables.d.ts.map +1 -0
  663. package/dist/transcription/bopomofo-tables.js +180 -0
  664. package/dist/transcription/bopomofo-tables.js.map +1 -0
  665. package/dist/transcription/bopomofo.d.ts +14 -32
  666. package/dist/transcription/bopomofo.d.ts.map +1 -1
  667. package/dist/transcription/bopomofo.js +5 -343
  668. package/dist/transcription/bopomofo.js.map +1 -1
  669. package/dist/transcription/gwoyeu-first-second.d.ts +36 -0
  670. package/dist/transcription/gwoyeu-first-second.d.ts.map +1 -0
  671. package/dist/transcription/gwoyeu-first-second.js +75 -0
  672. package/dist/transcription/gwoyeu-first-second.js.map +1 -0
  673. package/dist/transcription/gwoyeu-spelling.d.ts +38 -0
  674. package/dist/transcription/gwoyeu-spelling.d.ts.map +1 -0
  675. package/dist/transcription/gwoyeu-spelling.js +124 -0
  676. package/dist/transcription/gwoyeu-spelling.js.map +1 -0
  677. package/dist/transcription/gwoyeu-tables.d.ts +93 -0
  678. package/dist/transcription/gwoyeu-tables.d.ts.map +1 -0
  679. package/dist/transcription/gwoyeu-tables.js +205 -0
  680. package/dist/transcription/gwoyeu-tables.js.map +1 -0
  681. package/dist/transcription/gwoyeu-tonal-forms.d.ts +49 -0
  682. package/dist/transcription/gwoyeu-tonal-forms.d.ts.map +1 -0
  683. package/dist/transcription/gwoyeu-tonal-forms.js +89 -0
  684. package/dist/transcription/gwoyeu-tonal-forms.js.map +1 -0
  685. package/dist/transcription/gwoyeu-vowels.d.ts +51 -0
  686. package/dist/transcription/gwoyeu-vowels.d.ts.map +1 -0
  687. package/dist/transcription/gwoyeu-vowels.js +58 -0
  688. package/dist/transcription/gwoyeu-vowels.js.map +1 -0
  689. package/dist/transcription/gwoyeu.d.ts +1 -26
  690. package/dist/transcription/gwoyeu.d.ts.map +1 -1
  691. package/dist/transcription/gwoyeu.js +2 -540
  692. package/dist/transcription/gwoyeu.js.map +1 -1
  693. package/dist/transcription/ipa-symbols.d.ts +67 -0
  694. package/dist/transcription/ipa-symbols.d.ts.map +1 -0
  695. package/dist/transcription/ipa-symbols.js +135 -0
  696. package/dist/transcription/ipa-symbols.js.map +1 -0
  697. package/dist/transcription/ipa.d.ts +2 -10
  698. package/dist/transcription/ipa.d.ts.map +1 -1
  699. package/dist/transcription/ipa.js +2 -134
  700. package/dist/transcription/ipa.js.map +1 -1
  701. package/dist/transcription/wade-giles-index.d.ts +35 -0
  702. package/dist/transcription/wade-giles-index.d.ts.map +1 -0
  703. package/dist/transcription/wade-giles-index.js +110 -0
  704. package/dist/transcription/wade-giles-index.js.map +1 -0
  705. package/dist/transcription/wade-giles-parse.d.ts +36 -0
  706. package/dist/transcription/wade-giles-parse.d.ts.map +1 -0
  707. package/dist/transcription/wade-giles-parse.js +84 -0
  708. package/dist/transcription/wade-giles-parse.js.map +1 -0
  709. package/dist/transcription/wade-giles-spelling.d.ts +61 -0
  710. package/dist/transcription/wade-giles-spelling.d.ts.map +1 -0
  711. package/dist/transcription/wade-giles-spelling.js +107 -0
  712. package/dist/transcription/wade-giles-spelling.js.map +1 -0
  713. package/dist/transcription/wade-giles-syllable.d.ts +29 -0
  714. package/dist/transcription/wade-giles-syllable.d.ts.map +1 -0
  715. package/dist/transcription/wade-giles-syllable.js +90 -0
  716. package/dist/transcription/wade-giles-syllable.js.map +1 -0
  717. package/dist/transcription/wade-giles-tables.d.ts +80 -0
  718. package/dist/transcription/wade-giles-tables.d.ts.map +1 -0
  719. package/dist/transcription/wade-giles-tables.js +178 -0
  720. package/dist/transcription/wade-giles-tables.js.map +1 -0
  721. package/dist/transcription/wade-giles.d.ts +9 -60
  722. package/dist/transcription/wade-giles.d.ts.map +1 -1
  723. package/dist/transcription/wade-giles.js +6 -543
  724. package/dist/transcription/wade-giles.js.map +1 -1
  725. package/dist/transcription/yale-tables.d.ts +54 -0
  726. package/dist/transcription/yale-tables.d.ts.map +1 -0
  727. package/dist/transcription/yale-tables.js +125 -0
  728. package/dist/transcription/yale-tables.js.map +1 -0
  729. package/dist/transcription/yale.d.ts.map +1 -1
  730. package/dist/transcription/yale.js +1 -124
  731. package/dist/transcription/yale.js.map +1 -1
  732. package/package.json +2 -2
@@ -1,754 +1,61 @@
1
- import { characterCount, isSingleCharacter } from "../script/characters.js";
2
- import { toCanonicalGlyphs } from "../script/glyphs.js";
3
- import { nameBoundariesOf } from "../sources/cedict.js";
4
- import { isProperNounTag } from "../sources/jieba.js";
5
- import { FREQUENCY_FIELD, } from "../sources/unihan.js";
6
- import { NEUTRAL_TONE } from "../tone/tone.js";
7
- import { countCorpusMass, rankByCorpusMass } from "./corpus-mass.js";
8
- import { isSameReading } from "./entry.js";
9
- import { attachErhua, isErFinal, NON_ERHUA_ER_WORDS } from "./erhua.js";
10
- import { composeLocaleDeltas } from "./locale.js";
11
- import { NEUTRAL_SENSE_LOOKUP } from "./neutral-senses.js";
12
- import { OVERRIDE_READINGS } from "./overrides.js";
13
- import { ERHUA_TOKEN, readAlignedReading, readDictionaryReading, } from "./reading.js";
14
- import { pairScripts, TraditionalTable, } from "./traditional.js";
15
- /**
16
- * Order two strings by UTF-16 code unit, matching the key index's ordering.
17
- */
18
- function byCodeUnit(left, right) {
19
- if (left < right) {
20
- return -1;
21
- }
22
- return left > right ? 1 : 0;
23
- }
24
- /**
25
- * Whether a phrase-corpus headword is really the 繁體 spelling of another word.
26
- *
27
- * `large_pinyin.txt` is a 简体 corpus, and where it carries a 繁體 headword
28
- * anyway it has read it as though the characters were 简体: 特徵 is `tè zhǐ`
29
- * there because 徵 alone is `zhǐ`, 沈溺 is `shěn nì` because 沈 alone is the
30
- * surname, 蝨子 is `shī zǐ`, 纔然 is `shān rán`. Every one of those is a word
31
- * whose 简体 form the corpus also carries, correctly.
32
- *
33
- * Left in, each becomes an entry of its own that outranks the 繁體 key the
34
- * derivation would have hung on the 简体 entry, so the word reads one way in a
35
- * tier holding the phrase tail and another way in a tier without it.
36
- *
37
- * So the corpus is held to its own contract: a headword CC-CEDICT knows only as
38
- * the 繁體 spelling of a different 简体 word contributes no entry, and the word
39
- * keeps the reading CC-CEDICT pairs it with. It is 72 headwords, 13 of which
40
- * the corpus reads wrongly; the other 59 arrive at the same reading either way.
41
- *
42
- * Narrow on purpose. 2,854 corpus headwords contain a 繁體-only character and
43
- * only these 72 are ones CC-CEDICT pairs — the rest are rare or mixed-script
44
- * words whose characters do read them, and dropping those would lose coverage
45
- * to fix nothing.
46
- */
47
- function isSpeltTraditionally(word, byWord, byHant) {
48
- if (byWord.has(word)) {
49
- return false;
50
- }
51
- return (byHant.get(word) ?? []).some((entry) => entry.simplified !== entry.traditional);
52
- }
53
- /**
54
- * CC-CEDICT's entries for a word, keyed by one of its two written forms.
55
- */
56
- function indexCedict(cedict, formOf) {
57
- const byWord = new Map();
58
- for (const entry of cedict) {
59
- const form = formOf(entry);
60
- const existing = byWord.get(form);
61
- if (existing === undefined) {
62
- byWord.set(form, [entry]);
63
- }
64
- else {
65
- existing.push(entry);
66
- }
67
- }
68
- return byWord;
69
- }
70
- /**
71
- * How far apart two readings of the same length are.
72
- *
73
- * Used to pick which of CC-CEDICT's senses to compare against, since a word
74
- * with several senses has several readings and only the nearest one is talking
75
- * about the same pronunciation.
76
- *
77
- * A difference in spelling counts for more than a difference in tone, and the
78
- * distinction decides real cases. 行长 is `xíng zhǎng` in one CC-CEDICT sense
79
- * and `háng zhang` in another; against the phrase corpus's `háng zhǎng` the two
80
- * differ in one syllable each, but only the second is the same word — the first
81
- * has a different initial, so it is a different word that happens to be
82
- * written the same way.
83
- */
84
- function readingGap(left, right) {
85
- if (left.length !== right.length) {
86
- return Infinity;
87
- }
88
- let spelling = 0;
89
- let tones = 0;
90
- for (const [at, syllable] of left.entries()) {
91
- /* c8 ignore next -- the lengths match, so the fallback is unreachable */
92
- const other = right[at] ?? syllable;
93
- if (syllable.initial !== other.initial || syllable.final !== other.final) {
94
- spelling++;
95
- }
96
- else if (syllable.tone !== other.tone) {
97
- tones++;
98
- }
99
- }
100
- // Scaled so that any number of tone differences still beats one spelling
101
- // difference.
102
- return spelling * (left.length + 1) + tones;
103
- }
104
- /**
105
- * Take CC-CEDICT's neutral tones where it and the phrase corpus disagree.
106
- *
107
- * The disagreements between the two are almost entirely about 轻声, and
108
- * CC-CEDICT is the more careful source there: it has 头发 as `tou2 fa5` and
109
- * 还是 as `hai2 shi5` where the phrase corpus writes full tones on both. Only
110
- * the tone is taken, and only when it is neutral — a disagreement about the
111
- * syllable itself is left to the phrase corpus, which has three times the
112
- * coverage and is the primary source.
113
- *
114
- * The two readings must be the same length, which the caller establishes by
115
- * only passing a sense {@link readingGap} scored as finite.
116
- */
117
- function preferNeutralTones(phrase, cedict) {
118
- return phrase.map((syllable, at) => {
119
- /* c8 ignore next -- the caller only passes a sense of the same length */
120
- const other = cedict[at] ?? syllable;
121
- const isSameSound = syllable.initial === other.initial && syllable.final === other.final;
122
- return isSameSound &&
123
- other.tone === NEUTRAL_TONE &&
124
- syllable.tone !== NEUTRAL_TONE
125
- ? { ...syllable, tone: NEUTRAL_TONE }
126
- : syllable;
127
- });
128
- }
129
- /**
130
- * Whether a word's trailing 儿 is an r suffix rather than a syllable.
131
- *
132
- * CC-CEDICT decides wherever it has the word, because its `r5` token is an
133
- * explicit and reliable marker. Only where it is silent does the checked-in
134
- * exception list get a say, and there the default is 儿化 — a trailing 儿 is
135
- * far more often a diminutive suffix than the word 儿 itself.
136
- */
137
- function isErhua(word, cedictReadings) {
138
- if (!isErFinal(word)) {
139
- return false;
140
- }
141
- if (cedictReadings.length > 0) {
142
- return cedictReadings.some((reading) => reading.at(-1)?.erhua === true);
143
- }
144
- return !NON_ERHUA_ER_WORDS.has(word);
145
- }
146
- /**
147
- * Whether a candidate reads a syllable 轻声 that the chosen reading tones.
148
- *
149
- * What separates a sense that is the same word said more carefully from one
150
- * that is a different word: 东西's `dong1 xi5` reduces the `dōng xī` the corpus
151
- * wrote, while its `dong1 xi1` is that same reading and 行长's `háng zhang` has
152
- * a different initial. Length is checked because a reading of another length
153
- * describes another pronunciation entirely.
154
- */
155
- function reducesToNeutral(reading, candidate) {
156
- if (reading.length !== candidate.length) {
157
- return false;
158
- }
159
- return reading.some((syllable, at) => {
160
- const other = candidate[at];
161
- return (other !== undefined &&
162
- syllable.initial === other.initial &&
163
- syllable.final === other.final &&
164
- syllable.tone !== NEUTRAL_TONE &&
165
- other.tone === NEUTRAL_TONE);
166
- });
167
- }
168
- /**
169
- * The candidate reading nearest the chosen one, or undefined if none compares.
170
- *
171
- * Undefined covers both having no candidates at all and having only candidates
172
- * of a different length, which describe a different pronunciation rather than a
173
- * more careful transcription of this one.
174
- */
175
- function nearestReading(reading, candidates) {
176
- let nearest;
177
- let smallest = Infinity;
178
- for (const candidate of candidates) {
179
- const gap = readingGap(reading, candidate);
180
- if (gap < smallest) {
181
- nearest = candidate;
182
- smallest = gap;
183
- }
184
- }
185
- return nearest;
186
- }
187
- /**
188
- * The CC-CEDICT senses describing the pronunciation chosen for a word.
189
- *
190
- * A word with several pronunciations has several CC-CEDICT entries, and they
191
- * can disagree about more than the reading: 万 is written 萬 when read `wàn` and
192
- * 万 when read `mò`. Everything taken from CC-CEDICT for an entry — its 繁體
193
- * form, its Taiwan reading — has to come from a sense that matches the reading,
194
- * or the entry ends up describing two different words at once.
195
- *
196
- * Every sense equally near the reading is returned, most useful first, because
197
- * senses can agree about the pronunciation and still differ about the script:
198
- * 重复 is `chóng fù` whether it is written 重複 or 重覆, and both spellings are
199
- * this word. The first is the entry's 繁體 form and the rest are its
200
- * {@link DictionaryEntry.hantVariants}.
201
- *
202
- * Where nothing compares — no sense has a readable reading of the same length —
203
- * only the first is returned. A tie between senses that could not be measured
204
- * is not evidence that they are the same word.
205
- */
206
- function sensesForReading(word, entries, reading) {
207
- const measured = entries.map((entry) => {
208
- const candidate = readDictionaryReading(word, entry.readings);
209
- return {
210
- entry,
211
- gap: candidate === undefined ? Infinity : readingGap(reading, candidate),
212
- };
213
- });
214
- const nearest = Math.min(...measured.map(({ gap }) => gap));
215
- if (measured.length === 0 || nearest === Infinity) {
216
- return entries.slice(0, 1);
217
- }
218
- return measured
219
- .filter(({ gap }) => gap === nearest)
220
- .map(({ entry }) => entry);
221
- }
222
- /**
223
- * A word's readings as CC-CEDICT gives them, one per sense.
224
- */
225
- function cedictReadingsOf(word, entries) {
226
- return entries
227
- .map((entry) => readDictionaryReading(word, entry.readings))
228
- .filter((reading) => reading !== undefined);
229
- }
230
- /**
231
- * Whether a proposed 國語 reading is really another 普通话 sense of the word.
232
- *
233
- * The test that separates a locale shift from a sense selection, which the
234
- * sources write the same way and mean differently. 地 is offered `dì` against a
235
- * 普通话 `de` — but CC-CEDICT lists 地[de5] and 地[di4] as two entries, so `dì`
236
- * is what 地 reads in 普通话 when it means the ground, not what 國語 does to the
237
- * particle. The adverbial 地 is `de` in Taipei too, and 4,240 entries end in it.
238
- * 都 is the same shape, and so are 着, 应, 差, 称, 斗, 舍, 薄 and 万.
239
- *
240
- * A genuine delta leaves no such trace: nothing in 普通话 reads 和 as `hàn`, 期
241
- * as `qí` or 垃 as `lè`, which is why those survive this and 71 characters and
242
- * 3 words do not.
243
- *
244
- * Only CC-CEDICT is consulted. Unihan's reading fields carry rare and historical
245
- * pronunciations alongside current ones — 驯 is listed `xún` somewhere in them —
246
- * and a reading no one uses today is not evidence that a source meant a sense
247
- * rather than a locale.
248
- */
249
- function isOwnSense(taiwan, senseReadings) {
250
- return senseReadings.some((sense) => isSameReading(sense, taiwan));
251
- }
252
- /**
253
- * Whether a character's `Taiwan pr.` note describes one sense rather than the
254
- * character.
255
- *
256
- * The other half of the sense test, and the one {@link isOwnSense} cannot do.
257
- * That test asks whether the offered reading is a 普通话 sense of the word; this
258
- * asks whether the note was ever about the whole word to begin with. 從's
259
- * `Taiwan pr. [zong4]` sits on three of its eight senses — 侍從, 從兄弟, 從犯 —
260
- * and 教育部's dictionary agrees with CC-CEDICT about which: 跟隨, 依順, 參與 and
261
- * the preposition are `cóng` in Taipei exactly as they are in Beijing. Applying
262
- * it to the headword made 我从北京来 read `wǒ zòng Běijīng lái`. 會 (`huǐ`, only
263
- * 一會兒), 勞 (`lào`, only 慰勞) and 燥 (`sào`, only 肉燥) are the same shape.
264
- *
265
- * A note the entry leads with is kept, because the leading sense is what the
266
- * character means with nothing to narrow it: 和's `hàn` is on the conjunction,
267
- * which is what a bare 和 almost always is.
268
- *
269
- * **Only a character is tested this way.** Its entry is what every occurrence
270
- * no longer word covers falls back to, so it has to carry the reading that
271
- * survives out of context; a multi-character headword is reached only where
272
- * that exact word is written. Four of them carry an inline note — 相親, 載具,
273
- * 高挑 and 樂色 — and only 相親 has senses that differ, its dominant one being
274
- * the matchmaking sense that really is `xiàngqīn`.
275
- */
276
- function isSenseScopedNote(word, sense) {
277
- return sense?.taiwanScope === "sense" && isSingleCharacter(word);
278
- }
279
- /**
280
- * Strip the tone marks from a reading, for comparing two spellings.
281
- */
282
- function tonelessReading(reading) {
283
- return reading
284
- .normalize("NFD")
285
- .replaceAll(/[̀́̄̌]/gu, "")
286
- .normalize("NFC");
287
- }
288
1
  /**
289
- * Whether a reading carries a tone mark.
290
- */
291
- function isToneMarked(reading) {
292
- return tonelessReading(reading) !== reading;
293
- }
294
- /**
295
- * Put back a tone that `kHanyuPinlu` left off.
2
+ * The order the merge does its work in.
296
3
  *
297
- * The frequency field writes some readings without their tone mark: 李 is
298
- * `li(36)` there where every dictionary field writes `lǐ`. Read as 轻声 — which
299
- * is what an unmarked reading means in source data — that makes 李华 come out
300
- * `Li Huá`, and it is the only Unihan field this happens in.
301
- *
302
- * The other fields settle which it is. If they also write the spelling bare,
303
- * the neutral tone is real and 么, 们, 吧, 裳 keep it. If every one of them
304
- * writes it with a tone, the frequency field simply omitted the mark, and the
305
- * tone is taken back. Measured over the real file, 3,799 characters have a
306
- * `kHanyuPinlu` entry, 60 of those have only unmarked readings, and the split
307
- * is 45 that should carry a tone against 15 genuine 轻声.
4
+ * Which spellings get an entry and how each one is settled is `merge-walk.ts`.
5
+ * What is here is the sequence: the indexes and character defaults everything
6
+ * else reads, the walk, and the two passes that run over the finished entries.
308
7
  */
309
- function resolveFrequencyTones(unihan) {
310
- const frequencyReadings = unihan.fields.get(FREQUENCY_FIELD) ?? [];
311
- // A character whose frequency field marks any tone is already trustworthy:
312
- // there the unmarked readings sit alongside marked ones and mean 轻声.
313
- if (frequencyReadings.length === 0 ||
314
- frequencyReadings.some((reading) => isToneMarked(reading))) {
315
- return unihan.readings;
316
- }
317
- const elsewhere = [...unihan.fields]
318
- .filter(([field]) => field !== FREQUENCY_FIELD)
319
- .flatMap(([, readings]) => readings);
320
- return unihan.readings.map((reading) => {
321
- if (isToneMarked(reading)) {
322
- return reading;
323
- }
324
- const sameSpelling = elsewhere.filter((other) => tonelessReading(other) === reading);
325
- if (sameSpelling.length === 0 || sameSpelling.includes(reading)) {
326
- return reading;
327
- }
328
- return sameSpelling.find((other) => isToneMarked(other)) ?? reading;
329
- });
330
- }
331
- /**
332
- * A CC-CEDICT sense that describes a suffix rather than a word.
333
- *
334
- * Matches its own wording: 子 is `/noun suffix, as in 椅子[yi3 zi5] "chair"/`,
335
- * and the other suffix senses are written the same way.
336
- */
337
- const SUFFIX_SENSE = /\bsuffix\b/iu;
338
- /**
339
- * Whether CC-CEDICT reads the bare character 轻声 in its own right.
340
- *
341
- * The exception to {@link demoteReducedNeutrals}, and the thing that separates
342
- * a 语气词 from a syllable that is only ever unstressed inside a word. A
343
- * single-character CC-CEDICT headword with a neutral reading is a claim about
344
- * the character standing alone, which is exactly what the frequency field's
345
- * counting cannot distinguish: 吗 is `(question particle for "yes-no"
346
- * questions)`, 啊 is `modal particle ending sentence`, 得 is `structural
347
- * particle: used after a verb`. Nine characters carry one — 得, 啊, 吗, 呀, 啦,
348
- * 哇, 嘛, 罢 and 子 — and their 繁體 spellings with them.
349
- *
350
- * **A suffix sense is not such a claim.** 子's neutral headword is `noun
351
- * suffix, as in 椅子`, which says the character is unstressed *in words*, and
352
- * words are what the corpus can already see. 子 is `zǐ` on its own — 子曰, 母子
353
- * — and CPP's human labelling has it `zi3` in 30 of its 38 cases.
354
- *
355
- * 罢 is the known loss. CC-CEDICT calls its `ba5` a final particle, so it is
356
- * held here, and CPP labels the character `ba4` in all 40 of its cases: the
357
- * particle is the literary 也罢 and 罢了, while a modern bare 罢 is 罢工. Left
358
- * protected because the rule is about what a source claims of the character,
359
- * and singling one out because a dataset disagrees is fitting to the dataset.
360
- */
361
- function isNeutralAlone(character, entries) {
362
- return entries.some((entry) => {
363
- const reading = readDictionaryReading(character, entry.readings);
364
- return (reading?.length === 1 &&
365
- reading[0]?.tone === NEUTRAL_TONE &&
366
- !entry.definitions.some((definition) => SUFFIX_SENSE.test(definition)));
367
- });
368
- }
369
- /**
370
- * Demote a 轻声 the frequency field counted only inside words.
371
- *
372
- * `kHanyuPinlu` counts occurrences in running text, and a character's neutral
373
- * count there mixes two unrelated things: a character that stands alone
374
- * unstressed, and one reduced *inside a word*. Where the field writes the same
375
- * spelling both bare and toned it is reporting that split with no way to say
376
- * which is which — 西 is `xi(902) xī(738)`, and the 902 are 东西 — and since the
377
- * field leads {@link import("../sources/unihan.js").READING_FIELDS}, the
378
- * reduction became the character's reading. 西 read `xi`, so 往西 was `wǎng xi`;
379
- * 夫 read `fu`, 识 `shi`, 拾 `shi`, 候 `hou`, 姐 `jie`, 友 `you`.
380
- *
381
- * So a bare spelling the field also writes with a tone ranks below that twin —
382
- * demoted rather than dropped, keeping it as a candidate without letting it set
383
- * the default, exactly as a lone `kHanyuPinlu` reading is. It reaches 50
384
- * characters, and {@link isNeutralAlone} holds back the ones a source says are
385
- * neutral on their own.
386
- *
387
- * The other half of the same blind spot is already handled: where the field
388
- * marks *no* tone at all it omitted the mark rather than meaning 轻声, which is
389
- * {@link resolveFrequencyTones}.
390
- */
391
- function demoteReducedNeutrals(unihan, readings) {
392
- const frequency = unihan.fields.get(FREQUENCY_FIELD) ?? [];
393
- const reduced = new Set(frequency.filter((reading) => !isToneMarked(reading) &&
394
- frequency.some((other) => isToneMarked(other) && tonelessReading(other) === reading)));
395
- if (reduced.size === 0) {
396
- return readings;
397
- }
398
- return [
399
- ...readings.filter((reading) => !reduced.has(reading)),
400
- ...readings.filter((reading) => reduced.has(reading)),
401
- ];
402
- }
403
- /**
404
- * Parse a Unihan reading string for one character.
405
- *
406
- * Goes through the dictionary reader so that a Unihan reading gets the same
407
- * treatment as any other source's: an unmarked tone means neutral, and 一 and
408
- * 不 are restored to their underlying tones.
409
- */
410
- function characterSyllable(character, reading) {
411
- return readDictionaryReading(character, [reading])?.[0];
412
- }
8
+ import { composeLocaleDeltas } from "./locale.js";
9
+ import { indexCedict, senseLookup } from "./cedict-senses.js";
10
+ import { buildCharacterDefaults } from "./character-defaults.js";
11
+ import { repairConstituentReadings } from "./constituent-repair.js";
12
+ import { mergeWords, wordList } from "./merge-walk.js";
413
13
  /**
414
14
  * Build the merged dictionary from the four parsed sources.
415
15
  *
416
16
  * The order of operations is the one MERGE.md sets out, and it is not
417
17
  * arbitrary — each step depends on the one before. Spelling, tones, sandhi and
418
- * validation happen in {@link readAlignedReading} as each source is read; this
419
- * function then repairs 儿化, derives 繁體 forms, resolves the disagreements
420
- * between sources, and finally applies the override table.
18
+ * validation happen in {@link import("./reading.js").readAlignedReading} as each source is read;
19
+ * {@link mergeWords} then settles one word at a time, and the passes after it
20
+ * see every entry at once.
421
21
  */
422
22
  export function mergeSources(sources) {
423
- const { unihanReadings, unihanVariants, phrase, cedict, jieba } = sources;
23
+ const { phrase, cedict } = sources;
424
24
  const cedictByWord = indexCedict(cedict, (entry) => entry.simplified);
425
25
  // Only ever read for {@link isOwnSense}. A 繁體-only headword keeps its senses
426
26
  // under whichever 简体 form each one simplifies to — 沈 is `chén` under 沉 and
427
27
  // 誰 is `shéi` under 谁 — so the 简体 index alone cannot say what a character
428
28
  // like that already reads in 普通话.
429
29
  const cedictByHant = indexCedict(cedict, (entry) => entry.traditional);
430
- // ── 繁體 evidence, mined from CC-CEDICT's own pairings ──────
431
- // Before the character defaults, because the corpus mass those are ranked by
432
- // has to reach 繁體 characters through this table: jieba's corpus and the
433
- // phrase corpus are both 简体, so nothing else would count a vote for 髮.
434
- const pairings = [];
435
- for (const entry of cedict) {
436
- const aligned = readAlignedReading(entry.simplified, entry.readings);
437
- pairings.push(...pairScripts(entry.simplified, entry.traditional, aligned));
438
- }
439
- const traditional = TraditionalTable.build(pairings, unihanVariants, unihanReadings);
440
- // ── Character defaults, which every later step leans on ────
441
- // Unihan ranks the readings and the corpus re-ranks the ones it has seen: a
442
- // character's default is whichever of its readings the dictionary's own words
443
- // spend the most of jieba's corpus on, and Unihan's order decides the rest.
444
- const mass = countCorpusMass({ phrase, cedict, jieba }, traditional);
445
- const defaults = new Map();
446
- let reducedNeutrals = 0;
447
- for (const [character, readings] of unihanReadings) {
448
- const resolved = resolveFrequencyTones(readings);
449
- // A 轻声 the frequency field only ever counted inside words is not the
450
- // character's reading — unless a source says the bare character is neutral.
451
- const ranked = isNeutralAlone(character, [
452
- ...(cedictByWord.get(character) ?? []),
453
- ...(cedictByHant.get(character) ?? []),
454
- ])
455
- ? resolved
456
- : demoteReducedNeutrals(readings, resolved);
457
- if (ranked !== resolved && ranked[0] !== resolved[0]) {
458
- reducedNeutrals++;
459
- }
460
- const parsed = ranked
461
- .map((reading) => characterSyllable(character, reading))
462
- .filter((syllable) => syllable !== undefined);
463
- if (parsed.length > 0) {
464
- defaults.set(character, rankByCorpusMass(character, parsed, readings.fields, mass));
465
- }
466
- }
467
- const words = new Set([
468
- ...defaults.keys(),
469
- ...[...phrase.keys()].filter((word) => !isSpeltTraditionally(word, cedictByWord, cedictByHant)),
470
- ...cedictByWord.keys(),
471
- ]);
472
- const entries = [];
473
- const rejected = new Map();
474
- let neutralToneCorrections = 0;
475
- let erhuaRepairs = 0;
476
- let derivedTraditional = 0;
477
- let scriptPairs = 0;
478
- let variantSpellings = 0;
479
- let taiwanReadings = 0;
480
- let properNounVetoes = 0;
481
- let nameBoundaries = 0;
482
- let phraseWords = 0;
483
- let cedictWords = 0;
484
- let characters = 0;
485
- for (const word of [...words].toSorted(byCodeUnit)) {
486
- const cedictEntries = cedictByWord.get(word) ?? [];
487
- const cedictReadings = cedictReadingsOf(word, cedictEntries);
488
- // Every reading CC-CEDICT gives this spelling, under either script.
489
- const senseReadings = [
490
- ...cedictReadings,
491
- ...cedictReadingsOf(word, cedictByHant.get(word) ?? []),
492
- ];
493
- const phraseReading = phrase.get(word);
494
- const phraseAligned = phraseReading === undefined
495
- ? undefined
496
- : readAlignedReading(word, phraseReading);
497
- // ── The reading: phrase corpus leads, CC-CEDICT corrects ──
498
- let aligned = phraseAligned;
499
- let reading = aligned
500
- ?.map((read) => read.syllable)
501
- .filter((syllable) => syllable !== undefined);
502
- if (reading === undefined) {
503
- // No phrase entry. Single characters fall back to Unihan, which is the
504
- // better source for them anyway; everything else falls back to
505
- // CC-CEDICT.
506
- const characterDefault = defaults.get(word);
507
- if (isSingleCharacter(word) && characterDefault !== undefined) {
508
- reading = characterDefault.slice(0, 1);
509
- aligned = [{ characters: word, syllable: reading[0] }];
510
- }
511
- else if (cedictReadings[0] !== undefined) {
512
- reading = cedictReadings[0];
513
- aligned = readAlignedReading(word, cedictEntries[0]?.readings ?? []);
514
- }
515
- }
516
- if (reading === undefined || reading.length === 0) {
517
- rejected.set(word, phraseReading ?? cedictEntries[0]?.readings ?? []);
518
- continue;
519
- }
520
- // ── 儿化, before anything compares two readings ────────────
521
- if (isErhua(word, cedictReadings)) {
522
- const attached = attachErhua(reading);
523
- if (attached !== reading) {
524
- erhuaRepairs++;
525
- reading = attached;
526
- // Fold the alignment the same way, so the 繁體 derivation still knows
527
- // which character each syllable reads.
528
- const last = aligned?.at(-1);
529
- const previous = aligned?.at(-2);
530
- if (aligned !== undefined &&
531
- last !== undefined &&
532
- previous !== undefined) {
533
- aligned = [
534
- ...aligned.slice(0, -2),
535
- {
536
- characters: previous.characters + last.characters,
537
- syllable: attached.at(-1),
538
- },
539
- ];
540
- }
541
- }
542
- }
543
- else if (reading.every((syllable) => syllable.erhua !== true)) {
544
- // 儿化 in the middle of a word, which the trailing repair above cannot
545
- // reach: 一点儿事 is `yìdiǎnr shì`, three syllables over four characters,
546
- // and the phrase corpus writes four. Only CC-CEDICT's `r5` marks it, and
547
- // only it knows where, so where it does the whole reading is taken from
548
- // it — 53 of its 683 `r5` entries carry the marker mid-word.
549
- const marked = cedictEntries.find((entry) => entry.readings.includes(ERHUA_TOKEN));
550
- const markedAligned = marked === undefined
551
- ? undefined
552
- : readAlignedReading(word, marked.readings);
553
- if (markedAligned !== undefined) {
554
- erhuaRepairs++;
555
- aligned = markedAligned;
556
- reading = markedAligned
557
- .map((read) => read.syllable)
558
- .filter((syllable) => syllable !== undefined);
559
- }
560
- }
561
- // ── Disagreements: CC-CEDICT wins on neutral tones ────────
562
- // Which sense to correct against is normally the nearest one. For a word on
563
- // the 轻声 list it is the nearest sense that *reduces* a syllable, because
564
- // there the nearest sense is the full-tone homograph the corpus happens to
565
- // have written and the everyday word is the other one — see
566
- // {@link NEUTRAL_SENSE_WORDS}.
567
- const chosen = reading;
568
- const nearest = phraseAligned === undefined
569
- ? undefined
570
- : ((NEUTRAL_SENSE_LOOKUP.has(word)
571
- ? nearestReading(chosen, cedictReadings.filter((candidate) => reducesToNeutral(chosen, candidate)))
572
- : undefined) ?? nearestReading(chosen, cedictReadings));
573
- // A sense of a different length describes a different pronunciation, so
574
- // there is no syllable-for-syllable correction to make against it.
575
- if (nearest !== undefined) {
576
- const corrected = preferNeutralTones(reading, nearest);
577
- if (!isSameReading(corrected, reading)) {
578
- neutralToneCorrections++;
579
- reading = corrected;
580
- }
581
- }
582
- // ── The override table has the last word ──────────────────
583
- const override = OVERRIDE_READINGS.get(word);
584
- if (override !== undefined) {
585
- reading = override;
586
- }
587
- // ── 繁體: taken from CC-CEDICT, derived where it is silent ─
588
- // Which sense matters: 万 is 萬 when read wàn but stays 万 when read mò, and
589
- // CC-CEDICT carries both as separate entries. Taking whichever came first
590
- // in the file would pair the chosen reading with another sense's script.
591
- const senses = sensesForReading(word, cedictEntries, reading);
592
- const sense = senses[0];
593
- let hant;
594
- if (sense === undefined) {
595
- // Canonicalised because the derivation settles each word against Unihan's
596
- // variant lists with no single standard behind it, so 里 derives as 裏
597
- // where the corpus overwhelmingly writes 裡. Both are the same character
598
- // with the same reading, and a key written in the form the lookup path
599
- // normalises *away from* can never be found — see the note below.
600
- hant = toCanonicalGlyphs(traditional.convert(aligned ?? []));
601
- if (hant !== word) {
602
- derivedTraditional++;
603
- }
604
- }
605
- else {
606
- hant = toCanonicalGlyphs(sense.traditional);
607
- }
608
- if (hant !== word) {
609
- scriptPairs++;
610
- }
611
- // Other spellings of the same word, so that a 繁體 reader of either finds
612
- // it. Only what a source writes out: composing spellings from per-character
613
- // variants instead would add 229,482 keys to the full tier, almost all of
614
- // them forms nobody writes — 方麵 for 方面, 公裡 for 公里 — because the
615
- // reading that picks the right variant for one word does not generalise to
616
- // every word the character appears in.
617
- //
618
- // Canonicalised for the same reason `hant` is, and deduplicated after:
619
- // 裏面 and 裡面 are one spelling once the glyph forms are folded, and
620
- // keying both would claim a variant that does not exist.
621
- //
622
- // The 简体 headword's own canonical spelling joins them where it differs,
623
- // and that is not a nicety: the lookup path normalises 繁體 glyph forms
624
- // before it searches, so a key written in a form it normalises *away from*
625
- // can never be found. The phrase corpus carries a few hundred headwords
626
- // spelled with 峯, 藴 or 枱 — 鹫峯寺, 义藴, 写字枱 — and without this they
627
- // are entries nothing can reach.
628
- const hantVariants = [
629
- ...new Set([
630
- ...senses.map((other) => toCanonicalGlyphs(other.traditional)),
631
- toCanonicalGlyphs(word),
632
- ]),
633
- ].filter((form) => form !== hant && form !== word);
634
- if (hantVariants.length > 0) {
635
- variantSpellings++;
636
- }
637
- // ── zh-TW delta ───────────────────────────────────────────
638
- // Only from a sense that reads the way this entry reads. CC-CEDICT hangs
639
- // `Taiwan pr.` on one sense of a headword and the others know nothing about
640
- // it: 著 is marked `zhuó` on the chess-move sense that reads `zhāo`, and
641
- // reaching across for it gave the aspect particle 着 a 國語 reading of
642
- // `zhuó`.
643
- //
644
- // A note can also sit on a sense of the *right* reading and still not be
645
- // about the character — see `isSenseScopedNote`.
646
- const taiwanSense = senses.find((entry) => entry.taiwanReadings !== undefined);
647
- const taiwanTokens = isSenseScopedNote(word, taiwanSense)
648
- ? undefined
649
- : taiwanSense?.taiwanReadings;
650
- const unihanTaiwan = unihanReadings.get(word)?.taiwanReading;
651
- let taiwan;
652
- if (taiwanTokens !== undefined) {
653
- taiwan = readDictionaryReading(word, taiwanTokens);
654
- }
655
- else if (isSingleCharacter(word) && unihanTaiwan !== undefined) {
656
- const syllable = characterSyllable(word, unihanTaiwan);
657
- taiwan = syllable === undefined ? undefined : [syllable];
658
- }
659
- if (taiwan !== undefined &&
660
- (isSameReading(taiwan, reading) || isOwnSense(taiwan, senseReadings))) {
661
- taiwan = undefined;
662
- }
663
- if (taiwan !== undefined) {
664
- taiwanReadings++;
665
- }
666
- // ── Frequency, part of speech and the proper noun bit ─────
667
- const jiebaEntry = jieba.get(word);
668
- const partOfSpeech = jiebaEntry?.partOfSpeech ?? "";
669
- // jieba's tags propose a proper noun and CC-CEDICT's capitalisation can
670
- // veto it. The tags on their own are noisy enough to be worth correcting:
671
- // 沙发, 城市, 阿姨, 智能卡 and 花生仁 are all tagged nr or nz, and the
672
- // decoder capitalises straight off this bit, so 我买了一个沙发 came out as
673
- // `Wǒ mǎile yīge Shāfā`.
674
- //
675
- // The veto only ever demotes, never promotes. CC-CEDICT capitalises the
676
- // pinyin of a proper noun, which is a claim about the word rather than a
677
- // category it was sorted into — but it also capitalises any headword
678
- // written with Latin letters, so a capital there is not proof on its own.
679
- // A lowercase one is much better evidence, since nothing else would write
680
- // it that way.
681
- const isProperNoun = jiebaEntry === undefined
682
- ? cedictEntries.some((entry) => entry.isProperNoun)
683
- : isProperNounTag(partOfSpeech) &&
684
- (senses.length === 0 || senses.some((entry) => entry.isProperNoun));
685
- if (isProperNounTag(partOfSpeech) && !isProperNoun) {
686
- properNounVetoes++;
687
- }
688
- // ── Where the 姓 ends, where CC-CEDICT says so ────────────
689
- // Only for a word that survived the veto above: an entry no one takes for a
690
- // proper noun has no 姓 to end. The boundary counts characters, so it is
691
- // only meaningful where this word reads one syllable per character — 儿化
692
- // reads two characters as one syllable and could not be cut by it.
693
- const isAligned = characterCount(word) === reading.length;
694
- const boundaries = isProperNoun && isAligned
695
- ? (cedictEntries
696
- .map((entry) => nameBoundariesOf(entry.readings))
697
- .find((found) => found.length > 0) ?? [])
698
- : [];
699
- if (boundaries.length > 0) {
700
- nameBoundaries++;
701
- }
702
- // ── Polyphone priors, for single characters only ──────────
703
- const characterReadings = defaults.get(word) ?? [];
704
- const alternates = isSingleCharacter(word)
705
- ? characterReadings
706
- .filter((syllable) => !isSameReading([syllable], reading))
707
- .map((syllable) => [syllable])
708
- : [];
709
- entries.push({
710
- hans: word,
711
- hant,
712
- ...(hantVariants.length > 0 && { hantVariants }),
713
- readings: { cn: reading, ...(taiwan !== undefined && { tw: taiwan }) },
714
- frequency: jiebaEntry?.frequency ?? 0,
715
- partOfSpeech,
716
- isProperNoun,
717
- ...(boundaries.length > 0 && { nameBoundaries: boundaries }),
718
- ...(alternates.length > 0 && { alternates }),
719
- });
720
- if (isSingleCharacter(word)) {
721
- characters++;
722
- }
723
- if (phraseReading !== undefined) {
724
- phraseWords++;
725
- }
726
- if (cedictEntries.length > 0) {
727
- cedictWords++;
728
- }
729
- }
30
+ const { traditional, defaults, reducedNeutrals } = buildCharacterDefaults(sources, cedictByWord, cedictByHant);
31
+ const wordSources = {
32
+ cedictByWord,
33
+ cedictByHant,
34
+ phrase,
35
+ jieba: sources.jieba,
36
+ unihanReadings: sources.unihanReadings,
37
+ traditional,
38
+ defaults,
39
+ };
40
+ const { entries, rejected, counts } = mergeWords(wordList(phrase, defaults, cedictByWord, cedictByHant), wordSources);
41
+ // ── Phrase entries held to the words inside them ───────────
42
+ // Before the locale pass, which asks whether a compound reads a constituent
43
+ // the way that constituent's own entry reads it. A phrase entry repaired here
44
+ // answers yes where it used to answer no.
45
+ const held = repairConstituentReadings(entries, senseLookup(cedictByWord, cedictByHant));
730
46
  // ── zh-TW deltas the sources marked only on a constituent ──
731
47
  // Last, because it segments each compound against the finished entries: the
732
48
  // readings, both scripts' keys and the frequencies all have to be settled
733
49
  // before a compound can be asked what it is made of.
734
- const localised = composeLocaleDeltas(entries);
50
+ const localised = composeLocaleDeltas(held.entries);
735
51
  return {
736
52
  entries: localised.entries,
737
53
  rejected,
738
54
  stats: {
739
- characters,
740
- phraseWords,
741
- cedictWords,
742
- neutralToneCorrections,
55
+ ...counts,
743
56
  reducedNeutrals,
744
- erhuaRepairs,
745
- derivedTraditional,
746
- scriptPairs,
747
- variantSpellings,
748
- taiwanReadings,
57
+ repairedConstituents: held.repaired,
749
58
  composedTaiwanReadings: localised.composed,
750
- properNounVetoes,
751
- nameBoundaries,
752
59
  rejected: rejected.size,
753
60
  },
754
61
  };