Merge pull request #14097 from keymanapp/feat/developer/13937-ln-tran-bksp

feat(developer): remaining line numbers for tran/bksp compilers
This commit is contained in:
Steven R. Loomis 2025-06-04 08:38:39 -05:00 committed by GitHub
commit 72f4abc323
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 37 additions and 35 deletions

View file

@ -85,6 +85,7 @@ export class LdmlCompilerMessages {
`After minimization, one or more locales is repeated and has been removed`,
);
// This is the only allowed use of m() vs mx() in this file, all the others take context.
static ERROR_InvalidFile = SevError | 0x0007;
static Error_InvalidFile = (o:{errorText: string}) =>
m(this.ERROR_InvalidFile, `The source file has an invalid structure: ${def(o.errorText)}`);
@ -306,8 +307,10 @@ export class LdmlCompilerMessages {
);
static ERROR_UnparseableReorderSet = SevError | 0x0028;
static Error_UnparseableReorderSet = (o: { from: string, set: string }) =>
m(this.ERROR_UnparseableReorderSet, `Illegal UnicodeSet "${def(o.set)}" in reorder "${def(o.from)}`);
static Error_UnparseableReorderSet = (o: { from: string, set: string }, x?: ObjectWithMetadata) => mx(
this.ERROR_UnparseableReorderSet, x,
`Illegal UnicodeSet "${def(o.set)}" in reorder "${def(o.from)}`,
);
static ERROR_InvalidVariableIdentifier = SevError | 0x0029;
static Error_InvalidVariableIdentifier = (o: { id: string }, x?: ObjectWithMetadata) => mx(
@ -354,16 +357,18 @@ export class LdmlCompilerMessages {
// This is a bit of a catch-all and represents messages bubbling up from the underlying regex engine
static ERROR_UnparseableTransformFrom = SevErrorTransform | 0x00;
static Error_UnparseableTransformFrom = (o: { from: string, message: string }) =>
m(this.ERROR_UnparseableTransformFrom, `Invalid transform from="${def(o.from)}": "${def(o.message)}"`);
static Error_UnparseableTransformFrom = (o: { from: string, message: string }, x?: ObjectWithMetadata) => mx(
this.ERROR_UnparseableTransformFrom, x,
`Invalid transform from="${def(o.from)}": "${def(o.message)}"`,
);
//------------------------------------------------------------------------------|
// max length of detail message lines (checked by verifyCompilerMessagesObject) |
//------------------------------------------------------------------------------|
static ERROR_IllegalTransformDollarsign = SevErrorTransform | 0x01;
static Error_IllegalTransformDollarsign = (o: { from: string }) => m(
this.ERROR_IllegalTransformDollarsign,
static Error_IllegalTransformDollarsign = (o: { from: string }, x?: ObjectWithMetadata) => mx(
this.ERROR_IllegalTransformDollarsign, x,
`Invalid transform from="${def(o.from)}": Unescaped dollar-sign ($) is not valid transform syntax.`, `
**Hint**: Use \`\\$\` to match a literal dollar-sign. If this precedes a
variable name, the variable name may not be valid (A-Z, a-z, 0-9, _, 32
@ -377,30 +382,30 @@ export class LdmlCompilerMessages {
);
static ERROR_IllegalTransformPlus = SevErrorTransform | 0x03;
static Error_IllegalTransformPlus = (o: { from: string }) => m(
this.ERROR_IllegalTransformPlus,
static Error_IllegalTransformPlus = (o: { from: string }, x?: ObjectWithMetadata) => mx(
this.ERROR_IllegalTransformPlus, x,
`Invalid transform from="${def(o.from)}": Unescaped plus (+) is not valid transform syntax.`, `
**Hint**: Use \`\\+\` to match a literal plus.
`);
static ERROR_IllegalTransformAsterisk = SevErrorTransform | 0x04;
static Error_IllegalTransformAsterisk = (o: { from: string }) =>m(
this.ERROR_IllegalTransformAsterisk,
static Error_IllegalTransformAsterisk = (o: { from: string }, x?: ObjectWithMetadata) =>mx(
this.ERROR_IllegalTransformAsterisk, x,
`Invalid transform from="${def(o.from)}": Unescaped asterisk (*) is not valid transform syntax.`, `
**Hint**: Use \`\\*\` to match a literal asterisk.
`);
static ERROR_IllegalTransformToUset = SevErrorTransform | 0x05;
static Error_IllegalTransformToUset = (o: { to: string }) => m(
this.ERROR_IllegalTransformToUset,
static Error_IllegalTransformToUset = (o: { to: string }, x?: ObjectWithMetadata) => mx(
this.ERROR_IllegalTransformToUset, x,
`Invalid transform to="${def(o.to)}": Set variable (\\$[…]) cannot be used in 'to=' unless part of a map.`, `
**Hint**: If a map was meant, must use the form
\`<transform from="($[fromSet])" to="$[1:toSet]"/>\`.
`);
static ERROR_UnparseableTransformTo = SevErrorTransform | 0x06;
static Error_UnparseableTransformTo = (o: {to: string, message: string}) => m(
this.ERROR_UnparseableTransformTo,
static Error_UnparseableTransformTo = (o: {to: string, message: string}, x?: ObjectWithMetadata) => mx(
this.ERROR_UnparseableTransformTo, x,
`Invalid transform to="${def(o.to)}": "${def(o.message)}"`,
);

View file

@ -1,6 +1,6 @@
import { constants, SectionIdent } from "@keymanapp/ldml-keyboard-constants";
import { KMXPlus, LdmlKeyboardTypes, util } from '@keymanapp/common-types';
import { CompilerCallbacks, LDMLKeyboard } from "@keymanapp/developer-utils";
import { CompilerCallbacks, LDMLKeyboard, ObjectWithMetadata } from "@keymanapp/developer-utils";
import { SectionCompiler } from "./section-compiler.js";
import Bksp = KMXPlus.Bksp;
@ -204,7 +204,7 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
transform_from_parse(transform.from);
}
} catch (e) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_UnparseableTransformFrom({ from: cookedFrom, message: e.toString() }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_UnparseableTransformFrom({ from: cookedFrom, message: e.toString() }, transform));
return null;
}
@ -212,7 +212,7 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
try {
transform_to_parse(transform.to || '');
} catch (e) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_UnparseableTransformTo({ to: transform.to || '', message: e.toString() }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_UnparseableTransformTo({ to: transform.to || '', message: e.toString() }, transform));
return null;
}
@ -237,9 +237,9 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
* We have already checked that it's not a mapTo,
* so there should not be any illegal substitutions.
*/
private isValidTo(to: string) : boolean {
private isValidTo(to: string, x?: ObjectWithMetadata) : boolean {
if (/(?<!\\)(?:\\\\)*\$\[/.test(to)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformToUset({ to }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformToUset({ to }, x));
return false;
}
return true;
@ -251,18 +251,18 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
* @param from the original from - for error reporting
* @returns true if OK
*/
private isValidRegex(cookedFrom: string, from: string) : boolean {
private isValidRegex(cookedFrom: string, from: string, x?: ObjectWithMetadata) : boolean {
// check for any unescaped dollar sign here
if (/(?<!\\)(?:\\\\)*\$/.test(cookedFrom)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformDollarsign({ from }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformDollarsign({ from }, x));
return false;
}
if (/(?<!\\)(?:\\\\)*\*/.test(cookedFrom)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformAsterisk({ from }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformAsterisk({ from }, x));
return false;
}
if (/(?<!\\)(?:\\\\)*\+/.test(cookedFrom)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformPlus({ from }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_IllegalTransformPlus({ from }, x));
return false;
}
// Verify that the regex is syntactically valid
@ -272,14 +272,14 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
// does it match an empty string?
if (rg.test('')) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_TransformFromMatchesNothing({ from }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_TransformFromMatchesNothing({ from }, x));
return false;
}
} catch (e) {
// We're exposing the internal regex error message here.
// In the future, CLDR plans to expose the EBNF for the transform,
// at which point we would have more precise validation prior to getting to this point.
this.callbacks.reportMessage(LdmlCompilerMessages.Error_UnparseableTransformFrom({ from, message: e.message }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_UnparseableTransformFrom({ from, message: e.message }, x));
return false;
}
return true;

View file

@ -15,18 +15,20 @@ describe('LdmlCompilerMessages', function () {
/** all fns */
let total = 0;
/** does not take line numbers */
let noLines = 0;
const noLines = new Set<string>();
/** takes line numbers */
let lines = 0;
const fakeOffsetNumber = 1234;
const fakeOffsetObject = withOffset(fakeOffsetNumber);
for(const key of keys) {
if(typeof m[key] == 'function') {
// exclude this one, does not need line numbers
if (key == 'Error_InvalidFile') continue;
if (typeof m[key] == 'function') {
total++;
const f = m[key] as Function;
// console.log(`${f.name}: ${f.length}`);
if (f.length === 0) { // Error_foo()
noLines++;
noLines.add(key);
continue;
}
// now try to call it
@ -42,16 +44,11 @@ describe('LdmlCompilerMessages', function () {
expect(resp.offset).to.equal(fakeOffsetNumber, `Offset number round trip for error ${f.name} did not work, check the message function`);
} else {
// did not get a column number back
noLines++;
noLines.add(key);
}
}
}
expect(lines).to.not.be.equal(0, `None of ${total} messages had offset reporting.`);
if (noLines > 0) {
// Once this goes to zero, make it an error if it goes up!
// Oh, and while you're here, once this is zero, uncomment the code in testCompilationCases
// that asserts that all messages are actually generated with an offset.
console.warn(`TODO-LDML (#10622) ${noLines}/${total} ${Number((noLines/total)*1000).toFixed(0)}‰ of message(s) did not have detectable offset (line number) reporting.`);
}
expect(Array.from(noLines.values())).to.deep.equal([], `${noLines.size}/${total} ${Number((noLines.size/total)*100).toFixed(0)}% of message(s) did not have detectable offset (line number) reporting`);
});
});