diff --git a/common/web/types/src/ldml-keyboard/pattern-parser.ts b/common/web/types/src/ldml-keyboard/pattern-parser.ts
index 2ea9304a75..5bebb14669 100644
--- a/common/web/types/src/ldml-keyboard/pattern-parser.ts
+++ b/common/web/types/src/ldml-keyboard/pattern-parser.ts
@@ -69,9 +69,9 @@ export class MarkerParser {
public static readonly MAX_MARKER_COUNT = constants.marker_max_count;
private static anyMarkerMatch() : string {
- const start = hexQuad(this.MIN_MARKER_INDEX);
- const end = hexQuad(this.MAX_MARKER_INDEX);
- return `${this.SENTINEL_MATCH}${this.MARKER_CODE_MATCH}[\\u${start}-\\u${end}]`; // TODO-LDML: #9121 wrong escape format
+ const start = hexQuad(MarkerParser.MIN_MARKER_INDEX);
+ const end = hexQuad(MarkerParser.MAX_MARKER_INDEX);
+ return `${MarkerParser.SENTINEL_MATCH}${MarkerParser.MARKER_CODE_MATCH}[\\u${start}-\\u${end}]`; // TODO-LDML: #9121 wrong escape format
}
/** Expression that matches any marker */
@@ -91,7 +91,7 @@ export class MarkerParser {
if (!str) {
return [];
}
- return matchArray(str, this.REFERENCE);
+ return matchArray(str, MarkerParser.REFERENCE);
}
private static markerCodeToString(n: number, forMatch?: boolean): string {
@@ -108,19 +108,19 @@ export class MarkerParser {
throw RangeError(`Internal Error: marker index out of range ${n}`);
}
if (forMatch) {
- return this.SENTINEL_MATCH + this.MARKER_CODE_MATCH + this.markerCodeToString(n, forMatch);
+ return MarkerParser.SENTINEL_MATCH + MarkerParser.MARKER_CODE_MATCH + MarkerParser.markerCodeToString(n, forMatch);
} else {
- return this.SENTINEL + this.MARKER_CODE + this.markerCodeToString(n, forMatch);
+ return MarkerParser.SENTINEL + MarkerParser.MARKER_CODE + MarkerParser.markerCodeToString(n, forMatch);
}
}
/** @returns all marker strings as sentinel values */
public static toSentinelString(s: string, markers?: OrderedStringList, forMatch?: boolean) : string {
if (!s) return s;
- return s.replaceAll(this.REFERENCE, (sub, arg) => {
+ return s.replaceAll(MarkerParser.REFERENCE, (sub, arg) => {
if (arg === MarkerParser.ANY_MARKER_ID) {
if (forMatch) {
- return this.ANY_MARKER_MATCH;
+ return MarkerParser.ANY_MARKER_MATCH;
}
return MarkerParser.markerOutput(MarkerParser.ANY_MARKER_INDEX);
}
@@ -195,7 +195,7 @@ export class MarkerParser {
do {
/** remainder of string i..end, for match */
const rest = a.slice(i).join('');
- const p = this.parse_next_marker(rest, forMatch);
+ const p = MarkerParser.parse_next_marker(rest, forMatch);
const have_marker = !!(p?.match);
// First, categorize the current character.
@@ -245,7 +245,7 @@ export class MarkerParser {
*/
public static nfd_markers_segment(s: string, map: MarkerMap, forMatch?: boolean) : string {
// remove (and parse) the markers first
- const str_unmarked = this.remove_markers(s, map, forMatch);
+ const str_unmarked = MarkerParser.remove_markers(s, map, forMatch);
// then, NFD the normalized string
const str_unmarked_nfd = str_unmarked.normalize("NFD");
if(map.length == 0) {
@@ -257,7 +257,7 @@ export class MarkerParser {
} else {
// we had markers AND the normalization made a difference.
// add the markers back per the map, and return
- return this.add_back_markers(str_unmarked_nfd, map, forMatch);
+ return MarkerParser.add_back_markers(str_unmarked_nfd, map, forMatch);
}
}
@@ -266,7 +266,7 @@ export class MarkerParser {
if (forMatch && marker === constants.marker_any_index) {
return MarkerParser.ANY_MARKER_MATCH + s;
} else {
- return this.markerOutput(marker, forMatch) + s;
+ return MarkerParser.markerOutput(marker, forMatch) + s;
}
}
@@ -361,7 +361,7 @@ export class MarkerParser {
// iterate until the codepoint list is empty
while (a.length > 0) {
// does 'a' begin with a marker?
- const p = this.parse_next_marker(a.join(''), forMatch);
+ const p = MarkerParser.parse_next_marker(a.join(''), forMatch);
if (!p?.match) {
// no match
add_pending_markers(a[0]); // add any pending markers
@@ -484,7 +484,7 @@ export class VariableParser {
* @returns `[]` or an array of all string references referenced
*/
public static allStringReferences(str: string): string[] {
- return matchArray(str, this.STRING_REFERENCE);
+ return matchArray(str, VariableParser.STRING_REFERENCE);
}
/**
@@ -493,7 +493,7 @@ export class VariableParser {
* @returns `[]` or an array of all string references referenced
*/
public static allSetReferences(str: string): string[] {
- return matchArray(str, this.SET_REFERENCE);
+ return matchArray(str, VariableParser.SET_REFERENCE);
}
/**
@@ -570,7 +570,7 @@ export class ElementParser {
/** Split a string into ElementSegments */
public static segment(str: string): ElementSegment[] {
- if (this.MATCH_NESTED_SQUARE_BRACKETS.test(str)) {
+ if (ElementParser.MATCH_NESTED_SQUARE_BRACKETS.test(str)) {
throw Error(`Unsupported: nested square brackets in element segment: ${str}`);
}
const list: ElementSegment[] = [];
diff --git a/developer/src/kmc-ldml/test/fixtures/sections/keys/maximal.xml b/developer/src/kmc-ldml/test/fixtures/sections/keys/maximal.xml
index 35a58057cb..20c1e5534c 100644
--- a/developer/src/kmc-ldml/test/fixtures/sections/keys/maximal.xml
+++ b/developer/src/kmc-ldml/test/fixtures/sections/keys/maximal.xml
@@ -8,6 +8,7 @@
+
@@ -42,7 +43,7 @@
-
+
diff --git a/developer/src/kmc-ldml/test/fixtures/sections/tran/tran-vars.xml b/developer/src/kmc-ldml/test/fixtures/sections/tran/tran-vars.xml
index e78fef350e..38b6693b1b 100644
--- a/developer/src/kmc-ldml/test/fixtures/sections/tran/tran-vars.xml
+++ b/developer/src/kmc-ldml/test/fixtures/sections/tran/tran-vars.xml
@@ -22,6 +22,8 @@
+
+
diff --git a/developer/src/kmc-ldml/test/test-keys.ts b/developer/src/kmc-ldml/test/test-keys.ts
index c9d5fa58b8..9371b1823d 100644
--- a/developer/src/kmc-ldml/test/test-keys.ts
+++ b/developer/src/kmc-ldml/test/test-keys.ts
@@ -37,7 +37,7 @@ describe('keys', function () {
const keys = sect;
assert.ok(keys);
assert.equal(compilerTestCallbacks.messages.length, 0);
- assert.equal(keys.keys.length, 12 + KeysCompiler.reserved_count); // includes flick and gesture keys
+ assert.equal(keys.keys.length, 13 + KeysCompiler.reserved_count); // includes flick and gesture keys
const [w] = keys.keys.filter(({ id }) => id.value === 'w');
assert.ok(w);
@@ -63,6 +63,16 @@ describe('keys', function () {
const [flick0_ne_sw] = flick0.flicks.filter(({ directions }) => directions && directions.isEqual('ne sw'.split(' ')));
assert.ok(flick0_ne_sw);
assert.equal(flick0_ne_sw.keyId?.value, 'e-caret'); // via variable
+
+ // normalization w markers
+ const [amarker] = keys.keys.filter(({ id }) => id.value === 'amarker');
+ assert.equal(amarker.to.value, `a\u{0320}${MarkerParser.markerOutput(1, false)}\u{0301}`,
+ 'did not match (may be a normalization issue)'); // normalized
+
+ // normalization
+ const [aacute] = keys.keys.filter(({ id }) => id.value === 'a-acute');
+ assert.equal(aacute.to.value, 'a\u{0301}', 'did not match (may be a normalization issue)'); // normalized
+
},
},
{
diff --git a/developer/src/kmc-ldml/test/test-layr.ts b/developer/src/kmc-ldml/test/test-layr.ts
index 62b03b1eea..04bf461aa4 100644
--- a/developer/src/kmc-ldml/test/test-layr.ts
+++ b/developer/src/kmc-ldml/test/test-layr.ts
@@ -70,8 +70,8 @@ describe('layr', function () {
assert.equal(hardware1.mod, constants.keys_mod_shift);
const hardware1row0 = hardware1.rows[0];
assert.ok(hardware1row0);
- assert.equal(hardware1row0.keys.length, 2);
- allKeysOk(hardware1row0,'q w', 'hardware1row0');
+ assert.equal(hardware1row0.keys.length, 3);
+ allKeysOk(hardware1row0,'q w amarker', 'hardware1row0');
const listTouch = layr.lists.find(v => v.hardware.value === constants.layr_list_hardware_touch);
assert.ok(listTouch);
diff --git a/developer/src/kmc-ldml/test/test-tran.ts b/developer/src/kmc-ldml/test/test-tran.ts
index 4922facb63..9febfbbc05 100644
--- a/developer/src/kmc-ldml/test/test-tran.ts
+++ b/developer/src/kmc-ldml/test/test-tran.ts
@@ -4,7 +4,7 @@ import { TranCompiler, BkspCompiler } from '../src/compiler/tran.js';
import { BASIC_DEPENDENCIES, UsetCompiler } from '../src/compiler/empty-compiler.js';
import { CompilerMessages } from '../src/compiler/messages.js';
import { compilerTestCallbacks, testCompilationCases } from './helpers/index.js';
-import { KMXPlus } from '@keymanapp/common-types';
+import { KMXPlus, MarkerParser } from '@keymanapp/common-types';
import Tran = KMXPlus.Tran;// for tests…
import Bksp = KMXPlus.Bksp;// for tests…
@@ -41,14 +41,15 @@ describe('tran', function () {
{
subpath: 'sections/tran/tran-vars.xml',
callback(sect) {
+ const m = MarkerParser.markerOutput;
const tran = sect;
assert.ok(tran);
assert.lengthOf(compilerTestCallbacks.messages, 0);
// cautiously destructure
assert.lengthOf(tran.groups, 1);
const [ g0 ] = tran.groups;
- assert.lengthOf(g0.transforms, 4);
- const [ g0t0, g0t1, g0t2, g0t3 ] = g0.transforms;
+ assert.lengthOf(g0.transforms, 6);
+ const [ g0t0, g0t1, g0t2, g0t3, g0t4, g0t5 ] = g0.transforms;
assert.strictEqual(g0t0.from.value, "yes");
assert.strictEqual(g0t0.to.value, "no");
@@ -65,6 +66,17 @@ describe('tran', function () {
assert.strictEqual(g0t3.from.value, "((?:A|B|C|D|FF|E))");
assert.equal(g0t3.mapFrom?.value, "upper");
assert.equal(g0t3.mapTo?.value, "lower");
+
+ assert.strictEqual(g0t4.from.value,
+ `\u{03b9}${m(1,true)}\u{0309}\u{0301}`, '(warning: normalization)');
+ assert.strictEqual(g0t4.to.value,
+ `\u{03b9}\u{0313}\u{301}`, '(warning: normalization)');
+
+ assert.strictEqual(g0t5.from.value,
+ `\u{03b9}\u{033c}${m(MarkerParser.ANY_MARKER_INDEX, true)}\u{0301}`, '(warning: normalization)'
+ );
+ assert.strictEqual(g0t5.to.value,
+ `\u{03b9}\u{033c}${m(1,false)}\u{0300}`);
}
},
{