temml 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/contrib/auto-render/README.md +89 -0
  4. package/contrib/auto-render/auto-render.js +128 -0
  5. package/contrib/auto-render/dist/auto-render.js +217 -0
  6. package/contrib/auto-render/dist/auto-render.min.js +1 -0
  7. package/contrib/auto-render/splitAtDelimiters.js +84 -0
  8. package/contrib/auto-render/test/auto-render-spec.js +234 -0
  9. package/contrib/auto-render/test/auto-render.js +217 -0
  10. package/contrib/auto-render/test/test_page.html +59 -0
  11. package/contrib/mhchem/README.md +26 -0
  12. package/contrib/mhchem/mhchem.js +1705 -0
  13. package/contrib/mhchem/mhchem.min.js +1 -0
  14. package/contrib/physics/README.md +20 -0
  15. package/contrib/physics/physics.js +131 -0
  16. package/contrib/texvc/README.md +23 -0
  17. package/contrib/texvc/texvc.js +61 -0
  18. package/dist/Temml-Asana.css +201 -0
  19. package/dist/Temml-Latin-Modern.css +216 -0
  20. package/dist/Temml-Libertinus.css +214 -0
  21. package/dist/Temml-Local.css +194 -0
  22. package/dist/Temml-STIX2.css +203 -0
  23. package/dist/Temml.woff2 +0 -0
  24. package/dist/temml.cjs +13122 -0
  25. package/dist/temml.js +11225 -0
  26. package/dist/temml.min.js +1 -0
  27. package/dist/temml.mjs +13120 -0
  28. package/dist/temmlPostProcess.js +70 -0
  29. package/package.json +34 -0
  30. package/src/Lexer.js +121 -0
  31. package/src/MacroExpander.js +437 -0
  32. package/src/Namespace.js +107 -0
  33. package/src/ParseError.js +64 -0
  34. package/src/Parser.js +977 -0
  35. package/src/Settings.js +49 -0
  36. package/src/SourceLocation.js +29 -0
  37. package/src/Style.js +144 -0
  38. package/src/Token.js +40 -0
  39. package/src/buildMathML.js +235 -0
  40. package/src/constants.js +25 -0
  41. package/src/defineEnvironment.js +25 -0
  42. package/src/defineFunction.js +69 -0
  43. package/src/defineMacro.js +11 -0
  44. package/src/domTree.js +185 -0
  45. package/src/environments/array.js +791 -0
  46. package/src/environments/cd.js +252 -0
  47. package/src/environments.js +8 -0
  48. package/src/functions/accent.js +127 -0
  49. package/src/functions/accentunder.js +38 -0
  50. package/src/functions/arrow.js +204 -0
  51. package/src/functions/cancelto.js +36 -0
  52. package/src/functions/char.js +33 -0
  53. package/src/functions/color.js +253 -0
  54. package/src/functions/cr.js +46 -0
  55. package/src/functions/def.js +259 -0
  56. package/src/functions/delimsizing.js +304 -0
  57. package/src/functions/enclose.js +193 -0
  58. package/src/functions/envTag.js +38 -0
  59. package/src/functions/environment.js +59 -0
  60. package/src/functions/font.js +123 -0
  61. package/src/functions/genfrac.js +333 -0
  62. package/src/functions/hbox.js +29 -0
  63. package/src/functions/horizBrace.js +32 -0
  64. package/src/functions/href.js +90 -0
  65. package/src/functions/html.js +95 -0
  66. package/src/functions/includegraphics.js +131 -0
  67. package/src/functions/kern.js +75 -0
  68. package/src/functions/label.js +29 -0
  69. package/src/functions/lap.js +75 -0
  70. package/src/functions/math.js +40 -0
  71. package/src/functions/mathchoice.js +41 -0
  72. package/src/functions/mclass.js +201 -0
  73. package/src/functions/multiscript.js +91 -0
  74. package/src/functions/not.js +46 -0
  75. package/src/functions/op.js +338 -0
  76. package/src/functions/operatorname.js +139 -0
  77. package/src/functions/ordgroup.js +9 -0
  78. package/src/functions/phantom.js +73 -0
  79. package/src/functions/pmb.js +31 -0
  80. package/src/functions/raise.js +68 -0
  81. package/src/functions/ref.js +28 -0
  82. package/src/functions/relax.js +16 -0
  83. package/src/functions/rule.js +52 -0
  84. package/src/functions/sizing.js +64 -0
  85. package/src/functions/smash.js +66 -0
  86. package/src/functions/sqrt.js +31 -0
  87. package/src/functions/styling.js +58 -0
  88. package/src/functions/supsub.js +135 -0
  89. package/src/functions/symbolsOp.js +53 -0
  90. package/src/functions/symbolsOrd.js +102 -0
  91. package/src/functions/symbolsSpacing.js +53 -0
  92. package/src/functions/tag.js +8 -0
  93. package/src/functions/text.js +75 -0
  94. package/src/functions/tip.js +63 -0
  95. package/src/functions/toggle.js +13 -0
  96. package/src/functions/verb.js +33 -0
  97. package/src/functions.js +57 -0
  98. package/src/linebreaking.js +159 -0
  99. package/src/macros.js +708 -0
  100. package/src/mathMLTree.js +175 -0
  101. package/src/parseNode.js +42 -0
  102. package/src/parseTree.js +40 -0
  103. package/src/postProcess.js +57 -0
  104. package/src/replace.js +225 -0
  105. package/src/stretchy.js +66 -0
  106. package/src/svg.js +110 -0
  107. package/src/symbols.js +972 -0
  108. package/src/tree.js +50 -0
  109. package/src/unicodeAccents.js +16 -0
  110. package/src/unicodeScripts.js +119 -0
  111. package/src/unicodeSupOrSub.js +108 -0
  112. package/src/unicodeSymbolBuilder.js +31 -0
  113. package/src/unicodeSymbols.js +320 -0
  114. package/src/units.js +109 -0
  115. package/src/utils.js +109 -0
  116. package/src/variant.js +103 -0
  117. package/temml.js +181 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * This is a module for storing settings passed into Temml. It correctly handles
3
+ * default settings.
4
+ */
5
+
6
+ import utils from "./utils";
7
+
8
+ /**
9
+ * The main Settings object
10
+ */
11
+ export default class Settings {
12
+ constructor(options) {
13
+ // allow null options
14
+ options = options || {};
15
+ this.displayMode = utils.deflt(options.displayMode, false); // boolean
16
+ this.annotate = utils.deflt(options.annotate, false) // boolean
17
+ this.leqno = utils.deflt(options.leqno, false); // boolean
18
+ this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string
19
+ this.macros = options.macros || {};
20
+ this.wrap = utils.deflt(options.wrap, "none") // "none" | "tex" | "="
21
+ this.xml = utils.deflt(options.xml, false); // boolean
22
+ this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean
23
+ this.strict = utils.deflt(options.strict, false); // boolean
24
+ this.trust = utils.deflt(options.trust, false); // trust context. See html.js.
25
+ this.maxSize = (options.maxSize === undefined
26
+ ? [Infinity, Infinity]
27
+ : Array.isArray(options.maxSize)
28
+ ? options.maxSize
29
+ : [Infinity, Infinity]
30
+ )
31
+ this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number
32
+ }
33
+
34
+ /**
35
+ * Check whether to test potentially dangerous input, and return
36
+ * `true` (trusted) or `false` (untrusted). The sole argument `context`
37
+ * should be an object with `command` field specifying the relevant LaTeX
38
+ * command (as a string starting with `\`), and any other arguments, etc.
39
+ * If `context` has a `url` field, a `protocol` field will automatically
40
+ * get added by this function (changing the specified object).
41
+ */
42
+ isTrusted(context) {
43
+ if (context.url && !context.protocol) {
44
+ context.protocol = utils.protocolFromUrl(context.url);
45
+ }
46
+ const trust = typeof this.trust === "function" ? this.trust(context) : this.trust;
47
+ return Boolean(trust);
48
+ }
49
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Lexing or parsing positional information for error reporting.
3
+ * This object is immutable.
4
+ */
5
+ export default class SourceLocation {
6
+ constructor(lexer, start, end) {
7
+ this.lexer = lexer; // Lexer holding the input string.
8
+ this.start = start; // Start offset, zero-based inclusive.
9
+ this.end = end; // End offset, zero-based exclusive.
10
+ }
11
+
12
+ /**
13
+ * Merges two `SourceLocation`s from location providers, given they are
14
+ * provided in order of appearance.
15
+ * - Returns the first one's location if only the first is provided.
16
+ * - Returns a merged range of the first and the last if both are provided
17
+ * and their lexers match.
18
+ * - Otherwise, returns null.
19
+ */
20
+ static range(first, second) {
21
+ if (!second) {
22
+ return first && first.loc;
23
+ } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) {
24
+ return null;
25
+ } else {
26
+ return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end);
27
+ }
28
+ }
29
+ }
package/src/Style.js ADDED
@@ -0,0 +1,144 @@
1
+ /**
2
+ * This file contains information about the style that the mathmlBuilder carries
3
+ * around with it. Data is held in an `Style` object, and when
4
+ * recursing, a new `Style` object can be created with the `.with*` functions.
5
+ */
6
+
7
+ const subOrSupLevel = [2, 2, 3, 3];
8
+
9
+ /**
10
+ * This is the main Style class. It contains the current style.level, color, and font.
11
+ *
12
+ * Style objects should not be modified. To create a new Style with
13
+ * different properties, call a `.with*` method.
14
+ */
15
+ class Style {
16
+ constructor(data) {
17
+ // Style.level can be 0 | 1 | 2 | 3, which correspond to
18
+ // displaystyle, textstyle, scriptstyle, and scriptscriptstyle.
19
+ // style.level does not directly set MathML's script level. MathML does that itself.
20
+ // We use style.level to track, not set, math style so that we can get the
21
+ // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em.
22
+ this.level = data.level;
23
+ this.color = data.color; // string | void
24
+ // A font family applies to a group of fonts (i.e. SansSerif), while a font
25
+ // represents a specific font (i.e. SansSerif Bold).
26
+ // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
27
+ this.font = data.font || ""; // string
28
+ this.fontFamily = data.fontFamily || ""; // string
29
+ this.fontSize = data.fontSize || 1.0; // number
30
+ this.fontWeight = data.fontWeight || "";
31
+ this.fontShape = data.fontShape || "";
32
+ this.maxSize = data.maxSize; // [number, number]
33
+ }
34
+
35
+ /**
36
+ * Returns a new style object with the same properties as "this". Properties
37
+ * from "extension" will be copied to the new style object.
38
+ */
39
+ extend(extension) {
40
+ const data = {
41
+ level: this.level,
42
+ color: this.color,
43
+ font: this.font,
44
+ fontFamily: this.fontFamily,
45
+ fontSize: this.fontSize,
46
+ fontWeight: this.fontWeight,
47
+ fontShape: this.fontShape,
48
+ maxSize: this.maxSize
49
+ };
50
+
51
+ for (const key in extension) {
52
+ if (Object.prototype.hasOwnProperty.call(extension, key)) {
53
+ data[key] = extension[key];
54
+ }
55
+ }
56
+
57
+ return new Style(data);
58
+ }
59
+
60
+ withLevel(n) {
61
+ return this.extend({
62
+ level: n
63
+ });
64
+ }
65
+
66
+ incrementLevel() {
67
+ return this.extend({
68
+ level: Math.min(this.level + 1, 3)
69
+ });
70
+ }
71
+
72
+ inSubOrSup() {
73
+ return this.extend({
74
+ level: subOrSupLevel[this.level]
75
+ })
76
+ }
77
+
78
+ /**
79
+ * Create a new style object with the given color.
80
+ */
81
+ withColor(color) {
82
+ return this.extend({
83
+ color: color
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Creates a new style object with the given math font or old text font.
89
+ * @type {[type]}
90
+ */
91
+ withFont(font) {
92
+ return this.extend({
93
+ font
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Create a new style objects with the given fontFamily.
99
+ */
100
+ withTextFontFamily(fontFamily) {
101
+ return this.extend({
102
+ fontFamily,
103
+ font: ""
104
+ });
105
+ }
106
+
107
+ /**
108
+ * Creates a new style object with the given font size
109
+ */
110
+ withFontSize(num) {
111
+ return this.extend({
112
+ fontSize: num
113
+ });
114
+ }
115
+
116
+ /**
117
+ * Creates a new style object with the given font weight
118
+ */
119
+ withTextFontWeight(fontWeight) {
120
+ return this.extend({
121
+ fontWeight,
122
+ font: ""
123
+ });
124
+ }
125
+
126
+ /**
127
+ * Creates a new style object with the given font weight
128
+ */
129
+ withTextFontShape(fontShape) {
130
+ return this.extend({
131
+ fontShape,
132
+ font: ""
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Gets the CSS color of the current style object
138
+ */
139
+ getColor() {
140
+ return this.color;
141
+ }
142
+ }
143
+
144
+ export default Style;
package/src/Token.js ADDED
@@ -0,0 +1,40 @@
1
+ import SourceLocation from "./SourceLocation";
2
+
3
+ /**
4
+ * Interface required to break circular dependency between Token, Lexer, and
5
+ * ParseError.
6
+ */
7
+
8
+ /**
9
+ * The resulting token returned from `lex`.
10
+ *
11
+ * It consists of the token text plus some position information.
12
+ * The position information is essentially a range in an input string,
13
+ * but instead of referencing the bare input string, we refer to the lexer.
14
+ * That way it is possible to attach extra metadata to the input string,
15
+ * like for example a file name or similar.
16
+ *
17
+ * The position information is optional, so it is OK to construct synthetic
18
+ * tokens if appropriate. Not providing available position information may
19
+ * lead to degraded error reporting, though.
20
+ */
21
+ export class Token {
22
+ constructor(
23
+ text, // the text of this token
24
+ loc
25
+ ) {
26
+ this.text = text;
27
+ this.loc = loc;
28
+ }
29
+
30
+ /**
31
+ * Given a pair of tokens (this and endToken), compute a `Token` encompassing
32
+ * the whole input range enclosed by these two.
33
+ */
34
+ range(
35
+ endToken, // last token of the range, inclusive
36
+ text // the text of the newly constructed token
37
+ ) {
38
+ return new Token(text, SourceLocation.range(this, endToken));
39
+ }
40
+ }
@@ -0,0 +1,235 @@
1
+ /**
2
+ * This file converts a parse tree into a cooresponding MathML tree. The main
3
+ * entry point is the `buildMathML` function, which takes a parse tree from the
4
+ * parser.
5
+ */
6
+
7
+ import mathMLTree from "./mathMLTree"
8
+ import ParseError from "./ParseError"
9
+ import symbols, { ligatures } from "./symbols"
10
+ import { _mathmlGroupBuilders as groupBuilders } from "./defineFunction"
11
+ import { MathNode } from "./mathMLTree"
12
+ import setLineBreaks from "./linebreaking"
13
+
14
+ /**
15
+ * Takes a symbol and converts it into a MathML text node after performing
16
+ * optional replacement from symbols.js.
17
+ */
18
+ export const makeText = function(text, mode, style) {
19
+ if (
20
+ symbols[mode][text] &&
21
+ symbols[mode][text].replace &&
22
+ text.charCodeAt(0) !== 0xd835 &&
23
+ !(
24
+ Object.prototype.hasOwnProperty.call(ligatures, text) &&
25
+ style &&
26
+ ((style.fontFamily && style.fontFamily.slice(4, 6) === "tt") ||
27
+ (style.font && style.font.slice(4, 6) === "tt"))
28
+ )
29
+ ) {
30
+ text = symbols[mode][text].replace;
31
+ }
32
+
33
+ return new mathMLTree.TextNode(text);
34
+ };
35
+
36
+ export const consolidateText = mrow => {
37
+ // If possible, consolidate adjacent <mtext> elements into a single element.
38
+ if (mrow.type !== "mrow") { return mrow }
39
+ if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{}
40
+ if (!mrow.children[0].attributes || mrow.children[0].type !== "mtext") { return mrow }
41
+ const variant = mrow.children[0].attributes.mathvariant || ""
42
+ const mtext = new mathMLTree.MathNode(
43
+ "mtext",
44
+ [new mathMLTree.TextNode(mrow.children[0].children[0].text)]
45
+ )
46
+ for (let i = 1; i < mrow.children.length; i++) {
47
+ // Check each child and, if possible, copy the character into child[0].
48
+ const localVariant = mrow.children[i].attributes.mathvariant || ""
49
+ if (mrow.children[i].type === "mrow") {
50
+ const childRow = mrow.children[i]
51
+ for (let j = 0; j < childRow.children.length; j++) {
52
+ // We'll also check the children of a mrow. One level only. No recursion.
53
+ const childVariant = childRow.children[j].attributes.mathvariant || ""
54
+ if (childVariant !== variant || childRow.children[j].type !== "mtext") {
55
+ return mrow // At least one element cannot be consolidated. Get out.
56
+ } else {
57
+ mtext.children[0].text += childRow.children[j].children[0].text
58
+ }
59
+ }
60
+ } else if (localVariant !== variant || mrow.children[i].type !== "mtext") {
61
+ return mrow
62
+ } else {
63
+ mtext.children[0].text += mrow.children[i].children[0].text
64
+ }
65
+ }
66
+ // Firefox does not render a space at either end of an <mtext> string.
67
+ // To get proper rendering, we replace leading or trailing spaces with no-break spaces.
68
+ if (mtext.children[0].text.charAt(0) === " ") {
69
+ mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1)
70
+ }
71
+ const L = mtext.children[0].text.length
72
+ if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") {
73
+ mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"
74
+ }
75
+ return mtext
76
+ }
77
+
78
+ /**
79
+ * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
80
+ * unless the array has length 1. Always returns a single node.
81
+ */
82
+ export const makeRow = function(body) {
83
+ if (body.length === 1) {
84
+ return body[0];
85
+ } else {
86
+ return new mathMLTree.MathNode("mrow", body);
87
+ }
88
+ };
89
+
90
+ const isRel = item => {
91
+ return (item.type === "atom" && item.family === "rel") ||
92
+ (item.type === "mclass" && item.mclass === "mrel")
93
+ }
94
+
95
+ /**
96
+ * Takes a list of nodes, builds them, and returns a list of the generated
97
+ * MathML nodes. Also do a couple chores along the way:
98
+ * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}.
99
+ * (2) Suppress spacing between two adjacent relations.
100
+ */
101
+ export const buildExpression = function(expression, style, isOrdgroup) {
102
+ if (expression.length === 1) {
103
+ const group = buildGroup(expression[0], style);
104
+ if (isOrdgroup && group instanceof MathNode && group.type === "mo") {
105
+ // When TeX writers want to suppress spacing on an operator,
106
+ // they often put the operator by itself inside braces.
107
+ group.setAttribute("lspace", "0em");
108
+ group.setAttribute("rspace", "0em");
109
+ }
110
+ return [group];
111
+ }
112
+
113
+ const groups = [];
114
+ for (let i = 0; i < expression.length; i++) {
115
+ const group = buildGroup(expression[i], style);
116
+ // Suppress spacing between adjacent relations
117
+ if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) {
118
+ group.setAttribute("rspace", "0em")
119
+ }
120
+ if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) {
121
+ group.setAttribute("lspace", "0em")
122
+ }
123
+ groups.push(group);
124
+ }
125
+ return groups;
126
+ };
127
+
128
+ /**
129
+ * Equivalent to buildExpression, but wraps the elements in an <mrow>
130
+ * if there's more than one. Returns a single node instead of an array.
131
+ */
132
+ export const buildExpressionRow = function(expression, style, isOrdgroup) {
133
+ return makeRow(buildExpression(expression, style, isOrdgroup));
134
+ };
135
+
136
+ /**
137
+ * Takes a group from the parser and calls the appropriate groupBuilders function
138
+ * on it to produce a MathML node.
139
+ */
140
+ export const buildGroup = function(group, style) {
141
+ if (!group) {
142
+ return new mathMLTree.MathNode("mrow");
143
+ }
144
+
145
+ if (groupBuilders[group.type]) {
146
+ // Call the groupBuilders function
147
+ const result = groupBuilders[group.type](group, style);
148
+ return result;
149
+ } else {
150
+ throw new ParseError("Got group of unknown type: '" + group.type + "'");
151
+ }
152
+ };
153
+
154
+ const glue = _ => {
155
+ return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" })
156
+ }
157
+
158
+ const taggedExpression = (expression, tag, style, leqno) => {
159
+ tag = buildExpressionRow(tag[0].body, style)
160
+ tag = consolidateText(tag)
161
+ tag.classes.push("tml-tag")
162
+
163
+ expression = new mathMLTree.MathNode("mtd", [expression])
164
+ const rowArray = [glue(), expression, glue()]
165
+ if (leqno) {
166
+ rowArray[0].children.push(tag)
167
+ rowArray[0].style.textAlign = "-webkit-left"
168
+ } else {
169
+ rowArray[2].children.push(tag)
170
+ rowArray[2].style.textAlign = "-webkit-right"
171
+ }
172
+ const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"])
173
+ const table = new mathMLTree.MathNode("mtable", [mtr])
174
+ table.style.width = "100%"
175
+ table.setAttribute("displaystyle", "true")
176
+ return table
177
+ }
178
+
179
+ /**
180
+ * Takes a full parse tree and settings and builds a MathML representation of
181
+ * it.
182
+ */
183
+ export default function buildMathML(tree, texExpression, style, settings) {
184
+ // Strip off outer tag wrapper for processing below.
185
+ let tag = null
186
+ if (tree.length === 1 && tree[0].type === "tag") {
187
+ tag = tree[0].tag
188
+ tree = tree[0].body
189
+ }
190
+
191
+ const expression = buildExpression(tree, style);
192
+ const wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap
193
+
194
+ const n1 = expression.length === 0 ? null : expression[0]
195
+ let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode)
196
+ && !(n1.type === "mstyle" && n1.attributes.mathcolor)
197
+ ? expression[0]
198
+ : expression.length > 1 && wrap === "none"
199
+ ? new mathMLTree.MathNode("mrow", expression)
200
+ : setLineBreaks(expression, wrap, settings.displayMode)
201
+
202
+ if (tag) {
203
+ wrapper = taggedExpression(wrapper, tag, style, settings.leqno)
204
+ }
205
+
206
+ if (settings.annotate) {
207
+ // Build a TeX annotation of the source
208
+ const annotation = new mathMLTree.MathNode(
209
+ "annotation", [new mathMLTree.TextNode(texExpression)]);
210
+ annotation.setAttribute("encoding", "application/x-tex");
211
+ wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]);
212
+ }
213
+
214
+ if (wrap !== "none") {
215
+ const maths = []
216
+ for (let i = 0; i < wrapper.children.length; i++) {
217
+ const math = new mathMLTree.MathNode("math", [wrapper.children[i]])
218
+ if (settings.xml) {
219
+ math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML")
220
+ }
221
+ maths.push(math)
222
+ }
223
+ return mathMLTree.newDocumentFragment(maths)
224
+ }
225
+
226
+ const math = new mathMLTree.MathNode("math", [wrapper])
227
+
228
+ if (settings.xml) {
229
+ math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML")
230
+ }
231
+ if (settings.displayMode) {
232
+ math.setAttribute("display", "block");
233
+ }
234
+ return math;
235
+ }
@@ -0,0 +1,25 @@
1
+ // In TeX, there are actually three sets of dimensions, one for each of
2
+ // textstyle, scriptstyle, and scriptscriptstyle. These are
3
+ // provided in the the arrays below, in that order.
4
+ //
5
+ export const metrics = {
6
+ quad: [1.0, 1.171, 1.472], // Extracted from TeX
7
+
8
+ // The TeX default rule thickness, 0.04 em, often disappears from a browser screen.
9
+ // So we use a thicker rule.
10
+ defaultRuleThickness: [0.06, 0.074, 0.074],
11
+
12
+ // The space between adjacent `|` columns in an array definition.
13
+ doubleRuleSep: [0.3, 0.3, 0.3],
14
+
15
+ // The width of separator lines in {array} environments.
16
+ arrayRuleWidth: [0.06, 0.06, 0.04]
17
+ };
18
+
19
+ // Math style is not quite the same thing as script level.
20
+ export const StyleLevel = {
21
+ DISPLAY: 0,
22
+ TEXT: 1,
23
+ SCRIPT: 2,
24
+ SCRIPTSCRIPT: 3
25
+ };
@@ -0,0 +1,25 @@
1
+ import { _mathmlGroupBuilders } from "./defineFunction";
2
+
3
+ /**
4
+ * All registered environments.
5
+ * `environments.js` exports this same dictionary again and makes it public.
6
+ * `Parser.js` requires this dictionary via `environments.js`.
7
+ */
8
+ export const _environments = {};
9
+
10
+ export default function defineEnvironment({ type, names, props, handler, mathmlBuilder }) {
11
+ // Set default values of environments.
12
+ const data = {
13
+ type,
14
+ numArgs: props.numArgs || 0,
15
+ allowedInText: false,
16
+ numOptionalArgs: 0,
17
+ handler
18
+ };
19
+ for (let i = 0; i < names.length; ++i) {
20
+ _environments[names[i]] = data;
21
+ }
22
+ if (mathmlBuilder) {
23
+ _mathmlGroupBuilders[type] = mathmlBuilder;
24
+ }
25
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * All registered functions.
3
+ * `functions.js` just exports this same dictionary again and makes it public.
4
+ * `Parser.js` requires this dictionary.
5
+ */
6
+ export const _functions = {}
7
+
8
+ /**
9
+ * All MathML builders. Should be only used in the `define*` and the `build*ML`
10
+ * functions.
11
+ */
12
+ export const _mathmlGroupBuilders = {}
13
+
14
+ export default function defineFunction({
15
+ type,
16
+ names,
17
+ props,
18
+ handler,
19
+ mathmlBuilder
20
+ }) {
21
+ // Set default values of functions
22
+ const data = {
23
+ type,
24
+ numArgs: props.numArgs,
25
+ argTypes: props.argTypes,
26
+ allowedInArgument: !!props.allowedInArgument,
27
+ allowedInText: !!props.allowedInText,
28
+ allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath,
29
+ numOptionalArgs: props.numOptionalArgs || 0,
30
+ infix: !!props.infix,
31
+ primitive: !!props.primitive,
32
+ handler: handler
33
+ }
34
+ for (let i = 0; i < names.length; ++i) {
35
+ _functions[names[i]] = data
36
+ }
37
+ if (type) {
38
+ if (mathmlBuilder) {
39
+ _mathmlGroupBuilders[type] = mathmlBuilder
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Use this to register only the MathML builder for a function(e.g.
46
+ * if the function's ParseNode is generated in Parser.js rather than via a
47
+ * stand-alone handler provided to `defineFunction`).
48
+ */
49
+ export function defineFunctionBuilders({ type, mathmlBuilder }) {
50
+ defineFunction({
51
+ type,
52
+ names: [],
53
+ props: { numArgs: 0 },
54
+ handler() {
55
+ throw new Error("Should never be called.")
56
+ },
57
+ mathmlBuilder
58
+ })
59
+ }
60
+
61
+ export const normalizeArgument = function(arg) {
62
+ return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg
63
+ }
64
+
65
+ // Since the corresponding buildMathML function expects a
66
+ // list of elements, we normalize for different kinds of arguments
67
+ export const ordargument = function(arg) {
68
+ return arg.type === "ordgroup" ? arg.body : [arg]
69
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * All registered global/built-in macros.
3
+ * `macros.js` exports this same dictionary again and makes it public.
4
+ * `Parser.js` requires this dictionary via `macros.js`.
5
+ */
6
+ export const _macros = {};
7
+
8
+ // This function might one day accept an additional argument and do more things.
9
+ export default function defineMacro(name, body) {
10
+ _macros[name] = body;
11
+ }