ed-mathml2tex 0.1.5 → 0.1.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.
@@ -584,10 +584,10 @@ T.createMarker = function() {
584
584
  }
585
585
  };
586
586
 
587
- function getRender_joinSeparator(template, separator = '') {
587
+ function getRender_joinSeparator(template, separator = "") {
588
588
  return function (node, children) {
589
589
  const parts = renderChildren(children);
590
- return template.replace('@content', parts.join(separator));
590
+ return template.replace("@content", parts.join(separator));
591
591
  };
592
592
  }
593
593
 
@@ -599,9 +599,11 @@ function convert(mathmlHtml) {
599
599
  result = result.replace(/\\right\.\./g, "\\right."); // Loại bỏ dấu chấm trùng lặp
600
600
  result = result.replace(/\.\s*\./g, "."); // Loại bỏ dấu chấm trùng lặp
601
601
 
602
- if (mathmlHtml.includes("<munder>") &&
602
+ if (
603
+ mathmlHtml.includes("<munder>") &&
603
604
  mathmlHtml.includes("<mo>→</mo>") &&
604
- mathmlHtml.includes("<mrow/>")) {
605
+ mathmlHtml.includes("<mrow/>")
606
+ ) {
605
607
  if (result.includes("\\limits")) {
606
608
  result = "\\underset{}{\\rightarrow}";
607
609
  }
@@ -610,38 +612,71 @@ function convert(mathmlHtml) {
610
612
  // Thêm xử lý cho các thẻ MathML khác
611
613
  result = result
612
614
  .replace(/∞/g, "\\infty") // Vô cực
613
- .replace(/∑/g, "\\sum") // Tổng
614
- .replace(/∏/g, "\\prod") // Tích
615
- .replace(/∫/g, "\\int"); // Tích phân
615
+ .replace(/∑/g, "\\sum") // Tổng
616
+ .replace(/∏/g, "\\prod") // Tích
617
+ .replace(/∫/g, "\\int"); // Tích phân
616
618
 
617
619
  return result;
618
620
  }
619
621
 
620
622
  function toLatex(result) {
621
623
  // Xử lý binomial coefficients
622
- result = result.replace(/\\left\(\\DELETE_BRACKET_L/g, '');
623
- result = result.replace(/\\DELETE_BRACKET_R\\right\)/g, '');
624
- result = result.replace(/\\DELETE_BRACKET_L/g, '');
625
- result = result.replace(/\\DELETE_BRACKET_R/g, '');
624
+ result = result.replace(/\\left\(\\DELETE_BRACKET_L/g, "");
625
+ result = result.replace(/\\DELETE_BRACKET_R\\right\)/g, "");
626
+ result = result.replace(/\\DELETE_BRACKET_L/g, "");
627
+ result = result.replace(/\\DELETE_BRACKET_R/g, "");
626
628
 
627
629
  // Xử lý các trường hợp mũi tên với giới hạn
628
630
  result = result.replace(/→\\limits_{}/g, "\\underset{}{\\rightarrow}");
629
631
  result = result.replace(/→\\limits_{(\s*)}/g, "\\underset{}{\\rightarrow}");
630
- result = result.replace(/\\rightarrow\\limits_{}/g, "\\underset{}{\\rightarrow}");
631
- result = result.replace(/\\rightarrow\\limits_{(\s*)}/g, "\\underset{}{\\rightarrow}");
632
-
633
- result = result.replace(/→\\limits_\{([^}]*)\}/g, "\\underset{$1}{\\rightarrow}");
634
- result = result.replace(/\\rightarrow\\limits_\{([^}]*)\}/g, "\\underset{$1}{\\rightarrow}");
635
-
636
- result = result.replace(/→\\limits_\{([^}]*)\}\^\{([^}]*)\}/g, "\\overset{$2}{\\underset{$1}{\\rightarrow}}");
637
- result = result.replace(/\\rightarrow\\limits_\{([^}]*)\}\^\{([^}]*)\}/g, "\\overset{$2}{\\underset{$1}{\\rightarrow}}");
632
+ result = result.replace(
633
+ /\\rightarrow\\limits_{}/g,
634
+ "\\underset{}{\\rightarrow}"
635
+ );
636
+ result = result.replace(
637
+ /\\rightarrow\\limits_{(\s*)}/g,
638
+ "\\underset{}{\\rightarrow}"
639
+ );
640
+
641
+ result = result.replace(
642
+ /→\\limits_\{([^}]*)\}/g,
643
+ "\\underset{$1}{\\rightarrow}"
644
+ );
645
+ result = result.replace(
646
+ /\\rightarrow\\limits_\{([^}]*)\}/g,
647
+ "\\underset{$1}{\\rightarrow}"
648
+ );
649
+
650
+ result = result.replace(
651
+ /→\\limits_\{([^}]*)\}\^\{([^}]*)\}/g,
652
+ "\\overset{$2}{\\underset{$1}{\\rightarrow}}"
653
+ );
654
+ result = result.replace(
655
+ /\\rightarrow\\limits_\{([^}]*)\}\^\{([^}]*)\}/g,
656
+ "\\overset{$2}{\\underset{$1}{\\rightarrow}}"
657
+ );
638
658
 
639
659
  // Xử lý vector và các ký hiệu đặc biệt
640
- result = result.replace(/([^{}\s]+)\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
641
- result = result.replace(/\{([^{}]+)\}\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
642
- result = result.replace(/([A-Za-z0-9]+)_\{([^{}]+)\}\^\{\\rightarrow\}/g, "\\overrightarrow{$1_{$2}}");
643
- result = result.replace(/([A-Za-z0-9]+)_([0-9])\^\{\\rightarrow\}/g, "\\overrightarrow{$1_$2}");
644
- result = result.replace(/(\([^()]+\))\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
660
+ result = result.replace(
661
+ /([^{}\s]+)\^\{\\rightarrow\}/g,
662
+ "\\overrightarrow{$1}"
663
+ );
664
+ result = result.replace(
665
+ /\{([^{}]+)\}\^\{\\rightarrow\}/g,
666
+ "\\overrightarrow{$1}"
667
+ );
668
+ result = result.replace(
669
+ /([A-Za-z0-9]+)_\{([^{}]+)\}\^\{\\rightarrow\}/g,
670
+ "\\overrightarrow{$1_{$2}}"
671
+ );
672
+ result = result.replace(
673
+ /([A-Za-z0-9]+)_([0-9])\^\{\\rightarrow\}/g,
674
+ "\\overrightarrow{$1_$2}"
675
+ );
676
+ result = result.replace(
677
+ /(\([^()]+\))\^\{\\rightarrow\}/g,
678
+ "\\overrightarrow{$1}"
679
+ );
645
680
 
646
681
  // Remove or comment out these lines in toLatex function
647
682
  // Thêm xử lý các ký hiệu toán học phổ biến
@@ -669,7 +704,7 @@ function parse(node) {
669
704
  // @see https://www.w3.org/TR/MathML3/chapter7.html
670
705
  // Cải tiến parseLeaf để hỗ trợ thêm các ký hiệu
671
706
  function parseLeaf(node) {
672
- let r = '';
707
+ let r = "";
673
708
  const nodeName = NodeTool.getNodeName(node);
674
709
 
675
710
  if (nodeName === "mrow" && NodeTool.getNodeText(node).trim() === "") {
@@ -677,32 +712,32 @@ function parseLeaf(node) {
677
712
  }
678
713
 
679
714
  switch (nodeName) {
680
- case 'mi':
715
+ case "mi":
681
716
  r = parseElementMi(node);
682
717
  break;
683
- case 'mn':
718
+ case "mn":
684
719
  r = parseElementMn(node);
685
720
  break;
686
- case 'mo':
721
+ case "mo":
687
722
  r = parseOperator(node);
688
723
  break;
689
- case 'ms':
724
+ case "ms":
690
725
  r = parseElementMs(node);
691
726
  break;
692
- case 'mtext':
727
+ case "mtext":
693
728
  r = parseElementMtext(node);
694
729
  break;
695
- case 'mglyph':
730
+ case "mglyph":
696
731
  r = parseElementMglyph(node);
697
732
  break;
698
- case 'mprescripts':
699
- r = '';
733
+ case "mprescripts":
734
+ r = "";
700
735
  break;
701
- case 'mspace':
736
+ case "mspace":
702
737
  r = parseElementMspace();
703
738
  break;
704
- case 'none':
705
- r = '\\:';
739
+ case "none":
740
+ r = "\\:";
706
741
  break;
707
742
  default:
708
743
  r = escapeSpecialChars(NodeTool.getNodeText(node).trim());
@@ -711,10 +746,10 @@ function parseLeaf(node) {
711
746
  return r;
712
747
  }
713
748
 
714
- // Cải tiến parseOperator để hỗ trợ thêm toán tử
749
+ // --- PATCH by AI: Fix for set-builder notation and fraction output ---
750
+ // 1. Extend operatorMap and add π->\pi, |->\mid
715
751
  function parseOperator(node) {
716
752
  let it = NodeTool.getNodeText(node).trim();
717
-
718
753
  const operatorMap = {
719
754
  "→": " \\rightarrow ",
720
755
  "←": " \\leftarrow ",
@@ -733,12 +768,14 @@ function parseOperator(node) {
733
768
  ">": " > ",
734
769
  "=": " = ",
735
770
  ",": ", ", // Dấu phẩy trong tập hợp
736
- ";": ";", // Dấu chấm phẩy không cần khoảng trắng
737
- "Ω": "\\Omega" // Thêm ký hiệu Omega
771
+ ";": ";",
772
+ Ω: "\\Omega",
773
+ "|": " \\mid ", // PATCH: set-builder mid
774
+ π: " \\pi ", // PATCH: Greek letter
738
775
  };
739
-
740
776
  return operatorMap[it] || escapeSpecialChars(MathSymbol.parseOperator(it));
741
777
  }
778
+ // --- END PATCH ---
742
779
 
743
780
  // Math identifier
744
781
  function parseElementMi(node) {
@@ -746,7 +783,7 @@ function parseElementMi(node) {
746
783
 
747
784
  // Handle vectors (e.g. AB', AI)
748
785
  if (it.includes("'")) {
749
- return it; // Return as is to handle in mrow
786
+ return it; // Return as is to handle in mrow
750
787
  }
751
788
 
752
789
  // Handle subscripts (e.g. n₂)
@@ -770,27 +807,41 @@ function parseElementMn(node) {
770
807
  function parseElementMs(node) {
771
808
  const content = NodeTool.getNodeText(node).trimRight();
772
809
  const it = escapeSpecialChars(content);
773
- return ['"', it, '"'].join('');
810
+ return ['"', it, '"'].join("");
774
811
  }
775
812
 
776
813
  // Math Text
777
814
  function parseElementMtext(node) {
778
815
  let content = NodeTool.getNodeText(node)
779
816
  // Handle operators and spacing only
780
- .replace(/\s*=\s*/g, ' = ')
781
- .replace(/\s*\.\s*/g, ' \\cdot ')
817
+ .replace(/\s*=\s*/g, " = ")
818
+ .replace(/\s*\.\s*/g, " \\cdot ")
782
819
  .trim();
783
820
 
821
+ const specialMTextMap = {
822
+ ℝ: "\\mathbb{R}",
823
+ ℤ: "\\mathbb{Z}",
824
+ ℕ: "\\mathbb{N}",
825
+ ℚ: "\\mathbb{Q}",
826
+ ℂ: "\\mathbb{C}",
827
+ "\\": "\\setminus ",
828
+ "|": "\\mid ",
829
+ " ": "",
830
+ };
831
+ if (specialMTextMap[content]) return specialMTextMap[content];
832
+
784
833
  // Handle units with proper \mathrm formatting
785
- if (content.includes('(') && content.includes(')')) {
834
+ if (content.includes("(") && content.includes(")")) {
786
835
  const parts = content.split(/(\([^)]+\))/);
787
- content = parts.map(part => {
788
- if (part.startsWith('(') && part.endsWith(')')) {
789
- // Keep original characters in units
790
- return `\\mathrm{${part}}`;
791
- }
792
- return part;
793
- }).join('');
836
+ content = parts
837
+ .map((part) => {
838
+ if (part.startsWith("(") && part.endsWith(")")) {
839
+ // Keep original characters in units
840
+ return `\\mathrm{${part}}`;
841
+ }
842
+ return part;
843
+ })
844
+ .join("");
794
845
  }
795
846
 
796
847
  return content;
@@ -798,84 +849,124 @@ function parseElementMtext(node) {
798
849
 
799
850
  // Math glyph (image)
800
851
  function parseElementMglyph(node) {
801
- const it = ['"', NodeTool.getAttr(node, 'alt', ''), '"'].join('');
852
+ const it = ['"', NodeTool.getAttr(node, "alt", ""), '"'].join("");
802
853
  return escapeSpecialChars(it);
803
854
  }
804
855
 
805
856
  // TODO need or not
806
857
  function parseElementMspace(node) {
807
- return '';
858
+ return "";
808
859
  }
809
860
 
810
861
  function escapeSpecialChars(text) {
862
+ // Don't escape pi, Greek, or just a-z0-9 or Unicode Greek, or empty
863
+ if (
864
+ /^\\?[a-zA-Z0-9]+$/.test(text) ||
865
+ /^\\(?:pi|alpha|beta|gamma|Omega)$/.test(text) ||
866
+ /^π$/.test(text) ||
867
+ !text
868
+ ) {
869
+ return text;
870
+ }
871
+ // Otherwise escape only true reserved LaTeX
811
872
  const specialChars = /\$|%|_|&|#|\{|\}/g;
812
- text = text.replace(specialChars, char => `\\${char}`);
873
+ text = text.replace(specialChars, (char) => `\\${char}`);
813
874
  return text;
814
875
  }
815
876
 
816
-
817
877
  function parseContainer(node, children) {
818
878
  const render = getRender(node);
819
879
  if (render) {
820
880
  return render(node, children);
821
881
  } else {
822
- throw new Error(`Couldn't get render function for container node: ${NodeTool.getNodeName(node)}`);
882
+ throw new Error(
883
+ `Couldn't get render function for container node: ${NodeTool.getNodeName(
884
+ node
885
+ )}`
886
+ );
823
887
  }
824
888
  }
825
889
 
826
890
  function renderChildren(children) {
827
891
  const parts = [];
828
892
  let lefts = [];
829
- Array.prototype.forEach.call(children, (node) => {
830
- if (NodeTool.getNodeName(node) === 'mo') {
893
+
894
+ // PATCH: Special case for set-builder style: leading { ... trailing }
895
+ if (
896
+ children.length >= 3 &&
897
+ NodeTool.getNodeName(children[0]) === "mo" &&
898
+ NodeTool.getNodeText(children[0]).trim() === "{" &&
899
+ NodeTool.getNodeName(children[children.length - 1]) === "mo" &&
900
+ NodeTool.getNodeText(children[children.length - 1]).trim() === "}"
901
+ ) {
902
+ // Render inner content
903
+ const innerContent = Array.prototype.slice
904
+ .call(children, 1, -1)
905
+ .map((child) => parse(child))
906
+ .join("");
907
+ return `\\left\\{${innerContent}\\right\\}`;
908
+ }
909
+
910
+ Array.prototype.forEach.call(children, (node, idx) => {
911
+ // PATCH: Thin space between variables/numbers in mfrac numerator (k 2 π)
912
+ if (
913
+ NodeTool.getNodeName(node) === "mrow" &&
914
+ node.parentNode &&
915
+ NodeTool.getNodeName(node.parentNode) === "mfrac"
916
+ ) {
917
+ const mrowKids = Array.from(NodeTool.getChildren(node));
918
+ if (
919
+ mrowKids.every((n) =>
920
+ ["mi", "mn", "mo"].includes(NodeTool.getNodeName(n))
921
+ )
922
+ ) {
923
+ // Only vars, nums, ops (possibly Greek); join with thin space
924
+ const str = mrowKids.map((k) => parse(k)).join("\\,");
925
+ parts.push(str);
926
+ return;
927
+ }
928
+ }
929
+ // END PATCH
930
+ if (NodeTool.getNodeName(node) === "mo") {
831
931
  const op = NodeTool.getNodeText(node).trim();
832
932
  if (Brackets.contains(op)) {
833
- let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
834
- stretchy = ['', 'true'].indexOf(stretchy) > -1;
933
+ let stretchy = NodeTool.getAttr(node, "stretchy", "true");
934
+ stretchy = ["", "true"].indexOf(stretchy) > -1;
935
+
936
+ // Luôn escape dấu ngoặc nhọn cho LaTeX
937
+ let escapedOp = op;
938
+ if (op === "{" || op === "}") {
939
+ escapedOp = `\\${op}`;
940
+ }
835
941
 
836
942
  if (Brackets.isRight(op)) {
837
943
  const nearLeft = lefts[lefts.length - 1];
838
- if (nearLeft) {
839
- if (Brackets.isPair(nearLeft, op)) {
840
- // Kiểm tra xem có phải là một phần của biểu thức mũ không
841
- const parentNode = node.parentNode;
842
- const nextSibling = node.nextSibling;
843
- const prevSibling = node.previousSibling;
844
-
845
- const isInPower = parentNode && (
846
- NodeTool.getNodeName(parentNode) === 'msup' ||
847
- (nextSibling && NodeTool.getNodeName(nextSibling) === 'msup') ||
848
- (prevSibling && NodeTool.getNodeName(prevSibling) === 'msup')
849
- );
850
-
851
- if (isInPower) {
852
- parts.push(op); // Không thêm \right cho ngoặc trong mũ
853
- } else {
854
- parts.push(op); // Chỉ thêm dấu ngoặc đơn giản
855
- }
856
- lefts.pop();
944
+ if (nearLeft && Brackets.isPair(nearLeft, op)) {
945
+ const parentNode = node.parentNode;
946
+ const isInPower =
947
+ parentNode && NodeTool.getNodeName(parentNode) === "msup";
948
+
949
+ if (stretchy && !isInPower) {
950
+ parts.push(`\\right${escapedOp}`); // Dùng escapedOp
857
951
  } else {
858
- parts.push(op);
952
+ parts.push(escapedOp); // Dùng escapedOp
859
953
  }
954
+ lefts.pop();
860
955
  } else {
861
- parts.push(op);
956
+ parts.push(escapedOp); // Ngoặc phải không khớp
862
957
  }
863
958
  } else {
864
- // Kiểm tra cho dấu ngoặc mở
959
+ // ngoặc trái
865
960
  const parentNode = node.parentNode;
866
- const nextSibling = node.nextSibling;
867
-
868
- const isInPower = parentNode && (
869
- NodeTool.getNodeName(parentNode) === 'msup' ||
870
- (nextSibling && NodeTool.getNodeName(nextSibling) === 'msup')
871
- );
872
-
873
- if (isInPower) {
874
- parts.push(op); // Không thêm \left cho ngoặc trong mũ
961
+ const isInPower =
962
+ parentNode && NodeTool.getNodeName(parentNode) === "msup";
963
+
964
+ if (stretchy && !isInPower) {
965
+ parts.push(`\\left${escapedOp}`); // Dùng escapedOp
875
966
  } else {
876
- parts.push(op); // Chỉ thêm dấu ngoặc đơn giản
967
+ parts.push(escapedOp); // Dùng escapedOp
877
968
  }
878
- lefts.push(op);
969
+ lefts.push(op); // Dùng `op` gốc để so sánh cặp
879
970
  }
880
971
  } else {
881
972
  parts.push(parseOperator(node));
@@ -884,7 +975,6 @@ function renderChildren(children) {
884
975
  parts.push(parse(node));
885
976
  }
886
977
  });
887
-
888
978
  lefts = undefined;
889
979
  return parts;
890
980
  }
@@ -894,41 +984,49 @@ function getRender(node) {
894
984
  const nodeName = NodeTool.getNodeName(node);
895
985
 
896
986
  switch (nodeName) {
897
- case 'mrow':
987
+ case "mrow":
898
988
  render = function (node, children) {
899
989
  const childrenArray = Array.from(children);
900
- if (childrenArray.length >= 2 &&
901
- NodeTool.getNodeName(childrenArray[0]) === 'mo' &&
902
- NodeTool.getNodeName(childrenArray[childrenArray.length - 1]) === 'mo') {
990
+ if (
991
+ childrenArray.length >= 2 &&
992
+ NodeTool.getNodeName(childrenArray[0]) === "mo" &&
993
+ NodeTool.getNodeName(childrenArray[childrenArray.length - 1]) === "mo"
994
+ ) {
903
995
  const firstOp = NodeTool.getNodeText(childrenArray[0]).trim();
904
- const lastOp = NodeTool.getNodeText(childrenArray[childrenArray.length - 1]).trim();
996
+ const lastOp = NodeTool.getNodeText(
997
+ childrenArray[childrenArray.length - 1]
998
+ ).trim();
905
999
 
906
1000
  // Xử lý đặc biệt cho dấu ngoặc nhọn chứa mtable
907
- if (firstOp === '{' && childrenArray.some(child =>
908
- NodeTool.getNodeName(child) === 'mtable')) {
1001
+ if (
1002
+ firstOp === "{" &&
1003
+ childrenArray.some(
1004
+ (child) => NodeTool.getNodeName(child) === "mtable"
1005
+ )
1006
+ ) {
909
1007
  const innerContent = childrenArray
910
1008
  .slice(1, -1)
911
- .map(child => parse(child))
912
- .join('');
1009
+ .map((child) => parse(child))
1010
+ .join("");
913
1011
  return `\\left\\{${innerContent}\\right.`;
914
1012
  }
915
1013
 
916
1014
  // Xử lý cho trường hợp [a;b) và [a,b)
917
- if (firstOp === '[' && lastOp === ')') {
1015
+ if (firstOp === "[" && lastOp === ")") {
918
1016
  const innerContent = childrenArray
919
1017
  .slice(1, -1)
920
- .map(child => parse(child))
921
- .join('');
1018
+ .map((child) => parse(child))
1019
+ .join("");
922
1020
  return `\\left[${innerContent}\\right)`;
923
1021
  }
924
1022
 
925
1023
  // Xử lý ngoặc nhọn bình thường
926
- if (firstOp === '{' && lastOp === '}') {
1024
+ if (firstOp === "{" && lastOp === "}") {
927
1025
  const innerContent = childrenArray
928
1026
  .slice(1, -1)
929
- .map(child => parse(child))
930
- .join('');
931
- return `\\{${innerContent}\\}`;
1027
+ .map((child) => parse(child))
1028
+ .join("");
1029
+ return `\\left\\{${innerContent}\\right\\}`;
932
1030
  }
933
1031
 
934
1032
  // Bỏ qua nếu firstOp là rỗng (trường hợp <mo></mo>)
@@ -936,33 +1034,55 @@ function getRender(node) {
936
1034
  return getRender_joinSeparator("@content")(node, childrenArray);
937
1035
  }
938
1036
 
1037
+ if (firstOp === "[" && lastOp === "]") {
1038
+ const innerContent = childrenArray
1039
+ .slice(1, -1)
1040
+ .map((child) => parse(child))
1041
+ .join("");
1042
+ return `[${innerContent}]`;
1043
+ }
1044
+
939
1045
  // Xử lý đặc biệt cho dấu ngoặc vuông chứa mtable
940
- if (firstOp === '[') {
1046
+ if (firstOp === "[") {
941
1047
  const innerContent = childrenArray
942
1048
  .slice(1, -1) // Bỏ dấu ngoặc mở và đóng
943
- .map(child => {
1049
+ .map((child) => {
944
1050
  const parsed = parse(child);
945
1051
  // Nếu child là mtable, trả về nội dung đã được định dạng với \begin{array}{l} ... \end{array}
946
- if (NodeTool.getNodeName(child) === 'mtable') {
947
- const rows = Array.from(NodeTool.getChildren(child)).map(row => {
948
- const rowChildren = Array.from(NodeTool.getChildren(row));
949
- return rowChildren.map(cell => parse(cell)).join('');
950
- });
951
- return `\\begin{array}{l} ${rows.join(' \\\\ ')} \\end{array}`;
1052
+ if (NodeTool.getNodeName(child) === "mtable") {
1053
+ const rows = Array.from(NodeTool.getChildren(child)).map(
1054
+ (row) => {
1055
+ const rowChildren = Array.from(NodeTool.getChildren(row));
1056
+ return rowChildren.map((cell) => parse(cell)).join("");
1057
+ }
1058
+ );
1059
+ return `\\begin{array}{l} ${rows.join(
1060
+ " \\\\ "
1061
+ )} \\end{array}`;
952
1062
  }
953
1063
  // Nếu child là mrow chứa mtable, xử lý tương tự
954
- if (NodeTool.getNodeName(child) === 'mrow' &&
955
- Array.from(NodeTool.getChildren(child)).some(c => NodeTool.getNodeName(c) === 'mtable')) {
956
- const mtableChild = Array.from(NodeTool.getChildren(child)).find(c => NodeTool.getNodeName(c) === 'mtable');
957
- const rows = Array.from(NodeTool.getChildren(mtableChild)).map(row => {
1064
+ if (
1065
+ NodeTool.getNodeName(child) === "mrow" &&
1066
+ Array.from(NodeTool.getChildren(child)).some(
1067
+ (c) => NodeTool.getNodeName(c) === "mtable"
1068
+ )
1069
+ ) {
1070
+ const mtableChild = Array.from(
1071
+ NodeTool.getChildren(child)
1072
+ ).find((c) => NodeTool.getNodeName(c) === "mtable");
1073
+ const rows = Array.from(
1074
+ NodeTool.getChildren(mtableChild)
1075
+ ).map((row) => {
958
1076
  const rowChildren = Array.from(NodeTool.getChildren(row));
959
- return rowChildren.map(cell => parse(cell)).join('');
1077
+ return rowChildren.map((cell) => parse(cell)).join("");
960
1078
  });
961
- return `\\begin{array}{l} ${rows.join(' \\\\ ')} \\end{array}`;
1079
+ return `\\begin{array}{l} ${rows.join(
1080
+ " \\\\ "
1081
+ )} \\end{array}`;
962
1082
  }
963
1083
  return parsed;
964
1084
  })
965
- .join('');
1085
+ .join("");
966
1086
 
967
1087
  // Giữ nguyên dấu ngoặc vuông lớn
968
1088
  return `\\left[${innerContent}\\right.`;
@@ -971,36 +1091,41 @@ function getRender(node) {
971
1091
  if (Brackets.isPair(firstOp, lastOp)) {
972
1092
  const innerContent = childrenArray
973
1093
  .slice(1, -1)
974
- .map(child => parse(child))
975
- .join('');
1094
+ .map((child) => parse(child))
1095
+ .join("");
976
1096
  return `\\left${firstOp}${innerContent}\\right${lastOp}`;
977
1097
  }
978
1098
 
979
1099
  // Giữ nguyên dấu ngoặc nhọn trong MathML
980
- if (firstOp === '{' || lastOp === '}') {
1100
+ if (firstOp === "{" || lastOp === "}") {
981
1101
  const innerContent = childrenArray
982
- .slice(1, lastOp === '}' ? -1 : undefined)
983
- .map(child => parse(child))
984
- .join('');
985
- return `${firstOp === '{' ? '\\{' : ''}${innerContent}${lastOp === '}' ? '\\}' : ''}`;
1102
+ .slice(1, lastOp === "}" ? -1 : undefined)
1103
+ .map((child) => parse(child))
1104
+ .join("");
1105
+ return `${firstOp === "{" ? "\\{" : ""}${innerContent}${
1106
+ lastOp === "}" ? "\\}" : ""
1107
+ }`;
986
1108
  }
987
1109
  }
988
1110
  return getRender_joinSeparator("@content")(node, childrenArray);
989
1111
  };
990
1112
  break;
991
1113
 
992
- case 'msub':
1114
+ case "msub":
993
1115
  render = function (node, children) {
994
1116
  const childrenArray = Array.from(children);
995
- if (!childrenArray || childrenArray.length < 2) return '';
996
- const base = parse(childrenArray[0]) || '';
1117
+ if (!childrenArray || childrenArray.length < 2) return "";
1118
+ const base = parse(childrenArray[0]) || "";
997
1119
  const sub = childrenArray[1];
998
1120
  if (!sub) return base;
999
1121
 
1000
- if (NodeTool.getNodeName(sub) === 'msub' &&
1122
+ if (
1123
+ NodeTool.getNodeName(sub) === "msub" &&
1001
1124
  sub.firstChild &&
1002
- NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
1003
- (!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
1125
+ NodeTool.getNodeName(sub.firstChild) === "mrow" &&
1126
+ (!NodeTool.getNodeText(sub.firstChild) ||
1127
+ NodeTool.getNodeText(sub.firstChild).trim() === "")
1128
+ ) {
1004
1129
  const lastChild = sub.lastChild;
1005
1130
  return lastChild ? `${base}_${parse(lastChild)}` : base;
1006
1131
  }
@@ -1008,52 +1133,57 @@ function getRender(node) {
1008
1133
  };
1009
1134
  break;
1010
1135
 
1011
- case 'msup':
1136
+ case "msup":
1012
1137
  render = function (node, children) {
1013
1138
  const childrenArray = Array.from(children);
1014
- if (!childrenArray || childrenArray.length < 2) return '';
1015
- const base = parse(childrenArray[0]) || '';
1016
- const sup = parse(childrenArray[1]) || '';
1139
+ if (!childrenArray || childrenArray.length < 2) return "";
1140
+ const base = parse(childrenArray[0]) || "";
1141
+ const sup = parse(childrenArray[1]) || "";
1017
1142
  return `${base}^{${sup}}`;
1018
1143
  };
1019
1144
  break;
1020
1145
 
1021
- case 'msubsup':
1146
+ case "msubsup":
1022
1147
  render = function (node, children) {
1023
1148
  const childrenArray = Array.from(children);
1024
- if (!childrenArray || childrenArray.length < 3) return '';
1149
+ if (!childrenArray || childrenArray.length < 3) return "";
1025
1150
  const base = parse(childrenArray[0]);
1026
1151
  const sub = parse(childrenArray[1]);
1027
1152
  const sup = parse(childrenArray[2]);
1028
1153
 
1029
1154
  const lastChild = childrenArray[0].lastElementChild;
1030
- if (lastChild && NodeTool.getNodeName(lastChild) === 'mo' &&
1031
- NodeTool.getNodeText(lastChild).trim() === '|') {
1155
+ if (
1156
+ lastChild &&
1157
+ NodeTool.getNodeName(lastChild) === "mo" &&
1158
+ NodeTool.getNodeText(lastChild).trim() === "|"
1159
+ ) {
1032
1160
  const content = Array.from(childrenArray[0].children)
1033
1161
  .slice(0, -1)
1034
- .map(child => parse(child))
1035
- .join('');
1162
+ .map((child) => parse(child))
1163
+ .join("");
1036
1164
  return `\\left.${content}\\right|_{${sub}}^{${sup}}`;
1037
1165
  }
1038
1166
  return `${base}_{${sub}}^{${sup}}`;
1039
1167
  };
1040
1168
  break;
1041
1169
 
1042
- case 'mover':
1170
+ case "mover":
1043
1171
  render = function (node, children) {
1044
1172
  const childrenArray = Array.from(children);
1045
- if (!childrenArray || childrenArray.length < 2) return '';
1046
- const base = parse(childrenArray[0]) || '';
1047
- const over = parse(childrenArray[1]) || '';
1048
- const overText = NodeTool.getNodeText(childrenArray[1])?.trim() || '';
1173
+ if (!childrenArray || childrenArray.length < 2) return "";
1174
+ const base = parse(childrenArray[0]) || "";
1175
+ const over = parse(childrenArray[1]) || "";
1176
+ const overText = NodeTool.getNodeText(childrenArray[1])?.trim() || "";
1049
1177
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1050
1178
 
1051
1179
  // Handle biology notation (double overline)
1052
1180
  if (overText === "¯") {
1053
1181
  const parentNode = node.parentNode;
1054
1182
  // Check if this is part of a double overline structure
1055
- if (NodeTool.getNodeName(parentNode) === 'mover' &&
1056
- NodeTool.getNodeText(parentNode.lastChild)?.trim() === '¯') {
1183
+ if (
1184
+ NodeTool.getNodeName(parentNode) === "mover" &&
1185
+ NodeTool.getNodeText(parentNode.lastChild)?.trim() === "¯"
1186
+ ) {
1057
1187
  return `\\overline{${base}}`;
1058
1188
  }
1059
1189
  return `\\overline{${base}}`;
@@ -1065,55 +1195,68 @@ function getRender(node) {
1065
1195
  };
1066
1196
  break;
1067
1197
 
1068
- case 'munder':
1198
+ case "munder":
1069
1199
  render = function (node, children) {
1070
1200
  const childrenArray = Array.from(children);
1071
- if (!childrenArray || childrenArray.length < 2) return '';
1072
- const base = parse(childrenArray[0]) || '';
1073
- const under = parse(childrenArray[1]) || '';
1074
- const isUnderAccent = NodeTool.getAttr(node, "accentunder", "false") === "true";
1201
+ if (!childrenArray || childrenArray.length < 2) return "";
1202
+ const base = parse(childrenArray[0]) || "";
1203
+ const under = parse(childrenArray[1]) || "";
1204
+ const isUnderAccent =
1205
+ NodeTool.getAttr(node, "accentunder", "false") === "true";
1075
1206
 
1076
1207
  if (base === "∫") return `\\int_{${under}}`;
1077
1208
  return `\\underset{${under}}{${base}}`;
1078
1209
  };
1079
1210
  break;
1080
1211
 
1081
- case 'munderover':
1212
+ case "munderover":
1082
1213
  render = function (node, children) {
1083
1214
  const childrenArray = Array.from(children);
1084
- if (!childrenArray || childrenArray.length < 3) return '';
1215
+ if (!childrenArray || childrenArray.length < 3) return "";
1085
1216
  const base = parse(childrenArray[0]);
1086
1217
  const under = parse(childrenArray[1]);
1087
1218
  const over = parse(childrenArray[2]);
1088
1219
  const baseText = NodeTool.getNodeText(childrenArray[0]).trim();
1089
1220
 
1090
- if (baseText === '∫') return `\\int_{${under}}^{${over}}`;
1091
- if (baseText === '∑') return `\\sum_{${under}}^{${over}}`;
1092
- if (baseText === '∏') return `\\prod_{${under}}^{${over}}`;
1093
- if (baseText === '|') return `\\big|_{${under}}^{${over}}`;
1221
+ // Special handling for chemical reaction arrow
1222
+ if (
1223
+ baseText === "→" &&
1224
+ NodeTool.getNodeName(childrenArray[1]) === "msup"
1225
+ ) {
1226
+ return `\\xrightarrow[${under}]{${over}}`;
1227
+ }
1228
+
1229
+ if (baseText === "∫") return `\\int_{${under}}^{${over}}`;
1230
+ if (baseText === "∑") return `\\sum_{${under}}^{${over}}`;
1231
+ if (baseText === "∏") return `\\prod_{${under}}^{${over}}`;
1232
+ if (baseText === "|") return `\\big|_{${under}}^{${over}}`;
1094
1233
  return `${base}_{${under}}^{${over}}`;
1095
1234
  };
1096
1235
  break;
1097
1236
 
1098
- case 'mmultiscripts':
1237
+ case "mmultiscripts":
1099
1238
  render = function (node, children) {
1100
1239
  const childrenArray = Array.from(children);
1101
- if (!childrenArray || childrenArray.length < 1) return '';
1240
+ if (!childrenArray || childrenArray.length < 1) return "";
1102
1241
  const base = parse(childrenArray[0]);
1103
- let prescripts = '';
1104
- let postscripts = '';
1242
+ let prescripts = "";
1243
+ let postscripts = "";
1105
1244
  let i = 1;
1106
1245
 
1107
1246
  while (i < childrenArray.length) {
1108
- if (NodeTool.getNodeName(childrenArray[i]) === 'mprescripts') {
1247
+ if (NodeTool.getNodeName(childrenArray[i]) === "mprescripts") {
1109
1248
  i++;
1110
1249
  if (i + 1 < childrenArray.length) {
1111
- prescripts = `_{${parse(childrenArray[i])}}^{${parse(childrenArray[i + 1])}}`;
1250
+ prescripts = `_{${parse(childrenArray[i])}}^{${parse(
1251
+ childrenArray[i + 1]
1252
+ )}}`;
1112
1253
  i += 2;
1113
1254
  }
1114
1255
  } else {
1115
1256
  if (i + 1 < childrenArray.length) {
1116
- postscripts += `_{${parse(childrenArray[i])}}^{${parse(childrenArray[i + 1])}}`;
1257
+ postscripts += `_{${parse(childrenArray[i])}}^{${parse(
1258
+ childrenArray[i + 1]
1259
+ )}}`;
1117
1260
  i += 2;
1118
1261
  } else break;
1119
1262
  }
@@ -1122,33 +1265,35 @@ function getRender(node) {
1122
1265
  };
1123
1266
  break;
1124
1267
 
1125
- case 'mlongdiv':
1268
+ case "mlongdiv":
1126
1269
  render = function (node, children) {
1127
1270
  const childrenArray = Array.from(children);
1128
- if (!childrenArray || childrenArray.length < 2) return '';
1129
- return `\\longdiv{${parse(childrenArray[0])}}{${parse(childrenArray[1])}}`;
1271
+ if (!childrenArray || childrenArray.length < 2) return "";
1272
+ return `\\longdiv{${parse(childrenArray[0])}}{${parse(
1273
+ childrenArray[1]
1274
+ )}}`;
1130
1275
  };
1131
1276
  break;
1132
1277
 
1133
- case 'mroot':
1278
+ case "mroot":
1134
1279
  render = function (node, children) {
1135
1280
  const childrenArray = Array.from(children);
1136
- if (!childrenArray || childrenArray.length < 2) return '';
1281
+ if (!childrenArray || childrenArray.length < 2) return "";
1137
1282
  const base = parse(childrenArray[0]);
1138
1283
  const index = parse(childrenArray[1]);
1139
1284
  return `\\sqrt[${index}]{${base}}`;
1140
1285
  };
1141
1286
  break;
1142
1287
 
1143
- case 'msqrt':
1288
+ case "msqrt":
1144
1289
  render = function (node, children) {
1145
1290
  const childrenArray = Array.from(children);
1146
- const content = renderChildren(childrenArray).join('');
1291
+ const content = renderChildren(childrenArray).join("");
1147
1292
  return `\\sqrt{${content}}`;
1148
1293
  };
1149
1294
  break;
1150
1295
 
1151
- case 'mtable':
1296
+ case "mtable":
1152
1297
  render = function (node, children) {
1153
1298
  const childrenArray = Array.from(children);
1154
1299
 
@@ -1156,7 +1301,7 @@ function getRender(node) {
1156
1301
  let isNestedTable = false;
1157
1302
  let parent = node.parentNode;
1158
1303
  while (parent) {
1159
- if (NodeTool.getNodeName(parent) === 'mtable') {
1304
+ if (NodeTool.getNodeName(parent) === "mtable") {
1160
1305
  isNestedTable = true;
1161
1306
  break;
1162
1307
  }
@@ -1164,25 +1309,27 @@ function getRender(node) {
1164
1309
  }
1165
1310
 
1166
1311
  // Xử lý mỗi mtr như một hàng
1167
- const rows = childrenArray.map(row => {
1312
+ const rows = childrenArray.map((row) => {
1168
1313
  const rowChildren = Array.from(NodeTool.getChildren(row));
1169
- return rowChildren.map(cell => parse(cell)).join('');
1314
+ return rowChildren.map((cell) => parse(cell)).join("");
1170
1315
  });
1171
1316
 
1172
1317
  // Nếu là mtable con, chỉ trả về các hàng mà không bao bọc trong \begin{array}...\end{array}
1173
1318
  if (isNestedTable) {
1174
- return rows.join(' \\\\ ');
1319
+ return rows.join(" \\\\ ");
1175
1320
  }
1176
1321
 
1177
1322
  // Nếu mtable nằm trong mrow với dấu ngoặc vuông, sẽ được xử lý ở mrow
1178
1323
  let isInsideSquareBrackets = false;
1179
1324
  parent = node.parentNode;
1180
1325
  while (parent) {
1181
- if (NodeTool.getNodeName(parent) === 'mrow') {
1326
+ if (NodeTool.getNodeName(parent) === "mrow") {
1182
1327
  const childrenOfParent = Array.from(NodeTool.getChildren(parent));
1183
- if (childrenOfParent.length >= 2 &&
1184
- NodeTool.getNodeName(childrenOfParent[0]) === 'mo' &&
1185
- NodeTool.getNodeText(childrenOfParent[0]).trim() === '[') {
1328
+ if (
1329
+ childrenOfParent.length >= 2 &&
1330
+ NodeTool.getNodeName(childrenOfParent[0]) === "mo" &&
1331
+ NodeTool.getNodeText(childrenOfParent[0]).trim() === "["
1332
+ ) {
1186
1333
  isInsideSquareBrackets = true;
1187
1334
  break;
1188
1335
  }
@@ -1191,151 +1338,166 @@ function getRender(node) {
1191
1338
  }
1192
1339
 
1193
1340
  if (isInsideSquareBrackets) {
1194
- return rows.join(' \\\\ ');
1341
+ return rows.join(" \\\\ ");
1195
1342
  }
1196
1343
 
1197
1344
  // Nếu là mtable chính, bao bọc trong \begin{array}...\end{array}
1198
- const arrayContent = rows.join(' \\\\ ');
1345
+ const arrayContent = rows.join(" \\\\ ");
1199
1346
  return `\\begin{array}{l} ${arrayContent} \\end{array}`;
1200
1347
  };
1201
1348
  break;
1202
1349
 
1203
- case 'mtr':
1350
+ case "mtr":
1204
1351
  render = getRender_joinSeparator("@content", " & ");
1205
1352
  break;
1206
1353
 
1207
- case 'mtd':
1354
+ case "mtd":
1208
1355
  render = getRender_joinSeparator("@content");
1209
1356
  break;
1210
1357
 
1211
- case 'mfrac':
1358
+ case "mfrac":
1212
1359
  render = function (node, children) {
1213
1360
  const childrenArray = Array.from(children);
1214
- if (!childrenArray || childrenArray.length < 2) return '';
1361
+ if (!childrenArray || childrenArray.length < 2) return "";
1215
1362
  const num = parse(childrenArray[0]);
1216
1363
  const den = parse(childrenArray[1]);
1217
- const linethickness = NodeTool.getAttr(node, 'linethickness', 'medium');
1218
- if (linethickness === '0') return `\\binom{${num}}{${den}}`;
1364
+ const linethickness = NodeTool.getAttr(node, "linethickness", "medium");
1365
+ if (linethickness === "0") return `\\binom{${num}}{${den}}`;
1219
1366
  return `\\frac{${num}}{${den}}`;
1220
1367
  };
1221
1368
  break;
1222
1369
 
1223
- case 'mfenced':
1370
+ case "mfenced":
1224
1371
  render = function (node, children) {
1225
1372
  const childrenArray = Array.from(children);
1226
- const open = NodeTool.getAttr(node, 'open', '(');
1227
- const close = NodeTool.getAttr(node, 'close', ')');
1228
- const separators = NodeTool.getAttr(node, 'separators', ',').split('');
1373
+ const open = NodeTool.getAttr(node, "open", "(");
1374
+ const close = NodeTool.getAttr(node, "close", ")");
1375
+ const separators = NodeTool.getAttr(node, "separators", ",").split("");
1229
1376
 
1230
1377
  // Xử lý đặc biệt cho trường hợp dấu ngoặc đơn |
1231
- if (open === '|') {
1232
- const content = childrenArray.map(child => {
1233
- const parsed = parse(child);
1234
- // Loại bỏ các dấu | thừa và các \left|, \right| không cần thiết
1235
- return parsed
1236
- .replace(/\\left\|/g, '')
1237
- .replace(/\\right\|/g, '')
1238
- .replace(/\\left\./g, '')
1239
- .replace(/\|/g, '');
1240
- }).join('');
1241
-
1378
+ if (open === "|") {
1379
+ const content = childrenArray
1380
+ .map((child) => {
1381
+ const parsed = parse(child);
1382
+ // Loại bỏ các dấu | thừa và các \left|, \right| không cần thiết
1383
+ return parsed
1384
+ .replace(/\\left\|/g, "")
1385
+ .replace(/\\right\|/g, "")
1386
+ .replace(/\\left\./g, "")
1387
+ .replace(/\|/g, "");
1388
+ })
1389
+ .join("");
1390
+
1242
1391
  if (!close) {
1243
1392
  return `\\left|${content}\\right|`;
1244
- } else if (close === '|') {
1393
+ } else if (close === "|") {
1245
1394
  return `\\left|${content}\\right|`;
1246
1395
  }
1247
1396
  }
1248
1397
 
1249
1398
  // Xử lý đặc biệt cho mfenced chứa mtable
1250
- if (open === '{' && !close) {
1399
+ if (open === "{" && !close) {
1251
1400
  // Kiểm tra xem có phải là một phần của biểu thức mũ không
1252
- const hasMtable = childrenArray.some(child => {
1401
+ const hasMtable = childrenArray.some((child) => {
1253
1402
  // Kiểm tra trực tiếp mtable
1254
- if (NodeTool.getNodeName(child) === 'mtable') return true;
1403
+ if (NodeTool.getNodeName(child) === "mtable") return true;
1255
1404
  // Kiểm tra mtable trong mrow
1256
- if (NodeTool.getNodeName(child) === 'mrow') {
1405
+ if (NodeTool.getNodeName(child) === "mrow") {
1257
1406
  return Array.from(NodeTool.getChildren(child)).some(
1258
- grandChild => NodeTool.getNodeName(grandChild) === 'mtable'
1407
+ (grandChild) => NodeTool.getNodeName(grandChild) === "mtable"
1259
1408
  );
1260
1409
  }
1261
1410
  return false;
1262
1411
  });
1263
1412
 
1264
1413
  if (hasMtable) {
1265
- const content = childrenArray.map(child => parse(child)).join('');
1414
+ const content = childrenArray.map((child) => parse(child)).join("");
1266
1415
  return `\\left\\{${content}\\right.`;
1267
1416
  }
1268
1417
  }
1269
1418
 
1270
1419
  // Xử lý cho trường hợp [a;b)
1271
- if (open === '[' && close === ')') {
1420
+ if (open === "[" && close === ")") {
1272
1421
  const parts = [];
1273
1422
  childrenArray.forEach((child, index) => {
1274
1423
  parts.push(parse(child));
1275
- if (index < childrenArray.length - 1 && separators[index % separators.length]) {
1424
+ if (
1425
+ index < childrenArray.length - 1 &&
1426
+ separators[index % separators.length]
1427
+ ) {
1276
1428
  parts.push(separators[index % separators.length]);
1277
1429
  }
1278
1430
  });
1279
- return `\\left[${parts.join('')}\\right)`;
1431
+ return `\\left[${parts.join("")}\\right)`;
1280
1432
  }
1281
1433
 
1282
1434
  // Giữ nguyên xử lý cho các trường hợp khác
1283
1435
  const parts = [];
1284
1436
  childrenArray.forEach((child, index) => {
1285
1437
  parts.push(parse(child));
1286
- if (index < childrenArray.length - 1 && separators[index % separators.length]) {
1438
+ if (
1439
+ index < childrenArray.length - 1 &&
1440
+ separators[index % separators.length]
1441
+ ) {
1287
1442
  parts.push(separators[index % separators.length]);
1288
1443
  }
1289
1444
  });
1290
- const content = parts.join('');
1445
+ const content = parts.join("");
1291
1446
 
1292
- if (open === '{' && close === '}') return `\\{${content}\\}`;
1293
- if (open === '|' && close === '|') return `\\left|${content}\\right|`;
1447
+ if (open === "{" && close === "}") return `\\{${content}\\}`;
1448
+ if (open === "|" && close === "|") return `\\left|${content}\\right|`;
1294
1449
  if (!close) return `\\left${open}${content}\\right.`;
1295
1450
  if (!open) return `\\left.${content}\\right${close}`;
1296
1451
  return `\\left${open}${content}\\right${close}`;
1297
1452
  };
1298
1453
  break;
1299
1454
 
1300
- case 'menclose':
1455
+ case "menclose":
1301
1456
  render = function (node, children) {
1302
1457
  const childrenArray = Array.from(children);
1303
- const notation = NodeTool.getAttr(node, 'notation', 'longdiv');
1304
- const content = renderChildren(childrenArray).join('');
1458
+ const notation = NodeTool.getAttr(node, "notation", "longdiv");
1459
+ const content = renderChildren(childrenArray).join("");
1305
1460
  switch (notation) {
1306
- case 'box': return `\\boxed{${content}}`;
1307
- case 'circle': return `\\enclose{circle}{${content}}`;
1308
- case 'roundedbox': return `\\fbox{${content}}`;
1309
- default: return content;
1461
+ case "box":
1462
+ return `\\boxed{${content}}`;
1463
+ case "circle":
1464
+ return `\\enclose{circle}{${content}}`;
1465
+ case "roundedbox":
1466
+ return `\\fbox{${content}}`;
1467
+ default:
1468
+ return content;
1310
1469
  }
1311
1470
  };
1312
1471
  break;
1313
1472
 
1314
- case 'mi':
1315
- case 'mn':
1316
- case 'mo':
1317
- case 'ms':
1318
- case 'mtext':
1473
+ case "mi":
1474
+ case "mn":
1475
+ case "mo":
1476
+ case "ms":
1477
+ case "mtext":
1319
1478
  render = getRender_joinSeparator("@content");
1320
1479
  break;
1321
1480
 
1322
- case 'mphantom':
1481
+ case "mphantom":
1323
1482
  render = function (node, children) {
1324
1483
  const childrenArray = Array.from(children);
1325
- const content = renderChildren(childrenArray).join('');
1484
+ const content = renderChildren(childrenArray).join("");
1326
1485
  return `\\phantom{${content}}`;
1327
1486
  };
1328
1487
  break;
1329
1488
 
1330
- case 'mstyle':
1489
+ case "mstyle":
1331
1490
  render = function (node, children) {
1332
1491
  const childrenArray = Array.from(children);
1333
- const mathsize = NodeTool.getAttr(node, 'mathsize', 'normal');
1334
- const content = renderChildren(childrenArray).join('');
1492
+ const mathsize = NodeTool.getAttr(node, "mathsize", "normal");
1493
+ const content = renderChildren(childrenArray).join("");
1335
1494
  switch (mathsize) {
1336
- case 'big': return `\\large{${content}}`;
1337
- case 'small': return `\\small{${content}}`;
1338
- default: return content;
1495
+ case "big":
1496
+ return `\\large{${content}}`;
1497
+ case "small":
1498
+ return `\\small{${content}}`;
1499
+ default:
1500
+ return content;
1339
1501
  }
1340
1502
  };
1341
1503
  break;
@@ -1349,7 +1511,7 @@ function getRender(node) {
1349
1511
 
1350
1512
  // Export the convert function
1351
1513
  var mathml2latex = {
1352
- convert: convert
1514
+ convert: convert,
1353
1515
  };
1354
1516
 
1355
1517
  module.exports = mathml2latex;