tex2typst 0.3.27-beta.1 → 0.3.27

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
@@ -563,7 +563,8 @@ var TEX_UNARY_COMMANDS = [
563
563
  "overleftarrow",
564
564
  "overrightarrow",
565
565
  "hspace",
566
- "substack"
566
+ "substack",
567
+ "set"
567
568
  ];
568
569
  var TEX_BINARY_COMMANDS = [
569
570
  "frac",
@@ -1118,6 +1119,54 @@ function parseTex(tex, customTexMacros) {
1118
1119
  return parser.parse(tokens);
1119
1120
  }
1120
1121
 
1122
+ // src/typst-shorthands.ts
1123
+ var shorthandMap = /* @__PURE__ */ new Map([
1124
+ ["arrow.l.r.double.long", "<==>"],
1125
+ ["arrow.l.r.long", "<-->"],
1126
+ ["arrow.r.bar", "|->"],
1127
+ ["arrow.r.double.bar", "|=>"],
1128
+ ["arrow.r.double.long", "==>"],
1129
+ ["arrow.r.long", "-->"],
1130
+ ["arrow.r.long.squiggly", "~~>"],
1131
+ ["arrow.r.tail", ">->"],
1132
+ ["arrow.r.twohead", "->>"],
1133
+ ["arrow.l.double.long", "<=="],
1134
+ ["arrow.l.long", "<--"],
1135
+ ["arrow.l.long.squiggly", "<~~"],
1136
+ ["arrow.l.tail", "<-<"],
1137
+ ["arrow.l.twohead", "<<-"],
1138
+ ["arrow.l.r", "<->"],
1139
+ ["arrow.l.r.double", "<=>"],
1140
+ ["colon.double.eq", "::="],
1141
+ ["dots.h", "..."],
1142
+ ["gt.triple", ">>>"],
1143
+ ["lt.triple", "<<<"],
1144
+ ["arrow.r", "->"],
1145
+ ["arrow.r.double", "=>"],
1146
+ ["arrow.r.squiggly", "~>"],
1147
+ ["arrow.l", "<-"],
1148
+ ["arrow.l.squiggly", "<~"],
1149
+ ["bar.v.double", "||"],
1150
+ ["bracket.l.double", "[|"],
1151
+ ["bracket.r.double", "|]"],
1152
+ ["colon.eq", ":="],
1153
+ ["eq.colon", "=:"],
1154
+ ["eq.not", "!="],
1155
+ ["gt.double", ">>"],
1156
+ ["gt.eq", ">="],
1157
+ ["lt.double", "<<"],
1158
+ ["lt.eq", "<="],
1159
+ ["ast.op", "*"],
1160
+ ["minus", "-"],
1161
+ ["tilde.op", "~"]
1162
+ ]);
1163
+ var reverseShorthandMap = /* @__PURE__ */ new Map();
1164
+ for (const [key, value] of shorthandMap.entries()) {
1165
+ if (value.length > 1) {
1166
+ reverseShorthandMap.set(value, key);
1167
+ }
1168
+ }
1169
+
1121
1170
  // src/typst-types.ts
1122
1171
  var TypstToken = class _TypstToken {
1123
1172
  type;
@@ -1147,7 +1196,32 @@ var TypstToken = class _TypstToken {
1147
1196
  }
1148
1197
  static NONE = new _TypstToken(0 /* NONE */, "#none");
1149
1198
  static EMPTY = new _TypstToken(2 /* ELEMENT */, "");
1199
+ static LEFT_BRACE = new _TypstToken(2 /* ELEMENT */, "{");
1200
+ static RIGHT_BRACE = new _TypstToken(2 /* ELEMENT */, "}");
1201
+ static LEFT_DELIMITERS = [
1202
+ new _TypstToken(2 /* ELEMENT */, "("),
1203
+ new _TypstToken(2 /* ELEMENT */, "["),
1204
+ new _TypstToken(2 /* ELEMENT */, "{"),
1205
+ new _TypstToken(2 /* ELEMENT */, "|"),
1206
+ new _TypstToken(1 /* SYMBOL */, "angle.l")
1207
+ ];
1208
+ static RIGHT_DELIMITERS = [
1209
+ new _TypstToken(2 /* ELEMENT */, ")"),
1210
+ new _TypstToken(2 /* ELEMENT */, "]"),
1211
+ new _TypstToken(2 /* ELEMENT */, "}"),
1212
+ new _TypstToken(2 /* ELEMENT */, "|"),
1213
+ new _TypstToken(1 /* SYMBOL */, "angle.r")
1214
+ ];
1150
1215
  };
1216
+ var TypstWriterError = class extends Error {
1217
+ node;
1218
+ constructor(message, node) {
1219
+ super(message);
1220
+ this.name = "TypstWriterError";
1221
+ this.node = node;
1222
+ }
1223
+ };
1224
+ var SOFT_SPACE = new TypstToken(7 /* CONTROL */, " ");
1151
1225
  var TypstNode = class {
1152
1226
  type;
1153
1227
  head;
@@ -1178,6 +1252,39 @@ var TypstTerminal = class extends TypstNode {
1178
1252
  toString() {
1179
1253
  return this.head.toString();
1180
1254
  }
1255
+ serialize(env, options) {
1256
+ if (this.head.type === 2 /* ELEMENT */) {
1257
+ if (this.head.value === "," && env.insideFunctionDepth > 0) {
1258
+ return [new TypstToken(1 /* SYMBOL */, "comma")];
1259
+ }
1260
+ } else if (this.head.type === 1 /* SYMBOL */) {
1261
+ let symbol_name = this.head.value;
1262
+ if (options.preferShorthands) {
1263
+ if (shorthandMap.has(symbol_name)) {
1264
+ symbol_name = shorthandMap.get(symbol_name);
1265
+ }
1266
+ }
1267
+ if (options.inftyToOo && symbol_name === "infinity") {
1268
+ symbol_name = "oo";
1269
+ }
1270
+ return [new TypstToken(1 /* SYMBOL */, symbol_name)];
1271
+ } else if (this.head.type === 6 /* SPACE */ || this.head.type === 8 /* NEWLINE */) {
1272
+ const queue = [];
1273
+ for (const c of this.head.value) {
1274
+ if (c === " ") {
1275
+ if (options.keepSpaces) {
1276
+ queue.push(new TypstToken(6 /* SPACE */, c));
1277
+ }
1278
+ } else if (c === "\n") {
1279
+ queue.push(new TypstToken(1 /* SYMBOL */, c));
1280
+ } else {
1281
+ throw new TypstWriterError(`Unexpected whitespace character: ${c}`, this);
1282
+ }
1283
+ }
1284
+ return queue;
1285
+ }
1286
+ return [this.head];
1287
+ }
1181
1288
  };
1182
1289
  var TypstGroup = class extends TypstNode {
1183
1290
  items;
@@ -1188,6 +1295,16 @@ var TypstGroup = class extends TypstNode {
1188
1295
  isOverHigh() {
1189
1296
  return this.items.some((n) => n.isOverHigh());
1190
1297
  }
1298
+ serialize(env, options) {
1299
+ const queue = this.items.flatMap((n) => n.serialize(env, options));
1300
+ if (queue.length > 0 && queue[0].eq(SOFT_SPACE)) {
1301
+ queue.shift();
1302
+ }
1303
+ if (queue.length > 0 && queue[queue.length - 1].eq(SOFT_SPACE)) {
1304
+ queue.pop();
1305
+ }
1306
+ return queue;
1307
+ }
1191
1308
  };
1192
1309
  var TypstSupsub = class extends TypstNode {
1193
1310
  base;
@@ -1202,6 +1319,25 @@ var TypstSupsub = class extends TypstNode {
1202
1319
  isOverHigh() {
1203
1320
  return this.base.isOverHigh();
1204
1321
  }
1322
+ serialize(env, options) {
1323
+ const queue = [];
1324
+ let { base, sup, sub } = this;
1325
+ queue.push(...base.serialize(env, options));
1326
+ const has_prime = sup && sup.head.eq(new TypstToken(2 /* ELEMENT */, "'"));
1327
+ if (has_prime) {
1328
+ queue.push(new TypstToken(2 /* ELEMENT */, "'"));
1329
+ }
1330
+ if (sub) {
1331
+ queue.push(new TypstToken(2 /* ELEMENT */, "_"));
1332
+ queue.push(...sub.serialize(env, options));
1333
+ }
1334
+ if (sup && !has_prime) {
1335
+ queue.push(new TypstToken(2 /* ELEMENT */, "^"));
1336
+ queue.push(...sup.serialize(env, options));
1337
+ }
1338
+ queue.push(SOFT_SPACE);
1339
+ return queue;
1340
+ }
1205
1341
  };
1206
1342
  var TypstFuncCall = class extends TypstNode {
1207
1343
  args;
@@ -1215,6 +1351,27 @@ var TypstFuncCall = class extends TypstNode {
1215
1351
  }
1216
1352
  return this.args.some((n) => n.isOverHigh());
1217
1353
  }
1354
+ serialize(env, options) {
1355
+ const queue = [];
1356
+ const func_symbol = this.head;
1357
+ queue.push(func_symbol);
1358
+ env.insideFunctionDepth++;
1359
+ queue.push(TYPST_LEFT_PARENTHESIS);
1360
+ for (let i = 0; i < this.args.length; i++) {
1361
+ queue.push(...this.args[i].serialize(env, options));
1362
+ if (i < this.args.length - 1) {
1363
+ queue.push(new TypstToken(2 /* ELEMENT */, ","));
1364
+ }
1365
+ }
1366
+ if (this.options) {
1367
+ for (const [key, value] of Object.entries(this.options)) {
1368
+ queue.push(new TypstToken(3 /* LITERAL */, `, ${key}: ${value.toString()}`));
1369
+ }
1370
+ }
1371
+ queue.push(TYPST_RIGHT_PARENTHESIS);
1372
+ env.insideFunctionDepth--;
1373
+ return queue;
1374
+ }
1218
1375
  };
1219
1376
  var TypstFraction = class extends TypstNode {
1220
1377
  args;
@@ -1225,7 +1382,19 @@ var TypstFraction = class extends TypstNode {
1225
1382
  isOverHigh() {
1226
1383
  return true;
1227
1384
  }
1385
+ serialize(env, options) {
1386
+ const queue = [];
1387
+ const [numerator, denominator] = this.args;
1388
+ queue.push(SOFT_SPACE);
1389
+ queue.push(...numerator.serialize(env, options));
1390
+ queue.push(new TypstToken(2 /* ELEMENT */, "/"));
1391
+ queue.push(...denominator.serialize(env, options));
1392
+ queue.push(SOFT_SPACE);
1393
+ return queue;
1394
+ }
1228
1395
  };
1396
+ var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
1397
+ var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
1229
1398
  var TypstLeftright = class extends TypstNode {
1230
1399
  body;
1231
1400
  left;
@@ -1240,8 +1409,28 @@ var TypstLeftright = class extends TypstNode {
1240
1409
  isOverHigh() {
1241
1410
  return this.body.isOverHigh();
1242
1411
  }
1412
+ serialize(env, options) {
1413
+ const queue = [];
1414
+ const LR = new TypstToken(1 /* SYMBOL */, "lr");
1415
+ const { left, right } = this;
1416
+ if (this.head.eq(LR)) {
1417
+ queue.push(LR);
1418
+ queue.push(TYPST_LEFT_PARENTHESIS);
1419
+ }
1420
+ if (left) {
1421
+ queue.push(left);
1422
+ }
1423
+ queue.push(...this.body.serialize(env, options));
1424
+ if (right) {
1425
+ queue.push(right);
1426
+ }
1427
+ if (this.head.eq(LR)) {
1428
+ queue.push(TYPST_RIGHT_PARENTHESIS);
1429
+ }
1430
+ return queue;
1431
+ }
1243
1432
  };
1244
- var TypstMatrixLike = class extends TypstNode {
1433
+ var TypstMatrixLike = class _TypstMatrixLike extends TypstNode {
1245
1434
  matrix;
1246
1435
  // head is 'mat', 'cases' or null
1247
1436
  constructor(head, data) {
@@ -1251,6 +1440,48 @@ var TypstMatrixLike = class extends TypstNode {
1251
1440
  isOverHigh() {
1252
1441
  return true;
1253
1442
  }
1443
+ serialize(env, options) {
1444
+ const queue = [];
1445
+ let cell_sep;
1446
+ let row_sep;
1447
+ if (this.head.eq(_TypstMatrixLike.MAT)) {
1448
+ cell_sep = new TypstToken(2 /* ELEMENT */, ",");
1449
+ row_sep = new TypstToken(2 /* ELEMENT */, ";");
1450
+ } else if (this.head.eq(_TypstMatrixLike.CASES)) {
1451
+ cell_sep = new TypstToken(2 /* ELEMENT */, "&");
1452
+ row_sep = new TypstToken(2 /* ELEMENT */, ",");
1453
+ } else if (this.head.eq(TypstToken.NONE)) {
1454
+ cell_sep = new TypstToken(2 /* ELEMENT */, "&");
1455
+ row_sep = new TypstToken(1 /* SYMBOL */, "\\");
1456
+ }
1457
+ if (!this.head.eq(TypstToken.NONE)) {
1458
+ queue.push(this.head);
1459
+ env.insideFunctionDepth++;
1460
+ queue.push(TYPST_LEFT_PARENTHESIS);
1461
+ if (this.options) {
1462
+ for (const [key, value] of Object.entries(this.options)) {
1463
+ queue.push(new TypstToken(3 /* LITERAL */, `${key}: ${value.toString()}, `));
1464
+ }
1465
+ }
1466
+ }
1467
+ this.matrix.forEach((row, i) => {
1468
+ row.forEach((cell, j) => {
1469
+ queue.push(...cell.serialize(env, options));
1470
+ if (j < row.length - 1) {
1471
+ queue.push(cell_sep);
1472
+ } else {
1473
+ if (i < this.matrix.length - 1) {
1474
+ queue.push(row_sep);
1475
+ }
1476
+ }
1477
+ });
1478
+ });
1479
+ if (!this.head.eq(TypstToken.NONE)) {
1480
+ queue.push(TYPST_RIGHT_PARENTHESIS);
1481
+ env.insideFunctionDepth--;
1482
+ }
1483
+ return queue;
1484
+ }
1254
1485
  static MAT = new TypstToken(1 /* SYMBOL */, "mat");
1255
1486
  static CASES = new TypstToken(1 /* SYMBOL */, "cases");
1256
1487
  };
@@ -1270,88 +1501,45 @@ var TypstMarkupFunc = class extends TypstNode {
1270
1501
  isOverHigh() {
1271
1502
  return this.fragments.some((n) => n.isOverHigh());
1272
1503
  }
1273
- };
1274
-
1275
- // src/typst-shorthands.ts
1276
- var shorthandMap = /* @__PURE__ */ new Map([
1277
- ["arrow.l.r.double.long", "<==>"],
1278
- ["arrow.l.r.long", "<-->"],
1279
- ["arrow.r.bar", "|->"],
1280
- ["arrow.r.double.bar", "|=>"],
1281
- ["arrow.r.double.long", "==>"],
1282
- ["arrow.r.long", "-->"],
1283
- ["arrow.r.long.squiggly", "~~>"],
1284
- ["arrow.r.tail", ">->"],
1285
- ["arrow.r.twohead", "->>"],
1286
- ["arrow.l.double.long", "<=="],
1287
- ["arrow.l.long", "<--"],
1288
- ["arrow.l.long.squiggly", "<~~"],
1289
- ["arrow.l.tail", "<-<"],
1290
- ["arrow.l.twohead", "<<-"],
1291
- ["arrow.l.r", "<->"],
1292
- ["arrow.l.r.double", "<=>"],
1293
- ["colon.double.eq", "::="],
1294
- ["dots.h", "..."],
1295
- ["gt.triple", ">>>"],
1296
- ["lt.triple", "<<<"],
1297
- ["arrow.r", "->"],
1298
- ["arrow.r.double", "=>"],
1299
- ["arrow.r.squiggly", "~>"],
1300
- ["arrow.l", "<-"],
1301
- ["arrow.l.squiggly", "<~"],
1302
- ["bar.v.double", "||"],
1303
- ["bracket.l.double", "[|"],
1304
- ["bracket.r.double", "|]"],
1305
- ["colon.eq", ":="],
1306
- ["eq.colon", "=:"],
1307
- ["eq.not", "!="],
1308
- ["gt.double", ">>"],
1309
- ["gt.eq", ">="],
1310
- ["lt.double", "<<"],
1311
- ["lt.eq", "<="],
1312
- ["ast.op", "*"],
1313
- ["minus", "-"],
1314
- ["tilde.op", "~"]
1315
- ]);
1316
- var reverseShorthandMap = /* @__PURE__ */ new Map();
1317
- for (const [key, value] of shorthandMap.entries()) {
1318
- if (value.length > 1) {
1319
- reverseShorthandMap.set(value, key);
1504
+ serialize(env, options) {
1505
+ const queue = [];
1506
+ queue.push(this.head);
1507
+ env.insideFunctionDepth++;
1508
+ queue.push(TYPST_LEFT_PARENTHESIS);
1509
+ if (this.options) {
1510
+ const entries = Object.entries(this.options);
1511
+ for (let i = 0; i < entries.length; i++) {
1512
+ const [key, value] = entries[i];
1513
+ queue.push(new TypstToken(3 /* LITERAL */, `${key}: ${value.toString()}`));
1514
+ if (i < entries.length - 1) {
1515
+ queue.push(new TypstToken(2 /* ELEMENT */, ","));
1516
+ }
1517
+ }
1518
+ }
1519
+ queue.push(TYPST_RIGHT_PARENTHESIS);
1520
+ queue.push(new TypstToken(3 /* LITERAL */, "["));
1521
+ for (const frag of this.fragments) {
1522
+ queue.push(new TypstToken(3 /* LITERAL */, "$"));
1523
+ queue.push(...frag.serialize(env, options));
1524
+ queue.push(new TypstToken(3 /* LITERAL */, "$"));
1525
+ }
1526
+ queue.push(new TypstToken(3 /* LITERAL */, "]"));
1527
+ return queue;
1320
1528
  }
1321
- }
1529
+ };
1322
1530
 
1323
1531
  // src/typst-writer.ts
1324
- function is_delimiter(c) {
1325
- return c.head.type === 2 /* ELEMENT */ && ["(", ")", "[", "]", "{", "}", "|", "\u230A", "\u230B", "\u2308", "\u2309"].includes(c.head.value);
1326
- }
1327
- var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
1328
- var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
1532
+ var TYPST_LEFT_PARENTHESIS2 = new TypstToken(2 /* ELEMENT */, "(");
1533
+ var TYPST_RIGHT_PARENTHESIS2 = new TypstToken(2 /* ELEMENT */, ")");
1329
1534
  var TYPST_COMMA = new TypstToken(2 /* ELEMENT */, ",");
1330
1535
  var TYPST_NEWLINE = new TypstToken(1 /* SYMBOL */, "\n");
1331
- var SOFT_SPACE = new TypstToken(7 /* CONTROL */, " ");
1332
- var TypstWriterError = class extends Error {
1333
- node;
1334
- constructor(message, node) {
1335
- super(message);
1336
- this.name = "TypstWriterError";
1337
- this.node = node;
1338
- }
1339
- };
1536
+ var SOFT_SPACE2 = new TypstToken(7 /* CONTROL */, " ");
1340
1537
  var TypstWriter = class {
1341
- nonStrict;
1342
- preferShorthands;
1343
- keepSpaces;
1344
- inftyToOo;
1345
- optimize;
1346
1538
  buffer = "";
1347
1539
  queue = [];
1348
- insideFunctionDepth = 0;
1540
+ options;
1349
1541
  constructor(options) {
1350
- this.nonStrict = options.nonStrict;
1351
- this.preferShorthands = options.preferShorthands;
1352
- this.keepSpaces = options.keepSpaces;
1353
- this.inftyToOo = options.inftyToOo;
1354
- this.optimize = options.optimize;
1542
+ this.options = options;
1355
1543
  }
1356
1544
  writeBuffer(previousToken, token) {
1357
1545
  const str = token.toString();
@@ -1367,7 +1555,7 @@ var TypstWriter = class {
1367
1555
  no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
1368
1556
  no_need_space ||= str.startsWith("\n");
1369
1557
  no_need_space ||= this.buffer === "";
1370
- no_need_space ||= /^\s/.test(str);
1558
+ no_need_space ||= /\s$/.test(this.buffer) || /^\s/.test(str);
1371
1559
  no_need_space ||= this.buffer.endsWith("&") && str === "=";
1372
1560
  no_need_space ||= this.buffer.endsWith("/") || str === "/";
1373
1561
  no_need_space ||= token.type === 3 /* LITERAL */;
@@ -1382,239 +1570,31 @@ var TypstWriter = class {
1382
1570
  }
1383
1571
  // Serialize a tree of TypstNode into a list of TypstToken
1384
1572
  serialize(abstractNode) {
1385
- switch (abstractNode.type) {
1386
- case "terminal": {
1387
- const node = abstractNode;
1388
- if (node.head.type === 2 /* ELEMENT */) {
1389
- if (node.head.value === "," && this.insideFunctionDepth > 0) {
1390
- this.queue.push(new TypstToken(1 /* SYMBOL */, "comma"));
1391
- } else {
1392
- this.queue.push(node.head);
1393
- }
1394
- break;
1395
- } else if (node.head.type === 1 /* SYMBOL */) {
1396
- let symbol_name = node.head.value;
1397
- if (this.preferShorthands) {
1398
- if (shorthandMap.has(symbol_name)) {
1399
- symbol_name = shorthandMap.get(symbol_name);
1400
- }
1401
- }
1402
- if (this.inftyToOo && symbol_name === "infinity") {
1403
- symbol_name = "oo";
1404
- }
1405
- this.queue.push(new TypstToken(1 /* SYMBOL */, symbol_name));
1406
- break;
1407
- } else if (node.head.type === 6 /* SPACE */ || node.head.type === 8 /* NEWLINE */) {
1408
- for (const c of node.head.value) {
1409
- if (c === " ") {
1410
- if (this.keepSpaces) {
1411
- this.queue.push(new TypstToken(6 /* SPACE */, c));
1412
- }
1413
- } else if (c === "\n") {
1414
- this.queue.push(new TypstToken(1 /* SYMBOL */, c));
1415
- } else {
1416
- throw new TypstWriterError(`Unexpected whitespace character: ${c}`, node);
1417
- }
1418
- }
1419
- break;
1420
- } else {
1421
- this.queue.push(node.head);
1422
- break;
1423
- }
1424
- }
1425
- case "group": {
1426
- const node = abstractNode;
1427
- for (const item of node.items) {
1428
- this.serialize(item);
1429
- }
1430
- break;
1431
- }
1432
- case "leftright": {
1433
- const node = abstractNode;
1434
- const LR = new TypstToken(1 /* SYMBOL */, "lr");
1435
- const { left, right } = node;
1436
- if (node.head.eq(LR)) {
1437
- this.queue.push(LR);
1438
- this.queue.push(TYPST_LEFT_PARENTHESIS);
1439
- }
1440
- if (left) {
1441
- this.queue.push(left);
1442
- }
1443
- this.serialize(node.body);
1444
- if (right) {
1445
- this.queue.push(right);
1446
- }
1447
- if (node.head.eq(LR)) {
1448
- this.queue.push(TYPST_RIGHT_PARENTHESIS);
1449
- }
1450
- break;
1451
- }
1452
- case "supsub": {
1453
- const node = abstractNode;
1454
- let { base, sup, sub } = node;
1455
- this.appendWithBracketsIfNeeded(base);
1456
- let trailing_space_needed = false;
1457
- const has_prime = sup && sup.head.eq(new TypstToken(2 /* ELEMENT */, "'"));
1458
- if (has_prime) {
1459
- this.queue.push(new TypstToken(2 /* ELEMENT */, "'"));
1460
- trailing_space_needed = false;
1461
- }
1462
- if (sub) {
1463
- this.queue.push(new TypstToken(2 /* ELEMENT */, "_"));
1464
- trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
1465
- }
1466
- if (sup && !has_prime) {
1467
- this.queue.push(new TypstToken(2 /* ELEMENT */, "^"));
1468
- trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
1469
- }
1470
- if (trailing_space_needed) {
1471
- this.queue.push(SOFT_SPACE);
1472
- }
1473
- break;
1474
- }
1475
- case "funcCall": {
1476
- const node = abstractNode;
1477
- const func_symbol = node.head;
1478
- this.queue.push(func_symbol);
1479
- this.insideFunctionDepth++;
1480
- this.queue.push(TYPST_LEFT_PARENTHESIS);
1481
- for (let i = 0; i < node.args.length; i++) {
1482
- this.serialize(node.args[i]);
1483
- if (i < node.args.length - 1) {
1484
- this.queue.push(new TypstToken(2 /* ELEMENT */, ","));
1485
- }
1486
- }
1487
- if (node.options) {
1488
- for (const [key, value] of Object.entries(node.options)) {
1489
- this.queue.push(new TypstToken(3 /* LITERAL */, `, ${key}: ${value.toString()}`));
1490
- }
1491
- }
1492
- this.queue.push(TYPST_RIGHT_PARENTHESIS);
1493
- this.insideFunctionDepth--;
1494
- break;
1495
- }
1496
- case "fraction": {
1497
- const node = abstractNode;
1498
- const [numerator, denominator] = node.args;
1499
- const pos = this.queue.length;
1500
- const no_wrap = this.appendWithBracketsIfNeeded(numerator);
1501
- const wrapped = !no_wrap;
1502
- if (wrapped) {
1503
- this.queue.splice(pos, 0, SOFT_SPACE);
1504
- }
1505
- this.queue.push(new TypstToken(2 /* ELEMENT */, "/"));
1506
- this.appendWithBracketsIfNeeded(denominator);
1507
- break;
1508
- }
1509
- case "matrixLike": {
1510
- const node = abstractNode;
1511
- const matrix = node.matrix;
1512
- let cell_sep;
1513
- let row_sep;
1514
- if (node.head.eq(TypstMatrixLike.MAT)) {
1515
- cell_sep = new TypstToken(2 /* ELEMENT */, ",");
1516
- row_sep = new TypstToken(2 /* ELEMENT */, ";");
1517
- } else if (node.head.eq(TypstMatrixLike.CASES)) {
1518
- cell_sep = new TypstToken(2 /* ELEMENT */, "&");
1519
- row_sep = new TypstToken(2 /* ELEMENT */, ",");
1520
- } else if (node.head.eq(TypstToken.NONE)) {
1521
- cell_sep = new TypstToken(2 /* ELEMENT */, "&");
1522
- row_sep = new TypstToken(1 /* SYMBOL */, "\\");
1523
- }
1524
- if (!node.head.eq(TypstToken.NONE)) {
1525
- this.queue.push(node.head);
1526
- this.insideFunctionDepth++;
1527
- this.queue.push(TYPST_LEFT_PARENTHESIS);
1528
- if (node.options) {
1529
- for (const [key, value] of Object.entries(node.options)) {
1530
- this.queue.push(new TypstToken(3 /* LITERAL */, `${key}: ${value.toString()}, `));
1531
- }
1532
- }
1533
- }
1534
- matrix.forEach((row, i) => {
1535
- row.forEach((cell, j) => {
1536
- this.serialize(cell);
1537
- if (j < row.length - 1) {
1538
- this.queue.push(cell_sep);
1539
- } else {
1540
- if (i < matrix.length - 1) {
1541
- this.queue.push(row_sep);
1542
- }
1543
- }
1544
- });
1545
- });
1546
- if (!node.head.eq(TypstToken.NONE)) {
1547
- this.queue.push(TYPST_RIGHT_PARENTHESIS);
1548
- this.insideFunctionDepth--;
1549
- }
1550
- break;
1551
- }
1552
- case "markupFunc": {
1553
- const node = abstractNode;
1554
- this.queue.push(node.head);
1555
- this.queue.push(TYPST_LEFT_PARENTHESIS);
1556
- if (node.options) {
1557
- const entries = Object.entries(node.options);
1558
- for (let i = 0; i < entries.length; i++) {
1559
- const [key, value] = entries[i];
1560
- this.queue.push(new TypstToken(3 /* LITERAL */, `${key}: ${value.toString()}`));
1561
- if (i < entries.length - 1) {
1562
- this.queue.push(new TypstToken(2 /* ELEMENT */, ","));
1563
- }
1564
- }
1565
- }
1566
- this.queue.push(TYPST_RIGHT_PARENTHESIS);
1567
- this.queue.push(new TypstToken(3 /* LITERAL */, "["));
1568
- for (const frag of node.fragments) {
1569
- this.queue.push(new TypstToken(3 /* LITERAL */, "$"));
1570
- this.serialize(frag);
1571
- this.queue.push(new TypstToken(3 /* LITERAL */, "$"));
1572
- }
1573
- this.queue.push(new TypstToken(3 /* LITERAL */, "]"));
1574
- break;
1575
- }
1576
- default:
1577
- throw new TypstWriterError(`Unimplemented node type to append: ${abstractNode.type}`, abstractNode);
1578
- }
1573
+ const env = { insideFunctionDepth: 0 };
1574
+ this.queue.push(...abstractNode.serialize(env, this.options));
1579
1575
  }
1580
- appendWithBracketsIfNeeded(node) {
1581
- let need_to_wrap = ["group", "supsub", "matrixLike", "fraction", "empty"].includes(node.type);
1582
- if (node.type === "group") {
1583
- const group = node;
1584
- if (group.items.length === 0) {
1585
- need_to_wrap = true;
1586
- } else {
1587
- const first = group.items[0];
1588
- const last = group.items[group.items.length - 1];
1589
- if (is_delimiter(first) && is_delimiter(last)) {
1590
- need_to_wrap = false;
1591
- }
1576
+ flushQueue() {
1577
+ let qu = [];
1578
+ for (const token of this.queue) {
1579
+ if (token.eq(SOFT_SPACE2) && qu.length > 0 && qu[qu.length - 1].eq(SOFT_SPACE2)) {
1580
+ continue;
1592
1581
  }
1582
+ qu.push(token);
1593
1583
  }
1594
- if (need_to_wrap) {
1595
- this.queue.push(TYPST_LEFT_PARENTHESIS);
1596
- this.serialize(node);
1597
- this.queue.push(TYPST_RIGHT_PARENTHESIS);
1598
- } else {
1599
- this.serialize(node);
1600
- }
1601
- return !need_to_wrap;
1602
- }
1603
- flushQueue() {
1604
1584
  const dummy_token = new TypstToken(1 /* SYMBOL */, "");
1605
- for (let i = 0; i < this.queue.length; i++) {
1606
- let token = this.queue[i];
1607
- if (token.eq(SOFT_SPACE)) {
1608
- const to_delete = i === 0 || i === this.queue.length - 1 || this.queue[i - 1].type === 6 /* SPACE */ || this.queue[i - 1].isOneOf([TYPST_LEFT_PARENTHESIS, TYPST_NEWLINE]) || this.queue[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS, TYPST_COMMA, TYPST_NEWLINE]);
1585
+ for (let i = 0; i < qu.length; i++) {
1586
+ let token = qu[i];
1587
+ if (token.eq(SOFT_SPACE2)) {
1588
+ const to_delete = i === 0 || i === qu.length - 1 || qu[i - 1].type === 6 /* SPACE */ || qu[i - 1].isOneOf([TYPST_LEFT_PARENTHESIS2, TYPST_NEWLINE]) || qu[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS2, TYPST_COMMA, TYPST_NEWLINE]);
1609
1589
  if (to_delete) {
1610
- this.queue[i] = dummy_token;
1590
+ qu[i] = dummy_token;
1611
1591
  }
1612
1592
  }
1613
1593
  }
1614
- this.queue = this.queue.filter((token) => !token.eq(dummy_token));
1615
- for (let i = 0; i < this.queue.length; i++) {
1616
- let token = this.queue[i];
1617
- let previous_token = i === 0 ? null : this.queue[i - 1];
1594
+ qu = qu.filter((token) => !token.eq(dummy_token));
1595
+ for (let i = 0; i < qu.length; i++) {
1596
+ let token = qu[i];
1597
+ let previous_token = i === 0 ? null : qu[i - 1];
1618
1598
  this.writeBuffer(previous_token, token);
1619
1599
  }
1620
1600
  this.queue = [];
@@ -1636,7 +1616,7 @@ var TypstWriter = class {
1636
1616
  res = res.replace(/round\(\)/g, 'round("")');
1637
1617
  return res;
1638
1618
  };
1639
- if (this.optimize) {
1619
+ if (this.options.optimize) {
1640
1620
  const all_passes = [smartFloorPass, smartCeilPass, smartRoundPass];
1641
1621
  for (const pass of all_passes) {
1642
1622
  this.buffer = pass(this.buffer);
@@ -2874,6 +2854,35 @@ function convert_tex_array_align_literal(alignLiteral) {
2874
2854
  }
2875
2855
  return np;
2876
2856
  }
2857
+ var TYPST_LEFT_PARENTHESIS3 = new TypstToken(2 /* ELEMENT */, "(");
2858
+ var TYPST_RIGHT_PARENTHESIS3 = new TypstToken(2 /* ELEMENT */, ")");
2859
+ function is_delimiter(c) {
2860
+ return c.head.type === 2 /* ELEMENT */ && ["(", ")", "[", "]", "{", "}", "|", "\u230A", "\u230B", "\u2308", "\u2309"].includes(c.head.value);
2861
+ }
2862
+ function appendWithBracketsIfNeeded(node) {
2863
+ let need_to_wrap = ["group", "supsub", "matrixLike", "fraction", "empty"].includes(node.type);
2864
+ if (node.type === "group") {
2865
+ const group = node;
2866
+ if (group.items.length === 0) {
2867
+ need_to_wrap = true;
2868
+ } else {
2869
+ const first = group.items[0];
2870
+ const last = group.items[group.items.length - 1];
2871
+ if (is_delimiter(first) && is_delimiter(last)) {
2872
+ need_to_wrap = false;
2873
+ }
2874
+ }
2875
+ }
2876
+ if (need_to_wrap) {
2877
+ return new TypstLeftright(null, {
2878
+ left: TYPST_LEFT_PARENTHESIS3,
2879
+ right: TYPST_RIGHT_PARENTHESIS3,
2880
+ body: node
2881
+ });
2882
+ } else {
2883
+ return node;
2884
+ }
2885
+ }
2877
2886
  function convert_tex_node_to_typst(abstractNode, options = {}) {
2878
2887
  switch (abstractNode.type) {
2879
2888
  case "terminal": {
@@ -2914,6 +2923,13 @@ function convert_tex_node_to_typst(abstractNode, options = {}) {
2914
2923
  sup: sup ? convert_tex_node_to_typst(sup, options) : null,
2915
2924
  sub: sub ? convert_tex_node_to_typst(sub, options) : null
2916
2925
  };
2926
+ data.base = appendWithBracketsIfNeeded(data.base);
2927
+ if (data.sup) {
2928
+ data.sup = appendWithBracketsIfNeeded(data.sup);
2929
+ }
2930
+ if (data.sub) {
2931
+ data.sub = appendWithBracketsIfNeeded(data.sub);
2932
+ }
2917
2933
  return new TypstSupsub(data);
2918
2934
  }
2919
2935
  case "leftright": {
@@ -3010,6 +3026,12 @@ function convert_tex_node_to_typst(abstractNode, options = {}) {
3010
3026
  if (node2.head.value === "\\substack") {
3011
3027
  return arg0;
3012
3028
  }
3029
+ if (node2.head.value === "\\set") {
3030
+ return new TypstLeftright(
3031
+ null,
3032
+ { body: arg0, left: TypstToken.LEFT_BRACE, right: TypstToken.RIGHT_BRACE }
3033
+ );
3034
+ }
3013
3035
  if (node2.head.value === "\\overset") {
3014
3036
  return convert_overset(node2, options);
3015
3037
  }
@@ -3018,7 +3040,7 @@ function convert_tex_node_to_typst(abstractNode, options = {}) {
3018
3040
  }
3019
3041
  if (node2.head.value === "\\frac") {
3020
3042
  if (options.fracToSlash) {
3021
- return new TypstFraction(node2.args.map((n) => convert_tex_node_to_typst(n, options)));
3043
+ return new TypstFraction(node2.args.map((n) => convert_tex_node_to_typst(n, options)).map(appendWithBracketsIfNeeded));
3022
3044
  }
3023
3045
  }
3024
3046
  if (options.optimize) {
@@ -3511,8 +3533,8 @@ function find_closing_delim(tokens, start) {
3511
3533
  return _find_closing_match(
3512
3534
  tokens,
3513
3535
  start,
3514
- [LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET2, VERTICAL_BAR],
3515
- [RIGHT_PARENTHESES, RIGHT_BRACKET, RIGHT_CURLY_BRACKET2, VERTICAL_BAR]
3536
+ TypstToken.LEFT_DELIMITERS,
3537
+ TypstToken.RIGHT_DELIMITERS
3516
3538
  );
3517
3539
  }
3518
3540
  function find_closing_parenthesis(nodes, start) {
@@ -3645,7 +3667,6 @@ var LEFT_BRACKET = new TypstToken(2 /* ELEMENT */, "[");
3645
3667
  var RIGHT_BRACKET = new TypstToken(2 /* ELEMENT */, "]");
3646
3668
  var LEFT_CURLY_BRACKET2 = new TypstToken(2 /* ELEMENT */, "{");
3647
3669
  var RIGHT_CURLY_BRACKET2 = new TypstToken(2 /* ELEMENT */, "}");
3648
- var VERTICAL_BAR = new TypstToken(2 /* ELEMENT */, "|");
3649
3670
  var COMMA = new TypstToken(2 /* ELEMENT */, ",");
3650
3671
  var SEMICOLON = new TypstToken(2 /* ELEMENT */, ";");
3651
3672
  var SINGLE_SPACE = new TypstToken(6 /* SPACE */, " ");
@@ -3786,20 +3807,20 @@ var TypstParser = class {
3786
3807
  // start: the position of the left parentheses
3787
3808
  parseLrArguments(tokens, start) {
3788
3809
  const lr_token = tokens[start];
3789
- if (tokens[start + 1].isOneOf([LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET2, VERTICAL_BAR])) {
3790
- const end = find_closing_match2(tokens, start);
3810
+ const end = find_closing_match2(tokens, start);
3811
+ if (tokens[start + 1].isOneOf(TypstToken.LEFT_DELIMITERS)) {
3791
3812
  const inner_start = start + 1;
3792
3813
  const inner_end = find_closing_delim(tokens, inner_start);
3793
- const inner_args = this.parseArgumentsWithSeparator(tokens, inner_start + 1, inner_end, COMMA);
3814
+ const [inner_args, _] = this.parseGroup(tokens, inner_start + 1, inner_end);
3794
3815
  return [
3795
- new TypstLeftright(lr_token, { body: new TypstGroup(inner_args), left: tokens[inner_start], right: tokens[inner_end] }),
3816
+ new TypstLeftright(lr_token, { body: inner_args, left: tokens[inner_start], right: tokens[inner_end] }),
3796
3817
  end + 1
3797
3818
  ];
3798
3819
  } else {
3799
- const [args, end] = this.parseArguments(tokens, start);
3820
+ const [inner_args, _] = this.parseGroup(tokens, start + 1, end - 1);
3800
3821
  return [
3801
- new TypstLeftright(lr_token, { body: new TypstGroup(args), left: null, right: null }),
3802
- end
3822
+ new TypstLeftright(lr_token, { body: inner_args, left: null, right: null }),
3823
+ end + 1
3803
3824
  ];
3804
3825
  }
3805
3826
  }
@@ -3923,8 +3944,11 @@ function tex2typst(tex, options) {
3923
3944
  customTexMacros: {}
3924
3945
  };
3925
3946
  if (options !== void 0) {
3947
+ if (typeof options !== "object") {
3948
+ throw new Error("options must be an object");
3949
+ }
3926
3950
  for (const key in opt) {
3927
- if (options[key] !== void 0) {
3951
+ if (key in options) {
3928
3952
  opt[key] = options[key];
3929
3953
  }
3930
3954
  }