mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-10 05:28:41 +00:00
Replace ParseNode<*> with a more accurate AnyParseNode and fix flow errors. (#1387)
* Replace ParseNode<*> with a more accurate AnyParseNode and fix flow errors. * Allow "array" environment type spec to use any all symbol type. Before this commit, it was constrained to use "mathord" and "textord", but a recent change in HEAD resulted in a "rel" node being used in the spec for, e.g. \begin{array}{|l||c:r::}\end{array} * Address reviewer comments: rename `lastRow` to `row` in array.js.
This commit is contained in:
committed by
Kevin Barabash
parent
4492eedb68
commit
19d2aa63c3
@@ -4,7 +4,8 @@ import defineEnvironment from "../defineEnvironment";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import ParseError from "../ParseError";
|
||||
import ParseNode from "../ParseNode";
|
||||
import {assertNodeType} from "../ParseNode";
|
||||
import {assertNodeType, assertSymbolNodeType} from "../ParseNode";
|
||||
import {checkNodeType, checkSymbolNodeType} from "../ParseNode";
|
||||
import {calculateSize} from "../units";
|
||||
import utils from "../utils";
|
||||
|
||||
@@ -12,7 +13,9 @@ import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type Parser from "../Parser";
|
||||
import type {AnyParseNode} from "../ParseNode";
|
||||
import type {StyleStr} from "../types";
|
||||
import type {HtmlBuilder, MathMLBuilder} from "../defineFunction";
|
||||
|
||||
// Data stored in the ParseNode associated with the environment.
|
||||
type AlignSpec = { type: "separator", separator: string } | {
|
||||
@@ -28,8 +31,8 @@ export type ArrayEnvNodeData = {|
|
||||
arraystretch: number,
|
||||
addJot?: boolean,
|
||||
cols?: AlignSpec[],
|
||||
body: ParseNode<*>[][], // List of rows in the (2D) array.
|
||||
rowGaps: (?ParseNode<*>)[],
|
||||
body: AnyParseNode[][], // List of rows in the (2D) array.
|
||||
rowGaps: (?ParseNode<"size">)[],
|
||||
numHLinesBeforeRow: number[],
|
||||
|};
|
||||
// Same as above but with some fields not yet filled.
|
||||
@@ -40,8 +43,8 @@ type ArrayEnvNodeDataIncomplete = {|
|
||||
addJot?: boolean,
|
||||
cols?: AlignSpec[],
|
||||
// Before these fields are filled.
|
||||
body?: ParseNode<*>[][],
|
||||
rowGaps?: (?ParseNode<*>)[],
|
||||
body?: AnyParseNode[][],
|
||||
rowGaps?: (?ParseNode<"size">)[],
|
||||
numHLinesBeforeRow?: number[],
|
||||
|};
|
||||
|
||||
@@ -110,10 +113,8 @@ function parseArray(
|
||||
} else if (next === "\\end") {
|
||||
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
||||
// the last line is empty.
|
||||
const lastRow = body[body.length - 1];
|
||||
if (body.length > 1
|
||||
&& lastRow.length === 1
|
||||
&& lastRow[0].value.value[0].value.length === 0) {
|
||||
// NOTE: Currently, `cell` is the last item added into `row`.
|
||||
if (row.length === 1 && cell.value.value[0].value.length === 0) {
|
||||
body.pop();
|
||||
}
|
||||
break;
|
||||
@@ -161,8 +162,7 @@ type Outrow = {
|
||||
pos: number,
|
||||
};
|
||||
|
||||
const htmlBuilder = function(group, options) {
|
||||
const groupValue = assertNodeType(group, "array").value;
|
||||
const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
||||
let r;
|
||||
let c;
|
||||
const nr = group.value.body.length;
|
||||
@@ -180,7 +180,7 @@ const htmlBuilder = function(group, options) {
|
||||
// Default \jot from ltmath.dtx
|
||||
// TODO(edemaine): allow overriding \jot via \setlength (#687)
|
||||
const jot = 3 * pt;
|
||||
const arrayskip = groupValue.arraystretch * baselineskip;
|
||||
const arrayskip = group.value.arraystretch * baselineskip;
|
||||
const arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
|
||||
const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
|
||||
|
||||
@@ -194,8 +194,8 @@ const htmlBuilder = function(group, options) {
|
||||
hlinePos.push(totalHeight);
|
||||
}
|
||||
|
||||
for (r = 0; r < groupValue.body.length; ++r) {
|
||||
const inrow = groupValue.body[r];
|
||||
for (r = 0; r < group.value.body.length; ++r) {
|
||||
const inrow = group.value.body[r];
|
||||
let height = arstrutHeight; // \@array adds an \@arstrut
|
||||
let depth = arstrutDepth; // to each tow (via the template)
|
||||
|
||||
@@ -215,7 +215,7 @@ const htmlBuilder = function(group, options) {
|
||||
outrow[c] = elt;
|
||||
}
|
||||
|
||||
const rowGap = groupValue.rowGaps[r];
|
||||
const rowGap = group.value.rowGaps[r];
|
||||
let gap = 0;
|
||||
if (rowGap) {
|
||||
gap = calculateSize(rowGap.value.value, options);
|
||||
@@ -230,7 +230,7 @@ const htmlBuilder = function(group, options) {
|
||||
// In AMS multiline environments such as aligned and gathered, rows
|
||||
// correspond to lines that have additional \jot added to the
|
||||
// \baselineskip via \openup.
|
||||
if (groupValue.addJot) {
|
||||
if (group.value.addJot) {
|
||||
depth += jot;
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ const htmlBuilder = function(group, options) {
|
||||
}
|
||||
|
||||
const offset = totalHeight / 2 + options.fontMetrics().axisHeight;
|
||||
const colDescriptions = groupValue.cols || [];
|
||||
const colDescriptions = group.value.cols || [];
|
||||
const cols = [];
|
||||
let colSep;
|
||||
let colDescrNum;
|
||||
@@ -307,7 +307,7 @@ const htmlBuilder = function(group, options) {
|
||||
}
|
||||
|
||||
let sepwidth;
|
||||
if (c > 0 || groupValue.hskipBeforeAndAfter) {
|
||||
if (c > 0 || group.value.hskipBeforeAndAfter) {
|
||||
sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
|
||||
if (sepwidth !== 0) {
|
||||
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
||||
@@ -338,7 +338,7 @@ const htmlBuilder = function(group, options) {
|
||||
[col]);
|
||||
cols.push(col);
|
||||
|
||||
if (c < nc - 1 || groupValue.hskipBeforeAndAfter) {
|
||||
if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
|
||||
sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
|
||||
if (sepwidth !== 0) {
|
||||
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
||||
@@ -366,10 +366,9 @@ const htmlBuilder = function(group, options) {
|
||||
return buildCommon.makeSpan(["mord"], [body], options);
|
||||
};
|
||||
|
||||
const mathmlBuilder = function(group, options) {
|
||||
const groupValue = assertNodeType(group, "array").value;
|
||||
const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
||||
return new mathMLTree.MathNode(
|
||||
"mtable", groupValue.body.map(function(row) {
|
||||
"mtable", group.value.body.map(function(row) {
|
||||
return new mathMLTree.MathNode(
|
||||
"mtr", row.map(function(cell) {
|
||||
return new mathMLTree.MathNode(
|
||||
@@ -400,10 +399,12 @@ const alignedHandler = function(context, args) {
|
||||
let numMaths;
|
||||
let numCols = 0;
|
||||
const emptyGroup = new ParseNode("ordgroup", [], context.mode);
|
||||
if (args[0] && args[0].value) {
|
||||
const ordgroup = checkNodeType(args[0], "ordgroup");
|
||||
if (ordgroup) {
|
||||
let arg0 = "";
|
||||
for (let i = 0; i < args[0].value.length; i++) {
|
||||
arg0 += args[0].value[i].value;
|
||||
for (let i = 0; i < ordgroup.value.length; i++) {
|
||||
const textord = assertNodeType(ordgroup.value[i], "textord");
|
||||
arg0 += textord.value;
|
||||
}
|
||||
numMaths = Number(arg0);
|
||||
numCols = numMaths * 2;
|
||||
@@ -412,7 +413,8 @@ const alignedHandler = function(context, args) {
|
||||
res.value.body.forEach(function(row) {
|
||||
for (let i = 1; i < row.length; i += 2) {
|
||||
// Modify ordgroup node within styling node
|
||||
const ordgroup = row[i].value.value[0];
|
||||
const styling = assertNodeType(row[i], "styling");
|
||||
const ordgroup = assertNodeType(styling.value.value[0], "ordgroup");
|
||||
ordgroup.value.unshift(emptyGroup);
|
||||
}
|
||||
if (!isAligned) { // Case 1
|
||||
@@ -459,10 +461,16 @@ defineEnvironment({
|
||||
props: {
|
||||
numArgs: 1,
|
||||
},
|
||||
handler: function(context, args) {
|
||||
let colalign = args[0];
|
||||
colalign = colalign.value.map ? colalign.value : [colalign];
|
||||
const cols = colalign.map(function(node) {
|
||||
handler(context, args) {
|
||||
// Since no types are specified above, the two possibilities are
|
||||
// - The argument is wrapped in {} or [], in which case Parser's
|
||||
// parseGroup() returns an "ordgroup" wrapping some symbol node.
|
||||
// - The argument is a bare symbol node.
|
||||
const symNode = checkSymbolNodeType(args[0]);
|
||||
const colalign: AnyParseNode[] =
|
||||
symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").value;
|
||||
const cols = colalign.map(function(nde) {
|
||||
const node = assertSymbolNodeType(nde);
|
||||
const ca = node.value;
|
||||
if ("lcr".indexOf(ca) !== -1) {
|
||||
return {
|
||||
@@ -480,9 +488,7 @@ defineEnvironment({
|
||||
separator: ":",
|
||||
};
|
||||
}
|
||||
throw new ParseError(
|
||||
"Unknown column alignment: " + node.value,
|
||||
node);
|
||||
throw new ParseError("Unknown column alignment: " + ca, nde);
|
||||
});
|
||||
let res = {
|
||||
type: "array",
|
||||
|
Reference in New Issue
Block a user