ed-mathml2tex 0.1.6 → 0.1.8

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