@kensio/pinyinjs 1.9.9 → 1.10.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 (91) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +27 -8
  3. package/data/core.entries +21 -21
  4. package/data/full.entries +17396 -17396
  5. package/data/manifest.json +9 -7
  6. package/data/standard.entries +3625 -3625
  7. package/dist/cli/lookup-commands.d.ts.map +1 -1
  8. package/dist/cli/lookup-commands.js +2 -44
  9. package/dist/cli/lookup-commands.js.map +1 -1
  10. package/dist/cli/lookup-entry.d.ts +12 -0
  11. package/dist/cli/lookup-entry.d.ts.map +1 -0
  12. package/dist/cli/lookup-entry.js +55 -0
  13. package/dist/cli/lookup-entry.js.map +1 -0
  14. package/dist/dictionary/artifact-format.d.ts +20 -1
  15. package/dist/dictionary/artifact-format.d.ts.map +1 -1
  16. package/dist/dictionary/artifact-format.js +37 -0
  17. package/dist/dictionary/artifact-format.js.map +1 -1
  18. package/dist/dictionary/artifact-read.d.ts.map +1 -1
  19. package/dist/dictionary/artifact-read.js +3 -7
  20. package/dist/dictionary/artifact-read.js.map +1 -1
  21. package/dist/dictionary/artifact.d.ts.map +1 -1
  22. package/dist/dictionary/artifact.js +2 -2
  23. package/dist/dictionary/artifact.js.map +1 -1
  24. package/dist/dictionary/build-assertions.d.ts.map +1 -1
  25. package/dist/dictionary/build-assertions.js +2 -0
  26. package/dist/dictionary/build-assertions.js.map +1 -1
  27. package/dist/dictionary/cedict-senses.d.ts +4 -3
  28. package/dist/dictionary/cedict-senses.d.ts.map +1 -1
  29. package/dist/dictionary/cedict-senses.js +7 -4
  30. package/dist/dictionary/cedict-senses.js.map +1 -1
  31. package/dist/dictionary/dictionary-entry.d.ts +8 -0
  32. package/dist/dictionary/dictionary-entry.d.ts.map +1 -1
  33. package/dist/dictionary/dictionary-entry.js +3 -1
  34. package/dist/dictionary/dictionary-entry.js.map +1 -1
  35. package/dist/dictionary/entry-invariants.d.ts +6 -0
  36. package/dist/dictionary/entry-invariants.d.ts.map +1 -1
  37. package/dist/dictionary/entry-invariants.js +0 -27
  38. package/dist/dictionary/entry-invariants.js.map +1 -1
  39. package/dist/dictionary/entry.d.ts +8 -0
  40. package/dist/dictionary/entry.d.ts.map +1 -1
  41. package/dist/dictionary/entry.js.map +1 -1
  42. package/dist/dictionary/locale-invariants.d.ts +3 -0
  43. package/dist/dictionary/locale-invariants.d.ts.map +1 -0
  44. package/dist/dictionary/locale-invariants.js +52 -0
  45. package/dist/dictionary/locale-invariants.js.map +1 -0
  46. package/dist/dictionary/locale.d.ts +5 -1
  47. package/dist/dictionary/locale.d.ts.map +1 -1
  48. package/dist/dictionary/locale.js +6 -1
  49. package/dist/dictionary/locale.js.map +1 -1
  50. package/dist/dictionary/merge-types.d.ts +10 -0
  51. package/dist/dictionary/merge-types.d.ts.map +1 -1
  52. package/dist/dictionary/merge-types.js +2 -0
  53. package/dist/dictionary/merge-types.js.map +1 -1
  54. package/dist/dictionary/merge-word.js +7 -6
  55. package/dist/dictionary/merge-word.js.map +1 -1
  56. package/dist/dictionary/merge.d.ts.map +1 -1
  57. package/dist/dictionary/merge.js +5 -1
  58. package/dist/dictionary/merge.js.map +1 -1
  59. package/dist/dictionary/standard-readings.d.ts +42 -0
  60. package/dist/dictionary/standard-readings.d.ts.map +1 -0
  61. package/dist/dictionary/standard-readings.js +113 -0
  62. package/dist/dictionary/standard-readings.js.map +1 -0
  63. package/dist/dictionary/taiwan-notes.d.ts +13 -0
  64. package/dist/dictionary/taiwan-notes.d.ts.map +1 -0
  65. package/dist/dictionary/taiwan-notes.js +26 -0
  66. package/dist/dictionary/taiwan-notes.js.map +1 -0
  67. package/dist/dictionary/taiwan-reading.d.ts +22 -2
  68. package/dist/dictionary/taiwan-reading.d.ts.map +1 -1
  69. package/dist/dictionary/taiwan-reading.js +94 -25
  70. package/dist/dictionary/taiwan-reading.js.map +1 -1
  71. package/dist/dictionary/taiwan-settle.d.ts +22 -0
  72. package/dist/dictionary/taiwan-settle.d.ts.map +1 -0
  73. package/dist/dictionary/taiwan-settle.js +47 -0
  74. package/dist/dictionary/taiwan-settle.js.map +1 -0
  75. package/dist/search/match-readings.d.ts +2 -2
  76. package/dist/search/match-readings.d.ts.map +1 -1
  77. package/dist/search/match-readings.js +12 -7
  78. package/dist/search/match-readings.js.map +1 -1
  79. package/dist/sources/moe-workbook.d.ts +10 -0
  80. package/dist/sources/moe-workbook.d.ts.map +1 -0
  81. package/dist/sources/moe-workbook.js +89 -0
  82. package/dist/sources/moe-workbook.js.map +1 -0
  83. package/dist/sources/moe.d.ts +58 -0
  84. package/dist/sources/moe.d.ts.map +1 -0
  85. package/dist/sources/moe.js +79 -0
  86. package/dist/sources/moe.js.map +1 -0
  87. package/dist/sources/xlsx.d.ts +20 -0
  88. package/dist/sources/xlsx.d.ts.map +1 -0
  89. package/dist/sources/xlsx.js +78 -0
  90. package/dist/sources/xlsx.js.map +1 -0
  91. package/package.json +1 -1
@@ -1,38 +1,107 @@
1
1
  /**
2
2
  * The 國語 reading an entry carries, where a source states one.
3
3
  *
4
- * Both sources hedge it. CC-CEDICT hangs `Taiwan pr.` on one sense of a
5
- * headword and the others know nothing about it, and a note can sit on the
6
- * right sense and still be about that sense rather than the character. What
7
- * survives both tests, and is not simply another 普通话 sense of the word, is
8
- * the delta.
4
+ * 教育部's dictionaries are the standard and are asked first. For a word they
5
+ * list, what they say settles the entry, including when they say the word
6
+ * reads as it does in 普通话. A word they leave out falls back to CC-CEDICT's
7
+ * `Taiwan pr.` notes and Unihan's `kMandarin` pairs, which between them mark
8
+ * some 640 items.
9
+ *
10
+ * A character is settled the other way round. 教育部 lists a polyphone's
11
+ * readings in the order its entries are written, which leads with the literary
12
+ * reading as often as the current one: 們 is `mén` before `men` and 著 `zhù`
13
+ * before `zhe`. The order says nothing about which a character on its own
14
+ * means, so the dictionary is used as a check on the notes, not as a default.
15
+ * Both dictionaries are consulted for a character, since the question is only
16
+ * whether a reading is listed at all.
17
+ *
18
+ * Every source hedges in its own way. CC-CEDICT hangs `Taiwan pr.` on one
19
+ * sense of a headword and the others know nothing about it. What survives the
20
+ * sense tests, and is not simply another 普通话 sense of the word, is the
21
+ * delta. A reading that is the locale's but only for one sense is kept as an
22
+ * alternate, so a caller can still see it.
9
23
  */
10
24
  import { isSingleCharacter } from "../script/characters.js";
11
- import { isOwnSense, isSenseScopedNote } from "./cedict-senses.js";
12
- import { characterSyllable } from "./character-defaults.js";
25
+ import { isOwnSense } from "./cedict-senses.js";
13
26
  import { isSameReading } from "./entry.js";
14
- import { readDictionaryReading } from "./reading.js";
27
+ import { notedReadingOf } from "./taiwan-notes.js";
28
+ import { alternatesOf, isRetoned, standardReadingFor, standardReadingsOf, } from "./standard-readings.js";
15
29
  /**
16
- * Settle it for one word, or undefined where no source states one.
30
+ * What a word is held to: 教育部 where it lists the word, the notes where not.
31
+ *
32
+ * A word only the revised dictionary lists may move its tones and nothing
33
+ * else. That dictionary records classical words beside current ones under the
34
+ * same characters, and where the concise one is silent there is nothing to say
35
+ * which a headword is: it lists 五百 only as `wǔ bó`, which is not how
36
+ * Taipei reads the number. A tone is the shift 國語 makes across whole classes
37
+ * of words, and a change of sound is more often a different word written the
38
+ * same way.
17
39
  */
18
- export function taiwanReadingOf(word, senses, senseReadings, reading, unihan) {
19
- const taiwanSense = senses.find((entry) => entry.taiwanReadings !== undefined);
20
- const taiwanTokens = isSenseScopedNote(word, taiwanSense)
21
- ? undefined
22
- : taiwanSense?.taiwanReadings;
23
- const unihanTaiwan = unihan?.taiwanReading;
24
- let taiwan;
25
- if (taiwanTokens !== undefined) {
26
- taiwan = readDictionaryReading(word, taiwanTokens);
40
+ function wordReadingOf(standard, noted, reading, isDelta) {
41
+ if (standard.length === 0) {
42
+ return noted !== undefined && isDelta(noted.reading)
43
+ ? { reading: noted.reading, alternates: [], isStandard: false }
44
+ : { alternates: [], isStandard: false };
27
45
  }
28
- else if (isSingleCharacter(word) && unihanTaiwan !== undefined) {
29
- const syllable = characterSyllable(word, unihanTaiwan);
30
- taiwan = syllable === undefined ? undefined : [syllable];
46
+ const readings = standard.map((listed) => listed.reading);
47
+ const isCurrent = standard.some((listed) => listed.dictionary === "concise");
48
+ const chosen = standardReadingFor(readings, reading, isDelta);
49
+ const taiwan = chosen !== undefined && (isCurrent || isRetoned(chosen, reading))
50
+ ? chosen
51
+ : undefined;
52
+ return {
53
+ ...(taiwan !== undefined && { reading: taiwan }),
54
+ // The readings it could not be told apart from, which are other words
55
+ // written alike.
56
+ alternates: isCurrent ? alternatesOf(readings, taiwan, isDelta) : [],
57
+ isStandard: true,
58
+ };
59
+ }
60
+ /**
61
+ * What a character is held to: the notes, as far as 教育部 bears them out.
62
+ *
63
+ * A note 教育部 lists the reading for stands, as the default if it is about
64
+ * the whole character and as an alternate if it is about one sense: 和's `hàn`
65
+ * is listed, and is the conjunction only. A note it lists no such reading for
66
+ * is dropped, which is what the standard says of 俄 `è` and 法 `fà`.
67
+ *
68
+ * 教育部 never supplies a character's reading by itself. Its order is the
69
+ * order its entries are written in, and a character it does not list in its
70
+ * 普通话 reading is as often a gap in the concise dictionary as a reading that
71
+ * has moved: it has no 差 `chà`, and the one 差 it lists that 普通话 has no
72
+ * sense for is `cuō`.
73
+ */
74
+ function characterReadingOf(standard, noted, isDelta) {
75
+ const isStandard = standard.length > 0;
76
+ if (noted === undefined || !isDelta(noted.reading)) {
77
+ return { alternates: [], isStandard };
78
+ }
79
+ const isListed = standard.some((listed) => isSameReading(listed.reading, noted.reading));
80
+ if (isStandard && !isListed) {
81
+ return { alternates: [], isStandard };
31
82
  }
32
- if (taiwan !== undefined &&
33
- (isSameReading(taiwan, reading) || isOwnSense(taiwan, senseReadings))) {
34
- return undefined;
83
+ return noted.isSenseScoped
84
+ ? { alternates: [noted.reading], isStandard }
85
+ : { reading: noted.reading, alternates: [], isStandard };
86
+ }
87
+ /**
88
+ * Settle it for one word.
89
+ *
90
+ * `spellings` are the word's 繁體 forms, which is how 教育部 keys it.
91
+ */
92
+ export function taiwanReadingOf(word, spellings, senses, senseReadings, reading, unihan, moe) {
93
+ // A reading the word already has in 普通话 is a sense, not a locale.
94
+ const isDelta = (taiwan) => taiwan !== undefined &&
95
+ !isSameReading(taiwan, reading) &&
96
+ !isOwnSense(taiwan, senseReadings);
97
+ const noted = notedReadingOf(word, senses, unihan);
98
+ if (!isSingleCharacter(word)) {
99
+ return wordReadingOf(standardReadingsOf(spellings, moe), noted, reading, isDelta);
35
100
  }
36
- return taiwan;
101
+ // Every spelling, because a 简体 character can be a 繁體 one in its own
102
+ // right with readings of its own: 教育部 lists 台 only as `yí`, and the
103
+ // `tái` is under 臺.
104
+ const listed = spellings.flatMap((spelling) => standardReadingsOf([spelling], moe));
105
+ return characterReadingOf(listed, noted, isDelta);
37
106
  }
38
107
  //# sourceMappingURL=taiwan-reading.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"taiwan-reading.js","sourceRoot":"","sources":["../../src/dictionary/taiwan-reading.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAI5D,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,MAA8B,EAC9B,aAA+C,EAC/C,OAA4B,EAC5B,MAAkC;IAElC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAC7B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS,CAC9C,CAAC;IACF,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,EAAE,WAAW,CAAC;QACvD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,WAAW,EAAE,cAAc,CAAC;IAChC,MAAM,YAAY,GAAG,MAAM,EAAE,aAAa,CAAC;IAC3C,IAAI,MAAuC,CAAC;IAC5C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,qBAAqB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACrD,CAAC;SAAM,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACjE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACvD,MAAM,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC3D,CAAC;IACD,IACE,MAAM,KAAK,SAAS;QACpB,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,EACrE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"taiwan-reading.js","sourceRoot":"","sources":["../../src/dictionary/taiwan-reading.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Syllable } from "../syllable/syllable.js";
2
+ import type { EntryReadings } from "./entry.js";
3
+ import type { WordSources } from "./merge-types.js";
4
+ import type { TraditionalForm } from "./traditional-form.js";
5
+ import { type TaiwanReading } from "./taiwan-reading.js";
6
+ /**
7
+ * What a settled 國語 reading adds to the build's counts.
8
+ */
9
+ declare function taiwanTallyOf(taiwan: TaiwanReading): {
10
+ readonly taiwanReadings: number;
11
+ readonly standardTaiwanReadings: number;
12
+ };
13
+ /**
14
+ * Settle a word's 國語 reading, as the fields it fills on the entry and what
15
+ * it adds to the build's counts.
16
+ */
17
+ export declare function settleTaiwanReading(word: string, form: TraditionalForm, senseReadings: readonly (readonly Syllable[])[], reading: readonly Syllable[], sources: WordSources): {
18
+ readonly readings: Pick<EntryReadings, "tw" | "twAlternates">;
19
+ readonly tally: ReturnType<typeof taiwanTallyOf>;
20
+ };
21
+ export {};
22
+ //# sourceMappingURL=taiwan-settle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taiwan-settle.d.ts","sourceRoot":"","sources":["../../src/dictionary/taiwan-settle.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,KAAK,aAAa,EAAmB,MAAM,qBAAqB,CAAC;AAc1E;;GAEG;AACH,iBAAS,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG;IAC7C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC,CAMA;AAoBD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,eAAe,EACrB,aAAa,EAAE,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,EAC/C,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,OAAO,EAAE,WAAW,GACnB;IACD,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,cAAc,CAAC,CAAC;IAC9D,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;CAClD,CAWA"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * A word's settled 國語 reading in the shape the merge stores it: the fields
3
+ * it fills on the entry, and what it adds to the build's counts.
4
+ */
5
+ import { isSingleCharacter } from "../script/characters.js";
6
+ import { taiwanReadingOf } from "./taiwan-reading.js";
7
+ /**
8
+ * The fields of an entry's readings that a settled 國語 reading fills.
9
+ */
10
+ function taiwanColumnsOf(taiwan) {
11
+ return {
12
+ ...(taiwan.reading !== undefined && { tw: taiwan.reading }),
13
+ ...(taiwan.alternates.length > 0 && { twAlternates: taiwan.alternates }),
14
+ };
15
+ }
16
+ /**
17
+ * What a settled 國語 reading adds to the build's counts.
18
+ */
19
+ function taiwanTallyOf(taiwan) {
20
+ const isDelta = taiwan.reading !== undefined;
21
+ return {
22
+ taiwanReadings: isDelta ? 1 : 0,
23
+ standardTaiwanReadings: isDelta && taiwan.isStandard ? 1 : 0,
24
+ };
25
+ }
26
+ /**
27
+ * The spellings 教育部 is asked for a word under, which is how it keys it.
28
+ *
29
+ * A character's other 繁體 forms are other characters, which 教育部 reads as
30
+ * themselves: 最's include 冣, which it lists as `jù`. A word's are the same
31
+ * word, and its 简体 spelling is only asked where it is also the 繁體 one:
32
+ * 教育部 lists 听听, written with the 繁體 character 听, as `yǐn yǐn`.
33
+ */
34
+ function spellingsOf(word, hant, hantVariants) {
35
+ return isSingleCharacter(word)
36
+ ? [...new Set([hant, word])]
37
+ : [hant, ...hantVariants];
38
+ }
39
+ /**
40
+ * Settle a word's 國語 reading, as the fields it fills on the entry and what
41
+ * it adds to the build's counts.
42
+ */
43
+ export function settleTaiwanReading(word, form, senseReadings, reading, sources) {
44
+ const taiwan = taiwanReadingOf(word, spellingsOf(word, form.hant, form.hantVariants), form.senses, senseReadings, reading, sources.unihanReadings.get(word), sources.moe);
45
+ return { readings: taiwanColumnsOf(taiwan), tally: taiwanTallyOf(taiwan) };
46
+ }
47
+ //# sourceMappingURL=taiwan-settle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taiwan-settle.js","sourceRoot":"","sources":["../../src/dictionary/taiwan-settle.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAK5D,OAAO,EAAsB,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE1E;;GAEG;AACH,SAAS,eAAe,CACtB,MAAqB;IAErB,OAAO;QACL,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAC3D,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;KACzE,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,MAAqB;IAI1C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC;IAC7C,OAAO;QACL,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,sBAAsB,EAAE,OAAO,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAClB,IAAY,EACZ,IAAY,EACZ,YAA+B;IAE/B,OAAO,iBAAiB,CAAC,IAAI,CAAC;QAC5B,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,IAAqB,EACrB,aAA+C,EAC/C,OAA4B,EAC5B,OAAoB;IAKpB,MAAM,MAAM,GAAG,eAAe,CAC5B,IAAI,EACJ,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,EAC/C,IAAI,CAAC,MAAM,EACX,aAAa,EACb,OAAO,EACP,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAChC,OAAO,CAAC,GAAG,CACZ,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;AAC7E,CAAC"}
@@ -18,8 +18,8 @@ export declare class CharacterReadings {
18
18
  * glyph form is matched by the readings of the Taiwan-standard key it folds
19
19
  * to rather than by nothing.
20
20
  *
21
- * The 國語 reading goes on the end where it differs, so that 圾 answers to
22
- * `se` as well as to `ji`. A search box is not the place to insist on one
21
+ * The 國語 readings go on the end where they differ, so that 圾 answers to
22
+ * `se` as well as to `ji` and 和 to `han` as well as to `he`. A search box is not the place to insist on one
23
23
  * standard: somebody typing what they say is not typing it wrongly, and the
24
24
  * decoder's own reading is what ranks the two afterwards.
25
25
  */
@@ -1 +1 @@
1
- {"version":3,"file":"match-readings.d.ts","sourceRoot":"","sources":["../../src/search/match-readings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,qBAAa,iBAAiB;;IAK5B,YAAY,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,EAGhE;IAED;;;;;;;;;;;OAWG;IACH,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,CAgB/C;IAED;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE,CA2B7C;CACF"}
1
+ {"version":3,"file":"match-readings.d.ts","sourceRoot":"","sources":["../../src/search/match-readings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,qBAAa,iBAAiB;;IAK5B,YAAY,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,EAGhE;IAED;;;;;;;;;;;OAWG;IACH,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,CAoB/C;IAED;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE,CA2B7C;CACF"}
@@ -16,8 +16,8 @@ export class CharacterReadings {
16
16
  * glyph form is matched by the readings of the Taiwan-standard key it folds
17
17
  * to rather than by nothing.
18
18
  *
19
- * The 國語 reading goes on the end where it differs, so that 圾 answers to
20
- * `se` as well as to `ji`. A search box is not the place to insist on one
19
+ * The 國語 readings go on the end where they differ, so that 圾 answers to
20
+ * `se` as well as to `ji` and 和 to `han` as well as to `he`. A search box is not the place to insist on one
21
21
  * standard: somebody typing what they say is not typing it wrongly, and the
22
22
  * decoder's own reading is what ranks the two afterwards.
23
23
  */
@@ -29,11 +29,16 @@ export class CharacterReadings {
29
29
  /* c8 ignore next -- only ever asked about a character that is there */
30
30
  const character = toCanonicalGlyphs(this.#characters[at] ?? "");
31
31
  const found = this.#dictionary.readingsOf(character);
32
- const taiwan = this.#dictionary.lookup(character)?.taiwanReading;
33
- const readings = taiwan === undefined ||
34
- found.some((reading) => isSameReading(reading, taiwan))
35
- ? found
36
- : [...found, taiwan];
32
+ const entry = this.#dictionary.lookup(character);
33
+ const readings = [...found];
34
+ for (const taiwan of [
35
+ ...(entry?.taiwanReading === undefined ? [] : [entry.taiwanReading]),
36
+ ...(entry?.taiwanAlternates ?? []),
37
+ ]) {
38
+ if (!readings.some((reading) => isSameReading(reading, taiwan))) {
39
+ readings.push(taiwan);
40
+ }
41
+ }
37
42
  this.#readings[at] = readings;
38
43
  return readings;
39
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"match-readings.js","sourceRoot":"","sources":["../../src/search/match-readings.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,MAAM,OAAO,iBAAiB;IACnB,WAAW,CAAa;IACxB,WAAW,CAAoB;IAC/B,SAAS,GAAyC,EAAE,CAAC;IAE9D,YAAY,UAAsB,EAAE,UAA6B;QAC/D,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,EAAE,CAAC,EAAU;QACX,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,uEAAuE;QACvE,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;QACjE,MAAM,QAAQ,GACZ,MAAM,KAAK,SAAS;YACpB,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,MAAM,CAAC,CAAC;QACzB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC;QAC9B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAU;QACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO;YACP,IAAI;YACJ,UAAU,EAAE,CAAC;SACd,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO;YACL,GAAG,KAAK;YACR,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE;gBACpC,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5B,yEAAyE;gBACzE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;oBAC9C,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,OAAO;oBACL;wBACE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;wBACnD,IAAI;wBACJ,UAAU,EAAE,CAAC;qBACd;iBACF,CAAC;YACJ,CAAC,CAAC;SACH,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"match-readings.js","sourceRoot":"","sources":["../../src/search/match-readings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Turn a dictionary's worksheet into a table of headword, order and reading.
3
+ *
4
+ * Done once, when the download is cached, so the build reads a small table and
5
+ * never the 125 MB of XML the spreadsheet is made of. The output is one
6
+ * tab-separated line per reading, with a fourth column where the entry gives
7
+ * a variant reading, and the header row is dropped.
8
+ */
9
+ export declare function tabulateMoeWorkbook(sharedStringsXml: string, sheetXml: string): string;
10
+ //# sourceMappingURL=moe-workbook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moe-workbook.d.ts","sourceRoot":"","sources":["../../src/sources/moe-workbook.ts"],"names":[],"mappings":"AA+BA;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,GACf,MAAM,CA4CR"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Taking the readings out of a 教育部 dictionary's workbook.
3
+ *
4
+ * The workbook has seventeen columns, and only the headword, the order of its
5
+ * readings, its 漢語拼音 and its variant reading are read. Definitions,
6
+ * examples, synonyms and the rest are never parsed. See `moe.ts` for what is
7
+ * done with the readings.
8
+ */
9
+ import { HEADER_ROW, readRows, readSharedStrings } from "./xlsx.js";
10
+ /**
11
+ * The columns this package reads, by the name the header row gives them.
12
+ *
13
+ * Found by name rather than by letter, because the two dictionaries lay their
14
+ * columns out differently: 《重編國語辭典修訂本》 has 漢語拼音 in column L and
15
+ * 《國語辭典簡編本》 in column J. A release that drops one fails the build
16
+ * rather than reading the wrong column.
17
+ */
18
+ const HEADERS = {
19
+ word: "字詞名",
20
+ order: "多音排序",
21
+ pinyin: "漢語拼音",
22
+ variantKind: "變體類型",
23
+ variant: "變體漢語拼音",
24
+ };
25
+ /**
26
+ * The kinds of variant reading that are readings of the word itself.
27
+ */
28
+ const VARIANT_KINDS = new Set(["又音", "語音", "讀音", "或讀"]);
29
+ /**
30
+ * Turn a dictionary's worksheet into a table of headword, order and reading.
31
+ *
32
+ * Done once, when the download is cached, so the build reads a small table and
33
+ * never the 125 MB of XML the spreadsheet is made of. The output is one
34
+ * tab-separated line per reading, with a fourth column where the entry gives
35
+ * a variant reading, and the header row is dropped.
36
+ */
37
+ export function tabulateMoeWorkbook(sharedStringsXml, sheetXml) {
38
+ const strings = readSharedStrings(sharedStringsXml);
39
+ const header = readRows(HEADER_ROW.exec(sheetXml)?.[0] ?? "", strings).get(1);
40
+ // 變體類型 carries its legend in the header, and the two dictionaries'
41
+ // legends differ, so a header is matched on how it starts.
42
+ const columnOf = (name) => {
43
+ const found = [...(header ?? [])].find(([, text]) => text.startsWith(name))?.[0];
44
+ if (found === undefined) {
45
+ throw new Error(`教育部 dictionary has no ${name} column`);
46
+ }
47
+ return found;
48
+ };
49
+ const columns = {
50
+ word: columnOf(HEADERS.word),
51
+ order: columnOf(HEADERS.order),
52
+ pinyin: columnOf(HEADERS.pinyin),
53
+ variantKind: columnOf(HEADERS.variantKind),
54
+ variant: columnOf(HEADERS.variant),
55
+ };
56
+ const rows = readRows(sheetXml, strings, new Set(Object.values(columns)));
57
+ const lines = [];
58
+ for (const [row, cells] of rows) {
59
+ const word = cells.get(columns.word) ?? "";
60
+ const pinyin = cells.get(columns.pinyin) ?? "";
61
+ if (row === 1 || word === "" || pinyin === "") {
62
+ continue;
63
+ }
64
+ const kind = cells.get(columns.variantKind) ?? "";
65
+ const variant = VARIANT_KINDS.has(kind)
66
+ ? (cells.get(columns.variant) ?? "")
67
+ : "";
68
+ lines.push([
69
+ word,
70
+ orderOf(cells.get(columns.order)),
71
+ spaced(pinyin),
72
+ ...(variant === "" ? [] : [spaced(variant)]),
73
+ ].join("\t"));
74
+ }
75
+ return `${lines.join("\n")}\n`;
76
+ }
77
+ /**
78
+ * A headword's 多音排序, which is blank for a headword with one reading.
79
+ */
80
+ function orderOf(order) {
81
+ return order === undefined || order === "" ? "0" : order;
82
+ }
83
+ /**
84
+ * A reading with its syllables separated by single spaces.
85
+ */
86
+ function spaced(pinyin) {
87
+ return pinyin.replaceAll(/\s+/gu, " ");
88
+ }
89
+ //# sourceMappingURL=moe-workbook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moe-workbook.js","sourceRoot":"","sources":["../../src/sources/moe-workbook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Which of 教育部's two dictionaries a reading comes from.
3
+ *
4
+ * `concise` is 《國語辭典簡編本》, which describes current usage, and
5
+ * `revised` is 《重編國語辭典修訂本》, which adds the literary and historical.
6
+ */
7
+ export type MoeDictionary = "concise" | "revised";
8
+ /**
9
+ * One reading 教育部 gives a headword.
10
+ */
11
+ export interface MoeReading {
12
+ readonly dictionary: MoeDictionary;
13
+ /**
14
+ * Where the reading stands among the headword's readings.
15
+ *
16
+ * 0 for a headword with one reading. A headword with several numbers them
17
+ * from 1, and 1 is the reading the dictionary lists first: 和 is `hé` at 1
18
+ * and `hàn` at 5, 期 `qí` at 1 and `qī` at 2.
19
+ */
20
+ readonly order: number;
21
+ /**
22
+ * The reading as tokens {@link import("../dictionary/reading.js").readAlignedReading}
23
+ * accepts, one per syllable, with 儿化 split off as its own `r5` token.
24
+ */
25
+ readonly readings: readonly string[];
26
+ /**
27
+ * A second reading the dictionary gives the same entry, where it gives one.
28
+ *
29
+ * Only the kinds that are readings of the word: 又音, an alternative, and
30
+ * the 語音 and 讀音 pair of colloquial and literary readings. 變, which
31
+ * records a tone change in connected speech such as 一 before a fourth tone,
32
+ * is left out, since the merge stores tones before sandhi.
33
+ */
34
+ readonly variant?: readonly string[];
35
+ }
36
+ /**
37
+ * Read the table {@link tabulateMoeWorkbook} writes, keyed by headword.
38
+ *
39
+ * Headwords are 繁體, as Taiwan writes them. A headword's readings come back
40
+ * in the dictionary's own order.
41
+ */
42
+ export declare function parseMoeReadings(text: string, dictionary: MoeDictionary): ReadonlyMap<string, readonly MoeReading[]>;
43
+ /**
44
+ * Two dictionaries' readings as one.
45
+ *
46
+ * 《國語辭典簡編本》 is the one that describes current usage, and for a word
47
+ * both list it wins. 《重編國語辭典修訂本》 is four times its size and records
48
+ * the literary and historical readings too, so where the two list a word it is
49
+ * often the older one that the larger dictionary leads with: 玩 is `wàn` there
50
+ * before `wán`, 鹽 `yàn` before `yán`, and 它們 is `tuō men`. Only the words
51
+ * the concise dictionary leaves out are taken from it.
52
+ *
53
+ * A character keeps the readings of both, the concise dictionary's first.
54
+ * The merge only ever asks whether a character's reading is listed, and the
55
+ * concise dictionary leaves out some current ones: it has no 差 `chà`.
56
+ */
57
+ export declare function preferReadings(first: ReadonlyMap<string, readonly MoeReading[]>, second: ReadonlyMap<string, readonly MoeReading[]>): ReadonlyMap<string, readonly MoeReading[]>;
58
+ //# sourceMappingURL=moe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moe.d.ts","sourceRoot":"","sources":["../../src/sources/moe.ts"],"names":[],"mappings":"AAaA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAqBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,aAAa,GACxB,WAAW,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,CAqB5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,EACjD,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,GACjD,WAAW,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,CAO5C"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The readings of 教育部's two dictionaries of the 國語 standard,
3
+ * 《國語辭典簡編本》 and 《重編國語辭典修訂本》.
4
+ *
5
+ * Read from the table `moe-workbook.ts` takes out of each download, which holds
6
+ * a headword, the order of its readings, its 漢語拼音 and any variant reading,
7
+ * and nothing of the dictionaries' own text. See docs/dictionaries for why the
8
+ * readings alone are taken and what the licence says about them.
9
+ */
10
+ import { isSingleCharacter } from "../script/characters.js";
11
+ import { readSyllable } from "../syllable/syllable.js";
12
+ import { ERHUA_TOKEN } from "../dictionary/reading.js";
13
+ /**
14
+ * Split a reading into the tokens the merge aligns against a headword.
15
+ *
16
+ * 教育部 writes 儿化 on the syllable, as `yī huǐr` for 一會兒, where the merge
17
+ * expects CC-CEDICT's shape of a syllable followed by `r5`. A syllable that
18
+ * reads as 儿化 is split back into that shape, which leaves 兒 with a token to
19
+ * account for it; `ér` and `èr` are syllables of their own and stay whole.
20
+ */
21
+ function tokensOf(pinyin) {
22
+ return pinyin
23
+ .split(" ")
24
+ .filter((token) => token !== "")
25
+ .flatMap((token) => readSyllable(token)?.erhua === true
26
+ ? [token.slice(0, -1), ERHUA_TOKEN]
27
+ : [token]);
28
+ }
29
+ /**
30
+ * Read the table {@link tabulateMoeWorkbook} writes, keyed by headword.
31
+ *
32
+ * Headwords are 繁體, as Taiwan writes them. A headword's readings come back
33
+ * in the dictionary's own order.
34
+ */
35
+ export function parseMoeReadings(text, dictionary) {
36
+ const readings = new Map();
37
+ for (const line of text.split("\n")) {
38
+ const [word = "", order = "", pinyin = "", variant = ""] = line.split("\t");
39
+ if (word === "" || pinyin === "") {
40
+ continue;
41
+ }
42
+ const headword = word.normalize("NFC");
43
+ const listed = readings.get(headword) ?? [];
44
+ listed.push({
45
+ dictionary,
46
+ order: Number(order) || 0,
47
+ readings: tokensOf(pinyin),
48
+ ...(variant !== "" && { variant: tokensOf(variant) }),
49
+ });
50
+ readings.set(headword, listed);
51
+ }
52
+ for (const listed of readings.values()) {
53
+ listed.sort((left, right) => left.order - right.order);
54
+ }
55
+ return readings;
56
+ }
57
+ /**
58
+ * Two dictionaries' readings as one.
59
+ *
60
+ * 《國語辭典簡編本》 is the one that describes current usage, and for a word
61
+ * both list it wins. 《重編國語辭典修訂本》 is four times its size and records
62
+ * the literary and historical readings too, so where the two list a word it is
63
+ * often the older one that the larger dictionary leads with: 玩 is `wàn` there
64
+ * before `wán`, 鹽 `yàn` before `yán`, and 它們 is `tuō men`. Only the words
65
+ * the concise dictionary leaves out are taken from it.
66
+ *
67
+ * A character keeps the readings of both, the concise dictionary's first.
68
+ * The merge only ever asks whether a character's reading is listed, and the
69
+ * concise dictionary leaves out some current ones: it has no 差 `chà`.
70
+ */
71
+ export function preferReadings(first, second) {
72
+ const merged = new Map(second);
73
+ for (const [word, readings] of first) {
74
+ const extra = isSingleCharacter(word) ? (second.get(word) ?? []) : [];
75
+ merged.set(word, [...readings, ...extra]);
76
+ }
77
+ return merged;
78
+ }
79
+ //# sourceMappingURL=moe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moe.js","sourceRoot":"","sources":["../../src/sources/moe.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAuCvD;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,MAAc;IAC9B,OAAO,MAAM;SACV,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC;SAC/B,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CACjB,YAAY,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI;QACjC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;QACnC,CAAC,CAAC,CAAC,KAAK,CAAC,CACZ,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,UAAyB;IAEzB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC;IACjD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5E,IAAI,IAAI,KAAK,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YACjC,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC;YACV,UAAU;YACV,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC;YAC1B,GAAG,CAAC,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAiD,EACjD,MAAkD;IAElD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Reading cells out of a spreadsheet's XML, as an `.xlsx` workbook stores
3
+ * them: a worksheet of cells, and a table of the strings they share.
4
+ *
5
+ * Only as much of the format as 教育部's downloads use. Formulas, styles and
6
+ * the other sheets of a workbook are never read.
7
+ */
8
+ /**
9
+ * The header row of a worksheet.
10
+ */
11
+ export declare const HEADER_ROW: RegExp;
12
+ /**
13
+ * Read the workbook's shared string table.
14
+ */
15
+ export declare function readSharedStrings(xml: string): readonly string[];
16
+ /**
17
+ * Read a worksheet's cells into rows, keeping only the columns asked for.
18
+ */
19
+ export declare function readRows(sheetXml: string, strings: readonly string[], wanted?: ReadonlySet<string>): Map<number, Map<string, string>>;
20
+ //# sourceMappingURL=xlsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xlsx.d.ts","sourceRoot":"","sources":["../../src/sources/xlsx.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU,QAA+B,CAAC;AAsCvD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAIhE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA0BlC"}