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/src/convert.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { TexNode, TexToken, TexTokenType, TexFuncCall, TexGroup, TexSupSub,
2
2
  TexText, TexBeginEnd, TexLeftRight, TexTerminal} from "./tex-types";
3
- import type { Tex2TypstOptions } from "./exposed-types";
3
+ import type { Tex2TypstOptions, Typst2TexOptions } from "./exposed-types";
4
4
  import { TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstMarkupFunc, TypstMatrixLike, TypstNode, TypstSupsub, TypstTerminal } from "./typst-types";
5
5
  import { TypstNamedParams } from "./typst-types";
6
6
  import { TypstSupsubData } from "./typst-types";
@@ -224,7 +224,7 @@ function appendWithBracketsIfNeeded(node: TypstNode): TypstNode {
224
224
  }
225
225
  }
226
226
 
227
- export function convert_tex_node_to_typst(abstractNode: TexNode, options: Tex2TypstOptions = {}): TypstNode {
227
+ export function convert_tex_node_to_typst(abstractNode: TexNode, options: Tex2TypstOptions): TypstNode {
228
228
  switch (abstractNode.type) {
229
229
  case 'terminal': {
230
230
  const node = abstractNode as TexTerminal;
@@ -637,7 +637,9 @@ function typst_token_to_tex(token: TypstToken): TexToken {
637
637
 
638
638
  const TEX_NODE_COMMA = new TexToken(TexTokenType.ELEMENT, ',').toNode();
639
639
 
640
- export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
640
+ export function convert_typst_node_to_tex(abstractNode: TypstNode, options: Typst2TexOptions): TexNode {
641
+ const convert_node = (node: TypstNode) => convert_typst_node_to_tex(node, options);
642
+
641
643
  switch (abstractNode.type) {
642
644
  case 'terminal': {
643
645
  const node = abstractNode as TypstTerminal;
@@ -676,7 +678,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
676
678
 
677
679
  case 'group': {
678
680
  const node = abstractNode as TypstGroup;
679
- const args = node.items.map(convert_typst_node_to_tex);
681
+ const args = node.items.map(convert_node);
680
682
  const alignment_char = new TexToken(TexTokenType.CONTROL, '&').toNode();
681
683
  const newline_char = new TexToken(TexTokenType.CONTROL, '\\\\').toNode();
682
684
  if (array_includes(args, alignment_char)) {
@@ -693,7 +695,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
693
695
  }
694
696
  case 'leftright': {
695
697
  const node = abstractNode as TypstLeftright;
696
- const body = convert_typst_node_to_tex(node.body);
698
+ const body = convert_node(node.body);
697
699
  let left = node.left? typst_token_to_tex(node.left) : new TexToken(TexTokenType.ELEMENT, '.');
698
700
  let right = node.right? typst_token_to_tex(node.right) : new TexToken(TexTokenType.ELEMENT, '.');
699
701
  // const is_over_high = node.isOverHigh();
@@ -715,7 +717,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
715
717
  // `\left\| a + \frac{1}{3} \right\|` <- `norm(a + 1/3)`
716
718
  case 'norm': {
717
719
  const arg0 = node.args[0];
718
- const body = convert_typst_node_to_tex(arg0);
720
+ const body = convert_node(arg0);
719
721
  if (node.isOverHigh()) {
720
722
  return new TexLeftRight({
721
723
  body: body,
@@ -736,7 +738,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
736
738
  const left = "\\l" + node.head.value;
737
739
  const right = "\\r" + node.head.value;
738
740
  const arg0 = node.args[0];
739
- const body = convert_typst_node_to_tex(arg0);
741
+ const body = convert_node(arg0);
740
742
  const left_node = new TexToken(TexTokenType.COMMAND, left);
741
743
  const right_node = new TexToken(TexTokenType.COMMAND, right);
742
744
  if (node.isOverHigh()) {
@@ -752,22 +754,22 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
752
754
  // special hook for root
753
755
  case 'root': {
754
756
  const [degree, radicand] = node.args;
755
- const data = convert_typst_node_to_tex(degree);
756
- return new TexFuncCall(new TexToken(TexTokenType.COMMAND, '\\sqrt'), [convert_typst_node_to_tex(radicand)], data);
757
+ const data = convert_node(degree);
758
+ return new TexFuncCall(new TexToken(TexTokenType.COMMAND, '\\sqrt'), [convert_node(radicand)], data);
757
759
  }
758
760
  // special hook for overbrace and underbrace
759
761
  case 'overbrace':
760
762
  case 'underbrace': {
761
763
  const [body, label] = node.args;
762
- const base = new TexFuncCall(typst_token_to_tex(node.head), [convert_typst_node_to_tex(body)]);
763
- const script = convert_typst_node_to_tex(label);
764
+ const base = new TexFuncCall(typst_token_to_tex(node.head), [convert_node(body)]);
765
+ const script = convert_node(label);
764
766
  const data = node.head.value === 'overbrace' ? { base, sup: script, sub: null } : { base, sub: script, sup: null };
765
767
  return new TexSupSub(data);
766
768
  }
767
769
  // special hook for vec
768
770
  // "vec(a, b, c)" -> "\begin{pmatrix}a\\ b\\ c\end{pmatrix}"
769
771
  case 'vec': {
770
- const tex_matrix = node.args.map(convert_typst_node_to_tex).map((n) => [n]);
772
+ const tex_matrix = node.args.map(arg => [convert_node(arg)]);
771
773
  return new TexBeginEnd(new TexToken(TexTokenType.LITERAL, 'pmatrix'), tex_matrix);
772
774
  }
773
775
  // special hook for op
@@ -798,21 +800,47 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
798
800
  }
799
801
  return new TexFuncCall(
800
802
  new TexToken(TexTokenType.COMMAND, command),
801
- [convert_typst_node_to_tex(node.args[1])]
803
+ [convert_node(node.args[1])]
802
804
  );
803
805
  }
806
+ // display(...) -> \displaystyle ... \textstyle
807
+ // The postprocessor will remove \textstyle if it is the end of the math code
808
+ case 'display': {
809
+ const arg0 = node.args[0];
810
+ const group = new TexGroup([
811
+ TexToken.COMMAND_DISPLAYSTYLE.toNode(),
812
+ convert_node(arg0),
813
+ ]);
814
+ if (!options.blockMathMode) {
815
+ group.items.push(TexToken.COMMAND_TEXTSTYLE.toNode());
816
+ }
817
+ return group;
818
+ }
819
+ // inline(...) -> \textstyle ... \displaystyle
820
+ // The postprocessor will remove \displaystyle if it is the end of the math code
821
+ case 'inline': {
822
+ const arg0 = node.args[0];
823
+ const group = new TexGroup([
824
+ TexToken.COMMAND_TEXTSTYLE.toNode(),
825
+ convert_node(arg0),
826
+ ]);
827
+ if (options.blockMathMode) {
828
+ group.items.push(TexToken.COMMAND_DISPLAYSTYLE.toNode());
829
+ }
830
+ return group;
831
+ }
804
832
  // general case
805
833
  default: {
806
834
  const func_name_tex = typst_token_to_tex(node.head);
807
835
  const is_known_func = TEX_UNARY_COMMANDS.includes(func_name_tex.value.substring(1))
808
836
  || TEX_BINARY_COMMANDS.includes(func_name_tex.value.substring(1));
809
837
  if (func_name_tex.value.length > 0 && is_known_func) {
810
- return new TexFuncCall(func_name_tex, node.args.map(convert_typst_node_to_tex));
838
+ return new TexFuncCall(func_name_tex, node.args.map(convert_node));
811
839
  } else {
812
840
  return new TexGroup([
813
841
  typst_token_to_tex(node.head).toNode(),
814
842
  new TexToken(TexTokenType.ELEMENT, '(').toNode(),
815
- ...array_intersperse(node.args.map(convert_typst_node_to_tex), TEX_NODE_COMMA),
843
+ ...array_intersperse(node.args.map(convert_node), TEX_NODE_COMMA),
816
844
  new TexToken(TexTokenType.ELEMENT, ')').toNode()
817
845
  ]);
818
846
  }
@@ -828,7 +856,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
828
856
  const color = node.options['fill'];
829
857
  return new TexFuncCall(
830
858
  new TexToken(TexTokenType.COMMAND, '\\textcolor'),
831
- [convert_typst_node_to_tex(color), convert_typst_node_to_tex(node.fragments[0])]
859
+ [convert_node(color), convert_node(node.fragments[0])]
832
860
  )
833
861
  }
834
862
  }
@@ -840,8 +868,8 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
840
868
  case 'supsub': {
841
869
  const node = abstractNode as TypstSupsub;
842
870
  const { base, sup, sub } = node;
843
- const sup_tex = sup? convert_typst_node_to_tex(sup) : null;
844
- const sub_tex = sub? convert_typst_node_to_tex(sub) : null;
871
+ const sup_tex = sup? convert_node(sup) : null;
872
+ const sub_tex = sub? convert_node(sub) : null;
845
873
 
846
874
  // special hook for limits
847
875
  // `limits(+)^a` -> `\overset{a}{+}`
@@ -849,7 +877,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
849
877
  // `limits(+)_a^b` -> `\overset{b}{\underset{a}{+}}`
850
878
  if (base.head.eq(new TypstToken(TypstTokenType.SYMBOL, 'limits'))) {
851
879
  const limits = base as TypstFuncCall;
852
- const body_in_limits = convert_typst_node_to_tex(limits.args[0]);
880
+ const body_in_limits = convert_node(limits.args[0]);
853
881
  if (sup_tex !== null && sub_tex === null) {
854
882
  return new TexFuncCall(new TexToken(TexTokenType.COMMAND, '\\overset'), [sup_tex, body_in_limits]);
855
883
  } else if (sup_tex === null && sub_tex !== null) {
@@ -860,7 +888,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
860
888
  }
861
889
  }
862
890
 
863
- const base_tex = convert_typst_node_to_tex(base);
891
+ const base_tex = convert_node(base);
864
892
 
865
893
  const res = new TexSupSub({
866
894
  base: base_tex,
@@ -871,7 +899,7 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
871
899
  }
872
900
  case 'matrixLike': {
873
901
  const node = abstractNode as TypstMatrixLike;
874
- const tex_matrix = node.matrix.map(row => row.map(convert_typst_node_to_tex));
902
+ const tex_matrix = node.matrix.map(row => row.map(convert_node));
875
903
  if (node.head.eq(TypstMatrixLike.MAT)) {
876
904
  let env_type = 'pmatrix'; // typst mat use delim:"(" by default
877
905
  if (node.options) {
@@ -918,8 +946,8 @@ export function convert_typst_node_to_tex(abstractNode: TypstNode): TexNode {
918
946
  case 'fraction': {
919
947
  const node = abstractNode as TypstFraction;
920
948
  const [numerator, denominator] = node.args;
921
- const num_tex = convert_typst_node_to_tex(numerator);
922
- const den_tex = convert_typst_node_to_tex(denominator);
949
+ const num_tex = convert_node(numerator);
950
+ const den_tex = convert_node(denominator);
923
951
  return new TexFuncCall(new TexToken(TexTokenType.COMMAND, '\\frac'), [num_tex, den_tex]);
924
952
  }
925
953
  default:
@@ -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/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parseTex } from "./tex-parser";
2
- import type { Tex2TypstOptions } from "./exposed-types";
2
+ import type { Tex2TypstOptions, Typst2TexOptions } from "./exposed-types";
3
3
  import { TypstWriter } from "./typst-writer";
4
4
  import { type TypstWriterOptions } from "./typst-types";
5
5
  import { convert_tex_node_to_typst, convert_typst_node_to_tex } from "./convert";
@@ -9,7 +9,7 @@ import { TexWriter } from "./tex-writer";
9
9
  import { shorthandMap } from "./typst-shorthands";
10
10
 
11
11
 
12
- export function tex2typst(tex: string, options?: Tex2TypstOptions): string {
12
+ export function tex2typst(tex: string, options: Partial<Tex2TypstOptions> = {}): string {
13
13
  const opt: Tex2TypstOptions = {
14
14
  nonStrict: true,
15
15
  preferShorthands: true,
@@ -20,14 +20,12 @@ export function tex2typst(tex: string, options?: Tex2TypstOptions): string {
20
20
  customTexMacros: {}
21
21
  };
22
22
 
23
- if(options !== undefined) {
24
- if (typeof options !== 'object') {
25
- throw new Error("options must be an object");
26
- }
27
- for (const key in opt) {
28
- if (key in options) {
29
- opt[key as keyof Tex2TypstOptions] = options[key as keyof Tex2TypstOptions] as any;
30
- }
23
+ if (typeof options !== 'object') {
24
+ throw new Error("options must be an object");
25
+ }
26
+ for (const key in opt) {
27
+ if (key in options) {
28
+ opt[key as keyof Tex2TypstOptions] = options[key as keyof Tex2TypstOptions] as any;
31
29
  }
32
30
  }
33
31
 
@@ -38,9 +36,22 @@ export function tex2typst(tex: string, options?: Tex2TypstOptions): string {
38
36
  return writer.finalize();
39
37
  }
40
38
 
41
- export function typst2tex(typst: string): string {
39
+ export function typst2tex(typst: string, options: Partial<Typst2TexOptions> = {}): string {
40
+ const opt: Typst2TexOptions = {
41
+ blockMathMode: true,
42
+ };
43
+
44
+ if (typeof options !== 'object') {
45
+ throw new Error("options must be an object");
46
+ }
47
+ for (const key in opt) {
48
+ if (key in options) {
49
+ opt[key as keyof Typst2TexOptions] = options[key as keyof Typst2TexOptions] as any;
50
+ }
51
+ }
52
+
42
53
  const typstTree = parseTypst(typst);
43
- const texTree = convert_typst_node_to_tex(typstTree);
54
+ const texTree = convert_typst_node_to_tex(typstTree, opt);
44
55
  const writer = new TexWriter();
45
56
  writer.append(texTree);
46
57
  return writer.finalize();
package/src/map.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  const symbolMap = new Map<string, string>([
2
2
  ['displaystyle', 'display'],
3
+ ['textstyle', 'inline'],
3
4
  ['hspace', '#h'],
4
5
 
5
6
  ['|', 'bar.v.double'],
package/src/tex-types.ts CHANGED
@@ -44,6 +44,8 @@ export class TexToken {
44
44
  }
45
45
 
46
46
  public static readonly EMPTY = new TexToken(TexTokenType.EMPTY, '');
47
+ public static readonly COMMAND_DISPLAYSTYLE = new TexToken(TexTokenType.COMMAND, '\\displaystyle');
48
+ public static readonly COMMAND_TEXTSTYLE = new TexToken(TexTokenType.COMMAND, '\\textstyle');
47
49
  }
48
50
 
49
51
 
package/src/tex-writer.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { TexNode, TexToken, writeTexTokenBuffer } from "./tex-types";
1
+ import { TexNode, TexToken, TexTokenType, writeTexTokenBuffer } from "./tex-types";
2
2
 
3
3
 
4
4
 
@@ -12,6 +12,15 @@ export class TexWriter {
12
12
  }
13
13
 
14
14
  protected flushQueue() {
15
+ // remove \textstyle or \displaystyle if it is the end of the math code
16
+ while (this.queue.length > 0) {
17
+ const last_token = this.queue[this.queue.length - 1];
18
+ if (last_token.eq(TexToken.COMMAND_DISPLAYSTYLE) || last_token.eq(TexToken.COMMAND_TEXTSTYLE)) {
19
+ this.queue.pop();
20
+ } else {
21
+ break;
22
+ }
23
+ }
15
24
  for (let i = 0; i < this.queue.length; i++) {
16
25
  this.buffer = writeTexTokenBuffer(this.buffer, this.queue[i]);
17
26
  }
@@ -58,6 +58,8 @@ export class TypstToken {
58
58
  new TypstToken(TypstTokenType.ELEMENT, '{'),
59
59
  new TypstToken(TypstTokenType.ELEMENT, '|'),
60
60
  new TypstToken(TypstTokenType.SYMBOL, 'angle.l'),
61
+ new TypstToken(TypstTokenType.SYMBOL, 'paren.l'),
62
+ new TypstToken(TypstTokenType.SYMBOL, 'brace.l'),
61
63
  ];
62
64
 
63
65
  public static readonly RIGHT_DELIMITERS = [
@@ -66,6 +68,8 @@ export class TypstToken {
66
68
  new TypstToken(TypstTokenType.ELEMENT, '}'),
67
69
  new TypstToken(TypstTokenType.ELEMENT, '|'),
68
70
  new TypstToken(TypstTokenType.SYMBOL, 'angle.r'),
71
+ new TypstToken(TypstTokenType.SYMBOL, 'paren.r'),
72
+ new TypstToken(TypstTokenType.SYMBOL, 'brace.r'),
69
73
  ];
70
74
  }
71
75
 
@@ -156,6 +156,12 @@ cases:
156
156
  - title: left right angles
157
157
  tex: \left\langle \frac{1}{2} \right\rangle
158
158
  typst: lr(angle.l 1/2 angle.r)
159
+ - title: lparen rparen
160
+ tex: \left\lparen \frac{1}{3} \right\rparen
161
+ typst: lr(paren.l 1/3 paren.r)
162
+ - title: lbrace rbrace
163
+ tex: \left\lbrace \frac{1}{3} \right\rbrace
164
+ typst: lr(brace.l 1/3 brace.r)
159
165
  - title: fractions as function argument
160
166
  tex: g(\frac{1}{2})
161
167
  typst: g(1/2)
@@ -185,4 +191,13 @@ cases:
185
191
  typst: a class("binary", X) b
186
192
  - title: mathop
187
193
  tex: a \mathop{X} b
188
- typst: a class("large", X) b
194
+ typst: a class("large", X) b
195
+ - title: display style
196
+ tex: a = \displaystyle \sum_i x_i
197
+ typst: a = display(sum_i x_i)
198
+ - title: display style, case 3
199
+ tex: \displaystyle \lim_x F(x) = 0, \lim_x F(x) = 1
200
+ typst: display(lim_x F(x) = 0 comma lim_x F(x) = 1)
201
+ - title: display style, case 4
202
+ tex: \lim_x F(x) = 0, \displaystyle \lim_x F(x) = 1
203
+ typst: lim_x F(x) = 0, display(lim_x F(x) = 1)
@@ -56,12 +56,6 @@ cases:
56
56
  - title: paired delimiter commands
57
57
  tex: \left(\bigl[\biggl\{a\biggr\}\bigr]\right)
58
58
  typst: '([ {a}])'
59
- - title: lparen rparen
60
- tex: \left\lparen \frac{1}{3} \right\rparen
61
- typst: lr(paren.l 1/3 paren.r)
62
- - title: lbrace rbrace
63
- tex: \left\lbrace \frac{1}{3} \right\rbrace
64
- typst: lr(brace.l 1/3 brace.r)
65
59
  - title: operatorname
66
60
  tex: '\operatorname{diag} \text{diag}'
67
61
  typst: 'op("diag") "diag"'
@@ -412,12 +406,6 @@ cases:
412
406
  - title: Backslash space
413
407
  tex: a \ b
414
408
  typst: a med b
415
- - title: display style
416
- tex: \displaystyle \lim_{x \to -\infty} F(x) = 0, \lim_{x \to +\infty} F(x) = 1
417
- typst: display(lim_(x -> - infinity) F(x) = 0 comma lim_(x -> + infinity) F(x) = 1)
418
- - title: display style 2
419
- tex: \lim_{x \to -\infty} F(x) = 0, \displaystyle \lim_{x \to +\infty} F(x) = 1
420
- typst: lim_(x -> - infinity) F(x) = 0, display(lim_(x -> + infinity) F(x) = 1)
421
409
  # this test the typst formatter. Old bad implementation translated it to "C(x y)/z"
422
410
  - title: parenthesis in fraction
423
411
  tex: C \frac{xy}{z}
@@ -103,7 +103,7 @@ caseFiles.forEach((ymlFilename) => {
103
103
  let tex_node: null | TexNode = null;
104
104
  let result: null | string = null;
105
105
  try {
106
- const settings: Tex2TypstOptions = {
106
+ const settings: Partial<Tex2TypstOptions> = {
107
107
  nonStrict: c.nonStrict? c.nonStrict: false,
108
108
  preferShorthands: c.preferShorthands !== undefined? c.preferShorthands: true,
109
109
  inftyToOo: c.inftyToOo !== undefined? c.inftyToOo: false,
@@ -1,48 +1,72 @@
1
1
 
2
- import { describe, it, test, expect } from 'vitest';
2
+ import { describe, test, expect } from 'vitest';
3
3
  import { parseTypst } from '../src/typst-parser';
4
4
  import { TexWriter } from '../src/tex-writer';
5
5
  import { convert_typst_node_to_tex } from '../src/convert';
6
6
  import { loadTestCases, TestCase } from './test-common';
7
+ import { Typst2TexOptions } from '../src/exposed-types';
8
+ import { typst2tex } from '../src';
7
9
 
8
-
10
+ const options: Typst2TexOptions = {
11
+ blockMathMode: true,
12
+ };
9
13
 
10
14
  describe('examples', () => {
11
- it('a + b', function () {
15
+ test('a + b', function () {
12
16
  const typst_node = parseTypst('a + b');
13
- const tex_node = convert_typst_node_to_tex(typst_node);
17
+ const tex_node = convert_typst_node_to_tex(typst_node, options);
14
18
  const writer = new TexWriter();
15
19
  writer.append(tex_node);
16
20
  const res = writer.finalize();
17
21
  expect(res).toEqual('a + b');
18
22
  });
19
23
 
20
- it('sqrt(x)', function () {
24
+ test('sqrt(x)', function () {
21
25
  const typst_node = parseTypst('sqrt(x)');
22
- const tex_node = convert_typst_node_to_tex(typst_node);
26
+ const tex_node = convert_typst_node_to_tex(typst_node, options);
23
27
  const writer = new TexWriter();
24
28
  writer.append(tex_node);
25
29
  const res = writer.finalize();
26
30
  expect(res).toEqual('\\sqrt{x}');
27
31
  });
28
32
 
29
- it('integral_a^b f(x) dif x', function () {
33
+ test('integral_a^b f(x) dif x', function () {
30
34
  const typst_node = parseTypst('integral_a^b f(x) dif x');
31
- const tex_node = convert_typst_node_to_tex(typst_node);
35
+ const tex_node = convert_typst_node_to_tex(typst_node, options);
32
36
  const writer = new TexWriter();
33
37
  writer.append(tex_node);
34
38
  const res = writer.finalize();
35
39
  expect(res).toEqual('\\int_a^b f(x) \\mathrm{d} x');
36
40
  });
37
41
 
38
- it('lr({a + 1/3))', function () {
42
+ test('lr({a + 1/3))', function () {
39
43
  const typst_node = parseTypst('lr({a + 1/3))');
40
- const tex_node = convert_typst_node_to_tex(typst_node);
44
+ const tex_node = convert_typst_node_to_tex(typst_node, options);
41
45
  const writer = new TexWriter();
42
46
  writer.append(tex_node);
43
47
  const res = writer.finalize();
44
48
  expect(res).toEqual('\\left\\{a + \\frac{1}{3} \\right)');
45
49
  });
50
+
51
+ test('blockMathMode = false', function () {
52
+ const typst_code_1 = "a = display(sum_i x_i) b";
53
+ const res1 = typst2tex(typst_code_1, { blockMathMode: false });
54
+ expect(res1).toEqual(String.raw`a = \displaystyle \sum_i x_i \textstyle b`);
55
+
56
+ const typst_code_2 = "a = inline(sum_i x_i) b";
57
+ const res2 = typst2tex(typst_code_2, { blockMathMode: false });
58
+ expect(res2).toEqual(String.raw`a = \textstyle \sum_i x_i b`);
59
+ });
60
+
61
+ test('blockMathMode = true', function () {
62
+ const typst_code_1 = "a = inline(sum_i x_i) b";
63
+ const res1 = typst2tex(typst_code_1, { blockMathMode: true });
64
+ expect(res1).toEqual(String.raw`a = \textstyle \sum_i x_i \displaystyle b`);
65
+
66
+ const typst_code_2 = "a = display(sum_i x_i) b";
67
+ const res2 = typst2tex(typst_code_2, { blockMathMode: true });
68
+ expect(res2).toEqual(String.raw`a = \displaystyle \sum_i x_i b`);
69
+ });
46
70
  });
47
71
 
48
72
 
@@ -52,7 +76,7 @@ describe('struct-typst2tex.yaml', function () {
52
76
  suite.cases.forEach((c: TestCase) => {
53
77
  test(c.title, function () {
54
78
  const typst_node = parseTypst(c.typst);
55
- const tex_node = convert_typst_node_to_tex(typst_node);
79
+ const tex_node = convert_typst_node_to_tex(typst_node, options);
56
80
  const writer = new TexWriter();
57
81
  writer.append(tex_node);
58
82
  const res = writer.finalize();
@@ -66,7 +90,7 @@ describe('struct-bidirection.yaml', function () {
66
90
  suite.cases.forEach((c: TestCase) => {
67
91
  test(c.title, function () {
68
92
  const typst_node = parseTypst(c.typst);
69
- const tex_node = convert_typst_node_to_tex(typst_node);
93
+ const tex_node = convert_typst_node_to_tex(typst_node, options);
70
94
  const writer = new TexWriter();
71
95
  writer.append(tex_node);
72
96
  const res = writer.finalize();