mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-05 19:28: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 utils from "./src/utils";
|
||||||
|
|
||||||
import type {SettingsOptions} from "./src/Settings";
|
import type {SettingsOptions} from "./src/Settings";
|
||||||
import type ParseNode from "./src/ParseNode";
|
import type {AnyParseNode} from "./src/ParseNode";
|
||||||
|
|
||||||
import {defineSymbol} from './src/symbols';
|
import {defineSymbol} from './src/symbols';
|
||||||
import {defineMacro} from './src/macros';
|
import {defineMacro} from './src/macros';
|
||||||
@@ -70,7 +70,7 @@ const renderToString = function(
|
|||||||
const generateParseTree = function(
|
const generateParseTree = function(
|
||||||
expression: string,
|
expression: string,
|
||||||
options: SettingsOptions,
|
options: SettingsOptions,
|
||||||
): ParseNode<*>[] {
|
): AnyParseNode[] {
|
||||||
const settings = new Settings(options);
|
const settings = new Settings(options);
|
||||||
return parseTree(expression, settings);
|
return parseTree(expression, settings);
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import ParseNode from "./ParseNode";
|
|
||||||
import {Token} from "./Token";
|
import {Token} from "./Token";
|
||||||
|
|
||||||
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the ParseError class, which is the main error thrown by KaTeX
|
* 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
|
* 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.
|
// Error position based on passed-in Token or ParseNode.
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
message: string, // The error message
|
message: string, // The error message
|
||||||
token?: Token | ParseNode<*>, // An object providing position information
|
token?: ?Token | AnyParseNode, // An object providing position information
|
||||||
) {
|
) {
|
||||||
let error = "KaTeX parse error: " + message;
|
let error = "KaTeX parse error: " + message;
|
||||||
let start;
|
let start;
|
||||||
|
198
src/ParseNode.js
198
src/ParseNode.js
@@ -1,9 +1,10 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import SourceLocation from "./SourceLocation";
|
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 {Mode, StyleStr} from "./types";
|
||||||
import type {Token} from "./Token.js";
|
import type {Token} from "./Token";
|
||||||
import type {Measurement} from "./units.js";
|
import type {Measurement} from "./units";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The resulting parse tree nodes of the parse tree.
|
* The resulting parse tree nodes of the parse tree.
|
||||||
@@ -40,18 +41,83 @@ export type NodeValue<TYPE: NodeType> = $ElementType<ParseNodeTypes, TYPE>;
|
|||||||
|
|
||||||
export type LeftRightDelimType = {|
|
export type LeftRightDelimType = {|
|
||||||
type: "leftright",
|
type: "leftright",
|
||||||
body: ParseNode<*>[],
|
body: AnyParseNode[],
|
||||||
left: string,
|
left: string,
|
||||||
right: 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.
|
// Map from `type` field value to corresponding `value` type.
|
||||||
export type ParseNodeTypes = {
|
export type ParseNodeTypes = {
|
||||||
"array": ArrayEnvNodeData,
|
"array": ArrayEnvNodeData,
|
||||||
"color": {|
|
"color": {|
|
||||||
type: "color",
|
type: "color",
|
||||||
color: string,
|
color: string,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"color-token": string,
|
"color-token": string,
|
||||||
// To avoid requiring run-time type assertions, this more carefully captures
|
// To avoid requiring run-time type assertions, this more carefully captures
|
||||||
@@ -73,9 +139,9 @@ export type ParseNodeTypes = {
|
|||||||
suppressBaseShift?: boolean,
|
suppressBaseShift?: boolean,
|
||||||
symbol: false, // If 'symbol' is true, `body` *must* be set.
|
symbol: false, // If 'symbol' is true, `body` *must* be set.
|
||||||
body?: void,
|
body?: void,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"ordgroup": ParseNode<*>[],
|
"ordgroup": AnyParseNode[],
|
||||||
"size": {|
|
"size": {|
|
||||||
type: "size",
|
type: "size",
|
||||||
value: Measurement,
|
value: Measurement,
|
||||||
@@ -83,22 +149,22 @@ export type ParseNodeTypes = {
|
|||||||
"styling": {|
|
"styling": {|
|
||||||
type: "styling",
|
type: "styling",
|
||||||
style: StyleStr,
|
style: StyleStr,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"supsub": {|
|
"supsub": {|
|
||||||
type: "supsub",
|
type: "supsub",
|
||||||
base: ?ParseNode<*>,
|
base: ?AnyParseNode,
|
||||||
sup?: ?ParseNode<*>,
|
sup?: ?AnyParseNode,
|
||||||
sub?: ?ParseNode<*>,
|
sub?: ?AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"tag": {|
|
"tag": {|
|
||||||
type: "tag",
|
type: "tag",
|
||||||
body: ParseNode<*>[],
|
body: AnyParseNode[],
|
||||||
tag: ParseNode<*>[],
|
tag: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"text": {|
|
"text": {|
|
||||||
type: "text",
|
type: "text",
|
||||||
body: ParseNode<*>[],
|
body: AnyParseNode[],
|
||||||
font?: string,
|
font?: string,
|
||||||
|},
|
|},
|
||||||
"url": {|
|
"url": {|
|
||||||
@@ -131,14 +197,14 @@ export type ParseNodeTypes = {
|
|||||||
label: string,
|
label: string,
|
||||||
isStretchy?: boolean,
|
isStretchy?: boolean,
|
||||||
isShifty?: boolean,
|
isShifty?: boolean,
|
||||||
base: ParseNode<*>,
|
base: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"accentUnder": {|
|
"accentUnder": {|
|
||||||
type: "accentUnder",
|
type: "accentUnder",
|
||||||
label: string,
|
label: string,
|
||||||
isStretchy?: boolean,
|
isStretchy?: boolean,
|
||||||
isShifty?: boolean,
|
isShifty?: boolean,
|
||||||
base: ParseNode<*>,
|
base: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"cr": {|
|
"cr": {|
|
||||||
type: "cr",
|
type: "cr",
|
||||||
@@ -157,23 +223,23 @@ export type ParseNodeTypes = {
|
|||||||
label: string,
|
label: string,
|
||||||
backgroundColor?: ParseNode<"color-token">,
|
backgroundColor?: ParseNode<"color-token">,
|
||||||
borderColor?: ParseNode<"color-token">,
|
borderColor?: ParseNode<"color-token">,
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"environment": {|
|
"environment": {|
|
||||||
type: "environment",
|
type: "environment",
|
||||||
name: string,
|
name: string,
|
||||||
nameGroup: ParseNode<*>,
|
nameGroup: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"font": {|
|
"font": {|
|
||||||
type: "font",
|
type: "font",
|
||||||
font: string,
|
font: string,
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"genfrac": {|
|
"genfrac": {|
|
||||||
type: "genfrac",
|
type: "genfrac",
|
||||||
continued: boolean,
|
continued: boolean,
|
||||||
numer: ParseNode<*>,
|
numer: AnyParseNode,
|
||||||
denom: ParseNode<*>,
|
denom: AnyParseNode,
|
||||||
hasBarLine: boolean,
|
hasBarLine: boolean,
|
||||||
leftDelim: ?string,
|
leftDelim: ?string,
|
||||||
rightDelim: ?string,
|
rightDelim: ?string,
|
||||||
@@ -183,12 +249,12 @@ export type ParseNodeTypes = {
|
|||||||
type: "horizBrace",
|
type: "horizBrace",
|
||||||
label: string,
|
label: string,
|
||||||
isOver: boolean,
|
isOver: boolean,
|
||||||
base: ParseNode<*>,
|
base: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"href": {|
|
"href": {|
|
||||||
type: "href",
|
type: "href",
|
||||||
href: string,
|
href: string,
|
||||||
body: ParseNode<*>[],
|
body: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"infix": {|
|
"infix": {|
|
||||||
type: "infix",
|
type: "infix",
|
||||||
@@ -202,7 +268,7 @@ export type ParseNodeTypes = {
|
|||||||
"lap": {|
|
"lap": {|
|
||||||
type: "lap",
|
type: "lap",
|
||||||
alignment: string,
|
alignment: string,
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"leftright": LeftRightDelimType,
|
"leftright": LeftRightDelimType,
|
||||||
"leftright-right": {|
|
"leftright-right": {|
|
||||||
@@ -211,10 +277,10 @@ export type ParseNodeTypes = {
|
|||||||
|},
|
|},
|
||||||
"mathchoice": {|
|
"mathchoice": {|
|
||||||
type: "mathchoice",
|
type: "mathchoice",
|
||||||
display: ParseNode<*>[],
|
display: AnyParseNode[],
|
||||||
text: ParseNode<*>[],
|
text: AnyParseNode[],
|
||||||
script: ParseNode<*>[],
|
script: AnyParseNode[],
|
||||||
scriptscript: ParseNode<*>[],
|
scriptscript: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"middle": {|
|
"middle": {|
|
||||||
type: "middle",
|
type: "middle",
|
||||||
@@ -223,40 +289,40 @@ export type ParseNodeTypes = {
|
|||||||
"mclass": {|
|
"mclass": {|
|
||||||
type: "mclass",
|
type: "mclass",
|
||||||
mclass: string,
|
mclass: string,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"mod": {|
|
"mod": {|
|
||||||
type: "mod",
|
type: "mod",
|
||||||
modType: string,
|
modType: string,
|
||||||
value: ?ParseNode<*>[],
|
value: ?AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"operatorname": {|
|
"operatorname": {|
|
||||||
type: "operatorname",
|
type: "operatorname",
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"overline": {|
|
"overline": {|
|
||||||
type: "overline",
|
type: "overline",
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"phantom": {|
|
"phantom": {|
|
||||||
type: "phantom",
|
type: "phantom",
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"hphantom": {|
|
"hphantom": {|
|
||||||
type: "hphantom",
|
type: "hphantom",
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"vphantom": {|
|
"vphantom": {|
|
||||||
type: "vphantom",
|
type: "vphantom",
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"raisebox": {|
|
"raisebox": {|
|
||||||
type: "raisebox",
|
type: "raisebox",
|
||||||
dy: ParseNode<"size">,
|
dy: ParseNode<"size">,
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"rule": {|
|
"rule": {|
|
||||||
type: "rule",
|
type: "rule",
|
||||||
@@ -267,28 +333,28 @@ export type ParseNodeTypes = {
|
|||||||
"sizing": {|
|
"sizing": {|
|
||||||
type: "sizing",
|
type: "sizing",
|
||||||
size: number,
|
size: number,
|
||||||
value: ParseNode<*>[],
|
value: AnyParseNode[],
|
||||||
|},
|
|},
|
||||||
"smash": {|
|
"smash": {|
|
||||||
type: "smash",
|
type: "smash",
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
smashHeight: boolean,
|
smashHeight: boolean,
|
||||||
smashDepth: boolean,
|
smashDepth: boolean,
|
||||||
|},
|
|},
|
||||||
"sqrt": {|
|
"sqrt": {|
|
||||||
type: "sqrt",
|
type: "sqrt",
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
index: ?ParseNode<*>,
|
index: ?AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"underline": {|
|
"underline": {|
|
||||||
type: "underline",
|
type: "underline",
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
|},
|
|},
|
||||||
"xArrow": {|
|
"xArrow": {|
|
||||||
type: "xArrow",
|
type: "xArrow",
|
||||||
label: string,
|
label: string,
|
||||||
body: ParseNode<*>,
|
body: AnyParseNode,
|
||||||
below: ?ParseNode<*>,
|
below: ?AnyParseNode,
|
||||||
|},
|
|},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -297,8 +363,7 @@ export type ParseNodeTypes = {
|
|||||||
* typing. Throws if the node's type does not match.
|
* typing. Throws if the node's type does not match.
|
||||||
*/
|
*/
|
||||||
export function assertNodeType<NODETYPE: NodeType>(
|
export function assertNodeType<NODETYPE: NodeType>(
|
||||||
// The union allows either ParseNode<*> or the union of two specific nodes.
|
node: ?AnyParseNode,
|
||||||
node: ?ParseNode<*> | ParseNode<*>,
|
|
||||||
type: NODETYPE,
|
type: NODETYPE,
|
||||||
): ParseNode<NODETYPE> {
|
): ParseNode<NODETYPE> {
|
||||||
const typedNode = checkNodeType(node, type);
|
const typedNode = checkNodeType(node, type);
|
||||||
@@ -315,11 +380,38 @@ export function assertNodeType<NODETYPE: NodeType>(
|
|||||||
* returns null.
|
* returns null.
|
||||||
*/
|
*/
|
||||||
export function checkNodeType<NODETYPE: NodeType>(
|
export function checkNodeType<NODETYPE: NodeType>(
|
||||||
// The union allows either ParseNode<*> or the union of two specific nodes.
|
node: ?AnyParseNode,
|
||||||
node: ?ParseNode<*> | ParseNode<*>,
|
|
||||||
type: NODETYPE,
|
type: NODETYPE,
|
||||||
): ?ParseNode<NODETYPE> {
|
): ?ParseNode<NODETYPE> {
|
||||||
return node && node.type === type ?
|
if (node && node.type === type) {
|
||||||
(node: ParseNode<NODETYPE>) :
|
// $FlowFixMe: Inference not sophisticated enough to figure this out.
|
||||||
null;
|
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 {supportedCodepoint} from "./unicodeScripts";
|
||||||
import unicodeAccents from "./unicodeAccents";
|
import unicodeAccents from "./unicodeAccents";
|
||||||
import unicodeSymbols from "./unicodeSymbols";
|
import unicodeSymbols from "./unicodeSymbols";
|
||||||
import ParseNode, {assertNodeType} from "./ParseNode";
|
import ParseNode, {assertNodeType, checkNodeType} from "./ParseNode";
|
||||||
import ParseError from "./ParseError";
|
import ParseError from "./ParseError";
|
||||||
import {combiningDiacriticalMarksEndRegex} from "./Lexer.js";
|
import {combiningDiacriticalMarksEndRegex} from "./Lexer.js";
|
||||||
import Settings from "./Settings";
|
import Settings from "./Settings";
|
||||||
import {Token} from "./Token";
|
import {Token} from "./Token";
|
||||||
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
import type {Mode, ArgType, BreakToken} from "./types";
|
import type {Mode, ArgType, BreakToken} from "./types";
|
||||||
import type {FunctionContext, FunctionSpec} from "./defineFunction";
|
import type {FunctionContext, FunctionSpec} from "./defineFunction";
|
||||||
import type {EnvSpec} from "./defineEnvironment";
|
import type {EnvSpec} from "./defineEnvironment";
|
||||||
@@ -60,12 +60,12 @@ type ParsedFunc = {|
|
|||||||
|};
|
|};
|
||||||
type ParsedArg = {|
|
type ParsedArg = {|
|
||||||
type: "arg",
|
type: "arg",
|
||||||
result: ParseNode<*>,
|
result: AnyParseNode,
|
||||||
token: Token,
|
token: Token,
|
||||||
|};
|
|};
|
||||||
type ParsedFuncOrArg = ParsedFunc | ParsedArg;
|
type ParsedFuncOrArg = ParsedFunc | ParsedArg;
|
||||||
|
|
||||||
function newArgument(result: ParseNode<*>, token: Token): ParsedArg {
|
function newArgument(result: AnyParseNode, token: Token): ParsedArg {
|
||||||
return {type: "arg", result, token};
|
return {type: "arg", result, token};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ export default class Parser {
|
|||||||
/**
|
/**
|
||||||
* Main parsing function, which parses an entire input.
|
* Main parsing function, which parses an entire input.
|
||||||
*/
|
*/
|
||||||
parse(): ParseNode<*>[] {
|
parse(): AnyParseNode[] {
|
||||||
// Create a group namespace for the math expression.
|
// Create a group namespace for the math expression.
|
||||||
// (LaTeX creates a new group for every $...$, $$...$$, \[...\].)
|
// (LaTeX creates a new group for every $...$, $$...$$, \[...\].)
|
||||||
this.gullet.beginGroup();
|
this.gullet.beginGroup();
|
||||||
@@ -167,7 +167,7 @@ export default class Parser {
|
|||||||
parseExpression(
|
parseExpression(
|
||||||
breakOnInfix: boolean,
|
breakOnInfix: boolean,
|
||||||
breakOnTokenText?: BreakToken,
|
breakOnTokenText?: BreakToken,
|
||||||
): ParseNode<*>[] {
|
): AnyParseNode[] {
|
||||||
const body = [];
|
const body = [];
|
||||||
// Keep adding atoms to the body until we can't parse any more atoms (either
|
// Keep adding atoms to the body until we can't parse any more atoms (either
|
||||||
// we reached the end, a }, or a \right)
|
// 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
|
* 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 {}.
|
* then the expression is ambiguous. This can be resolved by adding {}.
|
||||||
*/
|
*/
|
||||||
handleInfixNodes(body: ParseNode<*>[]): ParseNode<*>[] {
|
handleInfixNodes(body: AnyParseNode[]): AnyParseNode[] {
|
||||||
let overIndex = -1;
|
let overIndex = -1;
|
||||||
let funcName;
|
let funcName;
|
||||||
|
|
||||||
for (let i = 0; i < body.length; i++) {
|
for (let i = 0; i < body.length; i++) {
|
||||||
const node = body[i];
|
const node = checkNodeType(body[i], "infix");
|
||||||
if (node.type === "infix") {
|
if (node) {
|
||||||
if (overIndex !== -1) {
|
if (overIndex !== -1) {
|
||||||
throw new ParseError(
|
throw new ParseError(
|
||||||
"only one infix operator per group",
|
"only one infix operator per group",
|
||||||
@@ -259,7 +259,7 @@ export default class Parser {
|
|||||||
*/
|
*/
|
||||||
handleSupSubscript(
|
handleSupSubscript(
|
||||||
name: string, // For error reporting.
|
name: string, // For error reporting.
|
||||||
): ParseNode<*> {
|
): AnyParseNode {
|
||||||
const symbolToken = this.nextToken;
|
const symbolToken = this.nextToken;
|
||||||
const symbol = symbolToken.text;
|
const symbol = symbolToken.text;
|
||||||
this.consume();
|
this.consume();
|
||||||
@@ -297,7 +297,7 @@ export default class Parser {
|
|||||||
* Converts the textual input of an unsupported command into a text node
|
* Converts the textual input of an unsupported command into a text node
|
||||||
* contained within a color node whose color is determined by errorColor
|
* contained within a color node whose color is determined by errorColor
|
||||||
*/
|
*/
|
||||||
handleUnsupportedCmd(): ParseNode<*> {
|
handleUnsupportedCmd(): AnyParseNode {
|
||||||
const text = this.nextToken.text;
|
const text = this.nextToken.text;
|
||||||
const textordArray = [];
|
const textordArray = [];
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ export default class Parser {
|
|||||||
/**
|
/**
|
||||||
* Parses a group with optional super/subscripts.
|
* 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
|
// The body of an atom is an implicit group, so that things like
|
||||||
// \left(x\right)^2 work correctly.
|
// \left(x\right)^2 work correctly.
|
||||||
const base = this.parseImplicitGroup(breakOnTokenText);
|
const base = this.parseImplicitGroup(breakOnTokenText);
|
||||||
@@ -352,14 +352,15 @@ export default class Parser {
|
|||||||
|
|
||||||
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
|
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
|
||||||
// We got a limit control
|
// 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(
|
throw new ParseError(
|
||||||
"Limit controls must follow a math operator",
|
"Limit controls must follow a math operator",
|
||||||
lex);
|
lex);
|
||||||
} else {
|
|
||||||
const limits = lex.text === "\\limits";
|
|
||||||
base.value.limits = limits;
|
|
||||||
base.value.alwaysHandleSupSub = true;
|
|
||||||
}
|
}
|
||||||
this.consume();
|
this.consume();
|
||||||
} else if (lex.text === "^") {
|
} else if (lex.text === "^") {
|
||||||
@@ -427,7 +428,7 @@ export default class Parser {
|
|||||||
* implicit grouping after it until the end of the group. E.g.
|
* implicit grouping after it until the end of the group. E.g.
|
||||||
* small text {\Large large text} small text again
|
* small text {\Large large text} small text again
|
||||||
*/
|
*/
|
||||||
parseImplicitGroup(breakOnTokenText?: BreakToken): ?ParseNode<*> {
|
parseImplicitGroup(breakOnTokenText?: BreakToken): ?AnyParseNode {
|
||||||
const start = this.parseSymbol();
|
const start = this.parseSymbol();
|
||||||
|
|
||||||
if (start == null) {
|
if (start == null) {
|
||||||
@@ -463,10 +464,12 @@ export default class Parser {
|
|||||||
const result = env.handler(context, args, optArgs);
|
const result = env.handler(context, args, optArgs);
|
||||||
this.expect("\\end", false);
|
this.expect("\\end", false);
|
||||||
const endNameToken = this.nextToken;
|
const endNameToken = this.nextToken;
|
||||||
const end = assertNodeType(this.parseFunction(), "environment");
|
let end = this.parseFunction();
|
||||||
if (!end) {
|
if (!end) {
|
||||||
throw new ParseError("failed to parse function after \\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(
|
throw new ParseError(
|
||||||
"Mismatch: \\begin{" + envName + "} matched " +
|
"Mismatch: \\begin{" + envName + "} matched " +
|
||||||
"by \\end{" + end.value.name + "}",
|
"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.
|
* 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.
|
* It also handles the case where the parsed node is not a function.
|
||||||
*/
|
*/
|
||||||
parseFunction(): ?ParseNode<*> {
|
parseFunction(): ?AnyParseNode {
|
||||||
const baseGroup = this.parseGroup();
|
const baseGroup = this.parseGroup();
|
||||||
return baseGroup ? this.parseGivenFunction(baseGroup) : null;
|
return baseGroup ? this.parseGivenFunction(baseGroup) : null;
|
||||||
}
|
}
|
||||||
@@ -495,7 +498,7 @@ export default class Parser {
|
|||||||
parseGivenFunction(
|
parseGivenFunction(
|
||||||
baseGroup: ParsedFuncOrArg,
|
baseGroup: ParsedFuncOrArg,
|
||||||
breakOnTokenText?: BreakToken,
|
breakOnTokenText?: BreakToken,
|
||||||
): ParseNode<*> {
|
): AnyParseNode {
|
||||||
if (baseGroup.type === "fn") {
|
if (baseGroup.type === "fn") {
|
||||||
const func = baseGroup.result;
|
const func = baseGroup.result;
|
||||||
const funcData = functions[func];
|
const funcData = functions[func];
|
||||||
@@ -535,11 +538,11 @@ export default class Parser {
|
|||||||
*/
|
*/
|
||||||
callFunction(
|
callFunction(
|
||||||
name: string,
|
name: string,
|
||||||
args: ParseNode<*>[],
|
args: AnyParseNode[],
|
||||||
optArgs: (?ParseNode<*>)[],
|
optArgs: (?AnyParseNode)[],
|
||||||
token?: Token,
|
token?: Token,
|
||||||
breakOnTokenText?: BreakToken,
|
breakOnTokenText?: BreakToken,
|
||||||
): ParseNode<*> {
|
): AnyParseNode {
|
||||||
const context: FunctionContext = {
|
const context: FunctionContext = {
|
||||||
funcName: name,
|
funcName: name,
|
||||||
parser: this,
|
parser: this,
|
||||||
@@ -561,8 +564,8 @@ export default class Parser {
|
|||||||
func: string, // Should look like "\name" or "\begin{name}".
|
func: string, // Should look like "\name" or "\begin{name}".
|
||||||
funcData: FunctionSpec<*> | EnvSpec<*>,
|
funcData: FunctionSpec<*> | EnvSpec<*>,
|
||||||
): {
|
): {
|
||||||
args: ParseNode<*>[],
|
args: AnyParseNode[],
|
||||||
optArgs: (?ParseNode<*>)[],
|
optArgs: (?AnyParseNode)[],
|
||||||
} {
|
} {
|
||||||
const totalArgs = funcData.numArgs + funcData.numOptionalArgs;
|
const totalArgs = funcData.numArgs + funcData.numOptionalArgs;
|
||||||
if (totalArgs === 0) {
|
if (totalArgs === 0) {
|
||||||
@@ -609,7 +612,7 @@ export default class Parser {
|
|||||||
"Expected group after '" + func + "'", nextToken);
|
"Expected group after '" + func + "'", nextToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let argNode: ParseNode<*>;
|
let argNode: AnyParseNode;
|
||||||
if (arg.type === "fn") {
|
if (arg.type === "fn") {
|
||||||
const argGreediness =
|
const argGreediness =
|
||||||
functions[arg.result].greediness;
|
functions[arg.result].greediness;
|
||||||
@@ -895,7 +898,7 @@ export default class Parser {
|
|||||||
* characters in its value. The representation is still ASCII source.
|
* characters in its value. The representation is still ASCII source.
|
||||||
* The group will be modified in place.
|
* The group will be modified in place.
|
||||||
*/
|
*/
|
||||||
formLigatures(group: ParseNode<*>[]) {
|
formLigatures(group: AnyParseNode[]) {
|
||||||
let n = group.length - 1;
|
let n = group.length - 1;
|
||||||
for (let i = 0; i < n; ++i) {
|
for (let i = 0; i < n; ++i) {
|
||||||
const a = group[i];
|
const a = group[i];
|
||||||
|
@@ -7,13 +7,13 @@
|
|||||||
|
|
||||||
import utils from "./utils";
|
import utils from "./utils";
|
||||||
import ParseError from "./ParseError.js";
|
import ParseError from "./ParseError.js";
|
||||||
import ParseNode from "./ParseNode";
|
|
||||||
import {Token} from "./Token";
|
import {Token} from "./Token";
|
||||||
|
|
||||||
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
import type {MacroMap} from "./macros";
|
import type {MacroMap} from "./macros";
|
||||||
|
|
||||||
export type StrictFunction =
|
export type StrictFunction =
|
||||||
(errorCode: string, errorMsg: string, token?: Token | ParseNode<*>) =>
|
(errorCode: string, errorMsg: string, token?: Token | AnyParseNode) =>
|
||||||
?(boolean | string);
|
?(boolean | string);
|
||||||
|
|
||||||
export type SettingsOptions = {
|
export type SettingsOptions = {
|
||||||
@@ -65,7 +65,7 @@ class Settings {
|
|||||||
* Can safely not be called if `this.strict` is false in JavaScript.
|
* Can safely not be called if `this.strict` is false in JavaScript.
|
||||||
*/
|
*/
|
||||||
reportNonstrict(errorCode: string, errorMsg: string,
|
reportNonstrict(errorCode: string, errorMsg: string,
|
||||||
token?: Token | ParseNode<*>) {
|
token?: Token | AnyParseNode) {
|
||||||
let strict = this.strict;
|
let strict = this.strict;
|
||||||
if (typeof strict === "function") {
|
if (typeof strict === "function") {
|
||||||
// Allow return value of strict function to be boolean or string
|
// 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.
|
* This is for the second category of `errorCode`s listed in the README.
|
||||||
*/
|
*/
|
||||||
useStrictBehavior(errorCode: string, errorMsg: string,
|
useStrictBehavior(errorCode: string, errorMsg: string,
|
||||||
token?: Token | ParseNode<*>) {
|
token?: Token | AnyParseNode) {
|
||||||
let strict = this.strict;
|
let strict = this.strict;
|
||||||
if (typeof strict === "function") {
|
if (typeof strict === "function") {
|
||||||
// Allow return value of strict function to be boolean or string
|
// Allow return value of strict function to be boolean or string
|
||||||
|
@@ -6,7 +6,7 @@ import Options from "./Options";
|
|||||||
import Settings from "./Settings";
|
import Settings from "./Settings";
|
||||||
import Style from "./Style";
|
import Style from "./Style";
|
||||||
|
|
||||||
import type ParseNode from "./ParseNode";
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
import type {DomSpan} from "./domTree";
|
import type {DomSpan} from "./domTree";
|
||||||
|
|
||||||
const optionsFromSettings = function(settings: Settings) {
|
const optionsFromSettings = function(settings: Settings) {
|
||||||
@@ -17,7 +17,7 @@ const optionsFromSettings = function(settings: Settings) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const buildTree = function(
|
export const buildTree = function(
|
||||||
tree: ParseNode<*>[],
|
tree: AnyParseNode[],
|
||||||
expression: string,
|
expression: string,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
): DomSpan {
|
): DomSpan {
|
||||||
@@ -39,7 +39,7 @@ export const buildTree = function(
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const buildHTMLTree = function(
|
export const buildHTMLTree = function(
|
||||||
tree: ParseNode<*>[],
|
tree: AnyParseNode[],
|
||||||
expression: string,
|
expression: string,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
): DomSpan {
|
): DomSpan {
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import {_htmlGroupBuilders, _mathmlGroupBuilders} from "./defineFunction";
|
import {_htmlGroupBuilders, _mathmlGroupBuilders} from "./defineFunction";
|
||||||
|
|
||||||
import Options from "./Options";
|
|
||||||
import ParseNode from "./ParseNode";
|
import ParseNode from "./ParseNode";
|
||||||
|
|
||||||
import type Parser from "./Parser";
|
import type Parser from "./Parser";
|
||||||
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
import type {ArgType, Mode} from "./types";
|
import type {ArgType, Mode} from "./types";
|
||||||
import type {HtmlDomNode} from "./domTree";
|
|
||||||
import type {NodeType} from "./ParseNode";
|
import type {NodeType} from "./ParseNode";
|
||||||
import type {MathNode} from "./mathMLTree";
|
import type {HtmlBuilder, MathMLBuilder} from "./defineFunction";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The context contains the following properties:
|
* The context contains the following properties:
|
||||||
@@ -29,8 +28,8 @@ type EnvContext = {|
|
|||||||
*/
|
*/
|
||||||
type EnvHandler<NODETYPE: NodeType> = (
|
type EnvHandler<NODETYPE: NodeType> = (
|
||||||
context: EnvContext,
|
context: EnvContext,
|
||||||
args: ParseNode<*>[],
|
args: AnyParseNode[],
|
||||||
optArgs: (?ParseNode<*>)[],
|
optArgs: (?AnyParseNode)[],
|
||||||
) => ParseNode<NODETYPE>;
|
) => ParseNode<NODETYPE>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,11 +84,11 @@ type EnvDefSpec<NODETYPE: NodeType> = {|
|
|||||||
|
|
||||||
// This function returns an object representing the DOM structure to be
|
// This function returns an object representing the DOM structure to be
|
||||||
// created when rendering the defined LaTeX function.
|
// 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
|
// This function returns an object representing the MathML structure to be
|
||||||
// created when rendering the defined LaTeX function.
|
// created when rendering the defined LaTeX function.
|
||||||
mathmlBuilder: (group: ParseNode<NODETYPE>, options: Options) => MathNode,
|
mathmlBuilder: MathMLBuilder<NODETYPE>,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export default function defineEnvironment<NODETYPE: NodeType>({
|
export default function defineEnvironment<NODETYPE: NodeType>({
|
||||||
|
@@ -3,7 +3,7 @@ import {checkNodeType} from "./ParseNode";
|
|||||||
import domTree from "./domTree";
|
import domTree from "./domTree";
|
||||||
|
|
||||||
import type Parser from "./Parser";
|
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 Options from "./Options";
|
||||||
import type {ArgType, BreakToken, Mode} from "./types";
|
import type {ArgType, BreakToken, Mode} from "./types";
|
||||||
import type {HtmlDomNode} from "./domTree";
|
import type {HtmlDomNode} from "./domTree";
|
||||||
@@ -20,8 +20,8 @@ export type FunctionContext = {|
|
|||||||
|
|
||||||
export type FunctionHandler<NODETYPE: NodeType> = (
|
export type FunctionHandler<NODETYPE: NodeType> = (
|
||||||
context: FunctionContext,
|
context: FunctionContext,
|
||||||
args: ParseNode<*>[],
|
args: AnyParseNode[],
|
||||||
optArgs: (?ParseNode<*>)[],
|
optArgs: (?AnyParseNode)[],
|
||||||
) => ParseNode<NODETYPE>;
|
) => ParseNode<NODETYPE>;
|
||||||
|
|
||||||
export type HtmlBuilder<NODETYPE> = (ParseNode<NODETYPE>, Options) => HtmlDomNode;
|
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
|
// Since the corresponding buildHTML/buildMathML function expects a
|
||||||
// list of elements, we normalize for different kinds of arguments
|
// 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");
|
const node = checkNodeType(arg, "ordgroup");
|
||||||
return node ? node.value : [arg];
|
return node ? node.value : [arg];
|
||||||
};
|
};
|
||||||
|
@@ -4,7 +4,8 @@ import defineEnvironment from "../defineEnvironment";
|
|||||||
import mathMLTree from "../mathMLTree";
|
import mathMLTree from "../mathMLTree";
|
||||||
import ParseError from "../ParseError";
|
import ParseError from "../ParseError";
|
||||||
import ParseNode from "../ParseNode";
|
import ParseNode from "../ParseNode";
|
||||||
import {assertNodeType} from "../ParseNode";
|
import {assertNodeType, assertSymbolNodeType} from "../ParseNode";
|
||||||
|
import {checkNodeType, checkSymbolNodeType} from "../ParseNode";
|
||||||
import {calculateSize} from "../units";
|
import {calculateSize} from "../units";
|
||||||
import utils from "../utils";
|
import utils from "../utils";
|
||||||
|
|
||||||
@@ -12,7 +13,9 @@ import * as html from "../buildHTML";
|
|||||||
import * as mml from "../buildMathML";
|
import * as mml from "../buildMathML";
|
||||||
|
|
||||||
import type Parser from "../Parser";
|
import type Parser from "../Parser";
|
||||||
|
import type {AnyParseNode} from "../ParseNode";
|
||||||
import type {StyleStr} from "../types";
|
import type {StyleStr} from "../types";
|
||||||
|
import type {HtmlBuilder, MathMLBuilder} from "../defineFunction";
|
||||||
|
|
||||||
// Data stored in the ParseNode associated with the environment.
|
// Data stored in the ParseNode associated with the environment.
|
||||||
type AlignSpec = { type: "separator", separator: string } | {
|
type AlignSpec = { type: "separator", separator: string } | {
|
||||||
@@ -28,8 +31,8 @@ export type ArrayEnvNodeData = {|
|
|||||||
arraystretch: number,
|
arraystretch: number,
|
||||||
addJot?: boolean,
|
addJot?: boolean,
|
||||||
cols?: AlignSpec[],
|
cols?: AlignSpec[],
|
||||||
body: ParseNode<*>[][], // List of rows in the (2D) array.
|
body: AnyParseNode[][], // List of rows in the (2D) array.
|
||||||
rowGaps: (?ParseNode<*>)[],
|
rowGaps: (?ParseNode<"size">)[],
|
||||||
numHLinesBeforeRow: number[],
|
numHLinesBeforeRow: number[],
|
||||||
|};
|
|};
|
||||||
// Same as above but with some fields not yet filled.
|
// Same as above but with some fields not yet filled.
|
||||||
@@ -40,8 +43,8 @@ type ArrayEnvNodeDataIncomplete = {|
|
|||||||
addJot?: boolean,
|
addJot?: boolean,
|
||||||
cols?: AlignSpec[],
|
cols?: AlignSpec[],
|
||||||
// Before these fields are filled.
|
// Before these fields are filled.
|
||||||
body?: ParseNode<*>[][],
|
body?: AnyParseNode[][],
|
||||||
rowGaps?: (?ParseNode<*>)[],
|
rowGaps?: (?ParseNode<"size">)[],
|
||||||
numHLinesBeforeRow?: number[],
|
numHLinesBeforeRow?: number[],
|
||||||
|};
|
|};
|
||||||
|
|
||||||
@@ -110,10 +113,8 @@ function parseArray(
|
|||||||
} else if (next === "\\end") {
|
} else if (next === "\\end") {
|
||||||
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
||||||
// the last line is empty.
|
// the last line is empty.
|
||||||
const lastRow = body[body.length - 1];
|
// NOTE: Currently, `cell` is the last item added into `row`.
|
||||||
if (body.length > 1
|
if (row.length === 1 && cell.value.value[0].value.length === 0) {
|
||||||
&& lastRow.length === 1
|
|
||||||
&& lastRow[0].value.value[0].value.length === 0) {
|
|
||||||
body.pop();
|
body.pop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -161,8 +162,7 @@ type Outrow = {
|
|||||||
pos: number,
|
pos: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
const htmlBuilder = function(group, options) {
|
const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
||||||
const groupValue = assertNodeType(group, "array").value;
|
|
||||||
let r;
|
let r;
|
||||||
let c;
|
let c;
|
||||||
const nr = group.value.body.length;
|
const nr = group.value.body.length;
|
||||||
@@ -180,7 +180,7 @@ const htmlBuilder = function(group, options) {
|
|||||||
// Default \jot from ltmath.dtx
|
// Default \jot from ltmath.dtx
|
||||||
// TODO(edemaine): allow overriding \jot via \setlength (#687)
|
// TODO(edemaine): allow overriding \jot via \setlength (#687)
|
||||||
const jot = 3 * pt;
|
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 arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
|
||||||
const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
|
const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
|
||||||
|
|
||||||
@@ -194,8 +194,8 @@ const htmlBuilder = function(group, options) {
|
|||||||
hlinePos.push(totalHeight);
|
hlinePos.push(totalHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (r = 0; r < groupValue.body.length; ++r) {
|
for (r = 0; r < group.value.body.length; ++r) {
|
||||||
const inrow = groupValue.body[r];
|
const inrow = group.value.body[r];
|
||||||
let height = arstrutHeight; // \@array adds an \@arstrut
|
let height = arstrutHeight; // \@array adds an \@arstrut
|
||||||
let depth = arstrutDepth; // to each tow (via the template)
|
let depth = arstrutDepth; // to each tow (via the template)
|
||||||
|
|
||||||
@@ -215,7 +215,7 @@ const htmlBuilder = function(group, options) {
|
|||||||
outrow[c] = elt;
|
outrow[c] = elt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowGap = groupValue.rowGaps[r];
|
const rowGap = group.value.rowGaps[r];
|
||||||
let gap = 0;
|
let gap = 0;
|
||||||
if (rowGap) {
|
if (rowGap) {
|
||||||
gap = calculateSize(rowGap.value.value, options);
|
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
|
// In AMS multiline environments such as aligned and gathered, rows
|
||||||
// correspond to lines that have additional \jot added to the
|
// correspond to lines that have additional \jot added to the
|
||||||
// \baselineskip via \openup.
|
// \baselineskip via \openup.
|
||||||
if (groupValue.addJot) {
|
if (group.value.addJot) {
|
||||||
depth += jot;
|
depth += jot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ const htmlBuilder = function(group, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const offset = totalHeight / 2 + options.fontMetrics().axisHeight;
|
const offset = totalHeight / 2 + options.fontMetrics().axisHeight;
|
||||||
const colDescriptions = groupValue.cols || [];
|
const colDescriptions = group.value.cols || [];
|
||||||
const cols = [];
|
const cols = [];
|
||||||
let colSep;
|
let colSep;
|
||||||
let colDescrNum;
|
let colDescrNum;
|
||||||
@@ -307,7 +307,7 @@ const htmlBuilder = function(group, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let sepwidth;
|
let sepwidth;
|
||||||
if (c > 0 || groupValue.hskipBeforeAndAfter) {
|
if (c > 0 || group.value.hskipBeforeAndAfter) {
|
||||||
sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
|
sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
|
||||||
if (sepwidth !== 0) {
|
if (sepwidth !== 0) {
|
||||||
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
||||||
@@ -338,7 +338,7 @@ const htmlBuilder = function(group, options) {
|
|||||||
[col]);
|
[col]);
|
||||||
cols.push(col);
|
cols.push(col);
|
||||||
|
|
||||||
if (c < nc - 1 || groupValue.hskipBeforeAndAfter) {
|
if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
|
||||||
sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
|
sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
|
||||||
if (sepwidth !== 0) {
|
if (sepwidth !== 0) {
|
||||||
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
||||||
@@ -366,10 +366,9 @@ const htmlBuilder = function(group, options) {
|
|||||||
return buildCommon.makeSpan(["mord"], [body], options);
|
return buildCommon.makeSpan(["mord"], [body], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mathmlBuilder = function(group, options) {
|
const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
||||||
const groupValue = assertNodeType(group, "array").value;
|
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtable", groupValue.body.map(function(row) {
|
"mtable", group.value.body.map(function(row) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtr", row.map(function(cell) {
|
"mtr", row.map(function(cell) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
@@ -400,10 +399,12 @@ const alignedHandler = function(context, args) {
|
|||||||
let numMaths;
|
let numMaths;
|
||||||
let numCols = 0;
|
let numCols = 0;
|
||||||
const emptyGroup = new ParseNode("ordgroup", [], context.mode);
|
const emptyGroup = new ParseNode("ordgroup", [], context.mode);
|
||||||
if (args[0] && args[0].value) {
|
const ordgroup = checkNodeType(args[0], "ordgroup");
|
||||||
|
if (ordgroup) {
|
||||||
let arg0 = "";
|
let arg0 = "";
|
||||||
for (let i = 0; i < args[0].value.length; i++) {
|
for (let i = 0; i < ordgroup.value.length; i++) {
|
||||||
arg0 += args[0].value[i].value;
|
const textord = assertNodeType(ordgroup.value[i], "textord");
|
||||||
|
arg0 += textord.value;
|
||||||
}
|
}
|
||||||
numMaths = Number(arg0);
|
numMaths = Number(arg0);
|
||||||
numCols = numMaths * 2;
|
numCols = numMaths * 2;
|
||||||
@@ -412,7 +413,8 @@ const alignedHandler = function(context, args) {
|
|||||||
res.value.body.forEach(function(row) {
|
res.value.body.forEach(function(row) {
|
||||||
for (let i = 1; i < row.length; i += 2) {
|
for (let i = 1; i < row.length; i += 2) {
|
||||||
// Modify ordgroup node within styling node
|
// 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);
|
ordgroup.value.unshift(emptyGroup);
|
||||||
}
|
}
|
||||||
if (!isAligned) { // Case 1
|
if (!isAligned) { // Case 1
|
||||||
@@ -459,10 +461,16 @@ defineEnvironment({
|
|||||||
props: {
|
props: {
|
||||||
numArgs: 1,
|
numArgs: 1,
|
||||||
},
|
},
|
||||||
handler: function(context, args) {
|
handler(context, args) {
|
||||||
let colalign = args[0];
|
// Since no types are specified above, the two possibilities are
|
||||||
colalign = colalign.value.map ? colalign.value : [colalign];
|
// - The argument is wrapped in {} or [], in which case Parser's
|
||||||
const cols = colalign.map(function(node) {
|
// 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;
|
const ca = node.value;
|
||||||
if ("lcr".indexOf(ca) !== -1) {
|
if ("lcr".indexOf(ca) !== -1) {
|
||||||
return {
|
return {
|
||||||
@@ -480,9 +488,7 @@ defineEnvironment({
|
|||||||
separator: ":",
|
separator: ":",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
throw new ParseError(
|
throw new ParseError("Unknown column alignment: " + ca, nde);
|
||||||
"Unknown column alignment: " + node.value,
|
|
||||||
node);
|
|
||||||
});
|
});
|
||||||
let res = {
|
let res = {
|
||||||
type: "array",
|
type: "array",
|
||||||
|
@@ -9,13 +9,14 @@ import ParseNode, {assertNodeType, checkNodeType} from "../ParseNode";
|
|||||||
import * as html from "../buildHTML";
|
import * as html from "../buildHTML";
|
||||||
import * as mml from "../buildMathML";
|
import * as mml from "../buildMathML";
|
||||||
|
|
||||||
|
import type {AnyParseNode} from "../ParseNode";
|
||||||
import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
||||||
|
|
||||||
// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but
|
// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but
|
||||||
// also "supsub" since an accent can affect super/subscripting.
|
// also "supsub" since an accent can affect super/subscripting.
|
||||||
export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
||||||
// Accents are handled in the TeXbook pg. 443, rule 12.
|
// Accents are handled in the TeXbook pg. 443, rule 12.
|
||||||
let base: ParseNode<*>;
|
let base: AnyParseNode;
|
||||||
let group: ParseNode<"accent">;
|
let group: ParseNode<"accent">;
|
||||||
|
|
||||||
const supSub = checkNodeType(grp, "supsub");
|
const supSub = checkNodeType(grp, "supsub");
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
import defineFunction, {ordargument} from "../defineFunction";
|
import defineFunction, {ordargument} from "../defineFunction";
|
||||||
import buildCommon from "../buildCommon";
|
import buildCommon from "../buildCommon";
|
||||||
import mathMLTree from "../mathMLTree";
|
import mathMLTree from "../mathMLTree";
|
||||||
import ParseError from "../ParseError";
|
|
||||||
import ParseNode, {assertNodeType} from "../ParseNode";
|
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||||
|
|
||||||
import * as html from "../buildHTML";
|
import * as html from "../buildHTML";
|
||||||
@@ -99,10 +98,7 @@ defineFunction({
|
|||||||
argTypes: ["color"],
|
argTypes: ["color"],
|
||||||
},
|
},
|
||||||
handler({parser, breakOnTokenText}, args) {
|
handler({parser, breakOnTokenText}, args) {
|
||||||
const color = args[0];
|
const color = assertNodeType(args[0], "color-token");
|
||||||
if (!color) {
|
|
||||||
throw new ParseError("\\color not followed by color");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we see a styling function, parse out the implicit body
|
// If we see a styling function, parse out the implicit body
|
||||||
const body = parser.parseExpression(true, breakOnTokenText);
|
const body = parser.parseExpression(true, breakOnTokenText);
|
||||||
|
@@ -5,11 +5,12 @@ import delimiter from "../delimiter";
|
|||||||
import mathMLTree from "../mathMLTree";
|
import mathMLTree from "../mathMLTree";
|
||||||
import ParseError from "../ParseError";
|
import ParseError from "../ParseError";
|
||||||
import utils from "../utils";
|
import utils from "../utils";
|
||||||
import ParseNode, {assertNodeType} from "../ParseNode";
|
import ParseNode, {assertNodeType, checkSymbolNodeType} from "../ParseNode";
|
||||||
|
|
||||||
import * as html from "../buildHTML";
|
import * as html from "../buildHTML";
|
||||||
import * as mml from "../buildMathML";
|
import * as mml from "../buildMathML";
|
||||||
|
|
||||||
|
import type {AnyParseNode, SymbolParseNode} from "../ParseNode";
|
||||||
import type {LeftRightDelimType} from "../ParseNode";
|
import type {LeftRightDelimType} from "../ParseNode";
|
||||||
import type {FunctionContext} from "../defineFunction";
|
import type {FunctionContext} from "../defineFunction";
|
||||||
|
|
||||||
@@ -52,14 +53,15 @@ const delimiters = [
|
|||||||
|
|
||||||
// Delimiter functions
|
// Delimiter functions
|
||||||
function checkDelimiter(
|
function checkDelimiter(
|
||||||
delim: ParseNode<*>,
|
delim: AnyParseNode,
|
||||||
context: FunctionContext,
|
context: FunctionContext,
|
||||||
): ParseNode<*> {
|
): SymbolParseNode {
|
||||||
if (utils.contains(delimiters, delim.value)) {
|
const symDelim = checkSymbolNodeType(delim);
|
||||||
return delim;
|
if (symDelim && utils.contains(delimiters, symDelim.value)) {
|
||||||
|
return symDelim;
|
||||||
} else {
|
} else {
|
||||||
throw new ParseError(
|
throw new ParseError(
|
||||||
"Invalid delimiter: '" + delim.value + "' after '" +
|
"Invalid delimiter: '" + String(delim.value) + "' after '" +
|
||||||
context.funcName + "'", delim);
|
context.funcName + "'", delim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import defineFunction from "../defineFunction";
|
import defineFunction from "../defineFunction";
|
||||||
import ParseError from "../ParseError";
|
import ParseError from "../ParseError";
|
||||||
import ParseNode from "../ParseNode";
|
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||||
|
|
||||||
// Environment delimiters. HTML/MathML rendering is defined in the corresponding
|
// Environment delimiters. HTML/MathML rendering is defined in the corresponding
|
||||||
// defineEnvironment definitions.
|
// defineEnvironment definitions.
|
||||||
@@ -19,7 +19,7 @@ defineFunction({
|
|||||||
}
|
}
|
||||||
let name = "";
|
let name = "";
|
||||||
for (let i = 0; i < nameGroup.value.length; ++i) {
|
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", {
|
return new ParseNode("environment", {
|
||||||
type: "environment",
|
type: "environment",
|
||||||
|
@@ -19,7 +19,7 @@ defineFunction({
|
|||||||
const height = assertNodeType(args[1], "size");
|
const height = assertNodeType(args[1], "size");
|
||||||
return new ParseNode("rule", {
|
return new ParseNode("rule", {
|
||||||
type: "rule",
|
type: "rule",
|
||||||
shift: shift && shift.value,
|
shift: shift && assertNodeType(shift, "size").value.value,
|
||||||
width: width.value.value,
|
width: width.value.value,
|
||||||
height: height.value.value,
|
height: height.value.value,
|
||||||
}, parser.mode);
|
}, parser.mode);
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
import defineFunction from "../defineFunction";
|
import defineFunction from "../defineFunction";
|
||||||
import buildCommon from "../buildCommon";
|
import buildCommon from "../buildCommon";
|
||||||
import mathMLTree from "../mathMLTree";
|
import mathMLTree from "../mathMLTree";
|
||||||
import ParseNode from "../ParseNode";
|
import ParseNode, {assertNodeType} from "../ParseNode";
|
||||||
|
|
||||||
import * as html from "../buildHTML";
|
import * as html from "../buildHTML";
|
||||||
import * as mml from "../buildMathML";
|
import * as mml from "../buildMathML";
|
||||||
@@ -19,7 +19,7 @@ defineFunction({
|
|||||||
handler: ({parser}, args, optArgs) => {
|
handler: ({parser}, args, optArgs) => {
|
||||||
let smashHeight = false;
|
let smashHeight = false;
|
||||||
let smashDepth = false;
|
let smashDepth = false;
|
||||||
const tbArg = optArgs[0];
|
const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup");
|
||||||
if (tbArg) {
|
if (tbArg) {
|
||||||
// Optional [tb] argument is engaged.
|
// Optional [tb] argument is engaged.
|
||||||
// ref: amsmath: \renewcommand{\smash}[1][tb]{%
|
// ref: amsmath: \renewcommand{\smash}[1][tb]{%
|
||||||
|
@@ -5,6 +5,7 @@ import domTree from "../domTree";
|
|||||||
import mathMLTree from "../mathMLTree";
|
import mathMLTree from "../mathMLTree";
|
||||||
import utils from "../utils";
|
import utils from "../utils";
|
||||||
import Style from "../Style";
|
import Style from "../Style";
|
||||||
|
import {checkNodeType} from "../ParseNode";
|
||||||
|
|
||||||
import * as html from "../buildHTML";
|
import * as html from "../buildHTML";
|
||||||
import * as mml from "../buildMathML";
|
import * as mml from "../buildMathML";
|
||||||
@@ -184,13 +185,13 @@ defineFunctionBuilders({
|
|||||||
let isBrace = false;
|
let isBrace = false;
|
||||||
let isOver;
|
let isOver;
|
||||||
let isSup;
|
let isSup;
|
||||||
if (group.value.base) {
|
|
||||||
if (group.value.base.value.type === "horizBrace") {
|
const horizBrace = checkNodeType(group.value.base, "horizBrace");
|
||||||
isSup = (group.value.sup ? true : false);
|
if (horizBrace) {
|
||||||
if (isSup === group.value.base.value.isOver) {
|
isSup = !!group.value.sup;
|
||||||
isBrace = true;
|
if (isSup === horizBrace.value.isOver) {
|
||||||
isOver = group.value.base.value.isOver;
|
isBrace = true;
|
||||||
}
|
isOver = horizBrace.value.isOver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,11 +9,12 @@ import ParseError from "./ParseError";
|
|||||||
import ParseNode from "./ParseNode";
|
import ParseNode from "./ParseNode";
|
||||||
|
|
||||||
import type Settings from "./Settings";
|
import type Settings from "./Settings";
|
||||||
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an expression using a Parser, then returns the parsed result.
|
* 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)) {
|
if (!(typeof toParse === 'string' || toParse instanceof String)) {
|
||||||
throw new TypeError('KaTeX can only parse string typed expression');
|
throw new TypeError('KaTeX can only parse string typed expression');
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ import mathMLTree from "./mathMLTree";
|
|||||||
import utils from "./utils";
|
import utils from "./utils";
|
||||||
|
|
||||||
import type Options from "./Options";
|
import type Options from "./Options";
|
||||||
import type ParseNode from "./ParseNode";
|
import type ParseNode, {AnyParseNode} from "./ParseNode";
|
||||||
import type {DomSpan, SvgSpan} from "./domTree";
|
import type {DomSpan, SvgSpan} from "./domTree";
|
||||||
|
|
||||||
const stretchyCodePoint: {[string]: string} = {
|
const stretchyCodePoint: {[string]: string} = {
|
||||||
@@ -159,7 +159,7 @@ const katexImagesData: {
|
|||||||
"shortrightharpoonabovebar"], 1.75, 716],
|
"shortrightharpoonabovebar"], 1.75, 716],
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupLength = function(arg: ParseNode<*>): number {
|
const groupLength = function(arg: AnyParseNode): number {
|
||||||
if (arg.type === "ordgroup") {
|
if (arg.type === "ordgroup") {
|
||||||
return arg.value.length;
|
return arg.value.length;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -24,9 +24,20 @@ type Font = "main" | "ams"
|
|||||||
// types for raw text tokens, and we want to avoid conflicts with higher-level
|
// types for raw text tokens, and we want to avoid conflicts with higher-level
|
||||||
// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
|
// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
|
||||||
// looking up the `symbols` map.
|
// looking up the `symbols` map.
|
||||||
export type Group =
|
export const GROUPS = { // Set of all the groups.
|
||||||
"accent-token" | "bin" | "close" | "inner" | "mathord" |
|
"accent-token": 1,
|
||||||
"op-token" | "open" | "punct" | "rel" | "spacing" | "textord";
|
"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}};
|
type CharInfoMap = {[string]: {font: Font, group: Group, replace: ?string}};
|
||||||
|
|
||||||
const symbols: {[Mode]: CharInfoMap} = {
|
const symbols: {[Mode]: CharInfoMap} = {
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
* files.
|
* files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type ParseNode from "./ParseNode";
|
import type {AnyParseNode} from "./ParseNode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide an `indexOf` function which works in IE8, but defers to native if
|
* 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
|
* cases, this will just be the group itself, but when ordgroups and colors have
|
||||||
* a single element, we want to pull that out.
|
* 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.type === "ordgroup") {
|
||||||
if (group.value.length === 1) {
|
if (group.value.length === 1) {
|
||||||
return getBaseElem(group.value[0]);
|
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,
|
* 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.
|
* 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);
|
const baseElem = getBaseElem(group);
|
||||||
|
|
||||||
// These are all they types of groups which hold single characters
|
// These are all they types of groups which hold single characters
|
||||||
|
Reference in New Issue
Block a user