tex2typst 0.3.28 → 0.4.0

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 CHANGED
@@ -6,17 +6,21 @@
6
6
  * Any undocumented options may be not working at present or break in the future!
7
7
  */
8
8
  export interface Tex2TypstOptions {
9
- nonStrict?: boolean; /** default is true */
10
- preferShorthands?: boolean; /** default is true */
11
- keepSpaces?: boolean; /** default is false */
12
- fracToSlash?: boolean; /** default is true */
13
- inftyToOo?: boolean; /** default is false */
14
- optimize?: boolean; /** default is true */
15
- customTexMacros?: { [key: string]: string; };
9
+ nonStrict: boolean; /** default is true */
10
+ preferShorthands: boolean; /** default is true */
11
+ keepSpaces: boolean; /** default is false */
12
+ fracToSlash: boolean; /** default is true */
13
+ inftyToOo: boolean; /** default is false */
14
+ optimize: boolean; /** default is true */
15
+ customTexMacros: { [key: string]: string; };
16
16
  }
17
17
 
18
- export declare function tex2typst(tex: string, options?: Tex2TypstOptions): string;
19
- export declare function typst2tex(typst: string): string;
18
+ export interface Typst2TexOptions {
19
+ blockMathMode: boolean; /** default is true */
20
+ }
21
+
22
+ export declare function tex2typst(tex: string, options?: Partial<Tex2TypstOptions>): string;
23
+ export declare function typst2tex(typst: string, options?: Partial<Typst2TexOptions>): string;
20
24
 
21
25
  export declare const symbolMap: Map<string, string>;
22
26
  export declare const shorthandMap: Map<string, string>;
package/dist/index.js CHANGED
@@ -31,6 +31,8 @@ var TexToken = class _TexToken {
31
31
  return new TexTerminal(this);
32
32
  }
33
33
  static EMPTY = new _TexToken(0 /* EMPTY */, "");
34
+ static COMMAND_DISPLAYSTYLE = new _TexToken(2 /* COMMAND */, "\\displaystyle");
35
+ static COMMAND_TEXTSTYLE = new _TexToken(2 /* COMMAND */, "\\textstyle");
34
36
  };
35
37
  var TexNode = class {
36
38
  type;
@@ -1229,14 +1231,18 @@ var TypstToken = class _TypstToken {
1229
1231
  new _TypstToken(2 /* ELEMENT */, "["),
1230
1232
  new _TypstToken(2 /* ELEMENT */, "{"),
1231
1233
  new _TypstToken(2 /* ELEMENT */, "|"),
1232
- new _TypstToken(1 /* SYMBOL */, "angle.l")
1234
+ new _TypstToken(1 /* SYMBOL */, "angle.l"),
1235
+ new _TypstToken(1 /* SYMBOL */, "paren.l"),
1236
+ new _TypstToken(1 /* SYMBOL */, "brace.l")
1233
1237
  ];
1234
1238
  static RIGHT_DELIMITERS = [
1235
1239
  new _TypstToken(2 /* ELEMENT */, ")"),
1236
1240
  new _TypstToken(2 /* ELEMENT */, "]"),
1237
1241
  new _TypstToken(2 /* ELEMENT */, "}"),
1238
1242
  new _TypstToken(2 /* ELEMENT */, "|"),
1239
- new _TypstToken(1 /* SYMBOL */, "angle.r")
1243
+ new _TypstToken(1 /* SYMBOL */, "angle.r"),
1244
+ new _TypstToken(1 /* SYMBOL */, "paren.r"),
1245
+ new _TypstToken(1 /* SYMBOL */, "brace.r")
1240
1246
  ];
1241
1247
  };
1242
1248
  var TypstWriterError = class extends Error {
@@ -1655,6 +1661,7 @@ var TypstWriter = class {
1655
1661
  // src/map.ts
1656
1662
  var symbolMap = /* @__PURE__ */ new Map([
1657
1663
  ["displaystyle", "display"],
1664
+ ["textstyle", "inline"],
1658
1665
  ["hspace", "#h"],
1659
1666
  ["|", "bar.v.double"],
1660
1667
  [",", "thin"],
@@ -2909,7 +2916,7 @@ function appendWithBracketsIfNeeded(node) {
2909
2916
  return node;
2910
2917
  }
2911
2918
  }
2912
- function convert_tex_node_to_typst(abstractNode, options = {}) {
2919
+ function convert_tex_node_to_typst(abstractNode, options) {
2913
2920
  switch (abstractNode.type) {
2914
2921
  case "terminal": {
2915
2922
  const node2 = abstractNode;
@@ -3221,7 +3228,8 @@ function typst_token_to_tex(token) {
3221
3228
  }
3222
3229
  }
3223
3230
  var TEX_NODE_COMMA = new TexToken(1 /* ELEMENT */, ",").toNode();
3224
- function convert_typst_node_to_tex(abstractNode) {
3231
+ function convert_typst_node_to_tex(abstractNode, options) {
3232
+ const convert_node = (node) => convert_typst_node_to_tex(node, options);
3225
3233
  switch (abstractNode.type) {
3226
3234
  case "terminal": {
3227
3235
  const node = abstractNode;
@@ -3254,7 +3262,7 @@ function convert_typst_node_to_tex(abstractNode) {
3254
3262
  }
3255
3263
  case "group": {
3256
3264
  const node = abstractNode;
3257
- const args = node.items.map(convert_typst_node_to_tex);
3265
+ const args = node.items.map(convert_node);
3258
3266
  const alignment_char = new TexToken(7 /* CONTROL */, "&").toNode();
3259
3267
  const newline_char = new TexToken(7 /* CONTROL */, "\\\\").toNode();
3260
3268
  if (array_includes(args, alignment_char)) {
@@ -3270,7 +3278,7 @@ function convert_typst_node_to_tex(abstractNode) {
3270
3278
  }
3271
3279
  case "leftright": {
3272
3280
  const node = abstractNode;
3273
- const body = convert_typst_node_to_tex(node.body);
3281
+ const body = convert_node(node.body);
3274
3282
  let left = node.left ? typst_token_to_tex(node.left) : new TexToken(1 /* ELEMENT */, ".");
3275
3283
  let right = node.right ? typst_token_to_tex(node.right) : new TexToken(1 /* ELEMENT */, ".");
3276
3284
  if (node.isOverHigh()) {
@@ -3287,7 +3295,7 @@ function convert_typst_node_to_tex(abstractNode) {
3287
3295
  // `\left\| a + \frac{1}{3} \right\|` <- `norm(a + 1/3)`
3288
3296
  case "norm": {
3289
3297
  const arg0 = node.args[0];
3290
- const body = convert_typst_node_to_tex(arg0);
3298
+ const body = convert_node(arg0);
3291
3299
  if (node.isOverHigh()) {
3292
3300
  return new TexLeftRight({
3293
3301
  body,
@@ -3308,7 +3316,7 @@ function convert_typst_node_to_tex(abstractNode) {
3308
3316
  const left = "\\l" + node.head.value;
3309
3317
  const right = "\\r" + node.head.value;
3310
3318
  const arg0 = node.args[0];
3311
- const body = convert_typst_node_to_tex(arg0);
3319
+ const body = convert_node(arg0);
3312
3320
  const left_node = new TexToken(2 /* COMMAND */, left);
3313
3321
  const right_node = new TexToken(2 /* COMMAND */, right);
3314
3322
  if (node.isOverHigh()) {
@@ -3324,22 +3332,22 @@ function convert_typst_node_to_tex(abstractNode) {
3324
3332
  // special hook for root
3325
3333
  case "root": {
3326
3334
  const [degree, radicand] = node.args;
3327
- const data = convert_typst_node_to_tex(degree);
3328
- return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\sqrt"), [convert_typst_node_to_tex(radicand)], data);
3335
+ const data = convert_node(degree);
3336
+ return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\sqrt"), [convert_node(radicand)], data);
3329
3337
  }
3330
3338
  // special hook for overbrace and underbrace
3331
3339
  case "overbrace":
3332
3340
  case "underbrace": {
3333
3341
  const [body, label] = node.args;
3334
- const base = new TexFuncCall(typst_token_to_tex(node.head), [convert_typst_node_to_tex(body)]);
3335
- const script = convert_typst_node_to_tex(label);
3342
+ const base = new TexFuncCall(typst_token_to_tex(node.head), [convert_node(body)]);
3343
+ const script = convert_node(label);
3336
3344
  const data = node.head.value === "overbrace" ? { base, sup: script, sub: null } : { base, sub: script, sup: null };
3337
3345
  return new TexSupSub(data);
3338
3346
  }
3339
3347
  // special hook for vec
3340
3348
  // "vec(a, b, c)" -> "\begin{pmatrix}a\\ b\\ c\end{pmatrix}"
3341
3349
  case "vec": {
3342
- const tex_matrix = node.args.map(convert_typst_node_to_tex).map((n) => [n]);
3350
+ const tex_matrix = node.args.map((arg) => [convert_node(arg)]);
3343
3351
  return new TexBeginEnd(new TexToken(3 /* LITERAL */, "pmatrix"), tex_matrix);
3344
3352
  }
3345
3353
  // special hook for op
@@ -3370,20 +3378,46 @@ function convert_typst_node_to_tex(abstractNode) {
3370
3378
  }
3371
3379
  return new TexFuncCall(
3372
3380
  new TexToken(2 /* COMMAND */, command),
3373
- [convert_typst_node_to_tex(node.args[1])]
3381
+ [convert_node(node.args[1])]
3374
3382
  );
3375
3383
  }
3384
+ // display(...) -> \displaystyle ... \textstyle
3385
+ // The postprocessor will remove \textstyle if it is the end of the math code
3386
+ case "display": {
3387
+ const arg0 = node.args[0];
3388
+ const group = new TexGroup([
3389
+ TexToken.COMMAND_DISPLAYSTYLE.toNode(),
3390
+ convert_node(arg0)
3391
+ ]);
3392
+ if (!options.blockMathMode) {
3393
+ group.items.push(TexToken.COMMAND_TEXTSTYLE.toNode());
3394
+ }
3395
+ return group;
3396
+ }
3397
+ // inline(...) -> \textstyle ... \displaystyle
3398
+ // The postprocessor will remove \displaystyle if it is the end of the math code
3399
+ case "inline": {
3400
+ const arg0 = node.args[0];
3401
+ const group = new TexGroup([
3402
+ TexToken.COMMAND_TEXTSTYLE.toNode(),
3403
+ convert_node(arg0)
3404
+ ]);
3405
+ if (options.blockMathMode) {
3406
+ group.items.push(TexToken.COMMAND_DISPLAYSTYLE.toNode());
3407
+ }
3408
+ return group;
3409
+ }
3376
3410
  // general case
3377
3411
  default: {
3378
3412
  const func_name_tex = typst_token_to_tex(node.head);
3379
3413
  const is_known_func = TEX_UNARY_COMMANDS.includes(func_name_tex.value.substring(1)) || TEX_BINARY_COMMANDS.includes(func_name_tex.value.substring(1));
3380
3414
  if (func_name_tex.value.length > 0 && is_known_func) {
3381
- return new TexFuncCall(func_name_tex, node.args.map(convert_typst_node_to_tex));
3415
+ return new TexFuncCall(func_name_tex, node.args.map(convert_node));
3382
3416
  } else {
3383
3417
  return new TexGroup([
3384
3418
  typst_token_to_tex(node.head).toNode(),
3385
3419
  new TexToken(1 /* ELEMENT */, "(").toNode(),
3386
- ...array_intersperse(node.args.map(convert_typst_node_to_tex), TEX_NODE_COMMA),
3420
+ ...array_intersperse(node.args.map(convert_node), TEX_NODE_COMMA),
3387
3421
  new TexToken(1 /* ELEMENT */, ")").toNode()
3388
3422
  ]);
3389
3423
  }
@@ -3398,7 +3432,7 @@ function convert_typst_node_to_tex(abstractNode) {
3398
3432
  const color = node.options["fill"];
3399
3433
  return new TexFuncCall(
3400
3434
  new TexToken(2 /* COMMAND */, "\\textcolor"),
3401
- [convert_typst_node_to_tex(color), convert_typst_node_to_tex(node.fragments[0])]
3435
+ [convert_node(color), convert_node(node.fragments[0])]
3402
3436
  );
3403
3437
  }
3404
3438
  }
@@ -3410,11 +3444,11 @@ function convert_typst_node_to_tex(abstractNode) {
3410
3444
  case "supsub": {
3411
3445
  const node = abstractNode;
3412
3446
  const { base, sup, sub } = node;
3413
- const sup_tex = sup ? convert_typst_node_to_tex(sup) : null;
3414
- const sub_tex = sub ? convert_typst_node_to_tex(sub) : null;
3447
+ const sup_tex = sup ? convert_node(sup) : null;
3448
+ const sub_tex = sub ? convert_node(sub) : null;
3415
3449
  if (base.head.eq(new TypstToken(1 /* SYMBOL */, "limits"))) {
3416
3450
  const limits = base;
3417
- const body_in_limits = convert_typst_node_to_tex(limits.args[0]);
3451
+ const body_in_limits = convert_node(limits.args[0]);
3418
3452
  if (sup_tex !== null && sub_tex === null) {
3419
3453
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\overset"), [sup_tex, body_in_limits]);
3420
3454
  } else if (sup_tex === null && sub_tex !== null) {
@@ -3424,7 +3458,7 @@ function convert_typst_node_to_tex(abstractNode) {
3424
3458
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\overset"), [sup_tex, underset_call]);
3425
3459
  }
3426
3460
  }
3427
- const base_tex = convert_typst_node_to_tex(base);
3461
+ const base_tex = convert_node(base);
3428
3462
  const res = new TexSupSub({
3429
3463
  base: base_tex,
3430
3464
  sup: sup_tex,
@@ -3434,7 +3468,7 @@ function convert_typst_node_to_tex(abstractNode) {
3434
3468
  }
3435
3469
  case "matrixLike": {
3436
3470
  const node = abstractNode;
3437
- const tex_matrix = node.matrix.map((row) => row.map(convert_typst_node_to_tex));
3471
+ const tex_matrix = node.matrix.map((row) => row.map(convert_node));
3438
3472
  if (node.head.eq(TypstMatrixLike.MAT)) {
3439
3473
  let env_type = "pmatrix";
3440
3474
  if (node.options) {
@@ -3481,8 +3515,8 @@ function convert_typst_node_to_tex(abstractNode) {
3481
3515
  case "fraction": {
3482
3516
  const node = abstractNode;
3483
3517
  const [numerator, denominator] = node.args;
3484
- const num_tex = convert_typst_node_to_tex(numerator);
3485
- const den_tex = convert_typst_node_to_tex(denominator);
3518
+ const num_tex = convert_node(numerator);
3519
+ const den_tex = convert_node(denominator);
3486
3520
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\frac"), [num_tex, den_tex]);
3487
3521
  }
3488
3522
  default:
@@ -3989,6 +4023,14 @@ var TexWriter = class {
3989
4023
  this.queue = this.queue.concat(node.serialize());
3990
4024
  }
3991
4025
  flushQueue() {
4026
+ while (this.queue.length > 0) {
4027
+ const last_token = this.queue[this.queue.length - 1];
4028
+ if (last_token.eq(TexToken.COMMAND_DISPLAYSTYLE) || last_token.eq(TexToken.COMMAND_TEXTSTYLE)) {
4029
+ this.queue.pop();
4030
+ } else {
4031
+ break;
4032
+ }
4033
+ }
3992
4034
  for (let i = 0; i < this.queue.length; i++) {
3993
4035
  this.buffer = writeTexTokenBuffer(this.buffer, this.queue[i]);
3994
4036
  }
@@ -4001,7 +4043,7 @@ var TexWriter = class {
4001
4043
  };
4002
4044
 
4003
4045
  // src/index.ts
4004
- function tex2typst(tex, options) {
4046
+ function tex2typst(tex, options = {}) {
4005
4047
  const opt = {
4006
4048
  nonStrict: true,
4007
4049
  preferShorthands: true,
@@ -4011,14 +4053,12 @@ function tex2typst(tex, options) {
4011
4053
  optimize: true,
4012
4054
  customTexMacros: {}
4013
4055
  };
4014
- if (options !== void 0) {
4015
- if (typeof options !== "object") {
4016
- throw new Error("options must be an object");
4017
- }
4018
- for (const key in opt) {
4019
- if (key in options) {
4020
- opt[key] = options[key];
4021
- }
4056
+ if (typeof options !== "object") {
4057
+ throw new Error("options must be an object");
4058
+ }
4059
+ for (const key in opt) {
4060
+ if (key in options) {
4061
+ opt[key] = options[key];
4022
4062
  }
4023
4063
  }
4024
4064
  const texTree = parseTex(tex, opt.customTexMacros);
@@ -4027,9 +4067,20 @@ function tex2typst(tex, options) {
4027
4067
  writer.serialize(typstTree);
4028
4068
  return writer.finalize();
4029
4069
  }
4030
- function typst2tex(typst) {
4070
+ function typst2tex(typst, options = {}) {
4071
+ const opt = {
4072
+ blockMathMode: true
4073
+ };
4074
+ if (typeof options !== "object") {
4075
+ throw new Error("options must be an object");
4076
+ }
4077
+ for (const key in opt) {
4078
+ if (key in options) {
4079
+ opt[key] = options[key];
4080
+ }
4081
+ }
4031
4082
  const typstTree = parseTypst(typst);
4032
- const texTree = convert_typst_node_to_tex(typstTree);
4083
+ const texTree = convert_typst_node_to_tex(typstTree, opt);
4033
4084
  const writer = new TexWriter();
4034
4085
  writer.append(texTree);
4035
4086
  return writer.finalize();