tex2typst 0.0.17 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,27 +1,849 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tex2typst = tex2typst;
4
- const parser_1 = require("./parser");
5
- const writer_1 = require("./writer");
6
- function tex2typst(tex, options) {
7
- const opt = {
8
- nonStrict: false,
9
- preferTypstIntrinsic: true,
10
- customTexMacros: {}
11
- };
12
- if (options) {
13
- if (options.nonStrict) {
14
- opt.nonStrict = options.nonStrict;
1
+ // src/parser.ts
2
+ import katex from "katex";
3
+ function katexNodeToTexNode(node) {
4
+ try {
5
+ if (node.loc) {
6
+ delete node.loc;
7
+ }
8
+ let res = {};
9
+ switch (node.type) {
10
+ case "atom":
11
+ res.type = "atom";
12
+ res.content = node.text;
13
+ if (node.text === "\\{" || node.text === "\\}") {
14
+ res.content = node.text.substring(1);
15
+ } else if (node.text.startsWith("\\")) {
16
+ res.type = "symbol";
17
+ }
18
+ break;
19
+ case "mathord":
20
+ case "textord":
21
+ case "op":
22
+ case "cr":
23
+ res.type = "symbol";
24
+ res.content = node.text;
25
+ if (node.type === "op") {
26
+ res.content = node["name"];
27
+ } else if (node.type === "cr") {
28
+ res.content = "\\\\";
29
+ }
30
+ break;
31
+ case "genfrac":
32
+ res.type = "binaryFunc";
33
+ if (node["leftDelim"] === "(" && node["rightDelim"] === ")") {
34
+ res.content = "\\binom";
35
+ } else {
36
+ res.content = "\\frac";
37
+ }
38
+ res.args = [
39
+ katexNodeToTexNode(node["numer"]),
40
+ katexNodeToTexNode(node["denom"])
41
+ ];
42
+ break;
43
+ case "supsub":
44
+ res.type = "supsub";
45
+ res.irregularData = {};
46
+ if (node["base"]) {
47
+ res.irregularData.base = katexNodeToTexNode(node["base"]);
48
+ }
49
+ if (node["sup"]) {
50
+ res.irregularData.sup = katexNodeToTexNode(node["sup"]);
51
+ }
52
+ if (node["sub"]) {
53
+ res.irregularData.sub = katexNodeToTexNode(node["sub"]);
54
+ }
55
+ break;
56
+ case "mclass":
57
+ case "ordgroup":
58
+ res.type = "ordgroup";
59
+ res.args = node.body.map((n) => katexNodeToTexNode(n));
60
+ if (res.args.length === 1) {
61
+ res = res.args[0];
62
+ }
63
+ break;
64
+ case "leftright": {
65
+ const body = katexNodeToTexNode({
66
+ type: "ordgroup",
67
+ mode: "math",
68
+ body: node.body
69
+ });
70
+ res.type = "leftright";
71
+ let left = node["left"];
72
+ if (left === "\\{") {
73
+ left = "{";
74
+ }
75
+ let right = node["right"];
76
+ if (right === "\\}") {
77
+ right = "}";
78
+ }
79
+ const is_atom = (str) => ["(", ")", "[", "]", "{", "}"].includes(str);
80
+ res.args = [
81
+ { type: is_atom(left) ? "atom" : "symbol", content: left },
82
+ body,
83
+ { type: is_atom(right) ? "atom" : "symbol", content: right }
84
+ ];
85
+ break;
86
+ }
87
+ case "underline":
88
+ case "overline":
89
+ res.type = "unaryFunc";
90
+ res.content = "\\" + node.type;
91
+ res.args = [
92
+ katexNodeToTexNode(node["body"])
93
+ ];
94
+ break;
95
+ case "accent": {
96
+ res.type = "unaryFunc";
97
+ res.content = node["label"];
98
+ res.args = [
99
+ katexNodeToTexNode(node["base"])
100
+ ];
101
+ break;
102
+ }
103
+ case "sqrt":
104
+ if (node["index"]) {
105
+ res.irregularData = katexNodeToTexNode(node["index"]);
106
+ }
107
+ case "font":
108
+ case "operatorname":
109
+ res.type = "unaryFunc";
110
+ res.content = "\\" + node.type;
111
+ if (node.type === "font") {
112
+ res.content = "\\" + node["font"];
113
+ }
114
+ if (Array.isArray(node.body)) {
115
+ const obj = {
116
+ type: "ordgroup",
117
+ mode: "math",
118
+ body: node.body
119
+ };
120
+ res.args = [
121
+ katexNodeToTexNode(obj)
122
+ ];
123
+ } else {
124
+ res.args = [
125
+ katexNodeToTexNode(node.body)
126
+ ];
127
+ }
128
+ break;
129
+ case "horizBrace":
130
+ res.type = "unaryFunc";
131
+ res.content = node["label"];
132
+ res.args = [
133
+ katexNodeToTexNode(node["base"])
134
+ ];
135
+ break;
136
+ case "array":
137
+ if (node["colSeparationType"] === "align") {
138
+ res.type = "align";
139
+ } else {
140
+ res.type = "matrix";
141
+ }
142
+ res.irregularData = node.body.map((row) => {
143
+ return row.map((cell) => {
144
+ if (cell.type !== "styling" || cell.body.length !== 1) {
145
+ throw new KatexNodeToTexNodeError("Expecting cell.type==='\\styling' and cell.body.length===1", cell);
146
+ }
147
+ return katexNodeToTexNode(cell.body[0]);
148
+ });
149
+ });
150
+ break;
151
+ case "text": {
152
+ res.type = "text";
153
+ let str = "";
154
+ node.body.forEach((n) => {
155
+ if (n.mode !== "text") {
156
+ throw new KatexNodeToTexNodeError("Expecting node.mode==='text'", node);
157
+ }
158
+ str += n.text;
159
+ });
160
+ res.content = str;
161
+ break;
162
+ }
163
+ case "spacing":
164
+ case "kern":
165
+ res.type = "empty";
166
+ res.content = " ";
167
+ break;
168
+ case "htmlmathml": {
169
+ const element = node["mathml"][0]["body"][0];
170
+ if (element && element.type === "textord" && element.text === "\u2260") {
171
+ res.type = "symbol";
172
+ res.content = "\\neq";
173
+ break;
174
+ } else {
175
+ }
176
+ }
177
+ case "color":
178
+ if (Array.isArray(node.body) && node.body.length === 1) {
179
+ const sub_body = node.body[0];
180
+ if (sub_body.type === "text") {
181
+ res.type = "unknownMacro";
182
+ const joined = sub_body.body.map((n) => n.text).join("");
183
+ if (/^\\[a-zA-Z]+$/.test(joined)) {
184
+ res.content = joined.substring(1);
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ throw new KatexNodeToTexNodeError(`Unknown error type in parsed result:`, node);
190
+ default:
191
+ throw new KatexNodeToTexNodeError(`Unknown node type: ${node.type}`, node);
192
+ break;
193
+ }
194
+ return res;
195
+ } catch (e) {
196
+ throw e;
197
+ }
198
+ }
199
+ function parseTex(tex, customTexMacros) {
200
+ const macros = {
201
+ "\\mod": "\\operatorname{SyMb01-mod}",
202
+ "\\liminf": "\\operatorname{SyMb01-liminf}",
203
+ "\\limsup": "\\operatorname{SyMb01-limsup}",
204
+ "\\qquad": "\\operatorname{SyMb01-qquad}",
205
+ "\\quad": "\\operatorname{SyMb01-quad}",
206
+ "\\cdots": "\\operatorname{SyMb01-cdots}",
207
+ "\\colon": "\\operatorname{SyMb01-colon}",
208
+ "\\imath": "\\operatorname{SyMb01-imath}",
209
+ "\\iiiint": "\\operatorname{SyMb01-iiiint}",
210
+ "\\jmath": "\\operatorname{SyMb01-jmath}",
211
+ "\\vdots": "\\operatorname{SyMb01-vdots}",
212
+ "\\notin": "\\operatorname{SyMb01-notin}",
213
+ "\\slash": "\\operatorname{SyMb01-slash}",
214
+ "\\LaTeX": "\\operatorname{SyMb01-LaTeX}",
215
+ "\\TeX": "\\operatorname{SyMb01-TeX}",
216
+ ...customTexMacros
217
+ };
218
+ const options = {
219
+ macros,
220
+ displayMode: true,
221
+ strict: "ignore",
222
+ throwOnError: false
223
+ };
224
+ let treeArray = generateParseTree(tex, options);
225
+ let t = {
226
+ type: "ordgroup",
227
+ mode: "math",
228
+ body: treeArray,
229
+ loc: {}
230
+ };
231
+ return katexNodeToTexNode(t);
232
+ }
233
+ var generateParseTree = katex.__parse;
234
+
235
+ class KatexNodeToTexNodeError extends Error {
236
+ node;
237
+ constructor(message, node) {
238
+ super(message);
239
+ this.name = "KatexNodeToTexNodeError";
240
+ this.node = node;
241
+ }
242
+ }
243
+
244
+ // src/map.ts
245
+ var symbolMap = new Map([
246
+ ["gets", "arrow.l"],
247
+ ["nonumber", ""],
248
+ ["vec", "arrow"],
249
+ ["neq", "eq.not"],
250
+ ["dot", "dot"],
251
+ ["ddot", "dot.double"],
252
+ ["doteq", "dot(eq)"],
253
+ ["dots", "dots.h"],
254
+ ["ldots", "dots.h"],
255
+ ["vdots", "dots.v"],
256
+ ["ddots", "dots.down"],
257
+ ["widehat", "hat"],
258
+ ["widetilde", "tilde"],
259
+ ["quad", "quad"],
260
+ ["qquad", "wide"],
261
+ ["overbrace", "overbrace"],
262
+ ["underbrace", "underbrace"],
263
+ ["overline", "overline"],
264
+ ["underline", "underline"],
265
+ ["bar", "macron"],
266
+ ["boldsymbol", "bold"],
267
+ ["mathbf", "bold"],
268
+ ["mathbb", "bb"],
269
+ ["mathcal", "cal"],
270
+ ["mathfrak", "frak"],
271
+ ["mathsf", "sans"],
272
+ ["mathtt", "mono"],
273
+ ["mathrm", "upright"],
274
+ ["rm", "upright"],
275
+ ["pmb", "bold"],
276
+ ["pm", "plus.minus"],
277
+ ["mp", "minus.plus"],
278
+ ["oplus", "xor"],
279
+ ["boxplus", "plus.square"],
280
+ ["otimes", "times.circle"],
281
+ ["boxtimes", "times.square"],
282
+ ["sim", "tilde"],
283
+ ["approx", "approx"],
284
+ ["cong", "tilde.equiv"],
285
+ ["simeq", "tilde.eq"],
286
+ ["asymp", "\u224D"],
287
+ ["equiv", "equiv"],
288
+ ["propto", "prop"],
289
+ ["implies", "arrow.r.double.long"],
290
+ ["Longrightarrow", "arrow.r.double.long"],
291
+ ["iff", "arrow.l.r.double.long"],
292
+ ["Longleftrightarrow", "arrow.l.r.double.long"],
293
+ ["leftrightarrow", "arrow.l.r"],
294
+ ["longleftrightarrow", "arrow.l.r.long"],
295
+ ["rightrightarrows", "arrows.rr"],
296
+ ["lfloor", "\u230A"],
297
+ ["rfloor", "\u230B"],
298
+ ["lceil", "\u2308"],
299
+ ["rceil", "\u2309"],
300
+ ["Cap", "sect.double"],
301
+ ["Cup", "union.double"],
302
+ ["Delta", "Delta"],
303
+ ["Gamma", "Gamma"],
304
+ ["Join", "join"],
305
+ ["Lambda", "Lambda"],
306
+ ["Longrightarrow", "arrow.r.double.long"],
307
+ ["Omega", "Omega"],
308
+ ["Phi", "Phi"],
309
+ ["Pi", "Pi"],
310
+ ["Psi", "Psi"],
311
+ ["Rightarrow", "arrow.double"],
312
+ ["Sigma", "Sigma"],
313
+ ["Theta", "Theta"],
314
+ ["aleph", "alef"],
315
+ ["alpha", "alpha"],
316
+ ["angle", "angle"],
317
+ ["approx", "approx"],
318
+ ["approxeq", "approx.eq"],
319
+ ["ast", "ast"],
320
+ ["beta", "beta"],
321
+ ["bigcap", "sect.big"],
322
+ ["bigcirc", "circle.big"],
323
+ ["bigcup", "union.big"],
324
+ ["bigodot", "dot.circle.big"],
325
+ ["bigoplus", "xor.big"],
326
+ ["bigotimes", "times.circle.big"],
327
+ ["bigsqcup", "union.sq.big"],
328
+ ["bigtriangledown", "triangle.b"],
329
+ ["bigtriangleup", "triangle.t"],
330
+ ["biguplus", "union.plus.big"],
331
+ ["bigvee", "or.big"],
332
+ ["bigwedge", "and.big"],
333
+ ["bullet", "bullet"],
334
+ ["cap", "sect"],
335
+ ["cdot", "dot.op"],
336
+ ["cdots", "dots.c"],
337
+ ["checkmark", "checkmark"],
338
+ ["chi", "chi"],
339
+ ["circ", "circle.small"],
340
+ ["colon", "colon"],
341
+ ["cong", "tilde.equiv"],
342
+ ["coprod", "product.co"],
343
+ ["cup", "union"],
344
+ ["curlyvee", "or.curly"],
345
+ ["curlywedge", "and.curly"],
346
+ ["dagger", "dagger"],
347
+ ["dashv", "tack.l"],
348
+ ["ddagger", "dagger.double"],
349
+ ["delta", "delta"],
350
+ ["ddots", "dots.down"],
351
+ ["diamond", "diamond"],
352
+ ["div", "div"],
353
+ ["divideontimes", "times.div"],
354
+ ["dotplus", "plus.dot"],
355
+ ["downarrow", "arrow.b"],
356
+ ["ell", "ell"],
357
+ ["emptyset", "nothing"],
358
+ ["epsilon", "epsilon.alt"],
359
+ ["equiv", "equiv"],
360
+ ["eta", "eta"],
361
+ ["exists", "exists"],
362
+ ["forall", "forall"],
363
+ ["gamma", "gamma"],
364
+ ["ge", "gt.eq"],
365
+ ["geq", "gt.eq"],
366
+ ["geqslant", "gt.eq.slant"],
367
+ ["gg", "gt.double"],
368
+ ["hbar", "planck.reduce"],
369
+ ["imath", "dotless.i"],
370
+ ["iiiint", "intgral.quad"],
371
+ ["iiint", "integral.triple"],
372
+ ["iint", "integral.double"],
373
+ ["in", "in"],
374
+ ["infty", "infinity"],
375
+ ["int", "integral"],
376
+ ["intercal", "top"],
377
+ ["iota", "iota"],
378
+ ["jmath", "dotless.j"],
379
+ ["kappa", "kappa"],
380
+ ["lambda", "lambda"],
381
+ ["land", "and"],
382
+ ["langle", "angle.l"],
383
+ ["lbrace", "brace.l"],
384
+ ["lbrack", "bracket.l"],
385
+ ["ldots", "dots.l"],
386
+ ["le", "lt.eq"],
387
+ ["leadsto", "arrow.squiggly"],
388
+ ["leftarrow", "arrow.l"],
389
+ ["leftthreetimes", "times.three.l"],
390
+ ["leftrightarrow", "arrow.l.r"],
391
+ ["leq", "lt.eq"],
392
+ ["leqslant", "lt.eq.slant"],
393
+ ["lhd", "triangle.l"],
394
+ ["ll", "lt.double"],
395
+ ["longmapsto", "arrow.long.bar"],
396
+ ["longrightarrow", "arrow.long"],
397
+ ["lor", "or"],
398
+ ["ltimes", "times.l"],
399
+ ["mapsto", "arrow.bar"],
400
+ ["measuredangle", "angle.arc"],
401
+ ["mid", "divides"],
402
+ ["models", "models"],
403
+ ["mp", "minus.plus"],
404
+ ["mu", "mu"],
405
+ ["nRightarrow", "arrow.double.not"],
406
+ ["nabla", "nabla"],
407
+ ["ncong", "tilde.nequiv"],
408
+ ["ne", "eq.not"],
409
+ ["neg", "not"],
410
+ ["neq", "eq.not"],
411
+ ["nexists", "exists.not"],
412
+ ["ni", "in.rev"],
413
+ ["nleftarrow", "arrow.l.not"],
414
+ ["nleq", "lt.eq.not"],
415
+ ["nparallel", "parallel.not"],
416
+ ["ngeq", "gt.eq.not"],
417
+ ["nmid", "divides.not"],
418
+ ["notin", "in.not"],
419
+ ["nrightarrow", "arrow.not"],
420
+ ["nsim", "tilde.not"],
421
+ ["nsubseteq", "subset.eq.not"],
422
+ ["nu", "nu"],
423
+ ["ntriangleleft", "lt.tri.not"],
424
+ ["ntriangleright", "gt.tri.not"],
425
+ ["nwarrow", "arrow.tl"],
426
+ ["odot", "dot.circle"],
427
+ ["oint", "integral.cont"],
428
+ ["oiint", "integral.surf"],
429
+ ["oiiint", "integral.vol"],
430
+ ["omega", "omega"],
431
+ ["ominus", "minus.circle"],
432
+ ["oplus", "xor"],
433
+ ["otimes", "times.circle"],
434
+ ["parallel", "parallel"],
435
+ ["partial", "diff"],
436
+ ["perp", "perp"],
437
+ ["phi", "phi.alt"],
438
+ ["pi", "pi"],
439
+ ["pm", "plus.minus"],
440
+ ["pounds", "pound"],
441
+ ["prec", "prec"],
442
+ ["preceq", "prec.eq"],
443
+ ["prime", "prime"],
444
+ ["prod", "product"],
445
+ ["propto", "prop"],
446
+ ["psi", "psi"],
447
+ ["rangle", "angle.r"],
448
+ ["rbrace", "brace.r"],
449
+ ["rbrack", "bracket.r"],
450
+ ["rhd", "triangle"],
451
+ ["rho", "rho"],
452
+ ["rightarrow", "arrow.r"],
453
+ ["rightthreetimes", "times.three.r"],
454
+ ["rtimes", "times.r"],
455
+ ["setminus", "without"],
456
+ ["sigma", "sigma"],
457
+ ["sim", "tilde"],
458
+ ["simeq", "tilde.eq"],
459
+ ["slash", "slash"],
460
+ ["smallsetminus", "without"],
461
+ ["spadesuit", "suit.spade"],
462
+ ["sqcap", "sect.sq"],
463
+ ["sqcup", "union.sq"],
464
+ ["sqsubseteq", "subset.eq.sq"],
465
+ ["sqsupseteq", "supset.eq.sq"],
466
+ ["star", "star"],
467
+ ["subset", "subset"],
468
+ ["subseteq", "subset.eq"],
469
+ ["subsetneq", "subset.neq"],
470
+ ["succ", "succ"],
471
+ ["succeq", "succ.eq"],
472
+ ["sum", "sum"],
473
+ ["supset", "supset"],
474
+ ["supseteq", "supset.eq"],
475
+ ["supsetneq", "supset.neq"],
476
+ ["swarrow", "arrow.bl"],
477
+ ["tau", "tau"],
478
+ ["theta", "theta"],
479
+ ["times", "times"],
480
+ ["to", "arrow.r"],
481
+ ["top", "top"],
482
+ ["triangle", "triangle.t"],
483
+ ["triangledown", "triangle.b.small"],
484
+ ["triangleleft", "triangle.l.small"],
485
+ ["triangleright", "triangle.r.small"],
486
+ ["twoheadrightarrow", "arrow.r.twohead"],
487
+ ["uparrow", "arrow.t"],
488
+ ["updownarrow", "arrow.t.b"],
489
+ ["upharpoonright", "harpoon.tr"],
490
+ ["uplus", "union.plus"],
491
+ ["upsilon", "upsilon"],
492
+ ["varepsilon", "epsilon"],
493
+ ["varnothing", "diameter"],
494
+ ["varphi", "phi"],
495
+ ["varpi", "pi.alt"],
496
+ ["varrho", "rho.alt"],
497
+ ["varsigma", "sigma.alt"],
498
+ ["vartheta", "theta.alt"],
499
+ ["vdash", "tack.r"],
500
+ ["vdots", "dots.v"],
501
+ ["vee", "or"],
502
+ ["wedge", "and"],
503
+ ["wr", "wreath"],
504
+ ["xi", "xi"],
505
+ ["yen", "yen"],
506
+ ["zeta", "zeta"],
507
+ ["mathscr", "scr"],
508
+ ["LaTeX", "#LaTeX"],
509
+ ["TeX", "#TeX"]
510
+ ]);
511
+
512
+ // src/writer.ts
513
+ function convertToken(token) {
514
+ if (/^[a-zA-Z0-9]$/.test(token)) {
515
+ return token;
516
+ } else if (token === "\\\\") {
517
+ return "\\\n";
518
+ } else if (["\\$", "\\#", "\\&", "\\_"].includes(token)) {
519
+ return token;
520
+ } else if (token.startsWith("\\")) {
521
+ const symbol = token.slice(1);
522
+ if (symbolMap.has(symbol)) {
523
+ return symbolMap.get(symbol);
524
+ } else {
525
+ return symbol;
526
+ }
527
+ }
528
+ return token;
529
+ }
530
+ var TYPST_INTRINSIC_SYMBOLS = [
531
+ "dim",
532
+ "id",
533
+ "im",
534
+ "mod",
535
+ "Pr",
536
+ "sech",
537
+ "csch"
538
+ ];
539
+
540
+ class TypstWriterError extends Error {
541
+ node;
542
+ constructor(message, node) {
543
+ super(message);
544
+ this.name = "TypstWriterError";
545
+ this.node = node;
546
+ }
547
+ }
548
+
549
+ class TypstWriter {
550
+ nonStrict;
551
+ preferTypstIntrinsic;
552
+ buffer = "";
553
+ queue = [];
554
+ needSpaceAfterSingleItemScript = false;
555
+ insideFunctionDepth = 0;
556
+ constructor(nonStrict, preferTypstIntrinsic) {
557
+ this.nonStrict = nonStrict;
558
+ this.preferTypstIntrinsic = preferTypstIntrinsic;
559
+ }
560
+ writeBuffer(str) {
561
+ if (this.needSpaceAfterSingleItemScript && /^[0-9a-zA-Z\(]/.test(str)) {
562
+ this.buffer += " ";
563
+ } else {
564
+ let no_need_space = false;
565
+ no_need_space ||= /[\(\|]$/.test(this.buffer) && /^\w/.test(str);
566
+ no_need_space ||= /^[}()_^,;!\|]$/.test(str);
567
+ no_need_space ||= str === "'";
568
+ no_need_space ||= /[0-9]$/.test(this.buffer) && /^[0-9]/.test(str);
569
+ no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
570
+ no_need_space ||= this.buffer === "";
571
+ no_need_space ||= /[\s"_^{\(]$/.test(this.buffer);
572
+ if (!no_need_space) {
573
+ this.buffer += " ";
574
+ }
575
+ }
576
+ if (this.needSpaceAfterSingleItemScript) {
577
+ this.needSpaceAfterSingleItemScript = false;
578
+ }
579
+ this.buffer += str;
580
+ }
581
+ append(node) {
582
+ if (node.type === "empty") {
583
+ return;
584
+ } else if (node.type === "ordgroup") {
585
+ node.args.forEach((arg) => this.append(arg));
586
+ } else if (node.type === "atom") {
587
+ let content = node.content;
588
+ if (node.content === "," && this.insideFunctionDepth > 0) {
589
+ content = "comma";
590
+ }
591
+ this.queue.push({ type: "atom", content });
592
+ } else if (node.type === "symbol") {
593
+ this.queue.push({ type: "symbol", content: node.content });
594
+ } else if (node.type === "text") {
595
+ this.queue.push(node);
596
+ } else if (node.type === "supsub") {
597
+ let { base, sup, sub } = node.irregularData;
598
+ if (base && base.type === "unaryFunc" && base.content === "\\overbrace" && sup) {
599
+ this.append({ type: "binaryFunc", content: "\\overbrace", args: [base.args[0], sup] });
600
+ return;
601
+ } else if (base && base.type === "unaryFunc" && base.content === "\\underbrace" && sub) {
602
+ this.append({ type: "binaryFunc", content: "\\underbrace", args: [base.args[0], sub] });
603
+ return;
604
+ }
605
+ if (!base) {
606
+ this.queue.push({ type: "text", content: "" });
607
+ } else {
608
+ this.appendWithBracketsIfNeeded(base);
609
+ }
610
+ let trailing_space_needed = false;
611
+ const has_prime = sup && sup.type === "symbol" && sup.content === "\\prime";
612
+ if (has_prime) {
613
+ this.queue.push({ type: "atom", content: "\'" });
614
+ trailing_space_needed = false;
615
+ }
616
+ if (sub) {
617
+ this.queue.push({ type: "atom", content: "_" });
618
+ trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
619
+ }
620
+ if (sup && !has_prime) {
621
+ this.queue.push({ type: "atom", content: "^" });
622
+ trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
623
+ }
624
+ if (trailing_space_needed) {
625
+ this.queue.push({ type: "softSpace", content: "" });
626
+ }
627
+ } else if (node.type === "leftright") {
628
+ const [left, body, right] = node.args;
629
+ if (["[]", "()", "{}", "\\lfloor\\rfloor", "\\lceil\\rceil"].includes(left.content + right.content)) {
630
+ this.append(left);
631
+ this.append(body);
632
+ this.append(right);
633
+ return;
634
+ }
635
+ const func_symbol = { type: "symbol", content: "lr" };
636
+ this.queue.push(func_symbol);
637
+ this.insideFunctionDepth++;
638
+ this.queue.push({ type: "atom", content: "(" });
639
+ this.append(left);
640
+ this.append(body);
641
+ this.append(right);
642
+ this.queue.push({ type: "atom", content: ")" });
643
+ this.insideFunctionDepth--;
644
+ } else if (node.type === "binaryFunc") {
645
+ const func_symbol = { type: "symbol", content: node.content };
646
+ const [arg0, arg1] = node.args;
647
+ this.queue.push(func_symbol);
648
+ this.insideFunctionDepth++;
649
+ this.queue.push({ type: "atom", content: "(" });
650
+ this.append(arg0);
651
+ this.queue.push({ type: "atom", content: "," });
652
+ this.append(arg1);
653
+ this.queue.push({ type: "atom", content: ")" });
654
+ this.insideFunctionDepth--;
655
+ } else if (node.type === "unaryFunc") {
656
+ const func_symbol = { type: "symbol", content: node.content };
657
+ const arg0 = node.args[0];
658
+ if (node.content === "\\sqrt" && node.irregularData) {
659
+ func_symbol.content = "root";
660
+ this.queue.push(func_symbol);
661
+ this.insideFunctionDepth++;
662
+ this.queue.push({ type: "atom", content: "(" });
663
+ this.append(node.irregularData);
664
+ this.queue.push({ type: "atom", content: "," });
665
+ this.append(arg0);
666
+ this.queue.push({ type: "atom", content: ")" });
667
+ this.insideFunctionDepth--;
668
+ return;
669
+ } else if (node.content === "\\mathbf") {
670
+ this.append({ type: "symbol", content: "upright" });
671
+ this.insideFunctionDepth++;
672
+ this.queue.push({ type: "atom", content: "(" });
673
+ this.queue.push(func_symbol);
674
+ this.insideFunctionDepth++;
675
+ this.queue.push({ type: "atom", content: "(" });
676
+ this.append(arg0);
677
+ this.queue.push({ type: "atom", content: ")" });
678
+ this.insideFunctionDepth--;
679
+ this.queue.push({ type: "atom", content: ")" });
680
+ this.insideFunctionDepth--;
681
+ return;
682
+ } else if (node.content === "\\mathbb") {
683
+ const body = node.args[0];
684
+ if (body.type === "symbol" && /^[A-Z]$/.test(body.content)) {
685
+ this.queue.push({ type: "symbol", content: body.content + body.content });
686
+ return;
15
687
  }
16
- if (options.preferTypstIntrinsic) {
17
- opt.preferTypstIntrinsic = options.preferTypstIntrinsic;
688
+ } else if (node.content === "\\operatorname") {
689
+ let body = node.args;
690
+ if (body.length === 1 && body[0].type == "ordgroup") {
691
+ body = body[0].args;
18
692
  }
19
- if (options.customTexMacros) {
20
- opt.customTexMacros = options.customTexMacros;
693
+ const text = body.reduce((buff, n) => {
694
+ buff += convertToken(n.content);
695
+ return buff;
696
+ }, "");
697
+ if (this.preferTypstIntrinsic && TYPST_INTRINSIC_SYMBOLS.includes(text)) {
698
+ this.queue.push({ type: "symbol", content: text });
699
+ } else if (text.startsWith("SyMb01-")) {
700
+ this.queue.push({ type: "symbol", content: "\\" + text.substring(7) });
701
+ } else {
702
+ this.queue.push({ type: "symbol", content: "op" });
703
+ this.queue.push({ type: "atom", content: "(" });
704
+ this.queue.push({ type: "text", content: text });
705
+ this.queue.push({ type: "atom", content: ")" });
21
706
  }
707
+ return;
708
+ }
709
+ this.queue.push(func_symbol);
710
+ this.insideFunctionDepth++;
711
+ this.queue.push({ type: "atom", content: "(" });
712
+ this.append(arg0);
713
+ this.queue.push({ type: "atom", content: ")" });
714
+ this.insideFunctionDepth--;
715
+ } else if (node.type === "align") {
716
+ const matrix = node.irregularData;
717
+ matrix.forEach((row, i) => {
718
+ row.forEach((cell, j) => {
719
+ if (j > 0) {
720
+ this.queue.push({ type: "atom", content: "&" });
721
+ }
722
+ this.append(cell);
723
+ });
724
+ if (i < matrix.length - 1) {
725
+ this.queue.push({ type: "symbol", content: "\\\\" });
726
+ }
727
+ });
728
+ } else if (node.type === "matrix") {
729
+ const matrix = node.irregularData;
730
+ this.queue.push({ type: "symbol", content: "mat" });
731
+ this.insideFunctionDepth++;
732
+ this.queue.push({ type: "atom", content: "(" });
733
+ this.queue.push({ type: "symbol", content: "delim: #none, " });
734
+ matrix.forEach((row, i) => {
735
+ row.forEach((cell, j) => {
736
+ if (cell.type === "ordgroup" && cell.args.length === 0) {
737
+ return;
738
+ }
739
+ this.append(cell);
740
+ if (j < row.length - 1) {
741
+ this.queue.push({ type: "atom", content: "," });
742
+ } else {
743
+ if (i < matrix.length - 1) {
744
+ this.queue.push({ type: "atom", content: ";" });
745
+ }
746
+ }
747
+ });
748
+ });
749
+ this.queue.push({ type: "atom", content: ")" });
750
+ this.insideFunctionDepth--;
751
+ } else if (node.type === "unknownMacro") {
752
+ if (this.nonStrict) {
753
+ this.queue.push({ type: "symbol", content: node.content });
754
+ } else {
755
+ throw new TypstWriterError(`Unknown macro: ${node.content}`, node);
756
+ }
757
+ } else {
758
+ throw new TypstWriterError(`Unimplemented node type to append: ${node.type}`, node);
759
+ }
760
+ }
761
+ flushQueue() {
762
+ this.queue.forEach((node) => {
763
+ let str = "";
764
+ switch (node.type) {
765
+ case "atom":
766
+ str = node.content;
767
+ break;
768
+ case "symbol":
769
+ str = convertToken(node.content);
770
+ break;
771
+ case "text":
772
+ str = `"${node.content}"`;
773
+ break;
774
+ case "softSpace":
775
+ this.needSpaceAfterSingleItemScript = true;
776
+ str = "";
777
+ break;
778
+ default:
779
+ throw new TypstWriterError(`Unexpected node type to stringify: ${node.type}`, node);
780
+ }
781
+ if (str !== "") {
782
+ this.writeBuffer(str);
783
+ }
784
+ });
785
+ this.queue = [];
786
+ }
787
+ appendWithBracketsIfNeeded(node) {
788
+ const is_single_atom = node.type === "atom";
789
+ const is_single_function = node.type === "unaryFunc" || node.type === "binaryFunc" || node.type === "leftright";
790
+ const is_single = ["atom", "symbol", "unaryFunc", "binaryFunc", "leftright"].includes(node.type);
791
+ if (is_single) {
792
+ this.append(node);
793
+ } else {
794
+ this.queue.push({
795
+ type: "atom",
796
+ content: "("
797
+ });
798
+ this.append(node);
799
+ this.queue.push({
800
+ type: "atom",
801
+ content: ")"
802
+ });
803
+ }
804
+ return is_single;
805
+ }
806
+ finalize() {
807
+ this.flushQueue();
808
+ const smartFloorPass = function(input) {
809
+ let res = input.replace(/⌊\s*(.*?)\s*⌋/g, "floor($1)");
810
+ res = res.replace(/floor\(\)/g, 'floor("")');
811
+ return res;
812
+ };
813
+ const smartCeilPass = function(input) {
814
+ let res = input.replace(/⌈\s*(.*?)\s*⌉/g, "ceil($1)");
815
+ res = res.replace(/ceil\(\)/g, 'ceil("")');
816
+ return res;
817
+ };
818
+ this.buffer = smartFloorPass(this.buffer);
819
+ this.buffer = smartCeilPass(this.buffer);
820
+ return this.buffer;
821
+ }
822
+ }
823
+
824
+ // src/index.ts
825
+ function tex2typst(tex, options) {
826
+ const opt = {
827
+ nonStrict: false,
828
+ preferTypstIntrinsic: true,
829
+ customTexMacros: {}
830
+ };
831
+ if (options) {
832
+ if (options.nonStrict) {
833
+ opt.nonStrict = options.nonStrict;
834
+ }
835
+ if (options.preferTypstIntrinsic) {
836
+ opt.preferTypstIntrinsic = options.preferTypstIntrinsic;
837
+ }
838
+ if (options.customTexMacros) {
839
+ opt.customTexMacros = options.customTexMacros;
22
840
  }
23
- const t = (0, parser_1.parseTex)(tex, opt.customTexMacros);
24
- const writer = new writer_1.TypstWriter(opt.nonStrict, opt.preferTypstIntrinsic);
25
- writer.append(t);
26
- return writer.finalize();
841
+ }
842
+ const t = parseTex(tex, opt.customTexMacros);
843
+ const writer2 = new TypstWriter(opt.nonStrict, opt.preferTypstIntrinsic);
844
+ writer2.append(t);
845
+ return writer2.finalize();
27
846
  }
847
+ export {
848
+ tex2typst
849
+ };