tex2typst 0.3.29 → 0.4.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/index.d.ts +13 -9
- package/dist/index.js +233 -224
- package/dist/tex2typst.min.js +12 -13
- package/package.json +2 -2
- package/src/convert.ts +88 -36
- package/src/exposed-types.ts +13 -9
- package/src/generic.ts +6 -6
- package/src/index.ts +23 -12
- package/src/map.ts +1 -0
- package/src/tex-parser.ts +19 -47
- package/src/tex-tokenizer.ts +1 -0
- package/src/tex-types.ts +3 -1
- package/src/tex-writer.ts +10 -1
- package/src/typst-parser.ts +114 -160
- package/tests/cheat-sheet.test.ts +0 -42
- package/tests/cheat-sheet.toml +0 -304
- package/tests/example.ts +0 -15
- package/tests/general-symbols.test.ts +0 -22
- package/tests/general-symbols.toml +0 -755
- package/tests/integration-tex2typst.yaml +0 -89
- package/tests/struct-bidirection.yaml +0 -194
- package/tests/struct-tex2typst.yaml +0 -457
- package/tests/struct-typst2tex.yaml +0 -412
- package/tests/symbol.yml +0 -126
- package/tests/test-common.ts +0 -26
- package/tests/tex-parser.test.ts +0 -97
- package/tests/tex-to-typst.test.ts +0 -136
- package/tests/typst-parser.test.ts +0 -134
- package/tests/typst-to-tex.test.ts +0 -76
- /package/src/{util.ts → utils.ts} +0 -0
package/src/typst-parser.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { TypstSupsubData } from "./typst-types";
|
|
|
6
6
|
import { TypstToken } from "./typst-types";
|
|
7
7
|
import { TypstTokenType } from "./typst-types";
|
|
8
8
|
import { tokenize_typst } from "./typst-tokenizer";
|
|
9
|
-
import { assert, isalpha } from "./
|
|
9
|
+
import { assert, isalpha } from "./utils";
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
// TODO: In Typst, y' ' is not the same as y''.
|
|
@@ -49,41 +49,37 @@ function find_closing_match(tokens: TypstToken[], start: number): number {
|
|
|
49
49
|
);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function find_closing_delim(tokens: TypstToken[], start: number): number {
|
|
53
|
-
return _find_closing_match(
|
|
54
|
-
tokens,
|
|
55
|
-
start,
|
|
56
|
-
TypstToken.LEFT_DELIMITERS,
|
|
57
|
-
TypstToken.RIGHT_DELIMITERS
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
52
|
|
|
53
|
+
function extract_named_params(arr: TypstNode[]): [TypstNode[], TypstNamedParams] {
|
|
54
|
+
const COLON = new TypstToken(TypstTokenType.ELEMENT, ':').toNode();
|
|
55
|
+
const np: TypstNamedParams = {};
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
assert(nodes[start].eq(left_parenthesis));
|
|
70
|
-
|
|
71
|
-
let count = 1;
|
|
72
|
-
let pos = start + 1;
|
|
57
|
+
const to_delete: number[] = [];
|
|
58
|
+
for(let i = 0; i < arr.length; i++) {
|
|
59
|
+
if(arr[i].type !== 'group') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
73
62
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
const g = arr[i] as TypstGroup;
|
|
64
|
+
const pos_colon = array_find(g.items, COLON);
|
|
65
|
+
if(pos_colon === -1 || pos_colon === 0) {
|
|
66
|
+
continue;
|
|
77
67
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
to_delete.push(i);
|
|
69
|
+
const param_name = g.items[pos_colon - 1];
|
|
70
|
+
if(param_name.eq(new TypstToken(TypstTokenType.SYMBOL, 'delim').toNode())) {
|
|
71
|
+
if(g.items.length !== 3) {
|
|
72
|
+
throw new TypstParserError('Invalid number of arguments for delim');
|
|
73
|
+
}
|
|
74
|
+
np['delim'] = g.items[pos_colon + 1];
|
|
75
|
+
} else {
|
|
76
|
+
throw new TypstParserError('Not implemented for other named parameters');
|
|
82
77
|
}
|
|
83
|
-
pos += 1;
|
|
84
78
|
}
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
for(let i = to_delete.length - 1; i >= 0; i--) {
|
|
80
|
+
arr.splice(to_delete[i], 1);
|
|
81
|
+
}
|
|
82
|
+
return [arr, np];
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
function primes(num: number): TypstNode[] {
|
|
@@ -129,36 +125,18 @@ function trim_whitespace_around_operators(nodes: TypstNode[]): TypstNode[] {
|
|
|
129
125
|
return res;
|
|
130
126
|
}
|
|
131
127
|
|
|
132
|
-
function process_operators(nodes: TypstNode[]
|
|
128
|
+
function process_operators(nodes: TypstNode[]): TypstNode {
|
|
133
129
|
nodes = trim_whitespace_around_operators(nodes);
|
|
134
130
|
|
|
135
|
-
const opening_bracket = LEFT_PARENTHESES.toNode();
|
|
136
|
-
const closing_bracket = RIGHT_PARENTHESES.toNode();
|
|
137
|
-
|
|
138
131
|
const stack: TypstNode[] = [];
|
|
139
132
|
|
|
140
133
|
const args: TypstNode[] = [];
|
|
141
134
|
let pos = 0;
|
|
142
135
|
while (pos < nodes.length) {
|
|
143
|
-
const
|
|
144
|
-
if
|
|
145
|
-
|
|
146
|
-
} else if(current.eq(DIV)) {
|
|
147
|
-
stack.push(current);
|
|
148
|
-
pos++;
|
|
136
|
+
const current_tree = nodes[pos];
|
|
137
|
+
if(current_tree.eq(DIV)) {
|
|
138
|
+
stack.push(current_tree);
|
|
149
139
|
} else {
|
|
150
|
-
let current_tree: TypstNode;
|
|
151
|
-
if(current.eq(opening_bracket)) {
|
|
152
|
-
// the expression is a group wrapped in parenthesis
|
|
153
|
-
const pos_closing = find_closing_parenthesis(nodes, pos);
|
|
154
|
-
current_tree = process_operators(nodes.slice(pos + 1, pos_closing), true);
|
|
155
|
-
pos = pos_closing + 1;
|
|
156
|
-
} else {
|
|
157
|
-
// the expression is just a single item
|
|
158
|
-
current_tree = current;
|
|
159
|
-
pos++;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
140
|
if(stack.length > 0 && stack[stack.length-1].eq(DIV)) {
|
|
163
141
|
let denominator = current_tree;
|
|
164
142
|
if(args.length === 0) {
|
|
@@ -179,13 +157,9 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
|
|
|
179
157
|
args.push(current_tree);
|
|
180
158
|
}
|
|
181
159
|
}
|
|
160
|
+
pos++;
|
|
182
161
|
}
|
|
183
|
-
|
|
184
|
-
if(parenthesis) {
|
|
185
|
-
return new TypstLeftright(null, { body: body, left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES } as TypstLeftRightData);
|
|
186
|
-
} else {
|
|
187
|
-
return body;
|
|
188
|
-
}
|
|
162
|
+
return args.length === 1? args[0]: new TypstGroup(args);
|
|
189
163
|
}
|
|
190
164
|
|
|
191
165
|
function parse_named_params(groups: TypstGroup[]): TypstNamedParams {
|
|
@@ -220,9 +194,14 @@ const LEFT_CURLY_BRACKET: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '{
|
|
|
220
194
|
const RIGHT_CURLY_BRACKET: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '}');
|
|
221
195
|
const COMMA = new TypstToken(TypstTokenType.ELEMENT, ',');
|
|
222
196
|
const SEMICOLON = new TypstToken(TypstTokenType.ELEMENT, ';');
|
|
223
|
-
const SINGLE_SPACE = new TypstToken(TypstTokenType.SPACE, ' ');
|
|
224
197
|
const CONTROL_AND = new TypstToken(TypstTokenType.CONTROL, '&');
|
|
225
198
|
|
|
199
|
+
|
|
200
|
+
interface TexParseEnv {
|
|
201
|
+
spaceSensitive: boolean;
|
|
202
|
+
newlineSensitive: boolean;
|
|
203
|
+
}
|
|
204
|
+
|
|
226
205
|
export class TypstParser {
|
|
227
206
|
space_sensitive: boolean;
|
|
228
207
|
newline_sensitive: boolean;
|
|
@@ -237,35 +216,8 @@ export class TypstParser {
|
|
|
237
216
|
return tree;
|
|
238
217
|
}
|
|
239
218
|
|
|
240
|
-
parseGroup(tokens: TypstToken[], start: number, end: number
|
|
241
|
-
|
|
242
|
-
let pos = start;
|
|
243
|
-
|
|
244
|
-
while (pos < end) {
|
|
245
|
-
const [res, newPos] = this.parseNextExpr(tokens, pos);
|
|
246
|
-
pos = newPos;
|
|
247
|
-
if (res.head.type === TypstTokenType.SPACE || res.head.type === TypstTokenType.NEWLINE) {
|
|
248
|
-
if (!this.space_sensitive && res.head.value.replace(/ /g, '').length === 0) {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
if (!this.newline_sensitive && res.head.value === '\n') {
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
results.push(res);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let node: TypstNode;
|
|
259
|
-
if(parentheses) {
|
|
260
|
-
node = process_operators(results, true);
|
|
261
|
-
} else {
|
|
262
|
-
if (results.length === 1) {
|
|
263
|
-
node = results[0];
|
|
264
|
-
} else {
|
|
265
|
-
node = process_operators(results);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return [node, end + 1];
|
|
219
|
+
parseGroup(tokens: TypstToken[], start: number, end: number): TypstParseResult {
|
|
220
|
+
return this.parseUntil(tokens.slice(start, end), 0, null);
|
|
269
221
|
}
|
|
270
222
|
|
|
271
223
|
parseNextExpr(tokens: TypstToken[], start: number): TypstParseResult {
|
|
@@ -298,12 +250,51 @@ export class TypstParser {
|
|
|
298
250
|
}
|
|
299
251
|
}
|
|
300
252
|
|
|
253
|
+
// return pos: (position of stopToken) + 1
|
|
254
|
+
// pos will be -1 if stopToken is not found
|
|
255
|
+
parseUntil(tokens: TypstToken[], start: number, stopToken: TypstToken | null, env: Partial<TexParseEnv> = {}): TypstParseResult {
|
|
256
|
+
if (env.spaceSensitive === undefined) {
|
|
257
|
+
env.spaceSensitive = this.space_sensitive;
|
|
258
|
+
}
|
|
259
|
+
if (env.newlineSensitive === undefined) {
|
|
260
|
+
env.newlineSensitive = this.newline_sensitive;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const results: TypstNode[] = [];
|
|
264
|
+
let pos = start;
|
|
265
|
+
|
|
266
|
+
while (pos < tokens.length) {
|
|
267
|
+
if (stopToken !== null && tokens[pos].eq(stopToken)) {
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
const [res, newPos] = this.parseNextExpr(tokens, pos);
|
|
271
|
+
pos = newPos;
|
|
272
|
+
if (res.head.type === TypstTokenType.SPACE || res.head.type === TypstTokenType.NEWLINE) {
|
|
273
|
+
if (!env.spaceSensitive && res.head.value.replace(/ /g, '').length === 0) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (!env.newlineSensitive && res.head.value === '\n') {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
results.push(res);
|
|
281
|
+
}
|
|
282
|
+
if (pos >= tokens.length && stopToken !== null) {
|
|
283
|
+
return [TypstToken.NONE.toNode(), -1];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const node = process_operators(results);
|
|
287
|
+
return [node, pos + 1];
|
|
288
|
+
}
|
|
289
|
+
|
|
301
290
|
parseSupOrSub(tokens: TypstToken[], start: number): TypstParseResult {
|
|
302
291
|
let node: TypstNode;
|
|
303
292
|
let end: number;
|
|
304
293
|
if(tokens[start].eq(LEFT_PARENTHESES)) {
|
|
305
|
-
|
|
306
|
-
|
|
294
|
+
[node, end] = this.parseUntil(tokens, start + 1, RIGHT_PARENTHESES);
|
|
295
|
+
if (end === -1) {
|
|
296
|
+
throw new Error("Unmatched '('");
|
|
297
|
+
}
|
|
307
298
|
} else {
|
|
308
299
|
[node, end] = this.parseNextExprWithoutSupSub(tokens, start);
|
|
309
300
|
}
|
|
@@ -319,8 +310,12 @@ export class TypstParser {
|
|
|
319
310
|
const firstToken = tokens[start];
|
|
320
311
|
const node = firstToken.toNode();
|
|
321
312
|
if(firstToken.eq(LEFT_PARENTHESES)) {
|
|
322
|
-
const
|
|
323
|
-
|
|
313
|
+
const [body, end] = this.parseUntil(tokens, start + 1, RIGHT_PARENTHESES);
|
|
314
|
+
if (end === -1) {
|
|
315
|
+
throw new Error("Unmatched '('");
|
|
316
|
+
}
|
|
317
|
+
const res = new TypstLeftright(null, { body: body, left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES } as TypstLeftRightData);
|
|
318
|
+
return [res, end];
|
|
324
319
|
}
|
|
325
320
|
if(firstToken.type === TypstTokenType.ELEMENT && !isalpha(firstToken.value[0])) {
|
|
326
321
|
return [node, start + 1];
|
|
@@ -371,29 +366,32 @@ export class TypstParser {
|
|
|
371
366
|
|
|
372
367
|
// start: the position of the left parentheses
|
|
373
368
|
parseLrArguments(tokens: TypstToken[], start: number): [TypstNode, number] {
|
|
374
|
-
const lr_token =
|
|
369
|
+
const lr_token = new TypstToken(TypstTokenType.SYMBOL, 'lr');
|
|
375
370
|
const end = find_closing_match(tokens, start);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
} else {
|
|
385
|
-
const [inner_args, _] = this.parseGroup(tokens, start + 1, end - 1);
|
|
386
|
-
return [
|
|
387
|
-
new TypstLeftright(lr_token, { body: inner_args, left: null, right: null }),
|
|
388
|
-
end + 1,
|
|
389
|
-
];
|
|
371
|
+
|
|
372
|
+
let left: TypstToken | null = null;
|
|
373
|
+
let right: TypstToken | null = null;
|
|
374
|
+
let inner_start = start + 1;
|
|
375
|
+
let inner_end = end;
|
|
376
|
+
if (inner_end > inner_start && tokens[inner_start].isOneOf(TypstToken.LEFT_DELIMITERS)) {
|
|
377
|
+
left = tokens[inner_start];
|
|
378
|
+
inner_start += 1;
|
|
390
379
|
}
|
|
380
|
+
if (inner_end - 1 > inner_start && tokens[inner_end - 1].isOneOf(TypstToken.RIGHT_DELIMITERS)) {
|
|
381
|
+
right = tokens[inner_end - 1];
|
|
382
|
+
inner_end -= 1;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const [inner_args, _] = this.parseGroup(tokens, inner_start, inner_end);
|
|
386
|
+
return [
|
|
387
|
+
new TypstLeftright(lr_token, { body: inner_args, left: left, right: right }),
|
|
388
|
+
end + 1,
|
|
389
|
+
];
|
|
391
390
|
}
|
|
392
391
|
|
|
393
392
|
// start: the position of the left parentheses
|
|
394
393
|
parseMatrix(tokens: TypstToken[], start: number, rowSepToken: TypstToken, cellSepToken: TypstToken): [TypstNode[][], TypstNamedParams, number] {
|
|
395
394
|
const end = find_closing_match(tokens, start);
|
|
396
|
-
tokens = tokens.slice(0, end);
|
|
397
395
|
|
|
398
396
|
const matrix: TypstNode[][] = [];
|
|
399
397
|
let named_params: TypstNamedParams = {};
|
|
@@ -402,45 +400,13 @@ export class TypstParser {
|
|
|
402
400
|
while (pos < end) {
|
|
403
401
|
while(pos < end) {
|
|
404
402
|
let next_stop = array_find(tokens, rowSepToken, pos);
|
|
405
|
-
if (next_stop === -1) {
|
|
403
|
+
if (next_stop === -1 || next_stop > end) {
|
|
406
404
|
next_stop = end;
|
|
407
405
|
}
|
|
408
406
|
|
|
409
407
|
let row = this.parseArgumentsWithSeparator(tokens, pos, next_stop, cellSepToken);
|
|
410
408
|
let np: TypstNamedParams = {};
|
|
411
409
|
|
|
412
|
-
function extract_named_params(arr: TypstNode[]): [TypstNode[], TypstNamedParams] {
|
|
413
|
-
const COLON = new TypstToken(TypstTokenType.ELEMENT, ':').toNode();
|
|
414
|
-
const np: TypstNamedParams = {};
|
|
415
|
-
|
|
416
|
-
const to_delete: number[] = [];
|
|
417
|
-
for(let i = 0; i < arr.length; i++) {
|
|
418
|
-
if(arr[i].type !== 'group') {
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
const g = arr[i] as TypstGroup;
|
|
423
|
-
const pos_colon = array_find(g.items, COLON);
|
|
424
|
-
if(pos_colon === -1 || pos_colon === 0) {
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
to_delete.push(i);
|
|
428
|
-
const param_name = g.items[pos_colon - 1];
|
|
429
|
-
if(param_name.eq(new TypstToken(TypstTokenType.SYMBOL, 'delim').toNode())) {
|
|
430
|
-
if(g.items.length !== 3) {
|
|
431
|
-
throw new TypstParserError('Invalid number of arguments for delim');
|
|
432
|
-
}
|
|
433
|
-
np['delim'] = g.items[pos_colon + 1];
|
|
434
|
-
} else {
|
|
435
|
-
throw new TypstParserError('Not implemented for other named parameters');
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
for(let i = to_delete.length - 1; i >= 0; i--) {
|
|
439
|
-
arr.splice(to_delete[i], 1);
|
|
440
|
-
}
|
|
441
|
-
return [arr, np];
|
|
442
|
-
}
|
|
443
|
-
|
|
444
410
|
[row, np] = extract_named_params(row);
|
|
445
411
|
matrix.push(row);
|
|
446
412
|
Object.assign(named_params, np);
|
|
@@ -455,29 +421,17 @@ export class TypstParser {
|
|
|
455
421
|
parseArgumentsWithSeparator(tokens: TypstToken[], start: number, end: number, sepToken: TypstToken): TypstNode[] {
|
|
456
422
|
const args: TypstNode[] = [];
|
|
457
423
|
let pos = start;
|
|
458
|
-
while (pos < end) {
|
|
459
|
-
let nodes: TypstNode[] = [];
|
|
460
|
-
while(pos < end) {
|
|
461
|
-
if(tokens[pos].eq(sepToken)) {
|
|
462
|
-
pos += 1;
|
|
463
|
-
break;
|
|
464
|
-
} else if(tokens[pos].eq(SINGLE_SPACE)) {
|
|
465
|
-
pos += 1;
|
|
466
|
-
continue;
|
|
467
|
-
}
|
|
468
|
-
const [argItem, newPos] = this.parseNextExpr(tokens, pos);
|
|
469
|
-
pos = newPos;
|
|
470
|
-
nodes.push(argItem);
|
|
471
|
-
}
|
|
472
424
|
|
|
425
|
+
while (pos < end) {
|
|
473
426
|
let arg: TypstNode;
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
427
|
+
let newPos: number;
|
|
428
|
+
const env = { spaceSensitive: false, newlineSensitive: true };
|
|
429
|
+
[arg, newPos] = this.parseUntil(tokens.slice(0, end), pos, sepToken, env);
|
|
430
|
+
if (newPos == -1) {
|
|
431
|
+
[arg, newPos] = this.parseUntil(tokens.slice(0, end), pos, null, env);
|
|
478
432
|
}
|
|
479
|
-
|
|
480
433
|
args.push(arg);
|
|
434
|
+
pos = newPos;
|
|
481
435
|
}
|
|
482
436
|
return args;
|
|
483
437
|
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import toml from 'toml';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import { describe, it, test, expect } from 'vitest';
|
|
5
|
-
import { tex2typst, symbolMap } from '../src';
|
|
6
|
-
|
|
7
|
-
interface CheatSheet {
|
|
8
|
-
math_commands: { [key: string]: string };
|
|
9
|
-
math_symbols: { [key: string]: string };
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
describe('cheat sheet', () => {
|
|
13
|
-
const cheatSheetFile = path.join(__dirname, 'cheat-sheet.toml');
|
|
14
|
-
const text_content = fs.readFileSync(cheatSheetFile, { encoding: 'utf-8' });
|
|
15
|
-
const data = toml.parse(text_content) as CheatSheet;
|
|
16
|
-
|
|
17
|
-
test('math_commands', () => {
|
|
18
|
-
expect(data.math_commands).toBeDefined();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
for (const [key, value] of Object.entries(data.math_commands)) {
|
|
22
|
-
const input = `\\${key}{x}{y}`;
|
|
23
|
-
const expected1 = `${value} x y`;
|
|
24
|
-
const expected2 = `${value}(x) y`;
|
|
25
|
-
const expected3 = `${value}(x, y)`;
|
|
26
|
-
const result = tex2typst(input, {preferShorthands: false});
|
|
27
|
-
expect([expected1, expected2, expected3]).toContain(result);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('math_symbols', () => {
|
|
32
|
-
expect(data.math_symbols).toBeDefined();
|
|
33
|
-
|
|
34
|
-
for (const [key, value] of Object.entries(data.math_symbols)) {
|
|
35
|
-
const input = `\\${key}`;
|
|
36
|
-
const expected = value;
|
|
37
|
-
const result = tex2typst(input, {preferShorthands: false});
|
|
38
|
-
expect(result).toBe(expected);
|
|
39
|
-
expect(symbolMap.get(key)).toBe(expected);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|