@kensio/pinyinjs 1.7.4 → 1.7.5

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 (695) hide show
  1. package/dist/accuracy/score-case.d.ts +23 -0
  2. package/dist/accuracy/score-case.d.ts.map +1 -0
  3. package/dist/accuracy/score-case.js +63 -0
  4. package/dist/accuracy/score-case.js.map +1 -0
  5. package/dist/accuracy/score.d.ts +1 -8
  6. package/dist/accuracy/score.d.ts.map +1 -1
  7. package/dist/accuracy/score.js +1 -55
  8. package/dist/accuracy/score.js.map +1 -1
  9. package/dist/cli/arguments.d.ts +4 -290
  10. package/dist/cli/arguments.d.ts.map +1 -1
  11. package/dist/cli/arguments.js +5 -357
  12. package/dist/cli/arguments.js.map +1 -1
  13. package/dist/cli/check-command.d.ts +9 -0
  14. package/dist/cli/check-command.d.ts.map +1 -0
  15. package/dist/cli/check-command.js +95 -0
  16. package/dist/cli/check-command.js.map +1 -0
  17. package/dist/cli/cli-input.d.ts +49 -0
  18. package/dist/cli/cli-input.d.ts.map +1 -0
  19. package/dist/cli/cli-input.js +31 -0
  20. package/dist/cli/cli-input.js.map +1 -0
  21. package/dist/cli/command.d.ts +97 -0
  22. package/dist/cli/command.d.ts.map +1 -0
  23. package/dist/cli/command.js +40 -0
  24. package/dist/cli/command.js.map +1 -0
  25. package/dist/cli/commands.d.ts +7 -110
  26. package/dist/cli/commands.d.ts.map +1 -1
  27. package/dist/cli/commands.js +14 -991
  28. package/dist/cli/commands.js.map +1 -1
  29. package/dist/cli/convert-command.d.ts +6 -0
  30. package/dist/cli/convert-command.d.ts.map +1 -0
  31. package/dist/cli/convert-command.js +52 -0
  32. package/dist/cli/convert-command.js.map +1 -0
  33. package/dist/cli/environment.d.ts +1 -1
  34. package/dist/cli/environment.d.ts.map +1 -1
  35. package/dist/cli/explain-command.d.ts +6 -0
  36. package/dist/cli/explain-command.d.ts.map +1 -0
  37. package/dist/cli/explain-command.js +40 -0
  38. package/dist/cli/explain-command.js.map +1 -0
  39. package/dist/cli/explain-syllable.d.ts +10 -0
  40. package/dist/cli/explain-syllable.d.ts.map +1 -0
  41. package/dist/cli/explain-syllable.js +70 -0
  42. package/dist/cli/explain-syllable.js.map +1 -0
  43. package/dist/cli/flag-help.d.ts +18 -0
  44. package/dist/cli/flag-help.d.ts.map +1 -0
  45. package/dist/cli/flag-help.js +78 -0
  46. package/dist/cli/flag-help.js.map +1 -0
  47. package/dist/cli/flag-lists.d.ts +49 -0
  48. package/dist/cli/flag-lists.d.ts.map +1 -0
  49. package/dist/cli/flag-lists.js +58 -0
  50. package/dist/cli/flag-lists.js.map +1 -0
  51. package/dist/cli/flag-values.d.ts +44 -0
  52. package/dist/cli/flag-values.d.ts.map +1 -0
  53. package/dist/cli/flag-values.js +56 -0
  54. package/dist/cli/flag-values.js.map +1 -0
  55. package/dist/cli/flags.d.ts +193 -0
  56. package/dist/cli/flags.d.ts.map +1 -0
  57. package/dist/cli/flags.js +133 -0
  58. package/dist/cli/flags.js.map +1 -0
  59. package/dist/cli/format-options.d.ts +29 -0
  60. package/dist/cli/format-options.d.ts.map +1 -0
  61. package/dist/cli/format-options.js +72 -0
  62. package/dist/cli/format-options.js.map +1 -0
  63. package/dist/cli/global-help.d.ts +23 -0
  64. package/dist/cli/global-help.d.ts.map +1 -0
  65. package/dist/cli/global-help.js +40 -0
  66. package/dist/cli/global-help.js.map +1 -0
  67. package/dist/cli/help.d.ts +1 -1
  68. package/dist/cli/help.d.ts.map +1 -1
  69. package/dist/cli/help.js +5 -99
  70. package/dist/cli/help.js.map +1 -1
  71. package/dist/cli/html-commands.d.ts +13 -0
  72. package/dist/cli/html-commands.d.ts.map +1 -0
  73. package/dist/cli/html-commands.js +49 -0
  74. package/dist/cli/html-commands.js.map +1 -0
  75. package/dist/cli/info-command.d.ts +7 -0
  76. package/dist/cli/info-command.d.ts.map +1 -0
  77. package/dist/cli/info-command.js +39 -0
  78. package/dist/cli/info-command.js.map +1 -0
  79. package/dist/cli/lookup-commands.d.ts +10 -0
  80. package/dist/cli/lookup-commands.d.ts.map +1 -0
  81. package/dist/cli/lookup-commands.js +101 -0
  82. package/dist/cli/lookup-commands.js.map +1 -0
  83. package/dist/cli/match-command.d.ts +11 -0
  84. package/dist/cli/match-command.d.ts.map +1 -0
  85. package/dist/cli/match-command.js +76 -0
  86. package/dist/cli/match-command.js.map +1 -0
  87. package/dist/cli/number-command.d.ts +12 -0
  88. package/dist/cli/number-command.d.ts.map +1 -0
  89. package/dist/cli/number-command.js +89 -0
  90. package/dist/cli/number-command.js.map +1 -0
  91. package/dist/cli/options.d.ts +30 -0
  92. package/dist/cli/options.d.ts.map +1 -0
  93. package/dist/cli/options.js +54 -0
  94. package/dist/cli/options.js.map +1 -0
  95. package/dist/cli/run-command.d.ts +24 -0
  96. package/dist/cli/run-command.d.ts.map +1 -0
  97. package/dist/cli/run-command.js +40 -0
  98. package/dist/cli/run-command.js.map +1 -0
  99. package/dist/cli/run.d.ts +4 -42
  100. package/dist/cli/run.d.ts.map +1 -1
  101. package/dist/cli/run.js +6 -61
  102. package/dist/cli/run.js.map +1 -1
  103. package/dist/cli/script-command.d.ts +10 -0
  104. package/dist/cli/script-command.d.ts.map +1 -0
  105. package/dist/cli/script-command.js +58 -0
  106. package/dist/cli/script-command.js.map +1 -0
  107. package/dist/cli/segment-command.d.ts +11 -0
  108. package/dist/cli/segment-command.d.ts.map +1 -0
  109. package/dist/cli/segment-command.js +53 -0
  110. package/dist/cli/segment-command.js.map +1 -0
  111. package/dist/cli/slug-command.d.ts +10 -0
  112. package/dist/cli/slug-command.d.ts.map +1 -0
  113. package/dist/cli/slug-command.js +28 -0
  114. package/dist/cli/slug-command.js.map +1 -0
  115. package/dist/cli/syllable-command.d.ts +14 -0
  116. package/dist/cli/syllable-command.d.ts.map +1 -0
  117. package/dist/cli/syllable-command.js +82 -0
  118. package/dist/cli/syllable-command.js.map +1 -0
  119. package/dist/cli/system-table.d.ts +12 -0
  120. package/dist/cli/system-table.d.ts.map +1 -0
  121. package/dist/cli/system-table.js +48 -0
  122. package/dist/cli/system-table.js.map +1 -0
  123. package/dist/cli/systems.d.ts +57 -0
  124. package/dist/cli/systems.d.ts.map +1 -0
  125. package/dist/cli/systems.js +27 -0
  126. package/dist/cli/systems.js.map +1 -0
  127. package/dist/cli/transcribe-command.d.ts +18 -0
  128. package/dist/cli/transcribe-command.d.ts.map +1 -0
  129. package/dist/cli/transcribe-command.js +86 -0
  130. package/dist/cli/transcribe-command.js.map +1 -0
  131. package/dist/cli/transcribe-reading.d.ts +15 -0
  132. package/dist/cli/transcribe-reading.d.ts.map +1 -0
  133. package/dist/cli/transcribe-reading.js +90 -0
  134. package/dist/cli/transcribe-reading.js.map +1 -0
  135. package/dist/cli/transcribe-rows.d.ts +26 -0
  136. package/dist/cli/transcribe-rows.d.ts.map +1 -0
  137. package/dist/cli/transcribe-rows.js +30 -0
  138. package/dist/cli/transcribe-rows.js.map +1 -0
  139. package/dist/cli/usage-error.d.ts +9 -0
  140. package/dist/cli/usage-error.d.ts.map +1 -0
  141. package/dist/cli/usage-error.js +9 -0
  142. package/dist/cli/usage-error.js.map +1 -0
  143. package/dist/decode/alternatives.d.ts +16 -0
  144. package/dist/decode/alternatives.d.ts.map +1 -0
  145. package/dist/decode/alternatives.js +31 -0
  146. package/dist/decode/alternatives.js.map +1 -0
  147. package/dist/decode/confidence.d.ts.map +1 -1
  148. package/dist/decode/confidence.js +3 -118
  149. package/dist/decode/confidence.js.map +1 -1
  150. package/dist/decode/convert-options.d.ts +116 -0
  151. package/dist/decode/convert-options.d.ts.map +1 -0
  152. package/dist/decode/convert-options.js +2 -0
  153. package/dist/decode/convert-options.js.map +1 -0
  154. package/dist/decode/convert-pipeline.d.ts +18 -0
  155. package/dist/decode/convert-pipeline.d.ts.map +1 -0
  156. package/dist/decode/convert-pipeline.js +66 -0
  157. package/dist/decode/convert-pipeline.js.map +1 -0
  158. package/dist/decode/convert.d.ts +9 -118
  159. package/dist/decode/convert.d.ts.map +1 -1
  160. package/dist/decode/convert.js +5 -453
  161. package/dist/decode/convert.js.map +1 -1
  162. package/dist/decode/decode.d.ts +2 -15
  163. package/dist/decode/decode.d.ts.map +1 -1
  164. package/dist/decode/decode.js +2 -121
  165. package/dist/decode/decode.js.map +1 -1
  166. package/dist/decode/decoders.d.ts +32 -0
  167. package/dist/decode/decoders.d.ts.map +1 -0
  168. package/dist/decode/decoders.js +29 -0
  169. package/dist/decode/decoders.js.map +1 -0
  170. package/dist/decode/edge-context.d.ts +38 -0
  171. package/dist/decode/edge-context.d.ts.map +1 -0
  172. package/dist/decode/edge-context.js +57 -0
  173. package/dist/decode/edge-context.js.map +1 -0
  174. package/dist/decode/hint-lattice.d.ts +45 -0
  175. package/dist/decode/hint-lattice.d.ts.map +1 -0
  176. package/dist/decode/hint-lattice.js +140 -0
  177. package/dist/decode/hint-lattice.js.map +1 -0
  178. package/dist/decode/hints.d.ts +2 -45
  179. package/dist/decode/hints.d.ts.map +1 -1
  180. package/dist/decode/hints.js +1 -139
  181. package/dist/decode/hints.js.map +1 -1
  182. package/dist/decode/jiao-rule.d.ts +58 -0
  183. package/dist/decode/jiao-rule.d.ts.map +1 -0
  184. package/dist/decode/jiao-rule.js +76 -0
  185. package/dist/decode/jiao-rule.js.map +1 -0
  186. package/dist/decode/lattice-costs.d.ts +55 -0
  187. package/dist/decode/lattice-costs.d.ts.map +1 -0
  188. package/dist/decode/lattice-costs.js +90 -0
  189. package/dist/decode/lattice-costs.js.map +1 -0
  190. package/dist/decode/lattice-edges.d.ts +29 -0
  191. package/dist/decode/lattice-edges.d.ts.map +1 -0
  192. package/dist/decode/lattice-edges.js +78 -0
  193. package/dist/decode/lattice-edges.js.map +1 -0
  194. package/dist/decode/lattice-slice.d.ts +37 -0
  195. package/dist/decode/lattice-slice.d.ts.map +1 -0
  196. package/dist/decode/lattice-slice.js +43 -0
  197. package/dist/decode/lattice-slice.js.map +1 -0
  198. package/dist/decode/lattice-types.d.ts +82 -0
  199. package/dist/decode/lattice-types.d.ts.map +1 -0
  200. package/dist/decode/lattice-types.js +44 -0
  201. package/dist/decode/lattice-types.js.map +1 -0
  202. package/dist/decode/lattice.d.ts +2 -59
  203. package/dist/decode/lattice.d.ts.map +1 -1
  204. package/dist/decode/lattice.js +2 -118
  205. package/dist/decode/lattice.js.map +1 -1
  206. package/dist/decode/number-pieces.d.ts +62 -0
  207. package/dist/decode/number-pieces.d.ts.map +1 -0
  208. package/dist/decode/number-pieces.js +106 -0
  209. package/dist/decode/number-pieces.js.map +1 -0
  210. package/dist/decode/numbers.d.ts +53 -0
  211. package/dist/decode/numbers.d.ts.map +1 -0
  212. package/dist/decode/numbers.js +69 -0
  213. package/dist/decode/numbers.js.map +1 -0
  214. package/dist/decode/pieces.d.ts +78 -0
  215. package/dist/decode/pieces.d.ts.map +1 -0
  216. package/dist/decode/pieces.js +136 -0
  217. package/dist/decode/pieces.js.map +1 -0
  218. package/dist/decode/polyphone-rules.d.ts +31 -0
  219. package/dist/decode/polyphone-rules.d.ts.map +1 -0
  220. package/dist/decode/polyphone-rules.js +159 -0
  221. package/dist/decode/polyphone-rules.js.map +1 -0
  222. package/dist/decode/reading-rules.d.ts +2 -97
  223. package/dist/decode/reading-rules.d.ts.map +1 -1
  224. package/dist/decode/reading-rules.js +4 -365
  225. package/dist/decode/reading-rules.js.map +1 -1
  226. package/dist/decode/rules.d.ts +1 -17
  227. package/dist/decode/rules.d.ts.map +1 -1
  228. package/dist/decode/rules.js +1 -43
  229. package/dist/decode/rules.js.map +1 -1
  230. package/dist/decode/run-lattice.d.ts +52 -0
  231. package/dist/decode/run-lattice.d.ts.map +1 -0
  232. package/dist/decode/run-lattice.js +91 -0
  233. package/dist/decode/run-lattice.js.map +1 -0
  234. package/dist/decode/sandhi-tones.d.ts +69 -0
  235. package/dist/decode/sandhi-tones.d.ts.map +1 -0
  236. package/dist/decode/sandhi-tones.js +88 -0
  237. package/dist/decode/sandhi-tones.js.map +1 -0
  238. package/dist/decode/sandhi.d.ts +1 -1
  239. package/dist/decode/sandhi.d.ts.map +1 -1
  240. package/dist/decode/sandhi.js +1 -81
  241. package/dist/decode/sandhi.js.map +1 -1
  242. package/dist/decode/script-types.d.ts +76 -0
  243. package/dist/decode/script-types.d.ts.map +1 -0
  244. package/dist/decode/script-types.js +35 -0
  245. package/dist/decode/script-types.js.map +1 -0
  246. package/dist/decode/script-words.d.ts +32 -0
  247. package/dist/decode/script-words.d.ts.map +1 -0
  248. package/dist/decode/script-words.js +77 -0
  249. package/dist/decode/script-words.js.map +1 -0
  250. package/dist/decode/script.d.ts +3 -73
  251. package/dist/decode/script.d.ts.map +1 -1
  252. package/dist/decode/script.js +3 -109
  253. package/dist/decode/script.js.map +1 -1
  254. package/dist/decode/tan-rule.d.ts +68 -0
  255. package/dist/decode/tan-rule.d.ts.map +1 -0
  256. package/dist/decode/tan-rule.js +131 -0
  257. package/dist/decode/tan-rule.js.map +1 -0
  258. package/dist/decode/write-run.d.ts +28 -0
  259. package/dist/decode/write-run.d.ts.map +1 -0
  260. package/dist/decode/write-run.js +77 -0
  261. package/dist/decode/write-run.js.map +1 -0
  262. package/dist/dictionary/artifact-claims.d.ts +25 -0
  263. package/dist/dictionary/artifact-claims.d.ts.map +1 -0
  264. package/dist/dictionary/artifact-claims.js +47 -0
  265. package/dist/dictionary/artifact-claims.js.map +1 -0
  266. package/dist/dictionary/artifact-format.d.ts +86 -0
  267. package/dist/dictionary/artifact-format.d.ts.map +1 -0
  268. package/dist/dictionary/artifact-format.js +91 -0
  269. package/dist/dictionary/artifact-format.js.map +1 -0
  270. package/dist/dictionary/artifact-read.d.ts +34 -0
  271. package/dist/dictionary/artifact-read.d.ts.map +1 -0
  272. package/dist/dictionary/artifact-read.js +114 -0
  273. package/dist/dictionary/artifact-read.js.map +1 -0
  274. package/dist/dictionary/artifact.d.ts +4 -63
  275. package/dist/dictionary/artifact.d.ts.map +1 -1
  276. package/dist/dictionary/artifact.js +12 -229
  277. package/dist/dictionary/artifact.js.map +1 -1
  278. package/dist/dictionary/assertions.d.ts +5 -57
  279. package/dist/dictionary/assertions.d.ts.map +1 -1
  280. package/dist/dictionary/assertions.js +4 -317
  281. package/dist/dictionary/assertions.js.map +1 -1
  282. package/dist/dictionary/build-assertions.d.ts +12 -0
  283. package/dist/dictionary/build-assertions.d.ts.map +1 -0
  284. package/dist/dictionary/build-assertions.js +13 -0
  285. package/dist/dictionary/build-assertions.js.map +1 -0
  286. package/dist/dictionary/built-dictionary.d.ts +46 -0
  287. package/dist/dictionary/built-dictionary.d.ts.map +1 -0
  288. package/dist/dictionary/built-dictionary.js +97 -0
  289. package/dist/dictionary/built-dictionary.js.map +1 -0
  290. package/dist/dictionary/cedict-senses.d.ts +80 -0
  291. package/dist/dictionary/cedict-senses.d.ts.map +1 -0
  292. package/dist/dictionary/cedict-senses.js +114 -0
  293. package/dist/dictionary/cedict-senses.js.map +1 -0
  294. package/dist/dictionary/character-defaults.d.ts +26 -0
  295. package/dist/dictionary/character-defaults.d.ts.map +1 -0
  296. package/dist/dictionary/character-defaults.js +67 -0
  297. package/dist/dictionary/character-defaults.js.map +1 -0
  298. package/dist/dictionary/character-readings.d.ts +10 -0
  299. package/dist/dictionary/character-readings.d.ts.map +1 -0
  300. package/dist/dictionary/character-readings.js +25 -0
  301. package/dist/dictionary/character-readings.js.map +1 -0
  302. package/dist/dictionary/dictionary-entry.d.ts +37 -0
  303. package/dist/dictionary/dictionary-entry.d.ts.map +1 -0
  304. package/dist/dictionary/dictionary-entry.js +41 -0
  305. package/dist/dictionary/dictionary-entry.js.map +1 -0
  306. package/dist/dictionary/dictionary-readings.d.ts +56 -0
  307. package/dist/dictionary/dictionary-readings.d.ts.map +1 -0
  308. package/dist/dictionary/dictionary-readings.js +93 -0
  309. package/dist/dictionary/dictionary-readings.js.map +1 -0
  310. package/dist/dictionary/dictionary.d.ts +6 -60
  311. package/dist/dictionary/dictionary.d.ts.map +1 -1
  312. package/dist/dictionary/dictionary.js +9 -169
  313. package/dist/dictionary/dictionary.js.map +1 -1
  314. package/dist/dictionary/entry-invariants.d.ts +3 -0
  315. package/dist/dictionary/entry-invariants.d.ts.map +1 -0
  316. package/dist/dictionary/entry-invariants.js +67 -0
  317. package/dist/dictionary/entry-invariants.js.map +1 -0
  318. package/dist/dictionary/entry-lines.d.ts +35 -0
  319. package/dist/dictionary/entry-lines.d.ts.map +1 -0
  320. package/dist/dictionary/entry-lines.js +70 -0
  321. package/dist/dictionary/entry-lines.js.map +1 -0
  322. package/dist/dictionary/erhua-repair.d.ts +26 -0
  323. package/dist/dictionary/erhua-repair.d.ts.map +1 -0
  324. package/dist/dictionary/erhua-repair.js +49 -0
  325. package/dist/dictionary/erhua-repair.js.map +1 -0
  326. package/dist/dictionary/frequency-tones.d.ts +74 -0
  327. package/dist/dictionary/frequency-tones.d.ts.map +1 -0
  328. package/dist/dictionary/frequency-tones.js +128 -0
  329. package/dist/dictionary/frequency-tones.js.map +1 -0
  330. package/dist/dictionary/inventory-invariants.d.ts +3 -0
  331. package/dist/dictionary/inventory-invariants.d.ts.map +1 -0
  332. package/dist/dictionary/inventory-invariants.js +54 -0
  333. package/dist/dictionary/inventory-invariants.js.map +1 -0
  334. package/dist/dictionary/locale-candidates.d.ts +40 -0
  335. package/dist/dictionary/locale-candidates.d.ts.map +1 -0
  336. package/dist/dictionary/locale-candidates.js +77 -0
  337. package/dist/dictionary/locale-candidates.js.map +1 -0
  338. package/dist/dictionary/locale-segments.d.ts +47 -0
  339. package/dist/dictionary/locale-segments.d.ts.map +1 -0
  340. package/dist/dictionary/locale-segments.js +141 -0
  341. package/dist/dictionary/locale-segments.js.map +1 -0
  342. package/dist/dictionary/locale.d.ts +1 -21
  343. package/dist/dictionary/locale.d.ts.map +1 -1
  344. package/dist/dictionary/locale.js +9 -198
  345. package/dist/dictionary/locale.js.map +1 -1
  346. package/dist/dictionary/merge-types.d.ts +121 -0
  347. package/dist/dictionary/merge-types.d.ts.map +1 -0
  348. package/dist/dictionary/merge-types.js +35 -0
  349. package/dist/dictionary/merge-types.js.map +1 -0
  350. package/dist/dictionary/merge-word.d.ts +7 -0
  351. package/dist/dictionary/merge-word.d.ts.map +1 -0
  352. package/dist/dictionary/merge-word.js +91 -0
  353. package/dist/dictionary/merge-word.js.map +1 -0
  354. package/dist/dictionary/merge.d.ts +5 -62
  355. package/dist/dictionary/merge.d.ts.map +1 -1
  356. package/dist/dictionary/merge.js +30 -713
  357. package/dist/dictionary/merge.js.map +1 -1
  358. package/dist/dictionary/proper-noun.d.ts +28 -0
  359. package/dist/dictionary/proper-noun.d.ts.map +1 -0
  360. package/dist/dictionary/proper-noun.js +43 -0
  361. package/dist/dictionary/proper-noun.js.map +1 -0
  362. package/dist/dictionary/reading-agreement.d.ts +71 -0
  363. package/dist/dictionary/reading-agreement.d.ts.map +1 -0
  364. package/dist/dictionary/reading-agreement.js +156 -0
  365. package/dist/dictionary/reading-agreement.js.map +1 -0
  366. package/dist/dictionary/script-conversion.d.ts +28 -0
  367. package/dist/dictionary/script-conversion.d.ts.map +1 -0
  368. package/dist/dictionary/script-conversion.js +58 -0
  369. package/dist/dictionary/script-conversion.js.map +1 -0
  370. package/dist/dictionary/script-pairings.d.ts +74 -0
  371. package/dist/dictionary/script-pairings.d.ts.map +1 -0
  372. package/dist/dictionary/script-pairings.js +120 -0
  373. package/dist/dictionary/script-pairings.js.map +1 -0
  374. package/dist/dictionary/script-tables.d.ts.map +1 -1
  375. package/dist/dictionary/script-tables.js +2 -165
  376. package/dist/dictionary/script-tables.js.map +1 -1
  377. package/dist/dictionary/taiwan-reading.d.ts +8 -0
  378. package/dist/dictionary/taiwan-reading.d.ts.map +1 -0
  379. package/dist/dictionary/taiwan-reading.js +38 -0
  380. package/dist/dictionary/taiwan-reading.js.map +1 -0
  381. package/dist/dictionary/tone-invariants.d.ts +3 -0
  382. package/dist/dictionary/tone-invariants.d.ts.map +1 -0
  383. package/dist/dictionary/tone-invariants.js +64 -0
  384. package/dist/dictionary/tone-invariants.js.map +1 -0
  385. package/dist/dictionary/traditional-form.d.ts +21 -0
  386. package/dist/dictionary/traditional-form.d.ts.map +1 -0
  387. package/dist/dictionary/traditional-form.js +59 -0
  388. package/dist/dictionary/traditional-form.js.map +1 -0
  389. package/dist/dictionary/traditional-ranking.d.ts +22 -0
  390. package/dist/dictionary/traditional-ranking.d.ts.map +1 -0
  391. package/dist/dictionary/traditional-ranking.js +74 -0
  392. package/dist/dictionary/traditional-ranking.js.map +1 -0
  393. package/dist/dictionary/traditional-table.d.ts +51 -0
  394. package/dist/dictionary/traditional-table.d.ts.map +1 -0
  395. package/dist/dictionary/traditional-table.js +98 -0
  396. package/dist/dictionary/traditional-table.js.map +1 -0
  397. package/dist/dictionary/traditional.d.ts +3 -56
  398. package/dist/dictionary/traditional.d.ts.map +1 -1
  399. package/dist/dictionary/traditional.js +3 -186
  400. package/dist/dictionary/traditional.js.map +1 -1
  401. package/dist/dictionary/variant-counts.d.ts +39 -0
  402. package/dist/dictionary/variant-counts.d.ts.map +1 -0
  403. package/dist/dictionary/variant-counts.js +38 -0
  404. package/dist/dictionary/variant-counts.js.map +1 -0
  405. package/dist/dictionary/word-reading.d.ts +26 -0
  406. package/dist/dictionary/word-reading.d.ts.map +1 -0
  407. package/dist/dictionary/word-reading.js +76 -0
  408. package/dist/dictionary/word-reading.js.map +1 -0
  409. package/dist/dictionary/word-readings.d.ts +15 -0
  410. package/dist/dictionary/word-readings.d.ts.map +1 -0
  411. package/dist/dictionary/word-readings.js +38 -0
  412. package/dist/dictionary/word-readings.js.map +1 -0
  413. package/dist/format/annotate.d.ts +90 -0
  414. package/dist/format/annotate.d.ts.map +1 -0
  415. package/dist/format/annotate.js +168 -0
  416. package/dist/format/annotate.js.map +1 -0
  417. package/dist/format/html.d.ts +15 -46
  418. package/dist/format/html.d.ts.map +1 -1
  419. package/dist/format/html.js +3 -162
  420. package/dist/format/html.js.map +1 -1
  421. package/dist/format/slug-hash.d.ts +51 -0
  422. package/dist/format/slug-hash.d.ts.map +1 -0
  423. package/dist/format/slug-hash.js +74 -0
  424. package/dist/format/slug-hash.js.map +1 -0
  425. package/dist/format/slug-options.d.ts +98 -0
  426. package/dist/format/slug-options.d.ts.map +1 -0
  427. package/dist/format/slug-options.js +2 -0
  428. package/dist/format/slug-options.js.map +1 -0
  429. package/dist/format/slug-words.d.ts +27 -0
  430. package/dist/format/slug-words.d.ts.map +1 -0
  431. package/dist/format/slug-words.js +0 -0
  432. package/dist/format/slug-words.js.map +1 -0
  433. package/dist/format/slug.d.ts +3 -128
  434. package/dist/format/slug.d.ts.map +1 -1
  435. package/dist/format/slug.js +0 -0
  436. package/dist/format/slug.js.map +1 -1
  437. package/dist/grade/check-readings.d.ts +41 -0
  438. package/dist/grade/check-readings.d.ts.map +1 -0
  439. package/dist/grade/check-readings.js +36 -0
  440. package/dist/grade/check-readings.js.map +1 -0
  441. package/dist/grade/check.d.ts +4 -4
  442. package/dist/grade/check.d.ts.map +1 -1
  443. package/dist/grade/check.js +5 -270
  444. package/dist/grade/check.js.map +1 -1
  445. package/dist/grade/pair-syllables.d.ts +48 -0
  446. package/dist/grade/pair-syllables.d.ts.map +1 -0
  447. package/dist/grade/pair-syllables.js +71 -0
  448. package/dist/grade/pair-syllables.js.map +1 -0
  449. package/dist/grade/reading-syllables.d.ts +62 -0
  450. package/dist/grade/reading-syllables.d.ts.map +1 -0
  451. package/dist/grade/reading-syllables.js +58 -0
  452. package/dist/grade/reading-syllables.js.map +1 -0
  453. package/dist/grade/reading-tolerance.d.ts +72 -0
  454. package/dist/grade/reading-tolerance.d.ts.map +1 -0
  455. package/dist/grade/reading-tolerance.js +107 -0
  456. package/dist/grade/reading-tolerance.js.map +1 -0
  457. package/dist/grade/typed-reading.d.ts +28 -0
  458. package/dist/grade/typed-reading.d.ts.map +1 -0
  459. package/dist/grade/typed-reading.js +36 -0
  460. package/dist/grade/typed-reading.js.map +1 -0
  461. package/dist/numerals/numeral-parse.d.ts +32 -0
  462. package/dist/numerals/numeral-parse.d.ts.map +1 -0
  463. package/dist/numerals/numeral-parse.js +44 -0
  464. package/dist/numerals/numeral-parse.js.map +1 -0
  465. package/dist/numerals/numeral-shapes.d.ts +89 -0
  466. package/dist/numerals/numeral-shapes.d.ts.map +1 -0
  467. package/dist/numerals/numeral-shapes.js +99 -0
  468. package/dist/numerals/numeral-shapes.js.map +1 -0
  469. package/dist/numerals/numerals.d.ts.map +1 -1
  470. package/dist/numerals/numerals.js +2 -36
  471. package/dist/numerals/numerals.js.map +1 -1
  472. package/dist/numerals/read-numeral.d.ts +76 -0
  473. package/dist/numerals/read-numeral.d.ts.map +1 -0
  474. package/dist/numerals/read-numeral.js +88 -0
  475. package/dist/numerals/read-numeral.js.map +1 -0
  476. package/dist/numerals/text.d.ts +3 -37
  477. package/dist/numerals/text.d.ts.map +1 -1
  478. package/dist/numerals/text.js +3 -254
  479. package/dist/numerals/text.js.map +1 -1
  480. package/dist/numerals/time.d.ts +34 -0
  481. package/dist/numerals/time.d.ts.map +1 -0
  482. package/dist/numerals/time.js +93 -0
  483. package/dist/numerals/time.js.map +1 -0
  484. package/dist/orthography/address-grouping.d.ts +34 -0
  485. package/dist/orthography/address-grouping.d.ts.map +1 -0
  486. package/dist/orthography/address-grouping.js +52 -0
  487. package/dist/orthography/address-grouping.js.map +1 -0
  488. package/dist/orthography/grouping.d.ts +3 -87
  489. package/dist/orthography/grouping.d.ts.map +1 -1
  490. package/dist/orthography/grouping.js +4 -270
  491. package/dist/orthography/grouping.js.map +1 -1
  492. package/dist/orthography/place-grouping.d.ts +39 -0
  493. package/dist/orthography/place-grouping.d.ts.map +1 -0
  494. package/dist/orthography/place-grouping.js +83 -0
  495. package/dist/orthography/place-grouping.js.map +1 -0
  496. package/dist/orthography/word-grouping.d.ts +48 -0
  497. package/dist/orthography/word-grouping.d.ts.map +1 -0
  498. package/dist/orthography/word-grouping.js +147 -0
  499. package/dist/orthography/word-grouping.js.map +1 -0
  500. package/dist/script/conversion-format.d.ts +22 -0
  501. package/dist/script/conversion-format.d.ts.map +1 -0
  502. package/dist/script/conversion-format.js +22 -0
  503. package/dist/script/conversion-format.js.map +1 -0
  504. package/dist/script/conversion-read.d.ts +9 -0
  505. package/dist/script/conversion-read.d.ts.map +1 -0
  506. package/dist/script/conversion-read.js +69 -0
  507. package/dist/script/conversion-read.js.map +1 -0
  508. package/dist/script/conversion-write.d.ts +14 -0
  509. package/dist/script/conversion-write.d.ts.map +1 -0
  510. package/dist/script/conversion-write.js +34 -0
  511. package/dist/script/conversion-write.js.map +1 -0
  512. package/dist/script/conversion.d.ts +10 -16
  513. package/dist/script/conversion.d.ts.map +1 -1
  514. package/dist/script/conversion.js +2 -115
  515. package/dist/script/conversion.js.map +1 -1
  516. package/dist/search/candidate-narrowing.d.ts +56 -0
  517. package/dist/search/candidate-narrowing.d.ts.map +1 -0
  518. package/dist/search/candidate-narrowing.js +55 -0
  519. package/dist/search/candidate-narrowing.js.map +1 -0
  520. package/dist/search/candidate-query.d.ts +25 -0
  521. package/dist/search/candidate-query.d.ts.map +1 -0
  522. package/dist/search/candidate-query.js +28 -0
  523. package/dist/search/candidate-query.js.map +1 -0
  524. package/dist/search/candidate-writings.d.ts +24 -0
  525. package/dist/search/candidate-writings.d.ts.map +1 -0
  526. package/dist/search/candidate-writings.js +114 -0
  527. package/dist/search/candidate-writings.js.map +1 -0
  528. package/dist/search/candidates.d.ts +7 -41
  529. package/dist/search/candidates.d.ts.map +1 -1
  530. package/dist/search/candidates.js +10 -164
  531. package/dist/search/candidates.js.map +1 -1
  532. package/dist/search/match-chunks.d.ts +19 -0
  533. package/dist/search/match-chunks.d.ts.map +1 -0
  534. package/dist/search/match-chunks.js +30 -0
  535. package/dist/search/match-chunks.js.map +1 -0
  536. package/dist/search/match-ranking.d.ts +39 -0
  537. package/dist/search/match-ranking.d.ts.map +1 -0
  538. package/dist/search/match-ranking.js +51 -0
  539. package/dist/search/match-ranking.js.map +1 -0
  540. package/dist/search/match-readings.d.ts +43 -0
  541. package/dist/search/match-readings.d.ts.map +1 -0
  542. package/dist/search/match-readings.js +83 -0
  543. package/dist/search/match-readings.js.map +1 -0
  544. package/dist/search/match-scoring.d.ts +146 -0
  545. package/dist/search/match-scoring.d.ts.map +1 -0
  546. package/dist/search/match-scoring.js +114 -0
  547. package/dist/search/match-scoring.js.map +1 -0
  548. package/dist/search/match-search.d.ts +28 -0
  549. package/dist/search/match-search.d.ts.map +1 -0
  550. package/dist/search/match-search.js +128 -0
  551. package/dist/search/match-search.js.map +1 -0
  552. package/dist/search/match.d.ts +5 -36
  553. package/dist/search/match.d.ts.map +1 -1
  554. package/dist/search/match.js +2 -379
  555. package/dist/search/match.js.map +1 -1
  556. package/dist/search/reverse-index-build.d.ts +30 -0
  557. package/dist/search/reverse-index-build.d.ts.map +1 -0
  558. package/dist/search/reverse-index-build.js +72 -0
  559. package/dist/search/reverse-index-build.js.map +1 -0
  560. package/dist/search/reverse-index-format.d.ts +60 -0
  561. package/dist/search/reverse-index-format.d.ts.map +1 -0
  562. package/dist/search/reverse-index-format.js +54 -0
  563. package/dist/search/reverse-index-format.js.map +1 -0
  564. package/dist/search/reverse-index-groups.d.ts +37 -0
  565. package/dist/search/reverse-index-groups.d.ts.map +1 -0
  566. package/dist/search/reverse-index-groups.js +71 -0
  567. package/dist/search/reverse-index-groups.js.map +1 -0
  568. package/dist/search/reverse-index-passes.d.ts +78 -0
  569. package/dist/search/reverse-index-passes.d.ts.map +1 -0
  570. package/dist/search/reverse-index-passes.js +59 -0
  571. package/dist/search/reverse-index-passes.js.map +1 -0
  572. package/dist/search/reverse-index-state.d.ts +36 -0
  573. package/dist/search/reverse-index-state.d.ts.map +1 -0
  574. package/dist/search/reverse-index-state.js +95 -0
  575. package/dist/search/reverse-index-state.js.map +1 -0
  576. package/dist/search/reverse-index.d.ts +8 -67
  577. package/dist/search/reverse-index.d.ts.map +1 -1
  578. package/dist/search/reverse-index.js +4 -255
  579. package/dist/search/reverse-index.js.map +1 -1
  580. package/dist/sources/unihan-readings.d.ts +58 -0
  581. package/dist/sources/unihan-readings.d.ts.map +1 -0
  582. package/dist/sources/unihan-readings.js +95 -0
  583. package/dist/sources/unihan-readings.js.map +1 -0
  584. package/dist/sources/unihan.d.ts +6 -9
  585. package/dist/sources/unihan.d.ts.map +1 -1
  586. package/dist/sources/unihan.js +2 -85
  587. package/dist/sources/unihan.js.map +1 -1
  588. package/dist/syllable/final-tables.d.ts +23 -0
  589. package/dist/syllable/final-tables.d.ts.map +1 -0
  590. package/dist/syllable/final-tables.js +50 -0
  591. package/dist/syllable/final-tables.js.map +1 -0
  592. package/dist/syllable/inventory.d.ts +8 -42
  593. package/dist/syllable/inventory.d.ts.map +1 -1
  594. package/dist/syllable/inventory.js +9 -918
  595. package/dist/syllable/inventory.js.map +1 -1
  596. package/dist/syllable/spellings.d.ts +40 -0
  597. package/dist/syllable/spellings.d.ts.map +1 -0
  598. package/dist/syllable/spellings.js +469 -0
  599. package/dist/syllable/spellings.js.map +1 -0
  600. package/dist/syllable/syllable-parts.d.ts +31 -0
  601. package/dist/syllable/syllable-parts.d.ts.map +1 -0
  602. package/dist/syllable/syllable-parts.js +105 -0
  603. package/dist/syllable/syllable-parts.js.map +1 -0
  604. package/dist/syllable/syllable.d.ts +1 -14
  605. package/dist/syllable/syllable.d.ts.map +1 -1
  606. package/dist/syllable/syllable.js +3 -144
  607. package/dist/syllable/syllable.js.map +1 -1
  608. package/dist/syllable/written-tones.d.ts +6 -0
  609. package/dist/syllable/written-tones.d.ts.map +1 -0
  610. package/dist/syllable/written-tones.js +453 -0
  611. package/dist/syllable/written-tones.js.map +1 -0
  612. package/dist/transcription/bopomofo-parse.d.ts +42 -0
  613. package/dist/transcription/bopomofo-parse.d.ts.map +1 -0
  614. package/dist/transcription/bopomofo-parse.js +92 -0
  615. package/dist/transcription/bopomofo-parse.js.map +1 -0
  616. package/dist/transcription/bopomofo-reverse.d.ts +31 -0
  617. package/dist/transcription/bopomofo-reverse.d.ts.map +1 -0
  618. package/dist/transcription/bopomofo-reverse.js +48 -0
  619. package/dist/transcription/bopomofo-reverse.js.map +1 -0
  620. package/dist/transcription/bopomofo-symbols.d.ts +36 -0
  621. package/dist/transcription/bopomofo-symbols.d.ts.map +1 -0
  622. package/dist/transcription/bopomofo-symbols.js +41 -0
  623. package/dist/transcription/bopomofo-symbols.js.map +1 -0
  624. package/dist/transcription/bopomofo-tables.d.ts +87 -0
  625. package/dist/transcription/bopomofo-tables.d.ts.map +1 -0
  626. package/dist/transcription/bopomofo-tables.js +180 -0
  627. package/dist/transcription/bopomofo-tables.js.map +1 -0
  628. package/dist/transcription/bopomofo.d.ts +14 -32
  629. package/dist/transcription/bopomofo.d.ts.map +1 -1
  630. package/dist/transcription/bopomofo.js +5 -343
  631. package/dist/transcription/bopomofo.js.map +1 -1
  632. package/dist/transcription/gwoyeu-first-second.d.ts +36 -0
  633. package/dist/transcription/gwoyeu-first-second.d.ts.map +1 -0
  634. package/dist/transcription/gwoyeu-first-second.js +75 -0
  635. package/dist/transcription/gwoyeu-first-second.js.map +1 -0
  636. package/dist/transcription/gwoyeu-spelling.d.ts +38 -0
  637. package/dist/transcription/gwoyeu-spelling.d.ts.map +1 -0
  638. package/dist/transcription/gwoyeu-spelling.js +124 -0
  639. package/dist/transcription/gwoyeu-spelling.js.map +1 -0
  640. package/dist/transcription/gwoyeu-tables.d.ts +93 -0
  641. package/dist/transcription/gwoyeu-tables.d.ts.map +1 -0
  642. package/dist/transcription/gwoyeu-tables.js +205 -0
  643. package/dist/transcription/gwoyeu-tables.js.map +1 -0
  644. package/dist/transcription/gwoyeu-tonal-forms.d.ts +49 -0
  645. package/dist/transcription/gwoyeu-tonal-forms.d.ts.map +1 -0
  646. package/dist/transcription/gwoyeu-tonal-forms.js +89 -0
  647. package/dist/transcription/gwoyeu-tonal-forms.js.map +1 -0
  648. package/dist/transcription/gwoyeu-vowels.d.ts +51 -0
  649. package/dist/transcription/gwoyeu-vowels.d.ts.map +1 -0
  650. package/dist/transcription/gwoyeu-vowels.js +58 -0
  651. package/dist/transcription/gwoyeu-vowels.js.map +1 -0
  652. package/dist/transcription/gwoyeu.d.ts +1 -26
  653. package/dist/transcription/gwoyeu.d.ts.map +1 -1
  654. package/dist/transcription/gwoyeu.js +2 -540
  655. package/dist/transcription/gwoyeu.js.map +1 -1
  656. package/dist/transcription/ipa-symbols.d.ts +67 -0
  657. package/dist/transcription/ipa-symbols.d.ts.map +1 -0
  658. package/dist/transcription/ipa-symbols.js +135 -0
  659. package/dist/transcription/ipa-symbols.js.map +1 -0
  660. package/dist/transcription/ipa.d.ts +2 -10
  661. package/dist/transcription/ipa.d.ts.map +1 -1
  662. package/dist/transcription/ipa.js +2 -134
  663. package/dist/transcription/ipa.js.map +1 -1
  664. package/dist/transcription/wade-giles-index.d.ts +35 -0
  665. package/dist/transcription/wade-giles-index.d.ts.map +1 -0
  666. package/dist/transcription/wade-giles-index.js +110 -0
  667. package/dist/transcription/wade-giles-index.js.map +1 -0
  668. package/dist/transcription/wade-giles-parse.d.ts +36 -0
  669. package/dist/transcription/wade-giles-parse.d.ts.map +1 -0
  670. package/dist/transcription/wade-giles-parse.js +84 -0
  671. package/dist/transcription/wade-giles-parse.js.map +1 -0
  672. package/dist/transcription/wade-giles-spelling.d.ts +61 -0
  673. package/dist/transcription/wade-giles-spelling.d.ts.map +1 -0
  674. package/dist/transcription/wade-giles-spelling.js +107 -0
  675. package/dist/transcription/wade-giles-spelling.js.map +1 -0
  676. package/dist/transcription/wade-giles-syllable.d.ts +29 -0
  677. package/dist/transcription/wade-giles-syllable.d.ts.map +1 -0
  678. package/dist/transcription/wade-giles-syllable.js +90 -0
  679. package/dist/transcription/wade-giles-syllable.js.map +1 -0
  680. package/dist/transcription/wade-giles-tables.d.ts +80 -0
  681. package/dist/transcription/wade-giles-tables.d.ts.map +1 -0
  682. package/dist/transcription/wade-giles-tables.js +178 -0
  683. package/dist/transcription/wade-giles-tables.js.map +1 -0
  684. package/dist/transcription/wade-giles.d.ts +9 -60
  685. package/dist/transcription/wade-giles.d.ts.map +1 -1
  686. package/dist/transcription/wade-giles.js +6 -543
  687. package/dist/transcription/wade-giles.js.map +1 -1
  688. package/dist/transcription/yale-tables.d.ts +54 -0
  689. package/dist/transcription/yale-tables.d.ts.map +1 -0
  690. package/dist/transcription/yale-tables.js +125 -0
  691. package/dist/transcription/yale-tables.js.map +1 -0
  692. package/dist/transcription/yale.d.ts.map +1 -1
  693. package/dist/transcription/yale.js +1 -124
  694. package/dist/transcription/yale.js.map +1 -1
  695. package/package.json +1 -1
@@ -1,730 +1,57 @@
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
1
  /**
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.
2
+ * Walking the word list, and gathering what each word came to.
248
3
  */
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
- /**
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.
296
- *
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 轻声.
308
- */
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
- }
4
+ import { byCodeUnit } from "./artifact-format.js";
5
+ import { composeLocaleDeltas } from "./locale.js";
6
+ import { indexCedict, isSpeltTraditionally } from "./cedict-senses.js";
7
+ import { buildCharacterDefaults } from "./character-defaults.js";
8
+ import { mergeWord } from "./merge-word.js";
9
+ import { addTally, NO_TALLY, } from "./merge-types.js";
413
10
  /**
414
11
  * Build the merged dictionary from the four parsed sources.
415
12
  *
416
13
  * The order of operations is the one MERGE.md sets out, and it is not
417
14
  * 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.
15
+ * validation happen in {@link import("./reading.js").readAlignedReading} as each source is read;
16
+ * {@link mergeWord} then settles one word at a time, and this walks the words
17
+ * and gathers what each of them came to.
421
18
  */
422
19
  export function mergeSources(sources) {
423
- const { unihanReadings, unihanVariants, phrase, cedict, jieba } = sources;
20
+ const { phrase, cedict } = sources;
424
21
  const cedictByWord = indexCedict(cedict, (entry) => entry.simplified);
425
22
  // Only ever read for {@link isOwnSense}. A 繁體-only headword keeps its senses
426
23
  // under whichever 简体 form each one simplifies to — 沈 is `chén` under 沉 and
427
24
  // 誰 is `shéi` under 谁 — so the 简体 index alone cannot say what a character
428
25
  // like that already reads in 普通话.
429
26
  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
- }
27
+ const { traditional, defaults, reducedNeutrals } = buildCharacterDefaults(sources, cedictByWord, cedictByHant);
467
28
  const words = new Set([
468
29
  ...defaults.keys(),
469
30
  ...[...phrase.keys()].filter((word) => !isSpeltTraditionally(word, cedictByWord, cedictByHant)),
470
31
  ...cedictByWord.keys(),
471
32
  ]);
33
+ const wordSources = {
34
+ cedictByWord,
35
+ cedictByHant,
36
+ phrase,
37
+ jieba: sources.jieba,
38
+ unihanReadings: sources.unihanReadings,
39
+ traditional,
40
+ defaults,
41
+ };
472
42
  const entries = [];
473
43
  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;
44
+ let counts = NO_TALLY;
485
45
  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 ?? []);
46
+ const merged = mergeWord(word, wordSources);
47
+ counts = addTally(counts, merged.tally);
48
+ if (merged.rejected !== undefined) {
49
+ rejected.set(word, merged.rejected);
518
50
  continue;
519
51
  }
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++;
52
+ /* c8 ignore next 3 -- a word is either rejected or gives an entry */
53
+ if (merged.entry !== undefined) {
54
+ entries.push(merged.entry);
728
55
  }
729
56
  }
730
57
  // ── zh-TW deltas the sources marked only on a constituent ──
@@ -736,19 +63,9 @@ export function mergeSources(sources) {
736
63
  entries: localised.entries,
737
64
  rejected,
738
65
  stats: {
739
- characters,
740
- phraseWords,
741
- cedictWords,
742
- neutralToneCorrections,
66
+ ...counts,
743
67
  reducedNeutrals,
744
- erhuaRepairs,
745
- derivedTraditional,
746
- scriptPairs,
747
- variantSpellings,
748
- taiwanReadings,
749
68
  composedTaiwanReadings: localised.composed,
750
- properNounVetoes,
751
- nameBoundaries,
752
69
  rejected: rejected.size,
753
70
  },
754
71
  };