mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-05 11:18:39 +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
katex.js
4
katex.js
@@ -18,7 +18,7 @@ import domTree from "./src/domTree";
|
||||
import utils from "./src/utils";
|
||||
|
||||
import type {SettingsOptions} from "./src/Settings";
|
||||
import type ParseNode from "./src/ParseNode";
|
||||
import type {AnyParseNode} from "./src/ParseNode";
|
||||
|
||||
import {defineSymbol} from './src/symbols';
|
||||
import {defineMacro} from './src/macros';
|
||||
@@ -70,7 +70,7 @@ const renderToString = function(
|
||||
const generateParseTree = function(
|
||||
expression: string,
|
||||
options: SettingsOptions,
|
||||
): ParseNode<*>[] {
|
||||
): AnyParseNode[] {
|
||||
const settings = new Settings(options);
|
||||
return parseTree(expression, settings);
|
||||
};
|
||||
|
@@ -1,7 +1,8 @@
|
||||
// @flow
|
||||
import ParseNode from "./ParseNode";
|
||||
import {Token} from "./Token";
|
||||
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
|
||||
/**
|
||||
* This is the ParseError class, which is the main error thrown by KaTeX
|
||||
* functions when something has gone wrong. This is used to distinguish internal
|
||||
@@ -15,8 +16,8 @@ class ParseError {
|
||||
// Error position based on passed-in Token or ParseNode.
|
||||
|
||||
constructor(
|
||||
message: string, // The error message
|
||||
token?: Token | ParseNode<*>, // An object providing position information
|
||||
message: string, // The error message
|
||||
token?: ?Token | AnyParseNode, // An object providing position information
|
||||
) {
|
||||
let error = "KaTeX parse error: " + message;
|
||||
let start;
|
||||
|
198
src/ParseNode.js
198
src/ParseNode.js
@@ -1,9 +1,10 @@
|
||||
// @flow
|
||||
import SourceLocation from "./SourceLocation";
|
||||
import type {ArrayEnvNodeData} from "./environments/array.js";
|
||||
import {GROUPS} from "./symbols";
|
||||
import type {ArrayEnvNodeData} from "./environments/array";
|
||||
import type {Mode, StyleStr} from "./types";
|
||||
import type {Token} from "./Token.js";
|
||||
import type {Measurement} from "./units.js";
|
||||
import type {Token} from "./Token";
|
||||
import type {Measurement} from "./units";
|
||||
|
||||
/**
|
||||
* The resulting parse tree nodes of the parse tree.
|
||||
@@ -40,18 +41,83 @@ export type NodeValue<TYPE: NodeType> = $ElementType<ParseNodeTypes, TYPE>;
|
||||
|
||||
export type LeftRightDelimType = {|
|
||||
type: "leftright",
|
||||
body: ParseNode<*>[],
|
||||
body: AnyParseNode[],
|
||||
left: string,
|
||||
right: string,
|
||||
|};
|
||||
|
||||
// ParseNode's corresponding to Symbol `Group`s in symbols.js.
|
||||
export type SymbolParseNode =
|
||||
ParseNode<"accent-token"> |
|
||||
ParseNode<"bin"> |
|
||||
ParseNode<"close"> |
|
||||
ParseNode<"inner"> |
|
||||
ParseNode<"mathord"> |
|
||||
ParseNode<"op-token"> |
|
||||
ParseNode<"open"> |
|
||||
ParseNode<"punct"> |
|
||||
ParseNode<"rel"> |
|
||||
ParseNode<"spacing"> |
|
||||
ParseNode<"textord">;
|
||||
|
||||
// Union of all possible `ParseNode<>` types.
|
||||
// Unable to derive this directly from `ParseNodeTypes` due to
|
||||
// https://github.com/facebook/flow/issues/6369.
|
||||
// Cannot use `ParseNode<NodeType>` since `ParseNode` is not strictly co-variant
|
||||
// w.r.t. its type parameter due to the way the value type is computed.
|
||||
export type AnyParseNode =
|
||||
SymbolParseNode |
|
||||
ParseNode<"array"> |
|
||||
ParseNode<"color"> |
|
||||
ParseNode<"color-token"> |
|
||||
ParseNode<"op"> |
|
||||
ParseNode<"ordgroup"> |
|
||||
ParseNode<"size"> |
|
||||
ParseNode<"styling"> |
|
||||
ParseNode<"supsub"> |
|
||||
ParseNode<"tag"> |
|
||||
ParseNode<"text"> |
|
||||
ParseNode<"url"> |
|
||||
ParseNode<"verb"> |
|
||||
ParseNode<"accent"> |
|
||||
ParseNode<"accentUnder"> |
|
||||
ParseNode<"cr"> |
|
||||
ParseNode<"delimsizing"> |
|
||||
ParseNode<"enclose"> |
|
||||
ParseNode<"environment"> |
|
||||
ParseNode<"font"> |
|
||||
ParseNode<"genfrac"> |
|
||||
ParseNode<"horizBrace"> |
|
||||
ParseNode<"href"> |
|
||||
ParseNode<"infix"> |
|
||||
ParseNode<"kern"> |
|
||||
ParseNode<"lap"> |
|
||||
ParseNode<"leftright"> |
|
||||
ParseNode<"leftright-right"> |
|
||||
ParseNode<"mathchoice"> |
|
||||
ParseNode<"middle"> |
|
||||
ParseNode<"mclass"> |
|
||||
ParseNode<"mod"> |
|
||||
ParseNode<"operatorname"> |
|
||||
ParseNode<"overline"> |
|
||||
ParseNode<"phantom"> |
|
||||
ParseNode<"hphantom"> |
|
||||
ParseNode<"vphantom"> |
|
||||
ParseNode<"raisebox"> |
|
||||
ParseNode<"rule"> |
|
||||
ParseNode<"sizing"> |
|
||||
ParseNode<"smash"> |
|
||||
ParseNode<"sqrt"> |
|
||||
ParseNode<"underline"> |
|
||||
ParseNode<"xArrow">;
|
||||
|
||||
// Map from `type` field value to corresponding `value` type.
|
||||
export type ParseNodeTypes = {
|
||||
"array": ArrayEnvNodeData,
|
||||
"color": {|
|
||||
type: "color",
|
||||
color: string,
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"color-token": string,
|
||||
// To avoid requiring run-time type assertions, this more carefully captures
|
||||
@@ -73,9 +139,9 @@ export type ParseNodeTypes = {
|
||||
suppressBaseShift?: boolean,
|
||||
symbol: false, // If 'symbol' is true, `body` *must* be set.
|
||||
body?: void,
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"ordgroup": ParseNode<*>[],
|
||||
"ordgroup": AnyParseNode[],
|
||||
"size": {|
|
||||
type: "size",
|
||||
value: Measurement,
|
||||
@@ -83,22 +149,22 @@ export type ParseNodeTypes = {
|
||||
"styling": {|
|
||||
type: "styling",
|
||||
style: StyleStr,
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"supsub": {|
|
||||
type: "supsub",
|
||||
base: ?ParseNode<*>,
|
||||
sup?: ?ParseNode<*>,
|
||||
sub?: ?ParseNode<*>,
|
||||
base: ?AnyParseNode,
|
||||
sup?: ?AnyParseNode,
|
||||
sub?: ?AnyParseNode,
|
||||
|},
|
||||
"tag": {|
|
||||
type: "tag",
|
||||
body: ParseNode<*>[],
|
||||
tag: ParseNode<*>[],
|
||||
body: AnyParseNode[],
|
||||
tag: AnyParseNode[],
|
||||
|},
|
||||
"text": {|
|
||||
type: "text",
|
||||
body: ParseNode<*>[],
|
||||
body: AnyParseNode[],
|
||||
font?: string,
|
||||
|},
|
||||
"url": {|
|
||||
@@ -131,14 +197,14 @@ export type ParseNodeTypes = {
|
||||
label: string,
|
||||
isStretchy?: boolean,
|
||||
isShifty?: boolean,
|
||||
base: ParseNode<*>,
|
||||
base: AnyParseNode,
|
||||
|},
|
||||
"accentUnder": {|
|
||||
type: "accentUnder",
|
||||
label: string,
|
||||
isStretchy?: boolean,
|
||||
isShifty?: boolean,
|
||||
base: ParseNode<*>,
|
||||
base: AnyParseNode,
|
||||
|},
|
||||
"cr": {|
|
||||
type: "cr",
|
||||
@@ -157,23 +223,23 @@ export type ParseNodeTypes = {
|
||||
label: string,
|
||||
backgroundColor?: ParseNode<"color-token">,
|
||||
borderColor?: ParseNode<"color-token">,
|
||||
body: ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"environment": {|
|
||||
type: "environment",
|
||||
name: string,
|
||||
nameGroup: ParseNode<*>,
|
||||
nameGroup: AnyParseNode,
|
||||
|},
|
||||
"font": {|
|
||||
type: "font",
|
||||
font: string,
|
||||
body: ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"genfrac": {|
|
||||
type: "genfrac",
|
||||
continued: boolean,
|
||||
numer: ParseNode<*>,
|
||||
denom: ParseNode<*>,
|
||||
numer: AnyParseNode,
|
||||
denom: AnyParseNode,
|
||||
hasBarLine: boolean,
|
||||
leftDelim: ?string,
|
||||
rightDelim: ?string,
|
||||
@@ -183,12 +249,12 @@ export type ParseNodeTypes = {
|
||||
type: "horizBrace",
|
||||
label: string,
|
||||
isOver: boolean,
|
||||
base: ParseNode<*>,
|
||||
base: AnyParseNode,
|
||||
|},
|
||||
"href": {|
|
||||
type: "href",
|
||||
href: string,
|
||||
body: ParseNode<*>[],
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"infix": {|
|
||||
type: "infix",
|
||||
@@ -202,7 +268,7 @@ export type ParseNodeTypes = {
|
||||
"lap": {|
|
||||
type: "lap",
|
||||
alignment: string,
|
||||
body: ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"leftright": LeftRightDelimType,
|
||||
"leftright-right": {|
|
||||
@@ -211,10 +277,10 @@ export type ParseNodeTypes = {
|
||||
|},
|
||||
"mathchoice": {|
|
||||
type: "mathchoice",
|
||||
display: ParseNode<*>[],
|
||||
text: ParseNode<*>[],
|
||||
script: ParseNode<*>[],
|
||||
scriptscript: ParseNode<*>[],
|
||||
display: AnyParseNode[],
|
||||
text: AnyParseNode[],
|
||||
script: AnyParseNode[],
|
||||
scriptscript: AnyParseNode[],
|
||||
|},
|
||||
"middle": {|
|
||||
type: "middle",
|
||||
@@ -223,40 +289,40 @@ export type ParseNodeTypes = {
|
||||
"mclass": {|
|
||||
type: "mclass",
|
||||
mclass: string,
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"mod": {|
|
||||
type: "mod",
|
||||
modType: string,
|
||||
value: ?ParseNode<*>[],
|
||||
value: ?AnyParseNode[],
|
||||
|},
|
||||
"operatorname": {|
|
||||
type: "operatorname",
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"overline": {|
|
||||
type: "overline",
|
||||
body: ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"phantom": {|
|
||||
type: "phantom",
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"hphantom": {|
|
||||
type: "hphantom",
|
||||
body: ParseNode<*>,
|
||||
value: ParseNode<*>[],
|
||||
body: AnyParseNode,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"vphantom": {|
|
||||
type: "vphantom",
|
||||
body: ParseNode<*>,
|
||||
value: ParseNode<*>[],
|
||||
body: AnyParseNode,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"raisebox": {|
|
||||
type: "raisebox",
|
||||
dy: ParseNode<"size">,
|
||||
body: ParseNode<*>,
|
||||
value: ParseNode<*>[],
|
||||
body: AnyParseNode,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"rule": {|
|
||||
type: "rule",
|
||||
@@ -267,28 +333,28 @@ export type ParseNodeTypes = {
|
||||
"sizing": {|
|
||||
type: "sizing",
|
||||
size: number,
|
||||
value: ParseNode<*>[],
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
"smash": {|
|
||||
type: "smash",
|
||||
body: ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
smashHeight: boolean,
|
||||
smashDepth: boolean,
|
||||
|},
|
||||
"sqrt": {|
|
||||
type: "sqrt",
|
||||
body: ParseNode<*>,
|
||||
index: ?ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
index: ?AnyParseNode,
|
||||
|},
|
||||
"underline": {|
|
||||
type: "underline",
|
||||
body: ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"xArrow": {|
|
||||
type: "xArrow",
|
||||
label: string,
|
||||
body: ParseNode<*>,
|
||||
below: ?ParseNode<*>,
|
||||
body: AnyParseNode,
|
||||
below: ?AnyParseNode,
|
||||
|},
|
||||
};
|
||||
|
||||
@@ -297,8 +363,7 @@ export type ParseNodeTypes = {
|
||||
* typing. Throws if the node's type does not match.
|
||||
*/
|
||||
export function assertNodeType<NODETYPE: NodeType>(
|
||||
// The union allows either ParseNode<*> or the union of two specific nodes.
|
||||
node: ?ParseNode<*> | ParseNode<*>,
|
||||
node: ?AnyParseNode,
|
||||
type: NODETYPE,
|
||||
): ParseNode<NODETYPE> {
|
||||
const typedNode = checkNodeType(node, type);
|
||||
@@ -315,11 +380,38 @@ export function assertNodeType<NODETYPE: NodeType>(
|
||||
* returns null.
|
||||
*/
|
||||
export function checkNodeType<NODETYPE: NodeType>(
|
||||
// The union allows either ParseNode<*> or the union of two specific nodes.
|
||||
node: ?ParseNode<*> | ParseNode<*>,
|
||||
node: ?AnyParseNode,
|
||||
type: NODETYPE,
|
||||
): ?ParseNode<NODETYPE> {
|
||||
return node && node.type === type ?
|
||||
(node: ParseNode<NODETYPE>) :
|
||||
null;
|
||||
if (node && node.type === type) {
|
||||
// $FlowFixMe: Inference not sophisticated enough to figure this out.
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node more strictly typed iff it is of the given type. Otherwise,
|
||||
* returns null.
|
||||
*/
|
||||
export function assertSymbolNodeType(node: ?AnyParseNode): SymbolParseNode {
|
||||
const typedNode = checkSymbolNodeType(node);
|
||||
if (!typedNode) {
|
||||
throw new Error(
|
||||
`Expected node of symbol group type, but got ` +
|
||||
(node ? `node of type ${node.type}` : String(node)));
|
||||
}
|
||||
return typedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node more strictly typed iff it is of the given type. Otherwise,
|
||||
* returns null.
|
||||
*/
|
||||
export function checkSymbolNodeType(node: ?AnyParseNode): ?SymbolParseNode {
|
||||
if (node && GROUPS.hasOwnProperty(node.type)) {
|
||||
// $FlowFixMe
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -9,12 +9,12 @@ import {validUnit} from "./units";
|
||||
import {supportedCodepoint} from "./unicodeScripts";
|
||||
import unicodeAccents from "./unicodeAccents";
|
||||
import unicodeSymbols from "./unicodeSymbols";
|
||||
import ParseNode, {assertNodeType} from "./ParseNode";
|
||||
import ParseNode, {assertNodeType, checkNodeType} from "./ParseNode";
|
||||
import ParseError from "./ParseError";
|
||||
import {combiningDiacriticalMarksEndRegex} from "./Lexer.js";
|
||||
import Settings from "./Settings";
|
||||
import {Token} from "./Token";
|
||||
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
import type {Mode, ArgType, BreakToken} from "./types";
|
||||
import type {FunctionContext, FunctionSpec} from "./defineFunction";
|
||||
import type {EnvSpec} from "./defineEnvironment";
|
||||
@@ -60,12 +60,12 @@ type ParsedFunc = {|
|
||||
|};
|
||||
type ParsedArg = {|
|
||||
type: "arg",
|
||||
result: ParseNode<*>,
|
||||
result: AnyParseNode,
|
||||
token: Token,
|
||||
|};
|
||||
type ParsedFuncOrArg = ParsedFunc | ParsedArg;
|
||||
|
||||
function newArgument(result: ParseNode<*>, token: Token): ParsedArg {
|
||||
function newArgument(result: AnyParseNode, token: Token): ParsedArg {
|
||||
return {type: "arg", result, token};
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export default class Parser {
|
||||
/**
|
||||
* Main parsing function, which parses an entire input.
|
||||
*/
|
||||
parse(): ParseNode<*>[] {
|
||||
parse(): AnyParseNode[] {
|
||||
// Create a group namespace for the math expression.
|
||||
// (LaTeX creates a new group for every $...$, $$...$$, \[...\].)
|
||||
this.gullet.beginGroup();
|
||||
@@ -167,7 +167,7 @@ export default class Parser {
|
||||
parseExpression(
|
||||
breakOnInfix: boolean,
|
||||
breakOnTokenText?: BreakToken,
|
||||
): ParseNode<*>[] {
|
||||
): AnyParseNode[] {
|
||||
const body = [];
|
||||
// Keep adding atoms to the body until we can't parse any more atoms (either
|
||||
// we reached the end, a }, or a \right)
|
||||
@@ -208,13 +208,13 @@ export default class Parser {
|
||||
* There can only be one infix operator per group. If there's more than one
|
||||
* then the expression is ambiguous. This can be resolved by adding {}.
|
||||
*/
|
||||
handleInfixNodes(body: ParseNode<*>[]): ParseNode<*>[] {
|
||||
handleInfixNodes(body: AnyParseNode[]): AnyParseNode[] {
|
||||
let overIndex = -1;
|
||||
let funcName;
|
||||
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
const node = body[i];
|
||||
if (node.type === "infix") {
|
||||
const node = checkNodeType(body[i], "infix");
|
||||
if (node) {
|
||||
if (overIndex !== -1) {
|
||||
throw new ParseError(
|
||||
"only one infix operator per group",
|
||||
@@ -259,7 +259,7 @@ export default class Parser {
|
||||
*/
|
||||
handleSupSubscript(
|
||||
name: string, // For error reporting.
|
||||
): ParseNode<*> {
|
||||
): AnyParseNode {
|
||||
const symbolToken = this.nextToken;
|
||||
const symbol = symbolToken.text;
|
||||
this.consume();
|
||||
@@ -297,7 +297,7 @@ export default class Parser {
|
||||
* Converts the textual input of an unsupported command into a text node
|
||||
* contained within a color node whose color is determined by errorColor
|
||||
*/
|
||||
handleUnsupportedCmd(): ParseNode<*> {
|
||||
handleUnsupportedCmd(): AnyParseNode {
|
||||
const text = this.nextToken.text;
|
||||
const textordArray = [];
|
||||
|
||||
@@ -329,7 +329,7 @@ export default class Parser {
|
||||
/**
|
||||
* Parses a group with optional super/subscripts.
|
||||
*/
|
||||
parseAtom(breakOnTokenText?: BreakToken): ?ParseNode<*> {
|
||||
parseAtom(breakOnTokenText?: BreakToken): ?AnyParseNode {
|
||||
// The body of an atom is an implicit group, so that things like
|
||||
// \left(x\right)^2 work correctly.
|
||||
const base = this.parseImplicitGroup(breakOnTokenText);
|
||||
@@ -352,14 +352,15 @@ export default class Parser {
|
||||
|
||||
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
|
||||
// We got a limit control
|
||||
if (!base || base.type !== "op") {
|
||||
const opNode = checkNodeType(base, "op");
|
||||
if (opNode) {
|
||||
const limits = lex.text === "\\limits";
|
||||
opNode.value.limits = limits;
|
||||
opNode.value.alwaysHandleSupSub = true;
|
||||
} else {
|
||||
throw new ParseError(
|
||||
"Limit controls must follow a math operator",
|
||||
lex);
|
||||
} else {
|
||||
const limits = lex.text === "\\limits";
|
||||
base.value.limits = limits;
|
||||
base.value.alwaysHandleSupSub = true;
|
||||
}
|
||||
this.consume();
|
||||
} else if (lex.text === "^") {
|
||||
@@ -427,7 +428,7 @@ export default class Parser {
|
||||
* implicit grouping after it until the end of the group. E.g.
|
||||
* small text {\Large large text} small text again
|
||||
*/
|
||||
parseImplicitGroup(breakOnTokenText?: BreakToken): ?ParseNode<*> {
|
||||
parseImplicitGroup(breakOnTokenText?: BreakToken): ?AnyParseNode {
|
||||
const start = this.parseSymbol();
|
||||
|
||||
if (start == null) {
|
||||
@@ -463,10 +464,12 @@ export default class Parser {
|
||||
const result = env.handler(context, args, optArgs);
|
||||
this.expect("\\end", false);
|
||||
const endNameToken = this.nextToken;
|
||||
const end = assertNodeType(this.parseFunction(), "environment");
|
||||
let end = this.parseFunction();
|
||||
if (!end) {
|
||||
throw new ParseError("failed to parse function after \\end");
|
||||
} else if (end.value.name !== envName) {
|
||||
}
|
||||
end = assertNodeType(end, "environment");
|
||||
if (end.value.name !== envName) {
|
||||
throw new ParseError(
|
||||
"Mismatch: \\begin{" + envName + "} matched " +
|
||||
"by \\end{" + end.value.name + "}",
|
||||
@@ -483,7 +486,7 @@ export default class Parser {
|
||||
* Parses an entire function, including its base and all of its arguments.
|
||||
* It also handles the case where the parsed node is not a function.
|
||||
*/
|
||||
parseFunction(): ?ParseNode<*> {
|
||||
parseFunction(): ?AnyParseNode {
|
||||
const baseGroup = this.parseGroup();
|
||||
return baseGroup ? this.parseGivenFunction(baseGroup) : null;
|
||||
}
|
||||
@@ -495,7 +498,7 @@ export default class Parser {
|
||||
parseGivenFunction(
|
||||
baseGroup: ParsedFuncOrArg,
|
||||
breakOnTokenText?: BreakToken,
|
||||
): ParseNode<*> {
|
||||
): AnyParseNode {
|
||||
if (baseGroup.type === "fn") {
|
||||
const func = baseGroup.result;
|
||||
const funcData = functions[func];
|
||||
@@ -535,11 +538,11 @@ export default class Parser {
|
||||
*/
|
||||
callFunction(
|
||||
name: string,
|
||||
args: ParseNode<*>[],
|
||||
optArgs: (?ParseNode<*>)[],
|
||||
args: AnyParseNode[],
|
||||
optArgs: (?AnyParseNode)[],
|
||||
token?: Token,
|
||||
breakOnTokenText?: BreakToken,
|
||||
): ParseNode<*> {
|
||||
): AnyParseNode {
|
||||
const context: FunctionContext = {
|
||||
funcName: name,
|
||||
parser: this,
|
||||
@@ -561,8 +564,8 @@ export default class Parser {
|
||||
func: string, // Should look like "\name" or "\begin{name}".
|
||||
funcData: FunctionSpec<*> | EnvSpec<*>,
|
||||
): {
|
||||
args: ParseNode<*>[],
|
||||
optArgs: (?ParseNode<*>)[],
|
||||
args: AnyParseNode[],
|
||||
optArgs: (?AnyParseNode)[],
|
||||
} {
|
||||
const totalArgs = funcData.numArgs + funcData.numOptionalArgs;
|
||||
if (totalArgs === 0) {
|
||||
@@ -609,7 +612,7 @@ export default class Parser {
|
||||
"Expected group after '" + func + "'", nextToken);
|
||||
}
|
||||
}
|
||||
let argNode: ParseNode<*>;
|
||||
let argNode: AnyParseNode;
|
||||
if (arg.type === "fn") {
|
||||
const argGreediness =
|
||||
functions[arg.result].greediness;
|
||||
@@ -895,7 +898,7 @@ export default class Parser {
|
||||
* characters in its value. The representation is still ASCII source.
|
||||
* The group will be modified in place.
|
||||
*/
|
||||
formLigatures(group: ParseNode<*>[]) {
|
||||
formLigatures(group: AnyParseNode[]) {
|
||||
let n = group.length - 1;
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const a = group[i];
|
||||
|
@@ -7,13 +7,13 @@
|
||||
|
||||
import utils from "./utils";
|
||||
import ParseError from "./ParseError.js";
|
||||
import ParseNode from "./ParseNode";
|
||||
import {Token} from "./Token";
|
||||
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
import type {MacroMap} from "./macros";
|
||||
|
||||
export type StrictFunction =
|
||||
(errorCode: string, errorMsg: string, token?: Token | ParseNode<*>) =>
|
||||
(errorCode: string, errorMsg: string, token?: Token | AnyParseNode) =>
|
||||
?(boolean | string);
|
||||
|
||||
export type SettingsOptions = {
|
||||
@@ -65,7 +65,7 @@ class Settings {
|
||||
* Can safely not be called if `this.strict` is false in JavaScript.
|
||||
*/
|
||||
reportNonstrict(errorCode: string, errorMsg: string,
|
||||
token?: Token | ParseNode<*>) {
|
||||
token?: Token | AnyParseNode) {
|
||||
let strict = this.strict;
|
||||
if (typeof strict === "function") {
|
||||
// Allow return value of strict function to be boolean or string
|
||||
@@ -98,7 +98,7 @@ class Settings {
|
||||
* This is for the second category of `errorCode`s listed in the README.
|
||||
*/
|
||||
useStrictBehavior(errorCode: string, errorMsg: string,
|
||||
token?: Token | ParseNode<*>) {
|
||||
token?: Token | AnyParseNode) {
|
||||
let strict = this.strict;
|
||||
if (typeof strict === "function") {
|
||||
// Allow return value of strict function to be boolean or string
|
||||
|
@@ -6,7 +6,7 @@ import Options from "./Options";
|
||||
import Settings from "./Settings";
|
||||
import Style from "./Style";
|
||||
|
||||
import type ParseNode from "./ParseNode";
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
import type {DomSpan} from "./domTree";
|
||||
|
||||
const optionsFromSettings = function(settings: Settings) {
|
||||
@@ -17,7 +17,7 @@ const optionsFromSettings = function(settings: Settings) {
|
||||
};
|
||||
|
||||
export const buildTree = function(
|
||||
tree: ParseNode<*>[],
|
||||
tree: AnyParseNode[],
|
||||
expression: string,
|
||||
settings: Settings,
|
||||
): DomSpan {
|
||||
@@ -39,7 +39,7 @@ export const buildTree = function(
|
||||
};
|
||||
|
||||
export const buildHTMLTree = function(
|
||||
tree: ParseNode<*>[],
|
||||
tree: AnyParseNode[],
|
||||
expression: string,
|
||||
settings: Settings,
|
||||
): DomSpan {
|
||||
|
@@ -1,14 +1,13 @@
|
||||
// @flow
|
||||
import {_htmlGroupBuilders, _mathmlGroupBuilders} from "./defineFunction";
|
||||
|
||||
import Options from "./Options";
|
||||
import ParseNode from "./ParseNode";
|
||||
|
||||
import type Parser from "./Parser";
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
import type {ArgType, Mode} from "./types";
|
||||
import type {HtmlDomNode} from "./domTree";
|
||||
import type {NodeType} from "./ParseNode";
|
||||
import type {MathNode} from "./mathMLTree";
|
||||
import type {HtmlBuilder, MathMLBuilder} from "./defineFunction";
|
||||
|
||||
/**
|
||||
* The context contains the following properties:
|
||||
@@ -29,8 +28,8 @@ type EnvContext = {|
|
||||
*/
|
||||
type EnvHandler<NODETYPE: NodeType> = (
|
||||
context: EnvContext,
|
||||
args: ParseNode<*>[],
|
||||
optArgs: (?ParseNode<*>)[],
|
||||
args: AnyParseNode[],
|
||||
optArgs: (?AnyParseNode)[],
|
||||
) => ParseNode<NODETYPE>;
|
||||
|
||||
/**
|
||||
@@ -85,11 +84,11 @@ type EnvDefSpec<NODETYPE: NodeType> = {|
|
||||
|
||||
// This function returns an object representing the DOM structure to be
|
||||
// created when rendering the defined LaTeX function.
|
||||
htmlBuilder: (group: ParseNode<NODETYPE>, options: Options) => HtmlDomNode,
|
||||
htmlBuilder: HtmlBuilder<NODETYPE>,
|
||||
|
||||
// This function returns an object representing the MathML structure to be
|
||||
// created when rendering the defined LaTeX function.
|
||||
mathmlBuilder: (group: ParseNode<NODETYPE>, options: Options) => MathNode,
|
||||
mathmlBuilder: MathMLBuilder<NODETYPE>,
|
||||
|};
|
||||
|
||||
export default function defineEnvironment<NODETYPE: NodeType>({
|
||||
|
@@ -3,7 +3,7 @@ import {checkNodeType} from "./ParseNode";
|
||||
import domTree from "./domTree";
|
||||
|
||||
import type Parser from "./Parser";
|
||||
import type ParseNode, {NodeType} from "./ParseNode";
|
||||
import type ParseNode, {AnyParseNode, NodeType} from "./ParseNode";
|
||||
import type Options from "./Options";
|
||||
import type {ArgType, BreakToken, Mode} from "./types";
|
||||
import type {HtmlDomNode} from "./domTree";
|
||||
@@ -20,8 +20,8 @@ export type FunctionContext = {|
|
||||
|
||||
export type FunctionHandler<NODETYPE: NodeType> = (
|
||||
context: FunctionContext,
|
||||
args: ParseNode<*>[],
|
||||
optArgs: (?ParseNode<*>)[],
|
||||
args: AnyParseNode[],
|
||||
optArgs: (?AnyParseNode)[],
|
||||
) => ParseNode<NODETYPE>;
|
||||
|
||||
export type HtmlBuilder<NODETYPE> = (ParseNode<NODETYPE>, Options) => HtmlDomNode;
|
||||
@@ -245,7 +245,7 @@ export function defineFunctionBuilders<NODETYPE: NodeType>({
|
||||
|
||||
// Since the corresponding buildHTML/buildMathML function expects a
|
||||
// list of elements, we normalize for different kinds of arguments
|
||||
export const ordargument = function(arg: ParseNode<*>): ParseNode<*>[] {
|
||||
export const ordargument = function(arg: AnyParseNode): AnyParseNode[] {
|
||||
const node = checkNodeType(arg, "ordgroup");
|
||||
return node ? node.value : [arg];
|
||||
};
|
||||
|
@@ -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",
|
||||
|
@@ -9,13 +9,14 @@ import ParseNode, {assertNodeType, checkNodeType} from "../ParseNode";
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type {AnyParseNode} from "../ParseNode";
|
||||
import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
||||
|
||||
// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but
|
||||
// also "supsub" since an accent can affect super/subscripting.
|
||||
export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
||||
// Accents are handled in the TeXbook pg. 443, rule 12.
|
||||
let base: ParseNode<*>;
|
||||
let base: AnyParseNode;
|
||||
let group: ParseNode<"accent">;
|
||||
|
||||
const supSub = checkNodeType(grp, "supsub");
|
||||
|
@@ -2,7 +2,6 @@
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import buildCommon from "../buildCommon";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import ParseError from "../ParseError";
|
||||
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
@@ -99,10 +98,7 @@ defineFunction({
|
||||
argTypes: ["color"],
|
||||
},
|
||||
handler({parser, breakOnTokenText}, args) {
|
||||
const color = args[0];
|
||||
if (!color) {
|
||||
throw new ParseError("\\color not followed by color");
|
||||
}
|
||||
const color = assertNodeType(args[0], "color-token");
|
||||
|
||||
// If we see a styling function, parse out the implicit body
|
||||
const body = parser.parseExpression(true, breakOnTokenText);
|
||||
|
@@ -5,11 +5,12 @@ import delimiter from "../delimiter";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import ParseError from "../ParseError";
|
||||
import utils from "../utils";
|
||||
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||
import ParseNode, {assertNodeType, checkSymbolNodeType} from "../ParseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type {AnyParseNode, SymbolParseNode} from "../ParseNode";
|
||||
import type {LeftRightDelimType} from "../ParseNode";
|
||||
import type {FunctionContext} from "../defineFunction";
|
||||
|
||||
@@ -52,14 +53,15 @@ const delimiters = [
|
||||
|
||||
// Delimiter functions
|
||||
function checkDelimiter(
|
||||
delim: ParseNode<*>,
|
||||
delim: AnyParseNode,
|
||||
context: FunctionContext,
|
||||
): ParseNode<*> {
|
||||
if (utils.contains(delimiters, delim.value)) {
|
||||
return delim;
|
||||
): SymbolParseNode {
|
||||
const symDelim = checkSymbolNodeType(delim);
|
||||
if (symDelim && utils.contains(delimiters, symDelim.value)) {
|
||||
return symDelim;
|
||||
} else {
|
||||
throw new ParseError(
|
||||
"Invalid delimiter: '" + delim.value + "' after '" +
|
||||
"Invalid delimiter: '" + String(delim.value) + "' after '" +
|
||||
context.funcName + "'", delim);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
import defineFunction from "../defineFunction";
|
||||
import ParseError from "../ParseError";
|
||||
import ParseNode from "../ParseNode";
|
||||
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||
|
||||
// Environment delimiters. HTML/MathML rendering is defined in the corresponding
|
||||
// defineEnvironment definitions.
|
||||
@@ -19,7 +19,7 @@ defineFunction({
|
||||
}
|
||||
let name = "";
|
||||
for (let i = 0; i < nameGroup.value.length; ++i) {
|
||||
name += nameGroup.value[i].value;
|
||||
name += assertNodeType(nameGroup.value[i], "textord").value;
|
||||
}
|
||||
return new ParseNode("environment", {
|
||||
type: "environment",
|
||||
|
@@ -19,7 +19,7 @@ defineFunction({
|
||||
const height = assertNodeType(args[1], "size");
|
||||
return new ParseNode("rule", {
|
||||
type: "rule",
|
||||
shift: shift && shift.value,
|
||||
shift: shift && assertNodeType(shift, "size").value.value,
|
||||
width: width.value.value,
|
||||
height: height.value.value,
|
||||
}, parser.mode);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
import defineFunction from "../defineFunction";
|
||||
import buildCommon from "../buildCommon";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import ParseNode from "../ParseNode";
|
||||
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
@@ -19,7 +19,7 @@ defineFunction({
|
||||
handler: ({parser}, args, optArgs) => {
|
||||
let smashHeight = false;
|
||||
let smashDepth = false;
|
||||
const tbArg = optArgs[0];
|
||||
const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup");
|
||||
if (tbArg) {
|
||||
// Optional [tb] argument is engaged.
|
||||
// ref: amsmath: \renewcommand{\smash}[1][tb]{%
|
||||
|
@@ -5,6 +5,7 @@ import domTree from "../domTree";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import utils from "../utils";
|
||||
import Style from "../Style";
|
||||
import {checkNodeType} from "../ParseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
@@ -184,13 +185,13 @@ defineFunctionBuilders({
|
||||
let isBrace = false;
|
||||
let isOver;
|
||||
let isSup;
|
||||
if (group.value.base) {
|
||||
if (group.value.base.value.type === "horizBrace") {
|
||||
isSup = (group.value.sup ? true : false);
|
||||
if (isSup === group.value.base.value.isOver) {
|
||||
isBrace = true;
|
||||
isOver = group.value.base.value.isOver;
|
||||
}
|
||||
|
||||
const horizBrace = checkNodeType(group.value.base, "horizBrace");
|
||||
if (horizBrace) {
|
||||
isSup = !!group.value.sup;
|
||||
if (isSup === horizBrace.value.isOver) {
|
||||
isBrace = true;
|
||||
isOver = horizBrace.value.isOver;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,11 +9,12 @@ import ParseError from "./ParseError";
|
||||
import ParseNode from "./ParseNode";
|
||||
|
||||
import type Settings from "./Settings";
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
|
||||
/**
|
||||
* Parses an expression using a Parser, then returns the parsed result.
|
||||
*/
|
||||
const parseTree = function(toParse: string, settings: Settings): ParseNode<*>[] {
|
||||
const parseTree = function(toParse: string, settings: Settings): AnyParseNode[] {
|
||||
if (!(typeof toParse === 'string' || toParse instanceof String)) {
|
||||
throw new TypeError('KaTeX can only parse string typed expression');
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import mathMLTree from "./mathMLTree";
|
||||
import utils from "./utils";
|
||||
|
||||
import type Options from "./Options";
|
||||
import type ParseNode from "./ParseNode";
|
||||
import type ParseNode, {AnyParseNode} from "./ParseNode";
|
||||
import type {DomSpan, SvgSpan} from "./domTree";
|
||||
|
||||
const stretchyCodePoint: {[string]: string} = {
|
||||
@@ -159,7 +159,7 @@ const katexImagesData: {
|
||||
"shortrightharpoonabovebar"], 1.75, 716],
|
||||
};
|
||||
|
||||
const groupLength = function(arg: ParseNode<*>): number {
|
||||
const groupLength = function(arg: AnyParseNode): number {
|
||||
if (arg.type === "ordgroup") {
|
||||
return arg.value.length;
|
||||
} else {
|
||||
|
@@ -24,9 +24,20 @@ type Font = "main" | "ams"
|
||||
// types for raw text tokens, and we want to avoid conflicts with higher-level
|
||||
// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
|
||||
// looking up the `symbols` map.
|
||||
export type Group =
|
||||
"accent-token" | "bin" | "close" | "inner" | "mathord" |
|
||||
"op-token" | "open" | "punct" | "rel" | "spacing" | "textord";
|
||||
export const GROUPS = { // Set of all the groups.
|
||||
"accent-token": 1,
|
||||
"bin": 1,
|
||||
"close": 1,
|
||||
"inner": 1,
|
||||
"mathord": 1,
|
||||
"op-token": 1,
|
||||
"open": 1,
|
||||
"punct": 1,
|
||||
"rel": 1,
|
||||
"spacing": 1,
|
||||
"textord": 1,
|
||||
};
|
||||
export type Group = $Keys<typeof GROUPS>;
|
||||
type CharInfoMap = {[string]: {font: Font, group: Group, replace: ?string}};
|
||||
|
||||
const symbols: {[Mode]: CharInfoMap} = {
|
||||
|
@@ -4,7 +4,7 @@
|
||||
* files.
|
||||
*/
|
||||
|
||||
import type ParseNode from "./ParseNode";
|
||||
import type {AnyParseNode} from "./ParseNode";
|
||||
|
||||
/**
|
||||
* Provide an `indexOf` function which works in IE8, but defers to native if
|
||||
@@ -96,7 +96,7 @@ function clearNode(node: Node) {
|
||||
* cases, this will just be the group itself, but when ordgroups and colors have
|
||||
* a single element, we want to pull that out.
|
||||
*/
|
||||
const getBaseElem = function(group: ParseNode<*>): ParseNode<*> {
|
||||
const getBaseElem = function(group: AnyParseNode): AnyParseNode {
|
||||
if (group.type === "ordgroup") {
|
||||
if (group.value.length === 1) {
|
||||
return getBaseElem(group.value[0]);
|
||||
@@ -121,7 +121,7 @@ const getBaseElem = function(group: ParseNode<*>): ParseNode<*> {
|
||||
* with a single character in them. To decide if something is a character box,
|
||||
* we find its innermost group, and see if it is a single character.
|
||||
*/
|
||||
const isCharacterBox = function(group: ParseNode<*>): boolean {
|
||||
const isCharacterBox = function(group: AnyParseNode): boolean {
|
||||
const baseElem = getBaseElem(group);
|
||||
|
||||
// These are all they types of groups which hold single characters
|
||||
|
Reference in New Issue
Block a user