tex2typst 0.3.0-alpha → 0.3.0-beta-1
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 +397 -372
- package/dist/tex2typst.min.js +19 -1
- package/package.json +1 -1
- package/src/tex-parser.ts +1 -1
- package/src/writer.ts +9 -0
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ var symbolMap = new Map([
|
|
|
42
42
|
["approx", "approx"],
|
|
43
43
|
["cong", "tilde.equiv"],
|
|
44
44
|
["simeq", "tilde.eq"],
|
|
45
|
-
["asymp", "
|
|
45
|
+
["asymp", "≍"],
|
|
46
46
|
["equiv", "equiv"],
|
|
47
47
|
["propto", "prop"],
|
|
48
48
|
["gets", "arrow.l"],
|
|
@@ -1027,12 +1027,6 @@ function array_split(array, sep) {
|
|
|
1027
1027
|
}
|
|
1028
1028
|
|
|
1029
1029
|
// src/types.ts
|
|
1030
|
-
function apply_escape_if_needed(c) {
|
|
1031
|
-
if (["{", "}", "%"].includes(c)) {
|
|
1032
|
-
return "\\" + c;
|
|
1033
|
-
}
|
|
1034
|
-
return c;
|
|
1035
|
-
}
|
|
1036
1030
|
class TexToken {
|
|
1037
1031
|
type;
|
|
1038
1032
|
value;
|
|
@@ -1054,6 +1048,12 @@ class TexToken {
|
|
|
1054
1048
|
}
|
|
1055
1049
|
}
|
|
1056
1050
|
}
|
|
1051
|
+
function apply_escape_if_needed(c) {
|
|
1052
|
+
if (["{", "}", "%"].includes(c)) {
|
|
1053
|
+
return "\\" + c;
|
|
1054
|
+
}
|
|
1055
|
+
return c;
|
|
1056
|
+
}
|
|
1057
1057
|
|
|
1058
1058
|
class TexNode {
|
|
1059
1059
|
type;
|
|
@@ -1166,7 +1166,8 @@ class TexNode {
|
|
|
1166
1166
|
let tokens = [];
|
|
1167
1167
|
const matrix = this.data;
|
|
1168
1168
|
tokens.push(new TexToken(1 /* COMMAND */, `\\begin{${this.content}}`));
|
|
1169
|
-
tokens.push(new TexToken(5 /* NEWLINE */,
|
|
1169
|
+
tokens.push(new TexToken(5 /* NEWLINE */, `
|
|
1170
|
+
`));
|
|
1170
1171
|
for (let i = 0;i < matrix.length; i++) {
|
|
1171
1172
|
const row = matrix[i];
|
|
1172
1173
|
for (let j = 0;j < row.length; j++) {
|
|
@@ -1180,7 +1181,8 @@ class TexNode {
|
|
|
1180
1181
|
tokens.push(new TexToken(6 /* CONTROL */, "\\\\"));
|
|
1181
1182
|
}
|
|
1182
1183
|
}
|
|
1183
|
-
tokens.push(new TexToken(5 /* NEWLINE */,
|
|
1184
|
+
tokens.push(new TexToken(5 /* NEWLINE */, `
|
|
1185
|
+
`));
|
|
1184
1186
|
tokens.push(new TexToken(1 /* COMMAND */, `\\end{${this.content}}`));
|
|
1185
1187
|
return tokens;
|
|
1186
1188
|
}
|
|
@@ -1280,6 +1282,46 @@ function assert(condition, message = "") {
|
|
|
1280
1282
|
}
|
|
1281
1283
|
|
|
1282
1284
|
// src/tex-parser.ts
|
|
1285
|
+
var UNARY_COMMANDS = [
|
|
1286
|
+
"sqrt",
|
|
1287
|
+
"text",
|
|
1288
|
+
"bar",
|
|
1289
|
+
"bold",
|
|
1290
|
+
"boldsymbol",
|
|
1291
|
+
"ddot",
|
|
1292
|
+
"dot",
|
|
1293
|
+
"hat",
|
|
1294
|
+
"mathbb",
|
|
1295
|
+
"mathbf",
|
|
1296
|
+
"mathcal",
|
|
1297
|
+
"mathfrak",
|
|
1298
|
+
"mathit",
|
|
1299
|
+
"mathrm",
|
|
1300
|
+
"mathscr",
|
|
1301
|
+
"mathsf",
|
|
1302
|
+
"mathtt",
|
|
1303
|
+
"operatorname",
|
|
1304
|
+
"overbrace",
|
|
1305
|
+
"overline",
|
|
1306
|
+
"pmb",
|
|
1307
|
+
"rm",
|
|
1308
|
+
"tilde",
|
|
1309
|
+
"underbrace",
|
|
1310
|
+
"underline",
|
|
1311
|
+
"vec",
|
|
1312
|
+
"widehat",
|
|
1313
|
+
"widetilde"
|
|
1314
|
+
];
|
|
1315
|
+
var BINARY_COMMANDS = [
|
|
1316
|
+
"frac",
|
|
1317
|
+
"tfrac",
|
|
1318
|
+
"binom",
|
|
1319
|
+
"dbinom",
|
|
1320
|
+
"dfrac",
|
|
1321
|
+
"tbinom",
|
|
1322
|
+
"overset"
|
|
1323
|
+
];
|
|
1324
|
+
var EMPTY_NODE = new TexNode("empty", "");
|
|
1283
1325
|
function get_command_param_num(command) {
|
|
1284
1326
|
if (UNARY_COMMANDS.includes(command)) {
|
|
1285
1327
|
return 1;
|
|
@@ -1289,6 +1331,10 @@ function get_command_param_num(command) {
|
|
|
1289
1331
|
return 0;
|
|
1290
1332
|
}
|
|
1291
1333
|
}
|
|
1334
|
+
var LEFT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "{");
|
|
1335
|
+
var RIGHT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "}");
|
|
1336
|
+
var LEFT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "[");
|
|
1337
|
+
var RIGHT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "]");
|
|
1292
1338
|
function eat_whitespaces(tokens, start) {
|
|
1293
1339
|
let pos = start;
|
|
1294
1340
|
while (pos < tokens.length && [4 /* SPACE */, 5 /* NEWLINE */].includes(tokens[pos].type)) {
|
|
@@ -1298,7 +1344,7 @@ function eat_whitespaces(tokens, start) {
|
|
|
1298
1344
|
}
|
|
1299
1345
|
function eat_parenthesis(tokens, start) {
|
|
1300
1346
|
const firstToken = tokens[start];
|
|
1301
|
-
if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}"].includes(firstToken.value)) {
|
|
1347
|
+
if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}", "."].includes(firstToken.value)) {
|
|
1302
1348
|
return firstToken;
|
|
1303
1349
|
} else if (firstToken.type === 1 /* COMMAND */ && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
|
|
1304
1350
|
return firstToken;
|
|
@@ -1337,9 +1383,13 @@ function find_closing_match(tokens, start, leftToken, rightToken) {
|
|
|
1337
1383
|
}
|
|
1338
1384
|
return pos - 1;
|
|
1339
1385
|
}
|
|
1386
|
+
var LEFT_COMMAND = new TexToken(1 /* COMMAND */, "\\left");
|
|
1387
|
+
var RIGHT_COMMAND = new TexToken(1 /* COMMAND */, "\\right");
|
|
1340
1388
|
function find_closing_right_command(tokens, start) {
|
|
1341
1389
|
return find_closing_match(tokens, start, LEFT_COMMAND, RIGHT_COMMAND);
|
|
1342
1390
|
}
|
|
1391
|
+
var BEGIN_COMMAND = new TexToken(1 /* COMMAND */, "\\begin");
|
|
1392
|
+
var END_COMMAND = new TexToken(1 /* COMMAND */, "\\end");
|
|
1343
1393
|
function find_closing_end_command(tokens, start) {
|
|
1344
1394
|
return find_closing_match(tokens, start, BEGIN_COMMAND, END_COMMAND);
|
|
1345
1395
|
}
|
|
@@ -1373,7 +1423,8 @@ function tokenize(latex) {
|
|
|
1373
1423
|
switch (firstChar) {
|
|
1374
1424
|
case "%": {
|
|
1375
1425
|
let newPos = pos + 1;
|
|
1376
|
-
while (newPos < latex.length && latex[newPos] !==
|
|
1426
|
+
while (newPos < latex.length && latex[newPos] !== `
|
|
1427
|
+
`) {
|
|
1377
1428
|
newPos += 1;
|
|
1378
1429
|
}
|
|
1379
1430
|
token = new TexToken(3 /* COMMENT */, latex.slice(pos + 1, newPos));
|
|
@@ -1388,16 +1439,20 @@ function tokenize(latex) {
|
|
|
1388
1439
|
token = new TexToken(6 /* CONTROL */, firstChar);
|
|
1389
1440
|
pos++;
|
|
1390
1441
|
break;
|
|
1391
|
-
case
|
|
1442
|
+
case `
|
|
1443
|
+
`:
|
|
1392
1444
|
token = new TexToken(5 /* NEWLINE */, firstChar);
|
|
1393
1445
|
pos++;
|
|
1394
1446
|
break;
|
|
1395
1447
|
case "\r": {
|
|
1396
|
-
if (pos + 1 < latex.length && latex[pos + 1] ===
|
|
1397
|
-
|
|
1448
|
+
if (pos + 1 < latex.length && latex[pos + 1] === `
|
|
1449
|
+
`) {
|
|
1450
|
+
token = new TexToken(5 /* NEWLINE */, `
|
|
1451
|
+
`);
|
|
1398
1452
|
pos += 2;
|
|
1399
1453
|
} else {
|
|
1400
|
-
token = new TexToken(5 /* NEWLINE */,
|
|
1454
|
+
token = new TexToken(5 /* NEWLINE */, `
|
|
1455
|
+
`);
|
|
1401
1456
|
pos++;
|
|
1402
1457
|
}
|
|
1403
1458
|
break;
|
|
@@ -1436,7 +1491,7 @@ function tokenize(latex) {
|
|
|
1436
1491
|
token = new TexToken(0 /* ELEMENT */, latex.slice(pos, newPos));
|
|
1437
1492
|
} else if (isalpha(firstChar)) {
|
|
1438
1493
|
token = new TexToken(0 /* ELEMENT */, firstChar);
|
|
1439
|
-
} else if ("
|
|
1494
|
+
} else if ("+-*/='<>!.,;?()[]|".includes(firstChar)) {
|
|
1440
1495
|
token = new TexToken(0 /* ELEMENT */, firstChar);
|
|
1441
1496
|
} else {
|
|
1442
1497
|
token = new TexToken(7 /* UNKNOWN */, firstChar);
|
|
@@ -1464,87 +1519,6 @@ function tokenize(latex) {
|
|
|
1464
1519
|
}
|
|
1465
1520
|
return tokens;
|
|
1466
1521
|
}
|
|
1467
|
-
function passIgnoreWhitespaceBeforeScriptMark(tokens) {
|
|
1468
|
-
const is_script_mark = (token) => token.eq(SUB_SYMBOL) || token.eq(SUP_SYMBOL);
|
|
1469
|
-
let out_tokens = [];
|
|
1470
|
-
for (let i = 0;i < tokens.length; i++) {
|
|
1471
|
-
if (tokens[i].type === 4 /* SPACE */ && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
|
|
1472
|
-
continue;
|
|
1473
|
-
}
|
|
1474
|
-
if (tokens[i].type === 4 /* SPACE */ && i - 1 >= 0 && is_script_mark(tokens[i - 1])) {
|
|
1475
|
-
continue;
|
|
1476
|
-
}
|
|
1477
|
-
out_tokens.push(tokens[i]);
|
|
1478
|
-
}
|
|
1479
|
-
return out_tokens;
|
|
1480
|
-
}
|
|
1481
|
-
function passExpandCustomTexMacros(tokens, customTexMacros) {
|
|
1482
|
-
let out_tokens = [];
|
|
1483
|
-
for (const token of tokens) {
|
|
1484
|
-
if (token.type === 1 /* COMMAND */ && customTexMacros[token.value]) {
|
|
1485
|
-
const expanded_tokens = tokenize(customTexMacros[token.value]);
|
|
1486
|
-
out_tokens = out_tokens.concat(expanded_tokens);
|
|
1487
|
-
} else {
|
|
1488
|
-
out_tokens.push(token);
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
return out_tokens;
|
|
1492
|
-
}
|
|
1493
|
-
function parseTex(tex, customTexMacros) {
|
|
1494
|
-
const parser = new LatexParser;
|
|
1495
|
-
let tokens = tokenize(tex);
|
|
1496
|
-
tokens = passIgnoreWhitespaceBeforeScriptMark(tokens);
|
|
1497
|
-
tokens = passExpandCustomTexMacros(tokens, customTexMacros);
|
|
1498
|
-
return parser.parse(tokens);
|
|
1499
|
-
}
|
|
1500
|
-
var UNARY_COMMANDS = [
|
|
1501
|
-
"sqrt",
|
|
1502
|
-
"text",
|
|
1503
|
-
"bar",
|
|
1504
|
-
"bold",
|
|
1505
|
-
"boldsymbol",
|
|
1506
|
-
"ddot",
|
|
1507
|
-
"dot",
|
|
1508
|
-
"hat",
|
|
1509
|
-
"mathbb",
|
|
1510
|
-
"mathbf",
|
|
1511
|
-
"mathcal",
|
|
1512
|
-
"mathfrak",
|
|
1513
|
-
"mathit",
|
|
1514
|
-
"mathrm",
|
|
1515
|
-
"mathscr",
|
|
1516
|
-
"mathsf",
|
|
1517
|
-
"mathtt",
|
|
1518
|
-
"operatorname",
|
|
1519
|
-
"overbrace",
|
|
1520
|
-
"overline",
|
|
1521
|
-
"pmb",
|
|
1522
|
-
"rm",
|
|
1523
|
-
"tilde",
|
|
1524
|
-
"underbrace",
|
|
1525
|
-
"underline",
|
|
1526
|
-
"vec",
|
|
1527
|
-
"widehat",
|
|
1528
|
-
"widetilde"
|
|
1529
|
-
];
|
|
1530
|
-
var BINARY_COMMANDS = [
|
|
1531
|
-
"frac",
|
|
1532
|
-
"tfrac",
|
|
1533
|
-
"binom",
|
|
1534
|
-
"dbinom",
|
|
1535
|
-
"dfrac",
|
|
1536
|
-
"tbinom",
|
|
1537
|
-
"overset"
|
|
1538
|
-
];
|
|
1539
|
-
var EMPTY_NODE = new TexNode("empty", "");
|
|
1540
|
-
var LEFT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "{");
|
|
1541
|
-
var RIGHT_CURLY_BRACKET = new TexToken(6 /* CONTROL */, "}");
|
|
1542
|
-
var LEFT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "[");
|
|
1543
|
-
var RIGHT_SQUARE_BRACKET = new TexToken(0 /* ELEMENT */, "]");
|
|
1544
|
-
var LEFT_COMMAND = new TexToken(1 /* COMMAND */, "\\left");
|
|
1545
|
-
var RIGHT_COMMAND = new TexToken(1 /* COMMAND */, "\\right");
|
|
1546
|
-
var BEGIN_COMMAND = new TexToken(1 /* COMMAND */, "\\begin");
|
|
1547
|
-
var END_COMMAND = new TexToken(1 /* COMMAND */, "\\end");
|
|
1548
1522
|
|
|
1549
1523
|
class LatexParserError extends Error {
|
|
1550
1524
|
constructor(message) {
|
|
@@ -1575,7 +1549,8 @@ class LatexParser {
|
|
|
1575
1549
|
if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
|
|
1576
1550
|
continue;
|
|
1577
1551
|
}
|
|
1578
|
-
if (!this.newline_sensitive && res.content ===
|
|
1552
|
+
if (!this.newline_sensitive && res.content === `
|
|
1553
|
+
`) {
|
|
1579
1554
|
continue;
|
|
1580
1555
|
}
|
|
1581
1556
|
}
|
|
@@ -1826,7 +1801,8 @@ class LatexParser {
|
|
|
1826
1801
|
if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
|
|
1827
1802
|
continue;
|
|
1828
1803
|
}
|
|
1829
|
-
if (!this.newline_sensitive && res.content ===
|
|
1804
|
+
if (!this.newline_sensitive && res.content === `
|
|
1805
|
+
`) {
|
|
1830
1806
|
continue;
|
|
1831
1807
|
}
|
|
1832
1808
|
}
|
|
@@ -1845,10 +1821,52 @@ class LatexParser {
|
|
|
1845
1821
|
return allRows;
|
|
1846
1822
|
}
|
|
1847
1823
|
}
|
|
1824
|
+
function passIgnoreWhitespaceBeforeScriptMark(tokens) {
|
|
1825
|
+
const is_script_mark = (token) => token.eq(SUB_SYMBOL) || token.eq(SUP_SYMBOL);
|
|
1826
|
+
let out_tokens = [];
|
|
1827
|
+
for (let i = 0;i < tokens.length; i++) {
|
|
1828
|
+
if (tokens[i].type === 4 /* SPACE */ && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
if (tokens[i].type === 4 /* SPACE */ && i - 1 >= 0 && is_script_mark(tokens[i - 1])) {
|
|
1832
|
+
continue;
|
|
1833
|
+
}
|
|
1834
|
+
out_tokens.push(tokens[i]);
|
|
1835
|
+
}
|
|
1836
|
+
return out_tokens;
|
|
1837
|
+
}
|
|
1838
|
+
function passExpandCustomTexMacros(tokens, customTexMacros) {
|
|
1839
|
+
let out_tokens = [];
|
|
1840
|
+
for (const token of tokens) {
|
|
1841
|
+
if (token.type === 1 /* COMMAND */ && customTexMacros[token.value]) {
|
|
1842
|
+
const expanded_tokens = tokenize(customTexMacros[token.value]);
|
|
1843
|
+
out_tokens = out_tokens.concat(expanded_tokens);
|
|
1844
|
+
} else {
|
|
1845
|
+
out_tokens.push(token);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
return out_tokens;
|
|
1849
|
+
}
|
|
1850
|
+
function parseTex(tex, customTexMacros) {
|
|
1851
|
+
const parser = new LatexParser;
|
|
1852
|
+
let tokens = tokenize(tex);
|
|
1853
|
+
tokens = passIgnoreWhitespaceBeforeScriptMark(tokens);
|
|
1854
|
+
tokens = passExpandCustomTexMacros(tokens, customTexMacros);
|
|
1855
|
+
return parser.parse(tokens);
|
|
1856
|
+
}
|
|
1848
1857
|
|
|
1849
1858
|
// src/writer.ts
|
|
1859
|
+
var TYPST_INTRINSIC_SYMBOLS = [
|
|
1860
|
+
"dim",
|
|
1861
|
+
"id",
|
|
1862
|
+
"im",
|
|
1863
|
+
"mod",
|
|
1864
|
+
"Pr",
|
|
1865
|
+
"sech",
|
|
1866
|
+
"csch"
|
|
1867
|
+
];
|
|
1850
1868
|
function is_delimiter(c) {
|
|
1851
|
-
return c.type === "atom" && ["(", ")", "[", "]", "{", "}", "|", "
|
|
1869
|
+
return c.type === "atom" && ["(", ")", "[", "]", "{", "}", "|", "⌊", "⌋", "⌈", "⌉"].includes(c.content);
|
|
1852
1870
|
}
|
|
1853
1871
|
function convert_overset(node) {
|
|
1854
1872
|
const [sup, base] = node.args;
|
|
@@ -1878,178 +1896,37 @@ function convert_overset(node) {
|
|
|
1878
1896
|
sup: convertTree(sup)
|
|
1879
1897
|
});
|
|
1880
1898
|
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
}
|
|
1913
|
-
if (sub) {
|
|
1914
|
-
data.sub = convertTree(sub);
|
|
1915
|
-
}
|
|
1916
|
-
return new TypstNode("supsub", "", [], data);
|
|
1917
|
-
}
|
|
1918
|
-
case "leftright": {
|
|
1919
|
-
const [left, body, right] = node.args;
|
|
1920
|
-
const group = new TypstNode("group", "", node.args.map(convertTree));
|
|
1921
|
-
if ([
|
|
1922
|
-
"[]",
|
|
1923
|
-
"()",
|
|
1924
|
-
"\\{\\}",
|
|
1925
|
-
"\\lfloor\\rfloor",
|
|
1926
|
-
"\\lceil\\rceil",
|
|
1927
|
-
"\\lfloor\\rceil"
|
|
1928
|
-
].includes(left.content + right.content)) {
|
|
1929
|
-
return group;
|
|
1930
|
-
}
|
|
1931
|
-
return new TypstNode("funcCall", "lr", [group]);
|
|
1932
|
-
}
|
|
1933
|
-
case "binaryFunc": {
|
|
1934
|
-
if (node.content === "\\overset") {
|
|
1935
|
-
return convert_overset(node);
|
|
1936
|
-
}
|
|
1937
|
-
return new TypstNode("funcCall", convertToken(node.content), node.args.map(convertTree));
|
|
1938
|
-
}
|
|
1939
|
-
case "unaryFunc": {
|
|
1940
|
-
const arg0 = convertTree(node.args[0]);
|
|
1941
|
-
if (node.content === "\\sqrt" && node.data) {
|
|
1942
|
-
const data = convertTree(node.data);
|
|
1943
|
-
return new TypstNode("funcCall", "root", [data, arg0]);
|
|
1944
|
-
}
|
|
1945
|
-
if (node.content === "\\mathbf") {
|
|
1946
|
-
const inner = new TypstNode("funcCall", "bold", [arg0]);
|
|
1947
|
-
return new TypstNode("funcCall", "upright", [inner]);
|
|
1948
|
-
}
|
|
1949
|
-
if (node.content === "\\mathbb" && arg0.type === "atom" && /^[A-Z]$/.test(arg0.content)) {
|
|
1950
|
-
return new TypstNode("symbol", arg0.content + arg0.content);
|
|
1951
|
-
}
|
|
1952
|
-
if (node.content === "\\operatorname") {
|
|
1953
|
-
const body = node.args;
|
|
1954
|
-
if (body.length !== 1 || body[0].type !== "text") {
|
|
1955
|
-
throw new TypstWriterError(`Expecting body of \\operatorname to be text but got`, node);
|
|
1956
|
-
}
|
|
1957
|
-
const text = body[0].content;
|
|
1958
|
-
if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
|
|
1959
|
-
return new TypstNode("symbol", text);
|
|
1960
|
-
} else {
|
|
1961
|
-
return new TypstNode("funcCall", "op", [new TypstNode("text", text)]);
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
return new TypstNode("funcCall", convertToken(node.content), node.args.map(convertTree));
|
|
1965
|
-
}
|
|
1966
|
-
case "beginend": {
|
|
1967
|
-
const matrix = node.data;
|
|
1968
|
-
const data = matrix.map((row) => row.map(convertTree));
|
|
1969
|
-
if (node.content.startsWith("align")) {
|
|
1970
|
-
return new TypstNode("align", "", [], data);
|
|
1971
|
-
} else {
|
|
1972
|
-
const res = new TypstNode("matrix", "", [], data);
|
|
1973
|
-
res.setOptions({ delim: "#none" });
|
|
1974
|
-
return res;
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
case "unknownMacro":
|
|
1978
|
-
return new TypstNode("unknown", convertToken(node.content));
|
|
1979
|
-
case "control":
|
|
1980
|
-
if (node.content === "\\\\") {
|
|
1981
|
-
return new TypstNode("symbol", "\\");
|
|
1982
|
-
} else if (node.content === "\\,") {
|
|
1983
|
-
return new TypstNode("symbol", "thin");
|
|
1984
|
-
} else {
|
|
1985
|
-
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
|
|
1986
|
-
}
|
|
1987
|
-
default:
|
|
1988
|
-
throw new TypstWriterError(`Unimplemented node type: ${node.type}`, node);
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
function convertToken(token) {
|
|
1992
|
-
if (/^[a-zA-Z0-9]$/.test(token)) {
|
|
1993
|
-
return token;
|
|
1994
|
-
} else if (token === "/") {
|
|
1995
|
-
return "\\/";
|
|
1996
|
-
} else if (token === "\\|") {
|
|
1997
|
-
return "parallel";
|
|
1998
|
-
} else if (token === "\\colon") {
|
|
1999
|
-
return ":";
|
|
2000
|
-
} else if (token === "\\\\") {
|
|
2001
|
-
return "\\";
|
|
2002
|
-
} else if (["\\$", "\\#", "\\&", "\\_"].includes(token)) {
|
|
2003
|
-
return token;
|
|
2004
|
-
} else if (token.startsWith("\\")) {
|
|
2005
|
-
const symbol = token.slice(1);
|
|
2006
|
-
if (symbolMap.has(symbol)) {
|
|
2007
|
-
return symbolMap.get(symbol);
|
|
2008
|
-
} else {
|
|
2009
|
-
return symbol;
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
return token;
|
|
2013
|
-
}
|
|
2014
|
-
var TYPST_INTRINSIC_SYMBOLS = [
|
|
2015
|
-
"dim",
|
|
2016
|
-
"id",
|
|
2017
|
-
"im",
|
|
2018
|
-
"mod",
|
|
2019
|
-
"Pr",
|
|
2020
|
-
"sech",
|
|
2021
|
-
"csch"
|
|
2022
|
-
];
|
|
2023
|
-
var TYPST_LEFT_PARENTHESIS = new TypstToken(1 /* ELEMENT */, "(");
|
|
2024
|
-
var TYPST_RIGHT_PARENTHESIS = new TypstToken(1 /* ELEMENT */, ")");
|
|
2025
|
-
var TYPST_COMMA = new TypstToken(1 /* ELEMENT */, ",");
|
|
2026
|
-
var TYPST_NEWLINE = new TypstToken(0 /* SYMBOL */, "\n");
|
|
2027
|
-
|
|
2028
|
-
class TypstWriterError extends Error {
|
|
2029
|
-
node;
|
|
2030
|
-
constructor(message, node) {
|
|
2031
|
-
super(message);
|
|
2032
|
-
this.name = "TypstWriterError";
|
|
2033
|
-
this.node = node;
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
class TypstWriter {
|
|
2038
|
-
nonStrict;
|
|
2039
|
-
preferTypstIntrinsic;
|
|
2040
|
-
keepSpaces;
|
|
2041
|
-
buffer = "";
|
|
2042
|
-
queue = [];
|
|
2043
|
-
insideFunctionDepth = 0;
|
|
2044
|
-
constructor(nonStrict, preferTypstIntrinsic, keepSpaces) {
|
|
2045
|
-
this.nonStrict = nonStrict;
|
|
2046
|
-
this.preferTypstIntrinsic = preferTypstIntrinsic;
|
|
2047
|
-
this.keepSpaces = keepSpaces;
|
|
2048
|
-
}
|
|
2049
|
-
writeBuffer(token) {
|
|
2050
|
-
const str = token.toString();
|
|
2051
|
-
if (str === "") {
|
|
2052
|
-
return;
|
|
1899
|
+
var TYPST_LEFT_PARENTHESIS = new TypstToken(1 /* ELEMENT */, "(");
|
|
1900
|
+
var TYPST_RIGHT_PARENTHESIS = new TypstToken(1 /* ELEMENT */, ")");
|
|
1901
|
+
var TYPST_COMMA = new TypstToken(1 /* ELEMENT */, ",");
|
|
1902
|
+
var TYPST_NEWLINE = new TypstToken(0 /* SYMBOL */, `
|
|
1903
|
+
`);
|
|
1904
|
+
|
|
1905
|
+
class TypstWriterError extends Error {
|
|
1906
|
+
node;
|
|
1907
|
+
constructor(message, node) {
|
|
1908
|
+
super(message);
|
|
1909
|
+
this.name = "TypstWriterError";
|
|
1910
|
+
this.node = node;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
class TypstWriter {
|
|
1915
|
+
nonStrict;
|
|
1916
|
+
preferTypstIntrinsic;
|
|
1917
|
+
keepSpaces;
|
|
1918
|
+
buffer = "";
|
|
1919
|
+
queue = [];
|
|
1920
|
+
insideFunctionDepth = 0;
|
|
1921
|
+
constructor(nonStrict, preferTypstIntrinsic, keepSpaces) {
|
|
1922
|
+
this.nonStrict = nonStrict;
|
|
1923
|
+
this.preferTypstIntrinsic = preferTypstIntrinsic;
|
|
1924
|
+
this.keepSpaces = keepSpaces;
|
|
1925
|
+
}
|
|
1926
|
+
writeBuffer(token) {
|
|
1927
|
+
const str = token.toString();
|
|
1928
|
+
if (str === "") {
|
|
1929
|
+
return;
|
|
2053
1930
|
}
|
|
2054
1931
|
let no_need_space = false;
|
|
2055
1932
|
no_need_space ||= /[\(\[\|]$/.test(this.buffer) && /^\w/.test(str);
|
|
@@ -2058,7 +1935,8 @@ class TypstWriter {
|
|
|
2058
1935
|
no_need_space ||= str === "'";
|
|
2059
1936
|
no_need_space ||= /[0-9]$/.test(this.buffer) && /^[0-9]/.test(str);
|
|
2060
1937
|
no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
|
|
2061
|
-
no_need_space ||= str.startsWith(
|
|
1938
|
+
no_need_space ||= str.startsWith(`
|
|
1939
|
+
`);
|
|
2062
1940
|
no_need_space ||= this.buffer === "";
|
|
2063
1941
|
no_need_space ||= /^\s/.test(str);
|
|
2064
1942
|
no_need_space ||= this.buffer.endsWith("&") && str === "=";
|
|
@@ -2095,7 +1973,8 @@ class TypstWriter {
|
|
|
2095
1973
|
if (this.keepSpaces) {
|
|
2096
1974
|
this.queue.push(new TypstToken(4 /* SPACE */, c));
|
|
2097
1975
|
}
|
|
2098
|
-
} else if (c ===
|
|
1976
|
+
} else if (c === `
|
|
1977
|
+
`) {
|
|
2099
1978
|
this.queue.push(new TypstToken(0 /* SYMBOL */, c));
|
|
2100
1979
|
} else {
|
|
2101
1980
|
throw new TypstWriterError(`Unexpected whitespace character: ${c}`, node);
|
|
@@ -2111,9 +1990,9 @@ class TypstWriter {
|
|
|
2111
1990
|
let { base, sup, sub } = node.data;
|
|
2112
1991
|
this.appendWithBracketsIfNeeded(base);
|
|
2113
1992
|
let trailing_space_needed = false;
|
|
2114
|
-
const has_prime = sup && sup.type === "atom" && sup.content === "
|
|
1993
|
+
const has_prime = sup && sup.type === "atom" && sup.content === "'";
|
|
2115
1994
|
if (has_prime) {
|
|
2116
|
-
this.queue.push(new TypstToken(1 /* ELEMENT */, "
|
|
1995
|
+
this.queue.push(new TypstToken(1 /* ELEMENT */, "'"));
|
|
2117
1996
|
trailing_space_needed = false;
|
|
2118
1997
|
}
|
|
2119
1998
|
if (sub) {
|
|
@@ -2261,6 +2140,146 @@ class TypstWriter {
|
|
|
2261
2140
|
return this.buffer;
|
|
2262
2141
|
}
|
|
2263
2142
|
}
|
|
2143
|
+
function convertTree(node) {
|
|
2144
|
+
switch (node.type) {
|
|
2145
|
+
case "empty":
|
|
2146
|
+
return new TypstNode("empty", "");
|
|
2147
|
+
case "whitespace":
|
|
2148
|
+
return new TypstNode("whitespace", node.content);
|
|
2149
|
+
case "ordgroup":
|
|
2150
|
+
return new TypstNode("group", "", node.args.map(convertTree));
|
|
2151
|
+
case "element":
|
|
2152
|
+
return new TypstNode("atom", convertToken(node.content));
|
|
2153
|
+
case "symbol":
|
|
2154
|
+
return new TypstNode("symbol", convertToken(node.content));
|
|
2155
|
+
case "text":
|
|
2156
|
+
return new TypstNode("text", node.content);
|
|
2157
|
+
case "comment":
|
|
2158
|
+
return new TypstNode("comment", node.content);
|
|
2159
|
+
case "supsub": {
|
|
2160
|
+
let { base, sup, sub } = node.data;
|
|
2161
|
+
if (base && base.type === "unaryFunc" && base.content === "\\overbrace" && sup) {
|
|
2162
|
+
return new TypstNode("funcCall", "overbrace", [convertTree(base.args[0]), convertTree(sup)]);
|
|
2163
|
+
} else if (base && base.type === "unaryFunc" && base.content === "\\underbrace" && sub) {
|
|
2164
|
+
return new TypstNode("funcCall", "underbrace", [convertTree(base.args[0]), convertTree(sub)]);
|
|
2165
|
+
}
|
|
2166
|
+
const data = {
|
|
2167
|
+
base: convertTree(base)
|
|
2168
|
+
};
|
|
2169
|
+
if (data.base.type === "empty") {
|
|
2170
|
+
data.base = new TypstNode("text", "");
|
|
2171
|
+
}
|
|
2172
|
+
if (sup) {
|
|
2173
|
+
data.sup = convertTree(sup);
|
|
2174
|
+
}
|
|
2175
|
+
if (sub) {
|
|
2176
|
+
data.sub = convertTree(sub);
|
|
2177
|
+
}
|
|
2178
|
+
return new TypstNode("supsub", "", [], data);
|
|
2179
|
+
}
|
|
2180
|
+
case "leftright": {
|
|
2181
|
+
const [left, body, right] = node.args;
|
|
2182
|
+
const group = new TypstNode("group", "", node.args.map(convertTree));
|
|
2183
|
+
if ([
|
|
2184
|
+
"[]",
|
|
2185
|
+
"()",
|
|
2186
|
+
"\\{\\}",
|
|
2187
|
+
"\\lfloor\\rfloor",
|
|
2188
|
+
"\\lceil\\rceil",
|
|
2189
|
+
"\\lfloor\\rceil"
|
|
2190
|
+
].includes(left.content + right.content)) {
|
|
2191
|
+
return group;
|
|
2192
|
+
}
|
|
2193
|
+
if (right.content === ".") {
|
|
2194
|
+
group.args.pop();
|
|
2195
|
+
return group;
|
|
2196
|
+
} else if (left.content === ".") {
|
|
2197
|
+
group.args.shift();
|
|
2198
|
+
return new TypstNode("funcCall", "lr", [group]);
|
|
2199
|
+
}
|
|
2200
|
+
return new TypstNode("funcCall", "lr", [group]);
|
|
2201
|
+
}
|
|
2202
|
+
case "binaryFunc": {
|
|
2203
|
+
if (node.content === "\\overset") {
|
|
2204
|
+
return convert_overset(node);
|
|
2205
|
+
}
|
|
2206
|
+
return new TypstNode("funcCall", convertToken(node.content), node.args.map(convertTree));
|
|
2207
|
+
}
|
|
2208
|
+
case "unaryFunc": {
|
|
2209
|
+
const arg0 = convertTree(node.args[0]);
|
|
2210
|
+
if (node.content === "\\sqrt" && node.data) {
|
|
2211
|
+
const data = convertTree(node.data);
|
|
2212
|
+
return new TypstNode("funcCall", "root", [data, arg0]);
|
|
2213
|
+
}
|
|
2214
|
+
if (node.content === "\\mathbf") {
|
|
2215
|
+
const inner = new TypstNode("funcCall", "bold", [arg0]);
|
|
2216
|
+
return new TypstNode("funcCall", "upright", [inner]);
|
|
2217
|
+
}
|
|
2218
|
+
if (node.content === "\\mathbb" && arg0.type === "atom" && /^[A-Z]$/.test(arg0.content)) {
|
|
2219
|
+
return new TypstNode("symbol", arg0.content + arg0.content);
|
|
2220
|
+
}
|
|
2221
|
+
if (node.content === "\\operatorname") {
|
|
2222
|
+
const body = node.args;
|
|
2223
|
+
if (body.length !== 1 || body[0].type !== "text") {
|
|
2224
|
+
throw new TypstWriterError(`Expecting body of \\operatorname to be text but got`, node);
|
|
2225
|
+
}
|
|
2226
|
+
const text = body[0].content;
|
|
2227
|
+
if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
|
|
2228
|
+
return new TypstNode("symbol", text);
|
|
2229
|
+
} else {
|
|
2230
|
+
return new TypstNode("funcCall", "op", [new TypstNode("text", text)]);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
return new TypstNode("funcCall", convertToken(node.content), node.args.map(convertTree));
|
|
2234
|
+
}
|
|
2235
|
+
case "beginend": {
|
|
2236
|
+
const matrix = node.data;
|
|
2237
|
+
const data = matrix.map((row) => row.map(convertTree));
|
|
2238
|
+
if (node.content.startsWith("align")) {
|
|
2239
|
+
return new TypstNode("align", "", [], data);
|
|
2240
|
+
} else {
|
|
2241
|
+
const res = new TypstNode("matrix", "", [], data);
|
|
2242
|
+
res.setOptions({ delim: "#none" });
|
|
2243
|
+
return res;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
case "unknownMacro":
|
|
2247
|
+
return new TypstNode("unknown", convertToken(node.content));
|
|
2248
|
+
case "control":
|
|
2249
|
+
if (node.content === "\\\\") {
|
|
2250
|
+
return new TypstNode("symbol", "\\");
|
|
2251
|
+
} else if (node.content === "\\,") {
|
|
2252
|
+
return new TypstNode("symbol", "thin");
|
|
2253
|
+
} else {
|
|
2254
|
+
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
|
|
2255
|
+
}
|
|
2256
|
+
default:
|
|
2257
|
+
throw new TypstWriterError(`Unimplemented node type: ${node.type}`, node);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
function convertToken(token) {
|
|
2261
|
+
if (/^[a-zA-Z0-9]$/.test(token)) {
|
|
2262
|
+
return token;
|
|
2263
|
+
} else if (token === "/") {
|
|
2264
|
+
return "\\/";
|
|
2265
|
+
} else if (token === "\\|") {
|
|
2266
|
+
return "parallel";
|
|
2267
|
+
} else if (token === "\\colon") {
|
|
2268
|
+
return ":";
|
|
2269
|
+
} else if (token === "\\\\") {
|
|
2270
|
+
return "\\";
|
|
2271
|
+
} else if (["\\$", "\\#", "\\&", "\\_"].includes(token)) {
|
|
2272
|
+
return token;
|
|
2273
|
+
} else if (token.startsWith("\\")) {
|
|
2274
|
+
const symbol = token.slice(1);
|
|
2275
|
+
if (symbolMap.has(symbol)) {
|
|
2276
|
+
return symbolMap.get(symbol);
|
|
2277
|
+
} else {
|
|
2278
|
+
return symbol;
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
return token;
|
|
2282
|
+
}
|
|
2264
2283
|
|
|
2265
2284
|
// src/typst-parser.ts
|
|
2266
2285
|
function eat_primes2(tokens, start) {
|
|
@@ -2277,6 +2296,7 @@ function eat_identifier_name(typst, start) {
|
|
|
2277
2296
|
}
|
|
2278
2297
|
return typst.substring(start, pos);
|
|
2279
2298
|
}
|
|
2299
|
+
var TYPST_EMPTY_NODE = new TypstNode("empty", "");
|
|
2280
2300
|
function tokenize_typst(typst) {
|
|
2281
2301
|
const tokens = [];
|
|
2282
2302
|
let pos = 0;
|
|
@@ -2290,16 +2310,20 @@ function tokenize_typst(typst) {
|
|
|
2290
2310
|
token = new TypstToken(6 /* CONTROL */, firstChar);
|
|
2291
2311
|
pos++;
|
|
2292
2312
|
break;
|
|
2293
|
-
case
|
|
2313
|
+
case `
|
|
2314
|
+
`:
|
|
2294
2315
|
token = new TypstToken(7 /* NEWLINE */, firstChar);
|
|
2295
2316
|
pos++;
|
|
2296
2317
|
break;
|
|
2297
2318
|
case "\r": {
|
|
2298
|
-
if (pos + 1 < typst.length && typst[pos + 1] ===
|
|
2299
|
-
|
|
2319
|
+
if (pos + 1 < typst.length && typst[pos + 1] === `
|
|
2320
|
+
`) {
|
|
2321
|
+
token = new TypstToken(7 /* NEWLINE */, `
|
|
2322
|
+
`);
|
|
2300
2323
|
pos += 2;
|
|
2301
2324
|
} else {
|
|
2302
|
-
token = new TypstToken(7 /* NEWLINE */,
|
|
2325
|
+
token = new TypstToken(7 /* NEWLINE */, `
|
|
2326
|
+
`);
|
|
2303
2327
|
pos++;
|
|
2304
2328
|
}
|
|
2305
2329
|
break;
|
|
@@ -2316,7 +2340,8 @@ function tokenize_typst(typst) {
|
|
|
2316
2340
|
case "/": {
|
|
2317
2341
|
if (pos < typst.length && typst[pos + 1] === "/") {
|
|
2318
2342
|
let newPos = pos + 2;
|
|
2319
|
-
while (newPos < typst.length && typst[newPos] !==
|
|
2343
|
+
while (newPos < typst.length && typst[newPos] !== `
|
|
2344
|
+
`) {
|
|
2320
2345
|
newPos++;
|
|
2321
2346
|
}
|
|
2322
2347
|
token = new TypstToken(3 /* COMMENT */, typst.slice(pos + 2, newPos));
|
|
@@ -2368,7 +2393,7 @@ function tokenize_typst(typst) {
|
|
|
2368
2393
|
newPos += 1;
|
|
2369
2394
|
}
|
|
2370
2395
|
token = new TypstToken(1 /* ELEMENT */, typst.slice(pos, newPos));
|
|
2371
|
-
} else if ("
|
|
2396
|
+
} else if ("+-*/='<>!.,;?()[]|".includes(firstChar)) {
|
|
2372
2397
|
token = new TypstToken(1 /* ELEMENT */, firstChar);
|
|
2373
2398
|
} else if (isalpha(firstChar)) {
|
|
2374
2399
|
const identifier = eat_identifier_name(typst, pos);
|
|
@@ -2427,6 +2452,7 @@ function primes(num) {
|
|
|
2427
2452
|
}
|
|
2428
2453
|
return res;
|
|
2429
2454
|
}
|
|
2455
|
+
var DIV = new TypstNode("atom", "/");
|
|
2430
2456
|
function next_non_whitespace(nodes, start) {
|
|
2431
2457
|
let pos = start;
|
|
2432
2458
|
while (pos < nodes.length && nodes[pos].type === "whitespace") {
|
|
@@ -2511,13 +2537,6 @@ function process_operators(nodes, parenthesis = false) {
|
|
|
2511
2537
|
}
|
|
2512
2538
|
}
|
|
2513
2539
|
}
|
|
2514
|
-
function parseTypst(typst) {
|
|
2515
|
-
const parser = new TypstParser;
|
|
2516
|
-
let tokens = tokenize_typst(typst);
|
|
2517
|
-
return parser.parse(tokens);
|
|
2518
|
-
}
|
|
2519
|
-
var TYPST_EMPTY_NODE = new TypstNode("empty", "");
|
|
2520
|
-
var DIV = new TypstNode("atom", "/");
|
|
2521
2540
|
|
|
2522
2541
|
class TypstParserError extends Error {
|
|
2523
2542
|
constructor(message) {
|
|
@@ -2558,7 +2577,8 @@ class TypstParser {
|
|
|
2558
2577
|
if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
|
|
2559
2578
|
continue;
|
|
2560
2579
|
}
|
|
2561
|
-
if (!this.newline_sensitive && res.content ===
|
|
2580
|
+
if (!this.newline_sensitive && res.content === `
|
|
2581
|
+
`) {
|
|
2562
2582
|
continue;
|
|
2563
2583
|
}
|
|
2564
2584
|
}
|
|
@@ -2700,14 +2720,95 @@ class TypstParser {
|
|
|
2700
2720
|
return args;
|
|
2701
2721
|
}
|
|
2702
2722
|
}
|
|
2723
|
+
function parseTypst(typst) {
|
|
2724
|
+
const parser = new TypstParser;
|
|
2725
|
+
let tokens = tokenize_typst(typst);
|
|
2726
|
+
return parser.parse(tokens);
|
|
2727
|
+
}
|
|
2703
2728
|
|
|
2704
2729
|
// src/tex-writer.ts
|
|
2730
|
+
var TYPST_UNARY_FUNCTIONS = [
|
|
2731
|
+
"sqrt",
|
|
2732
|
+
"bold",
|
|
2733
|
+
"arrow",
|
|
2734
|
+
"upright",
|
|
2735
|
+
"lr",
|
|
2736
|
+
"op",
|
|
2737
|
+
"macron",
|
|
2738
|
+
"dot",
|
|
2739
|
+
"dot.double",
|
|
2740
|
+
"hat",
|
|
2741
|
+
"tilde",
|
|
2742
|
+
"overline",
|
|
2743
|
+
"underline",
|
|
2744
|
+
"bb",
|
|
2745
|
+
"cal",
|
|
2746
|
+
"frak"
|
|
2747
|
+
];
|
|
2748
|
+
var TYPST_BINARY_FUNCTIONS = [
|
|
2749
|
+
"frac",
|
|
2750
|
+
"root",
|
|
2751
|
+
"overbrace",
|
|
2752
|
+
"underbrace"
|
|
2753
|
+
];
|
|
2705
2754
|
function apply_escape_if_needed2(c) {
|
|
2706
2755
|
if (["{", "}", "%"].includes(c)) {
|
|
2707
2756
|
return "\\" + c;
|
|
2708
2757
|
}
|
|
2709
2758
|
return c;
|
|
2710
2759
|
}
|
|
2760
|
+
|
|
2761
|
+
class TexWriter {
|
|
2762
|
+
buffer = "";
|
|
2763
|
+
queue = [];
|
|
2764
|
+
writeBuffer(token) {
|
|
2765
|
+
const str = token.toString();
|
|
2766
|
+
let no_need_space = false;
|
|
2767
|
+
if (token.type === 4 /* SPACE */) {
|
|
2768
|
+
no_need_space = true;
|
|
2769
|
+
} else {
|
|
2770
|
+
no_need_space ||= /[{\(\[\|]$/.test(this.buffer);
|
|
2771
|
+
no_need_space ||= /\\\w+$/.test(this.buffer) && str === "[";
|
|
2772
|
+
no_need_space ||= /^[\.,;:!\?\(\)\]{}_^]$/.test(str);
|
|
2773
|
+
no_need_space ||= ["\\{", "\\}"].includes(str);
|
|
2774
|
+
no_need_space ||= str === "'";
|
|
2775
|
+
no_need_space ||= this.buffer.endsWith("_") || this.buffer.endsWith("^");
|
|
2776
|
+
no_need_space ||= /\s$/.test(this.buffer);
|
|
2777
|
+
no_need_space ||= /^\s/.test(str);
|
|
2778
|
+
no_need_space ||= this.buffer === "";
|
|
2779
|
+
no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
|
|
2780
|
+
no_need_space ||= this.buffer.endsWith("&") && str === "=";
|
|
2781
|
+
}
|
|
2782
|
+
if (!no_need_space) {
|
|
2783
|
+
this.buffer += " ";
|
|
2784
|
+
}
|
|
2785
|
+
this.buffer += str;
|
|
2786
|
+
}
|
|
2787
|
+
append(node) {
|
|
2788
|
+
const alignment_char = new TexNode("control", "&");
|
|
2789
|
+
const newline_char = new TexNode("control", "\\\\");
|
|
2790
|
+
if (node.type === "ordgroup" && array_includes(node.args, alignment_char)) {
|
|
2791
|
+
const rows = array_split(node.args, newline_char);
|
|
2792
|
+
const data = [];
|
|
2793
|
+
for (const row of rows) {
|
|
2794
|
+
const cells = array_split(row, alignment_char);
|
|
2795
|
+
data.push(cells.map((cell) => new TexNode("ordgroup", "", cell)));
|
|
2796
|
+
}
|
|
2797
|
+
node = new TexNode("beginend", "aligned", [], data);
|
|
2798
|
+
}
|
|
2799
|
+
this.queue = this.queue.concat(node.serialize());
|
|
2800
|
+
}
|
|
2801
|
+
flushQueue() {
|
|
2802
|
+
for (let i = 0;i < this.queue.length; i++) {
|
|
2803
|
+
this.writeBuffer(this.queue[i]);
|
|
2804
|
+
}
|
|
2805
|
+
this.queue = [];
|
|
2806
|
+
}
|
|
2807
|
+
finalize() {
|
|
2808
|
+
this.flushQueue();
|
|
2809
|
+
return this.buffer;
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2711
2812
|
function convert_typst_node_to_tex(node) {
|
|
2712
2813
|
if (node.eq(new TypstNode("symbol", "eq.def"))) {
|
|
2713
2814
|
return new TexNode("binaryFunc", "\\overset", [
|
|
@@ -2842,82 +2943,6 @@ function typst_token_to_tex(token) {
|
|
|
2842
2943
|
}
|
|
2843
2944
|
return "\\" + token;
|
|
2844
2945
|
}
|
|
2845
|
-
var TYPST_UNARY_FUNCTIONS = [
|
|
2846
|
-
"sqrt",
|
|
2847
|
-
"bold",
|
|
2848
|
-
"arrow",
|
|
2849
|
-
"upright",
|
|
2850
|
-
"lr",
|
|
2851
|
-
"op",
|
|
2852
|
-
"macron",
|
|
2853
|
-
"dot",
|
|
2854
|
-
"dot.double",
|
|
2855
|
-
"hat",
|
|
2856
|
-
"tilde",
|
|
2857
|
-
"overline",
|
|
2858
|
-
"underline",
|
|
2859
|
-
"bb",
|
|
2860
|
-
"cal",
|
|
2861
|
-
"frak"
|
|
2862
|
-
];
|
|
2863
|
-
var TYPST_BINARY_FUNCTIONS = [
|
|
2864
|
-
"frac",
|
|
2865
|
-
"root",
|
|
2866
|
-
"overbrace",
|
|
2867
|
-
"underbrace"
|
|
2868
|
-
];
|
|
2869
|
-
|
|
2870
|
-
class TexWriter {
|
|
2871
|
-
buffer = "";
|
|
2872
|
-
queue = [];
|
|
2873
|
-
writeBuffer(token) {
|
|
2874
|
-
const str = token.toString();
|
|
2875
|
-
let no_need_space = false;
|
|
2876
|
-
if (token.type === 4 /* SPACE */) {
|
|
2877
|
-
no_need_space = true;
|
|
2878
|
-
} else {
|
|
2879
|
-
no_need_space ||= /[{\(\[\|]$/.test(this.buffer);
|
|
2880
|
-
no_need_space ||= /\\\w+$/.test(this.buffer) && str === "[";
|
|
2881
|
-
no_need_space ||= /^[\.,;:!\?\(\)\]{}_^]$/.test(str);
|
|
2882
|
-
no_need_space ||= ["\\{", "\\}"].includes(str);
|
|
2883
|
-
no_need_space ||= str === "'";
|
|
2884
|
-
no_need_space ||= this.buffer.endsWith("_") || this.buffer.endsWith("^");
|
|
2885
|
-
no_need_space ||= /\s$/.test(this.buffer);
|
|
2886
|
-
no_need_space ||= /^\s/.test(str);
|
|
2887
|
-
no_need_space ||= this.buffer === "";
|
|
2888
|
-
no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
|
|
2889
|
-
no_need_space ||= this.buffer.endsWith("&") && str === "=";
|
|
2890
|
-
}
|
|
2891
|
-
if (!no_need_space) {
|
|
2892
|
-
this.buffer += " ";
|
|
2893
|
-
}
|
|
2894
|
-
this.buffer += str;
|
|
2895
|
-
}
|
|
2896
|
-
append(node) {
|
|
2897
|
-
const alignment_char = new TexNode("control", "&");
|
|
2898
|
-
const newline_char = new TexNode("control", "\\\\");
|
|
2899
|
-
if (node.type === "ordgroup" && array_includes(node.args, alignment_char)) {
|
|
2900
|
-
const rows = array_split(node.args, newline_char);
|
|
2901
|
-
const data = [];
|
|
2902
|
-
for (const row of rows) {
|
|
2903
|
-
const cells = array_split(row, alignment_char);
|
|
2904
|
-
data.push(cells.map((cell) => new TexNode("ordgroup", "", cell)));
|
|
2905
|
-
}
|
|
2906
|
-
node = new TexNode("beginend", "aligned", [], data);
|
|
2907
|
-
}
|
|
2908
|
-
this.queue = this.queue.concat(node.serialize());
|
|
2909
|
-
}
|
|
2910
|
-
flushQueue() {
|
|
2911
|
-
for (let i = 0;i < this.queue.length; i++) {
|
|
2912
|
-
this.writeBuffer(this.queue[i]);
|
|
2913
|
-
}
|
|
2914
|
-
this.queue = [];
|
|
2915
|
-
}
|
|
2916
|
-
finalize() {
|
|
2917
|
-
this.flushQueue();
|
|
2918
|
-
return this.buffer;
|
|
2919
|
-
}
|
|
2920
|
-
}
|
|
2921
2946
|
|
|
2922
2947
|
// src/index.ts
|
|
2923
2948
|
function tex2typst(tex, options) {
|
|
@@ -2940,16 +2965,16 @@ function tex2typst(tex, options) {
|
|
|
2940
2965
|
}
|
|
2941
2966
|
const texTree = parseTex(tex, opt.customTexMacros);
|
|
2942
2967
|
const typstTree = convertTree(texTree);
|
|
2943
|
-
const
|
|
2944
|
-
|
|
2945
|
-
return
|
|
2968
|
+
const writer = new TypstWriter(opt.nonStrict, opt.preferTypstIntrinsic, opt.keepSpaces);
|
|
2969
|
+
writer.serialize(typstTree);
|
|
2970
|
+
return writer.finalize();
|
|
2946
2971
|
}
|
|
2947
2972
|
function typst2tex(typst) {
|
|
2948
2973
|
const typstTree = parseTypst(typst);
|
|
2949
2974
|
const texTree = convert_typst_node_to_tex(typstTree);
|
|
2950
|
-
const
|
|
2951
|
-
|
|
2952
|
-
return
|
|
2975
|
+
const writer = new TexWriter;
|
|
2976
|
+
writer.append(texTree);
|
|
2977
|
+
return writer.finalize();
|
|
2953
2978
|
}
|
|
2954
2979
|
export {
|
|
2955
2980
|
typst2tex,
|