tex2typst 0.6.0 → 0.6.2

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
@@ -323,8 +323,8 @@ function array_intersperse(array, sep) {
323
323
  return array.flatMap((x, i) => i !== array.length - 1 ? [x, sep] : [x]);
324
324
  }
325
325
 
326
- // src/jslex.ts
327
- var EOF = {};
326
+ // src/lex.ts
327
+ var EOF = null;
328
328
  function matchcompare(m1, m2) {
329
329
  const m1_len = m1.reMatchArray[0].length;
330
330
  const m2_len = m2.reMatchArray[0].length;
@@ -334,114 +334,31 @@ function matchcompare(m1, m2) {
334
334
  return m1.index - m2.index;
335
335
  }
336
336
  }
337
+ var ScanResult = class _ScanResult {
338
+ result;
339
+ status;
340
+ constructor(status, result) {
341
+ this.result = result;
342
+ this.status = status;
343
+ }
344
+ static Accepted(result) {
345
+ return new _ScanResult(0 /* ACCEPTED */, result);
346
+ }
347
+ static Rejected() {
348
+ return new _ScanResult(1 /* REJECTED */, []);
349
+ }
350
+ static Error(message) {
351
+ return new _ScanResult(2 /* ERROR */, []);
352
+ }
353
+ };
337
354
  var Scanner = class {
338
355
  _input;
339
- _lexer;
356
+ rules;
340
357
  // position within input stream
341
358
  _pos = 0;
342
- // current line number
343
- _line = 0;
344
- // current column number
345
- _col = 0;
346
- _offset = 0;
347
- _less = null;
348
- _go = false;
349
- _newstate = null;
350
- _state;
351
- _text = null;
352
- _leng = null;
353
- _reMatchArray = null;
354
- constructor(input, lexer) {
359
+ constructor(input, rules) {
355
360
  this._input = input;
356
- this._lexer = lexer;
357
- this._state = lexer.states[0];
358
- }
359
- /**
360
- * Analogous to yytext and yyleng in lex - will be set during scan.
361
- */
362
- text() {
363
- return this._text;
364
- }
365
- leng() {
366
- return this._leng;
367
- }
368
- reMatchArray() {
369
- return this._reMatchArray;
370
- }
371
- /**
372
- * Position of in stream, line number and column number of match.
373
- */
374
- pos() {
375
- return this._pos;
376
- }
377
- line() {
378
- return this._line;
379
- }
380
- column() {
381
- return this._col;
382
- }
383
- /**
384
- * Analogous to input() in lex.
385
- * @return {string} The next character in the stream.
386
- */
387
- input() {
388
- return this._input.charAt(this._pos + this._leng + this._offset++);
389
- }
390
- /**
391
- * Similar to unput() in lex, but does not allow modifying the stream.
392
- * @return {int} The offset position after the operation.
393
- */
394
- unput() {
395
- return this._offset = this._offset > 0 ? this._offset-- : 0;
396
- }
397
- /**
398
- * Analogous to yyless(n) in lex - retains the first n characters from this pattern, and returns
399
- * the rest to the input stream, such that they will be used in the next pattern-matching operation.
400
- * @param {int} n Number of characters to retain.
401
- * @return {int} Length of the stream after the operation has completed.
402
- */
403
- less(n) {
404
- this._less = n;
405
- this._offset = 0;
406
- this._text = this._text.substring(0, n);
407
- return this._leng = this._text.length;
408
- }
409
- /**
410
- * Like less(), but instead of retaining the first n characters, it chops off the last n.
411
- * @param {int} n Number of characters to chop.
412
- * @return {int} Length of the stream after the operation has completed.
413
- */
414
- pushback(n) {
415
- return this.less(this._leng - n);
416
- }
417
- /**
418
- * Similar to REJECT in lex, except it doesn't break the current execution context.
419
- * TIP: reject() should be the last instruction in a spec callback.
420
- */
421
- reject() {
422
- this._go = true;
423
- }
424
- /**
425
- * Analogous to BEGIN in lex - sets the named state (start condition).
426
- * @param {string|int} state Name of state to switch to, or ordinal number (0 is first, etc).
427
- * @return {string} The new state on successful switch, throws exception on failure.
428
- */
429
- begin(state) {
430
- if (this._lexer.specification[state]) {
431
- return this._newstate = state;
432
- }
433
- const s = this._lexer.states[parseInt(state)];
434
- if (s) {
435
- return this._newstate = s;
436
- }
437
- throw "Unknown state '" + state + "' requested";
438
- }
439
- /**
440
- * Simple accessor for reading in the current state.
441
- * @return {string} The current state.
442
- */
443
- state() {
444
- return this._state;
361
+ this.rules = rules;
445
362
  }
446
363
  /**
447
364
  * Scan method to be returned to caller - grabs the next token and fires appropriate calback.
@@ -452,7 +369,7 @@ var Scanner = class {
452
369
  return EOF;
453
370
  }
454
371
  const str = this._input.substring(this._pos);
455
- const rules = this._lexer.specification[this._state];
372
+ const rules = this.rules;
456
373
  const matches = [];
457
374
  for (let i = 0; i < rules.length; i++) {
458
375
  const rule = rules[i];
@@ -469,87 +386,50 @@ var Scanner = class {
469
386
  throw new Error("No match found for input '" + str + "'");
470
387
  }
471
388
  matches.sort(matchcompare);
472
- this._go = true;
473
- let result;
474
- let matched_text;
475
- for (let j = 0, n = matches.length; j < n && this._go; j++) {
476
- this._offset = 0;
477
- this._less = null;
478
- this._go = false;
479
- this._newstate = null;
480
- const m = matches[j];
481
- matched_text = m.reMatchArray[0];
482
- this._text = matched_text;
483
- this._leng = matched_text.length;
484
- this._reMatchArray = m.reMatchArray;
485
- result = m.rule.action(this);
486
- if (this._newstate && this._newstate != this._state) {
487
- this._state = this._newstate;
488
- break;
389
+ for (const m of matches) {
390
+ const matched_text = m.reMatchArray[0];
391
+ const result = m.rule.action({
392
+ pos: this._pos,
393
+ text: matched_text,
394
+ reMatchArray: m.reMatchArray
395
+ });
396
+ if (result.status === 0 /* ACCEPTED */) {
397
+ this._pos += matched_text.length;
398
+ return result.result;
489
399
  }
490
400
  }
491
- const text = this._less === null ? matched_text : matched_text.substring(0, this._less);
492
- const len = text.length;
493
- this._pos += len + this._offset;
494
- const nlm = text.match(/\n/g);
495
- if (nlm !== null) {
496
- this._line += nlm.length;
497
- this._col = len - text.lastIndexOf("\n") - 1;
498
- } else {
499
- this._col += len;
500
- }
501
- return result;
401
+ throw new Error("No match found for input '" + str + "'");
502
402
  }
503
403
  };
504
404
  var JSLex = class {
505
- states;
506
- specification;
507
- constructor(spec3) {
508
- this.states = Object.keys(spec3);
509
- this.specification = {};
510
- for (const s of this.states) {
511
- const rule_map = spec3[s];
512
- if (s in this.specification) {
513
- throw "Duplicate state declaration encountered for state '" + s + "'";
514
- }
515
- this.specification[s] = [];
516
- for (const [k, v] of rule_map.entries()) {
517
- let re;
518
- try {
519
- re = new RegExp("^" + k);
520
- } catch (err) {
521
- throw "Invalid regexp '" + k + "' in state '" + s + "' (" + err.message + ")";
522
- }
523
- this.specification[s].push({
524
- re,
525
- action: v
526
- });
405
+ rules = [];
406
+ constructor(ruleMap) {
407
+ for (const [k, v] of ruleMap.entries()) {
408
+ let re;
409
+ try {
410
+ re = new RegExp("^" + k);
411
+ } catch (err) {
412
+ throw "Invalid regexp '" + k + "' (" + err.message + ")";
527
413
  }
414
+ this.rules.push({
415
+ re,
416
+ action: v
417
+ });
528
418
  }
529
419
  }
530
- /**
531
- * Scanner function - makes a new scanner object which is used to get tokens one at a time.
532
- * @param {string} input Input text to tokenize.
533
- * @return {function} Scanner function.
534
- */
535
- scanner(input) {
536
- return new Scanner(input, this);
537
- }
538
420
  /**
539
421
  * Similar to lex's yylex() function, consumes all input, calling calback for each token.
540
422
  * @param {string} input Text to lex.
541
423
  * @param {function} callback Function to execute for each token.
542
424
  */
543
425
  lex(input, callback) {
544
- const scanner = this.scanner(input);
426
+ const scanner = new Scanner(input, this.rules);
545
427
  while (true) {
546
428
  const token = scanner.scan();
547
429
  if (token === EOF) {
548
- return;
549
- }
550
- if (token !== void 0) {
551
- callback(token);
430
+ break;
552
431
  }
432
+ callback(token);
553
433
  }
554
434
  }
555
435
  /**
@@ -647,8 +527,8 @@ var rules_map = /* @__PURE__ */ new Map([
647
527
  [
648
528
  String.raw`\\begin{(array|subarry)}{(.+?)}`,
649
529
  (s) => {
650
- const match = s.reMatchArray();
651
- return [
530
+ const match = s.reMatchArray;
531
+ return ScanResult.Accepted([
652
532
  new TexToken(2 /* COMMAND */, "\\begin"),
653
533
  new TexToken(7 /* CONTROL */, "{"),
654
534
  new TexToken(3 /* LITERAL */, match[1]),
@@ -656,74 +536,69 @@ var rules_map = /* @__PURE__ */ new Map([
656
536
  new TexToken(7 /* CONTROL */, "{"),
657
537
  new TexToken(3 /* LITERAL */, match[2]),
658
538
  new TexToken(7 /* CONTROL */, "}")
659
- ];
539
+ ]);
660
540
  }
661
541
  ],
662
542
  [
663
543
  String.raw`\\(text|operatorname\*?|textcolor|begin|end|hspace|array)\s*{(.+?)}`,
664
544
  (s) => {
665
- const match = s.reMatchArray();
666
- return [
545
+ const match = s.reMatchArray;
546
+ return ScanResult.Accepted([
667
547
  new TexToken(2 /* COMMAND */, "\\" + match[1]),
668
548
  new TexToken(7 /* CONTROL */, "{"),
669
549
  new TexToken(3 /* LITERAL */, unescape(match[2])),
670
550
  new TexToken(7 /* CONTROL */, "}")
671
- ];
551
+ ]);
672
552
  }
673
553
  ],
674
- [String.raw`%[^\n]*`, (s) => new TexToken(4 /* COMMENT */, s.text().substring(1))],
675
- [String.raw`[{}_^&]`, (s) => new TexToken(7 /* CONTROL */, s.text())],
676
- [String.raw`\\[\\,:;!> ]`, (s) => new TexToken(7 /* CONTROL */, s.text())],
677
- [String.raw`~`, (s) => new TexToken(7 /* CONTROL */, s.text())],
678
- [String.raw`\r?\n`, (_s) => new TexToken(6 /* NEWLINE */, "\n")],
679
- [String.raw`\s+`, (s) => new TexToken(5 /* SPACE */, s.text())],
680
- [String.raw`\\[{}%$&#_|]`, (s) => new TexToken(1 /* ELEMENT */, s.text())],
554
+ [String.raw`%[^\n]*`, (s) => ScanResult.Accepted(new TexToken(4 /* COMMENT */, s.text.substring(1)))],
555
+ [String.raw`[{}_^&]`, (s) => ScanResult.Accepted([new TexToken(7 /* CONTROL */, s.text)])],
556
+ [String.raw`\\[\\,:;!> ]`, (s) => ScanResult.Accepted([new TexToken(7 /* CONTROL */, s.text)])],
557
+ [String.raw`~`, (s) => ScanResult.Accepted([new TexToken(7 /* CONTROL */, s.text)])],
558
+ [String.raw`\r?\n`, (_s) => ScanResult.Accepted([new TexToken(6 /* NEWLINE */, "\n")])],
559
+ [String.raw`\s+`, (s) => ScanResult.Accepted([new TexToken(5 /* SPACE */, s.text)])],
560
+ [String.raw`\\[{}%$&#_|]`, (s) => ScanResult.Accepted([new TexToken(1 /* ELEMENT */, s.text)])],
681
561
  // e.g. match `\frac13`, `\frac1 b`, `\frac a b`
682
562
  [String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])\s*([0-9a-zA-Z])`, (s) => {
683
- const match = s.reMatchArray();
563
+ const match = s.reMatchArray;
684
564
  const command = match[1];
685
565
  if (TEX_BINARY_COMMANDS.includes(command.substring(1))) {
686
566
  const arg1 = match[2].trimStart();
687
567
  const arg2 = match[3];
688
- return [
568
+ return ScanResult.Accepted([
689
569
  new TexToken(2 /* COMMAND */, command),
690
570
  new TexToken(1 /* ELEMENT */, arg1),
691
571
  new TexToken(1 /* ELEMENT */, arg2)
692
- ];
572
+ ]);
693
573
  } else {
694
- s.reject();
695
- return [];
574
+ return ScanResult.Rejected();
696
575
  }
697
576
  }],
698
577
  // e.g. match `\sqrt3`, `\sqrt a`
699
578
  [String.raw`(\\[a-zA-Z]+)(\s*\d|\s+[a-zA-Z])`, (s) => {
700
- const match = s.reMatchArray();
579
+ const match = s.reMatchArray;
701
580
  const command = match[1];
702
581
  if (TEX_UNARY_COMMANDS.includes(command.substring(1))) {
703
582
  const arg1 = match[2].trimStart();
704
- return [
583
+ return ScanResult.Accepted([
705
584
  new TexToken(2 /* COMMAND */, command),
706
585
  new TexToken(1 /* ELEMENT */, arg1)
707
- ];
586
+ ]);
708
587
  } else {
709
- s.reject();
710
- return [];
588
+ return ScanResult.Rejected();
711
589
  }
712
590
  }],
713
- [String.raw`\\[a-zA-Z]+`, (s) => new TexToken(2 /* COMMAND */, s.text())],
591
+ [String.raw`\\[a-zA-Z]+`, (s) => ScanResult.Accepted(new TexToken(2 /* COMMAND */, s.text))],
714
592
  // Numbers like "123", "3.14"
715
- [String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TexToken(1 /* ELEMENT */, s.text())],
716
- [String.raw`[a-zA-Z]`, (s) => new TexToken(1 /* ELEMENT */, s.text())],
717
- [String.raw`[+\-*/='<>!.,;:?()\[\]|]`, (s) => new TexToken(1 /* ELEMENT */, s.text())],
593
+ [String.raw`[0-9]+(\.[0-9]+)?`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
594
+ [String.raw`[a-zA-Z]`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
595
+ [String.raw`[+\-*/='<>!.,;:?()\[\]|]`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
718
596
  // non-ASCII characters
719
- [String.raw`[^\x00-\x7F]`, (s) => new TexToken(1 /* ELEMENT */, s.text())],
720
- [String.raw`.`, (s) => new TexToken(8 /* UNKNOWN */, s.text())]
597
+ [String.raw`[^\x00-\x7F]`, (s) => ScanResult.Accepted(new TexToken(1 /* ELEMENT */, s.text))],
598
+ [String.raw`.`, (s) => ScanResult.Accepted([new TexToken(8 /* UNKNOWN */, s.text)])]
721
599
  ]);
722
- var spec = {
723
- "start": rules_map
724
- };
725
600
  function tokenize_tex(input) {
726
- const lexer = new JSLex(spec);
601
+ const lexer = new JSLex(rules_map);
727
602
  return lexer.collect(input);
728
603
  }
729
604
 
@@ -1398,6 +1273,9 @@ var TypstTerminal = class extends TypstNode {
1398
1273
  }
1399
1274
  return [this.head];
1400
1275
  }
1276
+ bottomTopTraversalTransform(transform) {
1277
+ return transform(this);
1278
+ }
1401
1279
  };
1402
1280
  var TypstTokenQueue = class {
1403
1281
  queue = [];
@@ -1433,7 +1311,7 @@ var TypstTokenQueue = class {
1433
1311
  return res;
1434
1312
  }
1435
1313
  };
1436
- var TypstGroup = class extends TypstNode {
1314
+ var TypstGroup = class _TypstGroup extends TypstNode {
1437
1315
  items;
1438
1316
  constructor(items) {
1439
1317
  super("group", TypstToken.NONE);
@@ -1478,8 +1356,12 @@ var TypstGroup = class extends TypstNode {
1478
1356
  }
1479
1357
  return queue;
1480
1358
  }
1359
+ bottomTopTraversalTransform(transform) {
1360
+ const g = new _TypstGroup(this.items.map((n) => n.bottomTopTraversalTransform(transform)));
1361
+ return transform(g);
1362
+ }
1481
1363
  };
1482
- var TypstSupsub = class extends TypstNode {
1364
+ var TypstSupsub = class _TypstSupsub extends TypstNode {
1483
1365
  base;
1484
1366
  sup;
1485
1367
  sub;
@@ -1516,8 +1398,16 @@ var TypstSupsub = class extends TypstNode {
1516
1398
  }
1517
1399
  return queue;
1518
1400
  }
1401
+ bottomTopTraversalTransform(transform) {
1402
+ const s = new _TypstSupsub({
1403
+ base: this.base.bottomTopTraversalTransform(transform),
1404
+ sup: this.sup?.bottomTopTraversalTransform(transform) || null,
1405
+ sub: this.sub?.bottomTopTraversalTransform(transform) || null
1406
+ });
1407
+ return transform(s);
1408
+ }
1519
1409
  };
1520
- var TypstFuncCall = class extends TypstNode {
1410
+ var TypstFuncCall = class _TypstFuncCall extends TypstNode {
1521
1411
  args;
1522
1412
  constructor(head, args) {
1523
1413
  super("funcCall", head);
@@ -1557,8 +1447,13 @@ var TypstFuncCall = class extends TypstNode {
1557
1447
  env.insideFunctionDepth--;
1558
1448
  return queue;
1559
1449
  }
1450
+ bottomTopTraversalTransform(transform) {
1451
+ const f = new _TypstFuncCall(this.head, this.args.map((n) => n.bottomTopTraversalTransform(transform)));
1452
+ f.options = this.options;
1453
+ return transform(f);
1454
+ }
1560
1455
  };
1561
- var TypstFraction = class extends TypstNode {
1456
+ var TypstFraction = class _TypstFraction extends TypstNode {
1562
1457
  args;
1563
1458
  constructor(args) {
1564
1459
  super("fraction", TypstToken.NONE);
@@ -1581,10 +1476,14 @@ var TypstFraction = class extends TypstNode {
1581
1476
  queue.push(...denominator.serialize(env, options));
1582
1477
  return queue;
1583
1478
  }
1479
+ bottomTopTraversalTransform(transform) {
1480
+ const f = new _TypstFraction(this.args.map((n) => n.bottomTopTraversalTransform(transform)));
1481
+ return transform(f);
1482
+ }
1584
1483
  };
1585
1484
  var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
1586
1485
  var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
1587
- var TypstLeftright = class extends TypstNode {
1486
+ var TypstLeftright = class _TypstLeftright extends TypstNode {
1588
1487
  body;
1589
1488
  left;
1590
1489
  right;
@@ -1630,6 +1529,14 @@ var TypstLeftright = class extends TypstNode {
1630
1529
  }
1631
1530
  return queue;
1632
1531
  }
1532
+ bottomTopTraversalTransform(transform) {
1533
+ const l = new _TypstLeftright(this.head, {
1534
+ body: this.body.bottomTopTraversalTransform(transform),
1535
+ left: this.left,
1536
+ right: this.right
1537
+ });
1538
+ return transform(l);
1539
+ }
1633
1540
  };
1634
1541
  var TypstMatrixLike = class _TypstMatrixLike extends TypstNode {
1635
1542
  matrix;
@@ -1697,10 +1604,16 @@ var TypstMatrixLike = class _TypstMatrixLike extends TypstNode {
1697
1604
  }
1698
1605
  return queue;
1699
1606
  }
1607
+ bottomTopTraversalTransform(transform) {
1608
+ const m = this.matrix.map((row) => row.map((cell) => cell.bottomTopTraversalTransform(transform)));
1609
+ const ml = new _TypstMatrixLike(this.head, m);
1610
+ ml.options = this.options;
1611
+ return transform(ml);
1612
+ }
1700
1613
  static MAT = new TypstToken(1 /* SYMBOL */, "mat");
1701
1614
  static CASES = new TypstToken(1 /* SYMBOL */, "cases");
1702
1615
  };
1703
- var TypstMarkupFunc = class extends TypstNode {
1616
+ var TypstMarkupFunc = class _TypstMarkupFunc extends TypstNode {
1704
1617
  /*
1705
1618
  In idealized situations, for `#heading([some text and math $x + y$ example])`,
1706
1619
  fragments would be [TypstMarkup{"some text and math "}, TypstNode{"x + y"}, TypstMarkup{" example"}]
@@ -1747,6 +1660,11 @@ var TypstMarkupFunc = class extends TypstNode {
1747
1660
  queue.push(new TypstToken(3 /* LITERAL */, "]"));
1748
1661
  return queue;
1749
1662
  }
1663
+ bottomTopTraversalTransform(transform) {
1664
+ const mf = new _TypstMarkupFunc(this.head, this.fragments.map((n) => n.bottomTopTraversalTransform(transform)));
1665
+ mf.options = this.options;
1666
+ return transform(mf);
1667
+ }
1750
1668
  };
1751
1669
 
1752
1670
  // src/typst-writer.ts
@@ -1866,7 +1784,6 @@ var symbolMap = /* @__PURE__ */ new Map([
1866
1784
  ["neq", "eq.not"],
1867
1785
  ["dot", "dot"],
1868
1786
  ["ddot", "dot.double"],
1869
- ["doteq", "dot(eq)"],
1870
1787
  ["dots", "dots.h"],
1871
1788
  ["vdots", "dots.v"],
1872
1789
  ["ddots", "dots.down"],
@@ -2939,7 +2856,6 @@ var reverseSymbolMap = /* @__PURE__ */ new Map();
2939
2856
  for (const [key, value] of Array.from(symbolMap.entries()).reverse()) {
2940
2857
  reverseSymbolMap.set(value, key);
2941
2858
  }
2942
- reverseSymbolMap.set("oo", "infty");
2943
2859
  var typst_to_tex_map = /* @__PURE__ */ new Map([
2944
2860
  ["top", "top"],
2945
2861
  ["frac", "frac"],
@@ -3024,8 +2940,6 @@ function tex_token_to_typst(token, options) {
3024
2940
  case 7 /* CONTROL */: {
3025
2941
  if (token.value === "\\\\") {
3026
2942
  return new TypstToken(7 /* CONTROL */, "\\");
3027
- } else if (token.value === "\\!") {
3028
- return new TypstToken(1 /* SYMBOL */, "#h(-math.thin.amount)");
3029
2943
  } else if (token.value === "~") {
3030
2944
  const typst_symbol = symbolMap.get("~");
3031
2945
  return new TypstToken(1 /* SYMBOL */, typst_symbol);
@@ -3125,6 +3039,12 @@ function convert_tex_node_to_typst(abstractNode, options) {
3125
3039
  switch (abstractNode.type) {
3126
3040
  case "terminal": {
3127
3041
  const node2 = abstractNode;
3042
+ if (node2.head.eq(new TexToken(7 /* CONTROL */, "\\!"))) {
3043
+ return new TypstFuncCall(
3044
+ new TypstToken(1 /* SYMBOL */, "#h"),
3045
+ [new TypstToken(3 /* LITERAL */, "-math.thin.amount").toNode()]
3046
+ );
3047
+ }
3128
3048
  return tex_token_to_typst(node2.head, options).toNode();
3129
3049
  }
3130
3050
  case "text": {
@@ -3550,21 +3470,6 @@ function convert_typst_node_to_tex(abstractNode, options) {
3550
3470
  case "terminal": {
3551
3471
  const node = abstractNode;
3552
3472
  if (node.head.type === 1 /* SYMBOL */) {
3553
- if (node.head.value === "eq.def") {
3554
- return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\overset"), [
3555
- new TexText(new TexToken(3 /* LITERAL */, "def")),
3556
- new TexToken(1 /* ELEMENT */, "=").toNode()
3557
- ]);
3558
- }
3559
- if (node.head.value === "comma") {
3560
- return new TexToken(1 /* ELEMENT */, ",").toNode();
3561
- }
3562
- if (node.head.value === "dif") {
3563
- return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\mathrm"), [new TexToken(1 /* ELEMENT */, "d").toNode()]);
3564
- }
3565
- if (node.head.value === "hyph" || node.head.value === "hyph.minus") {
3566
- return new TexText(new TexToken(3 /* LITERAL */, "-"));
3567
- }
3568
3473
  if (/^([A-Z])\1$/.test(node.head.value)) {
3569
3474
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\mathbb"), [
3570
3475
  new TexToken(1 /* ELEMENT */, node.head.value[0]).toNode()
@@ -3854,64 +3759,69 @@ function generate_regex_for_shorthands() {
3854
3759
  }
3855
3760
  var REGEX_SHORTHANDS = generate_regex_for_shorthands();
3856
3761
  var rules_map2 = /* @__PURE__ */ new Map([
3857
- [String.raw`//[^\n]*`, (s) => new TypstToken(5 /* COMMENT */, s.text().substring(2))],
3858
- [String.raw`/`, (s) => new TypstToken(2 /* ELEMENT */, s.text())],
3859
- [String.raw`[_^&]`, (s) => new TypstToken(7 /* CONTROL */, s.text())],
3860
- [String.raw`\r?\n`, (_s) => new TypstToken(8 /* NEWLINE */, "\n")],
3861
- [String.raw`\s+`, (s) => new TypstToken(6 /* SPACE */, s.text())],
3862
- [String.raw`\\[$&#_]`, (s) => new TypstToken(2 /* ELEMENT */, s.text())],
3863
- [String.raw`\\\n`, (s) => {
3864
- return [
3762
+ [String.raw`//[^\n]*`, (s) => ScanResult.Accepted(new TypstToken(5 /* COMMENT */, s.text.substring(2)))],
3763
+ [String.raw`/`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
3764
+ [String.raw`[_^&]`, (s) => ScanResult.Accepted(new TypstToken(7 /* CONTROL */, s.text))],
3765
+ [String.raw`\r?\n`, (_s) => ScanResult.Accepted(new TypstToken(8 /* NEWLINE */, "\n"))],
3766
+ [String.raw`\s+`, (s) => ScanResult.Accepted(new TypstToken(6 /* SPACE */, s.text))],
3767
+ [String.raw`\\[$&#_]`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
3768
+ [
3769
+ String.raw`\\\n`,
3770
+ (s) => ScanResult.Accepted([
3865
3771
  new TypstToken(7 /* CONTROL */, "\\"),
3866
3772
  new TypstToken(8 /* NEWLINE */, "\n")
3867
- ];
3868
- }],
3773
+ ])
3774
+ ],
3869
3775
  [String.raw`\\\s`, (s) => {
3870
- return [
3776
+ return ScanResult.Accepted([
3871
3777
  new TypstToken(7 /* CONTROL */, "\\"),
3872
3778
  new TypstToken(6 /* SPACE */, " ")
3873
- ];
3779
+ ]);
3874
3780
  }],
3875
3781
  // this backslash is dummy and will be ignored in later stages
3876
- [String.raw`\\\S`, (_s) => new TypstToken(7 /* CONTROL */, "")],
3782
+ [String.raw`\\\S`, (_s) => ScanResult.Accepted(new TypstToken(7 /* CONTROL */, ""))],
3877
3783
  [
3878
3784
  String.raw`"([^"]|(\\"))*"`,
3879
3785
  (s) => {
3880
- const text = s.text().substring(1, s.text().length - 1);
3786
+ const text = s.text.substring(1, s.text.length - 1);
3881
3787
  text.replaceAll('\\"', '"');
3882
- return new TypstToken(4 /* TEXT */, text);
3788
+ return ScanResult.Accepted(new TypstToken(4 /* TEXT */, text));
3883
3789
  }
3884
3790
  ],
3885
3791
  [
3886
3792
  REGEX_SHORTHANDS,
3887
3793
  (s) => {
3888
- const shorthand = s.text();
3794
+ const shorthand = s.text;
3889
3795
  const symbol = reverseShorthandMap.get(shorthand);
3890
- return new TypstToken(1 /* SYMBOL */, symbol);
3796
+ return ScanResult.Accepted(new TypstToken(1 /* SYMBOL */, symbol));
3891
3797
  }
3892
3798
  ],
3893
- [String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(2 /* ELEMENT */, s.text())],
3894
- [String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(2 /* ELEMENT */, s.text())],
3895
- [String.raw`#h\((.+?)\)`, (s) => {
3896
- const match = s.reMatchArray();
3897
- return [
3898
- new TypstToken(1 /* SYMBOL */, "#h"),
3899
- new TypstToken(2 /* ELEMENT */, "("),
3900
- new TypstToken(3 /* LITERAL */, match[1]),
3901
- new TypstToken(2 /* ELEMENT */, ")")
3902
- ];
3903
- }],
3904
- [String.raw`#none`, (s) => new TypstToken(0 /* NONE */, s.text())],
3799
+ [String.raw`[0-9]+(\.[0-9]+)?`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
3800
+ [String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))],
3801
+ [
3802
+ String.raw`#h\((.+?)\)`,
3803
+ (s) => {
3804
+ const match = s.reMatchArray;
3805
+ return ScanResult.Accepted([
3806
+ new TypstToken(1 /* SYMBOL */, "#h"),
3807
+ new TypstToken(2 /* ELEMENT */, "("),
3808
+ new TypstToken(3 /* LITERAL */, match[1]),
3809
+ new TypstToken(2 /* ELEMENT */, ")")
3810
+ ]);
3811
+ }
3812
+ ],
3813
+ [String.raw`#none`, (s) => ScanResult.Accepted(new TypstToken(0 /* NONE */, s.text))],
3814
+ [
3815
+ String.raw`#none`,
3816
+ (s) => ScanResult.Accepted(new TypstToken(0 /* NONE */, s.text))
3817
+ ],
3905
3818
  [String.raw`#?[a-zA-Z\.]+`, (s) => {
3906
- return new TypstToken(s.text().length === 1 ? 2 /* ELEMENT */ : 1 /* SYMBOL */, s.text());
3819
+ return ScanResult.Accepted(new TypstToken(s.text.length === 1 ? 2 /* ELEMENT */ : 1 /* SYMBOL */, s.text));
3907
3820
  }],
3908
- [String.raw`.`, (s) => new TypstToken(2 /* ELEMENT */, s.text())]
3821
+ [String.raw`.`, (s) => ScanResult.Accepted(new TypstToken(2 /* ELEMENT */, s.text))]
3909
3822
  ]);
3910
- var spec2 = {
3911
- "start": rules_map2
3912
- };
3913
3823
  function tokenize_typst(input) {
3914
- const lexer = new JSLex(spec2);
3824
+ const lexer = new JSLex(rules_map2);
3915
3825
  return lexer.collect(input);
3916
3826
  }
3917
3827
 
@@ -4324,7 +4234,8 @@ var TEX_PREDEFINED_MACROS = /* @__PURE__ */ new Map([
4324
4234
  ["\\varUpsilon", "\\mathit{\\Upsilon}"],
4325
4235
  ["\\varPhi", "\\mathit{\\Phi}"],
4326
4236
  ["\\varPsi", "\\mathit{\\Psi}"],
4327
- ["\\varOmega", "\\mathit{\\Omega}"]
4237
+ ["\\varOmega", "\\mathit{\\Omega}"],
4238
+ ["\\doteq", "\\dot{=}"]
4328
4239
  ]);
4329
4240
  function _expand_tex_predefined_macros(node) {
4330
4241
  switch (node.type) {
@@ -4345,6 +4256,39 @@ function expand_tex_predefined_macros(node) {
4345
4256
  return node.bottomTopTraversalTransform(_expand_tex_predefined_macros);
4346
4257
  }
4347
4258
 
4259
+ // src/typst-semantic-analyais.ts
4260
+ var TEX_PREDEFINED_VARIABLES = /* @__PURE__ */ new Map([
4261
+ ["dif", "upright(d)"],
4262
+ ["eq.def", 'limits(=)^"def"'],
4263
+ ["oo", "infinity"],
4264
+ ["comma", ","],
4265
+ ["hyph", '"-"'],
4266
+ ["hyph.minus", '"-"']
4267
+ /*
4268
+ ["AA", "bb(A)"],
4269
+ ["BB", "bb(B)"],
4270
+ ["CC", "bb(C)"],
4271
+ */
4272
+ ]);
4273
+ function _expand_typst_predefined_variables(node) {
4274
+ switch (node.type) {
4275
+ case "terminal": {
4276
+ if (node.head.type === 1 /* SYMBOL */) {
4277
+ if (TEX_PREDEFINED_VARIABLES.has(node.head.value)) {
4278
+ const target_str = TEX_PREDEFINED_VARIABLES.get(node.head.value);
4279
+ return parseTypst(target_str);
4280
+ }
4281
+ }
4282
+ }
4283
+ case "funcCall":
4284
+ default:
4285
+ return node;
4286
+ }
4287
+ }
4288
+ function expand_typst_predefined_variables(node) {
4289
+ return node.bottomTopTraversalTransform(_expand_typst_predefined_variables);
4290
+ }
4291
+
4348
4292
  // src/index.ts
4349
4293
  function tex2typst(tex, options = {}) {
4350
4294
  const opt = {
@@ -4384,7 +4328,8 @@ function typst2tex(typst, options = {}) {
4384
4328
  }
4385
4329
  }
4386
4330
  const typstTree = parseTypst(typst);
4387
- const texTree = convert_typst_node_to_tex(typstTree, opt);
4331
+ const preprocessedTypstTree = expand_typst_predefined_variables(typstTree);
4332
+ const texTree = convert_typst_node_to_tex(preprocessedTypstTree, opt);
4388
4333
  const writer = new TexWriter();
4389
4334
  writer.append(texTree);
4390
4335
  return writer.finalize();