tex2typst 0.3.24 → 0.3.25

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,5 +1,5 @@
1
1
  import { TexNode } from "./tex-types";
2
- import { TypstAlign, TypstCases, TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstMatrix, TypstNode, TypstSupsub, TypstTerminal } from "./typst-types";
2
+ import { TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstMarkupFunc, TypstMatrixLike, TypstNode, TypstSupsub, TypstTerminal } from "./typst-types";
3
3
  import { TypstToken } from "./typst-types";
4
4
  import { TypstTokenType } from "./typst-types";
5
5
  import { shorthandMap } from "./typst-shorthands";
@@ -54,7 +54,7 @@ export class TypstWriter {
54
54
  }
55
55
 
56
56
 
57
- private writeBuffer(token: TypstToken) {
57
+ private writeBuffer(previousToken: TypstToken | null, token: TypstToken) {
58
58
  const str = token.toString();
59
59
 
60
60
  if (str === '') {
@@ -84,8 +84,13 @@ export class TypstWriter {
84
84
  no_need_space ||= this.buffer.endsWith('&') && str === '=';
85
85
  // before or after a slash e.g. "a/b" instead of "a / b"
86
86
  no_need_space ||= this.buffer.endsWith('/') || str === '/';
87
+ // "[$x + y$]" instead of "[ $ x + y $ ]"
88
+ no_need_space ||= token.type === TypstTokenType.LITERAL;
87
89
  // other cases
88
90
  no_need_space ||= /[\s_^{\(]$/.test(this.buffer);
91
+ if (previousToken !== null) {
92
+ no_need_space ||= previousToken.type === TypstTokenType.LITERAL;
93
+ }
89
94
  if (!no_need_space) {
90
95
  this.buffer += ' ';
91
96
  }
@@ -137,7 +142,7 @@ export class TypstWriter {
137
142
  }
138
143
  case 'group': {
139
144
  const node = abstractNode as TypstGroup;
140
- for (const item of node.args!) {
145
+ for (const item of node.items) {
141
146
  this.serialize(item);
142
147
  }
143
148
  break;
@@ -153,9 +158,7 @@ export class TypstWriter {
153
158
  if (left) {
154
159
  this.queue.push(left);
155
160
  }
156
- for (const item of node.args!) {
157
- this.serialize(item);
158
- }
161
+ this.serialize(node.body);
159
162
  if (right) {
160
163
  this.queue.push(right);
161
164
  }
@@ -198,9 +201,9 @@ export class TypstWriter {
198
201
  this.queue.push(func_symbol);
199
202
  this.insideFunctionDepth++;
200
203
  this.queue.push(TYPST_LEFT_PARENTHESIS);
201
- for (let i = 0; i < node.args!.length; i++) {
202
- this.serialize(node.args![i]);
203
- if (i < node.args!.length - 1) {
204
+ for (let i = 0; i < node.args.length; i++) {
205
+ this.serialize(node.args[i]);
206
+ if (i < node.args.length - 1) {
204
207
  this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ','));
205
208
  }
206
209
  }
@@ -215,7 +218,7 @@ export class TypstWriter {
215
218
  }
216
219
  case 'fraction': {
217
220
  const node = abstractNode as TypstFraction;
218
- const [numerator, denominator] = node.args!;
221
+ const [numerator, denominator] = node.args;
219
222
  const pos = this.queue.length;
220
223
  const no_wrap = this.appendWithBracketsIfNeeded(numerator);
221
224
 
@@ -230,83 +233,77 @@ export class TypstWriter {
230
233
  this.appendWithBracketsIfNeeded(denominator);
231
234
  break;
232
235
  }
233
- case 'align': {
234
- const node = abstractNode as TypstAlign;
236
+ case 'matrixLike': {
237
+ const node = abstractNode as TypstMatrixLike;
235
238
  const matrix = node.matrix;
236
- matrix.forEach((row, i) => {
237
- row.forEach((cell, j) => {
238
- if (j > 0) {
239
- this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '&'));
239
+
240
+ let cell_sep: TypstToken;
241
+ let row_sep: TypstToken;
242
+ if (node.head.eq(TypstMatrixLike.MAT)) {
243
+ cell_sep = new TypstToken(TypstTokenType.ELEMENT, ',');
244
+ row_sep = new TypstToken(TypstTokenType.ELEMENT, ';');
245
+ } else if (node.head.eq(TypstMatrixLike.CASES)) {
246
+ cell_sep = new TypstToken(TypstTokenType.ELEMENT, '&');
247
+ row_sep = new TypstToken(TypstTokenType.ELEMENT, ',');
248
+ } else if (node.head.eq(TypstToken.NONE)){ // head is null
249
+ cell_sep = new TypstToken(TypstTokenType.ELEMENT, '&');
250
+ row_sep = new TypstToken(TypstTokenType.SYMBOL, '\\');
251
+ }
252
+
253
+ if (!node.head.eq(TypstToken.NONE)) {
254
+ this.queue.push(node.head);
255
+ this.insideFunctionDepth++;
256
+ this.queue.push(TYPST_LEFT_PARENTHESIS);
257
+ if (node.options) {
258
+ for (const [key, value] of Object.entries(node.options)) {
259
+ this.queue.push(new TypstToken(TypstTokenType.LITERAL, `${key}: ${value.toString()}, `));
240
260
  }
241
- this.serialize(cell);
242
- });
243
- if (i < matrix.length - 1) {
244
- this.queue.push(new TypstToken(TypstTokenType.SYMBOL, '\\'));
245
- }
246
- });
247
- break;
248
- }
249
- case 'matrix': {
250
- const node = abstractNode as TypstMatrix;
251
- const matrix = node.matrix;
252
- this.queue.push(new TypstToken(TypstTokenType.SYMBOL, 'mat'));
253
- this.insideFunctionDepth++;
254
- this.queue.push(TYPST_LEFT_PARENTHESIS);
255
- if (node.options) {
256
- for (const [key, value] of Object.entries(node.options)) {
257
- this.queue.push(new TypstToken(TypstTokenType.LITERAL, `${key}: ${value.toString()}, `));
258
261
  }
259
262
  }
263
+
260
264
  matrix.forEach((row, i) => {
261
265
  row.forEach((cell, j) => {
262
- // There is a leading & in row
263
- // if (cell.type === 'ordgroup' && cell.args!.length === 0) {
264
- // this.queue.push(new TypstNode('atom', ','));
265
- // return;
266
- // }
267
- // if (j == 0 && cell.type === 'newline' && cell.content === '\n') {
268
- // return;
269
- // }
270
266
  this.serialize(cell);
271
- // cell.args!.forEach((n) => this.append(n));
272
267
  if (j < row.length - 1) {
273
- this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ','));
268
+ this.queue.push(cell_sep);
274
269
  } else {
275
270
  if (i < matrix.length - 1) {
276
- this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ';'));
271
+ this.queue.push(row_sep);
277
272
  }
278
273
  }
279
274
  });
280
275
  });
281
- this.queue.push(TYPST_RIGHT_PARENTHESIS);
282
- this.insideFunctionDepth--;
276
+
277
+ if (!node.head.eq(TypstToken.NONE)) {
278
+ this.queue.push(TYPST_RIGHT_PARENTHESIS);
279
+ this.insideFunctionDepth--;
280
+ }
283
281
  break;
284
282
  }
285
- case 'cases': {
286
- const node = abstractNode as TypstCases;
287
- const cases = node.matrix;
288
- this.queue.push(new TypstToken(TypstTokenType.SYMBOL, 'cases'));
289
- this.insideFunctionDepth++;
283
+ case 'markupFunc': {
284
+ const node = abstractNode as TypstMarkupFunc;
285
+ this.queue.push(node.head);
290
286
  this.queue.push(TYPST_LEFT_PARENTHESIS);
291
287
  if (node.options) {
292
- for (const [key, value] of Object.entries(node.options)) {
293
- this.queue.push(new TypstToken(TypstTokenType.LITERAL, `${key}: ${value.toString()}, `));
288
+ const entries = Object.entries(node.options);
289
+ for (let i = 0; i < entries.length; i++) {
290
+ const [key, value] = entries[i];
291
+ this.queue.push(new TypstToken(TypstTokenType.LITERAL, `${key}: ${value.toString()}`));
292
+ if (i < entries.length - 1) {
293
+ this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ','));
294
+ }
294
295
  }
295
296
  }
296
- cases.forEach((row, i) => {
297
- row.forEach((cell, j) => {
298
- this.serialize(cell);
299
- if (j < row.length - 1) {
300
- this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '&'));
301
- } else {
302
- if (i < cases.length - 1) {
303
- this.queue.push(new TypstToken(TypstTokenType.ELEMENT, ','));
304
- }
305
- }
306
- });
307
- });
308
297
  this.queue.push(TYPST_RIGHT_PARENTHESIS);
309
- this.insideFunctionDepth--;
298
+
299
+ this.queue.push(new TypstToken(TypstTokenType.LITERAL, '['));
300
+ for (const frag of node.fragments) {
301
+ this.queue.push(new TypstToken(TypstTokenType.LITERAL, '$'));
302
+ this.serialize(frag);
303
+ this.queue.push(new TypstToken(TypstTokenType.LITERAL, '$'));
304
+ }
305
+ this.queue.push(new TypstToken(TypstTokenType.LITERAL, ']'));
306
+
310
307
  break;
311
308
  }
312
309
  default:
@@ -315,15 +312,16 @@ export class TypstWriter {
315
312
  }
316
313
 
317
314
  private appendWithBracketsIfNeeded(node: TypstNode): boolean {
318
- let need_to_wrap = ['group', 'supsub', 'align', 'fraction','empty'].includes(node.type);
315
+ let need_to_wrap = ['group', 'supsub', 'matrixLike', 'fraction','empty'].includes(node.type);
319
316
 
320
317
  if (node.type === 'group') {
321
- if (node.args!.length === 0) {
318
+ const group = node as TypstGroup;
319
+ if (group.items.length === 0) {
322
320
  // e.g. TeX `P_{}` converts to Typst `P_()`
323
321
  need_to_wrap = true;
324
322
  } else {
325
- const first = node.args![0];
326
- const last = node.args![node.args!.length - 1];
323
+ const first = group.items[0];
324
+ const last = group.items[group.items.length - 1];
327
325
  if (is_delimiter(first) && is_delimiter(last)) {
328
326
  need_to_wrap = false;
329
327
  }
@@ -361,9 +359,11 @@ export class TypstWriter {
361
359
 
362
360
  this.queue = this.queue.filter((token) => !token.eq(dummy_token));
363
361
 
364
- this.queue.forEach((token) => {
365
- this.writeBuffer(token)
366
- });
362
+ for(let i = 0; i < this.queue.length; i++) {
363
+ let token = this.queue[i];
364
+ let previous_token = i === 0 ? null : this.queue[i - 1];
365
+ this.writeBuffer(previous_token, token);
366
+ }
367
367
 
368
368
  this.queue = [];
369
369
  }