katex 0.16.44 → 0.16.46

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 (61) hide show
  1. package/README.md +3 -3
  2. package/contrib/copy-tex/README.md +2 -2
  3. package/contrib/mathtex-script-type/README.md +5 -5
  4. package/contrib/mathtex-script-type/mathtex-script-type.js +2 -1
  5. package/contrib/mhchem/README.md +1 -1
  6. package/contrib/render-a11y-string/render-a11y-string.ts +7 -5
  7. package/contrib/render-a11y-string/test/render-a11y-string-spec.ts +0 -1
  8. package/dist/README.md +3 -3
  9. package/dist/contrib/mathtex-script-type.js +2 -1
  10. package/dist/contrib/mathtex-script-type.min.js +1 -1
  11. package/dist/contrib/mathtex-script-type.mjs +2 -1
  12. package/dist/contrib/render-a11y-string.js +47 -8
  13. package/dist/contrib/render-a11y-string.min.js +1 -1
  14. package/dist/contrib/render-a11y-string.mjs +27 -2
  15. package/dist/katex-swap.css +5 -2
  16. package/dist/katex-swap.min.css +1 -1
  17. package/dist/katex.css +5 -2
  18. package/dist/katex.js +551 -345
  19. package/dist/katex.min.css +1 -1
  20. package/dist/katex.min.js +1 -1
  21. package/dist/katex.mjs +522 -348
  22. package/package.json +15 -15
  23. package/src/Options.ts +29 -28
  24. package/src/Parser.ts +12 -15
  25. package/src/Settings.ts +177 -60
  26. package/src/atoms.ts +33 -0
  27. package/src/buildCommon.ts +54 -46
  28. package/src/buildHTML.ts +4 -3
  29. package/src/buildMathML.ts +54 -47
  30. package/src/defineEnvironment.ts +1 -1
  31. package/src/defineFunction.ts +10 -3
  32. package/src/delimiter.ts +17 -13
  33. package/src/domTree.ts +28 -23
  34. package/src/environments/array.ts +12 -6
  35. package/src/environments/cd.ts +9 -2
  36. package/src/fontMetrics.ts +10 -23
  37. package/src/fontMetricsData.d.ts +6 -1
  38. package/src/functions/arrow.ts +4 -5
  39. package/src/functions/delimsizing.ts +22 -16
  40. package/src/functions/enclose.ts +6 -6
  41. package/src/functions/environment.ts +7 -2
  42. package/src/functions/font.ts +13 -8
  43. package/src/functions/hbox.ts +2 -2
  44. package/src/functions/horizBrace.ts +4 -6
  45. package/src/functions/math.ts +1 -0
  46. package/src/functions/op.ts +10 -5
  47. package/src/functions/smash.ts +1 -1
  48. package/src/functions/styling.ts +17 -5
  49. package/src/functions/supsub.ts +6 -3
  50. package/src/functions/text.ts +7 -3
  51. package/src/functions/vcenter.ts +3 -1
  52. package/src/parseNode.ts +7 -5
  53. package/src/stretchy.ts +14 -26
  54. package/src/styles/katex.scss +3 -1
  55. package/src/svgGeometry.ts +32 -27
  56. package/src/symbols.ts +11 -26
  57. package/src/tree.ts +11 -5
  58. package/src/types/fonts.ts +73 -0
  59. package/src/{types.ts → types/index.ts} +4 -10
  60. package/src/utils.ts +0 -1
  61. package/src/wide-character.ts +101 -55
package/dist/katex.js CHANGED
@@ -49,10 +49,6 @@ __webpack_require__.d(__webpack_exports__, {
49
49
  * about where in the source string the problem occurred.
50
50
  */
51
51
  class ParseError extends Error {
52
- // Error start position based on passed-in Token or ParseNode.
53
-
54
- // Length of affected text based on passed-in Token or ParseNode.
55
-
56
52
  // The underlying error message without any context added.
57
53
 
58
54
  constructor(message,
@@ -97,6 +93,11 @@ class ParseError extends Error {
97
93
  }
98
94
  super(error);
99
95
  this.name = "ParseError";
96
+ this.position = void 0;
97
+ // Error start position based on passed-in Token or ParseNode.
98
+ this.length = void 0;
99
+ // Length of affected text based on passed-in Token or ParseNode.
100
+ this.rawMessage = void 0;
100
101
  Object.setPrototypeOf(this, ParseError.prototype);
101
102
  this.position = start;
102
103
  if (start != null && end != null) {
@@ -171,7 +172,6 @@ const protocolFromUrl = url => {
171
172
  // Check for possible leading protocol.
172
173
  // https://url.spec.whatwg.org/#url-parsing strips leading whitespace
173
174
  // (U+20) or C0 control (U+00-U+1F) characters.
174
- // eslint-disable-next-line no-control-regex
175
175
  const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|&#0*58|&#x0*3a|&colon)/i.exec(url);
176
176
  if (!protocol) {
177
177
  return "_relative";
@@ -197,6 +197,13 @@ const protocolFromUrl = url => {
197
197
 
198
198
 
199
199
 
200
+
201
+ /**
202
+ * Union of all values that appear as schema defaults, cliDefaults, or
203
+ * cliProcessor return values. StrictFunction / TrustFunction are
204
+ * option-value types, not default/schema values, so they are excluded.
205
+ */
206
+
200
207
  // TODO: automatically generate documentation
201
208
  // TODO: check all properties on Settings exist
202
209
  // TODO: check the type of a property on Settings matches
@@ -290,16 +297,11 @@ const SETTINGS_SCHEMA = {
290
297
  cli: false
291
298
  }
292
299
  };
293
- function getDefaultValue(schema) {
294
- if ("default" in schema) {
295
- return schema.default;
296
- }
297
- const type = schema.type;
298
- const defaultType = Array.isArray(type) ? type[0] : type;
299
- if (typeof defaultType !== 'string') {
300
- return defaultType.enum[0];
300
+ function getImplicitDefault(type) {
301
+ if (typeof type !== 'string') {
302
+ return type.enum[0];
301
303
  }
302
- switch (defaultType) {
304
+ switch (type) {
303
305
  case 'boolean':
304
306
  return false;
305
307
  case 'string':
@@ -308,8 +310,21 @@ function getDefaultValue(schema) {
308
310
  return 0;
309
311
  case 'object':
310
312
  return {};
313
+ default:
314
+ throw new Error("Unexpected schema type; settings must declare an explicit default.");
311
315
  }
312
316
  }
317
+ function getDefaultValue(schema) {
318
+ if (schema.default !== undefined) {
319
+ return schema.default;
320
+ }
321
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
322
+ return getImplicitDefault(type);
323
+ }
324
+ function applySetting(target, prop, options, schema) {
325
+ const optionValue = options[prop];
326
+ target[prop] = optionValue !== undefined ? schema.processor ? schema.processor(optionValue) : optionValue : getDefaultValue(schema);
327
+ }
313
328
 
314
329
  /**
315
330
  * The main Settings object
@@ -326,13 +341,28 @@ class Settings {
326
341
  if (options === void 0) {
327
342
  options = {};
328
343
  }
344
+ this.displayMode = void 0;
345
+ this.output = void 0;
346
+ this.leqno = void 0;
347
+ this.fleqn = void 0;
348
+ this.throwOnError = void 0;
349
+ this.errorColor = void 0;
350
+ this.macros = void 0;
351
+ this.minRuleThickness = void 0;
352
+ this.colorIsTextColor = void 0;
353
+ this.strict = void 0;
354
+ this.trust = void 0;
355
+ this.maxSize = void 0;
356
+ this.maxExpand = void 0;
357
+ this.globalGroup = void 0;
329
358
  // allow null options
330
359
  options = options || {};
331
360
  for (const prop of Object.keys(SETTINGS_SCHEMA)) {
332
361
  const schema = SETTINGS_SCHEMA[prop];
333
- const optionValue = options[prop];
334
- // TODO: validate options
335
- this[prop] = optionValue !== undefined ? schema.processor ? schema.processor(optionValue) : optionValue : getDefaultValue(schema);
362
+ if (schema) {
363
+ // TODO: validate options
364
+ applySetting(this, prop, options, schema);
365
+ }
336
366
  }
337
367
  }
338
368
 
@@ -429,6 +459,9 @@ class Settings {
429
459
  */
430
460
  class Style {
431
461
  constructor(id, size, cramped) {
462
+ this.id = void 0;
463
+ this.size = void 0;
464
+ this.cramped = void 0;
432
465
  this.id = id;
433
466
  this.size = size;
434
467
  this.cramped = cramped;
@@ -640,6 +673,18 @@ function supportedCodepoint(codepoint) {
640
673
 
641
674
  // In all paths below, the viewBox-to-em scale is 1000:1.
642
675
 
676
+ // Second Brush Stroke
677
+ // Low resolution monitors struggle to display images in fine detail.
678
+ // So browsers apply anti-aliasing. A long straight arrow shaft therefore
679
+ // will sometimes appear as if it has a blurred edge.
680
+
681
+ // To mitigate this, these SVG files contain a second "brush-stroke" on the
682
+ // arrow shafts. That is, a second long thin rectangular SVG path has been
683
+ // written directly on top of each arrow shaft. This reinforcement causes
684
+ // some of the screen pixels to display as black instead of the anti-aliased
685
+ // gray pixel that a single path would generate. So we get arrow shafts
686
+ // whose edges appear to be sharper.
687
+ const doubleBrushStroke = svgPath => svgPath + " " + svgPath;
643
688
  const hLinePad = 80; // padding above a sqrt vinculum. Prevents image cropping.
644
689
 
645
690
  // The vinculum of a \sqrt can be made thicker by a KaTeX rendering option.
@@ -720,23 +765,23 @@ const innerPath = function (name, height) {
720
765
  // The inner part of stretchy tall delimiters
721
766
  switch (name) {
722
767
  case "\u239c":
723
- return "M291 0 H417 V" + height + " H291z M291 0 H417 V" + height + " H291z";
768
+ return doubleBrushStroke("M291 0 H417 V" + height + " H291z");
724
769
  case "\u2223":
725
- return "M145 0 H188 V" + height + " H145z M145 0 H188 V" + height + " H145z";
770
+ return doubleBrushStroke("M145 0 H188 V" + height + " H145z");
726
771
  case "\u2225":
727
- return "M145 0 H188 V" + height + " H145z M145 0 H188 V" + height + " H145z" + ("M367 0 H410 V" + height + " H367z M367 0 H410 V" + height + " H367z");
772
+ return doubleBrushStroke("M145 0 H188 V" + height + " H145z") + doubleBrushStroke("M367 0 H410 V" + height + " H367z");
728
773
  case "\u239f":
729
- return "M457 0 H583 V" + height + " H457z M457 0 H583 V" + height + " H457z";
774
+ return doubleBrushStroke("M457 0 H583 V" + height + " H457z");
730
775
  case "\u23a2":
731
- return "M319 0 H403 V" + height + " H319z M319 0 H403 V" + height + " H319z";
776
+ return doubleBrushStroke("M319 0 H403 V" + height + " H319z");
732
777
  case "\u23a5":
733
- return "M263 0 H347 V" + height + " H263z M263 0 H347 V" + height + " H263z";
778
+ return doubleBrushStroke("M263 0 H347 V" + height + " H263z");
734
779
  case "\u23aa":
735
- return "M384 0 H504 V" + height + " H384z M384 0 H504 V" + height + " H384z";
780
+ return doubleBrushStroke("M384 0 H504 V" + height + " H384z");
736
781
  case "\u23d0":
737
- return "M312 0 H355 V" + height + " H312z M312 0 H355 V" + height + " H312z";
782
+ return doubleBrushStroke("M312 0 H355 V" + height + " H312z");
738
783
  case "\u2016":
739
- return "M257 0 H300 V" + height + " H257z M257 0 H300 V" + height + " H257z" + ("M478 0 H521 V" + height + " H478z M478 0 H521 V" + height + " H478z");
784
+ return doubleBrushStroke("M257 0 H300 V" + height + " H257z") + doubleBrushStroke("M478 0 H521 V" + height + " H478z");
740
785
  default:
741
786
  return "";
742
787
  }
@@ -761,13 +806,13 @@ const path = {
761
806
  leftharpoondownplus: "M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12\n 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7\n-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0\nv40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z",
762
807
  // hook is from glyph U+21A9 in font KaTeX Main
763
808
  lefthook: "M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5\n-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3\n-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21\n 71.5 23h399859zM103 281v-40h399897v40z",
764
- leftlinesegment: "M40 281 V428 H0 V94 H40 V241 H400000 v40z\nM40 281 V428 H0 V94 H40 V241 H400000 v40z",
765
- leftbracketunder: "M0 0 h120 V290 H399995 v120 H0z\nM0 0 h120 V290 H399995 v120 H0z",
766
- leftbracketover: "M0 440 h120 V150 H399995 v-120 H0z\nM0 440 h120 V150 H399995 v-120 H0z",
767
- leftmapsto: "M40 281 V448H0V74H40V241H400000v40z\nM40 281 V448H0V74H40V241H400000v40z",
809
+ leftlinesegment: doubleBrushStroke("M40 281 V428 H0 V94 H40 V241 H400000 v40z"),
810
+ leftbracketunder: doubleBrushStroke("M0 0 h120 V290 H399995 v120 H0z"),
811
+ leftbracketover: doubleBrushStroke("M0 440 h120 V150 H399995 v-120 H0z"),
812
+ leftmapsto: doubleBrushStroke("M40 281 V448H0V74H40V241H400000v40z"),
768
813
  // tofrom is from glyph U+21C4 in font KaTeX AMS Regular
769
814
  leftToFrom: "M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23\n-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8\nc28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3\n 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z",
770
- longequal: "M0 50 h400000 v40H0z m0 194h40000v40H0z\nM0 50 h400000 v40H0z m0 194h40000v40H0z",
815
+ longequal: doubleBrushStroke("M0 50 h400000 v40H0z m0 194h40000v40H0z"),
771
816
  midbrace: "M200428 334\nc-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14\n-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7\n 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11\n 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z",
772
817
  midbraceunder: "M199572 214\nc100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14\n 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3\n 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0\n-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z",
773
818
  oiintSize1: "M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6\n-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z\nm368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8\n60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z",
@@ -784,9 +829,9 @@ const path = {
784
829
  rightharpoondown: "M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8\n 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5\n-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95\n-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z",
785
830
  rightharpoondownplus: "M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8\n 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3\n 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3\n-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z\nm0-194v40h400000v-40zm0 0v40h400000v-40z",
786
831
  righthook: "M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3\n 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0\n-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21\n 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z",
787
- rightlinesegment: "M399960 241 V94 h40 V428 h-40 V281 H0 v-40z\nM399960 241 V94 h40 V428 h-40 V281 H0 v-40z",
788
- rightbracketunder: "M399995 0 h-120 V290 H0 v120 H400000z\nM399995 0 h-120 V290 H0 v120 H400000z",
789
- rightbracketover: "M399995 440 h-120 V150 H0 v-120 H399995z\nM399995 440 h-120 V150 H0 v-120 H399995z",
832
+ rightlinesegment: doubleBrushStroke("M399960 241 V94 h40 V428 h-40 V281 H0 v-40z"),
833
+ rightbracketunder: doubleBrushStroke("M399995 0 h-120 V290 H0 v120 H400000z"),
834
+ rightbracketover: doubleBrushStroke("M399995 440 h-120 V150 H0 v-120 H399995z"),
790
835
  rightToFrom: "M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23\n 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32\n-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142\n-167z M100 147v40h399900v-40zM0 341v40h399900v-40z",
791
836
  // twoheadleftarrow is from glyph U+219E in font KaTeX AMS Regular
792
837
  twoheadleftarrow: "M0 167c68 40\n 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69\n-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3\n-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19\n-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101\n 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z",
@@ -854,6 +899,10 @@ const tallDelim = function (label, midHeight) {
854
899
  ;// ./src/tree.ts
855
900
  // To ensure that all nodes have compatible signatures for these methods.
856
901
 
902
+ function isMathDomNode(node) {
903
+ return 'toText' in node;
904
+ }
905
+
857
906
  /**
858
907
  * This node represents a document fragment, which contains elements, but when
859
908
  * placed into the DOM doesn't have any representation itself. It only contains
@@ -863,6 +912,12 @@ class DocumentFragment {
863
912
  // Never used; needed for satisfying interface.
864
913
 
865
914
  constructor(children) {
915
+ this.children = void 0;
916
+ this.classes = void 0;
917
+ this.height = void 0;
918
+ this.depth = void 0;
919
+ this.maxFontSize = void 0;
920
+ this.style = void 0;
866
921
  this.children = children;
867
922
  this.classes = [];
868
923
  this.height = 0;
@@ -899,11 +954,12 @@ class DocumentFragment {
899
954
  * MathDomNode's only.
900
955
  */
901
956
  toText() {
902
- // To avoid this, we would subclass documentFragment separately for
903
- // MathML, but polyfills for subclassing is expensive per PR 1469.
904
- // TODO(ts): Only works for ChildType = MathDomNode.
905
- const toText = child => child.toText();
906
- return this.children.map(toText).join("");
957
+ return this.children.map(child => {
958
+ if (isMathDomNode(child)) {
959
+ return child.toText();
960
+ }
961
+ throw new Error("Expected MathDomNode with toText, got " + child.constructor.name);
962
+ }).join("");
907
963
  }
908
964
  }
909
965
  ;// ./src/units.ts
@@ -1042,6 +1098,21 @@ const makeEm = function (n) {
1042
1098
  const createClass = function (classes) {
1043
1099
  return classes.filter(cls => cls).join(" ");
1044
1100
  };
1101
+
1102
+ /**
1103
+ * Serialize a CssStyle object into a semicolon-delimited inline-style string
1104
+ * (hyphenating camelCase property names). Returns "" when no property is set.
1105
+ */
1106
+ const cssStyleToString = function (style) {
1107
+ let styles = "";
1108
+ for (const key of Object.keys(style)) {
1109
+ const value = style[key];
1110
+ if (value !== undefined) {
1111
+ styles += hyphenate(key) + ":" + value + ";";
1112
+ }
1113
+ }
1114
+ return styles;
1115
+ };
1045
1116
  const initNode = function (classes, options, style) {
1046
1117
  this.classes = classes || [];
1047
1118
  this.attributes = {};
@@ -1070,9 +1141,7 @@ const toNode = function (tagName) {
1070
1141
  node.className = createClass(this.classes);
1071
1142
 
1072
1143
  // Apply inline styles
1073
- for (const key of Object.keys(this.style)) {
1074
- node.style[key] = this.style[key];
1075
- }
1144
+ Object.assign(node.style, this.style);
1076
1145
 
1077
1146
  // Apply attributes
1078
1147
  for (const attr of Object.keys(this.attributes)) {
@@ -1106,12 +1175,7 @@ const toMarkup = function (tagName) {
1106
1175
  if (this.classes.length) {
1107
1176
  markup += " class=\"" + utils_escape(createClass(this.classes)) + "\"";
1108
1177
  }
1109
- let styles = "";
1110
-
1111
- // Add the styles, after hyphenation
1112
- for (const key of Object.keys(this.style)) {
1113
- styles += hyphenate(key) + ":" + this.style[key] + ";";
1114
- }
1178
+ const styles = cssStyleToString(this.style);
1115
1179
  if (styles) {
1116
1180
  markup += " style=\"" + utils_escape(styles) + "\"";
1117
1181
  }
@@ -1156,6 +1220,20 @@ const toMarkup = function (tagName) {
1156
1220
  */
1157
1221
  class Span {
1158
1222
  constructor(classes, children, options, style) {
1223
+ this.children = void 0;
1224
+ this.attributes = void 0;
1225
+ this.classes = void 0;
1226
+ this.height = void 0;
1227
+ this.depth = void 0;
1228
+ this.width = void 0;
1229
+ this.maxFontSize = void 0;
1230
+ this.style = void 0;
1231
+ /**
1232
+ * Italic correction carried over from a SymbolNode when the symbol is
1233
+ * wrapped in a vlist (e.g. \oiint / \oiiint). Read by supsub to adjust
1234
+ * subscript positioning. Only set when nonzero; use `?? 0` at read sites.
1235
+ */
1236
+ this.italic = void 0;
1159
1237
  initNode.call(this, classes, options, style);
1160
1238
  this.children = children || [];
1161
1239
  }
@@ -1185,6 +1263,13 @@ class Span {
1185
1263
  */
1186
1264
  class Anchor {
1187
1265
  constructor(href, classes, children, options) {
1266
+ this.children = void 0;
1267
+ this.attributes = void 0;
1268
+ this.classes = void 0;
1269
+ this.height = void 0;
1270
+ this.depth = void 0;
1271
+ this.maxFontSize = void 0;
1272
+ this.style = void 0;
1188
1273
  initNode.call(this, classes, options);
1189
1274
  this.children = children || [];
1190
1275
  this.setAttribute('href', href);
@@ -1208,6 +1293,13 @@ class Anchor {
1208
1293
  */
1209
1294
  class Img {
1210
1295
  constructor(src, alt, style) {
1296
+ this.src = void 0;
1297
+ this.alt = void 0;
1298
+ this.classes = void 0;
1299
+ this.height = void 0;
1300
+ this.depth = void 0;
1301
+ this.maxFontSize = void 0;
1302
+ this.style = void 0;
1211
1303
  this.alt = alt;
1212
1304
  this.src = src;
1213
1305
  this.classes = ["mord"];
@@ -1226,19 +1318,12 @@ class Img {
1226
1318
  node.className = "mord";
1227
1319
 
1228
1320
  // Apply inline styles
1229
- for (const key of Object.keys(this.style)) {
1230
- node.style[key] = this.style[key];
1231
- }
1321
+ Object.assign(node.style, this.style);
1232
1322
  return node;
1233
1323
  }
1234
1324
  toMarkup() {
1235
1325
  let markup = "<img src=\"" + utils_escape(this.src) + "\"" + (" alt=\"" + utils_escape(this.alt) + "\"");
1236
-
1237
- // Add the styles, after hyphenation
1238
- let styles = "";
1239
- for (const key of Object.keys(this.style)) {
1240
- styles += hyphenate(key) + ":" + this.style[key] + ";";
1241
- }
1326
+ const styles = cssStyleToString(this.style);
1242
1327
  if (styles) {
1243
1328
  markup += " style=\"" + utils_escape(styles) + "\"";
1244
1329
  }
@@ -1261,6 +1346,15 @@ const iCombinations = {
1261
1346
  */
1262
1347
  class SymbolNode {
1263
1348
  constructor(text, height, depth, italic, skew, width, classes, style) {
1349
+ this.text = void 0;
1350
+ this.height = void 0;
1351
+ this.depth = void 0;
1352
+ this.italic = void 0;
1353
+ this.skew = void 0;
1354
+ this.width = void 0;
1355
+ this.maxFontSize = void 0;
1356
+ this.classes = void 0;
1357
+ this.style = void 0;
1264
1358
  this.text = text;
1265
1359
  this.height = height || 0;
1266
1360
  this.depth = depth || 0;
@@ -1306,9 +1400,9 @@ class SymbolNode {
1306
1400
  span = span || document.createElement("span");
1307
1401
  span.className = createClass(this.classes);
1308
1402
  }
1309
- for (const key of Object.keys(this.style)) {
1403
+ if (Object.keys(this.style).length > 0) {
1310
1404
  span = span || document.createElement("span");
1311
- span.style[key] = this.style[key];
1405
+ Object.assign(span.style, this.style);
1312
1406
  }
1313
1407
  if (span) {
1314
1408
  span.appendChild(node);
@@ -1336,9 +1430,7 @@ class SymbolNode {
1336
1430
  if (this.italic > 0) {
1337
1431
  styles += "margin-right:" + makeEm(this.italic) + ";";
1338
1432
  }
1339
- for (const key of Object.keys(this.style)) {
1340
- styles += hyphenate(key) + ":" + this.style[key] + ";";
1341
- }
1433
+ styles += cssStyleToString(this.style);
1342
1434
  if (styles) {
1343
1435
  needsSpan = true;
1344
1436
  markup += " style=\"" + utils_escape(styles) + "\"";
@@ -1360,6 +1452,8 @@ class SymbolNode {
1360
1452
  */
1361
1453
  class SvgNode {
1362
1454
  constructor(children, attributes) {
1455
+ this.children = void 0;
1456
+ this.attributes = void 0;
1363
1457
  this.children = children || [];
1364
1458
  this.attributes = attributes || {};
1365
1459
  }
@@ -1393,6 +1487,8 @@ class SvgNode {
1393
1487
  }
1394
1488
  class PathNode {
1395
1489
  constructor(pathName, alternate) {
1490
+ this.pathName = void 0;
1491
+ this.alternate = void 0;
1396
1492
  this.pathName = pathName;
1397
1493
  this.alternate = alternate; // Used only for \sqrt, \phase, & tall delims
1398
1494
  }
@@ -1416,6 +1512,7 @@ class PathNode {
1416
1512
  }
1417
1513
  class LineNode {
1418
1514
  constructor(attributes) {
1515
+ this.attributes = void 0;
1419
1516
  this.attributes = attributes || {};
1420
1517
  }
1421
1518
  toNode() {
@@ -3539,6 +3636,12 @@ const hasHtmlDomChildren = node => node instanceof Span || node instanceof Ancho
3539
3636
  });
3540
3637
  ;// ./src/fontMetrics.ts
3541
3638
 
3639
+ // This map contains a mapping from font name and character code to character
3640
+ // metrics, including height, depth, italic correction, and skew (kern from the
3641
+ // character to the corresponding \skewchar)
3642
+ // This map is generated via `make metrics`. It should not be changed manually.
3643
+
3644
+
3542
3645
  /**
3543
3646
  * This file contains metrics regarding fonts and individual symbols. The sigma
3544
3647
  * and xi variables, as well as the metricMap map contain data extracted from
@@ -3653,12 +3756,6 @@ const sigmasAndXis = {
3653
3756
  fboxrule: [0.04, 0.04, 0.04] // 0.4 pt / ptPerEm
3654
3757
  };
3655
3758
 
3656
- // This map contains a mapping from font name and character code to character
3657
- // metrics, including height, depth, italic correction, and skew (kern from the
3658
- // character to the corresponding \skewchar)
3659
- // This map is generated via `make metrics`. It should not be changed manually.
3660
-
3661
-
3662
3759
  // These are very rough approximations. We default to Times New Roman which
3663
3760
  // should have Latin-1 and Cyrillic characters, but may not depending on the
3664
3761
  // operating system. The metrics do not account for extra height from the
@@ -3740,6 +3837,7 @@ const extraCharacterMap = {
3740
3837
  'ю': 'm',
3741
3838
  'я': 'r'
3742
3839
  };
3840
+
3743
3841
  /**
3744
3842
  * This function adds new font metrics to default metricMap
3745
3843
  * It can also override existing metrics
@@ -3837,21 +3935,7 @@ function getGlobalMetrics(size) {
3837
3935
  // types for raw text tokens, and we want to avoid conflicts with higher-level
3838
3936
  // `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
3839
3937
  // looking up the `symbols` map.
3840
- const ATOMS = {
3841
- "bin": 1,
3842
- "close": 1,
3843
- "inner": 1,
3844
- "open": 1,
3845
- "punct": 1,
3846
- "rel": 1
3847
- };
3848
- const NON_ATOMS = {
3849
- "accent-token": 1,
3850
- "mathord": 1,
3851
- "op-token": 1,
3852
- "spacing": 1,
3853
- "textord": 1
3854
- };
3938
+
3855
3939
  const symbols = {
3856
3940
  "math": {},
3857
3941
  "text": {}
@@ -4397,8 +4481,8 @@ defineSymbol(symbols_text, main, spacing, "\u00a0", "\\ ");
4397
4481
  defineSymbol(symbols_text, main, spacing, "\u00a0", " ");
4398
4482
  defineSymbol(symbols_text, main, spacing, "\u00a0", "\\space");
4399
4483
  defineSymbol(symbols_text, main, spacing, "\u00a0", "\\nobreakspace");
4400
- defineSymbol(math, main, spacing, null, "\\nobreak");
4401
- defineSymbol(math, main, spacing, null, "\\allowbreak");
4484
+ defineSymbol(math, main, spacing, "", "\\nobreak");
4485
+ defineSymbol(math, main, spacing, "", "\\allowbreak");
4402
4486
  defineSymbol(math, main, punct, ",", ",");
4403
4487
  defineSymbol(math, main, punct, ";", ";");
4404
4488
  defineSymbol(math, ams, bin, "\u22bc", "\\barwedge", true);
@@ -4600,7 +4684,7 @@ defineSymbol(symbols_text, main, mathord, "h", "\u210E");
4600
4684
  // Mathematical Alphanumeric Symbols.
4601
4685
  // Some editors do not deal well with wide characters. So don't write the
4602
4686
  // string into this file. Instead, create the string from the surrogate pair.
4603
- let wideChar = "";
4687
+ let wideChar;
4604
4688
  for (let i = 0; i < letters.length; i++) {
4605
4689
  const ch = letters.charAt(i);
4606
4690
 
@@ -4689,116 +4773,136 @@ for (let i = 0; i < extraLatin.length; i++) {
4689
4773
  */
4690
4774
 
4691
4775
 
4776
+ const boldUpright = {
4777
+ mathClass: "mathbf",
4778
+ textClass: "textbf",
4779
+ font: "Main-Bold"
4780
+ };
4781
+ const italic = {
4782
+ mathClass: "mathnormal",
4783
+ textClass: "textit",
4784
+ font: "Math-Italic"
4785
+ };
4786
+ const boldItalic = {
4787
+ mathClass: "boldsymbol",
4788
+ textClass: "boldsymbol",
4789
+ font: "Main-BoldItalic"
4790
+ };
4791
+ const script = {
4792
+ mathClass: "mathscr",
4793
+ textClass: "textscr",
4794
+ font: "Script-Regular"
4795
+ };
4796
+ const noFont = {
4797
+ mathClass: "",
4798
+ textClass: "",
4799
+ font: ""
4800
+ };
4801
+ const fraktur = {
4802
+ mathClass: "mathfrak",
4803
+ textClass: "textfrak",
4804
+ font: "Fraktur-Regular"
4805
+ };
4806
+ const doubleStruck = {
4807
+ mathClass: "mathbb",
4808
+ textClass: "textbb",
4809
+ font: "AMS-Regular"
4810
+ };
4811
+ const boldFraktur = {
4812
+ mathClass: "mathboldfrak",
4813
+ textClass: "textboldfrak",
4814
+ font: "Fraktur-Regular"
4815
+ };
4816
+ const sansSerif = {
4817
+ mathClass: "mathsf",
4818
+ textClass: "textsf",
4819
+ font: "SansSerif-Regular"
4820
+ };
4821
+ const boldSansSerif = {
4822
+ mathClass: "mathboldsf",
4823
+ textClass: "textboldsf",
4824
+ font: "SansSerif-Bold"
4825
+ };
4826
+ const italicSansSerif = {
4827
+ mathClass: "mathitsf",
4828
+ textClass: "textitsf",
4829
+ font: "SansSerif-Italic"
4830
+ };
4831
+ const monospace = {
4832
+ mathClass: "mathtt",
4833
+ textClass: "texttt",
4834
+ font: "Typewriter-Regular"
4835
+ };
4692
4836
 
4693
4837
  /**
4694
4838
  * Data below is from https://www.unicode.org/charts/PDF/U1D400.pdf
4695
4839
  * That document sorts characters into groups by font type, say bold or italic.
4696
4840
  *
4697
- * In the arrays below, each subarray consists three elements:
4841
+ * In the arrays below, each object consists of three properties:
4698
4842
  * * The CSS class of that group when in math mode.
4699
4843
  * * The CSS class of that group when in text mode.
4700
4844
  * * The font name, so that KaTeX can get font metrics.
4701
4845
  */
4702
4846
 
4703
- const wideLatinLetterData = [["mathbf", "textbf", "Main-Bold"],
4704
- // A-Z bold upright
4705
- ["mathbf", "textbf", "Main-Bold"],
4706
- // a-z bold upright
4707
-
4708
- ["mathnormal", "textit", "Math-Italic"],
4709
- // A-Z italic
4710
- ["mathnormal", "textit", "Math-Italic"],
4711
- // a-z italic
4712
-
4713
- ["boldsymbol", "boldsymbol", "Main-BoldItalic"],
4714
- // A-Z bold italic
4715
- ["boldsymbol", "boldsymbol", "Main-BoldItalic"],
4716
- // a-z bold italic
4717
-
4847
+ const wideLatinLetterData = [boldUpright, boldUpright,
4848
+ // A-Z, a-z
4849
+ italic, italic,
4850
+ // A-Z, a-z
4851
+ boldItalic, boldItalic,
4852
+ // A-Z, a-z
4718
4853
  // Map fancy A-Z letters to script, not calligraphic.
4719
4854
  // This aligns with unicode-math and math fonts (except Cambria Math).
4720
- ["mathscr", "textscr", "Script-Regular"],
4721
- // A-Z script
4722
- ["", "", ""],
4723
- // a-z script. No font
4724
-
4725
- ["", "", ""],
4726
- // A-Z bold script. No font
4727
- ["", "", ""],
4728
- // a-z bold script. No font
4729
-
4730
- ["mathfrak", "textfrak", "Fraktur-Regular"],
4731
- // A-Z Fraktur
4732
- ["mathfrak", "textfrak", "Fraktur-Regular"],
4733
- // a-z Fraktur
4734
-
4735
- ["mathbb", "textbb", "AMS-Regular"],
4736
- // A-Z double-struck
4737
- ["mathbb", "textbb", "AMS-Regular"],
4738
- // k double-struck
4739
-
4855
+ script, noFont,
4856
+ // A-Z script, a-z — no font
4857
+ noFont, noFont,
4858
+ // A-Z bold script, a-z bold script — no font
4859
+ fraktur, fraktur,
4860
+ // A-Z, a-z
4861
+ doubleStruck, doubleStruck,
4862
+ // A-Z double-struck, k double-struck
4740
4863
  // Note that we are using a bold font, but font metrics for regular Fraktur.
4741
- ["mathboldfrak", "textboldfrak", "Fraktur-Regular"],
4742
- // A-Z bold Fraktur
4743
- ["mathboldfrak", "textboldfrak", "Fraktur-Regular"],
4744
- // a-z bold Fraktur
4745
-
4746
- ["mathsf", "textsf", "SansSerif-Regular"],
4747
- // A-Z sans-serif
4748
- ["mathsf", "textsf", "SansSerif-Regular"],
4749
- // a-z sans-serif
4750
-
4751
- ["mathboldsf", "textboldsf", "SansSerif-Bold"],
4752
- // A-Z bold sans-serif
4753
- ["mathboldsf", "textboldsf", "SansSerif-Bold"],
4754
- // a-z bold sans-serif
4755
-
4756
- ["mathitsf", "textitsf", "SansSerif-Italic"],
4757
- // A-Z italic sans-serif
4758
- ["mathitsf", "textitsf", "SansSerif-Italic"],
4759
- // a-z italic sans-serif
4760
-
4761
- ["", "", ""],
4762
- // A-Z bold italic sans. No font
4763
- ["", "", ""],
4764
- // a-z bold italic sans. No font
4765
-
4766
- ["mathtt", "texttt", "Typewriter-Regular"],
4767
- // A-Z monospace
4768
- ["mathtt", "texttt", "Typewriter-Regular"] // a-z monospace
4864
+ boldFraktur, boldFraktur,
4865
+ // A-Z, a-z
4866
+ sansSerif, sansSerif,
4867
+ // A-Z, a-z
4868
+ boldSansSerif, boldSansSerif,
4869
+ // A-Z, a-z
4870
+ italicSansSerif, italicSansSerif,
4871
+ // A-Z, a-z
4872
+ noFont, noFont,
4873
+ // A-Z bold italic sans, a-z bold italic sans - no font
4874
+ monospace, monospace // A-Z, a-z
4769
4875
  ];
4770
- const wideNumeralData = [["mathbf", "textbf", "Main-Bold"],
4771
- // 0-9 bold
4772
- ["", "", ""],
4876
+ const wideNumeralData = [boldUpright,
4877
+ // 0-9
4878
+ noFont,
4773
4879
  // 0-9 double-struck. No KaTeX font.
4774
- ["mathsf", "textsf", "SansSerif-Regular"],
4775
- // 0-9 sans-serif
4776
- ["mathboldsf", "textboldsf", "SansSerif-Bold"],
4777
- // 0-9 bold sans-serif
4778
- ["mathtt", "texttt", "Typewriter-Regular"] // 0-9 monospace
4880
+ sansSerif,
4881
+ // 0-9
4882
+ boldSansSerif,
4883
+ // 0-9
4884
+ monospace // 0-9
4779
4885
  ];
4780
- const wideCharacterFont = (wideChar, mode) => {
4886
+ const wideCharacterFont = wideChar => {
4781
4887
  // IE doesn't support codePointAt(). So work with the surrogate pair.
4782
4888
  const H = wideChar.charCodeAt(0); // high surrogate
4783
4889
  const L = wideChar.charCodeAt(1); // low surrogate
4784
4890
  const codePoint = (H - 0xD800) * 0x400 + (L - 0xDC00) + 0x10000;
4785
- const j = mode === "math" ? 0 : 1; // column index for CSS class.
4786
-
4787
4891
  if (0x1D400 <= codePoint && codePoint < 0x1D6A4) {
4788
4892
  // wideLatinLetterData contains exactly 26 chars on each row.
4789
4893
  // So we can calculate the relevant row. No traverse necessary.
4790
4894
  const i = Math.floor((codePoint - 0x1D400) / 26);
4791
- return [wideLatinLetterData[i][2], wideLatinLetterData[i][j]];
4895
+ return wideLatinLetterData[i];
4792
4896
  } else if (0x1D7CE <= codePoint && codePoint <= 0x1D7FF) {
4793
4897
  // Numerals, ten per row.
4794
4898
  const i = Math.floor((codePoint - 0x1D7CE) / 10);
4795
- return [wideNumeralData[i][2], wideNumeralData[i][j]];
4899
+ return wideNumeralData[i];
4796
4900
  } else if (codePoint === 0x1D6A5 || codePoint === 0x1D6A6) {
4797
4901
  // dotless i or j
4798
- return [wideLatinLetterData[0][2], wideLatinLetterData[0][j]];
4902
+ return wideLatinLetterData[0];
4799
4903
  } else if (0x1D6A6 < codePoint && codePoint < 0x1D7CE) {
4800
4904
  // Greek letters. Not supported, yet.
4801
- return ["", ""];
4905
+ return noFont;
4802
4906
  } else {
4803
4907
  // We don't support any wide characters outside 1D400–1D7FF.
4804
4908
  throw new src_ParseError("Unsupported character: " + wideChar);
@@ -4821,9 +4925,7 @@ const wideCharacterFont = (wideChar, mode) => {
4821
4925
  * Looks up the given symbol in fontMetrics, after applying any symbol
4822
4926
  * replacements defined in symbol.js
4823
4927
  */
4824
- const lookupSymbol = function (value,
4825
- // TODO(#963): Use a union type for this.
4826
- fontName, mode) {
4928
+ const lookupSymbol = function (value, fontName, mode) {
4827
4929
  // Replace the value with its replaced value from symbol.js
4828
4930
  if (src_symbols[mode][value]) {
4829
4931
  const replacement = src_symbols[mode][value].replace;
@@ -4906,7 +5008,7 @@ const mathsym = function (value, mode, options, classes) {
4906
5008
  * depending on the symbol. Use this function instead of fontMap for font
4907
5009
  * "boldsymbol".
4908
5010
  */
4909
- const boldsymbol = function (value, mode, options, classes, type) {
5011
+ const boldSymbol = function (value, mode, type) {
4910
5012
  if (type !== "textord" && lookupSymbol(value, "Math-BoldItalic", mode).metrics) {
4911
5013
  return {
4912
5014
  fontName: "Math-BoldItalic",
@@ -4929,31 +5031,39 @@ const makeOrd = function (group, options, type) {
4929
5031
  const mode = group.mode;
4930
5032
  const text = group.text;
4931
5033
  const classes = ["mord"];
5034
+ const {
5035
+ font,
5036
+ fontFamily,
5037
+ fontWeight,
5038
+ fontShape
5039
+ } = options;
4932
5040
 
4933
5041
  // Math mode or Old font (i.e. \rm)
4934
- const isFont = mode === "math" || mode === "text" && options.font;
4935
- const fontOrFamily = isFont ? options.font : options.fontFamily;
5042
+ const useFont = mode === "math" || mode === "text" && !!font;
5043
+ const fontOrFamily = useFont ? font : fontFamily;
4936
5044
  let wideFontName = "";
4937
5045
  let wideFontClass = "";
4938
5046
  if (text.charCodeAt(0) === 0xD835) {
4939
- [wideFontName, wideFontClass] = wideCharacterFont(text, mode);
5047
+ const wideCharData = wideCharacterFont(text);
5048
+ wideFontName = wideCharData.font;
5049
+ wideFontClass = wideCharData[mode + "Class"];
4940
5050
  }
4941
- if (wideFontName.length > 0) {
5051
+ if (wideFontName) {
4942
5052
  // surrogate pairs get special treatment
4943
5053
  return makeSymbol(text, wideFontName, mode, options, classes.concat(wideFontClass));
4944
5054
  } else if (fontOrFamily) {
4945
5055
  let fontName;
4946
5056
  let fontClasses;
4947
5057
  if (fontOrFamily === "boldsymbol") {
4948
- const fontData = boldsymbol(text, mode, options, classes, type);
5058
+ const fontData = boldSymbol(text, mode, type);
4949
5059
  fontName = fontData.fontName;
4950
5060
  fontClasses = [fontData.fontClass];
4951
- } else if (isFont) {
4952
- fontName = fontMap[fontOrFamily].fontName;
4953
- fontClasses = [fontOrFamily];
5061
+ } else if (useFont) {
5062
+ fontName = fontMap[font].fontName;
5063
+ fontClasses = [font];
4954
5064
  } else {
4955
- fontName = retrieveTextFontName(fontOrFamily, options.fontWeight, options.fontShape);
4956
- fontClasses = [fontOrFamily, options.fontWeight, options.fontShape];
5065
+ fontName = retrieveTextFontName(fontFamily, fontWeight, fontShape);
5066
+ fontClasses = [fontFamily, fontWeight, fontShape];
4957
5067
  }
4958
5068
  if (lookupSymbol(text, fontName, mode).metrics) {
4959
5069
  return makeSymbol(text, fontName, mode, options, classes.concat(fontClasses));
@@ -4973,16 +5083,16 @@ const makeOrd = function (group, options, type) {
4973
5083
  } else if (type === "textord") {
4974
5084
  const font = src_symbols[mode][text] && src_symbols[mode][text].font;
4975
5085
  if (font === "ams") {
4976
- const fontName = retrieveTextFontName("amsrm", options.fontWeight, options.fontShape);
4977
- return makeSymbol(text, fontName, mode, options, classes.concat("amsrm", options.fontWeight, options.fontShape));
5086
+ const fontName = retrieveTextFontName("amsrm", fontWeight, fontShape);
5087
+ return makeSymbol(text, fontName, mode, options, classes.concat("amsrm", fontWeight, fontShape));
4978
5088
  } else if (font === "main" || !font) {
4979
- const fontName = retrieveTextFontName("textrm", options.fontWeight, options.fontShape);
4980
- return makeSymbol(text, fontName, mode, options, classes.concat(options.fontWeight, options.fontShape));
5089
+ const fontName = retrieveTextFontName("textrm", fontWeight, fontShape);
5090
+ return makeSymbol(text, fontName, mode, options, classes.concat(fontWeight, fontShape));
4981
5091
  } else {
4982
5092
  // fonts added by plugins
4983
- const fontName = retrieveTextFontName(font, options.fontWeight, options.fontShape);
5093
+ const fontName = retrieveTextFontName(font, fontWeight, fontShape);
4984
5094
  // We add font name as a css class
4985
- return makeSymbol(text, fontName, mode, options, classes.concat(fontName, options.fontWeight, options.fontShape));
5095
+ return makeSymbol(text, fontName, mode, options, classes.concat(fontName, fontWeight, fontShape));
4986
5096
  }
4987
5097
  } else {
4988
5098
  throw new Error("unexpected type: " + type + " in makeOrd");
@@ -5290,8 +5400,9 @@ const makeGlue = (measurement, options) => {
5290
5400
  };
5291
5401
 
5292
5402
  // Takes font options, and returns the appropriate fontLookup name
5293
- const retrieveTextFontName = function (fontFamily, fontWeight, fontShape) {
5294
- let baseFontName = "";
5403
+ const retrieveTextFontName = (fontFamily, fontWeight, fontShape) => {
5404
+ let baseFontName;
5405
+ let fontStylesName;
5295
5406
  switch (fontFamily) {
5296
5407
  case "amsrm":
5297
5408
  baseFontName = "AMS";
@@ -5309,12 +5420,11 @@ const retrieveTextFontName = function (fontFamily, fontWeight, fontShape) {
5309
5420
  baseFontName = fontFamily;
5310
5421
  // use fonts added by a plugin
5311
5422
  }
5312
- let fontStylesName;
5313
5423
  if (fontWeight === "textbf" && fontShape === "textit") {
5314
5424
  fontStylesName = "BoldItalic";
5315
5425
  } else if (fontWeight === "textbf") {
5316
5426
  fontStylesName = "Bold";
5317
- } else if (fontWeight === "textit") {
5427
+ } else if (fontShape === "textit") {
5318
5428
  fontStylesName = "Italic";
5319
5429
  } else {
5320
5430
  fontStylesName = "Regular";
@@ -5537,13 +5647,20 @@ const _functions = {};
5537
5647
  /**
5538
5648
  * All HTML builders. Should be only used in the `define*` and the `build*ML`
5539
5649
  * functions.
5650
+ *
5651
+ * Builders for different node types are stored side by side, but
5652
+ * `HtmlBuilder<T>` is contravariant in `T`, so there is no single type
5653
+ * argument that makes storing/retrieving them typecheck. `any` is used
5654
+ * as an existential-quantifier escape hatch.
5540
5655
  */
5656
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5541
5657
  const _htmlGroupBuilders = {};
5542
5658
 
5543
5659
  /**
5544
5660
  * All MathML builders. Should be only used in the `define*` and the `build*ML`
5545
- * functions.
5661
+ * functions. See `_htmlGroupBuilders` above for the rationale behind `any`.
5546
5662
  */
5663
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5547
5664
  const _mathmlGroupBuilders = {};
5548
5665
  function defineFunction(_ref) {
5549
5666
  let {
@@ -5749,7 +5866,8 @@ const traverseNonSpaceNodes = function (nodes, callback, prev, next, isRoot) {
5749
5866
  const partialGroup = checkPartialGroup(node);
5750
5867
  if (partialGroup) {
5751
5868
  // Recursive DFS
5752
- // TODO(ts): make nodes a $ReadOnlyArray by returning a new array
5869
+ // TODO(ts): partialGroup.children is ReadonlyArray but this
5870
+ // function mutates the array (insertAfter splices into it).
5753
5871
  traverseNonSpaceNodes(partialGroup.children, callback, prev, null, isRoot);
5754
5872
  continue;
5755
5873
  }
@@ -5837,8 +5955,8 @@ const buildGroup = function (group, options, baseOptions) {
5837
5955
  return makeSpan();
5838
5956
  }
5839
5957
  if (_htmlGroupBuilders[group.type]) {
5840
- // Call the groupBuilders function
5841
- // TODO(ts)
5958
+ // TODO(ts): groupBuilders is Record<string, HtmlBuilder<any>>;
5959
+ // a type-safe registry would need a mapped type keyed by NodeType.
5842
5960
  let groupNode = _htmlGroupBuilders[group.type](group, options);
5843
5961
 
5844
5962
  // If the size changed between the parent and the current group, account
@@ -5994,6 +6112,10 @@ function newDocumentFragment(children) {
5994
6112
  */
5995
6113
  class MathNode {
5996
6114
  constructor(type, children, classes) {
6115
+ this.type = void 0;
6116
+ this.attributes = void 0;
6117
+ this.children = void 0;
6118
+ this.classes = void 0;
5997
6119
  this.type = type;
5998
6120
  this.attributes = {};
5999
6121
  this.children = children || [];
@@ -6082,6 +6204,7 @@ class MathNode {
6082
6204
  */
6083
6205
  class TextNode {
6084
6206
  constructor(text) {
6207
+ this.text = void 0;
6085
6208
  this.text = text;
6086
6209
  }
6087
6210
 
@@ -6118,6 +6241,8 @@ class SpaceNode {
6118
6241
  * Create a Space node with width given in CSS ems.
6119
6242
  */
6120
6243
  constructor(width) {
6244
+ this.width = void 0;
6245
+ this.character = void 0;
6121
6246
  this.width = width;
6122
6247
  // See https://www.w3.org/TR/2000/WD-MathML2-20000328/chapter6.html
6123
6248
  // for a table of space-like characters. We use Unicode
@@ -6217,57 +6342,55 @@ const makeRow = function (body) {
6217
6342
  return new MathNode("mrow", body);
6218
6343
  }
6219
6344
  };
6345
+ const mathFontVariants = {
6346
+ mathit: "italic",
6347
+ boldsymbol: group => group.type === "textord" ? "bold" : "bold-italic",
6348
+ mathbf: "bold",
6349
+ mathbb: "double-struck",
6350
+ mathsfit: "sans-serif-italic",
6351
+ mathfrak: "fraktur",
6352
+ mathscr: "script",
6353
+ mathcal: "script",
6354
+ mathsf: "sans-serif",
6355
+ mathtt: "monospace"
6356
+ };
6220
6357
 
6221
6358
  /**
6222
6359
  * Returns the math variant as a string or null if none is required.
6223
6360
  */
6224
- const getVariant = function (group, options) {
6361
+ const getVariant = (group, options) => {
6225
6362
  // Handle \text... font specifiers as best we can.
6226
6363
  // MathML has a limited list of allowable mathvariant specifiers; see
6227
6364
  // https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt
6228
- if (options.fontFamily === "texttt") {
6229
- return "monospace";
6230
- } else if (options.fontFamily === "textsf") {
6231
- if (options.fontShape === "textit" && options.fontWeight === "textbf") {
6232
- return "sans-serif-bold-italic";
6365
+ if (group.mode === "text") {
6366
+ if (options.fontFamily === "texttt") {
6367
+ return "monospace";
6368
+ } else if (options.fontFamily === "textsf") {
6369
+ if (options.fontShape === "textit" && options.fontWeight === "textbf") {
6370
+ return "sans-serif-bold-italic";
6371
+ } else if (options.fontShape === "textit") {
6372
+ return "sans-serif-italic";
6373
+ } else if (options.fontWeight === "textbf") {
6374
+ return "bold-sans-serif";
6375
+ } else {
6376
+ return "sans-serif";
6377
+ }
6378
+ } else if (options.fontShape === "textit" && options.fontWeight === "textbf") {
6379
+ return "bold-italic";
6233
6380
  } else if (options.fontShape === "textit") {
6234
- return "sans-serif-italic";
6381
+ return "italic";
6235
6382
  } else if (options.fontWeight === "textbf") {
6236
- return "bold-sans-serif";
6237
- } else {
6238
- return "sans-serif";
6383
+ return "bold";
6239
6384
  }
6240
- } else if (options.fontShape === "textit" && options.fontWeight === "textbf") {
6241
- return "bold-italic";
6242
- } else if (options.fontShape === "textit") {
6243
- return "italic";
6244
- } else if (options.fontWeight === "textbf") {
6245
- return "bold";
6246
6385
  }
6247
6386
  const font = options.font;
6248
6387
  if (!font || font === "mathnormal") {
6249
6388
  return null;
6250
6389
  }
6251
6390
  const mode = group.mode;
6252
- if (font === "mathit") {
6253
- return "italic";
6254
- } else if (font === "boldsymbol") {
6255
- return group.type === "textord" ? "bold" : "bold-italic";
6256
- } else if (font === "mathbf") {
6257
- return "bold";
6258
- } else if (font === "mathbb") {
6259
- return "double-struck";
6260
- } else if (font === "mathsfit") {
6261
- return "sans-serif-italic";
6262
- } else if (font === "mathfrak") {
6263
- return "fraktur";
6264
- } else if (font === "mathscr" || font === "mathcal") {
6265
- // MathML makes no distinction between script and calligraphic
6266
- return "script";
6267
- } else if (font === "mathsf") {
6268
- return "sans-serif";
6269
- } else if (font === "mathtt") {
6270
- return "monospace";
6391
+ const mathVariant = mathFontVariants[font];
6392
+ if (mathVariant) {
6393
+ return typeof mathVariant === "function" ? mathVariant(group) : mathVariant;
6271
6394
  }
6272
6395
  let text = group.text;
6273
6396
  if (noVariantSymbols.has(text)) {
@@ -6387,11 +6510,10 @@ const buildMathML_buildGroup = function (group, options) {
6387
6510
  return new MathNode("mrow");
6388
6511
  }
6389
6512
  if (_mathmlGroupBuilders[group.type]) {
6390
- // Call the groupBuilders function
6391
- // TODO(ts)
6392
- const result = _mathmlGroupBuilders[group.type](group, options);
6393
- // TODO(ts)
6394
- return result;
6513
+ // TODO(ts): MathMLBuilder returns MathDomNode but all concrete
6514
+ // builders return MathNode. Widening the return type here would
6515
+ // require updating all callers that assume MathNode.
6516
+ return _mathmlGroupBuilders[group.type](group, options);
6395
6517
  } else {
6396
6518
  throw new src_ParseError("Got group of unknown type: '" + group.type + "'");
6397
6519
  }
@@ -6436,8 +6558,11 @@ function buildMathML(tree, texExpression, options, isDisplayMode, forMathmlOnly)
6436
6558
  // NOTE: The span class is not typed to have <math> nodes as children, and
6437
6559
  // we don't want to make the children type more generic since the children
6438
6560
  // of span are expected to have more fields in `buildHtml` contexts.
6561
+ // The MathNode implements VirtualNode (toNode/toMarkup) which is all that
6562
+ // Span needs from its children for rendering.
6563
+ // TODO(ts): Span's child type is HtmlDomNode, but MathNode only implements
6564
+ // VirtualNode. The double-cast acknowledges this architectural limitation.
6439
6565
  const wrapperClass = forMathmlOnly ? "katex" : "katex-mathml";
6440
- // TODO(ts)
6441
6566
  return makeSpan([wrapperClass], [math]);
6442
6567
  }
6443
6568
  ;// ./src/Options.ts
@@ -6481,9 +6606,6 @@ const sizeMultipliers = [
6481
6606
  const sizeAtStyle = function (size, style) {
6482
6607
  return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1];
6483
6608
  };
6484
-
6485
- // In these types, "" (empty string) means "no change".
6486
-
6487
6609
  /**
6488
6610
  * This is the main options class. It contains the current style, size, color,
6489
6611
  * and font.
@@ -6493,6 +6615,22 @@ const sizeAtStyle = function (size, style) {
6493
6615
  */
6494
6616
  class Options {
6495
6617
  constructor(data) {
6618
+ this.style = void 0;
6619
+ this.color = void 0;
6620
+ this.size = void 0;
6621
+ this.textSize = void 0;
6622
+ this.phantom = void 0;
6623
+ // A font family applies to a group of fonts (i.e. SansSerif), while a font
6624
+ // represents a specific font (i.e. SansSerif Bold).
6625
+ // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
6626
+ this.font = void 0;
6627
+ this.fontFamily = void 0;
6628
+ this.fontWeight = void 0;
6629
+ this.fontShape = void 0;
6630
+ this.sizeMultiplier = void 0;
6631
+ this.maxSize = void 0;
6632
+ this.minRuleThickness = void 0;
6633
+ this._fontMetrics = void 0;
6496
6634
  this.style = data.style;
6497
6635
  this.color = data.color;
6498
6636
  this.size = data.size || Options.BASESIZE;
@@ -6500,8 +6638,8 @@ class Options {
6500
6638
  this.phantom = !!data.phantom;
6501
6639
  this.font = data.font || "";
6502
6640
  this.fontFamily = data.fontFamily || "";
6503
- this.fontWeight = data.fontWeight || '';
6504
- this.fontShape = data.fontShape || '';
6641
+ this.fontWeight = data.fontWeight || "";
6642
+ this.fontShape = data.fontShape || "";
6505
6643
  this.sizeMultiplier = sizeMultipliers[this.size - 1];
6506
6644
  this.maxSize = data.maxSize;
6507
6645
  this.minRuleThickness = data.minRuleThickness;
@@ -6715,9 +6853,6 @@ class Options {
6715
6853
  }
6716
6854
  }
6717
6855
  }
6718
- // A font family applies to a group of fonts (i.e. SansSerif), while a font
6719
- // represents a specific font (i.e. SansSerif Bold).
6720
- // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
6721
6856
  /**
6722
6857
  * The base size index.
6723
6858
  */
@@ -6863,18 +6998,6 @@ const stretchyMathML = function (label) {
6863
6998
  // Some functions, such as \cancel, need to vary their aspect ratio. These
6864
6999
  // functions do not get the overflow SVG treatment.
6865
7000
 
6866
- // Second Brush Stroke
6867
- // Low resolution monitors struggle to display images in fine detail.
6868
- // So browsers apply anti-aliasing. A long straight arrow shaft therefore
6869
- // will sometimes appear as if it has a blurred edge.
6870
-
6871
- // To mitigate this, these SVG files contain a second "brush-stroke" on the
6872
- // arrow shafts. That is, a second long thin rectangular SVG path has been
6873
- // written directly on top of each arrow shaft. This reinforcement causes
6874
- // some of the screen pixels to display as black instead of the anti-aliased
6875
- // gray pixel that a single path would generate. So we get arrow shafts
6876
- // whose edges appear to be sharper.
6877
-
6878
7001
  // In the katexImagesData object just below, the dimensions all
6879
7002
  // correspond to path geometry inside the relevant SVG.
6880
7003
  // For example, \overrightarrow uses the same arrowhead as glyph U+2192
@@ -6938,14 +7061,10 @@ const stretchySvg = function (group, options) {
6938
7061
  function buildSvgSpan_() {
6939
7062
  let viewBoxWidth = 400000; // default
6940
7063
  const label = group.label.slice(1);
6941
- if (wideAccentLabels.has(label)) {
6942
- // Each type in the `if` statement corresponds to one of the ParseNode
6943
- // types below. This narrowing is required to access `grp.base`.
6944
- // TODO(ts)
6945
- const grp = group;
7064
+ if (wideAccentLabels.has(label) && 'base' in group) {
6946
7065
  // There are four SVG images available for each function.
6947
7066
  // Choose a taller image when there are more characters.
6948
- const numChars = grp.base.type === "ordgroup" ? grp.base.body.length : 1;
7067
+ const numChars = group.base.type === "ordgroup" ? group.base.body.length : 1;
6949
7068
  let viewBoxHeight;
6950
7069
  let pathName;
6951
7070
  let height;
@@ -6990,16 +7109,20 @@ const stretchySvg = function (group, options) {
6990
7109
  } else {
6991
7110
  const spans = [];
6992
7111
  const data = katexImagesData[label];
7112
+ if (!data) {
7113
+ throw new Error("No SVG data for \"" + label + "\".");
7114
+ }
6993
7115
  const [paths, minWidth, viewBoxHeight] = data;
6994
7116
  const height = viewBoxHeight / 1000;
6995
7117
  const numSvgChildren = paths.length;
6996
7118
  let widthClasses;
6997
7119
  let aligns;
6998
7120
  if (numSvgChildren === 1) {
6999
- // TODO(ts): All these cases must be of the 4-tuple type.
7000
- const align1 = data[3];
7121
+ if (data.length !== 4) {
7122
+ throw new Error("Expected 4-tuple for single-path SVG data \"" + label + "\".");
7123
+ }
7001
7124
  widthClasses = ["hide-tail"];
7002
- aligns = [align1];
7125
+ aligns = [data[3]];
7003
7126
  } else if (numSvgChildren === 2) {
7004
7127
  widthClasses = ["halfarrow-left", "halfarrow-right"];
7005
7128
  aligns = ["xMinYMin", "xMaxYMin"];
@@ -7097,6 +7220,35 @@ const stretchyEnclose = function (inner, label, topPad, bottomPad, options) {
7097
7220
  img.style.height = makeEm(totalHeight);
7098
7221
  return img;
7099
7222
  };
7223
+ ;// ./src/atoms.ts
7224
+ /**
7225
+ * Small module for atom-group constants and type guard. Kept separate from
7226
+ * `symbols.ts` so that consumers (notably `contrib/render-a11y-string`) can
7227
+ * pull in `isAtom` without dragging in the ~870-line symbol tables.
7228
+ */
7229
+
7230
+ // Some of these have a "-token" suffix since these are also used as `ParseNode`
7231
+ // types for raw text tokens, and we want to avoid conflicts with higher-level
7232
+ // `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
7233
+ // looking up the `symbols` map.
7234
+ const ATOMS = {
7235
+ "bin": 1,
7236
+ "close": 1,
7237
+ "inner": 1,
7238
+ "open": 1,
7239
+ "punct": 1,
7240
+ "rel": 1
7241
+ };
7242
+ const NON_ATOMS = {
7243
+ "accent-token": 1,
7244
+ "mathord": 1,
7245
+ "op-token": 1,
7246
+ "spacing": 1,
7247
+ "textord": 1
7248
+ };
7249
+ function isAtom(value) {
7250
+ return value in ATOMS;
7251
+ }
7100
7252
  ;// ./src/parseNode.ts
7101
7253
 
7102
7254
 
@@ -7526,7 +7678,8 @@ defineFunction({
7526
7678
  }, {
7527
7679
  type: "elem",
7528
7680
  elem: arrowBody,
7529
- shift: arrowShift
7681
+ shift: arrowShift,
7682
+ wrapperClasses: ["svg-align"]
7530
7683
  }, {
7531
7684
  type: "elem",
7532
7685
  elem: lowerGroup,
@@ -7543,13 +7696,11 @@ defineFunction({
7543
7696
  }, {
7544
7697
  type: "elem",
7545
7698
  elem: arrowBody,
7546
- shift: arrowShift
7699
+ shift: arrowShift,
7700
+ wrapperClasses: ["svg-align"]
7547
7701
  }]
7548
7702
  }, options);
7549
7703
  }
7550
-
7551
- // TODO(ts): Replace this with passing "svg-align" into makeVList.
7552
- vlist.children[0].children[0].children[1].classes.push("svg-align");
7553
7704
  return makeSpan(["mrel", "x-arrow"], [vlist], options);
7554
7705
  },
7555
7706
  mathmlBuilder(group, options) {
@@ -7809,7 +7960,8 @@ const newCell = () => {
7809
7960
  type: "styling",
7810
7961
  body: [],
7811
7962
  mode: "math",
7812
- style: "display"
7963
+ style: "display",
7964
+ resetFont: true
7813
7965
  };
7814
7966
  };
7815
7967
  const isStartOfArrow = node => {
@@ -7871,7 +8023,6 @@ function parseCD(parser) {
7871
8023
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
7872
8024
  parser.gullet.beginGroup();
7873
8025
  while (true) {
7874
- // eslint-disable-line no-constant-condition
7875
8026
  // Get the parse nodes for the next row.
7876
8027
  parsedRows.push(parser.parseExpression(false, "\\\\"));
7877
8028
  parser.gullet.endGroup();
@@ -7964,7 +8115,9 @@ function parseCD(parser) {
7964
8115
  type: "styling",
7965
8116
  body: [arrow],
7966
8117
  mode: "math",
7967
- style: "display" // CD is always displaystyle.
8118
+ style: "display",
8119
+ // CD is always displaystyle.
8120
+ resetFont: true
7968
8121
  };
7969
8122
  row.push(wrappedArrow);
7970
8123
  // In CD's syntax, cells are implicit. That is, everything that
@@ -8909,9 +9062,9 @@ const makeSqrtImage = function (height, options) {
8909
9062
 
8910
9063
  // Create a span containing an SVG image of a sqrt symbol.
8911
9064
  let span;
8912
- let spanHeight = 0;
8913
- let texHeight = 0;
8914
- let viewBoxHeight = 0;
9065
+ let spanHeight;
9066
+ let texHeight;
9067
+ let viewBoxHeight;
8915
9068
  let advanceWidth;
8916
9069
 
8917
9070
  // We create viewBoxes with 80 units of "padding" above each surd.
@@ -9273,6 +9426,16 @@ const delimiterSizes = {
9273
9426
  }
9274
9427
  };
9275
9428
  const delimiters = new Set(["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230a", "\u230b", "\\lceil", "\\rceil", "\u2308", "\u2309", "<", ">", "\\langle", "\u27e8", "\\rangle", "\u27e9", "\\lt", "\\gt", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27ee", "\u27ef", "\\lmoustache", "\\rmoustache", "\u23b0", "\u23b1", "/", "\\backslash", "|", "\\vert", "\\|", "\\Vert", "\\uparrow", "\\Uparrow", "\\downarrow", "\\Downarrow", "\\updownarrow", "\\Updownarrow", "."]);
9429
+
9430
+ /**
9431
+ * An HtmlDomNode that carries an `isMiddle` property, used by the
9432
+ * \middle command to communicate delimiter info to the \left/\right builder.
9433
+ */
9434
+
9435
+ function isMiddleDelimNode(node) {
9436
+ return 'isMiddle' in node;
9437
+ }
9438
+
9276
9439
  // Delimiter functions
9277
9440
  function checkDelimiter(delim, context) {
9278
9441
  const symDelim = checkSymbolNodeType(delim);
@@ -9396,10 +9559,8 @@ defineFunction({
9396
9559
 
9397
9560
  // Calculate its height and depth
9398
9561
  for (let i = 0; i < inner.length; i++) {
9399
- // Property `isMiddle` not defined on `span`. See comment in
9400
- // "middle"'s htmlBuilder.
9401
- // TODO(ts)
9402
- if (inner[i].isMiddle) {
9562
+ const node = inner[i];
9563
+ if (isMiddleDelimNode(node)) {
9403
9564
  hadMiddle = true;
9404
9565
  } else {
9405
9566
  innerHeight = Math.max(inner[i].height, innerHeight);
@@ -9428,11 +9589,8 @@ defineFunction({
9428
9589
  if (hadMiddle) {
9429
9590
  for (let i = 1; i < inner.length; i++) {
9430
9591
  const middleDelim = inner[i];
9431
- // Property `isMiddle` not defined on `span`. See comment in
9432
- // "middle"'s htmlBuilder.
9433
- // TODO(ts)
9434
- const isMiddle = middleDelim.isMiddle;
9435
- if (isMiddle) {
9592
+ if (isMiddleDelimNode(middleDelim)) {
9593
+ const isMiddle = middleDelim.isMiddle;
9436
9594
  // Apply the options that were active when \middle was called
9437
9595
  inner[i] = makeLeftRightDelim(isMiddle.delim, innerHeight, innerDepth, isMiddle.options, group.mode, []);
9438
9596
  }
@@ -9493,16 +9651,15 @@ defineFunction({
9493
9651
  middleDelim = makeNullDelimiter(options, []);
9494
9652
  } else {
9495
9653
  middleDelim = makeSizedDelim(group.delim, 1, options, group.mode, []);
9496
- const isMiddle = {
9654
+
9655
+ // Patch an ad-hoc property onto the node so the \left/\right
9656
+ // builder can reconstruct appropriately sized middle delimiters.
9657
+ // isMiddle is not part of HtmlDomNode; the read side uses
9658
+ // isMiddleDelimNode() to check before accessing.
9659
+ middleDelim.isMiddle = {
9497
9660
  delim: group.delim,
9498
9661
  options
9499
9662
  };
9500
- // Property `isMiddle` not defined on `span`. It is only used in
9501
- // this file above.
9502
- // TODO: Fix this violation of the `span` type and possibly rename
9503
- // things since `isMiddle` sounds like a boolean, but is a struct.
9504
- // TODO(ts)
9505
- middleDelim.isMiddle = isMiddle;
9506
9663
  }
9507
9664
  return middleDelim;
9508
9665
  },
@@ -9541,7 +9698,7 @@ const enclose_htmlBuilder = (group, options) => {
9541
9698
  const label = group.label.slice(1);
9542
9699
  let scale = options.sizeMultiplier;
9543
9700
  let img;
9544
- let imgShift = 0;
9701
+ let imgShift;
9545
9702
 
9546
9703
  // In the LaTeX cancel package, line geometry is slightly different
9547
9704
  // depending on whether the subject is wider than it is tall, or vice versa.
@@ -9597,8 +9754,8 @@ const enclose_htmlBuilder = (group, options) => {
9597
9754
  }
9598
9755
 
9599
9756
  // Add vertical padding
9600
- let topPad = 0;
9601
- let bottomPad = 0;
9757
+ let topPad;
9758
+ let bottomPad;
9602
9759
  let ruleThickness = 0;
9603
9760
  // ref: cancel package: \advance\totalheight2\p@ % "+2"
9604
9761
  if (/box/.test(label)) {
@@ -9680,7 +9837,7 @@ const enclose_htmlBuilder = (group, options) => {
9680
9837
  }
9681
9838
  };
9682
9839
  const enclose_mathmlBuilder = (group, options) => {
9683
- let fboxsep = 0;
9840
+ let fboxsep;
9684
9841
  const node = new MathNode(group.label.includes("colorbox") ? "mpadded" : "menclose", [buildMathML_buildGroup(group.body, options)]);
9685
9842
  switch (group.label) {
9686
9843
  case "\\cancel":
@@ -9733,7 +9890,7 @@ defineFunction({
9733
9890
  props: {
9734
9891
  numArgs: 2,
9735
9892
  allowedInText: true,
9736
- argTypes: ["color", "text"]
9893
+ argTypes: ["color", "hbox"]
9737
9894
  },
9738
9895
  handler(_ref, args, optArgs) {
9739
9896
  let {
@@ -9759,7 +9916,7 @@ defineFunction({
9759
9916
  props: {
9760
9917
  numArgs: 3,
9761
9918
  allowedInText: true,
9762
- argTypes: ["color", "color", "text"]
9919
+ argTypes: ["color", "color", "hbox"]
9763
9920
  },
9764
9921
  handler(_ref2, args, optArgs) {
9765
9922
  let {
@@ -9962,12 +10119,15 @@ function defineMacro(name, body) {
9962
10119
  * This object is immutable.
9963
10120
  */
9964
10121
  class SourceLocation {
9965
- // The + prefix indicates that these fields aren't writeable
9966
- // Lexer holding the input string.
9967
- // Start offset, zero-based inclusive.
9968
10122
  // End offset, zero-based exclusive.
9969
10123
 
9970
10124
  constructor(lexer, start, end) {
10125
+ // The + prefix indicates that these fields aren't writeable
10126
+ this.lexer = void 0;
10127
+ // Lexer holding the input string.
10128
+ this.start = void 0;
10129
+ // Start offset, zero-based inclusive.
10130
+ this.end = void 0;
9971
10131
  this.lexer = lexer;
9972
10132
  this.start = start;
9973
10133
  this.end = end;
@@ -10013,12 +10173,16 @@ class SourceLocation {
10013
10173
  * lead to degraded error reporting, though.
10014
10174
  */
10015
10175
  class Token {
10016
- // don't expand the token
10017
10176
  // used in \noexpand
10018
10177
 
10019
10178
  constructor(text,
10020
10179
  // the text of this token
10021
10180
  loc) {
10181
+ this.text = void 0;
10182
+ this.loc = void 0;
10183
+ this.noexpand = void 0;
10184
+ // don't expand the token
10185
+ this.treatAsRelax = void 0;
10022
10186
  this.text = text;
10023
10187
  this.loc = loc;
10024
10188
  }
@@ -10166,7 +10330,6 @@ function parseArray(parser, _ref, style) {
10166
10330
  // Test for \hline at the top of the array.
10167
10331
  hLinesBeforeRow.push(getHLines(parser));
10168
10332
  while (true) {
10169
- // eslint-disable-line no-constant-condition
10170
10333
  // Parse each cell in its own group (namespace)
10171
10334
  const cellBody = parser.parseExpression(false, singleRow ? "\\end" : "\\\\");
10172
10335
  parser.gullet.endGroup();
@@ -10181,6 +10344,7 @@ function parseArray(parser, _ref, style) {
10181
10344
  type: "styling",
10182
10345
  mode: parser.mode,
10183
10346
  style,
10347
+ resetFont: true,
10184
10348
  body: [cell]
10185
10349
  };
10186
10350
  }
@@ -10324,7 +10488,12 @@ const array_htmlBuilder = function (group, options) {
10324
10488
  if (nc < inrow.length) {
10325
10489
  nc = inrow.length;
10326
10490
  }
10327
- const outrow = new Array(inrow.length);
10491
+ const outrow = {
10492
+ cells: new Array(inrow.length),
10493
+ height: 0,
10494
+ depth: 0,
10495
+ pos: 0
10496
+ };
10328
10497
  for (c = 0; c < inrow.length; ++c) {
10329
10498
  const elt = buildGroup(inrow[c], options);
10330
10499
  if (depth < elt.depth) {
@@ -10333,7 +10502,7 @@ const array_htmlBuilder = function (group, options) {
10333
10502
  if (height < elt.height) {
10334
10503
  height = elt.height;
10335
10504
  }
10336
- outrow[c] = elt;
10505
+ outrow.cells[c] = elt;
10337
10506
  }
10338
10507
  const rowGap = group.rowGaps[r];
10339
10508
  let gap = 0;
@@ -10449,7 +10618,7 @@ const array_htmlBuilder = function (group, options) {
10449
10618
  const colElems = [];
10450
10619
  for (r = 0; r < nr; ++r) {
10451
10620
  const row = body[r];
10452
- const elem = row[c];
10621
+ const elem = row.cells[c];
10453
10622
  if (!elem) {
10454
10623
  continue;
10455
10624
  }
@@ -11081,7 +11250,6 @@ const environments = _environments;
11081
11250
 
11082
11251
 
11083
11252
 
11084
-
11085
11253
  // Environment delimiters. HTML/MathML rendering is defined in the corresponding
11086
11254
  // defineEnvironment definitions.
11087
11255
  defineFunction({
@@ -11128,7 +11296,10 @@ defineFunction({
11128
11296
  if (end.name !== envName) {
11129
11297
  throw new src_ParseError("Mismatch: \\begin{" + envName + "} matched by \\end{" + end.name + "}", endNameToken);
11130
11298
  }
11131
- // TODO(ts), "environment" handler returns an environment ParseNode
11299
+ // env.handler returns the specific node type (e.g. "array"),
11300
+ // not "environment". This cast is unavoidable: defineFunction
11301
+ // requires the handler to return ParseNode<"environment"> but
11302
+ // \begin delegates to environment handlers with different types.
11132
11303
  return result;
11133
11304
  }
11134
11305
  return {
@@ -11160,8 +11331,7 @@ const font_mathmlBuilder = (group, options) => {
11160
11331
  const fontAliases = {
11161
11332
  "\\Bbb": "\\mathbb",
11162
11333
  "\\bold": "\\mathbf",
11163
- "\\frak": "\\mathfrak",
11164
- "\\bm": "\\boldsymbol"
11334
+ "\\frak": "\\mathfrak"
11165
11335
  };
11166
11336
  defineFunction({
11167
11337
  type: "font",
@@ -11242,11 +11412,10 @@ defineFunction({
11242
11412
  mode
11243
11413
  } = parser;
11244
11414
  const body = parser.parseExpression(true, breakOnTokenText);
11245
- const style = "math" + funcName.slice(1);
11246
11415
  return {
11247
11416
  type: "font",
11248
11417
  mode: mode,
11249
- font: style,
11418
+ font: "math" + funcName.slice(1),
11250
11419
  body: {
11251
11420
  type: "ordgroup",
11252
11421
  mode: parser.mode,
@@ -11730,18 +11899,18 @@ const horizBrace_htmlBuilder = (grp, options) => {
11730
11899
  size: 0.1
11731
11900
  }, {
11732
11901
  type: "elem",
11733
- elem: braceBody
11902
+ elem: braceBody,
11903
+ wrapperClasses: ["svg-align"]
11734
11904
  }]
11735
11905
  }, options);
11736
- // TODO(ts): Replace this with passing "svg-align" into makeVList.
11737
- vlist.children[0].children[0].children[1].classes.push("svg-align");
11738
11906
  } else {
11739
11907
  vlist = makeVList({
11740
11908
  positionType: "bottom",
11741
11909
  positionData: body.depth + 0.1 + braceBody.height,
11742
11910
  children: [{
11743
11911
  type: "elem",
11744
- elem: braceBody
11912
+ elem: braceBody,
11913
+ wrapperClasses: ["svg-align"]
11745
11914
  }, {
11746
11915
  type: "kern",
11747
11916
  size: 0.1
@@ -11750,8 +11919,6 @@ const horizBrace_htmlBuilder = (grp, options) => {
11750
11919
  elem: body
11751
11920
  }]
11752
11921
  }, options);
11753
- // TODO(ts): Replace this with passing "svg-align" into makeVList.
11754
- vlist.children[0].children[0].children[0].classes.push("svg-align");
11755
11922
  }
11756
11923
  if (supSubGroup) {
11757
11924
  // To write the supsub, wrap the first vlist in another vlist:
@@ -11949,11 +12116,11 @@ defineFunction({
11949
12116
  };
11950
12117
  },
11951
12118
  htmlBuilder(group, options) {
11952
- const elements = buildExpression(group.body, options, false);
12119
+ const elements = buildExpression(group.body, options.withFont(''), false);
11953
12120
  return makeFragment(elements);
11954
12121
  },
11955
12122
  mathmlBuilder(group, options) {
11956
- return new MathNode("mrow", buildMathML_buildExpression(group.body, options));
12123
+ return new MathNode("mrow", buildMathML_buildExpression(group.body, options.withFont('')));
11957
12124
  }
11958
12125
  });
11959
12126
  ;// ./src/functions/html.ts
@@ -12393,6 +12560,7 @@ defineFunction({
12393
12560
  type: "styling",
12394
12561
  mode: parser.mode,
12395
12562
  style: "text",
12563
+ resetFont: true,
12396
12564
  body
12397
12565
  };
12398
12566
  }
@@ -12627,6 +12795,9 @@ const op_htmlBuilder = (grp, options) => {
12627
12795
  large = true;
12628
12796
  }
12629
12797
  let base;
12798
+ // Italic correction from the symbol glyph, captured before the symbol
12799
+ // may be wrapped in a vlist (for \oiint/\oiiint). Stays 0 for non-symbol ops.
12800
+ let symbolItalic;
12630
12801
  if (group.symbol) {
12631
12802
  // If this is a symbol, create the symbol.
12632
12803
  const fontName = large ? "Size2-Regular" : "Size1-Regular";
@@ -12638,10 +12809,10 @@ const op_htmlBuilder = (grp, options) => {
12638
12809
  group.name = stash === "oiint" ? "\\iint" : "\\iiint";
12639
12810
  }
12640
12811
  base = makeSymbol(group.name, fontName, "math", options, ["mop", "op-symbol", large ? "large-op" : "small-op"]);
12812
+ symbolItalic = base.italic;
12641
12813
  if (stash.length > 0) {
12642
12814
  // We're in \oiint or \oiiint. Overlay the oval.
12643
12815
  // TODO: When font glyphs are available, delete this code.
12644
- const italic = base.italic;
12645
12816
  const oval = staticSvg(stash + "Size" + (large ? "2" : "1"), options);
12646
12817
  base = makeVList({
12647
12818
  positionType: "individualShift",
@@ -12657,8 +12828,9 @@ const op_htmlBuilder = (grp, options) => {
12657
12828
  }, options);
12658
12829
  group.name = "\\" + stash;
12659
12830
  base.classes.unshift("mop");
12660
- // TODO(ts)
12661
- base.italic = italic;
12831
+ // Carry the italic correction from the original symbol to the
12832
+ // vlist wrapper so supsub can use it for subscript positioning.
12833
+ base.italic = symbolItalic;
12662
12834
  }
12663
12835
  } else if (group.body) {
12664
12836
  // If this is a list, compose that list.
@@ -12683,6 +12855,7 @@ const op_htmlBuilder = (grp, options) => {
12683
12855
  let baseShift = 0;
12684
12856
  let slant = 0;
12685
12857
  if ((base instanceof SymbolNode || group.name === "\\oiint" || group.name === "\\oiiint") && !group.suppressBaseShift) {
12858
+ var _base$italic;
12686
12859
  // We suppress the shift of the base of \overset and \underset. Otherwise,
12687
12860
  // shift the symbol so its center lies on the axis (rule 13). It
12688
12861
  // appears that our fonts have the centers of the symbols already
@@ -12692,8 +12865,9 @@ const op_htmlBuilder = (grp, options) => {
12692
12865
  baseShift = (base.height - base.depth) / 2 - options.fontMetrics().axisHeight;
12693
12866
 
12694
12867
  // The slant of the symbol is just its italic correction.
12695
- // TODO(ts)
12696
- slant = base.italic || 0;
12868
+ // SymbolNode carries .italic natively; Span (for \oiint/\oiiint)
12869
+ // only has it set when nonzero, so default to 0.
12870
+ slant = (_base$italic = base.italic) != null ? _base$italic : 0;
12697
12871
  }
12698
12872
  if (hasLimits) {
12699
12873
  return assembleSupSub(base, supGroup, subGroup, options, style, slant, baseShift);
@@ -13427,7 +13601,7 @@ defineFunction({
13427
13601
  // Optional [tb] argument is engaged.
13428
13602
  // ref: amsmath: \renewcommand{\smash}[1][tb]{%
13429
13603
  // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}%
13430
- let letter = "";
13604
+ let letter;
13431
13605
  for (let i = 0; i < tbArg.body.length; ++i) {
13432
13606
  const node = tbArg.body[i];
13433
13607
  letter = assertSymbolNodeType(node).text;
@@ -13649,6 +13823,9 @@ const styling_styleMap = {
13649
13823
  "script": src_Style.SCRIPT,
13650
13824
  "scriptscript": src_Style.SCRIPTSCRIPT
13651
13825
  };
13826
+ function isStyleStr(s) {
13827
+ return s in styling_styleMap;
13828
+ }
13652
13829
  defineFunction({
13653
13830
  type: "styling",
13654
13831
  names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"],
@@ -13668,8 +13845,10 @@ defineFunction({
13668
13845
 
13669
13846
  // TODO: Refactor to avoid duplicating styleMap in multiple places (e.g.
13670
13847
  // here and in buildHTML and de-dupe the enumeration of all the styles).
13671
- // TODO(ts): The names above exactly match the styles.
13672
13848
  const style = funcName.slice(1, funcName.length - 5);
13849
+ if (!isStyleStr(style)) {
13850
+ throw new Error("Unknown style: " + style);
13851
+ }
13673
13852
  return {
13674
13853
  type: "styling",
13675
13854
  mode: parser.mode,
@@ -13682,13 +13861,19 @@ defineFunction({
13682
13861
  htmlBuilder(group, options) {
13683
13862
  // Style changes are handled in the TeXbook on pg. 442, Rule 3.
13684
13863
  const newStyle = styling_styleMap[group.style];
13685
- const newOptions = options.havingStyle(newStyle).withFont('');
13864
+ let newOptions = options.havingStyle(newStyle);
13865
+ if (group.resetFont) {
13866
+ newOptions = newOptions.withFont('');
13867
+ }
13686
13868
  return sizingGroup(group.body, newOptions, options);
13687
13869
  },
13688
13870
  mathmlBuilder(group, options) {
13689
13871
  // Figure out what style we're changing to.
13690
13872
  const newStyle = styling_styleMap[group.style];
13691
- const newOptions = options.havingStyle(newStyle);
13873
+ let newOptions = options.havingStyle(newStyle);
13874
+ if (group.resetFont) {
13875
+ newOptions = newOptions.withFont('');
13876
+ }
13692
13877
  const inner = buildMathML_buildExpression(group.body, newOptions);
13693
13878
  const node = new MathNode("mstyle", inner);
13694
13879
  const styleAttributes = {
@@ -13724,7 +13909,9 @@ defineFunction({
13724
13909
  * its inner element should handle the superscripts and subscripts instead of
13725
13910
  * handling them itself.
13726
13911
  */
13727
- const htmlBuilderDelegate = function (group, options) {
13912
+ const htmlBuilderDelegate = function (group, options
13913
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13914
+ ) {
13728
13915
  const base = group.base;
13729
13916
  if (!base) {
13730
13917
  return null;
@@ -13810,8 +13997,10 @@ defineFunctionBuilders({
13810
13997
  // amount. Note we only do this when the base is a single symbol.
13811
13998
  const isOiint = group.base && group.base.type === "op" && group.base.name && (group.base.name === "\\oiint" || group.base.name === "\\oiiint");
13812
13999
  if (base instanceof SymbolNode || isOiint) {
13813
- // @ts-ignore
13814
- marginLeft = makeEm(-base.italic);
14000
+ var _italic;
14001
+ // SymbolNode has .italic natively; for \oiint/\oiiint the
14002
+ // op builder stores .italic on the wrapping Span.
14003
+ marginLeft = makeEm(-((_italic = base.italic) != null ? _italic : 0));
13815
14004
  }
13816
14005
  }
13817
14006
  let supsub;
@@ -14286,7 +14475,9 @@ defineFunction({
14286
14475
  // There is no way to do this in MathML.
14287
14476
  // Write a class as a breadcrumb in case some post-processor wants
14288
14477
  // to perform a vcenter adjustment.
14289
- return new MathNode("mpadded", [buildMathML_buildGroup(group.body, options)], ["vcenter"]);
14478
+ // Wrap in mrow to ensure valid MathML when placed inside mo (e.g., \mathrel)
14479
+ const mpadded = new MathNode("mpadded", [buildMathML_buildGroup(group.body, options)], ["vcenter"]);
14480
+ return new MathNode("mrow", [mpadded]);
14290
14481
  }
14291
14482
  });
14292
14483
  ;// ./src/functions/verb.ts
@@ -14455,10 +14646,13 @@ combiningDiacriticalMarkString + "*") +
14455
14646
 
14456
14647
  /** Main Lexer class */
14457
14648
  class Lexer {
14458
- // Category codes. The lexer only supports comment characters (14) for now.
14459
- // MacroExpander additionally distinguishes active (13).
14460
-
14461
14649
  constructor(input, settings) {
14650
+ this.input = void 0;
14651
+ this.settings = void 0;
14652
+ this.tokenRegex = void 0;
14653
+ // Category codes. The lexer only supports comment characters (14) for now.
14654
+ // MacroExpander additionally distinguishes active (13).
14655
+ this.catcodes = void 0;
14462
14656
  // Separate accents from characters
14463
14657
  this.input = input;
14464
14658
  this.settings = settings;
@@ -14525,6 +14719,9 @@ class Namespace {
14525
14719
  if (globalMacros === void 0) {
14526
14720
  globalMacros = {};
14527
14721
  }
14722
+ this.current = void 0;
14723
+ this.builtins = void 0;
14724
+ this.undefStack = void 0;
14528
14725
  this.current = globalMacros;
14529
14726
  this.builtins = builtins;
14530
14727
  this.undefStack = [];
@@ -15628,6 +15825,12 @@ const implicitCommands = {
15628
15825
  };
15629
15826
  class MacroExpander {
15630
15827
  constructor(input, settings, mode) {
15828
+ this.settings = void 0;
15829
+ this.expansionCount = void 0;
15830
+ this.lexer = void 0;
15831
+ this.macros = void 0;
15832
+ this.stack = void 0;
15833
+ this.mode = void 0;
15631
15834
  this.settings = settings;
15632
15835
  this.expansionCount = 0;
15633
15836
  this.feed(input);
@@ -16174,6 +16377,7 @@ const uSubsAndSups = Object.freeze({
16174
16377
 
16175
16378
 
16176
16379
 
16380
+
16177
16381
  // Pre-evaluate both modules as unicodeSymbols require String.normalize()
16178
16382
  const unicodeAccents = {
16179
16383
  "́": {
@@ -16601,6 +16805,11 @@ const unicodeSymbols = {
16601
16805
 
16602
16806
  class Parser {
16603
16807
  constructor(input, settings) {
16808
+ this.mode = void 0;
16809
+ this.gullet = void 0;
16810
+ this.settings = void 0;
16811
+ this.leftrightDepth = void 0;
16812
+ this.nextToken = void 0;
16604
16813
  // Start in math mode
16605
16814
  this.mode = "math";
16606
16815
  // Create a new macro expander (gullet) and (indirectly via that) also a
@@ -17105,13 +17314,16 @@ class Parser {
17105
17314
  case "hbox":
17106
17315
  {
17107
17316
  // hbox argument type wraps the argument in the equivalent of
17108
- // \hbox, which is like \text but switching to \textstyle size.
17317
+ // \hbox, which is like \text but switching to \textstyle size
17318
+ // and resetting math font.
17109
17319
  const group = this.parseArgumentGroup(optional, "text");
17110
17320
  return group != null ? {
17111
17321
  type: "styling",
17112
17322
  mode: group.mode,
17113
17323
  body: [group],
17114
- style: "text" // simulate \textstyle
17324
+ style: "text",
17325
+ // simulate \textstyle
17326
+ resetFont: true
17115
17327
  } : null;
17116
17328
  }
17117
17329
  case "raw":
@@ -17477,18 +17689,15 @@ class Parser {
17477
17689
  const group = src_symbols[this.mode][text].group;
17478
17690
  const loc = SourceLocation.range(nucleus);
17479
17691
  let s;
17480
- if (ATOMS.hasOwnProperty(group)) {
17481
- // TODO(ts)
17482
- const family = group;
17692
+ if (isAtom(group)) {
17483
17693
  s = {
17484
17694
  type: "atom",
17485
17695
  mode: this.mode,
17486
- family,
17696
+ family: group,
17487
17697
  loc,
17488
17698
  text
17489
17699
  };
17490
17700
  } else {
17491
- // TODO(ts)
17492
17701
  s = {
17493
17702
  type: group,
17494
17703
  mode: this.mode,
@@ -17496,7 +17705,6 @@ class Parser {
17496
17705
  text
17497
17706
  };
17498
17707
  }
17499
- // TODO(ts)
17500
17708
  symbol = s;
17501
17709
  } else if (text.charCodeAt(0) >= 0x80) {
17502
17710
  // no symbol for e.g. ^
@@ -17542,12 +17750,10 @@ class Parser {
17542
17750
  label: command,
17543
17751
  isStretchy: false,
17544
17752
  isShifty: true,
17545
- // TODO(ts)
17546
17753
  base: symbol
17547
17754
  };
17548
17755
  }
17549
17756
  }
17550
- // TODO(ts)
17551
17757
  return symbol;
17552
17758
  }
17553
17759
  }
@@ -17693,7 +17899,7 @@ const renderToHTMLTree = function (expression, options) {
17693
17899
  return renderError(error, expression, settings);
17694
17900
  }
17695
17901
  };
17696
- const version = "0.16.44";
17902
+ const version = "0.16.46";
17697
17903
  const __domTree = {
17698
17904
  Span: Span,
17699
17905
  Anchor: Anchor,