@kensio/pinyinjs 1.7.14 → 1.8.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.
@@ -0,0 +1,55 @@
1
+ /**
2
+ * How the syllables group, and the two things sandhi reads out of a grouping.
3
+ *
4
+ * Third-tone sandhi wants the junctions, since its domain is the prosodic foot
5
+ * and a foot is built from structure. 一 wants the word ends, since a 一 that
6
+ * closes a longer word counts nothing after it. Both are answered here so that
7
+ * `sandhi.ts` holds the rules rather than the bookkeeping.
8
+ */
9
+ /**
10
+ * How the syllables group, for sandhi to read.
11
+ *
12
+ * One entry per word: its syllable count, or the counts of the constituents it
13
+ * divides into. 老板 很 好 is `[2, 1, 1]` and 纸老虎 is `[[1, 2]]`.
14
+ *
15
+ * Third-tone sandhi's domain is the prosodic foot rather than the word, and the
16
+ * foot is built from structure — which is why this is worth carrying. See
17
+ * {@link import("./sandhi.js").applySandhi}.
18
+ */
19
+ export type SandhiGrouping = readonly (number | readonly number[])[];
20
+ /**
21
+ * Where sandhi may apply, as the index of the syllable that would lower.
22
+ *
23
+ * Every junction is between adjacent syllables — words and their constituents
24
+ * cover the reading end to end — so one index says all of it, and the three
25
+ * lists are the three passes third-tone sandhi makes.
26
+ */
27
+ export interface SandhiJunctions {
28
+ /** Inside a constituent. */
29
+ readonly inner: readonly number[];
30
+ /** Between the constituents of a word. */
31
+ readonly parts: readonly number[];
32
+ /** Between a single-syllable word and the word after it. */
33
+ readonly words: readonly number[];
34
+ }
35
+ /**
36
+ * Read a grouping as the junctions it puts in the syllable array.
37
+ *
38
+ * The whole array is treated as one undivided word where no grouping is given,
39
+ * or where the one given does not account for exactly the syllables there are —
40
+ * a grouping that does not fit is describing some other text, and guessing
41
+ * which syllables it meant would be worse than ignoring it.
42
+ */
43
+ export declare function junctionsOf(length: number, grouping?: SandhiGrouping): SandhiJunctions;
44
+ /**
45
+ * Where a word of more than one syllable ends, as indices into the array.
46
+ *
47
+ * Empty without a grouping, and empty for a grouping that does not fit, which
48
+ * is the judgement {@link junctionsOf} makes and for the same reason.
49
+ *
50
+ * A one-syllable word is deliberately not an ending here. 一 on its own is a
51
+ * word and it counts the word after it: see
52
+ * {@link import("./sandhi.js").applySandhi}.
53
+ */
54
+ export declare function endingsOf(length: number, grouping?: SandhiGrouping): ReadonlySet<number>;
55
+ //# sourceMappingURL=sandhi-grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandhi-grouping.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi-grouping.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AASD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,cAAc,GACxB,eAAe,CAiCjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,cAAc,GACxB,WAAW,CAAC,MAAM,CAAC,CAerB"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * How the syllables group, and the two things sandhi reads out of a grouping.
3
+ *
4
+ * Third-tone sandhi wants the junctions, since its domain is the prosodic foot
5
+ * and a foot is built from structure. 一 wants the word ends, since a 一 that
6
+ * closes a longer word counts nothing after it. Both are answered here so that
7
+ * `sandhi.ts` holds the rules rather than the bookkeeping.
8
+ */
9
+ /**
10
+ * The syllable counts one grouping entry holds, as a flat list of its parts.
11
+ */
12
+ function partsOf(word) {
13
+ return typeof word === "number" ? [word] : word;
14
+ }
15
+ /**
16
+ * Read a grouping as the junctions it puts in the syllable array.
17
+ *
18
+ * The whole array is treated as one undivided word where no grouping is given,
19
+ * or where the one given does not account for exactly the syllables there are —
20
+ * a grouping that does not fit is describing some other text, and guessing
21
+ * which syllables it meant would be worse than ignoring it.
22
+ */
23
+ export function junctionsOf(length, grouping) {
24
+ const undivided = {
25
+ inner: Array.from({ length: Math.max(length - 1, 0) }, (_, at) => at),
26
+ parts: [],
27
+ words: [],
28
+ };
29
+ if (grouping === undefined) {
30
+ return undivided;
31
+ }
32
+ const inner = [];
33
+ const parts = [];
34
+ const words = [];
35
+ let at = 0;
36
+ for (const [index, word] of grouping.entries()) {
37
+ const divisions = partsOf(word);
38
+ const from = at;
39
+ for (const [division, size] of divisions.entries()) {
40
+ for (let step = 1; step < size; step++) {
41
+ inner.push(at + step - 1);
42
+ }
43
+ at += size;
44
+ // The junction closing a word's last constituent is the one *around* the
45
+ // word rather than one inside it.
46
+ if (division < divisions.length - 1) {
47
+ parts.push(at - 1);
48
+ }
49
+ }
50
+ if (at - from === 1 && index < grouping.length - 1) {
51
+ words.push(at - 1);
52
+ }
53
+ }
54
+ return at === length ? { inner, parts, words } : undivided;
55
+ }
56
+ /**
57
+ * Where a word of more than one syllable ends, as indices into the array.
58
+ *
59
+ * Empty without a grouping, and empty for a grouping that does not fit, which
60
+ * is the judgement {@link junctionsOf} makes and for the same reason.
61
+ *
62
+ * A one-syllable word is deliberately not an ending here. 一 on its own is a
63
+ * word and it counts the word after it: see
64
+ * {@link import("./sandhi.js").applySandhi}.
65
+ */
66
+ export function endingsOf(length, grouping) {
67
+ const endings = new Set();
68
+ if (grouping === undefined) {
69
+ return endings;
70
+ }
71
+ let at = 0;
72
+ for (const word of grouping) {
73
+ const size = partsOf(word).reduce((total, part) => total + part, 0);
74
+ at += size;
75
+ if (size > 1) {
76
+ endings.add(at - 1);
77
+ }
78
+ }
79
+ return at === length ? endings : new Set();
80
+ }
81
+ //# sourceMappingURL=sandhi-grouping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandhi-grouping.js","sourceRoot":"","sources":["../../src/decode/sandhi-grouping.ts"],"names":[],"mappings":"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"}
@@ -1,29 +1,34 @@
1
1
  /**
2
2
  * What the sandhi pass needs from a decoded run, beyond the syllables.
3
3
  *
4
- * Two questions sandhi cannot answer from a reading alone. Third-tone sandhi
5
- * applies inside a prosodic foot, so it has to be told where the words and
6
- * their parts are. 一 sandhi asks what stands in front of the 一, and the answer
7
- * is a character rather than a spelling. Both are things the decode knows and
8
- * the syllable array does not.
4
+ * Two questions sandhi cannot answer from a reading alone. Where the words and
5
+ * their parts are, which third-tone sandhi needs for the prosodic foot it
6
+ * applies inside and 一 needs for the word ends. And which 汉字 each syllable
7
+ * reads, which is what says a `yī` is 一 rather than 医 and what stands in front
8
+ * of it. Both are things the decode knows and the syllable array does not.
9
9
  */
10
10
  import type { Dictionary } from "../dictionary/dictionary.js";
11
11
  import type { Syllable } from "../syllable/syllable.js";
12
12
  import type { SandhiGrouping } from "./sandhi.js";
13
13
  import type { ScoredWord } from "./word.js";
14
14
  /**
15
- * Where the words and their constituents fall, for third-tone sandhi.
15
+ * Where the words and their constituents fall.
16
16
  *
17
- * Undefined unless third-tone sandhi was asked for, since dividing a word costs
18
- * dictionary lookups and nothing else reads the answer.
17
+ * One entry per word always, because 一 sandhi reads the word ends: a 一 that
18
+ * closes a longer word is not counting the word after it, so 唯一 stays `wéiyī`
19
+ * in front of anything.
20
+ *
21
+ * Where a word *divides* is only worked out for third-tone sandhi, which is the
22
+ * only pass that reads it and costs a dictionary lookup per word to answer.
19
23
  */
20
- export declare function groupingOf(dictionary: Dictionary, words: readonly ScoredWord[], readings: readonly (readonly Syllable[])[], isThirdTone: boolean): SandhiGrouping | undefined;
24
+ export declare function groupingOf(dictionary: Dictionary, words: readonly ScoredWord[], readings: readonly (readonly Syllable[])[], isThirdTone: boolean): SandhiGrouping;
21
25
  /**
22
26
  * One 汉字 per syllable, where a word offers one.
23
27
  *
24
28
  * A word whose reading is a different length from its text — 玩儿 as `wánr` —
25
29
  * has no character to give any one of its syllables, so its syllables get none
26
30
  * and the pass falls back to their spellings. See
31
+ * {@link import("./sandhi-tones.js").isYi} and
27
32
  * {@link import("./sandhi-tones.js").isCounting}.
28
33
  */
29
34
  export declare function charactersPerSyllable(words: readonly ScoredWord[], readings: readonly (readonly Syllable[])[]): readonly (string | undefined)[];
@@ -1 +1 @@
1
- {"version":3,"file":"sandhi-input.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,QAAQ,EAAE,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,EAC1C,WAAW,EAAE,OAAO,GACnB,cAAc,GAAG,SAAS,CAQ5B;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,QAAQ,EAAE,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,GACzC,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAQjC"}
1
+ {"version":3,"file":"sandhi-input.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,QAAQ,EAAE,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,EAC1C,WAAW,EAAE,OAAO,GACnB,cAAc,CAQhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,QAAQ,EAAE,SAAS,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,GACzC,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAQjC"}
@@ -1,17 +1,21 @@
1
1
  import { toCharacters } from "../script/characters.js";
2
2
  import { divisionOf } from "./constituents.js";
3
3
  /**
4
- * Where the words and their constituents fall, for third-tone sandhi.
4
+ * Where the words and their constituents fall.
5
5
  *
6
- * Undefined unless third-tone sandhi was asked for, since dividing a word costs
7
- * dictionary lookups and nothing else reads the answer.
6
+ * One entry per word always, because 一 sandhi reads the word ends: a 一 that
7
+ * closes a longer word is not counting the word after it, so 唯一 stays `wéiyī`
8
+ * in front of anything.
9
+ *
10
+ * Where a word *divides* is only worked out for third-tone sandhi, which is the
11
+ * only pass that reads it and costs a dictionary lookup per word to answer.
8
12
  */
9
13
  export function groupingOf(dictionary, words, readings, isThirdTone) {
10
- if (!isThirdTone) {
11
- return undefined;
12
- }
13
14
  return words.map((scored, index) => {
14
15
  const reading = readings[index] ?? [];
16
+ if (!isThirdTone) {
17
+ return reading.length;
18
+ }
15
19
  return divisionOf(dictionary, scored.word.text, reading) ?? reading.length;
16
20
  });
17
21
  }
@@ -21,6 +25,7 @@ export function groupingOf(dictionary, words, readings, isThirdTone) {
21
25
  * A word whose reading is a different length from its text — 玩儿 as `wánr` —
22
26
  * has no character to give any one of its syllables, so its syllables get none
23
27
  * and the pass falls back to their spellings. See
28
+ * {@link import("./sandhi-tones.js").isYi} and
24
29
  * {@link import("./sandhi-tones.js").isCounting}.
25
30
  */
26
31
  export function charactersPerSyllable(words, readings) {
@@ -1 +1 @@
1
- {"version":3,"file":"sandhi-input.js","sourceRoot":"","sources":["../../src/decode/sandhi-input.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,UAAsB,EACtB,KAA4B,EAC5B,QAA0C,EAC1C,WAAoB;IAEpB,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,OAAO,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAA4B,EAC5B,QAA0C;IAE1C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAmC,EAAE;QACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;YACnC,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,KAAK,CAAC,IAAI,CAAqB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"sandhi-input.js","sourceRoot":"","sources":["../../src/decode/sandhi-input.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CACxB,UAAsB,EACtB,KAA4B,EAC5B,QAA0C,EAC1C,WAAoB;IAEpB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,OAAO,CAAC,MAAM,CAAC;QACxB,CAAC;QACD,OAAO,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAA4B,EAC5B,QAA0C;IAE1C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAmC,EAAE;QACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;YACnC,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,KAAK,CAAC,IAAI,CAAqB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -7,13 +7,29 @@
7
7
  import { type Syllable } from "../syllable/syllable.js";
8
8
  import { type Tone } from "../tone/tone.js";
9
9
  /**
10
- * Whether a syllable is 一, which is the only thing spelled `yi` that sandhis.
10
+ * The 汉字 一.
11
11
  */
12
- export declare function isYi(syllable: Syllable): boolean;
12
+ export declare const YI_CHARACTER = "\u4E00";
13
+ /**
14
+ * The 汉字 不.
15
+ */
16
+ export declare const BU_CHARACTER = "\u4E0D";
17
+ /**
18
+ * Whether a syllable is 一.
19
+ *
20
+ * **Answered from the 汉字 where the caller has one**, and from the spelling
21
+ * where it does not, the way {@link isCounting} is. The spelling is not the
22
+ * morpheme and never was: 医, 依, 衣 and 伊 are all `yī` and none of them
23
+ * changes tone for what follows it. This rule is a fact about one character.
24
+ */
25
+ export declare function isYi(syllable: Syllable, character?: string): boolean;
13
26
  /**
14
27
  * Whether a syllable is 不.
28
+ *
29
+ * Read from the 汉字 or the spelling on the same terms as {@link isYi}, and for
30
+ * the same reason: 部, 布, 步 and 埠 are all `bù` and none of them flattens.
15
31
  */
16
- export declare function isBu(syllable: Syllable): boolean;
32
+ export declare function isBu(syllable: Syllable, character?: string): boolean;
17
33
  /**
18
34
  * The tone 一 takes before a given following tone.
19
35
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sandhi-tones.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi-tones.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAyB,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;GAEG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAK9D;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,aAAyC,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aAAsC,CAAC;AAEpE;;GAEG;AACH,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,aAS7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,2BAA2B,aAItC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB,WAAM,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,EAAE,EAAE,MAAM,EACV,UAAU,GAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAO,GAC/C,OAAO,CAwBT"}
1
+ {"version":3,"file":"sandhi-tones.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi-tones.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAyB,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,YAAY,WAAM,CAAC;AAEhC;;GAEG;AACH,eAAO,MAAM,YAAY,WAAM,CAAC;AAEhC;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAIpE;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAIpE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAK9D;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,aAAyC,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aAAsC,CAAC;AAEpE;;GAEG;AACH,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,aAS7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,2BAA2B,aAItC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB,WAAM,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,EAAE,EAAE,MAAM,EACV,UAAU,GAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAO,GAC/C,OAAO,CAwBT"}
@@ -7,16 +7,36 @@
7
7
  import { writeSyllableSpelling } from "../syllable/syllable.js";
8
8
  import { NEUTRAL_TONE } from "../tone/tone.js";
9
9
  /**
10
- * Whether a syllable is 一, which is the only thing spelled `yi` that sandhis.
10
+ * The 汉字 一.
11
11
  */
12
- export function isYi(syllable) {
13
- return syllable.initial === "" && syllable.final === "i";
12
+ export const YI_CHARACTER = "一";
13
+ /**
14
+ * The 汉字 不.
15
+ */
16
+ export const BU_CHARACTER = "不";
17
+ /**
18
+ * Whether a syllable is 一.
19
+ *
20
+ * **Answered from the 汉字 where the caller has one**, and from the spelling
21
+ * where it does not, the way {@link isCounting} is. The spelling is not the
22
+ * morpheme and never was: 医, 依, 衣 and 伊 are all `yī` and none of them
23
+ * changes tone for what follows it. This rule is a fact about one character.
24
+ */
25
+ export function isYi(syllable, character) {
26
+ return character === undefined
27
+ ? syllable.initial === "" && syllable.final === "i"
28
+ : character === YI_CHARACTER;
14
29
  }
15
30
  /**
16
31
  * Whether a syllable is 不.
32
+ *
33
+ * Read from the 汉字 or the spelling on the same terms as {@link isYi}, and for
34
+ * the same reason: 部, 布, 步 and 埠 are all `bù` and none of them flattens.
17
35
  */
18
- export function isBu(syllable) {
19
- return syllable.initial === "b" && syllable.final === "u";
36
+ export function isBu(syllable, character) {
37
+ return character === undefined
38
+ ? syllable.initial === "b" && syllable.final === "u"
39
+ : character === BU_CHARACTER;
20
40
  }
21
41
  /**
22
42
  * The tone 一 takes before a given following tone.
@@ -1 +1 @@
1
- {"version":3,"file":"sandhi-tones.js","sourceRoot":"","sources":["../../src/decode/sandhi-tones.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandhi-tones.js","sourceRoot":"","sources":["../../src/decode/sandhi-tones.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import type { Syllable } from "../syllable/syllable.js";
2
+ import { type SandhiGrouping } from "./sandhi-grouping.js";
3
+ export type { SandhiGrouping } from "./sandhi-grouping.js";
2
4
  /**
3
5
  * How much of the sandhi to apply.
4
6
  */
@@ -19,17 +21,6 @@ export interface SandhiOptions {
19
21
  */
20
22
  readonly thirdTone?: boolean;
21
23
  }
22
- /**
23
- * How the syllables group, for third-tone sandhi to read.
24
- *
25
- * One entry per word: its syllable count, or the counts of the constituents it
26
- * divides into. 老板 很 好 is `[2, 1, 1]` and 纸老虎 is `[[1, 2]]`.
27
- *
28
- * Sandhi's domain is the prosodic foot rather than the word, and the foot is
29
- * built from structure — which is why this is worth carrying. See
30
- * {@link applyThirdTone} for what is done with it.
31
- */
32
- export type SandhiGrouping = readonly (number | readonly number[])[];
33
24
  /**
34
25
  * Apply the tone sandhi that standard orthography writes.
35
26
  *
@@ -39,14 +30,24 @@ export type SandhiGrouping = readonly (number | readonly number[])[];
39
30
  * contextual tone is put back, over the whole syllable array rather than within
40
31
  * a word, which is what lets 不 in one word assimilate to a tone in the next.
41
32
  *
42
- * 不 assimilates to whatever follows it and needs nothing but the syllables.
43
- * Third-tone sandhi is not like that — its domain is the foot rather than the
44
- * syllable string — so `grouping` says where the words and their parts are.
45
- * Without one the whole array is taken for a single word, which is what a
46
- * caller holding nothing but a reading has. 一 sits between the two: the tone it
47
- * takes is settled by the syllables, and whether it takes one at all is a
48
- * question about the 汉字, so `characters` carries them where the caller has
49
- * them. See {@link isCounting}.
33
+ * A caller holding nothing but a reading can still use this, and several do:
34
+ * `pinyinjs sandhi bùshì` and the numeral reader both hand over syllables and
35
+ * nothing else. `grouping` and `characters` are what a caller that knows more
36
+ * says so with, and each one is read on its own, since a caller can have one
37
+ * and not the other.
38
+ *
39
+ * `characters` holds one 汉字 per syllable, and is what tells 一 and 不 apart
40
+ * from the syllables that merely sound like them — 医生 is `yīshēng` and 部队
41
+ * is `bùduì`. Without it the pass falls back to the spellings, which is all
42
+ * bare pinyin offers. See {@link isYi} and {@link isCounting}.
43
+ *
44
+ * `grouping` says where the words and their parts are. Third-tone sandhi needs
45
+ * it because its domain is the prosodic foot rather than the syllable string,
46
+ * and 一 needs the word ends out of it: a 一 that closes a longer word is not
47
+ * counting the word after it. Without a grouping the whole array is taken for
48
+ * a single word, which is all a bare reading says.
49
+ *
50
+ * 不 is the one rule that needs neither: it assimilates to whatever follows.
50
51
  *
51
52
  * Never operates on a string. The old project patched output text with regexes,
52
53
  * which is what made its rules order-dependent and untestable.
@@ -1 +1 @@
1
- {"version":3,"file":"sandhi.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;AA6HrE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,aAAkB,EAC3B,QAAQ,CAAC,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAC3C,SAAS,QAAQ,EAAE,CA6BrB"}
1
+ {"version":3,"file":"sandhi.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AA+DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,aAAkB,EAC3B,QAAQ,CAAC,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAC3C,SAAS,QAAQ,EAAE,CAsCrB"}
@@ -1,45 +1,5 @@
1
+ import { endingsOf, junctionsOf, } from "./sandhi-grouping.js";
1
2
  import { isBu, isCounting, isYi, yiToneBefore } from "./sandhi-tones.js";
2
- /**
3
- * Read a grouping as the junctions it puts in the syllable array.
4
- *
5
- * The whole array is treated as one undivided word where no grouping is given,
6
- * or where the one given does not account for exactly the syllables there are —
7
- * a grouping that does not fit is describing some other text, and guessing
8
- * which syllables it meant would be worse than ignoring it.
9
- */
10
- function junctionsOf(length, grouping) {
11
- const undivided = {
12
- inner: Array.from({ length: Math.max(length - 1, 0) }, (_, at) => at),
13
- parts: [],
14
- words: [],
15
- };
16
- if (grouping === undefined) {
17
- return undivided;
18
- }
19
- const inner = [];
20
- const parts = [];
21
- const words = [];
22
- let at = 0;
23
- for (const [index, word] of grouping.entries()) {
24
- const divisions = typeof word === "number" ? [word] : word;
25
- const from = at;
26
- for (const [division, size] of divisions.entries()) {
27
- for (let step = 1; step < size; step++) {
28
- inner.push(at + step - 1);
29
- }
30
- at += size;
31
- // The junction closing a word's last constituent is the one *around* the
32
- // word rather than one inside it.
33
- if (division < divisions.length - 1) {
34
- parts.push(at - 1);
35
- }
36
- }
37
- if (at - from === 1 && index < grouping.length - 1) {
38
- words.push(at - 1);
39
- }
40
- }
41
- return at === length ? { inner, parts, words } : undivided;
42
- }
43
3
  /**
44
4
  * Lower a third tone to a second where the syllable after it is a third too.
45
5
  *
@@ -103,14 +63,24 @@ function applyThirdTone(syllables, grouping) {
103
63
  * contextual tone is put back, over the whole syllable array rather than within
104
64
  * a word, which is what lets 不 in one word assimilate to a tone in the next.
105
65
  *
106
- * 不 assimilates to whatever follows it and needs nothing but the syllables.
107
- * Third-tone sandhi is not like that — its domain is the foot rather than the
108
- * syllable string — so `grouping` says where the words and their parts are.
109
- * Without one the whole array is taken for a single word, which is what a
110
- * caller holding nothing but a reading has. 一 sits between the two: the tone it
111
- * takes is settled by the syllables, and whether it takes one at all is a
112
- * question about the 汉字, so `characters` carries them where the caller has
113
- * them. See {@link isCounting}.
66
+ * A caller holding nothing but a reading can still use this, and several do:
67
+ * `pinyinjs sandhi bùshì` and the numeral reader both hand over syllables and
68
+ * nothing else. `grouping` and `characters` are what a caller that knows more
69
+ * says so with, and each one is read on its own, since a caller can have one
70
+ * and not the other.
71
+ *
72
+ * `characters` holds one 汉字 per syllable, and is what tells 一 and 不 apart
73
+ * from the syllables that merely sound like them — 医生 is `yīshēng` and 部队
74
+ * is `bùduì`. Without it the pass falls back to the spellings, which is all
75
+ * bare pinyin offers. See {@link isYi} and {@link isCounting}.
76
+ *
77
+ * `grouping` says where the words and their parts are. Third-tone sandhi needs
78
+ * it because its domain is the prosodic foot rather than the syllable string,
79
+ * and 一 needs the word ends out of it: a 一 that closes a longer word is not
80
+ * counting the word after it. Without a grouping the whole array is taken for
81
+ * a single word, which is all a bare reading says.
82
+ *
83
+ * 不 is the one rule that needs neither: it assimilates to whatever follows.
114
84
  *
115
85
  * Never operates on a string. The old project patched output text with regexes,
116
86
  * which is what made its rules order-dependent and untestable.
@@ -120,19 +90,28 @@ export function applySandhi(syllables, options = {}, grouping, characters) {
120
90
  const applied = thirdTone
121
91
  ? applyThirdTone(syllables, grouping)
122
92
  : [...syllables];
93
+ const endings = endingsOf(syllables.length, grouping);
123
94
  for (const [at, syllable] of applied.entries()) {
95
+ const character = characters?.[at];
124
96
  const following = applied[at + 1];
125
- if (yiBu && isYi(syllable) && syllable.tone === 1) {
97
+ if (yiBu && isYi(syllable, character) && syllable.tone === 1) {
126
98
  // A 一 that is not counting keeps its citation tone, so it is left
127
99
  // exactly as the dictionary stored it.
128
100
  if (isCounting(applied, at, characters)) {
129
- applied[at] = { ...syllable, tone: yiToneBefore(following?.tone) };
101
+ // A 一 closing a longer word counts nothing, because what follows it
102
+ // is outside the word: 唯一 is `wéiyī` whatever comes next, and so are
103
+ // 之一, 统一 and 星期一. The 一 of 一个 is a word of its own, which is
104
+ // why it still assimilates across the boundary.
105
+ const counted = endings.has(at) ? undefined : following;
106
+ applied[at] = { ...syllable, tone: yiToneBefore(counted?.tone) };
130
107
  }
131
108
  continue;
132
109
  }
133
110
  // 不 flattens to second tone before a fourth, and is otherwise unchanged.
111
+ // Unlike 一 it keeps assimilating at the end of a word, since what it
112
+ // negates is regularly in the next one: 决不会 is `juébú huì`.
134
113
  if (yiBu &&
135
- isBu(syllable) &&
114
+ isBu(syllable, character) &&
136
115
  syllable.tone === 4 &&
137
116
  following?.tone === 4) {
138
117
  applied[at] = { ...syllable, tone: 2 };
@@ -1 +1 @@
1
- {"version":3,"file":"sandhi.js","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandhi.js","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/pinyinjs",
3
- "version": "1.7.14",
3
+ "version": "1.8.0",
4
4
  "description": "Chinese hanzi to pinyin conversion",
5
5
  "repository": "https://github.com/KensioSoftware/pinyinjs",
6
6
  "homepage": "https://pinyinjs.dev",