Upgrade Katex to v0.16.10

This commit is contained in:
Will Faught
2024-04-06 17:58:45 -07:00
parent d0a44bcda1
commit 0e0df96c29
32 changed files with 3806 additions and 3525 deletions

View File

@@ -245,6 +245,18 @@ export default class MacroExpander implements MacroContextInterface {
return args;
}
/**
* Increment `expansionCount` by the specified amount.
* Throw an error if it exceeds `maxExpand`.
*/
countExpansion(amount: number): void {
this.expansionCount += amount;
if (this.expansionCount > this.settings.maxExpand) {
throw new ParseError("Too many expansions: infinite loop or " +
"need to increase maxExpand setting");
}
}
/**
* Expand the next token only once if possible.
*
@@ -276,11 +288,7 @@ export default class MacroExpander implements MacroContextInterface {
this.pushToken(topToken);
return false;
}
this.expansionCount++;
if (this.expansionCount > this.settings.maxExpand) {
throw new ParseError("Too many expansions: infinite loop or " +
"need to increase maxExpand setting");
}
this.countExpansion(1);
let tokens = expansion.tokens;
const args = this.consumeArgs(expansion.numArgs, expansion.delimiters);
if (expansion.numArgs) {
@@ -375,6 +383,9 @@ export default class MacroExpander implements MacroContextInterface {
output.push(token);
}
}
// Count all of these tokens as additional expansions, to prevent
// exponential blowup from linearly many \edef's.
this.countExpansion(output.length);
return output;
}

View File

@@ -405,19 +405,20 @@ export default class Parser {
// We treat these similarly to the unicode-math package.
// So we render a string of Unicode (sub|super)scripts the
// same as a (sub|super)script of regular characters.
let str = uSubsAndSups[lex.text];
const isSub = unicodeSubRegEx.test(lex.text);
const subsupTokens = [];
subsupTokens.push(new Token(uSubsAndSups[lex.text]));
this.consume();
// Continue fetching tokens to fill out the string.
while (true) {
const token = this.fetch().text;
if (!(uSubsAndSups[token])) { break; }
if (unicodeSubRegEx.test(token) !== isSub) { break; }
subsupTokens.unshift(new Token(uSubsAndSups[token]));
this.consume();
str += uSubsAndSups[token];
}
// Now create a (sub|super)script.
const body = (new Parser(str, this.settings)).parse();
const body = this.subparse(subsupTokens);
if (isSub) {
subscript = {type: "ordgroup", mode: "math", body};
} else {

View File

@@ -346,7 +346,11 @@ export default class Settings {
*/
isTrusted(context: AnyTrustContext): boolean {
if (context.url && !context.protocol) {
context.protocol = utils.protocolFromUrl(context.url);
const protocol = utils.protocolFromUrl(context.url);
if (protocol == null) {
return false;
}
context.protocol = protocol;
}
const trust = typeof this.trust === "function"
? this.trust(context)

View File

@@ -165,9 +165,13 @@ const makeOrd = function<NODETYPE: "spacing" | "mathord" | "textord">(
// Math mode or Old font (i.e. \rm)
const isFont = mode === "math" || (mode === "text" && options.font);
const fontOrFamily = isFont ? options.font : options.fontFamily;
let wideFontName = "";
let wideFontClass = "";
if (text.charCodeAt(0) === 0xD835) {
[wideFontName, wideFontClass] = wideCharacterFont(text, mode);
}
if (wideFontName.length > 0) {
// surrogate pairs get special treatment
const [wideFontName, wideFontClass] = wideCharacterFont(text, mode);
return makeSymbol(text, wideFontName, mode, options,
classes.concat(wideFontClass));
} else if (fontOrFamily) {

View File

@@ -315,7 +315,8 @@ export class Img implements VirtualNode {
}
toMarkup(): string {
let markup = `<img src='${this.src} 'alt='${this.alt}' `;
let markup = `<img src="${utils.escape(this.src)}"` +
` alt="${utils.escape(this.alt)}"`;
// Add the styles, after hyphenation
let styles = "";
@@ -512,7 +513,7 @@ export class SvgNode implements VirtualNode {
// Apply attributes
for (const attr in this.attributes) {
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
markup += ` ${attr}='${this.attributes[attr]}'`;
markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`;
}
}
@@ -553,9 +554,9 @@ export class PathNode implements VirtualNode {
toMarkup(): string {
if (this.alternate) {
return `<path d='${this.alternate}'/>`;
return `<path d="${utils.escape(this.alternate)}"/>`;
} else {
return `<path d='${path[this.pathName]}'/>`;
return `<path d="${utils.escape(path[this.pathName])}"/>`;
}
}
}
@@ -586,7 +587,7 @@ export class LineNode implements VirtualNode {
for (const attr in this.attributes) {
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
markup += ` ${attr}='${this.attributes[attr]}'`;
markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`;
}
}

View File

@@ -129,6 +129,12 @@
font-family: KaTeX_Fraktur;
}
.mathboldfrak,
.textboldfrak {
font-family: KaTeX_Fraktur;
font-weight: bold;
}
.mathtt {
font-family: KaTeX_Typewriter;
}

View File

@@ -204,7 +204,7 @@ defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons", true);
// AMS Negated Binary Relations
defineSymbol(math, ams, rel, "\u226e", "\\nless", true);
// Symbol names preceeded by "@" each have a corresponding macro.
// Symbol names preceded by "@" each have a corresponding macro.
defineSymbol(math, ams, rel, "\ue010", "\\@nleqslant");
defineSymbol(math, ams, rel, "\ue011", "\\@nleqq");
defineSymbol(math, ams, rel, "\u2a87", "\\lneq", true);
@@ -816,6 +816,10 @@ for (let i = 0; i < letters.length; i++) {
defineSymbol(math, main, mathord, ch, wideChar);
defineSymbol(text, main, textord, ch, wideChar);
wideChar = String.fromCharCode(0xD835, 0xDD6C + i); // A-Z a-z bold Fractur
defineSymbol(math, main, mathord, ch, wideChar);
defineSymbol(text, main, textord, ch, wideChar);
wideChar = String.fromCharCode(0xD835, 0xDDA0 + i); // A-Z a-z sans-serif
defineSymbol(math, main, mathord, ch, wideChar);
defineSymbol(text, main, textord, ch, wideChar);

View File

@@ -93,11 +93,30 @@ export const assert = function<T>(value: ?T): T {
/**
* Return the protocol of a URL, or "_relative" if the URL does not specify a
* protocol (and thus is relative).
* protocol (and thus is relative), or `null` if URL has invalid protocol
* (so should be outright rejected).
*/
export const protocolFromUrl = function(url: string): string {
const protocol = /^\s*([^\\/#]*?)(?::|&#0*58|&#x0*3a)/i.exec(url);
return (protocol != null ? protocol[1] : "_relative");
export const protocolFromUrl = function(url: string): string | null {
// Check for possible leading protocol.
// https://url.spec.whatwg.org/#url-parsing strips leading whitespace
// (U+20) or C0 control (U+00-U+1F) characters.
// eslint-disable-next-line no-control-regex
const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|&#0*58|&#x0*3a|&colon)/i
.exec(url);
if (!protocol) {
return "_relative";
}
// Reject weird colons
if (protocol[2] !== ":") {
return null;
}
// Reject invalid characters in scheme according to
// https://datatracker.ietf.org/doc/html/rfc3986#section-3.1
if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) {
return null;
}
// Lowercase the protocol
return protocol[1].toLowerCase();
};
export default {

View File

@@ -45,8 +45,9 @@ const wideLatinLetterData: Array<[string, string, string]> = [
["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck
["mathbb", "textbb", "AMS-Regular"], // k double-struck
["", "", ""], // A-Z bold Fraktur No font metrics
["", "", ""], // a-z bold Fraktur. No font.
// Note that we are using a bold font, but font metrics for regular Fraktur.
["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // A-Z bold Fraktur
["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // a-z bold Fraktur
["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif
["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif