tex2typst 0.2.16 → 0.3.0-beta-1
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/generic.d.ts +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1235 -442
- package/dist/map.d.ts +2 -1
- package/dist/tex-parser.d.ts +1 -7
- package/dist/tex-writer.d.ts +11 -0
- package/dist/tex2typst.min.js +19 -1
- package/dist/types.d.ts +15 -5
- package/dist/typst-parser.d.ts +21 -0
- package/dist/util.d.ts +3 -0
- package/package.json +1 -1
- package/src/generic.ts +37 -0
- package/src/index.ts +10 -0
- package/src/map.ts +28 -2
- package/src/tex-parser.ts +24 -101
- package/src/tex-writer.ts +249 -0
- package/src/tex2typst.ts +2 -1
- package/src/types.ts +206 -14
- package/src/typst-parser.ts +507 -0
- package/src/util.ts +14 -0
- package/src/writer.ts +51 -47
package/src/writer.ts
CHANGED
|
@@ -26,7 +26,7 @@ function convert_overset(node: TexNode): TypstNode {
|
|
|
26
26
|
const [sup, base] = node.args!;
|
|
27
27
|
|
|
28
28
|
const is_def = (n: TexNode): boolean => {
|
|
29
|
-
if (n.
|
|
29
|
+
if (n.eq(new TexNode('text', 'def'))) {
|
|
30
30
|
return true;
|
|
31
31
|
}
|
|
32
32
|
// \overset{def}{=} is also considered as eq.def
|
|
@@ -35,18 +35,18 @@ function convert_overset(node: TexNode): TypstNode {
|
|
|
35
35
|
const d = new TexNode('element', 'd');
|
|
36
36
|
const e = new TexNode('element', 'e');
|
|
37
37
|
const f = new TexNode('element', 'f');
|
|
38
|
-
if (a1.
|
|
38
|
+
if (a1.eq(d) && a2.eq(e) && a3.eq(f)) {
|
|
39
39
|
return true;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
return false;
|
|
43
43
|
};
|
|
44
|
-
const is_eq = (n: TexNode): boolean => n.
|
|
44
|
+
const is_eq = (n: TexNode): boolean => n.eq(new TexNode('element', '='));
|
|
45
45
|
if (is_def(sup) && is_eq(base)) {
|
|
46
46
|
return new TypstNode('symbol', 'eq.def');
|
|
47
47
|
}
|
|
48
48
|
const op_call = new TypstNode(
|
|
49
|
-
'
|
|
49
|
+
'funcCall',
|
|
50
50
|
'op',
|
|
51
51
|
[convertTree(base)]
|
|
52
52
|
);
|
|
@@ -62,9 +62,9 @@ function convert_overset(node: TexNode): TypstNode {
|
|
|
62
62
|
);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const TYPST_LEFT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.
|
|
66
|
-
const TYPST_RIGHT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.
|
|
67
|
-
const TYPST_COMMA: TypstToken = new TypstToken(TypstTokenType.
|
|
65
|
+
const TYPST_LEFT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '(');
|
|
66
|
+
const TYPST_RIGHT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.ELEMENT, ')');
|
|
67
|
+
const TYPST_COMMA: TypstToken = new TypstToken(TypstTokenType.ELEMENT, ',');
|
|
68
68
|
const TYPST_NEWLINE: TypstToken = new TypstToken(TypstTokenType.SYMBOL, '\n');
|
|
69
69
|
|
|
70
70
|
export class TypstWriterError extends Error {
|
|
@@ -95,17 +95,19 @@ export class TypstWriter {
|
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
private writeBuffer(token: TypstToken) {
|
|
98
|
-
const str = token.
|
|
98
|
+
const str = token.toString();
|
|
99
99
|
|
|
100
100
|
if (str === '') {
|
|
101
101
|
return;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
let no_need_space = false;
|
|
105
|
-
//
|
|
106
|
-
no_need_space ||= /[\(\|]$/.test(this.buffer) && /^\w/.test(str);
|
|
105
|
+
// putting the first token in clause
|
|
106
|
+
no_need_space ||= /[\(\[\|]$/.test(this.buffer) && /^\w/.test(str);
|
|
107
|
+
// closing a clause
|
|
108
|
+
no_need_space ||= /^[})\]\|]$/.test(str);
|
|
107
109
|
// putting punctuation
|
|
108
|
-
no_need_space ||= /^[
|
|
110
|
+
no_need_space ||= /^[(_^,;!]$/.test(str);
|
|
109
111
|
// putting a prime
|
|
110
112
|
no_need_space ||= str === "'";
|
|
111
113
|
// continue a number
|
|
@@ -118,6 +120,8 @@ export class TypstWriter {
|
|
|
118
120
|
no_need_space ||= this.buffer === "";
|
|
119
121
|
// str is starting with a space itself
|
|
120
122
|
no_need_space ||= /^\s/.test(str);
|
|
123
|
+
// "&=" instead of "& ="
|
|
124
|
+
no_need_space ||= this.buffer.endsWith('&') && str === '=';
|
|
121
125
|
// other cases
|
|
122
126
|
no_need_space ||= /[\s_^{\(]$/.test(this.buffer);
|
|
123
127
|
if (!no_need_space) {
|
|
@@ -136,7 +140,7 @@ export class TypstWriter {
|
|
|
136
140
|
if (node.content === ',' && this.insideFunctionDepth > 0) {
|
|
137
141
|
this.queue.push(new TypstToken(TypstTokenType.SYMBOL, 'comma'));
|
|
138
142
|
} else {
|
|
139
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
143
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, node.content));
|
|
140
144
|
}
|
|
141
145
|
break;
|
|
142
146
|
}
|
|
@@ -144,10 +148,10 @@ export class TypstWriter {
|
|
|
144
148
|
this.queue.push(new TypstToken(TypstTokenType.SYMBOL, node.content));
|
|
145
149
|
break;
|
|
146
150
|
case 'text':
|
|
147
|
-
this.queue.push(new TypstToken(TypstTokenType.TEXT,
|
|
151
|
+
this.queue.push(new TypstToken(TypstTokenType.TEXT, node.content));
|
|
148
152
|
break;
|
|
149
153
|
case 'comment':
|
|
150
|
-
this.queue.push(new TypstToken(TypstTokenType.COMMENT,
|
|
154
|
+
this.queue.push(new TypstToken(TypstTokenType.COMMENT, node.content));
|
|
151
155
|
break;
|
|
152
156
|
case 'whitespace':
|
|
153
157
|
for (const c of node.content) {
|
|
@@ -178,15 +182,15 @@ export class TypstWriter {
|
|
|
178
182
|
// e.g.
|
|
179
183
|
// y_1' -> y'_1
|
|
180
184
|
// y_{a_1}' -> y'_{a_1}
|
|
181
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
185
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '\''));
|
|
182
186
|
trailing_space_needed = false;
|
|
183
187
|
}
|
|
184
188
|
if (sub) {
|
|
185
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
189
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '_'));
|
|
186
190
|
trailing_space_needed = this.appendWithBracketsIfNeeded(sub);
|
|
187
191
|
}
|
|
188
192
|
if (sup && !has_prime) {
|
|
189
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
193
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '^'));
|
|
190
194
|
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
|
|
191
195
|
}
|
|
192
196
|
if (trailing_space_needed) {
|
|
@@ -194,26 +198,17 @@ export class TypstWriter {
|
|
|
194
198
|
}
|
|
195
199
|
break;
|
|
196
200
|
}
|
|
197
|
-
case '
|
|
201
|
+
case 'funcCall': {
|
|
198
202
|
const func_symbol: TypstToken = new TypstToken(TypstTokenType.SYMBOL, node.content);
|
|
199
|
-
const [arg0, arg1] = node.args!;
|
|
200
203
|
this.queue.push(func_symbol);
|
|
201
204
|
this.insideFunctionDepth++;
|
|
202
205
|
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
case 'unaryFunc': {
|
|
211
|
-
const func_symbol: TypstToken = new TypstToken(TypstTokenType.SYMBOL, node.content);
|
|
212
|
-
const arg0 = node.args![0];
|
|
213
|
-
this.queue.push(func_symbol);
|
|
214
|
-
this.insideFunctionDepth++;
|
|
215
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
216
|
-
this.serialize(arg0);
|
|
206
|
+
for (let i = 0; i < node.args!.length; i++) {
|
|
207
|
+
this.serialize(node.args![i]);
|
|
208
|
+
if (i < node.args!.length - 1) {
|
|
209
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ','));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
217
212
|
if (node.options) {
|
|
218
213
|
for (const [key, value] of Object.entries(node.options)) {
|
|
219
214
|
this.queue.push(new TypstToken(TypstTokenType.SYMBOL, `, ${key}: ${value}`));
|
|
@@ -228,7 +223,7 @@ export class TypstWriter {
|
|
|
228
223
|
matrix.forEach((row, i) => {
|
|
229
224
|
row.forEach((cell, j) => {
|
|
230
225
|
if (j > 0) {
|
|
231
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
226
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '&'));
|
|
232
227
|
}
|
|
233
228
|
this.serialize(cell);
|
|
234
229
|
});
|
|
@@ -261,10 +256,10 @@ export class TypstWriter {
|
|
|
261
256
|
this.serialize(cell);
|
|
262
257
|
// cell.args!.forEach((n) => this.append(n));
|
|
263
258
|
if (j < row.length - 1) {
|
|
264
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
259
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ','));
|
|
265
260
|
} else {
|
|
266
261
|
if (i < matrix.length - 1) {
|
|
267
|
-
this.queue.push(new TypstToken(TypstTokenType.
|
|
262
|
+
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ';'));
|
|
268
263
|
}
|
|
269
264
|
}
|
|
270
265
|
});
|
|
@@ -316,9 +311,9 @@ export class TypstWriter {
|
|
|
316
311
|
let token = this.queue[i];
|
|
317
312
|
if (token.eq(SOFT_SPACE)) {
|
|
318
313
|
if (i === this.queue.length - 1) {
|
|
319
|
-
this.queue[i].
|
|
314
|
+
this.queue[i].value = '';
|
|
320
315
|
} else if (this.queue[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS, TYPST_COMMA, TYPST_NEWLINE])) {
|
|
321
|
-
this.queue[i].
|
|
316
|
+
this.queue[i].value = '';
|
|
322
317
|
}
|
|
323
318
|
}
|
|
324
319
|
}
|
|
@@ -388,13 +383,13 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
388
383
|
// Special logic for overbrace
|
|
389
384
|
if (base && base.type === 'unaryFunc' && base.content === '\\overbrace' && sup) {
|
|
390
385
|
return new TypstNode(
|
|
391
|
-
'
|
|
386
|
+
'funcCall',
|
|
392
387
|
'overbrace',
|
|
393
388
|
[convertTree(base.args![0]), convertTree(sup)],
|
|
394
389
|
);
|
|
395
390
|
} else if (base && base.type === 'unaryFunc' && base.content === '\\underbrace' && sub) {
|
|
396
391
|
return new TypstNode(
|
|
397
|
-
'
|
|
392
|
+
'funcCall',
|
|
398
393
|
'underbrace',
|
|
399
394
|
[convertTree(base.args![0]), convertTree(sub)],
|
|
400
395
|
);
|
|
@@ -433,8 +428,17 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
433
428
|
].includes(left.content + right.content)) {
|
|
434
429
|
return group;
|
|
435
430
|
}
|
|
431
|
+
// "\left\{ A \right." -> "{A"
|
|
432
|
+
// "\left. A \right\}" -> "lr( A} )"
|
|
433
|
+
if(right.content === '.') {
|
|
434
|
+
group.args!.pop();
|
|
435
|
+
return group;
|
|
436
|
+
} else if(left.content === '.') {
|
|
437
|
+
group.args!.shift();
|
|
438
|
+
return new TypstNode( 'funcCall', 'lr', [group]);
|
|
439
|
+
}
|
|
436
440
|
return new TypstNode(
|
|
437
|
-
'
|
|
441
|
+
'funcCall',
|
|
438
442
|
'lr',
|
|
439
443
|
[group],
|
|
440
444
|
);
|
|
@@ -444,7 +448,7 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
444
448
|
return convert_overset(node);
|
|
445
449
|
}
|
|
446
450
|
return new TypstNode(
|
|
447
|
-
'
|
|
451
|
+
'funcCall',
|
|
448
452
|
convertToken(node.content),
|
|
449
453
|
node.args!.map(convertTree),
|
|
450
454
|
);
|
|
@@ -455,7 +459,7 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
455
459
|
if (node.content === '\\sqrt' && node.data) {
|
|
456
460
|
const data = convertTree(node.data as TexSqrtData); // the number of times to take the root
|
|
457
461
|
return new TypstNode(
|
|
458
|
-
'
|
|
462
|
+
'funcCall',
|
|
459
463
|
'root',
|
|
460
464
|
[data, arg0],
|
|
461
465
|
);
|
|
@@ -463,12 +467,12 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
463
467
|
// \mathbf{a} -> upright(mathbf(a))
|
|
464
468
|
if (node.content === '\\mathbf') {
|
|
465
469
|
const inner: TypstNode = new TypstNode(
|
|
466
|
-
'
|
|
470
|
+
'funcCall',
|
|
467
471
|
'bold',
|
|
468
472
|
[arg0],
|
|
469
473
|
);
|
|
470
474
|
return new TypstNode(
|
|
471
|
-
'
|
|
475
|
+
'funcCall',
|
|
472
476
|
'upright',
|
|
473
477
|
[inner],
|
|
474
478
|
);
|
|
@@ -489,7 +493,7 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
489
493
|
return new TypstNode('symbol', text);
|
|
490
494
|
} else {
|
|
491
495
|
return new TypstNode(
|
|
492
|
-
'
|
|
496
|
+
'funcCall',
|
|
493
497
|
'op',
|
|
494
498
|
[new TypstNode('text', text)],
|
|
495
499
|
);
|
|
@@ -498,7 +502,7 @@ export function convertTree(node: TexNode): TypstNode {
|
|
|
498
502
|
|
|
499
503
|
// generic case
|
|
500
504
|
return new TypstNode(
|
|
501
|
-
'
|
|
505
|
+
'funcCall',
|
|
502
506
|
convertToken(node.content),
|
|
503
507
|
node.args!.map(convertTree),
|
|
504
508
|
);
|