katex 0.16.8 → 0.16.10

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.
package/dist/katex.mjs CHANGED
@@ -254,12 +254,34 @@ var assert = function assert(value) {
254
254
  };
255
255
  /**
256
256
  * Return the protocol of a URL, or "_relative" if the URL does not specify a
257
- * protocol (and thus is relative).
257
+ * protocol (and thus is relative), or `null` if URL has invalid protocol
258
+ * (so should be outright rejected).
258
259
  */
259
260
 
260
261
  var protocolFromUrl = function protocolFromUrl(url) {
261
- var protocol = /^\s*([^\\/#]*?)(?::|&#0*58|&#x0*3a)/i.exec(url);
262
- return protocol != null ? protocol[1] : "_relative";
262
+ // Check for possible leading protocol.
263
+ // https://url.spec.whatwg.org/#url-parsing strips leading whitespace
264
+ // (U+20) or C0 control (U+00-U+1F) characters.
265
+ // eslint-disable-next-line no-control-regex
266
+ var protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|&#0*58|&#x0*3a|&colon)/i.exec(url);
267
+
268
+ if (!protocol) {
269
+ return "_relative";
270
+ } // Reject weird colons
271
+
272
+
273
+ if (protocol[2] !== ":") {
274
+ return null;
275
+ } // Reject invalid characters in scheme according to
276
+ // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1
277
+
278
+
279
+ if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) {
280
+ return null;
281
+ } // Lowercase the protocol
282
+
283
+
284
+ return protocol[1].toLowerCase();
263
285
  };
264
286
  var utils = {
265
287
  contains,
@@ -509,7 +531,13 @@ class Settings {
509
531
 
510
532
  isTrusted(context) {
511
533
  if (context.url && !context.protocol) {
512
- context.protocol = utils.protocolFromUrl(context.url);
534
+ var protocol = utils.protocolFromUrl(context.url);
535
+
536
+ if (protocol == null) {
537
+ return false;
538
+ }
539
+
540
+ context.protocol = protocol;
513
541
  }
514
542
 
515
543
  var trust = typeof this.trust === "function" ? this.trust(context) : this.trust;
@@ -4083,7 +4111,7 @@ class Img {
4083
4111
  }
4084
4112
 
4085
4113
  toMarkup() {
4086
- var markup = "<img src='" + this.src + " 'alt='" + this.alt + "' "; // Add the styles, after hyphenation
4114
+ var markup = "<img src=\"" + utils.escape(this.src) + "\"" + (" alt=\"" + utils.escape(this.alt) + "\""); // Add the styles, after hyphenation
4087
4115
 
4088
4116
  var styles = "";
4089
4117
 
@@ -4274,7 +4302,7 @@ class SvgNode {
4274
4302
 
4275
4303
  for (var attr in this.attributes) {
4276
4304
  if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
4277
- markup += " " + attr + "='" + this.attributes[attr] + "'";
4305
+ markup += " " + attr + "=\"" + utils.escape(this.attributes[attr]) + "\"";
4278
4306
  }
4279
4307
  }
4280
4308
 
@@ -4312,9 +4340,9 @@ class PathNode {
4312
4340
 
4313
4341
  toMarkup() {
4314
4342
  if (this.alternate) {
4315
- return "<path d='" + this.alternate + "'/>";
4343
+ return "<path d=\"" + utils.escape(this.alternate) + "\"/>";
4316
4344
  } else {
4317
- return "<path d='" + path[this.pathName] + "'/>";
4345
+ return "<path d=\"" + utils.escape(path[this.pathName]) + "\"/>";
4318
4346
  }
4319
4347
  }
4320
4348
 
@@ -4343,7 +4371,7 @@ class LineNode {
4343
4371
 
4344
4372
  for (var attr in this.attributes) {
4345
4373
  if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
4346
- markup += " " + attr + "='" + this.attributes[attr] + "'";
4374
+ markup += " " + attr + "=\"" + utils.escape(this.attributes[attr]) + "\"";
4347
4375
  }
4348
4376
  }
4349
4377
 
@@ -4545,7 +4573,7 @@ defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown", true);
4545
4573
  defineSymbol(math, main, rel, "\u2196", "\\nwarrow", true);
4546
4574
  defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons", true); // AMS Negated Binary Relations
4547
4575
 
4548
- defineSymbol(math, ams, rel, "\u226e", "\\nless", true); // Symbol names preceeded by "@" each have a corresponding macro.
4576
+ defineSymbol(math, ams, rel, "\u226e", "\\nless", true); // Symbol names preceded by "@" each have a corresponding macro.
4549
4577
 
4550
4578
  defineSymbol(math, ams, rel, "\ue010", "\\@nleqslant");
4551
4579
  defineSymbol(math, ams, rel, "\ue011", "\\@nleqq");
@@ -5170,6 +5198,10 @@ for (var _i3 = 0; _i3 < letters.length; _i3++) {
5170
5198
  defineSymbol(text, main, textord, _ch3, wideChar);
5171
5199
  wideChar = String.fromCharCode(0xD835, 0xDD04 + _i3); // A-Z a-z Fractur
5172
5200
 
5201
+ defineSymbol(math, main, mathord, _ch3, wideChar);
5202
+ defineSymbol(text, main, textord, _ch3, wideChar);
5203
+ wideChar = String.fromCharCode(0xD835, 0xDD6C + _i3); // A-Z a-z bold Fractur
5204
+
5173
5205
  defineSymbol(math, main, mathord, _ch3, wideChar);
5174
5206
  defineSymbol(text, main, textord, _ch3, wideChar);
5175
5207
  wideChar = String.fromCharCode(0xD835, 0xDDA0 + _i3); // A-Z a-z sans-serif
@@ -5277,8 +5309,9 @@ var wideLatinLetterData = [["mathbf", "textbf", "Main-Bold"], // A-Z bold uprigh
5277
5309
  ["mathfrak", "textfrak", "Fraktur-Regular"], // a-z Fraktur
5278
5310
  ["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck
5279
5311
  ["mathbb", "textbb", "AMS-Regular"], // k double-struck
5280
- ["", "", ""], // A-Z bold Fraktur No font metrics
5281
- ["", "", ""], // a-z bold Fraktur. No font.
5312
+ // Note that we are using a bold font, but font metrics for regular Fraktur.
5313
+ ["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // A-Z bold Fraktur
5314
+ ["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // a-z bold Fraktur
5282
5315
  ["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif
5283
5316
  ["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif
5284
5317
  ["mathboldsf", "textboldsf", "SansSerif-Bold"], // A-Z bold sans-serif
@@ -5454,10 +5487,15 @@ var makeOrd = function makeOrd(group, options, type) {
5454
5487
 
5455
5488
  var isFont = mode === "math" || mode === "text" && options.font;
5456
5489
  var fontOrFamily = isFont ? options.font : options.fontFamily;
5490
+ var wideFontName = "";
5491
+ var wideFontClass = "";
5457
5492
 
5458
5493
  if (text.charCodeAt(0) === 0xD835) {
5494
+ [wideFontName, wideFontClass] = wideCharacterFont(text, mode);
5495
+ }
5496
+
5497
+ if (wideFontName.length > 0) {
5459
5498
  // surrogate pairs get special treatment
5460
- var [wideFontName, wideFontClass] = wideCharacterFont(text, mode);
5461
5499
  return makeSymbol(text, wideFontName, mode, options, classes.concat(wideFontClass));
5462
5500
  } else if (fontOrFamily) {
5463
5501
  var fontName;
@@ -16324,6 +16362,19 @@ class MacroExpander {
16324
16362
 
16325
16363
  return args;
16326
16364
  }
16365
+ /**
16366
+ * Increment `expansionCount` by the specified amount.
16367
+ * Throw an error if it exceeds `maxExpand`.
16368
+ */
16369
+
16370
+
16371
+ countExpansion(amount) {
16372
+ this.expansionCount += amount;
16373
+
16374
+ if (this.expansionCount > this.settings.maxExpand) {
16375
+ throw new ParseError("Too many expansions: infinite loop or " + "need to increase maxExpand setting");
16376
+ }
16377
+ }
16327
16378
  /**
16328
16379
  * Expand the next token only once if possible.
16329
16380
  *
@@ -16359,12 +16410,7 @@ class MacroExpander {
16359
16410
  return false;
16360
16411
  }
16361
16412
 
16362
- this.expansionCount++;
16363
-
16364
- if (this.expansionCount > this.settings.maxExpand) {
16365
- throw new ParseError("Too many expansions: infinite loop or " + "need to increase maxExpand setting");
16366
- }
16367
-
16413
+ this.countExpansion(1);
16368
16414
  var tokens = expansion.tokens;
16369
16415
  var args = this.consumeArgs(expansion.numArgs, expansion.delimiters);
16370
16416
 
@@ -16470,8 +16516,11 @@ class MacroExpander {
16470
16516
 
16471
16517
  output.push(token);
16472
16518
  }
16473
- }
16519
+ } // Count all of these tokens as additional expansions, to prevent
16520
+ // exponential blowup from linearly many \edef's.
16521
+
16474
16522
 
16523
+ this.countExpansion(output.length);
16475
16524
  return output;
16476
16525
  }
16477
16526
  /**
@@ -17479,8 +17528,9 @@ class Parser {
17479
17528
  // We treat these similarly to the unicode-math package.
17480
17529
  // So we render a string of Unicode (sub|super)scripts the
17481
17530
  // same as a (sub|super)script of regular characters.
17482
- var str = uSubsAndSups[lex.text];
17483
17531
  var isSub = unicodeSubRegEx.test(lex.text);
17532
+ var subsupTokens = [];
17533
+ subsupTokens.push(new Token(uSubsAndSups[lex.text]));
17484
17534
  this.consume(); // Continue fetching tokens to fill out the string.
17485
17535
 
17486
17536
  while (true) {
@@ -17494,12 +17544,12 @@ class Parser {
17494
17544
  break;
17495
17545
  }
17496
17546
 
17547
+ subsupTokens.unshift(new Token(uSubsAndSups[token]));
17497
17548
  this.consume();
17498
- str += uSubsAndSups[token];
17499
17549
  } // Now create a (sub|super)script.
17500
17550
 
17501
17551
 
17502
- var body = new Parser(str, this.settings).parse();
17552
+ var body = this.subparse(subsupTokens);
17503
17553
 
17504
17554
  if (isSub) {
17505
17555
  subscript = {
@@ -18309,7 +18359,7 @@ var katex = {
18309
18359
  /**
18310
18360
  * Current KaTeX version
18311
18361
  */
18312
- version: "0.16.8",
18362
+ version: "0.16.10",
18313
18363
 
18314
18364
  /**
18315
18365
  * Renders the given LaTeX into an HTML+MathML combination, and adds
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "katex",
3
- "version": "0.16.8",
3
+ "version": "0.16.10",
4
4
  "description": "Fast math typesetting for the web.",
5
5
  "main": "dist/katex.js",
6
6
  "exports": {
@@ -47,7 +47,7 @@
47
47
  "dist/"
48
48
  ],
49
49
  "license": "MIT",
50
- "packageManager": "yarn@3.2.2",
50
+ "packageManager": "yarn@4.1.1",
51
51
  "devDependencies": {
52
52
  "@babel/core": "^7.18.13",
53
53
  "@babel/eslint-parser": "^7.18.9",
@@ -245,6 +245,18 @@ export default class MacroExpander implements MacroContextInterface {
245
245
  return args;
246
246
  }
247
247
 
248
+ /**
249
+ * Increment `expansionCount` by the specified amount.
250
+ * Throw an error if it exceeds `maxExpand`.
251
+ */
252
+ countExpansion(amount: number): void {
253
+ this.expansionCount += amount;
254
+ if (this.expansionCount > this.settings.maxExpand) {
255
+ throw new ParseError("Too many expansions: infinite loop or " +
256
+ "need to increase maxExpand setting");
257
+ }
258
+ }
259
+
248
260
  /**
249
261
  * Expand the next token only once if possible.
250
262
  *
@@ -276,11 +288,7 @@ export default class MacroExpander implements MacroContextInterface {
276
288
  this.pushToken(topToken);
277
289
  return false;
278
290
  }
279
- this.expansionCount++;
280
- if (this.expansionCount > this.settings.maxExpand) {
281
- throw new ParseError("Too many expansions: infinite loop or " +
282
- "need to increase maxExpand setting");
283
- }
291
+ this.countExpansion(1);
284
292
  let tokens = expansion.tokens;
285
293
  const args = this.consumeArgs(expansion.numArgs, expansion.delimiters);
286
294
  if (expansion.numArgs) {
@@ -375,6 +383,9 @@ export default class MacroExpander implements MacroContextInterface {
375
383
  output.push(token);
376
384
  }
377
385
  }
386
+ // Count all of these tokens as additional expansions, to prevent
387
+ // exponential blowup from linearly many \edef's.
388
+ this.countExpansion(output.length);
378
389
  return output;
379
390
  }
380
391
 
package/src/Parser.js CHANGED
@@ -405,19 +405,20 @@ export default class Parser {
405
405
  // We treat these similarly to the unicode-math package.
406
406
  // So we render a string of Unicode (sub|super)scripts the
407
407
  // same as a (sub|super)script of regular characters.
408
- let str = uSubsAndSups[lex.text];
409
408
  const isSub = unicodeSubRegEx.test(lex.text);
409
+ const subsupTokens = [];
410
+ subsupTokens.push(new Token(uSubsAndSups[lex.text]));
410
411
  this.consume();
411
412
  // Continue fetching tokens to fill out the string.
412
413
  while (true) {
413
414
  const token = this.fetch().text;
414
415
  if (!(uSubsAndSups[token])) { break; }
415
416
  if (unicodeSubRegEx.test(token) !== isSub) { break; }
417
+ subsupTokens.unshift(new Token(uSubsAndSups[token]));
416
418
  this.consume();
417
- str += uSubsAndSups[token];
418
419
  }
419
420
  // Now create a (sub|super)script.
420
- const body = (new Parser(str, this.settings)).parse();
421
+ const body = this.subparse(subsupTokens);
421
422
  if (isSub) {
422
423
  subscript = {type: "ordgroup", mode: "math", body};
423
424
  } else {
package/src/Settings.js CHANGED
@@ -346,7 +346,11 @@ export default class Settings {
346
346
  */
347
347
  isTrusted(context: AnyTrustContext): boolean {
348
348
  if (context.url && !context.protocol) {
349
- context.protocol = utils.protocolFromUrl(context.url);
349
+ const protocol = utils.protocolFromUrl(context.url);
350
+ if (protocol == null) {
351
+ return false;
352
+ }
353
+ context.protocol = protocol;
350
354
  }
351
355
  const trust = typeof this.trust === "function"
352
356
  ? this.trust(context)
@@ -165,9 +165,13 @@ const makeOrd = function<NODETYPE: "spacing" | "mathord" | "textord">(
165
165
  // Math mode or Old font (i.e. \rm)
166
166
  const isFont = mode === "math" || (mode === "text" && options.font);
167
167
  const fontOrFamily = isFont ? options.font : options.fontFamily;
168
+ let wideFontName = "";
169
+ let wideFontClass = "";
168
170
  if (text.charCodeAt(0) === 0xD835) {
171
+ [wideFontName, wideFontClass] = wideCharacterFont(text, mode);
172
+ }
173
+ if (wideFontName.length > 0) {
169
174
  // surrogate pairs get special treatment
170
- const [wideFontName, wideFontClass] = wideCharacterFont(text, mode);
171
175
  return makeSymbol(text, wideFontName, mode, options,
172
176
  classes.concat(wideFontClass));
173
177
  } else if (fontOrFamily) {
package/src/domTree.js CHANGED
@@ -315,7 +315,8 @@ export class Img implements VirtualNode {
315
315
  }
316
316
 
317
317
  toMarkup(): string {
318
- let markup = `<img src='${this.src} 'alt='${this.alt}' `;
318
+ let markup = `<img src="${utils.escape(this.src)}"` +
319
+ ` alt="${utils.escape(this.alt)}"`;
319
320
 
320
321
  // Add the styles, after hyphenation
321
322
  let styles = "";
@@ -512,7 +513,7 @@ export class SvgNode implements VirtualNode {
512
513
  // Apply attributes
513
514
  for (const attr in this.attributes) {
514
515
  if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
515
- markup += ` ${attr}='${this.attributes[attr]}'`;
516
+ markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`;
516
517
  }
517
518
  }
518
519
 
@@ -553,9 +554,9 @@ export class PathNode implements VirtualNode {
553
554
 
554
555
  toMarkup(): string {
555
556
  if (this.alternate) {
556
- return `<path d='${this.alternate}'/>`;
557
+ return `<path d="${utils.escape(this.alternate)}"/>`;
557
558
  } else {
558
- return `<path d='${path[this.pathName]}'/>`;
559
+ return `<path d="${utils.escape(path[this.pathName])}"/>`;
559
560
  }
560
561
  }
561
562
  }
@@ -586,7 +587,7 @@ export class LineNode implements VirtualNode {
586
587
 
587
588
  for (const attr in this.attributes) {
588
589
  if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
589
- markup += ` ${attr}='${this.attributes[attr]}'`;
590
+ markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`;
590
591
  }
591
592
  }
592
593
 
package/src/katex.less CHANGED
@@ -129,6 +129,12 @@
129
129
  font-family: KaTeX_Fraktur;
130
130
  }
131
131
 
132
+ .mathboldfrak,
133
+ .textboldfrak {
134
+ font-family: KaTeX_Fraktur;
135
+ font-weight: bold;
136
+ }
137
+
132
138
  .mathtt {
133
139
  font-family: KaTeX_Typewriter;
134
140
  }
package/src/symbols.js CHANGED
@@ -204,7 +204,7 @@ defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons", true);
204
204
 
205
205
  // AMS Negated Binary Relations
206
206
  defineSymbol(math, ams, rel, "\u226e", "\\nless", true);
207
- // Symbol names preceeded by "@" each have a corresponding macro.
207
+ // Symbol names preceded by "@" each have a corresponding macro.
208
208
  defineSymbol(math, ams, rel, "\ue010", "\\@nleqslant");
209
209
  defineSymbol(math, ams, rel, "\ue011", "\\@nleqq");
210
210
  defineSymbol(math, ams, rel, "\u2a87", "\\lneq", true);
@@ -816,6 +816,10 @@ for (let i = 0; i < letters.length; i++) {
816
816
  defineSymbol(math, main, mathord, ch, wideChar);
817
817
  defineSymbol(text, main, textord, ch, wideChar);
818
818
 
819
+ wideChar = String.fromCharCode(0xD835, 0xDD6C + i); // A-Z a-z bold Fractur
820
+ defineSymbol(math, main, mathord, ch, wideChar);
821
+ defineSymbol(text, main, textord, ch, wideChar);
822
+
819
823
  wideChar = String.fromCharCode(0xD835, 0xDDA0 + i); // A-Z a-z sans-serif
820
824
  defineSymbol(math, main, mathord, ch, wideChar);
821
825
  defineSymbol(text, main, textord, ch, wideChar);
package/src/utils.js CHANGED
@@ -93,11 +93,30 @@ export const assert = function<T>(value: ?T): T {
93
93
 
94
94
  /**
95
95
  * Return the protocol of a URL, or "_relative" if the URL does not specify a
96
- * protocol (and thus is relative).
96
+ * protocol (and thus is relative), or `null` if URL has invalid protocol
97
+ * (so should be outright rejected).
97
98
  */
98
- export const protocolFromUrl = function(url: string): string {
99
- const protocol = /^\s*([^\\/#]*?)(?::|&#0*58|&#x0*3a)/i.exec(url);
100
- return (protocol != null ? protocol[1] : "_relative");
99
+ export const protocolFromUrl = function(url: string): string | null {
100
+ // Check for possible leading protocol.
101
+ // https://url.spec.whatwg.org/#url-parsing strips leading whitespace
102
+ // (U+20) or C0 control (U+00-U+1F) characters.
103
+ // eslint-disable-next-line no-control-regex
104
+ const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|&#0*58|&#x0*3a|&colon)/i
105
+ .exec(url);
106
+ if (!protocol) {
107
+ return "_relative";
108
+ }
109
+ // Reject weird colons
110
+ if (protocol[2] !== ":") {
111
+ return null;
112
+ }
113
+ // Reject invalid characters in scheme according to
114
+ // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1
115
+ if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) {
116
+ return null;
117
+ }
118
+ // Lowercase the protocol
119
+ return protocol[1].toLowerCase();
101
120
  };
102
121
 
103
122
  export default {
@@ -45,8 +45,9 @@ const wideLatinLetterData: Array<[string, string, string]> = [
45
45
  ["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck
46
46
  ["mathbb", "textbb", "AMS-Regular"], // k double-struck
47
47
 
48
- ["", "", ""], // A-Z bold Fraktur No font metrics
49
- ["", "", ""], // a-z bold Fraktur. No font.
48
+ // Note that we are using a bold font, but font metrics for regular Fraktur.
49
+ ["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // A-Z bold Fraktur
50
+ ["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // a-z bold Fraktur
50
51
 
51
52
  ["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif
52
53
  ["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif