diff --git a/common/web/types/src/kpj/kpj-file-reader.ts b/common/web/types/src/kpj/kpj-file-reader.ts index 21e92c975b..9ac1bc8dbc 100644 --- a/common/web/types/src/kpj/kpj-file-reader.ts +++ b/common/web/types/src/kpj/kpj-file-reader.ts @@ -23,6 +23,12 @@ export class KPJFileReader { }); parser.parseString(file, (e: unknown, r: unknown) => { data = r as KPJFile }); + for(let file of data.KeymanDeveloperProject?.Files?.File) { + // xml2js imports
as '' so we will just delete the empty string + if(typeof file.Details == 'string') { + delete file.Details; + } + } data = this.boxArrays(data); return data as KPJFile; } diff --git a/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler.ts b/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler.ts index a4521b4fdc..65e2dbd13c 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler.ts @@ -8,7 +8,7 @@ import { VisualKeyboardFromFile } from "./visual-keyboard-compiler.js"; import { CompilerResult, STORETYPE_DEBUG, STORETYPE_OPTION, STORETYPE_RESERVED } from "../compiler/compiler.js"; function requote(s: string): string { - return "'" + s.replaceAll(/(['\\])/, "\\$1") + "'"; + return "'" + s.replaceAll(/(['\\])/g, "\\$1") + "'"; } export function RequotedString(s: string, RequoteSingleQuotes: boolean = false): string { diff --git a/developer/src/kmc-kmn/src/kmw-compiler/util.ts b/developer/src/kmc-kmn/src/kmw-compiler/util.ts index 21aa9d3c14..1b67b9c719 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/util.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/util.ts @@ -142,15 +142,17 @@ export function ExpandSentinel(fk: KMX.KEYBOARD, pwsz: string, x: number): TSent }; break; case KMX.KMXFile.CODE_RESETOPT: // I3429 + const resetOptIdx = pwsz.charCodeAt(x) - 1; result.ResetOpt = { - StoreIndex: pwsz.charCodeAt(x) - 1, - Store: fk.stores[result.ResetOpt.StoreIndex] + StoreIndex: resetOptIdx, + Store: fk.stores[resetOptIdx] }; break; case KMX.KMXFile.CODE_SAVEOPT: // I3429 + const saveOptIdx = pwsz.charCodeAt(x) - 1; result.SaveOpt = { - StoreIndex: pwsz.charCodeAt(x) - 1, - Store: fk.stores[result.SaveOpt.StoreIndex] + StoreIndex: saveOptIdx, + Store: fk.stores[saveOptIdx] }; break; case KMX.KMXFile.CODE_IFOPT: // I3429 diff --git a/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts b/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts index 1136a49c6a..bb9ebb1cbd 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/validate-layout-file.ts @@ -69,6 +69,12 @@ function CheckKey( FRequiredKeys: TRequiredKey[], FDictionary: string[] ): boolean { // I4119 + // + // Coerce missing ID and Text to empty strings for additional tests + // + + FId = FId ?? ''; + FText = FText ?? ''; // // Check that each touch layer has K_LOPT, [K_ROPT,] K_BKSP, K_ENTER @@ -101,7 +107,7 @@ function CheckKey( // if(FId.trim() == '') { - if(!(FKeyType in [TouchLayout.TouchLayoutKeySp.blank, TouchLayout.TouchLayoutKeySp.spacer]) && FNextLayer == '') { + if(!([TouchLayout.TouchLayoutKeySp.blank, TouchLayout.TouchLayoutKeySp.spacer].includes(FKeyType)) && FNextLayer == '') { callbacks.reportMessage(KmwCompilerMessages.Warn_TouchLayoutUnidentifiedKey({layerId: layer.id})); } return true; @@ -122,7 +128,7 @@ function CheckKey( // Check that each custom key code has at least *a* rule associated with it // - if (FValid == TKeyIdType.Key_Touch && FNextLayer == '' && FKeyType in [TouchLayout.TouchLayoutKeySp.normal, TouchLayout.TouchLayoutKeySp.deadkey]) { + if (FValid == TKeyIdType.Key_Touch && FNextLayer == '' && [TouchLayout.TouchLayoutKeySp.normal, TouchLayout.TouchLayoutKeySp.deadkey].includes(FKeyType)) { // Search for the key in the key dictionary - ignore K_LOPT, K_ROPT... if(FDictionary.indexOf(FId) < 0) { callbacks.reportMessage(KmwCompilerMessages.Warn_TouchLayoutCustomKeyNotDefined({keyId: FId, platformName: platformId, layerId: layer.id})); @@ -139,7 +145,7 @@ function CheckKey( if((CSpecialText10.includes(FText) || CSpecialText14.includes(FText)) && !CSpecialText14ZWNJ.includes(FText) && !IsKeyboardVersion14OrLater() && - !(FKeyType in [TouchLayout.TouchLayoutKeySp.special, TouchLayout.TouchLayoutKeySp.specialActive])) { + !([TouchLayout.TouchLayoutKeySp.special, TouchLayout.TouchLayoutKeySp.specialActive].includes(FKeyType))) { callbacks.reportMessage(KmwCompilerMessages.Warn_TouchLayoutSpecialLabelOnNormalKey({ keyId: FId, platformName: platformId, @@ -161,7 +167,7 @@ function CheckDictionaryKeyValidity(fk: KMX.KEYBOARD, FDictionary: string[]) { continue; } - if(KeyIdType(FDictionary[i]) in [TKeyIdType.Key_Invalid, TKeyIdType.Key_Constant]) { + if([TKeyIdType.Key_Invalid, TKeyIdType.Key_Constant].includes(KeyIdType(FDictionary[i]))) { for(let fgp of fk.groups) { if(fgp.fUsingKeys) { for(let fkp of fgp.keys) { @@ -217,9 +223,9 @@ export function ValidateLayoutFile(fk: KMX.KEYBOARD, FDebug: boolean, sLayoutFil // Test that the font matches on all platforms // I4872 if(FTouchLayoutFont == '') { - FTouchLayoutFont = platform.font; + FTouchLayoutFont = platform.font ?? ''; } - else if(platform.font.toLowerCase() != FTouchLayoutFont) { + else if(platform.font?.toLowerCase() ?? '' != FTouchLayoutFont) { callbacks.reportMessage(KmwCompilerMessages.Warn_TouchLayoutFontShouldBeSameForAllPlatforms()); // TODO: why support multiple font values if it has to be the same across all platforms?! } diff --git a/developer/src/kmc-package/src/compiler/package-validation.ts b/developer/src/kmc-package/src/compiler/package-validation.ts index 07fb5baaec..b663545fb0 100644 --- a/developer/src/kmc-package/src/compiler/package-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-validation.ts @@ -13,8 +13,8 @@ const MODEL_ID_PATTERN_PACKAGE = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a // const MODEL_ID_PATTERN_PROJECT = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_-]*\.[a-z_][a-z0-9_]*\.model\.kpj$/; // "Content files" within the package should adhere to these pattern: -const CONTENT_FILE_BASENAME_PATTERN = /^[a-z0-9_+.-]+$/; -const CONTENT_FILE_EXTENSION_PATTERN = /^\.[a-z0-9_]+$/; +const CONTENT_FILE_BASENAME_PATTERN = /^[a-z0-9_+.-]+$/i; // base names can be case insensitive +const CONTENT_FILE_EXTENSION_PATTERN = /^\.[a-z0-9_]+$/; // extensions should be lower-case export class PackageValidation { diff --git a/developer/src/kmc-package/src/compiler/package-version-validation.ts b/developer/src/kmc-package/src/compiler/package-version-validation.ts index 47e3e39b5c..b4f099ce13 100644 --- a/developer/src/kmc-package/src/compiler/package-version-validation.ts +++ b/developer/src/kmc-package/src/compiler/package-version-validation.ts @@ -73,7 +73,7 @@ export class PackageVersionValidation { if(result) { if(followKeyboardVersion) { - kmp.info.version.description = kmp.keyboards[0].version; + kmp.info.version = {description: kmp.keyboards[0].version}; } else if(kmp.info.version?.description != kmp.keyboards[0].version) { // Only need to compare against first keyboard as we compare keyboards above diff --git a/developer/src/kmc/src/commands/build.ts b/developer/src/kmc/src/commands/build.ts index c2e550ccc5..0f3fb38200 100644 --- a/developer/src/kmc/src/commands/build.ts +++ b/developer/src/kmc/src/commands/build.ts @@ -4,7 +4,7 @@ import { buildActivities } from './buildClasses/buildActivities.js'; import { BuildProject } from './buildClasses/BuildProject.js'; import { NodeCompilerCallbacks } from '../messages/NodeCompilerCallbacks.js'; import { InfrastructureMessages } from '../messages/messages.js'; -import { CompilerOptions, KeymanFileTypes } from '@keymanapp/common-types'; +import { CompilerErrorSeverity, CompilerOptions, KeymanFileTypes } from '@keymanapp/common-types'; import { BaseOptions } from '../util/baseOptions.js'; @@ -79,8 +79,11 @@ async function build(filename: string, options: CompilerOptions): Promise failureCodes.includes(m.code & CompilerErrorSeverity.Severity_Mask)); + if(result && firstFailureMessage == undefined) { callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename})); } else { callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename}));