tex2typst 0.3.18 → 0.3.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ var symbolMap = /* @__PURE__ */ new Map([
6
6
  [",", "thin"],
7
7
  [":", "med"],
8
8
  [";", "thick"],
9
+ /* textual operators */
10
+ ["ln", "ln"],
11
+ ["log", "log"],
9
12
  ["cos", "cos"],
10
13
  ["sin", "sin"],
11
14
  ["tan", "tan"],
@@ -1633,8 +1636,8 @@ var JSLex = class {
1633
1636
  }
1634
1637
  };
1635
1638
 
1636
- // src/tex-parser.ts
1637
- var UNARY_COMMANDS = [
1639
+ // src/tex-tokenizer.ts
1640
+ var TEX_UNARY_COMMANDS = [
1638
1641
  "sqrt",
1639
1642
  "text",
1640
1643
  "bar",
@@ -1667,7 +1670,7 @@ var UNARY_COMMANDS = [
1667
1670
  "overrightarrow",
1668
1671
  "hspace"
1669
1672
  ];
1670
- var BINARY_COMMANDS = [
1673
+ var TEX_BINARY_COMMANDS = [
1671
1674
  "frac",
1672
1675
  "tfrac",
1673
1676
  "binom",
@@ -1677,81 +1680,6 @@ var BINARY_COMMANDS = [
1677
1680
  "overset",
1678
1681
  "underset"
1679
1682
  ];
1680
- var IGNORED_COMMANDS = [
1681
- "bigl",
1682
- "bigr",
1683
- "biggl",
1684
- "biggr",
1685
- "Bigl",
1686
- "Bigr",
1687
- "Biggl",
1688
- "Biggr"
1689
- ];
1690
- var EMPTY_NODE = new TexNode("empty", "");
1691
- function get_command_param_num(command) {
1692
- if (UNARY_COMMANDS.includes(command)) {
1693
- return 1;
1694
- } else if (BINARY_COMMANDS.includes(command)) {
1695
- return 2;
1696
- } else {
1697
- return 0;
1698
- }
1699
- }
1700
- var LEFT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "{");
1701
- var RIGHT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "}");
1702
- var LEFT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "[");
1703
- var RIGHT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "]");
1704
- function eat_whitespaces(tokens, start) {
1705
- let pos = start;
1706
- while (pos < tokens.length && [4 /* SPACE */, 5 /* NEWLINE */].includes(tokens[pos].type)) {
1707
- pos++;
1708
- }
1709
- return tokens.slice(start, pos);
1710
- }
1711
- function eat_parenthesis(tokens, start) {
1712
- const firstToken = tokens[start];
1713
- if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}", ".", "\\|"].includes(firstToken.value)) {
1714
- return firstToken;
1715
- } else if (firstToken.type === 1 /* COMMAND */ && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
1716
- return firstToken;
1717
- } else {
1718
- return null;
1719
- }
1720
- }
1721
- function eat_primes(tokens, start) {
1722
- let pos = start;
1723
- while (pos < tokens.length && tokens[pos].eq(new TexToken(0 /* ELEMENT */, "'"))) {
1724
- pos += 1;
1725
- }
1726
- return pos - start;
1727
- }
1728
- function find_closing_match(tokens, start, leftToken, rightToken) {
1729
- assert(tokens[start].eq(leftToken));
1730
- let count = 1;
1731
- let pos = start + 1;
1732
- while (count > 0) {
1733
- if (pos >= tokens.length) {
1734
- return -1;
1735
- }
1736
- if (tokens[pos].eq(leftToken)) {
1737
- count += 1;
1738
- } else if (tokens[pos].eq(rightToken)) {
1739
- count -= 1;
1740
- }
1741
- pos += 1;
1742
- }
1743
- return pos - 1;
1744
- }
1745
- var LEFT_COMMAND = new TexToken(1 /* COMMAND */, "\\left");
1746
- var RIGHT_COMMAND = new TexToken(1 /* COMMAND */, "\\right");
1747
- function find_closing_right_command(tokens, start) {
1748
- return find_closing_match(tokens, start, LEFT_COMMAND, RIGHT_COMMAND);
1749
- }
1750
- var BEGIN_COMMAND = new TexToken(1 /* COMMAND */, "\\begin");
1751
- var END_COMMAND = new TexToken(1 /* COMMAND */, "\\end");
1752
- function find_closing_end_command(tokens, start) {
1753
- return find_closing_match(tokens, start, BEGIN_COMMAND, END_COMMAND);
1754
- }
1755
1683
  function unescape(str) {
1756
1684
  const chars = ["{", "}", "\\", "$", "&", "#", "_", "%"];
1757
1685
  for (const char of chars) {
@@ -1780,13 +1708,14 @@ var rules_map = /* @__PURE__ */ new Map([
1780
1708
  [String.raw`\r?\n`, (_s) => new TexToken(5 /* NEWLINE */, "\n")],
1781
1709
  [String.raw`\s+`, (s) => new TexToken(4 /* SPACE */, s.text())],
1782
1710
  [String.raw`\\[{}%$&#_|]`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
1711
+ // e.g. match `\frac13`, `\frac1 b`, `\frac a b`
1783
1712
  [String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])\s*([0-9a-zA-Z])`, (s) => {
1784
1713
  const text = s.text();
1785
1714
  const regex = RegExp(String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])\s*([0-9a-zA-Z])`);
1786
1715
  const match = text.match(regex);
1787
1716
  assert(match !== null);
1788
1717
  const command = match[1];
1789
- if (BINARY_COMMANDS.includes(command.substring(1))) {
1718
+ if (TEX_BINARY_COMMANDS.includes(command.substring(1))) {
1790
1719
  const arg1 = match[2].trimStart();
1791
1720
  const arg2 = match[3];
1792
1721
  return [
@@ -1799,13 +1728,14 @@ var rules_map = /* @__PURE__ */ new Map([
1799
1728
  return [];
1800
1729
  }
1801
1730
  }],
1731
+ // e.g. match `\sqrt3`, `\sqrt a`
1802
1732
  [String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`, (s) => {
1803
1733
  const text = s.text();
1804
1734
  const regex = RegExp(String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`);
1805
1735
  const match = text.match(regex);
1806
1736
  assert(match !== null);
1807
1737
  const command = match[1];
1808
- if (UNARY_COMMANDS.includes(command.substring(1))) {
1738
+ if (TEX_UNARY_COMMANDS.includes(command.substring(1))) {
1809
1739
  const arg1 = match[2].trimStart();
1810
1740
  return [
1811
1741
  new TexToken(1 /* COMMAND */, command),
@@ -1835,6 +1765,83 @@ function tokenize_tex(input) {
1835
1765
  const lexer = new JSLex(spec);
1836
1766
  return lexer.collect(input);
1837
1767
  }
1768
+
1769
+ // src/tex-parser.ts
1770
+ var IGNORED_COMMANDS = [
1771
+ "bigl",
1772
+ "bigr",
1773
+ "biggl",
1774
+ "biggr",
1775
+ "Bigl",
1776
+ "Bigr",
1777
+ "Biggl",
1778
+ "Biggr"
1779
+ ];
1780
+ var EMPTY_NODE = new TexNode("empty", "");
1781
+ function get_command_param_num(command) {
1782
+ if (TEX_UNARY_COMMANDS.includes(command)) {
1783
+ return 1;
1784
+ } else if (TEX_BINARY_COMMANDS.includes(command)) {
1785
+ return 2;
1786
+ } else {
1787
+ return 0;
1788
+ }
1789
+ }
1790
+ var LEFT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "{");
1791
+ var RIGHT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "}");
1792
+ var LEFT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "[");
1793
+ var RIGHT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "]");
1794
+ function eat_whitespaces(tokens, start) {
1795
+ let pos = start;
1796
+ while (pos < tokens.length && [4 /* SPACE */, 5 /* NEWLINE */].includes(tokens[pos].type)) {
1797
+ pos++;
1798
+ }
1799
+ return tokens.slice(start, pos);
1800
+ }
1801
+ function eat_parenthesis(tokens, start) {
1802
+ const firstToken = tokens[start];
1803
+ if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}", ".", "\\|"].includes(firstToken.value)) {
1804
+ return firstToken;
1805
+ } else if (firstToken.type === 1 /* COMMAND */ && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
1806
+ return firstToken;
1807
+ } else {
1808
+ return null;
1809
+ }
1810
+ }
1811
+ function eat_primes(tokens, start) {
1812
+ let pos = start;
1813
+ while (pos < tokens.length && tokens[pos].eq(new TexToken(0 /* ELEMENT */, "'"))) {
1814
+ pos += 1;
1815
+ }
1816
+ return pos - start;
1817
+ }
1818
+ function find_closing_match(tokens, start, leftToken, rightToken) {
1819
+ assert(tokens[start].eq(leftToken));
1820
+ let count = 1;
1821
+ let pos = start + 1;
1822
+ while (count > 0) {
1823
+ if (pos >= tokens.length) {
1824
+ return -1;
1825
+ }
1826
+ if (tokens[pos].eq(leftToken)) {
1827
+ count += 1;
1828
+ } else if (tokens[pos].eq(rightToken)) {
1829
+ count -= 1;
1830
+ }
1831
+ pos += 1;
1832
+ }
1833
+ return pos - 1;
1834
+ }
1835
+ var LEFT_COMMAND = new TexToken(1 /* COMMAND */, "\\left");
1836
+ var RIGHT_COMMAND = new TexToken(1 /* COMMAND */, "\\right");
1837
+ function find_closing_right_command(tokens, start) {
1838
+ return find_closing_match(tokens, start, LEFT_COMMAND, RIGHT_COMMAND);
1839
+ }
1840
+ var BEGIN_COMMAND = new TexToken(1 /* COMMAND */, "\\begin");
1841
+ var END_COMMAND = new TexToken(1 /* COMMAND */, "\\end");
1842
+ function find_closing_end_command(tokens, start) {
1843
+ return find_closing_match(tokens, start, BEGIN_COMMAND, END_COMMAND);
1844
+ }
1838
1845
  var LatexParserError = class extends Error {
1839
1846
  constructor(message) {
1840
1847
  super(message);
@@ -2274,6 +2281,7 @@ var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
2274
2281
  var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
2275
2282
  var TYPST_COMMA = new TypstToken(2 /* ELEMENT */, ",");
2276
2283
  var TYPST_NEWLINE = new TypstToken(1 /* SYMBOL */, "\n");
2284
+ var SOFT_SPACE = new TypstToken(6 /* CONTROL */, " ");
2277
2285
  function typst_primitive_to_string(value) {
2278
2286
  switch (typeof value) {
2279
2287
  case "string":
@@ -2397,7 +2405,7 @@ var TypstWriter = class {
2397
2405
  trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
2398
2406
  }
2399
2407
  if (trailing_space_needed) {
2400
- this.queue.push(new TypstToken(6 /* CONTROL */, " "));
2408
+ this.queue.push(SOFT_SPACE);
2401
2409
  }
2402
2410
  break;
2403
2411
  }
@@ -2428,7 +2436,12 @@ var TypstWriter = class {
2428
2436
  }
2429
2437
  case "fraction": {
2430
2438
  const [numerator, denominator] = node.args;
2431
- this.appendWithBracketsIfNeeded(numerator);
2439
+ const pos = this.queue.length;
2440
+ const no_wrap = this.appendWithBracketsIfNeeded(numerator);
2441
+ const wrapped = !no_wrap;
2442
+ if (wrapped) {
2443
+ this.queue.splice(pos, 0, SOFT_SPACE);
2444
+ }
2432
2445
  this.queue.push(new TypstToken(2 /* ELEMENT */, "/"));
2433
2446
  this.appendWithBracketsIfNeeded(denominator);
2434
2447
  break;
@@ -2537,17 +2550,17 @@ var TypstWriter = class {
2537
2550
  return !need_to_wrap;
2538
2551
  }
2539
2552
  flushQueue() {
2540
- const SOFT_SPACE = new TypstToken(6 /* CONTROL */, " ");
2553
+ const dummy_token = new TypstToken(1 /* SYMBOL */, "");
2541
2554
  for (let i = 0; i < this.queue.length; i++) {
2542
2555
  let token = this.queue[i];
2543
2556
  if (token.eq(SOFT_SPACE)) {
2544
- if (i === this.queue.length - 1) {
2545
- this.queue[i].value = "";
2546
- } else if (this.queue[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS, TYPST_COMMA, TYPST_NEWLINE])) {
2547
- this.queue[i].value = "";
2557
+ const to_delete = i === 0 || i === this.queue.length - 1 || this.queue[i - 1].type === 5 /* SPACE */ || this.queue[i - 1].isOneOf([TYPST_LEFT_PARENTHESIS, TYPST_NEWLINE]) || this.queue[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS, TYPST_COMMA, TYPST_NEWLINE]);
2558
+ if (to_delete) {
2559
+ this.queue[i] = dummy_token;
2548
2560
  }
2549
2561
  }
2550
2562
  }
2563
+ this.queue = this.queue.filter((token) => !token.eq(dummy_token));
2551
2564
  this.queue.forEach((token) => {
2552
2565
  this.writeBuffer(token);
2553
2566
  });
@@ -2581,7 +2594,7 @@ var TypstWriter = class {
2581
2594
  };
2582
2595
 
2583
2596
  // src/convert.ts
2584
- var TYPST_INTRINSIC_SYMBOLS = [
2597
+ var TYPST_INTRINSIC_OP = [
2585
2598
  "dim",
2586
2599
  "id",
2587
2600
  "im",
@@ -2795,9 +2808,6 @@ function convert_tex_node_to_typst(node, options = {}) {
2795
2808
  [inner]
2796
2809
  );
2797
2810
  }
2798
- if (node.content === "\\mathbb" && arg0.type === "atom" && /^[A-Z]$/.test(arg0.content)) {
2799
- return new TypstNode("symbol", arg0.content + arg0.content);
2800
- }
2801
2811
  if (node.content === "\\overrightarrow") {
2802
2812
  return new TypstNode(
2803
2813
  "funcCall",
@@ -2813,16 +2823,12 @@ function convert_tex_node_to_typst(node, options = {}) {
2813
2823
  );
2814
2824
  }
2815
2825
  if (node.content === "\\operatorname") {
2816
- const text = arg0.content;
2817
- if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
2818
- return new TypstNode("symbol", text);
2819
- } else {
2820
- return new TypstNode(
2821
- "funcCall",
2822
- "op",
2823
- [arg0]
2824
- );
2826
+ if (options.optimize) {
2827
+ if (TYPST_INTRINSIC_OP.includes(arg0.content)) {
2828
+ return new TypstNode("symbol", arg0.content);
2829
+ }
2825
2830
  }
2831
+ return new TypstNode("funcCall", "op", [arg0]);
2826
2832
  }
2827
2833
  if (node.content === "\\hspace") {
2828
2834
  const text = arg0.content;
@@ -2832,6 +2838,14 @@ function convert_tex_node_to_typst(node, options = {}) {
2832
2838
  [new TypstNode("symbol", text)]
2833
2839
  );
2834
2840
  }
2841
+ if (options.optimize) {
2842
+ if (node.content === "\\mathbb" && arg0.type === "atom" && /^[A-Z]$/.test(arg0.content)) {
2843
+ return new TypstNode("symbol", arg0.content + arg0.content);
2844
+ }
2845
+ if (node.content === "\\mathrm" && arg0.eq(new TypstNode("atom", "d"))) {
2846
+ return new TypstNode("symbol", "dif");
2847
+ }
2848
+ }
2835
2849
  return new TypstNode(
2836
2850
  "funcCall",
2837
2851
  tex_token_to_typst(node.content),
@@ -3191,15 +3205,8 @@ function convert_typst_node_to_tex(node) {
3191
3205
  }
3192
3206
  }
3193
3207
 
3194
- // src/typst-parser.ts
3208
+ // src/typst-tokenizer.ts
3195
3209
  var TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
3196
- function eat_primes2(tokens, start) {
3197
- let pos = start;
3198
- while (pos < tokens.length && tokens[pos].eq(new TypstToken(2 /* ELEMENT */, "'"))) {
3199
- pos += 1;
3200
- }
3201
- return pos - start;
3202
- }
3203
3210
  function generate_regex_for_shorthands() {
3204
3211
  const regex_list = TYPST_SHORTHANDS.map((s) => {
3205
3212
  s = s.replaceAll("|", "\\|");
@@ -3263,6 +3270,15 @@ function tokenize_typst(input) {
3263
3270
  const lexer = new JSLex(spec2);
3264
3271
  return lexer.collect(input);
3265
3272
  }
3273
+
3274
+ // src/typst-parser.ts
3275
+ function eat_primes2(tokens, start) {
3276
+ let pos = start;
3277
+ while (pos < tokens.length && tokens[pos].eq(new TypstToken(2 /* ELEMENT */, "'"))) {
3278
+ pos += 1;
3279
+ }
3280
+ return pos - start;
3281
+ }
3266
3282
  function _find_closing_match(tokens, start, leftBrackets, rightBrackets) {
3267
3283
  assert(tokens[start].isOneOf(leftBrackets));
3268
3284
  let count = 1;
@@ -3733,7 +3749,6 @@ var TexWriter = class {
3733
3749
  function tex2typst(tex, options) {
3734
3750
  const opt = {
3735
3751
  nonStrict: true,
3736
- preferTypstIntrinsic: true,
3737
3752
  preferShorthands: true,
3738
3753
  keepSpaces: false,
3739
3754
  fracToSlash: true,
@@ -1,5 +1,4 @@
1
1
  import { TexNode, TexToken } from "./types";
2
- export declare function tokenize_tex(input: string): TexToken[];
3
2
  export declare class LatexParserError extends Error {
4
3
  constructor(message: string);
5
4
  }
@@ -0,0 +1,4 @@
1
+ import { TexToken } from "./types";
2
+ export declare const TEX_UNARY_COMMANDS: string[];
3
+ export declare const TEX_BINARY_COMMANDS: string[];
4
+ export declare function tokenize_tex(input: string): TexToken[];