@keymanapp/kmc-ldml 18.0.41-alpha → 18.0.46-alpha
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.
- package/build/src/compiler/compiler.d.ts +123 -123
- package/build/src/compiler/compiler.js +307 -310
- package/build/src/compiler/compiler.js.map +1 -1
- package/build/src/compiler/disp.d.ts +11 -11
- package/build/src/compiler/disp.js +82 -85
- package/build/src/compiler/disp.js.map +1 -1
- package/build/src/compiler/empty-compiler.d.ts +37 -37
- package/build/src/compiler/empty-compiler.js +114 -117
- package/build/src/compiler/empty-compiler.js.map +1 -1
- package/build/src/compiler/keymanweb-compiler.d.ts +13 -13
- package/build/src/compiler/keymanweb-compiler.js +95 -98
- package/build/src/compiler/keymanweb-compiler.js.map +1 -1
- package/build/src/compiler/keys.d.ts +53 -53
- package/build/src/compiler/keys.js +417 -420
- package/build/src/compiler/keys.js.map +1 -1
- package/build/src/compiler/layr.d.ts +9 -9
- package/build/src/compiler/layr.js +81 -84
- package/build/src/compiler/layr.js.map +1 -1
- package/build/src/compiler/ldml-compiler-options.d.ts +11 -11
- package/build/src/compiler/ldml-compiler-options.js +3 -6
- package/build/src/compiler/ldml-compiler-options.js.map +1 -1
- package/build/src/compiler/loca.d.ts +15 -15
- package/build/src/compiler/loca.js +59 -62
- package/build/src/compiler/loca.js.map +1 -1
- package/build/src/compiler/messages.d.ts +186 -186
- package/build/src/compiler/messages.js +122 -125
- package/build/src/compiler/messages.js.map +1 -1
- package/build/src/compiler/meta.d.ts +13 -13
- package/build/src/compiler/meta.js +55 -58
- package/build/src/compiler/meta.js.map +1 -1
- package/build/src/compiler/metadata-compiler.d.ts +12 -12
- package/build/src/compiler/metadata-compiler.js +47 -50
- package/build/src/compiler/metadata-compiler.js.map +1 -1
- package/build/src/compiler/section-compiler.d.ts +35 -35
- package/build/src/compiler/section-compiler.js +40 -43
- package/build/src/compiler/section-compiler.js.map +1 -1
- package/build/src/compiler/substitution-tracker.d.ts +47 -47
- package/build/src/compiler/substitution-tracker.js +103 -106
- package/build/src/compiler/substitution-tracker.js.map +1 -1
- package/build/src/compiler/touch-layout-compiler.d.ts +7 -7
- package/build/src/compiler/touch-layout-compiler.js +91 -94
- package/build/src/compiler/touch-layout-compiler.js.map +1 -1
- package/build/src/compiler/tran.d.ts +57 -57
- package/build/src/compiler/tran.js +388 -391
- package/build/src/compiler/tran.js.map +1 -1
- package/build/src/compiler/vars.d.ts +21 -21
- package/build/src/compiler/vars.js +234 -237
- package/build/src/compiler/vars.js.map +1 -1
- package/build/src/compiler/visual-keyboard-compiler.d.ts +8 -8
- package/build/src/compiler/visual-keyboard-compiler.js +68 -71
- package/build/src/compiler/visual-keyboard-compiler.js.map +1 -1
- package/build/src/main.d.ts +3 -3
- package/build/src/main.js +3 -6
- package/build/src/main.js.map +1 -1
- package/build/src/util/util.d.ts +49 -49
- package/build/src/util/util.js +183 -186
- package/build/src/util/util.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,391 +1,388 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
//
|
|
136
|
-
cookedFrom = sections.vars.
|
|
137
|
-
//
|
|
138
|
-
cookedFrom =
|
|
139
|
-
//
|
|
140
|
-
cookedFrom =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
*
|
|
166
|
-
* @
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
result.elements
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
constants.section.
|
|
242
|
-
constants.section.
|
|
243
|
-
constants.section.
|
|
244
|
-
constants.section.
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
;
|
|
390
|
-
//# sourceMappingURL=tran.js.map
|
|
391
|
-
//# debugId=25bcdbe4-16f8-5d94-b6ef-d181bc95feed
|
|
1
|
+
import { constants } from "@keymanapp/ldml-keyboard-constants";
|
|
2
|
+
import { KMXPlus, VariableParser, MarkerParser, util } from '@keymanapp/common-types';
|
|
3
|
+
import { SectionCompiler } from "./section-compiler.js";
|
|
4
|
+
var Bksp = KMXPlus.Bksp;
|
|
5
|
+
var Tran = KMXPlus.Tran;
|
|
6
|
+
var TranReorder = KMXPlus.TranReorder;
|
|
7
|
+
var TranTransform = KMXPlus.TranTransform;
|
|
8
|
+
import { verifyValidAndUnique } from "../util/util.js";
|
|
9
|
+
import { CompilerMessages } from "./messages.js";
|
|
10
|
+
import { SubstitutionUse } from "./substitution-tracker.js";
|
|
11
|
+
export class TransformCompiler extends SectionCompiler {
|
|
12
|
+
static validateSubstitutions(keyboard, st) {
|
|
13
|
+
keyboard?.transforms?.forEach(transforms => transforms.transformGroup.forEach(transformGroup => {
|
|
14
|
+
transformGroup.transform?.forEach(({ to, from }) => {
|
|
15
|
+
st.addSetAndStringSubtitution(SubstitutionUse.consume, from);
|
|
16
|
+
st.addSetAndStringSubtitution(SubstitutionUse.emit, to);
|
|
17
|
+
const mapFrom = VariableParser.CAPTURE_SET_REFERENCE.exec(from);
|
|
18
|
+
const mapTo = VariableParser.MAPPED_SET_REFERENCE.exec(to || '');
|
|
19
|
+
if (mapFrom) {
|
|
20
|
+
// add the 'from' as a match
|
|
21
|
+
st.set.add(SubstitutionUse.consume, [mapFrom[1]]);
|
|
22
|
+
}
|
|
23
|
+
if (mapTo) {
|
|
24
|
+
// add the 'from' as a match
|
|
25
|
+
st.set.add(SubstitutionUse.emit, [mapTo[1]]);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
transformGroup.reorder?.forEach(({ before }) => {
|
|
29
|
+
st.addStringSubstitution(SubstitutionUse.consume, before);
|
|
30
|
+
});
|
|
31
|
+
}));
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
type;
|
|
35
|
+
constructor(source, callbacks) {
|
|
36
|
+
super(source, callbacks);
|
|
37
|
+
}
|
|
38
|
+
validate() {
|
|
39
|
+
const reportMessage = this.callbacks.reportMessage.bind(this.callbacks);
|
|
40
|
+
let valid = true;
|
|
41
|
+
const transforms = this?.keyboard3?.transforms;
|
|
42
|
+
if (transforms) {
|
|
43
|
+
const types = transforms.map(({ type }) => type);
|
|
44
|
+
if (!verifyValidAndUnique(types, types => reportMessage(CompilerMessages.Error_DuplicateTransformsType({ types })), new Set(['simple', 'backspace']), types => reportMessage(CompilerMessages.Error_InvalidTransformsType({ types })))) {
|
|
45
|
+
valid = false;
|
|
46
|
+
}
|
|
47
|
+
// check for mixed groups
|
|
48
|
+
let mixed = false;
|
|
49
|
+
let empty = false;
|
|
50
|
+
transforms.forEach(({ transformGroup }) => transformGroup.forEach((transformGroup) => {
|
|
51
|
+
if (transformGroup.reorder?.length && transformGroup.transform?.length) {
|
|
52
|
+
mixed = true;
|
|
53
|
+
}
|
|
54
|
+
if (!transformGroup.reorder?.length && !transformGroup.transform?.length) {
|
|
55
|
+
empty = true;
|
|
56
|
+
}
|
|
57
|
+
}));
|
|
58
|
+
if (mixed) {
|
|
59
|
+
valid = false;
|
|
60
|
+
reportMessage(CompilerMessages.Error_MixedTransformGroup()); // report this once
|
|
61
|
+
}
|
|
62
|
+
if (empty) {
|
|
63
|
+
valid = false;
|
|
64
|
+
reportMessage(CompilerMessages.Error_EmptyTransformGroup()); // report this once
|
|
65
|
+
}
|
|
66
|
+
// TODO-LDML: linting here should check for identical from, but this involves a double-parse which is ugly
|
|
67
|
+
// TODO-LDML: unicodesets means that either we fully parse them and verify conflicting rules or the linting is imperfect
|
|
68
|
+
}
|
|
69
|
+
return valid;
|
|
70
|
+
}
|
|
71
|
+
/* c8 ignore next 4 */
|
|
72
|
+
/** allocate a new TranBase subclass */
|
|
73
|
+
newTran() {
|
|
74
|
+
throw Error(`Internal Error: newTran() not implemented`);
|
|
75
|
+
}
|
|
76
|
+
compileTransforms(sections, transforms) {
|
|
77
|
+
let result = this.newTran();
|
|
78
|
+
if (transforms?.transformGroup) {
|
|
79
|
+
for (let transformGroup of transforms.transformGroup) {
|
|
80
|
+
const tg = this.compileTransformGroup(sections, transformGroup);
|
|
81
|
+
if (!tg)
|
|
82
|
+
return null; //error
|
|
83
|
+
result.groups.push(tg);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
compileTransformGroup(sections, transformGroup) {
|
|
89
|
+
if (transformGroup.reorder.length && transformGroup.transform.length) {
|
|
90
|
+
/* c8 ignore next 2 */
|
|
91
|
+
// should have been caught by validate
|
|
92
|
+
throw Error(`Internal error: transformGroup has both reorder and transform elements.`);
|
|
93
|
+
}
|
|
94
|
+
else if (transformGroup.reorder.length) {
|
|
95
|
+
return this.compileReorderTranGroup(sections, transformGroup.reorder);
|
|
96
|
+
}
|
|
97
|
+
else if (transformGroup.transform.length) {
|
|
98
|
+
return this.compileTransformTranGroup(sections, transformGroup.transform);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
/* c8 ignore next */
|
|
102
|
+
throw Error(`Internal error: transformGroup has neither reorder nor transform elements.`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
compileTransformTranGroup(sections, transforms) {
|
|
106
|
+
const result = {
|
|
107
|
+
type: constants.tran_group_type_transform,
|
|
108
|
+
transforms: transforms.map(transform => this.compileTransform(sections, transform)),
|
|
109
|
+
reorders: [],
|
|
110
|
+
};
|
|
111
|
+
if (result.transforms.includes(null))
|
|
112
|
+
return null;
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
compileTransform(sections, transform) {
|
|
116
|
+
let result = new TranTransform();
|
|
117
|
+
let cookedFrom = transform.from;
|
|
118
|
+
// check for incorrect \uXXXX escapes. Do this before substituting markers or sets.
|
|
119
|
+
cookedFrom = this.checkEscapes(cookedFrom); // check for \uXXXX escapes before normalizing
|
|
120
|
+
cookedFrom = sections.vars.substituteStrings(cookedFrom, sections, true);
|
|
121
|
+
const mapFrom = VariableParser.CAPTURE_SET_REFERENCE.exec(cookedFrom);
|
|
122
|
+
const mapTo = VariableParser.MAPPED_SET_REFERENCE.exec(transform.to || '');
|
|
123
|
+
if (mapFrom && mapTo) { // TODO-LDML: error cases
|
|
124
|
+
result.mapFrom = sections.strs.allocString(mapFrom[1]); // var name
|
|
125
|
+
result.mapTo = sections.strs.allocString(mapTo[1]); // var name
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
result.mapFrom = sections.strs.allocString('');
|
|
129
|
+
result.mapTo = sections.strs.allocString('');
|
|
130
|
+
}
|
|
131
|
+
if (cookedFrom === null)
|
|
132
|
+
return null; // error
|
|
133
|
+
// the set substution will not produce raw markers `\m{...}` but they will already be in sentinel form.
|
|
134
|
+
cookedFrom = sections.vars.substituteSetRegex(cookedFrom, sections);
|
|
135
|
+
// add in markers. idempotent if no markers.
|
|
136
|
+
cookedFrom = sections.vars.substituteMarkerString(cookedFrom, true);
|
|
137
|
+
// unescape from \u{} form to plain, or in some cases \uXXXX / \UXXXXXXXX for core
|
|
138
|
+
cookedFrom = util.unescapeStringToRegex(cookedFrom);
|
|
139
|
+
// check for denormalized ranges
|
|
140
|
+
cookedFrom = this.checkRanges(cookedFrom); // check before normalizing
|
|
141
|
+
if (!sections?.meta?.normalizationDisabled) {
|
|
142
|
+
// nfd here.
|
|
143
|
+
cookedFrom = MarkerParser.nfd_markers(cookedFrom, true);
|
|
144
|
+
}
|
|
145
|
+
// perform regex validation
|
|
146
|
+
if (!this.isValidRegex(cookedFrom, transform.from)) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
// cookedFrom is cooked above, since there's some special treatment
|
|
150
|
+
result.from = sections.strs.allocString(cookedFrom, {
|
|
151
|
+
unescape: false,
|
|
152
|
+
}, sections);
|
|
153
|
+
// 'to' is handled via allocString
|
|
154
|
+
result.to = sections.strs.allocString(transform.to, {
|
|
155
|
+
stringVariables: true,
|
|
156
|
+
markers: true,
|
|
157
|
+
unescape: true,
|
|
158
|
+
nfd: true,
|
|
159
|
+
}, sections);
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Validate the final regex
|
|
164
|
+
* @param cookedFrom the regex to use, missing the trailing '$'
|
|
165
|
+
* @param from the original from - for error reporting
|
|
166
|
+
* @returns true if OK
|
|
167
|
+
*/
|
|
168
|
+
isValidRegex(cookedFrom, from) {
|
|
169
|
+
// check for any unescaped dollar sign here
|
|
170
|
+
if (/(?<!\\)(?:\\\\)*\$/.test(cookedFrom)) {
|
|
171
|
+
this.callbacks.reportMessage(CompilerMessages.Error_IllegalTransformDollarsign({ from }));
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
if (/(?<!\\)(?:\\\\)*\*/.test(cookedFrom)) {
|
|
175
|
+
this.callbacks.reportMessage(CompilerMessages.Error_IllegalTransformAsterisk({ from }));
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (/(?<!\\)(?:\\\\)*\+/.test(cookedFrom)) {
|
|
179
|
+
this.callbacks.reportMessage(CompilerMessages.Error_IllegalTransformPlus({ from }));
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
// Verify that the regex is syntactically valid
|
|
183
|
+
try {
|
|
184
|
+
const rg = new RegExp(cookedFrom + '$', 'ug');
|
|
185
|
+
// Tests against the regex:
|
|
186
|
+
// does it match an empty string?
|
|
187
|
+
if (rg.test('')) {
|
|
188
|
+
this.callbacks.reportMessage(CompilerMessages.Error_TransformFromMatchesNothing({ from }));
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
// We're exposing the internal regex error message here.
|
|
194
|
+
// In the future, CLDR plans to expose the EBNF for the transform,
|
|
195
|
+
// at which point we would have more precise validation prior to getting to this point.
|
|
196
|
+
this.callbacks.reportMessage(CompilerMessages.Error_UnparseableTransformFrom({ from, message: e.message }));
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
compileReorderTranGroup(sections, reorders) {
|
|
202
|
+
const result = {
|
|
203
|
+
type: constants.tran_group_type_reorder,
|
|
204
|
+
transforms: [],
|
|
205
|
+
reorders: reorders.map(reorder => this.compileReorder(sections, reorder)),
|
|
206
|
+
};
|
|
207
|
+
if (result.reorders.includes(null))
|
|
208
|
+
return null; // if any of the reorders returned null, fail the entire group.
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
compileReorder(sections, reorder) {
|
|
212
|
+
let result = new TranReorder();
|
|
213
|
+
if (reorder.from && this.checkEscapes(reorder.from) === null) {
|
|
214
|
+
return null; // error'ed
|
|
215
|
+
}
|
|
216
|
+
if (reorder.before && this.checkEscapes(reorder.before) === null) {
|
|
217
|
+
return null; // error'ed
|
|
218
|
+
}
|
|
219
|
+
result.elements = sections.elem.allocElementString(sections, reorder.from, reorder.order, reorder.tertiary, reorder.tertiaryBase, reorder.preBase);
|
|
220
|
+
result.before = sections.elem.allocElementString(sections, reorder.before);
|
|
221
|
+
if (!result.elements || !result.before) {
|
|
222
|
+
return null; // already error'ed
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
return result;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
compile(sections) {
|
|
229
|
+
for (let t of this.keyboard3.transforms) {
|
|
230
|
+
if (t.type == this.type) {
|
|
231
|
+
// compile only the transforms of the correct type
|
|
232
|
+
return this.compileTransforms(sections, t);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return this.newTran(); // empty: nothing of this type found.
|
|
236
|
+
}
|
|
237
|
+
get dependencies() {
|
|
238
|
+
const defaults = new Set([
|
|
239
|
+
constants.section.elem,
|
|
240
|
+
constants.section.list,
|
|
241
|
+
constants.section.meta,
|
|
242
|
+
constants.section.strs,
|
|
243
|
+
constants.section.uset,
|
|
244
|
+
constants.section.vars,
|
|
245
|
+
]);
|
|
246
|
+
defaults.delete(this.id);
|
|
247
|
+
return defaults;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Analyze reorders and regexes for \uXXXX escapes.
|
|
251
|
+
* The LDML spec requires \u{XXXX} format.
|
|
252
|
+
* @param cookedFrom the original string
|
|
253
|
+
* @returns the original string, or null if an error was reported
|
|
254
|
+
*/
|
|
255
|
+
checkEscapes(cookedFrom) {
|
|
256
|
+
if (!cookedFrom)
|
|
257
|
+
return cookedFrom;
|
|
258
|
+
// should not follow marker prefix, nor marker prefix with range
|
|
259
|
+
const anyQuad = /(?<!\\uffff\\u0008(?:\[[0-9a-fA-F\\u-]*)?)\\u([0-9a-fA-F]{4})/g;
|
|
260
|
+
for (const [, sub] of cookedFrom.matchAll(anyQuad)) {
|
|
261
|
+
const s = util.unescapeOne(sub);
|
|
262
|
+
if (s !== '\uffff' && s !== '\u0008') { // markers
|
|
263
|
+
this.callbacks.reportMessage(CompilerMessages.Error_InvalidQuadEscape({ cp: s.codePointAt(0) }));
|
|
264
|
+
return null; // exit on the first error
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return cookedFrom;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Analyze character classes such as '[a-z]' for denormalized characters.
|
|
271
|
+
* Escapes non-NFD characters as hex escapes.
|
|
272
|
+
* @param cookedFrom input regex string
|
|
273
|
+
* @returns updated 'from' string
|
|
274
|
+
*/
|
|
275
|
+
checkRanges(cookedFrom) {
|
|
276
|
+
if (!cookedFrom)
|
|
277
|
+
return cookedFrom;
|
|
278
|
+
// extract all of the potential ranges - but don't match any-markers!
|
|
279
|
+
const anyRange = /(?<!\\uffff\\u0008)\[([^\]]+)\]/g;
|
|
280
|
+
const ranges = cookedFrom.matchAll(anyRange);
|
|
281
|
+
if (!ranges)
|
|
282
|
+
return cookedFrom;
|
|
283
|
+
// extract inner members of a range (inside the [])
|
|
284
|
+
const rangeRegex = /(\\u\{[0-9a-fA-F]\}{1,6}|.)-(\\u\{[0-9a-fA-F]\}{1,6}|.)|./g;
|
|
285
|
+
const rangeExplicit = new util.NFDAnalyzer();
|
|
286
|
+
const rangeImplicit = new util.NFDAnalyzer();
|
|
287
|
+
/** process an explicit entry */
|
|
288
|
+
function processExplicit(s) {
|
|
289
|
+
if (s.startsWith('\\u{')) {
|
|
290
|
+
s = util.unescapeString(s);
|
|
291
|
+
}
|
|
292
|
+
rangeExplicit.add(s);
|
|
293
|
+
return s;
|
|
294
|
+
}
|
|
295
|
+
for (const [, sub] of ranges) {
|
|
296
|
+
const subRanges = sub.matchAll(rangeRegex);
|
|
297
|
+
for (const [all, start, end] of subRanges) {
|
|
298
|
+
if (!start && !end) {
|
|
299
|
+
// explicit single char
|
|
300
|
+
processExplicit(all); // matched one char
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// start-end range - get explicit start and end chars
|
|
304
|
+
const s = processExplicit(start);
|
|
305
|
+
const sch = s.codePointAt(0);
|
|
306
|
+
const e = processExplicit(end);
|
|
307
|
+
const ech = e.codePointAt(0);
|
|
308
|
+
// now, process the inner chars, not including explicit
|
|
309
|
+
for (let n = sch; n < ech; n++) {
|
|
310
|
+
// add inner text
|
|
311
|
+
rangeImplicit.add(String.fromCodePoint(n));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// analyze ranges
|
|
317
|
+
let needCooking = false;
|
|
318
|
+
const explicitSet = rangeExplicit.analyze()?.get(util.BadStringType.denormalized);
|
|
319
|
+
if (explicitSet) {
|
|
320
|
+
this.callbacks.reportMessage(CompilerMessages.Warn_CharClassExplicitDenorm({ lowestCh: explicitSet.values().next().value }));
|
|
321
|
+
needCooking = true;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
// don't analyze the implicit set of THIS range, if explicit is already problematic
|
|
325
|
+
const implicitSet = rangeImplicit.analyze()?.get(util.BadStringType.denormalized);
|
|
326
|
+
if (implicitSet) {
|
|
327
|
+
this.callbacks.reportMessage(CompilerMessages.Hint_CharClassImplicitDenorm({ lowestCh: implicitSet.values().next().value }));
|
|
328
|
+
needCooking = true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// do we need to fixup the ranges?
|
|
332
|
+
// don't do this unless we flagged issues above
|
|
333
|
+
if (needCooking) {
|
|
334
|
+
// if we get here, there are some ranges with troublesome chars.
|
|
335
|
+
// we work around this by escaping all chars
|
|
336
|
+
function cookOne(s) {
|
|
337
|
+
if (s === '^') {
|
|
338
|
+
return s; // syntax
|
|
339
|
+
}
|
|
340
|
+
else if (s.startsWith('\\u{') || s.startsWith('\\u')) {
|
|
341
|
+
return s; // already escaped
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
return util.escapeRegexChar(s);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return cookedFrom.replaceAll(anyRange, (ignored1, sub) => {
|
|
348
|
+
return '[' + sub.replaceAll(rangeRegex, (all, start, end) => {
|
|
349
|
+
if (!start && !end) {
|
|
350
|
+
// explicit single char
|
|
351
|
+
return cookOne(all); // matched one char
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
return cookOne(start) + '-' + cookOne(end);
|
|
355
|
+
}
|
|
356
|
+
}) + ']';
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return cookedFrom; // no change
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
export class TranCompiler extends TransformCompiler {
|
|
363
|
+
constructor(source, callbacks) {
|
|
364
|
+
super(source, callbacks);
|
|
365
|
+
this.type = 'simple';
|
|
366
|
+
}
|
|
367
|
+
newTran() {
|
|
368
|
+
return new Tran();
|
|
369
|
+
}
|
|
370
|
+
get id() {
|
|
371
|
+
return constants.section.tran;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
;
|
|
375
|
+
export class BkspCompiler extends TransformCompiler {
|
|
376
|
+
constructor(source, callbacks) {
|
|
377
|
+
super(source, callbacks);
|
|
378
|
+
this.type = 'backspace';
|
|
379
|
+
}
|
|
380
|
+
newTran() {
|
|
381
|
+
return new Bksp();
|
|
382
|
+
}
|
|
383
|
+
get id() {
|
|
384
|
+
return constants.section.bksp;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
;
|
|
388
|
+
//# sourceMappingURL=tran.js.map
|