tex2typst 0.4.0 → 0.4.1

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.js CHANGED
@@ -1,4 +1,4 @@
1
- // src/util.ts
1
+ // src/utils.ts
2
2
  function isalpha(char) {
3
3
  return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(char);
4
4
  }
@@ -574,7 +574,8 @@ var TEX_UNARY_COMMANDS = [
574
574
  "mathinner",
575
575
  "mathrel",
576
576
  "mathbin",
577
- "mathop"
577
+ "mathop",
578
+ "not"
578
579
  ];
579
580
  var TEX_BINARY_COMMANDS = [
580
581
  "frac",
@@ -1066,51 +1067,25 @@ var LatexParser = class {
1066
1067
  this.alignmentDepth++;
1067
1068
  let pos = start;
1068
1069
  pos += eat_whitespaces(tokens, pos).length;
1069
- const allRows = [];
1070
- let row = [];
1071
- allRows.push(row);
1072
- let group = new TexGroup([]);
1073
- row.push(group);
1074
- while (pos < tokens.length) {
1075
- if (tokens[pos].eq(closingToken)) {
1076
- break;
1077
- }
1078
- const [res, newPos] = this.parseNextExpr(tokens, pos);
1079
- pos = newPos;
1080
- if (res.head.type === 5 /* SPACE */ || res.head.type === 6 /* NEWLINE */) {
1081
- if (!this.space_sensitive && res.head.value.replace(/ /g, "").length === 0) {
1082
- continue;
1083
- }
1084
- if (!this.newline_sensitive && res.head.value === "\n") {
1085
- continue;
1086
- }
1087
- }
1088
- if (res.head.eq(new TexToken(7 /* CONTROL */, "\\\\"))) {
1089
- row = [];
1090
- group = new TexGroup([]);
1091
- row.push(group);
1092
- allRows.push(row);
1093
- } else if (res.head.eq(new TexToken(7 /* CONTROL */, "&"))) {
1094
- group = new TexGroup([]);
1095
- row.push(group);
1096
- } else {
1097
- group.items.push(res);
1098
- }
1099
- }
1100
- if (pos >= tokens.length) {
1070
+ let closure;
1071
+ [closure, pos] = this.parseClosure(tokens, pos, closingToken);
1072
+ if (pos === -1) {
1101
1073
  return [[], -1];
1102
1074
  }
1103
- if (allRows.length > 0 && allRows[allRows.length - 1].length > 0) {
1104
- const last_cell = allRows[allRows.length - 1][allRows[allRows.length - 1].length - 1];
1105
- if (last_cell.type === "ordgroup") {
1106
- const last_cell_items = last_cell.items;
1107
- while (last_cell_items.length > 0 && [5 /* SPACE */, 6 /* NEWLINE */].includes(last_cell_items[last_cell_items.length - 1].head.type)) {
1108
- last_cell_items.pop();
1109
- }
1075
+ let allRows;
1076
+ if (closure.type === "ordgroup") {
1077
+ const elements = closure.items;
1078
+ while (elements.length > 0 && [5 /* SPACE */, 6 /* NEWLINE */].includes(elements[elements.length - 1].head.type)) {
1079
+ elements.pop();
1110
1080
  }
1081
+ allRows = array_split(elements, new TexToken(7 /* CONTROL */, "\\\\").toNode()).map((row) => {
1082
+ return array_split(row, new TexToken(7 /* CONTROL */, "&").toNode()).map((arr) => new TexGroup(arr));
1083
+ });
1084
+ } else {
1085
+ allRows = [[closure]];
1111
1086
  }
1112
1087
  this.alignmentDepth--;
1113
- return [allRows, pos + 1];
1088
+ return [allRows, pos];
1114
1089
  }
1115
1090
  };
1116
1091
  function passIgnoreWhitespaceBeforeScriptMark(tokens) {
@@ -3083,6 +3058,20 @@ function convert_tex_node_to_typst(abstractNode, options) {
3083
3058
  { body: arg0, left: TypstToken.LEFT_BRACE, right: TypstToken.RIGHT_BRACE }
3084
3059
  );
3085
3060
  }
3061
+ if (node2.head.value === "\\not") {
3062
+ const sym = convert_tex_node_to_typst(node2.args[0], options);
3063
+ assert(sym.type === "terminal");
3064
+ if (sym.head.type === 1 /* SYMBOL */) {
3065
+ return new TypstToken(1 /* SYMBOL */, sym.head.value + ".not").toNode();
3066
+ } else {
3067
+ switch (sym.head.value) {
3068
+ case "=":
3069
+ return new TypstToken(1 /* SYMBOL */, "eq.not").toNode();
3070
+ default:
3071
+ throw new Error(`Not supported: \\not ${sym.head.value}`);
3072
+ }
3073
+ }
3074
+ }
3086
3075
  if (node2.head.value === "\\overset") {
3087
3076
  return convert_overset(node2, options);
3088
3077
  }
@@ -3182,12 +3171,28 @@ function typst_token_to_tex(token) {
3182
3171
  return TexToken.EMPTY;
3183
3172
  case 1 /* SYMBOL */: {
3184
3173
  const _typst_symbol_to_tex = function(symbol) {
3185
- if (reverseSymbolMap.has(symbol)) {
3186
- return "\\" + reverseSymbolMap.get(symbol);
3187
- } else {
3188
- return "\\" + symbol;
3174
+ switch (symbol) {
3175
+ case "eq":
3176
+ return "=";
3177
+ case "plus":
3178
+ return "+";
3179
+ case "minus":
3180
+ return "-";
3181
+ case "percent":
3182
+ return "%";
3183
+ default: {
3184
+ if (reverseSymbolMap.has(symbol)) {
3185
+ return "\\" + reverseSymbolMap.get(symbol);
3186
+ } else {
3187
+ return "\\" + symbol;
3188
+ }
3189
+ }
3189
3190
  }
3190
3191
  };
3192
+ if (token.value.endsWith(".not")) {
3193
+ const sym = _typst_symbol_to_tex(token.value.slice(0, -4));
3194
+ return new TexToken(2 /* COMMAND */, sym.startsWith("\\") ? `\\not${sym}` : `\\not ${sym}`);
3195
+ }
3191
3196
  return new TexToken(2 /* COMMAND */, _typst_symbol_to_tex(token.value));
3192
3197
  }
3193
3198
  case 2 /* ELEMENT */: {
@@ -3632,32 +3637,34 @@ function find_closing_match(tokens, start) {
3632
3637
  [RIGHT_PARENTHESES, RIGHT_BRACKET, RIGHT_CURLY_BRACKET2]
3633
3638
  );
3634
3639
  }
3635
- function find_closing_delim(tokens, start) {
3636
- return _find_closing_match(
3637
- tokens,
3638
- start,
3639
- TypstToken.LEFT_DELIMITERS,
3640
- TypstToken.RIGHT_DELIMITERS
3641
- );
3642
- }
3643
- function find_closing_parenthesis(nodes, start) {
3644
- const left_parenthesis = new TypstToken(2 /* ELEMENT */, "(").toNode();
3645
- const right_parenthesis = new TypstToken(2 /* ELEMENT */, ")").toNode();
3646
- assert(nodes[start].eq(left_parenthesis));
3647
- let count = 1;
3648
- let pos = start + 1;
3649
- while (count > 0) {
3650
- if (pos >= nodes.length) {
3651
- throw new Error("Unmatched '('");
3640
+ function extract_named_params(arr) {
3641
+ const COLON = new TypstToken(2 /* ELEMENT */, ":").toNode();
3642
+ const np = {};
3643
+ const to_delete = [];
3644
+ for (let i = 0; i < arr.length; i++) {
3645
+ if (arr[i].type !== "group") {
3646
+ continue;
3652
3647
  }
3653
- if (nodes[pos].eq(left_parenthesis)) {
3654
- count += 1;
3655
- } else if (nodes[pos].eq(right_parenthesis)) {
3656
- count -= 1;
3648
+ const g = arr[i];
3649
+ const pos_colon = array_find(g.items, COLON);
3650
+ if (pos_colon === -1 || pos_colon === 0) {
3651
+ continue;
3652
+ }
3653
+ to_delete.push(i);
3654
+ const param_name = g.items[pos_colon - 1];
3655
+ if (param_name.eq(new TypstToken(1 /* SYMBOL */, "delim").toNode())) {
3656
+ if (g.items.length !== 3) {
3657
+ throw new TypstParserError("Invalid number of arguments for delim");
3658
+ }
3659
+ np["delim"] = g.items[pos_colon + 1];
3660
+ } else {
3661
+ throw new TypstParserError("Not implemented for other named parameters");
3657
3662
  }
3658
- pos += 1;
3659
3663
  }
3660
- return pos - 1;
3664
+ for (let i = to_delete.length - 1; i >= 0; i--) {
3665
+ arr.splice(to_delete[i], 1);
3666
+ }
3667
+ return [arr, np];
3661
3668
  }
3662
3669
  function primes(num) {
3663
3670
  const res = [];
@@ -3696,30 +3703,16 @@ function trim_whitespace_around_operators(nodes) {
3696
3703
  }
3697
3704
  return res;
3698
3705
  }
3699
- function process_operators(nodes, parenthesis = false) {
3706
+ function process_operators(nodes) {
3700
3707
  nodes = trim_whitespace_around_operators(nodes);
3701
- const opening_bracket = LEFT_PARENTHESES.toNode();
3702
- const closing_bracket = RIGHT_PARENTHESES.toNode();
3703
3708
  const stack = [];
3704
3709
  const args = [];
3705
3710
  let pos = 0;
3706
3711
  while (pos < nodes.length) {
3707
- const current = nodes[pos];
3708
- if (current.eq(closing_bracket)) {
3709
- throw new TypstParserError("Unexpected ')'");
3710
- } else if (current.eq(DIV)) {
3711
- stack.push(current);
3712
- pos++;
3712
+ const current_tree = nodes[pos];
3713
+ if (current_tree.eq(DIV)) {
3714
+ stack.push(current_tree);
3713
3715
  } else {
3714
- let current_tree;
3715
- if (current.eq(opening_bracket)) {
3716
- const pos_closing = find_closing_parenthesis(nodes, pos);
3717
- current_tree = process_operators(nodes.slice(pos + 1, pos_closing), true);
3718
- pos = pos_closing + 1;
3719
- } else {
3720
- current_tree = current;
3721
- pos++;
3722
- }
3723
3716
  if (stack.length > 0 && stack[stack.length - 1].eq(DIV)) {
3724
3717
  let denominator = current_tree;
3725
3718
  if (args.length === 0) {
@@ -3738,13 +3731,9 @@ function process_operators(nodes, parenthesis = false) {
3738
3731
  args.push(current_tree);
3739
3732
  }
3740
3733
  }
3734
+ pos++;
3741
3735
  }
3742
- const body = args.length === 1 ? args[0] : new TypstGroup(args);
3743
- if (parenthesis) {
3744
- return new TypstLeftright(null, { body, left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES });
3745
- } else {
3746
- return body;
3747
- }
3736
+ return args.length === 1 ? args[0] : new TypstGroup(args);
3748
3737
  }
3749
3738
  function parse_named_params(groups) {
3750
3739
  const COLON = new TypstToken(2 /* ELEMENT */, ":").toNode();
@@ -3772,7 +3761,6 @@ var LEFT_CURLY_BRACKET2 = new TypstToken(2 /* ELEMENT */, "{");
3772
3761
  var RIGHT_CURLY_BRACKET2 = new TypstToken(2 /* ELEMENT */, "}");
3773
3762
  var COMMA = new TypstToken(2 /* ELEMENT */, ",");
3774
3763
  var SEMICOLON = new TypstToken(2 /* ELEMENT */, ";");
3775
- var SINGLE_SPACE = new TypstToken(6 /* SPACE */, " ");
3776
3764
  var CONTROL_AND = new TypstToken(7 /* CONTROL */, "&");
3777
3765
  var TypstParser = class {
3778
3766
  space_sensitive;
@@ -3785,33 +3773,8 @@ var TypstParser = class {
3785
3773
  const [tree, _] = this.parseGroup(tokens, 0, tokens.length);
3786
3774
  return tree;
3787
3775
  }
3788
- parseGroup(tokens, start, end, parentheses = false) {
3789
- const results = [];
3790
- let pos = start;
3791
- while (pos < end) {
3792
- const [res, newPos] = this.parseNextExpr(tokens, pos);
3793
- pos = newPos;
3794
- if (res.head.type === 6 /* SPACE */ || res.head.type === 8 /* NEWLINE */) {
3795
- if (!this.space_sensitive && res.head.value.replace(/ /g, "").length === 0) {
3796
- continue;
3797
- }
3798
- if (!this.newline_sensitive && res.head.value === "\n") {
3799
- continue;
3800
- }
3801
- }
3802
- results.push(res);
3803
- }
3804
- let node;
3805
- if (parentheses) {
3806
- node = process_operators(results, true);
3807
- } else {
3808
- if (results.length === 1) {
3809
- node = results[0];
3810
- } else {
3811
- node = process_operators(results);
3812
- }
3813
- }
3814
- return [node, end + 1];
3776
+ parseGroup(tokens, start, end) {
3777
+ return this.parseUntil(tokens.slice(start, end), 0, null);
3815
3778
  }
3816
3779
  parseNextExpr(tokens, start) {
3817
3780
  let [base, pos] = this.parseNextExprWithoutSupSub(tokens, start);
@@ -3840,12 +3803,47 @@ var TypstParser = class {
3840
3803
  return [base, pos];
3841
3804
  }
3842
3805
  }
3806
+ // return pos: (position of stopToken) + 1
3807
+ // pos will be -1 if stopToken is not found
3808
+ parseUntil(tokens, start, stopToken, env = {}) {
3809
+ if (env.spaceSensitive === void 0) {
3810
+ env.spaceSensitive = this.space_sensitive;
3811
+ }
3812
+ if (env.newlineSensitive === void 0) {
3813
+ env.newlineSensitive = this.newline_sensitive;
3814
+ }
3815
+ const results = [];
3816
+ let pos = start;
3817
+ while (pos < tokens.length) {
3818
+ if (stopToken !== null && tokens[pos].eq(stopToken)) {
3819
+ break;
3820
+ }
3821
+ const [res, newPos] = this.parseNextExpr(tokens, pos);
3822
+ pos = newPos;
3823
+ if (res.head.type === 6 /* SPACE */ || res.head.type === 8 /* NEWLINE */) {
3824
+ if (!env.spaceSensitive && res.head.value.replace(/ /g, "").length === 0) {
3825
+ continue;
3826
+ }
3827
+ if (!env.newlineSensitive && res.head.value === "\n") {
3828
+ continue;
3829
+ }
3830
+ }
3831
+ results.push(res);
3832
+ }
3833
+ if (pos >= tokens.length && stopToken !== null) {
3834
+ return [TypstToken.NONE.toNode(), -1];
3835
+ }
3836
+ const node = process_operators(results);
3837
+ return [node, pos + 1];
3838
+ }
3843
3839
  parseSupOrSub(tokens, start) {
3844
3840
  let node;
3845
3841
  let end;
3846
3842
  if (tokens[start].eq(LEFT_PARENTHESES)) {
3847
- const pos_closing = find_closing_match(tokens, start);
3848
- [node, end] = this.parseGroup(tokens, start + 1, pos_closing);
3843
+ [node, end] = this.parseUntil(tokens, start + 1, RIGHT_PARENTHESES);
3844
+ if (end === -1) {
3845
+ throw new Error("Unmatched '('");
3846
+ }
3849
3847
  } else {
3850
3848
  [node, end] = this.parseNextExprWithoutSupSub(tokens, start);
3851
3849
  }
@@ -3860,8 +3858,12 @@ var TypstParser = class {
3860
3858
  const firstToken = tokens[start];
3861
3859
  const node = firstToken.toNode();
3862
3860
  if (firstToken.eq(LEFT_PARENTHESES)) {
3863
- const pos_closing = find_closing_match(tokens, start);
3864
- return this.parseGroup(tokens, start + 1, pos_closing, true);
3861
+ const [body, end] = this.parseUntil(tokens, start + 1, RIGHT_PARENTHESES);
3862
+ if (end === -1) {
3863
+ throw new Error("Unmatched '('");
3864
+ }
3865
+ const res = new TypstLeftright(null, { body, left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES });
3866
+ return [res, end];
3865
3867
  }
3866
3868
  if (firstToken.type === 2 /* ELEMENT */ && !isalpha(firstToken.value[0])) {
3867
3869
  return [node, start + 1];
@@ -3909,70 +3911,41 @@ var TypstParser = class {
3909
3911
  }
3910
3912
  // start: the position of the left parentheses
3911
3913
  parseLrArguments(tokens, start) {
3912
- const lr_token = tokens[start];
3914
+ const lr_token = new TypstToken(1 /* SYMBOL */, "lr");
3913
3915
  const end = find_closing_match(tokens, start);
3914
- if (tokens[start + 1].isOneOf(TypstToken.LEFT_DELIMITERS)) {
3915
- const inner_start = start + 1;
3916
- const inner_end = find_closing_delim(tokens, inner_start);
3917
- const [inner_args, _] = this.parseGroup(tokens, inner_start + 1, inner_end);
3918
- return [
3919
- new TypstLeftright(lr_token, { body: inner_args, left: tokens[inner_start], right: tokens[inner_end] }),
3920
- end + 1
3921
- ];
3922
- } else {
3923
- const [inner_args, _] = this.parseGroup(tokens, start + 1, end - 1);
3924
- return [
3925
- new TypstLeftright(lr_token, { body: inner_args, left: null, right: null }),
3926
- end + 1
3927
- ];
3928
- }
3916
+ let left = null;
3917
+ let right = null;
3918
+ let inner_start = start + 1;
3919
+ let inner_end = end;
3920
+ if (inner_end > inner_start && tokens[inner_start].isOneOf(TypstToken.LEFT_DELIMITERS)) {
3921
+ left = tokens[inner_start];
3922
+ inner_start += 1;
3923
+ }
3924
+ if (inner_end - 1 > inner_start && tokens[inner_end - 1].isOneOf(TypstToken.RIGHT_DELIMITERS)) {
3925
+ right = tokens[inner_end - 1];
3926
+ inner_end -= 1;
3927
+ }
3928
+ const [inner_args, _] = this.parseGroup(tokens, inner_start, inner_end);
3929
+ return [
3930
+ new TypstLeftright(lr_token, { body: inner_args, left, right }),
3931
+ end + 1
3932
+ ];
3929
3933
  }
3930
3934
  // start: the position of the left parentheses
3931
3935
  parseMatrix(tokens, start, rowSepToken, cellSepToken) {
3932
3936
  const end = find_closing_match(tokens, start);
3933
- tokens = tokens.slice(0, end);
3934
3937
  const matrix = [];
3935
3938
  let named_params = {};
3936
3939
  let pos = start + 1;
3937
3940
  while (pos < end) {
3938
3941
  while (pos < end) {
3939
- let extract_named_params2 = function(arr) {
3940
- const COLON = new TypstToken(2 /* ELEMENT */, ":").toNode();
3941
- const np2 = {};
3942
- const to_delete = [];
3943
- for (let i = 0; i < arr.length; i++) {
3944
- if (arr[i].type !== "group") {
3945
- continue;
3946
- }
3947
- const g = arr[i];
3948
- const pos_colon = array_find(g.items, COLON);
3949
- if (pos_colon === -1 || pos_colon === 0) {
3950
- continue;
3951
- }
3952
- to_delete.push(i);
3953
- const param_name = g.items[pos_colon - 1];
3954
- if (param_name.eq(new TypstToken(1 /* SYMBOL */, "delim").toNode())) {
3955
- if (g.items.length !== 3) {
3956
- throw new TypstParserError("Invalid number of arguments for delim");
3957
- }
3958
- np2["delim"] = g.items[pos_colon + 1];
3959
- } else {
3960
- throw new TypstParserError("Not implemented for other named parameters");
3961
- }
3962
- }
3963
- for (let i = to_delete.length - 1; i >= 0; i--) {
3964
- arr.splice(to_delete[i], 1);
3965
- }
3966
- return [arr, np2];
3967
- };
3968
- var extract_named_params = extract_named_params2;
3969
3942
  let next_stop = array_find(tokens, rowSepToken, pos);
3970
- if (next_stop === -1) {
3943
+ if (next_stop === -1 || next_stop > end) {
3971
3944
  next_stop = end;
3972
3945
  }
3973
3946
  let row = this.parseArgumentsWithSeparator(tokens, pos, next_stop, cellSepToken);
3974
3947
  let np = {};
3975
- [row, np] = extract_named_params2(row);
3948
+ [row, np] = extract_named_params(row);
3976
3949
  matrix.push(row);
3977
3950
  Object.assign(named_params, np);
3978
3951
  pos = next_stop + 1;
@@ -3985,26 +3958,15 @@ var TypstParser = class {
3985
3958
  const args = [];
3986
3959
  let pos = start;
3987
3960
  while (pos < end) {
3988
- let nodes = [];
3989
- while (pos < end) {
3990
- if (tokens[pos].eq(sepToken)) {
3991
- pos += 1;
3992
- break;
3993
- } else if (tokens[pos].eq(SINGLE_SPACE)) {
3994
- pos += 1;
3995
- continue;
3996
- }
3997
- const [argItem, newPos] = this.parseNextExpr(tokens, pos);
3998
- pos = newPos;
3999
- nodes.push(argItem);
4000
- }
4001
3961
  let arg;
4002
- if (nodes.length === 1) {
4003
- arg = nodes[0];
4004
- } else {
4005
- arg = process_operators(nodes);
3962
+ let newPos;
3963
+ const env = { spaceSensitive: false, newlineSensitive: true };
3964
+ [arg, newPos] = this.parseUntil(tokens.slice(0, end), pos, sepToken, env);
3965
+ if (newPos == -1) {
3966
+ [arg, newPos] = this.parseUntil(tokens.slice(0, end), pos, null, env);
4006
3967
  }
4007
3968
  args.push(arg);
3969
+ pos = newPos;
4008
3970
  }
4009
3971
  return args;
4010
3972
  }