ed-mathml2tex 0.0.5 → 0.0.7

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.
@@ -596,25 +596,6 @@ function getRender_joinSeparator(template, separator = '') {
596
596
  };
597
597
  }
598
598
 
599
- function getRender_joinSeparators(template, separators) {
600
- return function(node, children) {
601
- const parts = renderChildren(children);
602
- let content = '';
603
- if (separators.length === 0) {
604
- content = parts.join('');
605
- } else {
606
- content = parts.reduce((accumulator, part, index) => {
607
- accumulator += part;
608
- if (index < parts.length - 1) {
609
- accumulator += separators[index] || separators[separators.length - 1];
610
- }
611
- return accumulator;
612
- }, '');
613
- }
614
- return template.replace('@content', content);
615
- };
616
- }
617
-
618
599
  function convert(mathmlHtml){
619
600
  const math = NodeTool.parseMath(mathmlHtml);
620
601
  let result = toLatex(parse(math));
@@ -792,7 +773,7 @@ function escapeSpecialChars(text) {
792
773
 
793
774
  function parseContainer(node, children) {
794
775
  const render = getRender(node);
795
- if(render){
776
+ if (render) {
796
777
  return render(node, children);
797
778
  } else {
798
779
  throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
@@ -913,11 +894,28 @@ function getRender(node) {
913
894
  }
914
895
 
915
896
  function renderTable(node, children) {
916
- const template = "\\begin{matrix} @content \\end{matrix}";
917
- const render = getRender_joinSeparator(template);
897
+ const template = "\\begin{array}{l}@content\\end{array}";
898
+ const render = getRender_joinSeparator(template, "\\\\");
918
899
  return render(node, children);
919
900
  }
920
901
 
902
+ function renderMfenced(node, children) {
903
+ const [open, close, separatorsStr] = [
904
+ NodeTool.getAttr(node, 'open', '{'),
905
+ NodeTool.getAttr(node, 'close', '}'),
906
+ NodeTool.getAttr(node, 'separators', '|')
907
+ ];
908
+
909
+ const parts = renderChildren(children);
910
+ const content = parts.join(separatorsStr).trim();
911
+
912
+ if (open === '{' && close === '') {
913
+ return `\\left\\${open}${content}\\right.`;
914
+ }
915
+
916
+ return `\\left\\${open}${content}\\right\\${close}`;
917
+ }
918
+
921
919
  function renderMfrac(node, children){
922
920
  const [linethickness, bevelled] = [
923
921
  NodeTool.getAttr(node, 'linethickness', 'medium'),
@@ -945,40 +943,6 @@ function renderMfrac(node, children){
945
943
  return render(node, children);
946
944
  }
947
945
 
948
- function renderMfenced(node, children) {
949
- const [open, close, separatorsStr] = [
950
- NodeTool.getAttr(node, 'open', '('),
951
- NodeTool.getAttr(node, 'close', ')'),
952
- NodeTool.getAttr(node, 'separators', ',')
953
- ];
954
-
955
- // Handle special case for vectors inside brackets
956
- if (open === '[' && close === ']') {
957
- const parts = renderChildren(children);
958
- // Join parts with comma and space, preserving vector notation
959
- const content = parts.join(', ');
960
- return `\\left[${content}\\right]`;
961
- }
962
-
963
- // Handle special case for coordinates
964
- if (open === '(' && close === ')') {
965
- const parts = renderChildren(children);
966
- // Join parts with semicolon
967
- const content = parts.join(';');
968
- return `\\left(${content}\\right)`;
969
- }
970
-
971
- const [left, right] = [
972
- Brackets.parseLeft(open),
973
- Brackets.parseRight(close)
974
- ];
975
-
976
- const separators = separatorsStr.split('').filter((c) => c.trim().length === 1);
977
- const template = `${left}@content${right}`;
978
- const render = getRender_joinSeparators(template, separators);
979
- return render(node, children);
980
- }
981
-
982
946
  function renderMmultiscripts(node, children) {
983
947
  if(children.length === 0) { return '' }
984
948
  let sepIndex = -1;
@@ -1033,10 +997,17 @@ function renderMover(node, children) {
1033
997
 
1034
998
  // Get the base node and check if it's a subscript or mrow
1035
999
  const baseNode = children[0];
1000
+ const overNode = children[1];
1036
1001
  const nodeName = NodeTool.getNodeName(baseNode);
1037
1002
  const isSubscript = nodeName === 'msub';
1038
1003
  const isMrow = nodeName === 'mrow';
1039
1004
 
1005
+ // Handle case where the base is an arrow and mrow is above
1006
+ const baseText = NodeTool.getNodeText(baseNode).trim();
1007
+ if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
1008
+ return "\\rightarrow";
1009
+ }
1010
+
1040
1011
  if (isSubscript) {
1041
1012
  // Handle case like n₂ with arrow
1042
1013
  const base = parse(baseNode);
@@ -1046,7 +1017,6 @@ function renderMover(node, children) {
1046
1017
  if (isMrow) {
1047
1018
  // Handle case like 0 with arrow
1048
1019
  const base = parse(baseNode);
1049
- const overNode = children[1];
1050
1020
  const overText = NodeTool.getNodeText(overNode).trim();
1051
1021
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1052
1022
 
@@ -1055,11 +1025,10 @@ function renderMover(node, children) {
1055
1025
  }
1056
1026
  }
1057
1027
 
1058
- // Handle case where there is no base (like your example with just 0 and an arrow)
1059
- const overNode = children[1];
1028
+ // Handle case where there is only an arrow with no base
1060
1029
  const overText = NodeTool.getNodeText(overNode).trim();
1061
- if (overText === "→") {
1062
- return `\\overrightarrow{0}`;
1030
+ if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
1031
+ return `\\rightarrow`; // Return just the arrow
1063
1032
  }
1064
1033
 
1065
1034
  for (let i = 0; i < nodes.length - 1; i++) {
@@ -1067,16 +1036,13 @@ function renderMover(node, children) {
1067
1036
  result = parse(nodes[i]);
1068
1037
  }
1069
1038
 
1070
- const overNode = nodes[i + 1];
1071
- const overText = NodeTool.getNodeText(overNode).trim();
1039
+ const _overNode = nodes[i + 1];
1040
+ const overText = NodeTool.getNodeText(_overNode).trim();
1072
1041
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1073
1042
 
1074
1043
  if (overText === "→" && isAccent) {
1075
1044
  return `\\overrightarrow{${result}}`;
1076
1045
  }
1077
-
1078
- const over = parse(overNode);
1079
- result = `${result}^{${over}}`;
1080
1046
  }
1081
1047
  return result;
1082
1048
  }
@@ -594,25 +594,6 @@ function getRender_joinSeparator(template, separator = '') {
594
594
  };
595
595
  }
596
596
 
597
- function getRender_joinSeparators(template, separators) {
598
- return function(node, children) {
599
- const parts = renderChildren(children);
600
- let content = '';
601
- if (separators.length === 0) {
602
- content = parts.join('');
603
- } else {
604
- content = parts.reduce((accumulator, part, index) => {
605
- accumulator += part;
606
- if (index < parts.length - 1) {
607
- accumulator += separators[index] || separators[separators.length - 1];
608
- }
609
- return accumulator;
610
- }, '');
611
- }
612
- return template.replace('@content', content);
613
- };
614
- }
615
-
616
597
  function convert(mathmlHtml){
617
598
  const math = NodeTool.parseMath(mathmlHtml);
618
599
  let result = toLatex(parse(math));
@@ -790,7 +771,7 @@ function escapeSpecialChars(text) {
790
771
 
791
772
  function parseContainer(node, children) {
792
773
  const render = getRender(node);
793
- if(render){
774
+ if (render) {
794
775
  return render(node, children);
795
776
  } else {
796
777
  throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
@@ -911,11 +892,28 @@ function getRender(node) {
911
892
  }
912
893
 
913
894
  function renderTable(node, children) {
914
- const template = "\\begin{matrix} @content \\end{matrix}";
915
- const render = getRender_joinSeparator(template);
895
+ const template = "\\begin{array}{l}@content\\end{array}";
896
+ const render = getRender_joinSeparator(template, "\\\\");
916
897
  return render(node, children);
917
898
  }
918
899
 
900
+ function renderMfenced(node, children) {
901
+ const [open, close, separatorsStr] = [
902
+ NodeTool.getAttr(node, 'open', '{'),
903
+ NodeTool.getAttr(node, 'close', '}'),
904
+ NodeTool.getAttr(node, 'separators', '|')
905
+ ];
906
+
907
+ const parts = renderChildren(children);
908
+ const content = parts.join(separatorsStr).trim();
909
+
910
+ if (open === '{' && close === '') {
911
+ return `\\left\\${open}${content}\\right.`;
912
+ }
913
+
914
+ return `\\left\\${open}${content}\\right\\${close}`;
915
+ }
916
+
919
917
  function renderMfrac(node, children){
920
918
  const [linethickness, bevelled] = [
921
919
  NodeTool.getAttr(node, 'linethickness', 'medium'),
@@ -943,40 +941,6 @@ function renderMfrac(node, children){
943
941
  return render(node, children);
944
942
  }
945
943
 
946
- function renderMfenced(node, children) {
947
- const [open, close, separatorsStr] = [
948
- NodeTool.getAttr(node, 'open', '('),
949
- NodeTool.getAttr(node, 'close', ')'),
950
- NodeTool.getAttr(node, 'separators', ',')
951
- ];
952
-
953
- // Handle special case for vectors inside brackets
954
- if (open === '[' && close === ']') {
955
- const parts = renderChildren(children);
956
- // Join parts with comma and space, preserving vector notation
957
- const content = parts.join(', ');
958
- return `\\left[${content}\\right]`;
959
- }
960
-
961
- // Handle special case for coordinates
962
- if (open === '(' && close === ')') {
963
- const parts = renderChildren(children);
964
- // Join parts with semicolon
965
- const content = parts.join(';');
966
- return `\\left(${content}\\right)`;
967
- }
968
-
969
- const [left, right] = [
970
- Brackets.parseLeft(open),
971
- Brackets.parseRight(close)
972
- ];
973
-
974
- const separators = separatorsStr.split('').filter((c) => c.trim().length === 1);
975
- const template = `${left}@content${right}`;
976
- const render = getRender_joinSeparators(template, separators);
977
- return render(node, children);
978
- }
979
-
980
944
  function renderMmultiscripts(node, children) {
981
945
  if(children.length === 0) { return '' }
982
946
  let sepIndex = -1;
@@ -1031,10 +995,17 @@ function renderMover(node, children) {
1031
995
 
1032
996
  // Get the base node and check if it's a subscript or mrow
1033
997
  const baseNode = children[0];
998
+ const overNode = children[1];
1034
999
  const nodeName = NodeTool.getNodeName(baseNode);
1035
1000
  const isSubscript = nodeName === 'msub';
1036
1001
  const isMrow = nodeName === 'mrow';
1037
1002
 
1003
+ // Handle case where the base is an arrow and mrow is above
1004
+ const baseText = NodeTool.getNodeText(baseNode).trim();
1005
+ if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
1006
+ return "\\rightarrow";
1007
+ }
1008
+
1038
1009
  if (isSubscript) {
1039
1010
  // Handle case like n₂ with arrow
1040
1011
  const base = parse(baseNode);
@@ -1044,7 +1015,6 @@ function renderMover(node, children) {
1044
1015
  if (isMrow) {
1045
1016
  // Handle case like 0 with arrow
1046
1017
  const base = parse(baseNode);
1047
- const overNode = children[1];
1048
1018
  const overText = NodeTool.getNodeText(overNode).trim();
1049
1019
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1050
1020
 
@@ -1053,11 +1023,10 @@ function renderMover(node, children) {
1053
1023
  }
1054
1024
  }
1055
1025
 
1056
- // Handle case where there is no base (like your example with just 0 and an arrow)
1057
- const overNode = children[1];
1026
+ // Handle case where there is only an arrow with no base
1058
1027
  const overText = NodeTool.getNodeText(overNode).trim();
1059
- if (overText === "→") {
1060
- return `\\overrightarrow{0}`;
1028
+ if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
1029
+ return `\\rightarrow`; // Return just the arrow
1061
1030
  }
1062
1031
 
1063
1032
  for (let i = 0; i < nodes.length - 1; i++) {
@@ -1065,16 +1034,13 @@ function renderMover(node, children) {
1065
1034
  result = parse(nodes[i]);
1066
1035
  }
1067
1036
 
1068
- const overNode = nodes[i + 1];
1069
- const overText = NodeTool.getNodeText(overNode).trim();
1037
+ const _overNode = nodes[i + 1];
1038
+ const overText = NodeTool.getNodeText(_overNode).trim();
1070
1039
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1071
1040
 
1072
1041
  if (overText === "→" && isAccent) {
1073
1042
  return `\\overrightarrow{${result}}`;
1074
1043
  }
1075
-
1076
- const over = parse(overNode);
1077
- result = `${result}^{${over}}`;
1078
1044
  }
1079
1045
  return result;
1080
1046
  }
@@ -600,25 +600,6 @@
600
600
  };
601
601
  }
602
602
 
603
- function getRender_joinSeparators(template, separators) {
604
- return function(node, children) {
605
- const parts = renderChildren(children);
606
- let content = '';
607
- if (separators.length === 0) {
608
- content = parts.join('');
609
- } else {
610
- content = parts.reduce((accumulator, part, index) => {
611
- accumulator += part;
612
- if (index < parts.length - 1) {
613
- accumulator += separators[index] || separators[separators.length - 1];
614
- }
615
- return accumulator;
616
- }, '');
617
- }
618
- return template.replace('@content', content);
619
- };
620
- }
621
-
622
603
  function convert(mathmlHtml){
623
604
  const math = NodeTool.parseMath(mathmlHtml);
624
605
  let result = toLatex(parse(math));
@@ -796,7 +777,7 @@
796
777
 
797
778
  function parseContainer(node, children) {
798
779
  const render = getRender(node);
799
- if(render){
780
+ if (render) {
800
781
  return render(node, children);
801
782
  } else {
802
783
  throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
@@ -917,11 +898,28 @@
917
898
  }
918
899
 
919
900
  function renderTable(node, children) {
920
- const template = "\\begin{matrix} @content \\end{matrix}";
921
- const render = getRender_joinSeparator(template);
901
+ const template = "\\begin{array}{l}@content\\end{array}";
902
+ const render = getRender_joinSeparator(template, "\\\\");
922
903
  return render(node, children);
923
904
  }
924
905
 
906
+ function renderMfenced(node, children) {
907
+ const [open, close, separatorsStr] = [
908
+ NodeTool.getAttr(node, 'open', '{'),
909
+ NodeTool.getAttr(node, 'close', '}'),
910
+ NodeTool.getAttr(node, 'separators', '|')
911
+ ];
912
+
913
+ const parts = renderChildren(children);
914
+ const content = parts.join(separatorsStr).trim();
915
+
916
+ if (open === '{' && close === '') {
917
+ return `\\left\\${open}${content}\\right.`;
918
+ }
919
+
920
+ return `\\left\\${open}${content}\\right\\${close}`;
921
+ }
922
+
925
923
  function renderMfrac(node, children){
926
924
  const [linethickness, bevelled] = [
927
925
  NodeTool.getAttr(node, 'linethickness', 'medium'),
@@ -949,40 +947,6 @@
949
947
  return render(node, children);
950
948
  }
951
949
 
952
- function renderMfenced(node, children) {
953
- const [open, close, separatorsStr] = [
954
- NodeTool.getAttr(node, 'open', '('),
955
- NodeTool.getAttr(node, 'close', ')'),
956
- NodeTool.getAttr(node, 'separators', ',')
957
- ];
958
-
959
- // Handle special case for vectors inside brackets
960
- if (open === '[' && close === ']') {
961
- const parts = renderChildren(children);
962
- // Join parts with comma and space, preserving vector notation
963
- const content = parts.join(', ');
964
- return `\\left[${content}\\right]`;
965
- }
966
-
967
- // Handle special case for coordinates
968
- if (open === '(' && close === ')') {
969
- const parts = renderChildren(children);
970
- // Join parts with semicolon
971
- const content = parts.join(';');
972
- return `\\left(${content}\\right)`;
973
- }
974
-
975
- const [left, right] = [
976
- Brackets.parseLeft(open),
977
- Brackets.parseRight(close)
978
- ];
979
-
980
- const separators = separatorsStr.split('').filter((c) => c.trim().length === 1);
981
- const template = `${left}@content${right}`;
982
- const render = getRender_joinSeparators(template, separators);
983
- return render(node, children);
984
- }
985
-
986
950
  function renderMmultiscripts(node, children) {
987
951
  if(children.length === 0) { return '' }
988
952
  let sepIndex = -1;
@@ -1037,10 +1001,17 @@
1037
1001
 
1038
1002
  // Get the base node and check if it's a subscript or mrow
1039
1003
  const baseNode = children[0];
1004
+ const overNode = children[1];
1040
1005
  const nodeName = NodeTool.getNodeName(baseNode);
1041
1006
  const isSubscript = nodeName === 'msub';
1042
1007
  const isMrow = nodeName === 'mrow';
1043
1008
 
1009
+ // Handle case where the base is an arrow and mrow is above
1010
+ const baseText = NodeTool.getNodeText(baseNode).trim();
1011
+ if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
1012
+ return "\\rightarrow";
1013
+ }
1014
+
1044
1015
  if (isSubscript) {
1045
1016
  // Handle case like n₂ with arrow
1046
1017
  const base = parse(baseNode);
@@ -1050,7 +1021,6 @@
1050
1021
  if (isMrow) {
1051
1022
  // Handle case like 0 with arrow
1052
1023
  const base = parse(baseNode);
1053
- const overNode = children[1];
1054
1024
  const overText = NodeTool.getNodeText(overNode).trim();
1055
1025
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1056
1026
 
@@ -1059,11 +1029,10 @@
1059
1029
  }
1060
1030
  }
1061
1031
 
1062
- // Handle case where there is no base (like your example with just 0 and an arrow)
1063
- const overNode = children[1];
1032
+ // Handle case where there is only an arrow with no base
1064
1033
  const overText = NodeTool.getNodeText(overNode).trim();
1065
- if (overText === "→") {
1066
- return `\\overrightarrow{0}`;
1034
+ if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
1035
+ return `\\rightarrow`; // Return just the arrow
1067
1036
  }
1068
1037
 
1069
1038
  for (let i = 0; i < nodes.length - 1; i++) {
@@ -1071,16 +1040,13 @@
1071
1040
  result = parse(nodes[i]);
1072
1041
  }
1073
1042
 
1074
- const overNode = nodes[i + 1];
1075
- const overText = NodeTool.getNodeText(overNode).trim();
1043
+ const _overNode = nodes[i + 1];
1044
+ const overText = NodeTool.getNodeText(_overNode).trim();
1076
1045
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1077
1046
 
1078
1047
  if (overText === "→" && isAccent) {
1079
1048
  return `\\overrightarrow{${result}}`;
1080
1049
  }
1081
-
1082
- const over = parse(overNode);
1083
- result = `${result}^{${over}}`;
1084
1050
  }
1085
1051
  return result;
1086
1052
  }
@@ -596,25 +596,6 @@ function getRender_joinSeparator(template, separator = '') {
596
596
  };
597
597
  }
598
598
 
599
- function getRender_joinSeparators(template, separators) {
600
- return function(node, children) {
601
- const parts = renderChildren(children);
602
- let content = '';
603
- if (separators.length === 0) {
604
- content = parts.join('');
605
- } else {
606
- content = parts.reduce((accumulator, part, index) => {
607
- accumulator += part;
608
- if (index < parts.length - 1) {
609
- accumulator += separators[index] || separators[separators.length - 1];
610
- }
611
- return accumulator;
612
- }, '');
613
- }
614
- return template.replace('@content', content);
615
- };
616
- }
617
-
618
599
  function convert(mathmlHtml){
619
600
  const math = NodeTool.parseMath(mathmlHtml);
620
601
  let result = toLatex(parse(math));
@@ -792,7 +773,7 @@ function escapeSpecialChars(text) {
792
773
 
793
774
  function parseContainer(node, children) {
794
775
  const render = getRender(node);
795
- if(render){
776
+ if (render) {
796
777
  return render(node, children);
797
778
  } else {
798
779
  throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
@@ -913,11 +894,28 @@ function getRender(node) {
913
894
  }
914
895
 
915
896
  function renderTable(node, children) {
916
- const template = "\\begin{matrix} @content \\end{matrix}";
917
- const render = getRender_joinSeparator(template);
897
+ const template = "\\begin{array}{l}@content\\end{array}";
898
+ const render = getRender_joinSeparator(template, "\\\\");
918
899
  return render(node, children);
919
900
  }
920
901
 
902
+ function renderMfenced(node, children) {
903
+ const [open, close, separatorsStr] = [
904
+ NodeTool.getAttr(node, 'open', '{'),
905
+ NodeTool.getAttr(node, 'close', '}'),
906
+ NodeTool.getAttr(node, 'separators', '|')
907
+ ];
908
+
909
+ const parts = renderChildren(children);
910
+ const content = parts.join(separatorsStr).trim();
911
+
912
+ if (open === '{' && close === '') {
913
+ return `\\left\\${open}${content}\\right.`;
914
+ }
915
+
916
+ return `\\left\\${open}${content}\\right\\${close}`;
917
+ }
918
+
921
919
  function renderMfrac(node, children){
922
920
  const [linethickness, bevelled] = [
923
921
  NodeTool.getAttr(node, 'linethickness', 'medium'),
@@ -945,40 +943,6 @@ function renderMfrac(node, children){
945
943
  return render(node, children);
946
944
  }
947
945
 
948
- function renderMfenced(node, children) {
949
- const [open, close, separatorsStr] = [
950
- NodeTool.getAttr(node, 'open', '('),
951
- NodeTool.getAttr(node, 'close', ')'),
952
- NodeTool.getAttr(node, 'separators', ',')
953
- ];
954
-
955
- // Handle special case for vectors inside brackets
956
- if (open === '[' && close === ']') {
957
- const parts = renderChildren(children);
958
- // Join parts with comma and space, preserving vector notation
959
- const content = parts.join(', ');
960
- return `\\left[${content}\\right]`;
961
- }
962
-
963
- // Handle special case for coordinates
964
- if (open === '(' && close === ')') {
965
- const parts = renderChildren(children);
966
- // Join parts with semicolon
967
- const content = parts.join(';');
968
- return `\\left(${content}\\right)`;
969
- }
970
-
971
- const [left, right] = [
972
- Brackets.parseLeft(open),
973
- Brackets.parseRight(close)
974
- ];
975
-
976
- const separators = separatorsStr.split('').filter((c) => c.trim().length === 1);
977
- const template = `${left}@content${right}`;
978
- const render = getRender_joinSeparators(template, separators);
979
- return render(node, children);
980
- }
981
-
982
946
  function renderMmultiscripts(node, children) {
983
947
  if(children.length === 0) { return '' }
984
948
  let sepIndex = -1;
@@ -1033,10 +997,17 @@ function renderMover(node, children) {
1033
997
 
1034
998
  // Get the base node and check if it's a subscript or mrow
1035
999
  const baseNode = children[0];
1000
+ const overNode = children[1];
1036
1001
  const nodeName = NodeTool.getNodeName(baseNode);
1037
1002
  const isSubscript = nodeName === 'msub';
1038
1003
  const isMrow = nodeName === 'mrow';
1039
1004
 
1005
+ // Handle case where the base is an arrow and mrow is above
1006
+ const baseText = NodeTool.getNodeText(baseNode).trim();
1007
+ if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
1008
+ return "\\rightarrow";
1009
+ }
1010
+
1040
1011
  if (isSubscript) {
1041
1012
  // Handle case like n₂ with arrow
1042
1013
  const base = parse(baseNode);
@@ -1046,7 +1017,6 @@ function renderMover(node, children) {
1046
1017
  if (isMrow) {
1047
1018
  // Handle case like 0 with arrow
1048
1019
  const base = parse(baseNode);
1049
- const overNode = children[1];
1050
1020
  const overText = NodeTool.getNodeText(overNode).trim();
1051
1021
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1052
1022
 
@@ -1055,11 +1025,10 @@ function renderMover(node, children) {
1055
1025
  }
1056
1026
  }
1057
1027
 
1058
- // Handle case where there is no base (like your example with just 0 and an arrow)
1059
- const overNode = children[1];
1028
+ // Handle case where there is only an arrow with no base
1060
1029
  const overText = NodeTool.getNodeText(overNode).trim();
1061
- if (overText === "→") {
1062
- return `\\overrightarrow{0}`;
1030
+ if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
1031
+ return `\\rightarrow`; // Return just the arrow
1063
1032
  }
1064
1033
 
1065
1034
  for (let i = 0; i < nodes.length - 1; i++) {
@@ -1067,16 +1036,13 @@ function renderMover(node, children) {
1067
1036
  result = parse(nodes[i]);
1068
1037
  }
1069
1038
 
1070
- const overNode = nodes[i + 1];
1071
- const overText = NodeTool.getNodeText(overNode).trim();
1039
+ const _overNode = nodes[i + 1];
1040
+ const overText = NodeTool.getNodeText(_overNode).trim();
1072
1041
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1073
1042
 
1074
1043
  if (overText === "→" && isAccent) {
1075
1044
  return `\\overrightarrow{${result}}`;
1076
1045
  }
1077
-
1078
- const over = parse(overNode);
1079
- result = `${result}^{${over}}`;
1080
1046
  }
1081
1047
  return result;
1082
1048
  }
@@ -594,25 +594,6 @@ function getRender_joinSeparator(template, separator = '') {
594
594
  };
595
595
  }
596
596
 
597
- function getRender_joinSeparators(template, separators) {
598
- return function(node, children) {
599
- const parts = renderChildren(children);
600
- let content = '';
601
- if (separators.length === 0) {
602
- content = parts.join('');
603
- } else {
604
- content = parts.reduce((accumulator, part, index) => {
605
- accumulator += part;
606
- if (index < parts.length - 1) {
607
- accumulator += separators[index] || separators[separators.length - 1];
608
- }
609
- return accumulator;
610
- }, '');
611
- }
612
- return template.replace('@content', content);
613
- };
614
- }
615
-
616
597
  function convert(mathmlHtml){
617
598
  const math = NodeTool.parseMath(mathmlHtml);
618
599
  let result = toLatex(parse(math));
@@ -790,7 +771,7 @@ function escapeSpecialChars(text) {
790
771
 
791
772
  function parseContainer(node, children) {
792
773
  const render = getRender(node);
793
- if(render){
774
+ if (render) {
794
775
  return render(node, children);
795
776
  } else {
796
777
  throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
@@ -911,11 +892,28 @@ function getRender(node) {
911
892
  }
912
893
 
913
894
  function renderTable(node, children) {
914
- const template = "\\begin{matrix} @content \\end{matrix}";
915
- const render = getRender_joinSeparator(template);
895
+ const template = "\\begin{array}{l}@content\\end{array}";
896
+ const render = getRender_joinSeparator(template, "\\\\");
916
897
  return render(node, children);
917
898
  }
918
899
 
900
+ function renderMfenced(node, children) {
901
+ const [open, close, separatorsStr] = [
902
+ NodeTool.getAttr(node, 'open', '{'),
903
+ NodeTool.getAttr(node, 'close', '}'),
904
+ NodeTool.getAttr(node, 'separators', '|')
905
+ ];
906
+
907
+ const parts = renderChildren(children);
908
+ const content = parts.join(separatorsStr).trim();
909
+
910
+ if (open === '{' && close === '') {
911
+ return `\\left\\${open}${content}\\right.`;
912
+ }
913
+
914
+ return `\\left\\${open}${content}\\right\\${close}`;
915
+ }
916
+
919
917
  function renderMfrac(node, children){
920
918
  const [linethickness, bevelled] = [
921
919
  NodeTool.getAttr(node, 'linethickness', 'medium'),
@@ -943,40 +941,6 @@ function renderMfrac(node, children){
943
941
  return render(node, children);
944
942
  }
945
943
 
946
- function renderMfenced(node, children) {
947
- const [open, close, separatorsStr] = [
948
- NodeTool.getAttr(node, 'open', '('),
949
- NodeTool.getAttr(node, 'close', ')'),
950
- NodeTool.getAttr(node, 'separators', ',')
951
- ];
952
-
953
- // Handle special case for vectors inside brackets
954
- if (open === '[' && close === ']') {
955
- const parts = renderChildren(children);
956
- // Join parts with comma and space, preserving vector notation
957
- const content = parts.join(', ');
958
- return `\\left[${content}\\right]`;
959
- }
960
-
961
- // Handle special case for coordinates
962
- if (open === '(' && close === ')') {
963
- const parts = renderChildren(children);
964
- // Join parts with semicolon
965
- const content = parts.join(';');
966
- return `\\left(${content}\\right)`;
967
- }
968
-
969
- const [left, right] = [
970
- Brackets.parseLeft(open),
971
- Brackets.parseRight(close)
972
- ];
973
-
974
- const separators = separatorsStr.split('').filter((c) => c.trim().length === 1);
975
- const template = `${left}@content${right}`;
976
- const render = getRender_joinSeparators(template, separators);
977
- return render(node, children);
978
- }
979
-
980
944
  function renderMmultiscripts(node, children) {
981
945
  if(children.length === 0) { return '' }
982
946
  let sepIndex = -1;
@@ -1031,10 +995,17 @@ function renderMover(node, children) {
1031
995
 
1032
996
  // Get the base node and check if it's a subscript or mrow
1033
997
  const baseNode = children[0];
998
+ const overNode = children[1];
1034
999
  const nodeName = NodeTool.getNodeName(baseNode);
1035
1000
  const isSubscript = nodeName === 'msub';
1036
1001
  const isMrow = nodeName === 'mrow';
1037
1002
 
1003
+ // Handle case where the base is an arrow and mrow is above
1004
+ const baseText = NodeTool.getNodeText(baseNode).trim();
1005
+ if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
1006
+ return "\\rightarrow";
1007
+ }
1008
+
1038
1009
  if (isSubscript) {
1039
1010
  // Handle case like n₂ with arrow
1040
1011
  const base = parse(baseNode);
@@ -1044,7 +1015,6 @@ function renderMover(node, children) {
1044
1015
  if (isMrow) {
1045
1016
  // Handle case like 0 with arrow
1046
1017
  const base = parse(baseNode);
1047
- const overNode = children[1];
1048
1018
  const overText = NodeTool.getNodeText(overNode).trim();
1049
1019
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1050
1020
 
@@ -1053,11 +1023,10 @@ function renderMover(node, children) {
1053
1023
  }
1054
1024
  }
1055
1025
 
1056
- // Handle case where there is no base (like your example with just 0 and an arrow)
1057
- const overNode = children[1];
1026
+ // Handle case where there is only an arrow with no base
1058
1027
  const overText = NodeTool.getNodeText(overNode).trim();
1059
- if (overText === "→") {
1060
- return `\\overrightarrow{0}`;
1028
+ if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
1029
+ return `\\rightarrow`; // Return just the arrow
1061
1030
  }
1062
1031
 
1063
1032
  for (let i = 0; i < nodes.length - 1; i++) {
@@ -1065,16 +1034,13 @@ function renderMover(node, children) {
1065
1034
  result = parse(nodes[i]);
1066
1035
  }
1067
1036
 
1068
- const overNode = nodes[i + 1];
1069
- const overText = NodeTool.getNodeText(overNode).trim();
1037
+ const _overNode = nodes[i + 1];
1038
+ const overText = NodeTool.getNodeText(_overNode).trim();
1070
1039
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1071
1040
 
1072
1041
  if (overText === "→" && isAccent) {
1073
1042
  return `\\overrightarrow{${result}}`;
1074
1043
  }
1075
-
1076
- const over = parse(overNode);
1077
- result = `${result}^{${over}}`;
1078
1044
  }
1079
1045
  return result;
1080
1046
  }
@@ -600,25 +600,6 @@
600
600
  };
601
601
  }
602
602
 
603
- function getRender_joinSeparators(template, separators) {
604
- return function(node, children) {
605
- const parts = renderChildren(children);
606
- let content = '';
607
- if (separators.length === 0) {
608
- content = parts.join('');
609
- } else {
610
- content = parts.reduce((accumulator, part, index) => {
611
- accumulator += part;
612
- if (index < parts.length - 1) {
613
- accumulator += separators[index] || separators[separators.length - 1];
614
- }
615
- return accumulator;
616
- }, '');
617
- }
618
- return template.replace('@content', content);
619
- };
620
- }
621
-
622
603
  function convert(mathmlHtml){
623
604
  const math = NodeTool.parseMath(mathmlHtml);
624
605
  let result = toLatex(parse(math));
@@ -796,7 +777,7 @@
796
777
 
797
778
  function parseContainer(node, children) {
798
779
  const render = getRender(node);
799
- if(render){
780
+ if (render) {
800
781
  return render(node, children);
801
782
  } else {
802
783
  throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
@@ -917,11 +898,28 @@
917
898
  }
918
899
 
919
900
  function renderTable(node, children) {
920
- const template = "\\begin{matrix} @content \\end{matrix}";
921
- const render = getRender_joinSeparator(template);
901
+ const template = "\\begin{array}{l}@content\\end{array}";
902
+ const render = getRender_joinSeparator(template, "\\\\");
922
903
  return render(node, children);
923
904
  }
924
905
 
906
+ function renderMfenced(node, children) {
907
+ const [open, close, separatorsStr] = [
908
+ NodeTool.getAttr(node, 'open', '{'),
909
+ NodeTool.getAttr(node, 'close', '}'),
910
+ NodeTool.getAttr(node, 'separators', '|')
911
+ ];
912
+
913
+ const parts = renderChildren(children);
914
+ const content = parts.join(separatorsStr).trim();
915
+
916
+ if (open === '{' && close === '') {
917
+ return `\\left\\${open}${content}\\right.`;
918
+ }
919
+
920
+ return `\\left\\${open}${content}\\right\\${close}`;
921
+ }
922
+
925
923
  function renderMfrac(node, children){
926
924
  const [linethickness, bevelled] = [
927
925
  NodeTool.getAttr(node, 'linethickness', 'medium'),
@@ -949,40 +947,6 @@
949
947
  return render(node, children);
950
948
  }
951
949
 
952
- function renderMfenced(node, children) {
953
- const [open, close, separatorsStr] = [
954
- NodeTool.getAttr(node, 'open', '('),
955
- NodeTool.getAttr(node, 'close', ')'),
956
- NodeTool.getAttr(node, 'separators', ',')
957
- ];
958
-
959
- // Handle special case for vectors inside brackets
960
- if (open === '[' && close === ']') {
961
- const parts = renderChildren(children);
962
- // Join parts with comma and space, preserving vector notation
963
- const content = parts.join(', ');
964
- return `\\left[${content}\\right]`;
965
- }
966
-
967
- // Handle special case for coordinates
968
- if (open === '(' && close === ')') {
969
- const parts = renderChildren(children);
970
- // Join parts with semicolon
971
- const content = parts.join(';');
972
- return `\\left(${content}\\right)`;
973
- }
974
-
975
- const [left, right] = [
976
- Brackets.parseLeft(open),
977
- Brackets.parseRight(close)
978
- ];
979
-
980
- const separators = separatorsStr.split('').filter((c) => c.trim().length === 1);
981
- const template = `${left}@content${right}`;
982
- const render = getRender_joinSeparators(template, separators);
983
- return render(node, children);
984
- }
985
-
986
950
  function renderMmultiscripts(node, children) {
987
951
  if(children.length === 0) { return '' }
988
952
  let sepIndex = -1;
@@ -1037,10 +1001,17 @@
1037
1001
 
1038
1002
  // Get the base node and check if it's a subscript or mrow
1039
1003
  const baseNode = children[0];
1004
+ const overNode = children[1];
1040
1005
  const nodeName = NodeTool.getNodeName(baseNode);
1041
1006
  const isSubscript = nodeName === 'msub';
1042
1007
  const isMrow = nodeName === 'mrow';
1043
1008
 
1009
+ // Handle case where the base is an arrow and mrow is above
1010
+ const baseText = NodeTool.getNodeText(baseNode).trim();
1011
+ if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
1012
+ return "\\rightarrow";
1013
+ }
1014
+
1044
1015
  if (isSubscript) {
1045
1016
  // Handle case like n₂ with arrow
1046
1017
  const base = parse(baseNode);
@@ -1050,7 +1021,6 @@
1050
1021
  if (isMrow) {
1051
1022
  // Handle case like 0 with arrow
1052
1023
  const base = parse(baseNode);
1053
- const overNode = children[1];
1054
1024
  const overText = NodeTool.getNodeText(overNode).trim();
1055
1025
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1056
1026
 
@@ -1059,11 +1029,10 @@
1059
1029
  }
1060
1030
  }
1061
1031
 
1062
- // Handle case where there is no base (like your example with just 0 and an arrow)
1063
- const overNode = children[1];
1032
+ // Handle case where there is only an arrow with no base
1064
1033
  const overText = NodeTool.getNodeText(overNode).trim();
1065
- if (overText === "→") {
1066
- return `\\overrightarrow{0}`;
1034
+ if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
1035
+ return `\\rightarrow`; // Return just the arrow
1067
1036
  }
1068
1037
 
1069
1038
  for (let i = 0; i < nodes.length - 1; i++) {
@@ -1071,16 +1040,13 @@
1071
1040
  result = parse(nodes[i]);
1072
1041
  }
1073
1042
 
1074
- const overNode = nodes[i + 1];
1075
- const overText = NodeTool.getNodeText(overNode).trim();
1043
+ const _overNode = nodes[i + 1];
1044
+ const overText = NodeTool.getNodeText(_overNode).trim();
1076
1045
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1077
1046
 
1078
1047
  if (overText === "→" && isAccent) {
1079
1048
  return `\\overrightarrow{${result}}`;
1080
1049
  }
1081
-
1082
- const over = parse(overNode);
1083
- result = `${result}^{${over}}`;
1084
1050
  }
1085
1051
  return result;
1086
1052
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ed-mathml2tex",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Convert mathml to latex.",
5
5
  "author": "Mika",
6
6
  "license": "MIT",