tex2typst 0.3.1 → 0.3.3
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/README.md +5 -3
- package/dist/index.js +454 -322
- package/dist/jslex.d.ts +105 -0
- package/dist/tex-parser.d.ts +1 -1
- package/dist/tex2typst.min.js +13 -20
- package/dist/types.d.ts +3 -1
- package/dist/typst-parser.d.ts +1 -1
- package/dist/typst-shorthands.d.ts +3 -0
- package/dist/typst-writer.d.ts +9 -3
- package/docs/api-reference.md +64 -0
- package/package.json +1 -1
- package/src/convert.ts +31 -18
- package/src/index.ts +11 -14
- package/src/jslex.ts +304 -0
- package/src/map.ts +13 -36
- package/src/tex-parser.ts +44 -137
- package/src/types.ts +3 -1
- package/src/typst-parser.ts +72 -126
- package/src/typst-shorthands.ts +51 -0
- package/src/typst-writer.ts +29 -22
- package/tools/make-shorthand-map.py +33 -0
- package/tools/make-symbol-map.py +4 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
// src/map.ts
|
|
2
2
|
var symbolMap = /* @__PURE__ */ new Map([
|
|
3
|
+
["cos", "cos"],
|
|
4
|
+
["sin", "sin"],
|
|
5
|
+
["tan", "tan"],
|
|
6
|
+
["cot", "cot"],
|
|
7
|
+
["sec", "sec"],
|
|
8
|
+
["csc", "csc"],
|
|
9
|
+
["mod", "mod"],
|
|
10
|
+
["omicron", "omicron"],
|
|
11
|
+
["Xi", "Xi"],
|
|
12
|
+
["Upsilon", "Upsilon"],
|
|
13
|
+
["lim", "lim"],
|
|
3
14
|
["nonumber", ""],
|
|
4
15
|
["vec", "arrow"],
|
|
5
16
|
["neq", "eq.not"],
|
|
@@ -59,44 +70,16 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
59
70
|
["propto", "prop"],
|
|
60
71
|
/* arrows */
|
|
61
72
|
["gets", "arrow.l"],
|
|
62
|
-
["hookleftarrow", "arrow.l.hook"],
|
|
63
|
-
["leftharpoonup", "harpoon.lt"],
|
|
64
|
-
["leftharpoondown", "harpoon.lb"],
|
|
65
|
-
["rightleftharpoons", "harpoons.rtlb"],
|
|
66
|
-
["longleftarrow", "arrow.l.long"],
|
|
67
|
-
["longrightarrow", "arrow.r.long"],
|
|
68
|
-
["longleftrightarrow", "arrow.l.r.long"],
|
|
69
|
-
["Longleftarrow", "arrow.l.double.long"],
|
|
70
|
-
["Longrightarrow", "arrow.r.double.long"],
|
|
71
|
-
["Longleftrightarrow", "arrow.l.r.double.long"],
|
|
72
73
|
// ['longmapsto', 'arrow.r.bar'],
|
|
73
|
-
["hookrightarrow", "arrow.r.hook"],
|
|
74
|
-
["rightharpoonup", "harpoon.rt"],
|
|
75
|
-
["rightharpoondown", "harpoon.rb"],
|
|
76
74
|
["iff", "arrow.l.r.double.long"],
|
|
77
75
|
["implies", "arrow.r.double.long"],
|
|
78
|
-
["uparrow", "arrow.t"],
|
|
79
|
-
["downarrow", "arrow.b"],
|
|
80
|
-
["updownarrow", "arrow.t.b"],
|
|
81
|
-
["Uparrow", "arrow.t.double"],
|
|
82
|
-
["Downarrow", "arrow.b.double"],
|
|
83
|
-
["Updownarrow", "arrow.t.b.double"],
|
|
84
|
-
["nearrow", "arrow.tr"],
|
|
85
|
-
["searrow", "arrow.br"],
|
|
86
|
-
["swarrow", "arrow.bl"],
|
|
87
|
-
["nwarrow", "arrow.tl"],
|
|
88
76
|
["leadsto", "arrow.squiggly"],
|
|
89
|
-
["leftleftarrows", "arrows.ll"],
|
|
90
|
-
["rightrightarrows", "arrows.rr"],
|
|
91
77
|
["Cap", "sect.double"],
|
|
92
78
|
["Cup", "union.double"],
|
|
93
79
|
["Delta", "Delta"],
|
|
94
80
|
["Gamma", "Gamma"],
|
|
95
81
|
["Join", "join"],
|
|
96
82
|
["Lambda", "Lambda"],
|
|
97
|
-
["Leftarrow", "arrow.l.double"],
|
|
98
|
-
["Leftrightarrow", "arrow.l.r.double"],
|
|
99
|
-
["Longrightarrow", "arrow.r.double.long"],
|
|
100
83
|
["Omega", "Omega"],
|
|
101
84
|
["P", "pilcrow"],
|
|
102
85
|
["Phi", "Phi"],
|
|
@@ -152,7 +135,6 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
152
135
|
["div", "div"],
|
|
153
136
|
["divideontimes", "times.div"],
|
|
154
137
|
["dotplus", "plus.dot"],
|
|
155
|
-
["downarrow", "arrow.b"],
|
|
156
138
|
["ell", "ell"],
|
|
157
139
|
["emptyset", "nothing"],
|
|
158
140
|
["epsilon", "epsilon.alt"],
|
|
@@ -186,8 +168,6 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
186
168
|
["lbrack", "bracket.l"],
|
|
187
169
|
["ldots", "dots.h"],
|
|
188
170
|
["le", "lt.eq"],
|
|
189
|
-
["leadsto", "arrow.squiggly"],
|
|
190
|
-
["leftarrow", "arrow.l"],
|
|
191
171
|
["leftthreetimes", "times.three.l"],
|
|
192
172
|
["leftrightarrow", "arrow.l.r"],
|
|
193
173
|
["leq", "lt.eq"],
|
|
@@ -224,7 +204,6 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
224
204
|
["nu", "nu"],
|
|
225
205
|
["ntriangleleft", "lt.tri.not"],
|
|
226
206
|
["ntriangleright", "gt.tri.not"],
|
|
227
|
-
["nwarrow", "arrow.tl"],
|
|
228
207
|
["odot", "dot.circle"],
|
|
229
208
|
["oint", "integral.cont"],
|
|
230
209
|
["oiint", "integral.surf"],
|
|
@@ -277,7 +256,6 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
277
256
|
["supset", "supset"],
|
|
278
257
|
["supseteq", "supset.eq"],
|
|
279
258
|
["supsetneq", "supset.neq"],
|
|
280
|
-
["swarrow", "arrow.bl"],
|
|
281
259
|
["tau", "tau"],
|
|
282
260
|
["theta", "theta"],
|
|
283
261
|
["times", "times"],
|
|
@@ -288,8 +266,6 @@ var symbolMap = /* @__PURE__ */ new Map([
|
|
|
288
266
|
// ['triangleleft', 'triangle.l.small'],
|
|
289
267
|
// ['triangleright', 'triangle.r.small'],
|
|
290
268
|
["twoheadrightarrow", "arrow.r.twohead"],
|
|
291
|
-
["uparrow", "arrow.t"],
|
|
292
|
-
["updownarrow", "arrow.t.b"],
|
|
293
269
|
["upharpoonright", "harpoon.tr"],
|
|
294
270
|
["uplus", "union.plus"],
|
|
295
271
|
["upsilon", "upsilon"],
|
|
@@ -1081,6 +1057,7 @@ for (const [key, value] of Array.from(symbolMap.entries()).reverse()) {
|
|
|
1081
1057
|
reverseSymbolMap.set(value, key);
|
|
1082
1058
|
}
|
|
1083
1059
|
reverseSymbolMap.set("dif", "mathrm{d}");
|
|
1060
|
+
reverseSymbolMap.set("oo", "infty");
|
|
1084
1061
|
var typst_to_tex_map = /* @__PURE__ */ new Map([
|
|
1085
1062
|
["top", "top"],
|
|
1086
1063
|
["frac", "frac"],
|
|
@@ -1405,15 +1382,248 @@ var TypstNode = class {
|
|
|
1405
1382
|
function isalpha(char) {
|
|
1406
1383
|
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(char);
|
|
1407
1384
|
}
|
|
1408
|
-
function isdigit(char) {
|
|
1409
|
-
return "0123456789".includes(char);
|
|
1410
|
-
}
|
|
1411
1385
|
function assert(condition, message = "") {
|
|
1412
1386
|
if (!condition) {
|
|
1413
1387
|
throw new Error(message);
|
|
1414
1388
|
}
|
|
1415
1389
|
}
|
|
1416
1390
|
|
|
1391
|
+
// src/jslex.ts
|
|
1392
|
+
var EOF = {};
|
|
1393
|
+
function matchcompare(m1, m2) {
|
|
1394
|
+
if (m2.len !== m1.len) {
|
|
1395
|
+
return m2.len - m1.len;
|
|
1396
|
+
} else {
|
|
1397
|
+
return m1.index - m2.index;
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
var Scanner = class {
|
|
1401
|
+
constructor(input, lexer) {
|
|
1402
|
+
// position within input stream
|
|
1403
|
+
this._pos = 0;
|
|
1404
|
+
// current line number
|
|
1405
|
+
this._line = 0;
|
|
1406
|
+
// current column number
|
|
1407
|
+
this._col = 0;
|
|
1408
|
+
this._offset = 0;
|
|
1409
|
+
this._less = null;
|
|
1410
|
+
this._go = false;
|
|
1411
|
+
this._newstate = null;
|
|
1412
|
+
this._text = null;
|
|
1413
|
+
this._leng = null;
|
|
1414
|
+
this._input = input;
|
|
1415
|
+
this._lexer = lexer;
|
|
1416
|
+
this._state = lexer.states[0];
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Analogous to yytext and yyleng in lex - will be set during scan.
|
|
1420
|
+
*/
|
|
1421
|
+
text() {
|
|
1422
|
+
return this._text;
|
|
1423
|
+
}
|
|
1424
|
+
leng() {
|
|
1425
|
+
return this._leng;
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Position of in stream, line number and column number of match.
|
|
1429
|
+
*/
|
|
1430
|
+
pos() {
|
|
1431
|
+
return this._pos;
|
|
1432
|
+
}
|
|
1433
|
+
line() {
|
|
1434
|
+
return this._line;
|
|
1435
|
+
}
|
|
1436
|
+
column() {
|
|
1437
|
+
return this._col;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Analogous to input() in lex.
|
|
1441
|
+
* @return {string} The next character in the stream.
|
|
1442
|
+
*/
|
|
1443
|
+
input() {
|
|
1444
|
+
return this._input.charAt(this._pos + this._leng + this._offset++);
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Similar to unput() in lex, but does not allow modifying the stream.
|
|
1448
|
+
* @return {int} The offset position after the operation.
|
|
1449
|
+
*/
|
|
1450
|
+
unput() {
|
|
1451
|
+
return this._offset = this._offset > 0 ? this._offset-- : 0;
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* Analogous to yyless(n) in lex - retains the first n characters from this pattern, and returns
|
|
1455
|
+
* the rest to the input stream, such that they will be used in the next pattern-matching operation.
|
|
1456
|
+
* @param {int} n Number of characters to retain.
|
|
1457
|
+
* @return {int} Length of the stream after the operation has completed.
|
|
1458
|
+
*/
|
|
1459
|
+
less(n) {
|
|
1460
|
+
this._less = n;
|
|
1461
|
+
this._offset = 0;
|
|
1462
|
+
this._text = this._text.substring(0, n);
|
|
1463
|
+
return this._leng = this._text.length;
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Like less(), but instead of retaining the first n characters, it chops off the last n.
|
|
1467
|
+
* @param {int} n Number of characters to chop.
|
|
1468
|
+
* @return {int} Length of the stream after the operation has completed.
|
|
1469
|
+
*/
|
|
1470
|
+
pushback(n) {
|
|
1471
|
+
return this.less(this._leng - n);
|
|
1472
|
+
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Similar to REJECT in lex, except it doesn't break the current execution context.
|
|
1475
|
+
* TIP: reject() should be the last instruction in a spec callback.
|
|
1476
|
+
*/
|
|
1477
|
+
reject() {
|
|
1478
|
+
this._go = true;
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Analogous to BEGIN in lex - sets the named state (start condition).
|
|
1482
|
+
* @param {string|int} state Name of state to switch to, or ordinal number (0 is first, etc).
|
|
1483
|
+
* @return {string} The new state on successful switch, throws exception on failure.
|
|
1484
|
+
*/
|
|
1485
|
+
begin(state) {
|
|
1486
|
+
if (this._lexer.specification[state]) {
|
|
1487
|
+
return this._newstate = state;
|
|
1488
|
+
}
|
|
1489
|
+
const s = this._lexer.states[parseInt(state)];
|
|
1490
|
+
if (s) {
|
|
1491
|
+
return this._newstate = s;
|
|
1492
|
+
}
|
|
1493
|
+
throw "Unknown state '" + state + "' requested";
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Simple accessor for reading in the current state.
|
|
1497
|
+
* @return {string} The current state.
|
|
1498
|
+
*/
|
|
1499
|
+
state() {
|
|
1500
|
+
return this._state;
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Scan method to be returned to caller - grabs the next token and fires appropriate calback.
|
|
1504
|
+
* @return {T} The next token extracted from the stream.
|
|
1505
|
+
*/
|
|
1506
|
+
scan() {
|
|
1507
|
+
if (this._pos >= this._input.length) {
|
|
1508
|
+
return EOF;
|
|
1509
|
+
}
|
|
1510
|
+
const str = this._input.substring(this._pos);
|
|
1511
|
+
const rules = this._lexer.specification[this._state];
|
|
1512
|
+
const matches = [];
|
|
1513
|
+
for (let i = 0; i < rules.length; i++) {
|
|
1514
|
+
const rule = rules[i];
|
|
1515
|
+
const mt = str.match(rule.re);
|
|
1516
|
+
if (mt !== null && mt[0].length > 0) {
|
|
1517
|
+
matches.push({
|
|
1518
|
+
index: i,
|
|
1519
|
+
text: mt[0],
|
|
1520
|
+
len: mt[0].length,
|
|
1521
|
+
rule
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
if (matches.length === 0) {
|
|
1526
|
+
throw new Error("No match found for input '" + str + "'");
|
|
1527
|
+
}
|
|
1528
|
+
matches.sort(matchcompare);
|
|
1529
|
+
this._go = true;
|
|
1530
|
+
let result;
|
|
1531
|
+
let m;
|
|
1532
|
+
for (let j = 0, n = matches.length; j < n && this._go; j++) {
|
|
1533
|
+
this._offset = 0;
|
|
1534
|
+
this._less = null;
|
|
1535
|
+
this._go = false;
|
|
1536
|
+
this._newstate = null;
|
|
1537
|
+
m = matches[j];
|
|
1538
|
+
this._text = m.text;
|
|
1539
|
+
this._leng = m.len;
|
|
1540
|
+
result = m.rule.action(this);
|
|
1541
|
+
if (this._newstate && this._newstate != this._state) {
|
|
1542
|
+
this._state = this._newstate;
|
|
1543
|
+
break;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
const text = this._less === null ? m.text : m.text.substring(0, this._less);
|
|
1547
|
+
const len = text.length;
|
|
1548
|
+
this._pos += len + this._offset;
|
|
1549
|
+
const nlm = text.match(/\n/g);
|
|
1550
|
+
if (nlm !== null) {
|
|
1551
|
+
this._line += nlm.length;
|
|
1552
|
+
this._col = len - text.lastIndexOf("\n") - 1;
|
|
1553
|
+
} else {
|
|
1554
|
+
this._col += len;
|
|
1555
|
+
}
|
|
1556
|
+
return result;
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
var JSLex = class {
|
|
1560
|
+
constructor(spec3) {
|
|
1561
|
+
this.states = Object.keys(spec3);
|
|
1562
|
+
this.specification = {};
|
|
1563
|
+
for (const s of this.states) {
|
|
1564
|
+
const rule_map = spec3[s];
|
|
1565
|
+
if (s in this.specification) {
|
|
1566
|
+
throw "Duplicate state declaration encountered for state '" + s + "'";
|
|
1567
|
+
}
|
|
1568
|
+
this.specification[s] = [];
|
|
1569
|
+
for (const [k, v] of rule_map.entries()) {
|
|
1570
|
+
let re;
|
|
1571
|
+
try {
|
|
1572
|
+
re = new RegExp("^" + k);
|
|
1573
|
+
} catch (err) {
|
|
1574
|
+
throw "Invalid regexp '" + k + "' in state '" + s + "' (" + err.message + ")";
|
|
1575
|
+
}
|
|
1576
|
+
this.specification[s].push({
|
|
1577
|
+
re,
|
|
1578
|
+
action: v
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* Scanner function - makes a new scanner object which is used to get tokens one at a time.
|
|
1585
|
+
* @param {string} input Input text to tokenize.
|
|
1586
|
+
* @return {function} Scanner function.
|
|
1587
|
+
*/
|
|
1588
|
+
scanner(input) {
|
|
1589
|
+
return new Scanner(input, this);
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Similar to lex's yylex() function, consumes all input, calling calback for each token.
|
|
1593
|
+
* @param {string} input Text to lex.
|
|
1594
|
+
* @param {function} callback Function to execute for each token.
|
|
1595
|
+
*/
|
|
1596
|
+
lex(input, callback) {
|
|
1597
|
+
const scanner = this.scanner(input);
|
|
1598
|
+
while (true) {
|
|
1599
|
+
const token = scanner.scan();
|
|
1600
|
+
if (token === EOF) {
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
if (token !== void 0) {
|
|
1604
|
+
callback(token);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Consumes all input, collecting tokens along the way.
|
|
1610
|
+
* @param {string} input Text to lex.
|
|
1611
|
+
* @return {array} List of tokens, may contain an Error at the end.
|
|
1612
|
+
*/
|
|
1613
|
+
collect(input) {
|
|
1614
|
+
const tokens = [];
|
|
1615
|
+
const callback = function(item) {
|
|
1616
|
+
if (Array.isArray(item)) {
|
|
1617
|
+
tokens.push(...item);
|
|
1618
|
+
} else {
|
|
1619
|
+
tokens.push(item);
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
this.lex(input, callback);
|
|
1623
|
+
return tokens;
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1417
1627
|
// src/tex-parser.ts
|
|
1418
1628
|
var UNARY_COMMANDS = [
|
|
1419
1629
|
"sqrt",
|
|
@@ -1443,7 +1653,9 @@ var UNARY_COMMANDS = [
|
|
|
1443
1653
|
"underline",
|
|
1444
1654
|
"vec",
|
|
1445
1655
|
"widehat",
|
|
1446
|
-
"widetilde"
|
|
1656
|
+
"widetilde",
|
|
1657
|
+
"overleftarrow",
|
|
1658
|
+
"overrightarrow"
|
|
1447
1659
|
];
|
|
1448
1660
|
var BINARY_COMMANDS = [
|
|
1449
1661
|
"frac",
|
|
@@ -1492,13 +1704,6 @@ function eat_primes(tokens, start) {
|
|
|
1492
1704
|
}
|
|
1493
1705
|
return pos - start;
|
|
1494
1706
|
}
|
|
1495
|
-
function eat_command_name(latex, start) {
|
|
1496
|
-
let pos = start;
|
|
1497
|
-
while (pos < latex.length && isalpha(latex[pos])) {
|
|
1498
|
-
pos += 1;
|
|
1499
|
-
}
|
|
1500
|
-
return latex.substring(start, pos);
|
|
1501
|
-
}
|
|
1502
1707
|
function find_closing_match(tokens, start, leftToken, rightToken) {
|
|
1503
1708
|
assert(tokens[start].eq(leftToken));
|
|
1504
1709
|
let count = 1;
|
|
@@ -1526,126 +1731,46 @@ var END_COMMAND = new TexToken(1 /* COMMAND */, "\\end");
|
|
|
1526
1731
|
function find_closing_end_command(tokens, start) {
|
|
1527
1732
|
return find_closing_match(tokens, start, BEGIN_COMMAND, END_COMMAND);
|
|
1528
1733
|
}
|
|
1529
|
-
function
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
while (count > 0) {
|
|
1534
|
-
if (pos >= latex.length) {
|
|
1535
|
-
throw new LatexParserError("Unmatched curly brackets");
|
|
1536
|
-
}
|
|
1537
|
-
if (pos + 1 < latex.length && ["\\{", "\\}"].includes(latex.substring(pos, pos + 2))) {
|
|
1538
|
-
pos += 2;
|
|
1539
|
-
continue;
|
|
1540
|
-
}
|
|
1541
|
-
if (latex[pos] === "{") {
|
|
1542
|
-
count += 1;
|
|
1543
|
-
} else if (latex[pos] === "}") {
|
|
1544
|
-
count -= 1;
|
|
1545
|
-
}
|
|
1546
|
-
pos += 1;
|
|
1734
|
+
function unescape(str) {
|
|
1735
|
+
const chars = ["{", "}", "\\", "$", "&", "#", "_", "%"];
|
|
1736
|
+
for (const char of chars) {
|
|
1737
|
+
str = str.replaceAll("\\" + char, char);
|
|
1547
1738
|
}
|
|
1548
|
-
return
|
|
1739
|
+
return str;
|
|
1549
1740
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
token = new TexToken(5 /* NEWLINE */, "\n");
|
|
1584
|
-
pos++;
|
|
1585
|
-
}
|
|
1586
|
-
break;
|
|
1587
|
-
}
|
|
1588
|
-
case " ": {
|
|
1589
|
-
let newPos = pos;
|
|
1590
|
-
while (newPos < latex.length && latex[newPos] === " ") {
|
|
1591
|
-
newPos += 1;
|
|
1592
|
-
}
|
|
1593
|
-
token = new TexToken(4 /* SPACE */, latex.slice(pos, newPos));
|
|
1594
|
-
pos = newPos;
|
|
1595
|
-
break;
|
|
1596
|
-
}
|
|
1597
|
-
case "\\": {
|
|
1598
|
-
if (pos + 1 >= latex.length) {
|
|
1599
|
-
throw new LatexParserError("Expecting command name after \\");
|
|
1600
|
-
}
|
|
1601
|
-
const firstTwoChars = latex.slice(pos, pos + 2);
|
|
1602
|
-
if (["\\\\", "\\,"].includes(firstTwoChars)) {
|
|
1603
|
-
token = new TexToken(6 /* CONTROL */, firstTwoChars);
|
|
1604
|
-
} else if (["\\{", "\\}", "\\%", "\\$", "\\&", "\\#", "\\_", "\\|"].includes(firstTwoChars)) {
|
|
1605
|
-
token = new TexToken(0 /* ELEMENT */, firstTwoChars);
|
|
1606
|
-
} else {
|
|
1607
|
-
const command = eat_command_name(latex, pos + 1);
|
|
1608
|
-
token = new TexToken(1 /* COMMAND */, "\\" + command);
|
|
1609
|
-
}
|
|
1610
|
-
pos += token.value.length;
|
|
1611
|
-
break;
|
|
1612
|
-
}
|
|
1613
|
-
default: {
|
|
1614
|
-
if (isdigit(firstChar)) {
|
|
1615
|
-
let newPos = pos;
|
|
1616
|
-
while (newPos < latex.length && isdigit(latex[newPos])) {
|
|
1617
|
-
newPos += 1;
|
|
1618
|
-
}
|
|
1619
|
-
token = new TexToken(0 /* ELEMENT */, latex.slice(pos, newPos));
|
|
1620
|
-
} else if (isalpha(firstChar)) {
|
|
1621
|
-
token = new TexToken(0 /* ELEMENT */, firstChar);
|
|
1622
|
-
} else if ("+-*/='<>!.,;:?()[]|".includes(firstChar)) {
|
|
1623
|
-
token = new TexToken(0 /* ELEMENT */, firstChar);
|
|
1624
|
-
} else {
|
|
1625
|
-
token = new TexToken(7 /* UNKNOWN */, firstChar);
|
|
1626
|
-
}
|
|
1627
|
-
pos += token.value.length;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
tokens.push(token);
|
|
1631
|
-
if (token.type === 1 /* COMMAND */ && ["\\text", "\\operatorname", "\\begin", "\\end"].includes(token.value)) {
|
|
1632
|
-
if (pos >= latex.length || latex[pos] !== "{") {
|
|
1633
|
-
throw new LatexParserError(`No content for ${token.value} command`);
|
|
1634
|
-
}
|
|
1635
|
-
tokens.push(new TexToken(6 /* CONTROL */, "{"));
|
|
1636
|
-
const posClosingBracket = find_closing_curly_bracket_char(latex, pos);
|
|
1637
|
-
pos++;
|
|
1638
|
-
let textInside = latex.slice(pos, posClosingBracket);
|
|
1639
|
-
const chars = ["{", "}", "\\", "$", "&", "#", "_", "%"];
|
|
1640
|
-
for (const char of chars) {
|
|
1641
|
-
textInside = textInside.replaceAll("\\" + char, char);
|
|
1642
|
-
}
|
|
1643
|
-
tokens.push(new TexToken(2 /* TEXT */, textInside));
|
|
1644
|
-
tokens.push(new TexToken(6 /* CONTROL */, "}"));
|
|
1645
|
-
pos = posClosingBracket + 1;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
return tokens;
|
|
1741
|
+
var rules_map = /* @__PURE__ */ new Map([
|
|
1742
|
+
[
|
|
1743
|
+
String.raw`\\(text|operatorname|begin|end){.+?}`,
|
|
1744
|
+
(s) => {
|
|
1745
|
+
const text = s.text();
|
|
1746
|
+
const command = text.substring(0, text.indexOf("{"));
|
|
1747
|
+
const text_inside = text.substring(text.indexOf("{") + 1, text.lastIndexOf("}"));
|
|
1748
|
+
return [
|
|
1749
|
+
new TexToken(1 /* COMMAND */, command),
|
|
1750
|
+
new TexToken(6 /* CONTROL */, "{"),
|
|
1751
|
+
new TexToken(2 /* TEXT */, unescape(text_inside)),
|
|
1752
|
+
new TexToken(6 /* CONTROL */, "}")
|
|
1753
|
+
];
|
|
1754
|
+
}
|
|
1755
|
+
],
|
|
1756
|
+
[String.raw`%[^\n]*`, (s) => new TexToken(3 /* COMMENT */, s.text().substring(1))],
|
|
1757
|
+
[String.raw`[{}_^&]`, (s) => new TexToken(6 /* CONTROL */, s.text())],
|
|
1758
|
+
[String.raw`\r?\n`, (_s) => new TexToken(5 /* NEWLINE */, "\n")],
|
|
1759
|
+
[String.raw`\s+`, (s) => new TexToken(4 /* SPACE */, s.text())],
|
|
1760
|
+
[String.raw`\\[\\,]`, (s) => new TexToken(6 /* CONTROL */, s.text())],
|
|
1761
|
+
[String.raw`\\[{}%$&#_|]`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
|
|
1762
|
+
[String.raw`\\[a-zA-Z]+`, (s) => new TexToken(1 /* COMMAND */, s.text())],
|
|
1763
|
+
[String.raw`[0-9]+`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
|
|
1764
|
+
[String.raw`[a-zA-Z]`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
|
|
1765
|
+
[String.raw`[+\-*/='<>!.,;:?()\[\]|]`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
|
|
1766
|
+
[String.raw`.`, (s) => new TexToken(7 /* UNKNOWN */, s.text())]
|
|
1767
|
+
]);
|
|
1768
|
+
var spec = {
|
|
1769
|
+
"start": rules_map
|
|
1770
|
+
};
|
|
1771
|
+
function tokenize_tex(input) {
|
|
1772
|
+
const lexer = new JSLex(spec);
|
|
1773
|
+
return lexer.collect(input);
|
|
1649
1774
|
}
|
|
1650
1775
|
var LatexParserError = class extends Error {
|
|
1651
1776
|
constructor(message) {
|
|
@@ -1961,7 +2086,7 @@ function passExpandCustomTexMacros(tokens, customTexMacros) {
|
|
|
1961
2086
|
let out_tokens = [];
|
|
1962
2087
|
for (const token of tokens) {
|
|
1963
2088
|
if (token.type === 1 /* COMMAND */ && customTexMacros[token.value]) {
|
|
1964
|
-
const expanded_tokens =
|
|
2089
|
+
const expanded_tokens = tokenize_tex(customTexMacros[token.value]);
|
|
1965
2090
|
out_tokens = out_tokens.concat(expanded_tokens);
|
|
1966
2091
|
} else {
|
|
1967
2092
|
out_tokens.push(token);
|
|
@@ -1971,23 +2096,61 @@ function passExpandCustomTexMacros(tokens, customTexMacros) {
|
|
|
1971
2096
|
}
|
|
1972
2097
|
function parseTex(tex, customTexMacros) {
|
|
1973
2098
|
const parser = new LatexParser();
|
|
1974
|
-
let tokens =
|
|
2099
|
+
let tokens = tokenize_tex(tex);
|
|
1975
2100
|
tokens = passIgnoreWhitespaceBeforeScriptMark(tokens);
|
|
1976
2101
|
tokens = passExpandCustomTexMacros(tokens, customTexMacros);
|
|
1977
2102
|
return parser.parse(tokens);
|
|
1978
2103
|
}
|
|
1979
2104
|
|
|
2105
|
+
// src/typst-shorthands.ts
|
|
2106
|
+
var shorthandMap = /* @__PURE__ */ new Map([
|
|
2107
|
+
["arrow.l.r.double.long", "<==>"],
|
|
2108
|
+
["arrow.l.r.long", "<-->"],
|
|
2109
|
+
["arrow.r.bar", "|->"],
|
|
2110
|
+
["arrow.r.double.bar", "|=>"],
|
|
2111
|
+
["arrow.r.double.long", "==>"],
|
|
2112
|
+
["arrow.r.long", "-->"],
|
|
2113
|
+
["arrow.r.long.squiggly", "~~>"],
|
|
2114
|
+
["arrow.r.tail", ">->"],
|
|
2115
|
+
["arrow.r.twohead", "->>"],
|
|
2116
|
+
["arrow.l.double.long", "<=="],
|
|
2117
|
+
["arrow.l.long", "<--"],
|
|
2118
|
+
["arrow.l.long.squiggly", "<~~"],
|
|
2119
|
+
["arrow.l.tail", "<-<"],
|
|
2120
|
+
["arrow.l.twohead", "<<-"],
|
|
2121
|
+
["arrow.l.r", "<->"],
|
|
2122
|
+
["arrow.l.r.double", "<=>"],
|
|
2123
|
+
["colon.double.eq", "::="],
|
|
2124
|
+
["dots.h", "..."],
|
|
2125
|
+
["gt.triple", ">>>"],
|
|
2126
|
+
["lt.triple", "<<<"],
|
|
2127
|
+
["arrow.r", "->"],
|
|
2128
|
+
["arrow.r.double", "=>"],
|
|
2129
|
+
["arrow.r.squiggly", "~>"],
|
|
2130
|
+
["arrow.l", "<-"],
|
|
2131
|
+
["arrow.l.squiggly", "<~"],
|
|
2132
|
+
["bar.v.double", "||"],
|
|
2133
|
+
["bracket.l.double", "[|"],
|
|
2134
|
+
["bracket.r.double", "|]"],
|
|
2135
|
+
["colon.eq", ":="],
|
|
2136
|
+
["eq.colon", "=:"],
|
|
2137
|
+
["eq.not", "!="],
|
|
2138
|
+
["gt.double", ">>"],
|
|
2139
|
+
["gt.eq", ">="],
|
|
2140
|
+
["lt.double", "<<"],
|
|
2141
|
+
["lt.eq", "<="],
|
|
2142
|
+
["ast.op", "*"],
|
|
2143
|
+
["minus", "-"],
|
|
2144
|
+
["tilde.op", "~"]
|
|
2145
|
+
]);
|
|
2146
|
+
var reverseShorthandMap = /* @__PURE__ */ new Map();
|
|
2147
|
+
for (const [key, value] of shorthandMap.entries()) {
|
|
2148
|
+
if (value.length > 1) {
|
|
2149
|
+
reverseShorthandMap.set(value, key);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
|
|
1980
2153
|
// src/typst-writer.ts
|
|
1981
|
-
var TYPST_INTRINSIC_SYMBOLS = [
|
|
1982
|
-
"dim",
|
|
1983
|
-
"id",
|
|
1984
|
-
"im",
|
|
1985
|
-
"mod",
|
|
1986
|
-
"Pr",
|
|
1987
|
-
"sech",
|
|
1988
|
-
"csch"
|
|
1989
|
-
// 'sgn
|
|
1990
|
-
];
|
|
1991
2154
|
function is_delimiter(c) {
|
|
1992
2155
|
return c.type === "atom" && ["(", ")", "[", "]", "{", "}", "|", "\u230A", "\u230B", "\u2308", "\u2309"].includes(c.content);
|
|
1993
2156
|
}
|
|
@@ -2006,6 +2169,8 @@ function typst_primitive_to_string(value) {
|
|
|
2006
2169
|
default:
|
|
2007
2170
|
if (value === null) {
|
|
2008
2171
|
return "#none";
|
|
2172
|
+
} else if (value instanceof TypstToken) {
|
|
2173
|
+
return value.toString();
|
|
2009
2174
|
}
|
|
2010
2175
|
throw new TypstWriterError(`Invalid primitive value: ${value}`, value);
|
|
2011
2176
|
}
|
|
@@ -2018,13 +2183,14 @@ var TypstWriterError = class extends Error {
|
|
|
2018
2183
|
}
|
|
2019
2184
|
};
|
|
2020
2185
|
var TypstWriter = class {
|
|
2021
|
-
constructor(
|
|
2186
|
+
constructor(opt) {
|
|
2022
2187
|
this.buffer = "";
|
|
2023
2188
|
this.queue = [];
|
|
2024
2189
|
this.insideFunctionDepth = 0;
|
|
2025
|
-
this.nonStrict = nonStrict;
|
|
2026
|
-
this.
|
|
2027
|
-
this.keepSpaces = keepSpaces;
|
|
2190
|
+
this.nonStrict = opt.nonStrict;
|
|
2191
|
+
this.preferShorthands = opt.preferShorthands;
|
|
2192
|
+
this.keepSpaces = opt.keepSpaces;
|
|
2193
|
+
this.inftyToOo = opt.inftyToOo;
|
|
2028
2194
|
}
|
|
2029
2195
|
writeBuffer(token) {
|
|
2030
2196
|
const str = token.toString();
|
|
@@ -2063,9 +2229,19 @@ var TypstWriter = class {
|
|
|
2063
2229
|
}
|
|
2064
2230
|
break;
|
|
2065
2231
|
}
|
|
2066
|
-
case "symbol":
|
|
2067
|
-
|
|
2232
|
+
case "symbol": {
|
|
2233
|
+
let content = node.content;
|
|
2234
|
+
if (this.preferShorthands) {
|
|
2235
|
+
if (shorthandMap.has(content)) {
|
|
2236
|
+
content = shorthandMap.get(content);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
if (this.inftyToOo && content === "infinity") {
|
|
2240
|
+
content = "oo";
|
|
2241
|
+
}
|
|
2242
|
+
this.queue.push(new TypstToken(0 /* SYMBOL */, content));
|
|
2068
2243
|
break;
|
|
2244
|
+
}
|
|
2069
2245
|
case "text":
|
|
2070
2246
|
this.queue.push(new TypstToken(2 /* TEXT */, node.content));
|
|
2071
2247
|
break;
|
|
@@ -2267,6 +2443,16 @@ var TypstWriter = class {
|
|
|
2267
2443
|
};
|
|
2268
2444
|
|
|
2269
2445
|
// src/convert.ts
|
|
2446
|
+
var TYPST_INTRINSIC_SYMBOLS = [
|
|
2447
|
+
"dim",
|
|
2448
|
+
"id",
|
|
2449
|
+
"im",
|
|
2450
|
+
"mod",
|
|
2451
|
+
"Pr",
|
|
2452
|
+
"sech",
|
|
2453
|
+
"csch"
|
|
2454
|
+
// 'sgn
|
|
2455
|
+
];
|
|
2270
2456
|
function tex_token_to_typst(token) {
|
|
2271
2457
|
if (/^[a-zA-Z0-9]$/.test(token)) {
|
|
2272
2458
|
return token;
|
|
@@ -2448,6 +2634,20 @@ function convert_tex_node_to_typst(node, options = {}) {
|
|
|
2448
2634
|
if (node.content === "\\mathbb" && arg0.type === "atom" && /^[A-Z]$/.test(arg0.content)) {
|
|
2449
2635
|
return new TypstNode("symbol", arg0.content + arg0.content);
|
|
2450
2636
|
}
|
|
2637
|
+
if (node.content === "\\overrightarrow") {
|
|
2638
|
+
return new TypstNode(
|
|
2639
|
+
"funcCall",
|
|
2640
|
+
"arrow",
|
|
2641
|
+
[arg0]
|
|
2642
|
+
);
|
|
2643
|
+
}
|
|
2644
|
+
if (node.content === "\\overleftarrow") {
|
|
2645
|
+
return new TypstNode(
|
|
2646
|
+
"funcCall",
|
|
2647
|
+
"accent",
|
|
2648
|
+
[arg0, new TypstNode("symbol", "arrow.l")]
|
|
2649
|
+
);
|
|
2650
|
+
}
|
|
2451
2651
|
if (node.content === "\\operatorname") {
|
|
2452
2652
|
const body = node.args;
|
|
2453
2653
|
if (body.length !== 1 || body[0].type !== "text") {
|
|
@@ -2495,14 +2695,8 @@ function convert_tex_node_to_typst(node, options = {}) {
|
|
|
2495
2695
|
delim = "|";
|
|
2496
2696
|
break;
|
|
2497
2697
|
case "Vmatrix": {
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
const group = new TypstNode("group", "", [
|
|
2501
|
-
new TypstNode("symbol", "||"),
|
|
2502
|
-
matrix2,
|
|
2503
|
-
new TypstNode("symbol", "||")
|
|
2504
|
-
]);
|
|
2505
|
-
return new TypstNode("funcCall", "lr", [group]);
|
|
2698
|
+
delim = new TypstToken(0 /* SYMBOL */, "bar.v.double");
|
|
2699
|
+
break;
|
|
2506
2700
|
}
|
|
2507
2701
|
default:
|
|
2508
2702
|
throw new TypstWriterError(`Unimplemented beginend: ${node.content}`, node);
|
|
@@ -2731,6 +2925,8 @@ function convert_typst_node_to_tex(node) {
|
|
|
2731
2925
|
}
|
|
2732
2926
|
|
|
2733
2927
|
// src/typst-parser.ts
|
|
2928
|
+
var TYPST_EMPTY_NODE = new TypstNode("empty", "");
|
|
2929
|
+
var TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
|
|
2734
2930
|
function eat_primes2(tokens, start) {
|
|
2735
2931
|
let pos = start;
|
|
2736
2932
|
while (pos < tokens.length && tokens[pos].eq(new TypstToken(1 /* ELEMENT */, "'"))) {
|
|
@@ -2738,126 +2934,67 @@ function eat_primes2(tokens, start) {
|
|
|
2738
2934
|
}
|
|
2739
2935
|
return pos - start;
|
|
2740
2936
|
}
|
|
2741
|
-
function
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2937
|
+
function generate_regex_for_shorthands() {
|
|
2938
|
+
const regex_list = TYPST_SHORTHANDS.map((s) => {
|
|
2939
|
+
s = s.replaceAll("|", "\\|");
|
|
2940
|
+
s = s.replaceAll(".", "\\.");
|
|
2941
|
+
s = s.replaceAll("[", "\\[");
|
|
2942
|
+
s = s.replaceAll("]", "\\]");
|
|
2943
|
+
return s;
|
|
2944
|
+
});
|
|
2945
|
+
return `(${regex_list.join("|")})`;
|
|
2747
2946
|
}
|
|
2748
|
-
var
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
case "\\": {
|
|
2800
|
-
if (pos + 1 >= typst.length) {
|
|
2801
|
-
throw new Error("Expecting a character after \\");
|
|
2802
|
-
}
|
|
2803
|
-
const firstTwoChars = typst.substring(pos, pos + 2);
|
|
2804
|
-
if (["\\$", "\\&", "\\#", "\\_"].includes(firstTwoChars)) {
|
|
2805
|
-
token = new TypstToken(1 /* ELEMENT */, firstTwoChars);
|
|
2806
|
-
pos += 2;
|
|
2807
|
-
} else if (["\\\n", "\\ "].includes(firstTwoChars)) {
|
|
2808
|
-
token = new TypstToken(6 /* CONTROL */, "\\");
|
|
2809
|
-
pos += 1;
|
|
2810
|
-
} else {
|
|
2811
|
-
token = new TypstToken(6 /* CONTROL */, "");
|
|
2812
|
-
pos++;
|
|
2813
|
-
}
|
|
2814
|
-
break;
|
|
2815
|
-
}
|
|
2816
|
-
case '"': {
|
|
2817
|
-
let newPos = pos + 1;
|
|
2818
|
-
while (newPos < typst.length) {
|
|
2819
|
-
if (typst[newPos] === '"' && typst[newPos - 1] !== "\\") {
|
|
2820
|
-
break;
|
|
2821
|
-
}
|
|
2822
|
-
newPos++;
|
|
2823
|
-
}
|
|
2824
|
-
let text = typst.substring(pos + 1, newPos);
|
|
2825
|
-
const chars = ['"', "\\"];
|
|
2826
|
-
for (const char of chars) {
|
|
2827
|
-
text = text.replaceAll("\\" + char, char);
|
|
2828
|
-
}
|
|
2829
|
-
token = new TypstToken(2 /* TEXT */, text);
|
|
2830
|
-
pos = newPos + 1;
|
|
2831
|
-
break;
|
|
2832
|
-
}
|
|
2833
|
-
default: {
|
|
2834
|
-
if (isdigit(firstChar)) {
|
|
2835
|
-
let newPos = pos;
|
|
2836
|
-
while (newPos < typst.length && isdigit(typst[newPos])) {
|
|
2837
|
-
newPos += 1;
|
|
2838
|
-
}
|
|
2839
|
-
if (newPos < typst.length && typst[newPos] === ".") {
|
|
2840
|
-
newPos += 1;
|
|
2841
|
-
while (newPos < typst.length && isdigit(typst[newPos])) {
|
|
2842
|
-
newPos += 1;
|
|
2843
|
-
}
|
|
2844
|
-
}
|
|
2845
|
-
token = new TypstToken(1 /* ELEMENT */, typst.slice(pos, newPos));
|
|
2846
|
-
} else if ("+-*/='<>!.,;?()[]|".includes(firstChar)) {
|
|
2847
|
-
token = new TypstToken(1 /* ELEMENT */, firstChar);
|
|
2848
|
-
} else if (isalpha(firstChar)) {
|
|
2849
|
-
const identifier = eat_identifier_name(typst, pos);
|
|
2850
|
-
const _type = identifier.length === 1 ? 1 /* ELEMENT */ : 0 /* SYMBOL */;
|
|
2851
|
-
token = new TypstToken(_type, identifier);
|
|
2852
|
-
} else {
|
|
2853
|
-
token = new TypstToken(1 /* ELEMENT */, firstChar);
|
|
2854
|
-
}
|
|
2855
|
-
pos += token.value.length;
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
tokens.push(token);
|
|
2859
|
-
}
|
|
2860
|
-
return tokens;
|
|
2947
|
+
var REGEX_SHORTHANDS = generate_regex_for_shorthands();
|
|
2948
|
+
var rules_map2 = /* @__PURE__ */ new Map([
|
|
2949
|
+
[String.raw`//[^\n]*`, (s) => new TypstToken(3 /* COMMENT */, s.text().substring(2))],
|
|
2950
|
+
[String.raw`/`, (s) => new TypstToken(1 /* ELEMENT */, s.text())],
|
|
2951
|
+
[String.raw`[_^&]`, (s) => new TypstToken(6 /* CONTROL */, s.text())],
|
|
2952
|
+
[String.raw`\r?\n`, (_s) => new TypstToken(7 /* NEWLINE */, "\n")],
|
|
2953
|
+
[String.raw`\s+`, (s) => new TypstToken(4 /* SPACE */, s.text())],
|
|
2954
|
+
[String.raw`\\[$&#_]`, (s) => new TypstToken(1 /* ELEMENT */, s.text())],
|
|
2955
|
+
[String.raw`\\\n`, (s) => {
|
|
2956
|
+
return [
|
|
2957
|
+
new TypstToken(6 /* CONTROL */, "\\"),
|
|
2958
|
+
new TypstToken(7 /* NEWLINE */, "\n")
|
|
2959
|
+
];
|
|
2960
|
+
}],
|
|
2961
|
+
[String.raw`\\\s`, (s) => {
|
|
2962
|
+
return [
|
|
2963
|
+
new TypstToken(6 /* CONTROL */, "\\"),
|
|
2964
|
+
new TypstToken(4 /* SPACE */, " ")
|
|
2965
|
+
];
|
|
2966
|
+
}],
|
|
2967
|
+
// this backslash is dummy and will be ignored in later stages
|
|
2968
|
+
[String.raw`\\\S`, (_s) => new TypstToken(6 /* CONTROL */, "")],
|
|
2969
|
+
[
|
|
2970
|
+
String.raw`"([^"]|(\\"))*"`,
|
|
2971
|
+
(s) => {
|
|
2972
|
+
const text = s.text().substring(1, s.text().length - 1);
|
|
2973
|
+
text.replaceAll('\\"', '"');
|
|
2974
|
+
return new TypstToken(2 /* TEXT */, text);
|
|
2975
|
+
}
|
|
2976
|
+
],
|
|
2977
|
+
[
|
|
2978
|
+
REGEX_SHORTHANDS,
|
|
2979
|
+
(s) => {
|
|
2980
|
+
const shorthand = s.text();
|
|
2981
|
+
const symbol = reverseShorthandMap.get(shorthand);
|
|
2982
|
+
return new TypstToken(0 /* SYMBOL */, symbol);
|
|
2983
|
+
}
|
|
2984
|
+
],
|
|
2985
|
+
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(1 /* ELEMENT */, s.text())],
|
|
2986
|
+
[String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(1 /* ELEMENT */, s.text())],
|
|
2987
|
+
[String.raw`[a-zA-Z\.]+`, (s) => {
|
|
2988
|
+
return new TypstToken(s.text().length === 1 ? 1 /* ELEMENT */ : 0 /* SYMBOL */, s.text());
|
|
2989
|
+
}],
|
|
2990
|
+
[String.raw`.`, (s) => new TypstToken(1 /* ELEMENT */, s.text())]
|
|
2991
|
+
]);
|
|
2992
|
+
var spec2 = {
|
|
2993
|
+
"start": rules_map2
|
|
2994
|
+
};
|
|
2995
|
+
function tokenize_typst(input) {
|
|
2996
|
+
const lexer = new JSLex(spec2);
|
|
2997
|
+
return lexer.collect(input);
|
|
2861
2998
|
}
|
|
2862
2999
|
function find_closing_match2(tokens, start) {
|
|
2863
3000
|
assert(tokens[start].isOneOf([LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET2]));
|
|
@@ -3279,27 +3416,22 @@ function tex2typst(tex, options) {
|
|
|
3279
3416
|
const opt = {
|
|
3280
3417
|
nonStrict: true,
|
|
3281
3418
|
preferTypstIntrinsic: true,
|
|
3419
|
+
preferShorthands: true,
|
|
3282
3420
|
keepSpaces: false,
|
|
3283
3421
|
fracToSlash: true,
|
|
3422
|
+
inftyToOo: false,
|
|
3284
3423
|
customTexMacros: {}
|
|
3285
3424
|
};
|
|
3286
|
-
if (options) {
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
opt.preferTypstIntrinsic = options.preferTypstIntrinsic;
|
|
3292
|
-
}
|
|
3293
|
-
if (options.customTexMacros) {
|
|
3294
|
-
opt.customTexMacros = options.customTexMacros;
|
|
3295
|
-
}
|
|
3296
|
-
if (options.fracToSlash !== void 0) {
|
|
3297
|
-
opt.fracToSlash = options.fracToSlash;
|
|
3425
|
+
if (options !== void 0) {
|
|
3426
|
+
for (const key in opt) {
|
|
3427
|
+
if (options[key] !== void 0) {
|
|
3428
|
+
opt[key] = options[key];
|
|
3429
|
+
}
|
|
3298
3430
|
}
|
|
3299
3431
|
}
|
|
3300
3432
|
const texTree = parseTex(tex, opt.customTexMacros);
|
|
3301
3433
|
const typstTree = convert_tex_node_to_typst(texTree, opt);
|
|
3302
|
-
const writer = new TypstWriter(opt
|
|
3434
|
+
const writer = new TypstWriter(opt);
|
|
3303
3435
|
writer.serialize(typstTree);
|
|
3304
3436
|
return writer.finalize();
|
|
3305
3437
|
}
|