tex2typst 0.3.0 → 0.3.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
@@ -1,5 +1,16 @@
1
1
  // src/map.ts
2
- var symbolMap = new Map([
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"],
@@ -10,13 +21,19 @@ var symbolMap = new Map([
10
21
  ["vdots", "dots.v"],
11
22
  ["ddots", "dots.down"],
12
23
  ["widehat", "hat"],
24
+ // Ideally, the result of \widehat should be longer than \hat. But it is not implemented now.
13
25
  ["widetilde", "tilde"],
26
+ // Ideally, the result of \widetilde should be longer than \tilde. But it is not implemented now.
14
27
  ["quad", "quad"],
15
28
  ["qquad", "wide"],
16
29
  ["overbrace", "overbrace"],
30
+ // same
17
31
  ["underbrace", "underbrace"],
32
+ // same
18
33
  ["overline", "overline"],
34
+ // same
19
35
  ["underline", "underline"],
36
+ // same
20
37
  ["bar", "macron"],
21
38
  ["dbinom", "binom"],
22
39
  ["tbinom", "binom"],
@@ -33,56 +50,36 @@ var symbolMap = new Map([
33
50
  ["mathsf", "sans"],
34
51
  ["mathtt", "mono"],
35
52
  ["rm", "upright"],
53
+ // TODO: \pmb need special logic to handle but it is not implemented now. See the commented test case.
36
54
  ["pmb", "bold"],
55
+ /* variants of plus,minus,times,divide */
37
56
  ["pm", "plus.minus"],
38
57
  ["mp", "minus.plus"],
39
58
  ["boxplus", "plus.square"],
40
59
  ["otimes", "times.circle"],
41
60
  ["boxtimes", "times.square"],
61
+ /* wave */
62
+ // tex: \sim \approx \cong \simeq \asymp \equiv \propto
63
+ // typst: tilde.op approx tilde.equiv tilde.eq ≍ equiv prop
42
64
  ["approx", "approx"],
43
65
  ["cong", "tilde.equiv"],
44
66
  ["simeq", "tilde.eq"],
45
- ["asymp", ""],
67
+ ["asymp", "\u224D"],
68
+ // just use the unicode character :-)
46
69
  ["equiv", "equiv"],
47
70
  ["propto", "prop"],
71
+ /* arrows */
48
72
  ["gets", "arrow.l"],
49
- ["hookleftarrow", "arrow.l.hook"],
50
- ["leftharpoonup", "harpoon.lt"],
51
- ["leftharpoondown", "harpoon.lb"],
52
- ["rightleftharpoons", "harpoons.rtlb"],
53
- ["longleftarrow", "arrow.l.long"],
54
- ["longrightarrow", "arrow.r.long"],
55
- ["longleftrightarrow", "arrow.l.r.long"],
56
- ["Longleftarrow", "arrow.l.double.long"],
57
- ["Longrightarrow", "arrow.r.double.long"],
58
- ["Longleftrightarrow", "arrow.l.r.double.long"],
59
- ["hookrightarrow", "arrow.r.hook"],
60
- ["rightharpoonup", "harpoon.rt"],
61
- ["rightharpoondown", "harpoon.rb"],
73
+ // ['longmapsto', 'arrow.r.bar'],
62
74
  ["iff", "arrow.l.r.double.long"],
63
75
  ["implies", "arrow.r.double.long"],
64
- ["uparrow", "arrow.t"],
65
- ["downarrow", "arrow.b"],
66
- ["updownarrow", "arrow.t.b"],
67
- ["Uparrow", "arrow.t.double"],
68
- ["Downarrow", "arrow.b.double"],
69
- ["Updownarrow", "arrow.t.b.double"],
70
- ["nearrow", "arrow.tr"],
71
- ["searrow", "arrow.br"],
72
- ["swarrow", "arrow.bl"],
73
- ["nwarrow", "arrow.tl"],
74
76
  ["leadsto", "arrow.squiggly"],
75
- ["leftleftarrows", "arrows.ll"],
76
- ["rightrightarrows", "arrows.rr"],
77
77
  ["Cap", "sect.double"],
78
78
  ["Cup", "union.double"],
79
79
  ["Delta", "Delta"],
80
80
  ["Gamma", "Gamma"],
81
81
  ["Join", "join"],
82
82
  ["Lambda", "Lambda"],
83
- ["Leftarrow", "arrow.l.double"],
84
- ["Leftrightarrow", "arrow.l.r.double"],
85
- ["Longrightarrow", "arrow.r.double.long"],
86
83
  ["Omega", "Omega"],
87
84
  ["P", "pilcrow"],
88
85
  ["Phi", "Phi"],
@@ -94,26 +91,34 @@ var symbolMap = new Map([
94
91
  ["Theta", "Theta"],
95
92
  ["aleph", "alef"],
96
93
  ["alpha", "alpha"],
94
+ // ['amalg', 'product.co'],
97
95
  ["angle", "angle"],
98
96
  ["approx", "approx"],
99
97
  ["approxeq", "approx.eq"],
98
+ // ['ast', 'ast'],
100
99
  ["beta", "beta"],
101
100
  ["bigcap", "sect.big"],
102
101
  ["bigcirc", "circle.big"],
103
102
  ["bigcup", "union.big"],
104
103
  ["bigodot", "dot.circle.big"],
104
+ // ['bigoplus', 'xor.big'], // or "plus.circle.big"
105
105
  ["bigotimes", "times.circle.big"],
106
106
  ["bigsqcup", "union.sq.big"],
107
+ // ['bigtriangledown', 'triangle.b'],
108
+ // ['bigtriangleup', 'triangle.t'],
107
109
  ["biguplus", "union.plus.big"],
108
110
  ["bigvee", "or.big"],
109
111
  ["bigwedge", "and.big"],
112
+ // ['bowtie', 'join'],
110
113
  ["bullet", "bullet"],
111
114
  ["cap", "sect"],
112
115
  ["cdot", "dot.op"],
116
+ // 'dot.op' or 'dot.c'
113
117
  ["cdots", "dots.c"],
114
118
  ["checkmark", "checkmark"],
115
119
  ["chi", "chi"],
116
120
  ["circ", "circle.small"],
121
+ // 'circle.small' or 'compose'
117
122
  ["colon", "colon"],
118
123
  ["cong", "tilde.equiv"],
119
124
  ["coprod", "product.co"],
@@ -130,7 +135,6 @@ var symbolMap = new Map([
130
135
  ["div", "div"],
131
136
  ["divideontimes", "times.div"],
132
137
  ["dotplus", "plus.dot"],
133
- ["downarrow", "arrow.b"],
134
138
  ["ell", "ell"],
135
139
  ["emptyset", "nothing"],
136
140
  ["epsilon", "epsilon.alt"],
@@ -138,6 +142,7 @@ var symbolMap = new Map([
138
142
  ["eta", "eta"],
139
143
  ["exists", "exists"],
140
144
  ["forall", "forall"],
145
+ // ['frown', 'paren.t'],
141
146
  ["gamma", "gamma"],
142
147
  ["ge", "gt.eq"],
143
148
  ["geq", "gt.eq"],
@@ -152,6 +157,7 @@ var symbolMap = new Map([
152
157
  ["infty", "infinity"],
153
158
  ["int", "integral"],
154
159
  ["intercal", "top"],
160
+ // 'top' or 'tack.b'
155
161
  ["iota", "iota"],
156
162
  ["jmath", "dotless.j"],
157
163
  ["kappa", "kappa"],
@@ -162,21 +168,23 @@ var symbolMap = new Map([
162
168
  ["lbrack", "bracket.l"],
163
169
  ["ldots", "dots.h"],
164
170
  ["le", "lt.eq"],
165
- ["leadsto", "arrow.squiggly"],
166
- ["leftarrow", "arrow.l"],
167
171
  ["leftthreetimes", "times.three.l"],
168
172
  ["leftrightarrow", "arrow.l.r"],
169
173
  ["leq", "lt.eq"],
170
174
  ["leqslant", "lt.eq.slant"],
171
175
  ["lhd", "triangle.l"],
172
176
  ["ll", "lt.double"],
177
+ // ['longmapsto', 'arrow.bar.long'],
178
+ // ['longrightarrow', 'arrow.long'],
173
179
  ["lor", "or"],
174
180
  ["ltimes", "times.l"],
181
+ // ['mapsto', 'arrow.bar'],
175
182
  ["measuredangle", "angle.arc"],
176
183
  ["mid", "divides"],
177
184
  ["models", "models"],
178
185
  ["mp", "minus.plus"],
179
186
  ["mu", "mu"],
187
+ // ['nRightarrow', 'arrow.double.not'],
180
188
  ["nabla", "nabla"],
181
189
  ["ncong", "tilde.equiv.not"],
182
190
  ["ne", "eq.not"],
@@ -190,18 +198,20 @@ var symbolMap = new Map([
190
198
  ["ngeq", "gt.eq.not"],
191
199
  ["nmid", "divides.not"],
192
200
  ["notin", "in.not"],
201
+ // ['nrightarrow', 'arrow.not'],
193
202
  ["nsim", "tilde.not"],
194
203
  ["nsubseteq", "subset.eq.not"],
195
204
  ["nu", "nu"],
196
205
  ["ntriangleleft", "lt.tri.not"],
197
206
  ["ntriangleright", "gt.tri.not"],
198
- ["nwarrow", "arrow.tl"],
199
207
  ["odot", "dot.circle"],
200
208
  ["oint", "integral.cont"],
201
209
  ["oiint", "integral.surf"],
202
210
  ["oiiint", "integral.vol"],
203
211
  ["omega", "omega"],
212
+ // ['omicron', 'omicron'],
204
213
  ["ominus", "minus.circle"],
214
+ // ['oplus', 'xor'], // or 'plus.circle'
205
215
  ["otimes", "times.circle"],
206
216
  ["parallel", "parallel"],
207
217
  ["partial", "diff"],
@@ -230,11 +240,13 @@ var symbolMap = new Map([
230
240
  ["simeq", "tilde.eq"],
231
241
  ["slash", "slash"],
232
242
  ["smallsetminus", "without"],
243
+ // ['smile', 'paren.b'],
233
244
  ["spadesuit", "suit.spade"],
234
245
  ["sqcap", "sect.sq"],
235
246
  ["sqcup", "union.sq"],
236
247
  ["sqsubseteq", "subset.eq.sq"],
237
248
  ["sqsupseteq", "supset.eq.sq"],
249
+ // ['star', 'star'],
238
250
  ["subset", "subset"],
239
251
  ["subseteq", "subset.eq"],
240
252
  ["subsetneq", "subset.neq"],
@@ -244,21 +256,22 @@ var symbolMap = new Map([
244
256
  ["supset", "supset"],
245
257
  ["supseteq", "supset.eq"],
246
258
  ["supsetneq", "supset.neq"],
247
- ["swarrow", "arrow.bl"],
248
259
  ["tau", "tau"],
249
260
  ["theta", "theta"],
250
261
  ["times", "times"],
251
262
  ["to", "arrow.r"],
252
263
  ["top", "top"],
253
264
  ["triangle", "triangle.t"],
265
+ // ['triangledown', 'triangle.b.small'],
266
+ // ['triangleleft', 'triangle.l.small'],
267
+ // ['triangleright', 'triangle.r.small'],
254
268
  ["twoheadrightarrow", "arrow.r.twohead"],
255
- ["uparrow", "arrow.t"],
256
- ["updownarrow", "arrow.t.b"],
257
269
  ["upharpoonright", "harpoon.tr"],
258
270
  ["uplus", "union.plus"],
259
271
  ["upsilon", "upsilon"],
260
272
  ["varepsilon", "epsilon"],
261
273
  ["varnothing", "diameter"],
274
+ // empty set
262
275
  ["varphi", "phi"],
263
276
  ["varpi", "pi.alt"],
264
277
  ["varrho", "rho.alt"],
@@ -272,11 +285,12 @@ var symbolMap = new Map([
272
285
  ["xi", "xi"],
273
286
  ["yen", "yen"],
274
287
  ["zeta", "zeta"],
288
+ // extended
275
289
  ["mathscr", "scr"],
276
290
  ["LaTeX", "#LaTeX"],
277
291
  ["TeX", "#TeX"]
278
292
  ]);
279
- var map_from_official_docs = new Map([
293
+ var map_from_official_docs = /* @__PURE__ */ new Map([
280
294
  ["lparen", "paren.l"],
281
295
  ["lParen", "paren.l.double"],
282
296
  ["rparen", "paren.r"],
@@ -287,6 +301,7 @@ var map_from_official_docs = new Map([
287
301
  ["lBrace", "brace.l.double"],
288
302
  ["rbrace", "brace.r"],
289
303
  ["rBrace", "brace.r.double"],
304
+ // ['overbrace', 'brace.t'],
290
305
  ["underbrace", "brace.b"],
291
306
  ["lbrack", "bracket.l"],
292
307
  ["lBrack", "bracket.l.double"],
@@ -367,6 +382,7 @@ var map_from_official_docs = new Map([
367
382
  ["mathquestion", "quest"],
368
383
  ["Question", "quest.double"],
369
384
  ["mathoctothorpe", "hash"],
385
+ // ['mathhyphen', 'hyph'],
370
386
  ["mathpercent", "percent"],
371
387
  ["mathparagraph", "pilcrow"],
372
388
  ["mathsection", "section"],
@@ -435,6 +451,8 @@ var map_from_official_docs = new Map([
435
451
  ["stareq", "eq.star"],
436
452
  ["circledequal", "eq.circle"],
437
453
  ["eqcolon", "eq.colon"],
454
+ // \usepackage{mathtools} defines \eqdef
455
+ // https://tex.stackexchange.com/questions/28836/typesetting-the-define-equals-symbol
438
456
  ["eqdef", "eq.def"],
439
457
  ["triangleq", "eq.delta"],
440
458
  ["veeeq", "eq.equi"],
@@ -936,6 +954,64 @@ var map_from_official_docs = new Map([
936
954
  ["barV", "tack.b.double"],
937
955
  ["shortdowntack", "tack.b.short"],
938
956
  ["dashVdash", "tack.l.r"],
957
+ /*
958
+ ['mupalpha', 'alpha'],
959
+ ['mupbeta', 'beta'],
960
+ ['mupchi', 'chi'],
961
+ ['mupdelta', 'delta'],
962
+ ['mupvarepsilon', 'epsilon'],
963
+ ['mupepsilon', 'epsilon.alt'],
964
+ ['mupeta', 'eta'],
965
+ ['mupgamma', 'gamma'],
966
+ ['mupiota', 'iota'],
967
+ ['mupkappa', 'kappa'],
968
+ ['mupvarkappa', 'kappa.alt'],
969
+ ['muplambda', 'lambda'],
970
+ ['mupmu', 'mu'],
971
+ ['mupnu', 'nu'],
972
+ ['mho', 'ohm.inv'],
973
+ ['mupomega', 'omega'],
974
+ ['mupomicron', 'omicron'],
975
+ ['mupvarphi', 'phi'],
976
+ ['mupphi', 'phi.alt'],
977
+ ['muppi', 'pi'],
978
+ ['mupvarpi', 'pi.alt'],
979
+ ['muppsi', 'psi'],
980
+ ['muprho', 'rho'],
981
+ ['mupvarrho', 'rho.alt'],
982
+ ['mupsigma', 'sigma'],
983
+ ['mupvarsigma', 'sigma.alt'],
984
+ ['muptau', 'tau'],
985
+ ['muptheta', 'theta'],
986
+ ['mupvartheta', 'theta.alt'],
987
+ ['mupupsilon', 'upsilon'],
988
+ ['mupxi', 'xi'],
989
+ ['mupzeta', 'zeta'],
990
+ ['mupAlpha', 'Alpha'],
991
+ ['mupBeta', 'Beta'],
992
+ ['mupChi', 'Chi'],
993
+ ['mupDelta', 'Delta'],
994
+ ['mupEpsilon', 'Epsilon'],
995
+ ['mupEta', 'Eta'],
996
+ ['mupGamma', 'Gamma'],
997
+ ['mupIota', 'Iota'],
998
+ ['mupKappa', 'Kappa'],
999
+ ['mupLambda', 'Lambda'],
1000
+ ['mupMu', 'Mu'],
1001
+ ['mupNu', 'Nu'],
1002
+ ['mupOmega', 'Omega'],
1003
+ ['mupOmicron', 'Omicron'],
1004
+ ['mupPhi', 'Phi'],
1005
+ ['mupPi', 'Pi'],
1006
+ ['mupPsi', 'Psi'],
1007
+ ['mupRho', 'Rho'],
1008
+ ['mupSigma', 'Sigma'],
1009
+ ['mupTau', 'Tau'],
1010
+ ['mupTheta', 'Theta'],
1011
+ ['mupUpsilon', 'Upsilon'],
1012
+ ['mupXi', 'Xi'],
1013
+ ['mupZeta', 'Zeta'],
1014
+ */
939
1015
  ["BbbA", "AA"],
940
1016
  ["BbbB", "BB"],
941
1017
  ["BbbC", "CC"],
@@ -976,12 +1052,13 @@ for (const [key, value] of map_from_official_docs) {
976
1052
  symbolMap.set(key, value);
977
1053
  }
978
1054
  }
979
- var reverseSymbolMap = new Map;
1055
+ var reverseSymbolMap = /* @__PURE__ */ new Map();
980
1056
  for (const [key, value] of Array.from(symbolMap.entries()).reverse()) {
981
1057
  reverseSymbolMap.set(value, key);
982
1058
  }
983
1059
  reverseSymbolMap.set("dif", "mathrm{d}");
984
- var typst_to_tex_map = new Map([
1060
+ reverseSymbolMap.set("oo", "infty");
1061
+ var typst_to_tex_map = /* @__PURE__ */ new Map([
985
1062
  ["top", "top"],
986
1063
  ["frac", "frac"],
987
1064
  ["tilde", "tilde"],
@@ -996,7 +1073,7 @@ for (const [key, value] of typst_to_tex_map) {
996
1073
 
997
1074
  // src/generic.ts
998
1075
  function array_find(array, item, start = 0) {
999
- for (let i = start;i < array.length; i++) {
1076
+ for (let i = start; i < array.length; i++) {
1000
1077
  if (array[i].eq(item)) {
1001
1078
  return i;
1002
1079
  }
@@ -1027,9 +1104,7 @@ function array_split(array, sep) {
1027
1104
  }
1028
1105
 
1029
1106
  // src/types.ts
1030
- class TexToken {
1031
- type;
1032
- value;
1107
+ var TexToken = class {
1033
1108
  constructor(type, value) {
1034
1109
  this.type = type;
1035
1110
  this.value = value;
@@ -1047,25 +1122,21 @@ class TexToken {
1047
1122
  return this.value;
1048
1123
  }
1049
1124
  }
1050
- }
1125
+ };
1051
1126
  function apply_escape_if_needed(c) {
1052
1127
  if (["{", "}", "%"].includes(c)) {
1053
1128
  return "\\" + c;
1054
1129
  }
1055
1130
  return c;
1056
1131
  }
1057
-
1058
- class TexNode {
1059
- type;
1060
- content;
1061
- args;
1062
- data;
1132
+ var TexNode = class {
1063
1133
  constructor(type, content, args, data) {
1064
1134
  this.type = type;
1065
1135
  this.content = content;
1066
1136
  this.args = args;
1067
1137
  this.data = data;
1068
1138
  }
1139
+ // Note that this is only shallow equality.
1069
1140
  eq(other) {
1070
1141
  return this.type === other.type && this.content === other.content;
1071
1142
  }
@@ -1143,7 +1214,7 @@ class TexNode {
1143
1214
  return tokens;
1144
1215
  }
1145
1216
  case "supsub": {
1146
- let should_wrap_in_braces = function(node) {
1217
+ let should_wrap_in_braces2 = function(node) {
1147
1218
  if (node.type === "ordgroup" || node.type === "supsub" || node.type === "empty") {
1148
1219
  return true;
1149
1220
  } else if (node.type === "element" && /\d+(\.\d+)?/.test(node.content) && node.content.length > 1) {
@@ -1152,12 +1223,13 @@ class TexNode {
1152
1223
  return false;
1153
1224
  }
1154
1225
  };
1226
+ var should_wrap_in_braces = should_wrap_in_braces2;
1155
1227
  let tokens = [];
1156
1228
  const { base, sup, sub } = this.data;
1157
1229
  tokens = tokens.concat(base.serialize());
1158
1230
  if (sub) {
1159
1231
  tokens.push(new TexToken(6 /* CONTROL */, "_"));
1160
- if (should_wrap_in_braces(sub)) {
1232
+ if (should_wrap_in_braces2(sub)) {
1161
1233
  tokens.push(new TexToken(0 /* ELEMENT */, "{"));
1162
1234
  tokens = tokens.concat(sub.serialize());
1163
1235
  tokens.push(new TexToken(0 /* ELEMENT */, "}"));
@@ -1167,7 +1239,7 @@ class TexNode {
1167
1239
  }
1168
1240
  if (sup) {
1169
1241
  tokens.push(new TexToken(6 /* CONTROL */, "^"));
1170
- if (should_wrap_in_braces(sup)) {
1242
+ if (should_wrap_in_braces2(sup)) {
1171
1243
  tokens.push(new TexToken(0 /* ELEMENT */, "{"));
1172
1244
  tokens = tokens.concat(sup.serialize());
1173
1245
  tokens.push(new TexToken(0 /* ELEMENT */, "}"));
@@ -1184,11 +1256,10 @@ class TexNode {
1184
1256
  let tokens = [];
1185
1257
  const matrix = this.data;
1186
1258
  tokens.push(new TexToken(1 /* COMMAND */, `\\begin{${this.content}}`));
1187
- tokens.push(new TexToken(5 /* NEWLINE */, `
1188
- `));
1189
- for (let i = 0;i < matrix.length; i++) {
1259
+ tokens.push(new TexToken(5 /* NEWLINE */, "\n"));
1260
+ for (let i = 0; i < matrix.length; i++) {
1190
1261
  const row = matrix[i];
1191
- for (let j = 0;j < row.length; j++) {
1262
+ for (let j = 0; j < row.length; j++) {
1192
1263
  const cell = row[j];
1193
1264
  tokens = tokens.concat(cell.serialize());
1194
1265
  if (j !== row.length - 1) {
@@ -1199,8 +1270,7 @@ class TexNode {
1199
1270
  tokens.push(new TexToken(6 /* CONTROL */, "\\\\"));
1200
1271
  }
1201
1272
  }
1202
- tokens.push(new TexToken(5 /* NEWLINE */, `
1203
- `));
1273
+ tokens.push(new TexToken(5 /* NEWLINE */, "\n"));
1204
1274
  tokens.push(new TexToken(1 /* COMMAND */, `\\end{${this.content}}`));
1205
1275
  return tokens;
1206
1276
  }
@@ -1208,6 +1278,8 @@ class TexNode {
1208
1278
  throw new Error("[TexNode.serialize] Unimplemented type: " + this.type);
1209
1279
  }
1210
1280
  }
1281
+ // whether the node is over high so that if it's wrapped in braces, \left and \right should be used.
1282
+ // e.g. \frac{1}{2} is over high, "2" is not.
1211
1283
  isOverHigh() {
1212
1284
  switch (this.type) {
1213
1285
  case "element":
@@ -1220,6 +1292,7 @@ class TexNode {
1220
1292
  if (this.content === "\\frac") {
1221
1293
  return true;
1222
1294
  }
1295
+ // fall through
1223
1296
  case "unaryFunc":
1224
1297
  case "ordgroup":
1225
1298
  return this.args.some((n) => n.isOverHigh());
@@ -1232,10 +1305,8 @@ class TexNode {
1232
1305
  return false;
1233
1306
  }
1234
1307
  }
1235
- }
1236
- class TypstToken {
1237
- type;
1238
- value;
1308
+ };
1309
+ var TypstToken = class {
1239
1310
  constructor(type, content) {
1240
1311
  this.type = type;
1241
1312
  this.value = content;
@@ -1288,14 +1359,10 @@ class TypstToken {
1288
1359
  return this.value;
1289
1360
  }
1290
1361
  }
1291
- }
1292
-
1293
- class TypstNode {
1294
- type;
1295
- content;
1296
- args;
1297
- data;
1298
- options;
1362
+ };
1363
+ var TYPST_NONE = null;
1364
+ var TYPST_TRUE = true;
1365
+ var TypstNode = class {
1299
1366
  constructor(type, content, args, data) {
1300
1367
  this.type = type;
1301
1368
  this.content = content;
@@ -1305,10 +1372,11 @@ class TypstNode {
1305
1372
  setOptions(options) {
1306
1373
  this.options = options;
1307
1374
  }
1375
+ // Note that this is only shallow equality.
1308
1376
  eq(other) {
1309
1377
  return this.type === other.type && this.content === other.content;
1310
1378
  }
1311
- }
1379
+ };
1312
1380
 
1313
1381
  // src/util.ts
1314
1382
  function isalpha(char) {
@@ -1465,8 +1533,7 @@ function tokenize(latex) {
1465
1533
  switch (firstChar) {
1466
1534
  case "%": {
1467
1535
  let newPos = pos + 1;
1468
- while (newPos < latex.length && latex[newPos] !== `
1469
- `) {
1536
+ while (newPos < latex.length && latex[newPos] !== "\n") {
1470
1537
  newPos += 1;
1471
1538
  }
1472
1539
  token = new TexToken(3 /* COMMENT */, latex.slice(pos + 1, newPos));
@@ -1481,20 +1548,16 @@ function tokenize(latex) {
1481
1548
  token = new TexToken(6 /* CONTROL */, firstChar);
1482
1549
  pos++;
1483
1550
  break;
1484
- case `
1485
- `:
1551
+ case "\n":
1486
1552
  token = new TexToken(5 /* NEWLINE */, firstChar);
1487
1553
  pos++;
1488
1554
  break;
1489
1555
  case "\r": {
1490
- if (pos + 1 < latex.length && latex[pos + 1] === `
1491
- `) {
1492
- token = new TexToken(5 /* NEWLINE */, `
1493
- `);
1556
+ if (pos + 1 < latex.length && latex[pos + 1] === "\n") {
1557
+ token = new TexToken(5 /* NEWLINE */, "\n");
1494
1558
  pos += 2;
1495
1559
  } else {
1496
- token = new TexToken(5 /* NEWLINE */, `
1497
- `);
1560
+ token = new TexToken(5 /* NEWLINE */, "\n");
1498
1561
  pos++;
1499
1562
  }
1500
1563
  break;
@@ -1561,61 +1624,51 @@ function tokenize(latex) {
1561
1624
  }
1562
1625
  return tokens;
1563
1626
  }
1564
-
1565
- class LatexParserError extends Error {
1627
+ var LatexParserError = class extends Error {
1566
1628
  constructor(message) {
1567
1629
  super(message);
1568
1630
  this.name = "LatexParserError";
1569
1631
  }
1570
- }
1632
+ };
1571
1633
  var SUB_SYMBOL = new TexToken(6 /* CONTROL */, "_");
1572
1634
  var SUP_SYMBOL = new TexToken(6 /* CONTROL */, "^");
1573
-
1574
- class LatexParser {
1575
- space_sensitive;
1576
- newline_sensitive;
1635
+ var LatexParser = class {
1577
1636
  constructor(space_sensitive = false, newline_sensitive = true) {
1578
1637
  this.space_sensitive = space_sensitive;
1579
1638
  this.newline_sensitive = newline_sensitive;
1580
1639
  }
1581
1640
  parse(tokens) {
1641
+ const [tree, _] = this.parseGroup(tokens, 0, tokens.length);
1642
+ return tree;
1643
+ }
1644
+ parseGroup(tokens, start, end) {
1582
1645
  const results = [];
1583
- let pos = 0;
1584
- while (pos < tokens.length) {
1585
- const results2 = [];
1586
- let pos2 = 0;
1587
- while (pos2 < tokens.length) {
1588
- const [res, newPos] = this.parseNextExpr(tokens, pos2);
1589
- pos2 = newPos;
1590
- if (res.type === "whitespace") {
1591
- if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
1592
- continue;
1593
- }
1594
- if (!this.newline_sensitive && res.content === `
1595
- `) {
1596
- continue;
1597
- }
1646
+ let pos = start;
1647
+ while (pos < end) {
1648
+ const [res, newPos] = this.parseNextExpr(tokens, pos);
1649
+ pos = newPos;
1650
+ if (res.type === "whitespace") {
1651
+ if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
1652
+ continue;
1598
1653
  }
1599
- if (res.type === "control" && res.content === "&") {
1600
- throw new LatexParserError("Unexpected & outside of an alignment");
1654
+ if (!this.newline_sensitive && res.content === "\n") {
1655
+ continue;
1601
1656
  }
1602
- results2.push(res);
1603
1657
  }
1604
- if (results2.length === 0) {
1605
- return EMPTY_NODE;
1606
- } else if (results2.length === 1) {
1607
- return results2[0];
1608
- } else {
1609
- return new TexNode("ordgroup", "", results2);
1658
+ if (res.type === "control" && res.content === "&") {
1659
+ throw new LatexParserError("Unexpected & outside of an alignment");
1610
1660
  }
1661
+ results.push(res);
1611
1662
  }
1663
+ let node;
1612
1664
  if (results.length === 0) {
1613
- return EMPTY_NODE;
1665
+ node = EMPTY_NODE;
1614
1666
  } else if (results.length === 1) {
1615
- return results[0];
1667
+ node = results[0];
1616
1668
  } else {
1617
- return new TexNode("ordgroup", "", results);
1669
+ node = new TexNode("ordgroup", "", results);
1618
1670
  }
1671
+ return [node, end + 1];
1619
1672
  }
1620
1673
  parseNextExpr(tokens, start) {
1621
1674
  let [base, pos] = this.parseNextExprWithoutSupSub(tokens, start);
@@ -1653,7 +1706,7 @@ class LatexParser {
1653
1706
  }
1654
1707
  if (num_prime > 0) {
1655
1708
  res.sup = new TexNode("ordgroup", "", []);
1656
- for (let i = 0;i < num_prime; i++) {
1709
+ for (let i = 0; i < num_prime; i++) {
1657
1710
  res.sup.args.push(new TexNode("element", "'"));
1658
1711
  }
1659
1712
  if (sup) {
@@ -1672,8 +1725,7 @@ class LatexParser {
1672
1725
  }
1673
1726
  parseNextExprWithoutSupSub(tokens, start) {
1674
1727
  const firstToken = tokens[start];
1675
- const tokenType = firstToken.type;
1676
- switch (tokenType) {
1728
+ switch (firstToken.type) {
1677
1729
  case 0 /* ELEMENT */:
1678
1730
  return [new TexNode("element", firstToken.value), start + 1];
1679
1731
  case 2 /* TEXT */:
@@ -1699,8 +1751,7 @@ class LatexParser {
1699
1751
  if (posClosingBracket === -1) {
1700
1752
  throw new LatexParserError("Unmatched '{'");
1701
1753
  }
1702
- const exprInside = tokens.slice(start + 1, posClosingBracket);
1703
- return [this.parse(exprInside), posClosingBracket + 1];
1754
+ return this.parseGroup(tokens, start + 1, posClosingBracket);
1704
1755
  case "}":
1705
1756
  throw new LatexParserError("Unmatched '}'");
1706
1757
  case "\\\\":
@@ -1743,8 +1794,7 @@ class LatexParser {
1743
1794
  if (posRightSquareBracket === -1) {
1744
1795
  throw new LatexParserError("No matching right square bracket for [");
1745
1796
  }
1746
- const exprInside = tokens.slice(posLeftSquareBracket + 1, posRightSquareBracket);
1747
- const exponent = this.parse(exprInside);
1797
+ const [exponent, _] = this.parseGroup(tokens, posLeftSquareBracket + 1, posRightSquareBracket);
1748
1798
  const [arg12, newPos2] = this.parseNextExprWithoutSupSub(tokens, posRightSquareBracket + 1);
1749
1799
  return [new TexNode("unaryFunc", command, [arg12], exponent), newPos2];
1750
1800
  } else if (command === "\\text") {
@@ -1797,8 +1847,7 @@ class LatexParser {
1797
1847
  throw new LatexParserError("Invalid delimiter after \\right");
1798
1848
  }
1799
1849
  pos++;
1800
- const exprInside = tokens.slice(exprInsideStart, exprInsideEnd);
1801
- const body = this.parse(exprInside);
1850
+ const [body, _] = this.parseGroup(tokens, exprInsideStart, exprInsideEnd);
1802
1851
  const args = [
1803
1852
  new TexNode("element", leftDelimiter.value),
1804
1853
  body,
@@ -1852,8 +1901,7 @@ class LatexParser {
1852
1901
  if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
1853
1902
  continue;
1854
1903
  }
1855
- if (!this.newline_sensitive && res.content === `
1856
- `) {
1904
+ if (!this.newline_sensitive && res.content === "\n") {
1857
1905
  continue;
1858
1906
  }
1859
1907
  }
@@ -1871,11 +1919,11 @@ class LatexParser {
1871
1919
  }
1872
1920
  return allRows;
1873
1921
  }
1874
- }
1922
+ };
1875
1923
  function passIgnoreWhitespaceBeforeScriptMark(tokens) {
1876
1924
  const is_script_mark = (token) => token.eq(SUB_SYMBOL) || token.eq(SUP_SYMBOL);
1877
1925
  let out_tokens = [];
1878
- for (let i = 0;i < tokens.length; i++) {
1926
+ for (let i = 0; i < tokens.length; i++) {
1879
1927
  if (tokens[i].type === 4 /* SPACE */ && i + 1 < tokens.length && is_script_mark(tokens[i + 1])) {
1880
1928
  continue;
1881
1929
  }
@@ -1899,52 +1947,102 @@ function passExpandCustomTexMacros(tokens, customTexMacros) {
1899
1947
  return out_tokens;
1900
1948
  }
1901
1949
  function parseTex(tex, customTexMacros) {
1902
- const parser = new LatexParser;
1950
+ const parser = new LatexParser();
1903
1951
  let tokens = tokenize(tex);
1904
1952
  tokens = passIgnoreWhitespaceBeforeScriptMark(tokens);
1905
1953
  tokens = passExpandCustomTexMacros(tokens, customTexMacros);
1906
1954
  return parser.parse(tokens);
1907
1955
  }
1908
1956
 
1957
+ // src/typst-shorthands.ts
1958
+ var shorthandMap = /* @__PURE__ */ new Map([
1959
+ ["arrow.l.r.double.long", "<==>"],
1960
+ ["arrow.l.r.long", "<-->"],
1961
+ ["arrow.r.bar", "|->"],
1962
+ ["arrow.r.double.bar", "|=>"],
1963
+ ["arrow.r.double.long", "==>"],
1964
+ ["arrow.r.long", "-->"],
1965
+ ["arrow.r.long.squiggly", "~~>"],
1966
+ ["arrow.r.tail", ">->"],
1967
+ ["arrow.r.twohead", "->>"],
1968
+ ["arrow.l.double.long", "<=="],
1969
+ ["arrow.l.long", "<--"],
1970
+ ["arrow.l.long.squiggly", "<~~"],
1971
+ ["arrow.l.tail", "<-<"],
1972
+ ["arrow.l.twohead", "<<-"],
1973
+ ["arrow.l.r", "<->"],
1974
+ ["arrow.l.r.double", "<=>"],
1975
+ ["colon.double.eq", "::="],
1976
+ ["dots.h", "..."],
1977
+ ["gt.triple", ">>>"],
1978
+ ["lt.triple", "<<<"],
1979
+ ["arrow.r", "->"],
1980
+ ["arrow.r.double", "=>"],
1981
+ ["arrow.r.squiggly", "~>"],
1982
+ ["arrow.l", "<-"],
1983
+ ["arrow.l.squiggly", "<~"],
1984
+ ["bar.v.double", "||"],
1985
+ ["bracket.l.double", "[|"],
1986
+ ["bracket.r.double", "|]"],
1987
+ ["colon.eq", ":="],
1988
+ ["eq.colon", "=:"],
1989
+ ["eq.not", "!="],
1990
+ ["gt.double", ">>"],
1991
+ ["gt.eq", ">="],
1992
+ ["lt.double", "<<"],
1993
+ ["lt.eq", "<="],
1994
+ ["ast.op", "*"],
1995
+ ["minus", "-"],
1996
+ ["tilde.op", "~"]
1997
+ ]);
1998
+ var reverseShorthandMap = /* @__PURE__ */ new Map();
1999
+ for (const [key, value] of shorthandMap.entries()) {
2000
+ if (value.length > 1) {
2001
+ reverseShorthandMap.set(value, key);
2002
+ }
2003
+ }
2004
+
1909
2005
  // src/typst-writer.ts
1910
- var TYPST_INTRINSIC_SYMBOLS = [
1911
- "dim",
1912
- "id",
1913
- "im",
1914
- "mod",
1915
- "Pr",
1916
- "sech",
1917
- "csch"
1918
- ];
1919
2006
  function is_delimiter(c) {
1920
- return c.type === "atom" && ["(", ")", "[", "]", "{", "}", "|", "", "", "", ""].includes(c.content);
2007
+ return c.type === "atom" && ["(", ")", "[", "]", "{", "}", "|", "\u230A", "\u230B", "\u2308", "\u2309"].includes(c.content);
1921
2008
  }
1922
2009
  var TYPST_LEFT_PARENTHESIS = new TypstToken(1 /* ELEMENT */, "(");
1923
2010
  var TYPST_RIGHT_PARENTHESIS = new TypstToken(1 /* ELEMENT */, ")");
1924
2011
  var TYPST_COMMA = new TypstToken(1 /* ELEMENT */, ",");
1925
- var TYPST_NEWLINE = new TypstToken(0 /* SYMBOL */, `
1926
- `);
1927
-
1928
- class TypstWriterError extends Error {
1929
- node;
2012
+ var TYPST_NEWLINE = new TypstToken(0 /* SYMBOL */, "\n");
2013
+ function typst_primitive_to_string(value) {
2014
+ switch (typeof value) {
2015
+ case "string":
2016
+ return `"${value}"`;
2017
+ case "number":
2018
+ return value.toString();
2019
+ case "boolean":
2020
+ return value ? "#true" : "#false";
2021
+ default:
2022
+ if (value === null) {
2023
+ return "#none";
2024
+ } else if (value instanceof TypstToken) {
2025
+ return value.toString();
2026
+ }
2027
+ throw new TypstWriterError(`Invalid primitive value: ${value}`, value);
2028
+ }
2029
+ }
2030
+ var TypstWriterError = class extends Error {
1930
2031
  constructor(message, node) {
1931
2032
  super(message);
1932
2033
  this.name = "TypstWriterError";
1933
2034
  this.node = node;
1934
2035
  }
1935
- }
1936
-
1937
- class TypstWriter {
1938
- nonStrict;
1939
- preferTypstIntrinsic;
1940
- keepSpaces;
1941
- buffer = "";
1942
- queue = [];
1943
- insideFunctionDepth = 0;
1944
- constructor(nonStrict, preferTypstIntrinsic, keepSpaces) {
1945
- this.nonStrict = nonStrict;
1946
- this.preferTypstIntrinsic = preferTypstIntrinsic;
1947
- this.keepSpaces = keepSpaces;
2036
+ };
2037
+ var TypstWriter = class {
2038
+ constructor(opt) {
2039
+ this.buffer = "";
2040
+ this.queue = [];
2041
+ this.insideFunctionDepth = 0;
2042
+ this.nonStrict = opt.nonStrict;
2043
+ this.preferShorthands = opt.preferShorthands;
2044
+ this.keepSpaces = opt.keepSpaces;
2045
+ this.inftyToOo = opt.inftyToOo;
1948
2046
  }
1949
2047
  writeBuffer(token) {
1950
2048
  const str = token.toString();
@@ -1959,8 +2057,7 @@ class TypstWriter {
1959
2057
  no_need_space ||= str === "'";
1960
2058
  no_need_space ||= /[0-9]$/.test(this.buffer) && /^[0-9]/.test(str);
1961
2059
  no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
1962
- no_need_space ||= str.startsWith(`
1963
- `);
2060
+ no_need_space ||= str.startsWith("\n");
1964
2061
  no_need_space ||= this.buffer === "";
1965
2062
  no_need_space ||= /^\s/.test(str);
1966
2063
  no_need_space ||= this.buffer.endsWith("&") && str === "=";
@@ -1971,6 +2068,7 @@ class TypstWriter {
1971
2068
  }
1972
2069
  this.buffer += str;
1973
2070
  }
2071
+ // Serialize a tree of TypstNode into a list of TypstToken
1974
2072
  serialize(node) {
1975
2073
  switch (node.type) {
1976
2074
  case "empty":
@@ -1983,9 +2081,19 @@ class TypstWriter {
1983
2081
  }
1984
2082
  break;
1985
2083
  }
1986
- case "symbol":
1987
- this.queue.push(new TypstToken(0 /* SYMBOL */, node.content));
2084
+ case "symbol": {
2085
+ let content = node.content;
2086
+ if (this.preferShorthands) {
2087
+ if (shorthandMap.has(content)) {
2088
+ content = shorthandMap.get(content);
2089
+ }
2090
+ }
2091
+ if (this.inftyToOo && content === "infinity") {
2092
+ content = "oo";
2093
+ }
2094
+ this.queue.push(new TypstToken(0 /* SYMBOL */, content));
1988
2095
  break;
2096
+ }
1989
2097
  case "text":
1990
2098
  this.queue.push(new TypstToken(2 /* TEXT */, node.content));
1991
2099
  break;
@@ -1998,8 +2106,7 @@ class TypstWriter {
1998
2106
  if (this.keepSpaces) {
1999
2107
  this.queue.push(new TypstToken(4 /* SPACE */, c));
2000
2108
  }
2001
- } else if (c === `
2002
- `) {
2109
+ } else if (c === "\n") {
2003
2110
  this.queue.push(new TypstToken(0 /* SYMBOL */, c));
2004
2111
  } else {
2005
2112
  throw new TypstWriterError(`Unexpected whitespace character: ${c}`, node);
@@ -2038,7 +2145,7 @@ class TypstWriter {
2038
2145
  this.queue.push(func_symbol);
2039
2146
  this.insideFunctionDepth++;
2040
2147
  this.queue.push(TYPST_LEFT_PARENTHESIS);
2041
- for (let i = 0;i < node.args.length; i++) {
2148
+ for (let i = 0; i < node.args.length; i++) {
2042
2149
  this.serialize(node.args[i]);
2043
2150
  if (i < node.args.length - 1) {
2044
2151
  this.queue.push(new TypstToken(1 /* ELEMENT */, ","));
@@ -2046,7 +2153,8 @@ class TypstWriter {
2046
2153
  }
2047
2154
  if (node.options) {
2048
2155
  for (const [key, value] of Object.entries(node.options)) {
2049
- this.queue.push(new TypstToken(0 /* SYMBOL */, `, ${key}: ${value}`));
2156
+ const value_str = typst_primitive_to_string(value);
2157
+ this.queue.push(new TypstToken(0 /* SYMBOL */, `, ${key}: ${value_str}`));
2050
2158
  }
2051
2159
  }
2052
2160
  this.queue.push(TYPST_RIGHT_PARENTHESIS);
@@ -2094,7 +2202,8 @@ class TypstWriter {
2094
2202
  this.queue.push(TYPST_LEFT_PARENTHESIS);
2095
2203
  if (node.options) {
2096
2204
  for (const [key, value] of Object.entries(node.options)) {
2097
- this.queue.push(new TypstToken(0 /* SYMBOL */, `${key}: ${value}, `));
2205
+ const value_str = typst_primitive_to_string(value);
2206
+ this.queue.push(new TypstToken(0 /* SYMBOL */, `${key}: ${value_str}, `));
2098
2207
  }
2099
2208
  }
2100
2209
  matrix.forEach((row, i) => {
@@ -2145,7 +2254,7 @@ class TypstWriter {
2145
2254
  }
2146
2255
  flushQueue() {
2147
2256
  const SOFT_SPACE = new TypstToken(6 /* CONTROL */, " ");
2148
- for (let i = 0;i < this.queue.length; i++) {
2257
+ for (let i = 0; i < this.queue.length; i++) {
2149
2258
  let token = this.queue[i];
2150
2259
  if (token.eq(SOFT_SPACE)) {
2151
2260
  if (i === this.queue.length - 1) {
@@ -2183,9 +2292,19 @@ class TypstWriter {
2183
2292
  }
2184
2293
  return this.buffer;
2185
2294
  }
2186
- }
2295
+ };
2187
2296
 
2188
2297
  // src/convert.ts
2298
+ var TYPST_INTRINSIC_SYMBOLS = [
2299
+ "dim",
2300
+ "id",
2301
+ "im",
2302
+ "mod",
2303
+ "Pr",
2304
+ "sech",
2305
+ "csch"
2306
+ // 'sgn
2307
+ ];
2189
2308
  function tex_token_to_typst(token) {
2190
2309
  if (/^[a-zA-Z0-9]$/.test(token)) {
2191
2310
  return token;
@@ -2228,12 +2347,21 @@ function convert_overset(node, options) {
2228
2347
  if (is_def(sup) && is_eq(base)) {
2229
2348
  return new TypstNode("symbol", "eq.def");
2230
2349
  }
2231
- const op_call = new TypstNode("funcCall", "op", [convert_tex_node_to_typst(base, options)]);
2232
- op_call.setOptions({ limits: "#true" });
2233
- return new TypstNode("supsub", "", [], {
2234
- base: op_call,
2235
- sup: convert_tex_node_to_typst(sup, options)
2236
- });
2350
+ const op_call = new TypstNode(
2351
+ "funcCall",
2352
+ "op",
2353
+ [convert_tex_node_to_typst(base, options)]
2354
+ );
2355
+ op_call.setOptions({ limits: TYPST_TRUE });
2356
+ return new TypstNode(
2357
+ "supsub",
2358
+ "",
2359
+ [],
2360
+ {
2361
+ base: op_call,
2362
+ sup: convert_tex_node_to_typst(sup, options)
2363
+ }
2364
+ );
2237
2365
  }
2238
2366
  function convert_tex_node_to_typst(node, options = {}) {
2239
2367
  switch (node.type) {
@@ -2242,7 +2370,11 @@ function convert_tex_node_to_typst(node, options = {}) {
2242
2370
  case "whitespace":
2243
2371
  return new TypstNode("whitespace", node.content);
2244
2372
  case "ordgroup":
2245
- return new TypstNode("group", "", node.args.map((n) => convert_tex_node_to_typst(n, options)));
2373
+ return new TypstNode(
2374
+ "group",
2375
+ "",
2376
+ node.args.map((n) => convert_tex_node_to_typst(n, options))
2377
+ );
2246
2378
  case "element":
2247
2379
  return new TypstNode("atom", tex_token_to_typst(node.content));
2248
2380
  case "symbol":
@@ -2254,9 +2386,17 @@ function convert_tex_node_to_typst(node, options = {}) {
2254
2386
  case "supsub": {
2255
2387
  let { base, sup, sub } = node.data;
2256
2388
  if (base && base.type === "unaryFunc" && base.content === "\\overbrace" && sup) {
2257
- return new TypstNode("funcCall", "overbrace", [convert_tex_node_to_typst(base.args[0], options), convert_tex_node_to_typst(sup, options)]);
2389
+ return new TypstNode(
2390
+ "funcCall",
2391
+ "overbrace",
2392
+ [convert_tex_node_to_typst(base.args[0], options), convert_tex_node_to_typst(sup, options)]
2393
+ );
2258
2394
  } else if (base && base.type === "unaryFunc" && base.content === "\\underbrace" && sub) {
2259
- return new TypstNode("funcCall", "underbrace", [convert_tex_node_to_typst(base.args[0], options), convert_tex_node_to_typst(sub, options)]);
2395
+ return new TypstNode(
2396
+ "funcCall",
2397
+ "underbrace",
2398
+ [convert_tex_node_to_typst(base.args[0], options), convert_tex_node_to_typst(sub, options)]
2399
+ );
2260
2400
  }
2261
2401
  const data = {
2262
2402
  base: convert_tex_node_to_typst(base, options)
@@ -2274,7 +2414,11 @@ function convert_tex_node_to_typst(node, options = {}) {
2274
2414
  }
2275
2415
  case "leftright": {
2276
2416
  const [left, body, right] = node.args;
2277
- const group = new TypstNode("group", "", node.args.map((n) => convert_tex_node_to_typst(n, options)));
2417
+ const group = new TypstNode(
2418
+ "group",
2419
+ "",
2420
+ node.args.map((n) => convert_tex_node_to_typst(n, options))
2421
+ );
2278
2422
  if ([
2279
2423
  "[]",
2280
2424
  "()",
@@ -2292,7 +2436,11 @@ function convert_tex_node_to_typst(node, options = {}) {
2292
2436
  group.args.shift();
2293
2437
  return new TypstNode("funcCall", "lr", [group]);
2294
2438
  }
2295
- return new TypstNode("funcCall", "lr", [group]);
2439
+ return new TypstNode(
2440
+ "funcCall",
2441
+ "lr",
2442
+ [group]
2443
+ );
2296
2444
  }
2297
2445
  case "binaryFunc": {
2298
2446
  if (node.content === "\\overset") {
@@ -2300,20 +2448,40 @@ function convert_tex_node_to_typst(node, options = {}) {
2300
2448
  }
2301
2449
  if (node.content === "\\frac") {
2302
2450
  if (options.fracToSlash) {
2303
- return new TypstNode("fraction", "", node.args.map((n) => convert_tex_node_to_typst(n, options)));
2451
+ return new TypstNode(
2452
+ "fraction",
2453
+ "",
2454
+ node.args.map((n) => convert_tex_node_to_typst(n, options))
2455
+ );
2304
2456
  }
2305
2457
  }
2306
- return new TypstNode("funcCall", tex_token_to_typst(node.content), node.args.map((n) => convert_tex_node_to_typst(n, options)));
2458
+ return new TypstNode(
2459
+ "funcCall",
2460
+ tex_token_to_typst(node.content),
2461
+ node.args.map((n) => convert_tex_node_to_typst(n, options))
2462
+ );
2307
2463
  }
2308
2464
  case "unaryFunc": {
2309
2465
  const arg0 = convert_tex_node_to_typst(node.args[0], options);
2310
2466
  if (node.content === "\\sqrt" && node.data) {
2311
2467
  const data = convert_tex_node_to_typst(node.data, options);
2312
- return new TypstNode("funcCall", "root", [data, arg0]);
2468
+ return new TypstNode(
2469
+ "funcCall",
2470
+ "root",
2471
+ [data, arg0]
2472
+ );
2313
2473
  }
2314
2474
  if (node.content === "\\mathbf") {
2315
- const inner = new TypstNode("funcCall", "bold", [arg0]);
2316
- return new TypstNode("funcCall", "upright", [inner]);
2475
+ const inner = new TypstNode(
2476
+ "funcCall",
2477
+ "bold",
2478
+ [arg0]
2479
+ );
2480
+ return new TypstNode(
2481
+ "funcCall",
2482
+ "upright",
2483
+ [inner]
2484
+ );
2317
2485
  }
2318
2486
  if (node.content === "\\mathbb" && arg0.type === "atom" && /^[A-Z]$/.test(arg0.content)) {
2319
2487
  return new TypstNode("symbol", arg0.content + arg0.content);
@@ -2327,21 +2495,55 @@ function convert_tex_node_to_typst(node, options = {}) {
2327
2495
  if (TYPST_INTRINSIC_SYMBOLS.includes(text)) {
2328
2496
  return new TypstNode("symbol", text);
2329
2497
  } else {
2330
- return new TypstNode("funcCall", "op", [new TypstNode("text", text)]);
2498
+ return new TypstNode(
2499
+ "funcCall",
2500
+ "op",
2501
+ [new TypstNode("text", text)]
2502
+ );
2331
2503
  }
2332
2504
  }
2333
- return new TypstNode("funcCall", tex_token_to_typst(node.content), node.args.map((n) => convert_tex_node_to_typst(n, options)));
2505
+ return new TypstNode(
2506
+ "funcCall",
2507
+ tex_token_to_typst(node.content),
2508
+ node.args.map((n) => convert_tex_node_to_typst(n, options))
2509
+ );
2334
2510
  }
2335
2511
  case "beginend": {
2336
2512
  const matrix = node.data;
2337
2513
  const data = matrix.map((row) => row.map((n) => convert_tex_node_to_typst(n, options)));
2338
2514
  if (node.content.startsWith("align")) {
2339
2515
  return new TypstNode("align", "", [], data);
2340
- } else {
2516
+ }
2517
+ if (node.content.endsWith("matrix")) {
2518
+ let delim = null;
2519
+ switch (node.content) {
2520
+ case "matrix":
2521
+ delim = TYPST_NONE;
2522
+ break;
2523
+ case "pmatrix":
2524
+ delim = "(";
2525
+ break;
2526
+ case "bmatrix":
2527
+ delim = "[";
2528
+ break;
2529
+ case "Bmatrix":
2530
+ delim = "{";
2531
+ break;
2532
+ case "vmatrix":
2533
+ delim = "|";
2534
+ break;
2535
+ case "Vmatrix": {
2536
+ delim = new TypstToken(0 /* SYMBOL */, "bar.v.double");
2537
+ break;
2538
+ }
2539
+ default:
2540
+ throw new TypstWriterError(`Unimplemented beginend: ${node.content}`, node);
2541
+ }
2341
2542
  const res = new TypstNode("matrix", "", [], data);
2342
- res.setOptions({ delim: "#none" });
2543
+ res.setOptions({ "delim": delim });
2343
2544
  return res;
2344
2545
  }
2546
+ throw new TypstWriterError(`Unimplemented beginend: ${node.content}`, node);
2345
2547
  }
2346
2548
  case "unknownMacro":
2347
2549
  return new TypstNode("unknown", tex_token_to_typst(node.content));
@@ -2413,8 +2615,10 @@ function convert_typst_node_to_tex(node) {
2413
2615
  return new TexNode("element", node.content);
2414
2616
  case "symbol":
2415
2617
  switch (node.content) {
2618
+ // special hook for comma
2416
2619
  case "comma":
2417
2620
  return new TexNode("element", ",");
2621
+ // special hook for hyph and hyph.minus
2418
2622
  case "hyph":
2419
2623
  case "hyph.minus":
2420
2624
  return new TexNode("text", "-");
@@ -2498,7 +2702,7 @@ function convert_typst_node_to_tex(node) {
2498
2702
  if (node.options) {
2499
2703
  if ("delim" in node.options) {
2500
2704
  switch (node.options.delim) {
2501
- case "#none":
2705
+ case TYPST_NONE:
2502
2706
  return matrix;
2503
2707
  case "[":
2504
2708
  left_delim = "\\left[";
@@ -2559,6 +2763,8 @@ function convert_typst_node_to_tex(node) {
2559
2763
  }
2560
2764
 
2561
2765
  // src/typst-parser.ts
2766
+ var TYPST_EMPTY_NODE = new TypstNode("empty", "");
2767
+ var TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
2562
2768
  function eat_primes2(tokens, start) {
2563
2769
  let pos = start;
2564
2770
  while (pos < tokens.length && tokens[pos].eq(new TypstToken(1 /* ELEMENT */, "'"))) {
@@ -2573,7 +2779,14 @@ function eat_identifier_name(typst, start) {
2573
2779
  }
2574
2780
  return typst.substring(start, pos);
2575
2781
  }
2576
- var TYPST_EMPTY_NODE = new TypstNode("empty", "");
2782
+ function try_eat_shorthand(typst, start) {
2783
+ for (const shorthand of TYPST_SHORTHANDS) {
2784
+ if (typst.startsWith(shorthand, start)) {
2785
+ return shorthand;
2786
+ }
2787
+ }
2788
+ return null;
2789
+ }
2577
2790
  function tokenize_typst(typst) {
2578
2791
  const tokens = [];
2579
2792
  let pos = 0;
@@ -2587,20 +2800,16 @@ function tokenize_typst(typst) {
2587
2800
  token = new TypstToken(6 /* CONTROL */, firstChar);
2588
2801
  pos++;
2589
2802
  break;
2590
- case `
2591
- `:
2803
+ case "\n":
2592
2804
  token = new TypstToken(7 /* NEWLINE */, firstChar);
2593
2805
  pos++;
2594
2806
  break;
2595
2807
  case "\r": {
2596
- if (pos + 1 < typst.length && typst[pos + 1] === `
2597
- `) {
2598
- token = new TypstToken(7 /* NEWLINE */, `
2599
- `);
2808
+ if (pos + 1 < typst.length && typst[pos + 1] === "\n") {
2809
+ token = new TypstToken(7 /* NEWLINE */, "\n");
2600
2810
  pos += 2;
2601
2811
  } else {
2602
- token = new TypstToken(7 /* NEWLINE */, `
2603
- `);
2812
+ token = new TypstToken(7 /* NEWLINE */, "\n");
2604
2813
  pos++;
2605
2814
  }
2606
2815
  break;
@@ -2617,8 +2826,7 @@ function tokenize_typst(typst) {
2617
2826
  case "/": {
2618
2827
  if (pos < typst.length && typst[pos + 1] === "/") {
2619
2828
  let newPos = pos + 2;
2620
- while (newPos < typst.length && typst[newPos] !== `
2621
- `) {
2829
+ while (newPos < typst.length && typst[newPos] !== "\n") {
2622
2830
  newPos++;
2623
2831
  }
2624
2832
  token = new TypstToken(3 /* COMMENT */, typst.slice(pos + 2, newPos));
@@ -2664,6 +2872,12 @@ function tokenize_typst(typst) {
2664
2872
  break;
2665
2873
  }
2666
2874
  default: {
2875
+ const shorthand = try_eat_shorthand(typst, pos);
2876
+ if (shorthand !== null) {
2877
+ token = new TypstToken(0 /* SYMBOL */, reverseShorthandMap.get(shorthand));
2878
+ pos += shorthand.length;
2879
+ break;
2880
+ }
2667
2881
  if (isdigit(firstChar)) {
2668
2882
  let newPos = pos;
2669
2883
  while (newPos < typst.length && isdigit(typst[newPos])) {
@@ -2730,7 +2944,7 @@ function find_closing_parenthesis(nodes, start) {
2730
2944
  }
2731
2945
  function primes(num) {
2732
2946
  const res = [];
2733
- for (let i = 0;i < num; i++) {
2947
+ for (let i = 0; i < num; i++) {
2734
2948
  res.push(new TypstNode("atom", "'"));
2735
2949
  }
2736
2950
  return res;
@@ -2746,7 +2960,7 @@ function next_non_whitespace(nodes, start) {
2746
2960
  function trim_whitespace_around_operators(nodes) {
2747
2961
  let after_operator = false;
2748
2962
  const res = [];
2749
- for (let i = 0;i < nodes.length; i++) {
2963
+ for (let i = 0; i < nodes.length; i++) {
2750
2964
  const current = nodes[i];
2751
2965
  if (current.type === "whitespace") {
2752
2966
  if (after_operator) {
@@ -2820,13 +3034,12 @@ function process_operators(nodes, parenthesis = false) {
2820
3034
  }
2821
3035
  }
2822
3036
  }
2823
-
2824
- class TypstParserError extends Error {
3037
+ var TypstParserError = class extends Error {
2825
3038
  constructor(message) {
2826
3039
  super(message);
2827
3040
  this.name = "TypstParserError";
2828
3041
  }
2829
- }
3042
+ };
2830
3043
  var SUB_SYMBOL2 = new TypstToken(6 /* CONTROL */, "_");
2831
3044
  var SUP_SYMBOL2 = new TypstToken(6 /* CONTROL */, "^");
2832
3045
  var LEFT_PARENTHESES = new TypstToken(1 /* ELEMENT */, "(");
@@ -2838,10 +3051,7 @@ var RIGHT_CURLY_BRACKET2 = new TypstToken(1 /* ELEMENT */, "}");
2838
3051
  var COMMA = new TypstToken(1 /* ELEMENT */, ",");
2839
3052
  var SEMICOLON = new TypstToken(1 /* ELEMENT */, ";");
2840
3053
  var SINGLE_SPACE = new TypstToken(4 /* SPACE */, " ");
2841
-
2842
- class TypstParser {
2843
- space_sensitive;
2844
- newline_sensitive;
3054
+ var TypstParser = class {
2845
3055
  constructor(space_sensitive = true, newline_sensitive = true) {
2846
3056
  this.space_sensitive = space_sensitive;
2847
3057
  this.newline_sensitive = newline_sensitive;
@@ -2860,8 +3070,7 @@ class TypstParser {
2860
3070
  if (!this.space_sensitive && res.content.replace(/ /g, "").length === 0) {
2861
3071
  continue;
2862
3072
  }
2863
- if (!this.newline_sensitive && res.content === `
2864
- `) {
3073
+ if (!this.newline_sensitive && res.content === "\n") {
2865
3074
  continue;
2866
3075
  }
2867
3076
  }
@@ -2956,10 +3165,12 @@ class TypstParser {
2956
3165
  }
2957
3166
  return [node, start + 1];
2958
3167
  }
3168
+ // start: the position of the left parentheses
2959
3169
  parseArguments(tokens, start) {
2960
3170
  const end = find_closing_match2(tokens, start);
2961
3171
  return [this.parseCommaSeparatedArguments(tokens, start + 1, end), end + 1];
2962
3172
  }
3173
+ // start: the position of the left parentheses
2963
3174
  parseGroupsOfArguments(tokens, start) {
2964
3175
  const end = find_closing_match2(tokens, start);
2965
3176
  tokens = tokens.slice(0, end);
@@ -2968,11 +3179,11 @@ class TypstParser {
2968
3179
  let pos = start + 1;
2969
3180
  while (pos < end) {
2970
3181
  while (pos < end) {
2971
- let extract_named_params = function(arr) {
3182
+ let extract_named_params2 = function(arr) {
2972
3183
  const COLON = new TypstNode("atom", ":");
2973
3184
  const np2 = {};
2974
3185
  const to_delete = [];
2975
- for (let i = 0;i < arr.length; i++) {
3186
+ for (let i = 0; i < arr.length; i++) {
2976
3187
  if (arr[i].type !== "group") {
2977
3188
  continue;
2978
3189
  }
@@ -2993,7 +3204,7 @@ class TypstParser {
2993
3204
  if (g.args.length !== 4 || !g.args[pos_colon + 2].eq(new TypstNode("symbol", "none"))) {
2994
3205
  throw new TypstParserError("Invalid number of arguments for delim");
2995
3206
  }
2996
- np2["delim"] = "#none";
3207
+ np2["delim"] = TYPST_NONE;
2997
3208
  } else {
2998
3209
  throw new TypstParserError("Not implemented for other types of delim");
2999
3210
  }
@@ -3001,18 +3212,19 @@ class TypstParser {
3001
3212
  throw new TypstParserError("Not implemented for other named parameters");
3002
3213
  }
3003
3214
  }
3004
- for (let i = to_delete.length - 1;i >= 0; i--) {
3215
+ for (let i = to_delete.length - 1; i >= 0; i--) {
3005
3216
  arr.splice(to_delete[i], 1);
3006
3217
  }
3007
3218
  return [arr, np2];
3008
3219
  };
3220
+ var extract_named_params = extract_named_params2;
3009
3221
  let next_stop = array_find(tokens, SEMICOLON, pos);
3010
3222
  if (next_stop === -1) {
3011
3223
  next_stop = end;
3012
3224
  }
3013
3225
  let row = this.parseCommaSeparatedArguments(tokens, pos, next_stop);
3014
3226
  let np = {};
3015
- [row, np] = extract_named_params(row);
3227
+ [row, np] = extract_named_params2(row);
3016
3228
  matrix.push(row);
3017
3229
  Object.assign(named_params, np);
3018
3230
  pos = next_stop + 1;
@@ -3020,6 +3232,7 @@ class TypstParser {
3020
3232
  }
3021
3233
  return [matrix, named_params, end + 1];
3022
3234
  }
3235
+ // start: the position of the first token of arguments
3023
3236
  parseCommaSeparatedArguments(tokens, start, end) {
3024
3237
  const args = [];
3025
3238
  let pos = start;
@@ -3046,17 +3259,19 @@ class TypstParser {
3046
3259
  }
3047
3260
  return args;
3048
3261
  }
3049
- }
3262
+ };
3050
3263
  function parseTypst(typst) {
3051
- const parser = new TypstParser;
3264
+ const parser = new TypstParser();
3052
3265
  let tokens = tokenize_typst(typst);
3053
3266
  return parser.parse(tokens);
3054
3267
  }
3055
3268
 
3056
3269
  // src/tex-writer.ts
3057
- class TexWriter {
3058
- buffer = "";
3059
- queue = [];
3270
+ var TexWriter = class {
3271
+ constructor() {
3272
+ this.buffer = "";
3273
+ this.queue = [];
3274
+ }
3060
3275
  writeBuffer(token) {
3061
3276
  const str = token.toString();
3062
3277
  let no_need_space = false;
@@ -3095,7 +3310,7 @@ class TexWriter {
3095
3310
  this.queue = this.queue.concat(node.serialize());
3096
3311
  }
3097
3312
  flushQueue() {
3098
- for (let i = 0;i < this.queue.length; i++) {
3313
+ for (let i = 0; i < this.queue.length; i++) {
3099
3314
  this.writeBuffer(this.queue[i]);
3100
3315
  }
3101
3316
  this.queue = [];
@@ -3104,46 +3319,41 @@ class TexWriter {
3104
3319
  this.flushQueue();
3105
3320
  return this.buffer;
3106
3321
  }
3107
- }
3322
+ };
3108
3323
 
3109
3324
  // src/index.ts
3110
3325
  function tex2typst(tex, options) {
3111
3326
  const opt = {
3112
3327
  nonStrict: true,
3113
3328
  preferTypstIntrinsic: true,
3329
+ preferShorthands: true,
3114
3330
  keepSpaces: false,
3115
3331
  fracToSlash: true,
3332
+ inftyToOo: false,
3116
3333
  customTexMacros: {}
3117
3334
  };
3118
- if (options) {
3119
- if (options.nonStrict) {
3120
- opt.nonStrict = options.nonStrict;
3121
- }
3122
- if (options.preferTypstIntrinsic) {
3123
- opt.preferTypstIntrinsic = options.preferTypstIntrinsic;
3124
- }
3125
- if (options.customTexMacros) {
3126
- opt.customTexMacros = options.customTexMacros;
3127
- }
3128
- if (options.fracToSlash !== undefined) {
3129
- opt.fracToSlash = options.fracToSlash;
3335
+ if (options !== void 0) {
3336
+ for (const key in opt) {
3337
+ if (options[key] !== void 0) {
3338
+ opt[key] = options[key];
3339
+ }
3130
3340
  }
3131
3341
  }
3132
3342
  const texTree = parseTex(tex, opt.customTexMacros);
3133
3343
  const typstTree = convert_tex_node_to_typst(texTree, opt);
3134
- const writer = new TypstWriter(opt.nonStrict, opt.preferTypstIntrinsic, opt.keepSpaces);
3344
+ const writer = new TypstWriter(opt);
3135
3345
  writer.serialize(typstTree);
3136
3346
  return writer.finalize();
3137
3347
  }
3138
3348
  function typst2tex(typst) {
3139
3349
  const typstTree = parseTypst(typst);
3140
3350
  const texTree = convert_typst_node_to_tex(typstTree);
3141
- const writer = new TexWriter;
3351
+ const writer = new TexWriter();
3142
3352
  writer.append(texTree);
3143
3353
  return writer.finalize();
3144
3354
  }
3145
3355
  export {
3146
- typst2tex,
3356
+ symbolMap,
3147
3357
  tex2typst,
3148
- symbolMap
3358
+ typst2tex
3149
3359
  };