tex2typst 0.3.26 → 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/README.md +1 -1
- package/dist/index.d.ts +21 -4
- package/dist/index.js +409 -340
- package/dist/parser.js +23 -0
- package/dist/tex2typst.min.js +12 -12
- package/package.json +6 -7
- package/src/convert.ts +56 -6
- package/src/exposed-types.ts +23 -0
- package/src/index.ts +9 -5
- package/src/jslex.ts +1 -1
- package/src/tex-tokenizer.ts +1 -0
- package/src/tex-types.ts +1 -17
- package/src/tex2typst.ts +2 -4
- package/src/typst-parser.ts +9 -10
- package/src/typst-types.ts +484 -230
- package/src/typst-writer.ts +28 -274
- package/tests/cheat-sheet.test.ts +42 -0
- package/tests/cheat-sheet.toml +304 -0
- package/tests/example.ts +15 -0
- package/tests/general-symbols.test.ts +22 -0
- package/tests/general-symbols.toml +755 -0
- package/tests/integration-tex2typst.yaml +89 -0
- package/tests/struct-bidirection.yaml +179 -0
- package/tests/struct-tex2typst.yaml +443 -0
- package/tests/struct-typst2tex.yaml +412 -0
- package/tests/symbol.yml +123 -0
- package/tests/test-common.ts +26 -0
- package/tests/tex-parser.test.ts +57 -0
- package/tests/tex-to-typst.test.ts +143 -0
- package/tests/typst-parser.test.ts +134 -0
- package/tests/typst-to-tex.test.ts +76 -0
- package/tsconfig.json +11 -16
- package/dist/convert.d.ts +0 -9
- package/dist/generic.d.ts +0 -9
- package/dist/jslex.d.ts +0 -107
- package/dist/map.d.ts +0 -5
- package/dist/tex-parser.d.ts +0 -23
- package/dist/tex-tokenizer.d.ts +0 -4
- package/dist/tex-types.d.ts +0 -107
- package/dist/tex-writer.d.ts +0 -8
- package/dist/typst-parser.d.ts +0 -23
- package/dist/typst-shorthands.d.ts +0 -3
- package/dist/typst-tokenizer.d.ts +0 -2
- package/dist/typst-types.d.ts +0 -98
- package/dist/typst-writer.d.ts +0 -30
- package/dist/util.d.ts +0 -3
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ function assert(condition, message = "Assertion failed.") {
|
|
|
10
10
|
|
|
11
11
|
// src/tex-types.ts
|
|
12
12
|
var TexToken = class _TexToken {
|
|
13
|
+
type;
|
|
14
|
+
value;
|
|
13
15
|
constructor(type, value) {
|
|
14
16
|
this.type = type;
|
|
15
17
|
this.value = value;
|
|
@@ -28,11 +30,11 @@ var TexToken = class _TexToken {
|
|
|
28
30
|
toNode() {
|
|
29
31
|
return new TexTerminal(this);
|
|
30
32
|
}
|
|
31
|
-
static
|
|
32
|
-
this.EMPTY = new _TexToken(0 /* EMPTY */, "");
|
|
33
|
-
}
|
|
33
|
+
static EMPTY = new _TexToken(0 /* EMPTY */, "");
|
|
34
34
|
};
|
|
35
35
|
var TexNode = class {
|
|
36
|
+
type;
|
|
37
|
+
head;
|
|
36
38
|
constructor(type, head) {
|
|
37
39
|
this.type = type;
|
|
38
40
|
this.head = head ? head : TexToken.EMPTY;
|
|
@@ -90,6 +92,7 @@ var TexText = class extends TexNode {
|
|
|
90
92
|
}
|
|
91
93
|
};
|
|
92
94
|
var TexGroup = class extends TexNode {
|
|
95
|
+
items;
|
|
93
96
|
constructor(items) {
|
|
94
97
|
super("ordgroup", TexToken.EMPTY);
|
|
95
98
|
this.items = items;
|
|
@@ -99,6 +102,9 @@ var TexGroup = class extends TexNode {
|
|
|
99
102
|
}
|
|
100
103
|
};
|
|
101
104
|
var TexSupSub = class extends TexNode {
|
|
105
|
+
base;
|
|
106
|
+
sup;
|
|
107
|
+
sub;
|
|
102
108
|
constructor(data) {
|
|
103
109
|
super("supsub", TexToken.EMPTY);
|
|
104
110
|
this.base = data.base;
|
|
@@ -142,6 +148,9 @@ var TexSupSub = class extends TexNode {
|
|
|
142
148
|
}
|
|
143
149
|
};
|
|
144
150
|
var TexFuncCall = class extends TexNode {
|
|
151
|
+
args;
|
|
152
|
+
// For type="sqrt", it's additional argument wrapped square bracket. e.g. 3 in \sqrt[3]{x}
|
|
153
|
+
data;
|
|
145
154
|
constructor(head, args, data = null) {
|
|
146
155
|
super("funcCall", head);
|
|
147
156
|
this.args = args;
|
|
@@ -164,6 +173,9 @@ var TexFuncCall = class extends TexNode {
|
|
|
164
173
|
}
|
|
165
174
|
};
|
|
166
175
|
var TexLeftRight = class extends TexNode {
|
|
176
|
+
body;
|
|
177
|
+
left;
|
|
178
|
+
right;
|
|
167
179
|
constructor(data) {
|
|
168
180
|
super("leftright", TexToken.EMPTY);
|
|
169
181
|
this.body = data.body;
|
|
@@ -181,6 +193,9 @@ var TexLeftRight = class extends TexNode {
|
|
|
181
193
|
}
|
|
182
194
|
};
|
|
183
195
|
var TexBeginEnd = class extends TexNode {
|
|
196
|
+
matrix;
|
|
197
|
+
// for environment="array" or "subarray", there's additional data like {c|c} right after \begin{env}
|
|
198
|
+
data;
|
|
184
199
|
constructor(head, matrix, data = null) {
|
|
185
200
|
assert(head.type === 3 /* LITERAL */);
|
|
186
201
|
super("beginend", head);
|
|
@@ -279,20 +294,23 @@ function matchcompare(m1, m2) {
|
|
|
279
294
|
}
|
|
280
295
|
}
|
|
281
296
|
var Scanner = class {
|
|
297
|
+
_input;
|
|
298
|
+
_lexer;
|
|
299
|
+
// position within input stream
|
|
300
|
+
_pos = 0;
|
|
301
|
+
// current line number
|
|
302
|
+
_line = 0;
|
|
303
|
+
// current column number
|
|
304
|
+
_col = 0;
|
|
305
|
+
_offset = 0;
|
|
306
|
+
_less = null;
|
|
307
|
+
_go = false;
|
|
308
|
+
_newstate = null;
|
|
309
|
+
_state;
|
|
310
|
+
_text = null;
|
|
311
|
+
_leng = null;
|
|
312
|
+
_reMatchArray = null;
|
|
282
313
|
constructor(input, lexer) {
|
|
283
|
-
// position within input stream
|
|
284
|
-
this._pos = 0;
|
|
285
|
-
// current line number
|
|
286
|
-
this._line = 0;
|
|
287
|
-
// current column number
|
|
288
|
-
this._col = 0;
|
|
289
|
-
this._offset = 0;
|
|
290
|
-
this._less = null;
|
|
291
|
-
this._go = false;
|
|
292
|
-
this._newstate = null;
|
|
293
|
-
this._text = null;
|
|
294
|
-
this._leng = null;
|
|
295
|
-
this._reMatchArray = null;
|
|
296
314
|
this._input = input;
|
|
297
315
|
this._lexer = lexer;
|
|
298
316
|
this._state = lexer.states[0];
|
|
@@ -443,6 +461,8 @@ var Scanner = class {
|
|
|
443
461
|
}
|
|
444
462
|
};
|
|
445
463
|
var JSLex = class {
|
|
464
|
+
states;
|
|
465
|
+
specification;
|
|
446
466
|
constructor(spec3) {
|
|
447
467
|
this.states = Object.keys(spec3);
|
|
448
468
|
this.specification = {};
|
|
@@ -543,7 +563,8 @@ var TEX_UNARY_COMMANDS = [
|
|
|
543
563
|
"overleftarrow",
|
|
544
564
|
"overrightarrow",
|
|
545
565
|
"hspace",
|
|
546
|
-
"substack"
|
|
566
|
+
"substack",
|
|
567
|
+
"set"
|
|
547
568
|
];
|
|
548
569
|
var TEX_BINARY_COMMANDS = [
|
|
549
570
|
"frac",
|
|
@@ -736,6 +757,8 @@ var LatexParserError = class extends Error {
|
|
|
736
757
|
var SUB_SYMBOL = new TexToken(7 /* CONTROL */, "_");
|
|
737
758
|
var SUP_SYMBOL = new TexToken(7 /* CONTROL */, "^");
|
|
738
759
|
var LatexParser = class {
|
|
760
|
+
space_sensitive;
|
|
761
|
+
newline_sensitive;
|
|
739
762
|
constructor(space_sensitive = false, newline_sensitive = true) {
|
|
740
763
|
this.space_sensitive = space_sensitive;
|
|
741
764
|
this.newline_sensitive = newline_sensitive;
|
|
@@ -1096,8 +1119,58 @@ function parseTex(tex, customTexMacros) {
|
|
|
1096
1119
|
return parser.parse(tokens);
|
|
1097
1120
|
}
|
|
1098
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
|
+
|
|
1099
1170
|
// src/typst-types.ts
|
|
1100
1171
|
var TypstToken = class _TypstToken {
|
|
1172
|
+
type;
|
|
1173
|
+
value;
|
|
1101
1174
|
constructor(type, content) {
|
|
1102
1175
|
this.type = type;
|
|
1103
1176
|
this.value = content;
|
|
@@ -1121,14 +1194,39 @@ var TypstToken = class _TypstToken {
|
|
|
1121
1194
|
return this.value;
|
|
1122
1195
|
}
|
|
1123
1196
|
}
|
|
1124
|
-
static
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
static
|
|
1128
|
-
|
|
1197
|
+
static NONE = new _TypstToken(0 /* NONE */, "#none");
|
|
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
|
+
];
|
|
1215
|
+
};
|
|
1216
|
+
var TypstWriterError = class extends Error {
|
|
1217
|
+
node;
|
|
1218
|
+
constructor(message, node) {
|
|
1219
|
+
super(message);
|
|
1220
|
+
this.name = "TypstWriterError";
|
|
1221
|
+
this.node = node;
|
|
1129
1222
|
}
|
|
1130
1223
|
};
|
|
1224
|
+
var SOFT_SPACE = new TypstToken(7 /* CONTROL */, " ");
|
|
1131
1225
|
var TypstNode = class {
|
|
1226
|
+
type;
|
|
1227
|
+
head;
|
|
1228
|
+
// Some Typst functions accept additional options. e.g. mat() has option "delim", op() has option "limits"
|
|
1229
|
+
options;
|
|
1132
1230
|
constructor(type, head) {
|
|
1133
1231
|
this.type = type;
|
|
1134
1232
|
this.head = head ? head : TypstToken.NONE;
|
|
@@ -1154,8 +1252,42 @@ var TypstTerminal = class extends TypstNode {
|
|
|
1154
1252
|
toString() {
|
|
1155
1253
|
return this.head.toString();
|
|
1156
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
|
+
}
|
|
1157
1288
|
};
|
|
1158
1289
|
var TypstGroup = class extends TypstNode {
|
|
1290
|
+
items;
|
|
1159
1291
|
constructor(items) {
|
|
1160
1292
|
super("group", TypstToken.NONE);
|
|
1161
1293
|
this.items = items;
|
|
@@ -1163,8 +1295,21 @@ var TypstGroup = class extends TypstNode {
|
|
|
1163
1295
|
isOverHigh() {
|
|
1164
1296
|
return this.items.some((n) => n.isOverHigh());
|
|
1165
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
|
+
}
|
|
1166
1308
|
};
|
|
1167
1309
|
var TypstSupsub = class extends TypstNode {
|
|
1310
|
+
base;
|
|
1311
|
+
sup;
|
|
1312
|
+
sub;
|
|
1168
1313
|
constructor(data) {
|
|
1169
1314
|
super("supsub", TypstToken.NONE);
|
|
1170
1315
|
this.base = data.base;
|
|
@@ -1174,8 +1319,28 @@ var TypstSupsub = class extends TypstNode {
|
|
|
1174
1319
|
isOverHigh() {
|
|
1175
1320
|
return this.base.isOverHigh();
|
|
1176
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
|
+
}
|
|
1177
1341
|
};
|
|
1178
1342
|
var TypstFuncCall = class extends TypstNode {
|
|
1343
|
+
args;
|
|
1179
1344
|
constructor(head, args) {
|
|
1180
1345
|
super("funcCall", head);
|
|
1181
1346
|
this.args = args;
|
|
@@ -1186,8 +1351,30 @@ var TypstFuncCall = class extends TypstNode {
|
|
|
1186
1351
|
}
|
|
1187
1352
|
return this.args.some((n) => n.isOverHigh());
|
|
1188
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
|
+
}
|
|
1189
1375
|
};
|
|
1190
1376
|
var TypstFraction = class extends TypstNode {
|
|
1377
|
+
args;
|
|
1191
1378
|
constructor(args) {
|
|
1192
1379
|
super("fraction", TypstToken.NONE);
|
|
1193
1380
|
this.args = args;
|
|
@@ -1195,8 +1382,23 @@ var TypstFraction = class extends TypstNode {
|
|
|
1195
1382
|
isOverHigh() {
|
|
1196
1383
|
return true;
|
|
1197
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
|
+
}
|
|
1198
1395
|
};
|
|
1396
|
+
var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
|
|
1397
|
+
var TYPST_RIGHT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, ")");
|
|
1199
1398
|
var TypstLeftright = class extends TypstNode {
|
|
1399
|
+
body;
|
|
1400
|
+
left;
|
|
1401
|
+
right;
|
|
1200
1402
|
// head is either null or 'lr'
|
|
1201
1403
|
constructor(head, data) {
|
|
1202
1404
|
super("leftright", head);
|
|
@@ -1207,8 +1409,29 @@ var TypstLeftright = class extends TypstNode {
|
|
|
1207
1409
|
isOverHigh() {
|
|
1208
1410
|
return this.body.isOverHigh();
|
|
1209
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
|
+
}
|
|
1210
1432
|
};
|
|
1211
|
-
var TypstMatrixLike = class extends TypstNode {
|
|
1433
|
+
var TypstMatrixLike = class _TypstMatrixLike extends TypstNode {
|
|
1434
|
+
matrix;
|
|
1212
1435
|
// head is 'mat', 'cases' or null
|
|
1213
1436
|
constructor(head, data) {
|
|
1214
1437
|
super("matrixLike", head);
|
|
@@ -1217,14 +1440,60 @@ var TypstMatrixLike = class extends TypstNode {
|
|
|
1217
1440
|
isOverHigh() {
|
|
1218
1441
|
return true;
|
|
1219
1442
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
this.
|
|
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;
|
|
1225
1484
|
}
|
|
1485
|
+
static MAT = new TypstToken(1 /* SYMBOL */, "mat");
|
|
1486
|
+
static CASES = new TypstToken(1 /* SYMBOL */, "cases");
|
|
1226
1487
|
};
|
|
1227
1488
|
var TypstMarkupFunc = class extends TypstNode {
|
|
1489
|
+
/*
|
|
1490
|
+
In idealized situations, for `#heading([some text and math $x + y$ example])`,
|
|
1491
|
+
fragments would be [TypstMarkup{"some text and math "}, TypstNode{"x + y"}, TypstMarkup{" example"}]
|
|
1492
|
+
At present, we haven't implemented anything about TypstMarkup.
|
|
1493
|
+
So only pattens like `#heading(level: 2)[$x+y$]`, `#text(fill: red)[$x + y$]` are supported.
|
|
1494
|
+
Therefore, fragments is always a list containing exactly 1 TypstNode in well-working situations.
|
|
1495
|
+
*/
|
|
1496
|
+
fragments;
|
|
1228
1497
|
constructor(head, fragments) {
|
|
1229
1498
|
super("markupFunc", head);
|
|
1230
1499
|
this.fragments = fragments;
|
|
@@ -1232,82 +1501,45 @@ var TypstMarkupFunc = class extends TypstNode {
|
|
|
1232
1501
|
isOverHigh() {
|
|
1233
1502
|
return this.fragments.some((n) => n.isOverHigh());
|
|
1234
1503
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
["arrow.r", "->"],
|
|
1260
|
-
["arrow.r.double", "=>"],
|
|
1261
|
-
["arrow.r.squiggly", "~>"],
|
|
1262
|
-
["arrow.l", "<-"],
|
|
1263
|
-
["arrow.l.squiggly", "<~"],
|
|
1264
|
-
["bar.v.double", "||"],
|
|
1265
|
-
["bracket.l.double", "[|"],
|
|
1266
|
-
["bracket.r.double", "|]"],
|
|
1267
|
-
["colon.eq", ":="],
|
|
1268
|
-
["eq.colon", "=:"],
|
|
1269
|
-
["eq.not", "!="],
|
|
1270
|
-
["gt.double", ">>"],
|
|
1271
|
-
["gt.eq", ">="],
|
|
1272
|
-
["lt.double", "<<"],
|
|
1273
|
-
["lt.eq", "<="],
|
|
1274
|
-
["ast.op", "*"],
|
|
1275
|
-
["minus", "-"],
|
|
1276
|
-
["tilde.op", "~"]
|
|
1277
|
-
]);
|
|
1278
|
-
var reverseShorthandMap = /* @__PURE__ */ new Map();
|
|
1279
|
-
for (const [key, value] of shorthandMap.entries()) {
|
|
1280
|
-
if (value.length > 1) {
|
|
1281
|
-
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;
|
|
1282
1528
|
}
|
|
1283
|
-
}
|
|
1529
|
+
};
|
|
1284
1530
|
|
|
1285
1531
|
// src/typst-writer.ts
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1289
|
-
var TYPST_LEFT_PARENTHESIS = new TypstToken(2 /* ELEMENT */, "(");
|
|
1290
|
-
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 */, ")");
|
|
1291
1534
|
var TYPST_COMMA = new TypstToken(2 /* ELEMENT */, ",");
|
|
1292
1535
|
var TYPST_NEWLINE = new TypstToken(1 /* SYMBOL */, "\n");
|
|
1293
|
-
var
|
|
1294
|
-
var TypstWriterError = class extends Error {
|
|
1295
|
-
constructor(message, node) {
|
|
1296
|
-
super(message);
|
|
1297
|
-
this.name = "TypstWriterError";
|
|
1298
|
-
this.node = node;
|
|
1299
|
-
}
|
|
1300
|
-
};
|
|
1536
|
+
var SOFT_SPACE2 = new TypstToken(7 /* CONTROL */, " ");
|
|
1301
1537
|
var TypstWriter = class {
|
|
1538
|
+
buffer = "";
|
|
1539
|
+
queue = [];
|
|
1540
|
+
options;
|
|
1302
1541
|
constructor(options) {
|
|
1303
|
-
this.
|
|
1304
|
-
this.queue = [];
|
|
1305
|
-
this.insideFunctionDepth = 0;
|
|
1306
|
-
this.nonStrict = options.nonStrict;
|
|
1307
|
-
this.preferShorthands = options.preferShorthands;
|
|
1308
|
-
this.keepSpaces = options.keepSpaces;
|
|
1309
|
-
this.inftyToOo = options.inftyToOo;
|
|
1310
|
-
this.optimize = options.optimize;
|
|
1542
|
+
this.options = options;
|
|
1311
1543
|
}
|
|
1312
1544
|
writeBuffer(previousToken, token) {
|
|
1313
1545
|
const str = token.toString();
|
|
@@ -1323,7 +1555,7 @@ var TypstWriter = class {
|
|
|
1323
1555
|
no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(this.buffer) || this.buffer === "-" || this.buffer === "+";
|
|
1324
1556
|
no_need_space ||= str.startsWith("\n");
|
|
1325
1557
|
no_need_space ||= this.buffer === "";
|
|
1326
|
-
no_need_space ||= /^\s/.test(str);
|
|
1558
|
+
no_need_space ||= /\s$/.test(this.buffer) || /^\s/.test(str);
|
|
1327
1559
|
no_need_space ||= this.buffer.endsWith("&") && str === "=";
|
|
1328
1560
|
no_need_space ||= this.buffer.endsWith("/") || str === "/";
|
|
1329
1561
|
no_need_space ||= token.type === 3 /* LITERAL */;
|
|
@@ -1338,239 +1570,31 @@ var TypstWriter = class {
|
|
|
1338
1570
|
}
|
|
1339
1571
|
// Serialize a tree of TypstNode into a list of TypstToken
|
|
1340
1572
|
serialize(abstractNode) {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
const node = abstractNode;
|
|
1344
|
-
if (node.head.type === 2 /* ELEMENT */) {
|
|
1345
|
-
if (node.head.value === "," && this.insideFunctionDepth > 0) {
|
|
1346
|
-
this.queue.push(new TypstToken(1 /* SYMBOL */, "comma"));
|
|
1347
|
-
} else {
|
|
1348
|
-
this.queue.push(node.head);
|
|
1349
|
-
}
|
|
1350
|
-
break;
|
|
1351
|
-
} else if (node.head.type === 1 /* SYMBOL */) {
|
|
1352
|
-
let symbol_name = node.head.value;
|
|
1353
|
-
if (this.preferShorthands) {
|
|
1354
|
-
if (shorthandMap.has(symbol_name)) {
|
|
1355
|
-
symbol_name = shorthandMap.get(symbol_name);
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
if (this.inftyToOo && symbol_name === "infinity") {
|
|
1359
|
-
symbol_name = "oo";
|
|
1360
|
-
}
|
|
1361
|
-
this.queue.push(new TypstToken(1 /* SYMBOL */, symbol_name));
|
|
1362
|
-
break;
|
|
1363
|
-
} else if (node.head.type === 6 /* SPACE */ || node.head.type === 8 /* NEWLINE */) {
|
|
1364
|
-
for (const c of node.head.value) {
|
|
1365
|
-
if (c === " ") {
|
|
1366
|
-
if (this.keepSpaces) {
|
|
1367
|
-
this.queue.push(new TypstToken(6 /* SPACE */, c));
|
|
1368
|
-
}
|
|
1369
|
-
} else if (c === "\n") {
|
|
1370
|
-
this.queue.push(new TypstToken(1 /* SYMBOL */, c));
|
|
1371
|
-
} else {
|
|
1372
|
-
throw new TypstWriterError(`Unexpected whitespace character: ${c}`, node);
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
break;
|
|
1376
|
-
} else {
|
|
1377
|
-
this.queue.push(node.head);
|
|
1378
|
-
break;
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
case "group": {
|
|
1382
|
-
const node = abstractNode;
|
|
1383
|
-
for (const item of node.items) {
|
|
1384
|
-
this.serialize(item);
|
|
1385
|
-
}
|
|
1386
|
-
break;
|
|
1387
|
-
}
|
|
1388
|
-
case "leftright": {
|
|
1389
|
-
const node = abstractNode;
|
|
1390
|
-
const LR = new TypstToken(1 /* SYMBOL */, "lr");
|
|
1391
|
-
const { left, right } = node;
|
|
1392
|
-
if (node.head.eq(LR)) {
|
|
1393
|
-
this.queue.push(LR);
|
|
1394
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
1395
|
-
}
|
|
1396
|
-
if (left) {
|
|
1397
|
-
this.queue.push(left);
|
|
1398
|
-
}
|
|
1399
|
-
this.serialize(node.body);
|
|
1400
|
-
if (right) {
|
|
1401
|
-
this.queue.push(right);
|
|
1402
|
-
}
|
|
1403
|
-
if (node.head.eq(LR)) {
|
|
1404
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
1405
|
-
}
|
|
1406
|
-
break;
|
|
1407
|
-
}
|
|
1408
|
-
case "supsub": {
|
|
1409
|
-
const node = abstractNode;
|
|
1410
|
-
let { base, sup, sub } = node;
|
|
1411
|
-
this.appendWithBracketsIfNeeded(base);
|
|
1412
|
-
let trailing_space_needed = false;
|
|
1413
|
-
const has_prime = sup && sup.head.eq(new TypstToken(2 /* ELEMENT */, "'"));
|
|
1414
|
-
if (has_prime) {
|
|
1415
|
-
this.queue.push(new TypstToken(2 /* ELEMENT */, "'"));
|
|
1416
|
-
trailing_space_needed = false;
|
|
1417
|
-
}
|
|
1418
|
-
if (sub) {
|
|
1419
|
-
this.queue.push(new TypstToken(2 /* ELEMENT */, "_"));
|
|
1420
|
-
trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
|
|
1421
|
-
}
|
|
1422
|
-
if (sup && !has_prime) {
|
|
1423
|
-
this.queue.push(new TypstToken(2 /* ELEMENT */, "^"));
|
|
1424
|
-
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
|
|
1425
|
-
}
|
|
1426
|
-
if (trailing_space_needed) {
|
|
1427
|
-
this.queue.push(SOFT_SPACE);
|
|
1428
|
-
}
|
|
1429
|
-
break;
|
|
1430
|
-
}
|
|
1431
|
-
case "funcCall": {
|
|
1432
|
-
const node = abstractNode;
|
|
1433
|
-
const func_symbol = node.head;
|
|
1434
|
-
this.queue.push(func_symbol);
|
|
1435
|
-
this.insideFunctionDepth++;
|
|
1436
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
1437
|
-
for (let i = 0; i < node.args.length; i++) {
|
|
1438
|
-
this.serialize(node.args[i]);
|
|
1439
|
-
if (i < node.args.length - 1) {
|
|
1440
|
-
this.queue.push(new TypstToken(2 /* ELEMENT */, ","));
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
if (node.options) {
|
|
1444
|
-
for (const [key, value] of Object.entries(node.options)) {
|
|
1445
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, `, ${key}: ${value.toString()}`));
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
1449
|
-
this.insideFunctionDepth--;
|
|
1450
|
-
break;
|
|
1451
|
-
}
|
|
1452
|
-
case "fraction": {
|
|
1453
|
-
const node = abstractNode;
|
|
1454
|
-
const [numerator, denominator] = node.args;
|
|
1455
|
-
const pos = this.queue.length;
|
|
1456
|
-
const no_wrap = this.appendWithBracketsIfNeeded(numerator);
|
|
1457
|
-
const wrapped = !no_wrap;
|
|
1458
|
-
if (wrapped) {
|
|
1459
|
-
this.queue.splice(pos, 0, SOFT_SPACE);
|
|
1460
|
-
}
|
|
1461
|
-
this.queue.push(new TypstToken(2 /* ELEMENT */, "/"));
|
|
1462
|
-
this.appendWithBracketsIfNeeded(denominator);
|
|
1463
|
-
break;
|
|
1464
|
-
}
|
|
1465
|
-
case "matrixLike": {
|
|
1466
|
-
const node = abstractNode;
|
|
1467
|
-
const matrix = node.matrix;
|
|
1468
|
-
let cell_sep;
|
|
1469
|
-
let row_sep;
|
|
1470
|
-
if (node.head.eq(TypstMatrixLike.MAT)) {
|
|
1471
|
-
cell_sep = new TypstToken(2 /* ELEMENT */, ",");
|
|
1472
|
-
row_sep = new TypstToken(2 /* ELEMENT */, ";");
|
|
1473
|
-
} else if (node.head.eq(TypstMatrixLike.CASES)) {
|
|
1474
|
-
cell_sep = new TypstToken(2 /* ELEMENT */, "&");
|
|
1475
|
-
row_sep = new TypstToken(2 /* ELEMENT */, ",");
|
|
1476
|
-
} else if (node.head.eq(TypstToken.NONE)) {
|
|
1477
|
-
cell_sep = new TypstToken(2 /* ELEMENT */, "&");
|
|
1478
|
-
row_sep = new TypstToken(1 /* SYMBOL */, "\\");
|
|
1479
|
-
}
|
|
1480
|
-
if (!node.head.eq(TypstToken.NONE)) {
|
|
1481
|
-
this.queue.push(node.head);
|
|
1482
|
-
this.insideFunctionDepth++;
|
|
1483
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
1484
|
-
if (node.options) {
|
|
1485
|
-
for (const [key, value] of Object.entries(node.options)) {
|
|
1486
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, `${key}: ${value.toString()}, `));
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
matrix.forEach((row, i) => {
|
|
1491
|
-
row.forEach((cell, j) => {
|
|
1492
|
-
this.serialize(cell);
|
|
1493
|
-
if (j < row.length - 1) {
|
|
1494
|
-
this.queue.push(cell_sep);
|
|
1495
|
-
} else {
|
|
1496
|
-
if (i < matrix.length - 1) {
|
|
1497
|
-
this.queue.push(row_sep);
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
});
|
|
1501
|
-
});
|
|
1502
|
-
if (!node.head.eq(TypstToken.NONE)) {
|
|
1503
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
1504
|
-
this.insideFunctionDepth--;
|
|
1505
|
-
}
|
|
1506
|
-
break;
|
|
1507
|
-
}
|
|
1508
|
-
case "markupFunc": {
|
|
1509
|
-
const node = abstractNode;
|
|
1510
|
-
this.queue.push(node.head);
|
|
1511
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
1512
|
-
if (node.options) {
|
|
1513
|
-
const entries = Object.entries(node.options);
|
|
1514
|
-
for (let i = 0; i < entries.length; i++) {
|
|
1515
|
-
const [key, value] = entries[i];
|
|
1516
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, `${key}: ${value.toString()}`));
|
|
1517
|
-
if (i < entries.length - 1) {
|
|
1518
|
-
this.queue.push(new TypstToken(2 /* ELEMENT */, ","));
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
1523
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, "["));
|
|
1524
|
-
for (const frag of node.fragments) {
|
|
1525
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, "$"));
|
|
1526
|
-
this.serialize(frag);
|
|
1527
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, "$"));
|
|
1528
|
-
}
|
|
1529
|
-
this.queue.push(new TypstToken(3 /* LITERAL */, "]"));
|
|
1530
|
-
break;
|
|
1531
|
-
}
|
|
1532
|
-
default:
|
|
1533
|
-
throw new TypstWriterError(`Unimplemented node type to append: ${abstractNode.type}`, abstractNode);
|
|
1534
|
-
}
|
|
1573
|
+
const env = { insideFunctionDepth: 0 };
|
|
1574
|
+
this.queue.push(...abstractNode.serialize(env, this.options));
|
|
1535
1575
|
}
|
|
1536
|
-
|
|
1537
|
-
let
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
need_to_wrap = true;
|
|
1542
|
-
} else {
|
|
1543
|
-
const first = group.items[0];
|
|
1544
|
-
const last = group.items[group.items.length - 1];
|
|
1545
|
-
if (is_delimiter(first) && is_delimiter(last)) {
|
|
1546
|
-
need_to_wrap = false;
|
|
1547
|
-
}
|
|
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;
|
|
1548
1581
|
}
|
|
1582
|
+
qu.push(token);
|
|
1549
1583
|
}
|
|
1550
|
-
if (need_to_wrap) {
|
|
1551
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
1552
|
-
this.serialize(node);
|
|
1553
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
1554
|
-
} else {
|
|
1555
|
-
this.serialize(node);
|
|
1556
|
-
}
|
|
1557
|
-
return !need_to_wrap;
|
|
1558
|
-
}
|
|
1559
|
-
flushQueue() {
|
|
1560
1584
|
const dummy_token = new TypstToken(1 /* SYMBOL */, "");
|
|
1561
|
-
for (let i = 0; i <
|
|
1562
|
-
let token =
|
|
1563
|
-
if (token.eq(
|
|
1564
|
-
const to_delete = i === 0 || i ===
|
|
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]);
|
|
1565
1589
|
if (to_delete) {
|
|
1566
|
-
|
|
1590
|
+
qu[i] = dummy_token;
|
|
1567
1591
|
}
|
|
1568
1592
|
}
|
|
1569
1593
|
}
|
|
1570
|
-
|
|
1571
|
-
for (let i = 0; i <
|
|
1572
|
-
let token =
|
|
1573
|
-
let previous_token = i === 0 ? null :
|
|
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];
|
|
1574
1598
|
this.writeBuffer(previous_token, token);
|
|
1575
1599
|
}
|
|
1576
1600
|
this.queue = [];
|
|
@@ -1592,7 +1616,7 @@ var TypstWriter = class {
|
|
|
1592
1616
|
res = res.replace(/round\(\)/g, 'round("")');
|
|
1593
1617
|
return res;
|
|
1594
1618
|
};
|
|
1595
|
-
if (this.optimize) {
|
|
1619
|
+
if (this.options.optimize) {
|
|
1596
1620
|
const all_passes = [smartFloorPass, smartCeilPass, smartRoundPass];
|
|
1597
1621
|
for (const pass of all_passes) {
|
|
1598
1622
|
this.buffer = pass(this.buffer);
|
|
@@ -2687,6 +2711,7 @@ for (const [key, value] of texAliasMap) {
|
|
|
2687
2711
|
|
|
2688
2712
|
// src/convert.ts
|
|
2689
2713
|
var ConverterError = class extends Error {
|
|
2714
|
+
node;
|
|
2690
2715
|
constructor(message, node = null) {
|
|
2691
2716
|
super(message);
|
|
2692
2717
|
this.name = "ConverterError";
|
|
@@ -2829,6 +2854,35 @@ function convert_tex_array_align_literal(alignLiteral) {
|
|
|
2829
2854
|
}
|
|
2830
2855
|
return np;
|
|
2831
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
|
+
}
|
|
2832
2886
|
function convert_tex_node_to_typst(abstractNode, options = {}) {
|
|
2833
2887
|
switch (abstractNode.type) {
|
|
2834
2888
|
case "terminal": {
|
|
@@ -2869,6 +2923,13 @@ function convert_tex_node_to_typst(abstractNode, options = {}) {
|
|
|
2869
2923
|
sup: sup ? convert_tex_node_to_typst(sup, options) : null,
|
|
2870
2924
|
sub: sub ? convert_tex_node_to_typst(sub, options) : null
|
|
2871
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
|
+
}
|
|
2872
2933
|
return new TypstSupsub(data);
|
|
2873
2934
|
}
|
|
2874
2935
|
case "leftright": {
|
|
@@ -2965,6 +3026,12 @@ function convert_tex_node_to_typst(abstractNode, options = {}) {
|
|
|
2965
3026
|
if (node2.head.value === "\\substack") {
|
|
2966
3027
|
return arg0;
|
|
2967
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
|
+
}
|
|
2968
3035
|
if (node2.head.value === "\\overset") {
|
|
2969
3036
|
return convert_overset(node2, options);
|
|
2970
3037
|
}
|
|
@@ -2973,7 +3040,7 @@ function convert_tex_node_to_typst(abstractNode, options = {}) {
|
|
|
2973
3040
|
}
|
|
2974
3041
|
if (node2.head.value === "\\frac") {
|
|
2975
3042
|
if (options.fracToSlash) {
|
|
2976
|
-
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));
|
|
2977
3044
|
}
|
|
2978
3045
|
}
|
|
2979
3046
|
if (options.optimize) {
|
|
@@ -3466,8 +3533,8 @@ function find_closing_delim(tokens, start) {
|
|
|
3466
3533
|
return _find_closing_match(
|
|
3467
3534
|
tokens,
|
|
3468
3535
|
start,
|
|
3469
|
-
|
|
3470
|
-
|
|
3536
|
+
TypstToken.LEFT_DELIMITERS,
|
|
3537
|
+
TypstToken.RIGHT_DELIMITERS
|
|
3471
3538
|
);
|
|
3472
3539
|
}
|
|
3473
3540
|
function find_closing_parenthesis(nodes, start) {
|
|
@@ -3600,12 +3667,13 @@ var LEFT_BRACKET = new TypstToken(2 /* ELEMENT */, "[");
|
|
|
3600
3667
|
var RIGHT_BRACKET = new TypstToken(2 /* ELEMENT */, "]");
|
|
3601
3668
|
var LEFT_CURLY_BRACKET2 = new TypstToken(2 /* ELEMENT */, "{");
|
|
3602
3669
|
var RIGHT_CURLY_BRACKET2 = new TypstToken(2 /* ELEMENT */, "}");
|
|
3603
|
-
var VERTICAL_BAR = new TypstToken(2 /* ELEMENT */, "|");
|
|
3604
3670
|
var COMMA = new TypstToken(2 /* ELEMENT */, ",");
|
|
3605
3671
|
var SEMICOLON = new TypstToken(2 /* ELEMENT */, ";");
|
|
3606
3672
|
var SINGLE_SPACE = new TypstToken(6 /* SPACE */, " ");
|
|
3607
3673
|
var CONTROL_AND = new TypstToken(7 /* CONTROL */, "&");
|
|
3608
3674
|
var TypstParser = class {
|
|
3675
|
+
space_sensitive;
|
|
3676
|
+
newline_sensitive;
|
|
3609
3677
|
constructor(space_sensitive = true, newline_sensitive = true) {
|
|
3610
3678
|
this.space_sensitive = space_sensitive;
|
|
3611
3679
|
this.newline_sensitive = newline_sensitive;
|
|
@@ -3739,20 +3807,20 @@ var TypstParser = class {
|
|
|
3739
3807
|
// start: the position of the left parentheses
|
|
3740
3808
|
parseLrArguments(tokens, start) {
|
|
3741
3809
|
const lr_token = tokens[start];
|
|
3742
|
-
|
|
3743
|
-
|
|
3810
|
+
const end = find_closing_match2(tokens, start);
|
|
3811
|
+
if (tokens[start + 1].isOneOf(TypstToken.LEFT_DELIMITERS)) {
|
|
3744
3812
|
const inner_start = start + 1;
|
|
3745
3813
|
const inner_end = find_closing_delim(tokens, inner_start);
|
|
3746
|
-
const inner_args = this.
|
|
3814
|
+
const [inner_args, _] = this.parseGroup(tokens, inner_start + 1, inner_end);
|
|
3747
3815
|
return [
|
|
3748
|
-
new TypstLeftright(lr_token, { body:
|
|
3816
|
+
new TypstLeftright(lr_token, { body: inner_args, left: tokens[inner_start], right: tokens[inner_end] }),
|
|
3749
3817
|
end + 1
|
|
3750
3818
|
];
|
|
3751
3819
|
} else {
|
|
3752
|
-
const [
|
|
3820
|
+
const [inner_args, _] = this.parseGroup(tokens, start + 1, end - 1);
|
|
3753
3821
|
return [
|
|
3754
|
-
new TypstLeftright(lr_token, { body:
|
|
3755
|
-
end
|
|
3822
|
+
new TypstLeftright(lr_token, { body: inner_args, left: null, right: null }),
|
|
3823
|
+
end + 1
|
|
3756
3824
|
];
|
|
3757
3825
|
}
|
|
3758
3826
|
}
|
|
@@ -3846,10 +3914,8 @@ function parseTypst(typst) {
|
|
|
3846
3914
|
|
|
3847
3915
|
// src/tex-writer.ts
|
|
3848
3916
|
var TexWriter = class {
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
this.queue = [];
|
|
3852
|
-
}
|
|
3917
|
+
buffer = "";
|
|
3918
|
+
queue = [];
|
|
3853
3919
|
append(node) {
|
|
3854
3920
|
this.queue = this.queue.concat(node.serialize());
|
|
3855
3921
|
}
|
|
@@ -3878,8 +3944,11 @@ function tex2typst(tex, options) {
|
|
|
3878
3944
|
customTexMacros: {}
|
|
3879
3945
|
};
|
|
3880
3946
|
if (options !== void 0) {
|
|
3947
|
+
if (typeof options !== "object") {
|
|
3948
|
+
throw new Error("options must be an object");
|
|
3949
|
+
}
|
|
3881
3950
|
for (const key in opt) {
|
|
3882
|
-
if (
|
|
3951
|
+
if (key in options) {
|
|
3883
3952
|
opt[key] = options[key];
|
|
3884
3953
|
}
|
|
3885
3954
|
}
|