@keymanapp/kmc-package 17.0.155-alpha → 17.0.157-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 (61) hide show
  1. package/build/src/compiler/cp1252.d.ts +10 -0
  2. package/build/src/compiler/cp1252.d.ts.map +1 -0
  3. package/build/src/compiler/cp1252.js +289 -0
  4. package/build/src/compiler/cp1252.js.map +1 -0
  5. package/build/src/compiler/kmp-compiler.d.ts +28 -25
  6. package/build/src/compiler/kmp-compiler.d.ts.map +1 -1
  7. package/build/src/compiler/kmp-compiler.js +333 -265
  8. package/build/src/compiler/kmp-compiler.js.map +1 -1
  9. package/build/src/compiler/kmp-inf-writer.d.ts +24 -0
  10. package/build/src/compiler/kmp-inf-writer.d.ts.map +1 -0
  11. package/build/src/compiler/kmp-inf-writer.js +145 -0
  12. package/build/src/compiler/kmp-inf-writer.js.map +1 -0
  13. package/build/src/compiler/kmx-keyboard-metadata.d.ts +6 -0
  14. package/build/src/compiler/kmx-keyboard-metadata.d.ts.map +1 -0
  15. package/build/src/compiler/kmx-keyboard-metadata.js +18 -0
  16. package/build/src/compiler/kmx-keyboard-metadata.js.map +1 -0
  17. package/build/src/compiler/messages.d.ts +114 -114
  18. package/build/src/compiler/messages.d.ts.map +1 -1
  19. package/build/src/compiler/messages.js +70 -67
  20. package/build/src/compiler/messages.js.map +1 -1
  21. package/build/src/compiler/package-keyboard-target-validator.d.ts +15 -0
  22. package/build/src/compiler/package-keyboard-target-validator.d.ts.map +1 -0
  23. package/build/src/compiler/package-keyboard-target-validator.js +36 -0
  24. package/build/src/compiler/package-keyboard-target-validator.js.map +1 -0
  25. package/build/src/compiler/package-metadata-collector.d.ts +19 -0
  26. package/build/src/compiler/package-metadata-collector.d.ts.map +1 -0
  27. package/build/src/compiler/package-metadata-collector.js +78 -0
  28. package/build/src/compiler/package-metadata-collector.js.map +1 -0
  29. package/build/src/compiler/package-metadata-updater.d.ts +7 -0
  30. package/build/src/compiler/package-metadata-updater.d.ts.map +1 -0
  31. package/build/src/compiler/package-metadata-updater.js +13 -0
  32. package/build/src/compiler/package-metadata-updater.js.map +1 -0
  33. package/build/src/compiler/package-validation.d.ts +18 -15
  34. package/build/src/compiler/package-validation.d.ts.map +1 -1
  35. package/build/src/compiler/package-validation.js +162 -152
  36. package/build/src/compiler/package-validation.js.map +1 -1
  37. package/build/src/compiler/package-version-validator.d.ts +23 -0
  38. package/build/src/compiler/package-version-validator.d.ts.map +1 -0
  39. package/build/src/compiler/package-version-validator.js +92 -0
  40. package/build/src/compiler/package-version-validator.js.map +1 -0
  41. package/build/src/compiler/redist-files.d.ts +20 -18
  42. package/build/src/compiler/redist-files.d.ts.map +1 -1
  43. package/build/src/compiler/redist-files.js +59 -57
  44. package/build/src/compiler/redist-files.js.map +1 -1
  45. package/build/src/compiler/web-keyboard-metadata.d.ts +22 -0
  46. package/build/src/compiler/web-keyboard-metadata.d.ts.map +1 -0
  47. package/build/src/compiler/web-keyboard-metadata.js +34 -0
  48. package/build/src/compiler/web-keyboard-metadata.js.map +1 -0
  49. package/build/src/main.d.ts +5 -3
  50. package/build/src/main.d.ts.map +1 -1
  51. package/build/src/main.js +5 -3
  52. package/build/src/main.js.map +1 -1
  53. package/package.json +7 -8
  54. package/build/src/compiler/keyman-targets.d.ts +0 -18
  55. package/build/src/compiler/keyman-targets.d.ts.map +0 -1
  56. package/build/src/compiler/keyman-targets.js +0 -53
  57. package/build/src/compiler/keyman-targets.js.map +0 -1
  58. package/build/src/compiler/package-version-validation.d.ts +0 -24
  59. package/build/src/compiler/package-version-validation.d.ts.map +0 -1
  60. package/build/src/compiler/package-version-validation.js +0 -153
  61. package/build/src/compiler/package-version-validation.js.map +0 -1
@@ -1,265 +1,333 @@
1
- import * as xml2js from 'xml2js';
2
- import JSZip from 'jszip';
3
- import KEYMAN_VERSION from "@keymanapp/keyman-version";
4
- import { KvkFile } from '@keymanapp/common-types';
5
- import { CompilerMessages } from './messages.js';
6
- import { PackageVersionValidation } from './package-version-validation.js';
7
- const FILEVERSION_KMP_JSON = '12.0';
8
- export class KmpCompiler {
9
- callbacks;
10
- constructor(callbacks) {
11
- this.callbacks = callbacks;
12
- }
13
- transformKpsToKmpObject(kpsFilename) {
14
- // Load the KPS data from XML as JS structured data.
15
- const buffer = this.callbacks.loadFile(kpsFilename);
16
- if (!buffer) {
17
- this.callbacks.reportMessage(CompilerMessages.Error_FileDoesNotExist({ filename: kpsFilename }));
18
- return null;
19
- }
20
- const data = new TextDecoder().decode(buffer);
21
- const kpsPackage = (() => {
22
- let a;
23
- let parser = new xml2js.Parser({
24
- tagNameProcessors: [xml2js.processors.firstCharLowerCase],
25
- explicitArray: false
26
- });
27
- // TODO: add unit test for xml errors parsing .kps file
28
- parser.parseString(data, (e, r) => { if (e)
29
- throw e; a = r; });
30
- return a;
31
- })();
32
- let kps = kpsPackage.package;
33
- //
34
- // To convert to kmp.json, we need to:
35
- //
36
- // 1. Unwrap arrays (and convert to array where single object)
37
- // 2. Fix casing on `iD`
38
- // 3. Rewrap info, keyboard.languages, lexicalModel.languages, startMenu.items elements
39
- // 4. Remove options.followKeyboardVersion, file.fileType
40
- // 5. Convert file.copyLocation to a Number
41
- // 6. Filenames need to be basenames (but this comes after processing)
42
- //
43
- // Start to construct the kmp.json file from the .kps file
44
- let kmp = {
45
- system: {
46
- fileVersion: FILEVERSION_KMP_JSON,
47
- keymanDeveloperVersion: KEYMAN_VERSION.VERSION
48
- },
49
- options: {}
50
- };
51
- //
52
- // Fill in additional fields
53
- //
54
- let keys = [
55
- ['executeProgram', 'executeProgram'],
56
- ['graphicFile', 'graphicFile'],
57
- ['msiFileName', 'msiFilename'],
58
- ['msiOptions', 'msiOptions'],
59
- ['readMeFile', 'readmeFile']
60
- ];
61
- if (kps.options) {
62
- for (let [src, dst] of keys) {
63
- if (kps.options[src]) {
64
- kmp.options[dst] = kps.options[src];
65
- }
66
- }
67
- }
68
- //
69
- // Add basic metadata
70
- //
71
- if (kps.info) {
72
- kmp.info = this.kpsInfoToKmpInfo(kps.info);
73
- }
74
- //
75
- // Add file metadata
76
- //
77
- if (kps.files && kps.files.file) {
78
- kmp.files = this.arrayWrap(kps.files.file).map((file) => {
79
- return {
80
- name: file.name,
81
- description: file.description,
82
- copyLocation: parseInt(file.copyLocation, 10) || undefined
83
- // note: we don't emit fileType as that is not permitted in kmp.json
84
- };
85
- });
86
- }
87
- kmp.files = kmp.files ?? [];
88
- // Add the standard kmp.json self-referential to match existing implementations
89
- kmp.files.push({
90
- name: "kmp.json",
91
- description: "Package information (JSON)"
92
- });
93
- //
94
- // Add keyboard metadata
95
- //
96
- if (kps.keyboards && kps.keyboards.keyboard) {
97
- kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard) => ({
98
- displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined,
99
- oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined,
100
- name: keyboard.name,
101
- id: keyboard.iD,
102
- version: keyboard.version,
103
- languages: keyboard.languages ?
104
- this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language)) :
105
- []
106
- }));
107
- }
108
- //
109
- // Add lexical-model metadata
110
- //
111
- if (kps.lexicalModels && kps.lexicalModels.lexicalModel) {
112
- kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model) => ({
113
- name: model.name,
114
- id: model.iD,
115
- languages: model.languages ?
116
- this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language)) : []
117
- }));
118
- }
119
- //
120
- // Verify version metadata; doing this in the transform
121
- // while we have access to the .kps metadata, and keeping the
122
- //
123
- const versionValidator = new PackageVersionValidation(this.callbacks);
124
- if (!versionValidator.validateAndUpdateVersions(kpsFilename, kps, kmp)) {
125
- return null;
126
- }
127
- //
128
- // Add Windows Start Menu metadata
129
- //
130
- if (kps.startMenu && kps.startMenu.items) {
131
- kmp.startMenu = {};
132
- if (kps.startMenu.addUninstallEntry)
133
- kmp.startMenu.addUninstallEntry = kps.startMenu.addUninstallEntry === '';
134
- if (kps.startMenu.folder)
135
- kmp.startMenu.folder = kps.startMenu.folder;
136
- if (kps.startMenu.items && kps.startMenu.items.item)
137
- kmp.startMenu.items = this.arrayWrap(kps.startMenu.items.item);
138
- }
139
- //
140
- // Add translation strings
141
- //
142
- if (kps.strings && kps.strings.string) {
143
- kmp.strings = this.arrayWrap(kps.strings.string);
144
- }
145
- kmp = this.stripUndefined(kmp);
146
- return kmp;
147
- }
148
- // Helper functions
149
- kpsInfoToKmpInfo(info) {
150
- let ni = {};
151
- const keys = [
152
- ['author', 'author'],
153
- ['copyright', 'copyright'],
154
- ['name', 'name'],
155
- ['version', 'version'],
156
- ['webSite', 'website']
157
- ];
158
- for (let [src, dst] of keys) {
159
- if (info[src]) {
160
- ni[dst] = { description: info[src]._ ?? (typeof info[src] == 'string' ? info[src].toString() : '') };
161
- if (info[src].$ && info[src].$.URL)
162
- ni[dst].url = info[src].$.URL;
163
- }
164
- }
165
- return ni;
166
- }
167
- ;
168
- arrayWrap(a) {
169
- if (Array.isArray(a)) {
170
- return a;
171
- }
172
- return [a];
173
- }
174
- ;
175
- kpsLanguagesToKmpLanguages(language) {
176
- return language.map((element) => { return { name: element._, id: element.$.ID }; });
177
- }
178
- ;
179
- stripUndefined(o) {
180
- for (const key in o) {
181
- if (o[key] === undefined) {
182
- delete o[key];
183
- }
184
- else if (typeof o[key] == 'object') {
185
- o[key] = this.stripUndefined(o[key]);
186
- }
187
- }
188
- return o;
189
- }
190
- /**
191
- * Returns a Promise to the serialized data which can then be written to a .kmp file.
192
- *
193
- * @param kpsFilename - Filename of the kps, not read, used only for calculating relative paths
194
- * @param kmpJsonData - The kmp.json Object
195
- */
196
- buildKmpFile(kpsFilename, kmpJsonData) {
197
- const zip = JSZip();
198
- const kmpJsonFileName = 'kmp.json';
199
- // Make a copy of kmpJsonData, as we mutate paths for writing
200
- const data = JSON.parse(JSON.stringify(kmpJsonData));
201
- if (!data.files) {
202
- data.files = [];
203
- }
204
- let failed = false;
205
- data.files.forEach((value) => {
206
- // Get the path of the file
207
- let filename = value.name;
208
- // We add this separately after zipping all other files
209
- if (filename == 'kmp.json') {
210
- return;
211
- }
212
- if (this.callbacks.path.isAbsolute(filename)) {
213
- // absolute paths are not portable to other computers
214
- this.callbacks.reportMessage(CompilerMessages.Warn_AbsolutePath({ filename: filename }));
215
- }
216
- filename = this.callbacks.resolveFilename(kpsFilename, filename);
217
- const basename = this.callbacks.path.basename(filename);
218
- if (!this.callbacks.fs.existsSync(filename)) {
219
- this.callbacks.reportMessage(CompilerMessages.Error_FileDoesNotExist({ filename: filename }));
220
- failed = true;
221
- return;
222
- }
223
- let memberFileData;
224
- try {
225
- memberFileData = this.callbacks.loadFile(filename);
226
- }
227
- catch (e) {
228
- this.callbacks.reportMessage(CompilerMessages.Error_FileCouldNotBeRead({ filename: filename, e: e }));
229
- failed = true;
230
- return;
231
- }
232
- this.warnIfKvkFileIsNotBinary(filename, memberFileData);
233
- zip.file(basename, memberFileData);
234
- // Remove path data from files before JSON save
235
- value.name = basename;
236
- });
237
- if (failed) {
238
- return null;
239
- }
240
- zip.file(kmpJsonFileName, JSON.stringify(data, null, 2));
241
- // Generate kmp file
242
- return zip.generateAsync({ type: 'binarystring', compression: 'DEFLATE' });
243
- }
244
- /**
245
- * Legacy .kmp compiler would transform xml-format .kvk files into a binary .kvk file; now
246
- * we want that to remain the responsibility of the keyboard compiler, so we'll warn the
247
- * few users who are still doing this
248
- */
249
- warnIfKvkFileIsNotBinary(filename, data) {
250
- if (!filename.match(/\.kvk$/)) {
251
- return;
252
- }
253
- if (data.byteLength < 4) {
254
- // TODO: Not a valid .kvk file; should we be reporting this?
255
- return;
256
- }
257
- if (data[0] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[0] ||
258
- data[1] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[1] ||
259
- data[2] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[2] ||
260
- data[3] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[3]) {
261
- this.callbacks.reportMessage(CompilerMessages.Warn_FileIsNotABinaryKvkFile({ filename: filename }));
262
- }
263
- }
264
- }
265
- //# sourceMappingURL=kmp-compiler.js.map
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]="149aa499-2354-5472-a58b-4584cba7a5fe")}catch(e){}}();
2
+ import * as xml2js from 'xml2js';
3
+ import JSZip from 'jszip';
4
+ import KEYMAN_VERSION from "@keymanapp/keyman-version";
5
+ import { KeymanFileTypes, KvkFile } from '@keymanapp/common-types';
6
+ import { CompilerMessages } from './messages.js';
7
+ import { PackageMetadataCollector } from './package-metadata-collector.js';
8
+ import { KmpInfWriter } from './kmp-inf-writer.js';
9
+ import { transcodeToCP1252 } from './cp1252.js';
10
+ import { MIN_LM_FILEVERSION_KMP_JSON, PackageVersionValidator } from './package-version-validator.js';
11
+ import { PackageKeyboardTargetValidator } from './package-keyboard-target-validator.js';
12
+ import { PackageMetadataUpdater } from './package-metadata-updater.js';
13
+ const KMP_JSON_FILENAME = 'kmp.json';
14
+ const KMP_INF_FILENAME = 'kmp.inf';
15
+ export class KmpCompiler {
16
+ callbacks;
17
+ constructor(callbacks) {
18
+ this.callbacks = callbacks;
19
+ }
20
+ transformKpsToKmpObject(kpsFilename) {
21
+ // Load the KPS data from XML as JS structured data.
22
+ const buffer = this.callbacks.loadFile(kpsFilename);
23
+ if (!buffer) {
24
+ this.callbacks.reportMessage(CompilerMessages.Error_FileDoesNotExist({ filename: kpsFilename }));
25
+ return null;
26
+ }
27
+ const data = new TextDecoder().decode(buffer);
28
+ const kpsPackage = (() => {
29
+ let a;
30
+ let parser = new xml2js.Parser({
31
+ tagNameProcessors: [xml2js.processors.firstCharLowerCase],
32
+ explicitArray: false
33
+ });
34
+ // TODO: add unit test for xml errors parsing .kps file
35
+ parser.parseString(data, (e, r) => { if (e)
36
+ throw e; a = r; });
37
+ return a;
38
+ })();
39
+ let kps = kpsPackage.package;
40
+ //
41
+ // To convert to kmp.json, we need to:
42
+ //
43
+ // 1. Unwrap arrays (and convert to array where single object)
44
+ // 2. Fix casing on `iD`
45
+ // 3. Rewrap info, keyboard.languages, lexicalModel.languages, startMenu.items elements
46
+ // 4. Remove options.followKeyboardVersion, file.fileType
47
+ // 5. Convert file.copyLocation to a Number
48
+ // 6. Filenames need to be basenames (but this comes after processing)
49
+ //
50
+ // Start to construct the kmp.json file from the .kps file
51
+ let kmp = {
52
+ system: {
53
+ fileVersion: null,
54
+ keymanDeveloperVersion: KEYMAN_VERSION.VERSION
55
+ },
56
+ options: {}
57
+ };
58
+ //
59
+ // Fill in additional fields
60
+ //
61
+ let keys = [
62
+ ['executeProgram', 'executeProgram'],
63
+ ['graphicFile', 'graphicFile'],
64
+ ['msiFileName', 'msiFilename'],
65
+ ['msiOptions', 'msiOptions'],
66
+ ['readMeFile', 'readmeFile']
67
+ ];
68
+ if (kps.options) {
69
+ for (let [src, dst] of keys) {
70
+ if (kps.options[src]) {
71
+ if (dst == 'graphicFile' || dst == 'readmeFile') {
72
+ kmp.options[dst] = /[/\\]?([^/\\]*)$/.exec(kps.options[src])[1];
73
+ }
74
+ else {
75
+ kmp.options[dst] = kps.options[src];
76
+ }
77
+ }
78
+ }
79
+ }
80
+ //
81
+ // Add basic metadata
82
+ //
83
+ if (kps.info) {
84
+ kmp.info = this.kpsInfoToKmpInfo(kps.info);
85
+ }
86
+ //
87
+ // Add file metadata
88
+ //
89
+ if (kps.files && kps.files.file) {
90
+ kmp.files = this.arrayWrap(kps.files.file).map((file) => {
91
+ return {
92
+ name: file.name.trim(),
93
+ description: file.description.trim(),
94
+ copyLocation: parseInt(file.copyLocation, 10) || undefined
95
+ // note: we don't emit fileType as that is not permitted in kmp.json
96
+ };
97
+ });
98
+ }
99
+ kmp.files = kmp.files ?? [];
100
+ // Keyboard packages also include a legacy kmp.inf file (this will be removed,
101
+ // one day)
102
+ if (kps.keyboards && kps.keyboards.keyboard) {
103
+ kmp.files.push({
104
+ name: KMP_INF_FILENAME,
105
+ description: "Package information"
106
+ });
107
+ }
108
+ // Add the standard kmp.json self-referential to match existing implementations
109
+ kmp.files.push({
110
+ name: KMP_JSON_FILENAME,
111
+ description: "Package information (JSON)"
112
+ });
113
+ //
114
+ // Add keyboard metadata
115
+ //
116
+ if (kps.keyboards && kps.keyboards.keyboard) {
117
+ kmp.keyboards = this.arrayWrap(kps.keyboards.keyboard).map((keyboard) => ({
118
+ displayFont: keyboard.displayFont ? this.callbacks.path.basename(keyboard.displayFont) : undefined,
119
+ oskFont: keyboard.oSKFont ? this.callbacks.path.basename(keyboard.oSKFont) : undefined,
120
+ name: keyboard.name.trim(),
121
+ id: keyboard.iD.trim(),
122
+ version: keyboard.version.trim(),
123
+ rtl: keyboard.rTL == 'True' ? true : undefined,
124
+ languages: keyboard.languages ?
125
+ this.kpsLanguagesToKmpLanguages(this.arrayWrap(keyboard.languages.language)) :
126
+ []
127
+ }));
128
+ }
129
+ //
130
+ // Add lexical-model metadata
131
+ //
132
+ if (kps.lexicalModels && kps.lexicalModels.lexicalModel) {
133
+ kmp.lexicalModels = this.arrayWrap(kps.lexicalModels.lexicalModel).map((model) => ({
134
+ name: model.name.trim(),
135
+ id: model.iD.trim(),
136
+ languages: model.languages ?
137
+ this.kpsLanguagesToKmpLanguages(this.arrayWrap(model.languages.language)) : []
138
+ }));
139
+ }
140
+ //
141
+ // Collect metadata from keyboards (and later models) in order to update
142
+ // the kmp.json metadata for use downstream in apps. This will also be
143
+ // used later to fill in .keyboard_info file data.
144
+ //
145
+ const collector = new PackageMetadataCollector(this.callbacks);
146
+ const metadata = collector.collectKeyboardMetadata(kpsFilename, kmp);
147
+ if (metadata == null) {
148
+ return null;
149
+ }
150
+ //
151
+ // Verify keyboard versions and update version metadata where appropriate
152
+ //
153
+ const versionValidator = new PackageVersionValidator(this.callbacks);
154
+ if (!versionValidator.validateAndUpdateVersions(kps, kmp, metadata)) {
155
+ return null;
156
+ }
157
+ if (kps.keyboards && kps.keyboards.keyboard) {
158
+ kmp.system.fileVersion = versionValidator.getMinKeymanVersion(metadata);
159
+ }
160
+ else {
161
+ kmp.system.fileVersion = MIN_LM_FILEVERSION_KMP_JSON;
162
+ }
163
+ //
164
+ // Verify that packages that target mobile devices include a .js file
165
+ //
166
+ const targetValidator = new PackageKeyboardTargetValidator(this.callbacks);
167
+ targetValidator.verifyAllTargets(kmp, metadata);
168
+ //
169
+ // Update assorted keyboard metadata from the keyboards in the package
170
+ //
171
+ const updater = new PackageMetadataUpdater();
172
+ updater.updatePackage(metadata);
173
+ //
174
+ // Add Windows Start Menu metadata
175
+ //
176
+ if (kps.startMenu && (kps.startMenu.folder || kps.startMenu.items)) {
177
+ kmp.startMenu = {};
178
+ if (kps.startMenu.addUninstallEntry === '')
179
+ kmp.startMenu.addUninstallEntry = true;
180
+ if (kps.startMenu.folder)
181
+ kmp.startMenu.folder = kps.startMenu.folder;
182
+ if (kps.startMenu.items && kps.startMenu.items.item) {
183
+ kmp.startMenu.items = this.arrayWrap(kps.startMenu.items.item);
184
+ // Remove default values
185
+ for (let item of kmp.startMenu.items) {
186
+ if (item.icon == '')
187
+ delete item.icon;
188
+ if (item.location == 'psmelStartMenu')
189
+ delete item.location;
190
+ if (item.arguments == '')
191
+ delete item.arguments;
192
+ // Horrific case change between .kps and kmp.json:
193
+ item.filename = item.fileName;
194
+ delete item.fileName;
195
+ }
196
+ }
197
+ else {
198
+ kmp.startMenu.items = [];
199
+ }
200
+ }
201
+ kmp = this.stripUndefined(kmp);
202
+ return kmp;
203
+ }
204
+ // Helper functions
205
+ kpsInfoToKmpInfo(info) {
206
+ let ni = {};
207
+ const keys = [
208
+ ['author', 'author'],
209
+ ['copyright', 'copyright'],
210
+ ['name', 'name'],
211
+ ['version', 'version'],
212
+ ['webSite', 'website']
213
+ ];
214
+ for (let [src, dst] of keys) {
215
+ if (info[src]) {
216
+ ni[dst] = { description: info[src]._ ?? (typeof info[src] == 'string' ? info[src].toString() : '') };
217
+ if (info[src].$ && info[src].$.URL)
218
+ ni[dst].url = info[src].$.URL;
219
+ }
220
+ }
221
+ return ni;
222
+ }
223
+ ;
224
+ arrayWrap(a) {
225
+ if (Array.isArray(a)) {
226
+ return a;
227
+ }
228
+ return [a];
229
+ }
230
+ ;
231
+ kpsLanguagesToKmpLanguages(language) {
232
+ if (language.length == 0 || language[0] == undefined) {
233
+ return [];
234
+ }
235
+ return language.map((element) => { return { name: element._, id: element.$.ID }; });
236
+ }
237
+ ;
238
+ stripUndefined(o) {
239
+ for (const key in o) {
240
+ if (o[key] === undefined) {
241
+ delete o[key];
242
+ }
243
+ else if (typeof o[key] == 'object') {
244
+ o[key] = this.stripUndefined(o[key]);
245
+ }
246
+ }
247
+ return o;
248
+ }
249
+ /**
250
+ * Returns a Promise to the serialized data which can then be written to a .kmp file.
251
+ *
252
+ * @param kpsFilename - Filename of the kps, not read, used only for calculating relative paths
253
+ * @param kmpJsonData - The kmp.json Object
254
+ */
255
+ buildKmpFile(kpsFilename, kmpJsonData) {
256
+ const zip = JSZip();
257
+ // Make a copy of kmpJsonData, as we mutate paths for writing
258
+ const data = JSON.parse(JSON.stringify(kmpJsonData));
259
+ if (!data.files) {
260
+ data.files = [];
261
+ }
262
+ const hasKmpInf = !!data.files.find(file => file.name == KMP_INF_FILENAME);
263
+ let failed = false;
264
+ data.files.forEach((value) => {
265
+ // Get the path of the file
266
+ let filename = value.name;
267
+ // We add this separately after zipping all other files
268
+ if (filename == KMP_JSON_FILENAME || filename == KMP_INF_FILENAME) {
269
+ return;
270
+ }
271
+ if (this.callbacks.path.isAbsolute(filename)) {
272
+ // absolute paths are not portable to other computers
273
+ this.callbacks.reportMessage(CompilerMessages.Warn_AbsolutePath({ filename: filename }));
274
+ }
275
+ filename = this.callbacks.resolveFilename(kpsFilename, filename);
276
+ const basename = this.callbacks.path.basename(filename);
277
+ if (!this.callbacks.fs.existsSync(filename)) {
278
+ this.callbacks.reportMessage(CompilerMessages.Error_FileDoesNotExist({ filename: filename }));
279
+ failed = true;
280
+ return;
281
+ }
282
+ let memberFileData;
283
+ try {
284
+ memberFileData = this.callbacks.loadFile(filename);
285
+ }
286
+ catch (e) {
287
+ this.callbacks.reportMessage(CompilerMessages.Error_FileCouldNotBeRead({ filename: filename, e: e }));
288
+ failed = true;
289
+ return;
290
+ }
291
+ this.warnIfKvkFileIsNotBinary(filename, memberFileData);
292
+ zip.file(basename, memberFileData);
293
+ // Remove path data from files before JSON save
294
+ value.name = basename;
295
+ });
296
+ if (failed) {
297
+ return null;
298
+ }
299
+ zip.file(KMP_JSON_FILENAME, JSON.stringify(data, null, 2));
300
+ if (hasKmpInf) {
301
+ zip.file(KMP_INF_FILENAME, this.buildKmpInf(data));
302
+ }
303
+ // Generate kmp file
304
+ return zip.generateAsync({ type: 'binarystring', compression: 'DEFLATE' });
305
+ }
306
+ buildKmpInf(data) {
307
+ const writer = new KmpInfWriter(data);
308
+ const s = writer.write();
309
+ return transcodeToCP1252(s);
310
+ }
311
+ /**
312
+ * Legacy .kmp compiler would transform xml-format .kvk files into a binary .kvk file; now
313
+ * we want that to remain the responsibility of the keyboard compiler, so we'll warn the
314
+ * few users who are still doing this
315
+ */
316
+ warnIfKvkFileIsNotBinary(filename, data) {
317
+ if (!KeymanFileTypes.filenameIs(filename, ".kvk" /* KeymanFileTypes.Binary.VisualKeyboard */)) {
318
+ return;
319
+ }
320
+ if (data.byteLength < 4) {
321
+ // TODO: Not a valid .kvk file; should we be reporting this?
322
+ return;
323
+ }
324
+ if (data[0] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[0] ||
325
+ data[1] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[1] ||
326
+ data[2] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[2] ||
327
+ data[3] != KvkFile.KVK_HEADER_IDENTIFIER_BYTES[3]) {
328
+ this.callbacks.reportMessage(CompilerMessages.Warn_FileIsNotABinaryKvkFile({ filename: filename }));
329
+ }
330
+ }
331
+ }
332
+ //# debugId=149aa499-2354-5472-a58b-4584cba7a5fe
333
+ //# sourceMappingURL=kmp-compiler.js.map