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