Correct (type-wise) raisebox's usage of sizing's buildHtml. (#1361)

* Correct (type-wise) raisebox's usage of sizing's buildHtml.

* Move HTML and MathML groupTypes into defineFunction.

Currently, functions defined in functions/* import all exports from buildHtml
and buildMathML, but they should never use `groupTypes` directly as it loses
type-safety. They should instead use more type-safe `htmlBuilder`s and
`mathmlBuilder`s exported directly from other definitions `functions/*` to allow
flow to catch errors.

* Rename groupTypes to groupBuilders.
This commit is contained in:
Ashish Myles
2018-05-27 03:24:30 -04:00
committed by ylemkimon
parent d9fe716d0e
commit 9cde0336d3
6 changed files with 50 additions and 44 deletions

View File

@@ -1,8 +1,8 @@
/**
* This file does the main work of building a domTree structure from a parse
* tree. The entry point is the `buildHTML` function, which takes a parse tree.
* Then, the buildExpression, buildGroup, and various groupTypes functions are
* called, to produce a final HTML tree.
* Then, the buildExpression, buildGroup, and various groupBuilders functions
* are called, to produce a final HTML tree.
*/
import ParseError from "./ParseError";
@@ -12,6 +12,7 @@ import buildCommon from "./buildCommon";
import domTree from "./domTree";
import utils from "./utils";
import {spacings, tightSpacings} from "./spacingData";
import {_htmlGroupBuilders as groupBuilders} from "./defineFunction";
const makeSpan = buildCommon.makeSpan;
@@ -209,9 +210,6 @@ export const makeNullDelimiter = function(options, classes) {
return makeSpan(classes.concat(moreClasses));
};
/** This is a map of group types to the function used to handle that type. */
export const groupTypes = {};
/**
* buildGroup is the function that takes a group and calls the correct groupType
* function for it. It also handles the interaction of size and style changes
@@ -222,9 +220,9 @@ export const buildGroup = function(group, options, baseOptions) {
return makeSpan();
}
if (groupTypes[group.type]) {
// Call the groupTypes function
let groupNode = groupTypes[group.type](group, options);
if (groupBuilders[group.type]) {
// Call the groupBuilders function
let groupNode = groupBuilders[group.type](group, options);
// If the size changed between the parent and the current group, account
// for that size difference.

View File

@@ -10,6 +10,7 @@ import mathMLTree from "./mathMLTree";
import ParseError from "./ParseError";
import symbols from "./symbols";
import utils from "./utils";
import {_mathmlGroupBuilders as groupBuilders} from "./defineFunction";
/**
* Takes a symbol and converts it into a MathML text node after performing
@@ -70,12 +71,6 @@ export const getVariant = function(group, options) {
return null;
};
/**
* Functions for handling the different types of groups found in the parse
* tree. Each function should take a parse group and return a MathML node.
*/
export const groupTypes = {};
/**
* Takes a list of nodes, builds them, and returns a list of the generated
* MathML nodes. Also combine consecutive <mtext> outputs into a single
@@ -118,7 +113,7 @@ export const buildExpressionRow = function(expression, options) {
};
/**
* Takes a group from the parser and calls the appropriate groupTypes function
* Takes a group from the parser and calls the appropriate groupBuilders function
* on it to produce a MathML node.
*/
export const buildGroup = function(group, options) {
@@ -126,9 +121,9 @@ export const buildGroup = function(group, options) {
return new mathMLTree.MathNode("mrow");
}
if (groupTypes[group.type]) {
// Call the groupTypes function
const result = groupTypes[group.type](group, options);
if (groupBuilders[group.type]) {
// Call the groupBuilders function
const result = groupBuilders[group.type](group, options);
return result;
} else {
throw new ParseError(

View File

@@ -1,6 +1,5 @@
// @flow
import {groupTypes as htmlGroupTypes} from "./buildHTML";
import {groupTypes as mathmlGroupTypes} from "./buildMathML";
import {_htmlGroupBuilders, _mathmlGroupBuilders} from "./defineFunction";
import Options from "./Options";
import ParseNode from "./ParseNode";
@@ -114,9 +113,9 @@ export default function defineEnvironment<NODETYPE: NodeType>({
_environments[names[i]] = data;
}
if (htmlBuilder) {
htmlGroupTypes[type] = htmlBuilder;
_htmlGroupBuilders[type] = htmlBuilder;
}
if (mathmlBuilder) {
mathmlGroupTypes[type] = mathmlBuilder;
_mathmlGroupBuilders[type] = mathmlBuilder;
}
}

View File

@@ -1,6 +1,4 @@
// @flow
import {groupTypes as htmlGroupTypes} from "./buildHTML";
import {groupTypes as mathmlGroupTypes} from "./buildMathML";
import {checkNodeType} from "./ParseNode";
import domTree from "./domTree";
@@ -170,6 +168,18 @@ export type FunctionSpec<NODETYPE: NodeType> = {|
*/
export const _functions: {[string]: FunctionSpec<*>} = {};
/**
* All HTML builders. Should be only used in the `define*` and the `build*ML`
* functions.
*/
export const _htmlGroupBuilders: {[string]: HtmlBuilder<*>} = {};
/**
* All MathML builders. Should be only used in the `define*` and the `build*ML`
* functions.
*/
export const _mathmlGroupBuilders: {[string]: MathMLBuilder<*>} = {};
export default function defineFunction<NODETYPE: NodeType>({
type,
nodeType,
@@ -199,10 +209,10 @@ export default function defineFunction<NODETYPE: NodeType>({
}
if (type) {
if (htmlBuilder) {
htmlGroupTypes[type] = htmlBuilder;
_htmlGroupBuilders[type] = htmlBuilder;
}
if (mathmlBuilder) {
mathmlGroupTypes[type] = mathmlBuilder;
_mathmlGroupBuilders[type] = mathmlBuilder;
}
}
}

View File

@@ -2,11 +2,11 @@
import defineFunction, {ordargument} from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import {assertNodeType} from "../ParseNode";
import ParseNode, {assertNodeType} from "../ParseNode";
import {calculateSize} from "../units";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
import * as sizing from "./sizing";
// Box manipulation
defineFunction({
@@ -28,16 +28,17 @@ defineFunction({
};
},
htmlBuilder(group, options) {
const body = html.groupTypes.sizing({value: {
value: [{
type: "text",
value: {
body: group.value.value,
font: "mathrm", // simulate \textrm
},
}],
const text = new ParseNode("text", {
type: "text",
body: group.value.value,
font: "mathrm", // simulate \textrm
}, group.mode);
const sizedText = new ParseNode("sizing", {
type: "sizing",
value: [text],
size: 6, // simulate \normalsize
}}, options);
}, group.mode);
const body = sizing.htmlBuilder(sizedText, options);
const dy = calculateSize(group.value.dy.value, options);
return buildCommon.makeVList({
positionType: "shift",

View File

@@ -8,6 +8,7 @@ import * as html from "../buildHTML";
import * as mml from "../buildMathML";
import type Options from "../Options";
import type {HtmlBuilder} from "../defineFunction";
export function sizingGroup(value: *, options: Options, baseOptions: Options) {
const inner = html.buildExpression(value, options, false);
@@ -39,6 +40,14 @@ const sizeFuncs = [
"\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
];
export const htmlBuilder: HtmlBuilder<"sizing"> = (group, options) => {
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
// these functions inside of math expressions, so we do some special
// handling.
const newOptions = options.havingSize(group.value.size);
return sizingGroup(group.value.value, newOptions, options);
};
defineFunction({
type: "sizing",
names: sizeFuncs,
@@ -59,13 +68,7 @@ defineFunction({
value: body,
};
},
htmlBuilder: (group, options) => {
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
// these functions inside of math expressions, so we do some special
// handling.
const newOptions = options.havingSize(group.value.size);
return sizingGroup(group.value.value, newOptions, options);
},
htmlBuilder,
mathmlBuilder: (group, options) => {
const newOptions = options.havingSize(group.value.size);
const inner = mml.buildExpression(group.value.value, newOptions);