@kensio/pinyinjs 0.1.0-beta.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/NOTICE +7 -0
  3. package/README.md +144 -19
  4. package/data/full.entries +13400 -13400
  5. package/data/manifest.json +4 -4
  6. package/data/standard.entries +2492 -2492
  7. package/dist/cli/arguments.d.ts +67 -0
  8. package/dist/cli/arguments.d.ts.map +1 -1
  9. package/dist/cli/arguments.js +79 -0
  10. package/dist/cli/arguments.js.map +1 -1
  11. package/dist/cli/colour.d.ts +77 -0
  12. package/dist/cli/colour.d.ts.map +1 -0
  13. package/dist/cli/colour.js +117 -0
  14. package/dist/cli/colour.js.map +1 -0
  15. package/dist/cli/commands.d.ts +49 -1
  16. package/dist/cli/commands.d.ts.map +1 -1
  17. package/dist/cli/commands.js +404 -42
  18. package/dist/cli/commands.js.map +1 -1
  19. package/dist/cli/environment.d.ts.map +1 -1
  20. package/dist/cli/environment.js +20 -0
  21. package/dist/cli/environment.js.map +1 -1
  22. package/dist/cli/help.d.ts.map +1 -1
  23. package/dist/cli/help.js +43 -16
  24. package/dist/cli/help.js.map +1 -1
  25. package/dist/cli/run.d.ts +11 -0
  26. package/dist/cli/run.d.ts.map +1 -1
  27. package/dist/cli/run.js +4 -2
  28. package/dist/cli/run.js.map +1 -1
  29. package/dist/decode/convert.d.ts +20 -0
  30. package/dist/decode/convert.d.ts.map +1 -1
  31. package/dist/decode/convert.js +170 -12
  32. package/dist/decode/convert.js.map +1 -1
  33. package/dist/decode/decode.d.ts +3 -2
  34. package/dist/decode/decode.d.ts.map +1 -1
  35. package/dist/decode/decode.js +17 -4
  36. package/dist/decode/decode.js.map +1 -1
  37. package/dist/decode/reading-rules.d.ts +56 -0
  38. package/dist/decode/reading-rules.d.ts.map +1 -0
  39. package/dist/decode/reading-rules.js +107 -0
  40. package/dist/decode/reading-rules.js.map +1 -0
  41. package/dist/decode/rules.d.ts +66 -0
  42. package/dist/decode/rules.d.ts.map +1 -0
  43. package/dist/decode/rules.js +138 -0
  44. package/dist/decode/rules.js.map +1 -0
  45. package/dist/decode/sandhi.d.ts +1 -1
  46. package/dist/decode/sandhi.d.ts.map +1 -1
  47. package/dist/decode/sandhi.js +60 -1
  48. package/dist/decode/sandhi.js.map +1 -1
  49. package/dist/decode/word.d.ts +18 -0
  50. package/dist/decode/word.d.ts.map +1 -1
  51. package/dist/dictionary/artifact.d.ts.map +1 -1
  52. package/dist/dictionary/artifact.js +28 -1
  53. package/dist/dictionary/artifact.js.map +1 -1
  54. package/dist/dictionary/dictionary.d.ts +9 -0
  55. package/dist/dictionary/dictionary.d.ts.map +1 -1
  56. package/dist/dictionary/dictionary.js +7 -0
  57. package/dist/dictionary/dictionary.js.map +1 -1
  58. package/dist/dictionary/entry.d.ts +12 -0
  59. package/dist/dictionary/entry.d.ts.map +1 -1
  60. package/dist/dictionary/entry.js.map +1 -1
  61. package/dist/dictionary/merge.d.ts +3 -1
  62. package/dist/dictionary/merge.d.ts.map +1 -1
  63. package/dist/dictionary/merge.js +19 -1
  64. package/dist/dictionary/merge.js.map +1 -1
  65. package/dist/format/transcription.d.ts +52 -0
  66. package/dist/format/transcription.d.ts.map +1 -0
  67. package/dist/format/transcription.js +88 -0
  68. package/dist/format/transcription.js.map +1 -0
  69. package/dist/index.d.ts +24 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +15 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/numerals/cardinal.d.ts +39 -0
  74. package/dist/numerals/cardinal.d.ts.map +1 -0
  75. package/dist/numerals/cardinal.js +111 -0
  76. package/dist/numerals/cardinal.js.map +1 -0
  77. package/dist/numerals/characters.d.ts +31 -0
  78. package/dist/numerals/characters.d.ts.map +1 -0
  79. package/dist/numerals/characters.js +80 -0
  80. package/dist/numerals/characters.js.map +1 -0
  81. package/dist/numerals/numerals.d.ts +76 -0
  82. package/dist/numerals/numerals.d.ts.map +1 -0
  83. package/dist/numerals/numerals.js +119 -0
  84. package/dist/numerals/numerals.js.map +1 -0
  85. package/dist/numerals/text.d.ts +52 -0
  86. package/dist/numerals/text.d.ts.map +1 -0
  87. package/dist/numerals/text.js +248 -0
  88. package/dist/numerals/text.js.map +1 -0
  89. package/dist/orthography/grouping.d.ts +56 -11
  90. package/dist/orthography/grouping.d.ts.map +1 -1
  91. package/dist/orthography/grouping.js +109 -35
  92. package/dist/orthography/grouping.js.map +1 -1
  93. package/dist/orthography/idiom-list.d.ts +56 -0
  94. package/dist/orthography/idiom-list.d.ts.map +1 -0
  95. package/dist/orthography/idiom-list.js +296 -0
  96. package/dist/orthography/idiom-list.js.map +1 -0
  97. package/dist/orthography/idioms.d.ts +18 -0
  98. package/dist/orthography/idioms.d.ts.map +1 -0
  99. package/dist/orthography/idioms.js +22 -0
  100. package/dist/orthography/idioms.js.map +1 -0
  101. package/dist/orthography/reduplication.d.ts +52 -0
  102. package/dist/orthography/reduplication.d.ts.map +1 -0
  103. package/dist/orthography/reduplication.js +99 -0
  104. package/dist/orthography/reduplication.js.map +1 -0
  105. package/dist/orthography/rule.d.ts +50 -0
  106. package/dist/orthography/rule.d.ts.map +1 -0
  107. package/dist/orthography/rule.js +101 -0
  108. package/dist/orthography/rule.js.map +1 -0
  109. package/dist/sources/cedict.d.ts +23 -0
  110. package/dist/sources/cedict.d.ts.map +1 -1
  111. package/dist/sources/cedict.js +28 -0
  112. package/dist/sources/cedict.js.map +1 -1
  113. package/dist/syllable/syllable.d.ts +1 -1
  114. package/dist/syllable/syllable.d.ts.map +1 -1
  115. package/dist/syllable/syllable.js +2 -37
  116. package/dist/syllable/syllable.js.map +1 -1
  117. package/dist/tone/tone-mark.d.ts +23 -0
  118. package/dist/tone/tone-mark.d.ts.map +1 -1
  119. package/dist/tone/tone-mark.js +49 -0
  120. package/dist/tone/tone-mark.js.map +1 -1
  121. package/dist/transcription/bopomofo.d.ts +46 -0
  122. package/dist/transcription/bopomofo.d.ts.map +1 -0
  123. package/dist/transcription/bopomofo.js +371 -0
  124. package/dist/transcription/bopomofo.js.map +1 -0
  125. package/dist/transcription/gwoyeu.d.ts +32 -0
  126. package/dist/transcription/gwoyeu.d.ts.map +1 -0
  127. package/dist/transcription/gwoyeu.js +491 -0
  128. package/dist/transcription/gwoyeu.js.map +1 -0
  129. package/dist/transcription/ipa.d.ts +40 -0
  130. package/dist/transcription/ipa.d.ts.map +1 -0
  131. package/dist/transcription/ipa.js +221 -0
  132. package/dist/transcription/ipa.js.map +1 -0
  133. package/dist/transcription/spelling-index.d.ts +23 -0
  134. package/dist/transcription/spelling-index.d.ts.map +1 -0
  135. package/dist/transcription/spelling-index.js +61 -0
  136. package/dist/transcription/spelling-index.js.map +1 -0
  137. package/dist/transcription/wade-giles.d.ts +108 -0
  138. package/dist/transcription/wade-giles.d.ts.map +1 -0
  139. package/dist/transcription/wade-giles.js +656 -0
  140. package/dist/transcription/wade-giles.js.map +1 -0
  141. package/dist/transcription/yale.d.ts +43 -0
  142. package/dist/transcription/yale.d.ts.map +1 -0
  143. package/dist/transcription/yale.js +242 -0
  144. package/dist/transcription/yale.js.map +1 -0
  145. package/package.json +9 -5
@@ -0,0 +1,296 @@
1
+ /**
2
+ * The 成语 GB/T 16159 writes with a hyphen down the middle.
3
+ *
4
+ * 6.3.2: a four-syllable 成语 *that can be read as two disyllables* takes a
5
+ * connecting hyphen — `fēngpíng-làngjìng` — and one that cannot is written
6
+ * solid: `bùyìlèhū`, `chūqíbùyì`. The condition is prosodic and structural, and
7
+ * **nothing in the data tracks it.** Conditioning on both halves being
8
+ * dictionary words fires on 10,202 of the 22,192 four-character words jieba tags
9
+ * `i` and is uncorrelated with the standard: it fires on 层出不穷 and not on
10
+ * 风平浪静, which are the standard's own two examples of the same rule, and it
11
+ * fires on 精神文明 and 凯旋归来, which want a space rather than a hyphen. No
12
+ * source carries hyphenated pinyin either, so unlike every other claim this
13
+ * package makes, a 成语 rule could not be scored even if one were written.
14
+ *
15
+ * So: a list, on the same argument as [the spaced word list](./word-list.ts).
16
+ *
17
+ * **What is in it, and what is not.** Only 成语 whose two halves are each a
18
+ * self-contained disyllable — parallel halves (风平|浪静, 千军|万马), a
19
+ * disyllable and its predicate (声势|浩大), or a disyllabic stem with a
20
+ * reduplicated tail (小心|翼翼). Those are the ones where 2+2 is beyond doubt.
21
+ * Anything with a monosyllabic word breaking the rhythm is left out and stays
22
+ * solid, which is what the standard does with it anyway: 目不转睛 is 目 |
23
+ * 不转睛, 迫不及待 is 迫 | 不及待, 情不自禁 and 显而易见 and 名副其实 the same.
24
+ * Left out too is anything this file is not sure of, because a missing entry
25
+ * keeps today's output and a wrong one breaks it.
26
+ *
27
+ * It is not a complete 成语 list and is not meant to become one — 22,192 of them
28
+ * exist. Measured over 88,866 lines of Tatoeba and zh.wikipedia, the 117 here
29
+ * cover 264 of the 1,737 four-character `i`-tagged words that turn up, or
30
+ * 15.2%. Most of what is left is either genuinely not 2+2 (据我所知, 一无所知,
31
+ * 心不在焉, 难以置信) or not a 成语 at all (非常感谢, 重新启动, 可口可乐), which
32
+ * is the shape a curated list should have: the cases it declines are mostly
33
+ * cases it should decline.
34
+ */
35
+ /**
36
+ * 简体 forms, grouped by why the halves are halves.
37
+ */
38
+ const HANS = [
39
+ // ── Parallel halves: 联合式, the clearest case ─────────────
40
+ "风平浪静",
41
+ "山清水秀",
42
+ "千军万马",
43
+ "千家万户",
44
+ "千方百计",
45
+ "四面八方",
46
+ "四通八达",
47
+ "七零八落",
48
+ "大街小巷",
49
+ "成千上万",
50
+ "生死存亡",
51
+ "你死我活",
52
+ "翻来覆去",
53
+ "无影无踪",
54
+ "无声无息",
55
+ "自由自在",
56
+ "自言自语",
57
+ "自给自足",
58
+ "全心全意",
59
+ "一心一意",
60
+ "平起平坐",
61
+ "不慌不忙",
62
+ "所作所为",
63
+ "咬牙切齿",
64
+ "手忙脚乱",
65
+ "胡思乱想",
66
+ "横冲直撞",
67
+ "歌功颂德",
68
+ "耀武扬威",
69
+ "拨乱反正",
70
+ "提心吊胆",
71
+ "前仆后继",
72
+ "轻描淡写",
73
+ "斩钉截铁",
74
+ "讨价还价",
75
+ "粉身碎骨",
76
+ "惊天动地",
77
+ "大惊小怪",
78
+ "三心二意",
79
+ "爱憎分明",
80
+ "光明磊落",
81
+ "精疲力尽",
82
+ "新陈代谢",
83
+ "人杰地灵",
84
+ "错综复杂",
85
+ "心甘情愿",
86
+ "触目惊心",
87
+ "遍体鳞伤",
88
+ "气急败坏",
89
+ "大声疾呼",
90
+ "欢声雷动",
91
+ "星罗棋布",
92
+ "卧薪尝胆",
93
+ "目瞪口呆",
94
+ "赤手空拳",
95
+ "破口大骂",
96
+ "束手无策",
97
+ "大惊失色",
98
+ "手足无措",
99
+ "针锋相对",
100
+ "全力以赴",
101
+ "举世闻名",
102
+ "全军覆没",
103
+ "家喻户晓",
104
+ "想方设法",
105
+ "独立自主",
106
+ "不由自主",
107
+ "自力更生",
108
+ "艰苦奋斗",
109
+ "心满意足",
110
+ "不知不觉",
111
+ "心旷神怡",
112
+ "热血沸腾",
113
+ "光彩夺目",
114
+ "丰富多彩",
115
+ "慷慨激昂",
116
+ "声势浩大",
117
+ "兴高采烈",
118
+ "恶有恶报",
119
+ "开门见山",
120
+ "粗心大意",
121
+ "一见钟情",
122
+ "截然不同",
123
+ "独一无二",
124
+ "与众不同",
125
+ "大错特错",
126
+ "有朝一日",
127
+ "吹毛求疵",
128
+ "沉默寡言",
129
+ "鸡毛蒜皮",
130
+ "胡说八道",
131
+ "了如指掌",
132
+ "无家可归",
133
+ "乱七八糟",
134
+ "引人注目",
135
+ "大吃一惊",
136
+ "竭尽全力",
137
+ "五脏六腑",
138
+ "直截了当",
139
+ "出类拔萃",
140
+ "水落石出",
141
+ "倾盆大雨",
142
+ "完美无瑕",
143
+ "层出不穷",
144
+ // ── A disyllable with a reduplicated tail: ABCC ────────────
145
+ "小心翼翼",
146
+ "威风凛凛",
147
+ "忠心耿耿",
148
+ "杀气腾腾",
149
+ "兴致勃勃",
150
+ "气喘吁吁",
151
+ "忧心忡忡",
152
+ // ── A reduplicated head with a disyllable: AABC ────────────
153
+ "咄咄逼人",
154
+ "滔滔不绝",
155
+ "念念不忘",
156
+ "源源不断",
157
+ "息息相关",
158
+ "面面相觑",
159
+ ];
160
+ /**
161
+ * 繁體 spellings of the same 成语, where they differ.
162
+ *
163
+ * Listed rather than converted, because 繁體 is a key in its own right
164
+ * everywhere else in this package and routing it through 简体 to look something
165
+ * up is exactly what SCRIPTS-AND-LOCALES.md refuses to do. Every entry is
166
+ * checked against the dictionary by a test, so a spelling that is not a real
167
+ * word cannot sit here unnoticed.
168
+ */
169
+ const HANT = [
170
+ "風平浪靜",
171
+ "山清水秀",
172
+ "千軍萬馬",
173
+ "千家萬戶",
174
+ "千方百計",
175
+ "四面八方",
176
+ "四通八達",
177
+ "七零八落",
178
+ "大街小巷",
179
+ "成千上萬",
180
+ "生死存亡",
181
+ "你死我活",
182
+ "翻來覆去",
183
+ "無影無蹤",
184
+ "無聲無息",
185
+ "自由自在",
186
+ "自言自語",
187
+ "自給自足",
188
+ "全心全意",
189
+ "一心一意",
190
+ "平起平坐",
191
+ "不慌不忙",
192
+ "所作所為",
193
+ "咬牙切齒",
194
+ "手忙腳亂",
195
+ "胡思亂想",
196
+ "橫衝直撞",
197
+ "歌功頌德",
198
+ "耀武揚威",
199
+ "撥亂反正",
200
+ "提心吊膽",
201
+ "前仆後繼",
202
+ "輕描淡寫",
203
+ "斬釘截鐵",
204
+ "討價還價",
205
+ "粉身碎骨",
206
+ "驚天動地",
207
+ "大驚小怪",
208
+ "三心二意",
209
+ "愛憎分明",
210
+ "光明磊落",
211
+ "精疲力盡",
212
+ "新陳代謝",
213
+ "人傑地靈",
214
+ "錯綜複雜",
215
+ "心甘情願",
216
+ "觸目驚心",
217
+ "遍體鱗傷",
218
+ "氣急敗壞",
219
+ "大聲疾呼",
220
+ "歡聲雷動",
221
+ "星羅棋布",
222
+ "臥薪嘗膽",
223
+ "目瞪口呆",
224
+ "赤手空拳",
225
+ "破口大罵",
226
+ "束手無策",
227
+ "大驚失色",
228
+ "手足無措",
229
+ "針鋒相對",
230
+ "全力以赴",
231
+ "舉世聞名",
232
+ "全軍覆沒",
233
+ "家喻戶曉",
234
+ "想方設法",
235
+ "獨立自主",
236
+ "不由自主",
237
+ "自力更生",
238
+ "艱苦奮鬥",
239
+ "心滿意足",
240
+ "不知不覺",
241
+ "心曠神怡",
242
+ "熱血沸騰",
243
+ "光彩奪目",
244
+ "豐富多彩",
245
+ "慷慨激昂",
246
+ "聲勢浩大",
247
+ "興高采烈",
248
+ "惡有惡報",
249
+ "開門見山",
250
+ "粗心大意",
251
+ "一見鍾情",
252
+ "截然不同",
253
+ "獨一無二",
254
+ "與眾不同",
255
+ "大錯特錯",
256
+ "有朝一日",
257
+ "吹毛求疵",
258
+ "沉默寡言",
259
+ "雞毛蒜皮",
260
+ "胡說八道",
261
+ "瞭如指掌",
262
+ "無家可歸",
263
+ "亂七八糟",
264
+ "引人注目",
265
+ "大吃一驚",
266
+ "竭盡全力",
267
+ "五臟六腑",
268
+ "直截了當",
269
+ "出類拔萃",
270
+ "水落石出",
271
+ "傾盆大雨",
272
+ "完美無瑕",
273
+ "層出不窮",
274
+ "小心翼翼",
275
+ "威風凜凜",
276
+ "忠心耿耿",
277
+ "殺氣騰騰",
278
+ "興致勃勃",
279
+ "氣喘吁吁",
280
+ "憂心忡忡",
281
+ "咄咄逼人",
282
+ "滔滔不絕",
283
+ "念念不忘",
284
+ "源源不斷",
285
+ "息息相關",
286
+ "面面相覷",
287
+ ];
288
+ /**
289
+ * Every 成语 written with the 2+2 hyphen, paired across the two scripts.
290
+ */
291
+ export const HYPHENATED_IDIOMS = HANS.map((hans, at) => ({ hans, hant: HANT[at] ?? "" }));
292
+ /**
293
+ * Every spelling that takes the hyphen, which is how the rule asks.
294
+ */
295
+ export const HYPHENATED_IDIOM_FORMS = new Set(HYPHENATED_IDIOMS.flatMap((idiom) => [idiom.hans, idiom.hant]));
296
+ //# sourceMappingURL=idiom-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idiom-list.js","sourceRoot":"","sources":["../../src/orthography/idiom-list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;GAEG;AACH,MAAM,IAAI,GAAsB;IAC9B,2DAA2D;IAC3D,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IAEN,8DAA8D;IAC9D,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IAEN,8DAA8D;IAC9D,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,IAAI,GAAsB;IAC9B,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAgBF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA6B,IAAI,CAAC,GAAG,CACjE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAC/C,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAChE,iBAAiB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAC/D,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type GroupingRule } from "./rule.js";
2
+ /**
3
+ * The 成语 hyphen, from the list, since no rule reaches it.
4
+ *
5
+ * GB/T 16159 6.3.2 hyphenates a four-syllable 成语 that can be read as two
6
+ * disyllables and writes the rest solid. Which of the two an idiom is cannot be
7
+ * derived from anything this package holds — see
8
+ * [the list](./idiom-list.ts) for the measurement — so the list is the rule's
9
+ * whole evidence, and an idiom that is not on it is written the way it was
10
+ * before: solid, which is what the standard does with the ones that cannot be
11
+ * halved.
12
+ *
13
+ * Every entry decodes as a single four-syllable word, so this only ever cuts
14
+ * something the dictionary already agreed was one word, and cuts it where the
15
+ * list says.
16
+ */
17
+ export declare const IDIOM_HYPHENS: GroupingRule;
18
+ //# sourceMappingURL=idioms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idioms.d.ts","sourceRoot":"","sources":["../../src/orthography/idioms.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,WAAW,CAAC;AAEzD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,EAAE,YAM3B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { HYPHENATED_IDIOM_FORMS } from "./idiom-list.js";
2
+ import { hyphenate } from "./rule.js";
3
+ /**
4
+ * The 成语 hyphen, from the list, since no rule reaches it.
5
+ *
6
+ * GB/T 16159 6.3.2 hyphenates a four-syllable 成语 that can be read as two
7
+ * disyllables and writes the rest solid. Which of the two an idiom is cannot be
8
+ * derived from anything this package holds — see
9
+ * [the list](./idiom-list.ts) for the measurement — so the list is the rule's
10
+ * whole evidence, and an idiom that is not on it is written the way it was
11
+ * before: solid, which is what the standard does with the ones that cannot be
12
+ * halved.
13
+ *
14
+ * Every entry decodes as a single four-syllable word, so this only ever cuts
15
+ * something the dictionary already agreed was one word, and cuts it where the
16
+ * list says.
17
+ */
18
+ export const IDIOM_HYPHENS = {
19
+ name: "idiom-hyphens",
20
+ apply: (words) => words.flatMap((word) => HYPHENATED_IDIOM_FORMS.has(word.text) ? hyphenate(word, 2) : [word]),
21
+ };
22
+ //# sourceMappingURL=idioms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idioms.js","sourceRoot":"","sources":["../../src/orthography/idioms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAqB,SAAS,EAAE,MAAM,WAAW,CAAC;AAEzD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACrB,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CACpE;CACJ,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { type GroupingRule } from "./rule.js";
2
+ /**
3
+ * The 重叠 hyphen inside a four-character AABB word.
4
+ *
5
+ * GB/T 16159 6.1.3 writes 干干净净 as `gāngān-jìngjìng`: one word, with the
6
+ * boundary between its halves marked. The shape *is* the evidence — a
7
+ * four-character word whose first two characters double and whose last two
8
+ * double is a reduplication and essentially nothing else — so this needs no
9
+ * tag, which matters given that two thirds of the dictionary carries none.
10
+ *
11
+ * Two conditions keep it honest, both sized against the whole dictionary. The
12
+ * word must have reached the rule as **one** decoded word: 爸爸妈妈 and 哥哥姐姐
13
+ * decode as two words each and are two words, `bàba māma`, not a reduplication
14
+ * of 爸妈. And a proper noun is left alone, since a name that happens to be
15
+ * shaped this way is not a reduplication of anything.
16
+ *
17
+ * Fires on 1,541 of the dictionary's 1,590 AABB keys; the 49 it holds back are
18
+ * all jieba proper-noun tags that CC-CEDICT did not veto — 斯斯文文, 老老少少,
19
+ * 正正经经 — which are mis-tagged rather than misjudged here, and are already
20
+ * wrong in their capitals for the same reason.
21
+ *
22
+ * Over 711,000 decoded words of Tatoeba and zh.wikipedia it fires 66 times,
23
+ * and all 66 are reduplications: 时时刻刻, 马马虎虎, 形形色色, 轰轰烈烈. What
24
+ * it misses is the same shape arriving as two words — 43 spans, of which about
25
+ * 16 are reduplications the decode happened to split (匆匆忙忙, 来来往往) and
26
+ * the rest are 爸爸妈妈, 爷爷奶奶 and 爸爸刚刚, where joining would be wrong.
27
+ * Nothing separates the two halves of that mixture: 匆匆 and 爸爸 are both
28
+ * words, and so are 匆忙 and 爸妈.
29
+ */
30
+ export declare const AABB_REDUPLICATION: GroupingRule;
31
+ /**
32
+ * The 重叠 hyphen between a repeated two-character word: 研究研究.
33
+ *
34
+ * GB/T 16159 writes verb reduplication `yánjiū-yánjiū`, and this is the
35
+ * productive half of 重叠: 研究研究 is not a dictionary entry and never will be,
36
+ * so it arrives as two decoded words rather than as one word to be split.
37
+ * Marking the second is all that is needed, and no reading changes.
38
+ *
39
+ * The ABAB words the dictionary *does* hold are deliberately not touched: they
40
+ * decode as one word, and 50 keys are shaped this way with 哔哩哔哩 and
41
+ * 达姆达姆 among them, where a hyphen would be asserting a reduplication that
42
+ * is really a transliteration.
43
+ *
44
+ * Measured over the same 711,000 decoded words, it fires 54 times and is right
45
+ * 46 of them — 休息休息, 一天一天, 考虑考虑, 好久好久. The eight misfires are
46
+ * all one word ending a clause and the same word starting the next
47
+ * (告诉我们|我们在哪里, 不喜欢|喜欢不问问题的), or a noun said twice to
48
+ * address someone (大象大象). Nothing short of syntax separates those from
49
+ * 讨论讨论, and the eight are a spacing error where all 54 were one before.
50
+ */
51
+ export declare const ABAB_REDUPLICATION: GroupingRule;
52
+ //# sourceMappingURL=reduplication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduplication.d.ts","sourceRoot":"","sources":["../../src/orthography/reduplication.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,WAAW,CAAC;AAkBzD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,kBAAkB,EAAE,YAQhC,CAAC;AAyBF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,kBAAkB,EAAE,YAShC,CAAC"}
@@ -0,0 +1,99 @@
1
+ import { toCharacters } from "../script/characters.js";
2
+ import { hyphenate } from "./rule.js";
3
+ /**
4
+ * Whether four characters repeat as AABB, with A and B different.
5
+ *
6
+ * 干干净净 and 高高兴兴 do; 一一得一 does not, and neither does a 叠字 name
7
+ * like 丁丁 doubled, since A and B have to differ for there to be two halves.
8
+ */
9
+ function isAabb(characters) {
10
+ const [first, second, third, fourth] = characters;
11
+ return (characters.length === 4 &&
12
+ first === second &&
13
+ third === fourth &&
14
+ first !== third);
15
+ }
16
+ /**
17
+ * The 重叠 hyphen inside a four-character AABB word.
18
+ *
19
+ * GB/T 16159 6.1.3 writes 干干净净 as `gāngān-jìngjìng`: one word, with the
20
+ * boundary between its halves marked. The shape *is* the evidence — a
21
+ * four-character word whose first two characters double and whose last two
22
+ * double is a reduplication and essentially nothing else — so this needs no
23
+ * tag, which matters given that two thirds of the dictionary carries none.
24
+ *
25
+ * Two conditions keep it honest, both sized against the whole dictionary. The
26
+ * word must have reached the rule as **one** decoded word: 爸爸妈妈 and 哥哥姐姐
27
+ * decode as two words each and are two words, `bàba māma`, not a reduplication
28
+ * of 爸妈. And a proper noun is left alone, since a name that happens to be
29
+ * shaped this way is not a reduplication of anything.
30
+ *
31
+ * Fires on 1,541 of the dictionary's 1,590 AABB keys; the 49 it holds back are
32
+ * all jieba proper-noun tags that CC-CEDICT did not veto — 斯斯文文, 老老少少,
33
+ * 正正经经 — which are mis-tagged rather than misjudged here, and are already
34
+ * wrong in their capitals for the same reason.
35
+ *
36
+ * Over 711,000 decoded words of Tatoeba and zh.wikipedia it fires 66 times,
37
+ * and all 66 are reduplications: 时时刻刻, 马马虎虎, 形形色色, 轰轰烈烈. What
38
+ * it misses is the same shape arriving as two words — 43 spans, of which about
39
+ * 16 are reduplications the decode happened to split (匆匆忙忙, 来来往往) and
40
+ * the rest are 爸爸妈妈, 爷爷奶奶 and 爸爸刚刚, where joining would be wrong.
41
+ * Nothing separates the two halves of that mixture: 匆匆 and 爸爸 are both
42
+ * words, and so are 匆忙 and 爸妈.
43
+ */
44
+ export const AABB_REDUPLICATION = {
45
+ name: "aabb-reduplication",
46
+ apply: (words) => words.flatMap((word) => word.isProperNoun || !isAabb(toCharacters(word.text))
47
+ ? [word]
48
+ : hyphenate(word, 2)),
49
+ };
50
+ /**
51
+ * Whether two words are the same word repeated: 研究研究.
52
+ *
53
+ * Two characters each, because a one-character repeat is a different rule —
54
+ * 看看 is `kànkan`, written solid with a neutral second syllable — and because
55
+ * a repeated single character is as likely to be two separate words.
56
+ *
57
+ * Nothing is asked of the part of speech, which was measured rather than
58
+ * assumed: excluding noun-tagged repeats removes three misfires — 战争 falling
59
+ * either side of 克里米亚战争|战争中, and 大象大象 addressing an elephant
60
+ * twice — at the cost of four real reduplications, since jieba tags 商量,
61
+ * 多谢 and 拜托 as nouns. Fewer right answers for a better-looking rule.
62
+ */
63
+ function isRepeat(word, previous) {
64
+ return (word.text === previous.text &&
65
+ word.isKnown &&
66
+ !word.isProperNoun &&
67
+ toCharacters(word.text).length === 2 &&
68
+ word.separator === undefined);
69
+ }
70
+ /**
71
+ * The 重叠 hyphen between a repeated two-character word: 研究研究.
72
+ *
73
+ * GB/T 16159 writes verb reduplication `yánjiū-yánjiū`, and this is the
74
+ * productive half of 重叠: 研究研究 is not a dictionary entry and never will be,
75
+ * so it arrives as two decoded words rather than as one word to be split.
76
+ * Marking the second is all that is needed, and no reading changes.
77
+ *
78
+ * The ABAB words the dictionary *does* hold are deliberately not touched: they
79
+ * decode as one word, and 50 keys are shaped this way with 哔哩哔哩 and
80
+ * 达姆达姆 among them, where a hyphen would be asserting a reduplication that
81
+ * is really a transliteration.
82
+ *
83
+ * Measured over the same 711,000 decoded words, it fires 54 times and is right
84
+ * 46 of them — 休息休息, 一天一天, 考虑考虑, 好久好久. The eight misfires are
85
+ * all one word ending a clause and the same word starting the next
86
+ * (告诉我们|我们在哪里, 不喜欢|喜欢不问问题的), or a noun said twice to
87
+ * address someone (大象大象). Nothing short of syntax separates those from
88
+ * 讨论讨论, and the eight are a spacing error where all 54 were one before.
89
+ */
90
+ export const ABAB_REDUPLICATION = {
91
+ name: "abab-reduplication",
92
+ apply: (words) => words.map((word, at) => {
93
+ const previous = words[at - 1];
94
+ return previous !== undefined && isRepeat(word, previous)
95
+ ? { ...word, separator: "-" }
96
+ : word;
97
+ }),
98
+ };
99
+ //# sourceMappingURL=reduplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduplication.js","sourceRoot":"","sources":["../../src/orthography/reduplication.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAqB,SAAS,EAAE,MAAM,WAAW,CAAC;AAEzD;;;;;GAKG;AACH,SAAS,MAAM,CAAC,UAA6B;IAC3C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,UAAU,CAAC;IAClD,OAAO,CACL,UAAU,CAAC,MAAM,KAAK,CAAC;QACvB,KAAK,KAAK,MAAM;QAChB,KAAK,KAAK,MAAM;QAChB,KAAK,KAAK,KAAK,CAChB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAiB;IAC9C,IAAI,EAAE,oBAAoB;IAC1B,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACrB,IAAI,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC,IAAI,CAAC;QACR,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CACvB;CACJ,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,SAAS,QAAQ,CAAC,IAAiB,EAAE,QAAqB;IACxD,OAAO,CACL,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;QAC3B,IAAI,CAAC,OAAO;QACZ,CAAC,IAAI,CAAC,YAAY;QAClB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QACpC,IAAI,CAAC,SAAS,KAAK,SAAS,CAC7B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAiB;IAC9C,IAAI,EAAE,oBAAoB;IAC1B,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;QACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/B,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;YACvD,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,GAAY,EAAE;YACtC,CAAC,CAAC,IAAI,CAAC;IACX,CAAC,CAAC;CACL,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { DecodedWord } from "../decode/word.js";
2
+ import type { Dictionary } from "../dictionary/dictionary.js";
3
+ /**
4
+ * One 分词连写 rule, rewriting the words a decode produced.
5
+ *
6
+ * Typed and individually testable, which is the point ALGORITHM.md makes about
7
+ * rules: the old project patched the output string with regexes, so its rules
8
+ * were order-dependent and could not be tested apart from each other.
9
+ */
10
+ export interface GroupingRule {
11
+ readonly name: string;
12
+ readonly apply: (words: readonly DecodedWord[], dictionary: Dictionary) => readonly DecodedWord[];
13
+ }
14
+ /**
15
+ * Join two decoded words into one.
16
+ *
17
+ * The first word's flags carry, because it is the head: 看了 is the verb 看
18
+ * with an aspect particle stuck to it, not a new word of its own.
19
+ */
20
+ export declare function join(head: DecodedWord, tail: DecodedWord): DecodedWord;
21
+ /**
22
+ * Write a word as two halves with a hyphen between them.
23
+ *
24
+ * The 重叠 and 成语 hyphens are the same operation on different evidence: cut
25
+ * the word, mark the second half, and leave the reading exactly as it was. The
26
+ * word is returned untouched where its reading cannot be cut — 儿化 has no
27
+ * halves.
28
+ */
29
+ export declare function hyphenate(word: DecodedWord, at: number): readonly DecodedWord[];
30
+ /**
31
+ * Divide a decoded word at every one of a list of character offsets.
32
+ *
33
+ * {@link splitAt} generalised, for the proper names whose parts CC-CEDICT marks
34
+ * more than two of: 上海交通大学 divides at 2 and 4, and cutting only at the
35
+ * first would leave `Shànghǎi Jiāotōngdàxué`.
36
+ *
37
+ * The word comes back whole where its reading cannot be cut — the same 儿化
38
+ * condition {@link splitAt} has — or where an offset is out of order or outside
39
+ * the word, since a boundary that does not describe this word cannot be applied
40
+ * to it.
41
+ */
42
+ export declare function divideAt(word: DecodedWord, offsets: readonly number[]): readonly DecodedWord[];
43
+ /**
44
+ * Split a decoded word into two at a character offset.
45
+ *
46
+ * Only possible where the reading has one syllable per character, which 儿化
47
+ * does not: there is no way to cut `wánr` in half.
48
+ */
49
+ export declare function splitAt(word: DecodedWord, at: number): readonly [DecodedWord, DecodedWord] | undefined;
50
+ //# sourceMappingURL=rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../src/orthography/rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAG9D;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,CACd,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,UAAU,EAAE,UAAU,KACnB,SAAS,WAAW,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW,CAStE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,GACT,SAAS,WAAW,EAAE,CAOxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,SAAS,WAAW,EAAE,CA2BxB;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,GACT,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,SAAS,CAsBjD"}
@@ -0,0 +1,101 @@
1
+ import { toCharacters } from "../script/characters.js";
2
+ /**
3
+ * Join two decoded words into one.
4
+ *
5
+ * The first word's flags carry, because it is the head: 看了 is the verb 看
6
+ * with an aspect particle stuck to it, not a new word of its own.
7
+ */
8
+ export function join(head, tail) {
9
+ return {
10
+ text: head.text + tail.text,
11
+ reading: [...head.reading, ...tail.reading],
12
+ isProperNoun: head.isProperNoun,
13
+ partOfSpeech: head.partOfSpeech,
14
+ isKnown: head.isKnown && tail.isKnown,
15
+ ...(head.separator !== undefined && { separator: head.separator }),
16
+ };
17
+ }
18
+ /**
19
+ * Write a word as two halves with a hyphen between them.
20
+ *
21
+ * The 重叠 and 成语 hyphens are the same operation on different evidence: cut
22
+ * the word, mark the second half, and leave the reading exactly as it was. The
23
+ * word is returned untouched where its reading cannot be cut — 儿化 has no
24
+ * halves.
25
+ */
26
+ export function hyphenate(word, at) {
27
+ const split = splitAt(word, at);
28
+ if (split === undefined) {
29
+ return [word];
30
+ }
31
+ const [head, tail] = split;
32
+ return [head, { ...tail, separator: "-" }];
33
+ }
34
+ /**
35
+ * Divide a decoded word at every one of a list of character offsets.
36
+ *
37
+ * {@link splitAt} generalised, for the proper names whose parts CC-CEDICT marks
38
+ * more than two of: 上海交通大学 divides at 2 and 4, and cutting only at the
39
+ * first would leave `Shànghǎi Jiāotōngdàxué`.
40
+ *
41
+ * The word comes back whole where its reading cannot be cut — the same 儿化
42
+ * condition {@link splitAt} has — or where an offset is out of order or outside
43
+ * the word, since a boundary that does not describe this word cannot be applied
44
+ * to it.
45
+ */
46
+ export function divideAt(word, offsets) {
47
+ const characters = toCharacters(word.text);
48
+ if (word.reading.length !== characters.length) {
49
+ return [word];
50
+ }
51
+ const cuts = [0, ...offsets, characters.length];
52
+ const isOrdered = cuts.every((at, index) => index === 0 || at > (cuts[index - 1] ?? 0));
53
+ if (!isOrdered || (offsets.at(-1) ?? 0) >= characters.length) {
54
+ return [word];
55
+ }
56
+ return cuts.slice(0, -1).map((from, index) => {
57
+ const to = cuts[index + 1] ?? characters.length;
58
+ const part = {
59
+ text: characters.slice(from, to).join(""),
60
+ reading: word.reading.slice(from, to),
61
+ isProperNoun: word.isProperNoun,
62
+ partOfSpeech: word.partOfSpeech,
63
+ isKnown: word.isKnown,
64
+ };
65
+ // Only the head keeps what was written in front of the word: every later
66
+ // part is written against the part before it rather than against that.
67
+ return index === 0 && word.separator !== undefined
68
+ ? { ...part, separator: word.separator }
69
+ : part;
70
+ });
71
+ }
72
+ /**
73
+ * Split a decoded word into two at a character offset.
74
+ *
75
+ * Only possible where the reading has one syllable per character, which 儿化
76
+ * does not: there is no way to cut `wánr` in half.
77
+ */
78
+ export function splitAt(word, at) {
79
+ const characters = toCharacters(word.text);
80
+ if (word.reading.length !== characters.length) {
81
+ return undefined;
82
+ }
83
+ const part = (from, to) => ({
84
+ text: characters.slice(from, to).join(""),
85
+ reading: word.reading.slice(from, to),
86
+ isProperNoun: word.isProperNoun,
87
+ partOfSpeech: word.partOfSpeech,
88
+ isKnown: word.isKnown,
89
+ });
90
+ const head = part(0, at);
91
+ return [
92
+ // Only the head keeps whatever was written in front of the word, since the
93
+ // tail is now written against the head rather than against what came
94
+ // before it.
95
+ word.separator === undefined
96
+ ? head
97
+ : { ...head, separator: word.separator },
98
+ part(at, characters.length),
99
+ ];
100
+ }
101
+ //# sourceMappingURL=rule.js.map