tex2typst 0.3.29 → 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;
@@ -1659,6 +1661,7 @@ var TypstWriter = class {
1659
1661
  // src/map.ts
1660
1662
  var symbolMap = /* @__PURE__ */ new Map([
1661
1663
  ["displaystyle", "display"],
1664
+ ["textstyle", "inline"],
1662
1665
  ["hspace", "#h"],
1663
1666
  ["|", "bar.v.double"],
1664
1667
  [",", "thin"],
@@ -2913,7 +2916,7 @@ function appendWithBracketsIfNeeded(node) {
2913
2916
  return node;
2914
2917
  }
2915
2918
  }
2916
- function convert_tex_node_to_typst(abstractNode, options = {}) {
2919
+ function convert_tex_node_to_typst(abstractNode, options) {
2917
2920
  switch (abstractNode.type) {
2918
2921
  case "terminal": {
2919
2922
  const node2 = abstractNode;
@@ -3225,7 +3228,8 @@ function typst_token_to_tex(token) {
3225
3228
  }
3226
3229
  }
3227
3230
  var TEX_NODE_COMMA = new TexToken(1 /* ELEMENT */, ",").toNode();
3228
- 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);
3229
3233
  switch (abstractNode.type) {
3230
3234
  case "terminal": {
3231
3235
  const node = abstractNode;
@@ -3258,7 +3262,7 @@ function convert_typst_node_to_tex(abstractNode) {
3258
3262
  }
3259
3263
  case "group": {
3260
3264
  const node = abstractNode;
3261
- const args = node.items.map(convert_typst_node_to_tex);
3265
+ const args = node.items.map(convert_node);
3262
3266
  const alignment_char = new TexToken(7 /* CONTROL */, "&").toNode();
3263
3267
  const newline_char = new TexToken(7 /* CONTROL */, "\\\\").toNode();
3264
3268
  if (array_includes(args, alignment_char)) {
@@ -3274,7 +3278,7 @@ function convert_typst_node_to_tex(abstractNode) {
3274
3278
  }
3275
3279
  case "leftright": {
3276
3280
  const node = abstractNode;
3277
- const body = convert_typst_node_to_tex(node.body);
3281
+ const body = convert_node(node.body);
3278
3282
  let left = node.left ? typst_token_to_tex(node.left) : new TexToken(1 /* ELEMENT */, ".");
3279
3283
  let right = node.right ? typst_token_to_tex(node.right) : new TexToken(1 /* ELEMENT */, ".");
3280
3284
  if (node.isOverHigh()) {
@@ -3291,7 +3295,7 @@ function convert_typst_node_to_tex(abstractNode) {
3291
3295
  // `\left\| a + \frac{1}{3} \right\|` <- `norm(a + 1/3)`
3292
3296
  case "norm": {
3293
3297
  const arg0 = node.args[0];
3294
- const body = convert_typst_node_to_tex(arg0);
3298
+ const body = convert_node(arg0);
3295
3299
  if (node.isOverHigh()) {
3296
3300
  return new TexLeftRight({
3297
3301
  body,
@@ -3312,7 +3316,7 @@ function convert_typst_node_to_tex(abstractNode) {
3312
3316
  const left = "\\l" + node.head.value;
3313
3317
  const right = "\\r" + node.head.value;
3314
3318
  const arg0 = node.args[0];
3315
- const body = convert_typst_node_to_tex(arg0);
3319
+ const body = convert_node(arg0);
3316
3320
  const left_node = new TexToken(2 /* COMMAND */, left);
3317
3321
  const right_node = new TexToken(2 /* COMMAND */, right);
3318
3322
  if (node.isOverHigh()) {
@@ -3328,22 +3332,22 @@ function convert_typst_node_to_tex(abstractNode) {
3328
3332
  // special hook for root
3329
3333
  case "root": {
3330
3334
  const [degree, radicand] = node.args;
3331
- const data = convert_typst_node_to_tex(degree);
3332
- 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);
3333
3337
  }
3334
3338
  // special hook for overbrace and underbrace
3335
3339
  case "overbrace":
3336
3340
  case "underbrace": {
3337
3341
  const [body, label] = node.args;
3338
- const base = new TexFuncCall(typst_token_to_tex(node.head), [convert_typst_node_to_tex(body)]);
3339
- 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);
3340
3344
  const data = node.head.value === "overbrace" ? { base, sup: script, sub: null } : { base, sub: script, sup: null };
3341
3345
  return new TexSupSub(data);
3342
3346
  }
3343
3347
  // special hook for vec
3344
3348
  // "vec(a, b, c)" -> "\begin{pmatrix}a\\ b\\ c\end{pmatrix}"
3345
3349
  case "vec": {
3346
- 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)]);
3347
3351
  return new TexBeginEnd(new TexToken(3 /* LITERAL */, "pmatrix"), tex_matrix);
3348
3352
  }
3349
3353
  // special hook for op
@@ -3374,20 +3378,46 @@ function convert_typst_node_to_tex(abstractNode) {
3374
3378
  }
3375
3379
  return new TexFuncCall(
3376
3380
  new TexToken(2 /* COMMAND */, command),
3377
- [convert_typst_node_to_tex(node.args[1])]
3381
+ [convert_node(node.args[1])]
3378
3382
  );
3379
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
+ }
3380
3410
  // general case
3381
3411
  default: {
3382
3412
  const func_name_tex = typst_token_to_tex(node.head);
3383
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));
3384
3414
  if (func_name_tex.value.length > 0 && is_known_func) {
3385
- 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));
3386
3416
  } else {
3387
3417
  return new TexGroup([
3388
3418
  typst_token_to_tex(node.head).toNode(),
3389
3419
  new TexToken(1 /* ELEMENT */, "(").toNode(),
3390
- ...array_intersperse(node.args.map(convert_typst_node_to_tex), TEX_NODE_COMMA),
3420
+ ...array_intersperse(node.args.map(convert_node), TEX_NODE_COMMA),
3391
3421
  new TexToken(1 /* ELEMENT */, ")").toNode()
3392
3422
  ]);
3393
3423
  }
@@ -3402,7 +3432,7 @@ function convert_typst_node_to_tex(abstractNode) {
3402
3432
  const color = node.options["fill"];
3403
3433
  return new TexFuncCall(
3404
3434
  new TexToken(2 /* COMMAND */, "\\textcolor"),
3405
- [convert_typst_node_to_tex(color), convert_typst_node_to_tex(node.fragments[0])]
3435
+ [convert_node(color), convert_node(node.fragments[0])]
3406
3436
  );
3407
3437
  }
3408
3438
  }
@@ -3414,11 +3444,11 @@ function convert_typst_node_to_tex(abstractNode) {
3414
3444
  case "supsub": {
3415
3445
  const node = abstractNode;
3416
3446
  const { base, sup, sub } = node;
3417
- const sup_tex = sup ? convert_typst_node_to_tex(sup) : null;
3418
- 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;
3419
3449
  if (base.head.eq(new TypstToken(1 /* SYMBOL */, "limits"))) {
3420
3450
  const limits = base;
3421
- const body_in_limits = convert_typst_node_to_tex(limits.args[0]);
3451
+ const body_in_limits = convert_node(limits.args[0]);
3422
3452
  if (sup_tex !== null && sub_tex === null) {
3423
3453
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\overset"), [sup_tex, body_in_limits]);
3424
3454
  } else if (sup_tex === null && sub_tex !== null) {
@@ -3428,7 +3458,7 @@ function convert_typst_node_to_tex(abstractNode) {
3428
3458
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\overset"), [sup_tex, underset_call]);
3429
3459
  }
3430
3460
  }
3431
- const base_tex = convert_typst_node_to_tex(base);
3461
+ const base_tex = convert_node(base);
3432
3462
  const res = new TexSupSub({
3433
3463
  base: base_tex,
3434
3464
  sup: sup_tex,
@@ -3438,7 +3468,7 @@ function convert_typst_node_to_tex(abstractNode) {
3438
3468
  }
3439
3469
  case "matrixLike": {
3440
3470
  const node = abstractNode;
3441
- 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));
3442
3472
  if (node.head.eq(TypstMatrixLike.MAT)) {
3443
3473
  let env_type = "pmatrix";
3444
3474
  if (node.options) {
@@ -3485,8 +3515,8 @@ function convert_typst_node_to_tex(abstractNode) {
3485
3515
  case "fraction": {
3486
3516
  const node = abstractNode;
3487
3517
  const [numerator, denominator] = node.args;
3488
- const num_tex = convert_typst_node_to_tex(numerator);
3489
- const den_tex = convert_typst_node_to_tex(denominator);
3518
+ const num_tex = convert_node(numerator);
3519
+ const den_tex = convert_node(denominator);
3490
3520
  return new TexFuncCall(new TexToken(2 /* COMMAND */, "\\frac"), [num_tex, den_tex]);
3491
3521
  }
3492
3522
  default:
@@ -3993,6 +4023,14 @@ var TexWriter = class {
3993
4023
  this.queue = this.queue.concat(node.serialize());
3994
4024
  }
3995
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
+ }
3996
4034
  for (let i = 0; i < this.queue.length; i++) {
3997
4035
  this.buffer = writeTexTokenBuffer(this.buffer, this.queue[i]);
3998
4036
  }
@@ -4005,7 +4043,7 @@ var TexWriter = class {
4005
4043
  };
4006
4044
 
4007
4045
  // src/index.ts
4008
- function tex2typst(tex, options) {
4046
+ function tex2typst(tex, options = {}) {
4009
4047
  const opt = {
4010
4048
  nonStrict: true,
4011
4049
  preferShorthands: true,
@@ -4015,14 +4053,12 @@ function tex2typst(tex, options) {
4015
4053
  optimize: true,
4016
4054
  customTexMacros: {}
4017
4055
  };
4018
- if (options !== void 0) {
4019
- if (typeof options !== "object") {
4020
- throw new Error("options must be an object");
4021
- }
4022
- for (const key in opt) {
4023
- if (key in options) {
4024
- opt[key] = options[key];
4025
- }
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];
4026
4062
  }
4027
4063
  }
4028
4064
  const texTree = parseTex(tex, opt.customTexMacros);
@@ -4031,9 +4067,20 @@ function tex2typst(tex, options) {
4031
4067
  writer.serialize(typstTree);
4032
4068
  return writer.finalize();
4033
4069
  }
4034
- 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
+ }
4035
4082
  const typstTree = parseTypst(typst);
4036
- const texTree = convert_typst_node_to_tex(typstTree);
4083
+ const texTree = convert_typst_node_to_tex(typstTree, opt);
4037
4084
  const writer = new TexWriter();
4038
4085
  writer.append(texTree);
4039
4086
  return writer.finalize();