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,304 @@
1
+ import defineFunction from "../defineFunction";
2
+ import mathMLTree from "../mathMLTree";
3
+ import ParseError from "../ParseError";
4
+ import { assertNodeType, checkSymbolNodeType } from "../parseNode";
5
+
6
+ import * as mml from "../buildMathML";
7
+
8
+ // Extra data needed for the delimiter handler down below
9
+ export const delimiterSizes = {
10
+ "\\bigl": { mclass: "mopen", size: 1 },
11
+ "\\Bigl": { mclass: "mopen", size: 2 },
12
+ "\\biggl": { mclass: "mopen", size: 3 },
13
+ "\\Biggl": { mclass: "mopen", size: 4 },
14
+ "\\bigr": { mclass: "mclose", size: 1 },
15
+ "\\Bigr": { mclass: "mclose", size: 2 },
16
+ "\\biggr": { mclass: "mclose", size: 3 },
17
+ "\\Biggr": { mclass: "mclose", size: 4 },
18
+ "\\bigm": { mclass: "mrel", size: 1 },
19
+ "\\Bigm": { mclass: "mrel", size: 2 },
20
+ "\\biggm": { mclass: "mrel", size: 3 },
21
+ "\\Biggm": { mclass: "mrel", size: 4 },
22
+ "\\big": { mclass: "mord", size: 1 },
23
+ "\\Big": { mclass: "mord", size: 2 },
24
+ "\\bigg": { mclass: "mord", size: 3 },
25
+ "\\Bigg": { mclass: "mord", size: 4 }
26
+ };
27
+
28
+ export const delimiters = [
29
+ "(",
30
+ "\\lparen",
31
+ ")",
32
+ "\\rparen",
33
+ "[",
34
+ "\\lbrack",
35
+ "]",
36
+ "\\rbrack",
37
+ "\\{",
38
+ "\\lbrace",
39
+ "\\}",
40
+ "\\rbrace",
41
+ "\\lfloor",
42
+ "\\rfloor",
43
+ "\u230a",
44
+ "\u230b",
45
+ "\\lceil",
46
+ "\\rceil",
47
+ "\u2308",
48
+ "\u2309",
49
+ "<",
50
+ ">",
51
+ "\\langle",
52
+ "\u27e8",
53
+ "\\rangle",
54
+ "\u27e9",
55
+ "\\lt",
56
+ "\\gt",
57
+ "\\lvert",
58
+ "\\rvert",
59
+ "\\lVert",
60
+ "\\rVert",
61
+ "\\lgroup",
62
+ "\\rgroup",
63
+ "\u27ee",
64
+ "\u27ef",
65
+ "\\lmoustache",
66
+ "\\rmoustache",
67
+ "\u23b0",
68
+ "\u23b1",
69
+ "\\llbracket",
70
+ "\\rrbracket",
71
+ "\u27e6",
72
+ "\u27e6",
73
+ "\\lBrace",
74
+ "\\rBrace",
75
+ "\u2983",
76
+ "\u2984",
77
+ "/",
78
+ "\\backslash",
79
+ "|",
80
+ "\\vert",
81
+ "\\|",
82
+ "\\Vert",
83
+ "\\uparrow",
84
+ "\\Uparrow",
85
+ "\\downarrow",
86
+ "\\Downarrow",
87
+ "\\updownarrow",
88
+ "\\Updownarrow",
89
+ "."
90
+ ];
91
+
92
+ // Metrics of the different sizes. Found by looking at TeX's output of
93
+ // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
94
+ // Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
95
+ const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
96
+
97
+ // Delimiter functions
98
+ function checkDelimiter(delim, context) {
99
+ if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") {
100
+ // Recover "/" from the zero spacing group. (See macros.js)
101
+ delim = { type: "textord", text: "/", mode: "math" }
102
+ }
103
+ const symDelim = checkSymbolNodeType(delim)
104
+ if (symDelim && delimiters.includes(symDelim.text)) {
105
+ // If a character is not in the MathML operator dictionary, it will not stretch.
106
+ // Replace such characters w/characters that will stretch.
107
+ if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨" }
108
+ if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩" }
109
+ if (symDelim.text === "/") { symDelim.text = "\u2215" }
110
+ if (symDelim.text === "\\backslash") { symDelim.text = "\u2216" }
111
+ return symDelim;
112
+ } else if (symDelim) {
113
+ throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
114
+ } else {
115
+ throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim);
116
+ }
117
+ }
118
+
119
+ defineFunction({
120
+ type: "delimsizing",
121
+ names: [
122
+ "\\bigl",
123
+ "\\Bigl",
124
+ "\\biggl",
125
+ "\\Biggl",
126
+ "\\bigr",
127
+ "\\Bigr",
128
+ "\\biggr",
129
+ "\\Biggr",
130
+ "\\bigm",
131
+ "\\Bigm",
132
+ "\\biggm",
133
+ "\\Biggm",
134
+ "\\big",
135
+ "\\Big",
136
+ "\\bigg",
137
+ "\\Bigg"
138
+ ],
139
+ props: {
140
+ numArgs: 1,
141
+ argTypes: ["primitive"]
142
+ },
143
+ handler: (context, args) => {
144
+ const delim = checkDelimiter(args[0], context);
145
+
146
+ return {
147
+ type: "delimsizing",
148
+ mode: context.parser.mode,
149
+ size: delimiterSizes[context.funcName].size,
150
+ mclass: delimiterSizes[context.funcName].mclass,
151
+ delim: delim.text
152
+ };
153
+ },
154
+ mathmlBuilder: (group) => {
155
+ const children = [];
156
+
157
+ if (group.delim === ".") { group.delim = "" }
158
+ children.push(mml.makeText(group.delim, group.mode));
159
+
160
+ const node = new mathMLTree.MathNode("mo", children);
161
+
162
+ if (group.mclass === "mopen" || group.mclass === "mclose") {
163
+ // Only some of the delimsizing functions act as fences, and they
164
+ // return "mopen" or "mclose" mclass.
165
+ node.setAttribute("fence", "true");
166
+ } else {
167
+ // Explicitly disable fencing if it's not a fence, to override the
168
+ // defaults.
169
+ node.setAttribute("fence", "false");
170
+ }
171
+ if (group.delim === "\u2216" || group.delim.indexOf("arrow") > -1) {
172
+ // \backslash is not in the operator dictionary,
173
+ // so we have to explicitly set stretchy to true.
174
+ node.setAttribute("stretchy", "true")
175
+ }
176
+
177
+ node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
178
+ node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
179
+ // Don't set the maxsize attribute. It's broken in Chromium.
180
+ return node;
181
+ }
182
+ });
183
+
184
+ function assertParsed(group) {
185
+ if (!group.body) {
186
+ throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
187
+ }
188
+ }
189
+
190
+ defineFunction({
191
+ type: "leftright-right",
192
+ names: ["\\right"],
193
+ props: {
194
+ numArgs: 1,
195
+ argTypes: ["primitive"]
196
+ },
197
+ handler: (context, args) => {
198
+ // \left case below triggers parsing of \right in
199
+ // `const right = parser.parseFunction();`
200
+ // uses this return value.
201
+ const color = context.parser.gullet.macros.get("\\current@color");
202
+ if (color && typeof color !== "string") {
203
+ throw new ParseError("\\current@color set to non-string in \\right");
204
+ }
205
+ return {
206
+ type: "leftright-right",
207
+ mode: context.parser.mode,
208
+ delim: checkDelimiter(args[0], context).text,
209
+ color // undefined if not set via \color
210
+ };
211
+ }
212
+ });
213
+
214
+ defineFunction({
215
+ type: "leftright",
216
+ names: ["\\left"],
217
+ props: {
218
+ numArgs: 1,
219
+ argTypes: ["primitive"]
220
+ },
221
+ handler: (context, args) => {
222
+ const delim = checkDelimiter(args[0], context);
223
+
224
+ const parser = context.parser;
225
+ // Parse out the implicit body
226
+ ++parser.leftrightDepth;
227
+ // parseExpression stops before '\\right'
228
+ const body = parser.parseExpression(false);
229
+ --parser.leftrightDepth;
230
+ // Check the next token
231
+ parser.expect("\\right", false);
232
+ const right = assertNodeType(parser.parseFunction(), "leftright-right");
233
+ return {
234
+ type: "leftright",
235
+ mode: parser.mode,
236
+ body,
237
+ left: delim.text,
238
+ right: right.delim,
239
+ rightColor: right.color
240
+ };
241
+ },
242
+ mathmlBuilder: (group, style) => {
243
+ assertParsed(group);
244
+ const inner = mml.buildExpression(group.body, style);
245
+
246
+ if (group.left === ".") { group.left = "" }
247
+ const leftNode = new mathMLTree.MathNode("mo", [mml.makeText(group.left, group.mode)]);
248
+ leftNode.setAttribute("fence", "true")
249
+ leftNode.setAttribute("form", "prefix")
250
+ if (group.left === "\u2216" || group.left.indexOf("arrow") > -1) {
251
+ leftNode.setAttribute("stretchy", "true")
252
+ }
253
+ inner.unshift(leftNode)
254
+
255
+ if (group.right === ".") { group.right = "" }
256
+ const rightNode = new mathMLTree.MathNode("mo", [mml.makeText(group.right, group.mode)]);
257
+ rightNode.setAttribute("fence", "true")
258
+ rightNode.setAttribute("form", "postfix")
259
+ if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
260
+ rightNode.setAttribute("stretchy", "true")
261
+ }
262
+ if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor) }
263
+ inner.push(rightNode)
264
+
265
+ return mml.makeRow(inner);
266
+ }
267
+ });
268
+
269
+ defineFunction({
270
+ type: "middle",
271
+ names: ["\\middle"],
272
+ props: {
273
+ numArgs: 1,
274
+ argTypes: ["primitive"]
275
+ },
276
+ handler: (context, args) => {
277
+ const delim = checkDelimiter(args[0], context);
278
+ if (!context.parser.leftrightDepth) {
279
+ throw new ParseError("\\middle without preceding \\left", delim);
280
+ }
281
+
282
+ return {
283
+ type: "middle",
284
+ mode: context.parser.mode,
285
+ delim: delim.text
286
+ };
287
+ },
288
+ mathmlBuilder: (group, style) => {
289
+ const textNode = mml.makeText(group.delim, group.mode);
290
+ const middleNode = new mathMLTree.MathNode("mo", [textNode]);
291
+ middleNode.setAttribute("fence", "true");
292
+ if (group.delim.indexOf("arrow") > -1) {
293
+ middleNode.setAttribute("stretchy", "true")
294
+ }
295
+ // The next line is not semantically correct, but
296
+ // Chromium fails to stretch if it is not there.
297
+ middleNode.setAttribute("form", "prefix")
298
+ // MathML gives 5/18em spacing to each <mo> element.
299
+ // \middle should get delimiter spacing instead.
300
+ middleNode.setAttribute("lspace", "0.05em");
301
+ middleNode.setAttribute("rspace", "0.05em");
302
+ return middleNode;
303
+ }
304
+ });
@@ -0,0 +1,193 @@
1
+ import defineFunction from "../defineFunction";
2
+ import mathMLTree from "../mathMLTree";
3
+ import { assertNodeType } from "../parseNode";
4
+ import { colorFromSpec, validateColor } from "./color"
5
+ import * as mml from "../buildMathML";
6
+
7
+ const padding = _ => {
8
+ const node = new mathMLTree.MathNode("mspace")
9
+ node.setAttribute("width", "3pt")
10
+ return node
11
+ }
12
+
13
+ const mathmlBuilder = (group, style) => {
14
+ let node
15
+ if (group.label.indexOf("colorbox") > -1) {
16
+ // Chrome mpadded +width attribute is broken. Insert <mspace>
17
+ node = new mathMLTree.MathNode("mpadded", [
18
+ padding(),
19
+ mml.buildGroup(group.body, style),
20
+ padding()
21
+ ])
22
+ } else {
23
+ node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
24
+ }
25
+ switch (group.label) {
26
+ case "\\overline":
27
+ node.setAttribute("notation", "top")
28
+ node.style.padding = "0.1em 0 0 0"
29
+ node.style.borderTop = "0.065em solid"
30
+ break
31
+ case "\\underline":
32
+ node.setAttribute("notation", "bottom")
33
+ node.style.padding = "0 0 0.1em 0"
34
+ node.style.borderBottom = "0.065em solid"
35
+ break
36
+ case "\\cancel":
37
+ node.setAttribute("notation", "updiagonalstrike");
38
+ node.classes.push("cancel")
39
+ break
40
+ case "\\bcancel":
41
+ node.setAttribute("notation", "downdiagonalstrike");
42
+ node.classes.push("bcancel")
43
+ break
44
+ /*
45
+ case "\\longdiv":
46
+ node.setAttribute("notation", "longdiv");
47
+ break
48
+ case "\\phase":
49
+ node.setAttribute("notation", "phasorangle");
50
+ break */
51
+ case "\\angl":
52
+ node.setAttribute("notation", "actuarial")
53
+ node.style.padding = "0.03889em 0.03889em 0 0.03889em"
54
+ node.style.borderTop = "0.049em solid"
55
+ node.style.borderRight = "0.049em solid"
56
+ node.style.marginRight = "0.03889em"
57
+ break
58
+ case "\\sout":
59
+ node.setAttribute("notation", "horizontalstrike");
60
+ node.style["text-decoration"] = "line-through 0.08em solid"
61
+ break
62
+ case "\\fbox":
63
+ node.setAttribute("notation", "box");
64
+ node.style = { padding: "3pt", border: "1px solid" }
65
+ break
66
+ case "\\fcolorbox":
67
+ case "\\colorbox": {
68
+ // <menclose> doesn't have a good notation option for \colorbox.
69
+ // So use <mpadded> instead. Set some attributes that come
70
+ // included with <menclose>.
71
+ //const fboxsep = 3; // 3 pt from LaTeX source2e
72
+ //node.setAttribute("height", `+${2 * fboxsep}pt`)
73
+ //node.setAttribute("voffset", `${fboxsep}pt`)
74
+ const style = { padding: "3pt 0 3pt 0" }
75
+
76
+ if (group.label === "\\fcolorbox") {
77
+ style.border = "0.06em solid " + String(group.borderColor)
78
+ }
79
+ node.style = style
80
+ break
81
+ }
82
+ case "\\xcancel":
83
+ node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
84
+ node.classes.push("xcancel")
85
+ break
86
+ }
87
+ if (group.backgroundColor) {
88
+ node.setAttribute("mathbackground", group.backgroundColor);
89
+ }
90
+ return node;
91
+ };
92
+
93
+ defineFunction({
94
+ type: "enclose",
95
+ names: ["\\colorbox"],
96
+ props: {
97
+ numArgs: 2,
98
+ numOptionalArgs: 1,
99
+ allowedInText: true,
100
+ argTypes: ["raw", "raw", "text"]
101
+ },
102
+ handler({ parser, funcName }, args, optArgs) {
103
+ const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string
104
+ let color = ""
105
+ if (model) {
106
+ const spec = assertNodeType(args[0], "raw").string
107
+ color = colorFromSpec(model, spec)
108
+ } else {
109
+ color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros)
110
+ }
111
+ const body = args[1];
112
+ return {
113
+ type: "enclose",
114
+ mode: parser.mode,
115
+ label: funcName,
116
+ backgroundColor: color,
117
+ body
118
+ };
119
+ },
120
+ mathmlBuilder
121
+ });
122
+
123
+ defineFunction({
124
+ type: "enclose",
125
+ names: ["\\fcolorbox"],
126
+ props: {
127
+ numArgs: 3,
128
+ numOptionalArgs: 1,
129
+ allowedInText: true,
130
+ argTypes: ["raw", "raw", "raw", "text"]
131
+ },
132
+ handler({ parser, funcName }, args, optArgs) {
133
+ const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string
134
+ let borderColor = ""
135
+ let backgroundColor
136
+ if (model) {
137
+ const borderSpec = assertNodeType(args[0], "raw").string
138
+ const backgroundSpec = assertNodeType(args[0], "raw").string
139
+ borderColor = colorFromSpec(model, borderSpec)
140
+ backgroundColor = colorFromSpec(model, backgroundSpec)
141
+ } else {
142
+ borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros)
143
+ backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros)
144
+ }
145
+ const body = args[2];
146
+ return {
147
+ type: "enclose",
148
+ mode: parser.mode,
149
+ label: funcName,
150
+ backgroundColor,
151
+ borderColor,
152
+ body
153
+ };
154
+ },
155
+ mathmlBuilder
156
+ });
157
+
158
+ defineFunction({
159
+ type: "enclose",
160
+ names: ["\\fbox"],
161
+ props: {
162
+ numArgs: 1,
163
+ argTypes: ["hbox"],
164
+ allowedInText: true
165
+ },
166
+ handler({ parser }, args) {
167
+ return {
168
+ type: "enclose",
169
+ mode: parser.mode,
170
+ label: "\\fbox",
171
+ body: args[0]
172
+ };
173
+ }
174
+ });
175
+
176
+ defineFunction({
177
+ type: "enclose",
178
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\underline"],
179
+ // , "\\phase", "\\longdiv"
180
+ props: {
181
+ numArgs: 1
182
+ },
183
+ handler({ parser, funcName }, args) {
184
+ const body = args[0];
185
+ return {
186
+ type: "enclose",
187
+ mode: parser.mode,
188
+ label: funcName,
189
+ body
190
+ };
191
+ },
192
+ mathmlBuilder
193
+ });
@@ -0,0 +1,38 @@
1
+ import defineFunction from "../defineFunction";
2
+ import mathMLTree from "../mathMLTree";
3
+
4
+ defineFunction({
5
+ type: "envTag",
6
+ names: ["\\env@tag"],
7
+ props: {
8
+ numArgs: 1,
9
+ argTypes: ["math"]
10
+ },
11
+ handler({ parser }, args) {
12
+ return {
13
+ type: "envTag",
14
+ mode: parser.mode,
15
+ body: args[0]
16
+ };
17
+ },
18
+ mathmlBuilder(group, style) {
19
+ return new mathMLTree.MathNode("mrow");
20
+ }
21
+ });
22
+
23
+ defineFunction({
24
+ type: "noTag",
25
+ names: ["\\env@notag"],
26
+ props: {
27
+ numArgs: 0
28
+ },
29
+ handler({ parser }) {
30
+ return {
31
+ type: "noTag",
32
+ mode: parser.mode
33
+ };
34
+ },
35
+ mathmlBuilder(group, style) {
36
+ return new mathMLTree.MathNode("mrow");
37
+ }
38
+ });
@@ -0,0 +1,59 @@
1
+ import defineFunction from "../defineFunction";
2
+ import ParseError from "../ParseError";
3
+ import { assertNodeType } from "../parseNode";
4
+ import environments from "../environments";
5
+
6
+ // Environment delimiters. HTML/MathML rendering is defined in the corresponding
7
+ // defineEnvironment definitions.
8
+ defineFunction({
9
+ type: "environment",
10
+ names: ["\\begin", "\\end"],
11
+ props: {
12
+ numArgs: 1,
13
+ argTypes: ["text"]
14
+ },
15
+ handler({ parser, funcName }, args) {
16
+ const nameGroup = args[0];
17
+ if (nameGroup.type !== "ordgroup") {
18
+ throw new ParseError("Invalid environment name", nameGroup);
19
+ }
20
+ let envName = "";
21
+ for (let i = 0; i < nameGroup.body.length; ++i) {
22
+ envName += assertNodeType(nameGroup.body[i], "textord").text;
23
+ }
24
+
25
+ if (funcName === "\\begin") {
26
+ // begin...end is similar to left...right
27
+ if (!Object.prototype.hasOwnProperty.call(environments, envName )) {
28
+ throw new ParseError("No such environment: " + envName, nameGroup);
29
+ }
30
+ // Build the environment object. Arguments and other information will
31
+ // be made available to the begin and end methods using properties.
32
+ const env = environments[envName];
33
+ const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env);
34
+ const context = {
35
+ mode: parser.mode,
36
+ envName,
37
+ parser
38
+ };
39
+ const result = env.handler(context, args, optArgs);
40
+ parser.expect("\\end", false);
41
+ const endNameToken = parser.nextToken;
42
+ const end = assertNodeType(parser.parseFunction(), "environment");
43
+ if (end.name !== envName) {
44
+ throw new ParseError(
45
+ `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`,
46
+ endNameToken
47
+ );
48
+ }
49
+ return result;
50
+ }
51
+
52
+ return {
53
+ type: "environment",
54
+ mode: parser.mode,
55
+ name: envName,
56
+ nameGroup
57
+ };
58
+ }
59
+ });