temml 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ });