@keymanapp/kmc-kmn 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 +181 -181
- package/build/src/compiler/compiler.js +493 -496
- package/build/src/compiler/compiler.js.map +1 -1
- package/build/src/compiler/kmn-compiler-messages.d.ts +458 -458
- package/build/src/compiler/kmn-compiler-messages.d.ts.map +1 -1
- package/build/src/compiler/kmn-compiler-messages.js +459 -462
- package/build/src/compiler/kmn-compiler-messages.js.map +1 -1
- package/build/src/compiler/osk.d.ts +31 -31
- package/build/src/compiler/osk.js +84 -87
- package/build/src/compiler/osk.js.map +1 -1
- package/build/src/import/kmcmplib/wasm-host.d.ts +2 -2
- package/build/src/import/kmcmplib/wasm-host.js +3262 -3265
- package/build/src/import/kmcmplib/wasm-host.js.map +1 -1
- package/build/src/import/kmcmplib/wasm-host.wasm +0 -0
- package/build/src/kmw-compiler/compiler-globals.d.ts +19 -19
- package/build/src/kmw-compiler/compiler-globals.js +38 -41
- package/build/src/kmw-compiler/compiler-globals.js.map +1 -1
- package/build/src/kmw-compiler/constants.d.ts +16 -16
- package/build/src/kmw-compiler/constants.js +79 -82
- package/build/src/kmw-compiler/constants.js.map +1 -1
- package/build/src/kmw-compiler/javascript-strings.d.ts +32 -32
- package/build/src/kmw-compiler/javascript-strings.js +852 -855
- package/build/src/kmw-compiler/javascript-strings.js.map +1 -1
- package/build/src/kmw-compiler/keymanweb-key-codes.d.ts +22 -22
- package/build/src/kmw-compiler/keymanweb-key-codes.js +819 -822
- package/build/src/kmw-compiler/keymanweb-key-codes.js.map +1 -1
- package/build/src/kmw-compiler/kmw-compiler-messages.d.ts +30 -30
- package/build/src/kmw-compiler/kmw-compiler-messages.js +40 -43
- package/build/src/kmw-compiler/kmw-compiler-messages.js.map +1 -1
- package/build/src/kmw-compiler/kmw-compiler.d.ts +13 -13
- package/build/src/kmw-compiler/kmw-compiler.js +547 -550
- package/build/src/kmw-compiler/kmw-compiler.js.map +1 -1
- package/build/src/kmw-compiler/util.d.ts +74 -74
- package/build/src/kmw-compiler/util.js +247 -250
- package/build/src/kmw-compiler/util.js.map +1 -1
- package/build/src/kmw-compiler/validate-layout-file.d.ts +8 -8
- package/build/src/kmw-compiler/validate-layout-file.js +276 -279
- package/build/src/kmw-compiler/validate-layout-file.js.map +1 -1
- package/build/src/kmw-compiler/visual-keyboard-compiler.d.ts +2 -2
- package/build/src/kmw-compiler/visual-keyboard-compiler.js +119 -122
- package/build/src/kmw-compiler/visual-keyboard-compiler.js.map +1 -1
- package/build/src/main.d.ts +9 -9
- package/build/src/main.js +10 -13
- package/build/src/main.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,497 +1,494 @@
|
|
|
1
|
-
/*
|
|
2
|
-
TODO: implement additional interfaces:
|
|
3
|
-
|
|
4
|
-
typedef bool (*kmcmp_ValidateJsonMessageProc)();
|
|
5
|
-
extern "C" bool kmcmp_ValidateJsonFile();
|
|
6
|
-
*/
|
|
7
|
-
// TODO: rename wasm-host?
|
|
1
|
+
/*
|
|
2
|
+
TODO: implement additional interfaces:
|
|
8
3
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export const
|
|
23
|
-
export const
|
|
24
|
-
export const
|
|
25
|
-
;
|
|
26
|
-
;
|
|
27
|
-
export const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
;
|
|
31
|
-
;
|
|
32
|
-
;
|
|
33
|
-
;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let
|
|
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
|
-
if (artifacts
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
if (artifacts.
|
|
124
|
-
this.callbacks.fs.writeFileSync(artifacts.
|
|
125
|
-
}
|
|
126
|
-
if (artifacts.
|
|
127
|
-
this.callbacks.fs.writeFileSync(artifacts.
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
data = this.
|
|
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
|
-
for (let
|
|
181
|
-
result.extra.
|
|
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
|
-
* @param
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* @
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
wasm_options.
|
|
232
|
-
wasm_options.
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
if
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{
|
|
403
|
-
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{
|
|
404
|
-
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
* @
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return CompilerMessages.
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
4
|
+
typedef bool (*kmcmp_ValidateJsonMessageProc)();
|
|
5
|
+
extern "C" bool kmcmp_ValidateJsonFile();
|
|
6
|
+
*/
|
|
7
|
+
// TODO: rename wasm-host?
|
|
8
|
+
import { UnicodeSet, KvkFileReader } from '@keymanapp/common-types';
|
|
9
|
+
import { KvkFileWriter, KvksFileReader } from '@keymanapp/common-types';
|
|
10
|
+
import * as Osk from './osk.js';
|
|
11
|
+
import loadWasmHost from '../import/kmcmplib/wasm-host.js';
|
|
12
|
+
import { CompilerMessages, mapErrorFromKmcmplib } from './kmn-compiler-messages.js';
|
|
13
|
+
import { WriteCompiledKeyboard } from '../kmw-compiler/kmw-compiler.js';
|
|
14
|
+
//
|
|
15
|
+
// Matches kmcmplibapi.h definitions
|
|
16
|
+
//
|
|
17
|
+
export const STORETYPE_STORE = 0x01;
|
|
18
|
+
export const STORETYPE_RESERVED = 0x02;
|
|
19
|
+
export const STORETYPE_OPTION = 0x04;
|
|
20
|
+
export const STORETYPE_DEBUG = 0x08;
|
|
21
|
+
export const STORETYPE_CALL = 0x10;
|
|
22
|
+
export const STORETYPE__MASK = 0x1F;
|
|
23
|
+
;
|
|
24
|
+
;
|
|
25
|
+
export const COMPILETARGETS_KMX = 0x01;
|
|
26
|
+
export const COMPILETARGETS_JS = 0x02;
|
|
27
|
+
export const COMPILETARGETS__MASK = 0x03;
|
|
28
|
+
;
|
|
29
|
+
;
|
|
30
|
+
;
|
|
31
|
+
;
|
|
32
|
+
const baseOptions = {
|
|
33
|
+
shouldAddCompilerVersion: true,
|
|
34
|
+
saveDebug: true,
|
|
35
|
+
compilerWarningsAsErrors: false,
|
|
36
|
+
warnDeprecatedCode: true,
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Allows multiple instances of the Compiler class, by ensuring that the
|
|
40
|
+
* 'unique' kmnCompilerCallback global will be correlated with a specific
|
|
41
|
+
* instance of the Compiler class
|
|
42
|
+
*/
|
|
43
|
+
let callbackProcIdentifier = 0;
|
|
44
|
+
const callbackPrefix = 'kmnCompilerCallbacks_';
|
|
45
|
+
;
|
|
46
|
+
let Module;
|
|
47
|
+
/**
|
|
48
|
+
* @public
|
|
49
|
+
* Compiles a .kmn file to a .kmx, .kvk, and/or .js. The compiler does not read
|
|
50
|
+
* or write from filesystem or network directly, but relies on callbacks for all
|
|
51
|
+
* external IO.
|
|
52
|
+
*/
|
|
53
|
+
export class KmnCompiler {
|
|
54
|
+
callbackID; // a unique numeric id added to globals with prefixed names
|
|
55
|
+
callbacks;
|
|
56
|
+
wasmExports;
|
|
57
|
+
options;
|
|
58
|
+
constructor() {
|
|
59
|
+
this.callbackID = callbackPrefix + callbackProcIdentifier.toString();
|
|
60
|
+
callbackProcIdentifier++;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Initialize the compiler, including loading the WASM host for kmcmplib.
|
|
64
|
+
* Copies options.
|
|
65
|
+
* @param callbacks - Callbacks for external interfaces, including message
|
|
66
|
+
* reporting and file io
|
|
67
|
+
* @param options - Compiler options
|
|
68
|
+
* @returns false if initialization fails
|
|
69
|
+
*/
|
|
70
|
+
async init(callbacks, options) {
|
|
71
|
+
this.callbacks = callbacks;
|
|
72
|
+
this.options = { ...options };
|
|
73
|
+
if (!Module) {
|
|
74
|
+
try {
|
|
75
|
+
Module = await loadWasmHost();
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
/* c8 ignore next 3 */
|
|
79
|
+
this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({ e }));
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.wasmExports = (Module.wasmExports ?? Module.asm);
|
|
84
|
+
return this.verifyInitialized();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Verify that wasm is spun up OK.
|
|
88
|
+
* @returns true if OK
|
|
89
|
+
*/
|
|
90
|
+
verifyInitialized() {
|
|
91
|
+
if (!this.callbacks) {
|
|
92
|
+
// Can't report a message here.
|
|
93
|
+
throw Error('Must call Compiler.init(callbacks) before proceeding');
|
|
94
|
+
}
|
|
95
|
+
if (!Module) {
|
|
96
|
+
/* c8 ignore next 4 */
|
|
97
|
+
// fail if wasm not loaded or function not found
|
|
98
|
+
this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({}));
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Write artifacts from a successful compile to disk, via callbacks methods.
|
|
105
|
+
* The artifacts written may include:
|
|
106
|
+
*
|
|
107
|
+
* - .kmx file - binary keyboard used by Keyman on desktop platforms
|
|
108
|
+
* - .kvk file - binary on screen keyboard used by Keyman on desktop platforms
|
|
109
|
+
* - .js file - Javascript keyboard for web and touch platforms
|
|
110
|
+
*
|
|
111
|
+
* @param artifacts - object containing artifact binary data to write out
|
|
112
|
+
* @returns true on success
|
|
113
|
+
*/
|
|
114
|
+
async write(artifacts) {
|
|
115
|
+
if (!artifacts) {
|
|
116
|
+
throw Error('artifacts must be defined');
|
|
117
|
+
}
|
|
118
|
+
if (artifacts.kmx) {
|
|
119
|
+
this.callbacks.fs.writeFileSync(artifacts.kmx.filename, artifacts.kmx.data);
|
|
120
|
+
}
|
|
121
|
+
if (artifacts.kvk) {
|
|
122
|
+
this.callbacks.fs.writeFileSync(artifacts.kvk.filename, artifacts.kvk.data);
|
|
123
|
+
}
|
|
124
|
+
if (artifacts.js) {
|
|
125
|
+
this.callbacks.fs.writeFileSync(artifacts.js.filename, artifacts.js.data);
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
compilerMessageCallback = (line, code, msg) => {
|
|
130
|
+
this.callbacks.reportMessage(mapErrorFromKmcmplib(line, code, msg));
|
|
131
|
+
return 1;
|
|
132
|
+
};
|
|
133
|
+
cachedFile = {
|
|
134
|
+
filename: null,
|
|
135
|
+
data: null
|
|
136
|
+
};
|
|
137
|
+
loadFileCallback = (filename, baseFilename, buffer, bufferSize) => {
|
|
138
|
+
let resolvedFilename = this.callbacks.resolveFilename(baseFilename, filename);
|
|
139
|
+
let data;
|
|
140
|
+
if (this.cachedFile.filename == resolvedFilename) {
|
|
141
|
+
data = this.cachedFile.data;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
data = this.callbacks.loadFile(resolvedFilename);
|
|
145
|
+
if (!data) {
|
|
146
|
+
return -1;
|
|
147
|
+
}
|
|
148
|
+
this.cachedFile.filename = resolvedFilename;
|
|
149
|
+
this.cachedFile.data = data;
|
|
150
|
+
}
|
|
151
|
+
if (buffer == 0) {
|
|
152
|
+
/* We need to return buffer size required */
|
|
153
|
+
return data.byteLength;
|
|
154
|
+
}
|
|
155
|
+
if (bufferSize != data.byteLength) {
|
|
156
|
+
/* c8 ignore next 2 */
|
|
157
|
+
throw new Error(`loadFileCallback: second call, expected file size ${bufferSize} == ${data.byteLength}`);
|
|
158
|
+
}
|
|
159
|
+
Module.HEAP8.set(data, buffer);
|
|
160
|
+
return 1;
|
|
161
|
+
};
|
|
162
|
+
copyWasmResult(wasm_result) {
|
|
163
|
+
let result = {
|
|
164
|
+
// We cannot Object.assign or {...} on a wasm-defined object, so...
|
|
165
|
+
artifacts: {},
|
|
166
|
+
extra: {
|
|
167
|
+
targets: wasm_result.extra.targets,
|
|
168
|
+
displayMapFilename: wasm_result.extra.displayMapFilename,
|
|
169
|
+
kvksFilename: wasm_result.extra.kvksFilename,
|
|
170
|
+
stores: [],
|
|
171
|
+
groups: [],
|
|
172
|
+
},
|
|
173
|
+
displayMap: null
|
|
174
|
+
};
|
|
175
|
+
for (let store of wasm_result.extra.stores) {
|
|
176
|
+
result.extra.stores.push({ storeType: store.storeType, name: store.name, line: store.line });
|
|
177
|
+
}
|
|
178
|
+
for (let group of wasm_result.extra.groups) {
|
|
179
|
+
result.extra.groups.push({ isReadOnly: group.isReadOnly, name: group.name });
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* By default, when a `Uint8Array` is created from an `ArrayBuffer` (e.g.
|
|
185
|
+
* `Module.HEAP8.buffer`), it is a dynamic view into that buffer. This module
|
|
186
|
+
* buffer can be dynamically reallocated at any time, which can happen when
|
|
187
|
+
* allocating memory in WASM code (so the change will look _really_ weird in
|
|
188
|
+
* a stack trace). Thus, to ensure we don't trip over ourselves, we need to
|
|
189
|
+
* copy the buffer. Fortunately, creating a `Uint8Array` from a `Uint8Array`
|
|
190
|
+
* copies the data, and is pretty quick.
|
|
191
|
+
* @param offset - Offset into the WASM memory space, in bytes.
|
|
192
|
+
* @param size - Size of the buffer to copy, in bytes.
|
|
193
|
+
* @returns A _copy_ of the data in a new Uint8Array.
|
|
194
|
+
*/
|
|
195
|
+
copyWasmBuffer(offset, size) {
|
|
196
|
+
return new Uint8Array(new Uint8Array(Module.HEAP8.buffer, offset, size));
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Compiles a .kmn file to .kmx, .kvk, and/or .js files. Returns an object
|
|
200
|
+
* containing binary artifacts on success. The files are passed in by name,
|
|
201
|
+
* and the compiler will use callbacks as passed to the
|
|
202
|
+
* {@link KmnCompiler.init} function to read any input files by disk.
|
|
203
|
+
* @param infile - Path to source file. Path will be parsed to find relative
|
|
204
|
+
* references in the .kmn file, such as icon or On Screen
|
|
205
|
+
* Keyboard file
|
|
206
|
+
* @param outfile - Path to output file. The file will not be written to, but
|
|
207
|
+
* will be included in the result for use by
|
|
208
|
+
* {@link KmnCompiler.write}.
|
|
209
|
+
* @returns Binary artifacts on success, null on failure.
|
|
210
|
+
*/
|
|
211
|
+
async run(infile, outfile) {
|
|
212
|
+
if (!this.verifyInitialized()) {
|
|
213
|
+
/* c8 ignore next 2 */
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const options = { ...baseOptions, ...this.options };
|
|
217
|
+
outfile = outfile ?? infile.replace(/\.kmn$/i, '.kmx');
|
|
218
|
+
globalThis[this.callbackID] = {
|
|
219
|
+
message: this.compilerMessageCallback,
|
|
220
|
+
loadFile: this.loadFileCallback
|
|
221
|
+
};
|
|
222
|
+
let wasm_interface = new Module.CompilerInterface();
|
|
223
|
+
let wasm_options = new Module.CompilerOptions();
|
|
224
|
+
let wasm_result = null;
|
|
225
|
+
try {
|
|
226
|
+
wasm_options.saveDebug = options.saveDebug;
|
|
227
|
+
wasm_options.compilerWarningsAsErrors = options.compilerWarningsAsErrors;
|
|
228
|
+
wasm_options.warnDeprecatedCode = options.warnDeprecatedCode;
|
|
229
|
+
wasm_options.shouldAddCompilerVersion = options.shouldAddCompilerVersion;
|
|
230
|
+
wasm_options.target = 0; // CKF_KEYMAN; TODO use COMPILETARGETS_KMX
|
|
231
|
+
wasm_interface.callbacksKey = this.callbackID; // key of object on globalThis
|
|
232
|
+
wasm_result = Module.kmcmp_compile(infile, wasm_options, wasm_interface);
|
|
233
|
+
if (!wasm_result.result) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const result = this.copyWasmResult(wasm_result);
|
|
237
|
+
if (result.extra.targets & COMPILETARGETS_KMX) {
|
|
238
|
+
result.artifacts.kmx = {
|
|
239
|
+
filename: outfile,
|
|
240
|
+
data: this.copyWasmBuffer(wasm_result.kmx, wasm_result.kmxSize)
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//
|
|
244
|
+
// Visual Keyboard transform
|
|
245
|
+
//
|
|
246
|
+
if (result.extra.displayMapFilename) {
|
|
247
|
+
result.displayMap = this.loadDisplayMapping(infile, result.extra.displayMapFilename);
|
|
248
|
+
if (!result.displayMap) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (result.extra.kvksFilename) {
|
|
253
|
+
result.artifacts.kvk = this.runKvkCompiler(result.extra.kvksFilename, infile, outfile, result.displayMap);
|
|
254
|
+
if (!result.artifacts.kvk) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
//
|
|
259
|
+
// KeymanWeb compiler
|
|
260
|
+
//
|
|
261
|
+
if (wasm_result.extra.targets & COMPILETARGETS_JS) {
|
|
262
|
+
wasm_options.target = 1; // CKF_KEYMANWEB TODO use COMPILETARGETS_JS
|
|
263
|
+
// We always want debug data in the intermediate .kmx, so that error
|
|
264
|
+
// messages from KMW compiler can give line numbers in .kmn. This
|
|
265
|
+
// should have no impact on the final .js if options.debug is false
|
|
266
|
+
wasm_options.saveDebug = true;
|
|
267
|
+
wasm_result = Module.kmcmp_compile(infile, wasm_options, wasm_interface);
|
|
268
|
+
if (!wasm_result.result) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const kmw_result = this.copyWasmResult(wasm_result);
|
|
272
|
+
kmw_result.displayMap = result.displayMap; // we can safely re-use the kmx compile displayMap
|
|
273
|
+
const web_kmx = this.copyWasmBuffer(wasm_result.kmx, wasm_result.kmxSize);
|
|
274
|
+
result.artifacts.js = this.runWebCompiler(infile, outfile, web_kmx, result.artifacts.kvk?.data, kmw_result, options);
|
|
275
|
+
if (!result.artifacts.js) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
catch (e) {
|
|
282
|
+
/* c8 ignore next 3 */
|
|
283
|
+
this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({ e: e }));
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
if (wasm_result) {
|
|
288
|
+
wasm_result.delete();
|
|
289
|
+
}
|
|
290
|
+
wasm_interface.delete();
|
|
291
|
+
wasm_options.delete();
|
|
292
|
+
delete globalThis[this.callbackID];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
runWebCompiler(kmnFilename, kmxFilename, web_kmx, kvk, kmxResult, options) {
|
|
296
|
+
const data = WriteCompiledKeyboard(this.callbacks, kmnFilename, web_kmx, kvk, kmxResult, options.saveDebug);
|
|
297
|
+
if (!data) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
filename: this.callbacks.path.join(this.callbacks.path.dirname(kmxFilename), this.keyboardIdFromKmnFilename(kmnFilename) + ".js" /* KeymanFileTypes.Binary.WebKeyboard */),
|
|
302
|
+
data: new TextEncoder().encode(data)
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
keyboardIdFromKmnFilename(kmnFilename) {
|
|
306
|
+
return this.callbacks.path.basename(kmnFilename, ".kmn" /* KeymanFileTypes.Source.KeymanKeyboard */);
|
|
307
|
+
}
|
|
308
|
+
runKvkCompiler(kvksFilename, kmnFilename, kmxFilename, displayMap) {
|
|
309
|
+
// The compiler detected a .kvks file, which needs to be captured
|
|
310
|
+
kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename);
|
|
311
|
+
const data = this.callbacks.loadFile(kvksFilename);
|
|
312
|
+
if (!data) {
|
|
313
|
+
this.callbacks.reportMessage(CompilerMessages.Error_FileNotFound({ filename: kvksFilename }));
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
const filename = this.callbacks.path.basename(kvksFilename);
|
|
317
|
+
let basename = null;
|
|
318
|
+
let vk = null;
|
|
319
|
+
if (filename.endsWith('.kvk')) {
|
|
320
|
+
/* Legacy keyboards may reference a binary .kvk. That's not an error */
|
|
321
|
+
// TODO: (lowpri) add hint to convert to .kvks?
|
|
322
|
+
basename = this.callbacks.path.basename(kvksFilename, ".kvk" /* KeymanFileTypes.Binary.VisualKeyboard */);
|
|
323
|
+
const reader = new KvkFileReader();
|
|
324
|
+
try {
|
|
325
|
+
vk = reader.read(data);
|
|
326
|
+
}
|
|
327
|
+
catch (e) {
|
|
328
|
+
this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvkFile({ filename, e }));
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
basename = this.callbacks.path.basename(kvksFilename, ".kvks" /* KeymanFileTypes.Source.VisualKeyboard */);
|
|
334
|
+
const reader = new KvksFileReader();
|
|
335
|
+
let kvks = null;
|
|
336
|
+
try {
|
|
337
|
+
kvks = reader.read(data);
|
|
338
|
+
reader.validate(kvks);
|
|
339
|
+
}
|
|
340
|
+
catch (e) {
|
|
341
|
+
this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({ filename, e }));
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
let invalidVkeys = [];
|
|
345
|
+
vk = reader.transform(kvks, invalidVkeys);
|
|
346
|
+
for (let invalidVkey of invalidVkeys) {
|
|
347
|
+
this.callbacks.reportMessage(CompilerMessages.Warn_InvalidVkeyInKvksFile({ filename, invalidVkey }));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Make sure that we maintain the correspondence between source keyboard and
|
|
351
|
+
// .kvk. Appears to be used currently only by Windows package installer.
|
|
352
|
+
vk.header.associatedKeyboard = this.keyboardIdFromKmnFilename(kmnFilename);
|
|
353
|
+
if (displayMap) {
|
|
354
|
+
// Remap using the osk-char-use-rewriter
|
|
355
|
+
Osk.remapVisualKeyboard(vk, displayMap);
|
|
356
|
+
}
|
|
357
|
+
let writer = new KvkFileWriter();
|
|
358
|
+
return {
|
|
359
|
+
filename: this.callbacks.path.join(this.callbacks.path.dirname(kmxFilename), basename + ".kvk" /* KeymanFileTypes.Binary.VisualKeyboard */),
|
|
360
|
+
data: writer.write(vk)
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
loadDisplayMapping(kmnFilename, displayMapFilename) {
|
|
364
|
+
// Remap using the osk-char-use-rewriter
|
|
365
|
+
displayMapFilename = this.callbacks.resolveFilename(kmnFilename, displayMapFilename);
|
|
366
|
+
try {
|
|
367
|
+
// Expected file format: displaymap.schema.json
|
|
368
|
+
const data = this.callbacks.loadFile(displayMapFilename);
|
|
369
|
+
if (!data) {
|
|
370
|
+
this.callbacks.reportMessage(CompilerMessages.Error_FileNotFound({ filename: displayMapFilename }));
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const mapping = JSON.parse(new TextDecoder().decode(data));
|
|
374
|
+
return Osk.parseMapping(mapping);
|
|
375
|
+
}
|
|
376
|
+
catch (e) {
|
|
377
|
+
this.callbacks.reportMessage(CompilerMessages.Error_InvalidDisplayMapFile({ filename: displayMapFilename, e }));
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* @internal
|
|
383
|
+
* Generates an exception in kmcmplib to verify that Sentry error capture is
|
|
384
|
+
* working correctly
|
|
385
|
+
*/
|
|
386
|
+
testSentry() {
|
|
387
|
+
if (!this.verifyInitialized()) {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
return Module.kmcmp_testSentry();
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* @internal
|
|
394
|
+
* convert `\u{1234}` to `\u1234` etc
|
|
395
|
+
*/
|
|
396
|
+
static fixNewPattern(pattern) {
|
|
397
|
+
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{6})\}/g, `\\U00$1`);
|
|
398
|
+
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{5})\}/g, `\\U000$1`);
|
|
399
|
+
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{4})\}/g, `\\u$1`);
|
|
400
|
+
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{3})\}/g, `\\u0$1`);
|
|
401
|
+
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{2})\}/g, `\\u00$1`);
|
|
402
|
+
pattern = pattern.replaceAll(/\\u\{([0-9a-fA-F]{1})\}/g, `\\u000$1`);
|
|
403
|
+
return pattern;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* @internal
|
|
407
|
+
* @param pattern - UnicodeSet pattern such as `[a-z]`
|
|
408
|
+
* @param rangeCount - number of ranges to allocate
|
|
409
|
+
* @returns UnicodeSet accessor object, or null on failure
|
|
410
|
+
*/
|
|
411
|
+
parseUnicodeSet(pattern, rangeCount) {
|
|
412
|
+
if (!this.verifyInitialized()) {
|
|
413
|
+
/* c8 ignore next 2 */
|
|
414
|
+
// verifyInitialized will set a callback if needed
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
if ((rangeCount * 2) < 0) {
|
|
418
|
+
throw new RangeError(`Internal error: negative rangeCount * 2 = ${rangeCount * 2}`);
|
|
419
|
+
}
|
|
420
|
+
const buf = this.wasmExports.malloc(rangeCount * 2 * Module.HEAPU32.BYTES_PER_ELEMENT);
|
|
421
|
+
if (buf <= 0) {
|
|
422
|
+
// out of memory will return zero.
|
|
423
|
+
throw new RangeError(`Internal error: wasm malloc() returned ${buf}`);
|
|
424
|
+
}
|
|
425
|
+
// fix \u1234 pattern format
|
|
426
|
+
pattern = KmnCompiler.fixNewPattern(pattern);
|
|
427
|
+
const rc = Module.kmcmp_parseUnicodeSet(pattern, buf, rangeCount * 2);
|
|
428
|
+
if (rc >= 0) {
|
|
429
|
+
// If >= 0: it's a range count (which could be zero, an empty set).
|
|
430
|
+
const ranges = [];
|
|
431
|
+
const startu = (buf / Module.HEAPU32.BYTES_PER_ELEMENT);
|
|
432
|
+
for (let i = 0; i < rc; i++) {
|
|
433
|
+
const start = Module.HEAPU32[startu + (i * 2) + 0];
|
|
434
|
+
const end = Module.HEAPU32[startu + (i * 2) + 1];
|
|
435
|
+
ranges.push([start, end]);
|
|
436
|
+
}
|
|
437
|
+
this.wasmExports.free(buf);
|
|
438
|
+
return new UnicodeSet(pattern, ranges);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
// rc is negative: it's an error code.
|
|
442
|
+
this.wasmExports.free(buf);
|
|
443
|
+
// translate error code into callback
|
|
444
|
+
this.callbacks.reportMessage(getUnicodeSetError(rc));
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* @internal
|
|
450
|
+
*/
|
|
451
|
+
sizeUnicodeSet(pattern) {
|
|
452
|
+
if (!this.verifyInitialized()) {
|
|
453
|
+
/* c8 ignore next 2 */
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
// fix \u1234 pattern format
|
|
457
|
+
pattern = KmnCompiler.fixNewPattern(pattern);
|
|
458
|
+
// call with rangeCount = 0 to invoke in 'preflight' mode.
|
|
459
|
+
const rc = Module.kmcmp_parseUnicodeSet(pattern, 0, 0);
|
|
460
|
+
if (rc >= 0) {
|
|
461
|
+
return rc;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
this.callbacks.reportMessage(getUnicodeSetError(rc));
|
|
465
|
+
return -1;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* translate UnicodeSet return code into a compiler event
|
|
471
|
+
* @param rc parseUnicodeSet error code
|
|
472
|
+
* @returns the compiler event
|
|
473
|
+
*/
|
|
474
|
+
function getUnicodeSetError(rc) {
|
|
475
|
+
// from kmcmplib.h
|
|
476
|
+
const KMCMP_ERROR_SYNTAX_ERR = -1;
|
|
477
|
+
const KMCMP_ERROR_HAS_STRINGS = -2;
|
|
478
|
+
const KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3;
|
|
479
|
+
const KMCMP_FATAL_OUT_OF_RANGE = -4;
|
|
480
|
+
switch (rc) {
|
|
481
|
+
case KMCMP_ERROR_SYNTAX_ERR:
|
|
482
|
+
return CompilerMessages.Error_UnicodeSetSyntaxError();
|
|
483
|
+
case KMCMP_ERROR_HAS_STRINGS:
|
|
484
|
+
return CompilerMessages.Error_UnicodeSetHasStrings();
|
|
485
|
+
case KMCMP_ERROR_UNSUPPORTED_PROPERTY:
|
|
486
|
+
return CompilerMessages.Error_UnicodeSetHasProperties();
|
|
487
|
+
case KMCMP_FATAL_OUT_OF_RANGE:
|
|
488
|
+
return CompilerMessages.Fatal_UnicodeSetOutOfRange();
|
|
489
|
+
default:
|
|
490
|
+
/* c8 ignore next */
|
|
491
|
+
return CompilerMessages.Fatal_UnexpectedException({ e: `Unexpected UnicodeSet error code ${rc}` });
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
//# sourceMappingURL=compiler.js.map
|