ed-mathml2tex 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/mathml2latex.browser.cjs.js +199 -137
- package/lib/mathml2latex.browser.es.js +199 -137
- package/lib/mathml2latex.browser.umd.js +199 -137
- package/lib/mathml2latex.cjs.js +199 -137
- package/lib/mathml2latex.es.js +199 -137
- package/lib/mathml2latex.umd.js +199 -137
- package/package.json +1 -1
package/lib/mathml2latex.es.js
CHANGED
|
@@ -580,6 +580,39 @@ T.createMarker = function() {
|
|
|
580
580
|
}
|
|
581
581
|
};
|
|
582
582
|
|
|
583
|
+
function getRender_default(template) {
|
|
584
|
+
return function(node, children) {
|
|
585
|
+
const parts = renderChildren(children);
|
|
586
|
+
return renderTemplate(template, parts);
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function getRender_joinSeparator(template, separator = '') {
|
|
591
|
+
return function(node, children) {
|
|
592
|
+
const parts = renderChildren(children);
|
|
593
|
+
return template.replace('@content', parts.join(separator));
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function getRender_joinSeparators(template, separators) {
|
|
598
|
+
return function(node, children) {
|
|
599
|
+
const parts = renderChildren(children);
|
|
600
|
+
let content = '';
|
|
601
|
+
if (separators.length === 0) {
|
|
602
|
+
content = parts.join('');
|
|
603
|
+
} else {
|
|
604
|
+
content = parts.reduce((accumulator, part, index) => {
|
|
605
|
+
accumulator += part;
|
|
606
|
+
if (index < parts.length - 1) {
|
|
607
|
+
accumulator += separators[index] || separators[separators.length - 1];
|
|
608
|
+
}
|
|
609
|
+
return accumulator;
|
|
610
|
+
}, '');
|
|
611
|
+
}
|
|
612
|
+
return template.replace('@content', content);
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
583
616
|
function convert(mathmlHtml){
|
|
584
617
|
const math = NodeTool.parseMath(mathmlHtml);
|
|
585
618
|
|
|
@@ -626,6 +659,18 @@ function toLatex(result) {
|
|
|
626
659
|
result = result.replace(/→\\limits_\{([^}]*)\}\^\{([^}]*)\}/g, "\\overset{$2}{\\underset{$1}{\\rightarrow}}");
|
|
627
660
|
result = result.replace(/\\rightarrow\\limits_\{([^}]*)\}\^\{([^}]*)\}/g, "\\overset{$2}{\\underset{$1}{\\rightarrow}}");
|
|
628
661
|
|
|
662
|
+
// Case 4: mover - fix expressions with arrow superscript
|
|
663
|
+
// Simple expression with arrow superscript: expr^{\rightarrow} → \overrightarrow{expr}
|
|
664
|
+
result = result.replace(/([^{}\s]+)\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
|
|
665
|
+
result = result.replace(/\{([^{}]+)\}\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
|
|
666
|
+
|
|
667
|
+
// Complex expressions with subscripts and arrow: expr_{sub}^{\rightarrow} → \overrightarrow{expr_{sub}}
|
|
668
|
+
result = result.replace(/([A-Za-z0-9]+)_\{([^{}]+)\}\^\{\\rightarrow\}/g, "\\overrightarrow{$1_{$2}}");
|
|
669
|
+
result = result.replace(/([A-Za-z0-9]+)_([0-9])\^\{\\rightarrow\}/g, "\\overrightarrow{$1_$2}");
|
|
670
|
+
|
|
671
|
+
// Very complex expressions: (expr)^{\rightarrow} → \overrightarrow{(expr)}
|
|
672
|
+
result = result.replace(/(\([^()]+\))\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
|
|
673
|
+
|
|
629
674
|
// Also match if there are spaces
|
|
630
675
|
result = result.replace(/→\s*\\limits\s*_\s*{\s*}/g, "\\underset{}{\\rightarrow}");
|
|
631
676
|
result = result.replace(/\\rightarrow\s*\\limits\s*_\s*{\s*}/g, "\\underset{}{\\rightarrow}");
|
|
@@ -694,14 +739,27 @@ function parseOperator(node) {
|
|
|
694
739
|
}
|
|
695
740
|
|
|
696
741
|
// Math identifier
|
|
697
|
-
function parseElementMi(node){
|
|
742
|
+
function parseElementMi(node) {
|
|
698
743
|
let it = NodeTool.getNodeText(node).trim();
|
|
744
|
+
|
|
745
|
+
// Handle vectors (e.g. AB', AI)
|
|
746
|
+
if (it.includes("'")) {
|
|
747
|
+
return it; // Return as is to handle in mrow
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Handle subscripts (e.g. n₂)
|
|
751
|
+
if (it.match(/[a-zA-Z]\d/)) {
|
|
752
|
+
const base = it[0];
|
|
753
|
+
const sub = it[1];
|
|
754
|
+
return `${base}_{${sub}}`;
|
|
755
|
+
}
|
|
756
|
+
|
|
699
757
|
it = MathSymbol.parseIdentifier(it);
|
|
700
758
|
return escapeSpecialChars(it);
|
|
701
759
|
}
|
|
702
760
|
|
|
703
761
|
// Math Number
|
|
704
|
-
function parseElementMn(node){
|
|
762
|
+
function parseElementMn(node) {
|
|
705
763
|
let it = NodeTool.getNodeText(node).trim();
|
|
706
764
|
return escapeSpecialChars(it);
|
|
707
765
|
}
|
|
@@ -901,12 +959,29 @@ function renderMfrac(node, children){
|
|
|
901
959
|
return render(node, children);
|
|
902
960
|
}
|
|
903
961
|
|
|
904
|
-
function renderMfenced(node, children){
|
|
962
|
+
function renderMfenced(node, children) {
|
|
905
963
|
const [open, close, separatorsStr] = [
|
|
906
964
|
NodeTool.getAttr(node, 'open', '('),
|
|
907
965
|
NodeTool.getAttr(node, 'close', ')'),
|
|
908
966
|
NodeTool.getAttr(node, 'separators', ',')
|
|
909
967
|
];
|
|
968
|
+
|
|
969
|
+
// Handle special case for vectors inside brackets
|
|
970
|
+
if (open === '[' && close === ']') {
|
|
971
|
+
const parts = renderChildren(children);
|
|
972
|
+
// Join parts with comma and space, preserving vector notation
|
|
973
|
+
const content = parts.join(', ');
|
|
974
|
+
return `\\left[${content}\\right]`;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// Handle special case for coordinates
|
|
978
|
+
if (open === '(' && close === ')') {
|
|
979
|
+
const parts = renderChildren(children);
|
|
980
|
+
// Join parts with semicolon
|
|
981
|
+
const content = parts.join(';');
|
|
982
|
+
return `\\left(${content}\\right)`;
|
|
983
|
+
}
|
|
984
|
+
|
|
910
985
|
const [left, right] = [
|
|
911
986
|
Brackets.parseLeft(open),
|
|
912
987
|
Brackets.parseRight(close)
|
|
@@ -966,19 +1041,49 @@ function renderMmultiscripts(node, children) {
|
|
|
966
1041
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
967
1042
|
}
|
|
968
1043
|
|
|
969
|
-
function renderMover(node, children){
|
|
1044
|
+
function renderMover(node, children) {
|
|
970
1045
|
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
971
1046
|
let result = undefined;
|
|
1047
|
+
|
|
1048
|
+
// Get the base node and check if it's a subscript or mrow
|
|
1049
|
+
const baseNode = children[0];
|
|
1050
|
+
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1051
|
+
const isSubscript = nodeName === 'msub';
|
|
1052
|
+
const isMrow = nodeName === 'mrow';
|
|
1053
|
+
|
|
1054
|
+
if (isSubscript) {
|
|
1055
|
+
// Handle case like n₂ with arrow
|
|
1056
|
+
const base = parse(baseNode);
|
|
1057
|
+
return `\\overrightarrow{${base}}`;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (isMrow) {
|
|
1061
|
+
// Handle case like AB or AI
|
|
1062
|
+
const base = parse(baseNode);
|
|
1063
|
+
const overNode = children[1];
|
|
1064
|
+
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1065
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1066
|
+
|
|
1067
|
+
if (overText === "→" && isAccent) {
|
|
1068
|
+
return `\\overrightarrow{${base}}`;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
972
1072
|
for(let i = 0; i < nodes.length - 1; i++) {
|
|
973
|
-
if(!result){
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1073
|
+
if(!result) {
|
|
1074
|
+
result = parse(nodes[i]);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
const overNode = nodes[i + 1];
|
|
1078
|
+
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1079
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1080
|
+
|
|
1081
|
+
if (overText === "→" && isAccent) {
|
|
1082
|
+
return `\\overrightarrow{${result}}`;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
const over = parse(overNode);
|
|
1086
|
+
result = `${result}^{${over}}`;
|
|
982
1087
|
}
|
|
983
1088
|
return result;
|
|
984
1089
|
}
|
|
@@ -986,162 +1091,119 @@ function renderMover(node, children){
|
|
|
986
1091
|
function renderMunder(node, children){
|
|
987
1092
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
988
1093
|
let result = undefined;
|
|
989
|
-
|
|
990
|
-
// Early processing for arrow case
|
|
991
|
-
const baseNode = children[0];
|
|
992
|
-
if (baseNode && NodeTool.getNodeName(baseNode) === "mo") {
|
|
993
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
994
|
-
if (baseText === "→") {
|
|
995
|
-
// This is an arrow with under script
|
|
996
|
-
const underNode = children[1];
|
|
997
|
-
if (!underNode || NodeTool.getNodeName(underNode) === "mrow" && NodeTool.getNodeText(underNode).trim() === "") {
|
|
998
|
-
// Empty under script or mrow
|
|
999
|
-
console.log("Arrow with empty underscript, using \\underset{}");
|
|
1000
|
-
return "\\underset{}{\\rightarrow}";
|
|
1001
|
-
} else {
|
|
1002
|
-
// Non-empty under script
|
|
1003
|
-
const under = parse(underNode);
|
|
1004
|
-
console.log("Arrow with underscript:", under);
|
|
1005
|
-
return `\\underset{${under}}{\\rightarrow}`;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
1094
|
for(let i = 0; i < nodes.length - 1; i++) {
|
|
1011
1095
|
if(!result){ result = parse(nodes[i]); }
|
|
1012
1096
|
|
|
1013
1097
|
const underNode = nodes[i + 1];
|
|
1014
1098
|
const underText = NodeTool.getNodeText(underNode).trim();
|
|
1015
|
-
const
|
|
1099
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1016
1100
|
|
|
1017
|
-
//
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1101
|
+
// Special handling for arrow accent
|
|
1102
|
+
if (underText === "→" && isAccent) {
|
|
1103
|
+
return `\\underset{${result}}{\\rightarrow}`;
|
|
1020
1104
|
}
|
|
1021
1105
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
judgeChar: underText,
|
|
1031
|
-
defaultValue: "@1_{@2}" // Use simple subscript instead of \limits
|
|
1032
|
-
});
|
|
1033
|
-
|
|
1034
|
-
const under = parse(underNode);
|
|
1035
|
-
result = renderTemplate(template.replace("@v", "@1"), [result, under]);
|
|
1036
|
-
}
|
|
1106
|
+
const under = parse(underNode);
|
|
1107
|
+
const template = getMatchValueByChar({
|
|
1108
|
+
decimals: MathSymbol.underScript.decimals,
|
|
1109
|
+
values: MathSymbol.underScript.templates,
|
|
1110
|
+
judgeChar: underText,
|
|
1111
|
+
defaultValue: "@1_{@2}"
|
|
1112
|
+
});
|
|
1113
|
+
result = renderTemplate(template.replace("@v", "@1"), [result, under]);
|
|
1037
1114
|
}
|
|
1038
1115
|
return result;
|
|
1039
1116
|
}
|
|
1040
1117
|
|
|
1041
|
-
function renderMunderover(node, children)
|
|
1118
|
+
function renderMunderover(node, children){
|
|
1042
1119
|
const nodes = flattenNodeTreeByNodeName(node, 'munderover');
|
|
1043
1120
|
let result = undefined;
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const baseNode = nodes[0];
|
|
1047
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1121
|
+
for(let i = 0; i < nodes.length - 1; i++) {
|
|
1122
|
+
if(!result){ result = parse(nodes[i]); }
|
|
1048
1123
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
return `${base}\\limits_{${under}}^{${over}}`;
|
|
1124
|
+
const overNode = nodes[i + 1];
|
|
1125
|
+
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1126
|
+
const underNode = nodes[i + 2];
|
|
1127
|
+
const underText = NodeTool.getNodeText(underNode).trim();
|
|
1128
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1129
|
+
|
|
1130
|
+
// Special handling for arrow accent
|
|
1131
|
+
if (overText === "→" && isAccent) {
|
|
1132
|
+
return `\\overset{${result}}{\\underset{${underText}}{\\rightarrow}}`;
|
|
1059
1133
|
}
|
|
1134
|
+
|
|
1135
|
+
const over = parse(overNode);
|
|
1136
|
+
const under = parse(underNode);
|
|
1137
|
+
const template = getMatchValueByChar({
|
|
1138
|
+
decimals: MathSymbol.underoverScript.decimals,
|
|
1139
|
+
values: MathSymbol.underoverScript.templates,
|
|
1140
|
+
judgeChar: overText,
|
|
1141
|
+
defaultValue: "@1_{@2}^{@3}"
|
|
1142
|
+
});
|
|
1143
|
+
result = renderTemplate(template.replace("@v", "@1"), [over, under]);
|
|
1060
1144
|
}
|
|
1061
|
-
|
|
1062
|
-
for(let i = 0; i < nodes.length - 2; i++) {
|
|
1063
|
-
if(!result){ result = parse(nodes[i]); }
|
|
1064
|
-
const under = parse(nodes[i + 1]);
|
|
1065
|
-
const over = parse(nodes[i + 2]);
|
|
1066
|
-
result = renderTemplate("@1\\limits_{@2}^{@3}", [result, under, over]);
|
|
1067
|
-
}
|
|
1068
|
-
return result;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
function flattenNodeTreeByNodeName(root, nodeName) {
|
|
1072
|
-
let result = [];
|
|
1073
|
-
const children = NodeTool.getChildren(root);
|
|
1074
|
-
Array.prototype.forEach.call(children, (node) => {
|
|
1075
|
-
if (NodeTool.getNodeName(node) === nodeName) {
|
|
1076
|
-
result = result.concat(flattenNodeTreeByNodeName(node, nodeName));
|
|
1077
|
-
} else {
|
|
1078
|
-
result.push(node);
|
|
1079
|
-
}
|
|
1080
|
-
});
|
|
1081
1145
|
return result;
|
|
1082
1146
|
}
|
|
1083
1147
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1148
|
+
function renderMphantom(node, children){
|
|
1149
|
+
const nodes = flattenNodeTreeByNodeName(node, 'mphantom');
|
|
1150
|
+
let result = undefined;
|
|
1151
|
+
for(let i = 0; i < nodes.length - 1; i++) {
|
|
1152
|
+
if(!result){ result = parse(nodes[i]); }
|
|
1153
|
+
|
|
1154
|
+
const phantomNode = nodes[i + 1];
|
|
1155
|
+
const phantomText = NodeTool.getNodeText(phantomNode).trim();
|
|
1156
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1157
|
+
|
|
1158
|
+
// Special handling for arrow accent
|
|
1159
|
+
if (phantomText === "→" && isAccent) {
|
|
1160
|
+
return `\\overrightarrow{${result}}`;
|
|
1091
1161
|
}
|
|
1162
|
+
|
|
1163
|
+
const phantom = parse(phantomNode);
|
|
1164
|
+
const template = getMatchValueByChar({
|
|
1165
|
+
decimals: MathSymbol.phantomScript.decimals,
|
|
1166
|
+
values: MathSymbol.phantomScript.templates,
|
|
1167
|
+
judgeChar: phantomText,
|
|
1168
|
+
defaultValue: "@1^{@2}"
|
|
1169
|
+
});
|
|
1170
|
+
result = renderTemplate(template.replace("@v", "@1"), [result, phantom]);
|
|
1092
1171
|
}
|
|
1093
|
-
return
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
// https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mphantom
|
|
1097
|
-
// FIXME :)
|
|
1098
|
-
function renderMphantom(node, children) {
|
|
1099
|
-
return '';
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
function getRender_default(template) {
|
|
1105
|
-
return function(node, children) {
|
|
1106
|
-
const parts = renderChildren(children);
|
|
1107
|
-
return renderTemplate(template, parts)
|
|
1108
|
-
}
|
|
1172
|
+
return result;
|
|
1109
1173
|
}
|
|
1110
1174
|
|
|
1111
|
-
function renderTemplate(template,
|
|
1112
|
-
return template.replace(
|
|
1113
|
-
const
|
|
1114
|
-
return
|
|
1175
|
+
function renderTemplate(template, args) {
|
|
1176
|
+
return template.replace(/@(\d+)/g, (match, index) => {
|
|
1177
|
+
const arg = args[index - 1];
|
|
1178
|
+
return arg || match;
|
|
1115
1179
|
});
|
|
1116
1180
|
}
|
|
1117
1181
|
|
|
1118
|
-
function
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
}
|
|
1182
|
+
function getMatchValueByChar(options) {
|
|
1183
|
+
const { decimals, values, judgeChar, defaultValue } = options;
|
|
1184
|
+
const match = values.find(value => value.judgeChar === judgeChar);
|
|
1185
|
+
return match || defaultValue;
|
|
1123
1186
|
}
|
|
1124
1187
|
|
|
1125
|
-
function
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
return template.replace("@content", content);
|
|
1188
|
+
function flattenNodeTreeByNodeName(node, nodeName) {
|
|
1189
|
+
const nodes = [];
|
|
1190
|
+
const children = NodeTool.getChildren(node);
|
|
1191
|
+
if (children && children.length > 0) {
|
|
1192
|
+
// Convert HTMLCollection to Array before using forEach
|
|
1193
|
+
Array.from(children).forEach(child => {
|
|
1194
|
+
if (NodeTool.getNodeName(child) === nodeName) {
|
|
1195
|
+
nodes.push(child);
|
|
1196
|
+
} else {
|
|
1197
|
+
// Recursively search in child nodes
|
|
1198
|
+
const childNodes = flattenNodeTreeByNodeName(child, nodeName);
|
|
1199
|
+
nodes.push(...childNodes);
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1141
1202
|
}
|
|
1203
|
+
return nodes;
|
|
1142
1204
|
}
|
|
1143
1205
|
|
|
1144
|
-
//
|
|
1206
|
+
// Export the convert function
|
|
1145
1207
|
var mathml2latex = {
|
|
1146
1208
|
convert: convert
|
|
1147
1209
|
};
|