ed-mathml2tex 0.1.6 → 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,41 +1034,55 @@ function getRender(node) {
936
1034
  return getRender_joinSeparator("@content")(node, childrenArray);
937
1035
  }
938
1036
 
939
- if (firstOp === '[' && lastOp === ']') {
1037
+ if (firstOp === "[" && lastOp === "]") {
940
1038
  const innerContent = childrenArray
941
1039
  .slice(1, -1)
942
- .map(child => parse(child))
943
- .join('');
1040
+ .map((child) => parse(child))
1041
+ .join("");
944
1042
  return `[${innerContent}]`;
945
1043
  }
946
1044
 
947
1045
  // Xử lý đặc biệt cho dấu ngoặc vuông chứa mtable
948
- if (firstOp === '[') {
1046
+ if (firstOp === "[") {
949
1047
  const innerContent = childrenArray
950
1048
  .slice(1, -1) // Bỏ dấu ngoặc mở và đóng
951
- .map(child => {
1049
+ .map((child) => {
952
1050
  const parsed = parse(child);
953
1051
  // Nếu child là mtable, trả về nội dung đã được định dạng với \begin{array}{l} ... \end{array}
954
- if (NodeTool.getNodeName(child) === 'mtable') {
955
- const rows = Array.from(NodeTool.getChildren(child)).map(row => {
956
- const rowChildren = Array.from(NodeTool.getChildren(row));
957
- return rowChildren.map(cell => parse(cell)).join('');
958
- });
959
- 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}`;
960
1062
  }
961
1063
  // Nếu child là mrow chứa mtable, xử lý tương tự
962
- if (NodeTool.getNodeName(child) === 'mrow' &&
963
- Array.from(NodeTool.getChildren(child)).some(c => NodeTool.getNodeName(c) === 'mtable')) {
964
- const mtableChild = Array.from(NodeTool.getChildren(child)).find(c => NodeTool.getNodeName(c) === 'mtable');
965
- 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) => {
966
1076
  const rowChildren = Array.from(NodeTool.getChildren(row));
967
- return rowChildren.map(cell => parse(cell)).join('');
1077
+ return rowChildren.map((cell) => parse(cell)).join("");
968
1078
  });
969
- return `\\begin{array}{l} ${rows.join(' \\\\ ')} \\end{array}`;
1079
+ return `\\begin{array}{l} ${rows.join(
1080
+ " \\\\ "
1081
+ )} \\end{array}`;
970
1082
  }
971
1083
  return parsed;
972
1084
  })
973
- .join('');
1085
+ .join("");
974
1086
 
975
1087
  // Giữ nguyên dấu ngoặc vuông lớn
976
1088
  return `\\left[${innerContent}\\right.`;
@@ -979,36 +1091,41 @@ function getRender(node) {
979
1091
  if (Brackets.isPair(firstOp, lastOp)) {
980
1092
  const innerContent = childrenArray
981
1093
  .slice(1, -1)
982
- .map(child => parse(child))
983
- .join('');
1094
+ .map((child) => parse(child))
1095
+ .join("");
984
1096
  return `\\left${firstOp}${innerContent}\\right${lastOp}`;
985
1097
  }
986
1098
 
987
1099
  // Giữ nguyên dấu ngoặc nhọn trong MathML
988
- if (firstOp === '{' || lastOp === '}') {
1100
+ if (firstOp === "{" || lastOp === "}") {
989
1101
  const innerContent = childrenArray
990
- .slice(1, lastOp === '}' ? -1 : undefined)
991
- .map(child => parse(child))
992
- .join('');
993
- return `${firstOp === '{' ? '\\{' : ''}${innerContent}${lastOp === '}' ? '\\}' : ''}`;
1102
+ .slice(1, lastOp === "}" ? -1 : undefined)
1103
+ .map((child) => parse(child))
1104
+ .join("");
1105
+ return `${firstOp === "{" ? "\\{" : ""}${innerContent}${
1106
+ lastOp === "}" ? "\\}" : ""
1107
+ }`;
994
1108
  }
995
1109
  }
996
1110
  return getRender_joinSeparator("@content")(node, childrenArray);
997
1111
  };
998
1112
  break;
999
1113
 
1000
- case 'msub':
1114
+ case "msub":
1001
1115
  render = function (node, children) {
1002
1116
  const childrenArray = Array.from(children);
1003
- if (!childrenArray || childrenArray.length < 2) return '';
1004
- const base = parse(childrenArray[0]) || '';
1117
+ if (!childrenArray || childrenArray.length < 2) return "";
1118
+ const base = parse(childrenArray[0]) || "";
1005
1119
  const sub = childrenArray[1];
1006
1120
  if (!sub) return base;
1007
1121
 
1008
- if (NodeTool.getNodeName(sub) === 'msub' &&
1122
+ if (
1123
+ NodeTool.getNodeName(sub) === "msub" &&
1009
1124
  sub.firstChild &&
1010
- NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
1011
- (!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
+ ) {
1012
1129
  const lastChild = sub.lastChild;
1013
1130
  return lastChild ? `${base}_${parse(lastChild)}` : base;
1014
1131
  }
@@ -1016,52 +1133,57 @@ function getRender(node) {
1016
1133
  };
1017
1134
  break;
1018
1135
 
1019
- case 'msup':
1136
+ case "msup":
1020
1137
  render = function (node, children) {
1021
1138
  const childrenArray = Array.from(children);
1022
- if (!childrenArray || childrenArray.length < 2) return '';
1023
- const base = parse(childrenArray[0]) || '';
1024
- const sup = parse(childrenArray[1]) || '';
1139
+ if (!childrenArray || childrenArray.length < 2) return "";
1140
+ const base = parse(childrenArray[0]) || "";
1141
+ const sup = parse(childrenArray[1]) || "";
1025
1142
  return `${base}^{${sup}}`;
1026
1143
  };
1027
1144
  break;
1028
1145
 
1029
- case 'msubsup':
1146
+ case "msubsup":
1030
1147
  render = function (node, children) {
1031
1148
  const childrenArray = Array.from(children);
1032
- if (!childrenArray || childrenArray.length < 3) return '';
1149
+ if (!childrenArray || childrenArray.length < 3) return "";
1033
1150
  const base = parse(childrenArray[0]);
1034
1151
  const sub = parse(childrenArray[1]);
1035
1152
  const sup = parse(childrenArray[2]);
1036
1153
 
1037
1154
  const lastChild = childrenArray[0].lastElementChild;
1038
- if (lastChild && NodeTool.getNodeName(lastChild) === 'mo' &&
1039
- NodeTool.getNodeText(lastChild).trim() === '|') {
1155
+ if (
1156
+ lastChild &&
1157
+ NodeTool.getNodeName(lastChild) === "mo" &&
1158
+ NodeTool.getNodeText(lastChild).trim() === "|"
1159
+ ) {
1040
1160
  const content = Array.from(childrenArray[0].children)
1041
1161
  .slice(0, -1)
1042
- .map(child => parse(child))
1043
- .join('');
1162
+ .map((child) => parse(child))
1163
+ .join("");
1044
1164
  return `\\left.${content}\\right|_{${sub}}^{${sup}}`;
1045
1165
  }
1046
1166
  return `${base}_{${sub}}^{${sup}}`;
1047
1167
  };
1048
1168
  break;
1049
1169
 
1050
- case 'mover':
1170
+ case "mover":
1051
1171
  render = function (node, children) {
1052
1172
  const childrenArray = Array.from(children);
1053
- if (!childrenArray || childrenArray.length < 2) return '';
1054
- const base = parse(childrenArray[0]) || '';
1055
- const over = parse(childrenArray[1]) || '';
1056
- 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() || "";
1057
1177
  const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
1058
1178
 
1059
1179
  // Handle biology notation (double overline)
1060
1180
  if (overText === "¯") {
1061
1181
  const parentNode = node.parentNode;
1062
1182
  // Check if this is part of a double overline structure
1063
- if (NodeTool.getNodeName(parentNode) === 'mover' &&
1064
- NodeTool.getNodeText(parentNode.lastChild)?.trim() === '¯') {
1183
+ if (
1184
+ NodeTool.getNodeName(parentNode) === "mover" &&
1185
+ NodeTool.getNodeText(parentNode.lastChild)?.trim() === "¯"
1186
+ ) {
1065
1187
  return `\\overline{${base}}`;
1066
1188
  }
1067
1189
  return `\\overline{${base}}`;
@@ -1073,61 +1195,68 @@ function getRender(node) {
1073
1195
  };
1074
1196
  break;
1075
1197
 
1076
- case 'munder':
1198
+ case "munder":
1077
1199
  render = function (node, children) {
1078
1200
  const childrenArray = Array.from(children);
1079
- if (!childrenArray || childrenArray.length < 2) return '';
1080
- const base = parse(childrenArray[0]) || '';
1081
- const under = parse(childrenArray[1]) || '';
1082
- 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";
1083
1206
 
1084
1207
  if (base === "∫") return `\\int_{${under}}`;
1085
1208
  return `\\underset{${under}}{${base}}`;
1086
1209
  };
1087
1210
  break;
1088
1211
 
1089
- case 'munderover':
1212
+ case "munderover":
1090
1213
  render = function (node, children) {
1091
1214
  const childrenArray = Array.from(children);
1092
- if (!childrenArray || childrenArray.length < 3) return '';
1215
+ if (!childrenArray || childrenArray.length < 3) return "";
1093
1216
  const base = parse(childrenArray[0]);
1094
1217
  const under = parse(childrenArray[1]);
1095
1218
  const over = parse(childrenArray[2]);
1096
1219
  const baseText = NodeTool.getNodeText(childrenArray[0]).trim();
1097
1220
 
1098
1221
  // Special handling for chemical reaction arrow
1099
- if (baseText === '→' &&
1100
- NodeTool.getNodeName(childrenArray[1]) === 'msup') {
1222
+ if (
1223
+ baseText === "→" &&
1224
+ NodeTool.getNodeName(childrenArray[1]) === "msup"
1225
+ ) {
1101
1226
  return `\\xrightarrow[${under}]{${over}}`;
1102
1227
  }
1103
1228
 
1104
- if (baseText === '') return `\\int_{${under}}^{${over}}`;
1105
- if (baseText === '') return `\\sum_{${under}}^{${over}}`;
1106
- if (baseText === '') return `\\prod_{${under}}^{${over}}`;
1107
- if (baseText === '|') return `\\big|_{${under}}^{${over}}`;
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}}`;
1108
1233
  return `${base}_{${under}}^{${over}}`;
1109
1234
  };
1110
1235
  break;
1111
1236
 
1112
- case 'mmultiscripts':
1237
+ case "mmultiscripts":
1113
1238
  render = function (node, children) {
1114
1239
  const childrenArray = Array.from(children);
1115
- if (!childrenArray || childrenArray.length < 1) return '';
1240
+ if (!childrenArray || childrenArray.length < 1) return "";
1116
1241
  const base = parse(childrenArray[0]);
1117
- let prescripts = '';
1118
- let postscripts = '';
1242
+ let prescripts = "";
1243
+ let postscripts = "";
1119
1244
  let i = 1;
1120
1245
 
1121
1246
  while (i < childrenArray.length) {
1122
- if (NodeTool.getNodeName(childrenArray[i]) === 'mprescripts') {
1247
+ if (NodeTool.getNodeName(childrenArray[i]) === "mprescripts") {
1123
1248
  i++;
1124
1249
  if (i + 1 < childrenArray.length) {
1125
- prescripts = `_{${parse(childrenArray[i])}}^{${parse(childrenArray[i + 1])}}`;
1250
+ prescripts = `_{${parse(childrenArray[i])}}^{${parse(
1251
+ childrenArray[i + 1]
1252
+ )}}`;
1126
1253
  i += 2;
1127
1254
  }
1128
1255
  } else {
1129
1256
  if (i + 1 < childrenArray.length) {
1130
- postscripts += `_{${parse(childrenArray[i])}}^{${parse(childrenArray[i + 1])}}`;
1257
+ postscripts += `_{${parse(childrenArray[i])}}^{${parse(
1258
+ childrenArray[i + 1]
1259
+ )}}`;
1131
1260
  i += 2;
1132
1261
  } else break;
1133
1262
  }
@@ -1136,33 +1265,35 @@ function getRender(node) {
1136
1265
  };
1137
1266
  break;
1138
1267
 
1139
- case 'mlongdiv':
1268
+ case "mlongdiv":
1140
1269
  render = function (node, children) {
1141
1270
  const childrenArray = Array.from(children);
1142
- if (!childrenArray || childrenArray.length < 2) return '';
1143
- 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
+ )}}`;
1144
1275
  };
1145
1276
  break;
1146
1277
 
1147
- case 'mroot':
1278
+ case "mroot":
1148
1279
  render = function (node, children) {
1149
1280
  const childrenArray = Array.from(children);
1150
- if (!childrenArray || childrenArray.length < 2) return '';
1281
+ if (!childrenArray || childrenArray.length < 2) return "";
1151
1282
  const base = parse(childrenArray[0]);
1152
1283
  const index = parse(childrenArray[1]);
1153
1284
  return `\\sqrt[${index}]{${base}}`;
1154
1285
  };
1155
1286
  break;
1156
1287
 
1157
- case 'msqrt':
1288
+ case "msqrt":
1158
1289
  render = function (node, children) {
1159
1290
  const childrenArray = Array.from(children);
1160
- const content = renderChildren(childrenArray).join('');
1291
+ const content = renderChildren(childrenArray).join("");
1161
1292
  return `\\sqrt{${content}}`;
1162
1293
  };
1163
1294
  break;
1164
1295
 
1165
- case 'mtable':
1296
+ case "mtable":
1166
1297
  render = function (node, children) {
1167
1298
  const childrenArray = Array.from(children);
1168
1299
 
@@ -1170,7 +1301,7 @@ function getRender(node) {
1170
1301
  let isNestedTable = false;
1171
1302
  let parent = node.parentNode;
1172
1303
  while (parent) {
1173
- if (NodeTool.getNodeName(parent) === 'mtable') {
1304
+ if (NodeTool.getNodeName(parent) === "mtable") {
1174
1305
  isNestedTable = true;
1175
1306
  break;
1176
1307
  }
@@ -1178,25 +1309,27 @@ function getRender(node) {
1178
1309
  }
1179
1310
 
1180
1311
  // Xử lý mỗi mtr như một hàng
1181
- const rows = childrenArray.map(row => {
1312
+ const rows = childrenArray.map((row) => {
1182
1313
  const rowChildren = Array.from(NodeTool.getChildren(row));
1183
- return rowChildren.map(cell => parse(cell)).join('');
1314
+ return rowChildren.map((cell) => parse(cell)).join("");
1184
1315
  });
1185
1316
 
1186
1317
  // Nếu là mtable con, chỉ trả về các hàng mà không bao bọc trong \begin{array}...\end{array}
1187
1318
  if (isNestedTable) {
1188
- return rows.join(' \\\\ ');
1319
+ return rows.join(" \\\\ ");
1189
1320
  }
1190
1321
 
1191
1322
  // Nếu mtable nằm trong mrow với dấu ngoặc vuông, sẽ được xử lý ở mrow
1192
1323
  let isInsideSquareBrackets = false;
1193
1324
  parent = node.parentNode;
1194
1325
  while (parent) {
1195
- if (NodeTool.getNodeName(parent) === 'mrow') {
1326
+ if (NodeTool.getNodeName(parent) === "mrow") {
1196
1327
  const childrenOfParent = Array.from(NodeTool.getChildren(parent));
1197
- if (childrenOfParent.length >= 2 &&
1198
- NodeTool.getNodeName(childrenOfParent[0]) === 'mo' &&
1199
- NodeTool.getNodeText(childrenOfParent[0]).trim() === '[') {
1328
+ if (
1329
+ childrenOfParent.length >= 2 &&
1330
+ NodeTool.getNodeName(childrenOfParent[0]) === "mo" &&
1331
+ NodeTool.getNodeText(childrenOfParent[0]).trim() === "["
1332
+ ) {
1200
1333
  isInsideSquareBrackets = true;
1201
1334
  break;
1202
1335
  }
@@ -1205,151 +1338,166 @@ function getRender(node) {
1205
1338
  }
1206
1339
 
1207
1340
  if (isInsideSquareBrackets) {
1208
- return rows.join(' \\\\ ');
1341
+ return rows.join(" \\\\ ");
1209
1342
  }
1210
1343
 
1211
1344
  // Nếu là mtable chính, bao bọc trong \begin{array}...\end{array}
1212
- const arrayContent = rows.join(' \\\\ ');
1345
+ const arrayContent = rows.join(" \\\\ ");
1213
1346
  return `\\begin{array}{l} ${arrayContent} \\end{array}`;
1214
1347
  };
1215
1348
  break;
1216
1349
 
1217
- case 'mtr':
1350
+ case "mtr":
1218
1351
  render = getRender_joinSeparator("@content", " & ");
1219
1352
  break;
1220
1353
 
1221
- case 'mtd':
1354
+ case "mtd":
1222
1355
  render = getRender_joinSeparator("@content");
1223
1356
  break;
1224
1357
 
1225
- case 'mfrac':
1358
+ case "mfrac":
1226
1359
  render = function (node, children) {
1227
1360
  const childrenArray = Array.from(children);
1228
- if (!childrenArray || childrenArray.length < 2) return '';
1361
+ if (!childrenArray || childrenArray.length < 2) return "";
1229
1362
  const num = parse(childrenArray[0]);
1230
1363
  const den = parse(childrenArray[1]);
1231
- const linethickness = NodeTool.getAttr(node, 'linethickness', 'medium');
1232
- if (linethickness === '0') return `\\binom{${num}}{${den}}`;
1364
+ const linethickness = NodeTool.getAttr(node, "linethickness", "medium");
1365
+ if (linethickness === "0") return `\\binom{${num}}{${den}}`;
1233
1366
  return `\\frac{${num}}{${den}}`;
1234
1367
  };
1235
1368
  break;
1236
1369
 
1237
- case 'mfenced':
1370
+ case "mfenced":
1238
1371
  render = function (node, children) {
1239
1372
  const childrenArray = Array.from(children);
1240
- const open = NodeTool.getAttr(node, 'open', '(');
1241
- const close = NodeTool.getAttr(node, 'close', ')');
1242
- 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("");
1243
1376
 
1244
1377
  // Xử lý đặc biệt cho trường hợp dấu ngoặc đơn |
1245
- if (open === '|') {
1246
- const content = childrenArray.map(child => {
1247
- const parsed = parse(child);
1248
- // Loại bỏ các dấu | thừa và các \left|, \right| không cần thiết
1249
- return parsed
1250
- .replace(/\\left\|/g, '')
1251
- .replace(/\\right\|/g, '')
1252
- .replace(/\\left\./g, '')
1253
- .replace(/\|/g, '');
1254
- }).join('');
1255
-
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
+
1256
1391
  if (!close) {
1257
1392
  return `\\left|${content}\\right|`;
1258
- } else if (close === '|') {
1393
+ } else if (close === "|") {
1259
1394
  return `\\left|${content}\\right|`;
1260
1395
  }
1261
1396
  }
1262
1397
 
1263
1398
  // Xử lý đặc biệt cho mfenced chứa mtable
1264
- if (open === '{' && !close) {
1399
+ if (open === "{" && !close) {
1265
1400
  // Kiểm tra xem có phải là một phần của biểu thức mũ không
1266
- const hasMtable = childrenArray.some(child => {
1401
+ const hasMtable = childrenArray.some((child) => {
1267
1402
  // Kiểm tra trực tiếp mtable
1268
- if (NodeTool.getNodeName(child) === 'mtable') return true;
1403
+ if (NodeTool.getNodeName(child) === "mtable") return true;
1269
1404
  // Kiểm tra mtable trong mrow
1270
- if (NodeTool.getNodeName(child) === 'mrow') {
1405
+ if (NodeTool.getNodeName(child) === "mrow") {
1271
1406
  return Array.from(NodeTool.getChildren(child)).some(
1272
- grandChild => NodeTool.getNodeName(grandChild) === 'mtable'
1407
+ (grandChild) => NodeTool.getNodeName(grandChild) === "mtable"
1273
1408
  );
1274
1409
  }
1275
1410
  return false;
1276
1411
  });
1277
1412
 
1278
1413
  if (hasMtable) {
1279
- const content = childrenArray.map(child => parse(child)).join('');
1414
+ const content = childrenArray.map((child) => parse(child)).join("");
1280
1415
  return `\\left\\{${content}\\right.`;
1281
1416
  }
1282
1417
  }
1283
1418
 
1284
1419
  // Xử lý cho trường hợp [a;b)
1285
- if (open === '[' && close === ')') {
1420
+ if (open === "[" && close === ")") {
1286
1421
  const parts = [];
1287
1422
  childrenArray.forEach((child, index) => {
1288
1423
  parts.push(parse(child));
1289
- if (index < childrenArray.length - 1 && separators[index % separators.length]) {
1424
+ if (
1425
+ index < childrenArray.length - 1 &&
1426
+ separators[index % separators.length]
1427
+ ) {
1290
1428
  parts.push(separators[index % separators.length]);
1291
1429
  }
1292
1430
  });
1293
- return `\\left[${parts.join('')}\\right)`;
1431
+ return `\\left[${parts.join("")}\\right)`;
1294
1432
  }
1295
1433
 
1296
1434
  // Giữ nguyên xử lý cho các trường hợp khác
1297
1435
  const parts = [];
1298
1436
  childrenArray.forEach((child, index) => {
1299
1437
  parts.push(parse(child));
1300
- if (index < childrenArray.length - 1 && separators[index % separators.length]) {
1438
+ if (
1439
+ index < childrenArray.length - 1 &&
1440
+ separators[index % separators.length]
1441
+ ) {
1301
1442
  parts.push(separators[index % separators.length]);
1302
1443
  }
1303
1444
  });
1304
- const content = parts.join('');
1445
+ const content = parts.join("");
1305
1446
 
1306
- if (open === '{' && close === '}') return `\\{${content}\\}`;
1307
- if (open === '|' && close === '|') return `\\left|${content}\\right|`;
1447
+ if (open === "{" && close === "}") return `\\{${content}\\}`;
1448
+ if (open === "|" && close === "|") return `\\left|${content}\\right|`;
1308
1449
  if (!close) return `\\left${open}${content}\\right.`;
1309
1450
  if (!open) return `\\left.${content}\\right${close}`;
1310
1451
  return `\\left${open}${content}\\right${close}`;
1311
1452
  };
1312
1453
  break;
1313
1454
 
1314
- case 'menclose':
1455
+ case "menclose":
1315
1456
  render = function (node, children) {
1316
1457
  const childrenArray = Array.from(children);
1317
- const notation = NodeTool.getAttr(node, 'notation', 'longdiv');
1318
- const content = renderChildren(childrenArray).join('');
1458
+ const notation = NodeTool.getAttr(node, "notation", "longdiv");
1459
+ const content = renderChildren(childrenArray).join("");
1319
1460
  switch (notation) {
1320
- case 'box': return `\\boxed{${content}}`;
1321
- case 'circle': return `\\enclose{circle}{${content}}`;
1322
- case 'roundedbox': return `\\fbox{${content}}`;
1323
- 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;
1324
1469
  }
1325
1470
  };
1326
1471
  break;
1327
1472
 
1328
- case 'mi':
1329
- case 'mn':
1330
- case 'mo':
1331
- case 'ms':
1332
- case 'mtext':
1473
+ case "mi":
1474
+ case "mn":
1475
+ case "mo":
1476
+ case "ms":
1477
+ case "mtext":
1333
1478
  render = getRender_joinSeparator("@content");
1334
1479
  break;
1335
1480
 
1336
- case 'mphantom':
1481
+ case "mphantom":
1337
1482
  render = function (node, children) {
1338
1483
  const childrenArray = Array.from(children);
1339
- const content = renderChildren(childrenArray).join('');
1484
+ const content = renderChildren(childrenArray).join("");
1340
1485
  return `\\phantom{${content}}`;
1341
1486
  };
1342
1487
  break;
1343
1488
 
1344
- case 'mstyle':
1489
+ case "mstyle":
1345
1490
  render = function (node, children) {
1346
1491
  const childrenArray = Array.from(children);
1347
- const mathsize = NodeTool.getAttr(node, 'mathsize', 'normal');
1348
- const content = renderChildren(childrenArray).join('');
1492
+ const mathsize = NodeTool.getAttr(node, "mathsize", "normal");
1493
+ const content = renderChildren(childrenArray).join("");
1349
1494
  switch (mathsize) {
1350
- case 'big': return `\\large{${content}}`;
1351
- case 'small': return `\\small{${content}}`;
1352
- default: return content;
1495
+ case "big":
1496
+ return `\\large{${content}}`;
1497
+ case "small":
1498
+ return `\\small{${content}}`;
1499
+ default:
1500
+ return content;
1353
1501
  }
1354
1502
  };
1355
1503
  break;
@@ -1363,7 +1511,7 @@ function getRender(node) {
1363
1511
 
1364
1512
  // Export the convert function
1365
1513
  var mathml2latex = {
1366
- convert: convert
1514
+ convert: convert,
1367
1515
  };
1368
1516
 
1369
1517
  module.exports = mathml2latex;