mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-22 07:37:40 +00:00
feat(developer): errs on \uXXXX escapes 🙀
- note, some older test cases had to be fixed also. For: #10389
This commit is contained in:
parent
b99a2cf2a5
commit
8787073c40
10 changed files with 100 additions and 11 deletions
|
|
@ -36,7 +36,7 @@ export class UnescapeError extends Error {
|
|||
* @param hex one codepoint in hex, such as '0127'
|
||||
* @returns the unescaped codepoint
|
||||
*/
|
||||
function unescapeOne(hex: string): string {
|
||||
export function unescapeOne(hex: string): string {
|
||||
const codepoint = Number.parseInt(hex, 16);
|
||||
return String.fromCodePoint(codepoint);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,6 +173,10 @@ export class CompilerMessages {
|
|||
static Error_UnparseableTransformFrom = (o: { from: string }) =>
|
||||
m(this.ERROR_UnparseableTransformFrom, `Invalid transfom from "${o.from}"`);
|
||||
static ERROR_UnparseableTransformFrom = SevError | 0x0029;
|
||||
|
||||
static Error_InvalidQuadEscape = (o: { cp: number }) =>
|
||||
m(this.ERROR_InvalidQuadEscape, `Invalid escape "\\u${util.hexQuad(o?.cp || 0)}", use "\\u{${o?.cp?.toString(16)}}" instead.`);
|
||||
static ERROR_InvalidQuadEscape = SevError | 0x0030;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -144,8 +144,11 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
|
|||
// don't unescape literals here, because we are going to pass them through into the regex
|
||||
cookedFrom = util.unescapeStringToRegex(cookedFrom);
|
||||
|
||||
// cook the ranges also
|
||||
cookedFrom = this.checkEscapes(cookedFrom); // check for \uXXXX escapes before normalizing
|
||||
if (cookedFrom === null) return null; // error
|
||||
|
||||
cookedFrom = this.checkRanges(cookedFrom); // check before normalizing
|
||||
if (cookedFrom === null) return null; // error
|
||||
|
||||
if (!sections?.meta?.normalizationDisabled) {
|
||||
// nfd here.
|
||||
|
|
@ -156,7 +159,7 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
|
|||
new RegExp(cookedFrom, 'ug');
|
||||
} catch (e) {
|
||||
this.callbacks.reportMessage(CompilerMessages.Error_UnparseableTransformFrom({ from: transform.from }));
|
||||
return null;
|
||||
return null; // error
|
||||
}
|
||||
|
||||
// cookedFrom is cooked above, since there's some special treatment
|
||||
|
|
@ -185,6 +188,12 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
|
|||
|
||||
private compileReorder(sections: DependencySections, reorder: LKReorder): TranReorder {
|
||||
let result = new TranReorder();
|
||||
if (reorder.from && this.checkEscapes(reorder.from) === null) {
|
||||
return null; // error'ed
|
||||
}
|
||||
if (reorder.before && this.checkEscapes(reorder.before) === null) {
|
||||
return null; // error'ed
|
||||
}
|
||||
result.elements = sections.elem.allocElementString(sections, reorder.from, reorder.order, reorder.tertiary, reorder.tertiaryBase, reorder.preBase);
|
||||
result.before = sections.elem.allocElementString(sections, reorder.before);
|
||||
if (!result.elements || !result.before) {
|
||||
|
|
@ -216,9 +225,27 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
|
|||
return defaults;
|
||||
}
|
||||
|
||||
/** true if ok */
|
||||
private checkRanges(cookedFrom: string): string {
|
||||
/** returns ===null on error */
|
||||
private checkEscapes(cookedFrom: string): string | null {
|
||||
if (!cookedFrom) return cookedFrom;
|
||||
|
||||
// should not follow marker prefix, nor marker prefix with range
|
||||
const anyQuad = /(?<!\\uffff\\u0008(?:\[[0-9a-fA-F\\u-]*)?)\\u([0-9a-fA-F]{4})/g;
|
||||
|
||||
for (const [, sub] of cookedFrom.matchAll(anyQuad)) {
|
||||
const s = util.unescapeOne(sub);
|
||||
if (s !== '\uffff' && s !== '\u0008') { // markers
|
||||
this.callbacks.reportMessage(CompilerMessages.Error_InvalidQuadEscape({ cp: s.codePointAt(0) }));
|
||||
return null; // exit on the first error
|
||||
}
|
||||
}
|
||||
return cookedFrom;
|
||||
}
|
||||
|
||||
/** returns ===null on error */
|
||||
private checkRanges(cookedFrom: string): string | null {
|
||||
if (!cookedFrom) return cookedFrom;
|
||||
|
||||
// extract all of the potential ranges - but don't match any-markers!
|
||||
const anyRange = /(?<!\\uffff\\u0008)\[([^\]]+)\]/g;
|
||||
const ranges = cookedFrom.matchAll(anyRange);
|
||||
|
|
@ -226,7 +253,7 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
|
|||
if (!ranges) return cookedFrom;
|
||||
|
||||
// extract inner members of a range (inside the [])
|
||||
const rangeRegex = /(\\u[0-9a-fA-F]{4}|.)-(\\u[0-9a-fA-F]{4}|.)|./g;
|
||||
const rangeRegex = /(\\u\{[0-9a-fA-F]\}{1,6}|.)-(\\u\{[0-9a-fA-F]\}{1,6}|.)|./g;
|
||||
|
||||
const rangeExplicit = new util.NFDAnalyzer();
|
||||
const rangeImplicit = new util.NFDAnalyzer();
|
||||
|
|
@ -235,8 +262,6 @@ export abstract class TransformCompiler<T extends TransformCompilerType, TranBas
|
|||
function processExplicit(s: string) {
|
||||
if (s.startsWith('\\u{')) {
|
||||
s = util.unescapeString(s);
|
||||
} else if(s.startsWith('\\u')) {
|
||||
s = util.unescapeOneQuadString(s);
|
||||
}
|
||||
rangeExplicit.add(s);
|
||||
return s;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
<transformGroup>
|
||||
<!-- Northern Thai example from spec -->
|
||||
<reorder before="\u{1A6B}" from="\u{1A60}[\u1A75-\u1A79]\u{1A45}" order="10 55 10" />
|
||||
<reorder before="\u{1A6B}" from="\u{1A60}[\u{1A75}-\u{1A79}]\u{1A45}" order="10 55 10" />
|
||||
</transformGroup>
|
||||
</transforms>
|
||||
|
||||
|
|
|
|||
14
developer/src/kmc-ldml/test/fixtures/sections/tran/fail-bad-reorder-2.xml
vendored
Normal file
14
developer/src/kmc-ldml/test/fixtures/sections/tran/fail-bad-reorder-2.xml
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE keyboard3 SYSTEM "../../../../../../../resources/standards-data/ldml-keyboards/techpreview/dtd/ldmlKeyboard3.dtd">
|
||||
<keyboard3 locale="mt" conformsTo="techpreview">
|
||||
<info name="fail-bad-reorder"/>
|
||||
|
||||
<keys />
|
||||
|
||||
<transforms type="simple">
|
||||
<transformGroup>
|
||||
<reorder before="\u1A6B" from="\u{1A60}[\u{1A75}-\u{1A79}]\u{1A45}" order="10 55 10" />
|
||||
</transformGroup>
|
||||
</transforms>
|
||||
</keyboard3>
|
||||
14
developer/src/kmc-ldml/test/fixtures/sections/tran/fail-bad-reorder-3.xml
vendored
Normal file
14
developer/src/kmc-ldml/test/fixtures/sections/tran/fail-bad-reorder-3.xml
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE keyboard3 SYSTEM "../../../../../../../resources/standards-data/ldml-keyboards/techpreview/dtd/ldmlKeyboard3.dtd">
|
||||
<keyboard3 locale="mt" conformsTo="techpreview">
|
||||
<info name="fail-bad-reorder"/>
|
||||
|
||||
<keys />
|
||||
|
||||
<transforms type="simple">
|
||||
<transformGroup>
|
||||
<reorder from="\u1A60[\u1A75-\u1A79]\u1A45" order="10 55 10" />
|
||||
</transformGroup>
|
||||
</transforms>
|
||||
</keyboard3>
|
||||
14
developer/src/kmc-ldml/test/fixtures/sections/tran/fail-bad-tran-2.xml
vendored
Normal file
14
developer/src/kmc-ldml/test/fixtures/sections/tran/fail-bad-tran-2.xml
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE keyboard3 SYSTEM "../../../../../../../resources/standards-data/ldml-keyboards/techpreview/dtd/ldmlKeyboard3.dtd">
|
||||
<keyboard3 locale="mt" conformsTo="techpreview">
|
||||
<info name="fail-bad-tran-2"/>
|
||||
|
||||
<keys />
|
||||
|
||||
<transforms type="simple">
|
||||
<transformGroup>
|
||||
<transform from="\u0127" to="x"/> <!-- fail: use \u{1234} instead -->
|
||||
</transformGroup>
|
||||
</transforms>
|
||||
</keyboard3>
|
||||
|
|
@ -71,7 +71,7 @@ describe('compiler-tests', function() {
|
|||
const source = k.load(filename);
|
||||
assert.notOk(source, `Trying to loadTestData(${filename})`);
|
||||
});
|
||||
it('should fail on illegal chars', async function() {
|
||||
it('should fail on illegal chars - sections/strs/invalid-illegal.xml', async function() {
|
||||
const inputFilename = makePathToFixture('sections/strs/invalid-illegal.xml');
|
||||
const kmx = await compileKeyboard(inputFilename, { ...compilerTestOptions, saveDebug: true, shouldAddCompilerVersion: false },
|
||||
[
|
||||
|
|
|
|||
|
|
@ -265,11 +265,23 @@ describe('tran', function () {
|
|||
],
|
||||
},
|
||||
{
|
||||
subpath: 'sections/tran/fail-bad-reorder.xml',
|
||||
subpath: 'sections/tran/fail-bad-reorder-1.xml',
|
||||
errors: [
|
||||
KmnOtherCompilerMessages.Error_UnicodeSetSyntaxError()
|
||||
],
|
||||
},
|
||||
{
|
||||
subpath: 'sections/tran/fail-bad-reorder-2.xml',
|
||||
errors: [
|
||||
CompilerMessages.Error_InvalidQuadEscape({ cp: 0x1a6b }),
|
||||
],
|
||||
},
|
||||
{
|
||||
subpath: 'sections/tran/fail-bad-reorder-3.xml',
|
||||
errors: [
|
||||
CompilerMessages.Error_InvalidQuadEscape({ cp: 0x1a60 }),
|
||||
],
|
||||
},
|
||||
// error due to bad regex
|
||||
{
|
||||
subpath: `sections/tran/fail-bad-tran-1.xml`,
|
||||
|
|
@ -277,6 +289,12 @@ describe('tran', function () {
|
|||
CompilerMessages.Error_UnparseableTransformFrom({ from: 'AB(now if only I would terminate this group..' }),
|
||||
],
|
||||
},
|
||||
{
|
||||
subpath: `sections/tran/fail-bad-tran-2.xml`,
|
||||
errors: [
|
||||
CompilerMessages.Error_InvalidQuadEscape({ cp: 295 }),
|
||||
],
|
||||
},
|
||||
], tranDependencies);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue