feat(developer): add line numbers to disp compiler

Fixes #13938
This commit is contained in:
Steven R. Loomis 2025-05-26 10:44:12 -05:00
parent 235b2937e9
commit 577b439721
3 changed files with 18 additions and 13 deletions

View file

@ -31,20 +31,21 @@ export class DispCompiler extends SectionCompiler {
const ids = new Set();
if (this.keyboard3.displays?.display) {
for (const { output, keyId } of this.keyboard3.displays?.display) {
for (const display of this.keyboard3.displays?.display) {
const { output, keyId } = display;
if ((output && keyId) || (!output && !keyId)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_DisplayNeedsToOrId({ output, keyId }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_DisplayNeedsToOrId({ output, keyId }, display));
return false;
} else if (output) {
if (tos.has(output)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_DisplayIsRepeated({ output }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_DisplayIsRepeated({ output }, display));
return false;
} else {
tos.add(output);
}
} else if (keyId) {
if (ids.has(keyId)) {
this.callbacks.reportMessage(LdmlCompilerMessages.Error_DisplayIsRepeated({ keyId }));
this.callbacks.reportMessage(LdmlCompilerMessages.Error_DisplayIsRepeated({ keyId }, display));
return false;
} else {
ids.add(keyId);

View file

@ -147,8 +147,10 @@ export class LdmlCompilerMessages {
}
static ERROR_DisplayIsRepeated = SevError | 0x0010;
static Error_DisplayIsRepeated = (o:{output?: string, keyId?: string}) =>
m(this.ERROR_DisplayIsRepeated, `display ${LdmlCompilerMessages.outputOrKeyId(o)} has more than one display entry.`);
static Error_DisplayIsRepeated = (o:{output?: string, keyId?: string}, x?: ObjectWithMetadata) => mx(
this.ERROR_DisplayIsRepeated, x,
`display ${LdmlCompilerMessages.outputOrKeyId(o)} has more than one display entry.`,
);
static ERROR_KeyMissingToGapOrSwitch = SevError | 0x0011;
static Error_KeyMissingToGapOrSwitch = (o:{keyId: string}, x?: ObjectWithMetadata) => mx(
@ -244,8 +246,10 @@ export class LdmlCompilerMessages {
m(this.ERROR_MissingMarkers, `Markers used for matching but not defined: ${def(o.ids?.join(','))}`);
static ERROR_DisplayNeedsToOrId = SevError | 0x0022;
static Error_DisplayNeedsToOrId = (o:{output?: string, keyId?: string}) =>
m(this.ERROR_DisplayNeedsToOrId, `display ${LdmlCompilerMessages.outputOrKeyId(o)} needs output= or keyId=, but not both`);
static Error_DisplayNeedsToOrId = (o:{output?: string, keyId?: string}, x?: ObjectWithMetadata) => mx(
this.ERROR_DisplayNeedsToOrId, x,
`display ${LdmlCompilerMessages.outputOrKeyId(o)} needs output= or keyId=, but not both`,
);
static HINT_PUACharacters = SevHint | 0x0023;
static Hint_PUACharacters = (o: { count: number, lowestCh: number }) =>

View file

@ -1,7 +1,7 @@
import 'mocha';
import {assert} from 'chai';
import { DispCompiler } from '../src/compiler/disp.js';
import { compilerTestCallbacks, loadSectionFixture, testCompilationCases } from './helpers/index.js';
import { compilerTestCallbacks, loadSectionFixture, testCompilationCases, withOffset } from './helpers/index.js';
import { KMXPlus } from '@keymanapp/common-types';
import { LdmlCompilerMessages } from '../src/compiler/ldml-compiler-messages.js';
@ -67,25 +67,25 @@ describe('disp', function () {
const disp = await loadSectionFixture(DispCompiler, 'sections/disp/invalid-dupto.xml', compilerTestCallbacks) as Disp;
assert.isNull(disp);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayIsRepeated({ output: 'e' }));
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayIsRepeated({ output: 'e' }, withOffset(330)));
});
it('should reject duplicate ids', async function() {
const disp = await loadSectionFixture(DispCompiler, 'sections/disp/invalid-dupid.xml', compilerTestCallbacks) as Disp;1
assert.isNull(disp);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayIsRepeated({ keyId: 'e' }));
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayIsRepeated({ keyId: 'e' }, withOffset(329)));
});
it('should reject if neither to nor id', async function() {
const disp = await loadSectionFixture(DispCompiler, 'sections/disp/invalid-none.xml', compilerTestCallbacks) as Disp;
assert.isNull(disp);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayNeedsToOrId({}));
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayNeedsToOrId({}, withOffset(182)));
});
it('should reject if both to and id', async function() {
const disp = await loadSectionFixture(DispCompiler, 'sections/disp/invalid-both.xml', compilerTestCallbacks) as Disp;
assert.isNull(disp);
assert.equal(compilerTestCallbacks.messages.length, 1);
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayNeedsToOrId({ output: 'e', keyId: 'e' }));
assert.deepEqual(compilerTestCallbacks.messages[0], LdmlCompilerMessages.Error_DisplayNeedsToOrId({ output: 'e', keyId: 'e' }, withOffset(182)));
});
testCompilationCases(DispCompiler, [
{