From 3a677da0c6e76e7812264ea34ff7b0a1c2d40208 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 22 Sep 2023 16:48:07 -0500 Subject: [PATCH] =?UTF-8?q?feat(common):=20ldml=20scancodes=20=F0=9F=99=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For: #9403 - use Symbols to track import status --- .../ldml-keyboard/ldml-keyboard-xml-reader.ts | 17 ++++++++++---- .../src/ldml-keyboard/ldml-keyboard-xml.ts | 22 ++++++++++++++++++- .../test-ldml-keyboard-xml-reader.ts | 14 +++++++++++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts index 5bec1cde012..87f2cbbdbae 100644 --- a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +++ b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml-reader.ts @@ -1,5 +1,5 @@ import * as xml2js from 'xml2js'; -import { LDMLKeyboardXMLSourceFile, LKImport } from './ldml-keyboard-xml.js'; +import { LDMLKeyboardXMLSourceFile, LKImport, ImportStatus } from './ldml-keyboard-xml.js'; import { default as AjvModule } from 'ajv'; const Ajv = AjvModule.default; // The actual expected Ajv type. import { boxXmlArray } from '../util/util.js'; @@ -157,7 +157,7 @@ export class LDMLKeyboardXMLSourceFileReader { if (!this.resolveOneImport(obj, subtag, { base: constants.cldr_import_base, path: constants.cldr_implied_keys_import - })) { + }, true)) { return false; } } else if (subtag === 'forms') { @@ -165,7 +165,7 @@ export class LDMLKeyboardXMLSourceFileReader { if (!this.resolveOneImport(obj, subtag, { base: constants.cldr_import_base, path: constants.cldr_implied_forms_import - })) { + }, true)) { return false; } } @@ -176,9 +176,10 @@ export class LDMLKeyboardXMLSourceFileReader { * @param obj the object being imported into * @param subtag obj's element tag, e.g. `keys` * @param asImport the import structure + * @param implied true if it is an implied import * @returns true on success, false on failure */ - private resolveOneImport(obj: any, subtag: string, asImport: LKImport) : boolean { + private resolveOneImport(obj: any, subtag: string, asImport: LKImport, implied? : boolean) : boolean { const { base, path } = asImport; if (base !== constants.cldr_import_base) { this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidBase({base, path, subtag})); @@ -205,12 +206,20 @@ export class LDMLKeyboardXMLSourceFileReader { // pull all children of importXml[subtag] into obj for (const subsubtag of Object.keys(importRootNode).reverse()) { // e.g. const subsubval = importRootNode[subsubtag]; + const basePath = `${base}/${path}`; if (!Array.isArray(subsubval)) { // This is somewhat of an internal error, indicating that a non-mergeable XML file was imported // Not exercisable with the standard LDML imports. this.callbacks.reportMessage(CommonTypesMessages.Error_ImportMergeFail({base, path, subtag, subsubtag})); return false; } + // Mark all children as an import + subsubval.forEach(o => o[ImportStatus.import] = basePath); + if (implied) { + // mark all children as an implied import + subsubval.forEach(o => o[ImportStatus.impliedImport] = basePath); + } + if (!obj[subsubtag]) { obj[subsubtag] = []; // start with empty array } diff --git a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml.ts b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml.ts index 629b8e8aa24..0a6b2b0924e 100644 --- a/common/web/types/src/ldml-keyboard/ldml-keyboard-xml.ts +++ b/common/web/types/src/ldml-keyboard/ldml-keyboard-xml.ts @@ -12,7 +12,7 @@ export interface LDMLKeyboardXMLSourceFile { * -- the root element. */ keyboard3: LKKeyboard; -} +}; export interface LKKeyboard { locale?: string; @@ -193,3 +193,23 @@ export interface LKDisplays { display?: LKDisplay[]; displayOptions?: LKDisplayOptions; }; + +/** + * Utilities for determining the import status of items + */ +export class ImportStatus { + /** item came in via implied (spec based) import, such as keys-Latn-implied.xml */ + static impliedImport = Symbol.for('@keymanapp:implied_import'); + /** item came in via import */ + static import = Symbol.for('@keymanapp:import'); + + /** @returns true if the object was loaded through an implied import */ + static isImpliedImport(o : any) : boolean { + return o && !!o[ImportStatus.impliedImport]; + } + /** @returns true if the object was loaded through an explicit import */ + static isImport(o : any) : boolean { + return o && !!o[ImportStatus.import]; + } +}; + diff --git a/common/web/types/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts b/common/web/types/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts index 4da7a006636..296e36a8cc7 100644 --- a/common/web/types/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts +++ b/common/web/types/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts @@ -1,4 +1,4 @@ -import { LKKey } from './../../src/ldml-keyboard/ldml-keyboard-xml.js'; +import { LKKey, ImportStatus } from './../../src/ldml-keyboard/ldml-keyboard-xml.js'; import 'mocha'; import {assert} from 'chai'; import { CommonTypesMessages } from '../../src/util/common-events.js'; @@ -40,6 +40,9 @@ describe('ldml keyboard xml reader tests', function () { {id: 'b', to: 'b'}, {id: 'c', to: 'c'}, ]); + // all of the keys are implied imports here + assert.isTrue(ImportStatus.isImpliedImport(source?.keyboard3?.keys.key.find(({id}) => id === 'a'))); + assert.isTrue(ImportStatus.isImport(source?.keyboard3?.keys.key.find(({id}) => id === 'a'))); }, }, { @@ -81,6 +84,15 @@ describe('ldml keyboard xml reader tests', function () { {id: 'zz', to: 'zz'}, // new key {id: 'hash', to: '##'}, // override ]); + // 'a' is an implied import + assert.isTrue(ImportStatus.isImpliedImport(k.find(({id}) => id === 'a'))); + assert.isTrue(ImportStatus.isImport(k.find(({id}) => id === 'a'))); + // 'hash' is an import but not implied + assert.isFalse(ImportStatus.isImpliedImport(k.find(({id}) => id === 'hash'))); + assert.isTrue(ImportStatus.isImport(k.find(({id}) => id === 'hash'))); + // 'zz' is not imported + assert.isFalse(ImportStatus.isImpliedImport(k.find(({id}) => id === 'zz'))); + assert.isFalse(ImportStatus.isImport(k.find(({id}) => id === 'zz'))); }, }, {