New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

tex2typst

Package Overview
Dependencies
Maintainers
0
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tex2typst - npm Package Compare versions

Comparing version 0.2.7 to 0.2.8

1169

dist/index.js

@@ -0,1 +1,301 @@

// src/map.ts
var symbolMap = new Map([
["nonumber", ""],
["vec", "arrow"],
["neq", "eq.not"],
["dot", "dot"],
["ddot", "dot.double"],
["doteq", "dot(eq)"],
["dots", "dots.h"],
["ldots", "dots.h"],
["vdots", "dots.v"],
["ddots", "dots.down"],
["widehat", "hat"],
["widetilde", "tilde"],
["quad", "quad"],
["qquad", "wide"],
["overbrace", "overbrace"],
["underbrace", "underbrace"],
["overline", "overline"],
["underline", "underline"],
["bar", "macron"],
["dbinom", "binom"],
["tbinom", "binom"],
["dfrac", "frac"],
["tfrac", "frac"],
["boldsymbol", "bold"],
["mathbb", "bb"],
["mathbf", "bold"],
["mathcal", "cal"],
["mathit", "italic"],
["mathfrak", "frak"],
["mathrm", "upright"],
["mathsf", "sans"],
["mathtt", "mono"],
["rm", "upright"],
["pmb", "bold"],
["pm", "plus.minus"],
["mp", "minus.plus"],
["oplus", "xor"],
["boxplus", "plus.square"],
["otimes", "times.circle"],
["boxtimes", "times.square"],
["sim", "tilde"],
["approx", "approx"],
["cong", "tilde.equiv"],
["simeq", "tilde.eq"],
["asymp", "\u224D"],
["equiv", "equiv"],
["propto", "prop"],
["lfloor", "\u230A"],
["rfloor", "\u230B"],
["lceil", "\u2308"],
["rceil", "\u2309"],
["gets", "arrow.l"],
["hookleftarrow", "arrow.l.hook"],
["leftharpoonup", "harpoon.lt"],
["leftharpoondown", "harpoon.lb"],
["rightleftharpoons", "harpoons.rtlb"],
["longleftarrow", "arrow.l.long"],
["longrightarrow", "arrow.r.long"],
["longleftrightarrow", "arrow.l.r.long"],
["Longleftarrow", "arrow.l.double.long"],
["Longrightarrow", "arrow.r.double.long"],
["Longleftrightarrow", "arrow.l.r.double.long"],
["longmapsto", "arrow.r.bar"],
["hookrightarrow", "arrow.r.hook"],
["rightharpoonup", "harpoon.rt"],
["rightharpoondown", "harpoon.rb"],
["iff", "arrow.l.r.double.long"],
["implies", "arrow.r.double.long"],
["uparrow", "arrow.t"],
["downarrow", "arrow.b"],
["updownarrow", "arrow.t.b"],
["Uparrow", "arrow.t.double"],
["Downarrow", "arrow.b.double"],
["Updownarrow", "arrow.t.b.double"],
["nearrow", "arrow.tr"],
["searrow", "arrow.br"],
["swarrow", "arrow.bl"],
["nwarrow", "arrow.tl"],
["leadsto", "arrow.squiggly"],
["leftleftarrows", "arrows.ll"],
["rightrightarrows", "arrows.rr"],
["Cap", "sect.double"],
["Cup", "union.double"],
["Delta", "Delta"],
["Gamma", "Gamma"],
["Join", "join"],
["Lambda", "Lambda"],
["Leftarrow", "arrow.l.double"],
["Leftrightarrow", "arrow.l.r.double"],
["Longrightarrow", "arrow.r.double.long"],
["Omega", "Omega"],
["P", "pilcrow"],
["Phi", "Phi"],
["Pi", "Pi"],
["Psi", "Psi"],
["Rightarrow", "arrow.r.double"],
["S", "section"],
["Sigma", "Sigma"],
["Theta", "Theta"],
["aleph", "alef"],
["alpha", "alpha"],
["angle", "angle"],
["approx", "approx"],
["approxeq", "approx.eq"],
["ast", "ast"],
["beta", "beta"],
["bigcap", "sect.big"],
["bigcirc", "circle.big"],
["bigcup", "union.big"],
["bigodot", "dot.circle.big"],
["bigoplus", "xor.big"],
["bigotimes", "times.circle.big"],
["bigsqcup", "union.sq.big"],
["bigtriangledown", "triangle.b"],
["bigtriangleup", "triangle.t"],
["biguplus", "union.plus.big"],
["bigvee", "or.big"],
["bigwedge", "and.big"],
["bullet", "bullet"],
["cap", "sect"],
["cdot", "dot.op"],
["cdots", "dots.c"],
["checkmark", "checkmark"],
["chi", "chi"],
["circ", "circle.small"],
["colon", "colon"],
["cong", "tilde.equiv"],
["coprod", "product.co"],
["copyright", "copyright"],
["cup", "union"],
["curlyvee", "or.curly"],
["curlywedge", "and.curly"],
["dagger", "dagger"],
["dashv", "tack.l"],
["ddagger", "dagger.double"],
["delta", "delta"],
["ddots", "dots.down"],
["diamond", "diamond"],
["div", "div"],
["divideontimes", "times.div"],
["dotplus", "plus.dot"],
["downarrow", "arrow.b"],
["ell", "ell"],
["emptyset", "nothing"],
["epsilon", "epsilon.alt"],
["equiv", "equiv"],
["eta", "eta"],
["exists", "exists"],
["forall", "forall"],
["gamma", "gamma"],
["ge", "gt.eq"],
["geq", "gt.eq"],
["geqslant", "gt.eq.slant"],
["gg", "gt.double"],
["hbar", "planck.reduce"],
["imath", "dotless.i"],
["iiiint", "intgral.quad"],
["iiint", "integral.triple"],
["iint", "integral.double"],
["in", "in"],
["infty", "infinity"],
["int", "integral"],
["intercal", "top"],
["iota", "iota"],
["jmath", "dotless.j"],
["kappa", "kappa"],
["lambda", "lambda"],
["land", "and"],
["langle", "angle.l"],
["lbrace", "brace.l"],
["lbrack", "bracket.l"],
["ldots", "dots.l"],
["le", "lt.eq"],
["leadsto", "arrow.squiggly"],
["leftarrow", "arrow.l"],
["leftthreetimes", "times.three.l"],
["leftrightarrow", "arrow.l.r"],
["leq", "lt.eq"],
["leqslant", "lt.eq.slant"],
["lhd", "triangle.l"],
["ll", "lt.double"],
["longmapsto", "arrow.bar.long"],
["longrightarrow", "arrow.long"],
["lor", "or"],
["ltimes", "times.l"],
["mapsto", "arrow.bar"],
["measuredangle", "angle.arc"],
["mid", "divides"],
["models", "models"],
["mp", "minus.plus"],
["mu", "mu"],
["nRightarrow", "arrow.double.not"],
["nabla", "nabla"],
["ncong", "tilde.nequiv"],
["ne", "eq.not"],
["neg", "not"],
["neq", "eq.not"],
["nexists", "exists.not"],
["ni", "in.rev"],
["nleftarrow", "arrow.l.not"],
["nleq", "lt.eq.not"],
["nparallel", "parallel.not"],
["ngeq", "gt.eq.not"],
["nmid", "divides.not"],
["notin", "in.not"],
["nrightarrow", "arrow.not"],
["nsim", "tilde.not"],
["nsubseteq", "subset.eq.not"],
["nu", "nu"],
["ntriangleleft", "lt.tri.not"],
["ntriangleright", "gt.tri.not"],
["nwarrow", "arrow.tl"],
["odot", "dot.circle"],
["oint", "integral.cont"],
["oiint", "integral.surf"],
["oiiint", "integral.vol"],
["omega", "omega"],
["ominus", "minus.circle"],
["oplus", "xor"],
["otimes", "times.circle"],
["parallel", "parallel"],
["partial", "diff"],
["perp", "perp"],
["phi", "phi.alt"],
["pi", "pi"],
["pm", "plus.minus"],
["pounds", "pound"],
["prec", "prec"],
["preceq", "prec.eq"],
["prime", "prime"],
["prod", "product"],
["propto", "prop"],
["psi", "psi"],
["rangle", "angle.r"],
["rbrace", "brace.r"],
["rbrack", "bracket.r"],
["rhd", "triangle"],
["rho", "rho"],
["rightarrow", "arrow.r"],
["rightthreetimes", "times.three.r"],
["rtimes", "times.r"],
["setminus", "without"],
["sigma", "sigma"],
["sim", "tilde"],
["simeq", "tilde.eq"],
["slash", "slash"],
["smallsetminus", "without"],
["spadesuit", "suit.spade"],
["sqcap", "sect.sq"],
["sqcup", "union.sq"],
["sqsubseteq", "subset.eq.sq"],
["sqsupseteq", "supset.eq.sq"],
["star", "star"],
["subset", "subset"],
["subseteq", "subset.eq"],
["subsetneq", "subset.neq"],
["succ", "succ"],
["succeq", "succ.eq"],
["sum", "sum"],
["supset", "supset"],
["supseteq", "supset.eq"],
["supsetneq", "supset.neq"],
["swarrow", "arrow.bl"],
["tau", "tau"],
["theta", "theta"],
["times", "times"],
["to", "arrow.r"],
["top", "top"],
["triangle", "triangle.t"],
["triangledown", "triangle.b.small"],
["triangleleft", "triangle.l.small"],
["triangleright", "triangle.r.small"],
["twoheadrightarrow", "arrow.r.twohead"],
["uparrow", "arrow.t"],
["updownarrow", "arrow.t.b"],
["upharpoonright", "harpoon.tr"],
["uplus", "union.plus"],
["upsilon", "upsilon"],
["varepsilon", "epsilon"],
["varnothing", "diameter"],
["varphi", "phi"],
["varpi", "pi.alt"],
["varrho", "rho.alt"],
["varsigma", "sigma.alt"],
["vartheta", "theta.alt"],
["vdash", "tack.r"],
["vdots", "dots.v"],
["vee", "or"],
["wedge", "and"],
["wr", "wreath"],
["xi", "xi"],
["yen", "yen"],
["zeta", "zeta"],
["mathscr", "scr"],
["LaTeX", "#LaTeX"],
["TeX", "#TeX"]
]);
// src/parser.ts

@@ -58,3 +358,3 @@ function assert(condition, message = "") {

let pos = start;
while (pos < tokens.length && ["whitespace", "newline"].includes(tokens[pos].type)) {
while (pos < tokens.length && [4 /* WHITESPACE */, 5 /* NEWLINE */].includes(tokens[pos].type)) {
pos++;

@@ -66,5 +366,5 @@ }

const firstToken = tokens[start];
if (firstToken.type === "element" && ["(", ")", "[", "]", "|", "\\{", "\\}"].includes(firstToken.value)) {
if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}"].includes(firstToken.value)) {
return firstToken;
} else if (firstToken.type === "command" && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
} else if (firstToken.type === 1 /* COMMAND */ && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
return firstToken;

@@ -77,3 +377,3 @@ } else {

let pos = start;
while (pos < tokens.length && token_eq(tokens[pos], { type: "element", value: "'" })) {
while (pos < tokens.length && token_eq(tokens[pos], { type: 0 /* ELEMENT */, value: "'" })) {
pos += 1;

@@ -155,3 +455,3 @@ }

}
token = { type: "comment", value: latex.slice(pos + 1, newPos) };
token = { type: 3 /* COMMENT */, value: latex.slice(pos + 1, newPos) };
pos = newPos;

@@ -165,7 +465,7 @@ break;

case "&":
token = { type: "control", value: firstChar };
token = { type: 6 /* CONTROL */, value: firstChar };
pos++;
break;
case "\n":
token = { type: "newline", value: firstChar };
token = { type: 5 /* NEWLINE */, value: firstChar };
pos++;

@@ -175,6 +475,6 @@ break;

if (pos + 1 < latex.length && latex[pos + 1] === "\n") {
token = { type: "newline", value: "\n" };
token = { type: 5 /* NEWLINE */, value: "\n" };
pos += 2;
} else {
token = { type: "newline", value: "\n" };
token = { type: 5 /* NEWLINE */, value: "\n" };
pos++;

@@ -189,3 +489,3 @@ }

}
token = { type: "whitespace", value: latex.slice(pos, newPos) };
token = { type: 4 /* WHITESPACE */, value: latex.slice(pos, newPos) };
pos = newPos;

@@ -200,8 +500,8 @@ break;

if (["\\\\", "\\,"].includes(firstTwoChars)) {
token = { type: "control", value: firstTwoChars };
token = { type: 6 /* CONTROL */, value: firstTwoChars };
} else if (["\\{", "\\}", "\\%", "\\$", "\\&", "\\#", "\\_"].includes(firstTwoChars)) {
token = { type: "element", value: firstTwoChars };
token = { type: 0 /* ELEMENT */, value: firstTwoChars };
} else {
const command = eat_command_name(latex, pos + 1);
token = { type: "command", value: "\\" + command };
token = { type: 1 /* COMMAND */, value: "\\" + command };
}

@@ -217,9 +517,9 @@ pos += token.value.length;

}
token = { type: "element", value: latex.slice(pos, newPos) };
token = { type: 0 /* ELEMENT */, value: latex.slice(pos, newPos) };
} else if (isalpha(firstChar)) {
token = { type: "element", value: firstChar };
token = { type: 0 /* ELEMENT */, value: firstChar };
} else if ("+-*/=\'<>!.,;?()[]|".includes(firstChar)) {
token = { type: "element", value: firstChar };
token = { type: 0 /* ELEMENT */, value: firstChar };
} else {
token = { type: "unknown", value: firstChar };
token = { type: 7 /* UNKNOWN */, value: firstChar };
}

@@ -230,7 +530,7 @@ pos += token.value.length;

tokens.push(token);
if (token.type === "command" && ["\\text", "\\begin", "\\end"].includes(token.value)) {
if (token.type === 1 /* COMMAND */ && ["\\text", "\\operatorname", "\\begin", "\\end"].includes(token.value)) {
if (pos >= latex.length || latex[pos] !== "{") {
throw new LatexParserError(`No content for ${token.value} command`);
}
tokens.push({ type: "control", value: "{" });
tokens.push({ type: 6 /* CONTROL */, value: "{" });
const posClosingBracket = find_closing_curly_bracket_char(latex, pos);

@@ -243,4 +543,4 @@ pos++;

}
tokens.push({ type: "text", value: textInside });
tokens.push({ type: "control", value: "}" });
tokens.push({ type: 2 /* TEXT */, value: textInside });
tokens.push({ type: 6 /* CONTROL */, value: "}" });
pos = posClosingBracket + 1;

@@ -258,6 +558,6 @@ }

for (let i = 0;i < tokens.length; i++) {
if (tokens[i].type === "whitespace" && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
if (tokens[i].type === 4 /* WHITESPACE */ && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
continue;
}
if (tokens[i].type === "whitespace" && i - 1 >= 0 && is_script_mark(tokens[i - 1])) {
if (tokens[i].type === 4 /* WHITESPACE */ && i - 1 >= 0 && is_script_mark(tokens[i - 1])) {
continue;

@@ -272,3 +572,3 @@ }

for (const token of tokens) {
if (token.type === "command" && customTexMacros[token.value]) {
if (token.type === 1 /* COMMAND */ && customTexMacros[token.value]) {
const expanded_tokens = tokenize(customTexMacros[token.value]);

@@ -328,10 +628,10 @@ out_tokens = out_tokens.concat(expanded_tokens);

var EMPTY_NODE = { type: "empty", content: "" };
var LEFT_CURLY_BRACKET = { type: "control", value: "{" };
var RIGHT_CURLY_BRACKET = { type: "control", value: "}" };
var LEFT_SQUARE_BRACKET = { type: "element", value: "[" };
var RIGHT_SQUARE_BRACKET = { type: "element", value: "]" };
var LEFT_COMMAND = { type: "command", value: "\\left" };
var RIGHT_COMMAND = { type: "command", value: "\\right" };
var BEGIN_COMMAND = { type: "command", value: "\\begin" };
var END_COMMAND = { type: "command", value: "\\end" };
var LEFT_CURLY_BRACKET = { type: 6 /* CONTROL */, value: "{" };
var RIGHT_CURLY_BRACKET = { type: 6 /* CONTROL */, value: "}" };
var LEFT_SQUARE_BRACKET = { type: 0 /* ELEMENT */, value: "[" };
var RIGHT_SQUARE_BRACKET = { type: 0 /* ELEMENT */, value: "]" };
var LEFT_COMMAND = { type: 1 /* COMMAND */, value: "\\left" };
var RIGHT_COMMAND = { type: 1 /* COMMAND */, value: "\\right" };
var BEGIN_COMMAND = { type: 1 /* COMMAND */, value: "\\begin" };
var END_COMMAND = { type: 1 /* COMMAND */, value: "\\end" };

@@ -344,4 +644,4 @@ class LatexParserError extends Error {

}
var SUB_SYMBOL = { type: "control", value: "_" };
var SUP_SYMBOL = { type: "control", value: "^" };
var SUB_SYMBOL = { type: 6 /* CONTROL */, value: "_" };
var SUP_SYMBOL = { type: 6 /* CONTROL */, value: "^" };

@@ -428,3 +728,3 @@ class LatexParser {

for (let i = 0;i < num_prime; i++) {
res.sup.args.push({ type: "symbol", content: "\\prime" });
res.sup.args.push({ type: "element", content: "'" });
}

@@ -449,9 +749,13 @@ if (sup) {

switch (tokenType) {
case "element":
case "text":
case "comment":
case "whitespace":
case "newline":
return [{ type: tokenType, content: firstToken.value }, start + 1];
case "command":
case 0 /* ELEMENT */:
return [{ type: "element", content: firstToken.value }, start + 1];
case 2 /* TEXT */:
return [{ type: "text", content: firstToken.value }, start + 1];
case 3 /* COMMENT */:
return [{ type: "comment", content: firstToken.value }, start + 1];
case 4 /* WHITESPACE */:
return [{ type: "whitespace", content: firstToken.value }, start + 1];
case 5 /* NEWLINE */:
return [{ type: "newline", content: firstToken.value }, start + 1];
case 1 /* COMMAND */:
if (token_eq(firstToken, BEGIN_COMMAND)) {

@@ -464,3 +768,3 @@ return this.parseBeginEndExpr(tokens, start);

}
case "control":
case 6 /* CONTROL */:
const controlChar = firstToken.value;

@@ -494,3 +798,3 @@ switch (controlChar) {

parseCommandExpr(tokens, start) {
assert(tokens[start].type === "command");
assert(tokens[start].type === 1 /* COMMAND */);
const command = tokens[start].value;

@@ -502,30 +806,36 @@ let pos = start + 1;

const paramNum = get_command_param_num(command.slice(1));
if (paramNum === 0) {
return [{ type: "symbol", content: command }, pos];
} else if (paramNum === 1) {
if (command === "\\sqrt" && pos < tokens.length && token_eq(tokens[pos], LEFT_SQUARE_BRACKET)) {
const posLeftSquareBracket = pos;
const posRightSquareBracket = find_closing_square_bracket(tokens, pos);
const exprInside = tokens.slice(posLeftSquareBracket + 1, posRightSquareBracket);
const exponent = this.parse(exprInside);
const [arg12, newPos2] = this.parseNextExprWithoutSupSub(tokens, posRightSquareBracket + 1);
return [{ type: "unaryFunc", content: command, args: [arg12], data: exponent }, newPos2];
} else if (command === "\\text") {
if (pos + 2 >= tokens.length) {
throw new LatexParserError("Expecting content for \\text command");
switch (paramNum) {
case 0:
if (!symbolMap.has(command.slice(1))) {
return [{ type: "unknownMacro", content: command }, pos];
}
assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === "text");
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));
const text = tokens[pos + 1].value;
return [{ type: "text", content: text }, pos + 3];
return [{ type: "symbol", content: command }, pos];
case 1: {
if (command === "\\sqrt" && pos < tokens.length && token_eq(tokens[pos], LEFT_SQUARE_BRACKET)) {
const posLeftSquareBracket = pos;
const posRightSquareBracket = find_closing_square_bracket(tokens, pos);
const exprInside = tokens.slice(posLeftSquareBracket + 1, posRightSquareBracket);
const exponent = this.parse(exprInside);
const [arg12, newPos2] = this.parseNextExprWithoutSupSub(tokens, posRightSquareBracket + 1);
return [{ type: "unaryFunc", content: command, args: [arg12], data: exponent }, newPos2];
} else if (command === "\\text") {
if (pos + 2 >= tokens.length) {
throw new LatexParserError("Expecting content for \\text command");
}
assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === 2 /* TEXT */);
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));
const text = tokens[pos + 1].value;
return [{ type: "text", content: text }, pos + 3];
}
let [arg1, newPos] = this.parseNextExprWithoutSupSub(tokens, pos);
return [{ type: "unaryFunc", content: command, args: [arg1] }, newPos];
}
let [arg1, newPos] = this.parseNextExprWithoutSupSub(tokens, pos);
return [{ type: "unaryFunc", content: command, args: [arg1] }, newPos];
} else if (paramNum === 2) {
const [arg1, pos1] = this.parseNextExprWithoutSupSub(tokens, pos);
const [arg2, pos2] = this.parseNextExprWithoutSupSub(tokens, pos1);
return [{ type: "binaryFunc", content: command, args: [arg1, arg2] }, pos2];
} else {
throw new Error("Invalid number of parameters");
case 2: {
const [arg1, pos1] = this.parseNextExprWithoutSupSub(tokens, pos);
const [arg2, pos2] = this.parseNextExprWithoutSupSub(tokens, pos1);
return [{ type: "binaryFunc", content: command, args: [arg1, arg2] }, pos2];
}
default:
throw new Error("Invalid number of parameters");
}

@@ -575,3 +885,3 @@ }

assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === "text");
assert(tokens[pos + 1].type === 2 /* TEXT */);
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));

@@ -589,3 +899,3 @@ const envName = tokens[pos + 1].value;

assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === "text");
assert(tokens[pos + 1].type === 2 /* TEXT */);
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));

@@ -597,3 +907,3 @@ if (tokens[pos + 1].value !== envName) {

const exprInside = tokens.slice(exprInsideStart, exprInsideEnd);
while (exprInside.length > 0 && ["whitespace", "newline"].includes(exprInside[exprInside.length - 1].type)) {
while (exprInside.length > 0 && [4 /* WHITESPACE */, 5 /* NEWLINE */].includes(exprInside[exprInside.length - 1].type)) {
exprInside.pop();

@@ -635,303 +945,163 @@ }

// src/map.ts
var symbolMap = new Map([
["nonumber", ""],
["vec", "arrow"],
["neq", "eq.not"],
["dot", "dot"],
["ddot", "dot.double"],
["doteq", "dot(eq)"],
["dots", "dots.h"],
["ldots", "dots.h"],
["vdots", "dots.v"],
["ddots", "dots.down"],
["widehat", "hat"],
["widetilde", "tilde"],
["quad", "quad"],
["qquad", "wide"],
["overbrace", "overbrace"],
["underbrace", "underbrace"],
["overline", "overline"],
["underline", "underline"],
["bar", "macron"],
["dbinom", "binom"],
["tbinom", "binom"],
["dfrac", "frac"],
["tfrac", "frac"],
["boldsymbol", "bold"],
["mathbb", "bb"],
["mathbf", "bold"],
["mathcal", "cal"],
["mathit", "italic"],
["mathfrak", "frak"],
["mathrm", "upright"],
["mathsf", "sans"],
["mathtt", "mono"],
["rm", "upright"],
["pmb", "bold"],
["pm", "plus.minus"],
["mp", "minus.plus"],
["oplus", "xor"],
["boxplus", "plus.square"],
["otimes", "times.circle"],
["boxtimes", "times.square"],
["sim", "tilde"],
["approx", "approx"],
["cong", "tilde.equiv"],
["simeq", "tilde.eq"],
["asymp", "\u224D"],
["equiv", "equiv"],
["propto", "prop"],
["lfloor", "\u230A"],
["rfloor", "\u230B"],
["lceil", "\u2308"],
["rceil", "\u2309"],
["gets", "arrow.l"],
["hookleftarrow", "arrow.l.hook"],
["leftharpoonup", "harpoon.lt"],
["leftharpoondown", "harpoon.lb"],
["rightleftharpoons", "harpoons.rtlb"],
["longleftarrow", "arrow.l.long"],
["longrightarrow", "arrow.r.long"],
["longleftrightarrow", "arrow.l.r.long"],
["Longleftarrow", "arrow.l.double.long"],
["Longrightarrow", "arrow.r.double.long"],
["Longleftrightarrow", "arrow.l.r.double.long"],
["longmapsto", "arrow.r.bar"],
["hookrightarrow", "arrow.r.hook"],
["rightharpoonup", "harpoon.rt"],
["rightharpoondown", "harpoon.rb"],
["iff", "arrow.l.r.double.long"],
["implies", "arrow.r.double.long"],
["uparrow", "arrow.t"],
["downarrow", "arrow.b"],
["updownarrow", "arrow.t.b"],
["Uparrow", "arrow.t.double"],
["Downarrow", "arrow.b.double"],
["Updownarrow", "arrow.t.b.double"],
["nearrow", "arrow.tr"],
["searrow", "arrow.br"],
["swarrow", "arrow.bl"],
["nwarrow", "arrow.tl"],
["leadsto", "arrow.squiggly"],
["leftleftarrows", "arrows.ll"],
["rightrightarrows", "arrows.rr"],
["Cap", "sect.double"],
["Cup", "union.double"],
["Delta", "Delta"],
["Gamma", "Gamma"],
["Join", "join"],
["Lambda", "Lambda"],
["Leftarrow", "arrow.l.double"],
["Leftrightarrow", "arrow.l.r.double"],
["Longrightarrow", "arrow.r.double.long"],
["Omega", "Omega"],
["P", "pilcrow"],
["Phi", "Phi"],
["Pi", "Pi"],
["Psi", "Psi"],
["Rightarrow", "arrow.r.double"],
["S", "section"],
["Sigma", "Sigma"],
["Theta", "Theta"],
["aleph", "alef"],
["alpha", "alpha"],
["angle", "angle"],
["approx", "approx"],
["approxeq", "approx.eq"],
["ast", "ast"],
["beta", "beta"],
["bigcap", "sect.big"],
["bigcirc", "circle.big"],
["bigcup", "union.big"],
["bigodot", "dot.circle.big"],
["bigoplus", "xor.big"],
["bigotimes", "times.circle.big"],
["bigsqcup", "union.sq.big"],
["bigtriangledown", "triangle.b"],
["bigtriangleup", "triangle.t"],
["biguplus", "union.plus.big"],
["bigvee", "or.big"],
["bigwedge", "and.big"],
["bullet", "bullet"],
["cap", "sect"],
["cdot", "dot.op"],
["cdots", "dots.c"],
["checkmark", "checkmark"],
["chi", "chi"],
["circ", "circle.small"],
["colon", "colon"],
["cong", "tilde.equiv"],
["coprod", "product.co"],
["copyright", "copyright"],
["cup", "union"],
["curlyvee", "or.curly"],
["curlywedge", "and.curly"],
["dagger", "dagger"],
["dashv", "tack.l"],
["ddagger", "dagger.double"],
["delta", "delta"],
["ddots", "dots.down"],
["diamond", "diamond"],
["div", "div"],
["divideontimes", "times.div"],
["dotplus", "plus.dot"],
["downarrow", "arrow.b"],
["ell", "ell"],
["emptyset", "nothing"],
["epsilon", "epsilon.alt"],
["equiv", "equiv"],
["eta", "eta"],
["exists", "exists"],
["forall", "forall"],
["gamma", "gamma"],
["ge", "gt.eq"],
["geq", "gt.eq"],
["geqslant", "gt.eq.slant"],
["gg", "gt.double"],
["hbar", "planck.reduce"],
["imath", "dotless.i"],
["iiiint", "intgral.quad"],
["iiint", "integral.triple"],
["iint", "integral.double"],
["in", "in"],
["infty", "infinity"],
["int", "integral"],
["intercal", "top"],
["iota", "iota"],
["jmath", "dotless.j"],
["kappa", "kappa"],
["lambda", "lambda"],
["land", "and"],
["langle", "angle.l"],
["lbrace", "brace.l"],
["lbrack", "bracket.l"],
["ldots", "dots.l"],
["le", "lt.eq"],
["leadsto", "arrow.squiggly"],
["leftarrow", "arrow.l"],
["leftthreetimes", "times.three.l"],
["leftrightarrow", "arrow.l.r"],
["leq", "lt.eq"],
["leqslant", "lt.eq.slant"],
["lhd", "triangle.l"],
["ll", "lt.double"],
["longmapsto", "arrow.bar.long"],
["longrightarrow", "arrow.long"],
["lor", "or"],
["ltimes", "times.l"],
["mapsto", "arrow.bar"],
["measuredangle", "angle.arc"],
["mid", "divides"],
["models", "models"],
["mp", "minus.plus"],
["mu", "mu"],
["nRightarrow", "arrow.double.not"],
["nabla", "nabla"],
["ncong", "tilde.nequiv"],
["ne", "eq.not"],
["neg", "not"],
["neq", "eq.not"],
["nexists", "exists.not"],
["ni", "in.rev"],
["nleftarrow", "arrow.l.not"],
["nleq", "lt.eq.not"],
["nparallel", "parallel.not"],
["ngeq", "gt.eq.not"],
["nmid", "divides.not"],
["notin", "in.not"],
["nrightarrow", "arrow.not"],
["nsim", "tilde.not"],
["nsubseteq", "subset.eq.not"],
["nu", "nu"],
["ntriangleleft", "lt.tri.not"],
["ntriangleright", "gt.tri.not"],
["nwarrow", "arrow.tl"],
["odot", "dot.circle"],
["oint", "integral.cont"],
["oiint", "integral.surf"],
["oiiint", "integral.vol"],
["omega", "omega"],
["ominus", "minus.circle"],
["oplus", "xor"],
["otimes", "times.circle"],
["parallel", "parallel"],
["partial", "diff"],
["perp", "perp"],
["phi", "phi.alt"],
["pi", "pi"],
["pm", "plus.minus"],
["pounds", "pound"],
["prec", "prec"],
["preceq", "prec.eq"],
["prime", "prime"],
["prod", "product"],
["propto", "prop"],
["psi", "psi"],
["rangle", "angle.r"],
["rbrace", "brace.r"],
["rbrack", "bracket.r"],
["rhd", "triangle"],
["rho", "rho"],
["rightarrow", "arrow.r"],
["rightthreetimes", "times.three.r"],
["rtimes", "times.r"],
["setminus", "without"],
["sigma", "sigma"],
["sim", "tilde"],
["simeq", "tilde.eq"],
["slash", "slash"],
["smallsetminus", "without"],
["spadesuit", "suit.spade"],
["sqcap", "sect.sq"],
["sqcup", "union.sq"],
["sqsubseteq", "subset.eq.sq"],
["sqsupseteq", "supset.eq.sq"],
["star", "star"],
["subset", "subset"],
["subseteq", "subset.eq"],
["subsetneq", "subset.neq"],
["succ", "succ"],
["succeq", "succ.eq"],
["sum", "sum"],
["supset", "supset"],
["supseteq", "supset.eq"],
["supsetneq", "supset.neq"],
["swarrow", "arrow.bl"],
["tau", "tau"],
["theta", "theta"],
["times", "times"],
["to", "arrow.r"],
["top", "top"],
["triangle", "triangle.t"],
["triangledown", "triangle.b.small"],
["triangleleft", "triangle.l.small"],
["triangleright", "triangle.r.small"],
["twoheadrightarrow", "arrow.r.twohead"],
["uparrow", "arrow.t"],
["updownarrow", "arrow.t.b"],
["upharpoonright", "harpoon.tr"],
["uplus", "union.plus"],
["upsilon", "upsilon"],
["varepsilon", "epsilon"],
["varnothing", "diameter"],
["varphi", "phi"],
["varpi", "pi.alt"],
["varrho", "rho.alt"],
["varsigma", "sigma.alt"],
["vartheta", "theta.alt"],
["vdash", "tack.r"],
["vdots", "dots.v"],
["vee", "or"],
["wedge", "and"],
["wr", "wreath"],
["xi", "xi"],
["yen", "yen"],
["zeta", "zeta"],
["mathscr", "scr"],
["LaTeX", "#LaTeX"],
["TeX", "#TeX"]
]);
// src/writer.ts
function convertTree(node) {
switch (node.type) {
case "empty":
case "whitespace":
return { type: "empty", content: "" };
case "ordgroup":
return {
type: "group",
content: "",
args: node.args.map(convertTree)
};
case "element":
case "symbol":
return { type: "symbol", content: convertToken(node.content) };
case "text":
return { type: "text", content: node.content };
case "comment":
return { type: "comment", content: node.content };
case "supsub": {
let { base, sup, sub } = node.data;
if (base && base.type === "unaryFunc" && base.content === "\\overbrace" && sup) {
return {
type: "binaryFunc",
content: "overbrace",
args: [convertTree(base.args[0]), convertTree(sup)]
};
} else if (base && base.type === "unaryFunc" && base.content === "\\underbrace" && sub) {
return {
type: "binaryFunc",
content: "underbrace",
args: [convertTree(base.args[0]), convertTree(sub)]
};
}
const data = {
base: convertTree(base)
};
if (data.base.type === "empty") {
data.base = { type: "text", content: "" };
}
if (sup) {
data.sup = convertTree(sup);
}
if (sub) {
data.sub = convertTree(sub);
}
return {
type: "supsub",
content: "",
data
};
}
case "leftright": {
const [left, body, right] = node.args;
const group = {
type: "group",
content: "",
args: node.args.map(convertTree)
};
if (["[]", "()", "\\{\\}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
return group;
}
return {
type: "unaryFunc",
content: "lr",
args: [group]
};
}
case "binaryFunc": {
return {
type: "binaryFunc",
content: convertToken(node.content),
args: node.args.map(convertTree)
};
}
case "unaryFunc": {
const arg0 = convertTree(node.args[0]);
if (node.content === "\\sqrt" && node.data) {
const data = convertTree(node.data);
return {
type: "binaryFunc",
content: "root",
args: [data, arg0]
};
}
if (node.content === "\\mathbf") {
const inner = {
type: "unaryFunc",
content: "bold",
args: [arg0]
};
return {
type: "unaryFunc",
content: "upright",
args: [inner]
};
}
if (node.content === "\\mathbb" && arg0.type === "symbol" && /^[A-Z]$/.test(arg0.content)) {
return {
type: "symbol",
content: arg0.content + arg0.content
};
}
if (node.content === "\\operatorname") {
const body = node.args;
if (body.length !== 1 || body[0].type !== "text") {
throw new TypstWriterError(`Expecting body of \\operatorname to be text but got`, node);
}
const text = body[0].content;
if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
return {
type: "symbol",
content: text
};
} else {
return {
type: "unaryFunc",
content: "op",
args: [{ type: "text", content: text }]
};
}
}
return {
type: "unaryFunc",
content: convertToken(node.content),
args: node.args.map(convertTree)
};
}
case "newline":
return { type: "newline", content: "\n" };
case "beginend": {
const matrix = node.data;
const data = matrix.map((row) => row.map(convertTree));
if (node.content.startsWith("align")) {
return {
type: "align",
content: "",
data
};
} else {
return {
type: "matrix",
content: "mat",
data
};
}
}
case "unknownMacro":
return { type: "unknown", content: convertToken(node.content) };
case "control":
if (node.content === "\\\\") {
return { type: "symbol", content: "\\" };
} else if (node.content === "\\,") {
return { type: "symbol", content: "thin" };
} else {
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
}
default:
throw new TypstWriterError(`Unimplemented node type: ${node.type}`, node);
}
}
function convertToken(token) {

@@ -1009,93 +1179,61 @@ if (/^[a-zA-Z0-9]$/.test(token)) {

append(node) {
if (node.type === "empty" || node.type === "whitespace") {
return;
} else if (node.type === "ordgroup") {
node.args.forEach((arg) => this.append(arg));
} else if (node.type === "element") {
let content = node.content;
if (node.content === "," && this.insideFunctionDepth > 0) {
content = "comma";
switch (node.type) {
case "empty":
break;
case "symbol": {
let content = node.content;
if (node.content === "," && this.insideFunctionDepth > 0) {
content = "comma";
}
this.queue.push({ type: "symbol", content });
break;
}
this.queue.push({ type: "symbol", content });
} else if (node.type === "symbol") {
this.queue.push({ type: "symbol", content: node.content });
} else if (node.type === "text") {
this.queue.push(node);
} else if (node.type === "supsub") {
let { base, sup, sub } = node.data;
if (base && base.type === "unaryFunc" && base.content === "\\overbrace" && sup) {
this.append({ type: "binaryFunc", content: "\\overbrace", args: [base.args[0], sup] });
return;
} else if (base && base.type === "unaryFunc" && base.content === "\\underbrace" && sub) {
this.append({ type: "binaryFunc", content: "\\underbrace", args: [base.args[0], sub] });
return;
}
if (base.type === "empty") {
this.queue.push({ type: "text", content: "" });
} else {
case "text":
case "comment":
case "newline":
this.queue.push(node);
break;
case "group":
for (const item of node.args) {
this.append(item);
}
break;
case "supsub": {
let { base, sup, sub } = node.data;
this.appendWithBracketsIfNeeded(base);
let trailing_space_needed = false;
const has_prime = sup && sup.type === "symbol" && sup.content === "\'";
if (has_prime) {
this.queue.push({ type: "atom", content: "\'" });
trailing_space_needed = false;
}
if (sub) {
this.queue.push({ type: "atom", content: "_" });
trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
}
if (sup && !has_prime) {
this.queue.push({ type: "atom", content: "^" });
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
}
if (trailing_space_needed) {
this.queue.push({ type: "softSpace", content: "" });
}
break;
}
let trailing_space_needed = false;
const has_prime = sup && sup.type === "symbol" && sup.content === "\\prime";
if (has_prime) {
this.queue.push({ type: "atom", content: "\'" });
trailing_space_needed = false;
}
if (sub) {
this.queue.push({ type: "atom", content: "_" });
trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
}
if (sup && !has_prime) {
this.queue.push({ type: "atom", content: "^" });
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
}
if (trailing_space_needed) {
this.queue.push({ type: "softSpace", content: "" });
}
} else if (node.type === "leftright") {
const [left, body, right] = node.args;
if (["[]", "()", "\\{\\}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
this.append(left);
this.append(body);
this.append(right);
return;
}
const func_symbol = { type: "symbol", content: "lr" };
this.queue.push(func_symbol);
this.insideFunctionDepth++;
this.queue.push({ type: "atom", content: "(" });
this.append(left);
this.append(body);
this.append(right);
this.queue.push({ type: "atom", content: ")" });
this.insideFunctionDepth--;
} else if (node.type === "binaryFunc") {
const func_symbol = { type: "symbol", content: node.content };
const [arg0, arg1] = node.args;
this.queue.push(func_symbol);
this.insideFunctionDepth++;
this.queue.push({ type: "atom", content: "(" });
this.append(arg0);
this.queue.push({ type: "atom", content: "," });
this.append(arg1);
this.queue.push({ type: "atom", content: ")" });
this.insideFunctionDepth--;
} else if (node.type === "unaryFunc") {
const func_symbol = { type: "symbol", content: node.content };
const arg0 = node.args[0];
if (node.content === "\\sqrt" && node.data) {
func_symbol.content = "root";
case "binaryFunc": {
const func_symbol = { type: "symbol", content: node.content };
const [arg0, arg1] = node.args;
this.queue.push(func_symbol);
this.insideFunctionDepth++;
this.queue.push({ type: "atom", content: "(" });
this.append(node.data);
this.append(arg0);
this.queue.push({ type: "atom", content: "," });
this.append(arg0);
this.append(arg1);
this.queue.push({ type: "atom", content: ")" });
this.insideFunctionDepth--;
return;
} else if (node.content === "\\mathbf") {
this.append({ type: "symbol", content: "upright" });
this.insideFunctionDepth++;
this.queue.push({ type: "atom", content: "(" });
break;
}
case "unaryFunc": {
const func_symbol = { type: "symbol", content: node.content };
const arg0 = node.args[0];
this.queue.push(func_symbol);

@@ -1107,41 +1245,5 @@ this.insideFunctionDepth++;

this.insideFunctionDepth--;
this.queue.push({ type: "atom", content: ")" });
this.insideFunctionDepth--;
return;
} else if (node.content === "\\mathbb") {
const body = node.args[0];
if (body.type === "element" && /^[A-Z]$/.test(body.content)) {
this.queue.push({ type: "symbol", content: body.content + body.content });
return;
}
} else if (node.content === "\\operatorname") {
let body = node.args;
if (body.length === 1 && body[0].type == "ordgroup") {
body = body[0].args;
}
const text = body.reduce((buff, n) => {
buff += convertToken(n.content);
return buff;
}, "");
if (this.preferTypstIntrinsic && TYPST_INTRINSIC_SYMBOLS.includes(text)) {
this.queue.push({ type: "symbol", content: text });
} else {
this.queue.push({ type: "symbol", content: "op" });
this.queue.push({ type: "atom", content: "(" });
this.queue.push({ type: "text", content: text });
this.queue.push({ type: "atom", content: ")" });
}
return;
break;
}
this.queue.push(func_symbol);
this.insideFunctionDepth++;
this.queue.push({ type: "atom", content: "(" });
this.append(arg0);
this.queue.push({ type: "atom", content: ")" });
this.insideFunctionDepth--;
} else if (node.type === "newline") {
this.queue.push({ type: "newline", content: "\n" });
return;
} else if (node.type === "beginend") {
if (node.content.startsWith("align")) {
case "align": {
const matrix = node.data;

@@ -1156,6 +1258,8 @@ matrix.forEach((row, i) => {

if (i < matrix.length - 1) {
this.queue.push({ type: "symbol", content: "\\\\" });
this.queue.push({ type: "symbol", content: "\\" });
}
});
} else {
break;
}
case "matrix": {
const matrix = node.data;

@@ -1168,6 +1272,2 @@ this.queue.push({ type: "symbol", content: "mat" });

row.forEach((cell, j) => {
if (cell.type === "ordgroup" && cell.args.length === 0) {
this.queue.push({ type: "atom", content: "," });
return;
}
this.append(cell);

@@ -1185,23 +1285,32 @@ if (j < row.length - 1) {

this.insideFunctionDepth--;
break;
}
} else if (node.type === "matrix") {
} else if (node.type === "unknownMacro") {
if (this.nonStrict) {
this.queue.push({ type: "symbol", content: node.content });
} else {
throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
case "unknown": {
if (this.nonStrict) {
this.queue.push({ type: "symbol", content: node.content });
} else {
throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
}
break;
}
} else if (node.type === "control") {
if (node.content === "\\\\") {
this.queue.push({ type: "symbol", content: node.content });
} else if (node.content === "\\,") {
this.queue.push({ type: "symbol", content: "thin" });
} else {
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
}
} else if (node.type === "comment") {
this.queue.push({ type: "comment", content: node.content });
default:
throw new TypstWriterError(`Unimplemented node type to append: ${node.type}`, node);
}
}
appendWithBracketsIfNeeded(node) {
const is_single = !["group", "supsub", "empty"].includes(node.type);
if (is_single) {
this.append(node);
} else {
throw new TypstWriterError(`Unimplemented node type to append: ${node.type}`, node);
this.queue.push({
type: "atom",
content: "("
});
this.append(node);
this.queue.push({
type: "atom",
content: ")"
});
}
return is_single;
}

@@ -1213,7 +1322,5 @@ flushQueue() {

case "atom":
case "symbol":
str = node.content;
break;
case "symbol":
str = convertToken(node.content);
break;
case "text":

@@ -1241,19 +1348,2 @@ str = `"${node.content}"`;

}
appendWithBracketsIfNeeded(node) {
const is_single = ["symbol", "element", "unaryFunc", "binaryFunc", "leftright"].includes(node.type);
if (is_single) {
this.append(node);
} else {
this.queue.push({
type: "atom",
content: "("
});
this.append(node);
this.queue.push({
type: "atom",
content: ")"
});
}
return is_single;
}
finalize() {

@@ -1280,3 +1370,3 @@ this.flushQueue();

const opt = {
nonStrict: false,
nonStrict: true,
preferTypstIntrinsic: true,

@@ -1296,5 +1386,6 @@ customTexMacros: {}

}
const t = parseTex(tex, opt.customTexMacros);
const texTree = parseTex(tex, opt.customTexMacros);
const typstTree = convertTree(texTree);
const writer2 = new TypstWriter(opt.nonStrict, opt.preferTypstIntrinsic);
writer2.append(t);
writer2.append(typstTree);
return writer2.finalize();

@@ -1301,0 +1392,0 @@ }

@@ -1,6 +0,2 @@

import { TexNode } from "./types";
export interface Token {
type: 'element' | 'command' | 'text' | 'comment' | 'whitespace' | 'newline' | 'control' | 'unknown';
value: string;
}
import { TexNode, Token } from "./types";
export declare function tokenize(latex: string): Token[];

@@ -7,0 +3,0 @@ export declare class LatexParserError extends Error {

@@ -1,1 +0,1 @@

function v(z,Z=""){if(!z)throw new H(Z)}function c(z){if(u.includes(z))return 1;else if(m.includes(z))return 2;else return 0}function x(z,Z){v(q(z[Z],F));let J=1,V=Z+1;while(J>0){if(V>=z.length)throw new H("Unmatched curly brackets");if(q(z[V],F))J+=1;else if(q(z[V],D))J-=1;V+=1}return V-1}function l(z,Z){v(q(z[Z],y));let J=1,V=Z+1;while(J>0){if(V>=z.length)throw new H("Unmatched square brackets");if(q(z[V],y))J+=1;else if(q(z[V],_))J-=1;V+=1}return V-1}function g(z){return"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(z)}function R(z){return"0123456789".includes(z)}function S(z,Z){let J=Z;while(J<z.length&&["whitespace","newline"].includes(z[J].type))J++;return z.slice(Z,J)}function w(z,Z){const J=z[Z];if(J.type==="element"&&["(",")","[","]","|","\\{","\\}"].includes(J.value))return J;else if(J.type==="command"&&["lfloor","rfloor","lceil","rceil","langle","rangle"].includes(J.value.slice(1)))return J;else return null}function G(z,Z){let J=Z;while(J<z.length&&q(z[J],{type:"element",value:"'"}))J+=1;return J-Z}function i(z,Z){let J=Z;while(J<z.length&&g(z[J]))J+=1;return z.substring(Z,J)}function p(z,Z){let J=1,V=Z;while(J>0){if(V>=z.length)return-1;if(q(z[V],N))J+=1;else if(q(z[V],d))J-=1;V+=1}return V-1}function a(z,Z){let J=1,V=Z;while(J>0){if(V>=z.length)return-1;if(q(z[V],A))J+=1;else if(q(z[V],k))J-=1;V+=1}return V-1}function n(z,Z){v(z[Z]==="{");let J=1,V=Z+1;while(J>0){if(V>=z.length)throw new H("Unmatched curly brackets");if(V+1<z.length&&["\\{","\\}"].includes(z.substring(V,V+2))){V+=2;continue}if(z[V]==="{")J+=1;else if(z[V]==="}")J-=1;V+=1}return V-1}function C(z){const Z=[];let J=0;while(J<z.length){const V=z[J];let X;switch(V){case"%":{let $=J+1;while($<z.length&&z[$]!=="\n")$+=1;X={type:"comment",value:z.slice(J+1,$)},J=$;break}case"{":case"}":case"_":case"^":case"&":X={type:"control",value:V},J++;break;case"\n":X={type:"newline",value:V},J++;break;case"\r":{if(J+1<z.length&&z[J+1]==="\n")X={type:"newline",value:"\n"},J+=2;else X={type:"newline",value:"\n"},J++;break}case" ":{let $=J;while($<z.length&&z[$]===" ")$+=1;X={type:"whitespace",value:z.slice(J,$)},J=$;break}case"\\":{if(J+1>=z.length)throw new H("Expecting command name after \\");const $=z.slice(J,J+2);if(["\\\\","\\,"].includes($))X={type:"control",value:$};else if(["\\{","\\}","\\%","\\$","\\&","\\#","\\_"].includes($))X={type:"element",value:$};else X={type:"command",value:"\\"+i(z,J+1)};J+=X.value.length;break}default:{if(R(V)){let $=J;while($<z.length&&R(z[$]))$+=1;X={type:"element",value:z.slice(J,$)}}else if(g(V))X={type:"element",value:V};else if("+-*/=\'<>!.,;?()[]|".includes(V))X={type:"element",value:V};else X={type:"unknown",value:V};J+=X.value.length}}if(Z.push(X),X.type==="command"&&["\\text","\\begin","\\end"].includes(X.value)){if(J>=z.length||z[J]!=="{")throw new H(`No content for ${X.value} command`);Z.push({type:"control",value:"{"});const $=n(z,J);J++;let j=z.slice(J,$);const Q=["{","}","\\","$","&","#","_","%"];for(let W of Q)j=j.replaceAll("\\"+W,W);Z.push({type:"text",value:j}),Z.push({type:"control",value:"}"}),J=$+1}}return Z}function q(z,Z){return z.type==Z.type&&z.value==Z.value}function r(z){const Z=(V)=>q(V,I)||q(V,B);let J=[];for(let V=0;V<z.length;V++){if(z[V].type==="whitespace"&&V+1<z.length&&Z(z[V+1]))continue;if(z[V].type==="whitespace"&&V-1>=0&&Z(z[V-1]))continue;J.push(z[V])}return J}function t(z,Z){let J=[];for(let V of z)if(V.type==="command"&&Z[V.value]){const X=C(Z[V.value]);J=J.concat(X)}else J.push(V);return J}function T(z,Z){const J=new b;let V=C(z);return V=r(V),V=t(V,Z),J.parse(V)}var u=["sqrt","text","bar","bold","boldsymbol","ddot","dot","hat","mathbb","mathbf","mathcal","mathfrak","mathit","mathrm","mathscr","mathsf","mathtt","operatorname","overbrace","overline","pmb","rm","tilde","underbrace","underline","vec","widehat","widetilde"],m=["frac","tfrac","binom","dbinom","dfrac","tbinom"],U={type:"empty",content:""},F={type:"control",value:"{"},D={type:"control",value:"}"},y={type:"element",value:"["},_={type:"element",value:"]"},N={type:"command",value:"\\left"},d={type:"command",value:"\\right"},A={type:"command",value:"\\begin"},k={type:"command",value:"\\end"};class H extends Error{constructor(z){super(z);this.name="LatexParserError"}}var I={type:"control",value:"_"},B={type:"control",value:"^"};class b{space_sensitive;newline_sensitive;constructor(z=!1,Z=!0){this.space_sensitive=z,this.newline_sensitive=Z}parse(z){const Z=[];let J=0;while(J<z.length){const V=[];let X=0;while(X<z.length){const[$,j]=this.parseNextExpr(z,X);if(X=j,!this.space_sensitive&&$.type==="whitespace")continue;if(!this.newline_sensitive&&$.type==="newline")continue;if($.type==="control"&&$.content==="&")throw new H("Unexpected & outside of an alignment");V.push($)}if(V.length===0)return U;else if(V.length===1)return V[0];else return{type:"ordgroup",content:"",args:V}}if(Z.length===0)return U;else if(Z.length===1)return Z[0];else return{type:"ordgroup",content:"",args:Z}}parseNextExpr(z,Z){let[J,V]=this.parseNextExprWithoutSupSub(z,Z),X=null,$=null,j=0;if(j+=G(z,V),V+=j,V<z.length&&q(z[V],I)){if([X,V]=this.parseNextExprWithoutSupSub(z,V+1),j+=G(z,V),V+=j,V<z.length&&q(z[V],B)){if([$,V]=this.parseNextExprWithoutSupSub(z,V+1),G(z,V)>0)throw new H("Double superscript")}}else if(V<z.length&&q(z[V],B)){if([$,V]=this.parseNextExprWithoutSupSub(z,V+1),G(z,V)>0)throw new H("Double superscript");if(V<z.length&&q(z[V],I)){if([X,V]=this.parseNextExprWithoutSupSub(z,V+1),G(z,V)>0)throw new H("Double superscript")}}if(X!==null||$!==null||j>0){const Q={base:J};if(X)Q.sub=X;if(j>0){Q.sup={type:"ordgroup",content:"",args:[]};for(let W=0;W<j;W++)Q.sup.args.push({type:"symbol",content:"\\prime"});if($)Q.sup.args.push($);if(Q.sup.args.length===1)Q.sup=Q.sup.args[0]}else if($)Q.sup=$;return[{type:"supsub",content:"",data:Q},V]}else return[J,V]}parseNextExprWithoutSupSub(z,Z){const J=z[Z],V=J.type;switch(V){case"element":case"text":case"comment":case"whitespace":case"newline":return[{type:V,content:J.value},Z+1];case"command":if(q(J,A))return this.parseBeginEndExpr(z,Z);else if(q(J,N))return this.parseLeftRightExpr(z,Z);else return this.parseCommandExpr(z,Z);case"control":switch(J.value){case"{":const $=x(z,Z),j=z.slice(Z+1,$);return[this.parse(j),$+1];case"}":throw new H("Unmatched '}'");case"\\\\":return[{type:"control",content:"\\\\"},Z+1];case"\\,":return[{type:"control",content:"\\,"},Z+1];case"_":return[U,Z];case"^":return[U,Z];case"&":return[{type:"control",content:"&"},Z+1];default:throw new H("Unknown control sequence")}default:throw new H("Unknown token type")}}parseCommandExpr(z,Z){v(z[Z].type==="command");const J=z[Z].value;let V=Z+1;if(["left","right","begin","end"].includes(J.slice(1)))throw new H("Unexpected command: "+J);const X=c(J.slice(1));if(X===0)return[{type:"symbol",content:J},V];else if(X===1){if(J==="\\sqrt"&&V<z.length&&q(z[V],y)){const Q=V,W=l(z,V),O=z.slice(Q+1,W),h=this.parse(O),[f,E]=this.parseNextExprWithoutSupSub(z,W+1);return[{type:"unaryFunc",content:J,args:[f],data:h},E]}else if(J==="\\text"){if(V+2>=z.length)throw new H("Expecting content for \\text command");return v(q(z[V],F)),v(z[V+1].type==="text"),v(q(z[V+2],D)),[{type:"text",content:z[V+1].value},V+3]}let[$,j]=this.parseNextExprWithoutSupSub(z,V);return[{type:"unaryFunc",content:J,args:[$]},j]}else if(X===2){const[$,j]=this.parseNextExprWithoutSupSub(z,V),[Q,W]=this.parseNextExprWithoutSupSub(z,j);return[{type:"binaryFunc",content:J,args:[$,Q]},W]}else throw new Error("Invalid number of parameters")}parseLeftRightExpr(z,Z){v(q(z[Z],N));let J=Z+1;if(J+=S(z,J).length,J>=z.length)throw new H("Expecting delimiter after \\left");const V=w(z,J);if(V===null)throw new H("Invalid delimiter after \\left");J++;const X=J,$=p(z,J);if($===-1)throw new H("No matching \\right");const j=$;if(J=$+1,J+=S(z,J).length,J>=z.length)throw new H("Expecting \\right after \\left");const Q=w(z,J);if(Q===null)throw new H("Invalid delimiter after \\right");J++;const W=z.slice(X,j),O=this.parse(W);return[{type:"leftright",content:"",args:[{type:"element",content:V.value},O,{type:"element",content:Q.value}]},J]}parseBeginEndExpr(z,Z){v(q(z[Z],A));let J=Z+1;v(q(z[J],F)),v(z[J+1].type==="text"),v(q(z[J+2],D));const V=z[J+1].value;J+=3,J+=S(z,J).length;const X=J,$=a(z,J);if($===-1)throw new H("No matching \\end");const j=$;if(J=$+1,v(q(z[J],F)),v(z[J+1].type==="text"),v(q(z[J+2],D)),z[J+1].value!==V)throw new H("Mismatched \\begin and \\end environments");J+=3;const Q=z.slice(X,j);while(Q.length>0&&["whitespace","newline"].includes(Q[Q.length-1].type))Q.pop();const W=this.parseAligned(Q);return[{type:"beginend",content:V,data:W},J]}parseAligned(z){let Z=0;const J=[];let V=[];J.push(V);let X={type:"ordgroup",content:"",args:[]};V.push(X);while(Z<z.length){const[$,j]=this.parseNextExpr(z,Z);if(Z=j,$.type==="whitespace")continue;else if($.type==="newline"&&!this.newline_sensitive)continue;else if($.type==="control"&&$.content==="\\\\")V=[],X={type:"ordgroup",content:"",args:[]},V.push(X),J.push(V);else if($.type==="control"&&$.content==="&")X={type:"ordgroup",content:"",args:[]},V.push(X);else X.args.push($)}return J}}var Y=new Map([["nonumber",""],["vec","arrow"],["neq","eq.not"],["dot","dot"],["ddot","dot.double"],["doteq","dot(eq)"],["dots","dots.h"],["ldots","dots.h"],["vdots","dots.v"],["ddots","dots.down"],["widehat","hat"],["widetilde","tilde"],["quad","quad"],["qquad","wide"],["overbrace","overbrace"],["underbrace","underbrace"],["overline","overline"],["underline","underline"],["bar","macron"],["dbinom","binom"],["tbinom","binom"],["dfrac","frac"],["tfrac","frac"],["boldsymbol","bold"],["mathbb","bb"],["mathbf","bold"],["mathcal","cal"],["mathit","italic"],["mathfrak","frak"],["mathrm","upright"],["mathsf","sans"],["mathtt","mono"],["rm","upright"],["pmb","bold"],["pm","plus.minus"],["mp","minus.plus"],["oplus","xor"],["boxplus","plus.square"],["otimes","times.circle"],["boxtimes","times.square"],["sim","tilde"],["approx","approx"],["cong","tilde.equiv"],["simeq","tilde.eq"],["asymp","\u224D"],["equiv","equiv"],["propto","prop"],["lfloor","\u230A"],["rfloor","\u230B"],["lceil","\u2308"],["rceil","\u2309"],["gets","arrow.l"],["hookleftarrow","arrow.l.hook"],["leftharpoonup","harpoon.lt"],["leftharpoondown","harpoon.lb"],["rightleftharpoons","harpoons.rtlb"],["longleftarrow","arrow.l.long"],["longrightarrow","arrow.r.long"],["longleftrightarrow","arrow.l.r.long"],["Longleftarrow","arrow.l.double.long"],["Longrightarrow","arrow.r.double.long"],["Longleftrightarrow","arrow.l.r.double.long"],["longmapsto","arrow.r.bar"],["hookrightarrow","arrow.r.hook"],["rightharpoonup","harpoon.rt"],["rightharpoondown","harpoon.rb"],["iff","arrow.l.r.double.long"],["implies","arrow.r.double.long"],["uparrow","arrow.t"],["downarrow","arrow.b"],["updownarrow","arrow.t.b"],["Uparrow","arrow.t.double"],["Downarrow","arrow.b.double"],["Updownarrow","arrow.t.b.double"],["nearrow","arrow.tr"],["searrow","arrow.br"],["swarrow","arrow.bl"],["nwarrow","arrow.tl"],["leadsto","arrow.squiggly"],["leftleftarrows","arrows.ll"],["rightrightarrows","arrows.rr"],["Cap","sect.double"],["Cup","union.double"],["Delta","Delta"],["Gamma","Gamma"],["Join","join"],["Lambda","Lambda"],["Leftarrow","arrow.l.double"],["Leftrightarrow","arrow.l.r.double"],["Longrightarrow","arrow.r.double.long"],["Omega","Omega"],["P","pilcrow"],["Phi","Phi"],["Pi","Pi"],["Psi","Psi"],["Rightarrow","arrow.r.double"],["S","section"],["Sigma","Sigma"],["Theta","Theta"],["aleph","alef"],["alpha","alpha"],["angle","angle"],["approx","approx"],["approxeq","approx.eq"],["ast","ast"],["beta","beta"],["bigcap","sect.big"],["bigcirc","circle.big"],["bigcup","union.big"],["bigodot","dot.circle.big"],["bigoplus","xor.big"],["bigotimes","times.circle.big"],["bigsqcup","union.sq.big"],["bigtriangledown","triangle.b"],["bigtriangleup","triangle.t"],["biguplus","union.plus.big"],["bigvee","or.big"],["bigwedge","and.big"],["bullet","bullet"],["cap","sect"],["cdot","dot.op"],["cdots","dots.c"],["checkmark","checkmark"],["chi","chi"],["circ","circle.small"],["colon","colon"],["cong","tilde.equiv"],["coprod","product.co"],["copyright","copyright"],["cup","union"],["curlyvee","or.curly"],["curlywedge","and.curly"],["dagger","dagger"],["dashv","tack.l"],["ddagger","dagger.double"],["delta","delta"],["ddots","dots.down"],["diamond","diamond"],["div","div"],["divideontimes","times.div"],["dotplus","plus.dot"],["downarrow","arrow.b"],["ell","ell"],["emptyset","nothing"],["epsilon","epsilon.alt"],["equiv","equiv"],["eta","eta"],["exists","exists"],["forall","forall"],["gamma","gamma"],["ge","gt.eq"],["geq","gt.eq"],["geqslant","gt.eq.slant"],["gg","gt.double"],["hbar","planck.reduce"],["imath","dotless.i"],["iiiint","intgral.quad"],["iiint","integral.triple"],["iint","integral.double"],["in","in"],["infty","infinity"],["int","integral"],["intercal","top"],["iota","iota"],["jmath","dotless.j"],["kappa","kappa"],["lambda","lambda"],["land","and"],["langle","angle.l"],["lbrace","brace.l"],["lbrack","bracket.l"],["ldots","dots.l"],["le","lt.eq"],["leadsto","arrow.squiggly"],["leftarrow","arrow.l"],["leftthreetimes","times.three.l"],["leftrightarrow","arrow.l.r"],["leq","lt.eq"],["leqslant","lt.eq.slant"],["lhd","triangle.l"],["ll","lt.double"],["longmapsto","arrow.bar.long"],["longrightarrow","arrow.long"],["lor","or"],["ltimes","times.l"],["mapsto","arrow.bar"],["measuredangle","angle.arc"],["mid","divides"],["models","models"],["mp","minus.plus"],["mu","mu"],["nRightarrow","arrow.double.not"],["nabla","nabla"],["ncong","tilde.nequiv"],["ne","eq.not"],["neg","not"],["neq","eq.not"],["nexists","exists.not"],["ni","in.rev"],["nleftarrow","arrow.l.not"],["nleq","lt.eq.not"],["nparallel","parallel.not"],["ngeq","gt.eq.not"],["nmid","divides.not"],["notin","in.not"],["nrightarrow","arrow.not"],["nsim","tilde.not"],["nsubseteq","subset.eq.not"],["nu","nu"],["ntriangleleft","lt.tri.not"],["ntriangleright","gt.tri.not"],["nwarrow","arrow.tl"],["odot","dot.circle"],["oint","integral.cont"],["oiint","integral.surf"],["oiiint","integral.vol"],["omega","omega"],["ominus","minus.circle"],["oplus","xor"],["otimes","times.circle"],["parallel","parallel"],["partial","diff"],["perp","perp"],["phi","phi.alt"],["pi","pi"],["pm","plus.minus"],["pounds","pound"],["prec","prec"],["preceq","prec.eq"],["prime","prime"],["prod","product"],["propto","prop"],["psi","psi"],["rangle","angle.r"],["rbrace","brace.r"],["rbrack","bracket.r"],["rhd","triangle"],["rho","rho"],["rightarrow","arrow.r"],["rightthreetimes","times.three.r"],["rtimes","times.r"],["setminus","without"],["sigma","sigma"],["sim","tilde"],["simeq","tilde.eq"],["slash","slash"],["smallsetminus","without"],["spadesuit","suit.spade"],["sqcap","sect.sq"],["sqcup","union.sq"],["sqsubseteq","subset.eq.sq"],["sqsupseteq","supset.eq.sq"],["star","star"],["subset","subset"],["subseteq","subset.eq"],["subsetneq","subset.neq"],["succ","succ"],["succeq","succ.eq"],["sum","sum"],["supset","supset"],["supseteq","supset.eq"],["supsetneq","supset.neq"],["swarrow","arrow.bl"],["tau","tau"],["theta","theta"],["times","times"],["to","arrow.r"],["top","top"],["triangle","triangle.t"],["triangledown","triangle.b.small"],["triangleleft","triangle.l.small"],["triangleright","triangle.r.small"],["twoheadrightarrow","arrow.r.twohead"],["uparrow","arrow.t"],["updownarrow","arrow.t.b"],["upharpoonright","harpoon.tr"],["uplus","union.plus"],["upsilon","upsilon"],["varepsilon","epsilon"],["varnothing","diameter"],["varphi","phi"],["varpi","pi.alt"],["varrho","rho.alt"],["varsigma","sigma.alt"],["vartheta","theta.alt"],["vdash","tack.r"],["vdots","dots.v"],["vee","or"],["wedge","and"],["wr","wreath"],["xi","xi"],["yen","yen"],["zeta","zeta"],["mathscr","scr"],["LaTeX","#LaTeX"],["TeX","#TeX"]]);function L(z){if(/^[a-zA-Z0-9]$/.test(z))return z;else if(z==="\\\\")return"\\";else if(z=="/")return"\\/";else if(["\\$","\\#","\\&","\\_"].includes(z))return z;else if(z.startsWith("\\")){const Z=z.slice(1);if(Y.has(Z))return Y.get(Z);else return Z}return z}var o=["dim","id","im","mod","Pr","sech","csch"];class K extends Error{node;constructor(z,Z){super(z);this.name="TypstWriterError",this.node=Z}}class M{nonStrict;preferTypstIntrinsic;buffer="";queue=[];needSpaceAfterSingleItemScript=!1;insideFunctionDepth=0;constructor(z,Z){this.nonStrict=z,this.preferTypstIntrinsic=Z}writeBuffer(z){if(this.needSpaceAfterSingleItemScript&&/^[0-9a-zA-Z\(]/.test(z))this.buffer+=" ";else{let Z=!1;if(Z||=/[\(\|]$/.test(this.buffer)&&/^\w/.test(z),Z||=/^[}()_^,;!\|]$/.test(z),Z||=z==="'",Z||=/[0-9]$/.test(this.buffer)&&/^[0-9]/.test(z),Z||=/[\(\[{]\s*(-|\+)$/.test(this.buffer)||this.buffer==="-"||this.buffer==="+",Z||=z.startsWith("\n"),Z||=this.buffer==="",Z||=/[\s"_^{\(]$/.test(this.buffer),!Z)this.buffer+=" "}if(this.needSpaceAfterSingleItemScript)this.needSpaceAfterSingleItemScript=!1;this.buffer+=z}append(z){if(z.type==="empty"||z.type==="whitespace")return;else if(z.type==="ordgroup")z.args.forEach((Z)=>this.append(Z));else if(z.type==="element"){let Z=z.content;if(z.content===","&&this.insideFunctionDepth>0)Z="comma";this.queue.push({type:"symbol",content:Z})}else if(z.type==="symbol")this.queue.push({type:"symbol",content:z.content});else if(z.type==="text")this.queue.push(z);else if(z.type==="supsub"){let{base:Z,sup:J,sub:V}=z.data;if(Z&&Z.type==="unaryFunc"&&Z.content==="\\overbrace"&&J){this.append({type:"binaryFunc",content:"\\overbrace",args:[Z.args[0],J]});return}else if(Z&&Z.type==="unaryFunc"&&Z.content==="\\underbrace"&&V){this.append({type:"binaryFunc",content:"\\underbrace",args:[Z.args[0],V]});return}if(Z.type==="empty")this.queue.push({type:"text",content:""});else this.appendWithBracketsIfNeeded(Z);let X=!1;const $=J&&J.type==="symbol"&&J.content==="\\prime";if($)this.queue.push({type:"atom",content:"\'"}),X=!1;if(V)this.queue.push({type:"atom",content:"_"}),X=this.appendWithBracketsIfNeeded(V);if(J&&!$)this.queue.push({type:"atom",content:"^"}),X=this.appendWithBracketsIfNeeded(J);if(X)this.queue.push({type:"softSpace",content:""})}else if(z.type==="leftright"){const[Z,J,V]=z.args;if(["[]","()","\\{\\}","\\lfloor\\rfloor","\\lceil\\rceil"].includes(Z.content+V.content)){this.append(Z),this.append(J),this.append(V);return}const X={type:"symbol",content:"lr"};this.queue.push(X),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(Z),this.append(J),this.append(V),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--}else if(z.type==="binaryFunc"){const Z={type:"symbol",content:z.content},[J,V]=z.args;this.queue.push(Z),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(J),this.queue.push({type:"atom",content:","}),this.append(V),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--}else if(z.type==="unaryFunc"){const Z={type:"symbol",content:z.content},J=z.args[0];if(z.content==="\\sqrt"&&z.data){Z.content="root",this.queue.push(Z),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(z.data),this.queue.push({type:"atom",content:","}),this.append(J),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--;return}else if(z.content==="\\mathbf"){this.append({type:"symbol",content:"upright"}),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.queue.push(Z),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(J),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--,this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--;return}else if(z.content==="\\mathbb"){const V=z.args[0];if(V.type==="element"&&/^[A-Z]$/.test(V.content)){this.queue.push({type:"symbol",content:V.content+V.content});return}}else if(z.content==="\\operatorname"){let V=z.args;if(V.length===1&&V[0].type=="ordgroup")V=V[0].args;const X=V.reduce(($,j)=>{return $+=L(j.content),$},"");if(this.preferTypstIntrinsic&&o.includes(X))this.queue.push({type:"symbol",content:X});else this.queue.push({type:"symbol",content:"op"}),this.queue.push({type:"atom",content:"("}),this.queue.push({type:"text",content:X}),this.queue.push({type:"atom",content:")"});return}this.queue.push(Z),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(J),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--}else if(z.type==="newline"){this.queue.push({type:"newline",content:"\n"});return}else if(z.type==="beginend")if(z.content.startsWith("align")){const Z=z.data;Z.forEach((J,V)=>{if(J.forEach((X,$)=>{if($>0)this.queue.push({type:"atom",content:"&"});this.append(X)}),V<Z.length-1)this.queue.push({type:"symbol",content:"\\\\"})})}else{const Z=z.data;this.queue.push({type:"symbol",content:"mat"}),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.queue.push({type:"symbol",content:"delim: #none, "}),Z.forEach((J,V)=>{J.forEach((X,$)=>{if(X.type==="ordgroup"&&X.args.length===0){this.queue.push({type:"atom",content:","});return}if(this.append(X),$<J.length-1)this.queue.push({type:"atom",content:","});else if(V<Z.length-1)this.queue.push({type:"atom",content:";"})})}),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--}else if(z.type==="matrix");else if(z.type==="unknownMacro")if(this.nonStrict)this.queue.push({type:"symbol",content:z.content});else throw new K(`Unknown macro: ${z.content}`,z);else if(z.type==="control")if(z.content==="\\\\")this.queue.push({type:"symbol",content:z.content});else if(z.content==="\\,")this.queue.push({type:"symbol",content:"thin"});else throw new K(`Unknown control sequence: ${z.content}`,z);else if(z.type==="comment")this.queue.push({type:"comment",content:z.content});else throw new K(`Unimplemented node type to append: ${z.type}`,z)}flushQueue(){this.queue.forEach((z)=>{let Z="";switch(z.type){case"atom":Z=z.content;break;case"symbol":Z=L(z.content);break;case"text":Z=`"${z.content}"`;break;case"softSpace":this.needSpaceAfterSingleItemScript=!0,Z="";break;case"comment":Z=`//${z.content}`;break;case"newline":Z="\n";break;default:throw new K(`Unexpected node type to stringify: ${z.type}`,z)}if(Z!=="")this.writeBuffer(Z)}),this.queue=[]}appendWithBracketsIfNeeded(z){const Z=["symbol","element","unaryFunc","binaryFunc","leftright"].includes(z.type);if(Z)this.append(z);else this.queue.push({type:"atom",content:"("}),this.append(z),this.queue.push({type:"atom",content:")"});return Z}finalize(){this.flushQueue();const z=function(J){let V=J.replace(/⌊\s*(.*?)\s*⌋/g,"floor($1)");return V=V.replace(/floor\(\)/g,'floor("")'),V},Z=function(J){let V=J.replace(/⌈\s*(.*?)\s*⌉/g,"ceil($1)");return V=V.replace(/ceil\(\)/g,'ceil("")'),V};return this.buffer=z(this.buffer),this.buffer=Z(this.buffer),this.buffer}}function P(z,Z){const J={nonStrict:!1,preferTypstIntrinsic:!0,customTexMacros:{}};if(Z){if(Z.nonStrict)J.nonStrict=Z.nonStrict;if(Z.preferTypstIntrinsic)J.preferTypstIntrinsic=Z.preferTypstIntrinsic;if(Z.customTexMacros)J.customTexMacros=Z.customTexMacros}const V=T(z,J.customTexMacros),X=new M(J.nonStrict,J.preferTypstIntrinsic);return X.append(V),X.finalize()}if(typeof window!=="undefined")window.tex2typst=P;
var O=new Map([["nonumber",""],["vec","arrow"],["neq","eq.not"],["dot","dot"],["ddot","dot.double"],["doteq","dot(eq)"],["dots","dots.h"],["ldots","dots.h"],["vdots","dots.v"],["ddots","dots.down"],["widehat","hat"],["widetilde","tilde"],["quad","quad"],["qquad","wide"],["overbrace","overbrace"],["underbrace","underbrace"],["overline","overline"],["underline","underline"],["bar","macron"],["dbinom","binom"],["tbinom","binom"],["dfrac","frac"],["tfrac","frac"],["boldsymbol","bold"],["mathbb","bb"],["mathbf","bold"],["mathcal","cal"],["mathit","italic"],["mathfrak","frak"],["mathrm","upright"],["mathsf","sans"],["mathtt","mono"],["rm","upright"],["pmb","bold"],["pm","plus.minus"],["mp","minus.plus"],["oplus","xor"],["boxplus","plus.square"],["otimes","times.circle"],["boxtimes","times.square"],["sim","tilde"],["approx","approx"],["cong","tilde.equiv"],["simeq","tilde.eq"],["asymp","\u224D"],["equiv","equiv"],["propto","prop"],["lfloor","\u230A"],["rfloor","\u230B"],["lceil","\u2308"],["rceil","\u2309"],["gets","arrow.l"],["hookleftarrow","arrow.l.hook"],["leftharpoonup","harpoon.lt"],["leftharpoondown","harpoon.lb"],["rightleftharpoons","harpoons.rtlb"],["longleftarrow","arrow.l.long"],["longrightarrow","arrow.r.long"],["longleftrightarrow","arrow.l.r.long"],["Longleftarrow","arrow.l.double.long"],["Longrightarrow","arrow.r.double.long"],["Longleftrightarrow","arrow.l.r.double.long"],["longmapsto","arrow.r.bar"],["hookrightarrow","arrow.r.hook"],["rightharpoonup","harpoon.rt"],["rightharpoondown","harpoon.rb"],["iff","arrow.l.r.double.long"],["implies","arrow.r.double.long"],["uparrow","arrow.t"],["downarrow","arrow.b"],["updownarrow","arrow.t.b"],["Uparrow","arrow.t.double"],["Downarrow","arrow.b.double"],["Updownarrow","arrow.t.b.double"],["nearrow","arrow.tr"],["searrow","arrow.br"],["swarrow","arrow.bl"],["nwarrow","arrow.tl"],["leadsto","arrow.squiggly"],["leftleftarrows","arrows.ll"],["rightrightarrows","arrows.rr"],["Cap","sect.double"],["Cup","union.double"],["Delta","Delta"],["Gamma","Gamma"],["Join","join"],["Lambda","Lambda"],["Leftarrow","arrow.l.double"],["Leftrightarrow","arrow.l.r.double"],["Longrightarrow","arrow.r.double.long"],["Omega","Omega"],["P","pilcrow"],["Phi","Phi"],["Pi","Pi"],["Psi","Psi"],["Rightarrow","arrow.r.double"],["S","section"],["Sigma","Sigma"],["Theta","Theta"],["aleph","alef"],["alpha","alpha"],["angle","angle"],["approx","approx"],["approxeq","approx.eq"],["ast","ast"],["beta","beta"],["bigcap","sect.big"],["bigcirc","circle.big"],["bigcup","union.big"],["bigodot","dot.circle.big"],["bigoplus","xor.big"],["bigotimes","times.circle.big"],["bigsqcup","union.sq.big"],["bigtriangledown","triangle.b"],["bigtriangleup","triangle.t"],["biguplus","union.plus.big"],["bigvee","or.big"],["bigwedge","and.big"],["bullet","bullet"],["cap","sect"],["cdot","dot.op"],["cdots","dots.c"],["checkmark","checkmark"],["chi","chi"],["circ","circle.small"],["colon","colon"],["cong","tilde.equiv"],["coprod","product.co"],["copyright","copyright"],["cup","union"],["curlyvee","or.curly"],["curlywedge","and.curly"],["dagger","dagger"],["dashv","tack.l"],["ddagger","dagger.double"],["delta","delta"],["ddots","dots.down"],["diamond","diamond"],["div","div"],["divideontimes","times.div"],["dotplus","plus.dot"],["downarrow","arrow.b"],["ell","ell"],["emptyset","nothing"],["epsilon","epsilon.alt"],["equiv","equiv"],["eta","eta"],["exists","exists"],["forall","forall"],["gamma","gamma"],["ge","gt.eq"],["geq","gt.eq"],["geqslant","gt.eq.slant"],["gg","gt.double"],["hbar","planck.reduce"],["imath","dotless.i"],["iiiint","intgral.quad"],["iiint","integral.triple"],["iint","integral.double"],["in","in"],["infty","infinity"],["int","integral"],["intercal","top"],["iota","iota"],["jmath","dotless.j"],["kappa","kappa"],["lambda","lambda"],["land","and"],["langle","angle.l"],["lbrace","brace.l"],["lbrack","bracket.l"],["ldots","dots.l"],["le","lt.eq"],["leadsto","arrow.squiggly"],["leftarrow","arrow.l"],["leftthreetimes","times.three.l"],["leftrightarrow","arrow.l.r"],["leq","lt.eq"],["leqslant","lt.eq.slant"],["lhd","triangle.l"],["ll","lt.double"],["longmapsto","arrow.bar.long"],["longrightarrow","arrow.long"],["lor","or"],["ltimes","times.l"],["mapsto","arrow.bar"],["measuredangle","angle.arc"],["mid","divides"],["models","models"],["mp","minus.plus"],["mu","mu"],["nRightarrow","arrow.double.not"],["nabla","nabla"],["ncong","tilde.nequiv"],["ne","eq.not"],["neg","not"],["neq","eq.not"],["nexists","exists.not"],["ni","in.rev"],["nleftarrow","arrow.l.not"],["nleq","lt.eq.not"],["nparallel","parallel.not"],["ngeq","gt.eq.not"],["nmid","divides.not"],["notin","in.not"],["nrightarrow","arrow.not"],["nsim","tilde.not"],["nsubseteq","subset.eq.not"],["nu","nu"],["ntriangleleft","lt.tri.not"],["ntriangleright","gt.tri.not"],["nwarrow","arrow.tl"],["odot","dot.circle"],["oint","integral.cont"],["oiint","integral.surf"],["oiiint","integral.vol"],["omega","omega"],["ominus","minus.circle"],["oplus","xor"],["otimes","times.circle"],["parallel","parallel"],["partial","diff"],["perp","perp"],["phi","phi.alt"],["pi","pi"],["pm","plus.minus"],["pounds","pound"],["prec","prec"],["preceq","prec.eq"],["prime","prime"],["prod","product"],["propto","prop"],["psi","psi"],["rangle","angle.r"],["rbrace","brace.r"],["rbrack","bracket.r"],["rhd","triangle"],["rho","rho"],["rightarrow","arrow.r"],["rightthreetimes","times.three.r"],["rtimes","times.r"],["setminus","without"],["sigma","sigma"],["sim","tilde"],["simeq","tilde.eq"],["slash","slash"],["smallsetminus","without"],["spadesuit","suit.spade"],["sqcap","sect.sq"],["sqcup","union.sq"],["sqsubseteq","subset.eq.sq"],["sqsupseteq","supset.eq.sq"],["star","star"],["subset","subset"],["subseteq","subset.eq"],["subsetneq","subset.neq"],["succ","succ"],["succeq","succ.eq"],["sum","sum"],["supset","supset"],["supseteq","supset.eq"],["supsetneq","supset.neq"],["swarrow","arrow.bl"],["tau","tau"],["theta","theta"],["times","times"],["to","arrow.r"],["top","top"],["triangle","triangle.t"],["triangledown","triangle.b.small"],["triangleleft","triangle.l.small"],["triangleright","triangle.r.small"],["twoheadrightarrow","arrow.r.twohead"],["uparrow","arrow.t"],["updownarrow","arrow.t.b"],["upharpoonright","harpoon.tr"],["uplus","union.plus"],["upsilon","upsilon"],["varepsilon","epsilon"],["varnothing","diameter"],["varphi","phi"],["varpi","pi.alt"],["varrho","rho.alt"],["varsigma","sigma.alt"],["vartheta","theta.alt"],["vdash","tack.r"],["vdots","dots.v"],["vee","or"],["wedge","and"],["wr","wreath"],["xi","xi"],["yen","yen"],["zeta","zeta"],["mathscr","scr"],["LaTeX","#LaTeX"],["TeX","#TeX"]]);function W(z,Z=""){if(!z)throw new H(Z)}function x(z){if(c.includes(z))return 1;else if(_.includes(z))return 2;else return 0}function l(z,Z){W(j(z[Z],D));let J=1,V=Z+1;while(J>0){if(V>=z.length)throw new H("Unmatched curly brackets");if(j(z[V],D))J+=1;else if(j(z[V],v))J-=1;V+=1}return V-1}function d(z,Z){W(j(z[Z],I));let J=1,V=Z+1;while(J>0){if(V>=z.length)throw new H("Unmatched square brackets");if(j(z[V],I))J+=1;else if(j(z[V],i))J-=1;V+=1}return V-1}function L(z){return"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(z)}function g(z){return"0123456789".includes(z)}function A(z,Z){let J=Z;while(J<z.length&&[4,5].includes(z[J].type))J++;return z.slice(Z,J)}function C(z,Z){const J=z[Z];if(J.type===0&&["(",")","[","]","|","\\{","\\}"].includes(J.value))return J;else if(J.type===1&&["lfloor","rfloor","lceil","rceil","langle","rangle"].includes(J.value.slice(1)))return J;else return null}function U(z,Z){let J=Z;while(J<z.length&&j(z[J],{type:0,value:"'"}))J+=1;return J-Z}function T(z,Z){let J=Z;while(J<z.length&&L(z[J]))J+=1;return z.substring(Z,J)}function k(z,Z){let J=1,V=Z;while(J>0){if(V>=z.length)return-1;if(j(z[V],f))J+=1;else if(j(z[V],p))J-=1;V+=1}return V-1}function n(z,Z){let J=1,V=Z;while(J>0){if(V>=z.length)return-1;if(j(z[V],B))J+=1;else if(j(z[V],a))J-=1;V+=1}return V-1}function r(z,Z){W(z[Z]==="{");let J=1,V=Z+1;while(J>0){if(V>=z.length)throw new H("Unmatched curly brackets");if(V+1<z.length&&["\\{","\\}"].includes(z.substring(V,V+2))){V+=2;continue}if(z[V]==="{")J+=1;else if(z[V]==="}")J-=1;V+=1}return V-1}function P(z){const Z=[];let J=0;while(J<z.length){const V=z[J];let X;switch(V){case"%":{let $=J+1;while($<z.length&&z[$]!=="\n")$+=1;X={type:3,value:z.slice(J+1,$)},J=$;break}case"{":case"}":case"_":case"^":case"&":X={type:6,value:V},J++;break;case"\n":X={type:5,value:V},J++;break;case"\r":{if(J+1<z.length&&z[J+1]==="\n")X={type:5,value:"\n"},J+=2;else X={type:5,value:"\n"},J++;break}case" ":{let $=J;while($<z.length&&z[$]===" ")$+=1;X={type:4,value:z.slice(J,$)},J=$;break}case"\\":{if(J+1>=z.length)throw new H("Expecting command name after \\");const $=z.slice(J,J+2);if(["\\\\","\\,"].includes($))X={type:6,value:$};else if(["\\{","\\}","\\%","\\$","\\&","\\#","\\_"].includes($))X={type:0,value:$};else{const q=T(z,J+1);X={type:1,value:"\\"+q}}J+=X.value.length;break}default:{if(g(V)){let $=J;while($<z.length&&g(z[$]))$+=1;X={type:0,value:z.slice(J,$)}}else if(L(V))X={type:0,value:V};else if("+-*/=\'<>!.,;?()[]|".includes(V))X={type:0,value:V};else X={type:7,value:V};J+=X.value.length}}if(Z.push(X),X.type===1&&["\\text","\\operatorname","\\begin","\\end"].includes(X.value)){if(J>=z.length||z[J]!=="{")throw new H(`No content for ${X.value} command`);Z.push({type:6,value:"{"});const $=r(z,J);J++;let q=z.slice(J,$);const Q=["{","}","\\","$","&","#","_","%"];for(let F of Q)q=q.replaceAll("\\"+F,F);Z.push({type:2,value:q}),Z.push({type:6,value:"}"}),J=$+1}}return Z}function j(z,Z){return z.type==Z.type&&z.value==Z.value}function t(z){const Z=(V)=>j(V,M)||j(V,h);let J=[];for(let V=0;V<z.length;V++){if(z[V].type===4&&V+1<z.length&&Z(z[V+1]))continue;if(z[V].type===4&&V-1>=0&&Z(z[V-1]))continue;J.push(z[V])}return J}function s(z,Z){let J=[];for(let V of z)if(V.type===1&&Z[V.value]){const X=P(Z[V.value]);J=J.concat(X)}else J.push(V);return J}function u(z,Z){const J=new y;let V=P(z);return V=t(V),V=s(V,Z),J.parse(V)}var c=["sqrt","text","bar","bold","boldsymbol","ddot","dot","hat","mathbb","mathbf","mathcal","mathfrak","mathit","mathrm","mathscr","mathsf","mathtt","operatorname","overbrace","overline","pmb","rm","tilde","underbrace","underline","vec","widehat","widetilde"],_=["frac","tfrac","binom","dbinom","dfrac","tbinom"],S={type:"empty",content:""},D={type:6,value:"{"},v={type:6,value:"}"},I={type:0,value:"["},i={type:0,value:"]"},f={type:1,value:"\\left"},p={type:1,value:"\\right"},B={type:1,value:"\\begin"},a={type:1,value:"\\end"};class H extends Error{constructor(z){super(z);this.name="LatexParserError"}}var M={type:6,value:"_"},h={type:6,value:"^"};class y{space_sensitive;newline_sensitive;constructor(z=!1,Z=!0){this.space_sensitive=z,this.newline_sensitive=Z}parse(z){const Z=[];let J=0;while(J<z.length){const V=[];let X=0;while(X<z.length){const[$,q]=this.parseNextExpr(z,X);if(X=q,!this.space_sensitive&&$.type==="whitespace")continue;if(!this.newline_sensitive&&$.type==="newline")continue;if($.type==="control"&&$.content==="&")throw new H("Unexpected & outside of an alignment");V.push($)}if(V.length===0)return S;else if(V.length===1)return V[0];else return{type:"ordgroup",content:"",args:V}}if(Z.length===0)return S;else if(Z.length===1)return Z[0];else return{type:"ordgroup",content:"",args:Z}}parseNextExpr(z,Z){let[J,V]=this.parseNextExprWithoutSupSub(z,Z),X=null,$=null,q=0;if(q+=U(z,V),V+=q,V<z.length&&j(z[V],M)){if([X,V]=this.parseNextExprWithoutSupSub(z,V+1),q+=U(z,V),V+=q,V<z.length&&j(z[V],h)){if([$,V]=this.parseNextExprWithoutSupSub(z,V+1),U(z,V)>0)throw new H("Double superscript")}}else if(V<z.length&&j(z[V],h)){if([$,V]=this.parseNextExprWithoutSupSub(z,V+1),U(z,V)>0)throw new H("Double superscript");if(V<z.length&&j(z[V],M)){if([X,V]=this.parseNextExprWithoutSupSub(z,V+1),U(z,V)>0)throw new H("Double superscript")}}if(X!==null||$!==null||q>0){const Q={base:J};if(X)Q.sub=X;if(q>0){Q.sup={type:"ordgroup",content:"",args:[]};for(let F=0;F<q;F++)Q.sup.args.push({type:"element",content:"'"});if($)Q.sup.args.push($);if(Q.sup.args.length===1)Q.sup=Q.sup.args[0]}else if($)Q.sup=$;return[{type:"supsub",content:"",data:Q},V]}else return[J,V]}parseNextExprWithoutSupSub(z,Z){const J=z[Z];switch(J.type){case 0:return[{type:"element",content:J.value},Z+1];case 2:return[{type:"text",content:J.value},Z+1];case 3:return[{type:"comment",content:J.value},Z+1];case 4:return[{type:"whitespace",content:J.value},Z+1];case 5:return[{type:"newline",content:J.value},Z+1];case 1:if(j(J,B))return this.parseBeginEndExpr(z,Z);else if(j(J,f))return this.parseLeftRightExpr(z,Z);else return this.parseCommandExpr(z,Z);case 6:switch(J.value){case"{":const $=l(z,Z),q=z.slice(Z+1,$);return[this.parse(q),$+1];case"}":throw new H("Unmatched '}'");case"\\\\":return[{type:"control",content:"\\\\"},Z+1];case"\\,":return[{type:"control",content:"\\,"},Z+1];case"_":return[S,Z];case"^":return[S,Z];case"&":return[{type:"control",content:"&"},Z+1];default:throw new H("Unknown control sequence")}default:throw new H("Unknown token type")}}parseCommandExpr(z,Z){W(z[Z].type===1);const J=z[Z].value;let V=Z+1;if(["left","right","begin","end"].includes(J.slice(1)))throw new H("Unexpected command: "+J);switch(x(J.slice(1))){case 0:if(!O.has(J.slice(1)))return[{type:"unknownMacro",content:J},V];return[{type:"symbol",content:J},V];case 1:{if(J==="\\sqrt"&&V<z.length&&j(z[V],I)){const Q=V,F=d(z,V),Y=z.slice(Q+1,F),R=this.parse(Y),[w,E]=this.parseNextExprWithoutSupSub(z,F+1);return[{type:"unaryFunc",content:J,args:[w],data:R},E]}else if(J==="\\text"){if(V+2>=z.length)throw new H("Expecting content for \\text command");return W(j(z[V],D)),W(z[V+1].type===2),W(j(z[V+2],v)),[{type:"text",content:z[V+1].value},V+3]}let[$,q]=this.parseNextExprWithoutSupSub(z,V);return[{type:"unaryFunc",content:J,args:[$]},q]}case 2:{const[$,q]=this.parseNextExprWithoutSupSub(z,V),[Q,F]=this.parseNextExprWithoutSupSub(z,q);return[{type:"binaryFunc",content:J,args:[$,Q]},F]}default:throw new Error("Invalid number of parameters")}}parseLeftRightExpr(z,Z){W(j(z[Z],f));let J=Z+1;if(J+=A(z,J).length,J>=z.length)throw new H("Expecting delimiter after \\left");const V=C(z,J);if(V===null)throw new H("Invalid delimiter after \\left");J++;const X=J,$=k(z,J);if($===-1)throw new H("No matching \\right");const q=$;if(J=$+1,J+=A(z,J).length,J>=z.length)throw new H("Expecting \\right after \\left");const Q=C(z,J);if(Q===null)throw new H("Invalid delimiter after \\right");J++;const F=z.slice(X,q),Y=this.parse(F);return[{type:"leftright",content:"",args:[{type:"element",content:V.value},Y,{type:"element",content:Q.value}]},J]}parseBeginEndExpr(z,Z){W(j(z[Z],B));let J=Z+1;W(j(z[J],D)),W(z[J+1].type===2),W(j(z[J+2],v));const V=z[J+1].value;J+=3,J+=A(z,J).length;const X=J,$=n(z,J);if($===-1)throw new H("No matching \\end");const q=$;if(J=$+1,W(j(z[J],D)),W(z[J+1].type===2),W(j(z[J+2],v)),z[J+1].value!==V)throw new H("Mismatched \\begin and \\end environments");J+=3;const Q=z.slice(X,q);while(Q.length>0&&[4,5].includes(Q[Q.length-1].type))Q.pop();const F=this.parseAligned(Q);return[{type:"beginend",content:V,data:F},J]}parseAligned(z){let Z=0;const J=[];let V=[];J.push(V);let X={type:"ordgroup",content:"",args:[]};V.push(X);while(Z<z.length){const[$,q]=this.parseNextExpr(z,Z);if(Z=q,$.type==="whitespace")continue;else if($.type==="newline"&&!this.newline_sensitive)continue;else if($.type==="control"&&$.content==="\\\\")V=[],X={type:"ordgroup",content:"",args:[]},V.push(X),J.push(V);else if($.type==="control"&&$.content==="&")X={type:"ordgroup",content:"",args:[]},V.push(X);else X.args.push($)}return J}}function G(z){switch(z.type){case"empty":case"whitespace":return{type:"empty",content:""};case"ordgroup":return{type:"group",content:"",args:z.args.map(G)};case"element":case"symbol":return{type:"symbol",content:N(z.content)};case"text":return{type:"text",content:z.content};case"comment":return{type:"comment",content:z.content};case"supsub":{let{base:Z,sup:J,sub:V}=z.data;if(Z&&Z.type==="unaryFunc"&&Z.content==="\\overbrace"&&J)return{type:"binaryFunc",content:"overbrace",args:[G(Z.args[0]),G(J)]};else if(Z&&Z.type==="unaryFunc"&&Z.content==="\\underbrace"&&V)return{type:"binaryFunc",content:"underbrace",args:[G(Z.args[0]),G(V)]};const X={base:G(Z)};if(X.base.type==="empty")X.base={type:"text",content:""};if(J)X.sup=G(J);if(V)X.sub=G(V);return{type:"supsub",content:"",data:X}}case"leftright":{const[Z,J,V]=z.args,X={type:"group",content:"",args:z.args.map(G)};if(["[]","()","\\{\\}","\\lfloor\\rfloor","\\lceil\\rceil"].includes(Z.content+V.content))return X;return{type:"unaryFunc",content:"lr",args:[X]}}case"binaryFunc":return{type:"binaryFunc",content:N(z.content),args:z.args.map(G)};case"unaryFunc":{const Z=G(z.args[0]);if(z.content==="\\sqrt"&&z.data)return{type:"binaryFunc",content:"root",args:[G(z.data),Z]};if(z.content==="\\mathbf")return{type:"unaryFunc",content:"upright",args:[{type:"unaryFunc",content:"bold",args:[Z]}]};if(z.content==="\\mathbb"&&Z.type==="symbol"&&/^[A-Z]$/.test(Z.content))return{type:"symbol",content:Z.content+Z.content};if(z.content==="\\operatorname"){const J=z.args;if(J.length!==1||J[0].type!=="text")throw new K("Expecting body of \\operatorname to be text but got",z);const V=J[0].content;if(o.includes(V))return{type:"symbol",content:V};else return{type:"unaryFunc",content:"op",args:[{type:"text",content:V}]}}return{type:"unaryFunc",content:N(z.content),args:z.args.map(G)}}case"newline":return{type:"newline",content:"\n"};case"beginend":{const J=z.data.map((V)=>V.map(G));if(z.content.startsWith("align"))return{type:"align",content:"",data:J};else return{type:"matrix",content:"mat",data:J}}case"unknownMacro":return{type:"unknown",content:N(z.content)};case"control":if(z.content==="\\\\")return{type:"symbol",content:"\\"};else if(z.content==="\\,")return{type:"symbol",content:"thin"};else throw new K(`Unknown control sequence: ${z.content}`,z);default:throw new K(`Unimplemented node type: ${z.type}`,z)}}function N(z){if(/^[a-zA-Z0-9]$/.test(z))return z;else if(z==="\\\\")return"\\";else if(z=="/")return"\\/";else if(["\\$","\\#","\\&","\\_"].includes(z))return z;else if(z.startsWith("\\")){const Z=z.slice(1);if(O.has(Z))return O.get(Z);else return Z}return z}var o=["dim","id","im","mod","Pr","sech","csch"];class K extends Error{node;constructor(z,Z){super(z);this.name="TypstWriterError",this.node=Z}}class b{nonStrict;preferTypstIntrinsic;buffer="";queue=[];needSpaceAfterSingleItemScript=!1;insideFunctionDepth=0;constructor(z,Z){this.nonStrict=z,this.preferTypstIntrinsic=Z}writeBuffer(z){if(this.needSpaceAfterSingleItemScript&&/^[0-9a-zA-Z\(]/.test(z))this.buffer+=" ";else{let Z=!1;if(Z||=/[\(\|]$/.test(this.buffer)&&/^\w/.test(z),Z||=/^[}()_^,;!\|]$/.test(z),Z||=z==="'",Z||=/[0-9]$/.test(this.buffer)&&/^[0-9]/.test(z),Z||=/[\(\[{]\s*(-|\+)$/.test(this.buffer)||this.buffer==="-"||this.buffer==="+",Z||=z.startsWith("\n"),Z||=this.buffer==="",Z||=/[\s"_^{\(]$/.test(this.buffer),!Z)this.buffer+=" "}if(this.needSpaceAfterSingleItemScript)this.needSpaceAfterSingleItemScript=!1;this.buffer+=z}append(z){switch(z.type){case"empty":break;case"symbol":{let Z=z.content;if(z.content===","&&this.insideFunctionDepth>0)Z="comma";this.queue.push({type:"symbol",content:Z});break}case"text":case"comment":case"newline":this.queue.push(z);break;case"group":for(let Z of z.args)this.append(Z);break;case"supsub":{let{base:Z,sup:J,sub:V}=z.data;this.appendWithBracketsIfNeeded(Z);let X=!1;const $=J&&J.type==="symbol"&&J.content==="\'";if($)this.queue.push({type:"atom",content:"\'"}),X=!1;if(V)this.queue.push({type:"atom",content:"_"}),X=this.appendWithBracketsIfNeeded(V);if(J&&!$)this.queue.push({type:"atom",content:"^"}),X=this.appendWithBracketsIfNeeded(J);if(X)this.queue.push({type:"softSpace",content:""});break}case"binaryFunc":{const Z={type:"symbol",content:z.content},[J,V]=z.args;this.queue.push(Z),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(J),this.queue.push({type:"atom",content:","}),this.append(V),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--;break}case"unaryFunc":{const Z={type:"symbol",content:z.content},J=z.args[0];this.queue.push(Z),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.append(J),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--;break}case"align":{const Z=z.data;Z.forEach((J,V)=>{if(J.forEach((X,$)=>{if($>0)this.queue.push({type:"atom",content:"&"});this.append(X)}),V<Z.length-1)this.queue.push({type:"symbol",content:"\\"})});break}case"matrix":{const Z=z.data;this.queue.push({type:"symbol",content:"mat"}),this.insideFunctionDepth++,this.queue.push({type:"atom",content:"("}),this.queue.push({type:"symbol",content:"delim: #none, "}),Z.forEach((J,V)=>{J.forEach((X,$)=>{if(this.append(X),$<J.length-1)this.queue.push({type:"atom",content:","});else if(V<Z.length-1)this.queue.push({type:"atom",content:";"})})}),this.queue.push({type:"atom",content:")"}),this.insideFunctionDepth--;break}case"unknown":{if(this.nonStrict)this.queue.push({type:"symbol",content:z.content});else throw new K(`Unknown macro: ${z.content}`,z);break}default:throw new K(`Unimplemented node type to append: ${z.type}`,z)}}appendWithBracketsIfNeeded(z){const Z=!["group","supsub","empty"].includes(z.type);if(Z)this.append(z);else this.queue.push({type:"atom",content:"("}),this.append(z),this.queue.push({type:"atom",content:")"});return Z}flushQueue(){this.queue.forEach((z)=>{let Z="";switch(z.type){case"atom":case"symbol":Z=z.content;break;case"text":Z=`"${z.content}"`;break;case"softSpace":this.needSpaceAfterSingleItemScript=!0,Z="";break;case"comment":Z=`//${z.content}`;break;case"newline":Z="\n";break;default:throw new K(`Unexpected node type to stringify: ${z.type}`,z)}if(Z!=="")this.writeBuffer(Z)}),this.queue=[]}finalize(){this.flushQueue();const z=function(J){let V=J.replace(/⌊\s*(.*?)\s*⌋/g,"floor($1)");return V=V.replace(/floor\(\)/g,'floor("")'),V},Z=function(J){let V=J.replace(/⌈\s*(.*?)\s*⌉/g,"ceil($1)");return V=V.replace(/ceil\(\)/g,'ceil("")'),V};return this.buffer=z(this.buffer),this.buffer=Z(this.buffer),this.buffer}}function m(z,Z){const J={nonStrict:!0,preferTypstIntrinsic:!0,customTexMacros:{}};if(Z){if(Z.nonStrict)J.nonStrict=Z.nonStrict;if(Z.preferTypstIntrinsic)J.preferTypstIntrinsic=Z.preferTypstIntrinsic;if(Z.customTexMacros)J.customTexMacros=Z.customTexMacros}const V=u(z,J.customTexMacros),X=G(V),$=new b(J.nonStrict,J.preferTypstIntrinsic);return $.append(X),$.finalize()}if(typeof window!=="undefined")window.tex2typst=m;

@@ -0,1 +1,15 @@

export declare enum TokenType {
ELEMENT = 0,
COMMAND = 1,
TEXT = 2,
COMMENT = 3,
WHITESPACE = 4,
NEWLINE = 5,
CONTROL = 6,
UNKNOWN = 7
}
export interface Token {
type: TokenType;
value: string;
}
export interface TexSupsubData {

@@ -9,3 +23,3 @@ base: TexNode;

export interface TexNode {
type: string;
type: 'element' | 'text' | 'comment' | 'whitespace' | 'newline' | 'control' | 'ordgroup' | 'supsub' | 'unaryFunc' | 'binaryFunc' | 'leftright' | 'beginend' | 'symbol' | 'empty' | 'unknownMacro';
content: string;

@@ -15,6 +29,13 @@ args?: TexNode[];

}
export interface TypstSupsubData {
base: TypstNode;
sup?: TypstNode;
sub?: TypstNode;
}
export type TypstArrayData = TypstNode[][];
export interface TypstNode {
type: 'atom' | 'symbol' | 'text' | 'softSpace' | 'comment' | 'newline';
type: 'atom' | 'symbol' | 'text' | 'softSpace' | 'comment' | 'newline' | 'empty' | 'group' | 'supsub' | 'unaryFunc' | 'binaryFunc' | 'align' | 'matrix' | 'unknown';
content: string;
args?: TypstNode[];
data?: TypstSupsubData | TypstArrayData;
}

@@ -21,0 +42,0 @@ export interface Tex2TypstOptions {

import { TexNode, TypstNode } from "./types";
export declare class TypstWriterError extends Error {
node: TexNode;
node: TexNode | TypstNode;
constructor(message: string, node: TexNode | TypstNode);

@@ -15,6 +15,7 @@ }

private writeBuffer;
append(node: TexNode): void;
append(node: TypstNode): void;
private appendWithBracketsIfNeeded;
protected flushQueue(): void;
private appendWithBracketsIfNeeded;
finalize(): string;
}
export declare function convertTree(node: TexNode): TypstNode;
{
"name": "tex2typst",
"version": "0.2.7",
"version": "0.2.8",
"description": "JavaScript library for converting TeX code to Typst",

@@ -18,3 +18,3 @@ "type": "module",

"prebuild": "rimraf dist/",
"build:node": "bun build --entrypoints src/index.ts --outdir ./dist --target node --external katex",
"build:node": "bun build --entrypoints src/index.ts --outdir ./dist --target node",
"build:browser": "bun build --entrypoints src/tex2typst.ts --outdir ./dist --target browser --entry-naming [dir]/[name].min.[ext] --minify",

@@ -21,0 +21,0 @@ "build:types": "tsc --project ./tsconfig.json",

import { parseTex } from "./parser";
import { Tex2TypstOptions } from "./types";
import { TypstWriter } from "./writer";
import { convertTree, TypstWriter } from "./writer";
import { symbolMap } from "./map";

@@ -9,3 +9,3 @@

const opt: Tex2TypstOptions = {
nonStrict: false,
nonStrict: true,
preferTypstIntrinsic: true,

@@ -25,5 +25,6 @@ customTexMacros: {}

}
const t = parseTex(tex, opt.customTexMacros!);
const texTree = parseTex(tex, opt.customTexMacros!);
const typstTree = convertTree(texTree);
const writer = new TypstWriter(opt.nonStrict!, opt.preferTypstIntrinsic!);
writer.append(t);
writer.append(typstTree);
return writer.finalize();

@@ -30,0 +31,0 @@ }

@@ -1,2 +0,3 @@

import { TexNode, TexSupsubData } from "./types";
import { symbolMap } from "./map";
import { TexNode, TexSupsubData, Token, TokenType } from "./types";

@@ -45,3 +46,3 @@

const EMPTY_NODE = { 'type': 'empty', 'content': '' }
const EMPTY_NODE: TexNode = { type: 'empty', content: '' };

@@ -64,4 +65,4 @@ function assert(condition: boolean, message: string = ''): void {

const LEFT_CURLY_BRACKET: Token = {type: 'control', value: '{'};
const RIGHT_CURLY_BRACKET: Token = {type: 'control', value: '}'};
const LEFT_CURLY_BRACKET: Token = {type: TokenType.CONTROL, value: '{'};
const RIGHT_CURLY_BRACKET: Token = {type: TokenType.CONTROL, value: '}'};

@@ -88,4 +89,4 @@ function find_closing_curly_bracket(tokens: Token[], start: number): number {

const LEFT_SQUARE_BRACKET: Token = {type: 'element', value: '['};
const RIGHT_SQUARE_BRACKET: Token = {type: 'element', value: ']'};
const LEFT_SQUARE_BRACKET: Token = {type: TokenType.ELEMENT, value: '['};
const RIGHT_SQUARE_BRACKET: Token = {type: TokenType.ELEMENT, value: ']'};

@@ -123,3 +124,3 @@ function find_closing_square_bracket(tokens: Token[], start: number): number {

let pos = start;
while (pos < tokens.length && ['whitespace', 'newline'].includes(tokens[pos].type)) {
while (pos < tokens.length && [TokenType.WHITESPACE, TokenType.NEWLINE].includes(tokens[pos].type)) {
pos++;

@@ -133,5 +134,5 @@ }

const firstToken = tokens[start];
if (firstToken.type === 'element' && ['(', ')', '[', ']', '|', '\\{', '\\}'].includes(firstToken.value)) {
if (firstToken.type === TokenType.ELEMENT && ['(', ')', '[', ']', '|', '\\{', '\\}'].includes(firstToken.value)) {
return firstToken;
} else if (firstToken.type === 'command' && ['lfloor', 'rfloor', 'lceil', 'rceil', 'langle', 'rangle'].includes(firstToken.value.slice(1))) {
} else if (firstToken.type === TokenType.COMMAND && ['lfloor', 'rfloor', 'lceil', 'rceil', 'langle', 'rangle'].includes(firstToken.value.slice(1))) {
return firstToken;

@@ -145,3 +146,3 @@ } else {

let pos = start;
while (pos < tokens.length && token_eq(tokens[pos], { type: 'element', value: "'" })) {
while (pos < tokens.length && token_eq(tokens[pos], { type: TokenType.ELEMENT, value: "'" })) {
pos += 1;

@@ -164,4 +165,4 @@ }

const LEFT_COMMAND: Token = { type: 'command', value: '\\left' };
const RIGHT_COMMAND: Token = { type: 'command', value: '\\right' };
const LEFT_COMMAND: Token = { type: TokenType.COMMAND, value: '\\left' };
const RIGHT_COMMAND: Token = { type: TokenType.COMMAND, value: '\\right' };

@@ -188,4 +189,4 @@ function find_closing_right_command(tokens: Token[], start: number): number {

const BEGIN_COMMAND: Token = { type: 'command', value: '\\begin' };
const END_COMMAND: Token = { type: 'command', value: '\\end' };
const BEGIN_COMMAND: Token = { type: TokenType.COMMAND, value: '\\begin' };
const END_COMMAND: Token = { type: TokenType.COMMAND, value: '\\end' };

@@ -237,7 +238,2 @@

export interface Token {
type: 'element' | 'command' | 'text' | 'comment' | 'whitespace' | 'newline' | 'control' | 'unknown';
value: string;
}
export function tokenize(latex: string): Token[] {

@@ -256,3 +252,3 @@ const tokens: Token[] = [];

}
token = { type: 'comment', value: latex.slice(pos + 1, newPos) };
token = { type: TokenType.COMMENT, value: latex.slice(pos + 1, newPos) };
pos = newPos;

@@ -266,7 +262,7 @@ break;

case '&':
token = { type: 'control', value: firstChar};
token = { type: TokenType.CONTROL, value: firstChar};
pos++;
break;
case '\n':
token = { type: 'newline', value: firstChar};
token = { type: TokenType.NEWLINE, value: firstChar};
pos++;

@@ -276,6 +272,6 @@ break;

if (pos + 1 < latex.length && latex[pos + 1] === '\n') {
token = { type: 'newline', value: '\n' };
token = { type: TokenType.NEWLINE, value: '\n' };
pos += 2;
} else {
token = { type: 'newline', value: '\n' };
token = { type: TokenType.NEWLINE, value: '\n' };
pos ++;

@@ -290,3 +286,3 @@ }

}
token = {type: 'whitespace', value: latex.slice(pos, newPos)};
token = {type: TokenType.WHITESPACE, value: latex.slice(pos, newPos)};
pos = newPos;

@@ -301,8 +297,8 @@ break;

if (['\\\\', '\\,'].includes(firstTwoChars)) {
token = { type: 'control', value: firstTwoChars };
token = { type: TokenType.CONTROL, value: firstTwoChars };
} else if (['\\{','\\}', '\\%', '\\$', '\\&', '\\#', '\\_'].includes(firstTwoChars)) {
token = { type: 'element', value: firstTwoChars };
token = { type: TokenType.ELEMENT, value: firstTwoChars };
} else {
const command = eat_command_name(latex, pos + 1);
token = { type: 'command', value: '\\' + command};
token = { type: TokenType.COMMAND, value: '\\' + command};
}

@@ -318,9 +314,9 @@ pos += token.value.length;

}
token = { type: 'element', value: latex.slice(pos, newPos) }
token = { type: TokenType.ELEMENT, value: latex.slice(pos, newPos) }
} else if (isalpha(firstChar)) {
token = { type: 'element', value: firstChar };
token = { type: TokenType.ELEMENT, value: firstChar };
} else if ('+-*/=\'<>!.,;?()[]|'.includes(firstChar)) {
token = { type: 'element', value: firstChar }
token = { type: TokenType.ELEMENT, value: firstChar }
} else {
token = { type: 'unknown', value: firstChar };
token = { type: TokenType.UNKNOWN, value: firstChar };
}

@@ -333,7 +329,7 @@ pos += token.value.length;

if (token.type === 'command' && ['\\text', '\\begin', '\\end'].includes(token.value)) {
if (token.type === TokenType.COMMAND && ['\\text', '\\operatorname', '\\begin', '\\end'].includes(token.value)) {
if (pos >= latex.length || latex[pos] !== '{') {
throw new LatexParserError(`No content for ${token.value} command`);
}
tokens.push({ type: 'control', value: '{' });
tokens.push({ type: TokenType.CONTROL, value: '{' });
const posClosingBracket = find_closing_curly_bracket_char(latex, pos);

@@ -347,4 +343,4 @@ pos++;

}
tokens.push({ type: 'text', value: textInside });
tokens.push({ type: 'control', value: '}' });
tokens.push({ type: TokenType.TEXT, value: textInside });
tokens.push({ type: TokenType.CONTROL, value: '}' });
pos = posClosingBracket + 1;

@@ -371,4 +367,4 @@ }

const SUB_SYMBOL:Token = { type: 'control', value: '_' };
const SUP_SYMBOL:Token = { type: 'control', value: '^' };
const SUB_SYMBOL:Token = { type: TokenType.CONTROL, value: '_' };
const SUP_SYMBOL:Token = { type: TokenType.CONTROL, value: '^' };

@@ -464,3 +460,3 @@ export class LatexParser {

for (let i = 0; i < num_prime; i++) {
res.sup.args!.push({ type: 'symbol', content: '\\prime' });
res.sup.args!.push({ type: 'element', content: "'" });
}

@@ -486,9 +482,13 @@ if (sup) {

switch (tokenType) {
case 'element':
case 'text':
case 'comment':
case 'whitespace':
case 'newline':
return [{ type: tokenType, content: firstToken.value }, start + 1];
case 'command':
case TokenType.ELEMENT:
return [{ type: 'element', content: firstToken.value }, start + 1];
case TokenType.TEXT:
return [{ type: 'text', content: firstToken.value }, start + 1];
case TokenType.COMMENT:
return [{ type: 'comment', content: firstToken.value }, start + 1];
case TokenType.WHITESPACE:
return [{ type: 'whitespace', content: firstToken.value }, start + 1];
case TokenType.NEWLINE:
return [{ type: 'newline', content: firstToken.value }, start + 1];
case TokenType.COMMAND:
if (token_eq(firstToken, BEGIN_COMMAND)) {

@@ -501,3 +501,3 @@ return this.parseBeginEndExpr(tokens, start);

}
case 'control':
case TokenType.CONTROL:
const controlChar = firstToken.value;

@@ -532,3 +532,3 @@ switch (controlChar) {

parseCommandExpr(tokens: Token[], start: number): ParseResult {
assert(tokens[start].type === 'command');
assert(tokens[start].type === TokenType.COMMAND);

@@ -543,31 +543,38 @@ const command = tokens[start].value; // command name starts with a \

const paramNum = get_command_param_num(command.slice(1));
if (paramNum === 0) {
return [{ type: 'symbol', content: command }, pos];
} else if (paramNum === 1) {
if (command === '\\sqrt' && pos < tokens.length && token_eq(tokens[pos], LEFT_SQUARE_BRACKET)) {
const posLeftSquareBracket = pos;
const posRightSquareBracket = find_closing_square_bracket(tokens, pos);
const exprInside = tokens.slice(posLeftSquareBracket + 1, posRightSquareBracket);
const exponent = this.parse(exprInside);
const [arg1, newPos] = this.parseNextExprWithoutSupSub(tokens, posRightSquareBracket + 1);
return [{ type: 'unaryFunc', content: command, args: [arg1], data: exponent }, newPos];
} else if (command === '\\text') {
if (pos + 2 >= tokens.length) {
throw new LatexParserError('Expecting content for \\text command');
switch (paramNum) {
case 0:
if (!symbolMap.has(command.slice(1))) {
return [{ type: 'unknownMacro', content: command }, pos];
}
assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === 'text');
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));
const text = tokens[pos + 1].value;
return [{ type: 'text', content: text }, pos + 3];
return [{ type: 'symbol', content: command }, pos];
case 1: {
if (command === '\\sqrt' && pos < tokens.length && token_eq(tokens[pos], LEFT_SQUARE_BRACKET)) {
const posLeftSquareBracket = pos;
const posRightSquareBracket = find_closing_square_bracket(tokens, pos);
const exprInside = tokens.slice(posLeftSquareBracket + 1, posRightSquareBracket);
const exponent = this.parse(exprInside);
const [arg1, newPos] = this.parseNextExprWithoutSupSub(tokens, posRightSquareBracket + 1);
return [{ type: 'unaryFunc', content: command, args: [arg1], data: exponent }, newPos];
} else if (command === '\\text') {
if (pos + 2 >= tokens.length) {
throw new LatexParserError('Expecting content for \\text command');
}
assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === TokenType.TEXT);
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));
const text = tokens[pos + 1].value;
return [{ type: 'text', content: text }, pos + 3];
}
let [arg1, newPos] = this.parseNextExprWithoutSupSub(tokens, pos);
return [{ type: 'unaryFunc', content: command, args: [arg1] }, newPos];
}
let [arg1, newPos] = this.parseNextExprWithoutSupSub(tokens, pos);
return [{ type: 'unaryFunc', content: command, args: [arg1] }, newPos];
} else if (paramNum === 2) {
const [arg1, pos1] = this.parseNextExprWithoutSupSub(tokens, pos);
const [arg2, pos2] = this.parseNextExprWithoutSupSub(tokens, pos1);
return [{ type: 'binaryFunc', content: command, args: [arg1, arg2] }, pos2];
} else {
throw new Error( 'Invalid number of parameters');
case 2: {
const [arg1, pos1] = this.parseNextExprWithoutSupSub(tokens, pos);
const [arg2, pos2] = this.parseNextExprWithoutSupSub(tokens, pos1);
return [{ type: 'binaryFunc', content: command, args: [arg1, arg2] }, pos2];
}
default:
throw new Error( 'Invalid number of parameters');
}

@@ -612,3 +619,3 @@ }

const body = this.parse(exprInside);
const args = [
const args: TexNode[] = [
{ type: 'element', content: leftDelimiter.value },

@@ -618,3 +625,3 @@ body,

]
const res = { type: 'leftright', content: '', args: args };
const res: TexNode = { type: 'leftright', content: '', args: args };
return [res, pos];

@@ -628,3 +635,3 @@ }

assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === 'text');
assert(tokens[pos + 1].type === TokenType.TEXT);
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));

@@ -646,3 +653,3 @@ const envName = tokens[pos + 1].value;

assert(token_eq(tokens[pos], LEFT_CURLY_BRACKET));
assert(tokens[pos + 1].type === 'text');
assert(tokens[pos + 1].type === TokenType.TEXT);
assert(token_eq(tokens[pos + 2], RIGHT_CURLY_BRACKET));

@@ -656,7 +663,7 @@ if (tokens[pos + 1].value !== envName) {

// ignore whitespaces and '\n' before \end{envName}
while(exprInside.length > 0 && ['whitespace', 'newline'].includes(exprInside[exprInside.length - 1].type)) {
while(exprInside.length > 0 && [TokenType.WHITESPACE, TokenType.NEWLINE].includes(exprInside[exprInside.length - 1].type)) {
exprInside.pop();
}
const body = this.parseAligned(exprInside);
const res = { type: 'beginend', content: envName, data: body };
const res: TexNode = { type: 'beginend', content: envName, data: body };
return [res, pos];

@@ -696,3 +703,3 @@ }

// Remove all whitespace before and after _ or ^
// Remove all whitespace before or after _ or ^
function passIgnoreWhitespaceBeforeScriptMark(tokens: Token[]): Token[] {

@@ -702,6 +709,6 @@ const is_script_mark = (token: Token) => token_eq(token, SUB_SYMBOL) || token_eq(token, SUP_SYMBOL);

for (let i = 0; i < tokens.length; i++) {
if (tokens[i].type === 'whitespace' && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
if (tokens[i].type === TokenType.WHITESPACE && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
continue;
}
if (tokens[i].type === 'whitespace' && i - 1 >= 0 && is_script_mark(tokens[i - 1])) {
if (tokens[i].type === TokenType.WHITESPACE && i - 1 >= 0 && is_script_mark(tokens[i - 1])) {
continue;

@@ -718,3 +725,3 @@ }

for (const token of tokens) {
if (token.type === 'command' && customTexMacros[token.value]) {
if (token.type === TokenType.COMMAND && customTexMacros[token.value]) {
const expanded_tokens = tokenize(customTexMacros[token.value]);

@@ -721,0 +728,0 @@ out_tokens = out_tokens.concat(expanded_tokens);

@@ -0,1 +1,18 @@

export enum TokenType {
ELEMENT,
COMMAND,
TEXT,
COMMENT,
WHITESPACE,
NEWLINE,
CONTROL,
UNKNOWN,
}
export interface Token {
type: TokenType;
value: string;
}
export interface TexSupsubData {

@@ -12,3 +29,4 @@ base: TexNode;

export interface TexNode {
type: string;
type: 'element' | 'text' | 'comment' | 'whitespace' | 'newline' | 'control' | 'ordgroup' | 'supsub'
| 'unaryFunc' | 'binaryFunc' | 'leftright' | 'beginend' | 'symbol' | 'empty' | 'unknownMacro';
content: string;

@@ -23,6 +41,16 @@ args?: TexNode[];

export interface TypstSupsubData {
base: TypstNode;
sup?: TypstNode;
sub?: TypstNode;
}
export type TypstArrayData = TypstNode[][];
export interface TypstNode {
type: 'atom' | 'symbol' | 'text' | 'softSpace' | 'comment' | 'newline',
type: 'atom' | 'symbol' | 'text' | 'softSpace' | 'comment' | 'newline'
| 'empty' | 'group' | 'supsub' | 'unaryFunc' | 'binaryFunc' | 'align' | 'matrix' | 'unknown';
content: string;
args?: TypstNode[];
data?: TypstSupsubData | TypstArrayData;
}

@@ -29,0 +57,0 @@

import { symbolMap } from "./map";
import { TexNode, TexSqrtData, TexSupsubData, TypstNode } from "./types";
import { TexNode, TexSqrtData, TexSupsubData, TypstNode, TypstSupsubData } from "./types";

@@ -18,3 +18,3 @@

export class TypstWriterError extends Error {
node: TexNode;
node: TexNode | TypstNode;

@@ -77,107 +77,67 @@ constructor(message: string, node: TexNode | TypstNode) {

public append(node: TexNode) {
if (node.type === 'empty' || node.type === 'whitespace') {
return;
} else if (node.type === 'ordgroup') {
// const index = this.startBlock();
node.args!.forEach((arg) => this.append(arg));
// this.endBlock(index);
} else if (node.type === 'element') {
let content = node.content!;
if (node.content === ',' && this.insideFunctionDepth > 0) {
content = 'comma';
public append(node: TypstNode) {
switch (node.type) {
case 'empty':
break;
case 'symbol': {
let content = node.content!;
if (node.content === ',' && this.insideFunctionDepth > 0) {
content = 'comma';
}
this.queue.push({ type: 'symbol', content: content });
break;
}
this.queue.push({ type: 'symbol', content: content });
} else if (node.type === 'symbol') {
this.queue.push({ type: 'symbol', content: node.content });
} else if (node.type === 'text') {
this.queue.push(node as TypstNode)
} else if (node.type === 'supsub') {
let { base, sup, sub } = node.data as TexSupsubData;
// Special logic for overbrace
if (base && base.type === 'unaryFunc' && base.content === '\\overbrace' && sup) {
this.append({ type: 'binaryFunc', content: '\\overbrace', args: [base.args![0], sup] });
return;
} else if (base && base.type === 'unaryFunc' && base.content === '\\underbrace' && sub) {
this.append({ type: 'binaryFunc', content: '\\underbrace', args: [base.args![0], sub] });
return;
}
if (base.type === 'empty') {
this.queue.push({ type: 'text', content: '' });
} else {
case 'text':
case 'comment':
case 'newline':
this.queue.push(node);
break;
case 'group':
for (const item of node.args!) {
this.append(item);
}
break;
case 'supsub': {
let { base, sup, sub } = node.data as TypstSupsubData;
this.appendWithBracketsIfNeeded(base);
}
let trailing_space_needed = false;
const has_prime = (sup && sup.type === 'symbol' && sup.content === '\\prime');
if (has_prime) {
// Put prime symbol before '_'. Because $y_1'$ is not displayed properly in Typst (so far)
// e.g.
// y_1' -> y'_1
// y_{a_1}' -> y'_{a_1}
this.queue.push({ type: 'atom', content: '\''});
trailing_space_needed = false;
let trailing_space_needed = false;
const has_prime = (sup && sup.type === 'symbol' && sup.content === '\'');
if (has_prime) {
// Put prime symbol before '_'. Because $y_1'$ is not displayed properly in Typst (so far)
// e.g.
// y_1' -> y'_1
// y_{a_1}' -> y'_{a_1}
this.queue.push({ type: 'atom', content: '\''});
trailing_space_needed = false;
}
if (sub) {
this.queue.push({ type: 'atom', content: '_'});
trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
}
if (sup && !has_prime) {
this.queue.push({ type: 'atom', content: '^'});
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
}
if (trailing_space_needed) {
this.queue.push({ type: 'softSpace', content: ''});
}
break;
}
if (sub) {
this.queue.push({ type: 'atom', content: '_'});
trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
}
if (sup && !has_prime) {
this.queue.push({ type: 'atom', content: '^'});
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
}
if (trailing_space_needed) {
this.queue.push({ type: 'softSpace', content: ''});
}
} else if (node.type === 'leftright') {
const [left, body, right] = node.args!;
// These pairs will be handled by Typst compiler by default. No need to add lr()
if (["[]", "()", "\\{\\}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
this.append(left);
this.append(body);
this.append(right);
return;
}
const func_symbol: TypstNode = { type: 'symbol', content: 'lr' };
this.queue.push(func_symbol);
this.insideFunctionDepth ++;
this.queue.push({ type: 'atom', content: '('});
this.append(left);
this.append(body);
this.append(right);
this.queue.push({ type: 'atom', content: ')'});
this.insideFunctionDepth --;
} else if (node.type === 'binaryFunc') {
const func_symbol: TypstNode = { type: 'symbol', content: node.content };
const [arg0, arg1] = node.args!;
this.queue.push(func_symbol);
this.insideFunctionDepth ++;
this.queue.push({ type: 'atom', content: '('});
this.append(arg0);
this.queue.push({ type: 'atom', content: ','});
this.append(arg1);
this.queue.push({ type: 'atom', content: ')'});
this.insideFunctionDepth --;
} else if (node.type === 'unaryFunc') {
const func_symbol: TypstNode = { type: 'symbol', content: node.content };
const arg0 = node.args![0];
if (node.content === '\\sqrt' && node.data) {
func_symbol.content = 'root';
case 'binaryFunc': {
const func_symbol: TypstNode = { type: 'symbol', content: node.content };
const [arg0, arg1] = node.args!;
this.queue.push(func_symbol);
this.insideFunctionDepth ++;
this.queue.push({ type: 'atom', content: '('});
this.append(node.data as TexSqrtData); // the number of times to take the root
this.append(arg0);
this.queue.push({ type: 'atom', content: ','});
this.append(arg0);
this.append(arg1);
this.queue.push({ type: 'atom', content: ')'});
this.insideFunctionDepth --;
return;
} else if (node.content === '\\mathbf') {
this.append({ type: 'symbol', content: 'upright' });
this.insideFunctionDepth ++;
this.queue.push({ type: 'atom', content: '('});
break;
}
case 'unaryFunc': {
const func_symbol: TypstNode = { type: 'symbol', content: node.content };
const arg0 = node.args![0];
this.queue.push(func_symbol);

@@ -189,50 +149,6 @@ this.insideFunctionDepth ++;

this.insideFunctionDepth --;
this.queue.push({ type: 'atom', content: ')'});
this.insideFunctionDepth --;
return;
} else if (node.content === '\\mathbb') {
const body = node.args![0];
if (body.type === 'element' && /^[A-Z]$/.test(body.content)) {
// \mathbb{R} -> RR
this.queue.push({ type: 'symbol', content: body.content + body.content});
return;
}
// Fall through
} else if (node.content === '\\operatorname') {
let body = node.args!;
if (body.length === 1 && body[0].type == 'ordgroup') {
body = body[0].args!;
}
const text = body.reduce((buff, n) => {
// Hope convertToken() will not throw an error
// If it does, the input is bad.
buff += convertToken(n.content);
return buff;
}, "" as string);
if (this.preferTypstIntrinsic && TYPST_INTRINSIC_SYMBOLS.includes(text)) {
// e.g. we prefer just sech over op("sech")
this.queue.push({ type: 'symbol', content: text});
} else {
this.queue.push({ type: 'symbol', content: 'op' });
this.queue.push({ type: 'atom', content: '('});
this.queue.push({ type: 'text', content: text});
this.queue.push({ type: 'atom', content: ')'});
}
return;
break;
}
this.queue.push(func_symbol);
this.insideFunctionDepth ++;
this.queue.push({ type: 'atom', content: '('});
this.append(arg0);
this.queue.push({ type: 'atom', content: ')'});
this.insideFunctionDepth --;
} else if (node.type === 'newline') {
this.queue.push({ type: 'newline', content: '\n'});
return;
} else if (node.type === 'beginend') {
if (node.content!.startsWith('align')) {
// align, align*, alignat, alignat*, aligned, etc.
const matrix = node.data as TexNode[][];
case 'align': {
const matrix = node.data as TypstNode[][];
matrix.forEach((row, i) => {

@@ -246,7 +162,9 @@ row.forEach((cell, j) => {

if (i < matrix.length - 1) {
this.queue.push({ type: 'symbol', content: '\\\\' });
this.queue.push({ type: 'symbol', content: '\\' });
}
});
} else {
const matrix = node.data as TexNode[][];
break;
}
case 'matrix': {
const matrix = node.data as TypstNode[][];
this.queue.push({ type: 'symbol', content: 'mat' });

@@ -259,6 +177,6 @@ this.insideFunctionDepth ++;

// There is a leading & in row
if (cell.type === 'ordgroup' && cell.args!.length === 0) {
this.queue.push({ type: 'atom', content: ',' });
return;
}
// if (cell.type === 'ordgroup' && cell.args!.length === 0) {
// this.queue.push({ type: 'atom', content: ',' });
// return;
// }
// if (j == 0 && cell.type === 'newline' && cell.content === '\n') {

@@ -280,23 +198,33 @@ // return;

this.insideFunctionDepth --;
break;
}
} else if (node.type === 'matrix') {
} else if (node.type === 'unknownMacro') {
if (this.nonStrict) {
this.queue.push({ type: 'symbol', content: node.content });
} else {
throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
case 'unknown': {
if (this.nonStrict) {
this.queue.push({ type: 'symbol', content: node.content });
} else {
throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
}
break;
}
} else if (node.type === 'control') {
if (node.content === '\\\\') {
this.queue.push({ type: 'symbol', content: node.content });
} else if (node.content === '\\,') {
this.queue.push({ type: 'symbol', content: 'thin' });
} else {
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
}
} else if (node.type === 'comment') {
this.queue.push({ type: 'comment', content: node.content });
default:
throw new TypstWriterError(`Unimplemented node type to append: ${node.type}`, node);
}
}
private appendWithBracketsIfNeeded(node: TypstNode): boolean {
const is_single = !['group', 'supsub', 'empty'].includes(node.type);
if (is_single) {
this.append(node);
} else {
throw new TypstWriterError(`Unimplemented node type to append: ${node.type}`, node);
this.queue.push({
type: 'atom',
content: '('
});
this.append(node);
this.queue.push({
type: 'atom',
content: ')'
});
}
return is_single;
}

@@ -309,7 +237,5 @@

case 'atom':
case 'symbol':
str = node.content;
break;
case 'symbol':
str = convertToken(node.content);
break;
case 'text':

@@ -338,20 +264,2 @@ str = `"${node.content}"`;

private appendWithBracketsIfNeeded(node: TexNode): boolean {
const is_single = ['symbol', 'element', 'unaryFunc', 'binaryFunc', 'leftright'].includes(node.type);
if (is_single) {
this.append(node);
} else {
this.queue.push({
type: 'atom',
content: '('
});
this.append(node);
this.queue.push({
type: 'atom',
content: ')'
});
}
return is_single;
}
public finalize(): string {

@@ -379,3 +287,180 @@ this.flushQueue();

export function convertTree(node: TexNode): TypstNode {
switch (node.type) {
case 'empty':
case 'whitespace':
return { type: 'empty', content: '' };
case 'ordgroup':
return {
type: 'group',
content: '',
args: node.args!.map(convertTree),
};
case 'element':
case 'symbol':
return { type: 'symbol', content: convertToken(node.content) };
case 'text':
return { type: 'text', content: node.content };
case 'comment':
return { type: 'comment', content: node.content };
case 'supsub': {
let { base, sup, sub } = node.data as TexSupsubData;
// Special logic for overbrace
if (base && base.type === 'unaryFunc' && base.content === '\\overbrace' && sup) {
return {
type: 'binaryFunc',
content: 'overbrace',
args: [convertTree(base.args![0]), convertTree(sup)],
};
} else if (base && base.type === 'unaryFunc' && base.content === '\\underbrace' && sub) {
return {
type: 'binaryFunc',
content: 'underbrace',
args: [convertTree(base.args![0]), convertTree(sub)],
};
}
const data: TypstSupsubData = {
base: convertTree(base),
};
if (data.base.type === 'empty') {
data.base = { type: 'text', content: '' };
}
if (sup) {
data.sup = convertTree(sup);
}
if (sub) {
data.sub = convertTree(sub);
}
return {
type: 'supsub',
content: '',
data: data,
};
}
case 'leftright': {
const [left, body, right] = node.args!;
// These pairs will be handled by Typst compiler by default. No need to add lr()
const group: TypstNode = {
type: 'group',
content: '',
args: node.args!.map(convertTree),
};
if (["[]", "()", "\\{\\}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
return group;
}
return {
type: 'unaryFunc',
content: 'lr',
args: [group],
};
}
case 'binaryFunc': {
return {
type: 'binaryFunc',
content: convertToken(node.content),
args: node.args!.map(convertTree),
};
}
case 'unaryFunc': {
const arg0 = convertTree(node.args![0]);
// \sqrt{3}{x} -> root(3, x)
if (node.content === '\\sqrt' && node.data) {
const data = convertTree(node.data as TexSqrtData); // the number of times to take the root
return {
type: 'binaryFunc',
content: 'root',
args: [data, arg0],
};
}
// \mathbf{a} -> upright(mathbf(a))
if (node.content === '\\mathbf') {
const inner: TypstNode = {
type: 'unaryFunc',
content: 'bold',
args: [arg0],
};
return {
type: 'unaryFunc',
content: 'upright',
args: [inner],
};
}
// \mathbb{R} -> RR
if (node.content === '\\mathbb' && arg0.type === 'symbol' && /^[A-Z]$/.test(arg0.content)) {
return {
type: 'symbol',
content: arg0.content + arg0.content,
};
}
// \operatorname{opname} -> op("opname")
if (node.content === '\\operatorname') {
const body = node.args!;
if (body.length !== 1 || body[0].type !== 'text') {
throw new TypstWriterError(`Expecting body of \\operatorname to be text but got`, node);
}
const text = body[0].content;
if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
return {
type: 'symbol',
content: text,
};
} else {
return {
type: 'unaryFunc',
content: 'op',
args: [{ type: 'text', content: text }],
};
}
}
// generic case
return {
type: 'unaryFunc',
content: convertToken(node.content),
args: node.args!.map(convertTree),
};
}
case 'newline':
return { type: 'newline', content: '\n' };
case 'beginend': {
const matrix = node.data as TexNode[][];
const data = matrix.map((row) => row.map(convertTree));
if (node.content!.startsWith('align')) {
// align, align*, alignat, alignat*, aligned, etc.
return {
type: 'align',
content: '',
data: data,
};
} else {
return {
type: 'matrix',
content: 'mat',
data: data,
};
}
}
case 'unknownMacro':
return { type: 'unknown', content: convertToken(node.content) };
case 'control':
if (node.content === '\\\\') {
return { type: 'symbol', content: '\\' };
} else if (node.content === '\\,') {
return { type: 'symbol', content: 'thin' };
} else {
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
}
default:
throw new TypstWriterError(`Unimplemented node type: ${node.type}`, node);
}
}
function convertToken(token: string): string {

@@ -382,0 +467,0 @@ if (/^[a-zA-Z0-9]$/.test(token)) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc