temml 0.10.13 → 0.10.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -276,24 +276,94 @@ const mathmlBuilder = function(group, style) {
276
276
  // Write horizontal rules
277
277
  if (i === 0 && hlines[0].length > 0) {
278
278
  if (hlines[0].length === 2) {
279
- mtr.classes.push("tml-top-double")
279
+ mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double" })
280
280
  } else {
281
- mtr.classes.push(hlines[0][0] ? "tml-top-dashed" : "tml-top-solid")
281
+ mtr.children.forEach(cell => {
282
+ cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid"
283
+ })
282
284
  }
283
285
  }
284
286
  if (hlines[i + 1].length > 0) {
285
287
  if (hlines[i + 1].length === 2) {
286
- mtr.classes.push("tml-hline-double")
288
+ mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double" })
287
289
  } else {
288
- mtr.classes.push(hlines[i + 1][0] ? "tml-hline-dashed" : "tml-hline-solid")
290
+ mtr.children.forEach(cell => {
291
+ cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid"
292
+ })
289
293
  }
290
294
  }
291
295
  tbl.push(mtr);
292
296
  }
293
- let table = new mathMLTree.MathNode("mtable", tbl)
297
+
294
298
  if (group.envClasses.length > 0) {
295
- table.classes = group.envClasses.map(e => "tml-" + e)
299
+ const pad = group.envClasses.includes("jot")
300
+ ? "0.7" // 0.5ex + 0.09em top & bot padding
301
+ : group.envClasses.includes("small")
302
+ ? "0.35"
303
+ : "0.5" // 0.5ex default top & bot padding
304
+ const sidePadding = group.envClasses.includes("abut")
305
+ ? "0"
306
+ : group.envClasses.includes("cases")
307
+ ? "0"
308
+ : group.envClasses.includes("small")
309
+ ? "0.1389"
310
+ : group.envClasses.includes("cd")
311
+ ? "0.25"
312
+ : "0.4" // default side padding
313
+
314
+ const numCols = tbl.length === 0 ? 0 : tbl[0].children.length
315
+
316
+ const sidePad = (j, hand) => {
317
+ if (j === 0 && hand === 0) { return "0" }
318
+ if (j === numCols - 1 && hand === 1) { return "0" }
319
+ if (group.envClasses[0] !== "align") { return sidePadding }
320
+ if (hand === 1) { return "0" }
321
+ if (group.addEqnNum) {
322
+ return (j % 2) ? "1" : "0"
323
+ } else {
324
+ return (j % 2) ? "0" : "1"
325
+ }
326
+ }
327
+
328
+ // Padding
329
+ for (let i = 0; i < tbl.length; i++) {
330
+ for (let j = 0; j < tbl[i].children.length; j++) {
331
+ tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}em ${pad}ex ${sidePad(j, 0)}em`
332
+ }
333
+ }
334
+
335
+ // Justification
336
+ const align = group.envClasses.includes("align") || group.envClasses.includes("alignat")
337
+ for (let i = 0; i < tbl.length; i++) {
338
+ const row = tbl[i];
339
+ if (align) {
340
+ for (let j = 0; j < row.children.length; j++) {
341
+ // Chromium does not recognize text-align: left. Use -webkit-
342
+ // TODO: Remove -webkit- when Chromium no longer needs it.
343
+ row.children[j].style.textAlign = "-webkit-" + (j % 2 ? "left" : "right")
344
+ }
345
+ }
346
+ if (row.children.length > 1 && group.envClasses.includes("cases")) {
347
+ row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em")
348
+ }
349
+
350
+ if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) {
351
+ for (const cell of row.children) {
352
+ cell.style.textAlign = "-webkit-" + "left"
353
+ }
354
+ }
355
+ }
356
+ } else {
357
+ // Set zero padding on side of the matrix
358
+ for (let i = 0; i < tbl.length; i++) {
359
+ tbl[i].children[0].style.paddingLeft = "0em"
360
+ if (tbl[i].children.length === tbl[0].children.length) {
361
+ tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"
362
+ }
363
+ }
296
364
  }
365
+
366
+ let table = new mathMLTree.MathNode("mtable", tbl)
297
367
  if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true") }
298
368
 
299
369
  if (group.addEqnNum || group.envClasses.includes("multline")) {
@@ -373,6 +443,8 @@ const mathmlBuilder = function(group, style) {
373
443
  align = "left " + (align.length > 0 ? align : "center ") + "right "
374
444
  }
375
445
  if (align) {
446
+ // Firefox reads this attribute, not the -webkit-left|right written above.
447
+ // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line.
376
448
  table.setAttribute("columnalign", align.trim())
377
449
  }
378
450
 
@@ -397,7 +469,7 @@ const alignedHandler = function(context, args) {
397
469
  cols,
398
470
  addEqnNum: context.envName === "align" || context.envName === "alignat",
399
471
  emptySingleRow: true,
400
- envClasses: ["jot", "abut"], // set row spacing & provisional column spacing
472
+ envClasses: ["abut", "jot"], // set row spacing & provisional column spacing
401
473
  maxNumCols: context.envName === "split" ? 2 : undefined,
402
474
  leqno: context.parser.settings.leqno
403
475
  },
@@ -415,18 +487,22 @@ const alignedHandler = function(context, args) {
415
487
  // binary. This behavior is implemented in amsmath's \start@aligned.
416
488
  let numMaths;
417
489
  let numCols = 0;
418
- if (args[0] && args[0].type === "ordgroup") {
419
- let arg0 = "";
490
+ const isAlignedAt = context.envName.indexOf("at") > -1
491
+ if (args[0] && isAlignedAt) {
492
+ // alignat environment takes an argument w/ number of columns
493
+ let arg0 = ""
420
494
  for (let i = 0; i < args[0].body.length; i++) {
421
- const textord = assertNodeType(args[0].body[i], "textord");
422
- arg0 += textord.text;
495
+ const textord = assertNodeType(args[0].body[i], "textord")
496
+ arg0 += textord.text
497
+ }
498
+ if (isNaN(arg0)) {
499
+ throw new ParseError("The alignat enviroment requires a numeric first argument.")
423
500
  }
424
- numMaths = Number(arg0);
425
- numCols = numMaths * 2;
501
+ numMaths = Number(arg0)
502
+ numCols = numMaths * 2
426
503
  }
427
- const isAligned = !numCols;
428
504
  res.body.forEach(function(row) {
429
- if (!isAligned) {
505
+ if (isAlignedAt) {
430
506
  // Case 1
431
507
  const curMaths = row.length / 2;
432
508
  if (numMaths < curMaths) {
@@ -456,14 +532,10 @@ const alignedHandler = function(context, args) {
456
532
  }
457
533
  if (context.envName === "split") {
458
534
  // Append no more classes
459
- } else if (context.envName.indexOf("ed") > -1) {
460
- res.envClasses.push("aligned") // Sets justification
461
- } else if (isAligned) {
462
- res.envClasses[1] = context.envName === "align*"
463
- ? "align-star"
464
- : "align" // Sets column spacing & justification
535
+ } else if (isAlignedAt) {
536
+ res.envClasses.push("alignat") // Sets justification
465
537
  } else {
466
- res.envClasses.push("aligned") // Sets justification
538
+ res.envClasses[0] = "align" // Sets column spacing & justification
467
539
  }
468
540
  return res;
469
541
  };
@@ -713,7 +785,7 @@ defineEnvironment({
713
785
  }
714
786
  const res = {
715
787
  cols: [],
716
- envClasses: ["jot", "abut"],
788
+ envClasses: ["abut", "jot"],
717
789
  addEqnNum: context.envName === "gather",
718
790
  emptySingleRow: true,
719
791
  leqno: context.parser.settings.leqno
@@ -178,10 +178,9 @@ defineFunction({
178
178
  // so we have to explicitly set stretchy to true.
179
179
  node.setAttribute("stretchy", "true")
180
180
  }
181
-
182
181
  node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
183
- node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
184
- // Don't set the maxsize attribute. It's broken in Chromium.
182
+ node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em")
183
+ node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em")
185
184
  return node;
186
185
  }
187
186
  });
@@ -12,34 +12,42 @@ const padding = _ => {
12
12
 
13
13
  const mathmlBuilder = (group, style) => {
14
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", [
15
+ if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") {
16
+ // MathML core does not support +width attribute in <mpadded>.
17
+ // Firefox does not reliably add side padding.
18
+ // Insert <mspace>
19
+ node = new mathMLTree.MathNode("mrow", [
18
20
  padding(),
19
21
  mml.buildGroup(group.body, style),
20
22
  padding()
21
23
  ])
22
24
  } else {
23
- node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
25
+ node = new mathMLTree.MathNode("mrow", [mml.buildGroup(group.body, style)])
24
26
  }
25
27
  switch (group.label) {
26
28
  case "\\overline":
27
- node.setAttribute("notation", "top")
28
29
  node.style.padding = "0.1em 0 0 0"
29
30
  node.style.borderTop = "0.065em solid"
30
31
  break
31
32
  case "\\underline":
32
- node.setAttribute("notation", "bottom")
33
33
  node.style.padding = "0 0 0.1em 0"
34
34
  node.style.borderBottom = "0.065em solid"
35
35
  break
36
36
  case "\\cancel":
37
- node.setAttribute("notation", "updiagonalstrike");
38
- node.classes.push("cancel")
37
+ node.style.background = `linear-gradient(to top left,
38
+ rgba(0,0,0,0) 0%,
39
+ rgba(0,0,0,0) calc(50% - 0.06em),
40
+ rgba(0,0,0,1) 50%,
41
+ rgba(0,0,0,0) calc(50% + 0.06em),
42
+ rgba(0,0,0,0) 100%);`
39
43
  break
40
44
  case "\\bcancel":
41
- node.setAttribute("notation", "downdiagonalstrike");
42
- node.classes.push("bcancel")
45
+ node.style.background = `linear-gradient(to top right,
46
+ rgba(0,0,0,0) 0%,
47
+ rgba(0,0,0,0) calc(50% - 0.06em),
48
+ rgba(0,0,0,1) 50%,
49
+ rgba(0,0,0,0) calc(50% + 0.06em),
50
+ rgba(0,0,0,0) 100%);`
43
51
  break
44
52
  /*
45
53
  case "\\longdiv":
@@ -49,18 +57,21 @@ const mathmlBuilder = (group, style) => {
49
57
  node.setAttribute("notation", "phasorangle");
50
58
  break */
51
59
  case "\\angl":
52
- node.setAttribute("notation", "actuarial")
53
60
  node.style.padding = "0.03889em 0.03889em 0 0.03889em"
54
61
  node.style.borderTop = "0.049em solid"
55
62
  node.style.borderRight = "0.049em solid"
56
63
  node.style.marginRight = "0.03889em"
57
64
  break
58
65
  case "\\sout":
59
- node.setAttribute("notation", "horizontalstrike");
60
66
  node.style["text-decoration"] = "line-through 0.08em solid"
61
67
  break
68
+ case "\\boxed":
69
+ // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
70
+ node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }
71
+ node.setAttribute("scriptlevel", "0")
72
+ node.setAttribute("displaystyle", "true")
73
+ break
62
74
  case "\\fbox":
63
- node.setAttribute("notation", "box");
64
75
  node.style = { padding: "3pt", border: "1px solid" }
65
76
  break
66
77
  case "\\fcolorbox":
@@ -80,8 +91,18 @@ const mathmlBuilder = (group, style) => {
80
91
  break
81
92
  }
82
93
  case "\\xcancel":
83
- node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
84
- node.classes.push("xcancel")
94
+ node.style.background = `linear-gradient(to top left,
95
+ rgba(0,0,0,0) 0%,
96
+ rgba(0,0,0,0) calc(50% - 0.06em),
97
+ rgba(0,0,0,1) 50%,
98
+ rgba(0,0,0,0) calc(50% + 0.06em),
99
+ rgba(0,0,0,0) 100%),
100
+ linear-gradient(to top right,
101
+ rgba(0,0,0,0) 0%,
102
+ rgba(0,0,0,0) calc(50% - 0.06em),
103
+ rgba(0,0,0,1) 50%,
104
+ rgba(0,0,0,0) calc(50% + 0.06em),
105
+ rgba(0,0,0,0) 100%);`
85
106
  break
86
107
  }
87
108
  if (group.backgroundColor) {
@@ -175,7 +196,7 @@ defineFunction({
175
196
 
176
197
  defineFunction({
177
198
  type: "enclose",
178
- names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline"],
199
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"],
179
200
  // , "\\phase", "\\longdiv"
180
201
  props: {
181
202
  numArgs: 1
@@ -5,8 +5,6 @@ import { assertNodeType } from "../parseNode"
5
5
  import { calculateSize } from "../units"
6
6
  import * as mml from "../buildMathML"
7
7
 
8
- const sign = num => num >= 0 ? "+" : "-"
9
-
10
8
  // \raise, \lower, and \raisebox
11
9
 
12
10
  const mathmlBuilder = (group, style) => {
@@ -14,11 +12,13 @@ const mathmlBuilder = (group, style) => {
14
12
  const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, newStyle)])
15
13
  const dy = calculateSize(group.dy, style)
16
14
  node.setAttribute("voffset", dy.number + dy.unit)
17
- const dyAbs = Math.abs(dy.number)
18
- // The next two lines do not work in Chromium.
19
- // TODO: Find some other way to adjust height and depth.
20
- node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit)
21
- node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit)
15
+ // Add padding, which acts to increase height in Chromium.
16
+ // TODO: Figure out some way to change height in Firefox w/o breaking Chromium.
17
+ if (dy.number > 0) {
18
+ node.style.padding = dy.number + dy.unit + " 0 0 0"
19
+ } else {
20
+ node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0"
21
+ }
22
22
  return node
23
23
  }
24
24
 
@@ -26,13 +26,16 @@ import { DocumentFragment } from "./tree"
26
26
  * much of this module.
27
27
  */
28
28
 
29
+ const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃"
30
+ const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄"
31
+
29
32
  export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
30
33
  const mtrs = [];
31
34
  let mrows = [];
32
35
  let block = [];
33
36
  let numTopLevelEquals = 0
34
- let canBeBIN = false // The first node cannot be an infix binary operator.
35
37
  let i = 0
38
+ let level = 0
36
39
  while (i < expression.length) {
37
40
  while (expression[i] instanceof DocumentFragment) {
38
41
  expression.splice(i, 1, ...expression[i].children) // Expand the fragment.
@@ -55,7 +58,12 @@ export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
55
58
  }
56
59
  block.push(node);
57
60
  if (node.type && node.type === "mo" && node.children.length === 1) {
58
- if (wrapMode === "=" && node.children[0].text === "=") {
61
+ const ch = node.children[0].text
62
+ if (openDelims.indexOf(ch) > -1) {
63
+ level += 1
64
+ } else if (closeDelims.indexOf(ch) > -1) {
65
+ level -= 1
66
+ } else if (level === 0 && wrapMode === "=" && ch === "=") {
59
67
  numTopLevelEquals += 1
60
68
  if (numTopLevelEquals > 1) {
61
69
  block.pop()
@@ -64,59 +72,48 @@ export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
64
72
  mrows.push(element)
65
73
  block = [node];
66
74
  }
67
- } else if (wrapMode === "tex") {
68
- // This may be a place for a soft line break.
69
- if (canBeBIN && !node.attributes.form) {
70
- // Check if the following node is a \nobreak text node, e.g. "~""
71
- const next = i < expression.length - 1 ? expression[i + 1] : null;
72
- let glueIsFreeOfNobreak = true;
73
- if (
74
- !(
75
- next &&
76
- next.type === "mtext" &&
77
- next.attributes.linebreak &&
78
- next.attributes.linebreak === "nobreak"
79
- )
80
- ) {
81
- // We may need to start a new block.
82
- // First, put any post-operator glue on same line as operator.
83
- for (let j = i + 1; j < expression.length; j++) {
84
- const nd = expression[j];
75
+ } else if (level === 0 && wrapMode === "tex") {
76
+ // Check if the following node is a \nobreak text node, e.g. "~""
77
+ const next = i < expression.length - 1 ? expression[i + 1] : null;
78
+ let glueIsFreeOfNobreak = true;
79
+ if (
80
+ !(
81
+ next &&
82
+ next.type === "mtext" &&
83
+ next.attributes.linebreak &&
84
+ next.attributes.linebreak === "nobreak"
85
+ )
86
+ ) {
87
+ // We may need to start a new block.
88
+ // First, put any post-operator glue on same line as operator.
89
+ for (let j = i + 1; j < expression.length; j++) {
90
+ const nd = expression[j];
91
+ if (
92
+ nd.type &&
93
+ nd.type === "mspace" &&
94
+ !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
95
+ ) {
96
+ block.push(nd);
97
+ i += 1;
85
98
  if (
86
- nd.type &&
87
- nd.type === "mspace" &&
88
- !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
99
+ nd.attributes &&
100
+ nd.attributes.linebreak &&
101
+ nd.attributes.linebreak === "nobreak"
89
102
  ) {
90
- block.push(nd);
91
- i += 1;
92
- if (
93
- nd.attributes &&
94
- nd.attributes.linebreak &&
95
- nd.attributes.linebreak === "nobreak"
96
- ) {
97
- glueIsFreeOfNobreak = false;
98
- }
99
- } else {
100
- break;
103
+ glueIsFreeOfNobreak = false;
101
104
  }
105
+ } else {
106
+ break;
102
107
  }
103
108
  }
104
- if (glueIsFreeOfNobreak) {
105
- // Start a new block. (Insert a soft linebreak.)
106
- const element = new mathMLTree.MathNode("mrow", block)
107
- mrows.push(element)
108
- block = [];
109
- }
110
- canBeBIN = false
111
109
  }
112
- const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"
113
- // Any operator that follows an open delimiter is unary.
114
- canBeBIN = !(node.attributes.separator || isOpenDelimiter);
115
- } else {
116
- canBeBIN = true
110
+ if (glueIsFreeOfNobreak) {
111
+ // Start a new block. (Insert a soft linebreak.)
112
+ const element = new mathMLTree.MathNode("mrow", block)
113
+ mrows.push(element)
114
+ block = [];
115
+ }
117
116
  }
118
- } else {
119
- canBeBIN = true
120
117
  }
121
118
  i += 1
122
119
  }
package/src/macros.js CHANGED
@@ -238,9 +238,6 @@ defineMacro("\u22ee", "\\vdots");
238
238
  //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
239
239
  defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}");
240
240
 
241
- // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
242
- defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}");
243
-
244
241
  // \def\iff{\DOTSB\;\Longleftrightarrow\;}
245
242
  // \def\implies{\DOTSB\;\Longrightarrow\;}
246
243
  // \def\impliedby{\DOTSB\;\Longleftarrow\;}
@@ -489,7 +486,7 @@ defineMacro(
489
486
  defineMacro(
490
487
  "\\Temml",
491
488
  // eslint-disable-next-line max-len
492
- "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
489
+ "\\textrm{T}\\kern-0.2em\\lower{0.2em}{\\textrm{E}}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
493
490
  );
494
491
 
495
492
  // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
@@ -8,7 +8,7 @@
8
8
  * https://mit-license.org/
9
9
  */
10
10
 
11
- export const version = "0.10.13";
11
+ export const version = "0.10.15";
12
12
 
13
13
  export function postProcess(block) {
14
14
  const labelMap = {}
package/src/symbols.js CHANGED
@@ -212,6 +212,10 @@ defineSymbol(math, mathord, "\u21af", "\\lightning", true);
212
212
  defineSymbol(math, mathord, "\u220E", "\\QED", true);
213
213
  defineSymbol(math, mathord, "\u2030", "\\permil", true);
214
214
  defineSymbol(text, textord, "\u2030", "\\permil");
215
+ defineSymbol(math, mathord, "\u2609", "\\astrosun", true);
216
+ defineSymbol(math, mathord, "\u263c", "\\sun", true);
217
+ defineSymbol(math, mathord, "\u263e", "\\leftmoon", true);
218
+ defineSymbol(math, mathord, "\u263d", "\\rightmoon", true);
215
219
 
216
220
  // AMS Negated Binary Relations
217
221
  defineSymbol(math, rel, "\u226e", "\\nless", true);
@@ -356,6 +360,7 @@ defineSymbol(math, rel, "\u2ab7", "\\precapprox", true);
356
360
  defineSymbol(math, rel, "\u22b2", "\\vartriangleleft");
357
361
  defineSymbol(math, rel, "\u22b4", "\\trianglelefteq");
358
362
  defineSymbol(math, rel, "\u22a8", "\\vDash", true);
363
+ defineSymbol(math, rel, "\u22ab", "\\VDash", true);
359
364
  defineSymbol(math, rel, "\u22aa", "\\Vvdash", true);
360
365
  defineSymbol(math, rel, "\u2323", "\\smallsmile");
361
366
  defineSymbol(math, rel, "\u2322", "\\smallfrown");
package/temml.js CHANGED
@@ -21,6 +21,7 @@ import defineMacro from "./src/defineMacro";
21
21
  import { postProcess, version } from "./src/postProcess";
22
22
 
23
23
  /**
24
+ * @type {import('./temml').render}
24
25
  * Parse and build an expression, and place that expression in the DOM node
25
26
  * given.
26
27
  */
@@ -58,6 +59,7 @@ if (typeof document !== "undefined") {
58
59
  }
59
60
 
60
61
  /**
62
+ * @type {import('./temml').renderToString}
61
63
  * Parse and build an expression, and return the markup for that.
62
64
  */
63
65
  const renderToString = function(expression, options) {
@@ -66,6 +68,7 @@ const renderToString = function(expression, options) {
66
68
  };
67
69
 
68
70
  /**
71
+ * @type {import('./temml').generateParseTree}
69
72
  * Parse an expression and return the parse tree.
70
73
  */
71
74
  const generateParseTree = function(expression, options) {
@@ -74,6 +77,7 @@ const generateParseTree = function(expression, options) {
74
77
  };
75
78
 
76
79
  /**
80
+ * @type {import('./temml').definePreamble}
77
81
  * Take an expression which contains a preamble.
78
82
  * Parse it and return the macros.
79
83
  */
@@ -106,6 +110,7 @@ const renderError = function(error, expression, options) {
106
110
  };
107
111
 
108
112
  /**
113
+ * @type {import('./temml').renderToMathMLTree}
109
114
  * Generates and returns the Temml build tree. This is used for advanced
110
115
  * use cases (like rendering to custom output).
111
116
  */
@@ -123,6 +128,7 @@ const renderToMathMLTree = function(expression, options) {
123
128
  }
124
129
  };
125
130
 
131
+ /** @type {import('./temml').default} */
126
132
  export default {
127
133
  /**
128
134
  * Current Temml version