Skip to content
Open
6 changes: 3 additions & 3 deletions testsuite/tests/input/tex/Base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ describe('Error', () => {
});

it('Ampersand-error', () => {
expectTexError('&').toBe('Misplaced &');
expectTexError('&').toBe("Misplaced '&'");
});

it('Argument-error', () => {
Expand Down Expand Up @@ -389,7 +389,7 @@ describe('Error', () => {
});

it('Misplaced Cr', () => {
expectTexError('a\\cr b').toBe('Misplaced \\cr');
expectTexError('a\\cr b').toBe("Misplaced '\\cr'");
});

it('Dimension Error', () => {
Expand Down Expand Up @@ -461,7 +461,7 @@ describe('Error', () => {
});

it('Misplaced hline', () => {
expectTexError('\\hline').toBe('Misplaced \\hline');
expectTexError('\\hline').toBe("Misplaced '\\hline'");
});

it('UnsupportedHFill', () => {
Expand Down
12 changes: 12 additions & 0 deletions testsuite/tests/input/tex/Physics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2472,6 +2472,18 @@ describe('Physics Errors', () => {
it('InvalidNumber XMatrix m+', () => {
expectTexError('\\smqty(\\xmatrix{a}{2}{2.0})').toBe('Invalid number');
});

it('Missing Closing Delimiter', () => {
expect(
tex2mml('\\sin(1\\over2')
).toMatchSnapshot();
});

it('Extra Open Delimiter', () => {
expect(
tex2mml('\\sin((1\\over2)')
).toMatchSnapshot();
});
});

/**********************************************************************************/
Expand Down
26 changes: 22 additions & 4 deletions testsuite/tests/input/tex/Tex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { HandlerType, ConfigurationType } from '#js/input/tex/HandlerTypes.js';
import { CommandMap } from '#js/input/tex/TokenMap.js';
import { Token } from '#js/input/tex/Token.js';
import { TagsFactory } from '#js/input/tex/Tags.js';
import { texError } from '#js/input/tex/TexError.js';
import TexError from '#js/input/tex/TexError.js';
import {
ParseUtil,
Expand Down Expand Up @@ -138,26 +139,43 @@ describe('Tags', () => {

describe('TexError', () => {
test('Number argument', () => {
const err = new TexError(null, 'test', 'Number: %1', 1 as any);
const err = new TexError('test', 'Number: %1', 1 as any);
expect(err.message).toBe('Number: 1');
});

test('Braced insertion', () => {
const err = new TexError(null, 'test', 'Msg: %{1}, Number: %{2}', 'OK', 2 as any);
const err = new TexError('test', 'Msg: %{1}, Number: %{2}', 'OK', 2 as any);
expect(err.message).toBe('Msg: OK, Number: 2');
});

test.skip('Plural', () => {
const err = new TexError(null, 'test', '%{plural:%1|abc}', 'apple');
const err = new TexError('test', '%{plural:%1|abc}', 'apple');
expect(err.message).toBe('%{plural:%1|abc}');
});

test('Percent', () => {
const err = new TexError(null, 'test', '10%%');
const err = new TexError('test', '10%%');
expect(err.message).toBe('10%');
});
});

describe('texError', () => {
test('Number argument', () => {
expect(() => texError(null, 'test', 'Number: %1', '1'))
.toThrow('Number: 1');
});

test('Braced insertion', () => {
expect(() => texError(null, 'test', 'Msg: %{1}, Number: %{2}', 'OK', '2'))
.toThrow('Msg: OK, Number: 2');
});

test('Percent', () => {
expect(() => texError(null, 'test', '10%%'))
.toThrow('10%');
});
});

/**********************************************************************************/

setupComponents({
Expand Down
4 changes: 2 additions & 2 deletions testsuite/tests/input/tex/__snapshots__/Base.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3495,8 +3495,8 @@ exports[`Environments math 1`] = `

exports[`Error merror node 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="&amp;" display="block">
<merror data-mjx-error="Misplaced &amp;">
<mtext>Misplaced &amp;</mtext>
<merror data-mjx-error="Misplaced '&amp;'">
<mtext>Misplaced '&amp;'</mtext>
</merror>
</math>"
`;
Expand Down
6 changes: 3 additions & 3 deletions testsuite/tests/input/tex/__snapshots__/Noerrors.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`NoError Ampersand-error 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="&amp;" display="block">
<merror data-mjx-error="Misplaced &amp;" title="Misplaced &amp;">
<merror data-mjx-error="Misplaced '&amp;'" title="Misplaced '&amp;'">
<mtext>&amp;</mtext>
</merror>
</math>"
Expand Down Expand Up @@ -210,7 +210,7 @@ exports[`NoError Middle with Right 1`] = `

exports[`NoError Misplaced Cr 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="a\\cr b" display="block">
<merror data-mjx-error="Misplaced \\cr" title="Misplaced \\cr">
<merror data-mjx-error="Misplaced '\\cr'" title="Misplaced '\\cr'">
<mtext>a\\cr b</mtext>
</merror>
</math>"
Expand All @@ -226,7 +226,7 @@ exports[`NoError Misplaced Move Root 1`] = `

exports[`NoError Misplaced hline 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="\\hline" display="block">
<merror data-mjx-error="Misplaced \\hline" title="Misplaced \\hline">
<merror data-mjx-error="Misplaced '\\hline'" title="Misplaced '\\hline'">
<mtext>\\hline</mtext>
</merror>
</math>"
Expand Down
16 changes: 16 additions & 0 deletions testsuite/tests/input/tex/__snapshots__/Physics.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,22 @@ exports[`Options Italicdif true 1`] = `
</math>"
`;

exports[`Physics Errors Extra Open Delimiter 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="\\sin((1\\over2)" display="block">
<merror data-mjx-error="Extra open or missing close delimiter">
<mtext>Extra open or missing close delimiter</mtext>
</merror>
</math>"
`;

exports[`Physics Errors Missing Closing Delimiter 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="\\sin(1\\over2" display="block">
<merror data-mjx-error="Extra open or missing close delimiter">
<mtext>Extra open or missing close delimiter</mtext>
</merror>
</math>"
`;

exports[`Physics1_0 Quantities_Quantities_0 1`] = `
"<math xmlns="http://www.w3.org/1998/Math/MathML" data-latex="\\quantity" display="block">
<mrow data-mjx-texclass="INNER" data-latex="\\quantity">
Expand Down
14 changes: 7 additions & 7 deletions ts/input/tex/ColumnParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import { ArrayItem } from './base/BaseItems.js';
import TexParser from './TexParser.js';
import TexError from './TexError.js';
import { texError } from './TexError.js';
import { lookup } from '../../util/Options.js';
import { ParseUtil } from './ParseUtil.js';
import { UnitUtil } from './UnitUtil.js';
Expand Down Expand Up @@ -135,13 +135,13 @@ export class ColumnParser {
let n = 0;
while (state.i < state.template.length) {
if (n++ > this.MAXCOLUMNS) {
throw new TexError(COMPONENT, 'MaxColumns');
texError(COMPONENT, 'MaxColumns');
}
const code = state.template.codePointAt(state.i);
const c = (state.c = String.fromCodePoint(code));
state.i += c.length;
if (!Object.hasOwn(this.columnHandler, c)) {
throw new TexError(COMPONENT, 'BadPreamToken', c);
texError(COMPONENT, 'BadPreamToken', c);
}
this.columnHandler[c](state);
}
Expand Down Expand Up @@ -263,7 +263,7 @@ export class ColumnParser {
public getDimen(state: ColumnState): string {
const dim = this.getBraces(state);
if (!UnitUtil.matchDimen(dim)[0]) {
throw new TexError(COMPONENT, 'MissingColumnDimOrUnits', state.c);
texError(COMPONENT, 'MissingColumnDimOrUnits', state.c);
}
return dim;
}
Expand Down Expand Up @@ -294,7 +294,7 @@ export class ColumnParser {
public getBraces(state: ColumnState): string {
while (state.template[state.i] === ' ') state.i++;
if (state.i >= state.template.length) {
throw new TexError(COMPONENT, 'MissingArgForColumn', state.c);
texError(COMPONENT, 'MissingArgForColumn', state.c);
}
if (state.template[state.i] !== '{') {
return state.template[state.i++];
Expand All @@ -316,7 +316,7 @@ export class ColumnParser {
break;
}
}
throw new TexError(COMPONENT, 'MissingCloseBrace');
texError(COMPONENT, 'MissingCloseBrace');
}

/**
Expand Down Expand Up @@ -401,7 +401,7 @@ export class ColumnParser {
const cols = this.getBraces(state);
const n = parseInt(num);
if (String(n) !== num) {
throw new TexError(COMPONENT, 'ColArgNotNum', '*');
texError(COMPONENT, 'ColArgNotNum', '*');
}
state.template =
new Array(n).fill(cols).join('') + state.template.substring(state.i);
Expand Down
24 changes: 12 additions & 12 deletions ts/input/tex/ParseUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { ArrayItem } from './base/BaseItems.js';
import ParseOptions from './ParseOptions.js';
import NodeUtil from './NodeUtil.js';
import TexParser from './TexParser.js';
import TexError from './TexError.js';
import { texError } from './TexError.js';
import { entities } from '../../util/Entities.js';
import { MmlMunderover } from '../../core/MmlTree/MmlNodes/munderover.js';
import { UnitUtil } from './UnitUtil.js';
Expand Down Expand Up @@ -188,7 +188,7 @@ function readValue(
case '}':
if (!braces) {
// Closing braces.
throw new TexError(COMPONENT, 'ExtraCloseMissingOpen');
texError(COMPONENT, 'ExtraCloseMissingOpen');
}
braces--;
countBraces = false; // Stop counting start left braces.
Expand All @@ -211,7 +211,7 @@ function readValue(
value += c;
}
if (braces) {
throw new TexError(COMPONENT, 'ExtraOpenMissingClose');
texError(COMPONENT, 'ExtraOpenMissingClose');
}
return dropBrace && start
? ['', '', removeBraces(value, 1)]
Expand Down Expand Up @@ -543,7 +543,7 @@ export const ParseUtil = {
.substring(i)
.match(/^\s*(?:([0-9A-F])|\{\s*([0-9A-F]+)\s*\})/);
if (!arg) {
throw new TexError(COMPONENT, 'BadRawUnicode', '\\U');
texError(COMPONENT, 'BadRawUnicode', '\\U');
}
// Replace \U{...} with specified character
const c = String.fromCodePoint(parseInt(arg[1] || arg[2], 16));
Expand All @@ -558,7 +558,7 @@ export const ParseUtil = {
}
if (match !== '') {
// @test Internal Math Error
throw new TexError(COMPONENT, 'MathNotTerminated');
texError(COMPONENT, 'MathNotTerminated');
}
}
if (k < text.length) {
Expand Down Expand Up @@ -723,7 +723,7 @@ export const ParseUtil = {
text += c;
} else {
if (!c.match(/[1-9]/) || parseInt(c, 10) > args.length) {
throw new TexError(COMPONENT, 'IllegalMacroParam');
texError(COMPONENT, 'IllegalMacroParam');
}
newstring = ParseUtil.addArgs(
parser,
Expand Down Expand Up @@ -754,7 +754,7 @@ export const ParseUtil = {
s1 += ' ';
}
if (s1.length + s2.length > parser.configuration.options['maxBuffer']) {
throw new TexError(COMPONENT, 'MaxBufferSize');
texError(COMPONENT, 'MaxBufferSize');
}
return s1 + s2;
},
Expand All @@ -770,9 +770,9 @@ export const ParseUtil = {
return;
}
if (isMacro) {
throw new TexError(COMPONENT, 'MaxMacroSub1');
texError(COMPONENT, 'MaxMacroSub1');
} else {
throw new TexError(COMPONENT, 'MaxMacroSub2');
texError(COMPONENT, 'MaxMacroSub2');
}
},

Expand All @@ -795,7 +795,7 @@ export const ParseUtil = {
return;
}
if (!top.isKind('start') || first) {
throw new TexError(COMPONENT, 'ErroneousNestingEq');
texError(COMPONENT, 'ErroneousNestingEq');
}
},

Expand Down Expand Up @@ -874,13 +874,13 @@ export const ParseUtil = {
const type = allowed[key] as KeyValueDef<any>;
const value = String(def[key]);
if (!type.verify(value)) {
throw new TexError(COMPONENT, 'InvalidValue', key);
texError(COMPONENT, 'InvalidValue', key);
}
def[key] = type.convert(value);
}
} else {
if (error) {
throw new TexError(COMPONENT, 'InvalidOption', key);
texError(COMPONENT, 'InvalidOption', key);
}
delete def[key];
}
Expand Down
23 changes: 11 additions & 12 deletions ts/input/tex/StackItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@

import { MmlNode } from '../../core/MmlTree/MmlNode.js';
import { FactoryNodeClass } from '../../core/Tree/Factory.js';
import TexError from './TexError.js';
import { texError } from './TexError.js';
import StackItemFactory from './StackItemFactory.js';
import { TexConstant } from './TexConstants.js';

import { COMPONENT } from './__locales__/Component.js';

// Union types for abbreviation.
Expand Down Expand Up @@ -390,16 +389,16 @@ export abstract class BaseItem extends MmlStack implements StackItem {
/**
* A list of basic errors.
*
* @type {{[key: string]: string}}
* @type {{[key: string]: [string, string]}}
*/
protected static errors: { [key: string]: string } = {
protected static errors: { [key: string]: [string, string] } = {
// @test ExtraOpenMissingClose
end: 'MissingBeginExtraEnd',
end: [COMPONENT, 'MissingBeginExtraEnd'],
// @test ExtraCloseMissingOpen
close: 'ExtraCloseMissingOpen',
close: [COMPONENT, 'ExtraCloseMissingOpen'],
// @test MissingLeftExtraRight
right: 'MissingLeftExtraRight',
middle: 'ExtraMiddle',
right: [COMPONENT, 'MissingLeftExtraRight'],
middle: [COMPONENT, 'ExtraMiddle'],
};

/**
Expand Down Expand Up @@ -516,12 +515,12 @@ export abstract class BaseItem extends MmlStack implements StackItem {
return BaseItem.fail;
}
// @test Ampersand-error
throw new TexError(COMPONENT, 'Misplaced', item.getName());
texError(COMPONENT, 'Misplaced', item.getName());
}
if (item.isClose && this.getError(item.kind)) {
// @test ExtraOpenMissingClose, ExtraCloseMissingOpen,
// MissingLeftExtraRight, MissingBeginExtraEnd
throw new TexError(COMPONENT, this.getError(item.kind), item.getName());
texError(...this.getError(item.kind), item.getName());
}
if (!item.isFinal) {
return BaseItem.success;
Expand Down Expand Up @@ -567,9 +566,9 @@ export abstract class BaseItem extends MmlStack implements StackItem {
* subclasses.
*
* @param {string} kind The stack item type.
* @returns {string} The id of the error message.
* @returns {[string, string]} The component and id of the error message.
*/
public getError(kind: string): string {
public getError(kind: string): [string, string] {
const CLASS = this.constructor as typeof BaseItem;
return CLASS.errors?.[kind] ?? BaseItem.errors[kind];
}
Expand Down
Loading