@kensio/pinyinjs 1.7.12 → 1.7.14

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.
@@ -1 +1 @@
1
- {"version":3,"file":"apostrophe.d.ts","sourceRoot":"","sources":["../../src/orthography/apostrophe.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAyB9D;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,GAAE,eAA0B,GAChC,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,GAAE,eAA0B,GAChC,SAAS,MAAM,EAAE,CAcnB"}
1
+ {"version":3,"file":"apostrophe.d.ts","sourceRoot":"","sources":["../../src/orthography/apostrophe.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAgC9D;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,GAAE,eAA0B,GAChC,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,GAAE,eAA0B,GAChC,SAAS,MAAM,EAAE,CAcnB"}
@@ -1,3 +1,4 @@
1
+ import { stripToneMarks } from "../tone/tone-mark.js";
1
2
  import { isSeparableStart } from "../syllable/separation.js";
2
3
  import { splitSyllables } from "../syllable/split.js";
3
4
  /**
@@ -10,14 +11,21 @@ const APOSTROPHE = "'";
10
11
  * apostrophes.
11
12
  *
12
13
  * Asked of the reader rather than of a rule, by putting the question to the
13
- * same splitter that parses input: `hǎiōu` comes apart as `hǎi` + `ōu` and so
14
- * needs nothing, where `Xīān` reads as the single syllable `xian` and does.
14
+ * same splitter that parses input: `haiou` comes apart as `hai` + `ou` and so
15
+ * needs nothing, where `Xian` reads as the single syllable `xian` and does.
15
16
  * A word the splitter cannot read at all counts as ambiguous.
17
+ *
18
+ * Asked of the letters, with the tone marks stripped off first. The splitter
19
+ * reads a mark as evidence of where a syllable ends, which would answer that
20
+ * `Xīān` is clear enough and leave 西安 without its 隔音符号. The apostrophe is
21
+ * there for the letters, and a text that writes no tones at all needs it just
22
+ * the same.
16
23
  */
17
24
  function isUnambiguous(syllables) {
18
- const split = splitSyllables(syllables.join(""));
19
- return (split?.length === syllables.length &&
20
- split.every((read, at) => read === syllables[at]));
25
+ const toneless = syllables.map((syllable) => stripToneMarks(syllable));
26
+ const split = splitSyllables(toneless.join(""));
27
+ return (split?.length === toneless.length &&
28
+ split.every((read, at) => read === toneless[at]));
21
29
  }
22
30
  /**
23
31
  * Join a word's syllables, writing the 隔音符号 where the orthography wants it.
@@ -1 +1 @@
1
- {"version":3,"file":"apostrophe.js","sourceRoot":"","sources":["../../src/orthography/apostrophe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAYtD;;;GAGG;AACH,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB;;;;;;;;GAQG;AACH,SAAS,aAAa,CAAC,SAA4B;IACjD,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,CACL,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC,MAAM;QAClC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC,CAAC,CAClD,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CACtB,SAA4B,EAC5B,KAAK,GAAoB,QAAQ;IAEjC,OAAO,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CACtB,SAA4B,EAC5B,KAAK,GAAoB,QAAQ;IAEjC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAC5C,EAAE,GAAG,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAClC,CAAC,CAAC,GAAG,UAAU,GAAG,QAAQ,EAAE;QAC5B,CAAC,CAAC,QAAQ,CACb,CAAC;IAEF,IACE,KAAK,KAAK,OAAO;QACjB,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EACpD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,KAAK,UAAU,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/E,CAAC"}
1
+ {"version":3,"file":"apostrophe.js","sourceRoot":"","sources":["../../src/orthography/apostrophe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAYtD;;;GAGG;AACH,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB;;;;;;;;;;;;;;GAcG;AACH,SAAS,aAAa,CAAC,SAA4B;IACjD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvE,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,OAAO,CACL,KAAK,EAAE,MAAM,KAAK,QAAQ,CAAC,MAAM;QACjC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC,CAAC,CACjD,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CACtB,SAA4B,EAC5B,KAAK,GAAoB,QAAQ;IAEjC,OAAO,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CACtB,SAA4B,EAC5B,KAAK,GAAoB,QAAQ;IAEjC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAC5C,EAAE,GAAG,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAClC,CAAC,CAAC,GAAG,UAAU,GAAG,QAAQ,EAAE;QAC5B,CAAC,CAAC,QAAQ,CACb,CAAC;IAEF,IACE,KAAK,KAAK,OAAO;QACjB,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EACpD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,KAAK,UAAU,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { type Syllable } from "./syllable.js";
2
+ /**
3
+ * How long a written syllable can be, and so how far ahead a reading looks.
4
+ *
5
+ * The longest spelling in the inventory is `zhuang` at six letters, and the
6
+ * rest is what hangs off one: the r of 儿化, a tone digit or the raised form of
7
+ * it, `u:` where ü is typed that way, and a combining mark where the input
8
+ * arrives decomposed. Two of those cannot both be there, which leaves the
9
+ * longest piece worth reading two characters short of this.
10
+ */
11
+ export declare const LONGEST_SYLLABLE: number;
12
+ /**
13
+ * What the two passes over a run share.
14
+ *
15
+ * Both try the same pieces, and reading one costs a Unicode normalisation and
16
+ * a walk through the tables, so each piece is read once and remembered.
17
+ * `marksBefore` counts the tone marks in front of every position, which turns
18
+ * counting the marks on a piece into a subtraction, and `isSeparableAt` says
19
+ * of every position whether a syllable starting there would need an apostrophe
20
+ * before it.
21
+ */
22
+ export interface RunTables {
23
+ readonly marksBefore: readonly number[];
24
+ readonly isSeparableAt: readonly boolean[];
25
+ readonly syllables: Map<string, Syllable | undefined>;
26
+ readonly wellMarked: Map<string, boolean>;
27
+ readonly attested: Map<string, boolean>;
28
+ }
29
+ /**
30
+ * The tables for one run, read off its characters in a single pass.
31
+ */
32
+ export declare function tablesFor(run: string): RunTables;
33
+ /**
34
+ * Read a piece of the run as a syllable, remembering what it read.
35
+ */
36
+ export declare function readPiece(tables: RunTables, piece: string): Syllable | undefined;
37
+ /**
38
+ * Whether a piece is a syllable of the language, remembering the answer.
39
+ */
40
+ export declare function isPieceAttested(tables: RunTables, piece: string, syllable: Syllable): boolean;
41
+ /**
42
+ * Whether a piece writes its tone mark in place, remembering the answer.
43
+ */
44
+ export declare function isPieceWellMarked(tables: RunTables, piece: string, syllable: Syllable): boolean;
45
+ //# sourceMappingURL=run-tables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-tables.d.ts","sourceRoot":"","sources":["../../src/syllable/run-tables.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,QAAQ,EAGd,MAAM,eAAe,CAAC;AAEvB;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QACgD,CAAC;AAiC9E;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,SAAS,OAAO,EAAE,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;IACtD,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAiBhD;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,GACZ,QAAQ,GAAG,SAAS,CAQtB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAQT;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAQT"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * What one run's search reads once and then remembers.
3
+ *
4
+ * The questions `segment-run.ts` asks of a candidate piece, and how long a
5
+ * piece can be worth asking about at all.
6
+ */
7
+ import { countToneMarks } from "../tone/tone-mark.js";
8
+ import { ATTESTED_SYLLABLES, DICTIONARY_SYLLABLES } from "./inventory.js";
9
+ import { isSeparableStart } from "./separation.js";
10
+ import { normaliseUmlaut, readSyllable, writeSyllable, writeSyllableSpelling, } from "./syllable.js";
11
+ /**
12
+ * How long a written syllable can be, and so how far ahead a reading looks.
13
+ *
14
+ * The longest spelling in the inventory is `zhuang` at six letters, and the
15
+ * rest is what hangs off one: the r of 儿化, a tone digit or the raised form of
16
+ * it, `u:` where ü is typed that way, and a combining mark where the input
17
+ * arrives decomposed. Two of those cannot both be there, which leaves the
18
+ * longest piece worth reading two characters short of this.
19
+ */
20
+ export const LONGEST_SYLLABLE = Math.max(...[...ATTESTED_SYLLABLES].map((spelling) => spelling.length)) + 4;
21
+ /**
22
+ * Whether a syllable is one Mandarin actually uses.
23
+ *
24
+ * {@link readSyllable} asks only whether an initial and a final can be put
25
+ * together, which is a wider question: `tia` passes it and is not a syllable of
26
+ * the language. The 儿化 suffix is set aside before the check, since the
27
+ * inventory lists base syllables and `wanr` is `wan` with an r on it.
28
+ */
29
+ function isAttestedSyllable(syllable) {
30
+ return DICTIONARY_SYLLABLES.has(writeSyllableSpelling({ ...syllable, erhua: false }));
31
+ }
32
+ /**
33
+ * Whether a spelling writes its tone mark where the orthography puts it.
34
+ *
35
+ * `xīa` reads as x + ia in the first tone, which pinyin writes `xiā`, so the
36
+ * mark sits a letter early. Read on its own that is a slip worth tolerating,
37
+ * and {@link readSyllable} tolerates it. Inside a longer run it is also what
38
+ * two syllables written without a boundary look like, `xīan1` being 西安 half
39
+ * typed, and the search weighs the two readings by what they cost.
40
+ */
41
+ function isWellMarked(spelling, syllable) {
42
+ return (countToneMarks(spelling) === 0 ||
43
+ writeSyllable(syllable) ===
44
+ normaliseUmlaut(spelling).normalize("NFC").toLowerCase());
45
+ }
46
+ /**
47
+ * The tables for one run, read off its characters in a single pass.
48
+ */
49
+ export function tablesFor(run) {
50
+ const marksBefore = [0];
51
+ const isSeparableAt = [];
52
+ let marks = 0;
53
+ for (let at = 0; at < run.length; at++) {
54
+ const character = run.charAt(at);
55
+ marks += countToneMarks(character);
56
+ marksBefore.push(marks);
57
+ isSeparableAt.push(isSeparableStart(character));
58
+ }
59
+ return {
60
+ marksBefore,
61
+ isSeparableAt,
62
+ syllables: new Map(),
63
+ wellMarked: new Map(),
64
+ attested: new Map(),
65
+ };
66
+ }
67
+ /**
68
+ * Read a piece of the run as a syllable, remembering what it read.
69
+ */
70
+ export function readPiece(tables, piece) {
71
+ const read = tables.syllables.get(piece);
72
+ if (read !== undefined || tables.syllables.has(piece)) {
73
+ return read;
74
+ }
75
+ const syllable = readSyllable(piece);
76
+ tables.syllables.set(piece, syllable);
77
+ return syllable;
78
+ }
79
+ /**
80
+ * Whether a piece is a syllable of the language, remembering the answer.
81
+ */
82
+ export function isPieceAttested(tables, piece, syllable) {
83
+ const known = tables.attested.get(piece);
84
+ if (known !== undefined) {
85
+ return known;
86
+ }
87
+ const attested = isAttestedSyllable(syllable);
88
+ tables.attested.set(piece, attested);
89
+ return attested;
90
+ }
91
+ /**
92
+ * Whether a piece writes its tone mark in place, remembering the answer.
93
+ */
94
+ export function isPieceWellMarked(tables, piece, syllable) {
95
+ const known = tables.wellMarked.get(piece);
96
+ if (known !== undefined) {
97
+ return known;
98
+ }
99
+ const wellMarked = isWellMarked(piece, syllable);
100
+ tables.wellMarked.set(piece, wellMarked);
101
+ return wellMarked;
102
+ }
103
+ //# sourceMappingURL=run-tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-tables.js","sourceRoot":"","sources":["../../src/syllable/run-tables.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Segment a run, honouring the apostrophe rule where it can be honoured.
3
+ *
4
+ * The separated reading wins every tie, so the rule holds wherever it can. It
5
+ * gives way only to a cheaper reading, which is a reading leaving fewer tone
6
+ * marks out of place: `xīan1` reads as `xīa` + `n1` under the rule, and as `xī`
7
+ * + `an1` without it, and the mark on `xī` is what says the second is meant.
8
+ */
9
+ export declare function segmentRun(run: string): readonly string[] | undefined;
10
+ //# sourceMappingURL=segment-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segment-run.d.ts","sourceRoot":"","sources":["../../src/syllable/segment-run.ts"],"names":[],"mappings":"AAoIA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAgBrE"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Reading a run of pinyin with no boundaries written in it.
3
+ *
4
+ * `split.ts` deals with the boundaries a word does write, the apostrophes and
5
+ * the hyphens, and hands each run between them here. What happens here is a
6
+ * search: every way of cutting the run into syllables, scored, with the
7
+ * cheapest kept. This is the syllables inside one word, and not
8
+ * `decode/segment.ts`, which is the words inside a text.
9
+ */
10
+ import { isPieceAttested, isPieceWellMarked, LONGEST_SYLLABLE, readPiece, tablesFor, } from "./run-tables.js";
11
+ /**
12
+ * Read a run of pinyin with no explicit boundaries as syllables, as cheaply as
13
+ * it can be read.
14
+ *
15
+ * Works longest-first, which is what the orthography assumes: an apostrophe is
16
+ * required exactly where the longest-first reading would be wrong, so `xian` is
17
+ * one syllable and 西安 must be written `Xī'ān` to be read as two. Cost breaks
18
+ * that habit only where a tone mark says the boundary lies elsewhere, and ties
19
+ * go to the longer piece, so a run with every mark in place reads as it always
20
+ * did.
21
+ *
22
+ * `isSeparated` carries the other half of the apostrophe rule. Longest-first
23
+ * alone reads `guórén` as `guór'én` and `huángěi` as `huáng'ěi`, both of which
24
+ * the missing apostrophe rules out — so a run is first read with a/o/e barred
25
+ * from starting any syllable but the first, and only falls back to plain
26
+ * longest-first where that finds nothing or costs more. The fallback is what
27
+ * keeps input tolerant: `hǎiōu` is written wrong, and still reads as two
28
+ * syllables.
29
+ *
30
+ * The separated pass also holds out for real syllables rather than merely
31
+ * well-formed ones, because barring a vowel otherwise pushes it into nonsense:
32
+ * `Tiānānmén` would come apart as `tiā nān mén` where `tiā` is not a syllable
33
+ * of the language at all.
34
+ *
35
+ * Read back to front, one suffix at a time, since without that a long run of
36
+ * ambiguous syllables would backtrack exponentially.
37
+ *
38
+ * Reports whether either of the separated pass's own rules ever ruled a piece
39
+ * out, which is what tells {@link segmentRun} that the fallback has nothing
40
+ * new to find.
41
+ */
42
+ function readRun(run, tables, isSeparated) {
43
+ const readings = Array.from({
44
+ length: run.length + 1,
45
+ });
46
+ readings[run.length] = { syllables: [], cost: 0 };
47
+ let wasConstrained = false;
48
+ for (let at = run.length - 1; at >= 0; at--) {
49
+ let best;
50
+ const furthest = Math.min(run.length, at + LONGEST_SYLLABLE);
51
+ for (let end = furthest; end > at; end--) {
52
+ const rest = readings[end];
53
+ if (rest === undefined) {
54
+ continue;
55
+ }
56
+ // A piece costs a point at least, so a candidate that cannot come in
57
+ // under the best reading so far is not worth reading at all. Ties are
58
+ // pruned with the rest, which is what leaves them to the longer piece.
59
+ if (best !== undefined && rest.cost + 1 >= best.cost) {
60
+ continue;
61
+ }
62
+ // A syllable is written with one tone, so a second mark is a second
63
+ // syllable: `dìèr` is 第二 with the apostrophe left out.
64
+ /* c8 ignore next 2 -- unreachable: both indices are inside the run */
65
+ const marks = (tables.marksBefore[end] ?? 0) - (tables.marksBefore[at] ?? 0);
66
+ if (marks > 1) {
67
+ continue;
68
+ }
69
+ if (isSeparated && tables.isSeparableAt[end] === true) {
70
+ wasConstrained = true;
71
+ continue;
72
+ }
73
+ const piece = run.slice(at, end);
74
+ const syllable = readPiece(tables, piece);
75
+ if (syllable === undefined) {
76
+ continue;
77
+ }
78
+ if (isSeparated && !isPieceAttested(tables, piece, syllable)) {
79
+ wasConstrained = true;
80
+ continue;
81
+ }
82
+ const cost = rest.cost +
83
+ (marks === 0 || isPieceWellMarked(tables, piece, syllable) ? 1 : 2);
84
+ if (best === undefined || cost < best.cost) {
85
+ best = { syllables: [piece, ...rest.syllables], cost };
86
+ }
87
+ }
88
+ readings[at] = best;
89
+ }
90
+ return { reading: readings[0], wasConstrained };
91
+ }
92
+ /**
93
+ * Segment a run, honouring the apostrophe rule where it can be honoured.
94
+ *
95
+ * The separated reading wins every tie, so the rule holds wherever it can. It
96
+ * gives way only to a cheaper reading, which is a reading leaving fewer tone
97
+ * marks out of place: `xīan1` reads as `xīa` + `n1` under the rule, and as `xī`
98
+ * + `an1` without it, and the mark on `xī` is what says the second is meant.
99
+ */
100
+ export function segmentRun(run) {
101
+ const tables = tablesFor(run);
102
+ const separated = readRun(run, tables, true);
103
+ // Where neither of the separated pass's rules ever ruled a piece out, the two
104
+ // passes were choosing between the same readings and reached the same one.
105
+ if (separated.reading !== undefined && !separated.wasConstrained) {
106
+ return separated.reading.syllables;
107
+ }
108
+ const loose = readRun(run, tables, false).reading;
109
+ if (separated.reading === undefined) {
110
+ return loose?.syllables;
111
+ }
112
+ return loose !== undefined && loose.cost < separated.reading.cost
113
+ ? loose.syllables
114
+ : separated.reading.syllables;
115
+ }
116
+ //# sourceMappingURL=segment-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segment-run.js","sourceRoot":"","sources":["../../src/syllable/segment-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EAET,SAAS,GACV,MAAM,iBAAiB,CAAC;AA0BzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,SAAS,OAAO,CACd,GAAW,EACX,MAAiB,EACjB,WAAoB;IAEpB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAA2B;QACpD,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC;KACvB,CAAC,CAAC;IACH,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAClD,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,KAAK,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC;QAC5C,IAAI,IAA8B,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,gBAAgB,CAAC,CAAC;QAC7D,KAAK,IAAI,GAAG,GAAG,QAAQ,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,SAAS;YACX,CAAC;YACD,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACrD,SAAS;YACX,CAAC;YACD,oEAAoE;YACpE,uDAAuD;YACvD,sEAAsE;YACtE,MAAM,KAAK,GACT,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACjE,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,SAAS;YACX,CAAC;YACD,IAAI,WAAW,IAAI,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;gBACtD,cAAc,GAAG,IAAI,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACjC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,SAAS;YACX,CAAC;YACD,IAAI,WAAW,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC7D,cAAc,GAAG,IAAI,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GACR,IAAI,CAAC,IAAI;gBACT,CAAC,KAAK,KAAK,CAAC,IAAI,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC3C,IAAI,GAAG,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;YACzD,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7C,8EAA8E;IAC9E,2EAA2E;IAC3E,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;QACjE,OAAO,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC;IAClD,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,KAAK,EAAE,SAAS,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI;QAC/D,CAAC,CAAC,KAAK,CAAC,SAAS;QACjB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;AAClC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../src/syllable/split.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,QAAQ,EAEd,MAAM,eAAe,CAAC;AA2FvB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAe1E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,GAAG,SAAS,CAgBtE"}
1
+ {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../src/syllable/split.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAU5D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAe1E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,GAAG,SAAS,CAgBtE"}
@@ -1,6 +1,5 @@
1
- import { DICTIONARY_SYLLABLES } from "./inventory.js";
2
- import { isSeparableStart } from "./separation.js";
3
- import { isSyllable, readSyllable, writeSyllableSpelling, } from "./syllable.js";
1
+ import { segmentRun } from "./segment-run.js";
2
+ import { readSyllable } from "./syllable.js";
4
3
  /**
5
4
  * Characters that mark a syllable boundary explicitly.
6
5
  *
@@ -8,74 +7,6 @@ import { isSyllable, readSyllable, writeSyllableSpelling, } from "./syllable.js"
8
7
  * reduplicated word or a 成语 written 2+2.
9
8
  */
10
9
  const SYLLABLE_SEPARATORS = /['’‘-]/u;
11
- /**
12
- * Whether a spelling is a syllable Mandarin actually uses.
13
- *
14
- * {@link isSyllable} asks only whether an initial and a final can be put
15
- * together, which is a wider question: `tia` passes it and is not a syllable of
16
- * the language. The 儿化 suffix is set aside before the check, since the
17
- * inventory lists base syllables and `wanr` is `wan` with an r on it.
18
- */
19
- function isAttestedSyllable(text) {
20
- const syllable = readSyllable(text);
21
- return (syllable !== undefined &&
22
- DICTIONARY_SYLLABLES.has(writeSyllableSpelling({ ...syllable, erhua: false })));
23
- }
24
- /**
25
- * Split a run of pinyin with no explicit boundaries into syllables.
26
- *
27
- * Works longest-first, which is what the orthography assumes: an apostrophe is
28
- * required exactly where the longest-first reading would be wrong, so `xian` is
29
- * one syllable and 西安 must be written `Xī'ān` to be read as two.
30
- *
31
- * `isSeparated` carries the other half of that rule. Longest-first alone reads
32
- * `guórén` as `guór'én` and `huángěi` as `huáng'ěi`, both of which the missing
33
- * apostrophe rules out — so a run is first segmented with a/o/e barred from
34
- * starting any syllable but the first, and only falls back to plain
35
- * longest-first when that finds nothing. The fallback is what keeps input
36
- * tolerant: `hǎiōu` is written wrong, and still reads as two syllables.
37
- *
38
- * The strict pass also holds out for real syllables rather than merely
39
- * well-formed ones, because barring a vowel otherwise pushes it into nonsense:
40
- * `Tiānānmén` would come apart as `tiā nān mén` where `tiā` is not a syllable
41
- * of the language at all.
42
- *
43
- * Memoised on the suffix being segmented, since without it a long run of
44
- * ambiguous syllables would backtrack exponentially.
45
- */
46
- function segmentRun(run, memo, isSeparated) {
47
- if (run === "") {
48
- return [];
49
- }
50
- const cached = memo.get(run);
51
- if (cached !== undefined || memo.has(run)) {
52
- return cached;
53
- }
54
- let found;
55
- for (let length = run.length; length >= 1; length--) {
56
- const head = run.slice(0, length);
57
- if (isSeparated ? !isAttestedSyllable(head) : !isSyllable(head)) {
58
- continue;
59
- }
60
- const tail = run.slice(length);
61
- if (isSeparated && isSeparableStart(tail)) {
62
- continue;
63
- }
64
- const rest = segmentRun(tail, memo, isSeparated);
65
- if (rest !== undefined) {
66
- found = [head, ...rest];
67
- break;
68
- }
69
- }
70
- memo.set(run, found);
71
- return found;
72
- }
73
- /**
74
- * Segment a run, honouring the apostrophe rule where it can be honoured.
75
- */
76
- function segment(run) {
77
- return segmentRun(run, new Map(), true) ?? segmentRun(run, new Map(), false);
78
- }
79
10
  /**
80
11
  * Split a written pinyin word into its syllables.
81
12
  *
@@ -89,7 +20,7 @@ export function splitSyllables(word) {
89
20
  if (run === "") {
90
21
  continue;
91
22
  }
92
- const segmented = segment(run);
23
+ const segmented = segmentRun(run);
93
24
  if (segmented === undefined) {
94
25
  return undefined;
95
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"split.js","sourceRoot":"","sources":["../../src/syllable/split.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"split.js","sourceRoot":"","sources":["../../src/syllable/split.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACxC,0EAA0E;QAC1E,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -15,6 +15,14 @@ export declare function toneDiacritic(tone: Tone): string;
15
15
  * The diaeresis of ü is preserved, so ǚ becomes ü rather than u.
16
16
  */
17
17
  export declare function stripToneMarks(text: string): string;
18
+ /**
19
+ * How many tone diacritics a text carries.
20
+ *
21
+ * A syllable is written with one tone, so a second mark on a run of letters is
22
+ * a second syllable inside it: `dìèr` is 第二 with the apostrophe left out
23
+ * rather than any syllable of the language.
24
+ */
25
+ export declare function countToneMarks(text: string): number;
18
26
  /**
19
27
  * How each tone is written raised.
20
28
  *
@@ -1 +1 @@
1
- {"version":3,"file":"tone-mark.d.ts","sourceRoot":"","sources":["../../src/tone/tone-mark.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AA2CpD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,IAAI,EAAE,MAAM,CAMtD,CAAC;AAiBH;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAQ5D;AA8BD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,GAAG,SAAS,GACrB,MAAM,CAoBR"}
1
+ {"version":3,"file":"tone-mark.d.ts","sourceRoot":"","sources":["../../src/tone/tone-mark.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AA2CpD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,IAAI,EAAE,MAAM,CAMtD,CAAC;AAiBH;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAQ5D;AA8BD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,GAAG,SAAS,GACrB,MAAM,CAoBR"}
@@ -58,6 +58,16 @@ export function stripToneMarks(text) {
58
58
  .replaceAll(toneDiacriticPattern, "")
59
59
  .normalize("NFC");
60
60
  }
61
+ /**
62
+ * How many tone diacritics a text carries.
63
+ *
64
+ * A syllable is written with one tone, so a second mark on a run of letters is
65
+ * a second syllable inside it: `dìèr` is 第二 with the apostrophe left out
66
+ * rather than any syllable of the language.
67
+ */
68
+ export function countToneMarks(text) {
69
+ return text.normalize("NFD").match(toneDiacriticPattern)?.length ?? 0;
70
+ }
61
71
  /**
62
72
  * How each tone is written raised.
63
73
  *
@@ -1 +1 @@
1
- {"version":3,"file":"tone-mark.js","sourceRoot":"","sources":["../../src/tone/tone-mark.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tone-mark.js","sourceRoot":"","sources":["../../src/tone/tone-mark.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.12",
3
+ "version": "1.7.14",
4
4
  "description": "Chinese hanzi to pinyin conversion",
5
5
  "repository": "https://github.com/KensioSoftware/pinyinjs",
6
6
  "homepage": "https://pinyinjs.dev",
@@ -69,7 +69,7 @@
69
69
  "conventional-changelog-conventionalcommits": "9.3.1",
70
70
  "fta-cli": "^3.0.0",
71
71
  "jiti": "^2.7.0",
72
- "oxfmt": "^0.64.0",
72
+ "oxfmt": "^0.66.0",
73
73
  "oxlint": "^1.77.0",
74
74
  "oxlint-tsgolint": "^7.0.2001",
75
75
  "semantic-release": "25.0.9",