@keymanapp/common-types 18.0.17-alpha → 18.0.19-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.
Files changed (147) hide show
  1. package/build/src/consts/virtual-key-constants.js +222 -221
  2. package/build/src/consts/virtual-key-constants.js.map +1 -1
  3. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js +73 -72
  4. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js.map +1 -1
  5. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js +121 -120
  6. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js.map +1 -1
  7. package/build/src/keyman-touch-layout/keyman-touch-layout-file.js +55 -54
  8. package/build/src/keyman-touch-layout/keyman-touch-layout-file.js.map +1 -1
  9. package/build/src/kmx/element-string.d.ts.map +1 -1
  10. package/build/src/kmx/element-string.js +126 -120
  11. package/build/src/kmx/element-string.js.map +1 -1
  12. package/build/src/kmx/keyman-targets.js +80 -79
  13. package/build/src/kmx/keyman-targets.js.map +1 -1
  14. package/build/src/kmx/kmx-builder.js +190 -189
  15. package/build/src/kmx/kmx-builder.js.map +1 -1
  16. package/build/src/kmx/kmx-file-reader.js +135 -134
  17. package/build/src/kmx/kmx-file-reader.js.map +1 -1
  18. package/build/src/kmx/kmx-plus-builder/build-disp.js +28 -27
  19. package/build/src/kmx/kmx-plus-builder/build-disp.js.map +1 -1
  20. package/build/src/kmx/kmx-plus-builder/build-elem.js +90 -89
  21. package/build/src/kmx/kmx-plus-builder/build-elem.js.map +1 -1
  22. package/build/src/kmx/kmx-plus-builder/build-keys.js +108 -107
  23. package/build/src/kmx/kmx-plus-builder/build-keys.js.map +1 -1
  24. package/build/src/kmx/kmx-plus-builder/build-layr.js +102 -101
  25. package/build/src/kmx/kmx-plus-builder/build-layr.js.map +1 -1
  26. package/build/src/kmx/kmx-plus-builder/build-list.js +67 -66
  27. package/build/src/kmx/kmx-plus-builder/build-list.js.map +1 -1
  28. package/build/src/kmx/kmx-plus-builder/build-loca.js +22 -21
  29. package/build/src/kmx/kmx-plus-builder/build-loca.js.map +1 -1
  30. package/build/src/kmx/kmx-plus-builder/build-meta.js +23 -22
  31. package/build/src/kmx/kmx-plus-builder/build-meta.js.map +1 -1
  32. package/build/src/kmx/kmx-plus-builder/build-sect.js +16 -15
  33. package/build/src/kmx/kmx-plus-builder/build-sect.js.map +1 -1
  34. package/build/src/kmx/kmx-plus-builder/build-strs.js +47 -46
  35. package/build/src/kmx/kmx-plus-builder/build-strs.js.map +1 -1
  36. package/build/src/kmx/kmx-plus-builder/build-tran.js +70 -69
  37. package/build/src/kmx/kmx-plus-builder/build-tran.js.map +1 -1
  38. package/build/src/kmx/kmx-plus-builder/build-uset.js +61 -60
  39. package/build/src/kmx/kmx-plus-builder/build-uset.js.map +1 -1
  40. package/build/src/kmx/kmx-plus-builder/build-vars.js +49 -48
  41. package/build/src/kmx/kmx-plus-builder/build-vars.js.map +1 -1
  42. package/build/src/kmx/kmx-plus-builder/builder-section.js +5 -4
  43. package/build/src/kmx/kmx-plus-builder/builder-section.js.map +1 -1
  44. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js +138 -137
  45. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js.map +1 -1
  46. package/build/src/kmx/kmx-plus.d.ts +3 -2
  47. package/build/src/kmx/kmx-plus.d.ts.map +1 -1
  48. package/build/src/kmx/kmx-plus.js +831 -823
  49. package/build/src/kmx/kmx-plus.js.map +1 -1
  50. package/build/src/kmx/kmx.d.ts.map +1 -1
  51. package/build/src/kmx/kmx.js +303 -299
  52. package/build/src/kmx/kmx.js.map +1 -1
  53. package/build/src/kmx/string-list.js +89 -88
  54. package/build/src/kmx/string-list.js.map +1 -1
  55. package/build/src/kpj/keyman-developer-project.js +196 -195
  56. package/build/src/kpj/keyman-developer-project.js.map +1 -1
  57. package/build/src/kpj/kpj-file-reader.js +120 -119
  58. package/build/src/kpj/kpj-file-reader.js.map +1 -1
  59. package/build/src/kpj/kpj-file.js +13 -12
  60. package/build/src/kpj/kpj-file.js.map +1 -1
  61. package/build/src/kvk/kvk-file-reader.js +38 -37
  62. package/build/src/kvk/kvk-file-reader.js.map +1 -1
  63. package/build/src/kvk/kvk-file-writer.js +78 -77
  64. package/build/src/kvk/kvk-file-writer.js.map +1 -1
  65. package/build/src/kvk/kvk-file.js +91 -90
  66. package/build/src/kvk/kvk-file.js.map +1 -1
  67. package/build/src/kvk/kvks-file-reader.js +176 -175
  68. package/build/src/kvk/kvks-file-reader.js.map +1 -1
  69. package/build/src/kvk/kvks-file-writer.js +107 -106
  70. package/build/src/kvk/kvks-file-writer.js.map +1 -1
  71. package/build/src/kvk/kvks-file.js +12 -11
  72. package/build/src/kvk/kvks-file.js.map +1 -1
  73. package/build/src/kvk/visual-keyboard.js +76 -75
  74. package/build/src/kvk/visual-keyboard.js.map +1 -1
  75. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js +22 -21
  76. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js.map +1 -1
  77. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js +410 -409
  78. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js.map +1 -1
  79. package/build/src/ldml-keyboard/ldml-keyboard-xml.js +58 -57
  80. package/build/src/ldml-keyboard/ldml-keyboard-xml.js.map +1 -1
  81. package/build/src/ldml-keyboard/pattern-parser.js +491 -490
  82. package/build/src/ldml-keyboard/pattern-parser.js.map +1 -1
  83. package/build/src/ldml-keyboard/unicodeset-parser-api.js +30 -29
  84. package/build/src/ldml-keyboard/unicodeset-parser-api.js.map +1 -1
  85. package/build/src/main.js +35 -34
  86. package/build/src/main.js.map +1 -1
  87. package/build/src/package/kmp-json-file.js +4 -3
  88. package/build/src/package/kmp-json-file.js.map +1 -1
  89. package/build/src/package/kps-file.js +18 -17
  90. package/build/src/package/kps-file.js.map +1 -1
  91. package/build/src/schema-validators.js +28 -27
  92. package/build/src/schema-validators.js.map +1 -1
  93. package/build/src/schemas/displaymap.schema.js +38 -37
  94. package/build/src/schemas/displaymap.schema.js.map +1 -1
  95. package/build/src/schemas/displaymap.schema.validator.mjs +267 -266
  96. package/build/src/schemas/displaymap.schema.validator.mjs.map +1 -1
  97. package/build/src/schemas/keyboard_info.schema.js +101 -100
  98. package/build/src/schemas/keyboard_info.schema.js.map +1 -1
  99. package/build/src/schemas/keyboard_info.schema.validator.mjs +1161 -1160
  100. package/build/src/schemas/keyboard_info.schema.validator.mjs.map +1 -1
  101. package/build/src/schemas/keyman-touch-layout.clean.spec.js +154 -153
  102. package/build/src/schemas/keyman-touch-layout.clean.spec.js.map +1 -1
  103. package/build/src/schemas/keyman-touch-layout.clean.spec.validator.mjs +1095 -1094
  104. package/build/src/schemas/keyman-touch-layout.clean.spec.validator.mjs.map +1 -1
  105. package/build/src/schemas/keyman-touch-layout.spec.js +143 -142
  106. package/build/src/schemas/keyman-touch-layout.spec.js.map +1 -1
  107. package/build/src/schemas/keyman-touch-layout.spec.validator.mjs +1437 -1436
  108. package/build/src/schemas/keyman-touch-layout.spec.validator.mjs.map +1 -1
  109. package/build/src/schemas/kmp.schema.js +356 -355
  110. package/build/src/schemas/kmp.schema.js.map +1 -1
  111. package/build/src/schemas/kmp.schema.validator.mjs +1628 -1627
  112. package/build/src/schemas/kmp.schema.validator.mjs.map +1 -1
  113. package/build/src/schemas/kpj-9.0.schema.js +134 -133
  114. package/build/src/schemas/kpj-9.0.schema.js.map +1 -1
  115. package/build/src/schemas/kpj-9.0.schema.validator.mjs +656 -655
  116. package/build/src/schemas/kpj-9.0.schema.validator.mjs.map +1 -1
  117. package/build/src/schemas/kpj.schema.js +132 -131
  118. package/build/src/schemas/kpj.schema.js.map +1 -1
  119. package/build/src/schemas/kpj.schema.validator.mjs +516 -515
  120. package/build/src/schemas/kpj.schema.validator.mjs.map +1 -1
  121. package/build/src/schemas/kvks.schema.js +185 -184
  122. package/build/src/schemas/kvks.schema.js.map +1 -1
  123. package/build/src/schemas/kvks.schema.validator.mjs +626 -625
  124. package/build/src/schemas/kvks.schema.validator.mjs.map +1 -1
  125. package/build/src/schemas/ldml-keyboard3.schema.js +699 -698
  126. package/build/src/schemas/ldml-keyboard3.schema.js.map +1 -1
  127. package/build/src/schemas/ldml-keyboard3.schema.validator.mjs +3118 -3117
  128. package/build/src/schemas/ldml-keyboard3.schema.validator.mjs.map +1 -1
  129. package/build/src/schemas/ldml-keyboardtest3.schema.js +228 -227
  130. package/build/src/schemas/ldml-keyboardtest3.schema.js.map +1 -1
  131. package/build/src/schemas/ldml-keyboardtest3.schema.validator.mjs +745 -744
  132. package/build/src/schemas/ldml-keyboardtest3.schema.validator.mjs.map +1 -1
  133. package/build/src/schemas.js +26 -25
  134. package/build/src/schemas.js.map +1 -1
  135. package/build/src/util/common-events.js +29 -28
  136. package/build/src/util/common-events.js.map +1 -1
  137. package/build/src/util/compiler-interfaces.js +381 -380
  138. package/build/src/util/compiler-interfaces.js.map +1 -1
  139. package/build/src/util/errors.js +8 -7
  140. package/build/src/util/errors.js.map +1 -1
  141. package/build/src/util/file-types.js +143 -142
  142. package/build/src/util/file-types.js.map +1 -1
  143. package/build/src/util/util.d.ts +4 -0
  144. package/build/src/util/util.d.ts.map +1 -1
  145. package/build/src/util/util.js +369 -362
  146. package/build/src/util/util.js.map +1 -1
  147. package/package.json +2 -2
@@ -1,410 +1,411 @@
1
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ab9967fe-33bd-551c-b914-536877542742")}catch(e){}}();
2
- import * as xml2js from 'xml2js';
3
- import { ImportStatus } from './ldml-keyboard-xml.js';
4
- import { boxXmlArray } from '../util/util.js';
5
- import { constants } from '@keymanapp/ldml-keyboard-constants';
6
- import { CommonTypesMessages } from '../util/common-events.js';
7
- import SchemaValidators from '../schema-validators.js';
8
- ;
9
- export class LDMLKeyboardXMLSourceFileReaderOptions {
10
- importsPath;
11
- }
12
- ;
13
- export class LDMLKeyboardXMLSourceFileReader {
14
- options;
15
- callbacks;
16
- constructor(options, callbacks) {
17
- this.options = options;
18
- this.callbacks = callbacks;
19
- }
20
- static get defaultImportsURL() {
21
- return ['../import/', import.meta.url];
22
- }
23
- readImportFile(version, subpath) {
24
- const importPath = this.callbacks.resolveFilename(this.options.importsPath, `${version}/${subpath}`);
25
- return this.callbacks.loadFile(importPath);
26
- }
27
- /**
28
- * xml2js will not place single-entry objects into arrays.
29
- * Easiest way to fix this is to box them ourselves as needed
30
- * @param source any
31
- * @returns true on success, false on failure
32
- */
33
- boxArrays(source) {
34
- if (source?.keyboard3) {
35
- if (!source.keyboard3.keys) {
36
- // Note: this is here to put a substrate for the imported keys
37
- source.keyboard3.keys = {
38
- key: [],
39
- };
40
- }
41
- if (!source.keyboard3.keys.import) {
42
- source.keyboard3.keys.import = [];
43
- }
44
- if (!source.keyboard3.forms) {
45
- source.keyboard3.forms = {
46
- form: [],
47
- };
48
- }
49
- if (!source.keyboard3.forms.import) {
50
- source.keyboard3.forms.import = [];
51
- }
52
- }
53
- boxXmlArray(source?.keyboard3, 'layers');
54
- boxXmlArray(source?.keyboard3?.displays, 'display');
55
- boxXmlArray(source?.keyboard3?.keys, 'key');
56
- boxXmlArray(source?.keyboard3?.flicks, 'flick');
57
- boxXmlArray(source?.keyboard3?.locales, 'locale');
58
- boxXmlArray(source?.keyboard3, 'transforms');
59
- if (source?.keyboard3?.layers) {
60
- for (let layers of source?.keyboard3?.layers) {
61
- boxXmlArray(layers, 'layer');
62
- if (layers?.layer) {
63
- for (let layer of layers?.layer) {
64
- boxXmlArray(layer, 'row');
65
- }
66
- }
67
- }
68
- }
69
- if (source?.keyboard3?.forms?.form) {
70
- boxXmlArray(source?.keyboard3?.forms, 'form');
71
- for (let form of source?.keyboard3?.forms?.form) {
72
- boxXmlArray(form, 'scanCodes');
73
- }
74
- }
75
- if (source?.keyboard3?.flicks) {
76
- boxXmlArray(source?.keyboard3?.flicks, 'flick');
77
- for (let flick of source?.keyboard3?.flicks?.flick) {
78
- boxXmlArray(flick, 'flickSegment');
79
- }
80
- }
81
- if (source?.keyboard3?.variables) {
82
- boxXmlArray(source?.keyboard3?.variables, 'set');
83
- boxXmlArray(source?.keyboard3?.variables, 'string');
84
- boxXmlArray(source?.keyboard3?.variables, 'uset');
85
- }
86
- if (source?.keyboard3?.transforms) {
87
- for (let transforms of source.keyboard3.transforms) {
88
- boxXmlArray(transforms, 'transformGroup');
89
- for (let transformGroup of transforms.transformGroup) {
90
- boxXmlArray(transformGroup, 'transform');
91
- boxXmlArray(transformGroup, 'reorder');
92
- }
93
- }
94
- }
95
- return this.boxImportsAndSpecials(source, 'keyboard3');
96
- }
97
- /**
98
- * Recurse over object, boxing up any specials or imports
99
- * @param obj any object to be traversed
100
- * @param subtag the leafmost enclosing tag such as 'keyboard3'
101
- * @returns true on success, false on failure
102
- */
103
- boxImportsAndSpecials(obj, subtag) {
104
- if (!obj)
105
- return true;
106
- if (Array.isArray(obj)) {
107
- for (const sub of obj) {
108
- // retain the same subtag
109
- if (!this.boxImportsAndSpecials(sub, subtag)) {
110
- return false;
111
- }
112
- }
113
- }
114
- else if (typeof obj === 'object') {
115
- for (const key of Object.keys(obj)) {
116
- if (key === 'special') {
117
- boxXmlArray(obj, key);
118
- }
119
- else if (key === 'import') {
120
- // Need to 'box it up' first for processing
121
- boxXmlArray(obj, key);
122
- // Now, resolve the import
123
- if (!this.resolveImports(obj, subtag)) {
124
- return false;
125
- }
126
- // now delete the import array we so carefully constructed, the caller does not
127
- // want to see it.
128
- delete obj['import'];
129
- }
130
- else {
131
- if (!this.boxImportsAndSpecials(obj[key], key)) {
132
- return false;
133
- }
134
- }
135
- }
136
- }
137
- return true;
138
- }
139
- /**
140
- *
141
- * @param obj object to be imported into
142
- * @param subtag obj's element tag, e.g. `keys`
143
- * @returns true on success, false on failure
144
- */
145
- resolveImports(obj, subtag) {
146
- // These are in reverse order, because the imports insert at the beginning of the array.
147
- // first, the explicit imports
148
- for (const asImport of ([...obj['import']].reverse())) {
149
- if (!this.resolveOneImport(obj, subtag, asImport)) {
150
- return false;
151
- }
152
- }
153
- // then, the implied imports
154
- if (subtag === 'keys') {
155
- // <import base="cldr" path="45/keys-Latn-implied.xml"/>
156
- if (!this.resolveOneImport(obj, subtag, {
157
- base: constants.cldr_import_base,
158
- path: constants.cldr_implied_keys_import
159
- }, true)) {
160
- return false;
161
- }
162
- }
163
- else if (subtag === 'forms') {
164
- // <import base="cldr" path="45/scanCodes-implied.xml"/>
165
- if (!this.resolveOneImport(obj, subtag, {
166
- base: constants.cldr_import_base,
167
- path: constants.cldr_implied_forms_import
168
- }, true)) {
169
- return false;
170
- }
171
- }
172
- return true;
173
- }
174
- /**
175
- * @param obj the object being imported into
176
- * @param subtag obj's element tag, e.g. `keys`
177
- * @param asImport the import structure
178
- * @param implied true if it is an implied import
179
- * @returns true on success, false on failure
180
- */
181
- resolveOneImport(obj, subtag, asImport, implied) {
182
- const { base, path } = asImport;
183
- if (base !== constants.cldr_import_base) {
184
- this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidBase({ base, path, subtag }));
185
- return false;
186
- }
187
- const paths = path.split('/');
188
- if (paths[0] == '' || paths[1] == '' || paths.length !== 2) {
189
- this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidPath({ base, path, subtag }));
190
- return false;
191
- }
192
- const importData = this.readImportFile(paths[0], paths[1]);
193
- if (!importData || !importData.length) {
194
- this.callbacks.reportMessage(CommonTypesMessages.Error_ImportReadFail({ base, path, subtag }));
195
- return false;
196
- }
197
- const importXml = this.loadUnboxed(importData); // TODO-LDML: have to load as any because it is an arbitrary part
198
- const importRootNode = importXml[subtag]; // e.g. <keys/>
199
- // importXml will have one property: the root element.
200
- if (!importRootNode) {
201
- this.callbacks.reportMessage(CommonTypesMessages.Error_ImportWrongRoot({ base, path, subtag }));
202
- return false;
203
- }
204
- // pull all children of importXml[subtag] into obj
205
- for (const subsubtag of Object.keys(importRootNode).reverse()) { // e.g. <key/>
206
- const subsubval = importRootNode[subsubtag];
207
- const basePath = `${base}/${path}`;
208
- if (!Array.isArray(subsubval)) {
209
- // This is somewhat of an internal error, indicating that a non-mergeable XML file was imported
210
- // Not exercisable with the standard LDML imports.
211
- this.callbacks.reportMessage(CommonTypesMessages.Error_ImportMergeFail({ base, path, subtag, subsubtag }));
212
- return false;
213
- }
214
- // Mark all children as an import
215
- subsubval.forEach(o => o[ImportStatus.import] = basePath);
216
- if (implied) {
217
- // mark all children as an implied import
218
- subsubval.forEach(o => o[ImportStatus.impliedImport] = basePath);
219
- }
220
- if (!obj[subsubtag]) {
221
- obj[subsubtag] = []; // start with empty array
222
- }
223
- obj[subsubtag] = [...subsubval, ...obj[subsubtag]];
224
- }
225
- return true;
226
- }
227
- /**
228
- * @returns true if valid, false if invalid
229
- */
230
- validate(source) {
231
- if (!SchemaValidators.ldmlKeyboard3(source)) {
232
- for (let err of SchemaValidators.ldmlKeyboard3.errors) {
233
- this.callbacks.reportMessage(CommonTypesMessages.Error_SchemaValidationError({
234
- instancePath: err.instancePath,
235
- keyword: err.keyword,
236
- message: err.message || 'Unknown AJV Error',
237
- params: Object.entries(err.params || {}).sort().map(([k, v]) => `${k}="${v}"`).join(' '),
238
- }));
239
- }
240
- return false;
241
- }
242
- return true;
243
- }
244
- loadUnboxed(file) {
245
- let source = (() => {
246
- let a;
247
- let parser = new xml2js.Parser({
248
- explicitArray: false,
249
- mergeAttrs: true,
250
- includeWhiteChars: false,
251
- emptyTag: {}
252
- // Why "as any"? xml2js is broken:
253
- // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
254
- // that an old version of `emptyTag` is used which doesn't support
255
- // functions, but DefinitelyTyped is requiring use of function or a
256
- // string. See also notes at
257
- // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
258
- // An alternative fix would be to pull xml2js directly from github
259
- // rather than using the version tagged on npmjs.com.
260
- });
261
- parser.parseString(file, (e, r) => { a = r; }); // TODO-LDML: isn't 'e' the error?
262
- return a;
263
- })();
264
- return source;
265
- }
266
- /**
267
- * @param file
268
- * @returns source on success, otherwise null
269
- */
270
- load(file) {
271
- if (!file) {
272
- return null;
273
- }
274
- const source = this.loadUnboxed(file);
275
- if (this.boxArrays(source)) {
276
- return source;
277
- }
278
- else {
279
- return null;
280
- }
281
- }
282
- loadTestDataUnboxed(file) {
283
- let source = (() => {
284
- let a;
285
- let parser = new xml2js.Parser({
286
- // explicitArray: false,
287
- preserveChildrenOrder: true,
288
- explicitChildren: true, // needed for test data
289
- // mergeAttrs: true,
290
- // includeWhiteChars: false,
291
- // emptyTag: {} as any
292
- // Why "as any"? xml2js is broken:
293
- // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
294
- // that an old version of `emptyTag` is used which doesn't support
295
- // functions, but DefinitelyTyped is requiring use of function or a
296
- // string. See also notes at
297
- // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
298
- // An alternative fix would be to pull xml2js directly from github
299
- // rather than using the version tagged on npmjs.com.
300
- });
301
- parser.parseString(file, (e, r) => { a = r; }); // TODO-LDML: isn't 'e' the error?
302
- return a; // Why 'any'? Because we need to box up the $'s into proper properties.
303
- })();
304
- return source;
305
- }
306
- /**
307
- * Filter the obj array for a subtag
308
- * @param source array of source objs
309
- * @param subtag subtag to filter on
310
- * @returns
311
- */
312
- findSubtagArray(source, subtag) {
313
- return source?.filter(o => o['#name'] === subtag);
314
- }
315
- /**
316
- * Get exactly one element
317
- * @param source
318
- * @param subtag
319
- * @returns
320
- */
321
- findSubtag(source, subtag) {
322
- const r = this.findSubtagArray(source, subtag);
323
- if (!r || r.length === 0) {
324
- return null;
325
- }
326
- else if (r.length === 1) {
327
- return r[0];
328
- }
329
- else {
330
- this.callbacks.reportMessage(CommonTypesMessages.Error_TestDataUnexpectedArray({ subtag }));
331
- return null; // ERROR
332
- }
333
- }
334
- /**
335
- * The default test data stuffer.
336
- * Just gets $ (the attrs) as the body.
337
- * Override to use something more complex, such as including child nodes.
338
- * @param o object to map
339
- * @param r back ref to reader
340
- */
341
- static defaultMapper = ((o, r) => o?.$);
342
- /**
343
- *
344
- * @param obj target object
345
- * @param source array of $/#name strings
346
- * @param subtag name to extract
347
- * @param mapper custom mapper function
348
- */
349
- stuffBoxes(obj, source, subtag, asArray, mapper) {
350
- if (!mapper) {
351
- mapper = LDMLKeyboardXMLSourceFileReader.defaultMapper;
352
- }
353
- if (asArray) {
354
- const r = this;
355
- obj[subtag] = this.findSubtagArray(source, subtag)?.map((v) => mapper(v, r)); // extract contents only
356
- }
357
- else {
358
- obj[subtag] = mapper(this.findSubtag(source, subtag), this); // run the mapper once
359
- }
360
- }
361
- boxTestDataArrays(raw) {
362
- if (!raw)
363
- return null;
364
- const a = {
365
- keyboardTest3: {
366
- conformsTo: raw?.keyboardTest3?.$?.conformsTo,
367
- }
368
- };
369
- const $$ = raw?.keyboardTest3?.$$;
370
- this.stuffBoxes(a.keyboardTest3, $$, 'info');
371
- this.stuffBoxes(a.keyboardTest3, $$, 'repertoire', true);
372
- this.stuffBoxes(a.keyboardTest3, $$, 'tests', true, (o, r) => {
373
- // start with basic unpack
374
- const tests = LDMLKeyboardXMLSourceFileReader.defaultMapper(o, r);
375
- // add ingredients
376
- r.stuffBoxes(tests, o.$$, 'test', true, (o, r) => {
377
- // start with basic unpack
378
- const test = LDMLKeyboardXMLSourceFileReader.defaultMapper(o, r);
379
- // add ingredients
380
- const $$ = o.$$;
381
- r.stuffBoxes(test, $$, 'startContext'); // singleton
382
- // now the actions
383
- test.actions = $$.map(v => {
384
- const type = v['#name']; // element name
385
- if (type === 'startContext') {
386
- return null; // handled above
387
- }
388
- const subv = LDMLKeyboardXMLSourceFileReader.defaultMapper(v, r);
389
- return Object.assign({ type }, subv);
390
- }).filter(v => v !== null);
391
- return test;
392
- });
393
- return tests;
394
- });
395
- return a;
396
- }
397
- /**
398
- * @param file test file
399
- * @returns source on success, otherwise null
400
- */
401
- loadTestData(file) {
402
- if (!file) {
403
- return null;
404
- }
405
- const source = this.loadTestDataUnboxed(file);
406
- return this.boxTestDataArrays(source);
407
- }
408
- }
409
- //# debugId=ab9967fe-33bd-551c-b914-536877542742
1
+
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="065afd3b-524c-565a-b20d-4b1e3cfd778f")}catch(e){}}();
3
+ import * as xml2js from 'xml2js';
4
+ import { ImportStatus } from './ldml-keyboard-xml.js';
5
+ import { boxXmlArray } from '../util/util.js';
6
+ import { constants } from '@keymanapp/ldml-keyboard-constants';
7
+ import { CommonTypesMessages } from '../util/common-events.js';
8
+ import SchemaValidators from '../schema-validators.js';
9
+ ;
10
+ export class LDMLKeyboardXMLSourceFileReaderOptions {
11
+ importsPath;
12
+ }
13
+ ;
14
+ export class LDMLKeyboardXMLSourceFileReader {
15
+ options;
16
+ callbacks;
17
+ constructor(options, callbacks) {
18
+ this.options = options;
19
+ this.callbacks = callbacks;
20
+ }
21
+ static get defaultImportsURL() {
22
+ return ['../import/', import.meta.url];
23
+ }
24
+ readImportFile(version, subpath) {
25
+ const importPath = this.callbacks.resolveFilename(this.options.importsPath, `${version}/${subpath}`);
26
+ return this.callbacks.loadFile(importPath);
27
+ }
28
+ /**
29
+ * xml2js will not place single-entry objects into arrays.
30
+ * Easiest way to fix this is to box them ourselves as needed
31
+ * @param source any
32
+ * @returns true on success, false on failure
33
+ */
34
+ boxArrays(source) {
35
+ if (source?.keyboard3) {
36
+ if (!source.keyboard3.keys) {
37
+ // Note: this is here to put a substrate for the imported keys
38
+ source.keyboard3.keys = {
39
+ key: [],
40
+ };
41
+ }
42
+ if (!source.keyboard3.keys.import) {
43
+ source.keyboard3.keys.import = [];
44
+ }
45
+ if (!source.keyboard3.forms) {
46
+ source.keyboard3.forms = {
47
+ form: [],
48
+ };
49
+ }
50
+ if (!source.keyboard3.forms.import) {
51
+ source.keyboard3.forms.import = [];
52
+ }
53
+ }
54
+ boxXmlArray(source?.keyboard3, 'layers');
55
+ boxXmlArray(source?.keyboard3?.displays, 'display');
56
+ boxXmlArray(source?.keyboard3?.keys, 'key');
57
+ boxXmlArray(source?.keyboard3?.flicks, 'flick');
58
+ boxXmlArray(source?.keyboard3?.locales, 'locale');
59
+ boxXmlArray(source?.keyboard3, 'transforms');
60
+ if (source?.keyboard3?.layers) {
61
+ for (let layers of source?.keyboard3?.layers) {
62
+ boxXmlArray(layers, 'layer');
63
+ if (layers?.layer) {
64
+ for (let layer of layers?.layer) {
65
+ boxXmlArray(layer, 'row');
66
+ }
67
+ }
68
+ }
69
+ }
70
+ if (source?.keyboard3?.forms?.form) {
71
+ boxXmlArray(source?.keyboard3?.forms, 'form');
72
+ for (let form of source?.keyboard3?.forms?.form) {
73
+ boxXmlArray(form, 'scanCodes');
74
+ }
75
+ }
76
+ if (source?.keyboard3?.flicks) {
77
+ boxXmlArray(source?.keyboard3?.flicks, 'flick');
78
+ for (let flick of source?.keyboard3?.flicks?.flick) {
79
+ boxXmlArray(flick, 'flickSegment');
80
+ }
81
+ }
82
+ if (source?.keyboard3?.variables) {
83
+ boxXmlArray(source?.keyboard3?.variables, 'set');
84
+ boxXmlArray(source?.keyboard3?.variables, 'string');
85
+ boxXmlArray(source?.keyboard3?.variables, 'uset');
86
+ }
87
+ if (source?.keyboard3?.transforms) {
88
+ for (let transforms of source.keyboard3.transforms) {
89
+ boxXmlArray(transforms, 'transformGroup');
90
+ for (let transformGroup of transforms.transformGroup) {
91
+ boxXmlArray(transformGroup, 'transform');
92
+ boxXmlArray(transformGroup, 'reorder');
93
+ }
94
+ }
95
+ }
96
+ return this.boxImportsAndSpecials(source, 'keyboard3');
97
+ }
98
+ /**
99
+ * Recurse over object, boxing up any specials or imports
100
+ * @param obj any object to be traversed
101
+ * @param subtag the leafmost enclosing tag such as 'keyboard3'
102
+ * @returns true on success, false on failure
103
+ */
104
+ boxImportsAndSpecials(obj, subtag) {
105
+ if (!obj)
106
+ return true;
107
+ if (Array.isArray(obj)) {
108
+ for (const sub of obj) {
109
+ // retain the same subtag
110
+ if (!this.boxImportsAndSpecials(sub, subtag)) {
111
+ return false;
112
+ }
113
+ }
114
+ }
115
+ else if (typeof obj === 'object') {
116
+ for (const key of Object.keys(obj)) {
117
+ if (key === 'special') {
118
+ boxXmlArray(obj, key);
119
+ }
120
+ else if (key === 'import') {
121
+ // Need to 'box it up' first for processing
122
+ boxXmlArray(obj, key);
123
+ // Now, resolve the import
124
+ if (!this.resolveImports(obj, subtag)) {
125
+ return false;
126
+ }
127
+ // now delete the import array we so carefully constructed, the caller does not
128
+ // want to see it.
129
+ delete obj['import'];
130
+ }
131
+ else {
132
+ if (!this.boxImportsAndSpecials(obj[key], key)) {
133
+ return false;
134
+ }
135
+ }
136
+ }
137
+ }
138
+ return true;
139
+ }
140
+ /**
141
+ *
142
+ * @param obj object to be imported into
143
+ * @param subtag obj's element tag, e.g. `keys`
144
+ * @returns true on success, false on failure
145
+ */
146
+ resolveImports(obj, subtag) {
147
+ // These are in reverse order, because the imports insert at the beginning of the array.
148
+ // first, the explicit imports
149
+ for (const asImport of ([...obj['import']].reverse())) {
150
+ if (!this.resolveOneImport(obj, subtag, asImport)) {
151
+ return false;
152
+ }
153
+ }
154
+ // then, the implied imports
155
+ if (subtag === 'keys') {
156
+ // <import base="cldr" path="45/keys-Latn-implied.xml"/>
157
+ if (!this.resolveOneImport(obj, subtag, {
158
+ base: constants.cldr_import_base,
159
+ path: constants.cldr_implied_keys_import
160
+ }, true)) {
161
+ return false;
162
+ }
163
+ }
164
+ else if (subtag === 'forms') {
165
+ // <import base="cldr" path="45/scanCodes-implied.xml"/>
166
+ if (!this.resolveOneImport(obj, subtag, {
167
+ base: constants.cldr_import_base,
168
+ path: constants.cldr_implied_forms_import
169
+ }, true)) {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ }
175
+ /**
176
+ * @param obj the object being imported into
177
+ * @param subtag obj's element tag, e.g. `keys`
178
+ * @param asImport the import structure
179
+ * @param implied true if it is an implied import
180
+ * @returns true on success, false on failure
181
+ */
182
+ resolveOneImport(obj, subtag, asImport, implied) {
183
+ const { base, path } = asImport;
184
+ if (base !== constants.cldr_import_base) {
185
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidBase({ base, path, subtag }));
186
+ return false;
187
+ }
188
+ const paths = path.split('/');
189
+ if (paths[0] == '' || paths[1] == '' || paths.length !== 2) {
190
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidPath({ base, path, subtag }));
191
+ return false;
192
+ }
193
+ const importData = this.readImportFile(paths[0], paths[1]);
194
+ if (!importData || !importData.length) {
195
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportReadFail({ base, path, subtag }));
196
+ return false;
197
+ }
198
+ const importXml = this.loadUnboxed(importData); // TODO-LDML: have to load as any because it is an arbitrary part
199
+ const importRootNode = importXml[subtag]; // e.g. <keys/>
200
+ // importXml will have one property: the root element.
201
+ if (!importRootNode) {
202
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportWrongRoot({ base, path, subtag }));
203
+ return false;
204
+ }
205
+ // pull all children of importXml[subtag] into obj
206
+ for (const subsubtag of Object.keys(importRootNode).reverse()) { // e.g. <key/>
207
+ const subsubval = importRootNode[subsubtag];
208
+ const basePath = `${base}/${path}`;
209
+ if (!Array.isArray(subsubval)) {
210
+ // This is somewhat of an internal error, indicating that a non-mergeable XML file was imported
211
+ // Not exercisable with the standard LDML imports.
212
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportMergeFail({ base, path, subtag, subsubtag }));
213
+ return false;
214
+ }
215
+ // Mark all children as an import
216
+ subsubval.forEach(o => o[ImportStatus.import] = basePath);
217
+ if (implied) {
218
+ // mark all children as an implied import
219
+ subsubval.forEach(o => o[ImportStatus.impliedImport] = basePath);
220
+ }
221
+ if (!obj[subsubtag]) {
222
+ obj[subsubtag] = []; // start with empty array
223
+ }
224
+ obj[subsubtag] = [...subsubval, ...obj[subsubtag]];
225
+ }
226
+ return true;
227
+ }
228
+ /**
229
+ * @returns true if valid, false if invalid
230
+ */
231
+ validate(source) {
232
+ if (!SchemaValidators.ldmlKeyboard3(source)) {
233
+ for (let err of SchemaValidators.ldmlKeyboard3.errors) {
234
+ this.callbacks.reportMessage(CommonTypesMessages.Error_SchemaValidationError({
235
+ instancePath: err.instancePath,
236
+ keyword: err.keyword,
237
+ message: err.message || 'Unknown AJV Error',
238
+ params: Object.entries(err.params || {}).sort().map(([k, v]) => `${k}="${v}"`).join(' '),
239
+ }));
240
+ }
241
+ return false;
242
+ }
243
+ return true;
244
+ }
245
+ loadUnboxed(file) {
246
+ let source = (() => {
247
+ let a;
248
+ let parser = new xml2js.Parser({
249
+ explicitArray: false,
250
+ mergeAttrs: true,
251
+ includeWhiteChars: false,
252
+ emptyTag: {}
253
+ // Why "as any"? xml2js is broken:
254
+ // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
255
+ // that an old version of `emptyTag` is used which doesn't support
256
+ // functions, but DefinitelyTyped is requiring use of function or a
257
+ // string. See also notes at
258
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
259
+ // An alternative fix would be to pull xml2js directly from github
260
+ // rather than using the version tagged on npmjs.com.
261
+ });
262
+ parser.parseString(file, (e, r) => { a = r; }); // TODO-LDML: isn't 'e' the error?
263
+ return a;
264
+ })();
265
+ return source;
266
+ }
267
+ /**
268
+ * @param file
269
+ * @returns source on success, otherwise null
270
+ */
271
+ load(file) {
272
+ if (!file) {
273
+ return null;
274
+ }
275
+ const source = this.loadUnboxed(file);
276
+ if (this.boxArrays(source)) {
277
+ return source;
278
+ }
279
+ else {
280
+ return null;
281
+ }
282
+ }
283
+ loadTestDataUnboxed(file) {
284
+ let source = (() => {
285
+ let a;
286
+ let parser = new xml2js.Parser({
287
+ // explicitArray: false,
288
+ preserveChildrenOrder: true,
289
+ explicitChildren: true, // needed for test data
290
+ // mergeAttrs: true,
291
+ // includeWhiteChars: false,
292
+ // emptyTag: {} as any
293
+ // Why "as any"? xml2js is broken:
294
+ // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
295
+ // that an old version of `emptyTag` is used which doesn't support
296
+ // functions, but DefinitelyTyped is requiring use of function or a
297
+ // string. See also notes at
298
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
299
+ // An alternative fix would be to pull xml2js directly from github
300
+ // rather than using the version tagged on npmjs.com.
301
+ });
302
+ parser.parseString(file, (e, r) => { a = r; }); // TODO-LDML: isn't 'e' the error?
303
+ return a; // Why 'any'? Because we need to box up the $'s into proper properties.
304
+ })();
305
+ return source;
306
+ }
307
+ /**
308
+ * Filter the obj array for a subtag
309
+ * @param source array of source objs
310
+ * @param subtag subtag to filter on
311
+ * @returns
312
+ */
313
+ findSubtagArray(source, subtag) {
314
+ return source?.filter(o => o['#name'] === subtag);
315
+ }
316
+ /**
317
+ * Get exactly one element
318
+ * @param source
319
+ * @param subtag
320
+ * @returns
321
+ */
322
+ findSubtag(source, subtag) {
323
+ const r = this.findSubtagArray(source, subtag);
324
+ if (!r || r.length === 0) {
325
+ return null;
326
+ }
327
+ else if (r.length === 1) {
328
+ return r[0];
329
+ }
330
+ else {
331
+ this.callbacks.reportMessage(CommonTypesMessages.Error_TestDataUnexpectedArray({ subtag }));
332
+ return null; // ERROR
333
+ }
334
+ }
335
+ /**
336
+ * The default test data stuffer.
337
+ * Just gets $ (the attrs) as the body.
338
+ * Override to use something more complex, such as including child nodes.
339
+ * @param o object to map
340
+ * @param r back ref to reader
341
+ */
342
+ static defaultMapper = ((o, r) => o?.$);
343
+ /**
344
+ *
345
+ * @param obj target object
346
+ * @param source array of $/#name strings
347
+ * @param subtag name to extract
348
+ * @param mapper custom mapper function
349
+ */
350
+ stuffBoxes(obj, source, subtag, asArray, mapper) {
351
+ if (!mapper) {
352
+ mapper = LDMLKeyboardXMLSourceFileReader.defaultMapper;
353
+ }
354
+ if (asArray) {
355
+ const r = this;
356
+ obj[subtag] = this.findSubtagArray(source, subtag)?.map((v) => mapper(v, r)); // extract contents only
357
+ }
358
+ else {
359
+ obj[subtag] = mapper(this.findSubtag(source, subtag), this); // run the mapper once
360
+ }
361
+ }
362
+ boxTestDataArrays(raw) {
363
+ if (!raw)
364
+ return null;
365
+ const a = {
366
+ keyboardTest3: {
367
+ conformsTo: raw?.keyboardTest3?.$?.conformsTo,
368
+ }
369
+ };
370
+ const $$ = raw?.keyboardTest3?.$$;
371
+ this.stuffBoxes(a.keyboardTest3, $$, 'info');
372
+ this.stuffBoxes(a.keyboardTest3, $$, 'repertoire', true);
373
+ this.stuffBoxes(a.keyboardTest3, $$, 'tests', true, (o, r) => {
374
+ // start with basic unpack
375
+ const tests = LDMLKeyboardXMLSourceFileReader.defaultMapper(o, r);
376
+ // add ingredients
377
+ r.stuffBoxes(tests, o.$$, 'test', true, (o, r) => {
378
+ // start with basic unpack
379
+ const test = LDMLKeyboardXMLSourceFileReader.defaultMapper(o, r);
380
+ // add ingredients
381
+ const $$ = o.$$;
382
+ r.stuffBoxes(test, $$, 'startContext'); // singleton
383
+ // now the actions
384
+ test.actions = $$.map(v => {
385
+ const type = v['#name']; // element name
386
+ if (type === 'startContext') {
387
+ return null; // handled above
388
+ }
389
+ const subv = LDMLKeyboardXMLSourceFileReader.defaultMapper(v, r);
390
+ return Object.assign({ type }, subv);
391
+ }).filter(v => v !== null);
392
+ return test;
393
+ });
394
+ return tests;
395
+ });
396
+ return a;
397
+ }
398
+ /**
399
+ * @param file test file
400
+ * @returns source on success, otherwise null
401
+ */
402
+ loadTestData(file) {
403
+ if (!file) {
404
+ return null;
405
+ }
406
+ const source = this.loadTestDataUnboxed(file);
407
+ return this.boxTestDataArrays(source);
408
+ }
409
+ }
410
410
  //# sourceMappingURL=ldml-keyboard-xml-reader.js.map
411
+ //# debugId=065afd3b-524c-565a-b20d-4b1e3cfd778f