mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-06 03:38:39 +00:00
Flatten a bunch of non-pervasive ParseNode types (part 2) (#1552)
* Flatten "operatorname" ParseNode. * Flatten "overline" ParseNode. * Flatten "raisebox" ParseNode. * Flatten "rule" ParseNode. * Flatten "sizing" ParseNode. * Flatten "smash" ParseNode. * Flatten "sqrt" ParseNode. * Flatten "underline" ParseNode. * Flatten "enclose" ParseNode. * Flatten "environment" ParseNode. * Flatten "genfrac" ParseNode. * Flatten "htmlmathml" ParseNode. * Flatten "infix" ParseNode. * Flatten "kern" ParseNode. * Flatten "lap" ParseNode. * Flatten "color" ParseNode.
This commit is contained in:
@@ -223,10 +223,10 @@ export default class Parser {
|
||||
if (overIndex !== -1) {
|
||||
throw new ParseError(
|
||||
"only one infix operator per group",
|
||||
node.value.token);
|
||||
node.token);
|
||||
}
|
||||
overIndex = i;
|
||||
funcName = node.value.replaceWith;
|
||||
funcName = node.replaceWith;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,12 +327,9 @@ export default class Parser {
|
||||
|
||||
const colorNode = {
|
||||
type: "color",
|
||||
value: {
|
||||
type: "color",
|
||||
color: this.settings.errorColor,
|
||||
value: [textNode],
|
||||
},
|
||||
mode: this.mode,
|
||||
color: this.settings.errorColor,
|
||||
body: [textNode],
|
||||
};
|
||||
|
||||
this.consume();
|
||||
@@ -460,10 +457,10 @@ export default class Parser {
|
||||
const begin =
|
||||
assertNodeType(this.parseGivenFunction(start), "environment");
|
||||
|
||||
const envName = begin.value.name;
|
||||
const envName = begin.name;
|
||||
if (!environments.hasOwnProperty(envName)) {
|
||||
throw new ParseError(
|
||||
"No such environment: " + envName, begin.value.nameGroup);
|
||||
"No such environment: " + envName, begin.nameGroup);
|
||||
}
|
||||
// Build the environment object. Arguments and other information will
|
||||
// be made available to the begin and end methods using properties.
|
||||
@@ -483,10 +480,9 @@ export default class Parser {
|
||||
throw new ParseError("failed to parse function after \\end");
|
||||
}
|
||||
end = assertNodeType(end, "environment");
|
||||
if (end.value.name !== envName) {
|
||||
if (end.name !== envName) {
|
||||
throw new ParseError(
|
||||
"Mismatch: \\begin{" + envName + "} matched " +
|
||||
"by \\end{" + end.value.name + "}",
|
||||
`Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`,
|
||||
endNameToken);
|
||||
}
|
||||
return result;
|
||||
|
@@ -169,7 +169,7 @@ export const buildExpression = function(
|
||||
if (!node) {
|
||||
// No match.
|
||||
} else if (node.type === "sizing") {
|
||||
glueOptions = options.havingSize(node.value.size);
|
||||
glueOptions = options.havingSize(node.size);
|
||||
} else if (node.type === "styling") {
|
||||
glueOptions = options.havingStyle(
|
||||
styleMap[node.value.style]);
|
||||
|
@@ -9,8 +9,8 @@ import * as mml from "../buildMathML";
|
||||
|
||||
const htmlBuilder = (group, options) => {
|
||||
const elements = html.buildExpression(
|
||||
group.value.value,
|
||||
options.withColor(group.value.color),
|
||||
group.body,
|
||||
options.withColor(group.color),
|
||||
false
|
||||
);
|
||||
|
||||
@@ -22,11 +22,11 @@ const htmlBuilder = (group, options) => {
|
||||
};
|
||||
|
||||
const mathmlBuilder = (group, options) => {
|
||||
const inner = mml.buildExpression(group.value.value, options);
|
||||
const inner = mml.buildExpression(group.body, options);
|
||||
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
node.setAttribute("mathcolor", group.value.color);
|
||||
node.setAttribute("mathcolor", group.color);
|
||||
|
||||
return node;
|
||||
};
|
||||
@@ -46,11 +46,8 @@ defineFunction({
|
||||
return {
|
||||
type: "color",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "color",
|
||||
color: color.value,
|
||||
value: ordargument(body),
|
||||
},
|
||||
color: color.value,
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -85,11 +82,8 @@ defineFunction({
|
||||
return {
|
||||
type: "color",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "color",
|
||||
color: "katex-" + funcName.slice(1),
|
||||
value: ordargument(body),
|
||||
},
|
||||
color: "katex-" + funcName.slice(1),
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -114,11 +108,8 @@ defineFunction({
|
||||
return {
|
||||
type: "color",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "color",
|
||||
color: color.value,
|
||||
value: body,
|
||||
},
|
||||
color: color.value,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
|
@@ -12,9 +12,9 @@ import * as mml from "../buildMathML";
|
||||
|
||||
const htmlBuilder = (group, options) => {
|
||||
// \cancel, \bcancel, \xcancel, \sout, \fbox, \colorbox, \fcolorbox
|
||||
const inner = html.buildGroup(group.value.body, options);
|
||||
const inner = html.buildGroup(group.body, options);
|
||||
|
||||
const label = group.value.label.substr(1);
|
||||
const label = group.label.substr(1);
|
||||
const scale = options.sizeMultiplier;
|
||||
let img;
|
||||
let imgShift = 0;
|
||||
@@ -24,7 +24,7 @@ const htmlBuilder = (group, options) => {
|
||||
// We don't know the width of a group, so as a proxy, we test if
|
||||
// the subject is a single character. This captures most of the
|
||||
// subjects that should get the "tall" treatment.
|
||||
const isSingleChar = utils.isCharacterBox(group.value.body);
|
||||
const isSingleChar = utils.isCharacterBox(group.body);
|
||||
|
||||
if (label === "sout") {
|
||||
img = buildCommon.makeSpan(["stretchy", "sout"]);
|
||||
@@ -54,16 +54,16 @@ const htmlBuilder = (group, options) => {
|
||||
img = stretchy.encloseSpan(inner, label, vertPad, options);
|
||||
imgShift = inner.depth + vertPad;
|
||||
|
||||
if (group.value.backgroundColor) {
|
||||
img.style.backgroundColor = group.value.backgroundColor.value;
|
||||
if (group.value.borderColor) {
|
||||
img.style.borderColor = group.value.borderColor.value;
|
||||
if (group.backgroundColor) {
|
||||
img.style.backgroundColor = group.backgroundColor.value;
|
||||
if (group.borderColor) {
|
||||
img.style.borderColor = group.borderColor.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vlist;
|
||||
if (group.value.backgroundColor) {
|
||||
if (group.backgroundColor) {
|
||||
vlist = buildCommon.makeVList({
|
||||
positionType: "individualShift",
|
||||
children: [
|
||||
@@ -109,8 +109,8 @@ const htmlBuilder = (group, options) => {
|
||||
|
||||
const mathmlBuilder = (group, options) => {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"menclose", [mml.buildGroup(group.value.body, options)]);
|
||||
switch (group.value.label) {
|
||||
"menclose", [mml.buildGroup(group.body, options)]);
|
||||
switch (group.label) {
|
||||
case "\\cancel":
|
||||
node.setAttribute("notation", "updiagonalstrike");
|
||||
break;
|
||||
@@ -131,8 +131,8 @@ const mathmlBuilder = (group, options) => {
|
||||
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
||||
break;
|
||||
}
|
||||
if (group.value.backgroundColor) {
|
||||
node.setAttribute("mathbackground", group.value.backgroundColor.value);
|
||||
if (group.backgroundColor) {
|
||||
node.setAttribute("mathbackground", group.backgroundColor.value);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
@@ -152,12 +152,9 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: funcName,
|
||||
backgroundColor: color,
|
||||
body: body,
|
||||
},
|
||||
label: funcName,
|
||||
backgroundColor: color,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -180,13 +177,10 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: funcName,
|
||||
backgroundColor: backgroundColor,
|
||||
borderColor: borderColor,
|
||||
body: body,
|
||||
},
|
||||
label: funcName,
|
||||
backgroundColor: backgroundColor,
|
||||
borderColor: borderColor,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -205,11 +199,8 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: "\\fbox",
|
||||
body: args[0],
|
||||
},
|
||||
label: "\\fbox",
|
||||
body: args[0],
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -225,11 +216,8 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: funcName,
|
||||
body: body,
|
||||
},
|
||||
label: funcName,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
|
@@ -24,11 +24,8 @@ defineFunction({
|
||||
return {
|
||||
type: "environment",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "environment",
|
||||
name: name,
|
||||
nameGroup: nameGroup,
|
||||
},
|
||||
name,
|
||||
nameGroup,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@@ -15,15 +15,15 @@ const htmlBuilder = (group, options) => {
|
||||
// Figure out what style this fraction should be in based on the
|
||||
// function used
|
||||
let style = options.style;
|
||||
if (group.value.size === "display") {
|
||||
if (group.size === "display") {
|
||||
style = Style.DISPLAY;
|
||||
} else if (group.value.size === "text" &&
|
||||
} else if (group.size === "text" &&
|
||||
style.size === Style.DISPLAY.size) {
|
||||
// We're in a \tfrac but incoming style is displaystyle, so:
|
||||
style = Style.TEXT;
|
||||
} else if (group.value.size === "script") {
|
||||
} else if (group.size === "script") {
|
||||
style = Style.SCRIPT;
|
||||
} else if (group.value.size === "scriptscript") {
|
||||
} else if (group.size === "scriptscript") {
|
||||
style = Style.SCRIPTSCRIPT;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ const htmlBuilder = (group, options) => {
|
||||
let newOptions;
|
||||
|
||||
newOptions = options.havingStyle(nstyle);
|
||||
const numerm = html.buildGroup(group.value.numer, newOptions, options);
|
||||
const numerm = html.buildGroup(group.numer, newOptions, options);
|
||||
|
||||
if (group.value.continued) {
|
||||
if (group.continued) {
|
||||
// \cfrac inserts a \strut into the numerator.
|
||||
// Get \strut dimensions from TeXbook page 353.
|
||||
const hStrut = 8.5 / options.fontMetrics().ptPerEm;
|
||||
@@ -44,14 +44,14 @@ const htmlBuilder = (group, options) => {
|
||||
}
|
||||
|
||||
newOptions = options.havingStyle(dstyle);
|
||||
const denomm = html.buildGroup(group.value.denom, newOptions, options);
|
||||
const denomm = html.buildGroup(group.denom, newOptions, options);
|
||||
|
||||
let rule;
|
||||
let ruleWidth;
|
||||
let ruleSpacing;
|
||||
if (group.value.hasBarLine) {
|
||||
if (group.value.barSize) {
|
||||
ruleWidth = calculateSize(group.value.barSize, options);
|
||||
if (group.hasBarLine) {
|
||||
if (group.barSize) {
|
||||
ruleWidth = calculateSize(group.barSize, options);
|
||||
rule = buildCommon.makeLineSpan("frac-line", options, ruleWidth);
|
||||
} else {
|
||||
rule = buildCommon.makeLineSpan("frac-line", options);
|
||||
@@ -150,21 +150,21 @@ const htmlBuilder = (group, options) => {
|
||||
|
||||
let leftDelim;
|
||||
let rightDelim;
|
||||
if (group.value.leftDelim == null) {
|
||||
if (group.leftDelim == null) {
|
||||
leftDelim = html.makeNullDelimiter(options, ["mopen"]);
|
||||
} else {
|
||||
leftDelim = delimiter.customSizedDelim(
|
||||
group.value.leftDelim, delimSize, true,
|
||||
group.leftDelim, delimSize, true,
|
||||
options.havingStyle(style), group.mode, ["mopen"]);
|
||||
}
|
||||
|
||||
if (group.value.continued) {
|
||||
if (group.continued) {
|
||||
rightDelim = buildCommon.makeSpan([]); // zero width for \cfrac
|
||||
} else if (group.value.rightDelim == null) {
|
||||
} else if (group.rightDelim == null) {
|
||||
rightDelim = html.makeNullDelimiter(options, ["mclose"]);
|
||||
} else {
|
||||
rightDelim = delimiter.customSizedDelim(
|
||||
group.value.rightDelim, delimSize, true,
|
||||
group.rightDelim, delimSize, true,
|
||||
options.havingStyle(style), group.mode, ["mclose"]);
|
||||
}
|
||||
|
||||
@@ -178,23 +178,23 @@ const mathmlBuilder = (group, options) => {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mfrac",
|
||||
[
|
||||
mml.buildGroup(group.value.numer, options),
|
||||
mml.buildGroup(group.value.denom, options),
|
||||
mml.buildGroup(group.numer, options),
|
||||
mml.buildGroup(group.denom, options),
|
||||
]);
|
||||
|
||||
if (!group.value.hasBarLine) {
|
||||
if (!group.hasBarLine) {
|
||||
node.setAttribute("linethickness", "0px");
|
||||
} else if (group.value.barSize) {
|
||||
const ruleWidth = calculateSize(group.value.barSize, options);
|
||||
} else if (group.barSize) {
|
||||
const ruleWidth = calculateSize(group.barSize, options);
|
||||
node.setAttribute("linethickness", ruleWidth + "em");
|
||||
}
|
||||
|
||||
if (group.value.leftDelim != null || group.value.rightDelim != null) {
|
||||
if (group.leftDelim != null || group.rightDelim != null) {
|
||||
const withDelims = [];
|
||||
|
||||
if (group.value.leftDelim != null) {
|
||||
if (group.leftDelim != null) {
|
||||
const leftOp = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
|
||||
"mo", [new mathMLTree.TextNode(group.leftDelim)]);
|
||||
|
||||
leftOp.setAttribute("fence", "true");
|
||||
|
||||
@@ -203,9 +203,9 @@ const mathmlBuilder = (group, options) => {
|
||||
|
||||
withDelims.push(node);
|
||||
|
||||
if (group.value.rightDelim != null) {
|
||||
if (group.rightDelim != null) {
|
||||
const rightOp = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
|
||||
"mo", [new mathMLTree.TextNode(group.rightDelim)]);
|
||||
|
||||
rightOp.setAttribute("fence", "true");
|
||||
|
||||
@@ -284,17 +284,14 @@ defineFunction({
|
||||
return {
|
||||
type: "genfrac",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "genfrac",
|
||||
continued: funcName === "\\cfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
hasBarLine: hasBarLine,
|
||||
leftDelim: leftDelim,
|
||||
rightDelim: rightDelim,
|
||||
size: size,
|
||||
barSize: null,
|
||||
},
|
||||
continued: funcName === "\\cfrac",
|
||||
numer,
|
||||
denom,
|
||||
hasBarLine,
|
||||
leftDelim,
|
||||
rightDelim,
|
||||
size,
|
||||
barSize: null,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -335,11 +332,8 @@ defineFunction({
|
||||
return {
|
||||
type: "infix",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "infix",
|
||||
replaceWith: replaceWith,
|
||||
token: token,
|
||||
},
|
||||
replaceWith,
|
||||
token,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -413,17 +407,14 @@ defineFunction({
|
||||
return {
|
||||
type: "genfrac",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "genfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
continued: false,
|
||||
hasBarLine: hasBarLine,
|
||||
barSize: barSize,
|
||||
leftDelim: leftDelim,
|
||||
rightDelim: rightDelim,
|
||||
size: size,
|
||||
},
|
||||
numer,
|
||||
denom,
|
||||
continued: false,
|
||||
hasBarLine,
|
||||
barSize,
|
||||
leftDelim,
|
||||
rightDelim,
|
||||
size,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -445,12 +436,9 @@ defineFunction({
|
||||
return {
|
||||
type: "infix",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "infix",
|
||||
replaceWith: "\\\\abovefrac",
|
||||
sizeNode: sizeNode,
|
||||
token: token,
|
||||
},
|
||||
replaceWith: "\\\\abovefrac",
|
||||
sizeNode,
|
||||
token,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -465,7 +453,7 @@ defineFunction({
|
||||
handler: ({parser, funcName}, args) => {
|
||||
const numer = args[0];
|
||||
const infixNode = assertNodeType(args[1], "infix");
|
||||
const sizeNode = assertNodeType(infixNode.value.sizeNode, "size");
|
||||
const sizeNode = assertNodeType(infixNode.sizeNode, "size");
|
||||
const denom = args[2];
|
||||
|
||||
const barSize = sizeNode.value.value;
|
||||
@@ -473,17 +461,14 @@ defineFunction({
|
||||
return {
|
||||
type: "genfrac",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "genfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
continued: false,
|
||||
hasBarLine: hasBarLine,
|
||||
barSize: barSize,
|
||||
leftDelim: null,
|
||||
rightDelim: null,
|
||||
size: "auto",
|
||||
},
|
||||
numer,
|
||||
denom,
|
||||
continued: false,
|
||||
hasBarLine,
|
||||
barSize,
|
||||
leftDelim: null,
|
||||
rightDelim: null,
|
||||
size: "auto",
|
||||
};
|
||||
},
|
||||
|
||||
|
@@ -16,22 +16,19 @@ defineFunction({
|
||||
return {
|
||||
type: "htmlmathml",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "htmlmathml",
|
||||
html: ordargument(args[0]),
|
||||
mathml: ordargument(args[1]),
|
||||
},
|
||||
html: ordargument(args[0]),
|
||||
mathml: ordargument(args[1]),
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
const elements = html.buildExpression(
|
||||
group.value.html,
|
||||
group.html,
|
||||
options,
|
||||
false
|
||||
);
|
||||
return new buildCommon.makeFragment(elements);
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
return mml.buildExpressionRow(group.value.mathml, options);
|
||||
return mml.buildExpressionRow(group.mathml, options);
|
||||
},
|
||||
});
|
||||
|
@@ -42,17 +42,14 @@ defineFunction({
|
||||
return {
|
||||
type: "kern",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "kern",
|
||||
dimension: size.value.value,
|
||||
},
|
||||
dimension: size.value.value,
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
return buildCommon.makeGlue(group.value.dimension, options);
|
||||
return buildCommon.makeGlue(group.dimension, options);
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
const dimension = calculateSize(group.value.dimension, options);
|
||||
const dimension = calculateSize(group.dimension, options);
|
||||
return new mathMLTree.SpaceNode(dimension);
|
||||
},
|
||||
});
|
||||
|
@@ -19,29 +19,26 @@ defineFunction({
|
||||
return {
|
||||
type: "lap",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "lap",
|
||||
alignment: funcName.slice(5),
|
||||
body: body,
|
||||
},
|
||||
alignment: funcName.slice(5),
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
// mathllap, mathrlap, mathclap
|
||||
let inner;
|
||||
if (group.value.alignment === "clap") {
|
||||
if (group.alignment === "clap") {
|
||||
// ref: https://www.math.lsu.edu/~aperlis/publications/mathclap/
|
||||
inner = buildCommon.makeSpan(
|
||||
[], [html.buildGroup(group.value.body, options)]);
|
||||
[], [html.buildGroup(group.body, options)]);
|
||||
// wrap, since CSS will center a .clap > .inner > span
|
||||
inner = buildCommon.makeSpan(["inner"], [inner], options);
|
||||
} else {
|
||||
inner = buildCommon.makeSpan(
|
||||
["inner"], [html.buildGroup(group.value.body, options)]);
|
||||
["inner"], [html.buildGroup(group.body, options)]);
|
||||
}
|
||||
const fix = buildCommon.makeSpan(["fix"], []);
|
||||
let node = buildCommon.makeSpan(
|
||||
[group.value.alignment], [inner, fix], options);
|
||||
[group.alignment], [inner, fix], options);
|
||||
|
||||
// At this point, we have correctly set horizontal alignment of the
|
||||
// two items involved in the lap.
|
||||
@@ -64,10 +61,10 @@ defineFunction({
|
||||
mathmlBuilder: (group, options) => {
|
||||
// mathllap, mathrlap, mathclap
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [mml.buildGroup(group.value.body, options)]);
|
||||
"mpadded", [mml.buildGroup(group.body, options)]);
|
||||
|
||||
if (group.value.alignment !== "rlap") {
|
||||
const offset = (group.value.alignment === "llap" ? "-1" : "-0.5");
|
||||
if (group.alignment !== "rlap") {
|
||||
const offset = (group.alignment === "llap" ? "-1" : "-0.5");
|
||||
node.setAttribute("lspace", offset + "width");
|
||||
}
|
||||
node.setAttribute("width", "0px");
|
||||
|
@@ -20,16 +20,13 @@ defineFunction({
|
||||
return {
|
||||
type: "operatorname",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "operatorname",
|
||||
value: ordargument(body),
|
||||
},
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
|
||||
htmlBuilder: (group, options) => {
|
||||
if (group.value.value.length > 0) {
|
||||
const groupValue = group.value.value.map(child => {
|
||||
if (group.body.length > 0) {
|
||||
const body = group.body.map(child => {
|
||||
// $FlowFixMe: Check if the node has a string `value` property.
|
||||
const childValue = child.value;
|
||||
if (typeof childValue === "string") {
|
||||
@@ -45,7 +42,7 @@ defineFunction({
|
||||
|
||||
// Consolidate function names into symbol characters.
|
||||
const expression = html.buildExpression(
|
||||
groupValue, options.withFont("mathrm"), true);
|
||||
body, options.withFont("mathrm"), true);
|
||||
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
const child = expression[i];
|
||||
@@ -65,7 +62,7 @@ defineFunction({
|
||||
mathmlBuilder: (group, options) => {
|
||||
// The steps taken here are similar to the html version.
|
||||
let expression = mml.buildExpression(
|
||||
group.value.value, options.withFont("mathrm"));
|
||||
group.body, options.withFont("mathrm"));
|
||||
|
||||
// Is expression a string or has it something like a fraction?
|
||||
let isAllString = true; // default
|
||||
|
@@ -17,17 +17,14 @@ defineFunction({
|
||||
return {
|
||||
type: "overline",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "overline",
|
||||
body: body,
|
||||
},
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
// Overlines are handled in the TeXbook pg 443, Rule 9.
|
||||
|
||||
// Build the inner group in the cramped style.
|
||||
const innerGroup = html.buildGroup(group.value.body,
|
||||
const innerGroup = html.buildGroup(group.body,
|
||||
options.havingCrampedStyle());
|
||||
|
||||
// Create the line above the body
|
||||
@@ -53,7 +50,7 @@ defineFunction({
|
||||
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mover",
|
||||
[mml.buildGroup(group.value.body, options), operator]);
|
||||
[mml.buildGroup(group.body, options), operator]);
|
||||
node.setAttribute("accent", "true");
|
||||
|
||||
return node;
|
||||
|
@@ -23,12 +23,8 @@ defineFunction({
|
||||
return {
|
||||
type: "raisebox",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "raisebox",
|
||||
dy: amount,
|
||||
body: body,
|
||||
value: ordargument(body),
|
||||
},
|
||||
dy: amount,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
@@ -37,21 +33,18 @@ defineFunction({
|
||||
mode: group.mode,
|
||||
value: {
|
||||
type: "text",
|
||||
body: group.value.value,
|
||||
body: ordargument(group.body),
|
||||
font: "mathrm", // simulate \textrm
|
||||
},
|
||||
};
|
||||
const sizedText = {
|
||||
type: "sizing",
|
||||
mode: group.mode,
|
||||
value: {
|
||||
type: "sizing",
|
||||
value: [text],
|
||||
size: 6, // simulate \normalsize
|
||||
},
|
||||
body: [text],
|
||||
size: 6, // simulate \normalsize
|
||||
};
|
||||
const body = sizing.htmlBuilder(sizedText, options);
|
||||
const dy = calculateSize(group.value.dy.value.value, options);
|
||||
const dy = calculateSize(group.dy.value.value, options);
|
||||
return buildCommon.makeVList({
|
||||
positionType: "shift",
|
||||
positionData: -dy,
|
||||
@@ -60,9 +53,8 @@ defineFunction({
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [mml.buildGroup(group.value.body, options)]);
|
||||
const dy =
|
||||
group.value.dy.value.value.number + group.value.dy.value.value.unit;
|
||||
"mpadded", [mml.buildGroup(group.body, options)]);
|
||||
const dy = group.dy.value.value.number + group.dy.value.value.unit;
|
||||
node.setAttribute("voffset", dy);
|
||||
return node;
|
||||
},
|
||||
|
@@ -20,12 +20,9 @@ defineFunction({
|
||||
return {
|
||||
type: "rule",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "rule",
|
||||
shift: shift && assertNodeType(shift, "size").value.value,
|
||||
width: width.value.value,
|
||||
height: height.value.value,
|
||||
},
|
||||
shift: shift && assertNodeType(shift, "size").value.value,
|
||||
width: width.value.value,
|
||||
height: height.value.value,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
@@ -34,12 +31,12 @@ defineFunction({
|
||||
|
||||
// Calculate the shift, width, and height of the rule, and account for units
|
||||
let shift = 0;
|
||||
if (group.value.shift) {
|
||||
shift = calculateSize(group.value.shift, options);
|
||||
if (group.shift) {
|
||||
shift = calculateSize(group.shift, options);
|
||||
}
|
||||
|
||||
const width = calculateSize(group.value.width, options);
|
||||
const height = calculateSize(group.value.height, options);
|
||||
const width = calculateSize(group.width, options);
|
||||
const height = calculateSize(group.height, options);
|
||||
|
||||
// Style the rule to the right size
|
||||
rule.style.borderRightWidth = width + "em";
|
||||
|
@@ -8,9 +8,15 @@ import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type Options from "../Options";
|
||||
import type {AnyParseNode} from "../parseNode";
|
||||
import type {HtmlBuilder} from "../defineFunction";
|
||||
import type {documentFragment as HtmlDocumentFragment} from "../domTree";
|
||||
|
||||
export function sizingGroup(value: *, options: Options, baseOptions: Options) {
|
||||
export function sizingGroup(
|
||||
value: AnyParseNode[],
|
||||
options: Options,
|
||||
baseOptions: Options,
|
||||
): HtmlDocumentFragment {
|
||||
const inner = html.buildExpression(value, options, false);
|
||||
const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier;
|
||||
|
||||
@@ -44,8 +50,8 @@ export const htmlBuilder: HtmlBuilder<"sizing"> = (group, options) => {
|
||||
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
|
||||
// these functions inside of math expressions, so we do some special
|
||||
// handling.
|
||||
const newOptions = options.havingSize(group.value.size);
|
||||
return sizingGroup(group.value.value, newOptions, options);
|
||||
const newOptions = options.havingSize(group.size);
|
||||
return sizingGroup(group.body, newOptions, options);
|
||||
};
|
||||
|
||||
defineFunction({
|
||||
@@ -62,18 +68,15 @@ defineFunction({
|
||||
return {
|
||||
type: "sizing",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "sizing",
|
||||
// Figure out what size to use based on the list of functions above
|
||||
size: utils.indexOf(sizeFuncs, funcName) + 1,
|
||||
value: body,
|
||||
},
|
||||
// Figure out what size to use based on the list of functions above
|
||||
size: utils.indexOf(sizeFuncs, funcName) + 1,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder: (group, options) => {
|
||||
const newOptions = options.havingSize(group.value.size);
|
||||
const inner = mml.buildExpression(group.value.value, newOptions);
|
||||
const newOptions = options.havingSize(group.size);
|
||||
const inner = mml.buildExpression(group.body, newOptions);
|
||||
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
|
@@ -48,23 +48,20 @@ defineFunction({
|
||||
return {
|
||||
type: "smash",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "smash",
|
||||
body: body,
|
||||
smashHeight: smashHeight,
|
||||
smashDepth: smashDepth,
|
||||
},
|
||||
body,
|
||||
smashHeight,
|
||||
smashDepth,
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
const node = buildCommon.makeSpan(
|
||||
["mord"], [html.buildGroup(group.value.body, options)]);
|
||||
["mord"], [html.buildGroup(group.body, options)]);
|
||||
|
||||
if (!group.value.smashHeight && !group.value.smashDepth) {
|
||||
if (!group.smashHeight && !group.smashDepth) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (group.value.smashHeight) {
|
||||
if (group.smashHeight) {
|
||||
node.height = 0;
|
||||
// In order to influence makeVList, we have to reset the children.
|
||||
if (node.children) {
|
||||
@@ -74,7 +71,7 @@ defineFunction({
|
||||
}
|
||||
}
|
||||
|
||||
if (group.value.smashDepth) {
|
||||
if (group.smashDepth) {
|
||||
node.depth = 0;
|
||||
if (node.children) {
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
@@ -95,13 +92,13 @@ defineFunction({
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [mml.buildGroup(group.value.body, options)]);
|
||||
"mpadded", [mml.buildGroup(group.body, options)]);
|
||||
|
||||
if (group.value.smashHeight) {
|
||||
if (group.smashHeight) {
|
||||
node.setAttribute("height", "0px");
|
||||
}
|
||||
|
||||
if (group.value.smashDepth) {
|
||||
if (group.smashDepth) {
|
||||
node.setAttribute("depth", "0px");
|
||||
}
|
||||
|
||||
|
@@ -22,11 +22,8 @@ defineFunction({
|
||||
return {
|
||||
type: "sqrt",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "sqrt",
|
||||
body: body,
|
||||
index: index,
|
||||
},
|
||||
body,
|
||||
index,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
@@ -34,7 +31,7 @@ defineFunction({
|
||||
|
||||
// First, we do the same steps as in overline to build the inner group
|
||||
// and line
|
||||
let inner = html.buildGroup(group.value.body, options.havingCrampedStyle());
|
||||
let inner = html.buildGroup(group.body, options.havingCrampedStyle());
|
||||
if (inner.height === 0) {
|
||||
// Render a small surd.
|
||||
inner.height = options.fontMetrics().xHeight;
|
||||
@@ -89,14 +86,14 @@ defineFunction({
|
||||
],
|
||||
}, options);
|
||||
|
||||
if (!group.value.index) {
|
||||
if (!group.index) {
|
||||
return buildCommon.makeSpan(["mord", "sqrt"], [body], options);
|
||||
} else {
|
||||
// Handle the optional root index
|
||||
|
||||
// The index is always in scriptscript style
|
||||
const newOptions = options.havingStyle(Style.SCRIPTSCRIPT);
|
||||
const rootm = html.buildGroup(group.value.index, newOptions, options);
|
||||
const rootm = html.buildGroup(group.index, newOptions, options);
|
||||
|
||||
// The amount the index is shifted by. This is taken from the TeX
|
||||
// source, in the definition of `\r@@t`.
|
||||
@@ -117,7 +114,7 @@ defineFunction({
|
||||
}
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const {body, index} = group.value;
|
||||
const {body, index} = group;
|
||||
return index ?
|
||||
new mathMLTree.MathNode(
|
||||
"mroot", [
|
||||
|
@@ -14,20 +14,16 @@ defineFunction({
|
||||
allowedInText: true,
|
||||
},
|
||||
handler({parser}, args) {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "underline",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "underline",
|
||||
body: body,
|
||||
},
|
||||
body: args[0],
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
// Underlines are handled in the TeXbook pg 443, Rule 10.
|
||||
// Build the inner group.
|
||||
const innerGroup = html.buildGroup(group.value.body, options);
|
||||
const innerGroup = html.buildGroup(group.body, options);
|
||||
|
||||
// Create the line to go below the body
|
||||
const line = buildCommon.makeLineSpan("underline-line", options);
|
||||
@@ -53,7 +49,7 @@ defineFunction({
|
||||
|
||||
const node = new mathMLTree.MathNode(
|
||||
"munder",
|
||||
[mml.buildGroup(group.value.body, options), operator]);
|
||||
[mml.buildGroup(group.body, options), operator]);
|
||||
node.setAttribute("accentunder", "true");
|
||||
|
||||
return node;
|
||||
|
127
src/parseNode.js
127
src/parseNode.js
@@ -34,11 +34,8 @@ type ParseNodeTypes = {
|
||||
type: "color",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "color",
|
||||
color: string,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
color: string,
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"color-token": {|
|
||||
type: "color-token",
|
||||
@@ -216,23 +213,17 @@ type ParseNodeTypes = {
|
||||
type: "enclose",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "enclose",
|
||||
label: string,
|
||||
backgroundColor?: ParseNode<"color-token">,
|
||||
borderColor?: ParseNode<"color-token">,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
label: string,
|
||||
backgroundColor?: ParseNode<"color-token">,
|
||||
borderColor?: ParseNode<"color-token">,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"environment": {|
|
||||
type: "environment",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "environment",
|
||||
name: string,
|
||||
nameGroup: AnyParseNode,
|
||||
|},
|
||||
name: string,
|
||||
nameGroup: AnyParseNode,
|
||||
|},
|
||||
"font": {|
|
||||
type: "font",
|
||||
@@ -245,17 +236,14 @@ type ParseNodeTypes = {
|
||||
type: "genfrac",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "genfrac",
|
||||
continued: boolean,
|
||||
numer: AnyParseNode,
|
||||
denom: AnyParseNode,
|
||||
hasBarLine: boolean,
|
||||
leftDelim: ?string,
|
||||
rightDelim: ?string,
|
||||
size: StyleStr | "auto",
|
||||
barSize: Measurement | null,
|
||||
|},
|
||||
continued: boolean,
|
||||
numer: AnyParseNode,
|
||||
denom: AnyParseNode,
|
||||
hasBarLine: boolean,
|
||||
leftDelim: ?string,
|
||||
rightDelim: ?string,
|
||||
size: StyleStr | "auto",
|
||||
barSize: Measurement | null,
|
||||
|},
|
||||
"horizBrace": {|
|
||||
type: "horizBrace",
|
||||
@@ -276,41 +264,29 @@ type ParseNodeTypes = {
|
||||
type: "htmlmathml",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "htmlmathml",
|
||||
html: AnyParseNode[],
|
||||
mathml: AnyParseNode[],
|
||||
|},
|
||||
html: AnyParseNode[],
|
||||
mathml: AnyParseNode[],
|
||||
|},
|
||||
"infix": {|
|
||||
type: "infix",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "infix",
|
||||
replaceWith: string,
|
||||
sizeNode?: ParseNode<"size">,
|
||||
token: ?Token,
|
||||
|},
|
||||
replaceWith: string,
|
||||
sizeNode?: ParseNode<"size">,
|
||||
token: ?Token,
|
||||
|},
|
||||
"kern": {|
|
||||
type: "kern",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "kern",
|
||||
dimension: Measurement,
|
||||
|},
|
||||
dimension: Measurement,
|
||||
|},
|
||||
"lap": {|
|
||||
type: "lap",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "lap",
|
||||
alignment: string,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
alignment: string,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"leftright": {|
|
||||
type: "leftright",
|
||||
@@ -352,19 +328,13 @@ type ParseNodeTypes = {
|
||||
type: "operatorname",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "operatorname",
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"overline": {|
|
||||
type: "overline",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "overline",
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"phantom": {|
|
||||
type: "phantom",
|
||||
@@ -388,63 +358,44 @@ type ParseNodeTypes = {
|
||||
type: "raisebox",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "raisebox",
|
||||
dy: ParseNode<"size">,
|
||||
body: AnyParseNode,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
dy: ParseNode<"size">,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"rule": {|
|
||||
type: "rule",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "rule",
|
||||
shift: ?Measurement,
|
||||
width: Measurement,
|
||||
height: Measurement,
|
||||
|},
|
||||
shift: ?Measurement,
|
||||
width: Measurement,
|
||||
height: Measurement,
|
||||
|},
|
||||
"sizing": {|
|
||||
type: "sizing",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "sizing",
|
||||
size: number,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
size: number,
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"smash": {|
|
||||
type: "smash",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "smash",
|
||||
body: AnyParseNode,
|
||||
smashHeight: boolean,
|
||||
smashDepth: boolean,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
smashHeight: boolean,
|
||||
smashDepth: boolean,
|
||||
|},
|
||||
"sqrt": {|
|
||||
type: "sqrt",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "sqrt",
|
||||
body: AnyParseNode,
|
||||
index: ?AnyParseNode,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
index: ?AnyParseNode,
|
||||
|},
|
||||
"underline": {|
|
||||
type: "underline",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "underline",
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"xArrow": {|
|
||||
type: "xArrow",
|
||||
|
@@ -104,8 +104,8 @@ const getBaseElem = function(group: AnyParseNode): AnyParseNode {
|
||||
return group;
|
||||
}
|
||||
} else if (group.type === "color") {
|
||||
if (group.value.value.length === 1) {
|
||||
return getBaseElem(group.value.value[0]);
|
||||
if (group.body.length === 1) {
|
||||
return getBaseElem(group.body[0]);
|
||||
} else {
|
||||
return group;
|
||||
}
|
||||
|
@@ -643,42 +643,39 @@ exports[`An implicit group parser within optional groups should work style comma
|
||||
[
|
||||
{
|
||||
"type": "sqrt",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "sqrt",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "styling",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "styling",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "styling",
|
||||
"style": "text",
|
||||
"value": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
"style": "text",
|
||||
"value": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
`;
|
||||
@@ -687,42 +684,36 @@ exports[`An implicit group parser within optional groups should work with \\colo
|
||||
[
|
||||
{
|
||||
"type": "sqrt",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "sqrt",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "color",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "color",
|
||||
"color": "red",
|
||||
"value": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "color",
|
||||
"body": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"color": "red",
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
`;
|
||||
@@ -731,43 +722,40 @@ exports[`An implicit group parser within optional groups should work with old fo
|
||||
[
|
||||
{
|
||||
"type": "sqrt",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "sqrt",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "font",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "font",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"font": "mathtt",
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"value": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"font": "mathtt",
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
`;
|
||||
@@ -776,42 +764,36 @@ exports[`An implicit group parser within optional groups should work with sizing
|
||||
[
|
||||
{
|
||||
"type": "sqrt",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "sqrt",
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "sizing",
|
||||
"mode": "math",
|
||||
"value": {
|
||||
"type": "sizing",
|
||||
"size": 5,
|
||||
"value": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
"body": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "mathord",
|
||||
"mode": "math",
|
||||
"value": "x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"type": "ordgroup",
|
||||
"mode": "math",
|
||||
"value": [
|
||||
{
|
||||
"type": "sizing",
|
||||
"body": [
|
||||
{
|
||||
"type": "textord",
|
||||
"mode": "math",
|
||||
"value": "3"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"mode": "math",
|
||||
"size": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"mode": "math"
|
||||
}
|
||||
]
|
||||
`;
|
||||
|
@@ -92,7 +92,7 @@ describe("A rel parser", function() {
|
||||
for (let i = 0; i < parse.length; i++) {
|
||||
let group = parse[i];
|
||||
if (group.type === "htmlmathml") {
|
||||
group = group.value.html[0];
|
||||
group = group.html[0];
|
||||
}
|
||||
if (group.type === "mclass") {
|
||||
expect(group.mclass).toEqual("mrel");
|
||||
@@ -342,7 +342,8 @@ describe("An implicit group parser", function() {
|
||||
const sizing = parse[0];
|
||||
|
||||
expect(sizing.type).toEqual("sizing");
|
||||
expect(sizing.value).toBeTruthy();
|
||||
expect(sizing.body).toBeTruthy();
|
||||
expect(sizing.size).toBeDefined();
|
||||
});
|
||||
|
||||
it("should apply only after the function", function() {
|
||||
@@ -353,7 +354,7 @@ describe("An implicit group parser", function() {
|
||||
const sizing = parse[1];
|
||||
|
||||
expect(sizing.type).toEqual("sizing");
|
||||
expect(sizing.value.value).toHaveLength(3);
|
||||
expect(sizing.body).toHaveLength(3);
|
||||
});
|
||||
|
||||
it("should stop at the ends of groups", function() {
|
||||
@@ -363,7 +364,7 @@ describe("An implicit group parser", function() {
|
||||
const sizing = group.value[1];
|
||||
|
||||
expect(sizing.type).toEqual("sizing");
|
||||
expect(sizing.value.value).toHaveLength(1);
|
||||
expect(sizing.body).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe("within optional groups", () => {
|
||||
@@ -441,8 +442,8 @@ describe("A frac parser", function() {
|
||||
const parse = getParsed(expression)[0];
|
||||
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.numer).toBeDefined();
|
||||
expect(parse.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should also parse cfrac, dfrac, tfrac, and genfrac", function() {
|
||||
@@ -457,28 +458,28 @@ describe("A frac parser", function() {
|
||||
const dfracParse = getParsed(dfracExpression)[0];
|
||||
|
||||
expect(dfracParse.type).toEqual("genfrac");
|
||||
expect(dfracParse.value.numer).toBeDefined();
|
||||
expect(dfracParse.value.denom).toBeDefined();
|
||||
expect(dfracParse.numer).toBeDefined();
|
||||
expect(dfracParse.denom).toBeDefined();
|
||||
|
||||
const tfracParse = getParsed(tfracExpression)[0];
|
||||
|
||||
expect(tfracParse.type).toEqual("genfrac");
|
||||
expect(tfracParse.value.numer).toBeDefined();
|
||||
expect(tfracParse.value.denom).toBeDefined();
|
||||
expect(tfracParse.numer).toBeDefined();
|
||||
expect(tfracParse.denom).toBeDefined();
|
||||
|
||||
const cfracParse = getParsed(cfracExpression)[0];
|
||||
|
||||
expect(cfracParse.type).toEqual("genfrac");
|
||||
expect(cfracParse.value.numer).toBeDefined();
|
||||
expect(cfracParse.value.denom).toBeDefined();
|
||||
expect(cfracParse.numer).toBeDefined();
|
||||
expect(cfracParse.denom).toBeDefined();
|
||||
|
||||
const genfracParse = getParsed(genfrac1)[0];
|
||||
|
||||
expect(genfracParse.type).toEqual("genfrac");
|
||||
expect(genfracParse.value.numer).toBeDefined();
|
||||
expect(genfracParse.value.denom).toBeDefined();
|
||||
expect(genfracParse.value.leftDelim).toBeDefined();
|
||||
expect(genfracParse.value.rightDelim).toBeDefined();
|
||||
expect(genfracParse.numer).toBeDefined();
|
||||
expect(genfracParse.denom).toBeDefined();
|
||||
expect(genfracParse.leftDelim).toBeDefined();
|
||||
expect(genfracParse.rightDelim).toBeDefined();
|
||||
});
|
||||
|
||||
it("should fail, given math as a line thickness to genfrac", function() {
|
||||
@@ -495,9 +496,9 @@ describe("A frac parser", function() {
|
||||
const parse = getParsed`x \atop y`[0];
|
||||
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.value.hasBarLine).toEqual(false);
|
||||
expect(parse.numer).toBeDefined();
|
||||
expect(parse.denom).toBeDefined();
|
||||
expect(parse.hasBarLine).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -520,43 +521,43 @@ describe("An over/brace/brack parser", function() {
|
||||
parse = getParsed(simpleOver)[0];
|
||||
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.numer).toBeDefined();
|
||||
expect(parse.denom).toBeDefined();
|
||||
|
||||
parse = getParsed(complexOver)[0];
|
||||
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.numer).toBeDefined();
|
||||
expect(parse.denom).toBeDefined();
|
||||
|
||||
const parseBraceFrac = getParsed(braceFrac)[0];
|
||||
|
||||
expect(parseBraceFrac.type).toEqual("genfrac");
|
||||
expect(parseBraceFrac.value.numer).toBeDefined();
|
||||
expect(parseBraceFrac.value.denom).toBeDefined();
|
||||
expect(parseBraceFrac.value.leftDelim).toBeDefined();
|
||||
expect(parseBraceFrac.value.rightDelim).toBeDefined();
|
||||
expect(parseBraceFrac.numer).toBeDefined();
|
||||
expect(parseBraceFrac.denom).toBeDefined();
|
||||
expect(parseBraceFrac.leftDelim).toBeDefined();
|
||||
expect(parseBraceFrac.rightDelim).toBeDefined();
|
||||
|
||||
const parseBrackFrac = getParsed(brackFrac)[0];
|
||||
|
||||
expect(parseBrackFrac.type).toEqual("genfrac");
|
||||
expect(parseBrackFrac.value.numer).toBeDefined();
|
||||
expect(parseBrackFrac.value.denom).toBeDefined();
|
||||
expect(parseBrackFrac.value.leftDelim).toBeDefined();
|
||||
expect(parseBrackFrac.value.rightDelim).toBeDefined();
|
||||
expect(parseBrackFrac.numer).toBeDefined();
|
||||
expect(parseBrackFrac.denom).toBeDefined();
|
||||
expect(parseBrackFrac.leftDelim).toBeDefined();
|
||||
expect(parseBrackFrac.rightDelim).toBeDefined();
|
||||
});
|
||||
|
||||
it("should create a numerator from the atoms before \\over", function() {
|
||||
const parse = getParsed(complexOver)[0];
|
||||
|
||||
const numer = parse.value.numer;
|
||||
const numer = parse.numer;
|
||||
expect(numer.value).toHaveLength(4);
|
||||
});
|
||||
|
||||
it("should create a demonimator from the atoms after \\over", function() {
|
||||
const parse = getParsed(complexOver)[0];
|
||||
|
||||
const denom = parse.value.numer;
|
||||
const denom = parse.numer;
|
||||
expect(denom.value).toHaveLength(4);
|
||||
});
|
||||
|
||||
@@ -564,24 +565,24 @@ describe("An over/brace/brack parser", function() {
|
||||
const emptyNumerator = r`\over x`;
|
||||
const parse = getParsed(emptyNumerator)[0];
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.numer).toBeDefined();
|
||||
expect(parse.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle empty denominators", function() {
|
||||
const emptyDenominator = r`1 \over`;
|
||||
const parse = getParsed(emptyDenominator)[0];
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer).toBeDefined();
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.numer).toBeDefined();
|
||||
expect(parse.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle \\displaystyle correctly", function() {
|
||||
const displaystyleExpression = r`\displaystyle 1 \over 2`;
|
||||
const parse = getParsed(displaystyleExpression)[0];
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer.value[0].type).toEqual("styling");
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.numer.value[0].type).toEqual("styling");
|
||||
expect(parse.denom).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle \\textstyle correctly", function() {
|
||||
@@ -593,11 +594,11 @@ describe("An over/brace/brack parser", function() {
|
||||
const nestedOverExpression = r`{1 \over 2} \over 3`;
|
||||
const parse = getParsed(nestedOverExpression)[0];
|
||||
expect(parse.type).toEqual("genfrac");
|
||||
expect(parse.value.numer.value[0].type).toEqual("genfrac");
|
||||
expect(parse.value.numer.value[0].value.numer.value[0].value).toEqual("1");
|
||||
expect(parse.value.numer.value[0].value.denom.value[0].value).toEqual("2");
|
||||
expect(parse.value.denom).toBeDefined();
|
||||
expect(parse.value.denom.value[0].value).toEqual("3");
|
||||
expect(parse.numer.value[0].type).toEqual("genfrac");
|
||||
expect(parse.numer.value[0].numer.value[0].value).toEqual("1");
|
||||
expect(parse.numer.value[0].denom.value[0].value).toEqual("2");
|
||||
expect(parse.denom).toBeDefined();
|
||||
expect(parse.denom.value[0].value).toEqual("3");
|
||||
});
|
||||
|
||||
it("should fail with multiple overs in the same group", function() {
|
||||
@@ -641,7 +642,8 @@ describe("A sizing parser", function() {
|
||||
const parse = getParsed(sizeExpression)[0];
|
||||
|
||||
expect(parse.type).toEqual("sizing");
|
||||
expect(parse.value).toBeDefined();
|
||||
expect(parse.size).toBeDefined();
|
||||
expect(parse.body).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -778,8 +780,8 @@ describe("A color parser", function() {
|
||||
const parse = getParsed(colorExpression)[0];
|
||||
|
||||
expect(parse.type).toEqual("color");
|
||||
expect(parse.value.color).toBeDefined();
|
||||
expect(parse.value.value).toBeDefined();
|
||||
expect(parse.color).toBeDefined();
|
||||
expect(parse.body).toBeDefined();
|
||||
});
|
||||
|
||||
it("should parse a custom color", function() {
|
||||
@@ -791,8 +793,8 @@ describe("A color parser", function() {
|
||||
const parse1 = getParsed(customColorExpression1)[0];
|
||||
const parse2 = getParsed(customColorExpression2)[0];
|
||||
|
||||
expect(parse1.value.color).toEqual("#fA6");
|
||||
expect(parse2.value.color).toEqual("#fA6fA6");
|
||||
expect(parse1.color).toEqual("#fA6");
|
||||
expect(parse2.color).toEqual("#fA6fA6");
|
||||
});
|
||||
|
||||
it("should not parse a bad custom color", function() {
|
||||
@@ -984,25 +986,25 @@ describe("A rule parser", function() {
|
||||
const emParse = getParsed(emRule)[0];
|
||||
const exParse = getParsed(exRule)[0];
|
||||
|
||||
expect(emParse.value.width.unit).toEqual("em");
|
||||
expect(emParse.value.height.unit).toEqual("em");
|
||||
expect(emParse.width.unit).toEqual("em");
|
||||
expect(emParse.height.unit).toEqual("em");
|
||||
|
||||
expect(exParse.value.width.unit).toEqual("ex");
|
||||
expect(exParse.value.height.unit).toEqual("em");
|
||||
expect(exParse.width.unit).toEqual("ex");
|
||||
expect(exParse.height.unit).toEqual("em");
|
||||
});
|
||||
|
||||
it("should parse the number correctly", function() {
|
||||
const hardNumberParse = getParsed(hardNumberRule)[0];
|
||||
|
||||
expect(hardNumberParse.value.width.number).toBeCloseTo(1.24);
|
||||
expect(hardNumberParse.value.height.number).toBeCloseTo(2.45);
|
||||
expect(hardNumberParse.width.number).toBeCloseTo(1.24);
|
||||
expect(hardNumberParse.height.number).toBeCloseTo(2.45);
|
||||
});
|
||||
|
||||
it("should parse negative sizes", function() {
|
||||
const parse = getParsed`\rule{-1em}{- 0.2em}`[0];
|
||||
|
||||
expect(parse.value.width.number).toBeCloseTo(-1);
|
||||
expect(parse.value.height.number).toBeCloseTo(-0.2);
|
||||
expect(parse.width.number).toBeCloseTo(-1);
|
||||
expect(parse.height.number).toBeCloseTo(-0.2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1020,10 +1022,10 @@ describe("A kern parser", function() {
|
||||
const muParse = getParsed(muKern)[0];
|
||||
const abParse = getParsed(abKern)[1];
|
||||
|
||||
expect(emParse.value.dimension.unit).toEqual("em");
|
||||
expect(exParse.value.dimension.unit).toEqual("ex");
|
||||
expect(muParse.value.dimension.unit).toEqual("mu");
|
||||
expect(abParse.value.dimension.unit).toEqual("em");
|
||||
expect(emParse.dimension.unit).toEqual("em");
|
||||
expect(exParse.dimension.unit).toEqual("ex");
|
||||
expect(muParse.dimension.unit).toEqual("mu");
|
||||
expect(abParse.dimension.unit).toEqual("em");
|
||||
});
|
||||
|
||||
it("should not parse invalid units", function() {
|
||||
@@ -1033,12 +1035,12 @@ describe("A kern parser", function() {
|
||||
|
||||
it("should parse negative sizes", function() {
|
||||
const parse = getParsed`\kern{-1em}`[0];
|
||||
expect(parse.value.dimension.number).toBeCloseTo(-1);
|
||||
expect(parse.dimension.number).toBeCloseTo(-1);
|
||||
});
|
||||
|
||||
it("should parse positive sizes", function() {
|
||||
const parse = getParsed`\kern{+1em}`[0];
|
||||
expect(parse.value.dimension.number).toBeCloseTo(1);
|
||||
expect(parse.dimension.number).toBeCloseTo(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1060,12 +1062,12 @@ describe("A non-braced kern parser", function() {
|
||||
const abParse2 = getParsed(abKern2)[1];
|
||||
const abParse3 = getParsed(abKern3)[1];
|
||||
|
||||
expect(emParse.value.dimension.unit).toEqual("em");
|
||||
expect(exParse.value.dimension.unit).toEqual("ex");
|
||||
expect(muParse.value.dimension.unit).toEqual("mu");
|
||||
expect(abParse1.value.dimension.unit).toEqual("mu");
|
||||
expect(abParse2.value.dimension.unit).toEqual("mu");
|
||||
expect(abParse3.value.dimension.unit).toEqual("mu");
|
||||
expect(emParse.dimension.unit).toEqual("em");
|
||||
expect(exParse.dimension.unit).toEqual("ex");
|
||||
expect(muParse.dimension.unit).toEqual("mu");
|
||||
expect(abParse1.dimension.unit).toEqual("mu");
|
||||
expect(abParse2.dimension.unit).toEqual("mu");
|
||||
expect(abParse3.dimension.unit).toEqual("mu");
|
||||
});
|
||||
|
||||
it("should parse elements on either side of a kern", function() {
|
||||
@@ -1091,12 +1093,12 @@ describe("A non-braced kern parser", function() {
|
||||
|
||||
it("should parse negative sizes", function() {
|
||||
const parse = getParsed`\kern-1em`[0];
|
||||
expect(parse.value.dimension.number).toBeCloseTo(-1);
|
||||
expect(parse.dimension.number).toBeCloseTo(-1);
|
||||
});
|
||||
|
||||
it("should parse positive sizes", function() {
|
||||
const parse = getParsed`\kern+1em`[0];
|
||||
expect(parse.value.dimension.number).toBeCloseTo(1);
|
||||
expect(parse.dimension.number).toBeCloseTo(1);
|
||||
});
|
||||
|
||||
it("should handle whitespace", function() {
|
||||
@@ -1105,7 +1107,7 @@ describe("A non-braced kern parser", function() {
|
||||
|
||||
expect(abParse).toHaveLength(3);
|
||||
expect(abParse[0].value).toEqual("a");
|
||||
expect(abParse[1].value.dimension.unit).toEqual("mu");
|
||||
expect(abParse[1].dimension.unit).toEqual("mu");
|
||||
expect(abParse[2].value).toEqual("b");
|
||||
});
|
||||
});
|
||||
@@ -1511,9 +1513,9 @@ describe("A font parser", function() {
|
||||
|
||||
it("should work with \\textcolor", function() {
|
||||
const colorMathbbParse = getParsed`\textcolor{blue}{\mathbb R}`[0];
|
||||
expect(colorMathbbParse.value.type).toEqual("color");
|
||||
expect(colorMathbbParse.value.color).toEqual("blue");
|
||||
const body = colorMathbbParse.value.value;
|
||||
expect(colorMathbbParse.type).toEqual("color");
|
||||
expect(colorMathbbParse.color).toEqual("blue");
|
||||
const body = colorMathbbParse.body;
|
||||
expect(body).toHaveLength(1);
|
||||
expect(body[0].type).toEqual("font");
|
||||
expect(body[0].font).toEqual("mathbb");
|
||||
@@ -2589,7 +2591,7 @@ describe("A parser that does not throw on unsupported commands", function() {
|
||||
it("should produce color nodes with a color value given by errorColor", function() {
|
||||
const parsedInput = getParsed(r`\error`, noThrowSettings);
|
||||
expect(parsedInput[0].type).toBe("color");
|
||||
expect(parsedInput[0].value.color).toBe(errorColor);
|
||||
expect(parsedInput[0].color).toBe(errorColor);
|
||||
});
|
||||
|
||||
it("should build katex-error span for other type of KaTeX error", function() {
|
||||
|
Reference in New Issue
Block a user