From f2915bbb66b37bb7029dac42249bc201ca105c0e Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Wed, 26 Jul 2023 17:04:50 -0500 Subject: [PATCH 1/8] =?UTF-8?q?spec(core):=20update=20marker=20spec=20?= =?UTF-8?q?=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 'transform' doesn't have an 'after=' attribute For: #9118 --- core/src/ldml/C9134_ldml_markers.md | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/ldml/C9134_ldml_markers.md b/core/src/ldml/C9134_ldml_markers.md index 7a0f5d69597..0b2436b97f4 100644 --- a/core/src/ldml/C9134_ldml_markers.md +++ b/core/src/ldml/C9134_ldml_markers.md @@ -27,7 +27,6 @@ Markers can appear in both 'emitting' and 'matching-only' areas: #### Match only - `transform from=` to match markers -- `transform after=` to match markers - `display to=` for matching keys which contain markers ## Theory / Encoding From 0c7ad2c1af9b149993bc6b4e6d4732b8a5628e5f Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Wed, 26 Jul 2023 17:27:14 -0500 Subject: [PATCH 2/8] =?UTF-8?q?feat(developer):=20Marker=20tests=20?= =?UTF-8?q?=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tests for marker validation - TDD: it fails, hooray For: #9119 --- .../src/kmc-ldml/src/compiler/messages.ts | 4 ++ developer/src/kmc-ldml/src/compiler/vars.ts | 7 +++ .../sections/vars/fail-markers-badref-0.xml | 37 ++++++++++++++++ .../sections/vars/markers-maximal.xml | 44 +++++++++++++++++++ developer/src/kmc-ldml/test/test-vars.ts | 20 +++++++++ 5 files changed, 112 insertions(+) create mode 100644 developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml create mode 100644 developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml diff --git a/developer/src/kmc-ldml/src/compiler/messages.ts b/developer/src/kmc-ldml/src/compiler/messages.ts index a6a8b4ff495..e3ec8bcbf24 100644 --- a/developer/src/kmc-ldml/src/compiler/messages.ts +++ b/developer/src/kmc-ldml/src/compiler/messages.ts @@ -130,5 +130,9 @@ export class CompilerMessages { static Error_CantReferenceSetFromUnicodeSet = (o:{id: string}) => m(this.ERROR_CantReferenceSetFromUnicodeSet, `Illegal use of set variable from within UnicodeSet: \$[${o.id}]`); static ERROR_CantReferenceSetFromUnicodeSet = SevError | 0x0020; + + static Error_MissingMarkers = (o: { ids: string[] }) => + m(this.ERROR_MissingMarkers, `Markers used for matching but not defined: ${o.ids?.join(',')}`); + static ERROR_MissingMarkers = SevError | 0x0021; } diff --git a/developer/src/kmc-ldml/src/compiler/vars.ts b/developer/src/kmc-ldml/src/compiler/vars.ts index 19451c4db43..07ff1405306 100644 --- a/developer/src/kmc-ldml/src/compiler/vars.ts +++ b/developer/src/kmc-ldml/src/compiler/vars.ts @@ -130,9 +130,16 @@ export class VarsCompiler extends SectionCompiler { })); valid = false; } + + valid = valid && this.validateMarkers(); + return valid; } + private validateMarkers(): boolean { + return true; + } + public compile(sections: DependencySections): Vars { const result = new Vars(); diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml new file mode 100644 index 00000000000..59ce65fbb0e --- /dev/null +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml new file mode 100644 index 00000000000..baa93830759 --- /dev/null +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-ldml/test/test-vars.ts b/developer/src/kmc-ldml/test/test-vars.ts index a3cb303b825..fda20e19b93 100644 --- a/developer/src/kmc-ldml/test/test-vars.ts +++ b/developer/src/kmc-ldml/test/test-vars.ts @@ -183,4 +183,24 @@ describe('vars', function () { ], }, ]); + describe('markers', function () { + this.slow(500); // 0.5 sec -- json schema validation takes a while + + testCompilationCases(VarsCompiler, [ + { + subpath: 'sections/vars/markers-maximal.xml', + }, + { + subpath: 'sections/vars/fail-markers-badref-0.xml', + errors: [ + CompilerMessages.Error_MissingMarkers({ + ids: [ + 'doesnt-exist-1', + 'doesnt-exist-2', + ] + }), + ], + }, + ]); + }); }); From ab4a0f36ab49619f55c23197a0263c7663ee34b2 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Wed, 26 Jul 2023 18:06:22 -0500 Subject: [PATCH 3/8] =?UTF-8?q?feat(developer):=20Marker=20tests=20?= =?UTF-8?q?=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - wip , still not working For: #9119 --- .../types/src/ldml-keyboard/pattern-parser.ts | 3 ++ developer/src/kmc-ldml/src/compiler/disp.ts | 8 ++- developer/src/kmc-ldml/src/compiler/keys.ts | 8 ++- developer/src/kmc-ldml/src/compiler/tran.ts | 15 +++++- developer/src/kmc-ldml/src/compiler/vars.ts | 51 ++++++++++++++++++- .../sections/vars/fail-markers-badref-0.xml | 6 +++ developer/src/kmc-ldml/test/test-vars.ts | 1 + 7 files changed, 86 insertions(+), 6 deletions(-) diff --git a/common/web/types/src/ldml-keyboard/pattern-parser.ts b/common/web/types/src/ldml-keyboard/pattern-parser.ts index 1b41b9416c4..34c400b8672 100644 --- a/common/web/types/src/ldml-keyboard/pattern-parser.ts +++ b/common/web/types/src/ldml-keyboard/pattern-parser.ts @@ -51,6 +51,9 @@ export class MarkerParser { * @returns `[]` or an array of all markers referenced */ public static allReferences(str: string): string[] { + if (!str) { + return []; + } return matchArray(str, this.REFERENCE); } } diff --git a/developer/src/kmc-ldml/src/compiler/disp.ts b/developer/src/kmc-ldml/src/compiler/disp.ts index 1ed2e14b145..d83a90cca37 100644 --- a/developer/src/kmc-ldml/src/compiler/disp.ts +++ b/developer/src/kmc-ldml/src/compiler/disp.ts @@ -1,5 +1,5 @@ import { constants } from "@keymanapp/ldml-keyboard-constants"; -import { KMXPlus } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboard, MarkerParser } from '@keymanapp/common-types'; import { CompilerMessages } from "./messages.js"; import { SectionCompiler } from "./section-compiler.js"; @@ -9,6 +9,12 @@ import Disp = KMXPlus.Disp; import DispItem = KMXPlus.DispItem; export class DispCompiler extends SectionCompiler { + static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set): boolean { + keyboard.displays?.display?.forEach(({ to }) => { + MarkerParser.allReferences(to).forEach(marker => matchMarkers.add(marker)); + }); + return true; + } public get id() { return constants.section.disp; diff --git a/developer/src/kmc-ldml/src/compiler/keys.ts b/developer/src/kmc-ldml/src/compiler/keys.ts index b3e13b70fc7..614be67ebf3 100644 --- a/developer/src/kmc-ldml/src/compiler/keys.ts +++ b/developer/src/kmc-ldml/src/compiler/keys.ts @@ -1,5 +1,5 @@ import { constants } from '@keymanapp/ldml-keyboard-constants'; -import { LDMLKeyboard, KMXPlus, Constants } from '@keymanapp/common-types'; +import { LDMLKeyboard, KMXPlus, Constants, MarkerParser } from '@keymanapp/common-types'; import { CompilerMessages } from './messages.js'; import { SectionCompiler } from "./section-compiler.js"; @@ -10,6 +10,12 @@ import KeysFlicks = KMXPlus.KeysFlicks; import { allUsedKeyIdsInLayers, calculateUniqueKeys, translateLayerAttrToModifier, validModifier } from '../util/util.js'; export class KeysCompiler extends SectionCompiler { + static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set): boolean { + keyboard.keys?.key?.forEach(({ to }) => { + MarkerParser.allReferences(to).forEach(marker => emitMarkers.add(marker)); + }); + return true; + } public get id() { return constants.section.keys; diff --git a/developer/src/kmc-ldml/src/compiler/tran.ts b/developer/src/kmc-ldml/src/compiler/tran.ts index d0173b7bfb3..2175ca2dbe4 100644 --- a/developer/src/kmc-ldml/src/compiler/tran.ts +++ b/developer/src/kmc-ldml/src/compiler/tran.ts @@ -1,5 +1,5 @@ import { constants, SectionIdent } from "@keymanapp/ldml-keyboard-constants"; -import { KMXPlus, LDMLKeyboard, CompilerCallbacks, VariableParser } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboard, CompilerCallbacks, VariableParser, MarkerParser } from '@keymanapp/common-types'; import { SectionCompiler } from "./section-compiler.js"; import Bksp = KMXPlus.Bksp; @@ -18,7 +18,18 @@ import { CompilerMessages } from "./messages.js"; type TransformCompilerType = 'simple' | 'backspace'; -class TransformCompiler extends SectionCompiler { +export class TransformCompiler extends SectionCompiler { + + static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set): boolean { + keyboard?.transforms?.forEach(transforms => + transforms.transformGroup.forEach(transformGroup => { + transformGroup.transform?.forEach(({ to, from }) => { + MarkerParser.allReferences(from).forEach(marker => matchMarkers.add(marker)); + MarkerParser.allReferences(to).forEach(marker => emitMarkers.add(marker)); + }); + })); + return true; + } protected type: T; diff --git a/developer/src/kmc-ldml/src/compiler/vars.ts b/developer/src/kmc-ldml/src/compiler/vars.ts index 07ff1405306..03647e213ac 100644 --- a/developer/src/kmc-ldml/src/compiler/vars.ts +++ b/developer/src/kmc-ldml/src/compiler/vars.ts @@ -1,5 +1,5 @@ import { SectionIdent, constants } from "@keymanapp/ldml-keyboard-constants"; -import { KMXPlus, LDMLKeyboard, CompilerCallbacks } from '@keymanapp/common-types'; +import { KMXPlus, LDMLKeyboard, CompilerCallbacks, MarkerParser } from '@keymanapp/common-types'; import { VariableParser } from '@keymanapp/common-types'; import { SectionCompiler } from "./section-compiler.js"; import Vars = KMXPlus.Vars; @@ -9,6 +9,9 @@ import UnicodeSetItem = KMXPlus.UnicodeSetItem; import DependencySections = KMXPlus.DependencySections; import LDMLKeyboardXMLSourceFile = LDMLKeyboard.LDMLKeyboardXMLSourceFile; import { CompilerMessages } from "./messages.js"; +import { KeysCompiler } from "./keys.js"; +import { TransformCompiler } from "./tran.js"; +import { DispCompiler } from "./disp.js"; export class VarsCompiler extends SectionCompiler { public get id() { return constants.section.vars; @@ -131,12 +134,56 @@ export class VarsCompiler extends SectionCompiler { valid = false; } - valid = valid && this.validateMarkers(); + valid = this.validateMarkers() && valid; // accumulate validity + + return valid; + } + + private collectMarkers(emitMarkers : Set, matchMarkers : Set) : boolean { + let valid = true; + + // call our friends to validate + valid = this.validateVarsMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity + valid = KeysCompiler.validateMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity + valid = TransformCompiler.validateMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity + valid = DispCompiler.validateMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity return valid; } private validateMarkers(): boolean { + /** only the markers used in emitters */ + const emitMarkers : Set = new Set(); + /** only the markers used in matchers */ + const matchMarkers : Set = new Set(); + + + let valid = this.collectMarkers(emitMarkers, matchMarkers); + + // see if there are any matched-but-not-emitted + const matchedNotEmitted : string[] = []; + for (const m of matchMarkers.values()) { + if (m === '.') continue; // match-all marker + if (!emitMarkers.has(m)) { + matchedNotEmitted.push(m); + } + } + + // report once + if (matchedNotEmitted.length) { + matchedNotEmitted.sort(); + this.callbacks.reportMessage(CompilerMessages.Error_MissingMarkers({ ids: matchedNotEmitted })); + valid = false; + } + return valid; + } + + validateVarsMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set) : boolean { + keyboard?.variables?.string?.forEach(({value}) => + MarkerParser.allReferences(value).forEach(marker => { + emitMarkers.add(marker); + matchMarkers.add(marker); + })); return true; } diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml index 59ce65fbb0e..093849ac1a8 100644 --- a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml @@ -24,6 +24,12 @@ This will fail because the two markers given don't exist anywhere. + + + + + + diff --git a/developer/src/kmc-ldml/test/test-vars.ts b/developer/src/kmc-ldml/test/test-vars.ts index fda20e19b93..5efdc4c4a09 100644 --- a/developer/src/kmc-ldml/test/test-vars.ts +++ b/developer/src/kmc-ldml/test/test-vars.ts @@ -197,6 +197,7 @@ describe('vars', function () { ids: [ 'doesnt-exist-1', 'doesnt-exist-2', + 'doesnt-exist-3', ] }), ], From 4854cba4c9c8a11f68aa2ad31dfa0a052ac7a7a2 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 28 Jul 2023 21:40:02 -0500 Subject: [PATCH 4/8] =?UTF-8?q?feat(developer):=20fix=20marker=20validatio?= =?UTF-8?q?n=20test=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - was using the wrong syntax, hyphen instead of underscore #9119 --- .../fixtures/sections/vars/fail-markers-badref-0.xml | 12 ++++++------ developer/src/kmc-ldml/test/test-vars.ts | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml index 093849ac1a8..063b5a5d114 100644 --- a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml @@ -12,30 +12,30 @@ This will fail because the two markers given don't exist anywhere. - + - + - + - + - + - + diff --git a/developer/src/kmc-ldml/test/test-vars.ts b/developer/src/kmc-ldml/test/test-vars.ts index 5efdc4c4a09..d9e9d4df29f 100644 --- a/developer/src/kmc-ldml/test/test-vars.ts +++ b/developer/src/kmc-ldml/test/test-vars.ts @@ -195,9 +195,9 @@ describe('vars', function () { errors: [ CompilerMessages.Error_MissingMarkers({ ids: [ - 'doesnt-exist-1', - 'doesnt-exist-2', - 'doesnt-exist-3', + 'doesnt_exist_1', + 'doesnt_exist_2', + 'doesnt_exist_3', ] }), ], From 52e54395f983140123682cd35b40d58beb0e00a2 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Sat, 29 Jul 2023 14:18:37 -0500 Subject: [PATCH 5/8] =?UTF-8?q?feat(developer):=20marker=20accounting=20?= =?UTF-8?q?=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - split out MarkerTracker, could give us more precise messages about marker use - for now, we parse all markers twice. - update builder for the markers list #9119 --- .../src/kmx/kmx-plus-builder/build-vars.ts | 6 +- .../kmx/kmx-plus-builder/kmx-plus-builder.ts | 2 +- common/web/types/src/kmx/string-list.ts | 7 +- developer/src/kmc-ldml/src/compiler/disp.ts | 8 +- developer/src/kmc-ldml/src/compiler/keys.ts | 111 +++++++++++++----- .../kmc-ldml/src/compiler/marker-tracker.ts | 72 ++++++++++++ developer/src/kmc-ldml/src/compiler/tran.ts | 10 +- developer/src/kmc-ldml/src/compiler/vars.ts | 61 +++++----- .../sections/vars/markers-maximal.xml | 14 +-- developer/src/kmc-ldml/test/test-vars.ts | 6 + 10 files changed, 217 insertions(+), 80 deletions(-) create mode 100644 developer/src/kmc-ldml/src/compiler/marker-tracker.ts diff --git a/common/web/types/src/kmx/kmx-plus-builder/build-vars.ts b/common/web/types/src/kmx/kmx-plus-builder/build-vars.ts index 5f70689e962..daa0e4a46c2 100644 --- a/common/web/types/src/kmx/kmx-plus-builder/build-vars.ts +++ b/common/web/types/src/kmx/kmx-plus-builder/build-vars.ts @@ -2,7 +2,7 @@ import { constants } from "@keymanapp/ldml-keyboard-constants"; import { KMXPlusData } from "../kmx-plus.js"; import { build_strs_index, BUILDER_STR_REF, BUILDER_STRS } from "./build-strs.js"; import { BUILDER_SECTION } from "./builder-section.js"; -import { BUILDER_LIST_REF } from "./build-list.js"; +import { build_list_index, BUILDER_LIST, BUILDER_LIST_REF } from "./build-list.js"; import { build_elem_index, BUILDER_ELEM, BUILDER_ELEM_REF } from "./build-elem.js"; @@ -22,7 +22,7 @@ export interface BUILDER_VARS extends BUILDER_SECTION { /** * Builder for the 'vars' section */ -export function build_vars(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_elem: BUILDER_ELEM) : BUILDER_VARS { +export function build_vars(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_elem: BUILDER_ELEM, sect_list: BUILDER_LIST) : BUILDER_VARS { if(!kmxplus.vars) { return null; } @@ -49,7 +49,7 @@ export function build_vars(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_e size: constants.length_vars + (constants.length_vars_item * kmxplus.vars.totalCount()), _offset: 0, - markers: 0, + markers: build_list_index(sect_list, kmxplus.vars.markers), varCount: kmxplus.vars.totalCount(), varEntries: [ ...stringVars, diff --git a/common/web/types/src/kmx/kmx-plus-builder/kmx-plus-builder.ts b/common/web/types/src/kmx/kmx-plus-builder/kmx-plus-builder.ts index 082e5495eb3..3cc58c9fe75 100644 --- a/common/web/types/src/kmx/kmx-plus-builder/kmx-plus-builder.ts +++ b/common/web/types/src/kmx/kmx-plus-builder/kmx-plus-builder.ts @@ -99,7 +99,7 @@ export default class KMXPlusBuilder { this.sect.name = build_name(this.file.kmxplus, this.sect.strs); this.sect.tran = build_tran(this.file.kmxplus.tran, this.sect.strs, this.sect.elem); this.sect.uset = build_uset(this.file.kmxplus, this.sect.strs); - this.sect.vars = build_vars(this.file.kmxplus, this.sect.strs, this.sect.elem); + this.sect.vars = build_vars(this.file.kmxplus, this.sect.strs, this.sect.elem, this.sect.list); this.sect.vkey = build_vkey(this.file.kmxplus); // Finalize the sect (index) section diff --git a/common/web/types/src/kmx/string-list.ts b/common/web/types/src/kmx/string-list.ts index 4b5716b85d7..b683aae411b 100644 --- a/common/web/types/src/kmx/string-list.ts +++ b/common/web/types/src/kmx/string-list.ts @@ -68,7 +68,12 @@ export class ListItem extends Array { return 0; } } + /** for debugging, print as single string */ toString(): string { - return this.map(v => v.value.value).join(' '); + return this.toStringArray().join(' '); + } + /** for debugging, map to string array */ + toStringArray(): string[] { + return this.map(v => v.value.value); } }; diff --git a/developer/src/kmc-ldml/src/compiler/disp.ts b/developer/src/kmc-ldml/src/compiler/disp.ts index d83a90cca37..d644f56b888 100644 --- a/developer/src/kmc-ldml/src/compiler/disp.ts +++ b/developer/src/kmc-ldml/src/compiler/disp.ts @@ -7,12 +7,12 @@ import { SectionCompiler } from "./section-compiler.js"; import DependencySections = KMXPlus.DependencySections; import Disp = KMXPlus.Disp; import DispItem = KMXPlus.DispItem; +import { MarkerTracker, MarkerUse } from "./marker-tracker.js"; export class DispCompiler extends SectionCompiler { - static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set): boolean { - keyboard.displays?.display?.forEach(({ to }) => { - MarkerParser.allReferences(to).forEach(marker => matchMarkers.add(marker)); - }); + static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, mt : MarkerTracker): boolean { + keyboard.displays?.display?.forEach(({ to }) => + mt.add(MarkerUse.match, MarkerParser.allReferences(to))); return true; } diff --git a/developer/src/kmc-ldml/src/compiler/keys.ts b/developer/src/kmc-ldml/src/compiler/keys.ts index 614be67ebf3..28cc1536b87 100644 --- a/developer/src/kmc-ldml/src/compiler/keys.ts +++ b/developer/src/kmc-ldml/src/compiler/keys.ts @@ -8,12 +8,16 @@ import Keys = KMXPlus.Keys; import ListItem = KMXPlus.ListItem; import KeysFlicks = KMXPlus.KeysFlicks; import { allUsedKeyIdsInLayers, calculateUniqueKeys, translateLayerAttrToModifier, validModifier } from '../util/util.js'; +import { MarkerTracker, MarkerUse } from './marker-tracker.js'; export class KeysCompiler extends SectionCompiler { - static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set): boolean { - keyboard.keys?.key?.forEach(({ to }) => { - MarkerParser.allReferences(to).forEach(marker => emitMarkers.add(marker)); - }); + static validateMarkers( + keyboard: LDMLKeyboard.LKKeyboard, + mt: MarkerTracker + ): boolean { + keyboard.keys?.key?.forEach(({ to }) => + mt.add(MarkerUse.emit, MarkerParser.allReferences(to)) + ); return true; } @@ -26,7 +30,7 @@ export class KeysCompiler extends SectionCompiler { * @returns just the non-touch layers. */ public hardwareLayers() { - return this.keyboard.layers?.filter(({form}) => form !== 'touch'); + return this.keyboard.layers?.filter(({ form }) => form !== "touch"); } public validate() { @@ -36,7 +40,7 @@ export class KeysCompiler extends SectionCompiler { const usedKeys = allUsedKeyIdsInLayers(this.keyboard?.layers); const uniqueKeys = calculateUniqueKeys([...this.keyboard.keys?.key]); for (let key of uniqueKeys) { - const {id, flicks} = key; + const { id, flicks } = key; if (!usedKeys.has(id)) { continue; // unused key, ignore } @@ -44,10 +48,14 @@ export class KeysCompiler extends SectionCompiler { if (!flicks) { continue; // no flicks } - const flickEntry = this.keyboard.keys?.flicks?.find(x => x.id === flicks); - if (!flickEntry ) { + const flickEntry = this.keyboard.keys?.flicks?.find( + (x) => x.id === flicks + ); + if (!flickEntry) { valid = false; - this.callbacks.reportMessage(CompilerMessages.Error_MissingFlicks({flicks, id})); + this.callbacks.reportMessage( + CompilerMessages.Error_MissingFlicks({ flicks, id }) + ); } } @@ -59,8 +67,9 @@ export class KeysCompiler extends SectionCompiler { if (hardwareLayers.length >= 1) { // validate all errors for (let layers of hardwareLayers) { - for(let layer of layers.layer) { - valid = this.validateHardwareLayerForKmap(layers.form, layer) && valid; // note: always validate even if previously invalid results found + for (let layer of layers.layer) { + valid = + this.validateHardwareLayerForKmap(layers.form, layer) && valid; // note: always validate even if previously invalid results found } } // TODO-LDML: } else { touch? @@ -90,11 +99,13 @@ export class KeysCompiler extends SectionCompiler { /* c8 ignore next 3 */ if (hardwareLayers.length > 1) { // validation should have already caught this - throw Error(`Internal error: Expected 0 or 1 hardware layer, not ${hardwareLayers.length}`); + throw Error( + `Internal error: Expected 0 or 1 hardware layer, not ${hardwareLayers.length}` + ); } else if (hardwareLayers.length === 1) { const theLayers = hardwareLayers[0]; const { form } = theLayers; - for(let layer of theLayers.layer) { + for (let layer of theLayers.layer) { this.compileHardwareLayerToKmap(sections, layer, sect, form); } } // else: TODO-LDML do nothing if only touch layers @@ -104,7 +115,9 @@ export class KeysCompiler extends SectionCompiler { public loadFlicks(sections: DependencySections, sect: Keys) { for (let lkflicks of this.keyboard.keys.flicks) { - let flicks: KeysFlicks = new KeysFlicks(sections.strs.allocString(lkflicks.id)); + let flicks: KeysFlicks = new KeysFlicks( + sections.strs.allocString(lkflicks.id) + ); for (let lkflick of lkflicks.flick) { let flags = 0; @@ -112,7 +125,10 @@ export class KeysCompiler extends SectionCompiler { if (!to.isOneChar) { flags |= constants.keys_flick_flags_extend; } - let directions: ListItem = sections.list.allocListFromSpaces(sections.strs, lkflick.directions); + let directions: ListItem = sections.list.allocListFromSpaces( + sections.strs, + lkflick.directions + ); flicks.flicks.push({ directions, flags, @@ -138,19 +154,27 @@ export class KeysCompiler extends SectionCompiler { if (!!key.gap) { flags |= constants.keys_key_flags_gap; } - if (key.transform === 'no') { + if (key.transform === "no") { flags |= constants.keys_key_flags_notransform; } const id = sections.strs.allocString(key.id); - const longPress: ListItem = sections.list.allocListFromEscapedSpaces(sections.strs, key.longPress); - const longPressDefault = sections.strs.allocAndUnescapeString(key.longPressDefault); - const multiTap: ListItem = sections.list.allocListFromEscapedSpaces(sections.strs, key.multiTap); + const longPress: ListItem = sections.list.allocListFromEscapedSpaces( + sections.strs, + key.longPress + ); + const longPressDefault = sections.strs.allocAndUnescapeString( + key.longPressDefault + ); + const multiTap: ListItem = sections.list.allocListFromEscapedSpaces( + sections.strs, + key.multiTap + ); const keySwitch = sections.strs.allocString(key.switch); // 'switch' is a reserved word const to = sections.strs.allocAndUnescapeString(key.to, true); if (!to.isOneChar) { flags |= constants.keys_key_flags_extend; } - const width = Math.ceil((key.width || 1) * 10.0); // default, width=1 + const width = Math.ceil((key.width || 1) * 10.0); // default, width=1 sect.keys.push({ flags, flicks, @@ -172,12 +196,17 @@ export class KeysCompiler extends SectionCompiler { * @param layer * @returns */ - private validateHardwareLayerForKmap(hardware: string, layer: LDMLKeyboard.LKLayer) { + private validateHardwareLayerForKmap( + hardware: string, + layer: LDMLKeyboard.LKLayer + ) { let valid = true; const { modifier } = layer; if (!validModifier(modifier)) { - this.callbacks.reportMessage(CompilerMessages.Error_InvalidModifier({ modifier, layer: layer.id })); + this.callbacks.reportMessage( + CompilerMessages.Error_InvalidModifier({ modifier, layer: layer.id }) + ); valid = false; } @@ -185,21 +214,31 @@ export class KeysCompiler extends SectionCompiler { /* c8 ignore next 5 */ if (!keymap) { // not reached due to XML validation - this.callbacks.reportMessage(CompilerMessages.Error_InvalidHardware({ form: hardware })); + this.callbacks.reportMessage( + CompilerMessages.Error_InvalidHardware({ form: hardware }) + ); valid = false; } const uniqueKeys = calculateUniqueKeys([...this.keyboard.keys?.key]); if (layer.row.length > keymap.length) { - this.callbacks.reportMessage(CompilerMessages.Error_HardwareLayerHasTooManyRows()); + this.callbacks.reportMessage( + CompilerMessages.Error_HardwareLayerHasTooManyRows() + ); valid = false; } for (let y = 0; y < layer.row.length && y < keymap.length; y++) { - const keys = layer.row[y].keys.split(' '); + const keys = layer.row[y].keys.split(" "); if (keys.length > keymap[y].length) { - this.callbacks.reportMessage(CompilerMessages.Error_RowOnHardwareLayerHasTooManyKeys({ row: y + 1, hardware, modifier })); + this.callbacks.reportMessage( + CompilerMessages.Error_RowOnHardwareLayerHasTooManyKeys({ + row: y + 1, + hardware, + modifier, + }) + ); valid = false; } @@ -207,14 +246,24 @@ export class KeysCompiler extends SectionCompiler { for (let key of keys) { x++; - let keydef = uniqueKeys.find(x => x.id == key); + let keydef = uniqueKeys.find((x) => x.id == key); if (!keydef) { - this.callbacks.reportMessage(CompilerMessages.Error_KeyNotFoundInKeyBag({ keyId: key, col: x + 1, row: y + 1, layer: layer.id, form: 'hardware' })); + this.callbacks.reportMessage( + CompilerMessages.Error_KeyNotFoundInKeyBag({ + keyId: key, + col: x + 1, + row: y + 1, + layer: layer.id, + form: "hardware", + }) + ); valid = false; continue; } if (!keydef.to && !keydef.gap && !keydef.switch) { - this.callbacks.reportMessage(CompilerMessages.Error_KeyMissingToGapOrSwitch({ keyId: key })); + this.callbacks.reportMessage( + CompilerMessages.Error_KeyMissingToGapOrSwitch({ keyId: key }) + ); valid = false; continue; } @@ -228,7 +277,7 @@ export class KeysCompiler extends SectionCompiler { sections: DependencySections, layer: LDMLKeyboard.LKLayer, sect: Keys, - hardware: string, + hardware: string ): Keys { const mod = translateLayerAttrToModifier(layer); const keymap = Constants.HardwareToKeymap.get(hardware); @@ -237,7 +286,7 @@ export class KeysCompiler extends SectionCompiler { for (let row of layer.row) { y++; - const keys = row.keys.split(' '); + const keys = row.keys.split(" "); let x = -1; for (let key of keys) { x++; diff --git a/developer/src/kmc-ldml/src/compiler/marker-tracker.ts b/developer/src/kmc-ldml/src/compiler/marker-tracker.ts new file mode 100644 index 00000000000..8007f29e5bf --- /dev/null +++ b/developer/src/kmc-ldml/src/compiler/marker-tracker.ts @@ -0,0 +1,72 @@ +/** + * Verb for MarkerTracker.add() + */ +export enum MarkerUse { + /** outputs this marker into context (e.g. transform to= or key to=) */ + emit, + /** consumes this marker out of the context (e.g. transform from=) */ + consume, + /** matches the marker, but doesn't consume (e.g. display to=) */ + match, + /** variable definition: might consume, emit, or match. */ + variable, +} + +type MarkerSet = Set; + +/** Tracks usage of markers */ +export class MarkerTracker { + /** markers that were emitted */ + emitted: MarkerSet; + /** markers that were consumed and removed from the context */ + consumed: MarkerSet; + /** markers that were matched, but not necessarily consumed */ + matched: MarkerSet; + /** all markers */ + all: MarkerSet; + + constructor() { + this.emitted = new Set(); + this.consumed = new Set(); + this.matched = new Set(); + this.all = new Set(); + } + + /** + * + * @param verb what kind of use we are adding + * @param markers list of markers to add + */ + add(verb: MarkerUse, markers: string[]) { + if (!markers.length) { + return; // skip if empty + } + if (verb == MarkerUse.emit) { + markers.forEach((m) => { + this.emitted.add(m); + this.all.add(m); + }); + } else if (verb == MarkerUse.consume) { + markers.forEach((m) => { + this.consumed.add(m); + this.all.add(m); + }); + } else if (verb == MarkerUse.match) { + markers.forEach((m) => { + this.matched.add(m); + this.all.add(m); + }); + } else if (verb == MarkerUse.variable) { + markers.forEach((m) => { + // we don't know, so add it to all three + this.matched.add(m); + this.emitted.add(m); + this.consumed.add(m); + this.all.add(m); + }); + /* c8 skip next 3 */ + } else { + throw Error(`Internal error: unsupported verb ${verb} for match`); + } + } +} diff --git a/developer/src/kmc-ldml/src/compiler/tran.ts b/developer/src/kmc-ldml/src/compiler/tran.ts index 2175ca2dbe4..15db1b2220f 100644 --- a/developer/src/kmc-ldml/src/compiler/tran.ts +++ b/developer/src/kmc-ldml/src/compiler/tran.ts @@ -15,19 +15,19 @@ import LKTransform = LDMLKeyboard.LKTransform; import LKTransforms = LDMLKeyboard.LKTransforms; import { verifyValidAndUnique } from "../util/util.js"; import { CompilerMessages } from "./messages.js"; +import { MarkerTracker, MarkerUse } from "./marker-tracker.js"; type TransformCompilerType = 'simple' | 'backspace'; export class TransformCompiler extends SectionCompiler { - static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set): boolean { + static validateMarkers(keyboard: LDMLKeyboard.LKKeyboard, mt : MarkerTracker): boolean { keyboard?.transforms?.forEach(transforms => transforms.transformGroup.forEach(transformGroup => { transformGroup.transform?.forEach(({ to, from }) => { - MarkerParser.allReferences(from).forEach(marker => matchMarkers.add(marker)); - MarkerParser.allReferences(to).forEach(marker => emitMarkers.add(marker)); - }); - })); + mt.add(MarkerUse.emit, MarkerParser.allReferences(to)); + mt.add(MarkerUse.consume, MarkerParser.allReferences(from)); + })})); return true; } diff --git a/developer/src/kmc-ldml/src/compiler/vars.ts b/developer/src/kmc-ldml/src/compiler/vars.ts index 03647e213ac..822f6e7d428 100644 --- a/developer/src/kmc-ldml/src/compiler/vars.ts +++ b/developer/src/kmc-ldml/src/compiler/vars.ts @@ -12,6 +12,7 @@ import { CompilerMessages } from "./messages.js"; import { KeysCompiler } from "./keys.js"; import { TransformCompiler } from "./tran.js"; import { DispCompiler } from "./disp.js"; +import { MarkerTracker, MarkerUse } from "./marker-tracker.js"; export class VarsCompiler extends SectionCompiler { public get id() { return constants.section.vars; @@ -20,7 +21,8 @@ export class VarsCompiler extends SectionCompiler { public get dependencies(): Set { const defaults = new Set([ constants.section.strs, - constants.section.elem + constants.section.elem, + constants.section.list, ]); defaults.delete(this.id); return defaults; @@ -32,7 +34,6 @@ export class VarsCompiler extends SectionCompiler { public validate(): boolean { let valid = true; - // TODO-LDML scan for markers? // Check for duplicate ids const allIds = new Set(); @@ -139,51 +140,47 @@ export class VarsCompiler extends SectionCompiler { return valid; } - private collectMarkers(emitMarkers : Set, matchMarkers : Set) : boolean { + private collectMarkers(mt : MarkerTracker) : boolean { let valid = true; // call our friends to validate - valid = this.validateVarsMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity - valid = KeysCompiler.validateMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity - valid = TransformCompiler.validateMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity - valid = DispCompiler.validateMarkers(this.keyboard, emitMarkers, matchMarkers) && valid; // accumulate validity + valid = this.validateVarsMarkers(this.keyboard, mt) && valid; // accumulate validity + valid = KeysCompiler.validateMarkers(this.keyboard, mt) && valid; // accumulate validity + valid = TransformCompiler.validateMarkers(this.keyboard, mt) && valid; // accumulate validity + valid = DispCompiler.validateMarkers(this.keyboard, mt) && valid; // accumulate validity return valid; } private validateMarkers(): boolean { - /** only the markers used in emitters */ - const emitMarkers : Set = new Set(); - /** only the markers used in matchers */ - const matchMarkers : Set = new Set(); - - - let valid = this.collectMarkers(emitMarkers, matchMarkers); - + const mt = new MarkerTracker(); + let valid = this.collectMarkers(mt); // see if there are any matched-but-not-emitted - const matchedNotEmitted : string[] = []; - for (const m of matchMarkers.values()) { - if (m === '.') continue; // match-all marker - if (!emitMarkers.has(m)) { - matchedNotEmitted.push(m); + const matchedNotEmitted : Set = new Set(); + for (const m of mt.matched.values()) { + if (m === MarkerParser.ANY_MARKER_ID) continue; // match-all marker + if (!mt.emitted.has(m)) { + matchedNotEmitted.add(m); + } + } + for (const m of mt.consumed.values()) { + if (m === MarkerParser.ANY_MARKER_ID) continue; // match-all marker + if (!mt.emitted.has(m)) { + matchedNotEmitted.add(m); } } // report once - if (matchedNotEmitted.length) { - matchedNotEmitted.sort(); - this.callbacks.reportMessage(CompilerMessages.Error_MissingMarkers({ ids: matchedNotEmitted })); + if (matchedNotEmitted.size > 0) { + this.callbacks.reportMessage(CompilerMessages.Error_MissingMarkers({ ids: Array.from(matchedNotEmitted.values()).sort() })); valid = false; } return valid; } - validateVarsMarkers(keyboard: LDMLKeyboard.LKKeyboard, emitMarkers: Set, matchMarkers: Set) : boolean { + validateVarsMarkers(keyboard: LDMLKeyboard.LKKeyboard, mt : MarkerTracker) : boolean { keyboard?.variables?.string?.forEach(({value}) => - MarkerParser.allReferences(value).forEach(marker => { - emitMarkers.add(marker); - matchMarkers.add(marker); - })); + mt.add(MarkerUse.variable, MarkerParser.allReferences(value))); return true; } @@ -207,6 +204,14 @@ export class VarsCompiler extends SectionCompiler { variables?.unicodeSet?.forEach((e) => this.addUnicodeSet(result, e, sections)); + // reload markers - TODO-LDML: double work! + const mt = new MarkerTracker(); + this.collectMarkers(mt); + + // collect all markers, excluding the match-all + const allMarkers : string[] = Array.from(mt.all).filter(m => m !== MarkerParser.ANY_MARKER_ID).sort(); + result.markers = sections.list.allocList(sections.strs, allMarkers); + return result.valid() ? result : null; } diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml index baa93830759..cbe36d4db1c 100644 --- a/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/markers-maximal.xml @@ -15,30 +15,30 @@ - + - + - + - - + + - + - + diff --git a/developer/src/kmc-ldml/test/test-vars.ts b/developer/src/kmc-ldml/test/test-vars.ts index d9e9d4df29f..6acaef35daa 100644 --- a/developer/src/kmc-ldml/test/test-vars.ts +++ b/developer/src/kmc-ldml/test/test-vars.ts @@ -189,6 +189,12 @@ describe('vars', function () { testCompilationCases(VarsCompiler, [ { subpath: 'sections/vars/markers-maximal.xml', + callback(sect) { + const vars = sect; + assert.ok(vars.markers); + assert.sameDeepOrderedMembers(vars.markers.toStringArray(), + ['m','x']); + }, }, { subpath: 'sections/vars/fail-markers-badref-0.xml', From 99886623a5022f01c094dde63ecbd56b632b0423 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Sat, 29 Jul 2023 14:48:08 -0500 Subject: [PATCH 6/8] =?UTF-8?q?feat(developer):=20marker=20accounting=20?= =?UTF-8?q?=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .. and the basic.txt to prove it #9119 --- .../src/kmc-ldml/test/fixtures/basic.txt | 30 +++++++++++++------ .../src/kmc-ldml/test/fixtures/basic.xml | 1 + 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/developer/src/kmc-ldml/test/fixtures/basic.txt b/developer/src/kmc-ldml/test/fixtures/basic.txt index 0fe6d67a308..8713f93ae10 100644 --- a/developer/src/kmc-ldml/test/fixtures/basic.txt +++ b/developer/src/kmc-ldml/test/fixtures/basic.txt @@ -257,7 +257,7 @@ block(keys) # struct COMP_KMXPLUS_KEYS { index(strNull,strHmaqtugha,2) # KMXPLUS_STR 'hmaqtugha' 00 00 00 00 # KMXPLUS_STR switch 0A 00 00 00 # KMX_DWORD width*10 - 01 00 00 00 # TODO: index(listNull,indexAe,4) # LIST longPress 'a e' + 02 00 00 00 # TODO: index(listNull,indexAe,4) # LIST longPress 'a e' 00 00 00 00 # STR longPressDefault 00 00 00 00 # TODO: index(listNull,listNull,4) # LIST multiTap 00 00 00 00 # flicks 0 @@ -324,21 +324,25 @@ block(layr) # struct COMP_KMXPLUS_LAYR { block(list) # struct COMP_KMXPLUS_LAYR_LIST { 6c 69 73 74 # KMX_DWORD header.ident; // 0000 Section name - list diff(list,endList) # KMX_DWORD header.size; // 0004 Section length - 02 00 00 00 # KMX_DWORD listCount (should be 2) - 02 00 00 00 # KMX_DWORD indexCount (should be 2) + 03 00 00 00 # KMX_DWORD listCount (should be 2) + 03 00 00 00 # KMX_DWORD indexCount (should be 2) # list #0 the null list block(listNull) 00 00 00 00 #index(indexNull,indexNull,2) # KMX_DWORD list index (0) 00 00 00 00 # KMX_DWORD lists[0].count - # list #1 the ae list + block(listA) + 00 00 00 00 # first index + 01 00 00 00 #count block(listAe) - 00 00 00 00 # index(indexAe,indexNull,2) # KMX_DWORD list index (also 0) + 01 00 00 00 # index(indexAe,indexNull,2) # KMX_DWORD list index (also 0) 02 00 00 00 # KMX_DWORD count block(endLists) # indices #block(indexNull) # No null index # index(strNull,strNull,2) # KMXPLUS_STR string index + block(indexA) + index(strNull,strA,2) # a block(indexAe) index(strNull,strA,2) # KMXPLUS_STR a index(strNull,strElemBkspFrom2,2) # KMXPLUS_STR e @@ -401,6 +405,7 @@ block(strs) # struct COMP_KMXPLUS_STRS { diff(strs,strName) sizeof(strName,2) diff(strs,strFromSet) sizeof(strFromSet,2) diff(strs,strUSet) sizeof(strUSet,2) + diff(strs,strAmarker) sizeof(strAmarker,2) diff(strs,strElemTranFrom1) sizeof(strElemTranFrom1,2) diff(strs,strElemTranFrom1a) sizeof(strElemTranFrom1a,2) diff(strs,strElemTranFrom1b) sizeof(strElemTranFrom1b,2) @@ -433,6 +438,7 @@ block(strs) # struct COMP_KMXPLUS_STRS { block(strName) 54 00 65 00 73 00 74 00 4b 00 62 00 64 00 block(x) 00 00 # 'TestKbd' block(strFromSet) 5B 00 5C 00 75 00 31 00 41 00 37 00 35 00 2D 00 5C 00 75 00 31 00 41 00 37 00 39 00 5D 00 block(x) 00 00 # [\u1a75-\u1a79] block(strUSet) 5b 00 61 00 62 00 63 00 5d 00 block(x) 00 00 # '[abc]' + block(strAmarker) 5C 00 6D 00 7B 00 61 00 7D 00 block(x) 00 00 # '\m{a}' block(strElemTranFrom1) 5E 00 block(x) 00 00 # '^' block(strElemTranFrom1a) 5E 00 61 00 block(x) 00 00 # '^a' block(strElemTranFrom1b) 5E 00 65 00 block(x) 00 00 # '^e' @@ -520,23 +526,29 @@ block(uset) block(vars) # struct COMP_KMXPLUS_VARS { 76 61 72 73 # KMX_DWORD header.ident; // 0000 Section name - vars diff(vars,varsEnd) # KMX_DWORD header.size; // 0004 Section length - 00 00 00 00 # KMX_DWORD markers - list + 01 00 00 00 # KMX_DWORD markers - list 1 ['a'] diff(varsBegin,varsEnd,16) # KMX_DWORD varCount - # var 0 block(varsBegin) + # var 0 + 00 00 00 00 # KMX_DWORD type = str + index(strNull,strA,2) # KMXPLUS_STR id 'a' + index(strNull,strAmarker,2) # KMXPLUS_STR value '\m{a}' + 00 00 00 00 # KMXPLUS_ELEM + + # var 1 01 00 00 00 # KMX_DWORD type = set index(strNull,strVse,2) # KMXPLUS_STR id 'vse' index(strNull,strSet,2) # KMXPLUS_STR value 'a b c' 01 00 00 00 # KMXPLUS_ELEM elem 'a b c' see 'elemSet' - # var 1 + # var 2 00 00 00 00 # KMX_DWORD type = string index(strNull,strVst,2) # KMXPLUS_STR id 'vst' index(strNull,strSet2,2) # KMXPLUS_STR value 'abc' 00 00 00 00 # KMXPLUS_ELEM elem - # var 2 + # var 3 02 00 00 00 # KMX_DWORD type = string index(strNull,strVus,2) # KMXPLUS_STR id 'vus' index(strNull,strUSet,2) # KMXPLUS_STR value '[abc]' diff --git a/developer/src/kmc-ldml/test/fixtures/basic.xml b/developer/src/kmc-ldml/test/fixtures/basic.xml index 0eb6676490f..cb0c56d2692 100644 --- a/developer/src/kmc-ldml/test/fixtures/basic.xml +++ b/developer/src/kmc-ldml/test/fixtures/basic.xml @@ -37,6 +37,7 @@ + From 581d65a4c7f62b6da93adb8f94952652bf1a9e8e Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Sat, 29 Jul 2023 14:55:21 -0500 Subject: [PATCH 7/8] =?UTF-8?q?fix(common):=20list=20fix=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - a falsy list should show up as list #0 #9119 --- common/web/types/src/kmx/kmx-plus-builder/build-list.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/web/types/src/kmx/kmx-plus-builder/build-list.ts b/common/web/types/src/kmx/kmx-plus-builder/build-list.ts index e770e7b2783..26659f8eb6a 100644 --- a/common/web/types/src/kmx/kmx-plus-builder/build-list.ts +++ b/common/web/types/src/kmx/kmx-plus-builder/build-list.ts @@ -86,6 +86,9 @@ export function build_list(source_list: List, sect_strs: BUILDER_STRS): BUILDER_ * @returns */ export function build_list_index(sect_list: BUILDER_LIST, value: ListItem) : BUILDER_LIST_REF { + if (!value) { + return 0; // empty list + } if(!(value instanceof ListItem)) { throw new Error('unexpected value '+ value); } From f2fea17b66effbf3e857e43a1d98937a702e9be9 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Mon, 31 Jul 2023 15:57:44 -0500 Subject: [PATCH 8/8] Update developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml Co-authored-by: Marc Durdin --- .../test/fixtures/sections/vars/fail-markers-badref-0.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml index 063b5a5d114..fd63c36b025 100644 --- a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-markers-badref-0.xml @@ -13,7 +13,7 @@ This will fail because the two markers given don't exist anywhere. - +