tex2typst 0.3.18 → 0.3.19

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
@@ -1633,8 +1633,8 @@ var JSLex = class {
1633
1633
  }
1634
1634
  };
1635
1635
 
1636
- // src/tex-parser.ts
1637
- var UNARY_COMMANDS = [
1636
+ // src/tex-tokenizer.ts
1637
+ var TEX_UNARY_COMMANDS = [
1638
1638
  "sqrt",
1639
1639
  "text",
1640
1640
  "bar",
@@ -1667,7 +1667,7 @@ var UNARY_COMMANDS = [
1667
1667
  "overrightarrow",
1668
1668
  "hspace"
1669
1669
  ];
1670
- var BINARY_COMMANDS = [
1670
+ var TEX_BINARY_COMMANDS = [
1671
1671
  "frac",
1672
1672
  "tfrac",
1673
1673
  "binom",
@@ -1677,81 +1677,6 @@ var BINARY_COMMANDS = [
1677
1677
  "overset",
1678
1678
  "underset"
1679
1679
  ];
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
1680
  function unescape(str) {
1756
1681
  const chars = ["{", "}", "\\", "$", "&", "#", "_", "%"];
1757
1682
  for (const char of chars) {
@@ -1780,13 +1705,14 @@ var rules_map = /* @__PURE__ */ new Map([
1780
1705
  [String.raw`\r?\n`, (_s) => new TexToken(5 /* NEWLINE */, "\n")],
1781
1706
  [String.raw`\s+`, (s) => new TexToken(4 /* SPACE */, s.text())],
1782
1707
  [String.raw`\\[{}%$&#_|]`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
1708
+ // e.g. match `\frac13`, `\frac1 b`, `\frac a b`
1783
1709
  [String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])\s*([0-9a-zA-Z])`, (s) => {
1784
1710
  const text = s.text();
1785
1711
  const regex = RegExp(String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])\s*([0-9a-zA-Z])`);
1786
1712
  const match = text.match(regex);
1787
1713
  assert(match !== null);
1788
1714
  const command = match[1];
1789
- if (BINARY_COMMANDS.includes(command.substring(1))) {
1715
+ if (TEX_BINARY_COMMANDS.includes(command.substring(1))) {
1790
1716
  const arg1 = match[2].trimStart();
1791
1717
  const arg2 = match[3];
1792
1718
  return [
@@ -1799,13 +1725,14 @@ var rules_map = /* @__PURE__ */ new Map([
1799
1725
  return [];
1800
1726
  }
1801
1727
  }],
1728
+ // e.g. match `\sqrt3`, `\sqrt a`
1802
1729
  [String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`, (s) => {
1803
1730
  const text = s.text();
1804
1731
  const regex = RegExp(String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`);
1805
1732
  const match = text.match(regex);
1806
1733
  assert(match !== null);
1807
1734
  const command = match[1];
1808
- if (UNARY_COMMANDS.includes(command.substring(1))) {
1735
+ if (TEX_UNARY_COMMANDS.includes(command.substring(1))) {
1809
1736
  const arg1 = match[2].trimStart();
1810
1737
  return [
1811
1738
  new TexToken(1 /* COMMAND */, command),
@@ -1835,6 +1762,83 @@ function tokenize_tex(input) {
1835
1762
  const lexer = new JSLex(spec);
1836
1763
  return lexer.collect(input);
1837
1764
  }
1765
+
1766
+ // src/tex-parser.ts
1767
+ var IGNORED_COMMANDS = [
1768
+ "bigl",
1769
+ "bigr",
1770
+ "biggl",
1771
+ "biggr",
1772
+ "Bigl",
1773
+ "Bigr",
1774
+ "Biggl",
1775
+ "Biggr"
1776
+ ];
1777
+ var EMPTY_NODE = new TexNode("empty", "");
1778
+ function get_command_param_num(command) {
1779
+ if (TEX_UNARY_COMMANDS.includes(command)) {
1780
+ return 1;
1781
+ } else if (TEX_BINARY_COMMANDS.includes(command)) {
1782
+ return 2;
1783
+ } else {
1784
+ return 0;
1785
+ }
1786
+ }
1787
+ var LEFT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "{");
1788
+ var RIGHT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "}");
1789
+ var LEFT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "[");
1790
+ var RIGHT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "]");
1791
+ function eat_whitespaces(tokens, start) {
1792
+ let pos = start;
1793
+ while (pos < tokens.length && [4 /* SPACE */, 5 /* NEWLINE */].includes(tokens[pos].type)) {
1794
+ pos++;
1795
+ }
1796
+ return tokens.slice(start, pos);
1797
+ }
1798
+ function eat_parenthesis(tokens, start) {
1799
+ const firstToken = tokens[start];
1800
+ if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}", ".", "\\|"].includes(firstToken.value)) {
1801
+ return firstToken;
1802
+ } else if (firstToken.type === 1 /* COMMAND */ && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
1803
+ return firstToken;
1804
+ } else {
1805
+ return null;
1806
+ }
1807
+ }
1808
+ function eat_primes(tokens, start) {
1809
+ let pos = start;
1810
+ while (pos < tokens.length && tokens[pos].eq(new TexToken(0 /* ELEMENT */, "'"))) {
1811
+ pos += 1;
1812
+ }
1813
+ return pos - start;
1814
+ }
1815
+ function find_closing_match(tokens, start, leftToken, rightToken) {
1816
+ assert(tokens[start].eq(leftToken));
1817
+ let count = 1;
1818
+ let pos = start + 1;
1819
+ while (count > 0) {
1820
+ if (pos >= tokens.length) {
1821
+ return -1;
1822
+ }
1823
+ if (tokens[pos].eq(leftToken)) {
1824
+ count += 1;
1825
+ } else if (tokens[pos].eq(rightToken)) {
1826
+ count -= 1;
1827
+ }
1828
+ pos += 1;
1829
+ }
1830
+ return pos - 1;
1831
+ }
1832
+ var LEFT_COMMAND = new TexToken(1 /* COMMAND */, "\\left");
1833
+ var RIGHT_COMMAND = new TexToken(1 /* COMMAND */, "\\right");
1834
+ function find_closing_right_command(tokens, start) {
1835
+ return find_closing_match(tokens, start, LEFT_COMMAND, RIGHT_COMMAND);
1836
+ }
1837
+ var BEGIN_COMMAND = new TexToken(1 /* COMMAND */, "\\begin");
1838
+ var END_COMMAND = new TexToken(1 /* COMMAND */, "\\end");
1839
+ function find_closing_end_command(tokens, start) {
1840
+ return find_closing_match(tokens, start, BEGIN_COMMAND, END_COMMAND);
1841
+ }
1838
1842
  var LatexParserError = class extends Error {
1839
1843
  constructor(message) {
1840
1844
  super(message);
@@ -2274,6 +2278,7 @@ var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
2274
2278
  var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
2275
2279
  var TYPST_COMMA = new TypstToken(2 /* ELEMENT */, ",");
2276
2280
  var TYPST_NEWLINE = new TypstToken(1 /* SYMBOL */, "\n");
2281
+ var SOFT_SPACE = new TypstToken(6 /* CONTROL */, " ");
2277
2282
  function typst_primitive_to_string(value) {
2278
2283
  switch (typeof value) {
2279
2284
  case "string":
@@ -2397,7 +2402,7 @@ var TypstWriter = class {
2397
2402
  trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
2398
2403
  }
2399
2404
  if (trailing_space_needed) {
2400
- this.queue.push(new TypstToken(6 /* CONTROL */, " "));
2405
+ this.queue.push(SOFT_SPACE);
2401
2406
  }
2402
2407
  break;
2403
2408
  }
@@ -2428,7 +2433,12 @@ var TypstWriter = class {
2428
2433
  }
2429
2434
  case "fraction": {
2430
2435
  const [numerator, denominator] = node.args;
2431
- this.appendWithBracketsIfNeeded(numerator);
2436
+ const pos = this.queue.length;
2437
+ const no_wrap = this.appendWithBracketsIfNeeded(numerator);
2438
+ const wrapped = !no_wrap;
2439
+ if (wrapped) {
2440
+ this.queue.splice(pos, 0, SOFT_SPACE);
2441
+ }
2432
2442
  this.queue.push(new TypstToken(2 /* ELEMENT */, "/"));
2433
2443
  this.appendWithBracketsIfNeeded(denominator);
2434
2444
  break;
@@ -2537,17 +2547,17 @@ var TypstWriter = class {
2537
2547
  return !need_to_wrap;
2538
2548
  }
2539
2549
  flushQueue() {
2540
- const SOFT_SPACE = new TypstToken(6 /* CONTROL */, " ");
2550
+ const dummy_token = new TypstToken(1 /* SYMBOL */, "");
2541
2551
  for (let i = 0; i < this.queue.length; i++) {
2542
2552
  let token = this.queue[i];
2543
2553
  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 = "";
2554
+ const to_delete = i === 0 || i === this.queue.length - 1 || this.queue[i - 1].isOneOf([TYPST_NEWLINE]) || this.queue[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS, TYPST_COMMA, TYPST_NEWLINE]);
2555
+ if (to_delete) {
2556
+ this.queue[i] = dummy_token;
2548
2557
  }
2549
2558
  }
2550
2559
  }
2560
+ this.queue = this.queue.filter((token) => !token.eq(dummy_token));
2551
2561
  this.queue.forEach((token) => {
2552
2562
  this.writeBuffer(token);
2553
2563
  });
@@ -2813,16 +2823,13 @@ 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
+ const text = arg0.content;
2828
+ if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
2829
+ return new TypstNode("symbol", text);
2830
+ }
2825
2831
  }
2832
+ return new TypstNode("funcCall", "op", [arg0]);
2826
2833
  }
2827
2834
  if (node.content === "\\hspace") {
2828
2835
  const text = arg0.content;
@@ -3191,15 +3198,8 @@ function convert_typst_node_to_tex(node) {
3191
3198
  }
3192
3199
  }
3193
3200
 
3194
- // src/typst-parser.ts
3201
+ // src/typst-tokenizer.ts
3195
3202
  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
3203
  function generate_regex_for_shorthands() {
3204
3204
  const regex_list = TYPST_SHORTHANDS.map((s) => {
3205
3205
  s = s.replaceAll("|", "\\|");
@@ -3263,6 +3263,15 @@ function tokenize_typst(input) {
3263
3263
  const lexer = new JSLex(spec2);
3264
3264
  return lexer.collect(input);
3265
3265
  }
3266
+
3267
+ // src/typst-parser.ts
3268
+ function eat_primes2(tokens, start) {
3269
+ let pos = start;
3270
+ while (pos < tokens.length && tokens[pos].eq(new TypstToken(2 /* ELEMENT */, "'"))) {
3271
+ pos += 1;
3272
+ }
3273
+ return pos - start;
3274
+ }
3266
3275
  function _find_closing_match(tokens, start, leftBrackets, rightBrackets) {
3267
3276
  assert(tokens[start].isOneOf(leftBrackets));
3268
3277
  let count = 1;
@@ -3733,7 +3742,6 @@ var TexWriter = class {
3733
3742
  function tex2typst(tex, options) {
3734
3743
  const opt = {
3735
3744
  nonStrict: true,
3736
- preferTypstIntrinsic: true,
3737
3745
  preferShorthands: true,
3738
3746
  keepSpaces: false,
3739
3747
  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[];