From 19ebc627b3ddf8f39df561080cafb4a1ed0bbaae Mon Sep 17 00:00:00 2001 From: Sabine Date: Mon, 20 Apr 2026 17:24:49 +0200 Subject: [PATCH 01/33] feat(developer): ensure typesafety for 'return null' and others --- .../src/kmc-convert/src/converter-messages.ts | 2 +- developer/src/kmc-convert/src/converter.ts | 4 +- .../keylayout-to-kmn-converter.ts | 52 ++++++------ .../src/keylayout-to-kmn/kmn-file-writer.ts | 67 ++++++++------- .../test/keylayout-to-kmn-converter.tests.ts | 51 ++++++------ .../kmc-convert/test/kmn-file-writer.tests.ts | 83 ++++++++++++++++++- 6 files changed, 166 insertions(+), 93 deletions(-) diff --git a/developer/src/kmc-convert/src/converter-messages.ts b/developer/src/kmc-convert/src/converter-messages.ts index 42bfff9057..ea5e9b84cf 100644 --- a/developer/src/kmc-convert/src/converter-messages.ts +++ b/developer/src/kmc-convert/src/converter-messages.ts @@ -30,7 +30,7 @@ export class ConverterMessages { ); static ERROR_FileNotFound = SevError | 0x0003; - static Error_FileNotFound = (o: { inputFilename: string; }) => m( + static Error_FileNotFound = (o: { inputFilename: string | null; }) => m( this.ERROR_FileNotFound, `Input filename '${def(o.inputFilename)}' does not exist or could not be loaded.` ); diff --git a/developer/src/kmc-convert/src/converter.ts b/developer/src/kmc-convert/src/converter.ts index 6c32603fac..f1858fa5b5 100644 --- a/developer/src/kmc-convert/src/converter.ts +++ b/developer/src/kmc-convert/src/converter.ts @@ -68,9 +68,9 @@ export class Converter implements KeymanCompiler { return null; } - const ConverterClass = ConverterClassFactory.find(inputFilename, outputFilename); + const ConverterClass = ConverterClassFactory.find(inputFilename, outputFilename ??''); if (!ConverterClass) { - this.callbacks.reportMessage(ConverterMessages.Error_NoConverterFound({ inputFilename, outputFilename })); + this.callbacks.reportMessage(ConverterMessages.Error_NoConverterFound({ inputFilename, outputFilename: outputFilename ?? '' })); return null; } diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index caf939851c..49696712b2 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -45,12 +45,12 @@ export interface KeylayoutFileData { * Interface for storing data read from a .keylayout file and used for processing rules. * These are used for obtaining one entity form the other (e.g. from action id to output, from keycode to modifier, etc.) */ - actionId?: string; - keyCode?: string; - key?: string; - behavior?: string; + actionId?: string | undefined; + keyCode?: string | undefined; + key?: string | undefined; + behavior?: string | undefined; modifier?: string; - outchar?: string; + outchar?: string | undefined; }; export interface ActionStateOutput { @@ -117,7 +117,7 @@ export class KeylayoutToKmnConverter { constructor(private callbacks: CompilerCallbacks, options: CompilerOptions) { this.options = { ...options }; - }; + }; /** * @brief member function to run read/convert/write @@ -125,7 +125,7 @@ export class KeylayoutToKmnConverter { * @param outputFilename the resulting keyman .kmn-file * @return null on success */ - async run(inputFilename: string, outputFilename?: string): Promise { + async run(inputFilename: string, outputFilename?: string): Promise { if (!inputFilename) { this.callbacks.reportMessage(ConverterMessages.Error_FileNotFound({ inputFilename })); @@ -145,7 +145,7 @@ export class KeylayoutToKmnConverter { if (!KeylayoutReader.validate(jsonO)) { return null; } - } catch (e) { + } catch (e: any) { this.callbacks.reportMessage(ConverterMessages.Error_InvalidFile({ errorText: e.toString() })); return null; } @@ -154,10 +154,13 @@ export class KeylayoutToKmnConverter { const kmnFileWriter = new KmnFileWriter(this.callbacks, this.options); // write to object/ConverterToKmnResult - const outputKmn = kmnFileWriter.write(processedData); + const outputKmn = processedData ? kmnFileWriter.write(processedData) : null; const result: ConverterToKmnResult = { artifacts: { - kmn: { data: outputKmn, filename: processedData.kmnFilename } + kmn: { + data: outputKmn ?? new Uint8Array(0), + filename: processedData?.kmnFilename ?? "" + } } }; return result; @@ -168,7 +171,7 @@ export class KeylayoutToKmnConverter { * @param jsonObj containing filename, behaviorand rules of a json object * @return an ProcessedData containing all data ready to print out */ - private convert(jsonObj: any, inputfilename: string, outputFilename?: string): ProcessedData { + private convert(jsonObj: any, inputfilename: string, outputFilename?: string): ProcessedData | null { // modifiers for each behavior const modifierBehavior: string[][] = []; @@ -218,7 +221,7 @@ export class KeylayoutToKmnConverter { * @param jsonObj: json Object containing all data read from a keylayout file * @return an object containing the name of the input file, an array of behaviors and a populated array of Rules[] */ - public createRuleData(dataUkelele: ProcessedData, jsonObj: any): ProcessedData { + public createRuleData(dataUkelele: ProcessedData, jsonObj: any): ProcessedData | null { const rules: Rule[] = []; let dkCounterC3: number = 0; @@ -322,8 +325,8 @@ export class KeylayoutToKmnConverter { /* dk for C2*/ 0, /* unique B */ 0, - /* modifierKey*/ b1ModifierKeyObj[m].modifier, - /* key */ b1ModifierKeyObj[m].key, + /* modifierKey*/ b1ModifierKeyObj[m].modifier ?? "", + /* key */ b1ModifierKeyObj[m].key ?? "", /* output */ new TextEncoder().encode(outputchar) ); if ((outputchar !== undefined) && (outputchar !== "undefined") && (outputchar !== "")) { @@ -402,8 +405,8 @@ export class KeylayoutToKmnConverter { /* dk for C2*/ dkCounterC2++, /* unique B */ 0, - /* modifierKey*/ b1ModifierKeyObj[n4].modifier, - /* key */ b1ModifierKeyObj[n4].key, + /* modifierKey*/ b1ModifierKeyObj[n4].modifier ?? "", + /* key */ b1ModifierKeyObj[n4].key ?? "", /* output */ new TextEncoder().encode(b1ModifierKeyObj[n4].outchar), ); if ((b1ModifierKeyObj[n4].outchar !== undefined) @@ -490,8 +493,8 @@ export class KeylayoutToKmnConverter { /* dk for C2*/ 0, /* unique B */ 0, - /* modifierKey*/ b1ModifierKeyObj[n7].modifier, - /* key */ b1ModifierKeyObj[n7].key, + /* modifierKey*/ b1ModifierKeyObj[n7].modifier ?? "", + /* key */ b1ModifierKeyObj[n7].key ?? "", /* output */ new TextEncoder().encode(b1ModifierKeyObj[n7].outchar), ); if ((b1ModifierKeyObj[n7].outchar !== undefined) @@ -851,7 +854,7 @@ export class KeylayoutToKmnConverter { public getModifierArrayFromKeyModifierArray(data: any, search: KeylayoutFileData[]): string[] { const returnString1D: string[] = []; for (let i = 0; i < search.length; i++) { - returnString1D.push(data[search[i].behavior]); + returnString1D.push(data[search[i].behavior ?? ""]); } return returnString1D; } @@ -946,8 +949,7 @@ export class KeylayoutToKmnConverter { * @return an array: KeylayoutFileData[] containing [{KeyName,actionId,behavior,modifier,output}] */ public getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(data: any, search: KeylayoutFileData[], isCAPSused: boolean): KeylayoutFileData[] { - const keyBehaviorModOutput = []; - + const keyBehaviorModOutput: KeylayoutFileData[] = []; if (!((search === undefined) || (search === null) || (search.length === 0))) { for (let i = 0; i < search.length; i++) { const behaviorIdx: number = Number(search[i].behavior); @@ -964,7 +966,7 @@ export class KeylayoutToKmnConverter { } } // remove duplicates - const uniquekeyBehaviorModOutput = keyBehaviorModOutput.reduce((unique, o) => { + const uniquekeyBehaviorModOutput = keyBehaviorModOutput.reduce((unique, o) => { if (!unique.some(obj => obj.actionId === o.actionId && obj.key === o.key && @@ -988,10 +990,10 @@ export class KeylayoutToKmnConverter { * @param isCAPSused : boolean - flag to indicate if CAPS is used in a keylayout file or not * @return an array: KeylayoutFileData[] containing [{actionID,output, behavior,keyname,modifier}] */ - public getActionOutputBehaviorKeyModiFromActionIDStateOutput(data: any, modi: string[][], search: string, outchar: string, isCapsused: boolean): KeylayoutFileData[] { + public getActionOutputBehaviorKeyModiFromActionIDStateOutput(data: any, modi: string[][] | null, search: string, outchar: string, isCapsused: boolean): KeylayoutFileData[] { const actionOutputBehaviorKeyModi = []; - if ((search === "") || (search === undefined) || !((isCapsused === true) || (isCapsused === false))) { + if ((!modi)||(search === "") || (search === undefined) || !((isCapsused === true) || (isCapsused === false)|| (!modi))) { return []; } // loop behaviors (in ukelele it is possible to define multiple modifier combinations that behave in the same way) @@ -1016,7 +1018,7 @@ export class KeylayoutToKmnConverter { //............................................................................. // remove duplicates - const uniqueactionOutputBehaviorKey = actionOutputBehaviorKeyModi.reduce((unique, o) => { + const uniqueactionOutputBehaviorKey = actionOutputBehaviorKeyModi.reduce((unique, o) => { if (!unique.some(obj => obj.outchar === o.outchar && obj.actionId === o.actionId && diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 5f850735d7..5c01977f50 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -9,7 +9,6 @@ import { CompilerCallbacks, CompilerOptions } from "@keymanapp/developer-utils"; import { KeylayoutToKmnConverter, ProcessedData, Rule } from './keylayout-to-kmn-converter.js'; -import { ConverterMessages } from '../converter-messages.js'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; export interface messageCharacter { @@ -38,12 +37,7 @@ export class KmnFileWriter { if (dataRules) data += dataStores + dataRules; - try { - return new TextEncoder().encode(data); - } catch (err) { - this.callbacks.reportMessage(ConverterMessages.Error_UnableToWrite({ outputFilename: dataUkelele.kmnFilename, errorText: err })); - return null; - } + return new TextEncoder().encode(data); } /** @@ -51,7 +45,10 @@ export class KmnFileWriter { * @param dataUkelele an object containing all data read from a .keylayout file * @return string - all stores to be printed */ - public writeKmnFileHeader(dataUkelele: ProcessedData): string { + public writeKmnFileHeader(dataUkelele: ProcessedData | null): string { + if (!dataUkelele) { + return ""; + } let data: string = ""; @@ -78,8 +75,10 @@ export class KmnFileWriter { * @param dataUkelele an object containing all data read from a .keylayout file * @return string - all rules to be printed */ - public writeDataRules(dataUkelele: ProcessedData): string { - + public writeDataRules(dataUkelele: ProcessedData | null): string { + if (!dataUkelele) { + return ""; + } const keylayoutKmnConverter = new KeylayoutToKmnConverter(this.callbacks, this.options); let data: string = ""; @@ -95,7 +94,7 @@ export class KmnFileWriter { || (curr.ruleType === "C2" && (curr.deadkey !== "")) || (curr.ruleType === "C3" && (curr.deadkey !== "") && (curr.prevDeadkey !== ""))) ); - }).reduce((unique, o) => { + }).reduce((unique, o) => { if (!unique.some((obj: Rule) => new TextDecoder().decode(obj.output) === new TextDecoder().decode(o.output) @@ -112,7 +111,7 @@ export class KmnFileWriter { unique.push(o); } return unique; - }, []); + }, [] as Rule[]); //................................................ C0 C1 ................................................................ @@ -149,10 +148,10 @@ export class KmnFileWriter { // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - if ((outputCharacter !== undefined) || (outputCharacter !== "")) { + if ((outputCharacter !== undefined) && (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; + versionOutputCharacter = characterMessage?.character ?? ""; + warnText[2] = characterMessage?.message ?? ""; } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used @@ -202,10 +201,10 @@ export class KmnFileWriter { // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - if ((outputCharacter !== undefined) || (outputCharacter !== "")) { + if ((outputCharacter !== undefined) && (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; + versionOutputCharacter = characterMessage?.character ?? ""; + warnText[2] = characterMessage?.message ?? ""; } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used @@ -276,10 +275,10 @@ export class KmnFileWriter { const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14564 use functions from util instead of the ones in this class - if ((outputCharacter !== undefined) || (outputCharacter !== "")) { + if ((outputCharacter !== undefined) && (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; + versionOutputCharacter = characterMessage?.character ?? ""; + warnText[2] = characterMessage?.message ?? ""; } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used @@ -486,7 +485,7 @@ export class KmnFileWriter { + " " + amb_1_1[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output))?.character ?? "") + "\' "); } @@ -497,7 +496,7 @@ export class KmnFileWriter { + " " + dup_1_1[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output))?.character ?? "") + "\' "); } } @@ -582,7 +581,7 @@ export class KmnFileWriter { + " " + amb_3_3[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output))?.character ?? "") + "\' "); } @@ -595,7 +594,7 @@ export class KmnFileWriter { + " " + dup_3_3[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output))?.character ?? "") + "\' "); } @@ -723,7 +722,7 @@ export class KmnFileWriter { + " " + amb_6_3[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output))?.character ?? "") + "\' "); } @@ -736,7 +735,7 @@ export class KmnFileWriter { + " " + dup_6_3[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output))?.character ?? "") + "\' "); } @@ -797,7 +796,7 @@ export class KmnFileWriter { + " " + amb_6_6[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output))?.character ?? "") + "\' "); } @@ -810,7 +809,7 @@ export class KmnFileWriter { + " " + dup_6_6[0].key + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character + + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output))?.character ?? "") + "\' "); } } @@ -856,7 +855,7 @@ export class KmnFileWriter { * a non-control character will be written as itself ( 'A', '1', '፩', '😎') * null in case of an empty string or null or undefined input */ - public writeCharacterOrUnicode(ctr: string, msg: string = ""): messageCharacter { + public writeCharacterOrUnicode(ctr: string, msg: string = ""): messageCharacter | null { if ((ctr === null) || (ctr === undefined) || (ctr.length === 0)) { return null; @@ -874,10 +873,10 @@ export class KmnFileWriter { // find the value of output character which may be specified in unicode, html hex or html dec format ( e.g. U+1234 -> 1234; ሴ -> 1234; ሴ -> 1234) const ctr_val = ((m_uni || m_hex || m_dec) ? - m_uni ? parseInt(m_uni[1], 16) : m_hex ? parseInt(m_hex[1], 16) : parseInt(m_dec[1], 10) : KeylayoutToKmnConverter.MAX_CTRL_CHARACTER + m_uni ? parseInt(m_uni[1], 16) : m_hex ? parseInt(m_hex[1], 16) : m_dec ? parseInt(m_dec[1], 10) : KeylayoutToKmnConverter.MAX_CTRL_CHARACTER : KeylayoutToKmnConverter.MAX_CTRL_CHARACTER ); - // for control charactersin 'U+...', '&#x...' or '&#...' format as well as in "" format + // for control characters in 'U+...', '&#x...' or '&#...' format as well as in "" format if ((ctr_val < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER) || (ctr.charCodeAt(0) < KeylayoutToKmnConverter.MAX_CTRL_CHARACTER)) { // for control characters in 'U+...', '&#x...' or '&#...' format @@ -900,7 +899,7 @@ export class KmnFileWriter { } } else { - out.character = this.convertToUnicodeCharacter(ctr);; + out.character = this.convertToUnicodeCharacter(ctr) ?? ""; } return out; } @@ -911,7 +910,7 @@ export class KmnFileWriter { * @param inputString the value that will converted * @return a unicode character like 'c', 'ሴ', '😎' or undefined if inputString is not recognized */ - public convertToUnicodeCharacter(inputString: string): string { + public convertToUnicodeCharacter(inputString: string): string | undefined { // null, undefined will later be refused for conversion diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index bff598a390..434f6285ae 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -125,31 +125,24 @@ describe('KeylayoutToKmnConverter', function () { describe('run() ', function () { const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); - it('run() should throw on null input file name and null output file name', async function () { + it('run() should throw on empty input file name and empty output file name', async function () { // note, could use 'chai as promised' library to make this more fluent: - const result = sut.run(null, null); + const result = sut.run('', ''); assert.isNotNull(result); assert.equal(compilerTestCallbacks.messages.length, 1); - assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null })); + assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: '' })); }); - it('run() should throw on null input file name and empty output file name', async function () { - const result = sut.run(null, ''); + it('run() should throw on empty input file name and unknown output file name', async function () { + const result = sut.run('', 'X'); assert.isNotNull(result); assert.equal(compilerTestCallbacks.messages.length, 1); - assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null })); - }); - - it('run() should throw on null input file name and unknown output file name', async function () { - const result = sut.run(null, 'X'); - assert.isNotNull(result); - assert.equal(compilerTestCallbacks.messages.length, 1); - assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: null })); + assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_FileNotFound({ inputFilename: '' })); }); it('run() should throw on unavailable input file name and null output file name', async function () { const inputFilename = makePathToFixture('../data/Unavailable.keylayout'); - const result = sut.run(inputFilename, null); + const result = sut.run(inputFilename, undefined); assert.isNotNull(result); assert.equal(compilerTestCallbacks.messages.length, 2); assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_UnableToRead()); @@ -170,7 +163,7 @@ describe('KeylayoutToKmnConverter', function () { [makePathToFixture('../data/OutputXName.bb')], ].forEach(function (files) { it(infile + " should run ", async function () { - await NodeAssert.doesNotReject(async () => sut.run(makePathToFixture(infile), files[0])); + await NodeAssert.doesNotReject(async () => sut.run(makePathToFixture(infile), files[0] ?? undefined)); assert.equal(compilerTestCallbacks.messages.length, 0); }); }); @@ -196,7 +189,7 @@ describe('KeylayoutToKmnConverter', function () { const convertedEmpty = sut.convertBound.convert(readEmpty, inputFilenameEmpty); it('should return converted array on correct input', async function () { - assert.isTrue(converted.rules.length !== 0); + assert.isTrue(converted?.rules.length !== 0); }); it('should return empty on empty name as input', async function () { @@ -377,7 +370,7 @@ describe('KeylayoutToKmnConverter', function () { it((values[1] !== null) ? ("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + JSON.stringify(values[1]) + "'" : ("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + "null" + "'", async function () { - const result = sut.getModifierArrayFromKeyModifierArray(converted.modifiers, values[0] as KeylayoutFileData[]); + const result = sut.getModifierArrayFromKeyModifierArray(converted?.modifiers, values[0] as KeylayoutFileData[]); assert.deepStrictEqual(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -399,8 +392,10 @@ describe('KeylayoutToKmnConverter', function () { ['', []], ].forEach(function (values) { let outstring = '[ '; - for (let i = 0; i < values[1].length; i++) { - outstring = outstring + "[ " + JSON.stringify(values[1][i]) + "], "; + if (values[1]) { + for (let i = 0; i < values[1].length; i++) { + outstring = outstring + "[ " + JSON.stringify(values[1]?.[i]) + "], "; + } } it(("getKeyModifierArrayFromActionID('" + values[0] + "')").padEnd(57, " ") + ' should return ' + outstring.substring(0, outstring.lastIndexOf(']') + 2) + " ]", async function () { const result = sut.getKeyModifierArrayFromActionID(read, String(values[0])); @@ -591,7 +586,7 @@ describe('KeylayoutToKmnConverter', function () { ].forEach(function (values) { const isCaps = true; it(("getKeybehaviorModOutputArrayFromKeyActionbehaviorOutputArray([" + values[0] + "])").padEnd(74, " ") + ' should return ' + "[" + values[1] + "]", async function () { - const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read, values[0], isCaps); + const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read, values[0] ?? [], isCaps); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -670,12 +665,14 @@ describe('KeylayoutToKmnConverter', function () { ['', 'a', false, []], ['', '', , []], ].forEach(function (values) { - it((JSON.stringify(values[3]).length > 35) ? - ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' : - ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () { - const result = sut.getActionOutputBehaviorKeyModiFromActionIDStateOutput(read, converted.modifiers, String(values[0]), String(values[1]), Boolean(values[2])); - assert.equal(JSON.stringify(result), JSON.stringify(values[3])); - }); + if (converted) { + it((JSON.stringify(values[3]).length > 35) ? + ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' : + ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () { + const result = sut.getActionOutputBehaviorKeyModiFromActionIDStateOutput(read, converted.modifiers, String(values[0]), String(values[1]), Boolean(values[2])); + assert.equal(JSON.stringify(result), JSON.stringify(values[3])); + }); + } }); }); @@ -839,7 +836,7 @@ describe('KeylayoutToKmnConverter', function () { const inputFilename = makePathToFixture(values[0][0]); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); const processedData = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); - assert.deepEqual(processedData.rules[0], values[1][0]); + assert.deepEqual(processedData?.rules[0], values[1][0]); }); }); }); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 0eb23c88b4..fe23436784 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -21,6 +21,41 @@ describe('KmnFileWriter', function () { compilerTestCallbacks.clear(); }); + describe('RunONE', function () { + const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); + [ + [makePathToFixture('../data/Test_mixedEncodings.keylayout')], + ].forEach(function (files) { + it(files + " should give no errors ", async function () { + sut.run(files[0]); + assert.isTrue(compilerTestCallbacks.messages.length === 0); + }); + }); + }); + + describe('RunFILES', function () { + this.timeout(10000); // allow longer time for these tests + const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); + [ + [makePathToFixture('../data/Polish.keylayout')], + [makePathToFixture('../data/Spanish.keylayout')], + [makePathToFixture('../data/French.keylayout')], + [makePathToFixture('../data/German_complete_reduced.keylayout')], + // [makePathToFixture('../data/German_complete.keylayout')], + // [makePathToFixture('../data/German_standard.keylayout')], + [makePathToFixture('../data/Italian_command.keylayout')], + [makePathToFixture('../data/Italian.keylayout')], + [makePathToFixture('../data/Latin_American.keylayout')], + [makePathToFixture('../data/Swiss_French.keylayout')], + [makePathToFixture('../data/Swiss_German.keylayout')], + [makePathToFixture('../data/US.keylayout')], + ].forEach(function (files) { + it(files + " should give no errors ", async function () { + sut.run(files[0]); + assert.isTrue(compilerTestCallbacks.messages.length === 0); + }); + }); + }); describe("writeDataRules() ", function () { const inputFilename = makePathToFixture('../data/Test.keylayout'); const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); @@ -63,7 +98,7 @@ describe('KmnFileWriter', function () { it(('writeKmnFileHeader should return store text with filename ').padEnd(62, " ") + 'on correct input', async function () { const writtenCorrectName = sutW.writeKmnFileHeader(converted); - assert.equal(writtenCorrectName, (outExpectedFirst + converted.keylayoutFilename + outExpectedLast)); + assert.equal(writtenCorrectName, (outExpectedFirst + (converted?.keylayoutFilename ?? "") + outExpectedLast)); }); }); @@ -74,7 +109,7 @@ describe('KmnFileWriter', function () { ["ሴ", 'ሴ'], ["😎", '😎'], ["", '\u0002'], - ["�",undefined ], + ["�", undefined], ["a", 'a'], ["ሴ", 'ሴ'], ["😆", '😆'], @@ -95,8 +130,16 @@ describe('KmnFileWriter', function () { ["␤", '␤'], ["␕", '␕'], ["", ''], - [undefined, undefined], - [null, undefined] + [null, undefined], + ["<", '<'], + ["&Gt", undefined], + ["U+D801", undefined], + ["�", undefined], + ["�", undefined], + ["�", undefined], + ["U+D801", undefined], + ["&#xmmm;", undefined], + ["�", undefined], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { const result = sutW.convertToUnicodeCharacter(values[0] as string); @@ -105,6 +148,38 @@ describe('KmnFileWriter', function () { }); }); + describe('writeCharacterOrUnicode ', function () { + const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); + [ + ["A", "Msg", "A", "Msg"], + ["ሴ", "Msg", "ሴ", "Msg"], + ["😀", "Msg", "😀", "Msg"], + ["ẘ", "Msg", "ẘ", "Msg"], + ["U+0001", "Msg", "U+0001", "Msg; Use of a control character "], + ["U+0061", "Msg", "a", "Msg"], + ["", "Msg", "U+0002", "Msg; Use of a control character "], + ["ሴ", "Msg", 'ሴ', "Msg",], + ["", "Msg", "U+0003", "Msg; Use of a control character "], + ["ሺ", "Msg", "ሺ", "Msg",], + [null, "Msg", null, null], + [undefined, "Msg", null, null], + ["", "Msg", null, null], + ["", "Msg", "U+0006", "Msg; Use of a control character "], + ].forEach(function (values) { + it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[2] + '"', async function () { + const result = sutW.writeCharacterOrUnicode(values[0] as string, values[1] as string); + if (result) { + assert.equal(result.character, values[2]); + assert.equal(result.message, values[3]); + } + else { + assert.isNull(values[2]); + assert.isNull(values[3]); + } + }); + }); + }); + describe('reviewRules messages', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); [ From 30ea90484ef2c25d57ad55fd6be9b24783c6e406 Mon Sep 17 00:00:00 2001 From: Sabine Date: Mon, 20 Apr 2026 17:47:37 +0200 Subject: [PATCH 02/33] feat(developer): remove tests for entire keyboards --- .../kmc-convert/test/kmn-file-writer.tests.ts | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index fe23436784..89d70d83f3 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -21,41 +21,6 @@ describe('KmnFileWriter', function () { compilerTestCallbacks.clear(); }); - describe('RunONE', function () { - const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); - [ - [makePathToFixture('../data/Test_mixedEncodings.keylayout')], - ].forEach(function (files) { - it(files + " should give no errors ", async function () { - sut.run(files[0]); - assert.isTrue(compilerTestCallbacks.messages.length === 0); - }); - }); - }); - - describe('RunFILES', function () { - this.timeout(10000); // allow longer time for these tests - const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); - [ - [makePathToFixture('../data/Polish.keylayout')], - [makePathToFixture('../data/Spanish.keylayout')], - [makePathToFixture('../data/French.keylayout')], - [makePathToFixture('../data/German_complete_reduced.keylayout')], - // [makePathToFixture('../data/German_complete.keylayout')], - // [makePathToFixture('../data/German_standard.keylayout')], - [makePathToFixture('../data/Italian_command.keylayout')], - [makePathToFixture('../data/Italian.keylayout')], - [makePathToFixture('../data/Latin_American.keylayout')], - [makePathToFixture('../data/Swiss_French.keylayout')], - [makePathToFixture('../data/Swiss_German.keylayout')], - [makePathToFixture('../data/US.keylayout')], - ].forEach(function (files) { - it(files + " should give no errors ", async function () { - sut.run(files[0]); - assert.isTrue(compilerTestCallbacks.messages.length === 0); - }); - }); - }); describe("writeDataRules() ", function () { const inputFilename = makePathToFixture('../data/Test.keylayout'); const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); From 6802ec4da7cf3365fc763e0283a0c09b288c7595 Mon Sep 17 00:00:00 2001 From: Sabine Date: Mon, 20 Apr 2026 22:38:53 +0200 Subject: [PATCH 03/33] feat(developer): read() throw error instead of return null --- .../kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts index 2dc98fdb3c..30c8ea6051 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts @@ -85,7 +85,7 @@ export class KeylayoutFileReader { } catch (err) { this.callbacks.reportMessage(ConverterMessages.Error_UnableToRead()); - return null; + throw new Error('Failed to parse keylayout file'); } } } From 9b9cafe720383455e0c4f5cc112ec78a278288b0 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 21 Apr 2026 10:08:11 +0200 Subject: [PATCH 04/33] feat(developer): more typesafety + add tests for validate() --- developer/src/kmc-convert/src/converter.ts | 2 +- .../keylayout-to-kmn/keylayout-file-reader.ts | 10 +++-- .../keylayout-to-kmn-converter.ts | 7 +++- .../src/keylayout-to-kmn/kmn-file-writer.ts | 9 ++++ .../kmc-convert/test/kmn-file-reader.tests.ts | 42 +++++++++++++++++++ 5 files changed, 64 insertions(+), 6 deletions(-) diff --git a/developer/src/kmc-convert/src/converter.ts b/developer/src/kmc-convert/src/converter.ts index f1858fa5b5..a1e696e7b8 100644 --- a/developer/src/kmc-convert/src/converter.ts +++ b/developer/src/kmc-convert/src/converter.ts @@ -68,7 +68,7 @@ export class Converter implements KeymanCompiler { return null; } - const ConverterClass = ConverterClassFactory.find(inputFilename, outputFilename ??''); + const ConverterClass = ConverterClassFactory.find(inputFilename, outputFilename ?? '.kmn'); if (!ConverterClass) { this.callbacks.reportMessage(ConverterMessages.Error_NoConverterFound({ inputFilename, outputFilename: outputFilename ?? '' })); return null; diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts index 30c8ea6051..aeb0d7737b 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts @@ -19,7 +19,11 @@ export class KeylayoutFileReader { /** * @returns true if valid, false if invalid */ - public validate(source: Keylayout.KeylayoutXMLSourceFile): boolean { + public validate(source: Keylayout.KeylayoutXMLSourceFile|null): boolean { + if (!source) { + this.callbacks.reportMessage(ConverterMessages.Error_UnableToRead()); + return false; + } if (!SchemaValidators.default.keylayout(source)) { for (const err of (SchemaValidators.default.keylayout).errors) { this.callbacks.reportMessage(DeveloperUtilsMessages.Error_InvalidXml({ @@ -75,7 +79,7 @@ export class KeylayoutFileReader { * @param inputFilename the ukelele .keylayout-file to be parsed * @return in case of success: json object containing data of the .keylayout file; else null */ - public read(source: Uint8Array): Keylayout.KeylayoutXMLSourceFile { + public read(source: Uint8Array): Keylayout.KeylayoutXMLSourceFile | null { try { const data = new TextDecoder().decode(source); @@ -85,7 +89,7 @@ export class KeylayoutFileReader { } catch (err) { this.callbacks.reportMessage(ConverterMessages.Error_UnableToRead()); - throw new Error('Failed to parse keylayout file'); + return null; } } } diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 49696712b2..2a887f2798 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -155,6 +155,10 @@ export class KeylayoutToKmnConverter { // write to object/ConverterToKmnResult const outputKmn = processedData ? kmnFileWriter.write(processedData) : null; + + if (!processedData || !outputKmn) { + return null; + } const result: ConverterToKmnResult = { artifacts: { kmn: { @@ -992,8 +996,7 @@ export class KeylayoutToKmnConverter { */ public getActionOutputBehaviorKeyModiFromActionIDStateOutput(data: any, modi: string[][] | null, search: string, outchar: string, isCapsused: boolean): KeylayoutFileData[] { const actionOutputBehaviorKeyModi = []; - - if ((!modi)||(search === "") || (search === undefined) || !((isCapsused === true) || (isCapsused === false)|| (!modi))) { + if ((!modi) || (search === "") || (search === undefined) ) { return []; } // loop behaviors (in ukelele it is possible to define multiple modifier combinations that behave in the same way) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 5c01977f50..94daec484c 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -148,6 +148,9 @@ export class KmnFileWriter { // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); + // in case writeCharacterOrUnicode() returns null, the fallback is empty strings for characterMessage.character + // and characterMessage.message. Then versionOutputCharacter could be "" and would be written into the kmn file + // as ... > '', producing an invalid kmn rule. if ((outputCharacter !== undefined) && (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); versionOutputCharacter = characterMessage?.character ?? ""; @@ -201,6 +204,9 @@ export class KmnFileWriter { // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); + // in case writeCharacterOrUnicode() returns null, the fallback is empty strings for characterMessage.character + // and characterMessage.message. Then versionOutputCharacter could be "" and would be written into the kmn file + // as ... > '', producing an invalid kmn rule. if ((outputCharacter !== undefined) && (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); versionOutputCharacter = characterMessage?.character ?? ""; @@ -275,6 +281,9 @@ export class KmnFileWriter { const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14564 use functions from util instead of the ones in this class + // in case writeCharacterOrUnicode() returns null, the fallback is empty strings for characterMessage.character + // and characterMessage.message. Then versionOutputCharacter could be "" and would be written into the kmn file + // as ... > '', producing an invalid kmn rule. if ((outputCharacter !== undefined) && (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); versionOutputCharacter = characterMessage?.character ?? ""; diff --git a/developer/src/kmc-convert/test/kmn-file-reader.tests.ts b/developer/src/kmc-convert/test/kmn-file-reader.tests.ts index c68e0e5241..35da499d44 100644 --- a/developer/src/kmc-convert/test/kmn-file-reader.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-reader.tests.ts @@ -9,6 +9,7 @@ import 'mocha'; import { assert } from 'chai'; +import { Keylayout } from "@keymanapp/developer-utils"; import { compilerTestCallbacks, makePathToFixture } from './helpers/index.js'; import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js'; @@ -18,6 +19,47 @@ describe('KeylayoutFileReader', function () { compilerTestCallbacks.clear(); }); + describe("validate() ", function () { + + it('validate() should return true on correct inputfile', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test.keylayout'); + const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result); + assert.isTrue(validated); + }); + + it('validate() should return false on inputfile with unknown tags', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test_unknownTags.keylayout'); + const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result); + assert.isFalse(validated); + }); + + it('validate() should return false on inputfile with additional tags', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test_additionalTags.keylayout'); + const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result); + assert.isFalse(validated); + }); + it('validate() should return false on inputfile with missing tags', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test_missingTags.keylayout'); + const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result); + assert.isFalse(validated); + }); + it('validate() should return false on no entries in action-when', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test_noActionWhen.keylayout'); + const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result); + assert.isFalse(validated); + }); + }); + describe("read() ", function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); From ef1cf18746f2ce8f9d32638f96ac7731bf1e2020 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 21 Apr 2026 10:50:24 +0200 Subject: [PATCH 05/33] feat(developer): more typesafety --- .../src/keylayout-to-kmn/keylayout-to-kmn-converter.ts | 5 ++--- .../src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 2a887f2798..28321f6bfc 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -162,8 +162,7 @@ export class KeylayoutToKmnConverter { const result: ConverterToKmnResult = { artifacts: { kmn: { - data: outputKmn ?? new Uint8Array(0), - filename: processedData?.kmnFilename ?? "" + data: outputKmn, filename: processedData.kmnFilename } } }; @@ -996,7 +995,7 @@ export class KeylayoutToKmnConverter { */ public getActionOutputBehaviorKeyModiFromActionIDStateOutput(data: any, modi: string[][] | null, search: string, outchar: string, isCapsused: boolean): KeylayoutFileData[] { const actionOutputBehaviorKeyModi = []; - if ((!modi) || (search === "") || (search === undefined) ) { + if ((!modi) || (search === "") || (search === undefined)) { return []; } // loop behaviors (in ukelele it is possible to define multiple modifier combinations that behave in the same way) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 94daec484c..f1388e935c 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -87,8 +87,7 @@ export class KmnFileWriter { // (e.g. when in a keylayout file the same modifiers occur in several behaviors thus producing the same rules). // This is to filter out those duplicate Rule objects const uniqueDataRules: Rule[] = dataUkelele.rules.filter((curr) => { - return (!(curr.output === new TextEncoder().encode("") || curr.output === undefined) - && (curr.key !== "") + return ((curr.key !== "") && ((curr.ruleType === "C0") || (curr.ruleType === "C1") || (curr.ruleType === "C2" && (curr.deadkey !== "")) From 417c044d9048127465910bcda86d6b4996f87151 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 21 Apr 2026 16:44:34 +0200 Subject: [PATCH 06/33] feat(developer): baseUrl problem of tsconfig.json, errorMsg typo --- developer/src/kmc-convert/src/converter-messages.ts | 2 +- .../src/keylayout-to-kmn/keylayout-to-kmn-converter.ts | 2 +- developer/src/kmc-convert/test/tsconfig.json | 1 + developer/src/kmc-convert/tsconfig.json | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc-convert/src/converter-messages.ts b/developer/src/kmc-convert/src/converter-messages.ts index ea5e9b84cf..f95e497b86 100644 --- a/developer/src/kmc-convert/src/converter-messages.ts +++ b/developer/src/kmc-convert/src/converter-messages.ts @@ -26,7 +26,7 @@ export class ConverterMessages { static ERROR_IntputFilenameIsRequired = SevError | 0x0002; static Error_IntputFilenameIsRequired = () => m( this.ERROR_IntputFilenameIsRequired, - `An output filename is required for keyboard conversion.` + `An Input filename is required for keyboard conversion.` ); static ERROR_FileNotFound = SevError | 0x0003; diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 28321f6bfc..743bf7d187 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -135,7 +135,7 @@ export class KeylayoutToKmnConverter { const KeylayoutReader = new KeylayoutFileReader(this.callbacks/*, this.options*/); const binaryData = this.callbacks.loadFile(inputFilename); - const jsonO: Keylayout.KeylayoutXMLSourceFile = KeylayoutReader.read(binaryData); + const jsonO: Keylayout.KeylayoutXMLSourceFile|null = KeylayoutReader.read(binaryData); if (!jsonO) { this.callbacks.reportMessage(ConverterMessages.Error_UnableToReadFile({ inputFilename: inputFilename })); diff --git a/developer/src/kmc-convert/test/tsconfig.json b/developer/src/kmc-convert/test/tsconfig.json index 78127d66db..9c543db4b1 100644 --- a/developer/src/kmc-convert/test/tsconfig.json +++ b/developer/src/kmc-convert/test/tsconfig.json @@ -6,6 +6,7 @@ "rootDirs": ["./", "../src/"], "outDir": "../build/test", "baseUrl": ".", + "ignoreDeprecations": "6.0", }, "include": [ "**/*.tests.ts", diff --git a/developer/src/kmc-convert/tsconfig.json b/developer/src/kmc-convert/tsconfig.json index 32235e2468..72a38d4a96 100644 --- a/developer/src/kmc-convert/tsconfig.json +++ b/developer/src/kmc-convert/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "build/src/", "rootDir": "src/", "baseUrl": ".", + "ignoreDeprecations": "6.0", }, "include": [ "src/**/*.ts" From 47168873df32f7dbc01ecc895150c0b24551eaa8 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 21 Apr 2026 17:02:33 +0200 Subject: [PATCH 07/33] feat(developer): restore tsconfig.json --- developer/src/kmc-convert/test/tsconfig.json | 1 - developer/src/kmc-convert/tsconfig.json | 1 - 2 files changed, 2 deletions(-) diff --git a/developer/src/kmc-convert/test/tsconfig.json b/developer/src/kmc-convert/test/tsconfig.json index 9c543db4b1..78127d66db 100644 --- a/developer/src/kmc-convert/test/tsconfig.json +++ b/developer/src/kmc-convert/test/tsconfig.json @@ -6,7 +6,6 @@ "rootDirs": ["./", "../src/"], "outDir": "../build/test", "baseUrl": ".", - "ignoreDeprecations": "6.0", }, "include": [ "**/*.tests.ts", diff --git a/developer/src/kmc-convert/tsconfig.json b/developer/src/kmc-convert/tsconfig.json index 72a38d4a96..32235e2468 100644 --- a/developer/src/kmc-convert/tsconfig.json +++ b/developer/src/kmc-convert/tsconfig.json @@ -5,7 +5,6 @@ "outDir": "build/src/", "rootDir": "src/", "baseUrl": ".", - "ignoreDeprecations": "6.0", }, "include": [ "src/**/*.ts" From 1d3d53e2e7897eb44ae09f22647b95d503546e07 Mon Sep 17 00:00:00 2001 From: Sabine Date: Mon, 4 May 2026 20:04:43 +0200 Subject: [PATCH 08/33] feat(developer): add returntypes --- .../keylayout-to-kmn/keylayout-file-reader.ts | 2 +- .../keylayout-to-kmn-converter.ts | 54 ++++++++++--------- .../test/keylayout-to-kmn-converter.tests.ts | 45 ++++++++-------- .../kmc-convert/test/kmn-file-reader.tests.ts | 20 +++---- 4 files changed, 62 insertions(+), 59 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts index ec5fd3bea4..0be7550ef8 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts @@ -81,7 +81,7 @@ export class KeylayoutFileReader { /** * @returns true if valid, false if invalid */ - public validate(source: Keylayout.KeylayoutXMLSourceFile|null): boolean { + public validate(source: Keylayout.KeylayoutXMLSourceFile, inputFilename: string): boolean { if (!source) { this.callbacks.reportMessage(ConverterMessages.Error_UnableToRead()); return false; diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 609df13274..e3c8175c52 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -118,7 +118,7 @@ export class KeylayoutToKmnConverter { const KeylayoutReader = new KeylayoutFileReader(this.callbacks/*, this.options*/); const binaryData = this.callbacks.loadFile(inputFilename); - const jsonO: Keylayout.KeylayoutXMLSourceFile|null = KeylayoutReader.read(binaryData); + const jsonO: Keylayout.KeylayoutXMLSourceFile | null = KeylayoutReader.read(binaryData); if (!jsonO) { this.callbacks.reportMessage(ConverterMessages.Error_UnableToReadFile({ inputFilename: inputFilename })); @@ -157,7 +157,7 @@ export class KeylayoutToKmnConverter { * @param jsonObj containing filename, behaviorand rules of a json object * @return an ProcessedData containing all data ready to print out */ - private convert(jsonObj: Keylayout.KeylayoutXMLSourceFile, inputfilename: string, outputFilename?: string): ProcessedData { + private convert(jsonObj: Keylayout.KeylayoutXMLSourceFile, inputfilename: string, outputFilename?: string): ProcessedData | null { // modifiers for each behavior const modifierBehavior: string[][] = []; @@ -203,7 +203,7 @@ export class KeylayoutToKmnConverter { * @param jsonObj: json Object containing all data read from a keylayout file * @return an object containing the name of the input file, an array of behaviors and a populated array of Rules[] */ - public createRuleData(dataUkelele: ProcessedData, jsonObj: Keylayout.KeylayoutXMLSourceFile): ProcessedData { + public createRuleData(dataUkelele: ProcessedData, jsonObj: Keylayout.KeylayoutXMLSourceFile): ProcessedData | null { const rules: Rule[] = []; let dkCounterC3: number = 0; @@ -346,7 +346,7 @@ export class KeylayoutToKmnConverter { // with present actionId (a18) find all keycode-behavior-pairs that use this action (a18) => (keymapIndex 0/keycode 24 and keymapIndex 3/keycode 24) .................................... // from these create an array of modifier combinations e.g. [['','caps?'], ['Caps']] ..................................................................................................... /* eg: [['24', 0], ['24', 3]] */ const b4DeadkeyObj: KeylayoutFileData[] = this.getKeyModifierArrayFromActionID(jsonObj, actionId); - /* e.g. [['','caps?'], ['Caps']]*/ const b4DeadkeyModifierObj: string[][] = this.getModifierArrayFromKeyModifierArray(dataUkelele.modifiers, b4DeadkeyObj); + /* e.g. [['','caps?'], ['Caps']]*/ const b4DeadkeyModifierObj: string[][] = this.getModifierArrayFromKeyModifierArray(dataUkelele.modifiers, b4DeadkeyObj) as string[][]; // ........................................................................................................................................................................................ @@ -410,21 +410,22 @@ export class KeylayoutToKmnConverter { // with actionId from above loop all 'action' and search for a state-next-pair ................................................................................................................... // e.g. in Block 5: find for action id a16 ............................................................................................................................. - for (let l = 0; l < jsonObj.keyboard.actions.action[b1ActionIndex].when.length; l++) { - if ((jsonObj.keyboard.actions.action[b1ActionIndex].when[l]['state'] !== "none") - && (jsonObj.keyboard.actions.action[b1ActionIndex].when[l]['next'] !== undefined)) { + if (jsonObj.keyboard.actions?.action?.[b1ActionIndex]?.when) { + for (const when of jsonObj.keyboard.actions.action[b1ActionIndex].when) { + if ((when['state'] !== "none") + && (when['next'] !== undefined)) { // Data of Block Nr 5 ........................................................................................................................................................................ // of this state-next-pair get value of next (next="1") and state="3" ........................................................................................................................ - /* e.g. state = 3 */ const b5ValueState: string = jsonObj.keyboard.actions.action[b1ActionIndex].when[l]['state']; - /* e.g. next = 1 */ const b5ValueNext: string = jsonObj.keyboard.actions.action[b1ActionIndex].when[l]['next']; + /* e.g. state = 3 */ const b5ValueState: string = when['state'] as string; + /* e.g. next = 1 */ const b5ValueNext: string = when['next']; // ........................................................................................................................................................................................... // Data of Block Nr 4 ........................................................................................................................................................................ // with present actionId (a16) find all keycode-behavior-pairs that use this action (a16) => (keymapIndex 3/keycode 32) .................................................................... // from these create an array of modifier combinations e.g. [ [ 'anyOption', 'Caps' ] ] ..................................................................................................... /* e.g. [['32', 3]] */ const b4DeadkeyObj: KeylayoutFileData[] = this.getKeyModifierArrayFromActionID(jsonObj, actionId); - /* e.g. [ [ 'anyOption', 'Caps' ] ]*/ const b4DeadkeyModifierObj: string[][] = this.getModifierArrayFromKeyModifierArray(dataUkelele.modifiers, b4DeadkeyObj); + /* e.g. [ [ 'anyOption', 'Caps' ] ]*/ const b4DeadkeyModifierObj: string[][] = this.getModifierArrayFromKeyModifierArray(dataUkelele.modifiers, b4DeadkeyObj) as string[][]; // ........................................................................................................................................................................................... // Data of Block Nr 3 ........................................................................................................................................................................ @@ -436,7 +437,7 @@ export class KeylayoutToKmnConverter { // with present actionId (a17) find all key names and behaviors that use this action (a17) => (keymapIndex 3/keycode 28) .................................................................... // from these create an array of modifier combinations e.g. [ [ 'anyOption', 'Caps' ] ] ..................................................................................................... /* eg: index=3 */ const b2PrevDeadkeyObj: KeylayoutFileData[] = this.getKeyModifierArrayFromActionID(jsonObj, b3ActionId); - /* e.g. [ [ 'anyOption', 'Caps' ] ] */ const b2PrevDeadkeyModifierObj: string[][] = this.getModifierArrayFromKeyModifierArray(dataUkelele.modifiers, b2PrevDeadkeyObj); + /* e.g. [ [ 'anyOption', 'Caps' ] ] */ const b2PrevDeadkeyModifierObj: string[][] = this.getModifierArrayFromKeyModifierArray(dataUkelele.modifiers, b2PrevDeadkeyObj) as string[][]; // ........................................................................................................................................................................................... // Data of Block Nr 6 ........................................................................................................................................................................ // create an array[action id,state,output] from all state-output-pairs that use state = b5ValueNext (e.g. use 1 in ) ......................................... @@ -447,17 +448,17 @@ export class KeylayoutToKmnConverter { // create array[Keycode,Keyname,action id,actionIndex,output] and array[Keyname,action id,behavior,modifier,output] ......................................................................... /* eg: ['49','K_SPACE','a0','0','Â'] */ const b1KeycodeObj: KeylayoutFileData[] = this.getKeyActionOutputArrayFromActionStateOutputArray(jsonObj, b6ActionIdObj); /* eg: ['K_SPACE','a0','0','NCAPS','Â'] */ const b1ModifierKeyObj: KeylayoutFileData[] = this.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(jsonObj, b1KeycodeObj, isCapsused); - // ........................................................................................................................................................................................... + // ........................................................................................................................................................................................... - for (let n1 = 0; n1 < b2PrevDeadkeyModifierObj.length; n1++) { - for (let n2 = 0; n2 < b2PrevDeadkeyModifierObj[n1].length; n2++) { - for (let n3 = 0; n3 < b2PrevDeadkeyObj.length; n3++) { - for (let n4 = 0; n4 < b4DeadkeyModifierObj.length; n4++) { - for (let n5 = 0; n5 < b4DeadkeyModifierObj[n4].length; n5++) { - for (let n6 = 0; n6 < b4DeadkeyObj.length; n6++) { - for (let n7 = 0; n7 < b1ModifierKeyObj.length; n7++) { + for (let n1 = 0; n1 < b2PrevDeadkeyModifierObj.length; n1++) { + for (let n2 = 0; n2 < b2PrevDeadkeyModifierObj[n1].length; n2++) { + for (let n3 = 0; n3 < b2PrevDeadkeyObj.length; n3++) { + for (let n4 = 0; n4 < b4DeadkeyModifierObj.length; n4++) { + for (let n5 = 0; n5 < b4DeadkeyModifierObj[n4].length; n5++) { + for (let n6 = 0; n6 < b4DeadkeyObj.length; n6++) { + for (let n7 = 0; n7 < b1ModifierKeyObj.length; n7++) { - ruleObj = new Rule( + ruleObj = new Rule( /* ruleType */ "C3", /* modifierPrevDeadkey*/ this.createKmnModifier(b2PrevDeadkeyModifierObj[n1][n2], isCapsused), /* prevDeadkey */ this.mapUkeleleKeycodeToVK(Number(b2PrevDeadkeyObj[n3].key)), @@ -472,11 +473,12 @@ export class KeylayoutToKmnConverter { /* modifierKey*/ b1ModifierKeyObj[n7].modifier ?? "", /* key */ b1ModifierKeyObj[n7].key ?? "", /* output */ new TextEncoder().encode(b1ModifierKeyObj[n7].outchar), - ); - if ((b1ModifierKeyObj[n7].outchar !== undefined) - && (b1ModifierKeyObj[n7].outchar !== "undefined") - && (b1ModifierKeyObj[n7].outchar !== "")) { - rules.push(ruleObj); + ); + if ((b1ModifierKeyObj[n7].outchar !== undefined) + && (b1ModifierKeyObj[n7].outchar !== "undefined") + && (b1ModifierKeyObj[n7].outchar !== "")) { + rules.push(ruleObj); + } } } } @@ -492,7 +494,7 @@ export class KeylayoutToKmnConverter { this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({ inputFilename: jsonObj.keyboard['name'] + ".keylayout", keymapIndex: jsonObj.keyboard.keyMapSet[0].keyMap[i]['index'], - output: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['output'], + output: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['output'] as string, key: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['code'], KeyName: this.mapUkeleleKeycodeToVK(Number(jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['code'])) })); diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 97f478f0cc..99d6e1fc27 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -13,6 +13,7 @@ import { compilerTestCallbacks, compilerTestOptions, makePathToFixture } from '. import { ActionStateOutput, KeylayoutFileData, KeylayoutToKmnConverter, Rule } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js'; import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js'; import { ConverterMessages } from '../src/converter-messages.js'; +import { KeylayoutXMLSourceFile } from '../../common/web/utils/src/types/keylayout/keylayout-xml.js'; describe('KeylayoutToKmnConverter', function () { @@ -155,17 +156,17 @@ describe('KeylayoutToKmnConverter', function () { // ProcessedData from usable file const inputFilename = makePathToFixture('../data/Test.keylayout'); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.convertBound.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); // ProcessedData from unavailable file const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout'); const readUnavailable = sutR.read(compilerTestCallbacks.loadFile(inputFilenameUnavailable)); - const convertedUnavailable = sut.convertBound.convert(readUnavailable, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn')); + const convertedUnavailable = sut.convertBound.convert(readUnavailable as KeylayoutXMLSourceFile, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn')); // ProcessedData from empty file const inputFilenameEmpty = makePathToFixture(''); const readEmpty = sutR.read(compilerTestCallbacks.loadFile(inputFilenameEmpty)); - const convertedEmpty = sut.convertBound.convert(readEmpty, inputFilenameEmpty); + const convertedEmpty = sut.convertBound.convert(readEmpty as KeylayoutXMLSourceFile, inputFilenameEmpty); it('should return converted array on correct input', async function () { assert.isTrue(converted?.rules.length !== 0); @@ -180,7 +181,7 @@ describe('KeylayoutToKmnConverter', function () { }); it('should return empty array of rules on null input', async function () { - const convertedRule = sut.convertBound.convert(null, 'ABC.kmn'); + const convertedRule = sut.convertBound.convert(null , 'ABC.kmn'); assert.isNull(convertedRule); }); }); @@ -317,7 +318,7 @@ describe('KeylayoutToKmnConverter', function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test.keylayout'); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.convertBound.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); [ [[{ key: '0', behavior: 0 }], [['', 'shift? caps? ']]], [[{ key: '0', behavior: 2 }], [['shift? leftShift caps? ', 'anyShift caps?', 'shift leftShift caps ', 'shift? rightShift caps? ']]], @@ -332,7 +333,7 @@ describe('KeylayoutToKmnConverter', function () { it((values[1] !== null) ? ("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + JSON.stringify(values[1]) + "'" : ("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + "null" + "'", async function () { - const result = sut.getModifierArrayFromKeyModifierArray(converted?.modifiers, values[0] as KeylayoutFileData[]); + const result = sut.getModifierArrayFromKeyModifierArray(converted?.modifiers as string[][], values[0] as unknown as KeylayoutFileData[]); assert.deepStrictEqual(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -360,7 +361,7 @@ describe('KeylayoutToKmnConverter', function () { } } it(("getKeyModifierArrayFromActionID('" + values[0] + "')").padEnd(57, " ") + ' should return ' + outstring.substring(0, outstring.lastIndexOf(']') + 2) + " ]", async function () { - const result = sut.getKeyModifierArrayFromActionID(read, String(values[0])); + const result = sut.getKeyModifierArrayFromActionID(read as KeylayoutXMLSourceFile, String(values[0])); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -386,7 +387,7 @@ describe('KeylayoutToKmnConverter', function () { ['unknown', ''], ].forEach(function (values) { it(("getActionIdFromActionNext('" + values[0] + "')").padEnd(49, " ") + ' should return ' + "'" + values[1] + "'", async function () { - const result = sut.getActionIdFromActionNext(read, String(values[0])); + const result = sut.getActionIdFromActionNext(read as KeylayoutXMLSourceFile, String(values[0])); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -410,7 +411,7 @@ describe('KeylayoutToKmnConverter', function () { ['unknown', -1], ].forEach(function (values) { it(("getActionIndexFromActionId('" + values[0] + "')").padEnd(50, " ") + ' should return ' + values[1], async function () { - const result = sut.getActionIndexFromActionId(read, String(values[0])); + const result = sut.getActionIndexFromActionId(read as KeylayoutXMLSourceFile, String(values[0])); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -430,7 +431,7 @@ describe('KeylayoutToKmnConverter', function () { ].forEach(function (values) { it( ("getOutputFromActionIdNone('" + values[0] + "')").padEnd(56, " ") + ' should return ' + "'" + values[1] + "'", async function () { - const result = sut.getOutputFromActionIdNone(read, String(values[0])); + const result = sut.getOutputFromActionIdNone(read as KeylayoutXMLSourceFile, String(values[0])); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -440,7 +441,7 @@ describe('KeylayoutToKmnConverter', function () { [99, ''], ].forEach(function (values) { it(("getOutputFromActionIdNone('" + values[0] + "')").padEnd(56, " ") + ' should return ' + values[1], async function () { - const result = sut.getOutputFromActionIdNone(read, String(values[0])); + const result = sut.getOutputFromActionIdNone(read as KeylayoutXMLSourceFile, String(values[0])); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -523,7 +524,7 @@ describe('KeylayoutToKmnConverter', function () { it((JSON.stringify(values[1]).length > 60) ? 'an array of objects should return an array of objects' : stringIn.padEnd(74, " ") + ' should return ' + stringOut, async function () { - const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read, values[0], isCapsUsed); + const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read as KeylayoutXMLSourceFile, values[0], isCapsUsed); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -537,7 +538,7 @@ describe('KeylayoutToKmnConverter', function () { const stringOut = "['" + values[1].actionId + "', '" + "', '" + values[1].modifier + "', '" + values[1].key + "', '" + values[1].outchar + "']"; it(stringIn.padEnd(74, " ") + ' should return ' + stringOut, async function () { - const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read, [values[0]], isCapsUsed); + const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read as KeylayoutXMLSourceFile, [values[0]], isCapsUsed); assert.equal(JSON.stringify(result), JSON.stringify([values[1]])); }); }); @@ -548,7 +549,7 @@ describe('KeylayoutToKmnConverter', function () { ].forEach(function (values) { const isCaps = true; it(("getKeybehaviorModOutputArrayFromKeyActionbehaviorOutputArray([" + values[0] + "])").padEnd(74, " ") + ' should return ' + "[" + values[1] + "]", async function () { - const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read, values[0] ?? [], isCaps); + const result = sut.getKeyBehaviorModOutputArrayFromKeyActionBehaviorOutputArray(read as KeylayoutXMLSourceFile, values[0] ?? [], isCaps); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -595,7 +596,7 @@ describe('KeylayoutToKmnConverter', function () { it((JSON.stringify(values[1]).length > 30) ? ("getActionStateOutputArrayFromActionState('" + values[0] + "')").padEnd(60, " ") + ' should return an array of objects' : ("getActionStateOutputArrayFromActionState('" + values[0] + "')").padEnd(60, " ") + ' should return ' + "'" + JSON.stringify(values[1]) + "'", async function () { - const result = sut.getActionStateOutputArrayFromActionState(read, String(values[0])); + const result = sut.getActionStateOutputArrayFromActionState(read as KeylayoutXMLSourceFile, String(values[0])); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -606,7 +607,7 @@ describe('KeylayoutToKmnConverter', function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test.keylayout'); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.convertBound.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); [ ['A_1', 'A', true, [{ "outchar": "A", "actionId": "A_1", "behavior": "1", "key": "K_A", "modifier": "CAPS" }, @@ -631,7 +632,7 @@ describe('KeylayoutToKmnConverter', function () { it((JSON.stringify(values[3]).length > 35) ? ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' : ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () { - const result = sut.getActionOutputBehaviorKeyModiFromActionIDStateOutput(read, converted.modifiers, String(values[0]), String(values[1]), Boolean(values[2])); + const result = sut.getActionOutputBehaviorKeyModiFromActionIDStateOutput(read as KeylayoutXMLSourceFile, converted.modifiers, String(values[0]), String(values[1]), Boolean(values[2])); assert.equal(JSON.stringify(result), JSON.stringify(values[3])); }); } @@ -686,7 +687,7 @@ describe('KeylayoutToKmnConverter', function () { [[b6ActionIdArr, b1KeycodeArr], ].forEach(function (values) { it(("getKeyActionOutputArrayFromActionStateOutputArray([['" + JSON.stringify(values[0]) + "'],..])").padEnd(73, " ") + '1 should return an array of objects', async function () { - const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]); + const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read as KeylayoutXMLSourceFile, values[0] as ActionStateOutput[]); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -716,7 +717,7 @@ describe('KeylayoutToKmnConverter', function () { [[{ "id": "A_0", "state": "", "output": "ˆ" }], oneEntryResult], ].forEach(function (values) { it(("getKeyActionOutputArrayFromActionStateOutputArray(['" + JSON.stringify(values[0]) + "'])").padEnd(73, " ") + ' should return an array of objects', async function () { - const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]); + const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read as KeylayoutXMLSourceFile, values[0] as ActionStateOutput[]); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -727,7 +728,7 @@ describe('KeylayoutToKmnConverter', function () { ].forEach(function (values) { it(("getKeyActionOutputArrayFromActionStateOutputArray(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () { - const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]); + const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read as KeylayoutXMLSourceFile, values[0] as ActionStateOutput[]); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -737,7 +738,7 @@ describe('KeylayoutToKmnConverter', function () { [null, []], ].forEach(function (values) { it(("getKeyActionOutputArrayFromActionStateOutputArray(" + JSON.stringify(values[0]) + ")").padEnd(73, " ") + ' should return ' + "'[" + JSON.stringify(values[1]) + "]'", async function () { - const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read, values[0] as ActionStateOutput[]); + const result = sut.getKeyActionOutputArrayFromActionStateOutputArray(read as KeylayoutXMLSourceFile, values[0] as ActionStateOutput[]); assert.equal(JSON.stringify(result), JSON.stringify(values[1])); }); }); @@ -797,7 +798,7 @@ describe('KeylayoutToKmnConverter', function () { it('data of \'' + values[0] + "' passed into createRuleData() " + 'should create an array of rules', async function () { const inputFilename = makePathToFixture(values[0][0]); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const processedData = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + const processedData = sut.convertBound.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); assert.deepEqual(processedData?.rules[0], values[1][0]); }); }); diff --git a/developer/src/kmc-convert/test/kmn-file-reader.tests.ts b/developer/src/kmc-convert/test/kmn-file-reader.tests.ts index 35da499d44..c3509a5dd4 100644 --- a/developer/src/kmc-convert/test/kmn-file-reader.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-reader.tests.ts @@ -24,38 +24,38 @@ describe('KeylayoutFileReader', function () { it('validate() should return true on correct inputfile', async function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test.keylayout'); - const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const validated = sutR.validate(result); + const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result as Keylayout.KeylayoutXMLSourceFile, inputFilename); assert.isTrue(validated); }); it('validate() should return false on inputfile with unknown tags', async function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test_unknownTags.keylayout'); - const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const validated = sutR.validate(result); + const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result as Keylayout.KeylayoutXMLSourceFile, inputFilename); assert.isFalse(validated); }); it('validate() should return false on inputfile with additional tags', async function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test_additionalTags.keylayout'); - const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const validated = sutR.validate(result); + const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result as Keylayout.KeylayoutXMLSourceFile, inputFilename); assert.isFalse(validated); }); it('validate() should return false on inputfile with missing tags', async function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test_missingTags.keylayout'); - const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const validated = sutR.validate(result); + const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result as Keylayout.KeylayoutXMLSourceFile, inputFilename); assert.isFalse(validated); }); it('validate() should return false on no entries in action-when', async function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const inputFilename = makePathToFixture('../data/Test_noActionWhen.keylayout'); - const result: Keylayout.KeylayoutXMLSourceFile|null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const validated = sutR.validate(result); + const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(result as Keylayout.KeylayoutXMLSourceFile, inputFilename); assert.isFalse(validated); }); }); From 9675611e89ea93ebb2539ae20e3bdb3cbf410e02 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 5 May 2026 13:10:21 +0200 Subject: [PATCH 09/33] feat(developer): add tests and comments --- .../keylayout-to-kmn/keylayout-file-reader.ts | 12 ++- .../kmc-convert/test/kmn-file-reader.tests.ts | 93 +++++++++++++++++++ .../kmc-convert/test/kmn-file-writer.tests.ts | 11 +++ 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts index 0be7550ef8..d8443e369b 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts @@ -19,7 +19,9 @@ export class KeylayoutFileReader { /** - * @brief helper function to find a specific keyMap index in a keyMapSet + * @brief helper function to check if a specific keyMap index exists in a keyMapSet + * neccessary because the amount of must correspond to + * the amount of * @param jsonObj the read keylayout data to be checked * @param keyMapSelect the keyMapSelect element to find in keyMapSet * @return true if the keyMapSet element is found, false if not @@ -36,7 +38,9 @@ export class KeylayoutFileReader { } /** - * @brief helper function to find a specific keyMapSelect index in a modifierMap + * @brief helper function to check if a specific keyMapSelect index exists in a modifierMap + * neccessary because the amount of must correspond to + * the amount of * @param jsonObj the read keylayout data to be checked * @param keyMap the keyMap element to find in modifierMap * @return true if the keyMap element is found, false if not @@ -53,8 +57,8 @@ export class KeylayoutFileReader { } /** - * @brief member function checking if all keyMapSelect elements have a corresponding keyMap - * element in the .keylayout file (if not, the .keylayout file is invalid and will not be converted) + * @brief member function checking if all keyMapSelect elements have exact one corresponding keyMap element (per keyMapSet) + * in the .keylayout file (if not, the .keylayout file is invalid and will not be converted) * see TN2056 (https://developer.apple.com/library/archive/technotes/tn2056/_index.html#//apple_ref/doc/uid/DTS10003085-CH1-SUBSECTION7) * @param jsonObj the read keylayout data to be checked * @return true if all keyMapSelect elements have a corresponding keyMap element, false if not diff --git a/developer/src/kmc-convert/test/kmn-file-reader.tests.ts b/developer/src/kmc-convert/test/kmn-file-reader.tests.ts index c3509a5dd4..5ea9f9e244 100644 --- a/developer/src/kmc-convert/test/kmn-file-reader.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-reader.tests.ts @@ -12,6 +12,7 @@ import { assert } from 'chai'; import { Keylayout } from "@keymanapp/developer-utils"; import { compilerTestCallbacks, makePathToFixture } from './helpers/index.js'; import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js'; +import { KL_KeyMap, KL_KeyMapSelect } from "../../common/web/utils/src/types/keylayout/keylayout-xml.js"; describe('KeylayoutFileReader', function () { @@ -58,6 +59,20 @@ describe('KeylayoutFileReader', function () { const validated = sutR.validate(result as Keylayout.KeylayoutXMLSourceFile, inputFilename); assert.isFalse(validated); }); + it('validate() should return false on null as input', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test_noActionWhen.keylayout'); + //const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(null, inputFilename); + assert.isFalse(validated); + }); + it('validate() should return false on undefined as input', async function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test_noActionWhen.keylayout'); + //const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const validated = sutR.validate(undefined, inputFilename); + assert.isFalse(validated); + }); }); describe("read() ", function () { @@ -91,4 +106,82 @@ describe('KeylayoutFileReader', function () { }); }); + describe('findMapIndexinKeymap ', function () { + const keyMapSelect: KL_KeyMapSelect = { + mapIndex: '', + modifier: [] + }; + + keyMapSelect.modifier.push({ keys: 'caps' }); + keyMapSelect.modifier.push({ keys: 'rightOption' }); + keyMapSelect.modifier.push({ keys: 'rightShift caps' }); + + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test.keylayout'); + const jsonO: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + [ + ['0', true], + ['7', true], + ['999', false], + ['A', false], + [123, false], + ['', false], + [null, false], + [undefined, false], + ].forEach(function (values) { + it(("findMapIndexinKeymap(keyMapSelect.mapIndex = '" + values[0] + "')").padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { + keyMapSelect.mapIndex = values[0] as string; + const result = sutR.findMapIndexinKeymap(jsonO as Keylayout.KeylayoutXMLSourceFile, keyMapSelect); + assert.isTrue(result === values[1]); + }); + }); + }); + + describe('findIndexinKeymapSelect ', function () { + const keyMap: KL_KeyMap = { + index: '', + key: [] + }; + keyMap.key.push({ code: '0', output: 'A' }); + keyMap.key.push({ code: '1', action: 'S' }); + keyMap.key.push({ code: '2', output: 'D' }); + + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + const inputFilename = makePathToFixture('../data/Test.keylayout'); + const jsonO: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + [ + ['0', true], + ['7', true], + ['999', false], + ['A', false], + [123, false], + ['', false], + [null, false], + [undefined, false], + ].forEach(function (values) { + it(("findIndexinKeymapSelect(keyMap.index = '" + values[0] + "')").padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { + keyMap.index = values[0] as string; + const result = sutR.findIndexinKeymapSelect(jsonO as Keylayout.KeylayoutXMLSourceFile, keyMap); + assert.isTrue(result === values[1]); + }); + }); + }); + + describe('checkForCorrespondingElements ', function () { + const sutR = new KeylayoutFileReader(compilerTestCallbacks); + [ + ['../data/Test.keylayout', true], + ['../data/Test_sameKeyMapAndKeyMapselectAndJisERROR.keylayout', true], + ['../data/Test_moreKeymapSelectThanKeymapERROR.keylayout', false], + ['../data/Test_moreKeyMapThanKeyMapselectERROR.keylayout', false], + ['../data/Test_moreKeyMapThanKeyMapselectAndJisERROR.keylayout', false], + ].forEach(function (values) { + it(("checkForCorrespondingElements in " + values[0] ).padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { + const jsonO: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(makePathToFixture(values[0] as string))); + const result = sutR.checkForCorrespondingElements(jsonO as Keylayout.KeylayoutXMLSourceFile); + assert.isTrue(result === values[1]); + }); + }); + }); + }); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index c3ee842bab..635caff354 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -65,6 +65,12 @@ describe('KmnFileWriter', function () { const writtenCorrectName = sutW.writeKmnFileHeader(converted); assert.equal(writtenCorrectName, (outExpectedFirst + (converted?.keylayoutFilename ?? "") + outExpectedLast)); }); + it(('writeKmnFileHeader should return no text with null filename ').padEnd(62, " ") + 'on correct input', async function () { + const writtenEmptytName = sutW.writeKmnFileHeader(null); + assert.equal(writtenEmptytName, ''); + }); + + }); describe('convertToUnicodeCharacter ', function () { @@ -483,7 +489,12 @@ describe('KmnFileWriter', function () { const result1 = sutW.writeDataRules(data); assert.isTrue(result1 === values[1][0]); }); + }); + it(('null should create empty string '), async function () { + const result1 = sutW.writeDataRules(null); + assert.isTrue(result1 === ''); + }); }); }); From 302e7b0aa569cbb83963f5587ab980baa09ba077 Mon Sep 17 00:00:00 2001 From: Sabine Date: Tue, 5 May 2026 13:19:40 +0200 Subject: [PATCH 10/33] feat(developer): add testfile --- ...KeyMapAndKeyMapselectAndJisERROR.keylayout | 78 +++++++++++++++++++ .../kmc-convert/test/kmn-file-writer.tests.ts | 5 +- 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 developer/src/kmc-convert/test/data/Test_sameKeyMapAndKeyMapselectAndJisERROR.keylayout diff --git a/developer/src/kmc-convert/test/data/Test_sameKeyMapAndKeyMapselectAndJisERROR.keylayout b/developer/src/kmc-convert/test/data/Test_sameKeyMapAndKeyMapselectAndJisERROR.keylayout new file mode 100644 index 0000000000..ca02f833f0 --- /dev/null +++ b/developer/src/kmc-convert/test/data/Test_sameKeyMapAndKeyMapselectAndJisERROR.keylayout @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 635caff354..6610d78357 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -11,6 +11,7 @@ import 'mocha'; import { assert } from 'chai'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { compilerTestCallbacks, compilerTestOptions, makePathToFixture } from './helpers/index.js'; +import { KeylayoutXMLSourceFile } from '../../common/web/utils/src/types/keylayout/keylayout-xml.js'; import { KeylayoutToKmnConverter, ProcessedData, Rule } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js'; import { KmnFileWriter } from '../src/keylayout-to-kmn/kmn-file-writer.js'; import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js'; @@ -27,7 +28,7 @@ describe('KmnFileWriter', function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.convertBound.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); it('writeDataRules() should return true (no error) if written', async function () { const result = sutW.writeDataRules(converted); @@ -42,7 +43,7 @@ describe('KmnFileWriter', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); const inputFilename = makePathToFixture('../data/Test.keylayout'); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.convertBound.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.convertBound.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); const outExpectedFirst: string = "c ..................................................................................................................\n" From 5052581b076bab96dd71cb6f594674ac7d1d4635 Mon Sep 17 00:00:00 2001 From: Sabine Date: Wed, 20 May 2026 13:18:31 +0200 Subject: [PATCH 11/33] feat(developer): add missing bracket --- .../src/kmc-convert/test/keylayout-file-reader.tests.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts b/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts index ea0725a32a..a5c4bccb55 100644 --- a/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts @@ -71,6 +71,7 @@ describe('KeylayoutFileReader', function () { //const result: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); const validated = sutR.validate(undefined, inputFilename); assert.isFalse(validated); + }); }); describe('validate() should return false on inputfiles with errors ', function () { @@ -200,11 +201,14 @@ describe('KeylayoutFileReader', function () { ['../data/Test_moreKeyMapThanKeyMapselectERROR.keylayout', false], ['../data/Test_moreKeyMapThanKeyMapselectAndJisERROR.keylayout', false], ].forEach(function (values) { - it(("checkForCorrespondingElements in " + values[0] ).padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { + it(("checkForCorrespondingElements in " + values[0]).padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { const jsonO: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(makePathToFixture(values[0] as string))); const result = sutR.checkForCorrespondingElements(jsonO as Keylayout.KeylayoutXMLSourceFile); assert.isTrue(result === values[1]); }); + }); + }); + describe("read() check structure of returned JSON", function () { it('read() should have the correct JSON structure', async function () { From 82c8af203476b38dc0331dad9d6512bc85a244e1 Mon Sep 17 00:00:00 2001 From: Sabine Date: Wed, 20 May 2026 22:36:43 +0200 Subject: [PATCH 12/33] feat(developer): dummy change to start team city --- .../kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts index a28ce15529..099193e32b 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts @@ -17,7 +17,6 @@ export class KeylayoutFileReader { constructor(private callbacks: CompilerCallbacks /*,private options: CompilerOptions*/) { }; - /** * @brief helper function to check if a specific keyMap index exists in a keyMapSet * neccessary because the amount of must correspond to From 160f92a858d0c4027eb2d89cee17dad94bc44da8 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 11:20:45 +0200 Subject: [PATCH 13/33] feat(developer): work on comments of PR review --- .../src/kmc-convert/src/converter-messages.ts | 2 +- .../keylayout-to-kmn/keylayout-file-reader.ts | 12 +-- .../keylayout-to-kmn-converter.ts | 4 +- .../src/keylayout-to-kmn/kmn-file-writer.ts | 55 +++++------- .../test/keylayout-file-reader.tests.ts | 16 ++-- .../test/keylayout-to-kmn-converter.tests.ts | 83 +++++++++---------- .../kmc-convert/test/kmn-file-writer.tests.ts | 69 ++++++++------- 7 files changed, 117 insertions(+), 124 deletions(-) diff --git a/developer/src/kmc-convert/src/converter-messages.ts b/developer/src/kmc-convert/src/converter-messages.ts index 7c8b0d3a3e..b234c1c073 100644 --- a/developer/src/kmc-convert/src/converter-messages.ts +++ b/developer/src/kmc-convert/src/converter-messages.ts @@ -20,7 +20,7 @@ export class ConverterMessages { static ERROR_FileNotFound = SevError | 0x0003; static Error_FileNotFound = (o: { inputFilename: string | null; }) => m( this.ERROR_FileNotFound, - `Input filename '${def(o.inputFilename)}' does not exist or could not be loaded.` + `Input filename '${def(o?.inputFilename)}' does not exist or could not be loaded.` ); static ERROR_InvalidFile = SevError | 0x0004; diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts index 099193e32b..d35e32de56 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts @@ -18,9 +18,9 @@ export class KeylayoutFileReader { constructor(private callbacks: CompilerCallbacks /*,private options: CompilerOptions*/) { }; /** - * @brief helper function to check if a specific keyMap index exists in a keyMapSet - * neccessary because the amount of must correspond to - * the amount of + * @brief Helper function to check if a specific keyMap index exists in a keyMapSet. + * This is neccessary because the amount of must correspond to + * the amount of . * @param jsonObj the read keylayout data to be checked * @param keyMapSelect the keyMapSelect element to find in keyMapSet * @return true if the keyMapSet element is found, false if not @@ -37,9 +37,9 @@ export class KeylayoutFileReader { } /** - * @brief helper function to check if a specific keyMapSelect index exists in a modifierMap - * neccessary because the amount of must correspond to - * the amount of + * @brief Helper function to check if a specific keyMapSelect index exists in a modifierMap. + * This is neccessary because the amount of must correspond to + * the amount of . * @param jsonObj the read keylayout data to be checked * @param keyMap the keyMap element to find in modifierMap * @return true if the keyMap element is found, false if not diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index c91905b290..6e85da7d74 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -52,7 +52,7 @@ export interface KeylayoutFileData { key?: string; behavior: string; modifier?: string; - outchar?: string | undefined; + outchar?: string; }; /** @@ -492,7 +492,7 @@ export class KeylayoutToKmnConverter { } else { this.callbacks.reportMessage(ConverterMessages.Error_UnsupportedCharactersDetected({ keymapIndex: jsonObj.keyboard.keyMapSet[0].keyMap[i]['index'], - output: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['output'] ?? '' as string, + output: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['output'] ?? '', key: jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['code'], KeyName: this.mapUkeleleKeycodeToVK(Number(jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['code'])) })); diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 68cc0be382..e66db3623f 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -149,7 +149,6 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - let versionOutputCharacter; const warnText = this.reviewRules(uniqueDataRules, k); const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); @@ -157,16 +156,9 @@ export class KmnFileWriter { // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - // in case writeCharacterOrUnicode() returns null, the fallback is empty strings for characterMessage.character - // and characterMessage.message. Then versionOutputCharacter could be "" and would be written into the kmn file - // as ... > '', producing an invalid kmn rule. - if ((outputCharacter !== undefined) && (outputCharacter !== "")) { - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - - versionOutputCharacter = characterMessage?.character ?? ""; - warnText[2] = characterMessage?.message ?? ""; - - } + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + const versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -219,7 +211,6 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - let versionOutputCharacter; const warnText = this.reviewRules(uniqueDataRules, k); const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); @@ -227,14 +218,9 @@ export class KmnFileWriter { // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - // in case writeCharacterOrUnicode() returns null, the fallback is empty strings for characterMessage.character - // and characterMessage.message. Then versionOutputCharacter could be "" and would be written into the kmn file - // as ... > '', producing an invalid kmn rule. - if ((outputCharacter !== undefined) && (outputCharacter !== "")) { - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - versionOutputCharacter = characterMessage?.character ?? ""; - warnText[2] = characterMessage?.message ?? ""; - } + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + const versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -309,20 +295,14 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - let versionOutputCharacter; const warnText = this.reviewRules(uniqueDataRules, k); const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class - // in case writeCharacterOrUnicode() returns null, the fallback is empty strings for characterMessage.character - // and characterMessage.message. Then versionOutputCharacter could be "" and would be written into the kmn file - // as ... > '', producing an invalid kmn rule. - if ((outputCharacter !== undefined) && (outputCharacter !== "")) { - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - versionOutputCharacter = characterMessage?.character ?? ""; - warnText[2] = characterMessage?.message ?? ""; - } + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + const versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -1636,10 +1616,10 @@ export class KmnFileWriter { * a non-control character will be written as itself ( 'A', '1', '፩', '😎') * null in case of an empty string or null or undefined input */ - public writeCharacterOrUnicode(ctr: string, msg: string = ""): MessageCharacter | null { + public writeCharacterOrUnicode(ctr: string, msg: string = ""): MessageCharacter { if ((ctr === null) || (ctr === undefined) || (ctr.length === 0)) { - return null; + return { character: '', message: '' }; } let versionOutputCharacter; @@ -1653,8 +1633,14 @@ export class KmnFileWriter { const m_dec = /^&#([0-9]{1,7});$/.exec(ctr); // find the value of output character which may be specified in unicode, html hex or html dec format ( e.g. U+1234 -> 1234; ሴ -> 1234; ሴ -> 1234) - const ctr_val = ((m_uni || m_hex || m_dec) ? - m_uni ? parseInt(m_uni[1], 16) : m_hex ? parseInt(m_hex[1], 16) : m_dec ? parseInt(m_dec[1], 10) : KeylayoutToKmnConverter.MAX_CTRL_CHARACTER : KeylayoutToKmnConverter.MAX_CTRL_CHARACTER + const ctr_val = ( + m_uni + ? parseInt(m_uni[1], 16) + : m_hex + ? parseInt(m_hex[1], 16) + : m_dec + ? parseInt(m_dec[1], 10) + : KeylayoutToKmnConverter.MAX_CTRL_CHARACTER ); // for control characters in 'U+...', '&#x...' or '&#...' format as well as in "" format @@ -1693,8 +1679,7 @@ export class KmnFileWriter { */ public convertToUnicodeCharacter(inputString: string): string | undefined { - - // null, undefined will later be refused for conversion + // null, undefined will later be treated as '' in conversion if (inputString == null || inputString == undefined) { return undefined; } diff --git a/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts b/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts index a5c4bccb55..f9abe65d9c 100644 --- a/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-file-reader.tests.ts @@ -157,7 +157,7 @@ describe('KeylayoutFileReader', function () { it(("findMapIndexinKeymap(keyMapSelect.mapIndex = '" + values[0] + "')").padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { keyMapSelect.mapIndex = values[0] as string; const result = sutR.findMapIndexinKeymap(jsonO as Keylayout.KeylayoutXMLSourceFile, keyMapSelect); - assert.isTrue(result === values[1]); + assert.equal(result, values[1]); }); }); }); @@ -187,7 +187,7 @@ describe('KeylayoutFileReader', function () { it(("findIndexinKeymapSelect(keyMap.index = '" + values[0] + "')").padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { keyMap.index = values[0] as string; const result = sutR.findIndexinKeymapSelect(jsonO as Keylayout.KeylayoutXMLSourceFile, keyMap); - assert.isTrue(result === values[1]); + assert.equal(result, values[1]); }); }); }); @@ -204,7 +204,7 @@ describe('KeylayoutFileReader', function () { it(("checkForCorrespondingElements in " + values[0]).padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { const jsonO: Keylayout.KeylayoutXMLSourceFile | null = sutR.read(compilerTestCallbacks.loadFile(makePathToFixture(values[0] as string))); const result = sutR.checkForCorrespondingElements(jsonO as Keylayout.KeylayoutXMLSourceFile); - assert.isTrue(result === values[1]); + assert.equal(result, values[1]); }); }); }); @@ -219,7 +219,7 @@ describe('KeylayoutFileReader', function () { const result: Keylayout.KeylayoutXMLSourceFile = sutR.read(binaryData); assert.isNotNull(result); - assert.isTrue(result.keyboard !== null); + assert.notEqual(result.keyboard, null); for (let i = 0; i < result.keyboard.layouts.length; i++) { assert.isTrue(result.keyboard.layouts[i].layout.length > 0); @@ -231,8 +231,8 @@ describe('KeylayoutFileReader', function () { for (let j = 0; j < result.keyboard.keyMapSet[i].keyMap.length; j++) { assert.isTrue(result.keyboard.keyMapSet[i].keyMap[j].key.length > 0); for (let k = 0; k < result.keyboard.keyMapSet[i].keyMap[j].key.length; k++) { - assert.isTrue(result.keyboard.keyMapSet[i].keyMap[j].key[k]['action'] !== null - || result.keyboard.keyMapSet[i].keyMap[j].key[k]['output'] !== null); + assert.isNotNull(result.keyboard.keyMapSet[i].keyMap[j].key[k]['action']); + assert.isNotNull(result.keyboard.keyMapSet[i].keyMap[j].key[k]['output']); } } } @@ -247,8 +247,8 @@ describe('KeylayoutFileReader', function () { for (let i = 0; i < result.keyboard.modifierMap.length; i++) { assert.isTrue(result.keyboard.modifierMap[i].keyMapSelect.length > 0); for (let j = 0; j < result.keyboard.keyMapSet.length; j++) { - assert.isTrue(result.keyboard.keyMapSet[j].keyMap.length - === result.keyboard.modifierMap[i].keyMapSelect.length); + assert.equal(result.keyboard.keyMapSet[j].keyMap.length, + result.keyboard.modifierMap[i].keyMapSelect.length); } } }); diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index b4443a6f9f..e7afbf3fc6 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -47,8 +47,8 @@ describe('KeylayoutToKmnConverter', function () { ['../data/Test_ExtraWarning.keylayout'], ].forEach(function (files) { it(files + " should give no errors ", async function () { - sut.run(makePathToFixture(files[0])); - assert.isTrue(compilerTestCallbacks.messages.length === 0); + await sut.run(makePathToFixture(files[0])); + assert.equal(compilerTestCallbacks.messages.length, 0); }); }); }); @@ -70,7 +70,7 @@ describe('KeylayoutToKmnConverter', function () { ['../data/Test_characters.keylayout'], ].forEach(function (files) { it(files + " should give an error ", async function () { - sut.run(makePathToFixture(files[0])); + await sut.run(makePathToFixture(files[0])); assert.isTrue(compilerTestCallbacks.messages.length > 0); }); }); @@ -83,8 +83,8 @@ describe('KeylayoutToKmnConverter', function () { ['../data/Test_undefinedAction.keylayout'], ].forEach(function (files) { it(files + " should give Error: undefined action detected", async function () { - sut.run(makePathToFixture(files[0])); - assert.isTrue(compilerTestCallbacks.messages.length === 1); + await sut.run(makePathToFixture(files[0])); + assert.equal(compilerTestCallbacks.messages.length, 1); assert.equal(compilerTestCallbacks.messages[0].code, 5292040); }); }); @@ -95,10 +95,9 @@ describe('KeylayoutToKmnConverter', function () { it('run() should throw on unavailable input file name and null output file name', async function () { const inputFilename = makePathToFixture('../data/Unavailable.keylayout'); - const result = sut.run(inputFilename, undefined); - assert.isNotNull(result); + const result = await sut.run(inputFilename, undefined); + assert.isNull(result); assert.equal(compilerTestCallbacks.messages.length, 2); - //assert.deepEqual(compilerTestCallbacks.messages[0], ConverterMessages.Error_UnableToRead()); assert.isTrue(compilerTestCallbacks.hasMessage(ConverterMessages.ERROR_UnableToRead)); assert.equal(compilerTestCallbacks.messages[1].code, 5292037); }); @@ -115,43 +114,44 @@ describe('KeylayoutToKmnConverter', function () { ['../data/OutputXName.bb'], ].forEach(function (files) { it(infile + " should run ", async function () { - await NodeAssert.doesNotReject(async () => sut.run(makePathToFixture(infile), makePathToFixture(files[0])?? undefined)); + await NodeAssert.doesNotReject(async () => await sut.run(makePathToFixture(infile), makePathToFixture(files[0]) ?? undefined)); assert.equal(compilerTestCallbacks.messages.length, 0); }); }); }); describe('convert() ', function () { - const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); - const sutR = new KeylayoutFileReader(compilerTestCallbacks); - // ProcessedData from usable file - const inputFilename = makePathToFixture('../data/Test.keylayout'); - const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + let sut: KeylayoutToKmnConverter; + let sutR: KeylayoutFileReader; - const converted = sut.unitTestEndpoints.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); - - - // ProcessedData from unavailable file - const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout'); - const readUnavailable = sutR.read(compilerTestCallbacks.loadFile(inputFilenameUnavailable)); - - const convertedUnavailable = sut.unitTestEndpoints.convert(readUnavailable as KeylayoutXMLSourceFile, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn')); - - // ProcessedData from empty file - const inputFilenameEmpty = makePathToFixture(''); - const readEmpty = sutR.read(compilerTestCallbacks.loadFile(inputFilenameEmpty)); - const convertedEmpty = sut.unitTestEndpoints.convert(readEmpty as KeylayoutXMLSourceFile, inputFilenameEmpty); - - it('should return converted array on correct input', async function () { - assert.isTrue(converted?.rules.length !== 0); + beforeEach(function () { + sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); + sutR = new KeylayoutFileReader(compilerTestCallbacks); }); + // ProcessedData from usable file + it('should return converted array on correct input', async function () { + const inputFilename = makePathToFixture('../data/Test.keylayout'); + const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); + const converted = sut.unitTestEndpoints.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); + assert.isNotNull(converted); + assert.notEqual(converted.rules.length, 0); + }); + + // ProcessedData from unavailable file it('should return null on empty name as input', async function () { + const inputFilenameUnavailable = makePathToFixture('../data/X.keylayout'); + const readUnavailable = sutR.read(compilerTestCallbacks.loadFile(inputFilenameUnavailable)); + const convertedUnavailable = sut.unitTestEndpoints.convert(readUnavailable as KeylayoutXMLSourceFile, inputFilenameUnavailable.replace(/\.keylayout$/, '.kmn')); assert.isNull(convertedUnavailable); }); + // ProcessedData from empty file it('should return null on empty input', async function () { + const inputFilenameEmpty = makePathToFixture(''); + const readEmpty = sutR.read(compilerTestCallbacks.loadFile(inputFilenameEmpty)); + const convertedEmpty = sut.unitTestEndpoints.convert(readEmpty as KeylayoutXMLSourceFile, inputFilenameEmpty); assert.isNull(convertedEmpty); }); @@ -281,7 +281,7 @@ describe('KeylayoutToKmnConverter', function () { ].forEach(function (values) { it(("checkIfCapsIsUsed(" + values[0] + ")").padEnd(40, " ") + "should return " + "'" + values[1] + "'", async function () { const result = sut.checkIfCapsIsUsed(values[0] as string[][]); - assert.isTrue(result === values[1]); + assert.equal(result, values[1]); }); }); }); @@ -308,7 +308,6 @@ describe('KeylayoutToKmnConverter', function () { it((values[1] !== null) ? ("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + JSON.stringify(values[1]) + "'" : ("getModifierArrayFromKeyModifierArray('" + JSON.stringify(values[0]) + "')").padEnd(68, " ") + " should return '" + "null" + "'", async function () { - const result = sut.getModifierArrayFromKeyModifierArray(converted?.modifiers as string[][], values[0] as unknown as KeylayoutFileData[]); assert.deepStrictEqual(JSON.stringify(result), JSON.stringify(values[1])); }); @@ -605,14 +604,13 @@ describe('KeylayoutToKmnConverter', function () { ['', 'a', false, []], ['', '', , []], ].forEach(function (values) { - if (converted) { - it((JSON.stringify(values[3]).length > 35) ? - ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' : - ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () { - const result = sut.getActionOutputBehaviorKeyModiFromActionIDStateOutput(read as KeylayoutXMLSourceFile, converted.modifiers, String(values[0]), String(values[1]), Boolean(values[2])); - assert.equal(JSON.stringify(result), JSON.stringify(values[3])); - }); - } + assert.isNotNull(read); + it((JSON.stringify(values[3]).length > 35) ? + ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return an array of objects' : + ("getActionOutputbehaviorKeyModiFromActionIDStateOutput('" + values[0] + "', '" + values[1] + "', " + values[2] + ")").padEnd(67, " ") + ' should return ' + "'" + JSON.stringify(values[3]) + "'", async function () { + const result = sut.getActionOutputBehaviorKeyModiFromActionIDStateOutput(read as KeylayoutXMLSourceFile, converted.modifiers, String(values[0]), String(values[1]), Boolean(values[2])); + assert.equal(JSON.stringify(result), JSON.stringify(values[3])); + }); }); }); @@ -775,8 +773,9 @@ describe('KeylayoutToKmnConverter', function () { it('data of \'' + values[0] + "' passed into createRuleData() " + 'should create an array of rules', async function () { const inputFilename = makePathToFixture(values[0][0]); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const processedData = sut.unitTestEndpoints.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); - assert.deepEqual(processedData?.rules[0], values[1][0]); + const processedData = sut.unitTestEndpoints.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); + assert.isNotNull(processedData); + assert.deepEqual(processedData.rules[0], values[1][0]); }); }); }); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index caa21faf65..c90ea3f095 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -64,7 +64,8 @@ describe('KmnFileWriter', function () { it(('writeKmnFileHeader should return store text with filename ').padEnd(62, " ") + 'on correct input', async function () { const writtenCorrectName = sutW.writeKmnFileHeader(converted); - assert.equal(writtenCorrectName, (outExpectedFirst + (converted?.keylayoutFilename ?? "") + outExpectedLast)); + assert.isNotNull(converted); + assert.equal(writtenCorrectName, (outExpectedFirst + (converted.keylayoutFilename ?? "") + outExpectedLast)); }); it(('writeKmnFileHeader should return no text with null filename ').padEnd(62, " ") + 'on correct input', async function () { const writtenEmptytName = sutW.writeKmnFileHeader(null); @@ -120,34 +121,42 @@ describe('KmnFileWriter', function () { }); }); - describe('writeCharacterOrUnicode ', function () { + describe('writeCharacterOrUnicode and return values', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); [ - ["A", "Msg", "A", "Msg"], - ["ሴ", "Msg", "ሴ", "Msg"], - ["😀", "Msg", "😀", "Msg"], - ["ẘ", "Msg", "ẘ", "Msg"], - ["U+0001", "Msg", "U+0001", "Msg; Use of a control character "], - ["U+0061", "Msg", "a", "Msg"], - ["", "Msg", "U+0002", "Msg; Use of a control character "], - ["ሴ", "Msg", 'ሴ', "Msg",], - ["", "Msg", "U+0003", "Msg; Use of a control character "], - ["ሺ", "Msg", "ሺ", "Msg",], - [null, "Msg", null, null], - [undefined, "Msg", null, null], - ["", "Msg", null, null], - ["", "Msg", "U+0006", "Msg; Use of a control character "], + ["A", "A", "Msg"], + ["ሴ", "ሴ", "Msg"], + ["😀", "😀", "Msg"], + ["ẘ", "ẘ", "Msg"], + ["U+0001", "U+0001", "Msg; Use of a control character "], + ["U+0061", "a", "Msg"], + ["", "U+0002", "Msg; Use of a control character "], + ["ሴ", 'ሴ', "Msg"], + ["", "U+0003", "Msg; Use of a control character "], + ["ሺ", "ሺ", "Msg"], + ["", "U+0006", "Msg; Use of a control character "], ].forEach(function (values) { - it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[2] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, values[1] as string); - if (result) { - assert.equal(result.character, values[2]); - assert.equal(result.message, values[3]); - } - else { - assert.isNull(values[2]); - assert.isNull(values[3]); - } + it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); + assert.isNotNull(result); + assert.equal(result.character, values[1]); + assert.equal(result.message, values[2]); + }); + }); + }); + + describe('writeCharacterOrUnicode and return empty string for result.message and result.character', function () { + const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); + [ + [null, '', ''], + [undefined,'', ''], + ['', '', ''], + ].forEach(function (values) { + it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); + assert.isNotNull(result); + assert.equal(result.character, values[1]); + assert.equal(result.message, values[2]); }); }); }); @@ -488,14 +497,14 @@ describe('KmnFileWriter', function () { rules: values[0] as Rule[] }; const result1 = sutW.writeDataRules(data); - assert.isTrue(result1 === values[1][0]); + assert.equal(result1, values[1][0]); }); }); it(('null should create empty string '), async function () { - const result1 = sutW.writeDataRules(null); - assert.isTrue(result1 === ''); - }); + const result1 = sutW.writeDataRules(null); + assert.equal(result1, ''); + }); }); }); From c11e6f8b15ce4034b732c706888aaba809505e70 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 18:43:26 +0200 Subject: [PATCH 14/33] feat(developer):kmc-convert fix typos in tests --- developer/src/kmc-convert/test/kmn-file-writer.tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index c90ea3f095..baabf277da 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -137,7 +137,7 @@ describe('KmnFileWriter', function () { ["", "U+0006", "Msg; Use of a control character "], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg; "); assert.isNotNull(result); assert.equal(result.character, values[1]); assert.equal(result.message, values[2]); @@ -153,7 +153,7 @@ describe('KmnFileWriter', function () { ['', '', ''], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg; "); assert.isNotNull(result); assert.equal(result.character, values[1]); assert.equal(result.message, values[2]); From 9dcd90c634aee2a608b7469a2ec0a2f3131df4fd Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 18:58:08 +0200 Subject: [PATCH 15/33] feat(developer):kmc-convert fix more typos in tests --- .../src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts | 2 +- developer/src/kmc-convert/test/kmn-file-writer.tests.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 7c8f5800bc..eb92f3a797 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -1673,7 +1673,7 @@ export class KmnFileWriter { // add a warning message if (msg !== "") { - msg = msg + msg_control + msg_entity; + msg = msg + "; " + msg_control + msg_entity; } if ((msg === "") && (msg_entity !== "" || msg_control !== "")) { msg = "c WARNING: " + msg_entity + msg_control; diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index baabf277da..bd93bbdeba 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -137,7 +137,7 @@ describe('KmnFileWriter', function () { ["", "U+0006", "Msg; Use of a control character "], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg; "); + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); assert.isNotNull(result); assert.equal(result.character, values[1]); assert.equal(result.message, values[2]); From 0a898029272d58bd927f8882937e69c1043f0c3e Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 18:58:08 +0200 Subject: [PATCH 16/33] feat(developer):kmc-convert fix more typos in tests --- .../src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts | 2 +- developer/src/kmc-convert/test/kmn-file-writer.tests.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 7c8f5800bc..eb92f3a797 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -1673,7 +1673,7 @@ export class KmnFileWriter { // add a warning message if (msg !== "") { - msg = msg + msg_control + msg_entity; + msg = msg + "; " + msg_control + msg_entity; } if ((msg === "") && (msg_entity !== "" || msg_control !== "")) { msg = "c WARNING: " + msg_entity + msg_control; diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index baabf277da..c90ea3f095 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -137,7 +137,7 @@ describe('KmnFileWriter', function () { ["", "U+0006", "Msg; Use of a control character "], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg; "); + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); assert.isNotNull(result); assert.equal(result.character, values[1]); assert.equal(result.message, values[2]); @@ -153,7 +153,7 @@ describe('KmnFileWriter', function () { ['', '', ''], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg; "); + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); assert.isNotNull(result); assert.equal(result.character, values[1]); assert.equal(result.message, values[2]); From 425ff625dd6d0b805c4235d3d92eaa0b82c11352 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 20:05:37 +0200 Subject: [PATCH 17/33] feat(developer): kmc-convert tests for writeCharacterOrUnicode --- .../kmc-convert/test/kmn-file-writer.tests.ts | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index c90ea3f095..48978874cd 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -124,17 +124,18 @@ describe('KmnFileWriter', function () { describe('writeCharacterOrUnicode and return values', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); [ - ["A", "A", "Msg"], - ["ሴ", "ሴ", "Msg"], - ["😀", "😀", "Msg"], - ["ẘ", "ẘ", "Msg"], + ["A", "A", "Msg; "], + ["ሴ", "ሴ", "Msg; "], + ["😀", "😀", "Msg; "], + ["ẘ", "ẘ", "Msg; "], ["U+0001", "U+0001", "Msg; Use of a control character "], - ["U+0061", "a", "Msg"], + ["U+0061", "a", "Msg; "], ["", "U+0002", "Msg; Use of a control character "], - ["ሴ", 'ሴ', "Msg"], + ["ሴ", 'ሴ', "Msg; "], ["", "U+0003", "Msg; Use of a control character "], - ["ሺ", "ሺ", "Msg"], + ["ሺ", "ሺ", "Msg; "], ["", "U+0006", "Msg; Use of a control character "], + ['', '', 'Msg; empty output or unsupported numerical html entity: '], ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); @@ -145,18 +146,16 @@ describe('KmnFileWriter', function () { }); }); - describe('writeCharacterOrUnicode and return empty string for result.message and result.character', function () { + describe('writeCharacterOrUnicode and return null for result.message and result.character', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); [ - [null, '', ''], - [undefined,'', ''], - ['', '', ''], + [null, null], + [undefined, null], + ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); - assert.isNotNull(result); - assert.equal(result.character, values[1]); - assert.equal(result.message, values[2]); + const result = sutW.writeCharacterOrUnicode(values[0], ""); + assert.isNull(result); }); }); }); From 9dedbe1c32d43d9ffbb5907bb05d5b0066107559 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 20:29:00 +0200 Subject: [PATCH 18/33] feat(developer): kmc-convert test for warning of html entities --- .../src/kmc-convert/test/data/Test_differentEncodings.keylayout | 2 ++ .../src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout b/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout index 1868fce990..f327ca23ea 100644 --- a/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout +++ b/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout @@ -24,6 +24,8 @@ + + diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 54b2c3d3ae..4a239fcfb4 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -24,6 +24,7 @@ describe('KeylayoutToKmnConverter', function () { describe('RunSpecialTestFiles', function () { const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); [ + ['../data/Test_mixedEncodings.keylayout'], ['../data/Test_C0.keylayout'], ['../data/Test_C1.keylayout'], ['../data/Test_C2.keylayout'], From 974f0c00a00905e260b0f9bfcd7abaaea5cc8873 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 4 Jun 2026 20:29:00 +0200 Subject: [PATCH 19/33] feat(developer): kmc-convert changed test for warning of html entities --- .../src/kmc-convert/test/data/Test_differentEncodings.keylayout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout b/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout index 1868fce990..3daceae474 100644 --- a/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout +++ b/developer/src/kmc-convert/test/data/Test_differentEncodings.keylayout @@ -24,6 +24,8 @@ + + From 9361ec927fe8207823c782de0351c0cca9607594 Mon Sep 17 00:00:00 2001 From: Sabine Date: Fri, 5 Jun 2026 10:33:35 +0200 Subject: [PATCH 20/33] feat(developer):kmc-convert dummy change to start TeamCity --- .../src/keylayout-to-kmn/keylayout-to-kmn-converter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 85052f9acc..7f002a7e63 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -234,7 +234,7 @@ export class KeylayoutToKmnConverter { // ...............e. g. ............................................................................... // ............................................................................................................................... - if (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['output'] !== undefined) { + if (jsonObj.keyboard.keyMapSet[0].keyMap[i].key[j]['output'] !== undefined) { // loop modifiers for (let l = 0; l < dataUkelele.modifiers[i].length; l++) { From 70bbf61c8c89f1cb57d5a10f7cb00690139883a4 Mon Sep 17 00:00:00 2001 From: Sabine Date: Sat, 6 Jun 2026 22:43:25 +0200 Subject: [PATCH 21/33] feat(developer): reviewRules: return object instead of string[] messages correct --- .../src/common/web/utils/src/xml-utils.ts | 6 +- .../src/kmc-convert/src/converter-messages.ts | 17 +- .../keylayout-to-kmn-converter.ts | 2 +- .../src/keylayout-to-kmn/kmn-file-writer.ts | 1326 +++++++---------- .../src/kmc-convert/test/data/OutputXName.bb | 1290 ---------------- .../test/keylayout-to-kmn-converter.tests.ts | 22 + .../kmc-convert/test/kmn-file-writer.tests.ts | 84 +- 7 files changed, 582 insertions(+), 2165 deletions(-) delete mode 100644 developer/src/kmc-convert/test/data/OutputXName.bb diff --git a/developer/src/common/web/utils/src/xml-utils.ts b/developer/src/common/web/utils/src/xml-utils.ts index cfe42987dd..765a5b7167 100644 --- a/developer/src/common/web/utils/src/xml-utils.ts +++ b/developer/src/common/web/utils/src/xml-utils.ts @@ -6,7 +6,7 @@ * Abstraction for XML reading and writing */ -import { XMLParser, XMLBuilder, XMLMetaData, X2jOptions, XmlBuilderOptions, JPathOrMatcher } from 'fast-xml-parser'; +import { XMLParser, XMLBuilder, XMLMetaData, X2jOptions, XmlBuilderOptions } from 'fast-xml-parser'; import { SymbolUtils } from "./symbol-utils.js"; /** Symbol giving the start offset, in chars, of the node */ @@ -85,8 +85,8 @@ const PARSER_OPTIONS: KeymanXMLParserOptionsBag = { }, 'kvks': { ...PARSER_COMMON_OPTIONS, - tagValueProcessor: (_tagName: string, tagValue: string, _jPathOrMatcher: JPathOrMatcher, _hasAttributes: boolean, isLeafNode: boolean) : unknown => { - if (!isLeafNode) { + tagValueProcessor: (_tagName: string, tagValue: string, _jPath: string, _hasAttributes: boolean, isLeafNode: boolean): string | undefined => { + if (!isLeafNode) { return tagValue?.trim(); // trimmed value } else { return undefined; // no change to leaf nodes diff --git a/developer/src/kmc-convert/src/converter-messages.ts b/developer/src/kmc-convert/src/converter-messages.ts index 2f4bdb4767..2453d00851 100644 --- a/developer/src/kmc-convert/src/converter-messages.ts +++ b/developer/src/kmc-convert/src/converter-messages.ts @@ -6,9 +6,9 @@ import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def } from '@keymanapp/developer-utils'; const Namespace = CompilerErrorNamespace.Converter; -//const SevInfo = CompilerErrorSeverity.Info | Namespace; - const SevHint = CompilerErrorSeverity.Hint | Namespace; -const SevWarn = CompilerErrorSeverity.Warn | Namespace; +// const SevInfo = CompilerErrorSeverity.Info | Namespace; +// const SevHint = CompilerErrorSeverity.Hint | Namespace; +// const SevWarn = CompilerErrorSeverity.Warn | Namespace; const SevError = CompilerErrorSeverity.Error | Namespace; // const SevFatal = CompilerErrorSeverity.Fatal | Namespace; @@ -77,15 +77,4 @@ export class ConverterMessages { `Input data could not be parsed.` ); - static WARN_EmptyOutput = SevWarn | 0x000D; - static Warn_EmptyOutput =(o: { keymapIndex: string, key: string, KeyName: string; }) => m( - this.WARN_EmptyOutput, - `Key has empty output (possibly caused by use of html entity) at keyMap index ${def(o.keymapIndex)} on Keycode ${def(o.key)} (${def(o.KeyName)})` - ); - static HINT_EmptyOutput = SevHint | 0x000E; - static Hint_EmptyOutput =(o: { keymapIndex: string, key: string, KeyName: string; }) => m( - this.HINT_EmptyOutput, - `Key has empty output at keyMap index ${def(o.keymapIndex)} on Keycode ${def(o.key)} (${def(o.KeyName)}) possibly caused by use of html entity ` - ); - } diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 1bf2318908..7b9e98bf61 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -135,7 +135,7 @@ export class KeylayoutToKmnConverter { const processedData = await this.convert(jsonO, inputFilename, outputFilename); const kmnFileWriter = new KmnFileWriter(this.callbacks, this.options); - +kmnFileWriter.writeToFile((processedData)); // write to object/ConverterToKmnResult const outputKmn = kmnFileWriter.write(processedData); const result: ConverterToKmnResult = { diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 8ac6a501f8..5c3b4b83b4 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -25,54 +25,71 @@ interface RuleReview { hasWarning_1: boolean; hasWarning_2: boolean; warningMessages: string[]; + extraWarning: string; - type: 'RuleReview'; + type: 'RuleReview' | 'UnavailableModifier' | 'UnavailableSuperior' | + 'DuplicateRule' | 'AmbiguousRule'; isEarlier: boolean; + isLater: boolean; isused: boolean; context: string; - prevDK_modifier: string; - prevDK_key: string; - DK_modifier: string; - DK_key: string; + prevDk_id: number; + dk_prefix: string; + prev_dk_prefix: string; + prevDk_modifier: string; + prevDk_key: string; + textpart: string; + dk_id: number; + Dk_modifier: string; + Dk_key: string; modifier: string; key: string; output: string; }; -//interface UnavailableModifier /*extends RuleReview*/ { -/*interface UnavailableModifier { + +interface UnavailableModifier extends RuleReview { type: 'UnavailableModifier'; - isEarlier: boolean; - isused: boolean; - context: string; - prevDK_modifier: string; - prevDK_key: string; - DK_modifier: string; - DK_key: string; - modifier: string; - key: string; - output: string; - warningMessage: string[]; -};*/ -interface RuleReview { - type: 'RuleReview'; - isEarlier: boolean; - isused: boolean; - context: string; - prevDK_modifier: string; - prevDK_key: string; - DK_modifier: string; - DK_key: string; - modifier: string; - key: string; - output: string; - - warningMessages: string[]; + isUnavailable: boolean; }; +interface UnavailableSuperior extends RuleReview { + type: 'UnavailableSuperior'; + isUnavailable: boolean; +}; +interface DuplicateRules extends RuleReview { + type: 'DuplicateRule'; + hasExtraWarning: boolean; + isEarlier: boolean; + isLater: boolean; +}; +interface AmbiguousRules extends RuleReview { + type: 'AmbiguousRule'; + hasExtraWarning: boolean; + isEarlier: boolean; + isLater: boolean; + dk_prefix: string; + prev_dk_prefix: string; +}; + + export class KmnFileWriter { constructor(private callbacks: CompilerCallbacks, private options: CompilerOptions) { }; + // TODO remove + public writeToFile(dataUkelele: ProcessedData): boolean { + + let data: string = "\n"; + + // add top part of kmn file: STORES + data += this.writeKmnFileHeader(dataUkelele); + + // add bottom part of kmn file: RULES + data += this.writeDataRules(dataUkelele); + + this.callbacks.fs.writeFileSync(dataUkelele.kmnFilename, new TextEncoder().encode(data)); + return true; + } /** * @brief member function to write data from object to a Uint8Array * @param dataUkelele the array holding all keyboard data @@ -428,12 +445,9 @@ export class KmnFileWriter { + "] > " + versionOutputCharacter + "\n"; - } - } } - if ((warnText[0].indexOf("duplicate") < 0) || (warnText[1].indexOf("duplicate") < 0) || (warnText[2].indexOf("duplicate") < 0)) { data += "\n"; } @@ -442,6 +456,137 @@ export class KmnFileWriter { return data; } + /** + * @brief take a child object of RuleReview and return the appropriate warning message + * @param inObj : an object containing all data + * @return outMsg the warning message + */ + public createWarningText(inObj: RuleReview, pos: number = 2): string[] { + const outMsg: string[] = ['', '', '']; + outMsg[0] = inObj.warningMessages[0]; + outMsg[1] = inObj.warningMessages[1]; + outMsg[2] = inObj.warningMessages[2]; + + if (inObj.type === 'AmbiguousRule') { + + // version for dk 5-5 + if (!inObj.prevDk_modifier && !inObj.prevDk_key + && inObj.Dk_modifier && inObj.Dk_key + && !inObj.modifier && !inObj.key + && (inObj.dk_id !== -1)) { + const position = (inObj.isEarlier ? "earlier" : "later"); + const doubletextpreventer = + ('ambiguous rule: ' + position + + ': dk(' + inObj.dk_prefix + + inObj.dk_id + + ") + [" + + inObj.Dk_modifier + + " " + + inObj.Dk_key + + "] > " + + 'dk(' + inObj.prev_dk_prefix + + inObj.prevDk_id + + ") "); + if (outMsg[pos].indexOf(doubletextpreventer) === -1) + outMsg[pos] += doubletextpreventer; + } + + // version for key with no dk_id amb 6-6 + else if (!inObj.prevDk_modifier && !inObj.prevDk_key + && (inObj.dk_id !== -1) + && inObj.modifier && inObj.key && (inObj.output) + && ((inObj.isEarlier === true /*&& inObj.isLater === true*/))) { + const position = (inObj.isEarlier ? "earlier" : "later"); + outMsg[pos] = inObj.warningMessages[2] + + ('ambiguous rule: ' + + position + + ': dk(' + inObj.dk_prefix + + inObj.dk_id + ") + [" + + inObj.modifier + " " + + inObj.key + "] > \'" + + inObj.output + "\' "); + } + // version for 2_2 2_1 + else if ((!inObj.prevDk_modifier && !inObj.prevDk_key) + && inObj.Dk_modifier && inObj.Dk_key + && (inObj.dk_id !== -1)) { + const position = (inObj.isEarlier ? "earlier" : "later"); + const doubletextpreventer = + ("ambiguous rule: " + + position + ": [" + + inObj.Dk_modifier + " " + + inObj.Dk_key + "] > dk(" + inObj.dk_prefix + + inObj.dk_id + ") "); + if (outMsg[pos].indexOf(doubletextpreventer) === -1) + outMsg[pos] += doubletextpreventer; + } + + // version for dk 4-4 2-4 + else if (inObj.Dk_modifier && inObj.Dk_key + && (inObj.dk_id !== -1) + && !inObj.modifier && !inObj.key) { + const position = (inObj.isEarlier ? "earlier" : "later"); + const doubletextpreventer = + ("ambiguous rule: " + + position + ": [" + + inObj.prevDk_modifier + " " + + inObj.prevDk_key + "] > dk(" + inObj.prev_dk_prefix + + inObj.prevDk_id + ") "); + if (outMsg[pos].indexOf(doubletextpreventer) === -1) + outMsg[pos] += doubletextpreventer; + } + + + // version for prev dk // 4_1 4_2 + else if (inObj.prevDk_modifier && inObj.prevDk_key && (inObj.prevDk_id !== -1)) { + const position = (inObj.isEarlier ? "earlier" : "later"); + const doubletextpreventer = + ("ambiguous rule: " + + position + ": [" + + inObj.prevDk_modifier + " " + + inObj.prevDk_key + "] > dk(" + inObj.prev_dk_prefix + + inObj.prevDk_id + ") "); + if (outMsg[pos].indexOf(doubletextpreventer) === -1) + outMsg[pos] += doubletextpreventer; + } + + // version for dk 6-3 or 3-3 + else if (!inObj.prevDk_modifier && !inObj.prevDk_key + && !inObj.Dk_modifier && !inObj.Dk_key + && (inObj.dk_id !== -1) + ) { + const position = (inObj.isEarlier ? "earlier" : "later"); + const doubletextpreventer = + ('ambiguous rule: ' + + position + + ': dk(' + inObj.dk_prefix + + inObj.dk_id + ") + [" + + inObj.modifier + " " + + inObj.key + "] > \'" + + inObj.output + "\' "); + if (outMsg[pos].indexOf(doubletextpreventer) === -1) + outMsg[pos] += doubletextpreventer; + } + + // version for key with no dk_id amb 1-1 + else if (inObj.modifier && inObj.key + && (inObj.output) + && (inObj.dk_id === -1) + && ((inObj.isEarlier === true /*&& inObj.isLater === true*/))) { + const position = (inObj.isEarlier ? "earlier" : "later"); + outMsg[pos] = inObj.warningMessages[2] + + ("ambiguous rule: " + + position + + ": [" + + inObj.modifier + " " + + inObj.key + "] > \'" + + inObj.output + + "\' "); + } + } + return outMsg; + } + /** * @brief member function to review rules for acceptable modifiers, duplicate or ambiguous rules and return an array containing possible warnings. * Keyman can not handle duplicate rules so we need to make sure a rule is written only once by either omitting a duplicate rule or commenting out an ambiguous rule. @@ -451,7 +596,6 @@ export class KmnFileWriter { * @param index the index of a rule in Rule[] * @return a string[] containing possible warnings for a rule */ - public reviewRules(rule: Rule[], index: number): string[] { const resultWarnings: RuleReview = { @@ -466,60 +610,53 @@ export class KmnFileWriter { type: 'RuleReview', isused: false, isEarlier: false, + isLater: false, context: '', - prevDK_modifier: '', - prevDK_key: '', - DK_modifier: '', - DK_key: '', + prevDk_id: -1, + prevDk_modifier: '', + dk_prefix: "A", + prev_dk_prefix: "C", + prevDk_key: '', + textpart: '', + dk_id: -1, + Dk_modifier: '', + Dk_key: '', modifier: '', key: '', output: '', warningMessages: ['', '', ''], + + extraWarning: 'PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN !', }; - /* const resultWarnings: UnavailableModifier = { - type: 'UnavailableModifier', - isused: false, - isEarlier: false, - context: '', - prevDK_modifier: '', - prevDK_key: '', - DK_modifier: '', - DK_key: '', - modifier: '', - key: '', - output: '', - warningMessage: Array(3).fill("") - };*/ - /*const resultAll: RuleReview = { - type: 'RuleReview', - isused: false, - isEarlier: false, - context: '', - prevDK_modifier: '', - prevDK_key: '', - DK_modifier: '', - DK_key: '', - modifier: '', - key: '', - output: '', - warningMessage: Array(3).fill("") - };*/ + const unavailableModiWarnings = { + type: 'UnavailableModifier', + isUnavailable: true, + warningMessages: ['', '', ''], + } as UnavailableModifier; - /* - resultWarnings.type = ''; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessage[0] = ""; - resultWarnings.warningMessage[1] = ""; - resultWarnings.warningMessage[2] = ""; - */ + const unavailableSuperiWarnings = { + type: 'UnavailableSuperior', + isUnavailable: true, + warningMessages: ['', '', ''], + } as UnavailableSuperior; + + const duplicateWarnings = { + type: 'DuplicateRule', + isLater: false, + isEarlier: false, + hasExtraWarning: false, + warningMessages: ['', '', ''], + } as DuplicateRules; + + + const ambiguousWarnings = { + type: 'AmbiguousRule', + isEarlier: false, + isLater: false, + hasExtraWarning: false, + warningMessages: ['', '', ''], + } as AmbiguousRules; const keylayoutKmnConverter = new KeylayoutToKmnConverter(this.callbacks, this.options); const warningText: string[] = Array(3).fill(""); @@ -528,22 +665,18 @@ export class KmnFileWriter { if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; - // resultWarnings.warningMessages[2] = "unavailable modifier : "; - resultWarnings.hasWarning_2 = true; + warningText[2] = "unavailable modifier "; - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = "unavailable modifier : "; + unavailableModiWarnings.isused = true; + unavailableModiWarnings.modifier = rule[index].modifierKey; + unavailableModiWarnings.key = rule[index].key; + unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); + unavailableModiWarnings.warningMessages[2] = "unavailable modifier "; } } - else if (rule[index].ruleType === "C2") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier : "; + warningText[1] = "unavailable modifier "; warningText[2] = "unavailable superior rule ( [" + rule[index].modifierDeadkey + " " + rule[index].deadkey @@ -551,26 +684,18 @@ export class KmnFileWriter { + rule[index].idDeadkey + ") ) : "; - /* resultWarnings.warningMessages[1] = "unavailable modifier : "; - resultWarnings.hasWarning_1 = true; - resultWarnings.warningMessages[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(A" - + rule[index].idDeadkey - + ") ) : "; - resultWarnings.hasWarning_2 = true;*/ + unavailableModiWarnings.isused = true; + unavailableSuperiWarnings.isused = true; + unavailableModiWarnings.textpart = '] > dk(A'; + unavailableModiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableModiWarnings.Dk_key = rule[index].deadkey; + unavailableModiWarnings.modifier = rule[index].modifierKey; + unavailableModiWarnings.key = rule[index].key; + unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = "unavailable modifier : "; - resultWarnings.warningMessages[2] = "unavailable superior rule ( [" + unavailableModiWarnings.warningMessages[1] = "unavailable modifier "; + unavailableSuperiWarnings.warningMessages[2] = "unavailable superior rule ( [" + rule[index].modifierDeadkey + " " + rule[index].deadkey + "] > dk(A" @@ -579,28 +704,23 @@ export class KmnFileWriter { } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; - - /* resultWarnings.warningMessages[2] = "unavailable modifier : "; - resultWarnings.hasWarning_2 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = "unavailable modifier : "; + warningText[2] = "unavailable modifier "; + unavailableModiWarnings.isused = true; + unavailableModiWarnings.prevDk_key = rule[index].prevDeadkey; + unavailableModiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + unavailableModiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableModiWarnings.Dk_key = rule[index].deadkey; + unavailableModiWarnings.modifier = rule[index].modifierKey; + unavailableModiWarnings.key = rule[index].key; + unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); + unavailableModiWarnings.warningMessages[2] = "unavailable modifier "; } } else if (rule[index].ruleType === "C3") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierPrevDeadkey)) { - warningText[0] = "unavailable modifier : "; + warningText[0] = "unavailable modifier "; warningText[1] = "unavailable superior rule ( [" + rule[index].modifierPrevDeadkey + " " + rule[index].prevDeadkey @@ -612,99 +732,47 @@ export class KmnFileWriter { + rule[index].prevDeadkey + "] > dk(A" + rule[index].idPrevDeadkey - + ") ) and ( dk(A" + - + rule[index].idPrevDeadkey + ") [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; - /* resultWarnings.warningMessages[0] = "unavailable modifier : "; - resultWarnings.hasWarning_0 = true; - - resultWarnings.warningMessages[1] = "unavailable superior rule ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) : "; - resultWarnings.hasWarning_1 = true; - resultWarnings.warningMessages[2] = "unavailable superior rules ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) and ( dk(A" + - + rule[index].idPrevDeadkey + ") [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : ";*/ + + ") ) "; - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[0] = "unavailable modifier : "; - - resultWarnings.warningMessages[1] = "unavailable superior rule ( [" + unavailableSuperiWarnings.warningMessages[0] = "unavailable modifier "; + unavailableSuperiWarnings.warningMessages[1] = "unavailable superior rule ( [" + rule[index].modifierPrevDeadkey + " " + rule[index].prevDeadkey + "] > dk(A" + rule[index].idPrevDeadkey + ") ) : "; - resultWarnings.warningMessages[2] = "unavailable superior rules ( [" + unavailableSuperiWarnings.warningMessages[2] = "unavailable superior rules ( [" + rule[index].modifierPrevDeadkey + " " + rule[index].prevDeadkey + "] > dk(A" + rule[index].idPrevDeadkey - + ") ) and ( dk(A" + - + rule[index].idPrevDeadkey + ") [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; - + + ") ) "; } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier : "; + warningText[1] = "unavailable modifier "; warningText[2] = "unavailable superior rule ( [" + rule[index].modifierDeadkey + " " + rule[index].deadkey + "] > dk(B" + rule[index].idDeadkey + ") ) : "; - /*resultWarnings.warningMessages[1] = "unavailable modifier : "; - resultWarnings.hasWarning_1 = true; - resultWarnings.warningMessages[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; - resultWarnings.hasWarning_2 = true;*/ + unavailableModiWarnings.isused = true; + unavailableSuperiWarnings.isused = true; + unavailableModiWarnings.prevDk_key = rule[index].prevDeadkey; + unavailableModiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = "unavailable modifier : "; - resultWarnings.warningMessages[2] = "unavailable superior rule ( [" + unavailableSuperiWarnings.textpart = '] > dk(B'; + unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableSuperiWarnings.Dk_key = rule[index].deadkey; + unavailableSuperiWarnings.modifier = rule[index].modifierKey; + unavailableSuperiWarnings.key = rule[index].key; + unavailableSuperiWarnings.output = new TextDecoder().decode(rule[index].output); + unavailableSuperiWarnings.warningMessages[1] = unavailableSuperiWarnings.warningMessages[1] + + "unavailable modifier "; + unavailableSuperiWarnings.warningMessages[2] = "unavailable superior rule ( [" + rule[index].modifierDeadkey + " " + rule[index].deadkey + "] > dk(B" @@ -713,23 +781,21 @@ export class KmnFileWriter { } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] += "unavailable modifier : "; - /*resultWarnings.warningMessages[2] += "unavailable modifier : "; - resultWarnings.hasWarning_2 = true;*/ + warningText[2] += "unavailable modifier "; - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] += "unavailable modifier : "; + unavailableModiWarnings.isused = true; + unavailableModiWarnings.prevDk_key = rule[index].prevDeadkey; + unavailableModiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + unavailableModiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableModiWarnings.Dk_key = rule[index].deadkey; + unavailableModiWarnings.modifier = rule[index].modifierKey; + unavailableModiWarnings.key = rule[index].key; + unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); + unavailableModiWarnings.warningMessages[2] += "unavailable modifier "; } } + // ------------------------- check ambiguous/duplicate rules ------------------------- if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { @@ -774,151 +840,74 @@ export class KmnFileWriter { ); if (amb_4_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: later: [" - + amb_4_1[0].modifierPrevDeadkey - + " " - + amb_4_1[0].prevDeadkey - + "] > dk(C" - + amb_2_1[0].idDeadkey - + ") "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("ambiguous rule: later: [" - + amb_4_1[0].modifierPrevDeadkey - + " " - + amb_4_1[0].prevDeadkey - + "] > dk(C" - + amb_2_1[0].idDeadkey - + ") "); - resultWarnings.hasWarning_2 = true;*/ + ambiguousWarnings.prevDk_id = amb_4_1[0].idPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_4_1[0].prevDeadkey; + ambiguousWarnings.prevDk_modifier = amb_4_1[0].modifierPrevDeadkey; - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("ambiguous rule: later: [" - + amb_4_1[0].modifierPrevDeadkey - + " " - + amb_4_1[0].prevDeadkey - + "] > dk(C" - + amb_2_1[0].idDeadkey - + ") "); + ambiguousWarnings.isEarlier = false; + ambiguousWarnings.isLater = true; + ambiguousWarnings.modifier = amb_4_1[0].modifierKey; + ambiguousWarnings.key = amb_4_1[0].key; + ambiguousWarnings.prev_dk_prefix = 'C'; + ambiguousWarnings.dk_prefix = 'A'; + const tester_amb_4_1 = this.createWarningText(ambiguousWarnings); + ambiguousWarnings.warningMessages = tester_amb_4_1; } if (amb_2_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: later: [" - + amb_2_1[0].modifierDeadkey - + " " - + amb_2_1[0].deadkey - + "] > dk(A" - + amb_2_1[0].idDeadkey - + ") "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("ambiguous rule: later: [" - + amb_2_1[0].modifierDeadkey - + " " - + amb_2_1[0].deadkey - + "] > dk(A" - + amb_2_1[0].idDeadkey - + ") "); - resultWarnings.hasWarning_2 = true;*/ - resultWarnings.type = 'RuleReview'; resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("ambiguous rule: later: [" - + amb_2_1[0].modifierDeadkey - + " " - + amb_2_1[0].deadkey - + "] > dk(A" - + amb_2_1[0].idDeadkey - + ") "); + ambiguousWarnings.textpart = '] > dk(A'; + ambiguousWarnings.prevDk_id = amb_2_1[0].idPrevDeadkey; + ambiguousWarnings.prevDk_modifier = amb_2_1[0].modifierPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_2_1[0].prevDeadkey; + ambiguousWarnings.dk_id = amb_2_1[0].idDeadkey; + ambiguousWarnings.Dk_modifier = amb_2_1[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_2_1[0].deadkey; + + ambiguousWarnings.modifier = amb_2_1[0].modifierKey; + ambiguousWarnings.key = amb_2_1[0].key; + ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_2_1[0].output)).character; + + ambiguousWarnings.prev_dk_prefix = 'C'; + ambiguousWarnings.dk_prefix = 'A'; + ambiguousWarnings.isEarlier = false; + ambiguousWarnings.isLater = true; + const tester_amb_2_1 = this.createWarningText(ambiguousWarnings); + ambiguousWarnings.warningMessages = tester_amb_2_1; } if (amb_1_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: [" - + amb_1_1[0].modifierKey - + " " - + amb_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character - + "\' "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("ambiguous rule: earlier: [" - + amb_1_1[0].modifierKey - + " " - + amb_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true;*/ + ambiguousWarnings.prevDk_id = amb_1_1[0].idPrevDeadkey; + ambiguousWarnings.prevDk_modifier = amb_1_1[0].modifierPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_1_1[0].prevDeadkey; + ambiguousWarnings.dk_id = -1;// needed!!! + ambiguousWarnings.prevDk_id = -1;// needed!!! + ambiguousWarnings.Dk_modifier = amb_1_1[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_1_1[0].deadkey; - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("ambiguous rule: earlier: [" - + amb_1_1[0].modifierKey - + " " - + amb_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character - + "\' "); - + ambiguousWarnings.prev_dk_prefix = 'C'; + ambiguousWarnings.dk_prefix = 'A'; + ambiguousWarnings.modifier = amb_1_1[0].modifierKey; + ambiguousWarnings.key = amb_1_1[0].key; + ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.isLater = false; + const tester_amb_1_1 = this.createWarningText(ambiguousWarnings, 2); + ambiguousWarnings.warningMessages = tester_amb_1_1; } if (dup_1_1.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: [" - + dup_1_1[0].modifierKey - + " " - + dup_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character - + "\' "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("duplicate rule: earlier: [" - + dup_1_1[0].modifierKey - + " " - + dup_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true;*/ - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + duplicateWarnings.isused = true; + duplicateWarnings.textpart = '] > \''; + duplicateWarnings.modifier = dup_1_1[0].modifierKey; + duplicateWarnings.key = dup_1_1[0].key; + duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character; + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[2] = duplicateWarnings.warningMessages[2] + ("duplicate rule: earlier: [" + dup_1_1[0].modifierKey + " " @@ -929,11 +918,6 @@ export class KmnFileWriter { } } - /* console.log("compare", ((resultWarnings.warningMessage[0] === warningText[0]) - && (resultWarnings.warningMessage[1] === warningText[1]) - && (resultWarnings.warningMessage[2] === warningText[2])));*/ - - if (rule[index].ruleType === "C2") { // 2-2: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C3) @@ -984,42 +968,17 @@ export class KmnFileWriter { ); if (amb_2_2.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: [" - + amb_2_2[0].modifierDeadkey - + " " - + amb_2_2[0].deadkey - + "] > dk(C" - + amb_2_2[0].idDeadkey - + ") "); - /*resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] - + ("ambiguous rule: earlier: [" - + amb_2_2[0].modifierDeadkey - + " " - + amb_2_2[0].deadkey - + "] > dk(C" - + amb_2_2[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] - + ("ambiguous rule: earlier: [" - + amb_2_2[0].modifierDeadkey - + " " - + amb_2_2[0].deadkey - + "] > dk(C" - + amb_2_2[0].idDeadkey - + ") "); - + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.isLater = false; + ambiguousWarnings.prev_dk_prefix = 'A'; + ambiguousWarnings.dk_prefix = 'C'; + ambiguousWarnings.dk_id = amb_2_2[0].idDeadkey; + ambiguousWarnings.Dk_modifier = amb_2_2[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_2_2[0].deadkey; + ambiguousWarnings.modifier = amb_2_2[0].modifierKey; + ambiguousWarnings.key = amb_2_2[0].key; + const tester_amb_2_2 = this.createWarningText(ambiguousWarnings, 1); + ambiguousWarnings.warningMessages = tester_amb_2_2; } if (dup_2_2.length > 0) { @@ -1031,76 +990,33 @@ export class KmnFileWriter { + "] > dk(C" + dup_2_2[0].idDeadkey + ") "); - /* resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true;*/ resultWarnings.type = 'RuleReview'; resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); + duplicateWarnings.textpart = '] > dk(C'; + duplicateWarnings.dk_id = dup_2_2[0].idDeadkey; + duplicateWarnings.Dk_modifier = dup_2_2[0].modifierDeadkey; + duplicateWarnings.Dk_key = dup_2_2[0].deadkey; + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[1] = duplicateWarnings.warningMessages[1] + + ("duplicate rule: earlier: [" + + dup_2_2[0].modifierDeadkey + + " " + + dup_2_2[0].deadkey + + "] > dk(C" + + dup_2_2[0].idDeadkey + + ") "); } if (amb_3_3.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: dk(A" - + amb_3_3[0].idDeadkey - + ") + [" - + amb_3_3[0].modifierKey - + " " - + amb_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character - + "\' "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("ambiguous rule: earlier: dk(A" - + amb_3_3[0].idDeadkey - + ") + [" - + amb_3_3[0].modifierKey - + " " - + amb_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] - + ("ambiguous rule: earlier: dk(A" - + amb_3_3[0].idDeadkey - + ") + [" - + amb_3_3[0].modifierKey - + " " - + amb_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character - + "\' "); + ambiguousWarnings.dk_prefix = 'A'; + ambiguousWarnings.dk_id = amb_3_3[0].idDeadkey; + ambiguousWarnings.modifier = amb_3_3[0].modifierKey; + ambiguousWarnings.key = amb_3_3[0].key; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character; + const tester_amb_3_3 = this.createWarningText(ambiguousWarnings, 2); + ambiguousWarnings.warningMessages = tester_amb_3_3; } if (dup_3_3.length > 0) { @@ -1114,27 +1030,16 @@ export class KmnFileWriter { + "] > \'" + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character + "\' "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(A" - + dup_3_3[0].idDeadkey - + ") + [" - + dup_3_3[0].modifierKey - + " " - + dup_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true;*/ resultWarnings.type = 'RuleReview'; resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(A" + duplicateWarnings.textpart = '] > \''; + duplicateWarnings.dk_id = dup_3_3[0].idDeadkey; + duplicateWarnings.modifier = dup_3_3[0].modifierKey; + duplicateWarnings.key = dup_3_3[0].key; + duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character; + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[2] = duplicateWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(A" + dup_3_3[0].idDeadkey + ") + [" + dup_3_3[0].modifierKey @@ -1147,42 +1052,17 @@ export class KmnFileWriter { } if (amb_4_2.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: later: [" - + amb_4_2[0].modifierPrevDeadkey - + " " - + amb_4_2[0].prevDeadkey - + "] > dk(C" - + amb_4_2[0].idPrevDeadkey - + ") "); - /* resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] - + ("ambiguous rule: later: [" - + amb_4_2[0].modifierPrevDeadkey - + " " - + amb_4_2[0].prevDeadkey - + "] > dk(C" - + amb_4_2[0].idPrevDeadkey - + ") "); - resultWarnings.hasWarning_0 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] - + ("ambiguous rule: later: [" - + amb_4_2[0].modifierPrevDeadkey - + " " - + amb_4_2[0].prevDeadkey - + "] > dk(C" - + amb_4_2[0].idPrevDeadkey - + ") "); + ambiguousWarnings.prevDk_id = amb_4_2[0].idPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_4_2[0].prevDeadkey; + ambiguousWarnings.prevDk_modifier = amb_4_2[0].modifierPrevDeadkey; + ambiguousWarnings.prev_dk_prefix = 'C'; + ambiguousWarnings.dk_prefix = 'A'; + ambiguousWarnings.modifier = amb_4_2[0].modifierKey; + ambiguousWarnings.key = amb_4_2[0].key; + ambiguousWarnings.isLater = true; + const tester_amb_4_2 = this.createWarningText(ambiguousWarnings, 0); + ambiguousWarnings.warningMessages = tester_amb_4_2; } } @@ -1279,84 +1159,28 @@ export class KmnFileWriter { ); if (amb_2_4.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: earlier: [" - + amb_2_4[0].modifierDeadkey - + " " - + amb_2_4[0].deadkey - + "] > dk(A" - + amb_2_4[0].idDeadkey - + ") "); - /*resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + ("ambiguous rule: earlier: [" - + amb_2_4[0].modifierDeadkey - + " " - + amb_2_4[0].deadkey - + "] > dk(A" - + amb_2_4[0].idDeadkey - + ") "); - resultWarnings.hasWarning_0 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + ("ambiguous rule: earlier: [" - + amb_2_4[0].modifierDeadkey - + " " - + amb_2_4[0].deadkey - + "] > dk(A" - + amb_2_4[0].idDeadkey - + ") "); + ambiguousWarnings.prev_dk_prefix = 'C'; + ambiguousWarnings.dk_prefix = 'A'; + ambiguousWarnings.dk_id = amb_2_4[0].idDeadkey; + ambiguousWarnings.Dk_modifier = amb_2_4[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_2_4[0].deadkey; + ambiguousWarnings.modifier = amb_2_4[0].modifierKey; + ambiguousWarnings.key = amb_2_4[0].key; + ambiguousWarnings.isEarlier = true; + const tester_amb_2_4 = this.createWarningText(ambiguousWarnings, 0); + ambiguousWarnings.warningMessages = tester_amb_2_4; } if (amb_6_3.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: dk(C" - + amb_6_3[0].idDeadkey - + ") + [" - + amb_6_3[0].modifierKey - + " " - + amb_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character - + "\' "); - /*resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] - + ("ambiguous rule: earlier: dk(C" - + amb_6_3[0].idDeadkey - + ") + [" - + amb_6_3[0].modifierKey - + " " - + amb_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_1 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] - + ("ambiguous rule: earlier: dk(C" - + amb_6_3[0].idDeadkey - + ") + [" - + amb_6_3[0].modifierKey - + " " - + amb_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character - + "\' "); + ambiguousWarnings.dk_prefix = 'C'; + ambiguousWarnings.dk_id = amb_6_3[0].idDeadkey; + ambiguousWarnings.modifier = amb_6_3[0].modifierKey; + ambiguousWarnings.key = amb_6_3[0].key; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character; + const tester_amb_6_3 = this.createWarningText(ambiguousWarnings, 1); + ambiguousWarnings.warningMessages = tester_amb_6_3; } if (dup_6_3.length > 0) { @@ -1370,28 +1194,16 @@ export class KmnFileWriter { + "] > \'" + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character + "\' "); - /* resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] - + ("duplicate rule: earlier: dk(C" - + dup_6_3[0].idDeadkey - + ") + [" - + dup_6_3[0].modifierKey - + " " - + dup_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_1 = true;*/ resultWarnings.type = 'RuleReview'; resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ambiguousWarnings.textpart = ''; + ambiguousWarnings.dk_id = dup_6_3[0].idDeadkey; + duplicateWarnings.modifier = dup_6_3[0].modifierKey; + duplicateWarnings.key = dup_6_3[0].key; + duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character; + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[1] = duplicateWarnings.warningMessages[1] + ("duplicate rule: earlier: dk(C" + dup_6_3[0].idDeadkey + ") + [" @@ -1404,39 +1216,22 @@ export class KmnFileWriter { } if (amb_4_4.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: earlier: [" - + amb_4_4[0].modifierPrevDeadkey - + " " - + amb_4_4[0].prevDeadkey - + "] > dk(C" - + amb_4_4[0].idPrevDeadkey - + ") "); - /* resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + ("ambiguous rule: earlier: [" - + amb_4_4[0].modifierPrevDeadkey - + " " - + amb_4_4[0].prevDeadkey - + "] > dk(C" - + amb_4_4[0].idPrevDeadkey - + ") "); - resultWarnings.hasWarning_0 = true;*/ resultWarnings.type = 'RuleReview'; resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + ("ambiguous rule: earlier: [" - + amb_4_4[0].modifierPrevDeadkey - + " " - + amb_4_4[0].prevDeadkey - + "] > dk(C" - + amb_4_4[0].idPrevDeadkey - + ") "); + ambiguousWarnings.textpart = '] > dk(C'; + ambiguousWarnings.prevDk_id = amb_4_4[0].idPrevDeadkey; + resultWarnings.prevDk_key = amb_4_4[0].prevDeadkey; + resultWarnings.prevDk_modifier = amb_4_4[0].modifierPrevDeadkey; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.prev_dk_prefix = 'C'; + ambiguousWarnings.dk_prefix = 'C'; + ambiguousWarnings.dk_id = amb_4_4[0].idDeadkey; + ambiguousWarnings.Dk_modifier = amb_4_4[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_4_4[0].deadkey; + const tester_amb_4_4 = this.createWarningText(ambiguousWarnings, 0); + ambiguousWarnings.warningMessages = tester_amb_4_4; + } if (dup_4_4.length > 0) { @@ -1448,25 +1243,18 @@ export class KmnFileWriter { + "] > dk(C" + dup_4_4[0].idPrevDeadkey + ") "); - /* resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + ("duplicate rule: earlier: [" - + dup_4_4[0].modifierPrevDeadkey - + " " - + dup_4_4[0].prevDeadkey - + "] > dk(C" - + dup_4_4[0].idPrevDeadkey - + ") "); - resultWarnings.hasWarning_0 = true;*/ resultWarnings.type = 'RuleReview'; resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; + resultWarnings.prevDk_key = rule[index].prevDeadkey; + resultWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + resultWarnings.Dk_modifier = rule[index].modifierDeadkey; + resultWarnings.Dk_key = rule[index].deadkey; resultWarnings.modifier = rule[index].modifierKey; resultWarnings.key = rule[index].key; resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + ("duplicate rule: earlier: [" + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[0] = duplicateWarnings.warningMessages[0] + ("duplicate rule: earlier: [" + dup_4_4[0].modifierPrevDeadkey + " " + dup_4_4[0].prevDeadkey @@ -1476,45 +1264,16 @@ export class KmnFileWriter { } if (amb_5_5.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: dk(B" - + amb_5_5[0].idPrevDeadkey - + ") + [" - + amb_5_5[0].modifierDeadkey - + " " - + amb_5_5[0].deadkey - + "] > dk(B" - + amb_5_5[0].idDeadkey - + ") "); - /* resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ("ambiguous rule: earlier: dk(B" - + amb_5_5[0].idPrevDeadkey - + ") + [" - + amb_5_5[0].modifierDeadkey - + " " - + amb_5_5[0].deadkey - + "] > dk(B" - + amb_5_5[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ("ambiguous rule: earlier: dk(B" - + amb_5_5[0].idPrevDeadkey - + ") + [" - + amb_5_5[0].modifierDeadkey - + " " - + amb_5_5[0].deadkey - + "] > dk(B" - + amb_5_5[0].idDeadkey - + ") "); + ambiguousWarnings.warningMessages[2] = ''; + ambiguousWarnings.prevDk_id = amb_5_5[0].idPrevDeadkey; + ambiguousWarnings.prev_dk_prefix = 'B'; + ambiguousWarnings.dk_prefix = 'B'; + ambiguousWarnings.dk_id = amb_5_5[0].idDeadkey; + ambiguousWarnings.Dk_modifier = amb_5_5[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_5_5[0].deadkey; + ambiguousWarnings.isEarlier = true; + const tester_amb_5_5 = this.createWarningText(ambiguousWarnings, 1); + ambiguousWarnings.warningMessages = tester_amb_5_5; } if (dup_5_5.length > 0) { @@ -1528,7 +1287,18 @@ export class KmnFileWriter { + "] > dk(B" + dup_5_5[0].idDeadkey + ") "); - /* resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ("duplicate rule: earlier: dk(B" + + resultWarnings.type = 'RuleReview'; + resultWarnings.isused = true; + resultWarnings.prevDk_key = rule[index].prevDeadkey; + resultWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + resultWarnings.Dk_modifier = rule[index].modifierDeadkey; + resultWarnings.Dk_key = rule[index].deadkey; + resultWarnings.modifier = rule[index].modifierKey; + resultWarnings.key = rule[index].key; + resultWarnings.output = new TextDecoder().decode(rule[index].output); + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[1] = duplicateWarnings.warningMessages[1] + ("duplicate rule: earlier: dk(B" + dup_5_5[0].idPrevDeadkey + ") + [" + dup_5_5[0].modifierDeadkey @@ -1537,64 +1307,21 @@ export class KmnFileWriter { + "] > dk(B" + dup_5_5[0].idDeadkey + ") "); - resultWarnings.hasWarning_1 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + ("duplicate rule: earlier: dk(B" - + dup_5_5[0].idPrevDeadkey - + ") + [" - + dup_5_5[0].modifierDeadkey - + " " - + dup_5_5[0].deadkey - + "] > dk(B" - + dup_5_5[0].idDeadkey - + ") "); - + } if (amb_6_6.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: dk(B" - + amb_6_6[0].idDeadkey - + ") + [" - + amb_6_6[0].modifierKey - + " " - + amb_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character - + "\' "); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("ambiguous rule: earlier: dk(B" - + amb_6_6[0].idDeadkey - + ") + [" - + amb_6_6[0].modifierKey - + " " - + amb_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; - /* resultAll - resultWarnings.type = ''; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessage[0] = ""; - resultWarnings.warningMessage[1] = ""; - resultWarnings.warningMessage[2] = ""; - */ + ambiguousWarnings.isused = true; + ambiguousWarnings.dk_id = amb_6_6[0].idDeadkey;// needed!!! + ambiguousWarnings.Dk_modifier = amb_6_6[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_6_6[0].deadkey; + ambiguousWarnings.modifier = amb_6_6[0].modifierKey; + ambiguousWarnings.key = amb_6_6[0].key; + ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = 'B'; + const tester_amb_6_6 = this.createWarningText(ambiguousWarnings); + ambiguousWarnings.warningMessages = tester_amb_6_6; } if (dup_6_6.length > 0) { @@ -1608,27 +1335,18 @@ export class KmnFileWriter { + "] > \'" + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character + "\' "); - /* resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(B" - + dup_6_6[0].idDeadkey - + ") + [" - + dup_6_6[0].modifierKey - + " " - + dup_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true;*/ - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(B" + + resultWarnings.type = 'RuleReview'; + resultWarnings.isused = true; + resultWarnings.prevDk_key = rule[index].prevDeadkey; + resultWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + resultWarnings.Dk_modifier = rule[index].modifierDeadkey; + resultWarnings.Dk_key = rule[index].deadkey; + resultWarnings.modifier = rule[index].modifierKey; + resultWarnings.key = rule[index].key; + resultWarnings.output = new TextDecoder().decode(rule[index].output); + duplicateWarnings.isEarlier = true; + duplicateWarnings.warningMessages[2] = duplicateWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(B" + dup_6_6[0].idDeadkey + ") + [" + dup_6_6[0].modifierKey @@ -1647,75 +1365,61 @@ export class KmnFileWriter { // assuming that if a C0/C1 and a C2/C3 rule is ambiguous the user prefers to use the C2/C3 rule over the C0/C1 rule // if both happens, nothing would be written, therefore this messsage - const extraWarning = "PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! "; - /* resultAll - resultWarnings.type = ''; - resultWarnings.isused = true; - resultWarnings.prevDK_key = rule[index].prevDeadkey; - resultWarnings.prevDK_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.DK_modifier = rule[index].modifierDeadkey; - resultWarnings.DK_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - resultWarnings.warningMessage[0] = ""; - resultWarnings.warningMessage[1] = ""; - resultWarnings.warningMessage[2] = ""; - */ + const extraWarning = "PLEASE CHECK THAT RULE AS IT WILL NOT BE WRITTEN !"; - if (warningText[0] !== "") { - warningText[0] = "c WARNING: " + warningText[0] + "here: "; - + + /* if ((warningText[0].indexOf("earlier:") > 0) && (warningText[0].indexOf("later:") > 0)) { - warningText[0] = warningText[0] + extraWarning; + warningText[0] = warningText[0] + extraWarning; } - } - if (resultWarnings.warningMessages[0]) { - resultWarnings.warningMessages[0] = "c WARNING: " + resultWarnings.warningMessages[0] + "here: "; - - if ((resultWarnings.warningMessages[0].indexOf("earlier:") > 0) && (resultWarnings.warningMessages[0].indexOf("later:") > 0)) { - resultWarnings.warningMessages[0] = resultWarnings.warningMessages[0] + extraWarning; - } - } - - if (warningText[1] !== "") { - warningText[1] = "c WARNING: " + warningText[1] + "here: "; - if ((warningText[1].indexOf("earlier:") > 0) && (warningText[1].indexOf("later:") > 0)) { - warningText[1] = warningText[1] + extraWarning; - } - } - if (resultWarnings.warningMessages[1] !== "") { - resultWarnings.warningMessages[1] = "c WARNING: " + resultWarnings.warningMessages[1] + "here: "; - if ((resultWarnings.warningMessages[1].indexOf("earlier:") > 0) && (resultWarnings.warningMessages[1].indexOf("later:") > 0)) { - resultWarnings.warningMessages[1] = resultWarnings.warningMessages[1] + extraWarning; - } - } - - if (warningText[2] !== "") { - warningText[2] = "c WARNING: " + warningText[2] + "here: "; - - if ((warningText[2].indexOf("earlier:") > 0) && (warningText[2].indexOf("later:") > 0)) { - warningText[2] = warningText[2] + extraWarning; - } - } - - if (resultWarnings.warningMessages[2] !== "") { - resultWarnings.warningMessages[2] = "c WARNING: " + resultWarnings.warningMessages[2] + "here: "; - - if ((resultWarnings.warningMessages[2].indexOf("earlier:") > 0) && (resultWarnings.warningMessages[2].indexOf("later:") > 0)) { - resultWarnings.warningMessages[2] = resultWarnings.warningMessages[2] + extraWarning; + */ + if (ambiguousWarnings.warningMessages[0]) { + if ((ambiguousWarnings.warningMessages[0].indexOf("earlier:") > 0) && (ambiguousWarnings.warningMessages[0].indexOf("later:") > 0)) { + ambiguousWarnings.warningMessages[0] = ambiguousWarnings.warningMessages[0] + extraWarning; } } /* - warningText[0] = resultWarnings.warningMessage[0] - warningText[1] = resultWarnings.warningMessage[1] - warningText[2] =resultWarnings.warningMessage[2]*/ + if ((warningText[1].indexOf("earlier:") > 0) && (warningText[1].indexOf("later:") > 0)) { + warningText[1] = warningText[1] + extraWarning; + } + */ + if (ambiguousWarnings.warningMessages[1] !== "") { + if ((ambiguousWarnings.warningMessages[1].indexOf("earlier:") > 0) && (ambiguousWarnings.warningMessages[1].indexOf("later:") > 0)) { + ambiguousWarnings.warningMessages[1] = ambiguousWarnings.warningMessages[1] + extraWarning; + } + } + + /* if ((warningText[2].indexOf("earlier:") > 0) && (warningText[2].indexOf("later:") > 0)) { + warningText[2] = warningText[2] + extraWarning; + } + */ + if (ambiguousWarnings.warningMessages[2] !== "") { + if ((ambiguousWarnings.warningMessages[2].indexOf("earlier:") > 0) && (ambiguousWarnings.warningMessages[2].indexOf("later:") > 0)) { + ambiguousWarnings.warningMessages[2] = ambiguousWarnings.warningMessages[2] + extraWarning; + } + } + + const completeWarning0 = unavailableSuperiWarnings.warningMessages[0] + + duplicateWarnings.warningMessages[0] + + ambiguousWarnings.warningMessages[0] + + unavailableModiWarnings.warningMessages[0]; + + const completeWarning1 = unavailableSuperiWarnings.warningMessages[1] + + duplicateWarnings.warningMessages[1] + + ambiguousWarnings.warningMessages[1] + + unavailableModiWarnings.warningMessages[1]; + + const completeWarning2 = unavailableSuperiWarnings.warningMessages[2] + + duplicateWarnings.warningMessages[2] + + ambiguousWarnings.warningMessages[2] + + unavailableModiWarnings.warningMessages[2]; + + completeWarning0 ? (warningText[0] = "c WARNING: " + completeWarning0 + " here: ") : warningText[0] = ''; + completeWarning1 ? (warningText[1] = "c WARNING: " + completeWarning1 + " here: ") : warningText[1] = ''; + completeWarning2 ? (warningText[2] = "c WARNING: " + completeWarning2 + " here: ") : warningText[2] = ''; - warningText[0] = resultWarnings.warningMessages[0]; - warningText[1] = resultWarnings.warningMessages[1]; - warningText[2] = resultWarnings.warningMessages[2]; return warningText; } @@ -1772,7 +1476,7 @@ export class KmnFileWriter { msg_control = "Use of a control character "; } else { - out.character = this.convertToUnicodeCharacter(ctr);; + out.character = this.convertToUnicodeCharacter(ctr); } // add a warning message diff --git a/developer/src/kmc-convert/test/data/OutputXName.bb b/developer/src/kmc-convert/test/data/OutputXName.bb deleted file mode 100644 index 6e45decf3b..0000000000 --- a/developer/src/kmc-convert/test/data/OutputXName.bb +++ /dev/null @@ -1,1290 +0,0 @@ - -c .................................................................................................................. -c .................................................................................................................. -c Keyman keyboard generated by kmn-convert version: 19.0.230 -c from Ukelele file: C:\Projects\keyman\keyman\developer\src\kmc-convert\test\data\Test.keylayout -c .................................................................................................................. -c .................................................................................................................. - -store(&TARGETS) 'desktop' - -begin Unicode > use(main) - -group(main) using keys - - -+ [NCAPS K_A] > 'A' -+ [CAPS K_A] > 'A' -+ [NCAPS SHIFT K_A] > 'A' -+ [SHIFT CAPS K_A] > 'A' -+ [NCAPS RALT CTRL K_A] > '😀' -+ [NCAPS CTRL K_A] > '😀' -+ [NCAPS SHIFT RALT K_A] > 'Å' -+ [NCAPS RALT K_A] > 'å' -c WARNING: ambiguous rule: earlier: [CAPS K_A] > 'A' here: + [CAPS K_A] > 'å' -+ [CAPS RALT K_A] > 'Å' - -+ [NCAPS K_S] > 's' -+ [CAPS K_S] > 'S' -+ [NCAPS SHIFT K_S] > 'S' -+ [SHIFT CAPS K_S] > 'S' -+ [NCAPS RALT CTRL K_S] > '😁' -+ [NCAPS CTRL K_S] > '😁' -+ [NCAPS SHIFT RALT K_S] > '¯' -+ [NCAPS RALT K_S] > 'ß' -c WARNING: ambiguous rule: earlier: [CAPS K_S] > 'S' here: + [CAPS K_S] > 'ß' -+ [CAPS RALT K_S] > 'ß' - -+ [NCAPS K_D] > 'd' -+ [CAPS K_D] > 'D' -+ [NCAPS SHIFT K_D] > 'D' -+ [SHIFT CAPS K_D] > 'D' -+ [NCAPS RALT CTRL K_D] > 'ሴ' -+ [NCAPS CTRL K_D] > 'ሴ' -+ [NCAPS SHIFT RALT K_D] > '˘' -+ [NCAPS RALT K_D] > '∂' -c WARNING: ambiguous rule: earlier: [CAPS K_D] > 'D' here: + [CAPS K_D] > '∂' -+ [CAPS RALT K_D] > '∂' - -+ [NCAPS K_F] > 'f' -+ [CAPS K_F] > 'F' -+ [NCAPS SHIFT K_F] > 'F' -+ [SHIFT CAPS K_F] > 'F' -+ [NCAPS RALT CTRL K_F] > 'ሴ' -+ [NCAPS CTRL K_F] > 'ሴ' -+ [NCAPS SHIFT RALT K_F] > '˙' -+ [NCAPS RALT K_F] > 'ƒ' -c WARNING: ambiguous rule: earlier: [CAPS K_F] > 'F' here: + [CAPS K_F] > 'ƒ' -+ [CAPS RALT K_F] > 'ƒ' - -+ [NCAPS K_H] > 'h' -+ [CAPS K_H] > '@' -+ [NCAPS SHIFT K_H] > 'H' -+ [SHIFT CAPS K_H] > 'H' -+ [NCAPS RALT CTRL K_H] > '😎' -+ [NCAPS CTRL K_H] > '😎' -+ [NCAPS SHIFT RALT K_H] > '¸' -+ [NCAPS RALT K_H] > '∆' -c WARNING: ambiguous rule: earlier: [CAPS K_H] > '@' here: + [CAPS K_H] > '∆' -c WARNING: ambiguous rule: earlier: [NCAPS RALT K_H] > '∆' here: + [NCAPS RALT K_H] > 'ẞ' -+ [CAPS RALT K_H] > '€' - -+ [NCAPS K_G] > 'g' -+ [CAPS K_G] > 'G' -+ [NCAPS SHIFT K_G] > 'G' -+ [SHIFT CAPS K_G] > 'G' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_G] > U+0007 -c WARNING: Use of a control character + [NCAPS CTRL K_G] > U+0007 -+ [NCAPS SHIFT RALT K_G] > '˚' -+ [NCAPS RALT K_G] > '∞' -c WARNING: ambiguous rule: earlier: [CAPS K_G] > 'G' here: + [CAPS K_G] > '∞' -+ [CAPS RALT K_G] > '∞' - -+ [NCAPS K_Z] > 'z' -+ [CAPS K_Z] > 'Z' -+ [NCAPS SHIFT K_Z] > 'Z' -+ [SHIFT CAPS K_Z] > 'Z' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_Z] > U+0017 -c WARNING: Use of a control character + [NCAPS CTRL K_Z] > U+0017 -+ [NCAPS K_SPACE] > ' ' -+ [CAPS K_SPACE] > ' ' -+ [NCAPS SHIFT K_SPACE] > ' ' -+ [SHIFT CAPS K_SPACE] > ' ' -+ [NCAPS RALT CTRL K_SPACE] > ' ' -+ [NCAPS CTRL K_SPACE] > ' ' - -+ [NCAPS SHIFT RALT K_Z] > ' ' - -+ [NCAPS SHIFT RALT K_9] > ' ' - -+ [NCAPS SHIFT RALT K_COMMA] > ' ' -+ [NCAPS RALT K_Z] > '∑' -c WARNING: ambiguous rule: earlier: [CAPS K_Z] > 'Z' here: + [CAPS K_Z] > '∑' -+ [CAPS RALT K_Z] > '∑' - -+ [NCAPS K_X] > 'x' -+ [CAPS K_X] > 'X' -+ [NCAPS SHIFT K_X] > 'X' -+ [SHIFT CAPS K_X] > 'X' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_X] > U+0018 -c WARNING: Use of a control character + [NCAPS CTRL K_X] > U+0018 -+ [NCAPS SHIFT RALT K_X] > '‡' -+ [NCAPS RALT K_X] > '†' -c WARNING: ambiguous rule: earlier: [CAPS K_X] > 'X' here: + [CAPS K_X] > '†' -+ [CAPS RALT K_X] > '†' - -+ [NCAPS K_C] > 'c' -+ [CAPS K_C] > 'C' -+ [NCAPS SHIFT K_C] > 'C' -+ [SHIFT CAPS K_C] > 'C' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_C] > U+0003 -c WARNING: Use of a control character + [NCAPS CTRL K_C] > U+0003 -+ [NCAPS SHIFT RALT K_C] > 'Á' -+ [NCAPS RALT K_C] > '©' -c WARNING: ambiguous rule: earlier: [CAPS K_C] > 'C' here: + [CAPS K_C] > '©' -+ [CAPS RALT K_C] > '©' - -+ [NCAPS K_V] > 'v' -+ [CAPS K_V] > 'V' -+ [NCAPS SHIFT K_V] > 'V' -+ [SHIFT CAPS K_V] > 'V' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_V] > U+0016 -c WARNING: Use of a control character + [NCAPS CTRL K_V] > U+0016 -+ [NCAPS SHIFT RALT K_V] > 'É' -+ [NCAPS RALT K_V] > '√' -c WARNING: ambiguous rule: earlier: [CAPS K_V] > 'V' here: + [CAPS K_V] > '√' -+ [CAPS RALT K_V] > '√' - -+ [NCAPS K_BKQUOTE] > '\' -+ [CAPS K_BKQUOTE] > '\' -+ [NCAPS SHIFT K_BKQUOTE] > '|' -+ [SHIFT CAPS K_BKQUOTE] > '|' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_BKQUOTE] > U+001C -c WARNING: Use of a control character + [NCAPS CTRL K_BKQUOTE] > U+001C -+ [NCAPS SHIFT RALT K_BKQUOTE] > 'ı' -+ [NCAPS RALT K_BKQUOTE] > '`' -c WARNING: ambiguous rule: earlier: [CAPS K_BKQUOTE] > '\' here: + [CAPS K_BKQUOTE] > '`' -+ [CAPS RALT K_BKQUOTE] > '`' - -+ [NCAPS K_B] > 'b' -+ [CAPS K_B] > 'B' -+ [NCAPS SHIFT K_B] > 'B' -+ [SHIFT CAPS K_B] > 'B' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_B] > U+0002 -c WARNING: Use of a control character + [NCAPS CTRL K_B] > U+0002 -+ [NCAPS SHIFT RALT K_B] > 'Í' -+ [NCAPS RALT K_B] > '∫' -c WARNING: ambiguous rule: earlier: [CAPS K_B] > 'B' here: + [CAPS K_B] > '∫' -+ [CAPS RALT K_B] > '∫' - -+ [NCAPS K_Q] > 'q' -+ [CAPS K_Q] > 'Q' -+ [NCAPS SHIFT K_Q] > 'Q' -+ [SHIFT CAPS K_Q] > 'Q' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_Q] > U+0011 -c WARNING: Use of a control character + [NCAPS CTRL K_Q] > U+0011 -+ [NCAPS SHIFT RALT K_Q] > '‚' -+ [NCAPS RALT K_Q] > '„' -c WARNING: ambiguous rule: earlier: [CAPS K_Q] > 'Q' here: + [CAPS K_Q] > '„' -+ [CAPS RALT K_Q] > '„' - -+ [NCAPS K_W] > 'w' -+ [CAPS K_W] > 'W' -+ [NCAPS SHIFT K_W] > 'W' -+ [SHIFT CAPS K_W] > 'W' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_W] > U+001A -c WARNING: Use of a control character + [NCAPS CTRL K_W] > U+001A -+ [NCAPS SHIFT RALT K_W] > 'À' -+ [NCAPS RALT K_W] > 'Ω' -c WARNING: ambiguous rule: earlier: [CAPS K_W] > 'W' here: + [CAPS K_W] > 'Ω' -+ [CAPS RALT K_W] > 'Ω' -+ [NCAPS K_E] > 'e' -+ [CAPS K_E] > 'E' -+ [NCAPS SHIFT K_E] > 'E' -+ [SHIFT CAPS K_E] > 'E' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_E] > U+0005 -c WARNING: Use of a control character + [NCAPS CTRL K_E] > U+0005 -+ [NCAPS SHIFT RALT K_E] > 'È' -+ [NCAPS RALT K_E] > '€' -c WARNING: ambiguous rule: earlier: [CAPS K_E] > 'E' here: + [CAPS K_E] > '€' -+ [CAPS RALT K_E] > '€' - -+ [NCAPS K_R] > 'r' -+ [CAPS K_R] > 'R' -+ [NCAPS SHIFT K_R] > 'R' -+ [SHIFT CAPS K_R] > 'R' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_R] > U+0012 -c WARNING: Use of a control character + [NCAPS CTRL K_R] > U+0012 -+ [NCAPS SHIFT RALT K_R] > 'Ì' -+ [NCAPS RALT K_R] > '®' -c WARNING: ambiguous rule: earlier: [CAPS K_R] > 'R' here: + [CAPS K_R] > '®' -+ [CAPS RALT K_R] > '®' -+ [NCAPS K_Y] > 'y' -+ [CAPS K_Y] > 'Y' -+ [NCAPS SHIFT K_Y] > 'Y' -+ [SHIFT CAPS K_Y] > 'Y' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_Y] > U+0019 -c WARNING: Use of a control character + [NCAPS CTRL K_Y] > U+0019 -+ [NCAPS SHIFT RALT K_Y] > 'Æ' -+ [NCAPS RALT K_Y] > 'æ' -c WARNING: ambiguous rule: earlier: [CAPS K_Y] > 'Y' here: + [CAPS K_Y] > 'æ' -+ [CAPS RALT K_Y] > 'Æ' - -+ [NCAPS K_T] > 't' -+ [CAPS K_T] > 'T' -+ [NCAPS SHIFT K_T] > 'T' -+ [SHIFT CAPS K_T] > 'T' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_T] > U+0014 -c WARNING: Use of a control character + [NCAPS CTRL K_T] > U+0014 -+ [NCAPS SHIFT RALT K_T] > 'Ò' -+ [NCAPS RALT K_T] > '™' -c WARNING: ambiguous rule: earlier: [CAPS K_T] > 'T' here: + [CAPS K_T] > '™' -+ [CAPS RALT K_T] > '™' - -+ [NCAPS K_1] > '1' -+ [CAPS K_1] > '1' -+ [NCAPS SHIFT K_1] > '!' -+ [SHIFT CAPS K_1] > '!' -+ [NCAPS RALT CTRL K_1] > '1' -+ [NCAPS CTRL K_1] > '1' -+ [NCAPS SHIFT RALT K_1] > '»' -+ [NCAPS RALT K_1] > '«' -c WARNING: ambiguous rule: earlier: [CAPS K_1] > '1' here: + [CAPS K_1] > '«' -+ [CAPS RALT K_1] > '«' - -+ [NCAPS K_2] > '2' -+ [CAPS K_2] > '2' -+ [NCAPS SHIFT K_2] > '"' -+ [SHIFT CAPS K_2] > '"' -+ [NCAPS RALT CTRL K_2] > '2' -+ [NCAPS CTRL K_2] > '2' -+ [NCAPS SHIFT RALT K_2] > '”' -+ [NCAPS RALT K_2] > '“' -c WARNING: ambiguous rule: earlier: [CAPS K_2] > '2' here: + [CAPS K_2] > '“' -+ [CAPS RALT K_2] > '“' - -+ [NCAPS K_3] > '3' -+ [CAPS K_3] > '3' -+ [NCAPS SHIFT K_3] > '£' -+ [SHIFT CAPS K_3] > '£' -+ [NCAPS RALT CTRL K_3] > '3' -+ [NCAPS CTRL K_3] > '3' -+ [NCAPS SHIFT RALT K_3] > '’' -+ [NCAPS RALT K_3] > '‘' -c WARNING: ambiguous rule: earlier: [CAPS K_3] > '3' here: + [CAPS K_3] > '‘' -+ [CAPS RALT K_3] > '‘' - -+ [NCAPS K_4] > '4' -+ [CAPS K_4] > '4' -+ [NCAPS SHIFT K_4] > '$' -+ [SHIFT CAPS K_4] > '$' -+ [NCAPS RALT CTRL K_4] > '4' -+ [NCAPS CTRL K_4] > '4' -+ [NCAPS SHIFT RALT K_4] > '¢' -+ [NCAPS RALT K_4] > '¥' -c WARNING: ambiguous rule: earlier: [CAPS K_4] > '4' here: + [CAPS K_4] > '¥' -+ [CAPS RALT K_4] > '¥' - -+ [NCAPS K_6] > '6' -+ [CAPS K_6] > '6' -+ [NCAPS SHIFT K_6] > '&' -+ [SHIFT CAPS K_6] > '&' -+ [NCAPS RALT CTRL K_6] > '6' -+ [NCAPS CTRL K_6] > '6' -+ [NCAPS SHIFT RALT K_6] > '›' -+ [NCAPS RALT K_6] > '‹' -c WARNING: ambiguous rule: earlier: [CAPS K_6] > '6' here: + [CAPS K_6] > '‹' -+ [CAPS RALT K_6] > '‹' - -+ [NCAPS K_5] > '5' -+ [CAPS K_5] > '5' -+ [NCAPS SHIFT K_5] > '%' -+ [SHIFT CAPS K_5] > '%' -+ [NCAPS RALT CTRL K_5] > '5' -+ [NCAPS CTRL K_5] > '5' -+ [NCAPS SHIFT RALT K_5] > '‰' -+ [NCAPS RALT K_5] > '~' -c WARNING: ambiguous rule: earlier: [CAPS K_5] > '5' here: + [CAPS K_5] > '~' -+ [CAPS RALT K_5] > '~' -c WARNING: ambiguous rule: later: [CAPS K_EQUAL] > dk(A3) here: + [CAPS K_EQUAL] > 'ì' -+ [NCAPS SHIFT K_EQUAL] > '^' -+ [SHIFT CAPS K_EQUAL] > '^' -+ [NCAPS RALT CTRL K_EQUAL] > '=' -+ [NCAPS CTRL K_EQUAL] > '=' -+ [NCAPS SHIFT RALT K_EQUAL] > '±' -c WARNING: ambiguous rule: later: [NCAPS RALT K_EQUAL] > dk(A2) here: + [NCAPS RALT K_EQUAL] > 'ˆ' -+ [CAPS RALT K_EQUAL] > 'ˆ' - -+ [NCAPS K_9] > '9' -c WARNING: ambiguous rule: later: [CAPS K_9] > dk(A5) here: + [CAPS K_9] > '9' -+ [NCAPS SHIFT K_9] > ')' -+ [SHIFT CAPS K_9] > ')' -+ [NCAPS RALT CTRL K_9] > '9' -+ [NCAPS CTRL K_9] > '9' -c WARNING: ambiguous rule: later: [NCAPS RALT K_9] > dk(A4) here: + [NCAPS RALT K_9] > '`' -+ [CAPS RALT K_9] > '`' - -+ [NCAPS K_7] > '7' -+ [CAPS K_7] > '7' -+ [NCAPS SHIFT K_7] > '/' -+ [SHIFT CAPS K_7] > '/' -+ [NCAPS RALT CTRL K_7] > '7' -+ [NCAPS CTRL K_7] > '7' -+ [NCAPS SHIFT RALT K_7] > '⁄' -+ [NCAPS RALT K_7] > '÷' -c WARNING: ambiguous rule: earlier: [CAPS K_7] > '7' here: + [CAPS K_7] > '÷' -+ [CAPS RALT K_7] > '÷' - -+ [NCAPS K_HYPHEN] > "'" -+ [CAPS K_HYPHEN] > "'" -+ [NCAPS SHIFT K_HYPHEN] > '?' -+ [SHIFT CAPS K_HYPHEN] > '?' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_HYPHEN] > U+001F -c WARNING: Use of a control character + [NCAPS CTRL K_HYPHEN] > U+001F -+ [NCAPS SHIFT RALT K_HYPHEN] > '¿' -+ [NCAPS RALT K_HYPHEN] > '¡' -c WARNING: ambiguous rule: earlier: [CAPS K_HYPHEN] > ''' here: + [CAPS K_HYPHEN] > '¡' -+ [CAPS RALT K_HYPHEN] > '¡' - -+ [NCAPS K_8] > '8' -c WARNING: ambiguous rule: later: [CAPS K_8] > dk(C13) ambiguous rule: later: [CAPS K_8] > dk(A13) here: + [CAPS K_8] > '8' -+ [NCAPS SHIFT K_8] > '(' -+ [SHIFT CAPS K_8] > '(' -+ [NCAPS RALT CTRL K_8] > '8' -+ [NCAPS CTRL K_8] > '8' -+ [NCAPS SHIFT RALT K_8] > '' -c WARNING: ambiguous rule: later: [NCAPS RALT K_8] > dk(C12) ambiguous rule: later: [NCAPS RALT K_8] > dk(A12) here: + [NCAPS RALT K_8] > '´' -+ [CAPS RALT K_8] > '´' - -+ [NCAPS K_0] > '0' -+ [CAPS K_0] > '0' -+ [NCAPS SHIFT K_0] > '=' -+ [SHIFT CAPS K_0] > '=' -+ [NCAPS RALT CTRL K_0] > '0' -+ [NCAPS CTRL K_0] > '0' -+ [NCAPS SHIFT RALT K_0] > '≈' -+ [NCAPS RALT K_0] > '≠' -c WARNING: ambiguous rule: earlier: [CAPS K_0] > '0' here: + [CAPS K_0] > '≠' -+ [CAPS RALT K_0] > '≠' - -+ [NCAPS K_RBRKT] > '+' -+ [CAPS K_RBRKT] > '+' -+ [NCAPS SHIFT K_RBRKT] > '*' -+ [SHIFT CAPS K_RBRKT] > '*' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_RBRKT] > U+001D -c WARNING: Use of a control character + [NCAPS CTRL K_RBRKT] > U+001D -+ [NCAPS SHIFT RALT K_RBRKT] > '}' -+ [NCAPS RALT K_RBRKT] > ']' -c WARNING: ambiguous rule: earlier: [CAPS K_RBRKT] > '+' here: + [CAPS K_RBRKT] > ']' -+ [CAPS RALT K_RBRKT] > ']' -+ [NCAPS K_O] > 'o' -+ [CAPS K_O] > 'O' -+ [NCAPS SHIFT K_O] > 'O' -+ [SHIFT CAPS K_O] > 'O' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_O] > U+000F -c WARNING: Use of a control character + [NCAPS CTRL K_O] > U+000F -+ [NCAPS SHIFT RALT K_O] > 'Ø' -+ [NCAPS RALT K_O] > 'ø' -c WARNING: ambiguous rule: earlier: [CAPS K_O] > 'O' here: + [CAPS K_O] > 'ø' -+ [CAPS RALT K_O] > 'Ø' -+ [NCAPS K_U] > 'u' -c WARNING: ambiguous rule: later: [CAPS K_U] > dk(A9) here: + [CAPS K_U] > 'U' -+ [NCAPS SHIFT K_U] > 'U' -+ [SHIFT CAPS K_U] > 'U' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_U] > U+0015 -c WARNING: Use of a control character + [NCAPS CTRL K_U] > U+0015 -+ [NCAPS SHIFT RALT K_U] > 'Ù' -c WARNING: ambiguous rule: later: [NCAPS RALT K_U] > dk(A8) here: + [NCAPS RALT K_U] > '¨' -+ [CAPS RALT K_U] > '¨' - -+ [NCAPS K_LBRKT] > 'è' -+ [CAPS K_LBRKT] > 'è' -+ [NCAPS SHIFT K_LBRKT] > 'é' -+ [SHIFT CAPS K_LBRKT] > 'é' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_LBRKT] > U+001E -c WARNING: Use of a control character + [NCAPS CTRL K_LBRKT] > U+001E -+ [NCAPS SHIFT RALT K_LBRKT] > '{' -+ [NCAPS RALT K_LBRKT] > '[' -c WARNING: ambiguous rule: earlier: [CAPS K_LBRKT] > 'è' here: + [CAPS K_LBRKT] > '[' -+ [CAPS RALT K_LBRKT] > '[' -+ [NCAPS K_I] > 'i' -+ [CAPS K_I] > 'I' -+ [NCAPS SHIFT K_I] > 'I' -+ [SHIFT CAPS K_I] > 'I' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_I] > U+0009 -c WARNING: Use of a control character + [NCAPS CTRL K_I] > U+0009 -+ [NCAPS SHIFT RALT K_I] > 'Œ' -+ [NCAPS RALT K_I] > 'œ' -c WARNING: ambiguous rule: earlier: [CAPS K_I] > 'I' here: + [CAPS K_I] > 'œ' -+ [CAPS RALT K_I] > 'Œ' - -+ [NCAPS K_P] > 'p' -+ [CAPS K_P] > 'P' -+ [NCAPS SHIFT K_P] > 'P' -+ [SHIFT CAPS K_P] > 'P' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_P] > U+0010 -c WARNING: Use of a control character + [NCAPS CTRL K_P] > U+0010 -+ [NCAPS SHIFT RALT K_P] > '∏' -+ [NCAPS RALT K_P] > 'π' -c WARNING: ambiguous rule: earlier: [CAPS K_P] > 'P' here: + [CAPS K_P] > 'π' -+ [CAPS RALT K_P] > '∏' - -+ [NCAPS K_L] > 'l' -+ [CAPS K_L] > 'L' -+ [NCAPS SHIFT K_L] > 'L' -+ [SHIFT CAPS K_L] > 'L' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_L] > U+000C -c WARNING: Use of a control character + [NCAPS CTRL K_L] > U+000C -+ [NCAPS SHIFT RALT K_L] > 'ˇ' -+ [NCAPS RALT K_L] > '¬' -c WARNING: ambiguous rule: earlier: [CAPS K_L] > 'L' here: + [CAPS K_L] > '¬' -+ [CAPS RALT K_L] > '¬' - -+ [NCAPS K_J] > 'j' -+ [CAPS K_J] > 'J' -+ [NCAPS SHIFT K_J] > 'J' -+ [SHIFT CAPS K_J] > 'J' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_J] > U+000A -c WARNING: Use of a control character + [NCAPS CTRL K_J] > U+000A -+ [NCAPS SHIFT RALT K_J] > '˝' -+ [NCAPS RALT K_J] > 'ª' -c WARNING: ambiguous rule: earlier: [CAPS K_J] > 'J' here: + [CAPS K_J] > 'ª' -+ [CAPS RALT K_J] > 'ª' - -+ [NCAPS K_QUOTE] > 'à' -+ [CAPS K_QUOTE] > 'à' -+ [NCAPS SHIFT K_QUOTE] > '°' -+ [SHIFT CAPS K_QUOTE] > '°' -+ [NCAPS RALT CTRL K_QUOTE] > '%' -+ [NCAPS CTRL K_QUOTE] > '%' -+ [NCAPS SHIFT RALT K_QUOTE] > '∞' -+ [NCAPS RALT K_QUOTE] > '#' -c WARNING: ambiguous rule: earlier: [CAPS K_QUOTE] > 'à' here: + [CAPS K_QUOTE] > '#' -+ [CAPS RALT K_QUOTE] > '#' - -+ [NCAPS K_K] > 'k' -+ [CAPS K_K] > 'K' -+ [NCAPS SHIFT K_K] > 'K' -+ [SHIFT CAPS K_K] > 'K' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_K] > U+000B -c WARNING: Use of a control character + [NCAPS CTRL K_K] > U+000B -+ [NCAPS SHIFT RALT K_K] > '˛' -+ [NCAPS RALT K_K] > 'º' -c WARNING: ambiguous rule: earlier: [CAPS K_K] > 'K' here: + [CAPS K_K] > 'º' -+ [CAPS RALT K_K] > 'º' - -+ [NCAPS K_COLON] > 'ò' -+ [CAPS K_COLON] > 'ò' -+ [NCAPS SHIFT K_COLON] > 'ç' -+ [SHIFT CAPS K_COLON] > 'ç' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_COLON] > U+000D -c WARNING: Use of a control character + [NCAPS CTRL K_COLON] > U+000D -+ [NCAPS SHIFT RALT K_COLON] > 'Ç' -+ [NCAPS RALT K_COLON] > '@' -c WARNING: ambiguous rule: earlier: [CAPS K_COLON] > 'ò' here: + [CAPS K_COLON] > '@' -+ [CAPS RALT K_COLON] > '@' - -+ [NCAPS K_BKSLASH] > 'ù' -+ [CAPS K_BKSLASH] > 'ù' -+ [NCAPS SHIFT K_BKSLASH] > '§' -+ [SHIFT CAPS K_BKSLASH] > '§' -+ [NCAPS RALT CTRL K_BKSLASH] > '°' -+ [NCAPS CTRL K_BKSLASH] > '°' -+ [NCAPS SHIFT RALT K_BKSLASH] > '◊' -+ [NCAPS RALT K_BKSLASH] > '¶' -c WARNING: ambiguous rule: earlier: [CAPS K_BKSLASH] > 'ù' here: + [CAPS K_BKSLASH] > '¶' -+ [CAPS RALT K_BKSLASH] > '¶' - -+ [NCAPS K_COMMA] > ',' -+ [CAPS K_COMMA] > ',' -+ [NCAPS SHIFT K_COMMA] > ';' -+ [SHIFT CAPS K_COMMA] > ';' -+ [NCAPS RALT CTRL K_COMMA] > '.' -+ [NCAPS CTRL K_COMMA] > '.' -+ [NCAPS RALT K_COMMA] > '…' -c WARNING: ambiguous rule: earlier: [CAPS K_COMMA] > ',' here: + [CAPS K_COMMA] > '…' -+ [CAPS RALT K_COMMA] > '…' - -+ [NCAPS K_SLASH] > '-' -+ [CAPS K_SLASH] > '-' -+ [NCAPS SHIFT K_SLASH] > '_' -+ [SHIFT CAPS K_SLASH] > '_' -+ [NCAPS RALT CTRL K_SLASH] > '!' -+ [NCAPS CTRL K_SLASH] > '!' -+ [NCAPS SHIFT RALT K_SLASH] > '—' -+ [NCAPS RALT K_SLASH] > '–' -c WARNING: ambiguous rule: earlier: [CAPS K_SLASH] > '-' here: + [CAPS K_SLASH] > '–' -+ [CAPS RALT K_SLASH] > '–' -+ [NCAPS K_N] > 'n' -c WARNING: ambiguous rule: later: [CAPS K_N] > dk(A11) here: + [CAPS K_N] > 'N' -+ [NCAPS SHIFT K_N] > 'N' -+ [SHIFT CAPS K_N] > 'N' -c WARNING: Use of a control character + [NCAPS RALT CTRL K_N] > U+000E -c WARNING: Use of a control character + [NCAPS CTRL K_N] > U+000E -+ [NCAPS SHIFT RALT K_N] > 'Ó' -c WARNING: ambiguous rule: later: [NCAPS RALT K_N] > dk(A10) here: + [NCAPS RALT K_N] > '˜' -+ [CAPS RALT K_N] > '˜' - -+ [NCAPS K_M] > 'm' -+ [CAPS K_M] > 'M' -+ [NCAPS SHIFT K_M] > 'M' -+ [SHIFT CAPS K_M] > 'M' -+ [NCAPS RALT CTRL K_M] > '?' -+ [NCAPS CTRL K_M] > '?' -+ [NCAPS SHIFT RALT K_M] > 'Ú' -+ [NCAPS RALT K_M] > 'µ' -c WARNING: ambiguous rule: earlier: [CAPS K_M] > 'M' here: + [CAPS K_M] > 'µ' -+ [CAPS RALT K_M] > 'µ' - -+ [NCAPS K_PERIOD] > '.' -+ [CAPS K_PERIOD] > '.' -+ [NCAPS SHIFT K_PERIOD] > ':' -+ [SHIFT CAPS K_PERIOD] > ':' -+ [NCAPS RALT CTRL K_PERIOD] > '/' -+ [NCAPS CTRL K_PERIOD] > '/' -+ [NCAPS SHIFT RALT K_PERIOD] > '·' -+ [NCAPS RALT K_PERIOD] > '•' -c WARNING: ambiguous rule: earlier: [CAPS K_PERIOD] > '.' here: + [CAPS K_PERIOD] > '•' -+ [CAPS RALT K_PERIOD] > '•' - -+ [NCAPS SHIFT RALT K_SPACE] > ' ' -+ [NCAPS RALT K_SPACE] > ' ' -c WARNING: ambiguous rule: earlier: [CAPS K_SPACE] > ' ' here: + [CAPS K_SPACE] > ' ' -+ [CAPS RALT K_SPACE] > ' ' -+ [NCAPS K_EQUAL] > dk(A1) -dk(A1) + [NCAPS K_SPACE] > 'ˆ' - -dk(A1) + [CAPS K_SPACE] > 'ˆ' - -dk(A1) + [NCAPS SHIFT K_SPACE] > 'ˆ' - -dk(A1) + [SHIFT CAPS K_SPACE] > 'ˆ' - -dk(A1) + [NCAPS RALT CTRL K_SPACE] > 'ˆ' - -dk(A1) + [NCAPS CTRL K_SPACE] > 'ˆ' - -dk(A1) + [NCAPS SHIFT RALT K_Z] > 'ˆ' - -dk(A1) + [NCAPS SHIFT RALT K_9] > 'ˆ' - -dk(A1) + [NCAPS SHIFT RALT K_COMMA] > 'ˆ' - -dk(A1) + [CAPS K_A] > 'Â' - -dk(A1) + [NCAPS SHIFT K_A] > 'Â' - -dk(A1) + [SHIFT CAPS K_A] > 'Â' - -dk(A1) + [NCAPS K_E] > 'ê' - -dk(A1) + [NCAPS K_I] > 'î' - -dk(A1) + [NCAPS K_O] > 'ô' - -dk(A1) + [NCAPS K_U] > 'û' - -dk(A1) + [CAPS K_E] > 'Ê' - -dk(A1) + [NCAPS SHIFT K_E] > 'Ê' - -dk(A1) + [SHIFT CAPS K_E] > 'Ê' - -dk(A1) + [CAPS K_I] > 'Î' - -dk(A1) + [NCAPS SHIFT K_I] > 'Î' - -dk(A1) + [SHIFT CAPS K_I] > 'Î' - -dk(A1) + [CAPS K_O] > 'Ô' - -dk(A1) + [NCAPS SHIFT K_O] > 'Ô' - -dk(A1) + [SHIFT CAPS K_O] > 'Ô' - -dk(A1) + [CAPS K_U] > 'Û' - -dk(A1) + [NCAPS SHIFT K_U] > 'Û' - -dk(A1) + [SHIFT CAPS K_U] > 'Û' - -dk(A1) + [NCAPS K_A] > 'â' - -+ [NCAPS RALT K_EQUAL] > dk(A2) -dk(A2) + [NCAPS K_SPACE] > 'ˆ' - -dk(A2) + [CAPS K_SPACE] > 'ˆ' - -dk(A2) + [NCAPS SHIFT K_SPACE] > 'ˆ' - -dk(A2) + [SHIFT CAPS K_SPACE] > 'ˆ' - -dk(A2) + [NCAPS RALT CTRL K_SPACE] > 'ˆ' - -dk(A2) + [NCAPS CTRL K_SPACE] > 'ˆ' - -dk(A2) + [NCAPS SHIFT RALT K_Z] > 'ˆ' - -dk(A2) + [NCAPS SHIFT RALT K_9] > 'ˆ' - -dk(A2) + [NCAPS SHIFT RALT K_COMMA] > 'ˆ' - -dk(A2) + [CAPS K_A] > 'Â' - -dk(A2) + [NCAPS SHIFT K_A] > 'Â' - -dk(A2) + [SHIFT CAPS K_A] > 'Â' - -dk(A2) + [NCAPS K_E] > 'ê' - -dk(A2) + [NCAPS K_I] > 'î' - -dk(A2) + [NCAPS K_O] > 'ô' - -dk(A2) + [NCAPS K_U] > 'û' - -dk(A2) + [CAPS K_E] > 'Ê' - -dk(A2) + [NCAPS SHIFT K_E] > 'Ê' - -dk(A2) + [SHIFT CAPS K_E] > 'Ê' - -dk(A2) + [CAPS K_I] > 'Î' - -dk(A2) + [NCAPS SHIFT K_I] > 'Î' - -dk(A2) + [SHIFT CAPS K_I] > 'Î' - -dk(A2) + [CAPS K_O] > 'Ô' - -dk(A2) + [NCAPS SHIFT K_O] > 'Ô' - -dk(A2) + [SHIFT CAPS K_O] > 'Ô' - -dk(A2) + [CAPS K_U] > 'Û' - -dk(A2) + [NCAPS SHIFT K_U] > 'Û' - -dk(A2) + [SHIFT CAPS K_U] > 'Û' - -dk(A2) + [NCAPS K_A] > 'â' - -+ [CAPS K_EQUAL] > dk(A3) -dk(A3) + [NCAPS K_SPACE] > 'ˆ' - -dk(A3) + [CAPS K_SPACE] > 'ˆ' - -dk(A3) + [NCAPS SHIFT K_SPACE] > 'ˆ' - -dk(A3) + [SHIFT CAPS K_SPACE] > 'ˆ' - -dk(A3) + [NCAPS RALT CTRL K_SPACE] > 'ˆ' - -dk(A3) + [NCAPS CTRL K_SPACE] > 'ˆ' - -dk(A3) + [NCAPS SHIFT RALT K_Z] > 'ˆ' - -dk(A3) + [NCAPS SHIFT RALT K_9] > 'ˆ' - -dk(A3) + [NCAPS SHIFT RALT K_COMMA] > 'ˆ' - -dk(A3) + [CAPS K_A] > 'Â' - -dk(A3) + [NCAPS SHIFT K_A] > 'Â' - -dk(A3) + [SHIFT CAPS K_A] > 'Â' - -dk(A3) + [NCAPS K_E] > 'ê' - -dk(A3) + [NCAPS K_I] > 'î' - -dk(A3) + [NCAPS K_O] > 'ô' - -dk(A3) + [NCAPS K_U] > 'û' - -dk(A3) + [CAPS K_E] > 'Ê' - -dk(A3) + [NCAPS SHIFT K_E] > 'Ê' - -dk(A3) + [SHIFT CAPS K_E] > 'Ê' - -dk(A3) + [CAPS K_I] > 'Î' - -dk(A3) + [NCAPS SHIFT K_I] > 'Î' - -dk(A3) + [SHIFT CAPS K_I] > 'Î' - -dk(A3) + [CAPS K_O] > 'Ô' - -dk(A3) + [NCAPS SHIFT K_O] > 'Ô' - -dk(A3) + [SHIFT CAPS K_O] > 'Ô' - -dk(A3) + [CAPS K_U] > 'Û' - -dk(A3) + [NCAPS SHIFT K_U] > 'Û' - -dk(A3) + [SHIFT CAPS K_U] > 'Û' - -dk(A3) + [NCAPS K_A] > 'â' - -+ [NCAPS RALT K_9] > dk(A4) -dk(A4) + [NCAPS K_SPACE] > '`' - -dk(A4) + [CAPS K_SPACE] > '`' - -dk(A4) + [NCAPS SHIFT K_SPACE] > '`' - -dk(A4) + [SHIFT CAPS K_SPACE] > '`' - -dk(A4) + [NCAPS RALT CTRL K_SPACE] > '`' - -dk(A4) + [NCAPS CTRL K_SPACE] > '`' - -dk(A4) + [NCAPS SHIFT RALT K_Z] > '`' - -dk(A4) + [NCAPS SHIFT RALT K_9] > '`' - -dk(A4) + [NCAPS SHIFT RALT K_COMMA] > '`' - -dk(A4) + [CAPS K_A] > 'À' - -dk(A4) + [NCAPS SHIFT K_A] > 'À' - -dk(A4) + [SHIFT CAPS K_A] > 'À' - -dk(A4) + [NCAPS K_E] > 'è' - -dk(A4) + [NCAPS K_I] > 'ì' - -dk(A4) + [NCAPS K_O] > 'ò' - -dk(A4) + [NCAPS K_U] > 'ù' - -dk(A4) + [CAPS K_E] > 'È' - -dk(A4) + [NCAPS SHIFT K_E] > 'È' - -dk(A4) + [SHIFT CAPS K_E] > 'È' - -dk(A4) + [CAPS K_I] > 'Ì' - -dk(A4) + [NCAPS SHIFT K_I] > 'Ì' - -dk(A4) + [SHIFT CAPS K_I] > 'Ì' - -dk(A4) + [CAPS K_O] > 'Ò' - -dk(A4) + [NCAPS SHIFT K_O] > 'Ò' - -dk(A4) + [SHIFT CAPS K_O] > 'Ò' - -dk(A4) + [CAPS K_U] > 'Ù' - -dk(A4) + [NCAPS SHIFT K_U] > 'Ù' - -dk(A4) + [SHIFT CAPS K_U] > 'Ù' - -dk(A4) + [NCAPS K_A] > 'à' - -+ [CAPS K_9] > dk(A5) -dk(A5) + [NCAPS K_SPACE] > '`' - -dk(A5) + [CAPS K_SPACE] > '`' - -dk(A5) + [NCAPS SHIFT K_SPACE] > '`' - -dk(A5) + [SHIFT CAPS K_SPACE] > '`' - -dk(A5) + [NCAPS RALT CTRL K_SPACE] > '`' - -dk(A5) + [NCAPS CTRL K_SPACE] > '`' - -dk(A5) + [NCAPS SHIFT RALT K_Z] > '`' - -dk(A5) + [NCAPS SHIFT RALT K_9] > '`' - -dk(A5) + [NCAPS SHIFT RALT K_COMMA] > '`' - -dk(A5) + [CAPS K_A] > 'À' - -dk(A5) + [NCAPS SHIFT K_A] > 'À' - -dk(A5) + [SHIFT CAPS K_A] > 'À' - -dk(A5) + [NCAPS K_E] > 'è' - -dk(A5) + [NCAPS K_I] > 'ì' - -dk(A5) + [NCAPS K_O] > 'ò' - -dk(A5) + [NCAPS K_U] > 'ù' - -dk(A5) + [CAPS K_E] > 'È' - -dk(A5) + [NCAPS SHIFT K_E] > 'È' - -dk(A5) + [SHIFT CAPS K_E] > 'È' - -dk(A5) + [CAPS K_I] > 'Ì' - -dk(A5) + [NCAPS SHIFT K_I] > 'Ì' - -dk(A5) + [SHIFT CAPS K_I] > 'Ì' - -dk(A5) + [CAPS K_O] > 'Ò' - -dk(A5) + [NCAPS SHIFT K_O] > 'Ò' - -dk(A5) + [SHIFT CAPS K_O] > 'Ò' - -dk(A5) + [CAPS K_U] > 'Ù' - -dk(A5) + [NCAPS SHIFT K_U] > 'Ù' - -dk(A5) + [SHIFT CAPS K_U] > 'Ù' - -dk(A5) + [NCAPS K_A] > 'à' - -+ [NCAPS RALT K_8] > dk(A12) -dk(A12) + [NCAPS K_SPACE] > '´' - -dk(A12) + [CAPS K_SPACE] > '´' - -dk(A12) + [NCAPS SHIFT K_SPACE] > '´' - -dk(A12) + [SHIFT CAPS K_SPACE] > '´' - -dk(A12) + [NCAPS RALT CTRL K_SPACE] > '´' - -dk(A12) + [NCAPS CTRL K_SPACE] > '´' - -dk(A12) + [NCAPS SHIFT RALT K_Z] > '´' - -dk(A12) + [NCAPS SHIFT RALT K_9] > '´' - -dk(A12) + [NCAPS SHIFT RALT K_COMMA] > '´' - -dk(A12) + [CAPS K_A] > 'Á' - -dk(A12) + [NCAPS SHIFT K_A] > 'Á' - -dk(A12) + [SHIFT CAPS K_A] > 'Á' - -dk(A12) + [NCAPS K_E] > 'é' - -dk(A12) + [NCAPS K_I] > 'í' - -dk(A12) + [NCAPS K_O] > 'ó' - -dk(A12) + [NCAPS K_U] > 'ú' - -dk(A12) + [CAPS K_E] > 'É' - -dk(A12) + [NCAPS SHIFT K_E] > 'É' - -dk(A12) + [SHIFT CAPS K_E] > 'É' - -dk(A12) + [CAPS K_I] > 'Í' - -dk(A12) + [NCAPS SHIFT K_I] > 'Í' - -dk(A12) + [SHIFT CAPS K_I] > 'Í' - -dk(A12) + [CAPS K_O] > 'Ó' - -dk(A12) + [NCAPS SHIFT K_O] > 'Ó' - -dk(A12) + [SHIFT CAPS K_O] > 'Ó' - -dk(A12) + [CAPS K_U] > 'Ú' - -dk(A12) + [NCAPS SHIFT K_U] > 'Ú' - -dk(A12) + [SHIFT CAPS K_U] > 'Ú' - -dk(A12) + [NCAPS K_A] > 'á' - -+ [CAPS K_8] > dk(A13) -dk(A13) + [NCAPS K_SPACE] > '´' - -dk(A13) + [CAPS K_SPACE] > '´' - -dk(A13) + [NCAPS SHIFT K_SPACE] > '´' - -dk(A13) + [SHIFT CAPS K_SPACE] > '´' - -dk(A13) + [NCAPS RALT CTRL K_SPACE] > '´' - -dk(A13) + [NCAPS CTRL K_SPACE] > '´' - -dk(A13) + [NCAPS SHIFT RALT K_Z] > '´' - -dk(A13) + [NCAPS SHIFT RALT K_9] > '´' - -dk(A13) + [NCAPS SHIFT RALT K_COMMA] > '´' - -dk(A13) + [CAPS K_A] > 'Á' - -dk(A13) + [NCAPS SHIFT K_A] > 'Á' - -dk(A13) + [SHIFT CAPS K_A] > 'Á' - -dk(A13) + [NCAPS K_E] > 'é' - -dk(A13) + [NCAPS K_I] > 'í' - -dk(A13) + [NCAPS K_O] > 'ó' - -dk(A13) + [NCAPS K_U] > 'ú' - -dk(A13) + [CAPS K_E] > 'É' - -dk(A13) + [NCAPS SHIFT K_E] > 'É' - -dk(A13) + [SHIFT CAPS K_E] > 'É' - -dk(A13) + [CAPS K_I] > 'Í' - -dk(A13) + [NCAPS SHIFT K_I] > 'Í' - -dk(A13) + [SHIFT CAPS K_I] > 'Í' - -dk(A13) + [CAPS K_O] > 'Ó' - -dk(A13) + [NCAPS SHIFT K_O] > 'Ó' - -dk(A13) + [SHIFT CAPS K_O] > 'Ó' - -dk(A13) + [CAPS K_U] > 'Ú' - -dk(A13) + [NCAPS SHIFT K_U] > 'Ú' - -dk(A13) + [SHIFT CAPS K_U] > 'Ú' - -dk(A13) + [NCAPS K_A] > 'á' - -+ [NCAPS RALT K_U] > dk(A8) -dk(A8) + [NCAPS K_SPACE] > '¨' - -dk(A8) + [CAPS K_SPACE] > '¨' - -dk(A8) + [NCAPS SHIFT K_SPACE] > '¨' - -dk(A8) + [SHIFT CAPS K_SPACE] > '¨' - -dk(A8) + [NCAPS RALT CTRL K_SPACE] > '¨' - -dk(A8) + [NCAPS CTRL K_SPACE] > '¨' - -dk(A8) + [NCAPS SHIFT RALT K_Z] > '¨' - -dk(A8) + [NCAPS SHIFT RALT K_9] > '¨' - -dk(A8) + [NCAPS SHIFT RALT K_COMMA] > '¨' - -dk(A8) + [CAPS K_A] > 'Ä' - -dk(A8) + [NCAPS SHIFT K_A] > 'Ä' - -dk(A8) + [SHIFT CAPS K_A] > 'Ä' - -dk(A8) + [NCAPS K_E] > 'ë' - -dk(A8) + [NCAPS K_I] > 'ï' - -dk(A8) + [NCAPS K_O] > 'ö' - -dk(A8) + [NCAPS K_U] > 'ü' - -dk(A8) + [NCAPS K_Y] > 'ÿ' - -dk(A8) + [CAPS K_E] > 'Ë' - -dk(A8) + [NCAPS SHIFT K_E] > 'Ë' - -dk(A8) + [SHIFT CAPS K_E] > 'Ë' - -dk(A8) + [CAPS K_I] > 'Ï' - -dk(A8) + [NCAPS SHIFT K_I] > 'Ï' - -dk(A8) + [SHIFT CAPS K_I] > 'Ï' - -dk(A8) + [CAPS K_O] > 'Ö' - -dk(A8) + [NCAPS SHIFT K_O] > 'Ö' - -dk(A8) + [SHIFT CAPS K_O] > 'Ö' - -dk(A8) + [CAPS K_U] > 'Ü' - -dk(A8) + [NCAPS SHIFT K_U] > 'Ü' - -dk(A8) + [SHIFT CAPS K_U] > 'Ü' - -dk(A8) + [CAPS K_Y] > 'Ÿ' - -dk(A8) + [NCAPS SHIFT K_Y] > 'Ÿ' - -dk(A8) + [SHIFT CAPS K_Y] > 'Ÿ' - -dk(A8) + [NCAPS K_A] > 'ä' - -+ [CAPS K_U] > dk(A9) -dk(A9) + [NCAPS K_SPACE] > '¨' - -dk(A9) + [CAPS K_SPACE] > '¨' - -dk(A9) + [NCAPS SHIFT K_SPACE] > '¨' - -dk(A9) + [SHIFT CAPS K_SPACE] > '¨' - -dk(A9) + [NCAPS RALT CTRL K_SPACE] > '¨' - -dk(A9) + [NCAPS CTRL K_SPACE] > '¨' - -dk(A9) + [NCAPS SHIFT RALT K_Z] > '¨' - -dk(A9) + [NCAPS SHIFT RALT K_9] > '¨' - -dk(A9) + [NCAPS SHIFT RALT K_COMMA] > '¨' - -dk(A9) + [CAPS K_A] > 'Ä' - -dk(A9) + [NCAPS SHIFT K_A] > 'Ä' - -dk(A9) + [SHIFT CAPS K_A] > 'Ä' - -dk(A9) + [NCAPS K_E] > 'ë' - -dk(A9) + [NCAPS K_I] > 'ï' - -dk(A9) + [NCAPS K_O] > 'ö' - -dk(A9) + [NCAPS K_U] > 'ü' - -dk(A9) + [NCAPS K_Y] > 'ÿ' - -dk(A9) + [CAPS K_E] > 'Ë' - -dk(A9) + [NCAPS SHIFT K_E] > 'Ë' - -dk(A9) + [SHIFT CAPS K_E] > 'Ë' - -dk(A9) + [CAPS K_I] > 'Ï' - -dk(A9) + [NCAPS SHIFT K_I] > 'Ï' - -dk(A9) + [SHIFT CAPS K_I] > 'Ï' - -dk(A9) + [CAPS K_O] > 'Ö' - -dk(A9) + [NCAPS SHIFT K_O] > 'Ö' - -dk(A9) + [SHIFT CAPS K_O] > 'Ö' - -dk(A9) + [CAPS K_U] > 'Ü' - -dk(A9) + [NCAPS SHIFT K_U] > 'Ü' - -dk(A9) + [SHIFT CAPS K_U] > 'Ü' - -dk(A9) + [CAPS K_Y] > 'Ÿ' - -dk(A9) + [NCAPS SHIFT K_Y] > 'Ÿ' - -dk(A9) + [SHIFT CAPS K_Y] > 'Ÿ' - -dk(A9) + [NCAPS K_A] > 'ä' - -+ [NCAPS RALT K_N] > dk(A10) -dk(A10) + [NCAPS K_SPACE] > '˜' - -dk(A10) + [CAPS K_SPACE] > '˜' - -dk(A10) + [NCAPS SHIFT K_SPACE] > '˜' - -dk(A10) + [SHIFT CAPS K_SPACE] > '˜' - -dk(A10) + [NCAPS RALT CTRL K_SPACE] > '˜' - -dk(A10) + [NCAPS CTRL K_SPACE] > '˜' - -dk(A10) + [NCAPS SHIFT RALT K_Z] > '˜' - -dk(A10) + [NCAPS SHIFT RALT K_9] > '˜' - -dk(A10) + [NCAPS SHIFT RALT K_COMMA] > '˜' - -dk(A10) + [CAPS K_A] > 'Ã' - -dk(A10) + [NCAPS SHIFT K_A] > 'Ã' - -dk(A10) + [SHIFT CAPS K_A] > 'Ã' - -dk(A10) + [NCAPS K_N] > 'ñ' - -dk(A10) + [NCAPS K_O] > 'õ' - -dk(A10) + [CAPS K_N] > 'Ñ' - -dk(A10) + [NCAPS SHIFT K_N] > 'Ñ' - -dk(A10) + [SHIFT CAPS K_N] > 'Ñ' - -dk(A10) + [CAPS K_O] > 'Õ' - -dk(A10) + [NCAPS SHIFT K_O] > 'Õ' - -dk(A10) + [SHIFT CAPS K_O] > 'Õ' - -dk(A10) + [NCAPS K_A] > 'ã' - -+ [CAPS K_N] > dk(A11) -dk(A11) + [NCAPS K_SPACE] > '˜' - -dk(A11) + [CAPS K_SPACE] > '˜' - -dk(A11) + [NCAPS SHIFT K_SPACE] > '˜' - -dk(A11) + [SHIFT CAPS K_SPACE] > '˜' - -dk(A11) + [NCAPS RALT CTRL K_SPACE] > '˜' - -dk(A11) + [NCAPS CTRL K_SPACE] > '˜' - -dk(A11) + [NCAPS SHIFT RALT K_Z] > '˜' - -dk(A11) + [NCAPS SHIFT RALT K_9] > '˜' - -dk(A11) + [NCAPS SHIFT RALT K_COMMA] > '˜' - -dk(A11) + [CAPS K_A] > 'Ã' - -dk(A11) + [NCAPS SHIFT K_A] > 'Ã' - -dk(A11) + [SHIFT CAPS K_A] > 'Ã' - -dk(A11) + [NCAPS K_N] > 'ñ' - -dk(A11) + [NCAPS K_O] > 'õ' - -dk(A11) + [CAPS K_N] > 'Ñ' - -dk(A11) + [NCAPS SHIFT K_N] > 'Ñ' - -dk(A11) + [SHIFT CAPS K_N] > 'Ñ' - -dk(A11) + [CAPS K_O] > 'Õ' - -dk(A11) + [NCAPS SHIFT K_O] > 'Õ' - -dk(A11) + [SHIFT CAPS K_O] > 'Õ' - -dk(A11) + [NCAPS K_A] > 'ã' - -c WARNING: ambiguous rule: earlier: [NCAPS RALT K_8] > dk(A12) here: + [NCAPS RALT K_8] > dk(A12) -dk(A12) + [NCAPS RALT K_U] > dk(B8) -dk(B8) + [NCAPS K_SPACE] > 'ˆ' - -dk(B8) + [CAPS K_SPACE] > 'ˆ' - -dk(B8) + [NCAPS SHIFT K_SPACE] > 'ˆ' - -dk(B8) + [SHIFT CAPS K_SPACE] > 'ˆ' - -dk(B8) + [NCAPS RALT CTRL K_SPACE] > 'ˆ' - -dk(B8) + [NCAPS CTRL K_SPACE] > 'ˆ' - -dk(B8) + [NCAPS SHIFT RALT K_Z] > 'ˆ' - -dk(B8) + [NCAPS SHIFT RALT K_9] > 'ˆ' - -dk(B8) + [NCAPS SHIFT RALT K_COMMA] > 'ˆ' - -dk(B8) + [CAPS K_A] > 'Â' - -dk(B8) + [NCAPS SHIFT K_A] > 'Â' - -dk(B8) + [SHIFT CAPS K_A] > 'Â' - -dk(B8) + [NCAPS K_E] > 'ê' - -dk(B8) + [NCAPS K_I] > 'î' - -dk(B8) + [NCAPS K_O] > 'ô' - -dk(B8) + [NCAPS K_U] > 'û' - -dk(B8) + [CAPS K_E] > 'Ê' - -dk(B8) + [NCAPS SHIFT K_E] > 'Ê' - -dk(B8) + [SHIFT CAPS K_E] > 'Ê' - -dk(B8) + [CAPS K_I] > 'Î' - -dk(B8) + [NCAPS SHIFT K_I] > 'Î' - -dk(B8) + [SHIFT CAPS K_I] > 'Î' - -dk(B8) + [CAPS K_O] > 'Ô' - -dk(B8) + [NCAPS SHIFT K_O] > 'Ô' - -dk(B8) + [SHIFT CAPS K_O] > 'Ô' - -dk(B8) + [CAPS K_U] > 'Û' - -dk(B8) + [NCAPS SHIFT K_U] > 'Û' - -dk(B8) + [SHIFT CAPS K_U] > 'Û' - -dk(B8) + [NCAPS K_A] > 'â' - -dk(A12) + [CAPS K_U] > dk(B9) -dk(B9) + [NCAPS K_SPACE] > 'ˆ' - -dk(B9) + [CAPS K_SPACE] > 'ˆ' - -dk(B9) + [NCAPS SHIFT K_SPACE] > 'ˆ' - -dk(B9) + [SHIFT CAPS K_SPACE] > 'ˆ' - -dk(B9) + [NCAPS RALT CTRL K_SPACE] > 'ˆ' - -dk(B9) + [NCAPS CTRL K_SPACE] > 'ˆ' - -dk(B9) + [NCAPS SHIFT RALT K_Z] > 'ˆ' - -dk(B9) + [NCAPS SHIFT RALT K_9] > 'ˆ' - -dk(B9) + [NCAPS SHIFT RALT K_COMMA] > 'ˆ' - -dk(B9) + [CAPS K_A] > 'Â' - -dk(B9) + [NCAPS SHIFT K_A] > 'Â' - -dk(B9) + [SHIFT CAPS K_A] > 'Â' - -dk(B9) + [NCAPS K_E] > 'ê' - -dk(B9) + [NCAPS K_I] > 'î' - -dk(B9) + [NCAPS K_O] > 'ô' - -dk(B9) + [NCAPS K_U] > 'û' - -dk(B9) + [CAPS K_E] > 'Ê' - -dk(B9) + [NCAPS SHIFT K_E] > 'Ê' - -dk(B9) + [SHIFT CAPS K_E] > 'Ê' - -dk(B9) + [CAPS K_I] > 'Î' - -dk(B9) + [NCAPS SHIFT K_I] > 'Î' - -dk(B9) + [SHIFT CAPS K_I] > 'Î' - -dk(B9) + [CAPS K_O] > 'Ô' - -dk(B9) + [NCAPS SHIFT K_O] > 'Ô' - -dk(B9) + [SHIFT CAPS K_O] > 'Ô' - -dk(B9) + [CAPS K_U] > 'Û' - -dk(B9) + [NCAPS SHIFT K_U] > 'Û' - -dk(B9) + [SHIFT CAPS K_U] > 'Û' - -dk(B9) + [NCAPS K_A] > 'â' - -c WARNING: ambiguous rule: earlier: [CAPS K_8] > dk(A13) here: + [CAPS K_8] > dk(A13) -dk(A13) + [NCAPS RALT K_U] > dk(B8) - -dk(A13) + [CAPS K_U] > dk(B9) - diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 54b2c3d3ae..628142d10c 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -20,6 +20,28 @@ describe('KeylayoutToKmnConverter', function () { before(function () { compilerTestCallbacks.clear(); }); +describe('RunFILES', function () { + this.timeout(10000); // allow longer time for these tests + const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); + [ + [makePathToFixture('../data/Polish.keylayout')], + [makePathToFixture('../data/Spanish.keylayout')], + [makePathToFixture('../data/French.keylayout')], + // [makePathToFixture('../data/German_complete_reduced.keylayout')], + // [makePathToFixture('../data/German_standard.keylayout')], + [makePathToFixture('../data/Italian_command.keylayout')], + [makePathToFixture('../data/Italian.keylayout')], + [makePathToFixture('../data/Latin_American.keylayout')], + [makePathToFixture('../data/Swiss_French.keylayout')], + [makePathToFixture('../data/Swiss_German.keylayout')], + [makePathToFixture('../data/US.keylayout')], + ].forEach(function (files) { + it(files + " should give no errors ", async function () { + sut.run(files[0]); + assert.isTrue(compilerTestCallbacks.messages.length === 0); + }); + }); + }); describe('RunSpecialTestFiles', function () { const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 8b841b6dad..d3d19abbe8 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -105,43 +105,34 @@ describe('KmnFileWriter', function () { }); }); + describe('reviewRules messages', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); - [/* + [ [[new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'UNAVAILABLE', 'K_A', new TextEncoder().encode('A'))], [''], [''], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: ']], [[new Rule("C1", '', '', 0, 0, 'CAPS', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_B', new TextEncoder().encode('B'))], [''], [''], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: ']], [[new Rule("C2", '', '', 0, 0, 'CAPS', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], [''], [''], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: ']], [[new Rule("C2", '', '', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], [''], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(A0) ) : unavailable modifier here: ']], [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : here: ']], - -*/ - - [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'UNAVAIL', 'K_C', new TextEncoder().encode('D'),)], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : unavailable modifier : here: ']], - - - + ['c WARNING: unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_prev_dk K_D] > dk(A0) ) : unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : here: ']], [[new Rule("C3", 'CAPS', 'K_D', 0, 0, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], [''], @@ -149,9 +140,9 @@ describe('KmnFileWriter', function () { ['']], [[new Rule("C3", 'X', 'K_X', 0, 0, 'Y', 'K_Y', 0, 0, 'SHIFT', 'K_Z', new TextEncoder().encode('D'),)], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable superior rule ( [Y K_Y] > dk(B0) ) : here: ']], + ['c WARNING: unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [X K_X] > dk(A0) ) : unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [Y K_Y] > dk(B0) ) : here: ']], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule " ' + (values[0][0] as Rule).ruleType as string + ' "') + 'should create "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { @@ -163,6 +154,7 @@ describe('KmnFileWriter', function () { }); }); + describe('reviewRules messages duplicate and ambiguous', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); [ @@ -170,9 +162,9 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: duplicate rule: earlier: dk(B0) + [SHIFT K_B] > dk(B0) here: "], - ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ["c WARNING: duplicate rule: earlier: dk(B0) + [SHIFT K_B] > dk(B0) here: "], + ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], //6-6 dup [[ @@ -180,7 +172,7 @@ describe('KmnFileWriter', function () { new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], [''], [""], - ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], //6-6 amb [[ @@ -188,29 +180,29 @@ describe('KmnFileWriter', function () { new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),], [''], [""], - ["c WARNING: ambiguous rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: ambiguous rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], // 5-5 amb [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 1, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: ambiguous rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], [''], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ["c WARNING: ambiguous rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], [''], ], // 5-5 dup [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: duplicate rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ["c WARNING: duplicate rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], ['']], // 4-2 amb [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'LALT', 'K_A', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], + ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], [''], ['']], @@ -218,7 +210,7 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 1, 1, 'NCAPS', 'K_E', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], - ['c WARNING: ambiguous rule: earlier: [LALT K_A] > dk(C0) here: '], + ['c WARNING: ambiguous rule: earlier: [LALT K_A] > dk(C0) here: '], [""], [''],], @@ -226,7 +218,7 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_E', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], [''], ['']], @@ -234,7 +226,7 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'LALT', 'K_A', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], - ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], + ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], [''], ['']], @@ -243,7 +235,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], [''], - ["c WARNING: duplicate rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], + ["c WARNING: duplicate rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], [''],], // 6-3 amb @@ -251,14 +243,14 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),], [''], - ["c WARNING: ambiguous rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], + ["c WARNING: ambiguous rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], [''],], // 2-4 amb [[ new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'SHIFT', 'K_B', 0, 0, 'NCAPS', 'K_E', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], - ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(A0) here: '], + ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(A0) here: '], [''], ['']], @@ -267,7 +259,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 1, 1, 'RALT', 'K_F', new TextEncoder().encode('Y')),], [''], - ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(C0) here: '], + ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(C0) here: '], ['']], // 2-2 dup @@ -275,7 +267,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], [''], - ['c WARNING: duplicate rule: earlier: [SHIFT K_B] > dk(C0) here: '], + ['c WARNING: duplicate rule: earlier: [SHIFT K_B] > dk(C0) here: '], ['']], // 3-3 dup @@ -284,7 +276,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], [''], [''], - ["c WARNING: duplicate rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: duplicate rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], // 3-3 amb [[ @@ -292,7 +284,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),], [''], [''], - ["c WARNING: ambiguous rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: ambiguous rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], // 2-1 amb [[ @@ -300,7 +292,7 @@ describe('KmnFileWriter', function () { new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'RALT', 'K_B', new TextEncoder().encode('Y'))], [''], [''], - ['c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) here: ']], + ['c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) here: ']], // 1-1 amb [[ @@ -308,7 +300,7 @@ describe('KmnFileWriter', function () { new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y'))], [''], [''], - ["c WARNING: ambiguous rule: earlier: [CAPS K_C] > 'X' here: "]], + ["c WARNING: ambiguous rule: earlier: [CAPS K_C] > 'X' here: "]], // 1-1 amb [[ @@ -316,7 +308,7 @@ describe('KmnFileWriter', function () { new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X'))], [''], [''], - ["c WARNING: duplicate rule: earlier: [CAPS K_C] > 'X' here: "]], + ["c WARNING: duplicate rule: earlier: [CAPS K_C] > 'X' here: "]], ].forEach(function (values: (string[] | Rule[])[], index: number) { it('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { @@ -337,7 +329,7 @@ describe('KmnFileWriter', function () { ], [''], [''], - ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' here: PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! "]], + ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! here: "]], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "') + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 2); From 0a5dbe3fa96a959306191c7190803e21561b13f6 Mon Sep 17 00:00:00 2001 From: Sabine Date: Wed, 24 Jun 2026 16:18:01 +0200 Subject: [PATCH 22/33] feat(developer): reviewRules: return object instead of string[] --- .../src/common/web/utils/src/xml-utils.ts | 6 +- .../keylayout-to-kmn-converter.ts | 2 +- .../src/keylayout-to-kmn/kmn-file-writer.ts | 932 ++++++------------ .../test/keylayout-to-kmn-converter.tests.ts | 22 - .../kmc-convert/test/kmn-file-writer.tests.ts | 2 +- 5 files changed, 282 insertions(+), 682 deletions(-) diff --git a/developer/src/common/web/utils/src/xml-utils.ts b/developer/src/common/web/utils/src/xml-utils.ts index 765a5b7167..0f73771fb6 100644 --- a/developer/src/common/web/utils/src/xml-utils.ts +++ b/developer/src/common/web/utils/src/xml-utils.ts @@ -6,7 +6,7 @@ * Abstraction for XML reading and writing */ -import { XMLParser, XMLBuilder, XMLMetaData, X2jOptions, XmlBuilderOptions } from 'fast-xml-parser'; +import { XMLParser, XMLBuilder, XMLMetaData, X2jOptions, XmlBuilderOptions,JPathOrMatcher } from 'fast-xml-parser'; import { SymbolUtils } from "./symbol-utils.js"; /** Symbol giving the start offset, in chars, of the node */ @@ -85,8 +85,8 @@ const PARSER_OPTIONS: KeymanXMLParserOptionsBag = { }, 'kvks': { ...PARSER_COMMON_OPTIONS, - tagValueProcessor: (_tagName: string, tagValue: string, _jPath: string, _hasAttributes: boolean, isLeafNode: boolean): string | undefined => { - if (!isLeafNode) { + tagValueProcessor: (_tagName: string, tagValue: string, _jPathOrMatcher: JPathOrMatcher, _hasAttributes: boolean, isLeafNode: boolean) : unknown => { + if (!isLeafNode) { return tagValue?.trim(); // trimmed value } else { return undefined; // no change to leaf nodes diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts index 7b9e98bf61..1bf2318908 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts @@ -135,7 +135,7 @@ export class KeylayoutToKmnConverter { const processedData = await this.convert(jsonO, inputFilename, outputFilename); const kmnFileWriter = new KmnFileWriter(this.callbacks, this.options); -kmnFileWriter.writeToFile((processedData)); + // write to object/ConverterToKmnResult const outputKmn = kmnFileWriter.write(processedData); const result: ConverterToKmnResult = { diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 5c3b4b83b4..79414e2ff6 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -16,59 +16,36 @@ interface MessageCharacter { message: string; character: string; }; -// Todo-kmc-convert edit interface + interface RuleReview { - warningMessage_0: string; - warningMessages_1: string; - warningMessages_2: string; - hasWarning_0: boolean; - hasWarning_1: boolean; - hasWarning_2: boolean; warningMessages: string[]; extraWarning: string; - - type: 'RuleReview' | 'UnavailableModifier' | 'UnavailableSuperior' | + type: 'RuleReview' | 'UnavailableModifier' | 'UnavailableSuperiorRule' | 'DuplicateRule' | 'AmbiguousRule'; - isEarlier: boolean; - isLater: boolean; - isused: boolean; - context: string; - prevDk_id: number; - dk_prefix: string; - prev_dk_prefix: string; + compare_type: string; + earlier_later: [boolean, boolean]; + dk_bothPrefix_prevdk_dk: [string, string];// todo rename to dk_prefix prevDk_modifier: string; prevDk_key: string; - textpart: string; - dk_id: number; + dk_bothId_prevdk_dk: [number, number];// todo rename to dk_id Dk_modifier: string; Dk_key: string; modifier: string; key: string; output: string; - }; interface UnavailableModifier extends RuleReview { type: 'UnavailableModifier'; - isUnavailable: boolean; }; -interface UnavailableSuperior extends RuleReview { - type: 'UnavailableSuperior'; - isUnavailable: boolean; +interface UnavailableSuperiorRule extends RuleReview { + type: 'UnavailableSuperiorRule'; }; interface DuplicateRules extends RuleReview { type: 'DuplicateRule'; - hasExtraWarning: boolean; - isEarlier: boolean; - isLater: boolean; }; interface AmbiguousRules extends RuleReview { type: 'AmbiguousRule'; - hasExtraWarning: boolean; - isEarlier: boolean; - isLater: boolean; - dk_prefix: string; - prev_dk_prefix: string; }; @@ -76,20 +53,6 @@ export class KmnFileWriter { constructor(private callbacks: CompilerCallbacks, private options: CompilerOptions) { }; - // TODO remove - public writeToFile(dataUkelele: ProcessedData): boolean { - - let data: string = "\n"; - - // add top part of kmn file: STORES - data += this.writeKmnFileHeader(dataUkelele); - - // add bottom part of kmn file: RULES - data += this.writeDataRules(dataUkelele); - - this.callbacks.fs.writeFileSync(dataUkelele.kmnFilename, new TextEncoder().encode(data)); - return true; - } /** * @brief member function to write data from object to a Uint8Array * @param dataUkelele the array holding all keyboard data @@ -459,131 +422,134 @@ export class KmnFileWriter { /** * @brief take a child object of RuleReview and return the appropriate warning message * @param inObj : an object containing all data - * @return outMsg the warning message + * @return outMsg the warning message */ - public createWarningText(inObj: RuleReview, pos: number = 2): string[] { - const outMsg: string[] = ['', '', '']; - outMsg[0] = inObj.warningMessages[0]; - outMsg[1] = inObj.warningMessages[1]; - outMsg[2] = inObj.warningMessages[2]; + public createWarningText(inObj: RuleReview, pos: number): string[] { - if (inObj.type === 'AmbiguousRule') { + const outMsg = [...inObj.warningMessages]; - // version for dk 5-5 - if (!inObj.prevDk_modifier && !inObj.prevDk_key - && inObj.Dk_modifier && inObj.Dk_key - && !inObj.modifier && !inObj.key - && (inObj.dk_id !== -1)) { - const position = (inObj.isEarlier ? "earlier" : "later"); - const doubletextpreventer = - ('ambiguous rule: ' + position - + ': dk(' + inObj.dk_prefix - + inObj.dk_id - + ") + [" - + inObj.Dk_modifier - + " " - + inObj.Dk_key - + "] > " - + 'dk(' + inObj.prev_dk_prefix - + inObj.prevDk_id - + ") "); - if (outMsg[pos].indexOf(doubletextpreventer) === -1) - outMsg[pos] += doubletextpreventer; + if (inObj.compare_type === 'unav_C0_C1') { + outMsg[pos] = "unavailable modifier "; + } + + if (inObj.compare_type === 'unav_C2') { + // if the dk is unavailable, the dependant C0 rules and theIr modifiers need to get a warning 'unavailable superior rule ' + if (inObj.Dk_modifier) { + outMsg[1] = "unavailable modifier "; + outMsg[2] = "unavailable superior rule ( [" + + inObj.Dk_modifier + " " + + inObj.Dk_key + + "] > dk(" + + inObj.dk_bothPrefix_prevdk_dk[1] + + inObj.dk_bothId_prevdk_dk[1] + + ") ) : "; } - // version for key with no dk_id amb 6-6 - else if (!inObj.prevDk_modifier && !inObj.prevDk_key - && (inObj.dk_id !== -1) - && inObj.modifier && inObj.key && (inObj.output) - && ((inObj.isEarlier === true /*&& inObj.isLater === true*/))) { - const position = (inObj.isEarlier ? "earlier" : "later"); - outMsg[pos] = inObj.warningMessages[2] - + ('ambiguous rule: ' - + position - + ': dk(' + inObj.dk_prefix - + inObj.dk_id + ") + [" - + inObj.modifier + " " - + inObj.key + "] > \'" - + inObj.output + "\' "); - } - // version for 2_2 2_1 - else if ((!inObj.prevDk_modifier && !inObj.prevDk_key) - && inObj.Dk_modifier && inObj.Dk_key - && (inObj.dk_id !== -1)) { - const position = (inObj.isEarlier ? "earlier" : "later"); - const doubletextpreventer = - ("ambiguous rule: " - + position + ": [" - + inObj.Dk_modifier + " " - + inObj.Dk_key + "] > dk(" + inObj.dk_prefix - + inObj.dk_id + ") "); - if (outMsg[pos].indexOf(doubletextpreventer) === -1) - outMsg[pos] += doubletextpreventer; - } - - // version for dk 4-4 2-4 - else if (inObj.Dk_modifier && inObj.Dk_key - && (inObj.dk_id !== -1) - && !inObj.modifier && !inObj.key) { - const position = (inObj.isEarlier ? "earlier" : "later"); - const doubletextpreventer = - ("ambiguous rule: " - + position + ": [" - + inObj.prevDk_modifier + " " - + inObj.prevDk_key + "] > dk(" + inObj.prev_dk_prefix - + inObj.prevDk_id + ") "); - if (outMsg[pos].indexOf(doubletextpreventer) === -1) - outMsg[pos] += doubletextpreventer; - } - - - // version for prev dk // 4_1 4_2 - else if (inObj.prevDk_modifier && inObj.prevDk_key && (inObj.prevDk_id !== -1)) { - const position = (inObj.isEarlier ? "earlier" : "later"); - const doubletextpreventer = - ("ambiguous rule: " - + position + ": [" - + inObj.prevDk_modifier + " " - + inObj.prevDk_key + "] > dk(" + inObj.prev_dk_prefix - + inObj.prevDk_id + ") "); - if (outMsg[pos].indexOf(doubletextpreventer) === -1) - outMsg[pos] += doubletextpreventer; - } - - // version for dk 6-3 or 3-3 - else if (!inObj.prevDk_modifier && !inObj.prevDk_key - && !inObj.Dk_modifier && !inObj.Dk_key - && (inObj.dk_id !== -1) - ) { - const position = (inObj.isEarlier ? "earlier" : "later"); - const doubletextpreventer = - ('ambiguous rule: ' + - position - + ': dk(' + inObj.dk_prefix - + inObj.dk_id + ") + [" - + inObj.modifier + " " - + inObj.key + "] > \'" - + inObj.output + "\' "); - if (outMsg[pos].indexOf(doubletextpreventer) === -1) - outMsg[pos] += doubletextpreventer; - } - - // version for key with no dk_id amb 1-1 - else if (inObj.modifier && inObj.key - && (inObj.output) - && (inObj.dk_id === -1) - && ((inObj.isEarlier === true /*&& inObj.isLater === true*/))) { - const position = (inObj.isEarlier ? "earlier" : "later"); - outMsg[pos] = inObj.warningMessages[2] - + ("ambiguous rule: " - + position + - ": [" - + inObj.modifier + " " - + inObj.key + "] > \'" - + inObj.output - + "\' "); + if (inObj.modifier) { + outMsg[2] = "unavailable modifier "; } } + + if (inObj.compare_type === 'unav_C3') { + + // if the dk is unavailable, the dependant C0 rules and theIr modifiers need to get a warning 'unavailable superior rule ' + if (inObj.prevDk_modifier) { + outMsg[0] = "unavailable modifier "; + outMsg[1] = "unavailable superior rule ( [" + + inObj.prevDk_modifier + " " + + inObj.prevDk_key + + "] > dk(" + + inObj.dk_bothPrefix_prevdk_dk[1] + + inObj.dk_bothId_prevdk_dk[1] + + ") ) : "; + } + + + // if the dk is unavailable, the dependant C0 rules and theIr modifiers need to get a warning 'unavailable superior rule ' + if (inObj.Dk_modifier) { + outMsg[1] += "unavailable modifier "; + outMsg[2] = "unavailable superior rule ( [" + + inObj.Dk_modifier + " " + + inObj.Dk_key + + "] > dk(" + + inObj.dk_bothPrefix_prevdk_dk[1] + + inObj.dk_bothId_prevdk_dk[1] + + ") ) : "; + } + + if (inObj.modifier) { + outMsg[2] = "unavailable modifier "; + } + } + + if (inObj.compare_type === 'amb_1_1' || inObj.compare_type === 'dup_1_1') { + + outMsg[pos] = inObj.warningMessages[2] + + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " + + (inObj.earlier_later[0] ? "earlier" : "later") + + ": [" + inObj.modifier + " " + inObj.key + "] > \'" + + inObj.output + "\' "; + } + + + if (inObj.compare_type === 'amb_2_2' || inObj.compare_type === 'dup_2_2' + || inObj.compare_type === 'amb_2_1' + || inObj.compare_type === 'amb_2_4') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " + + (inObj.earlier_later[0] ? "earlier" : "later") + + ": [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > dk(" + + inObj.dk_bothPrefix_prevdk_dk[1] + inObj.dk_bothId_prevdk_dk[1] + ") "); + + if (outMsg[pos].indexOf(textsegment) === -1) + outMsg[pos] += textsegment; + } + + + if (inObj.compare_type === 'amb_4_4' || inObj.compare_type === 'dup_4_4' + || inObj.compare_type === 'amb_4_1' + || inObj.compare_type === 'amb_4_2') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " + + (inObj.earlier_later[0] ? "earlier" : "later") + ": [" + + inObj.prevDk_modifier + " " + inObj.prevDk_key + "] > dk(" + + inObj.dk_bothPrefix_prevdk_dk[0] + inObj.dk_bothId_prevdk_dk[0] + ") "); + + if (outMsg[pos].indexOf(textsegment) === -1) + outMsg[pos] += textsegment; + } + + + if (inObj.compare_type === 'amb_5_5' || inObj.compare_type === 'dup_5_5') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.earlier_later[0] ? "earlier" : "later") + + ': dk(' + inObj.dk_bothPrefix_prevdk_dk[1] + inObj.dk_bothId_prevdk_dk[1] + ") + [" + + inObj.Dk_modifier + " " + inObj.Dk_key + "] > " + + 'dk(' + inObj.dk_bothPrefix_prevdk_dk[0] + inObj.dk_bothId_prevdk_dk[0] + ") "); + + if (outMsg[pos].indexOf(textsegment) === -1) + outMsg[pos] += textsegment; + } + + + if (inObj.compare_type === 'amb_6_3' || inObj.compare_type === 'dup_6_3' + || inObj.compare_type === 'amb_3_3' || inObj.compare_type === 'dup_3_3' + || inObj.compare_type === 'amb_6_6' || inObj.compare_type === 'dup_6_6') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.earlier_later[0] ? "earlier" : "later") + + ': dk(' + inObj.dk_bothPrefix_prevdk_dk[1] + inObj.dk_bothId_prevdk_dk[1] + ") + [" + + inObj.modifier + " " + inObj.key + "] > \'" + inObj.output + "\' "); + + if (outMsg[pos].indexOf(textsegment) === -1) + outMsg[pos] += textsegment; + } + return outMsg; } @@ -598,63 +564,23 @@ export class KmnFileWriter { */ public reviewRules(rule: Rule[], index: number): string[] { - const resultWarnings: RuleReview = { - - warningMessage_0: '', - warningMessages_1: '', - warningMessages_2: '', - hasWarning_0: false, - hasWarning_1: false, - hasWarning_2: false, - - type: 'RuleReview', - isused: false, - isEarlier: false, - isLater: false, - context: '', - prevDk_id: -1, - prevDk_modifier: '', - dk_prefix: "A", - prev_dk_prefix: "C", - prevDk_key: '', - textpart: '', - dk_id: -1, - Dk_modifier: '', - Dk_key: '', - modifier: '', - key: '', - output: '', - warningMessages: ['', '', ''], - - extraWarning: 'PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN !', - }; - const unavailableModiWarnings = { type: 'UnavailableModifier', - isUnavailable: true, warningMessages: ['', '', ''], } as UnavailableModifier; const unavailableSuperiWarnings = { - type: 'UnavailableSuperior', - isUnavailable: true, + type: 'UnavailableSuperiorRule', warningMessages: ['', '', ''], - } as UnavailableSuperior; + } as UnavailableSuperiorRule; const duplicateWarnings = { type: 'DuplicateRule', - isLater: false, - isEarlier: false, - hasExtraWarning: false, warningMessages: ['', '', ''], } as DuplicateRules; - const ambiguousWarnings = { type: 'AmbiguousRule', - isEarlier: false, - isLater: false, - hasExtraWarning: false, warningMessages: ['', '', ''], } as AmbiguousRules; @@ -665,134 +591,56 @@ export class KmnFileWriter { if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier "; - - unavailableModiWarnings.isused = true; - unavailableModiWarnings.modifier = rule[index].modifierKey; - unavailableModiWarnings.key = rule[index].key; - unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); - unavailableModiWarnings.warningMessages[2] = "unavailable modifier "; + unavailableModiWarnings.compare_type = 'unav_C0_C1'; + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings, 2); } } + + else if (rule[index].ruleType === "C2") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier "; - warningText[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(A" - + rule[index].idDeadkey - + ") ) : "; - - unavailableModiWarnings.isused = true; - unavailableSuperiWarnings.isused = true; - - unavailableModiWarnings.textpart = '] > dk(A'; - unavailableModiWarnings.Dk_modifier = rule[index].modifierDeadkey; - unavailableModiWarnings.Dk_key = rule[index].deadkey; - unavailableModiWarnings.modifier = rule[index].modifierKey; - unavailableModiWarnings.key = rule[index].key; - unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); - - unavailableModiWarnings.warningMessages[1] = "unavailable modifier "; - unavailableSuperiWarnings.warningMessages[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(A" - + rule[index].idDeadkey - + ") ) : "; + unavailableSuperiWarnings.compare_type = 'unav_C2'; + unavailableSuperiWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; + unavailableSuperiWarnings.dk_bothId_prevdk_dk = [rule[0].idPrevDeadkey, rule[0].idDeadkey]; + unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableSuperiWarnings.Dk_key = rule[index].deadkey; + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier "; - unavailableModiWarnings.isused = true; - unavailableModiWarnings.prevDk_key = rule[index].prevDeadkey; - unavailableModiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - unavailableModiWarnings.Dk_modifier = rule[index].modifierDeadkey; - unavailableModiWarnings.Dk_key = rule[index].deadkey; + unavailableModiWarnings.compare_type = 'unav_C2'; unavailableModiWarnings.modifier = rule[index].modifierKey; unavailableModiWarnings.key = rule[index].key; - unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); - unavailableModiWarnings.warningMessages[2] = "unavailable modifier "; + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings, 2); } } + else if (rule[index].ruleType === "C3") { - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierPrevDeadkey)) { - warningText[0] = "unavailable modifier "; - warningText[1] = "unavailable superior rule ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) : "; - warningText[2] = "unavailable superior rules ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) "; - - - unavailableSuperiWarnings.warningMessages[0] = "unavailable modifier "; - unavailableSuperiWarnings.warningMessages[1] = "unavailable superior rule ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) : "; - unavailableSuperiWarnings.warningMessages[2] = "unavailable superior rules ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) "; + unavailableSuperiWarnings.compare_type = 'unav_C3'; + unavailableSuperiWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; + unavailableSuperiWarnings.dk_bothId_prevdk_dk = [rule[0].idPrevDeadkey, rule[0].idDeadkey]; + unavailableSuperiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + unavailableSuperiWarnings.prevDk_key = rule[index].prevDeadkey; + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier "; - warningText[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; - - unavailableModiWarnings.isused = true; - unavailableSuperiWarnings.isused = true; - unavailableModiWarnings.prevDk_key = rule[index].prevDeadkey; - unavailableModiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - - unavailableSuperiWarnings.textpart = '] > dk(B'; + unavailableSuperiWarnings.compare_type = 'unav_C3'; + unavailableSuperiWarnings.prevDk_modifier = ''; + unavailableSuperiWarnings.dk_bothPrefix_prevdk_dk = ['', 'B']; + unavailableSuperiWarnings.dk_bothId_prevdk_dk = [rule[0].idPrevDeadkey, rule[0].idDeadkey]; unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; unavailableSuperiWarnings.Dk_key = rule[index].deadkey; - unavailableSuperiWarnings.modifier = rule[index].modifierKey; - unavailableSuperiWarnings.key = rule[index].key; - unavailableSuperiWarnings.output = new TextDecoder().decode(rule[index].output); - unavailableSuperiWarnings.warningMessages[1] = unavailableSuperiWarnings.warningMessages[1] - + "unavailable modifier "; - unavailableSuperiWarnings.warningMessages[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] += "unavailable modifier "; - - unavailableModiWarnings.isused = true; - unavailableModiWarnings.prevDk_key = rule[index].prevDeadkey; - unavailableModiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - unavailableModiWarnings.Dk_modifier = rule[index].modifierDeadkey; - unavailableModiWarnings.Dk_key = rule[index].deadkey; + unavailableModiWarnings.compare_type = 'unav_C3'; unavailableModiWarnings.modifier = rule[index].modifierKey; unavailableModiWarnings.key = rule[index].key; - unavailableModiWarnings.output = new TextDecoder().decode(rule[index].output); - unavailableModiWarnings.warningMessages[2] += "unavailable modifier "; - + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings, 2); } } @@ -840,84 +688,45 @@ export class KmnFileWriter { ); if (amb_4_1.length > 0) { - ambiguousWarnings.prevDk_id = amb_4_1[0].idPrevDeadkey; - ambiguousWarnings.prevDk_key = amb_4_1[0].prevDeadkey; + ambiguousWarnings.compare_type = 'amb_4_1'; + ambiguousWarnings.earlier_later = [false, true]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_4_1[0].idPrevDeadkey, amb_4_1[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_1[0].modifierPrevDeadkey; - - ambiguousWarnings.isEarlier = false; - ambiguousWarnings.isLater = true; - ambiguousWarnings.modifier = amb_4_1[0].modifierKey; - ambiguousWarnings.key = amb_4_1[0].key; - ambiguousWarnings.prev_dk_prefix = 'C'; - ambiguousWarnings.dk_prefix = 'A'; - const tester_amb_4_1 = this.createWarningText(ambiguousWarnings); - ambiguousWarnings.warningMessages = tester_amb_4_1; + ambiguousWarnings.prevDk_key = amb_4_1[0].prevDeadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (amb_2_1.length > 0) { - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - ambiguousWarnings.textpart = '] > dk(A'; - - ambiguousWarnings.prevDk_id = amb_2_1[0].idPrevDeadkey; - ambiguousWarnings.prevDk_modifier = amb_2_1[0].modifierPrevDeadkey; - ambiguousWarnings.prevDk_key = amb_2_1[0].prevDeadkey; - - ambiguousWarnings.dk_id = amb_2_1[0].idDeadkey; + ambiguousWarnings.compare_type = 'amb_2_1'; + ambiguousWarnings.earlier_later = [false, true]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_2_1[0].idPrevDeadkey, amb_2_1[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_1[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_1[0].deadkey; - - ambiguousWarnings.modifier = amb_2_1[0].modifierKey; - ambiguousWarnings.key = amb_2_1[0].key; - ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_2_1[0].output)).character; - - ambiguousWarnings.prev_dk_prefix = 'C'; - ambiguousWarnings.dk_prefix = 'A'; - ambiguousWarnings.isEarlier = false; - ambiguousWarnings.isLater = true; - const tester_amb_2_1 = this.createWarningText(ambiguousWarnings); - ambiguousWarnings.warningMessages = tester_amb_2_1; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (amb_1_1.length > 0) { - ambiguousWarnings.prevDk_id = amb_1_1[0].idPrevDeadkey; - ambiguousWarnings.prevDk_modifier = amb_1_1[0].modifierPrevDeadkey; - ambiguousWarnings.prevDk_key = amb_1_1[0].prevDeadkey; - - ambiguousWarnings.dk_id = -1;// needed!!! - ambiguousWarnings.prevDk_id = -1;// needed!!! - ambiguousWarnings.Dk_modifier = amb_1_1[0].modifierDeadkey; - ambiguousWarnings.Dk_key = amb_1_1[0].deadkey; - - ambiguousWarnings.prev_dk_prefix = 'C'; - ambiguousWarnings.dk_prefix = 'A'; + ambiguousWarnings.compare_type = 'amb_1_1'; + ambiguousWarnings.earlier_later = [true, false]; ambiguousWarnings.modifier = amb_1_1[0].modifierKey; ambiguousWarnings.key = amb_1_1[0].key; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character; - ambiguousWarnings.isEarlier = true; ambiguousWarnings.isLater = false; - const tester_amb_1_1 = this.createWarningText(ambiguousWarnings, 2); - ambiguousWarnings.warningMessages = tester_amb_1_1; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (dup_1_1.length > 0) { - resultWarnings.type = 'RuleReview'; - duplicateWarnings.isused = true; - duplicateWarnings.textpart = '] > \''; + duplicateWarnings.compare_type = 'dup_1_1'; + duplicateWarnings.earlier_later = [true, false]; duplicateWarnings.modifier = dup_1_1[0].modifierKey; duplicateWarnings.key = dup_1_1[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character; - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[2] = duplicateWarnings.warningMessages[2] - + ("duplicate rule: earlier: [" - + dup_1_1[0].modifierKey - + " " - + dup_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character - + "\' "); + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 2); } } + if (rule[index].ruleType === "C2") { // 2-2: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C3) @@ -968,104 +777,59 @@ export class KmnFileWriter { ); if (amb_2_2.length > 0) { - ambiguousWarnings.isEarlier = true; - ambiguousWarnings.isLater = false; - ambiguousWarnings.prev_dk_prefix = 'A'; - ambiguousWarnings.dk_prefix = 'C'; - ambiguousWarnings.dk_id = amb_2_2[0].idDeadkey; + ambiguousWarnings.compare_type = 'amb_2_2'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_2_2[0].idPrevDeadkey, amb_2_2[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_2[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_2[0].deadkey; - ambiguousWarnings.modifier = amb_2_2[0].modifierKey; - ambiguousWarnings.key = amb_2_2[0].key; - const tester_amb_2_2 = this.createWarningText(ambiguousWarnings, 1); - ambiguousWarnings.warningMessages = tester_amb_2_2; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); } if (dup_2_2.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - duplicateWarnings.textpart = '] > dk(C'; - duplicateWarnings.dk_id = dup_2_2[0].idDeadkey; + duplicateWarnings.compare_type = 'dup_2_2'; + duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; + duplicateWarnings.dk_bothId_prevdk_dk = [dup_2_2[0].idPrevDeadkey, dup_2_2[0].idDeadkey]; duplicateWarnings.Dk_modifier = dup_2_2[0].modifierDeadkey; duplicateWarnings.Dk_key = dup_2_2[0].deadkey; - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[1] = duplicateWarnings.warningMessages[1] - + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); } if (amb_3_3.length > 0) { - ambiguousWarnings.dk_prefix = 'A'; - ambiguousWarnings.dk_id = amb_3_3[0].idDeadkey; + ambiguousWarnings.compare_type = 'amb_3_3'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'A']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_3_3[0].idPrevDeadkey, amb_3_3[0].idDeadkey]; ambiguousWarnings.modifier = amb_3_3[0].modifierKey; ambiguousWarnings.key = amb_3_3[0].key; - ambiguousWarnings.isEarlier = true; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character; - const tester_amb_3_3 = this.createWarningText(ambiguousWarnings, 2); - ambiguousWarnings.warningMessages = tester_amb_3_3; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (dup_3_3.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: dk(A" - + dup_3_3[0].idDeadkey - + ") + [" - + dup_3_3[0].modifierKey - + " " - + dup_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character - + "\' "); - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - duplicateWarnings.textpart = '] > \''; - duplicateWarnings.dk_id = dup_3_3[0].idDeadkey; + duplicateWarnings.compare_type = 'dup_3_3'; + duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.dk_bothId_prevdk_dk = [dup_3_3[0].idPrevDeadkey, dup_3_3[0].idDeadkey]; + duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'A']; duplicateWarnings.modifier = dup_3_3[0].modifierKey; duplicateWarnings.key = dup_3_3[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character; - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[2] = duplicateWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(A" - + dup_3_3[0].idDeadkey - + ") + [" - + dup_3_3[0].modifierKey - + " " - + dup_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character - + "\' "); - + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 2); } if (amb_4_2.length > 0) { - - ambiguousWarnings.prevDk_id = amb_4_2[0].idPrevDeadkey; - ambiguousWarnings.prevDk_key = amb_4_2[0].prevDeadkey; + ambiguousWarnings.compare_type = 'amb_4_2'; + ambiguousWarnings.earlier_later = [false, true]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', '']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_4_2[0].idPrevDeadkey, amb_4_2[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_2[0].modifierPrevDeadkey; - ambiguousWarnings.prev_dk_prefix = 'C'; - ambiguousWarnings.dk_prefix = 'A'; - ambiguousWarnings.modifier = amb_4_2[0].modifierKey; - ambiguousWarnings.key = amb_4_2[0].key; - ambiguousWarnings.isLater = true; - const tester_amb_4_2 = this.createWarningText(ambiguousWarnings, 0); - ambiguousWarnings.warningMessages = tester_amb_4_2; + ambiguousWarnings.prevDk_key = amb_4_2[0].prevDeadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); } } + if (rule[index].ruleType === "C3") { // 2-4 + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(B11) @@ -1148,213 +912,106 @@ export class KmnFileWriter { ); // 6-6 dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'Ã' - const dup_6_6 = - rule.filter((curr, idx) => - (curr.ruleType === "C3") - && curr.idDeadkey === rule[index].idDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && (new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output)) - && idx < index - ); + const dup_6_6 = rule.filter((curr, idx) => + (curr.ruleType === "C3") + && curr.idDeadkey === rule[index].idDeadkey + && curr.modifierKey === rule[index].modifierKey + && curr.key === rule[index].key + && (new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output)) + && idx < index + ); if (amb_2_4.length > 0) { - - ambiguousWarnings.prev_dk_prefix = 'C'; - ambiguousWarnings.dk_prefix = 'A'; - ambiguousWarnings.dk_id = amb_2_4[0].idDeadkey; + ambiguousWarnings.compare_type = 'amb_2_4'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'A']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_2_4[0].idPrevDeadkey, amb_2_4[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_4[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_4[0].deadkey; - ambiguousWarnings.modifier = amb_2_4[0].modifierKey; - ambiguousWarnings.key = amb_2_4[0].key; - ambiguousWarnings.isEarlier = true; - const tester_amb_2_4 = this.createWarningText(ambiguousWarnings, 0); - ambiguousWarnings.warningMessages = tester_amb_2_4; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); } if (amb_6_3.length > 0) { - ambiguousWarnings.dk_prefix = 'C'; - ambiguousWarnings.dk_id = amb_6_3[0].idDeadkey; + ambiguousWarnings.compare_type = 'amb_6_3'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_6_3[0].idPrevDeadkey, amb_6_3[0].idDeadkey]; ambiguousWarnings.modifier = amb_6_3[0].modifierKey; ambiguousWarnings.key = amb_6_3[0].key; - ambiguousWarnings.isEarlier = true; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character; - const tester_amb_6_3 = this.createWarningText(ambiguousWarnings, 1); - ambiguousWarnings.warningMessages = tester_amb_6_3; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); } if (dup_6_3.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: dk(C" - + dup_6_3[0].idDeadkey - + ") + [" - + dup_6_3[0].modifierKey - + " " - + dup_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character - + "\' "); - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - ambiguousWarnings.textpart = ''; - ambiguousWarnings.dk_id = dup_6_3[0].idDeadkey; + duplicateWarnings.compare_type = 'dup_6_3'; + duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; + duplicateWarnings.dk_bothId_prevdk_dk = [dup_6_3[0].idPrevDeadkey, dup_6_3[0].idDeadkey]; duplicateWarnings.modifier = dup_6_3[0].modifierKey; duplicateWarnings.key = dup_6_3[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character; - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[1] = duplicateWarnings.warningMessages[1] - + ("duplicate rule: earlier: dk(C" - + dup_6_3[0].idDeadkey - + ") + [" - + dup_6_3[0].modifierKey - + " " - + dup_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character - + "\' "); + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); } if (amb_4_4.length > 0) { - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - ambiguousWarnings.textpart = '] > dk(C'; - ambiguousWarnings.prevDk_id = amb_4_4[0].idPrevDeadkey; - resultWarnings.prevDk_key = amb_4_4[0].prevDeadkey; - resultWarnings.prevDk_modifier = amb_4_4[0].modifierPrevDeadkey; - ambiguousWarnings.isEarlier = true; - ambiguousWarnings.prev_dk_prefix = 'C'; - ambiguousWarnings.dk_prefix = 'C'; - ambiguousWarnings.dk_id = amb_4_4[0].idDeadkey; - ambiguousWarnings.Dk_modifier = amb_4_4[0].modifierDeadkey; - ambiguousWarnings.Dk_key = amb_4_4[0].deadkey; - const tester_amb_4_4 = this.createWarningText(ambiguousWarnings, 0); - ambiguousWarnings.warningMessages = tester_amb_4_4; - + ambiguousWarnings.compare_type = 'amb_4_4'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', '']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_4_4[0].idPrevDeadkey, amb_4_4[0].idDeadkey]; + ambiguousWarnings.prevDk_modifier = amb_4_4[0].modifierPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_4_4[0].prevDeadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); } if (dup_4_4.length > 0) { - warningText[0] = warningText[0] - + ("duplicate rule: earlier: [" - + dup_4_4[0].modifierPrevDeadkey - + " " - + dup_4_4[0].prevDeadkey - + "] > dk(C" - + dup_4_4[0].idPrevDeadkey - + ") "); - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDk_key = rule[index].prevDeadkey; - resultWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.Dk_modifier = rule[index].modifierDeadkey; - resultWarnings.Dk_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[0] = duplicateWarnings.warningMessages[0] + ("duplicate rule: earlier: [" - + dup_4_4[0].modifierPrevDeadkey - + " " - + dup_4_4[0].prevDeadkey - + "] > dk(C" - + dup_4_4[0].idPrevDeadkey - + ") "); + duplicateWarnings.compare_type = 'dup_4_4'; + duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.dk_bothPrefix_prevdk_dk = ['C', '']; + duplicateWarnings.dk_bothId_prevdk_dk = [dup_4_4[0].idPrevDeadkey, dup_4_4[0].idDeadkey]; + duplicateWarnings.prevDk_modifier = dup_4_4[0].modifierPrevDeadkey; + duplicateWarnings.prevDk_key = dup_4_4[0].prevDeadkey; + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 0); } if (amb_5_5.length > 0) { - ambiguousWarnings.warningMessages[2] = ''; - ambiguousWarnings.prevDk_id = amb_5_5[0].idPrevDeadkey; - ambiguousWarnings.prev_dk_prefix = 'B'; - ambiguousWarnings.dk_prefix = 'B'; - ambiguousWarnings.dk_id = amb_5_5[0].idDeadkey; + ambiguousWarnings.compare_type = 'amb_5_5'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['B', 'B']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_5_5[0].idPrevDeadkey, amb_5_5[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_5_5[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_5_5[0].deadkey; - ambiguousWarnings.isEarlier = true; - const tester_amb_5_5 = this.createWarningText(ambiguousWarnings, 1); - ambiguousWarnings.warningMessages = tester_amb_5_5; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); } if (dup_5_5.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: dk(B" - + dup_5_5[0].idPrevDeadkey - + ") + [" - + dup_5_5[0].modifierDeadkey - + " " - + dup_5_5[0].deadkey - + "] > dk(B" - + dup_5_5[0].idDeadkey - + ") "); - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDk_key = rule[index].prevDeadkey; - resultWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.Dk_modifier = rule[index].modifierDeadkey; - resultWarnings.Dk_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[1] = duplicateWarnings.warningMessages[1] + ("duplicate rule: earlier: dk(B" - + dup_5_5[0].idPrevDeadkey - + ") + [" - + dup_5_5[0].modifierDeadkey - + " " - + dup_5_5[0].deadkey - + "] > dk(B" - + dup_5_5[0].idDeadkey - + ") "); - + duplicateWarnings.compare_type = 'dup_5_5'; + duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.dk_bothPrefix_prevdk_dk = ['B', 'B']; + duplicateWarnings.Dk_modifier = rule[index].modifierDeadkey; + duplicateWarnings.Dk_key = rule[index].deadkey; + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); } if (amb_6_6.length > 0) { - ambiguousWarnings.isused = true; - ambiguousWarnings.dk_id = amb_6_6[0].idDeadkey;// needed!!! - ambiguousWarnings.Dk_modifier = amb_6_6[0].modifierDeadkey; - ambiguousWarnings.Dk_key = amb_6_6[0].deadkey; + ambiguousWarnings.compare_type = 'amb_6_6'; + ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'B']; + ambiguousWarnings.dk_bothId_prevdk_dk = [amb_6_6[0].idPrevDeadkey, amb_6_6[0].idDeadkey]; ambiguousWarnings.modifier = amb_6_6[0].modifierKey; ambiguousWarnings.key = amb_6_6[0].key; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character; - ambiguousWarnings.isEarlier = true; - ambiguousWarnings.dk_prefix = 'B'; - const tester_amb_6_6 = this.createWarningText(ambiguousWarnings); - ambiguousWarnings.warningMessages = tester_amb_6_6; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (dup_6_6.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: dk(B" - + dup_6_6[0].idDeadkey - + ") + [" - + dup_6_6[0].modifierKey - + " " - + dup_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character - + "\' "); - - resultWarnings.type = 'RuleReview'; - resultWarnings.isused = true; - resultWarnings.prevDk_key = rule[index].prevDeadkey; - resultWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; - resultWarnings.Dk_modifier = rule[index].modifierDeadkey; - resultWarnings.Dk_key = rule[index].deadkey; - resultWarnings.modifier = rule[index].modifierKey; - resultWarnings.key = rule[index].key; - resultWarnings.output = new TextDecoder().decode(rule[index].output); - duplicateWarnings.isEarlier = true; - duplicateWarnings.warningMessages[2] = duplicateWarnings.warningMessages[2] + ("duplicate rule: earlier: dk(B" - + dup_6_6[0].idDeadkey - + ") + [" - + dup_6_6[0].modifierKey - + " " - + dup_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character - + "\' "); + duplicateWarnings.compare_type = 'dup_6_6'; + duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'B']; + duplicateWarnings.dk_bothId_prevdk_dk = [dup_6_6[0].idPrevDeadkey, dup_6_6[0].idDeadkey]; + duplicateWarnings.modifier = dup_6_6[0].modifierKey; + duplicateWarnings.key = dup_6_6[0].key; + duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character; + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 2); } } @@ -1367,60 +1024,25 @@ export class KmnFileWriter { const extraWarning = "PLEASE CHECK THAT RULE AS IT WILL NOT BE WRITTEN !"; - - /* - if ((warningText[0].indexOf("earlier:") > 0) && (warningText[0].indexOf("later:") > 0)) { - warningText[0] = warningText[0] + extraWarning; - } - */ - if (ambiguousWarnings.warningMessages[0]) { - if ((ambiguousWarnings.warningMessages[0].indexOf("earlier:") > 0) && (ambiguousWarnings.warningMessages[0].indexOf("later:") > 0)) { - ambiguousWarnings.warningMessages[0] = ambiguousWarnings.warningMessages[0] + extraWarning; + for (let i = 0; i < 3; i++) { + if (ambiguousWarnings.warningMessages[i] !== "") { + if ((ambiguousWarnings.warningMessages[i].indexOf("earlier:") > -1) && (ambiguousWarnings.warningMessages[i].indexOf("later:") > -1)) { + ambiguousWarnings.warningMessages[i] = ambiguousWarnings.warningMessages[i] + extraWarning; + } } } - /* - if ((warningText[1].indexOf("earlier:") > 0) && (warningText[1].indexOf("later:") > 0)) { - warningText[1] = warningText[1] + extraWarning; - } - */ - if (ambiguousWarnings.warningMessages[1] !== "") { - if ((ambiguousWarnings.warningMessages[1].indexOf("earlier:") > 0) && (ambiguousWarnings.warningMessages[1].indexOf("later:") > 0)) { - ambiguousWarnings.warningMessages[1] = ambiguousWarnings.warningMessages[1] + extraWarning; - } + for (let i = 0; i < 3; i++) { + const completeWarning = + unavailableSuperiWarnings.warningMessages[i] + + duplicateWarnings.warningMessages[i] + + ambiguousWarnings.warningMessages[i] + + unavailableModiWarnings.warningMessages[i]; + + completeWarning ? (warningText[i] = "c WARNING: " + completeWarning + " here: ") : warningText[i] = ''; + } - /* if ((warningText[2].indexOf("earlier:") > 0) && (warningText[2].indexOf("later:") > 0)) { - warningText[2] = warningText[2] + extraWarning; - } - */ - if (ambiguousWarnings.warningMessages[2] !== "") { - if ((ambiguousWarnings.warningMessages[2].indexOf("earlier:") > 0) && (ambiguousWarnings.warningMessages[2].indexOf("later:") > 0)) { - ambiguousWarnings.warningMessages[2] = ambiguousWarnings.warningMessages[2] + extraWarning; - } - } - - const completeWarning0 = unavailableSuperiWarnings.warningMessages[0] - + duplicateWarnings.warningMessages[0] - + ambiguousWarnings.warningMessages[0] - + unavailableModiWarnings.warningMessages[0]; - - const completeWarning1 = unavailableSuperiWarnings.warningMessages[1] - + duplicateWarnings.warningMessages[1] - + ambiguousWarnings.warningMessages[1] - + unavailableModiWarnings.warningMessages[1]; - - const completeWarning2 = unavailableSuperiWarnings.warningMessages[2] - + duplicateWarnings.warningMessages[2] - + ambiguousWarnings.warningMessages[2] - + unavailableModiWarnings.warningMessages[2]; - - completeWarning0 ? (warningText[0] = "c WARNING: " + completeWarning0 + " here: ") : warningText[0] = ''; - completeWarning1 ? (warningText[1] = "c WARNING: " + completeWarning1 + " here: ") : warningText[1] = ''; - completeWarning2 ? (warningText[2] = "c WARNING: " + completeWarning2 + " here: ") : warningText[2] = ''; - - - return warningText; } diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 628142d10c..54b2c3d3ae 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -20,28 +20,6 @@ describe('KeylayoutToKmnConverter', function () { before(function () { compilerTestCallbacks.clear(); }); -describe('RunFILES', function () { - this.timeout(10000); // allow longer time for these tests - const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); - [ - [makePathToFixture('../data/Polish.keylayout')], - [makePathToFixture('../data/Spanish.keylayout')], - [makePathToFixture('../data/French.keylayout')], - // [makePathToFixture('../data/German_complete_reduced.keylayout')], - // [makePathToFixture('../data/German_standard.keylayout')], - [makePathToFixture('../data/Italian_command.keylayout')], - [makePathToFixture('../data/Italian.keylayout')], - [makePathToFixture('../data/Latin_American.keylayout')], - [makePathToFixture('../data/Swiss_French.keylayout')], - [makePathToFixture('../data/Swiss_German.keylayout')], - [makePathToFixture('../data/US.keylayout')], - ].forEach(function (files) { - it(files + " should give no errors ", async function () { - sut.run(files[0]); - assert.isTrue(compilerTestCallbacks.messages.length === 0); - }); - }); - }); describe('RunSpecialTestFiles', function () { const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index d3d19abbe8..7857ae2765 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -329,7 +329,7 @@ describe('KmnFileWriter', function () { ], [''], [''], - ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! here: "]], + ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' PLEASE CHECK THAT RULE AS IT WILL NOT BE WRITTEN ! here: "]], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "') + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 2); From e7db3742027f4c2be38176cd24dd4824b075d1e0 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 25 Jun 2026 16:35:15 +0200 Subject: [PATCH 23/33] feat(developer): createWarningTextbrush up e.g. rename variables --- .../src/common/web/utils/src/xml-utils.ts | 2 +- .../src/keylayout-to-kmn/kmn-file-writer.ts | 153 +++++++++--------- 2 files changed, 82 insertions(+), 73 deletions(-) diff --git a/developer/src/common/web/utils/src/xml-utils.ts b/developer/src/common/web/utils/src/xml-utils.ts index 0f73771fb6..cfe42987dd 100644 --- a/developer/src/common/web/utils/src/xml-utils.ts +++ b/developer/src/common/web/utils/src/xml-utils.ts @@ -6,7 +6,7 @@ * Abstraction for XML reading and writing */ -import { XMLParser, XMLBuilder, XMLMetaData, X2jOptions, XmlBuilderOptions,JPathOrMatcher } from 'fast-xml-parser'; +import { XMLParser, XMLBuilder, XMLMetaData, X2jOptions, XmlBuilderOptions, JPathOrMatcher } from 'fast-xml-parser'; import { SymbolUtils } from "./symbol-utils.js"; /** Symbol giving the start offset, in chars, of the node */ diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 79414e2ff6..82fc86cf39 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -24,10 +24,12 @@ interface RuleReview { 'DuplicateRule' | 'AmbiguousRule'; compare_type: string; earlier_later: [boolean, boolean]; - dk_bothPrefix_prevdk_dk: [string, string];// todo rename to dk_prefix + // dk_id[0]: prev_dk; dk_id[1]: dk; + dk_id: [number, number]; + // dk_prefix[0]: prev_dk_prefix; dk_prefix[1]: dk_prefix; + dk_prefix: [string, string]; prevDk_modifier: string; prevDk_key: string; - dk_bothId_prevdk_dk: [number, number];// todo rename to dk_id Dk_modifier: string; Dk_key: string; modifier: string; @@ -241,7 +243,6 @@ export class KmnFileWriter { // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character let versionOutputCharacter; const warnText = this.reviewRules(uniqueDataRules, k); - const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); @@ -420,28 +421,34 @@ export class KmnFileWriter { } /** - * @brief take a child object of RuleReview and return the appropriate warning message - * @param inObj : an object containing all data - * @return outMsg the warning message + * @brief take a child object of RuleReview and return the appropriate warning message array + * @param inObj : an object containing filtered data for a specified comparison + * @param posWarning : index specifying to which element of the warning message array a warning message will be added: + * outMsg[0]: Warning for part 1 of a rule (e.g. modifier_prev_dk + key_prev_dk > prev_dk) + * outMsg[1]: Warning for part 2 of a rule (e.g. (prev_dk +) modifier_dk + key_dk > dk) + * outMsg[2]: Warning for part 3 of a rule (e.g. (dk +) modifier+key > output) + * see here on parts of a rule: + * https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.16sx096j6jmy + * @return outMsg the warning message array for all parts */ - public createWarningText(inObj: RuleReview, pos: number): string[] { + public createWarningText(inObj: RuleReview, posWarning: number = 2): string[] { const outMsg = [...inObj.warningMessages]; if (inObj.compare_type === 'unav_C0_C1') { - outMsg[pos] = "unavailable modifier "; + outMsg[posWarning] = "unavailable modifier "; } if (inObj.compare_type === 'unav_C2') { - // if the dk is unavailable, the dependant C0 rules and theIr modifiers need to get a warning 'unavailable superior rule ' + // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' if (inObj.Dk_modifier) { outMsg[1] = "unavailable modifier "; outMsg[2] = "unavailable superior rule ( [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > dk(" - + inObj.dk_bothPrefix_prevdk_dk[1] - + inObj.dk_bothId_prevdk_dk[1] + + inObj.dk_prefix[1] + + inObj.dk_id[1] + ") ) : "; } @@ -452,28 +459,28 @@ export class KmnFileWriter { if (inObj.compare_type === 'unav_C3') { - // if the dk is unavailable, the dependant C0 rules and theIr modifiers need to get a warning 'unavailable superior rule ' + // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' if (inObj.prevDk_modifier) { outMsg[0] = "unavailable modifier "; outMsg[1] = "unavailable superior rule ( [" + inObj.prevDk_modifier + " " + inObj.prevDk_key + "] > dk(" - + inObj.dk_bothPrefix_prevdk_dk[1] - + inObj.dk_bothId_prevdk_dk[1] + + inObj.dk_prefix[0] + + inObj.dk_id[0] + ") ) : "; } - // if the dk is unavailable, the dependant C0 rules and theIr modifiers need to get a warning 'unavailable superior rule ' + // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' if (inObj.Dk_modifier) { outMsg[1] += "unavailable modifier "; outMsg[2] = "unavailable superior rule ( [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > dk(" - + inObj.dk_bothPrefix_prevdk_dk[1] - + inObj.dk_bothId_prevdk_dk[1] + + inObj.dk_prefix[1] + + inObj.dk_id[1] + ") ) : "; } @@ -484,7 +491,7 @@ export class KmnFileWriter { if (inObj.compare_type === 'amb_1_1' || inObj.compare_type === 'dup_1_1') { - outMsg[pos] = inObj.warningMessages[2] + outMsg[posWarning] = inObj.warningMessages[posWarning] + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " + (inObj.earlier_later[0] ? "earlier" : "later") + ": [" + inObj.modifier + " " + inObj.key + "] > \'" @@ -500,10 +507,10 @@ export class KmnFileWriter { ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " + (inObj.earlier_later[0] ? "earlier" : "later") + ": [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > dk(" - + inObj.dk_bothPrefix_prevdk_dk[1] + inObj.dk_bothId_prevdk_dk[1] + ") "); + + inObj.dk_prefix[1] + inObj.dk_id[1] + ") "); - if (outMsg[pos].indexOf(textsegment) === -1) - outMsg[pos] += textsegment; + if (outMsg[posWarning].indexOf(textsegment) === -1) + outMsg[posWarning] += textsegment; } @@ -515,10 +522,10 @@ export class KmnFileWriter { ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " + (inObj.earlier_later[0] ? "earlier" : "later") + ": [" + inObj.prevDk_modifier + " " + inObj.prevDk_key + "] > dk(" - + inObj.dk_bothPrefix_prevdk_dk[0] + inObj.dk_bothId_prevdk_dk[0] + ") "); + + inObj.dk_prefix[0] + inObj.dk_id[0] + ") "); - if (outMsg[pos].indexOf(textsegment) === -1) - outMsg[pos] += textsegment; + if (outMsg[posWarning].indexOf(textsegment) === -1) + outMsg[posWarning] += textsegment; } @@ -527,12 +534,12 @@ export class KmnFileWriter { const textsegment = ( ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + (inObj.earlier_later[0] ? "earlier" : "later") - + ': dk(' + inObj.dk_bothPrefix_prevdk_dk[1] + inObj.dk_bothId_prevdk_dk[1] + ") + [" + + ': dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") + [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > " - + 'dk(' + inObj.dk_bothPrefix_prevdk_dk[0] + inObj.dk_bothId_prevdk_dk[0] + ") "); + + 'dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] + ") "); - if (outMsg[pos].indexOf(textsegment) === -1) - outMsg[pos] += textsegment; + if (outMsg[1].indexOf(textsegment) === -1) + outMsg[1] += textsegment; } @@ -543,11 +550,11 @@ export class KmnFileWriter { const textsegment = ( ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + (inObj.earlier_later[0] ? "earlier" : "later") - + ': dk(' + inObj.dk_bothPrefix_prevdk_dk[1] + inObj.dk_bothId_prevdk_dk[1] + ") + [" + + ': dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") + [" + inObj.modifier + " " + inObj.key + "] > \'" + inObj.output + "\' "); - if (outMsg[pos].indexOf(textsegment) === -1) - outMsg[pos] += textsegment; + if (outMsg[posWarning].indexOf(textsegment) === -1) + outMsg[posWarning] += textsegment; } return outMsg; @@ -592,7 +599,7 @@ export class KmnFileWriter { if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { unavailableModiWarnings.compare_type = 'unav_C0_C1'; - unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings, 2); + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings); } } @@ -600,18 +607,18 @@ export class KmnFileWriter { else if (rule[index].ruleType === "C2") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { unavailableSuperiWarnings.compare_type = 'unav_C2'; - unavailableSuperiWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; - unavailableSuperiWarnings.dk_bothId_prevdk_dk = [rule[0].idPrevDeadkey, rule[0].idDeadkey]; + unavailableSuperiWarnings.dk_prefix = ['C', 'A']; + unavailableSuperiWarnings.dk_id = [rule[index].idPrevDeadkey, rule[index].idDeadkey]; unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; unavailableSuperiWarnings.Dk_key = rule[index].deadkey; - unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings); } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { unavailableModiWarnings.compare_type = 'unav_C2'; unavailableModiWarnings.modifier = rule[index].modifierKey; unavailableModiWarnings.key = rule[index].key; - unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings, 2); + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings); } } @@ -619,8 +626,8 @@ export class KmnFileWriter { else if (rule[index].ruleType === "C3") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierPrevDeadkey)) { unavailableSuperiWarnings.compare_type = 'unav_C3'; - unavailableSuperiWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; - unavailableSuperiWarnings.dk_bothId_prevdk_dk = [rule[0].idPrevDeadkey, rule[0].idDeadkey]; + unavailableSuperiWarnings.dk_prefix = ['A', '']; + unavailableSuperiWarnings.dk_id = [rule[index].idPrevDeadkey, rule[index].idDeadkey]; unavailableSuperiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; unavailableSuperiWarnings.prevDk_key = rule[index].prevDeadkey; unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); @@ -629,8 +636,8 @@ export class KmnFileWriter { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { unavailableSuperiWarnings.compare_type = 'unav_C3'; unavailableSuperiWarnings.prevDk_modifier = ''; - unavailableSuperiWarnings.dk_bothPrefix_prevdk_dk = ['', 'B']; - unavailableSuperiWarnings.dk_bothId_prevdk_dk = [rule[0].idPrevDeadkey, rule[0].idDeadkey]; + unavailableSuperiWarnings.dk_prefix = ['', 'B']; + unavailableSuperiWarnings.dk_id = [rule[index].idPrevDeadkey, rule[index].idDeadkey]; unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; unavailableSuperiWarnings.Dk_key = rule[index].deadkey; unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); @@ -690,8 +697,8 @@ export class KmnFileWriter { if (amb_4_1.length > 0) { ambiguousWarnings.compare_type = 'amb_4_1'; ambiguousWarnings.earlier_later = [false, true]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_4_1[0].idPrevDeadkey, amb_4_1[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['C', 'A']; + ambiguousWarnings.dk_id = [amb_4_1[0].idPrevDeadkey, amb_4_1[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_1[0].modifierPrevDeadkey; ambiguousWarnings.prevDk_key = amb_4_1[0].prevDeadkey; ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); @@ -700,8 +707,8 @@ export class KmnFileWriter { if (amb_2_1.length > 0) { ambiguousWarnings.compare_type = 'amb_2_1'; ambiguousWarnings.earlier_later = [false, true]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', 'A']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_2_1[0].idPrevDeadkey, amb_2_1[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['C', 'A']; + ambiguousWarnings.dk_id = [amb_2_1[0].idPrevDeadkey, amb_2_1[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_1[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_1[0].deadkey; ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); @@ -779,8 +786,8 @@ export class KmnFileWriter { if (amb_2_2.length > 0) { ambiguousWarnings.compare_type = 'amb_2_2'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_2_2[0].idPrevDeadkey, amb_2_2[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['', 'C']; + ambiguousWarnings.dk_id = [amb_2_2[0].idPrevDeadkey, amb_2_2[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_2[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_2[0].deadkey; ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); @@ -789,8 +796,8 @@ export class KmnFileWriter { if (dup_2_2.length > 0) { duplicateWarnings.compare_type = 'dup_2_2'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; - duplicateWarnings.dk_bothId_prevdk_dk = [dup_2_2[0].idPrevDeadkey, dup_2_2[0].idDeadkey]; + duplicateWarnings.dk_prefix = ['', 'C']; + duplicateWarnings.dk_id = [dup_2_2[0].idPrevDeadkey, dup_2_2[0].idDeadkey]; duplicateWarnings.Dk_modifier = dup_2_2[0].modifierDeadkey; duplicateWarnings.Dk_key = dup_2_2[0].deadkey; duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); @@ -799,8 +806,8 @@ export class KmnFileWriter { if (amb_3_3.length > 0) { ambiguousWarnings.compare_type = 'amb_3_3'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'A']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_3_3[0].idPrevDeadkey, amb_3_3[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['', 'A']; + ambiguousWarnings.dk_id = [amb_3_3[0].idPrevDeadkey, amb_3_3[0].idDeadkey]; ambiguousWarnings.modifier = amb_3_3[0].modifierKey; ambiguousWarnings.key = amb_3_3[0].key; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character; @@ -810,8 +817,8 @@ export class KmnFileWriter { if (dup_3_3.length > 0) { duplicateWarnings.compare_type = 'dup_3_3'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_bothId_prevdk_dk = [dup_3_3[0].idPrevDeadkey, dup_3_3[0].idDeadkey]; - duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'A']; + duplicateWarnings.dk_id = [dup_3_3[0].idPrevDeadkey, dup_3_3[0].idDeadkey]; + duplicateWarnings.dk_prefix = ['', 'A']; duplicateWarnings.modifier = dup_3_3[0].modifierKey; duplicateWarnings.key = dup_3_3[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character; @@ -821,8 +828,8 @@ export class KmnFileWriter { if (amb_4_2.length > 0) { ambiguousWarnings.compare_type = 'amb_4_2'; ambiguousWarnings.earlier_later = [false, true]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', '']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_4_2[0].idPrevDeadkey, amb_4_2[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['C', '']; + ambiguousWarnings.dk_id = [amb_4_2[0].idPrevDeadkey, amb_4_2[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_2[0].modifierPrevDeadkey; ambiguousWarnings.prevDk_key = amb_4_2[0].prevDeadkey; ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); @@ -924,8 +931,8 @@ export class KmnFileWriter { if (amb_2_4.length > 0) { ambiguousWarnings.compare_type = 'amb_2_4'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'A']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_2_4[0].idPrevDeadkey, amb_2_4[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['', 'A']; + ambiguousWarnings.dk_id = [amb_2_4[0].idPrevDeadkey, amb_2_4[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_4[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_4[0].deadkey; ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); @@ -934,8 +941,8 @@ export class KmnFileWriter { if (amb_6_3.length > 0) { ambiguousWarnings.compare_type = 'amb_6_3'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_6_3[0].idPrevDeadkey, amb_6_3[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['', 'C']; + ambiguousWarnings.dk_id = [amb_6_3[0].idPrevDeadkey, amb_6_3[0].idDeadkey]; ambiguousWarnings.modifier = amb_6_3[0].modifierKey; ambiguousWarnings.key = amb_6_3[0].key; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character; @@ -945,8 +952,8 @@ export class KmnFileWriter { if (dup_6_3.length > 0) { duplicateWarnings.compare_type = 'dup_6_3'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'C']; - duplicateWarnings.dk_bothId_prevdk_dk = [dup_6_3[0].idPrevDeadkey, dup_6_3[0].idDeadkey]; + duplicateWarnings.dk_prefix = ['', 'C']; + duplicateWarnings.dk_id = [dup_6_3[0].idPrevDeadkey, dup_6_3[0].idDeadkey]; duplicateWarnings.modifier = dup_6_3[0].modifierKey; duplicateWarnings.key = dup_6_3[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character; @@ -956,8 +963,8 @@ export class KmnFileWriter { if (amb_4_4.length > 0) { ambiguousWarnings.compare_type = 'amb_4_4'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['C', '']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_4_4[0].idPrevDeadkey, amb_4_4[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['C', '']; + ambiguousWarnings.dk_id = [amb_4_4[0].idPrevDeadkey, amb_4_4[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_4[0].modifierPrevDeadkey; ambiguousWarnings.prevDk_key = amb_4_4[0].prevDeadkey; ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); @@ -966,8 +973,8 @@ export class KmnFileWriter { if (dup_4_4.length > 0) { duplicateWarnings.compare_type = 'dup_4_4'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_bothPrefix_prevdk_dk = ['C', '']; - duplicateWarnings.dk_bothId_prevdk_dk = [dup_4_4[0].idPrevDeadkey, dup_4_4[0].idDeadkey]; + duplicateWarnings.dk_prefix = ['C', '']; + duplicateWarnings.dk_id = [dup_4_4[0].idPrevDeadkey, dup_4_4[0].idDeadkey]; duplicateWarnings.prevDk_modifier = dup_4_4[0].modifierPrevDeadkey; duplicateWarnings.prevDk_key = dup_4_4[0].prevDeadkey; duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 0); @@ -976,17 +983,19 @@ export class KmnFileWriter { if (amb_5_5.length > 0) { ambiguousWarnings.compare_type = 'amb_5_5'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['B', 'B']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_5_5[0].idPrevDeadkey, amb_5_5[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['B', 'B']; + ambiguousWarnings.dk_id = [amb_5_5[0].idPrevDeadkey, amb_5_5[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_5_5[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_5_5[0].deadkey; - ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings); } if (dup_5_5.length > 0) { duplicateWarnings.compare_type = 'dup_5_5'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_bothPrefix_prevdk_dk = ['B', 'B']; + duplicateWarnings.dk_prefix = ['B', 'B']; + duplicateWarnings.dk_id = [dup_5_5[0].idPrevDeadkey, dup_5_5[0].idDeadkey]; + duplicateWarnings.Dk_modifier = rule[index].modifierDeadkey; duplicateWarnings.Dk_key = rule[index].deadkey; duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); @@ -995,8 +1004,8 @@ export class KmnFileWriter { if (amb_6_6.length > 0) { ambiguousWarnings.compare_type = 'amb_6_6'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_bothPrefix_prevdk_dk = ['', 'B']; - ambiguousWarnings.dk_bothId_prevdk_dk = [amb_6_6[0].idPrevDeadkey, amb_6_6[0].idDeadkey]; + ambiguousWarnings.dk_prefix = ['', 'B']; + ambiguousWarnings.dk_id = [amb_6_6[0].idPrevDeadkey, amb_6_6[0].idDeadkey]; ambiguousWarnings.modifier = amb_6_6[0].modifierKey; ambiguousWarnings.key = amb_6_6[0].key; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character; @@ -1006,8 +1015,8 @@ export class KmnFileWriter { if (dup_6_6.length > 0) { duplicateWarnings.compare_type = 'dup_6_6'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_bothPrefix_prevdk_dk = ['', 'B']; - duplicateWarnings.dk_bothId_prevdk_dk = [dup_6_6[0].idPrevDeadkey, dup_6_6[0].idDeadkey]; + duplicateWarnings.dk_prefix = ['', 'B']; + duplicateWarnings.dk_id = [dup_6_6[0].idPrevDeadkey, dup_6_6[0].idDeadkey]; duplicateWarnings.modifier = dup_6_6[0].modifierKey; duplicateWarnings.key = dup_6_6[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character; From 49c07a413ff90381c021581dfc90b01b21b32cd8 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 25 Jun 2026 18:00:23 +0200 Subject: [PATCH 24/33] feat(developer): returntype of reviewRules changed to object --- .../src/keylayout-to-kmn/kmn-file-writer.ts | 24 +++++++++++-------- .../test/keylayout-to-kmn-converter.tests.ts | 1 - .../kmc-convert/test/kmn-file-writer.tests.ts | 20 ++++++++-------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 82fc86cf39..3ffe0bf79b 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -21,7 +21,7 @@ interface RuleReview { warningMessages: string[]; extraWarning: string; type: 'RuleReview' | 'UnavailableModifier' | 'UnavailableSuperiorRule' | - 'DuplicateRule' | 'AmbiguousRule'; + 'DuplicateRule' | 'AmbiguousRule' | 'WarningTextSet'; compare_type: string; earlier_later: [boolean, boolean]; // dk_id[0]: prev_dk; dk_id[1]: dk; @@ -49,7 +49,9 @@ interface DuplicateRules extends RuleReview { interface AmbiguousRules extends RuleReview { type: 'AmbiguousRule'; }; - +interface WarningTextSet extends RuleReview { + type: 'WarningTextSet'; +}; export class KmnFileWriter { @@ -177,7 +179,7 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character let versionOutputCharacter; - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class @@ -242,7 +244,7 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character let versionOutputCharacter; - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); @@ -329,7 +331,7 @@ export class KmnFileWriter { // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character let versionOutputCharacter; - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class @@ -569,7 +571,7 @@ export class KmnFileWriter { * @param index the index of a rule in Rule[] * @return a string[] containing possible warnings for a rule */ - public reviewRules(rule: Rule[], index: number): string[] { + public reviewRules(rule: Rule[], index: number): RuleReview { const unavailableModiWarnings = { type: 'UnavailableModifier', @@ -591,8 +593,11 @@ export class KmnFileWriter { warningMessages: ['', '', ''], } as AmbiguousRules; + const resultWarningTextSet = { + warningMessages: ['', '', ''], + } as WarningTextSet; + const keylayoutKmnConverter = new KeylayoutToKmnConverter(this.callbacks, this.options); - const warningText: string[] = Array(3).fill(""); // ------------------------- check unavailable modifiers ------------------------- @@ -1048,11 +1053,10 @@ export class KmnFileWriter { + ambiguousWarnings.warningMessages[i] + unavailableModiWarnings.warningMessages[i]; - completeWarning ? (warningText[i] = "c WARNING: " + completeWarning + " here: ") : warningText[i] = ''; - + completeWarning ? (resultWarningTextSet.warningMessages[i] = "c WARNING: " + completeWarning + " here: ") : resultWarningTextSet.warningMessages[i] = ''; } - return warningText; + return resultWarningTextSet; } /** diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 9658d033cd..e86c133167 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -61,7 +61,6 @@ describe('KeylayoutToKmnConverter', function () { ].forEach(function (files) { it(files + " should give no errors ", async function () { sut.run(makePathToFixture(files[0])); - // assert.isTrue(compilerTestCallbacks.messages.length === 1 && compilerTestCallbacks.messages[0].code === 5292037); assert.isTrue(compilerTestCallbacks.messages.length === 0); await sut.run(makePathToFixture(files[0])); assert.equal(compilerTestCallbacks.messages.length, 0); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 7857ae2765..89528238a4 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -124,29 +124,29 @@ describe('KmnFileWriter', function () { [''], ['c WARNING: unavailable modifier here: ']], - [[new Rule("C2", '', '', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], + [[new Rule("C2", '', '', 1, 1, 'UNAVAILABLE_dk', 'K_EQUAL', 2, 2, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], [''], ['c WARNING: unavailable modifier here: '], - ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(A0) ) : unavailable modifier here: ']], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(A2) ) : unavailable modifier here: ']], - [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], + [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 1, 1, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], ['c WARNING: unavailable modifier here: '], - ['c WARNING: unavailable superior rule ( [UNAVAILABLE_prev_dk K_D] > dk(A0) ) : unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_prev_dk K_D] > dk(A1) ) : unavailable modifier here: '], ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : here: ']], - [[new Rule("C3", 'CAPS', 'K_D', 0, 0, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], + [[new Rule("C3", 'CAPS', 'K_D',1, 1, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], [''], [''], ['']], - [[new Rule("C3", 'X', 'K_X', 0, 0, 'Y', 'K_Y', 0, 0, 'SHIFT', 'K_Z', new TextEncoder().encode('D'),)], + [[new Rule("C3", 'X', 'K_X', 1, 1, 'Y', 'K_Y', 0, 0, 'SHIFT', 'K_Z', new TextEncoder().encode('D'),)], ['c WARNING: unavailable modifier here: '], - ['c WARNING: unavailable superior rule ( [X K_X] > dk(A0) ) : unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [X K_X] > dk(A1) ) : unavailable modifier here: '], ['c WARNING: unavailable superior rule ( [Y K_Y] > dk(B0) ) : here: ']], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule " ' + (values[0][0] as Rule).ruleType as string + ' "') + 'should create "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { - const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 0); + const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 0).warningMessages; assert.equal(result[0], values[1][0]); assert.equal(result[1], values[2][0]); assert.equal(result[2], values[3][0]); @@ -312,7 +312,7 @@ describe('KmnFileWriter', function () { ].forEach(function (values: (string[] | Rule[])[], index: number) { it('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { - const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 1); + const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 1).warningMessages; assert.equal(result[0], values[1][0]); assert.equal(result[1], values[2][0]); assert.equal(result[2], values[3][0]); @@ -332,7 +332,7 @@ describe('KmnFileWriter', function () { ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' PLEASE CHECK THAT RULE AS IT WILL NOT BE WRITTEN ! here: "]], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "') + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { - const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 2); + const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 2).warningMessages; assert.equal(result[0], values[1][0]); assert.equal(result[1], values[2][0]); assert.equal(result[2], values[3][0]); From 1fab2540228abdebbecd485e8f375dbbc16047c3 Mon Sep 17 00:00:00 2001 From: Sabine Date: Fri, 26 Jun 2026 09:27:48 +0200 Subject: [PATCH 25/33] feat(developer): dup_5_5, amb_5_5 swap dk and prev_dk output --- .../src/keylayout-to-kmn/kmn-file-writer.ts | 10 +++++----- .../test/keylayout-to-kmn-converter.tests.ts | 8 ++++---- .../src/kmc-convert/test/kmn-file-writer.tests.ts | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 3ffe0bf79b..0916056f32 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -536,9 +536,9 @@ export class KmnFileWriter { const textsegment = ( ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + (inObj.earlier_later[0] ? "earlier" : "later") - + ': dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") + [" + + ': dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] + ") + [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > " - + 'dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] + ") "); + + 'dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") "); if (outMsg[1].indexOf(textsegment) === -1) outMsg[1] += textsegment; @@ -712,7 +712,7 @@ export class KmnFileWriter { if (amb_2_1.length > 0) { ambiguousWarnings.compare_type = 'amb_2_1'; ambiguousWarnings.earlier_later = [false, true]; - ambiguousWarnings.dk_prefix = ['C', 'A']; + ambiguousWarnings.dk_prefix = ['', 'A']; ambiguousWarnings.dk_id = [amb_2_1[0].idPrevDeadkey, amb_2_1[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_1[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_2_1[0].deadkey; @@ -988,7 +988,7 @@ export class KmnFileWriter { if (amb_5_5.length > 0) { ambiguousWarnings.compare_type = 'amb_5_5'; ambiguousWarnings.earlier_later = [true, false]; - ambiguousWarnings.dk_prefix = ['B', 'B']; + ambiguousWarnings.dk_prefix = ['C', 'B']; ambiguousWarnings.dk_id = [amb_5_5[0].idPrevDeadkey, amb_5_5[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_5_5[0].modifierDeadkey; ambiguousWarnings.Dk_key = amb_5_5[0].deadkey; @@ -998,7 +998,7 @@ export class KmnFileWriter { if (dup_5_5.length > 0) { duplicateWarnings.compare_type = 'dup_5_5'; duplicateWarnings.earlier_later = [true, false]; - duplicateWarnings.dk_prefix = ['B', 'B']; + duplicateWarnings.dk_prefix = ['C', 'B']; duplicateWarnings.dk_id = [dup_5_5[0].idPrevDeadkey, dup_5_5[0].idDeadkey]; duplicateWarnings.Dk_modifier = rule[index].modifierDeadkey; diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index e86c133167..8ed4f88e73 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -64,9 +64,9 @@ describe('KeylayoutToKmnConverter', function () { assert.isTrue(compilerTestCallbacks.messages.length === 0); await sut.run(makePathToFixture(files[0])); assert.equal(compilerTestCallbacks.messages.length, 0); - }); - }); - }); + }); + }); + }); describe('RunTestFiles resulting in errors ', function () { const sut = new KeylayoutToKmnConverter(compilerTestCallbacks, compilerTestOptions); [ @@ -96,7 +96,7 @@ describe('KeylayoutToKmnConverter', function () { ['../data/Test_undefinedAction.keylayout'], ].forEach(function (files) { it(files + " should give Error: undefined action detected", async function () { - sut.run(makePathToFixture(files[0])); + sut.run(makePathToFixture(files[0])); assert.equal(compilerTestCallbacks.messages.length, 1); assert.equal(compilerTestCallbacks.messages[0].code, 5292040); }); diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 89528238a4..ff4f58a7b6 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -134,7 +134,7 @@ describe('KmnFileWriter', function () { ['c WARNING: unavailable superior rule ( [UNAVAILABLE_prev_dk K_D] > dk(A1) ) : unavailable modifier here: '], ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : here: ']], - [[new Rule("C3", 'CAPS', 'K_D',1, 1, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], + [[new Rule("C3", 'CAPS', 'K_D', 1, 1, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], [''], [''], ['']], @@ -163,7 +163,7 @@ describe('KmnFileWriter', function () { new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: duplicate rule: earlier: dk(B0) + [SHIFT K_B] > dk(B0) here: "], + ["c WARNING: duplicate rule: earlier: dk(C0) + [SHIFT K_B] > dk(B0) here: "], ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], //6-6 dup @@ -187,7 +187,7 @@ describe('KmnFileWriter', function () { new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 1, 'RALT', 'K_F', new TextEncoder().encode('X')),], ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: ambiguous rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], [''], + ["c WARNING: ambiguous rule: earlier: dk(C0) + [NCAPS K_B] > dk(B0) here: "], [''], ], // 5-5 dup @@ -195,7 +195,7 @@ describe('KmnFileWriter', function () { new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: duplicate rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], + ["c WARNING: duplicate rule: earlier: dk(C0) + [NCAPS K_B] > dk(B0) here: "], ['']], // 4-2 amb From 688e222c21e915e3258cce61ca6075c168c157c5 Mon Sep 17 00:00:00 2001 From: Sabine Date: Fri, 26 Jun 2026 11:23:02 +0200 Subject: [PATCH 26/33] feat(developer): exchange earlier_later: [boolean, boolean] with isEarlier: boolean; --- .../src/keylayout-to-kmn/kmn-file-writer.ts | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 0916056f32..bfc1f9743a 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -23,7 +23,7 @@ interface RuleReview { type: 'RuleReview' | 'UnavailableModifier' | 'UnavailableSuperiorRule' | 'DuplicateRule' | 'AmbiguousRule' | 'WarningTextSet'; compare_type: string; - earlier_later: [boolean, boolean]; + isEarlier: boolean; // dk_id[0]: prev_dk; dk_id[1]: dk; dk_id: [number, number]; // dk_prefix[0]: prev_dk_prefix; dk_prefix[1]: dk_prefix; @@ -438,24 +438,24 @@ export class KmnFileWriter { const outMsg = [...inObj.warningMessages]; if (inObj.compare_type === 'unav_C0_C1') { - outMsg[posWarning] = "unavailable modifier "; + outMsg[posWarning] = 'unavailable modifier '; } if (inObj.compare_type === 'unav_C2') { // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' if (inObj.Dk_modifier) { - outMsg[1] = "unavailable modifier "; - outMsg[2] = "unavailable superior rule ( [" - + inObj.Dk_modifier + " " + outMsg[1] = 'unavailable modifier '; + outMsg[2] = 'unavailable superior rule ( [' + + inObj.Dk_modifier + ' ' + inObj.Dk_key - + "] > dk(" + + '] > dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] - + ") ) : "; + + ') ) : '; } if (inObj.modifier) { - outMsg[2] = "unavailable modifier "; + outMsg[2] = 'unavailable modifier '; } } @@ -463,41 +463,41 @@ export class KmnFileWriter { // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' if (inObj.prevDk_modifier) { - outMsg[0] = "unavailable modifier "; - outMsg[1] = "unavailable superior rule ( [" - + inObj.prevDk_modifier + " " + outMsg[0] = 'unavailable modifier '; + outMsg[1] = 'unavailable superior rule ( [' + + inObj.prevDk_modifier + ' ' + inObj.prevDk_key - + "] > dk(" + + '] > dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] - + ") ) : "; + + ') ) : '; } // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' if (inObj.Dk_modifier) { - outMsg[1] += "unavailable modifier "; - outMsg[2] = "unavailable superior rule ( [" - + inObj.Dk_modifier + " " + outMsg[1] += 'unavailable modifier '; + outMsg[2] = 'unavailable superior rule ( [' + + inObj.Dk_modifier + ' ' + inObj.Dk_key - + "] > dk(" + + '] > dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] - + ") ) : "; + + ') ) : '; } if (inObj.modifier) { - outMsg[2] = "unavailable modifier "; + outMsg[2] = 'unavailable modifier '; } } if (inObj.compare_type === 'amb_1_1' || inObj.compare_type === 'dup_1_1') { outMsg[posWarning] = inObj.warningMessages[posWarning] - + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " - + (inObj.earlier_later[0] ? "earlier" : "later") - + ": [" + inObj.modifier + " " + inObj.key + "] > \'" - + inObj.output + "\' "; + + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': [' + inObj.modifier + ' ' + inObj.key + '] > \'' + + inObj.output + '\' '; } @@ -506,10 +506,10 @@ export class KmnFileWriter { || inObj.compare_type === 'amb_2_4') { const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " - + (inObj.earlier_later[0] ? "earlier" : "later") - + ": [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > dk(" - + inObj.dk_prefix[1] + inObj.dk_id[1] + ") "); + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': [' + inObj.Dk_modifier + ' ' + inObj.Dk_key + '] > dk(' + + inObj.dk_prefix[1] + inObj.dk_id[1] + ') '); if (outMsg[posWarning].indexOf(textsegment) === -1) outMsg[posWarning] += textsegment; @@ -521,10 +521,10 @@ export class KmnFileWriter { || inObj.compare_type === 'amb_4_2') { const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + "rule: " - + (inObj.earlier_later[0] ? "earlier" : "later") + ": [" - + inObj.prevDk_modifier + " " + inObj.prevDk_key + "] > dk(" - + inObj.dk_prefix[0] + inObj.dk_id[0] + ") "); + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': [' + inObj.prevDk_modifier + ' ' + inObj.prevDk_key + '] > dk(' + + inObj.dk_prefix[0] + inObj.dk_id[0] + ') '); if (outMsg[posWarning].indexOf(textsegment) === -1) outMsg[posWarning] += textsegment; @@ -535,7 +535,7 @@ export class KmnFileWriter { const textsegment = ( ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' - + (inObj.earlier_later[0] ? "earlier" : "later") + + (inObj.isEarlier ? 'earlier' : 'later') + ': dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] + ") + [" + inObj.Dk_modifier + " " + inObj.Dk_key + "] > " + 'dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") "); @@ -550,10 +550,11 @@ export class KmnFileWriter { || inObj.compare_type === 'amb_6_6' || inObj.compare_type === 'dup_6_6') { const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + - (inObj.earlier_later[0] ? "earlier" : "later") + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + ': dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") + [" - + inObj.modifier + " " + inObj.key + "] > \'" + inObj.output + "\' "); + + inObj.modifier + " " + inObj.key + "] > \'" + + inObj.output + "\' "); if (outMsg[posWarning].indexOf(textsegment) === -1) outMsg[posWarning] += textsegment; @@ -701,7 +702,7 @@ export class KmnFileWriter { if (amb_4_1.length > 0) { ambiguousWarnings.compare_type = 'amb_4_1'; - ambiguousWarnings.earlier_later = [false, true]; + ambiguousWarnings.isEarlier = false; ambiguousWarnings.dk_prefix = ['C', 'A']; ambiguousWarnings.dk_id = [amb_4_1[0].idPrevDeadkey, amb_4_1[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_1[0].modifierPrevDeadkey; @@ -711,7 +712,7 @@ export class KmnFileWriter { if (amb_2_1.length > 0) { ambiguousWarnings.compare_type = 'amb_2_1'; - ambiguousWarnings.earlier_later = [false, true]; + ambiguousWarnings.isEarlier = false; ambiguousWarnings.dk_prefix = ['', 'A']; ambiguousWarnings.dk_id = [amb_2_1[0].idPrevDeadkey, amb_2_1[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_1[0].modifierDeadkey; @@ -721,7 +722,7 @@ export class KmnFileWriter { if (amb_1_1.length > 0) { ambiguousWarnings.compare_type = 'amb_1_1'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.modifier = amb_1_1[0].modifierKey; ambiguousWarnings.key = amb_1_1[0].key; ambiguousWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character; @@ -730,7 +731,7 @@ export class KmnFileWriter { if (dup_1_1.length > 0) { duplicateWarnings.compare_type = 'dup_1_1'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.modifier = dup_1_1[0].modifierKey; duplicateWarnings.key = dup_1_1[0].key; duplicateWarnings.output = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character; @@ -790,7 +791,7 @@ export class KmnFileWriter { if (amb_2_2.length > 0) { ambiguousWarnings.compare_type = 'amb_2_2'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['', 'C']; ambiguousWarnings.dk_id = [amb_2_2[0].idPrevDeadkey, amb_2_2[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_2[0].modifierDeadkey; @@ -800,7 +801,7 @@ export class KmnFileWriter { if (dup_2_2.length > 0) { duplicateWarnings.compare_type = 'dup_2_2'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.dk_prefix = ['', 'C']; duplicateWarnings.dk_id = [dup_2_2[0].idPrevDeadkey, dup_2_2[0].idDeadkey]; duplicateWarnings.Dk_modifier = dup_2_2[0].modifierDeadkey; @@ -810,7 +811,7 @@ export class KmnFileWriter { if (amb_3_3.length > 0) { ambiguousWarnings.compare_type = 'amb_3_3'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['', 'A']; ambiguousWarnings.dk_id = [amb_3_3[0].idPrevDeadkey, amb_3_3[0].idDeadkey]; ambiguousWarnings.modifier = amb_3_3[0].modifierKey; @@ -821,7 +822,7 @@ export class KmnFileWriter { if (dup_3_3.length > 0) { duplicateWarnings.compare_type = 'dup_3_3'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.dk_id = [dup_3_3[0].idPrevDeadkey, dup_3_3[0].idDeadkey]; duplicateWarnings.dk_prefix = ['', 'A']; duplicateWarnings.modifier = dup_3_3[0].modifierKey; @@ -832,7 +833,7 @@ export class KmnFileWriter { if (amb_4_2.length > 0) { ambiguousWarnings.compare_type = 'amb_4_2'; - ambiguousWarnings.earlier_later = [false, true]; + ambiguousWarnings.isEarlier = false; ambiguousWarnings.dk_prefix = ['C', '']; ambiguousWarnings.dk_id = [amb_4_2[0].idPrevDeadkey, amb_4_2[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_2[0].modifierPrevDeadkey; @@ -935,7 +936,7 @@ export class KmnFileWriter { if (amb_2_4.length > 0) { ambiguousWarnings.compare_type = 'amb_2_4'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['', 'A']; ambiguousWarnings.dk_id = [amb_2_4[0].idPrevDeadkey, amb_2_4[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_2_4[0].modifierDeadkey; @@ -945,7 +946,7 @@ export class KmnFileWriter { if (amb_6_3.length > 0) { ambiguousWarnings.compare_type = 'amb_6_3'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['', 'C']; ambiguousWarnings.dk_id = [amb_6_3[0].idPrevDeadkey, amb_6_3[0].idDeadkey]; ambiguousWarnings.modifier = amb_6_3[0].modifierKey; @@ -956,7 +957,7 @@ export class KmnFileWriter { if (dup_6_3.length > 0) { duplicateWarnings.compare_type = 'dup_6_3'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.dk_prefix = ['', 'C']; duplicateWarnings.dk_id = [dup_6_3[0].idPrevDeadkey, dup_6_3[0].idDeadkey]; duplicateWarnings.modifier = dup_6_3[0].modifierKey; @@ -967,7 +968,7 @@ export class KmnFileWriter { if (amb_4_4.length > 0) { ambiguousWarnings.compare_type = 'amb_4_4'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['C', '']; ambiguousWarnings.dk_id = [amb_4_4[0].idPrevDeadkey, amb_4_4[0].idDeadkey]; ambiguousWarnings.prevDk_modifier = amb_4_4[0].modifierPrevDeadkey; @@ -977,7 +978,7 @@ export class KmnFileWriter { if (dup_4_4.length > 0) { duplicateWarnings.compare_type = 'dup_4_4'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.dk_prefix = ['C', '']; duplicateWarnings.dk_id = [dup_4_4[0].idPrevDeadkey, dup_4_4[0].idDeadkey]; duplicateWarnings.prevDk_modifier = dup_4_4[0].modifierPrevDeadkey; @@ -987,7 +988,7 @@ export class KmnFileWriter { if (amb_5_5.length > 0) { ambiguousWarnings.compare_type = 'amb_5_5'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['C', 'B']; ambiguousWarnings.dk_id = [amb_5_5[0].idPrevDeadkey, amb_5_5[0].idDeadkey]; ambiguousWarnings.Dk_modifier = amb_5_5[0].modifierDeadkey; @@ -997,10 +998,9 @@ export class KmnFileWriter { if (dup_5_5.length > 0) { duplicateWarnings.compare_type = 'dup_5_5'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.dk_prefix = ['C', 'B']; duplicateWarnings.dk_id = [dup_5_5[0].idPrevDeadkey, dup_5_5[0].idDeadkey]; - duplicateWarnings.Dk_modifier = rule[index].modifierDeadkey; duplicateWarnings.Dk_key = rule[index].deadkey; duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); @@ -1008,7 +1008,7 @@ export class KmnFileWriter { if (amb_6_6.length > 0) { ambiguousWarnings.compare_type = 'amb_6_6'; - ambiguousWarnings.earlier_later = [true, false]; + ambiguousWarnings.isEarlier = true; ambiguousWarnings.dk_prefix = ['', 'B']; ambiguousWarnings.dk_id = [amb_6_6[0].idPrevDeadkey, amb_6_6[0].idDeadkey]; ambiguousWarnings.modifier = amb_6_6[0].modifierKey; @@ -1019,7 +1019,7 @@ export class KmnFileWriter { if (dup_6_6.length > 0) { duplicateWarnings.compare_type = 'dup_6_6'; - duplicateWarnings.earlier_later = [true, false]; + duplicateWarnings.isEarlier = true; duplicateWarnings.dk_prefix = ['', 'B']; duplicateWarnings.dk_id = [dup_6_6[0].idPrevDeadkey, dup_6_6[0].idDeadkey]; duplicateWarnings.modifier = dup_6_6[0].modifierKey; From 778916309a01cd0c9e12f425b5846a9599ab7c06 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 2 Jul 2026 17:38:35 +0200 Subject: [PATCH 27/33] feat(developer):kmc-convert use changed ReviewRule from PR 16703 --- .../src/kmc-convert/src/converter-messages.ts | 2 +- .../src/keylayout-to-kmn/kmn-file-writer.ts | 1413 ++++++----------- .../kmc-convert/test/kmn-file-writer.tests.ts | 161 +- 3 files changed, 499 insertions(+), 1077 deletions(-) diff --git a/developer/src/kmc-convert/src/converter-messages.ts b/developer/src/kmc-convert/src/converter-messages.ts index a2bcd79683..efa8ac22bf 100644 --- a/developer/src/kmc-convert/src/converter-messages.ts +++ b/developer/src/kmc-convert/src/converter-messages.ts @@ -18,7 +18,7 @@ const SevError = CompilerErrorSeverity.Error | Namespace; export class ConverterMessages { static ERROR_FileNotFound = SevError | 0x0003; - static Error_FileNotFound = (o: { inputFilename: string | null; }) => m( + static Error_FileNotFound = (o?: { inputFilename: string | null; }) => m( this.ERROR_FileNotFound, `Input filename '${def(o?.inputFilename)}' does not exist or could not be loaded.` ); diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index eb92f3a797..5f14adf740 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -15,14 +15,41 @@ interface MessageCharacter { message: string; character: string; }; -// Todo-kmc-convert edit interface -interface ReviewRulesResult { - warningMessage_0: string; - warningMessage_1: string; - warningMessage_2: string; - hasWarning_0: boolean; - hasWarning_1: boolean; - hasWarning_2: boolean; + +interface RuleReview { + warningMessages: string[]; + extraWarning: string; + type: 'RuleReview' | 'UnavailableModifier' | 'UnavailableSuperiorRule' | + 'DuplicateRule' | 'AmbiguousRule' | 'WarningTextSet'; + compare_type: string; + isEarlier: boolean; + // dk_id[0]: prev_dk; dk_id[1]: dk; + dk_id: [number, number]; + // dk_prefix[0]: prev_dk_prefix; dk_prefix[1]: dk_prefix; + dk_prefix: [string, string]; + prevDk_modifier: string; + prevDk_key: string; + Dk_modifier: string; + Dk_key: string; + modifier: string; + key: string; + output: string; +}; + +interface UnavailableModifier extends RuleReview { + type: 'UnavailableModifier'; +}; +interface UnavailableSuperiorRule extends RuleReview { + type: 'UnavailableSuperiorRule'; +}; +interface DuplicateRules extends RuleReview { + type: 'DuplicateRule'; +}; +interface AmbiguousRules extends RuleReview { + type: 'AmbiguousRule'; +}; +interface WarningTextSet extends RuleReview { + type: 'WarningTextSet'; }; export class KmnFileWriter { @@ -150,16 +177,21 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - const warnText = this.reviewRules(uniqueDataRules, k); + let versionOutputCharacter = ''; + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - const versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; + if ((outputCharacter !== undefined) || (outputCharacter !== "")) { + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + if (characterMessage !== null) { + versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; + } + } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -212,16 +244,21 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - const warnText = this.reviewRules(uniqueDataRules, k); - + let versionOutputCharacter = ''; + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - const versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; + if ((outputCharacter !== undefined) || (outputCharacter !== "")) { + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + + if (characterMessage !== null) { + versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; + } + } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -296,14 +333,20 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character + let versionOutputCharacter; - const warnText = this.reviewRules(uniqueDataRules, k); + + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - const versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; + if ((outputCharacter !== undefined) || (outputCharacter !== "")) { + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + if (characterMessage !== null) { + versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; + } + } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -375,12 +418,9 @@ export class KmnFileWriter { + "] > " + versionOutputCharacter + "\n"; - } - } } - if ((warnText[0].indexOf("duplicate") < 0) || (warnText[1].indexOf("duplicate") < 0) || (warnText[2].indexOf("duplicate") < 0)) { data += "\n"; } @@ -398,60 +438,95 @@ export class KmnFileWriter { * @param index the index of a rule in Rule[] * @return a string[] containing possible warnings for a rule */ - private reviewRules(rule: Rule[], index: number): string[] { + public reviewRules(rule: Rule[], index: number): RuleReview { + + const unavailableModiWarnings = { + type: 'UnavailableModifier', + warningMessages: ['', '', ''], + output: '', + } as UnavailableModifier; + + const unavailableSuperiWarnings = { + type: 'UnavailableSuperiorRule', + warningMessages: ['', '', ''], + output: '', + } as UnavailableSuperiorRule; + + const duplicateWarnings = { + type: 'DuplicateRule', + warningMessages: ['', '', ''], + output: '', + } as DuplicateRules; + + const ambiguousWarnings = { + type: 'AmbiguousRule', + warningMessages: ['', '', ''], + output: '', + } as AmbiguousRules; + + const resultWarningTextSet = { + warningMessages: ['', '', ''], + } as WarningTextSet; const keylayoutKmnConverter = new KeylayoutToKmnConverter(this.callbacks, this.options); - const warningText: string[] = Array(3).fill(""); // ------------------------- check unavailable modifiers ------------------------- if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; + unavailableModiWarnings.compare_type = 'unav_C0_C1'; + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings); } } + else if (rule[index].ruleType === "C2") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier : "; - warningText[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(A" - + rule[index].idDeadkey - + ") ) : "; + unavailableSuperiWarnings.compare_type = 'unav_C2'; + unavailableSuperiWarnings.dk_prefix = ['C', 'A']; + unavailableSuperiWarnings.dk_id = [rule[index].idPrevDeadkey, rule[index].idDeadkey]; + unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableSuperiWarnings.Dk_key = rule[index].deadkey; + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings); } + if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; + unavailableModiWarnings.compare_type = 'unav_C2'; + unavailableModiWarnings.modifier = rule[index].modifierKey; + unavailableModiWarnings.key = rule[index].key; + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings); } } - else if (rule[index].ruleType === "C3") { + else if (rule[index].ruleType === "C3") { if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierPrevDeadkey)) { - warningText[0] = "unavailable modifier : "; - warningText[1] = "unavailable superior rule ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) : "; + unavailableSuperiWarnings.compare_type = 'unav_C3'; + unavailableSuperiWarnings.dk_prefix = ['A', '']; + unavailableSuperiWarnings.dk_id = [rule[index].idPrevDeadkey, rule[index].idDeadkey]; + unavailableSuperiWarnings.prevDk_modifier = rule[index].modifierPrevDeadkey; + unavailableSuperiWarnings.prevDk_key = rule[index].prevDeadkey; + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier : "; - warningText[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; + unavailableSuperiWarnings.compare_type = 'unav_C3'; + unavailableSuperiWarnings.prevDk_modifier = ''; + unavailableSuperiWarnings.dk_prefix = ['', 'B']; + unavailableSuperiWarnings.dk_id = [rule[index].idPrevDeadkey, rule[index].idDeadkey]; + unavailableSuperiWarnings.Dk_modifier = rule[index].modifierDeadkey; + unavailableSuperiWarnings.Dk_key = rule[index].deadkey; + unavailableSuperiWarnings.warningMessages = this.createWarningText(unavailableSuperiWarnings, 2); } if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; + unavailableModiWarnings.compare_type = 'unav_C3'; + unavailableModiWarnings.modifier = rule[index].modifierKey; + unavailableModiWarnings.key = rule[index].key; + unavailableModiWarnings.warningMessages = this.createWarningText(unavailableModiWarnings, 2); } } + // ------------------------- check ambiguous/duplicate rules ------------------------- if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { @@ -496,50 +571,52 @@ export class KmnFileWriter { ); if (amb_4_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: later: [" - + amb_4_1[0].modifierPrevDeadkey - + " " - + amb_4_1[0].prevDeadkey - + "] > dk(C" - + amb_2_1[0].idDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_4_1'; + ambiguousWarnings.isEarlier = false; + ambiguousWarnings.dk_prefix = ['C', 'A']; + ambiguousWarnings.dk_id = [amb_4_1[0].idPrevDeadkey, amb_4_1[0].idDeadkey]; + ambiguousWarnings.prevDk_modifier = amb_4_1[0].modifierPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_4_1[0].prevDeadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (amb_2_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: later: [" - + amb_2_1[0].modifierDeadkey - + " " - + amb_2_1[0].deadkey - + "] > dk(A" - + amb_2_1[0].idDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_2_1'; + ambiguousWarnings.isEarlier = false; + ambiguousWarnings.dk_prefix = ['', 'A']; + ambiguousWarnings.dk_id = [amb_2_1[0].idPrevDeadkey, amb_2_1[0].idDeadkey]; + ambiguousWarnings.Dk_modifier = amb_2_1[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_2_1[0].deadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (amb_1_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: [" - + amb_1_1[0].modifierKey - + " " - + amb_1_1[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output))?.character ?? "") - + "\' "); + ambiguousWarnings.compare_type = 'amb_1_1'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.modifier = amb_1_1[0].modifierKey; + ambiguousWarnings.key = amb_1_1[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)); + if (outputCharacter !== null) { + ambiguousWarnings.output = outputCharacter.character; + } + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); + } if (dup_1_1.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: [" - + dup_1_1[0].modifierKey - + " " - + dup_1_1[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output))?.character ?? "") - + "\' "); + duplicateWarnings.compare_type = 'dup_1_1'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.modifier = dup_1_1[0].modifierKey; + duplicateWarnings.key = dup_1_1[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)); + if (outputCharacter !== null) { + duplicateWarnings.output = outputCharacter.character; + } + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 2); } } + if (rule[index].ruleType === "C2") { // 2-2: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C3) @@ -590,65 +667,66 @@ export class KmnFileWriter { ); if (amb_2_2.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: [" - + amb_2_2[0].modifierDeadkey - + " " - + amb_2_2[0].deadkey - + "] > dk(C" - + amb_2_2[0].idDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_2_2'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['', 'C']; + ambiguousWarnings.dk_id = [amb_2_2[0].idPrevDeadkey, amb_2_2[0].idDeadkey]; + ambiguousWarnings.Dk_modifier = amb_2_2[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_2_2[0].deadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); } if (dup_2_2.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); + duplicateWarnings.compare_type = 'dup_2_2'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.dk_prefix = ['', 'C']; + duplicateWarnings.dk_id = [dup_2_2[0].idPrevDeadkey, dup_2_2[0].idDeadkey]; + duplicateWarnings.Dk_modifier = dup_2_2[0].modifierDeadkey; + duplicateWarnings.Dk_key = dup_2_2[0].deadkey; + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); } if (amb_3_3.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: dk(A" - + amb_3_3[0].idDeadkey - + ") + [" - + amb_3_3[0].modifierKey - + " " - + amb_3_3[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output))?.character ?? "") - + "\' "); + ambiguousWarnings.compare_type = 'amb_3_3'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['', 'A']; + ambiguousWarnings.dk_id = [amb_3_3[0].idPrevDeadkey, amb_3_3[0].idDeadkey]; + ambiguousWarnings.modifier = amb_3_3[0].modifierKey; + ambiguousWarnings.key = amb_3_3[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)); + if (outputCharacter !== null) { + ambiguousWarnings.output = outputCharacter.character; + } + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); + } if (dup_3_3.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: dk(A" - + dup_3_3[0].idDeadkey - + ") + [" - + dup_3_3[0].modifierKey - + " " - + dup_3_3[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output))?.character ?? "") - + "\' "); + duplicateWarnings.compare_type = 'dup_3_3'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.dk_id = [dup_3_3[0].idPrevDeadkey, dup_3_3[0].idDeadkey]; + duplicateWarnings.dk_prefix = ['', 'A']; + duplicateWarnings.modifier = dup_3_3[0].modifierKey; + duplicateWarnings.key = dup_3_3[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)); + if (outputCharacter !== null) { + duplicateWarnings.output = outputCharacter.character; + } + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 2); } if (amb_4_2.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: later: [" - + amb_4_2[0].modifierPrevDeadkey - + " " - + amb_4_2[0].prevDeadkey - + "] > dk(C" - + amb_4_2[0].idPrevDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_4_2'; + ambiguousWarnings.isEarlier = false; + ambiguousWarnings.dk_prefix = ['C', '']; + ambiguousWarnings.dk_id = [amb_4_2[0].idPrevDeadkey, amb_4_2[0].idDeadkey]; + ambiguousWarnings.prevDk_modifier = amb_4_2[0].modifierPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_4_2[0].prevDeadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); } } + if (rule[index].ruleType === "C3") { // 2-4 + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(B11) @@ -731,827 +809,119 @@ export class KmnFileWriter { ); // 6-6 dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'Ã' - const dup_6_6 = - rule.filter((curr, idx) => - (curr.ruleType === "C3") - && curr.idDeadkey === rule[index].idDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && (new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output)) - && idx < index - ); + const dup_6_6 = rule.filter((curr, idx) => + (curr.ruleType === "C3") + && curr.idDeadkey === rule[index].idDeadkey + && curr.modifierKey === rule[index].modifierKey + && curr.key === rule[index].key + && (new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output)) + && idx < index + ); if (amb_2_4.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: earlier: [" - + amb_2_4[0].modifierDeadkey - + " " - + amb_2_4[0].deadkey - + "] > dk(A" - + amb_2_4[0].idDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_2_4'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['', 'A']; + ambiguousWarnings.dk_id = [amb_2_4[0].idPrevDeadkey, amb_2_4[0].idDeadkey]; + ambiguousWarnings.Dk_modifier = amb_2_4[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_2_4[0].deadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); } if (amb_6_3.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: dk(C" - + amb_6_3[0].idDeadkey - + ") + [" - + amb_6_3[0].modifierKey - + " " - + amb_6_3[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output))?.character ?? "") - + "\' "); + ambiguousWarnings.compare_type = 'amb_6_3'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['', 'C']; + ambiguousWarnings.dk_id = [amb_6_3[0].idPrevDeadkey, amb_6_3[0].idDeadkey]; + ambiguousWarnings.modifier = amb_6_3[0].modifierKey; + ambiguousWarnings.key = amb_6_3[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)); + if (outputCharacter !== null) { + ambiguousWarnings.output = outputCharacter.character; + } + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 1); } if (dup_6_3.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: dk(C" - + dup_6_3[0].idDeadkey - + ") + [" - + dup_6_3[0].modifierKey - + " " - + dup_6_3[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output))?.character ?? "") - + "\' "); + duplicateWarnings.compare_type = 'dup_6_3'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.dk_prefix = ['', 'C']; + duplicateWarnings.dk_id = [dup_6_3[0].idPrevDeadkey, dup_6_3[0].idDeadkey]; + duplicateWarnings.modifier = dup_6_3[0].modifierKey; + duplicateWarnings.key = dup_6_3[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)); + if (outputCharacter !== null) { + duplicateWarnings.output = outputCharacter.character; + } + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); } if (amb_4_4.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: earlier: [" - + amb_4_4[0].modifierPrevDeadkey - + " " - + amb_4_4[0].prevDeadkey - + "] > dk(C" - + amb_4_4[0].idPrevDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_4_4'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['C', '']; + ambiguousWarnings.dk_id = [amb_4_4[0].idPrevDeadkey, amb_4_4[0].idDeadkey]; + ambiguousWarnings.prevDk_modifier = amb_4_4[0].modifierPrevDeadkey; + ambiguousWarnings.prevDk_key = amb_4_4[0].prevDeadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 0); } if (dup_4_4.length > 0) { - warningText[0] = warningText[0] - + ("duplicate rule: earlier: [" - + dup_4_4[0].modifierPrevDeadkey - + " " - + dup_4_4[0].prevDeadkey - + "] > dk(C" - + dup_4_4[0].idPrevDeadkey - + ") "); + duplicateWarnings.compare_type = 'dup_4_4'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.dk_prefix = ['C', '']; + duplicateWarnings.dk_id = [dup_4_4[0].idPrevDeadkey, dup_4_4[0].idDeadkey]; + duplicateWarnings.prevDk_modifier = dup_4_4[0].modifierPrevDeadkey; + duplicateWarnings.prevDk_key = dup_4_4[0].prevDeadkey; + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 0); } if (amb_5_5.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: dk(B" - + amb_5_5[0].idPrevDeadkey - + ") + [" - + amb_5_5[0].modifierDeadkey - + " " - + amb_5_5[0].deadkey - + "] > dk(B" - + amb_5_5[0].idDeadkey - + ") "); + ambiguousWarnings.compare_type = 'amb_5_5'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['C', 'B']; + ambiguousWarnings.dk_id = [amb_5_5[0].idPrevDeadkey, amb_5_5[0].idDeadkey]; + ambiguousWarnings.Dk_modifier = amb_5_5[0].modifierDeadkey; + ambiguousWarnings.Dk_key = amb_5_5[0].deadkey; + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings); } if (dup_5_5.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: dk(B" - + dup_5_5[0].idPrevDeadkey - + ") + [" - + dup_5_5[0].modifierDeadkey - + " " - + dup_5_5[0].deadkey - + "] > dk(B" - + dup_5_5[0].idDeadkey - + ") "); + duplicateWarnings.compare_type = 'dup_5_5'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.dk_prefix = ['C', 'B']; + duplicateWarnings.dk_id = [dup_5_5[0].idPrevDeadkey, dup_5_5[0].idDeadkey]; + duplicateWarnings.Dk_modifier = rule[index].modifierDeadkey; + duplicateWarnings.Dk_key = rule[index].deadkey; + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 1); } if (amb_6_6.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: dk(B" - + amb_6_6[0].idDeadkey - + ") + [" - + amb_6_6[0].modifierKey - + " " - + amb_6_6[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output))?.character ?? "") - + "\' "); + ambiguousWarnings.compare_type = 'amb_6_6'; + ambiguousWarnings.isEarlier = true; + ambiguousWarnings.dk_prefix = ['', 'B']; + ambiguousWarnings.dk_id = [amb_6_6[0].idPrevDeadkey, amb_6_6[0].idDeadkey]; + ambiguousWarnings.modifier = amb_6_6[0].modifierKey; + ambiguousWarnings.key = amb_6_6[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)); + if (outputCharacter !== null) { + ambiguousWarnings.output = outputCharacter.character; + } + ambiguousWarnings.warningMessages = this.createWarningText(ambiguousWarnings, 2); } if (dup_6_6.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: dk(B" - + dup_6_6[0].idDeadkey - + ") + [" - + dup_6_6[0].modifierKey - + " " - + dup_6_6[0].key - + "] > \'" - + (this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output))?.character ?? "") - + "\' "); - } - } - // In rare cases a rule might not be written out therefore we need to inform the user: - // usually we write the first occurance of an ambiguous C0/C1 rule and comment out the later - // assuming that if several C0/C1 rules are ambiguous the user prefers to use the first C0/C1 rule - // for C2/C3 rules we write the last occurance of an ambiguous rule and comment out the earlier - // assuming that if a C0/C1 and a C2/C3 rule is ambiguous the user prefers to use the C2/C3 rule over the C0/C1 rule - // if both happens, nothing would be written, therefore this messsage - - const extraWarning = "PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! "; - - if (warningText[0] !== "") { - warningText[0] = "c WARNING: " + warningText[0] + "here: "; - - if ((warningText[0].indexOf("earlier:") > 0) && (warningText[0].indexOf("later:") > 0)) { - warningText[0] = warningText[0] + extraWarning; - } - } - if (warningText[1] !== "") { - warningText[1] = "c WARNING: " + warningText[1] + "here: "; - - if ((warningText[1].indexOf("earlier:") > 0) && (warningText[1].indexOf("later:") > 0)) { - warningText[1] = warningText[1] + extraWarning; - } - } - - if (warningText[2] !== "") { - warningText[2] = "c WARNING: " + warningText[2] + "here: "; - - if ((warningText[2].indexOf("earlier:") > 0) && (warningText[2].indexOf("later:") > 0)) { - warningText[2] = warningText[2] + extraWarning; - } - } - - return warningText; - } - - public reviewRules_returnObject(rule: Rule[], index: number): ReviewRulesResult { - - const resultWarnings: ReviewRulesResult = { - warningMessage_0: '', - warningMessage_1: '', - warningMessage_2: '', - hasWarning_0: false, - hasWarning_1: false, - hasWarning_2: false - }; - - const keylayoutKmnConverter = new KeylayoutToKmnConverter(this.callbacks, this.options); - const warningText: string[] = Array(3).fill(""); - - // ------------------------- check unavailable modifiers ------------------------- - - if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; - resultWarnings.warningMessage_2 = "unavailable modifier : "; - resultWarnings.hasWarning_2 = true; - } - } - - else if (rule[index].ruleType === "C2") { - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier : "; - warningText[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(A" - + rule[index].idDeadkey - + ") ) : "; - - resultWarnings.warningMessage_1 = "unavailable modifier : "; - resultWarnings.hasWarning_1 = true; - resultWarnings.warningMessage_2 = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(A" - + rule[index].idDeadkey - + ") ) : "; - resultWarnings.hasWarning_2 = true; - } - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; - - resultWarnings.warningMessage_2 = "unavailable modifier : "; - resultWarnings.hasWarning_2 = true; - } - } - - else if (rule[index].ruleType === "C3") { - - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierPrevDeadkey)) { - warningText[0] = "unavailable modifier : "; - warningText[1] = "unavailable superior rule ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) : "; - resultWarnings.warningMessage_0 = "unavailable modifier : "; - resultWarnings.hasWarning_0 = true; - - resultWarnings.warningMessage_1 = "unavailable superior rule ( [" - + rule[index].modifierPrevDeadkey + " " - + rule[index].prevDeadkey - + "] > dk(A" - + rule[index].idPrevDeadkey - + ") ) : "; - resultWarnings.hasWarning_1 = true; - } - - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierDeadkey)) { - warningText[1] = "unavailable modifier : "; - warningText[2] = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; - resultWarnings.warningMessage_1 = "unavailable modifier : "; - resultWarnings.hasWarning_1 = true; - resultWarnings.warningMessage_2 = "unavailable superior rule ( [" - + rule[index].modifierDeadkey + " " - + rule[index].deadkey - + "] > dk(B" - + rule[index].idDeadkey - + ") ) : "; - resultWarnings.hasWarning_2 = true; - } - - if (!keylayoutKmnConverter.isAcceptableKeymanModifier(rule[index].modifierKey)) { - warningText[2] = "unavailable modifier : "; - resultWarnings.warningMessage_2 = "unavailable modifier : "; - resultWarnings.hasWarning_2 = true; - } - } - // ------------------------- check ambiguous/duplicate rules ------------------------- - - if ((rule[index].ruleType === "C0") || (rule[index].ruleType === "C1")) { - - // 1-1: + [CAPS K_N] > 'N' <-> + [CAPS K_N] > 'A' - const amb_1_1 = rule.filter((curr, idx) => - (curr.ruleType === "C0" || curr.ruleType === "C1") - && curr.modifierPrevDeadkey === "" - && curr.prevDeadkey === "" - && curr.modifierDeadkey === "" - && curr.deadkey === "" - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && new TextDecoder().decode(curr.output) !== new TextDecoder().decode(rule[index].output) - && idx < index - ); - // 1-1: + [CAPS K_N] > 'N' <-> + [CAPS K_N] > 'N' - const dup_1_1 = rule.filter((curr, idx) => - (curr.ruleType === "C0" || curr.ruleType === "C1") - && curr.modifierPrevDeadkey === "" - && curr.prevDeadkey === "" - && curr.modifierDeadkey === "" - && curr.deadkey === "" - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output) - && idx < index - ); - - // 4-1: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > 'Ñ' - const amb_4_1 = rule.filter((curr, idx) => - ((curr.ruleType === "C3")) - && curr.modifierPrevDeadkey === rule[index].modifierKey - && curr.prevDeadkey === rule[index].key - ); - - // 2-1: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > 'Ñ' - const amb_2_1 = rule.filter((curr, idx) => - ((curr.ruleType === "C2")) - && curr.modifierDeadkey === rule[index].modifierKey - && curr.deadkey === rule[index].key - ); - - if (amb_4_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: later: [" - + amb_4_1[0].modifierPrevDeadkey - + " " - + amb_4_1[0].prevDeadkey - + "] > dk(C" - + amb_2_1[0].idDeadkey - + ") "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 + ("ambiguous rule: later: [" - + amb_4_1[0].modifierPrevDeadkey - + " " - + amb_4_1[0].prevDeadkey - + "] > dk(C" - + amb_2_1[0].idDeadkey - + ") "); - resultWarnings.hasWarning_2 = true; - } - - if (amb_2_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: later: [" - + amb_2_1[0].modifierDeadkey - + " " - + amb_2_1[0].deadkey - + "] > dk(A" - + amb_2_1[0].idDeadkey - + ") "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 - + ("ambiguous rule: later: [" - + amb_2_1[0].modifierDeadkey - + " " - + amb_2_1[0].deadkey - + "] > dk(A" - + amb_2_1[0].idDeadkey - + ") "); - resultWarnings.hasWarning_2 = true; - } - - if (amb_1_1.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: [" - + amb_1_1[0].modifierKey - + " " - + amb_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character - + "\' "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 - + ("ambiguous rule: earlier: [" - + amb_1_1[0].modifierKey - + " " - + amb_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_1_1[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; - } - - if (dup_1_1.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: [" - + dup_1_1[0].modifierKey - + " " - + dup_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character - + "\' "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 - + ("duplicate rule: earlier: [" - + dup_1_1[0].modifierKey - + " " - + dup_1_1[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_1_1[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; - } - } - - if (rule[index].ruleType === "C2") { - - // 2-2: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C3) - const amb_2_2 = rule.filter((curr, idx) => - curr.ruleType === "C2" - && curr.modifierDeadkey === rule[index].modifierDeadkey - && curr.deadkey === rule[index].deadkey - && curr.idDeadkey !== rule[index].idDeadkey - && idx < index - ); - - // 2-2: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C11) - const dup_2_2 = rule.filter((curr, idx) => - curr.ruleType === "C2" - && curr.modifierDeadkey === rule[index].modifierDeadkey - && curr.deadkey === rule[index].deadkey - && curr.idDeadkey === rule[index].idDeadkey - && idx < index - ); - - //3-3: dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'B' - const amb_3_3 = rule.filter((curr, idx) => - (curr.ruleType === "C2") - && curr.idDeadkey === rule[index].idDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && new TextDecoder().decode(curr.output) !== new TextDecoder().decode(rule[index].output) - && idx < index - ); - - //3-3: dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'Ã' - const dup_3_3 = rule.filter((curr, idx) => - (curr.ruleType === "C2") - && curr.idDeadkey === rule[index].idDeadkey - && rule[index].uniqueDeadkey === 0 - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output) - && idx < index - ); - - // 4-2: + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(B11) - const amb_4_2 = rule.filter((curr, idx) => - ((curr.ruleType === "C3")) - && curr.modifierPrevDeadkey === rule[index].modifierDeadkey - && curr.prevDeadkey === rule[index].deadkey - && curr.idPrevDeadkey === rule[index].idDeadkey - ); - - if (amb_2_2.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: [" - + amb_2_2[0].modifierDeadkey - + " " - + amb_2_2[0].deadkey - + "] > dk(C" - + amb_2_2[0].idDeadkey - + ") "); - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 - + ("ambiguous rule: earlier: [" - + amb_2_2[0].modifierDeadkey - + " " - + amb_2_2[0].deadkey - + "] > dk(C" - + amb_2_2[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true; - } - - if (dup_2_2.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 + ("duplicate rule: earlier: [" - + dup_2_2[0].modifierDeadkey - + " " - + dup_2_2[0].deadkey - + "] > dk(C" - + dup_2_2[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true; - } - - if (amb_3_3.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: dk(A" - + amb_3_3[0].idDeadkey - + ") + [" - + amb_3_3[0].modifierKey - + " " - + amb_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character - + "\' "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 - + ("ambiguous rule: earlier: dk(A" - + amb_3_3[0].idDeadkey - + ") + [" - + amb_3_3[0].modifierKey - + " " - + amb_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_3_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; - } - - if (dup_3_3.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: dk(A" - + dup_3_3[0].idDeadkey - + ") + [" - + dup_3_3[0].modifierKey - + " " - + dup_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character - + "\' "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 + ("duplicate rule: earlier: dk(A" - + dup_3_3[0].idDeadkey - + ") + [" - + dup_3_3[0].modifierKey - + " " - + dup_3_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_3_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; - } - - if (amb_4_2.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: later: [" - + amb_4_2[0].modifierPrevDeadkey - + " " - + amb_4_2[0].prevDeadkey - + "] > dk(C" - + amb_4_2[0].idPrevDeadkey - + ") "); - resultWarnings.warningMessage_0 = resultWarnings.warningMessage_0 - + ("ambiguous rule: later: [" - + amb_4_2[0].modifierPrevDeadkey - + " " - + amb_4_2[0].prevDeadkey - + "] > dk(C" - + amb_4_2[0].idPrevDeadkey - + ") "); - resultWarnings.hasWarning_0 = true; - } - } - - if (rule[index].ruleType === "C3") { - - // 2-4 + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(B11) - const amb_2_4 = rule.filter((curr, idx) => - ((curr.ruleType === "C2")) - && curr.modifierDeadkey === rule[index].modifierPrevDeadkey - && curr.deadkey === rule[index].prevDeadkey - && curr.idDeadkey === rule[index].idPrevDeadkey - ); - - // 6-3 dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'B' - const amb_6_3 = rule.filter((curr, idx) => - (curr.ruleType === "C2") - && curr.idPrevDeadkey === rule[index].idPrevDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && (new TextDecoder().decode(curr.output) !== new TextDecoder().decode(rule[index].output)) - ); - - // 6-3 dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'Ã' - const dup_6_3 = rule.filter((curr, idx) => - (curr.ruleType === "C2") - && curr.idPrevDeadkey === rule[index].idPrevDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output) - ); - - // 4-4 + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C1) - const amb_4_4 = rule.filter((curr, idx) => - curr.ruleType === "C3" - && curr.modifierPrevDeadkey === rule[index].modifierPrevDeadkey - && curr.idPrevDeadkey !== rule[index].idPrevDeadkey - && curr.prevDeadkey === rule[index].prevDeadkey - && rule[index].uniquePrevDeadkey !== 0 - && idx < index - ); - - // 4-4 + [CAPS K_N] > dk(C11) <-> + [CAPS K_N] > dk(C11) - const dup_4_4 = rule.filter((curr, idx) => - curr.ruleType === "C3" - && curr.modifierPrevDeadkey === rule[index].modifierPrevDeadkey - && curr.prevDeadkey === rule[index].prevDeadkey - && curr.idPrevDeadkey === rule[index].idPrevDeadkey - && idx < index - ); - - // 5-5 dk(C1) + [SHIFT CAPS K_A] > dk(C2) <-> dk(C1) + [SHIFT CAPS K_A] > dk(C3) - const amb_5_5 = rule.filter((curr, idx) => ( - (curr.ruleType === "C3") - && curr.idPrevDeadkey === rule[index].idPrevDeadkey - && curr.modifierDeadkey === rule[index].modifierDeadkey - && curr.deadkey === rule[index].deadkey - && curr.idDeadkey === rule[index].idDeadkey) - && idx < index - && (rule[index].uniqueDeadkey !== 0 || rule[index].uniquePrevDeadkey !== 0) - ); - - // 5-5 dk(C1) + [SHIFT CAPS K_A] > dk(C2) <-> dk(C1) + [SHIFT CAPS K_A] > dk(C2) - const dup_5_5 = rule.filter((curr, idx) => - (curr.ruleType === "C3") - && curr.idPrevDeadkey === rule[index].idPrevDeadkey - && curr.modifierPrevDeadkey === rule[index].modifierPrevDeadkey - && curr.prevDeadkey === rule[index].prevDeadkey - && curr.modifierDeadkey === rule[index].modifierDeadkey - && curr.deadkey === rule[index].deadkey - && curr.idDeadkey === rule[index].idDeadkey - && rule[index].uniqueDeadkey === 0 - && idx < index - ); - - // 6-6 dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'B' - const amb_6_6 = rule.filter((curr, idx) => - (curr.ruleType === "C3") - && curr.idPrevDeadkey === rule[index].idPrevDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && (new TextDecoder().decode(curr.output) !== new TextDecoder().decode(rule[index].output)) - && idx < index - ); - - // 6-6 dk(C11) + [SHIFT CAPS K_A] > 'Ã' <-> dk(C11) + [SHIFT CAPS K_A] > 'Ã' - const dup_6_6 = - rule.filter((curr, idx) => - (curr.ruleType === "C3") - && curr.idDeadkey === rule[index].idDeadkey - && curr.modifierKey === rule[index].modifierKey - && curr.key === rule[index].key - && (new TextDecoder().decode(curr.output) === new TextDecoder().decode(rule[index].output)) - && idx < index - ); - - if (amb_2_4.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: earlier: [" - + amb_2_4[0].modifierDeadkey - + " " - + amb_2_4[0].deadkey - + "] > dk(A" - + amb_2_4[0].idDeadkey - + ") "); - resultWarnings.warningMessage_0 = resultWarnings.warningMessage_0 + ("ambiguous rule: earlier: [" - + amb_2_4[0].modifierDeadkey - + " " - + amb_2_4[0].deadkey - + "] > dk(A" - + amb_2_4[0].idDeadkey - + ") "); - resultWarnings.hasWarning_0 = true; - } - - if (amb_6_3.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: dk(C" - + amb_6_3[0].idDeadkey - + ") + [" - + amb_6_3[0].modifierKey - + " " - + amb_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character - + "\' "); - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 - + ("ambiguous rule: earlier: dk(C" - + amb_6_3[0].idDeadkey - + ") + [" - + amb_6_3[0].modifierKey - + " " - + amb_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_1 = true; - } - - if (dup_6_3.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: dk(C" - + dup_6_3[0].idDeadkey - + ") + [" - + dup_6_3[0].modifierKey - + " " - + dup_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character - + "\' "); - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 - + ("duplicate rule: earlier: dk(C" - + dup_6_3[0].idDeadkey - + ") + [" - + dup_6_3[0].modifierKey - + " " - + dup_6_3[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_3[0].output)).character - + "\' "); - resultWarnings.hasWarning_1 = true; - } - - if (amb_4_4.length > 0) { - warningText[0] = warningText[0] - + ("ambiguous rule: earlier: [" - + amb_4_4[0].modifierPrevDeadkey - + " " - + amb_4_4[0].prevDeadkey - + "] > dk(C" - + amb_4_4[0].idPrevDeadkey - + ") "); - resultWarnings.warningMessage_0 = resultWarnings.warningMessage_0 + ("ambiguous rule: earlier: [" - + amb_4_4[0].modifierPrevDeadkey - + " " - + amb_4_4[0].prevDeadkey - + "] > dk(C" - + amb_4_4[0].idPrevDeadkey - + ") "); - resultWarnings.hasWarning_0 = true; - } - - if (dup_4_4.length > 0) { - warningText[0] = warningText[0] - + ("duplicate rule: earlier: [" - + dup_4_4[0].modifierPrevDeadkey - + " " - + dup_4_4[0].prevDeadkey - + "] > dk(C" - + dup_4_4[0].idPrevDeadkey - + ") "); - resultWarnings.warningMessage_0 = resultWarnings.warningMessage_0 + ("duplicate rule: earlier: [" - + dup_4_4[0].modifierPrevDeadkey - + " " - + dup_4_4[0].prevDeadkey - + "] > dk(C" - + dup_4_4[0].idPrevDeadkey - + ") "); - resultWarnings.hasWarning_0 = true; - } - - if (amb_5_5.length > 0) { - warningText[1] = warningText[1] - + ("ambiguous rule: earlier: dk(B" - + amb_5_5[0].idPrevDeadkey - + ") + [" - + amb_5_5[0].modifierDeadkey - + " " - + amb_5_5[0].deadkey - + "] > dk(B" - + amb_5_5[0].idDeadkey - + ") "); - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 + ("ambiguous rule: earlier: dk(B" - + amb_5_5[0].idPrevDeadkey - + ") + [" - + amb_5_5[0].modifierDeadkey - + " " - + amb_5_5[0].deadkey - + "] > dk(B" - + amb_5_5[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true; - } - - if (dup_5_5.length > 0) { - warningText[1] = warningText[1] - + ("duplicate rule: earlier: dk(B" - + dup_5_5[0].idPrevDeadkey - + ") + [" - + dup_5_5[0].modifierDeadkey - + " " - + dup_5_5[0].deadkey - + "] > dk(B" - + dup_5_5[0].idDeadkey - + ") "); - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 + ("duplicate rule: earlier: dk(B" - + dup_5_5[0].idPrevDeadkey - + ") + [" - + dup_5_5[0].modifierDeadkey - + " " - + dup_5_5[0].deadkey - + "] > dk(B" - + dup_5_5[0].idDeadkey - + ") "); - resultWarnings.hasWarning_1 = true; - } - - if (amb_6_6.length > 0) { - warningText[2] = warningText[2] - + ("ambiguous rule: earlier: dk(B" - + amb_6_6[0].idDeadkey - + ") + [" - + amb_6_6[0].modifierKey - + " " - + amb_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character - + "\' "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 + ("ambiguous rule: earlier: dk(B" - + amb_6_6[0].idDeadkey - + ") + [" - + amb_6_6[0].modifierKey - + " " - + amb_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(amb_6_6[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; - } - - if (dup_6_6.length > 0) { - warningText[2] = warningText[2] - + ("duplicate rule: earlier: dk(B" - + dup_6_6[0].idDeadkey - + ") + [" - + dup_6_6[0].modifierKey - + " " - + dup_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character - + "\' "); - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 + ("duplicate rule: earlier: dk(B" - + dup_6_6[0].idDeadkey - + ") + [" - + dup_6_6[0].modifierKey - + " " - + dup_6_6[0].key - + "] > \'" - + this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)).character - + "\' "); - resultWarnings.hasWarning_2 = true; + duplicateWarnings.compare_type = 'dup_6_6'; + duplicateWarnings.isEarlier = true; + duplicateWarnings.dk_prefix = ['', 'B']; + duplicateWarnings.dk_id = [dup_6_6[0].idPrevDeadkey, dup_6_6[0].idDeadkey]; + duplicateWarnings.modifier = dup_6_6[0].modifierKey; + duplicateWarnings.key = dup_6_6[0].key; + const outputCharacter = this.writeCharacterOrUnicode(new TextDecoder().decode(dup_6_6[0].output)); + if (outputCharacter !== null) { + duplicateWarnings.output = outputCharacter.character; + } + duplicateWarnings.warningMessages = this.createWarningText(duplicateWarnings, 2); } } @@ -1562,54 +932,169 @@ export class KmnFileWriter { // assuming that if a C0/C1 and a C2/C3 rule is ambiguous the user prefers to use the C2/C3 rule over the C0/C1 rule // if both happens, nothing would be written, therefore this messsage - const extraWarning = "PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! "; + const extraWarning = "PLEASE CHECK THAT RULE AS IT WILL NOT BE WRITTEN !"; - if (warningText[0] !== "") { - warningText[0] = "c WARNING: " + warningText[0] + "here: "; - - if ((warningText[0].indexOf("earlier:") > 0) && (warningText[0].indexOf("later:") > 0)) { - warningText[0] = warningText[0] + extraWarning; - } - } - if (resultWarnings.warningMessage_0) { - resultWarnings.warningMessage_0 = "c WARNING: " + resultWarnings.warningMessage_0 + "here: "; - - if ((resultWarnings.warningMessage_0.indexOf("earlier:") > 0) && (resultWarnings.warningMessage_0.indexOf("later:") > 0)) { - resultWarnings.warningMessage_0 = resultWarnings.warningMessage_0 + extraWarning; + for (let i = 0; i < 3; i++) { + if (ambiguousWarnings.warningMessages[i] !== "") { + if ((ambiguousWarnings.warningMessages[i].indexOf("earlier:") > -1) && (ambiguousWarnings.warningMessages[i].indexOf("later:") > -1)) { + ambiguousWarnings.warningMessages[i] = ambiguousWarnings.warningMessages[i] + extraWarning; + } } } - if (warningText[1] !== "") { - warningText[1] = "c WARNING: " + warningText[1] + "here: "; - if ((warningText[1].indexOf("earlier:") > 0) && (warningText[1].indexOf("later:") > 0)) { - warningText[1] = warningText[1] + extraWarning; - } - } - if (resultWarnings.warningMessage_1 !== "") { - resultWarnings.warningMessage_1 = "c WARNING: " + resultWarnings.warningMessage_1 + "here: "; - if ((resultWarnings.warningMessage_1.indexOf("earlier:") > 0) && (resultWarnings.warningMessage_1.indexOf("later:") > 0)) { - resultWarnings.warningMessage_1 = resultWarnings.warningMessage_1 + extraWarning; - } + for (let i = 0; i < 3; i++) { + const completeWarning = + unavailableSuperiWarnings.warningMessages[i] + + duplicateWarnings.warningMessages[i] + + ambiguousWarnings.warningMessages[i] + + unavailableModiWarnings.warningMessages[i]; + + completeWarning ? (resultWarningTextSet.warningMessages[i] = "c WARNING: " + completeWarning + " here: ") : resultWarningTextSet.warningMessages[i] = ''; } - if (warningText[2] !== "") { - warningText[2] = "c WARNING: " + warningText[2] + "here: "; - - if ((warningText[2].indexOf("earlier:") > 0) && (warningText[2].indexOf("later:") > 0)) { - warningText[2] = warningText[2] + extraWarning; - } - } - - if (resultWarnings.warningMessage_2 !== "") { - resultWarnings.warningMessage_2 = "c WARNING: " + resultWarnings.warningMessage_2 + "here: "; - - if ((resultWarnings.warningMessage_2.indexOf("earlier:") > 0) && (resultWarnings.warningMessage_2.indexOf("later:") > 0)) { - resultWarnings.warningMessage_2 = resultWarnings.warningMessage_2 + extraWarning; - } - } - return resultWarnings; + return resultWarningTextSet; } + /** + * @brief take a child object of RuleReview and return the appropriate warning message array + * @param inObj : an object containing filtered data for a specified comparison + * @param posWarning : index specifying to which element of the warning message array a warning message will be added: + * outMsg[0]: Warning for part 1 of a rule (e.g. modifier_prev_dk + key_prev_dk > prev_dk) + * outMsg[1]: Warning for part 2 of a rule (e.g. (prev_dk +) modifier_dk + key_dk > dk) + * outMsg[2]: Warning for part 3 of a rule (e.g. (dk +) modifier+key > output) + * see here on parts of a rule: + * https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.16sx096j6jmy + * @return outMsg the warning message array for all parts + */ + public createWarningText(inObj: RuleReview, posWarning: number = 2): string[] { + + const outMsg = [...inObj.warningMessages]; + + if (inObj.compare_type === 'unav_C0_C1') { + outMsg[posWarning] = 'unavailable modifier '; + } + + if (inObj.compare_type === 'unav_C2') { + // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' + if (inObj.Dk_modifier) { + outMsg[1] = 'unavailable modifier '; + outMsg[2] = 'unavailable superior rule ( [' + + inObj.Dk_modifier + ' ' + + inObj.Dk_key + + '] > dk(' + + inObj.dk_prefix[1] + + inObj.dk_id[1] + + ') ) : '; + } + + if (inObj.modifier) { + outMsg[2] = 'unavailable modifier '; + } + } + + if (inObj.compare_type === 'unav_C3') { + + // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' + if (inObj.prevDk_modifier) { + outMsg[0] = 'unavailable modifier '; + outMsg[1] = 'unavailable superior rule ( [' + + inObj.prevDk_modifier + ' ' + + inObj.prevDk_key + + '] > dk(' + + inObj.dk_prefix[0] + + inObj.dk_id[0] + + ') ) : '; + } + + + // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' + if (inObj.Dk_modifier) { + outMsg[1] += 'unavailable modifier '; + outMsg[2] = 'unavailable superior rule ( [' + + inObj.Dk_modifier + ' ' + + inObj.Dk_key + + '] > dk(' + + inObj.dk_prefix[1] + + inObj.dk_id[1] + + ') ) : '; + } + + if (inObj.modifier) { + outMsg[2] = 'unavailable modifier '; + } + } + + if (inObj.compare_type === 'amb_1_1' || inObj.compare_type === 'dup_1_1') { + + outMsg[posWarning] = inObj.warningMessages[posWarning] + + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': [' + inObj.modifier + ' ' + inObj.key + '] > \'' + + inObj.output + '\' '; + } + + + if (inObj.compare_type === 'amb_2_2' || inObj.compare_type === 'dup_2_2' + || inObj.compare_type === 'amb_2_1' + || inObj.compare_type === 'amb_2_4') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': [' + inObj.Dk_modifier + ' ' + inObj.Dk_key + '] > dk(' + + inObj.dk_prefix[1] + inObj.dk_id[1] + ') '); + + if (outMsg[posWarning].indexOf(textsegment) === -1) + outMsg[posWarning] += textsegment; + } + + + if (inObj.compare_type === 'amb_4_4' || inObj.compare_type === 'dup_4_4' + || inObj.compare_type === 'amb_4_1' + || inObj.compare_type === 'amb_4_2') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': [' + inObj.prevDk_modifier + ' ' + inObj.prevDk_key + '] > dk(' + + inObj.dk_prefix[0] + inObj.dk_id[0] + ') '); + + if (outMsg[posWarning].indexOf(textsegment) === -1) + outMsg[posWarning] += textsegment; + } + + + if (inObj.compare_type === 'amb_5_5' || inObj.compare_type === 'dup_5_5') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] + ") + [" + + inObj.Dk_modifier + " " + inObj.Dk_key + "] > " + + 'dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") "); + + if (outMsg[1].indexOf(textsegment) === -1) + outMsg[1] += textsegment; + } + + + if (inObj.compare_type === 'amb_6_3' || inObj.compare_type === 'dup_6_3' + || inObj.compare_type === 'amb_3_3' || inObj.compare_type === 'dup_3_3' + || inObj.compare_type === 'amb_6_6' || inObj.compare_type === 'dup_6_6') { + + const textsegment = ( + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' + + (inObj.isEarlier ? 'earlier' : 'later') + + ': dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") + [" + + inObj.modifier + " " + inObj.key + "] > \'" + + inObj.output + "\' "); + + if (outMsg[posWarning].indexOf(textsegment) === -1) + outMsg[posWarning] += textsegment; + } + + return outMsg; + } /** * @brief member function to write a character as Unicode Character or Unicode Codepoint depending on the character that is to be written * @param ctr : string - the character to be written @@ -1618,7 +1103,7 @@ export class KmnFileWriter { * a non-control character will be written as itself ( 'A', '1', '፩', '😎') * null in case of an empty string or null or undefined input */ - public writeCharacterOrUnicode(ctr: string, msg: string = ""): MessageCharacter { + public writeCharacterOrUnicode(ctr: string, msg: string = ""): MessageCharacter | null { if ((ctr === null) || (ctr === undefined)) { return null; @@ -1673,7 +1158,7 @@ export class KmnFileWriter { // add a warning message if (msg !== "") { - msg = msg + "; " + msg_control + msg_entity; + msg = msg + msg_control + msg_entity; } if ((msg === "") && (msg_entity !== "" || msg_control !== "")) { msg = "c WARNING: " + msg_entity + msg_control; diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 48978874cd..fa08b1e77f 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -11,7 +11,6 @@ import 'mocha'; import { assert } from 'chai'; import KEYMAN_VERSION from "@keymanapp/keyman-version"; import { compilerTestCallbacks, compilerTestOptions, makePathToFixture } from './helpers/index.js'; -import { KeylayoutXMLSourceFile } from '../../common/web/utils/src/types/keylayout/keylayout-xml.js'; import { KeylayoutToKmnConverter, ProcessedData, Rule } from '../src/keylayout-to-kmn/keylayout-to-kmn-converter.js'; import { KmnFileWriter } from '../src/keylayout-to-kmn/kmn-file-writer.js'; import { KeylayoutFileReader } from '../src/keylayout-to-kmn/keylayout-file-reader.js'; @@ -28,7 +27,7 @@ describe('KmnFileWriter', function () { const sutR = new KeylayoutFileReader(compilerTestCallbacks); const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.unitTestEndpoints.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.unitTestEndpoints.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); it('writeDataRules() should return true (no error) if written', async function () { const result = sutW.writeDataRules(converted); @@ -43,7 +42,7 @@ describe('KmnFileWriter', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); const inputFilename = makePathToFixture('../data/Test.keylayout'); const read = sutR.read(compilerTestCallbacks.loadFile(inputFilename)); - const converted = sut.unitTestEndpoints.convert(read as KeylayoutXMLSourceFile, inputFilename.replace(/\.keylayout$/, '.kmn')); + const converted = sut.unitTestEndpoints.convert(read, inputFilename.replace(/\.keylayout$/, '.kmn')); const outExpectedFirst: string = "c ..................................................................................................................\n" @@ -64,15 +63,8 @@ describe('KmnFileWriter', function () { it(('writeKmnFileHeader should return store text with filename ').padEnd(62, " ") + 'on correct input', async function () { const writtenCorrectName = sutW.writeKmnFileHeader(converted); - assert.isNotNull(converted); - assert.equal(writtenCorrectName, (outExpectedFirst + (converted.keylayoutFilename ?? "") + outExpectedLast)); + assert.equal(writtenCorrectName, (outExpectedFirst + (converted?.keylayoutFilename ?? "") + outExpectedLast)); }); - it(('writeKmnFileHeader should return no text with null filename ').padEnd(62, " ") + 'on correct input', async function () { - const writtenEmptytName = sutW.writeKmnFileHeader(null); - assert.equal(writtenEmptytName, ''); - }); - - }); describe('convertToUnicodeCharacter ', function () { @@ -103,16 +95,8 @@ describe('KmnFileWriter', function () { ["␤", '␤'], ["␕", '␕'], ["", ''], - [null, undefined], - ["<", '<'], - ["&Gt", undefined], - ["U+D801", undefined], - ["�", undefined], - ["�", undefined], - ["�", undefined], - ["U+D801", undefined], - ["&#xmmm;", undefined], - ["�", undefined], + [undefined, undefined], + [null, undefined] ].forEach(function (values) { it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { const result = sutW.convertToUnicodeCharacter(values[0] as string); @@ -121,44 +105,6 @@ describe('KmnFileWriter', function () { }); }); - describe('writeCharacterOrUnicode and return values', function () { - const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); - [ - ["A", "A", "Msg; "], - ["ሴ", "ሴ", "Msg; "], - ["😀", "😀", "Msg; "], - ["ẘ", "ẘ", "Msg; "], - ["U+0001", "U+0001", "Msg; Use of a control character "], - ["U+0061", "a", "Msg; "], - ["", "U+0002", "Msg; Use of a control character "], - ["ሴ", 'ሴ', "Msg; "], - ["", "U+0003", "Msg; Use of a control character "], - ["ሺ", "ሺ", "Msg; "], - ["", "U+0006", "Msg; Use of a control character "], - ['', '', 'Msg; empty output or unsupported numerical html entity: '], - ].forEach(function (values) { - it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg"); - assert.isNotNull(result); - assert.equal(result.character, values[1]); - assert.equal(result.message, values[2]); - }); - }); - }); - - describe('writeCharacterOrUnicode and return null for result.message and result.character', function () { - const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); - [ - [null, null], - [undefined, null], - - ].forEach(function (values) { - it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { - const result = sutW.writeCharacterOrUnicode(values[0], ""); - assert.isNull(result); - }); - }); - }); describe('reviewRules messages', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); @@ -166,46 +112,41 @@ describe('KmnFileWriter', function () { [[new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'UNAVAILABLE', 'K_A', new TextEncoder().encode('A'))], [''], [''], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: ']], [[new Rule("C1", '', '', 0, 0, 'CAPS', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_B', new TextEncoder().encode('B'))], [''], [''], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: ']], [[new Rule("C2", '', '', 0, 0, 'CAPS', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], [''], [''], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: ']], - [[new Rule("C2", '', '', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], + [[new Rule("C2", '', '', 1, 1, 'UNAVAILABLE_dk', 'K_EQUAL', 2, 2, 'UNAVAILABLE', 'K_C', new TextEncoder().encode('C'),)], [''], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: ']], + ['c WARNING: unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(A2) ) : unavailable modifier here: ']], - [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : here: ']], + [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 1, 1, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], + ['c WARNING: unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_prev_dk K_D] > dk(A1) ) : unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [UNAVAILABLE_dk K_EQUAL] > dk(B0) ) : here: ']], - [[new Rule("C3", 'UNAVAILABLE_prev_dk', 'K_D', 0, 0, 'UNAVAILABLE_dk', 'K_EQUAL', 0, 0, 'UNAVAIL', 'K_C', new TextEncoder().encode('D'),)], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: ']], - - [[new Rule("C3", 'CAPS', 'K_D', 0, 0, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], + [[new Rule("C3", 'CAPS', 'K_D', 1, 1, 'RALT', 'K_EQUAL', 0, 0, 'SHIFT', 'K_C', new TextEncoder().encode('D'),)], [''], [''], ['']], - [[new Rule("C3", 'X', 'K_X', 0, 0, 'Y', 'K_Y', 0, 0, 'SHIFT', 'K_Z', new TextEncoder().encode('D'),)], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable modifier : here: '], - ['c WARNING: unavailable superior rule ( [Y K_Y] > dk(B0) ) : here: ']], + [[new Rule("C3", 'X', 'K_X', 1, 1, 'Y', 'K_Y', 0, 0, 'SHIFT', 'K_Z', new TextEncoder().encode('D'),)], + ['c WARNING: unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [X K_X] > dk(A1) ) : unavailable modifier here: '], + ['c WARNING: unavailable superior rule ( [Y K_Y] > dk(B0) ) : here: ']], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule " ' + (values[0][0] as Rule).ruleType as string + ' "') + 'should create "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { - const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 0); + const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 0).warningMessages; assert.equal(result[0], values[1][0]); assert.equal(result[1], values[2][0]); assert.equal(result[2], values[3][0]); @@ -213,6 +154,7 @@ describe('KmnFileWriter', function () { }); }); + describe('reviewRules messages duplicate and ambiguous', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); [ @@ -220,9 +162,9 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: duplicate rule: earlier: dk(B0) + [SHIFT K_B] > dk(B0) here: "], - ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ["c WARNING: duplicate rule: earlier: dk(C0) + [SHIFT K_B] > dk(B0) here: "], + ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], //6-6 dup [[ @@ -230,7 +172,7 @@ describe('KmnFileWriter', function () { new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], [''], [""], - ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: duplicate rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], //6-6 amb [[ @@ -238,29 +180,29 @@ describe('KmnFileWriter', function () { new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),], [''], [""], - ["c WARNING: ambiguous rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: ambiguous rule: earlier: dk(B0) + [CAPS K_C] > 'X' here: "]], // 5-5 amb [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 1, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: ambiguous rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], [''], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ["c WARNING: ambiguous rule: earlier: dk(C0) + [NCAPS K_B] > dk(B0) here: "], [''], ], // 5-5 dup [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_B', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], - ["c WARNING: duplicate rule: earlier: dk(B0) + [NCAPS K_B] > dk(B0) here: "], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ["c WARNING: duplicate rule: earlier: dk(C0) + [NCAPS K_B] > dk(B0) here: "], ['']], // 4-2 amb [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'LALT', 'K_A', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], + ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], [''], ['']], @@ -268,7 +210,7 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 1, 1, 'NCAPS', 'K_E', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], - ['c WARNING: ambiguous rule: earlier: [LALT K_A] > dk(C0) here: '], + ['c WARNING: ambiguous rule: earlier: [LALT K_A] > dk(C0) here: '], [""], [''],], @@ -276,7 +218,7 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'LALT', 'K_A', 0, 0, 'NCAPS', 'K_E', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('X')),], - ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], + ['c WARNING: duplicate rule: earlier: [LALT K_A] > dk(C0) here: '], [''], ['']], @@ -284,7 +226,7 @@ describe('KmnFileWriter', function () { [[ new Rule("C3", 'LALT', 'K_A', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'LALT', 'K_A', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], - ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], + ['c WARNING: ambiguous rule: later: [LALT K_A] > dk(C0) here: '], [''], ['']], @@ -293,7 +235,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], [''], - ["c WARNING: duplicate rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], + ["c WARNING: duplicate rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], [''],], // 6-3 amb @@ -301,14 +243,14 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'CTRL', 'K_D', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),], [''], - ["c WARNING: ambiguous rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], + ["c WARNING: ambiguous rule: earlier: dk(C0) + [CAPS K_C] > 'X' here: "], [''],], // 2-4 amb [[ new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C3", 'SHIFT', 'K_B', 0, 0, 'NCAPS', 'K_E', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], - ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(A0) here: '], + ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(A0) here: '], [''], ['']], @@ -317,7 +259,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 1, 1, 'RALT', 'K_F', new TextEncoder().encode('Y')),], [''], - ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(C0) here: '], + ['c WARNING: ambiguous rule: earlier: [SHIFT K_B] > dk(C0) here: '], ['']], // 2-2 dup @@ -325,7 +267,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')), new Rule("C2", '', '', 0, 0, 'SHIFT', 'K_B', 0, 0, 'RALT', 'K_F', new TextEncoder().encode('Y')),], [''], - ['c WARNING: duplicate rule: earlier: [SHIFT K_B] > dk(C0) here: '], + ['c WARNING: duplicate rule: earlier: [SHIFT K_B] > dk(C0) here: '], ['']], // 3-3 dup @@ -334,7 +276,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X')),], [''], [''], - ["c WARNING: duplicate rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: duplicate rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], // 3-3 amb [[ @@ -342,7 +284,7 @@ describe('KmnFileWriter', function () { new Rule("C2", '', '', 0, 0, 'NCAPS', 'K_E', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y')),], [''], [''], - ["c WARNING: ambiguous rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], + ["c WARNING: ambiguous rule: earlier: dk(A0) + [CAPS K_C] > 'X' here: "]], // 2-1 amb [[ @@ -350,7 +292,7 @@ describe('KmnFileWriter', function () { new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'RALT', 'K_B', new TextEncoder().encode('Y'))], [''], [''], - ['c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) here: ']], + ['c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) here: ']], // 1-1 amb [[ @@ -358,7 +300,7 @@ describe('KmnFileWriter', function () { new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('Y'))], [''], [''], - ["c WARNING: ambiguous rule: earlier: [CAPS K_C] > 'X' here: "]], + ["c WARNING: ambiguous rule: earlier: [CAPS K_C] > 'X' here: "]], // 1-1 amb [[ @@ -366,11 +308,11 @@ describe('KmnFileWriter', function () { new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'CAPS', 'K_C', new TextEncoder().encode('X'))], [''], [''], - ["c WARNING: duplicate rule: earlier: [CAPS K_C] > 'X' here: "]], + ["c WARNING: duplicate rule: earlier: [CAPS K_C] > 'X' here: "]], ].forEach(function (values: (string[] | Rule[])[], index: number) { it('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "' + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { - const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 1); + const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 1).warningMessages; assert.equal(result[0], values[1][0]); assert.equal(result[1], values[2][0]); assert.equal(result[2], values[3][0]); @@ -387,10 +329,10 @@ describe('KmnFileWriter', function () { ], [''], [''], - ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' here: PLEASE CHECK THE FOLLOWING RULE AS IT WILL NOT BE WRITTEN ! "]], + ["c WARNING: ambiguous rule: later: [RALT K_B] > dk(A0) ambiguous rule: earlier: [RALT K_B] > 'X' PLEASE CHECK THAT RULE AS IT WILL NOT BE WRITTEN ! here: "]], ].forEach(function (values: (string[] | Rule[])[], index: number) { it(('rule ' + (values[0][0] as Rule).ruleType as string + ' should create " ' + ' "') + values[1] + ' | ' + values[2] + ' | ' + values[3] + '"', async function () { - const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 2); + const result: string[] = sutW.unitTestEndpoints.reviewRules(values[0] as Rule[], 2).warningMessages; assert.equal(result[0], values[1][0]); assert.equal(result[1], values[2][0]); assert.equal(result[2], values[3][0]); @@ -496,13 +438,8 @@ describe('KmnFileWriter', function () { rules: values[0] as Rule[] }; const result1 = sutW.writeDataRules(data); - assert.equal(result1, values[1][0]); + assert.isTrue(result1 === values[1][0]); }); - - }); - it(('null should create empty string '), async function () { - const result1 = sutW.writeDataRules(null); - assert.equal(result1, ''); }); }); From 04ae3864c33da2d686aca983ddbea67e4457b6b5 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 2 Jul 2026 18:03:05 +0200 Subject: [PATCH 28/33] feat(developer):kmc-convert fix problems from merge --- .../src/keylayout-to-kmn/kmn-file-writer.ts | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 461ce99494..5f14adf740 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -52,37 +52,6 @@ interface WarningTextSet extends RuleReview { type: 'WarningTextSet'; }; -}; -//interface UnavailableModifier /*extends RuleReview*/ { -/*interface UnavailableModifier { - type: 'UnavailableModifier'; - isEarlier: boolean; - isused: boolean; - context: string; - prevDK_modifier: string; - prevDK_key: string; - DK_modifier: string; - DK_key: string; - modifier: string; - key: string; - output: string; - warningMessage: string[]; -};*/ -interface RuleReview { - type: 'RuleReview'; - isEarlier: boolean; - isused: boolean; - context: string; - prevDK_modifier: string; - prevDK_key: string; - DK_modifier: string; - DK_key: string; - modifier: string; - key: string; - output: string; - - warningMessages: string[]; -}; export class KmnFileWriter { constructor(private callbacks: CompilerCallbacks, private options: CompilerOptions) { }; From 14b2e8be46ee2d4d79c7d1eeb4b1b99c845ef029 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 2 Jul 2026 18:23:51 +0200 Subject: [PATCH 29/33] feat(developer):kmc-convert fix problems from merge; add tests --- .../kmc-convert/test/kmn-file-writer.tests.ts | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts index 896031f1dc..64f0f3762c 100644 --- a/developer/src/kmc-convert/test/kmn-file-writer.tests.ts +++ b/developer/src/kmc-convert/test/kmn-file-writer.tests.ts @@ -108,7 +108,7 @@ describe('KmnFileWriter', function () { describe('reviewRules messages', function () { const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); - [/* + [ [[new Rule("C0", '', '', 0, 0, '', '', 0, 0, 'UNAVAILABLE', 'K_A', new TextEncoder().encode('A'))], [''], [''], @@ -442,5 +442,42 @@ describe('KmnFileWriter', function () { }); }); }); +describe('writeCharacterOrUnicode and return values', function () { + const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); + [ + ["A", "A", "Msg "], + ["ሴ", "ሴ", "Msg "], + ["😀", "😀", "Msg "], + ["ẘ", "ẘ", "Msg "], + ["U+0001", "U+0001", "Msg Use of a control character "], + ["U+0061", "a", "Msg "], + ["", "U+0002", "Msg Use of a control character "], + ["ሴ", 'ሴ', "Msg "], + ["", "U+0003", "Msg Use of a control character "], + ["ሺ", "ሺ", "Msg "], + ["", "U+0006", "Msg Use of a control character "], + ['', '', 'Msg empty output or unsupported numerical html entity: '], + ].forEach(function (values) { + it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { + const result = sutW.writeCharacterOrUnicode(values[0] as string, "Msg "); + assert.isNotNull(result); + assert.equal(result.character, values[1]); + assert.equal(result.message, values[2]); + }); + }); + }); + describe('writeCharacterOrUnicode and return null for result.message and result.character', function () { + const sutW = new KmnFileWriter(compilerTestCallbacks, compilerTestOptions); + [ + [null, null], + [undefined, null], + + ].forEach(function (values) { + it(('should convert "' + values[0] + '"').padEnd(25, " ") + 'to "' + values[1] + '"', async function () { + const result = sutW.writeCharacterOrUnicode(values[0], ""); + assert.isNull(result); + }); + }); + }); }); From 39c516164c792ee8c70e9630b4d1dbf4d15ef255 Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 2 Jul 2026 19:11:05 +0200 Subject: [PATCH 30/33] feat(developer): use await for async run function --- .../src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts | 1 - .../src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 5f14adf740..04db7a1a1d 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -253,7 +253,6 @@ export class KmnFileWriter { if ((outputCharacter !== undefined) || (outputCharacter !== "")) { const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - if (characterMessage !== null) { versionOutputCharacter = characterMessage.character; warnText[2] = characterMessage.message; diff --git a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts index 9658d033cd..0e6dd937d0 100644 --- a/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts +++ b/developer/src/kmc-convert/test/keylayout-to-kmn-converter.tests.ts @@ -60,7 +60,7 @@ describe('KeylayoutToKmnConverter', function () { ['../data/Test.keylayout'], ].forEach(function (files) { it(files + " should give no errors ", async function () { - sut.run(makePathToFixture(files[0])); + await sut.run(makePathToFixture(files[0])); // assert.isTrue(compilerTestCallbacks.messages.length === 1 && compilerTestCallbacks.messages[0].code === 5292037); assert.isTrue(compilerTestCallbacks.messages.length === 0); await sut.run(makePathToFixture(files[0])); @@ -97,7 +97,7 @@ describe('KeylayoutToKmnConverter', function () { ['../data/Test_undefinedAction.keylayout'], ].forEach(function (files) { it(files + " should give Error: undefined action detected", async function () { - sut.run(makePathToFixture(files[0])); + await sut.run(makePathToFixture(files[0])); assert.equal(compilerTestCallbacks.messages.length, 1); assert.equal(compilerTestCallbacks.messages[0].code, 5292040); }); From 8390e7db966ce600792eecbe59f3b13bfe2d435b Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 3 Jul 2026 10:36:47 +0200 Subject: [PATCH 31/33] chore(developer): remove duplicated createWarningText post merge --- .../src/keylayout-to-kmn/kmn-file-writer.ts | 143 +----------------- 1 file changed, 2 insertions(+), 141 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 2b24ecc4b9..d4c661057c 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -1094,147 +1094,7 @@ export class KmnFileWriter { return resultWarningTextSet; } - /** - * @brief take a child object of RuleReview and return the appropriate warning message array - * @param inObj : an object containing filtered data for a specified comparison - * @param posWarning : index specifying to which element of the warning message array a warning message will be added: - * outMsg[0]: Warning for part 1 of a rule (e.g. modifier_prev_dk + key_prev_dk > prev_dk) - * outMsg[1]: Warning for part 2 of a rule (e.g. (prev_dk +) modifier_dk + key_dk > dk) - * outMsg[2]: Warning for part 3 of a rule (e.g. (dk +) modifier+key > output) - * see here on parts of a rule: - * https://docs.google.com/document/d/12J3NGO6RxIthCpZDTR8FYSRjiMgXJDLwPY2z9xqKzJ0/edit?tab=t.0#heading=h.16sx096j6jmy - * @return outMsg the warning message array for all parts - */ - public createWarningText(inObj: RuleReview, posWarning: number = 2): string[] { - - const outMsg = [...inObj.warningMessages]; - - if (inObj.compare_type === 'unav_C0_C1') { - outMsg[posWarning] = 'unavailable modifier '; - } - - if (inObj.compare_type === 'unav_C2') { - // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' - if (inObj.Dk_modifier) { - outMsg[1] = 'unavailable modifier '; - outMsg[2] = 'unavailable superior rule ( [' - + inObj.Dk_modifier + ' ' - + inObj.Dk_key - + '] > dk(' - + inObj.dk_prefix[1] - + inObj.dk_id[1] - + ') ) : '; - } - - if (inObj.modifier) { - outMsg[2] = 'unavailable modifier '; - } - } - - if (inObj.compare_type === 'unav_C3') { - - // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' - if (inObj.prevDk_modifier) { - outMsg[0] = 'unavailable modifier '; - outMsg[1] = 'unavailable superior rule ( [' - + inObj.prevDk_modifier + ' ' - + inObj.prevDk_key - + '] > dk(' - + inObj.dk_prefix[0] - + inObj.dk_id[0] - + ') ) : '; - } - - - // if the dk is unavailable, the modifiers of the dependant C0 rule will get a warning 'unavailable superior rule ' - if (inObj.Dk_modifier) { - outMsg[1] += 'unavailable modifier '; - outMsg[2] = 'unavailable superior rule ( [' - + inObj.Dk_modifier + ' ' - + inObj.Dk_key - + '] > dk(' - + inObj.dk_prefix[1] - + inObj.dk_id[1] - + ') ) : '; - } - - if (inObj.modifier) { - outMsg[2] = 'unavailable modifier '; - } - } - - if (inObj.compare_type === 'amb_1_1' || inObj.compare_type === 'dup_1_1') { - - outMsg[posWarning] = inObj.warningMessages[posWarning] - + ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' - + (inObj.isEarlier ? 'earlier' : 'later') - + ': [' + inObj.modifier + ' ' + inObj.key + '] > \'' - + inObj.output + '\' '; - } - - - if (inObj.compare_type === 'amb_2_2' || inObj.compare_type === 'dup_2_2' - || inObj.compare_type === 'amb_2_1' - || inObj.compare_type === 'amb_2_4') { - - const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' - + (inObj.isEarlier ? 'earlier' : 'later') - + ': [' + inObj.Dk_modifier + ' ' + inObj.Dk_key + '] > dk(' - + inObj.dk_prefix[1] + inObj.dk_id[1] + ') '); - - if (outMsg[posWarning].indexOf(textsegment) === -1) - outMsg[posWarning] += textsegment; - } - - - if (inObj.compare_type === 'amb_4_4' || inObj.compare_type === 'dup_4_4' - || inObj.compare_type === 'amb_4_1' - || inObj.compare_type === 'amb_4_2') { - - const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' - + (inObj.isEarlier ? 'earlier' : 'later') - + ': [' + inObj.prevDk_modifier + ' ' + inObj.prevDk_key + '] > dk(' - + inObj.dk_prefix[0] + inObj.dk_id[0] + ') '); - - if (outMsg[posWarning].indexOf(textsegment) === -1) - outMsg[posWarning] += textsegment; - } - - - if (inObj.compare_type === 'amb_5_5' || inObj.compare_type === 'dup_5_5') { - - const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' - + (inObj.isEarlier ? 'earlier' : 'later') - + ': dk(' + inObj.dk_prefix[0] + inObj.dk_id[0] + ") + [" - + inObj.Dk_modifier + " " + inObj.Dk_key + "] > " - + 'dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") "); - - if (outMsg[1].indexOf(textsegment) === -1) - outMsg[1] += textsegment; - } - - - if (inObj.compare_type === 'amb_6_3' || inObj.compare_type === 'dup_6_3' - || inObj.compare_type === 'amb_3_3' || inObj.compare_type === 'dup_3_3' - || inObj.compare_type === 'amb_6_6' || inObj.compare_type === 'dup_6_6') { - - const textsegment = ( - ((inObj.type === 'AmbiguousRule') ? 'ambiguous ' : 'duplicate ') + 'rule: ' - + (inObj.isEarlier ? 'earlier' : 'later') - + ': dk(' + inObj.dk_prefix[1] + inObj.dk_id[1] + ") + [" - + inObj.modifier + " " + inObj.key + "] > \'" - + inObj.output + "\' "); - - if (outMsg[posWarning].indexOf(textsegment) === -1) - outMsg[posWarning] += textsegment; - } - - return outMsg; - } - /** +/** * @brief member function to write a character as Unicode Character or Unicode Codepoint depending on the character that is to be written * @param ctr : string - the character to be written * @return a string containing the Unicode representation of the control character. @@ -1404,6 +1264,7 @@ export class KmnFileWriter { } return undefined; } + /** @internal */ public unitTestEndpoints = { reviewRules: this.reviewRules.bind(this), From ddb5de02e028aace5060c6dddc6bee06f4b78a3c Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 6 Aug 2026 17:38:17 +0200 Subject: [PATCH 32/33] feat(developer): restore writing of warnText --- .../src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index 0415447ae1..6e98f62816 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -178,7 +178,7 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class @@ -239,7 +239,7 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class From ed02e93bc8243b6e0f0693b3d3265bc2d9ac06dc Mon Sep 17 00:00:00 2001 From: Sabine Date: Thu, 6 Aug 2026 18:22:12 +0200 Subject: [PATCH 33/33] feat(developer): restore writeDataRules() after merge conflict --- .../src/keylayout-to-kmn/kmn-file-writer.ts | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts index cee9f3e3f7..6c9679d019 100644 --- a/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts +++ b/developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts @@ -177,18 +177,18 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - if (characterMessage !== null) { - const versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; - } + let versionOutputCharacter; + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + if (characterMessage !== null) { + versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; + } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used @@ -242,18 +242,19 @@ export class KmnFileWriter { // use of Unicode Character vs Unicode Codepoint; // If it`s a ctrl character we print out the Unicode Codepoint else we print out the Unicode Character - const warnText = this.reviewRules(uniqueDataRules, k); + const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; + let versionOutputCharacter; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class // const outputUnicodeCharacter = util.convertToUnicodeCharacter(outputCharacter); // const outputUnicodeCodePoint = util.convertToUnicodeCodePoint(outputCharacter); - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - if (characterMessage !== null) { - const versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; - } + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + if (characterMessage !== null) { + versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; + } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used // if warning contains duplicate rules we do not write out the entire rule @@ -332,12 +333,12 @@ export class KmnFileWriter { const warnText = this.reviewRules(uniqueDataRules, k).warningMessages; const outputCharacter = new TextDecoder().decode(uniqueDataRules[k].output); // TODO-kmc-convert: after merge of PR 14569 use functions from util instead of the ones in this class - - const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); - if (characterMessage !== null) { - const versionOutputCharacter = characterMessage.character; - warnText[2] = characterMessage.message; - } + let versionOutputCharacter; + const characterMessage = this.writeCharacterOrUnicode(outputCharacter, warnText[2]); + if (characterMessage !== null) { + versionOutputCharacter = characterMessage.character; + warnText[2] = characterMessage.message; + } // add a warning in front of rules in case unavailable modifiers or ambiguous rules are used @@ -1089,14 +1090,14 @@ export class KmnFileWriter { return resultWarningTextSet; } -/** - * @brief member function to write a character as Unicode Character or Unicode Codepoint depending on the character that is to be written - * @param ctr : string - the character to be written - * @return a string containing the Unicode representation of the control character. - * A control character will be written as unicode (U+0004), - * a non-control character will be written as itself ( 'A', '1', '፩', '😎') - * null in case of an empty string or null or undefined input - */ + /** + * @brief member function to write a character as Unicode Character or Unicode Codepoint depending on the character that is to be written + * @param ctr : string - the character to be written + * @return a string containing the Unicode representation of the control character. + * A control character will be written as unicode (U+0004), + * a non-control character will be written as itself ( 'A', '1', '፩', '😎') + * null in case of an empty string or null or undefined input + */ public writeCharacterOrUnicode(ctr: string, msg: string = ""): MessageCharacter | null { if ((ctr === null) || (ctr === undefined)) {