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