tex2typst 0.3.23 → 0.3.24

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.
@@ -1,6 +1,10 @@
1
1
 
2
2
  import { array_find } from "./generic";
3
- import { TYPST_NONE, TypstLrData, TypstNamedParams, TypstNode, TypstSupsubData, TypstToken, TypstTokenType } from "./types";
3
+ import { TypstCases, TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstLeftRightData, TypstMatrix, TypstNode, TypstSupsub } from "./typst-types";
4
+ import { TypstNamedParams } from "./typst-types";
5
+ import { TypstSupsubData } from "./typst-types";
6
+ import { TypstToken } from "./typst-types";
7
+ import { TypstTokenType } from "./typst-types";
4
8
  import { tokenize_typst } from "./typst-tokenizer";
5
9
  import { assert, isalpha } from "./util";
6
10
 
@@ -24,7 +28,7 @@ function _find_closing_match(tokens: TypstToken[], start: number,
24
28
 
25
29
  while (count > 0) {
26
30
  if (pos >= tokens.length) {
27
- throw new Error('Unmatched brackets');
31
+ throw new Error('Unmatched brackets or parentheses');
28
32
  }
29
33
  if (tokens[pos].isOneOf(rightBrackets)) {
30
34
  count -= 1;
@@ -58,8 +62,10 @@ function find_closing_delim(tokens: TypstToken[], start: number): number {
58
62
 
59
63
 
60
64
  function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
61
- const left_parenthesis = new TypstNode('atom', '(');
62
- const right_parenthesis = new TypstNode('atom', ')');
65
+ const left_parenthesis = new TypstToken(TypstTokenType.ELEMENT, '(').toNode();
66
+ const right_parenthesis = new TypstToken(TypstTokenType.ELEMENT, ')').toNode();
67
+
68
+
63
69
 
64
70
  assert(nodes[start].eq(left_parenthesis));
65
71
 
@@ -68,7 +74,7 @@ function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
68
74
 
69
75
  while (count > 0) {
70
76
  if (pos >= nodes.length) {
71
- throw new Error('Unmatched brackets');
77
+ throw new Error("Unmatched '('");
72
78
  }
73
79
  if (nodes[pos].eq(left_parenthesis)) {
74
80
  count += 1;
@@ -84,18 +90,18 @@ function find_closing_parenthesis(nodes: TypstNode[], start: number): number {
84
90
  function primes(num: number): TypstNode[] {
85
91
  const res: TypstNode[] = [];
86
92
  for (let i = 0; i < num; i++) {
87
- res.push(new TypstNode('atom', "'"));
93
+ res.push(new TypstToken(TypstTokenType.ELEMENT, "'").toNode());
88
94
  }
89
95
  return res;
90
96
  }
91
97
 
92
- const DIV = new TypstNode('atom', '/');
98
+ const DIV = new TypstToken(TypstTokenType.ELEMENT, '/').toNode();
93
99
 
94
100
 
95
101
 
96
102
  function next_non_whitespace(nodes: TypstNode[], start: number): TypstNode | null {
97
103
  let pos = start;
98
- while (pos < nodes.length && nodes[pos].type === 'whitespace') {
104
+ while (pos < nodes.length && (nodes[pos].head.type === TypstTokenType.SPACE || nodes[pos].head.type === TypstTokenType.NEWLINE)) {
99
105
  pos++;
100
106
  }
101
107
  return pos === nodes.length ? null : nodes[pos];
@@ -106,7 +112,7 @@ function trim_whitespace_around_operators(nodes: TypstNode[]): TypstNode[] {
106
112
  const res: TypstNode[] = [];
107
113
  for (let i = 0; i < nodes.length; i++) {
108
114
  const current = nodes[i];
109
- if (current.type === 'whitespace') {
115
+ if (current.head.type === TypstTokenType.SPACE || current.head.type === TypstTokenType.NEWLINE) {
110
116
  if(after_operator) {
111
117
  continue;
112
118
  }
@@ -127,8 +133,8 @@ function trim_whitespace_around_operators(nodes: TypstNode[]): TypstNode[] {
127
133
  function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
128
134
  nodes = trim_whitespace_around_operators(nodes);
129
135
 
130
- const opening_bracket = new TypstNode('atom', '(');
131
- const closing_bracket = new TypstNode('atom', ')');
136
+ const opening_bracket = LEFT_PARENTHESES.toNode();
137
+ const closing_bracket = RIGHT_PARENTHESES.toNode();
132
138
 
133
139
  const stack: TypstNode[] = [];
134
140
 
@@ -155,20 +161,20 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
155
161
  }
156
162
 
157
163
  if(stack.length > 0 && stack[stack.length-1].eq(DIV)) {
158
- const denominator = current_tree;
164
+ let denominator = current_tree;
159
165
  if(args.length === 0) {
160
166
  throw new TypstParserError("Unexpected '/' operator, no numerator before it");
161
167
  }
162
- const numerator = args.pop()!;
168
+ let numerator = args.pop()!;
163
169
 
164
- if(denominator.type === 'group' && denominator.content === 'parenthesis') {
165
- denominator.content = '';
170
+ if(denominator.type === 'leftright') {
171
+ denominator = new TypstGroup(denominator.args!);
166
172
  }
167
- if(numerator.type === 'group' && numerator.content === 'parenthesis') {
168
- numerator.content = '';
173
+ if(numerator.type === 'leftright') {
174
+ numerator = new TypstGroup(numerator.args!);
169
175
  }
170
176
 
171
- args.push(new TypstNode('fraction', '', [numerator, denominator]));
177
+ args.push(new TypstFraction([numerator, denominator]));
172
178
  stack.pop(); // drop the '/' operator
173
179
  } else {
174
180
  args.push(current_tree);
@@ -176,12 +182,12 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
176
182
  }
177
183
  }
178
184
  if(parenthesis) {
179
- return new TypstNode('group', 'parenthesis', args);
185
+ return new TypstLeftright(null, args, { left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES } as TypstLeftRightData);
180
186
  } else {
181
187
  if(args.length === 1) {
182
188
  return args[0];
183
189
  } else {
184
- return new TypstNode('group', '', args);
190
+ return new TypstGroup(args);
185
191
  }
186
192
  }
187
193
  }
@@ -208,6 +214,7 @@ const VERTICAL_BAR = new TypstToken(TypstTokenType.ELEMENT, '|');
208
214
  const COMMA = new TypstToken(TypstTokenType.ELEMENT, ',');
209
215
  const SEMICOLON = new TypstToken(TypstTokenType.ELEMENT, ';');
210
216
  const SINGLE_SPACE = new TypstToken(TypstTokenType.SPACE, ' ');
217
+ const CONTROL_AND = new TypstToken(TypstTokenType.CONTROL, '&');
211
218
 
212
219
  export class TypstParser {
213
220
  space_sensitive: boolean;
@@ -230,11 +237,11 @@ export class TypstParser {
230
237
  while (pos < end) {
231
238
  const [res, newPos] = this.parseNextExpr(tokens, pos);
232
239
  pos = newPos;
233
- if (res.type === 'whitespace') {
234
- if (!this.space_sensitive && res.content.replace(/ /g, '').length === 0) {
240
+ if (res.head.type === TypstTokenType.SPACE || res.head.type === TypstTokenType.NEWLINE) {
241
+ if (!this.space_sensitive && res.head.value.replace(/ /g, '').length === 0) {
235
242
  continue;
236
243
  }
237
- if (!this.newline_sensitive && res.content === '\n') {
244
+ if (!this.newline_sensitive && res.head.value === '\n') {
238
245
  continue;
239
246
  }
240
247
  }
@@ -261,7 +268,7 @@ export class TypstParser {
261
268
 
262
269
  const num_base_prime = eat_primes(tokens, pos);
263
270
  if (num_base_prime > 0) {
264
- base = new TypstNode('group', '', [base].concat(primes(num_base_prime)));
271
+ base = new TypstGroup([base].concat(primes(num_base_prime)));
265
272
  pos += num_base_prime;
266
273
  }
267
274
  if (pos < tokens.length && tokens[pos].eq(SUB_SYMBOL)) {
@@ -277,14 +284,8 @@ export class TypstParser {
277
284
  }
278
285
 
279
286
  if (sub !== null || sup !== null) {
280
- const res: TypstSupsubData = { base };
281
- if (sub) {
282
- res.sub = sub;
283
- }
284
- if (sup) {
285
- res.sup = sup;
286
- }
287
- return [new TypstNode('supsub', '', [], res), pos];
287
+ const res: TypstSupsubData = { base, sup, sub };
288
+ return [new TypstSupsub(res), pos];
288
289
  } else {
289
290
  return [base, pos];
290
291
  }
@@ -301,7 +302,7 @@ export class TypstParser {
301
302
  }
302
303
  const num_prime = eat_primes(tokens, end);
303
304
  if (num_prime > 0) {
304
- node = new TypstNode('group', '', [node].concat(primes(num_prime)));
305
+ node = new TypstGroup([node].concat(primes(num_prime)));
305
306
  end += num_prime;
306
307
  }
307
308
  return [node, end];
@@ -320,24 +321,22 @@ export class TypstParser {
320
321
  if ([TypstTokenType.ELEMENT, TypstTokenType.SYMBOL].includes(firstToken.type)) {
321
322
  if (start + 1 < tokens.length && tokens[start + 1].eq(LEFT_PARENTHESES)) {
322
323
  if(firstToken.value === 'mat') {
323
- const [matrix, named_params, newPos] = this.parseGroupsOfArguments(tokens, start + 1);
324
- const mat = new TypstNode('matrix', '', [], matrix);
324
+ const [matrix, named_params, newPos] = this.parseMatrix(tokens, start + 1, SEMICOLON, COMMA);
325
+ const mat = new TypstMatrix(matrix);
325
326
  mat.setOptions(named_params);
326
327
  return [mat, newPos];
327
328
  }
328
329
  if(firstToken.value === 'cases') {
329
- const [cases, named_params, newPos] = this.parseGroupsOfArguments(tokens, start + 1, COMMA);
330
- const casesNode = new TypstNode('cases', '', [], cases);
330
+ const [cases, named_params, newPos] = this.parseMatrix(tokens, start + 1, COMMA, CONTROL_AND);
331
+ const casesNode = new TypstCases(cases);
331
332
  casesNode.setOptions(named_params);
332
333
  return [casesNode, newPos];
333
334
  }
334
335
  if (firstToken.value === 'lr') {
335
- const [args, newPos, lrData] = this.parseLrArguments(tokens, start + 1);
336
- const func_call = new TypstNode('funcCall', firstToken.value, args, lrData);
337
- return [func_call, newPos];
336
+ return this.parseLrArguments(tokens, start + 1);
338
337
  }
339
338
  const [args, newPos] = this.parseArguments(tokens, start + 1);
340
- const func_call = new TypstNode('funcCall', firstToken.value, args);
339
+ const func_call = new TypstFuncCall(firstToken, args);
341
340
  return [func_call, newPos];
342
341
  }
343
342
  }
@@ -348,33 +347,32 @@ export class TypstParser {
348
347
  // start: the position of the left parentheses
349
348
  parseArguments(tokens: TypstToken[], start: number): [TypstNode[], number] {
350
349
  const end = find_closing_match(tokens, start);
351
- return [this.parseCommaSeparatedArguments(tokens, start + 1, end), end + 1];
350
+ return [this.parseArgumentsWithSeparator(tokens, start + 1, end, COMMA), end + 1];
352
351
  }
353
352
 
354
353
  // start: the position of the left parentheses
355
- parseLrArguments(tokens: TypstToken[], start: number): [TypstNode[], number, TypstLrData] {
354
+ parseLrArguments(tokens: TypstToken[], start: number): [TypstNode, number] {
355
+ const lr_token = tokens[start];
356
356
  if (tokens[start + 1].isOneOf([LEFT_PARENTHESES, LEFT_BRACKET, LEFT_CURLY_BRACKET, VERTICAL_BAR])) {
357
357
  const end = find_closing_match(tokens, start);
358
358
  const inner_start = start + 1;
359
359
  const inner_end = find_closing_delim(tokens, inner_start);
360
- const inner_args= this.parseCommaSeparatedArguments(tokens, inner_start + 1, inner_end);
360
+ const inner_args= this.parseArgumentsWithSeparator(tokens, inner_start + 1, inner_end, COMMA);
361
361
  return [
362
- inner_args,
362
+ new TypstLeftright(lr_token, inner_args, {left: tokens[inner_start], right: tokens[inner_end]}),
363
363
  end + 1,
364
- {leftDelim: tokens[inner_start].value, rightDelim: tokens[inner_end].value} as TypstLrData
365
364
  ];
366
365
  } else {
367
366
  const [args, end] = this.parseArguments(tokens, start);
368
367
  return [
369
- args,
368
+ new TypstLeftright(lr_token, args, { left: null, right: null }),
370
369
  end,
371
- {leftDelim: null, rightDelim: null} as TypstLrData,
372
370
  ];
373
371
  }
374
372
  }
375
373
 
376
374
  // start: the position of the left parentheses
377
- parseGroupsOfArguments(tokens: TypstToken[], start: number, newline_token = SEMICOLON): [TypstNode[][], TypstNamedParams, number] {
375
+ parseMatrix(tokens: TypstToken[], start: number, rowSepToken: TypstToken, cellSepToken: TypstToken): [TypstNode[][], TypstNamedParams, number] {
378
376
  const end = find_closing_match(tokens, start);
379
377
  tokens = tokens.slice(0, end);
380
378
 
@@ -384,16 +382,16 @@ export class TypstParser {
384
382
  let pos = start + 1;
385
383
  while (pos < end) {
386
384
  while(pos < end) {
387
- let next_stop = array_find(tokens, newline_token, pos);
385
+ let next_stop = array_find(tokens, rowSepToken, pos);
388
386
  if (next_stop === -1) {
389
387
  next_stop = end;
390
388
  }
391
389
 
392
- let row = this.parseCommaSeparatedArguments(tokens, pos, next_stop);
390
+ let row = this.parseArgumentsWithSeparator(tokens, pos, next_stop, cellSepToken);
393
391
  let np: TypstNamedParams = {};
394
392
 
395
393
  function extract_named_params(arr: TypstNode[]): [TypstNode[], TypstNamedParams] {
396
- const COLON = new TypstNode('atom', ':');
394
+ const COLON = new TypstToken(TypstTokenType.ELEMENT, ':').toNode();
397
395
  const np: TypstNamedParams = {};
398
396
 
399
397
  const to_delete: number[] = [];
@@ -409,7 +407,7 @@ export class TypstParser {
409
407
  }
410
408
  to_delete.push(i);
411
409
  const param_name = g.args![pos_colon - 1];
412
- if(param_name.eq(new TypstNode('symbol', 'delim'))) {
410
+ if(param_name.eq(new TypstToken(TypstTokenType.SYMBOL, 'delim').toNode())) {
413
411
  if(g.args!.length !== 3) {
414
412
  throw new TypstParserError('Invalid number of arguments for delim');
415
413
  }
@@ -435,13 +433,13 @@ export class TypstParser {
435
433
  }
436
434
 
437
435
  // start: the position of the first token of arguments
438
- parseCommaSeparatedArguments(tokens: TypstToken[], start: number, end: number): TypstNode[] {
436
+ parseArgumentsWithSeparator(tokens: TypstToken[], start: number, end: number, sepToken: TypstToken): TypstNode[] {
439
437
  const args: TypstNode[] = [];
440
438
  let pos = start;
441
439
  while (pos < end) {
442
440
  let nodes: TypstNode[] = [];
443
441
  while(pos < end) {
444
- if(tokens[pos].eq(COMMA)) {
442
+ if(tokens[pos].eq(sepToken)) {
445
443
  pos += 1;
446
444
  break;
447
445
  } else if(tokens[pos].eq(SINGLE_SPACE)) {
@@ -1,85 +1,86 @@
1
- import { TypstToken, TypstTokenType } from "./types";
2
- import { reverseShorthandMap } from "./typst-shorthands";
3
- import { JSLex, Scanner } from "./jslex";
4
-
5
- const TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
6
-
7
-
8
- function generate_regex_for_shorthands(): string {
9
- const regex_list = TYPST_SHORTHANDS.map((s) => {
10
- s = s.replaceAll('|', '\\|');
11
- s = s.replaceAll('.', '\\.');
12
- s = s.replaceAll('[', '\\[');
13
- s = s.replaceAll(']', '\\]');
14
- return s;
15
- });
16
- return `(${regex_list.join('|')})`;
17
- }
18
-
19
-
20
- const REGEX_SHORTHANDS = generate_regex_for_shorthands();
21
-
22
- const rules_map = new Map<string, (a: Scanner<TypstToken>) => TypstToken | TypstToken[]>([
23
- [String.raw`//[^\n]*`, (s) => new TypstToken(TypstTokenType.COMMENT, s.text()!.substring(2))],
24
- [String.raw`/`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
25
- [String.raw`[_^&]`, (s) => new TypstToken(TypstTokenType.CONTROL, s.text()!)],
26
- [String.raw`\r?\n`, (_s) => new TypstToken(TypstTokenType.NEWLINE, "\n")],
27
- [String.raw`\s+`, (s) => new TypstToken(TypstTokenType.SPACE, s.text()!)],
28
- [String.raw`\\[$&#_]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
29
- [String.raw`\\\n`, (s) => {
30
- return [
31
- new TypstToken(TypstTokenType.CONTROL, "\\"),
32
- new TypstToken(TypstTokenType.NEWLINE, "\n"),
33
- ]
34
- }],
35
- [String.raw`\\\s`, (s) => {
36
- return [
37
- new TypstToken(TypstTokenType.CONTROL, "\\"),
38
- new TypstToken(TypstTokenType.SPACE, " "),
39
- ]
40
- }],
41
- // this backslash is dummy and will be ignored in later stages
42
- [String.raw`\\\S`, (_s) => new TypstToken(TypstTokenType.CONTROL, "")],
43
- [
44
- String.raw`"([^"]|(\\"))*"`,
45
- (s) => {
46
- const text = s.text()!.substring(1, s.text()!.length - 1);
47
- // replace all escape characters with their actual characters
48
- text.replaceAll('\\"', '"');
49
- return new TypstToken(TypstTokenType.TEXT, text);
50
- }
51
- ],
52
- [
53
- REGEX_SHORTHANDS,
54
- (s) => {
55
- const shorthand = s.text()!;
56
- const symbol = reverseShorthandMap.get(shorthand)!;
57
- return new TypstToken(TypstTokenType.SYMBOL, symbol);
58
- }
59
- ],
60
- [String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
61
- [String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
62
- [String.raw`#h\((.+?)\)`, (s) => {
63
- const match = s.reMatchArray()!;
64
- return [
65
- new TypstToken(TypstTokenType.SYMBOL, "#h"),
66
- new TypstToken(TypstTokenType.ELEMENT, "("),
67
- new TypstToken(TypstTokenType.LITERAL, match[1]),
68
- new TypstToken(TypstTokenType.ELEMENT, ")"),
69
- ];
70
- }],
71
- [String.raw`[a-zA-Z\.]+`, (s) => {
72
- return new TypstToken(s.text()!.length === 1? TypstTokenType.ELEMENT: TypstTokenType.SYMBOL, s.text()!);
73
- }],
74
- [String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
75
- [String.raw`.`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
76
- ]);
77
-
78
- const spec = {
79
- "start": rules_map
80
- };
81
-
82
- export function tokenize_typst(input: string): TypstToken[] {
83
- const lexer = new JSLex<TypstToken>(spec);
84
- return lexer.collect(input);
85
- }
1
+ import { TypstToken } from "./typst-types";
2
+ import { TypstTokenType } from "./typst-types";
3
+ import { reverseShorthandMap } from "./typst-shorthands";
4
+ import { JSLex, Scanner } from "./jslex";
5
+
6
+ const TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
7
+
8
+
9
+ function generate_regex_for_shorthands(): string {
10
+ const regex_list = TYPST_SHORTHANDS.map((s) => {
11
+ s = s.replaceAll('|', '\\|');
12
+ s = s.replaceAll('.', '\\.');
13
+ s = s.replaceAll('[', '\\[');
14
+ s = s.replaceAll(']', '\\]');
15
+ return s;
16
+ });
17
+ return `(${regex_list.join('|')})`;
18
+ }
19
+
20
+
21
+ const REGEX_SHORTHANDS = generate_regex_for_shorthands();
22
+
23
+ const rules_map = new Map<string, (a: Scanner<TypstToken>) => TypstToken | TypstToken[]>([
24
+ [String.raw`//[^\n]*`, (s) => new TypstToken(TypstTokenType.COMMENT, s.text()!.substring(2))],
25
+ [String.raw`/`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
26
+ [String.raw`[_^&]`, (s) => new TypstToken(TypstTokenType.CONTROL, s.text()!)],
27
+ [String.raw`\r?\n`, (_s) => new TypstToken(TypstTokenType.NEWLINE, "\n")],
28
+ [String.raw`\s+`, (s) => new TypstToken(TypstTokenType.SPACE, s.text()!)],
29
+ [String.raw`\\[$&#_]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
30
+ [String.raw`\\\n`, (s) => {
31
+ return [
32
+ new TypstToken(TypstTokenType.CONTROL, "\\"),
33
+ new TypstToken(TypstTokenType.NEWLINE, "\n"),
34
+ ]
35
+ }],
36
+ [String.raw`\\\s`, (s) => {
37
+ return [
38
+ new TypstToken(TypstTokenType.CONTROL, "\\"),
39
+ new TypstToken(TypstTokenType.SPACE, " "),
40
+ ]
41
+ }],
42
+ // this backslash is dummy and will be ignored in later stages
43
+ [String.raw`\\\S`, (_s) => new TypstToken(TypstTokenType.CONTROL, "")],
44
+ [
45
+ String.raw`"([^"]|(\\"))*"`,
46
+ (s) => {
47
+ const text = s.text()!.substring(1, s.text()!.length - 1);
48
+ // replace all escape characters with their actual characters
49
+ text.replaceAll('\\"', '"');
50
+ return new TypstToken(TypstTokenType.TEXT, text);
51
+ }
52
+ ],
53
+ [
54
+ REGEX_SHORTHANDS,
55
+ (s) => {
56
+ const shorthand = s.text()!;
57
+ const symbol = reverseShorthandMap.get(shorthand)!;
58
+ return new TypstToken(TypstTokenType.SYMBOL, symbol);
59
+ }
60
+ ],
61
+ [String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
62
+ [String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
63
+ [String.raw`#h\((.+?)\)`, (s) => {
64
+ const match = s.reMatchArray()!;
65
+ return [
66
+ new TypstToken(TypstTokenType.SYMBOL, "#h"),
67
+ new TypstToken(TypstTokenType.ELEMENT, "("),
68
+ new TypstToken(TypstTokenType.LITERAL, match[1]),
69
+ new TypstToken(TypstTokenType.ELEMENT, ")"),
70
+ ];
71
+ }],
72
+ [String.raw`[a-zA-Z\.]+`, (s) => {
73
+ return new TypstToken(s.text()!.length === 1? TypstTokenType.ELEMENT: TypstTokenType.SYMBOL, s.text()!);
74
+ }],
75
+ [String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
76
+ [String.raw`.`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
77
+ ]);
78
+
79
+ const spec = {
80
+ "start": rules_map
81
+ };
82
+
83
+ export function tokenize_typst(input: string): TypstToken[] {
84
+ const lexer = new JSLex<TypstToken>(spec);
85
+ return lexer.collect(input);
86
+ }