@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,111 @@
1
+ import { DIGIT_CHARACTERS } from "./characters.js";
2
+ /**
3
+ * The places inside one group of four digits, largest first.
4
+ */
5
+ const PLACES = ["千", "百", "十", ""];
6
+ /**
7
+ * The group separators, in the order the groups come off the number.
8
+ */
9
+ const GROUPS = ["", "万", "亿", "万亿"];
10
+ /**
11
+ * How many digits one group holds.
12
+ *
13
+ * Chinese numbers are grouped by 万 rather than by thousands, which is why a
14
+ * group is four digits wide and why 12,345 is *one* 万 and 2,345.
15
+ */
16
+ const GROUP_DIGITS = 4;
17
+ /**
18
+ * The largest number this can write, being four groups of four digits.
19
+ */
20
+ export const LARGEST_CARDINAL = 10 ** 16 - 1;
21
+ /**
22
+ * Whether a lone 2 opening this group takes 两.
23
+ */
24
+ function isLiang(liang, isLeading) {
25
+ return liang === "always" || (liang === "leading" && isLeading);
26
+ }
27
+ /**
28
+ * The character a digit takes in a place: 两 before a 千, 二 otherwise.
29
+ */
30
+ function digitAt(value, place, isFirst, options) {
31
+ return value === 2 &&
32
+ place === "千" &&
33
+ isLiang(options.liang, options.isLeading && isFirst)
34
+ ? "两"
35
+ : (DIGIT_CHARACTERS[value] ?? "");
36
+ }
37
+ /**
38
+ * Write one group of at most four digits: 2345 as 二千三百四十五.
39
+ *
40
+ * Empty for a group that is all zeros. A run of zeros inside the group becomes
41
+ * one 零, and only where a non-zero digit follows it: 1,005 is 一千零五 while
42
+ * 1,500 is 一千五百.
43
+ */
44
+ function writeGroup(group, options) {
45
+ const digits = String(group).padStart(GROUP_DIGITS, "0").split("");
46
+ let written = "";
47
+ let isPending = false;
48
+ for (const [at, digit] of digits.entries()) {
49
+ const value = Number(digit);
50
+ if (value === 0) {
51
+ isPending = written !== "";
52
+ continue;
53
+ }
54
+ const place = PLACES[at] ?? "";
55
+ if (isPending) {
56
+ written += "零";
57
+ isPending = false;
58
+ }
59
+ // 十五 rather than 一十五: the 一 drops only from a bare leading 十, so
60
+ // 一百一十五 keeps it and so does the 一十五 inside 一万零一十五.
61
+ const isBareTen = value === 1 && place === "十" && written === "" && options.isLeading;
62
+ written += isBareTen
63
+ ? place
64
+ : digitAt(value, place, written === "", options) + place;
65
+ }
66
+ return written;
67
+ }
68
+ /**
69
+ * Write a non-negative integer as a cardinal: 12345 → 一万二千三百四十五.
70
+ *
71
+ * The awkward parts are 零 and the bare 十, and both are about saying the
72
+ * number aloud rather than about arithmetic. A 零 goes where a place is skipped
73
+ * inside* the spoken number (一千零五) and not where the number simply ends
74
+ * (一千五百), which is the same question one level up between groups: 25,000 is
75
+ * 两万五千 because the lower group fills its 千, and 20,050 is 两万零五十
76
+ * because it does not.
77
+ * @throws {RangeError} for a negative, a fraction, or anything above 10^16.
78
+ */
79
+ export function cardinalHanzi(value, options = {}) {
80
+ if (!Number.isSafeInteger(value) || value < 0 || value > LARGEST_CARDINAL) {
81
+ throw new RangeError(`not a writable whole number: ${String(value)}`);
82
+ }
83
+ if (value === 0) {
84
+ return "零";
85
+ }
86
+ const { liang = "always" } = options;
87
+ const groups = [];
88
+ for (let rest = value; rest > 0; rest = Math.floor(rest / 10_000)) {
89
+ groups.push(rest % 10_000);
90
+ }
91
+ let written = "";
92
+ for (const [at, group] of groups.entries()) {
93
+ if (group === 0) {
94
+ continue;
95
+ }
96
+ const unit = GROUPS[at] ?? "";
97
+ const body = writeGroup(group, {
98
+ isLeading: at === groups.length - 1,
99
+ liang,
100
+ });
101
+ // The group immediately below decides whether a 零 is spoken between them:
102
+ // it is needed unless that group fills its own 千 place.
103
+ const below = groups[at - 1] ?? 0;
104
+ const gap = written !== "" && below < 1000 ? "零" : "";
105
+ const isLeading = at === groups.length - 1;
106
+ const lone = body === "二" && unit !== "" && isLiang(liang, isLeading) ? "两" : body;
107
+ written = lone + unit + gap + written;
108
+ }
109
+ return written;
110
+ }
111
+ //# sourceMappingURL=cardinal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cardinal.js","sourceRoot":"","sources":["../../src/numerals/cardinal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { type Syllable } from "../syllable/syllable.js";
2
+ /**
3
+ * The 汉字 a digit is written with, indexed by its value.
4
+ */
5
+ export declare const DIGIT_CHARACTERS = "\u96F6\u4E00\u4E8C\u4E09\u56DB\u4E94\u516D\u4E03\u516B\u4E5D";
6
+ /**
7
+ * The other 汉字 a written number is made of, and what each is worth.
8
+ *
9
+ * 十, 百 and 千 are the places inside a group of four; 万 and 亿 are the group
10
+ * separators, which is what makes Chinese numbers myriad-grouped rather than
11
+ * thousand-grouped: 12,345 is 一万二千三百四十五, one 万 and 2,345.
12
+ */
13
+ export declare const UNIT_VALUES: ReadonlyMap<string, number>;
14
+ /**
15
+ * Read one numeral character.
16
+ *
17
+ * Undefined for anything that is not one, which is how a caller tells a
18
+ * numeral apart from the text around it.
19
+ */
20
+ export declare function numeralSyllable(character: string): Syllable | undefined;
21
+ /**
22
+ * `yāo`, which is how 一 is said when digits are read out one at a time.
23
+ *
24
+ * 110 is `yāo yāo líng` and 120 is `yāo èr líng`, because `yī` and `qī` are
25
+ * hard to tell apart over a bad line. It is a reading of the digit rather than
26
+ * a different digit — 一 is still written — and it belongs to phone numbers,
27
+ * room numbers and the like rather than to counting, which is why it is a
28
+ * separate reading here and an option rather than a rule.
29
+ */
30
+ export declare function yaoSyllable(): Syllable | undefined;
31
+ //# sourceMappingURL=characters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"characters.d.ts","sourceRoot":"","sources":["../../src/numerals/characters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEtE;;GAEG;AACH,eAAO,MAAM,gBAAgB,iEAAe,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAMlD,CAAC;AAyCH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAGvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,IAAI,QAAQ,GAAG,SAAS,CAElD"}
@@ -0,0 +1,80 @@
1
+ import { readSyllable } from "../syllable/syllable.js";
2
+ /**
3
+ * The 汉字 a digit is written with, indexed by its value.
4
+ */
5
+ export const DIGIT_CHARACTERS = "零一二三四五六七八九";
6
+ /**
7
+ * The other 汉字 a written number is made of, and what each is worth.
8
+ *
9
+ * 十, 百 and 千 are the places inside a group of four; 万 and 亿 are the group
10
+ * separators, which is what makes Chinese numbers myriad-grouped rather than
11
+ * thousand-grouped: 12,345 is 一万二千三百四十五, one 万 and 2,345.
12
+ */
13
+ export const UNIT_VALUES = new Map([
14
+ ["十", 10],
15
+ ["百", 100],
16
+ ["千", 1000],
17
+ ["万", 10_000],
18
+ ["亿", 100_000_000],
19
+ ]);
20
+ /**
21
+ * Every character a number can be written with, and how it is read.
22
+ *
23
+ * This is the whole of the numerals' data — twenty-odd readings, carried here
24
+ * rather than looked up, because reading a number needs no dictionary and a
25
+ * package that needed one for it would be the wrong shape. Readings are
26
+ * underlying*: 一 is `yī` and 不 would be `bù`, with the contextual tone left
27
+ * to the sandhi pass, exactly as the dictionary stores them.
28
+ */
29
+ const READINGS = new Map([
30
+ ["零", "líng"],
31
+ ["〇", "líng"],
32
+ ["一", "yī"],
33
+ ["二", "èr"],
34
+ ["两", "liǎng"],
35
+ ["兩", "liǎng"],
36
+ ["三", "sān"],
37
+ ["四", "sì"],
38
+ ["五", "wǔ"],
39
+ ["六", "liù"],
40
+ ["七", "qī"],
41
+ ["八", "bā"],
42
+ ["九", "jiǔ"],
43
+ ["十", "shí"],
44
+ ["百", "bǎi"],
45
+ ["千", "qiān"],
46
+ ["万", "wàn"],
47
+ ["萬", "wàn"],
48
+ ["亿", "yì"],
49
+ ["億", "yì"],
50
+ ["点", "diǎn"],
51
+ ["點", "diǎn"],
52
+ ["负", "fù"],
53
+ ["負", "fù"],
54
+ ["分", "fēn"],
55
+ ["之", "zhī"],
56
+ ["百分之", "bǎi fēn zhī"],
57
+ ]);
58
+ /**
59
+ * Read one numeral character.
60
+ *
61
+ * Undefined for anything that is not one, which is how a caller tells a
62
+ * numeral apart from the text around it.
63
+ */
64
+ export function numeralSyllable(character) {
65
+ const spelling = READINGS.get(character);
66
+ return spelling === undefined ? undefined : readSyllable(spelling);
67
+ }
68
+ /**
69
+ * `yāo`, which is how 一 is said when digits are read out one at a time.
70
+ *
71
+ * 110 is `yāo yāo líng` and 120 is `yāo èr líng`, because `yī` and `qī` are
72
+ * hard to tell apart over a bad line. It is a reading of the digit rather than
73
+ * a different digit — 一 is still written — and it belongs to phone numbers,
74
+ * room numbers and the like rather than to counting, which is why it is a
75
+ * separate reading here and an option rather than a rule.
76
+ */
77
+ export function yaoSyllable() {
78
+ return readSyllable("yāo");
79
+ }
80
+ //# sourceMappingURL=characters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"characters.js","sourceRoot":"","sources":["../../src/numerals/characters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAiB,MAAM,yBAAyB,CAAC;AAEtE;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAgC,IAAI,GAAG,CAAC;IAC9D,CAAC,GAAG,EAAE,EAAE,CAAC;IACT,CAAC,GAAG,EAAE,GAAG,CAAC;IACV,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,WAAW,CAAC;CACnB,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,QAAQ,GAAgC,IAAI,GAAG,CAAC;IACpD,CAAC,GAAG,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,OAAO,CAAC;IACd,CAAC,GAAG,EAAE,OAAO,CAAC;IACd,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,IAAI,CAAC;IACX,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,KAAK,EAAE,aAAa,CAAC;CACvB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzC,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,76 @@
1
+ import type { Syllable } from "../syllable/syllable.js";
2
+ import { type CardinalOptions } from "./cardinal.js";
3
+ /**
4
+ * How a number is said: as a quantity, or digit by digit.
5
+ *
6
+ * The distinction is the whole of this module's difficulty, because the *same*
7
+ * digits go both ways depending on what they are counting. 2026年 is
8
+ * `èr líng èr liù nián`, read out one digit at a time, and 2026个 is
9
+ * `liǎng qiān líng èr shí liù gè`, counted. Nothing about the number says
10
+ * which; only what follows it does, so the choice belongs to the caller and
11
+ * this module will do either.
12
+ */
13
+ export type NumeralStyle = "cardinal" | "digits";
14
+ /**
15
+ * How a number should be written and read.
16
+ */
17
+ export interface NumeralOptions extends CardinalOptions {
18
+ /** Defaults to `cardinal`. */
19
+ readonly style?: NumeralStyle;
20
+ /**
21
+ * Whether 1 is read `yāo` when the digits are read out one at a time.
22
+ *
23
+ * Off by default and meaningless outside `digits`. 110 is `yāo yāo líng` and
24
+ * a room number is said the same way, because `yī` and `qī` are hard to tell
25
+ * apart down a bad line — but 2019 is `èr líng yī jiǔ` with an ordinary `yī`,
26
+ * so this is a property of what is being said rather than of the digits.
27
+ */
28
+ readonly yao?: boolean;
29
+ /**
30
+ * Which zero the digit style writes. Defaults to 〇, as dates and years do.
31
+ */
32
+ readonly zero?: "零" | "〇";
33
+ }
34
+ /**
35
+ * Write a number in 汉字: 12345 → 一万二千三百四十五, or 一二三四五.
36
+ *
37
+ * Undefined for anything that is not a number, and for a `cardinal` whose whole
38
+ * part is too large to write — a digit string is not limited that way, since
39
+ * reading digits out needs no arithmetic at all.
40
+ *
41
+ * The fractional part is always read digit by digit whatever the style, because
42
+ * that is how it is said: 3.14 is 三点一四 and never 三点十四.
43
+ */
44
+ export declare function numeralHanzi(value: string | number, options?: NumeralOptions): string | undefined;
45
+ /**
46
+ * Read written numeral 汉字 as syllables.
47
+ *
48
+ * Undefined where the text holds anything that is not a numeral character, so a
49
+ * caller can tell "not a number" from a number that reads oddly.
50
+ */
51
+ export declare function readNumeralHanzi(hanzi: string, options?: NumeralOptions): readonly Syllable[] | undefined;
52
+ /**
53
+ * Read a number as syllables: 2019 as `èr líng yī jiǔ`, or as a quantity.
54
+ *
55
+ * The readings are *underlying*, as the dictionary's are — 一 is `yī` however
56
+ * it will be said in context — so a caller assembling a longer utterance runs
57
+ * the sandhi pass over the result and gets `yìbǎi` and `yí gè` from it. That is
58
+ * the same contract `decodeRun` has, and it is what keeps a number from having
59
+ * to know what follows it.
60
+ */
61
+ export declare function readNumeral(value: string | number, options?: NumeralOptions): readonly Syllable[] | undefined;
62
+ /**
63
+ * Write a percentage the way it is said: 95% → 百分之九十五.
64
+ *
65
+ * The order reverses — "of a hundred parts, ninety-five" — which is why this
66
+ * cannot be left to whoever writes the number and the sign separately.
67
+ */
68
+ export declare function percentHanzi(value: string | number, options?: NumeralOptions): string | undefined;
69
+ /**
70
+ * Write a fraction the way it is said: 3/4 → 四分之三.
71
+ *
72
+ * Same reversal as a percentage, of which this is the general case: the
73
+ * denominator is named first and the numerator second.
74
+ */
75
+ export declare function fractionHanzi(numerator: string | number, denominator: string | number, options?: NumeralOptions): string | undefined;
76
+ //# sourceMappingURL=numerals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numerals.d.ts","sourceRoot":"","sources":["../../src/numerals/numerals.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,eAAe,CAAC;AAOvB;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,eAAe;IACrD,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;CAC3B;AAiDD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,SAAS,CAqBpB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,SAAS,QAAQ,EAAE,GAAG,SAAS,CAajC;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,OAAO,GAAE,cAAmB,GAC3B,SAAS,QAAQ,EAAE,GAAG,SAAS,CAGjC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,SAAS,CAMpB"}
@@ -0,0 +1,119 @@
1
+ import { toCharacters } from "../script/characters.js";
2
+ import { cardinalHanzi, LARGEST_CARDINAL, } from "./cardinal.js";
3
+ import { DIGIT_CHARACTERS, numeralSyllable, yaoSyllable, } from "./characters.js";
4
+ /**
5
+ * Anything this module will read: digits, optionally signed and pointed.
6
+ */
7
+ const NUMBER = /^(?<sign>-?)(?<whole>\d+)(?:\.(?<fraction>\d+))?$/u;
8
+ /**
9
+ * Take a number apart, keeping the digits exactly as they were written.
10
+ *
11
+ * A string rather than a number is the input that carries the most: `007` and
12
+ * `7` are the same quantity and different digits, and a room number keeps its
13
+ * zeros. A `number` is stringified first, which is why a caller who cares about
14
+ * leading zeros should pass the string.
15
+ */
16
+ function parse(value) {
17
+ const found = NUMBER.exec(String(value))?.groups;
18
+ if (found === undefined) {
19
+ return undefined;
20
+ }
21
+ return {
22
+ isNegative: found["sign"] === "-",
23
+ whole: found["whole"] ?? "",
24
+ fraction: found["fraction"] ?? "",
25
+ };
26
+ }
27
+ /**
28
+ * Write digits one at a time: 2019 → 二〇一九.
29
+ */
30
+ function digitsHanzi(digits, zero) {
31
+ return toCharacters(digits)
32
+ .map((digit) => digit === "0" ? zero : (DIGIT_CHARACTERS[Number(digit)] ?? digit))
33
+ .join("");
34
+ }
35
+ /**
36
+ * Write a number in 汉字: 12345 → 一万二千三百四十五, or 一二三四五.
37
+ *
38
+ * Undefined for anything that is not a number, and for a `cardinal` whose whole
39
+ * part is too large to write — a digit string is not limited that way, since
40
+ * reading digits out needs no arithmetic at all.
41
+ *
42
+ * The fractional part is always read digit by digit whatever the style, because
43
+ * that is how it is said: 3.14 is 三点一四 and never 三点十四.
44
+ */
45
+ export function numeralHanzi(value, options = {}) {
46
+ const parsed = parse(value);
47
+ if (parsed === undefined) {
48
+ return undefined;
49
+ }
50
+ const { style = "cardinal", zero = "〇" } = options;
51
+ let whole;
52
+ if (style === "digits") {
53
+ whole = digitsHanzi(parsed.whole, zero);
54
+ }
55
+ else {
56
+ const quantity = Number(parsed.whole);
57
+ if (!Number.isSafeInteger(quantity) || quantity > LARGEST_CARDINAL) {
58
+ return undefined;
59
+ }
60
+ whole = cardinalHanzi(quantity, options);
61
+ }
62
+ const point = parsed.fraction === "" ? "" : `点${digitsHanzi(parsed.fraction, "零")}`;
63
+ return `${parsed.isNegative ? "负" : ""}${whole}${point}`;
64
+ }
65
+ /**
66
+ * Read written numeral 汉字 as syllables.
67
+ *
68
+ * Undefined where the text holds anything that is not a numeral character, so a
69
+ * caller can tell "not a number" from a number that reads oddly.
70
+ */
71
+ export function readNumeralHanzi(hanzi, options = {}) {
72
+ const isYao = options.yao ?? false;
73
+ const syllables = [];
74
+ for (const character of toCharacters(hanzi)) {
75
+ const syllable = isYao && character === "一" ? yaoSyllable() : numeralSyllable(character);
76
+ if (syllable === undefined) {
77
+ return undefined;
78
+ }
79
+ syllables.push(syllable);
80
+ }
81
+ return syllables;
82
+ }
83
+ /**
84
+ * Read a number as syllables: 2019 as `èr líng yī jiǔ`, or as a quantity.
85
+ *
86
+ * The readings are *underlying*, as the dictionary's are — 一 is `yī` however
87
+ * it will be said in context — so a caller assembling a longer utterance runs
88
+ * the sandhi pass over the result and gets `yìbǎi` and `yí gè` from it. That is
89
+ * the same contract `decodeRun` has, and it is what keeps a number from having
90
+ * to know what follows it.
91
+ */
92
+ export function readNumeral(value, options = {}) {
93
+ const hanzi = numeralHanzi(value, options);
94
+ return hanzi === undefined ? undefined : readNumeralHanzi(hanzi, options);
95
+ }
96
+ /**
97
+ * Write a percentage the way it is said: 95% → 百分之九十五.
98
+ *
99
+ * The order reverses — "of a hundred parts, ninety-five" — which is why this
100
+ * cannot be left to whoever writes the number and the sign separately.
101
+ */
102
+ export function percentHanzi(value, options = {}) {
103
+ const written = numeralHanzi(value, options);
104
+ return written === undefined ? undefined : `百分之${written}`;
105
+ }
106
+ /**
107
+ * Write a fraction the way it is said: 3/4 → 四分之三.
108
+ *
109
+ * Same reversal as a percentage, of which this is the general case: the
110
+ * denominator is named first and the numerator second.
111
+ */
112
+ export function fractionHanzi(numerator, denominator, options = {}) {
113
+ const top = numeralHanzi(numerator, options);
114
+ const bottom = numeralHanzi(denominator, options);
115
+ return top === undefined || bottom === undefined
116
+ ? undefined
117
+ : `${bottom}分之${top}`;
118
+ }
119
+ //# sourceMappingURL=numerals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numerals.js","sourceRoot":"","sources":["../../src/numerals/numerals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type SandhiOptions } from "../decode/sandhi.js";
2
+ import type { Syllable } from "../syllable/syllable.js";
3
+ import { type NumeralOptions, type NumeralStyle } from "./numerals.js";
4
+ /**
5
+ * One stretch of text that was never Han, read or left as it was.
6
+ */
7
+ export interface NumeralSegment {
8
+ /** The characters this covers, exactly as they were written. */
9
+ readonly text: string;
10
+ /** How it is said, where it was read as a number. */
11
+ readonly reading: readonly Syllable[] | undefined;
12
+ /** The 汉字 the number would be written with, where it was read. */
13
+ readonly hanzi: string | undefined;
14
+ /** How it was read, which decides whether sandhi applies to it. */
15
+ readonly style: NumeralStyle | undefined;
16
+ /**
17
+ * Where the words break, as a syllable count each.
18
+ *
19
+ * A counted number is one word and needs none of this. A time is three or
20
+ * four — 6:30 is `liù diǎn sānshí fēn`, where the hour and the minutes are
21
+ * numbers and 点 and 分 are not — and nothing in the syllables themselves
22
+ * says where those breaks are.
23
+ */
24
+ readonly words?: readonly number[];
25
+ }
26
+ /**
27
+ * Split a stretch of non-Han text into what is read and what is not.
28
+ *
29
+ * `following` is the first character of the Han that comes after this stretch,
30
+ * which is the only context a number has: 年 makes 1997 a year and 个 makes 3 a
31
+ * count. Where there is nothing after it, or nothing that decides, the number
32
+ * is counted.
33
+ *
34
+ * Text that is not a number is returned unread rather than dropped, so the
35
+ * segments always concatenate back to the input.
36
+ */
37
+ export declare function readNumbersIn(text: string, following: string, options?: NumeralOptions): readonly NumeralSegment[];
38
+ /**
39
+ * A number as it is said, with the sandhi a counted quantity takes.
40
+ *
41
+ * Two things decide how much of it assimilates. A number read out digit by
42
+ * digit does not at all — 110 is `yāo yāo líng` and never `yì yì líng` —
43
+ * and in a counted one the sandhi stops at the 点, since everything after the
44
+ * decimal point is read digit by digit whatever the style: 3.14 is
45
+ * `sān diǎn yī sì`.
46
+ *
47
+ * `following` is the syllable after the number, which is what a 一 at the end
48
+ * of it assimilates to: the 一 of 一个 is `yí` because 个 is a fourth tone, and
49
+ * that tone is in the next run rather than in the number.
50
+ */
51
+ export declare function saidNumeral(segment: NumeralSegment, following: Syllable | undefined, sandhi: SandhiOptions | undefined): readonly Syllable[];
52
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/numerals/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAEvB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC;IAClD,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;IACzC;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAsMD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,cAAmB,GAC3B,SAAS,cAAc,EAAE,CA2C3B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,QAAQ,GAAG,SAAS,EAC/B,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,SAAS,QAAQ,EAAE,CAUrB"}