pravapis 0.1.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,155 @@
1
+ import { b as CaseFormsRow, D as DirectedPairs, O as Orthography, S as StemRow, A as Alternation, R as RuleJson, F as FunctionWordRow, d as CoreData, a as ConversionResult, T as TokenExplanation } from './types-wqNurkip.js';
2
+
3
+ declare class CaseForms {
4
+ private readonly table;
5
+ private readonly dativeLocative;
6
+ constructor(table: ReadonlyMap<string, CaseFormsRow>, dativeLocative?: ReadonlySet<string>);
7
+ static fromRecord(rows: Readonly<Record<string, CaseFormsRow>>, dativeLocative?: ReadonlySet<string>): CaseForms;
8
+ has(word: string): boolean;
9
+ /** [lowercase target, reason] for `word` after `previous`, or null if not listed. */
10
+ choose(word: string, previous: string | null): [string, string] | null;
11
+ }
12
+
13
+ declare class Lexicon {
14
+ private readonly exceptions;
15
+ private readonly loanwords;
16
+ private readonly properNouns;
17
+ constructor(exceptions: DirectedPairs, loanwords: DirectedPairs, properNouns: DirectedPairs);
18
+ /** Exact-key lookup (keys are lowercase). `direction` is the target orthography. */
19
+ lookup(word: string, direction: Orthography): string | null;
20
+ lookupCi(word: string, direction: Orthography): string | null;
21
+ /** Is `word` explicitly listed as spelled the same in both orthographies? */
22
+ isIdentity(word: string): boolean;
23
+ }
24
+
25
+ type WordClass = StemRow["class"];
26
+ /** Where a known stem was found in a word, and what it licenses. Mirrors
27
+ * pravapis.lexicon.stems.StemMatch. */
28
+ interface StemMatch {
29
+ stem: string;
30
+ cls: WordClass;
31
+ alternations: readonly Alternation[];
32
+ start: number;
33
+ end: number;
34
+ target: string | null;
35
+ /** Length of the word this match was resolved against, or -1 for an anchored match
36
+ * (which is always resolved at [0, stem.length) and so never goes stale). A rule
37
+ * that changes the word's length after resolution invalidates a nonnegative one —
38
+ * see spansStill(). */
39
+ wordLen: number;
40
+ }
41
+ declare class StemIndex {
42
+ private readonly anchoredSorted;
43
+ private readonly byAnchoredStem;
44
+ private readonly maxAnchoredLen;
45
+ /** Longest first, so the leftmost-position scan in `match()` prefers the longest
46
+ * stem among several that start at the same position — the same preference
47
+ * `regex.compile("|".join(...))`'s ordered alternation gives the Python side. */
48
+ private readonly unanchoredByLenDesc;
49
+ constructor(rows: readonly StemRow[]);
50
+ static empty(): StemIndex;
51
+ get size(): number;
52
+ /** Exact membership in the sorted anchored-stem array, by binary search. */
53
+ private hasAnchored;
54
+ /** The longest anchored stem that prefixes `w`, tried longest-first so the first
55
+ * hit is already the answer — no need to scan the rest. One binary search per
56
+ * candidate length, capped at the longest stem in the inventory: at most
57
+ * `maxAnchoredLen` searches of a ~200-entry array, not a measurable cost. */
58
+ private matchAnchored;
59
+ /** The leftmost position in `w` where any unanchored stem occurs, preferring the
60
+ * longest stem at that position — mirrors `regex.Pattern.search` over an
61
+ * alternation of literals ordered longest-first. Only 8 unanchored stems exist
62
+ * today (see data/lexicon/stems/stems.tsv), so a plain nested scan costs nothing;
63
+ * this is not the array a bigger inventory would want. */
64
+ private matchUnanchored;
65
+ /** The longest known stem in `word`; anchored wins ties (an unanchored match only
66
+ * overrides when it is strictly longer) — see data/schemas/stems.schema.json,
67
+ * "Longest match wins... anchored beating unanchored on a tie". */
68
+ match(word: string): StemMatch | null;
69
+ }
70
+
71
+ interface RuleTraceEntry {
72
+ ruleId: string;
73
+ before: string;
74
+ after: string;
75
+ }
76
+ declare class RuleEngine {
77
+ private readonly rules;
78
+ private readonly byDirection;
79
+ private readonly repeatRules;
80
+ private readonly byId;
81
+ private readonly stems;
82
+ readonly includeOptional: boolean;
83
+ constructor(rules: readonly RuleJson[], stems: ReadonlyMap<Orthography, StemIndex>, includeOptional?: boolean);
84
+ withOptional(include: boolean): RuleEngine;
85
+ stemMatch(word: string, direction: Orthography): StemMatch | null;
86
+ get(ruleId: string): RuleJson | undefined;
87
+ citationFor(ruleId: string): string | null;
88
+ private firesOn;
89
+ private transform;
90
+ /** Apply every rule for `direction` and record the ones that changed the word. */
91
+ explain(word: string, direction: Orthography): RuleTraceEntry[];
92
+ apply(word: string, direction: Orthography): [string, string[]];
93
+ }
94
+
95
+ declare class FunctionWords {
96
+ readonly particlesN2t: ReadonlyMap<string, string>;
97
+ readonly particlesT2n: ReadonlyMap<string, string>;
98
+ readonly softeningPrepositions: ReadonlySet<string>;
99
+ readonly clitics: ReadonlySet<string>;
100
+ /** Longer stems must not be shadowed by a shorter one that happens to precede it in
101
+ * iteration order, so this is checked with an explicit "does any stem prefix the
102
+ * word" scan, not `Array.prototype.includes`. */
103
+ readonly stressedInitialU: readonly string[];
104
+ readonly dativeLocativePrepositions: ReadonlySet<string>;
105
+ constructor(rows: readonly FunctionWordRow[]);
106
+ static empty(): FunctionWords;
107
+ hasStressedInitialUPrefix(lowerWord: string): boolean;
108
+ }
109
+
110
+ declare class MentSuffix {
111
+ private readonly forms;
112
+ constructor(lemmas: readonly string[]);
113
+ static empty(): MentSuffix;
114
+ /** Does this word carry a -мент base, and so inherit its э? Asked of the word as it
115
+ * *arrived*, never of a partly converted one. */
116
+ applies(narkamaukaForm: string): boolean;
117
+ static toHard(word: string): string;
118
+ static toSoft(word: string): string;
119
+ }
120
+
121
+ declare class Converter {
122
+ private readonly lexicon;
123
+ private readonly engine;
124
+ private readonly caseForms;
125
+ private readonly functionWords;
126
+ private readonly mentSuffix;
127
+ private readonly cache;
128
+ private readonly citationCache;
129
+ private readonly contextSensitiveWords;
130
+ constructor(lexicon: Lexicon, engine: RuleEngine, caseForms: CaseForms, functionWords: FunctionWords, mentSuffix: MentSuffix);
131
+ /** `properNouns` defaults to empty: proper-noun lookups then simply miss the
132
+ * lexicon and fall through to the rule engine / passthrough, same as any other
133
+ * unlisted word. Pass names.json's table (see js/src/names.ts) to include it —
134
+ * loaded lazily and separately because it is one of the largest lexicon tables and
135
+ * most conversions never touch a proper noun. */
136
+ static fromCore(core: CoreData, properNouns?: CoreData["exceptions"]): Converter;
137
+ private isAmbiguous;
138
+ citationFor(ruleId: string | null): string | null;
139
+ private contextFor;
140
+ private lookupStep;
141
+ private resolve;
142
+ private resolveCached;
143
+ private nextTarget;
144
+ private resolveClitic;
145
+ private resolveHyphenated;
146
+ private cascade;
147
+ private initialU;
148
+ private withOutputSpans;
149
+ convert(text: string, direction: Orthography, unresolvedRequested?: boolean): ConversionResult;
150
+ explain(text: string, direction: Orthography): TokenExplanation[];
151
+ private explanationFor;
152
+ private tracesFor;
153
+ }
154
+
155
+ export { Converter as C };
@@ -0,0 +1,155 @@
1
+ import { b as CaseFormsRow, D as DirectedPairs, O as Orthography, S as StemRow, A as Alternation, R as RuleJson, F as FunctionWordRow, d as CoreData, a as ConversionResult, T as TokenExplanation } from './types-wqNurkip.cjs';
2
+
3
+ declare class CaseForms {
4
+ private readonly table;
5
+ private readonly dativeLocative;
6
+ constructor(table: ReadonlyMap<string, CaseFormsRow>, dativeLocative?: ReadonlySet<string>);
7
+ static fromRecord(rows: Readonly<Record<string, CaseFormsRow>>, dativeLocative?: ReadonlySet<string>): CaseForms;
8
+ has(word: string): boolean;
9
+ /** [lowercase target, reason] for `word` after `previous`, or null if not listed. */
10
+ choose(word: string, previous: string | null): [string, string] | null;
11
+ }
12
+
13
+ declare class Lexicon {
14
+ private readonly exceptions;
15
+ private readonly loanwords;
16
+ private readonly properNouns;
17
+ constructor(exceptions: DirectedPairs, loanwords: DirectedPairs, properNouns: DirectedPairs);
18
+ /** Exact-key lookup (keys are lowercase). `direction` is the target orthography. */
19
+ lookup(word: string, direction: Orthography): string | null;
20
+ lookupCi(word: string, direction: Orthography): string | null;
21
+ /** Is `word` explicitly listed as spelled the same in both orthographies? */
22
+ isIdentity(word: string): boolean;
23
+ }
24
+
25
+ type WordClass = StemRow["class"];
26
+ /** Where a known stem was found in a word, and what it licenses. Mirrors
27
+ * pravapis.lexicon.stems.StemMatch. */
28
+ interface StemMatch {
29
+ stem: string;
30
+ cls: WordClass;
31
+ alternations: readonly Alternation[];
32
+ start: number;
33
+ end: number;
34
+ target: string | null;
35
+ /** Length of the word this match was resolved against, or -1 for an anchored match
36
+ * (which is always resolved at [0, stem.length) and so never goes stale). A rule
37
+ * that changes the word's length after resolution invalidates a nonnegative one —
38
+ * see spansStill(). */
39
+ wordLen: number;
40
+ }
41
+ declare class StemIndex {
42
+ private readonly anchoredSorted;
43
+ private readonly byAnchoredStem;
44
+ private readonly maxAnchoredLen;
45
+ /** Longest first, so the leftmost-position scan in `match()` prefers the longest
46
+ * stem among several that start at the same position — the same preference
47
+ * `regex.compile("|".join(...))`'s ordered alternation gives the Python side. */
48
+ private readonly unanchoredByLenDesc;
49
+ constructor(rows: readonly StemRow[]);
50
+ static empty(): StemIndex;
51
+ get size(): number;
52
+ /** Exact membership in the sorted anchored-stem array, by binary search. */
53
+ private hasAnchored;
54
+ /** The longest anchored stem that prefixes `w`, tried longest-first so the first
55
+ * hit is already the answer — no need to scan the rest. One binary search per
56
+ * candidate length, capped at the longest stem in the inventory: at most
57
+ * `maxAnchoredLen` searches of a ~200-entry array, not a measurable cost. */
58
+ private matchAnchored;
59
+ /** The leftmost position in `w` where any unanchored stem occurs, preferring the
60
+ * longest stem at that position — mirrors `regex.Pattern.search` over an
61
+ * alternation of literals ordered longest-first. Only 8 unanchored stems exist
62
+ * today (see data/lexicon/stems/stems.tsv), so a plain nested scan costs nothing;
63
+ * this is not the array a bigger inventory would want. */
64
+ private matchUnanchored;
65
+ /** The longest known stem in `word`; anchored wins ties (an unanchored match only
66
+ * overrides when it is strictly longer) — see data/schemas/stems.schema.json,
67
+ * "Longest match wins... anchored beating unanchored on a tie". */
68
+ match(word: string): StemMatch | null;
69
+ }
70
+
71
+ interface RuleTraceEntry {
72
+ ruleId: string;
73
+ before: string;
74
+ after: string;
75
+ }
76
+ declare class RuleEngine {
77
+ private readonly rules;
78
+ private readonly byDirection;
79
+ private readonly repeatRules;
80
+ private readonly byId;
81
+ private readonly stems;
82
+ readonly includeOptional: boolean;
83
+ constructor(rules: readonly RuleJson[], stems: ReadonlyMap<Orthography, StemIndex>, includeOptional?: boolean);
84
+ withOptional(include: boolean): RuleEngine;
85
+ stemMatch(word: string, direction: Orthography): StemMatch | null;
86
+ get(ruleId: string): RuleJson | undefined;
87
+ citationFor(ruleId: string): string | null;
88
+ private firesOn;
89
+ private transform;
90
+ /** Apply every rule for `direction` and record the ones that changed the word. */
91
+ explain(word: string, direction: Orthography): RuleTraceEntry[];
92
+ apply(word: string, direction: Orthography): [string, string[]];
93
+ }
94
+
95
+ declare class FunctionWords {
96
+ readonly particlesN2t: ReadonlyMap<string, string>;
97
+ readonly particlesT2n: ReadonlyMap<string, string>;
98
+ readonly softeningPrepositions: ReadonlySet<string>;
99
+ readonly clitics: ReadonlySet<string>;
100
+ /** Longer stems must not be shadowed by a shorter one that happens to precede it in
101
+ * iteration order, so this is checked with an explicit "does any stem prefix the
102
+ * word" scan, not `Array.prototype.includes`. */
103
+ readonly stressedInitialU: readonly string[];
104
+ readonly dativeLocativePrepositions: ReadonlySet<string>;
105
+ constructor(rows: readonly FunctionWordRow[]);
106
+ static empty(): FunctionWords;
107
+ hasStressedInitialUPrefix(lowerWord: string): boolean;
108
+ }
109
+
110
+ declare class MentSuffix {
111
+ private readonly forms;
112
+ constructor(lemmas: readonly string[]);
113
+ static empty(): MentSuffix;
114
+ /** Does this word carry a -мент base, and so inherit its э? Asked of the word as it
115
+ * *arrived*, never of a partly converted one. */
116
+ applies(narkamaukaForm: string): boolean;
117
+ static toHard(word: string): string;
118
+ static toSoft(word: string): string;
119
+ }
120
+
121
+ declare class Converter {
122
+ private readonly lexicon;
123
+ private readonly engine;
124
+ private readonly caseForms;
125
+ private readonly functionWords;
126
+ private readonly mentSuffix;
127
+ private readonly cache;
128
+ private readonly citationCache;
129
+ private readonly contextSensitiveWords;
130
+ constructor(lexicon: Lexicon, engine: RuleEngine, caseForms: CaseForms, functionWords: FunctionWords, mentSuffix: MentSuffix);
131
+ /** `properNouns` defaults to empty: proper-noun lookups then simply miss the
132
+ * lexicon and fall through to the rule engine / passthrough, same as any other
133
+ * unlisted word. Pass names.json's table (see js/src/names.ts) to include it —
134
+ * loaded lazily and separately because it is one of the largest lexicon tables and
135
+ * most conversions never touch a proper noun. */
136
+ static fromCore(core: CoreData, properNouns?: CoreData["exceptions"]): Converter;
137
+ private isAmbiguous;
138
+ citationFor(ruleId: string | null): string | null;
139
+ private contextFor;
140
+ private lookupStep;
141
+ private resolve;
142
+ private resolveCached;
143
+ private nextTarget;
144
+ private resolveClitic;
145
+ private resolveHyphenated;
146
+ private cascade;
147
+ private initialU;
148
+ private withOutputSpans;
149
+ convert(text: string, direction: Orthography, unresolvedRequested?: boolean): ConversionResult;
150
+ explain(text: string, direction: Orthography): TokenExplanation[];
151
+ private explanationFor;
152
+ private tracesFor;
153
+ }
154
+
155
+ export { Converter as C };