@furifont/dictionary 0.1.2 → 0.3.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.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Dictionary } from "@furifont/core";
2
2
  //#region src/index.d.ts
3
- /** Loads the compiled dictionary: JMdict and JMnedict place names, aligned by JmdictFurigana, with KANJIDIC2's on'yomi and JLPT levels. */
3
+ /** Loads the compiled dictionary: JMdict and JMnedict place names, aligned by JmdictFurigana, with KANJIDIC2's on'yomi, JLPT levels and uses in Tatoeba's sentences. */
4
4
  export declare function loadDictionary(): Promise<Dictionary>;
5
5
  //#endregion
package/dist/index.mjs CHANGED
@@ -1,18 +1,95 @@
1
1
  import * as v from "valibot";
2
- //#region src/defaults.ts
2
+ //#region src/manual/mahjong-yaku.ts
3
3
  /**
4
- * Default readings the compiled data ranks wrong, in inline notation. JMdict's
4
+ * The yaku (scoring hands) and tiles of Japanese riichi mahjong, as the Japan
5
+ * Professional Mahjong League lists them: https://www.ma-jan.or.jp/activity/yaku.html
6
+ * Each name reads in katakana there; here it is hiragana, in inline notation.
7
+ * Their readings are jargon (立直 りーち, 七対子 ちーといつ), so they only fill runs
8
+ * that no common word claims.
9
+ */
10
+ const MAHJONG_YAKU = [
11
+ "門[めん]前[ぜん]清[ちん]自[つ]摸[も]和[ほー]",
12
+ "立[りー]直[ち]",
13
+ "平[ぴん]和[ふ]",
14
+ "断[たん]么九[やお]",
15
+ "役[やく]牌[はい]",
16
+ "三[さん]元[げん]牌[はい]",
17
+ "場[ば]風[かぜ]牌[はい]",
18
+ "自[じ]風[かぜ]牌[はい]",
19
+ "連[れん]風[ぷう]牌[はい]",
20
+ "客[きゃく]風[ふう]牌[はい]",
21
+ "一[いー]盃[ぺー]口[こー]",
22
+ "嶺[りん]上[しゃん]開[かい]花[ほー]",
23
+ "搶[ちゃん]槓[かん]",
24
+ "槍[ちゃん]槓[かん]",
25
+ "海[はい]底[てい]摸[もー]月[ゆえ]",
26
+ "河[ほー]底[てい]撈[らお]魚[ゆい]",
27
+ "一[いっ]発[ぱつ]",
28
+ "三[さん]色[しょく]同[どう]順[じゅん]",
29
+ "一[いっ]気[き]通[つう]貫[かん]",
30
+ "七[ちー]対[とい]子[つ]",
31
+ "対[とい]々[とい]和[ほー]",
32
+ "三[さん]暗[あん]刻[こう]",
33
+ "三[さん]色[しょく]同[どう]刻[こう]",
34
+ "混全帯么九[ちゃんた]",
35
+ "三[さん]槓[かん]子[つ]",
36
+ "小[しょう]三[さん]元[げん]",
37
+ "混[ほん]老[ろう]頭[とう]",
38
+ "混一色[ほんいつ]",
39
+ "純全帯么九[じゅんちゃん]",
40
+ "二[りゃん]盃[ぺー]口[こー]",
41
+ "清一色[ちんいつ]",
42
+ "国[こく]士[し]無[む]双[そう]",
43
+ "四[すー]暗[あん]刻[こう]",
44
+ "四[すー]暗[あん]刻[こう]単[たん]騎[き]",
45
+ "大[だい]三[さん]元[げん]",
46
+ "字[つー]一[いー]色[そー]",
47
+ "小[しょう]四[すー]喜[しー]",
48
+ "大[だい]四[すー]喜[しー]",
49
+ "清[ちん]老[ろう]頭[とう]",
50
+ "緑[りゅー]一[いー]色[そー]",
51
+ "九[ちゅー]蓮[れん]宝[ぽう]燈[とう]",
52
+ "純[じゅん]正[せい]九[ちゅー]蓮[れん]宝[ぽう]燈[とう]",
53
+ "四[すー]槓[かん]子[つ]",
54
+ "天[てん]和[ほー]",
55
+ "地[ち]和[ほー]",
56
+ "役[やく]満[まん]",
57
+ "赤[あか]牌[はい]"
58
+ ];
59
+ //#endregion
60
+ //#region src/manual/index.ts
61
+ const NotationsSchema = v.array(v.string());
62
+ /**
63
+ * Word lists kept by hand, by source name, in inline notation. A source is a
64
+ * list written in this directory, or a file under `data/manual/` that a script
65
+ * compiled from a web page, which bundlers split into a lazy chunk. Add a
66
+ * source here and a build includes it, unless its plan lists the sources it wants.
67
+ */
68
+ const MANUAL_SOURCES = {
69
+ "mahjong-yaku": async () => MAHJONG_YAKU,
70
+ "yojijukugo": async () => v.parse(NotationsSchema, (await import("./yojijukugo-B8mguWRF.mjs")).default),
71
+ "jr-stations": async () => v.parse(NotationsSchema, (await import("./jr-stations-Rjpbmev2.mjs")).default)
72
+ };
73
+ async function loadManualSources() {
74
+ return Object.fromEntries(await Promise.all(Object.entries(MANUAL_SOURCES).map(async ([name, load]) => [name, await load()])));
75
+ }
76
+ //#endregion
77
+ //#region src/overrides.ts
78
+ /**
79
+ * Readings that override the compiled data where it ranks them wrong, in inline notation. JMdict's
5
80
  * frequency tags belong to a written form, so across entries they cannot tell
6
81
  * two readings apart; and a form that drops its okurigana usually meets it in
7
82
  * running text, where the font cannot see it. Users' pins override these.
8
83
  */
9
- const DEFAULT_READINGS = [
84
+ const OVERRIDE_READINGS = [
10
85
  "出[で]来[き]",
11
86
  "何[なん]人[にん]",
12
87
  "何[なん]時[じ]",
13
88
  "三[さん]十[じゅう]日[にち]",
14
89
  "外[そと]付[づ]",
15
- "支[し]払[はら]"
90
+ "支[し]払[はら]",
91
+ "字[じ]",
92
+ "明[みん]朝[ちょう]"
16
93
  ];
17
94
  /**
18
95
  * Kanji left bare when alone in a run, though one reading dominates the
@@ -50,6 +127,11 @@ const JlptSchema = v.array(v.tuple([
50
127
  5
51
128
  ])
52
129
  ]));
130
+ const TatoebaSchema = v.array(v.tuple([
131
+ v.string(),
132
+ v.string(),
133
+ v.pipe(v.number(), v.integer(), v.minValue(1))
134
+ ]));
53
135
  /**
54
136
  * A data file as a JSON module, which Node loads and bundlers split into a
55
137
  * lazy chunk. The path is a template so that TypeScript leaves the 11 MB file
@@ -59,25 +141,31 @@ async function readData(name, schema) {
59
141
  const { default: data } = await import(`../data/${name}.json`, { with: { type: "json" } });
60
142
  return v.parse(schema, data);
61
143
  }
62
- /** Loads the compiled dictionary: JMdict and JMnedict place names, aligned by JmdictFurigana, with KANJIDIC2's on'yomi and JLPT levels. */
144
+ /** Loads the compiled dictionary: JMdict and JMnedict place names, aligned by JmdictFurigana, with KANJIDIC2's on'yomi, JLPT levels and uses in Tatoeba's sentences. */
63
145
  async function loadDictionary() {
64
- const [data, places, jlpt] = await Promise.all([
146
+ const [data, places, jlpt, tatoeba, manual] = await Promise.all([
65
147
  readData("dictionary", DataSchema),
66
148
  readData("places", PlacesSchema),
67
- readData("jlpt", JlptSchema)
149
+ readData("jlpt", JlptSchema),
150
+ readData("tatoeba", TatoebaSchema),
151
+ loadManualSources()
68
152
  ]);
69
153
  const levels = new Map(jlpt.map(([form, furigana, level]) => [`${form}|${furigana}`, level]));
154
+ const uses = new Map(tatoeba.map(([form, furigana, n]) => [`${form}|${furigana}`, n]));
70
155
  return {
71
156
  sources: data.sources,
72
157
  onyomi: data.onyomi,
73
- defaults: DEFAULT_READINGS,
158
+ defaults: OVERRIDE_READINGS,
74
159
  bare: BARE_FORMS,
160
+ manual,
75
161
  places: places.map(([form, furigana]) => ({
76
162
  form,
77
163
  furigana
78
164
  })),
79
165
  entries: data.entries.map(([form, furigana, nf, priority, order, conjugates]) => {
80
166
  const level = levels.get(`${form}|${furigana}`);
167
+ const n = uses.get(`${form}|${furigana}`);
168
+ uses.delete(`${form}|${furigana}`);
81
169
  return {
82
170
  form,
83
171
  furigana,
@@ -85,7 +173,8 @@ async function loadDictionary() {
85
173
  priority,
86
174
  order,
87
175
  ...conjugates && { conjugatesReading: true },
88
- ...level && { jlpt: level }
176
+ ...level && { jlpt: level },
177
+ ...n && { tatoeba: n }
89
178
  };
90
179
  })
91
180
  };