temml 0.9.2 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -1
- package/contrib/auto-render/test/auto-render-spec.js +1 -1
- package/contrib/mhchem/mhchem.js +2 -2
- package/dist/Temml-Asana.css +0 -4
- package/dist/Temml-Latin-Modern.css +0 -5
- package/dist/Temml-Libertinus.css +0 -5
- package/dist/Temml-Local.css +0 -4
- package/dist/Temml-STIX2.css +0 -5
- package/dist/temml.cjs +112 -56
- package/dist/temml.js +110 -54
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +112 -56
- package/dist/temmlPostProcess.js +1 -1
- package/package.json +2 -1
- package/src/MacroExpander.js +20 -21
- package/src/Parser.js +25 -3
- package/src/asciiFromScript.js +29 -0
- package/src/buildMathML.js +1 -1
- package/src/functions/cr.js +2 -3
- package/src/functions/delimsizing.js +5 -0
- package/src/functions/font.js +0 -1
- package/src/functions/op.js +1 -5
- package/src/functions/operatorname.js +10 -8
- package/src/functions/supsub.js +7 -0
- package/src/functions/symbolsOrd.js +1 -4
- package/src/mathMLTree.js +1 -1
- package/src/postProcess.js +1 -1
- package/src/symbols.js +7 -2
- package/src/variant.js +1 -4
package/dist/temml.mjs
CHANGED
@@ -666,7 +666,7 @@ class TextNode {
|
|
666
666
|
|
667
667
|
/**
|
668
668
|
* Converts the text node into a string
|
669
|
-
* (representing the text
|
669
|
+
* (representing the text itself).
|
670
670
|
*/
|
671
671
|
toText() {
|
672
672
|
return this.text;
|
@@ -843,7 +843,6 @@ defineSymbol(math, rel, "\u226a", "\\ll", true);
|
|
843
843
|
defineSymbol(math, rel, "\u226b", "\\gg", true);
|
844
844
|
defineSymbol(math, rel, "\u224d", "\\asymp", true);
|
845
845
|
defineSymbol(math, rel, "\u2225", "\\parallel");
|
846
|
-
defineSymbol(math, rel, "\u22c8", "\\bowtie", true);
|
847
846
|
defineSymbol(math, rel, "\u2323", "\\smile", true);
|
848
847
|
defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true);
|
849
848
|
defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true);
|
@@ -1160,7 +1159,6 @@ defineSymbol(math, rel, "\u22d9", "\\gggtr");
|
|
1160
1159
|
defineSymbol(math, bin, "\u22b2", "\\lhd");
|
1161
1160
|
defineSymbol(math, bin, "\u22b3", "\\rhd");
|
1162
1161
|
defineSymbol(math, rel, "\u2242", "\\eqsim", true);
|
1163
|
-
defineSymbol(math, rel, "\u22c8", "\\Join");
|
1164
1162
|
defineSymbol(math, rel, "\u2251", "\\Doteq", true);
|
1165
1163
|
defineSymbol(math, rel, "\u297d", "\\strictif", true);
|
1166
1164
|
defineSymbol(math, rel, "\u297c", "\\strictfi", true);
|
@@ -1186,6 +1184,11 @@ defineSymbol(math, bin, "\u22ba", "\\intercal", true);
|
|
1186
1184
|
defineSymbol(math, bin, "\u22d2", "\\doublecap");
|
1187
1185
|
defineSymbol(math, bin, "\u22d3", "\\doublecup");
|
1188
1186
|
defineSymbol(math, bin, "\u22a0", "\\boxtimes", true);
|
1187
|
+
defineSymbol(math, bin, "\u22c8", "\\bowtie", true);
|
1188
|
+
defineSymbol(math, bin, "\u22c8", "\\Join");
|
1189
|
+
defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true);
|
1190
|
+
defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true);
|
1191
|
+
defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true);
|
1189
1192
|
|
1190
1193
|
// AMS Arrows
|
1191
1194
|
// Note: unicode-math maps \u21e2 to their own function \rightdasharrow.
|
@@ -1232,6 +1235,8 @@ defineSymbol(math, textord, "\u2018", "`");
|
|
1232
1235
|
defineSymbol(math, textord, "$", "\\$");
|
1233
1236
|
defineSymbol(text, textord, "$", "\\$");
|
1234
1237
|
defineSymbol(text, textord, "$", "\\textdollar");
|
1238
|
+
defineSymbol(math, textord, "¢", "\\cent");
|
1239
|
+
defineSymbol(text, textord, "¢", "\\cent");
|
1235
1240
|
defineSymbol(math, textord, "%", "\\%");
|
1236
1241
|
defineSymbol(text, textord, "%", "\\%");
|
1237
1242
|
defineSymbol(math, textord, "_", "\\_");
|
@@ -1888,7 +1893,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode, color) {
|
|
1888
1893
|
}
|
1889
1894
|
|
1890
1895
|
/**
|
1891
|
-
* This file converts a parse tree into a
|
1896
|
+
* This file converts a parse tree into a corresponding MathML tree. The main
|
1892
1897
|
* entry point is the `buildMathML` function, which takes a parse tree from the
|
1893
1898
|
* parser.
|
1894
1899
|
*/
|
@@ -3146,13 +3151,12 @@ defineFunction({
|
|
3146
3151
|
names: ["\\\\"],
|
3147
3152
|
props: {
|
3148
3153
|
numArgs: 0,
|
3149
|
-
numOptionalArgs:
|
3150
|
-
argTypes: ["size"],
|
3154
|
+
numOptionalArgs: 0,
|
3151
3155
|
allowedInText: true
|
3152
3156
|
},
|
3153
3157
|
|
3154
3158
|
handler({ parser }, args, optArgs) {
|
3155
|
-
const size =
|
3159
|
+
const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null;
|
3156
3160
|
const newLine = !parser.settings.displayMode;
|
3157
3161
|
return {
|
3158
3162
|
type: "cr",
|
@@ -3520,6 +3524,11 @@ const delimiters = [
|
|
3520
3524
|
"."
|
3521
3525
|
];
|
3522
3526
|
|
3527
|
+
// Export isDelimiter for benefit of parser.
|
3528
|
+
const dels = ["}", "\\left", "\\middle", "\\right"];
|
3529
|
+
const isDelimiter = str => str.length > 0 &&
|
3530
|
+
(delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
|
3531
|
+
|
3523
3532
|
// Metrics of the different sizes. Found by looking at TeX's output of
|
3524
3533
|
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
3525
3534
|
// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
|
@@ -4912,7 +4921,6 @@ defineFunction({
|
|
4912
4921
|
"\\mathscr",
|
4913
4922
|
"\\mathsf",
|
4914
4923
|
"\\mathtt",
|
4915
|
-
"\\oldstylenums",
|
4916
4924
|
|
4917
4925
|
// aliases
|
4918
4926
|
"\\Bbb",
|
@@ -6203,10 +6211,6 @@ const noSuccessor = ["\\smallint"];
|
|
6203
6211
|
// Math operators (e.g. \sin) need a space between these types and themselves:
|
6204
6212
|
const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
|
6205
6213
|
|
6206
|
-
const dels$1 = ["}", "\\left", "\\middle", "\\right"];
|
6207
|
-
const isDelimiter$1 = str => str.length > 0 &&
|
6208
|
-
(delimiters.includes(str) || delimiterSizes[str] || dels$1.includes(str));
|
6209
|
-
|
6210
6214
|
// NOTE: Unlike most `builders`s, this one handles not only "op", but also
|
6211
6215
|
// "supsub" since some of them (like \int) can affect super/subscripting.
|
6212
6216
|
|
@@ -6427,7 +6431,7 @@ defineFunction({
|
|
6427
6431
|
parentIsSupSub: false,
|
6428
6432
|
symbol: false,
|
6429
6433
|
stack: false,
|
6430
|
-
isFollowedByDelimiter: isDelimiter
|
6434
|
+
isFollowedByDelimiter: isDelimiter(next),
|
6431
6435
|
needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
|
6432
6436
|
name: funcName
|
6433
6437
|
};
|
@@ -6452,7 +6456,7 @@ defineFunction({
|
|
6452
6456
|
parentIsSupSub: false,
|
6453
6457
|
symbol: false,
|
6454
6458
|
stack: false,
|
6455
|
-
isFollowedByDelimiter: isDelimiter
|
6459
|
+
isFollowedByDelimiter: isDelimiter(next),
|
6456
6460
|
needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
|
6457
6461
|
name: funcName
|
6458
6462
|
};
|
@@ -6538,11 +6542,7 @@ function defineMacro(name, body) {
|
|
6538
6542
|
_macros[name] = body;
|
6539
6543
|
}
|
6540
6544
|
|
6541
|
-
|
6542
|
-
const isDelimiter = str => str.length > 0 &&
|
6543
|
-
(delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
|
6544
|
-
|
6545
|
-
// NOTE: Unlike most builders, this one handles not only
|
6545
|
+
// NOTE: Unlike most builders, this one handles not only
|
6546
6546
|
// "operatorname", but also "supsub" since \operatorname* can
|
6547
6547
|
// affect super/subscripting.
|
6548
6548
|
|
@@ -6552,8 +6552,12 @@ const mathmlBuilder$1 = (group, style) => {
|
|
6552
6552
|
// Is expression a string or has it something like a fraction?
|
6553
6553
|
let isAllString = true; // default
|
6554
6554
|
for (let i = 0; i < expression.length; i++) {
|
6555
|
-
|
6555
|
+
let node = expression[i];
|
6556
6556
|
if (node instanceof mathMLTree.MathNode) {
|
6557
|
+
if (node.type === "mrow" && node.children.length === 1 &&
|
6558
|
+
node.children[0] instanceof mathMLTree.MathNode) {
|
6559
|
+
node = node.children[0];
|
6560
|
+
}
|
6557
6561
|
switch (node.type) {
|
6558
6562
|
case "mi":
|
6559
6563
|
case "mn":
|
@@ -6611,7 +6615,9 @@ const mathmlBuilder$1 = (group, style) => {
|
|
6611
6615
|
let wrapper;
|
6612
6616
|
if (isAllString) {
|
6613
6617
|
wrapper = new mathMLTree.MathNode("mi", expression);
|
6614
|
-
|
6618
|
+
if (expression[0].text.length === 1) {
|
6619
|
+
wrapper.setAttribute("mathvariant", "normal");
|
6620
|
+
}
|
6615
6621
|
} else {
|
6616
6622
|
wrapper = new mathMLTree.MathNode("mrow", expression);
|
6617
6623
|
}
|
@@ -7149,6 +7155,7 @@ defineFunctionBuilders({
|
|
7149
7155
|
let isOver;
|
7150
7156
|
let isSup;
|
7151
7157
|
let appendApplyFunction = false;
|
7158
|
+
let appendSpace = false;
|
7152
7159
|
let needsLeadingSpace = false;
|
7153
7160
|
|
7154
7161
|
if (group.base && group.base.type === "horizBrace") {
|
@@ -7163,6 +7170,7 @@ defineFunctionBuilders({
|
|
7163
7170
|
(group.base.type === "op" || group.base.type === "operatorname")) {
|
7164
7171
|
group.base.parentIsSupSub = true;
|
7165
7172
|
appendApplyFunction = !group.base.symbol;
|
7173
|
+
appendSpace = appendApplyFunction && !group.isFollowedByDelimiter;
|
7166
7174
|
needsLeadingSpace = group.base.needsLeadingSpace;
|
7167
7175
|
}
|
7168
7176
|
|
@@ -7250,6 +7258,11 @@ defineFunctionBuilders({
|
|
7250
7258
|
} else {
|
7251
7259
|
node = mathMLTree.newDocumentFragment([node, operator]);
|
7252
7260
|
}
|
7261
|
+
if (appendSpace) {
|
7262
|
+
const space = new mathMLTree.MathNode("mspace");
|
7263
|
+
space.setAttribute("width", "0.1667em"); // thin space.
|
7264
|
+
node.children.push(space);
|
7265
|
+
}
|
7253
7266
|
} else if (symbolRegEx.test(nodeType)) {
|
7254
7267
|
// Wrap in a <mrow>. Otherwise Firefox stretchy parens will not stretch to include limits.
|
7255
7268
|
node = new mathMLTree.MathNode("mrow", [node]);
|
@@ -7326,8 +7339,7 @@ const fontMap = {
|
|
7326
7339
|
mathfrak: "fraktur",
|
7327
7340
|
mathscr: "script",
|
7328
7341
|
mathsf: "sans-serif",
|
7329
|
-
mathtt: "monospace"
|
7330
|
-
oldstylenums: "oldstylenums"
|
7342
|
+
mathtt: "monospace"
|
7331
7343
|
};
|
7332
7344
|
|
7333
7345
|
/**
|
@@ -7397,8 +7409,6 @@ const getVariant = function(group, style) {
|
|
7397
7409
|
return "sans-serif"
|
7398
7410
|
case "mathtt":
|
7399
7411
|
return "monospace"
|
7400
|
-
case "oldstylenums":
|
7401
|
-
return "oldstylenums"
|
7402
7412
|
}
|
7403
7413
|
|
7404
7414
|
let text = group.text;
|
@@ -7694,10 +7704,7 @@ defineFunctionBuilders({
|
|
7694
7704
|
let node;
|
7695
7705
|
if (numberRegEx$1.test(group.text)) {
|
7696
7706
|
const tag = group.mode === "text" ? "mtext" : "mn";
|
7697
|
-
if (variant === "
|
7698
|
-
const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]);
|
7699
|
-
node = new mathMLTree.MathNode(tag, [ms]);
|
7700
|
-
} else if (variant === "italic" || variant === "bold-italic") {
|
7707
|
+
if (variant === "italic" || variant === "bold-italic") {
|
7701
7708
|
return italicNumber(text, variant, tag)
|
7702
7709
|
} else {
|
7703
7710
|
if (variant !== "normal") {
|
@@ -8888,7 +8895,7 @@ defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{
|
|
8888
8895
|
defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}");
|
8889
8896
|
|
8890
8897
|
/* eslint-disable */
|
8891
|
-
/* -*- Mode:
|
8898
|
+
/* -*- Mode: JavaScript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
|
8892
8899
|
/* vim: set ts=2 et sw=2 tw=80: */
|
8893
8900
|
|
8894
8901
|
/*************************************************************
|
@@ -10585,7 +10592,7 @@ defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap
|
|
10585
10592
|
};
|
10586
10593
|
|
10587
10594
|
//
|
10588
|
-
// Helpers for code
|
10595
|
+
// Helpers for code analysis
|
10589
10596
|
// Will show type error at calling position
|
10590
10597
|
//
|
10591
10598
|
/** @param {number} a */
|
@@ -11010,15 +11017,15 @@ class MacroExpander {
|
|
11010
11017
|
* Expand the next token only once if possible.
|
11011
11018
|
*
|
11012
11019
|
* If the token is expanded, the resulting tokens will be pushed onto
|
11013
|
-
* the stack in reverse order and
|
11014
|
-
*
|
11020
|
+
* the stack in reverse order, and the number of such tokens will be
|
11021
|
+
* returned. This number might be zero or positive.
|
11015
11022
|
*
|
11016
|
-
* If not, the
|
11017
|
-
*
|
11018
|
-
* instead of an `Array` return value.
|
11023
|
+
* If not, the return value is `false`, and the next token remains at the
|
11024
|
+
* top of the stack.
|
11019
11025
|
*
|
11020
11026
|
* In either case, the next token will be on the top of the stack,
|
11021
|
-
* or the stack will be empty
|
11027
|
+
* or the stack will be empty (in case of empty expansion
|
11028
|
+
* and no other tokens).
|
11022
11029
|
*
|
11023
11030
|
* Used to implement `expandAfterFuture` and `expandNextToken`.
|
11024
11031
|
*
|
@@ -11034,7 +11041,7 @@ class MacroExpander {
|
|
11034
11041
|
throw new ParseError("Undefined control sequence: " + name);
|
11035
11042
|
}
|
11036
11043
|
this.pushToken(topToken);
|
11037
|
-
return
|
11044
|
+
return false;
|
11038
11045
|
}
|
11039
11046
|
this.expansionCount++;
|
11040
11047
|
if (this.expansionCount > this.settings.maxExpand) {
|
@@ -11068,7 +11075,7 @@ class MacroExpander {
|
|
11068
11075
|
}
|
11069
11076
|
// Concatenate expansion onto top of stack.
|
11070
11077
|
this.pushTokens(tokens);
|
11071
|
-
return tokens;
|
11078
|
+
return tokens.length;
|
11072
11079
|
}
|
11073
11080
|
|
11074
11081
|
/**
|
@@ -11087,14 +11094,13 @@ class MacroExpander {
|
|
11087
11094
|
*/
|
11088
11095
|
expandNextToken() {
|
11089
11096
|
for (;;) {
|
11090
|
-
|
11091
|
-
|
11092
|
-
if (expanded instanceof Token) {
|
11097
|
+
if (this.expandOnce() === false) { // fully expanded
|
11098
|
+
const token = this.stack.pop();
|
11093
11099
|
// The token after \noexpand is interpreted as if its meaning were ‘\relax’
|
11094
|
-
if (
|
11095
|
-
|
11100
|
+
if (token.treatAsRelax) {
|
11101
|
+
token.text = "\\relax";
|
11096
11102
|
}
|
11097
|
-
return
|
11103
|
+
return token
|
11098
11104
|
}
|
11099
11105
|
}
|
11100
11106
|
|
@@ -11120,15 +11126,15 @@ class MacroExpander {
|
|
11120
11126
|
const oldStackLength = this.stack.length;
|
11121
11127
|
this.pushTokens(tokens);
|
11122
11128
|
while (this.stack.length > oldStackLength) {
|
11123
|
-
|
11124
|
-
|
11125
|
-
|
11126
|
-
if (
|
11129
|
+
// Expand only expandable tokens
|
11130
|
+
if (this.expandOnce(true) === false) { // fully expanded
|
11131
|
+
const token = this.stack.pop();
|
11132
|
+
if (token.treatAsRelax) {
|
11127
11133
|
// the expansion of \noexpand is the token itself
|
11128
|
-
|
11129
|
-
|
11134
|
+
token.noexpand = false;
|
11135
|
+
token.treatAsRelax = false;
|
11130
11136
|
}
|
11131
|
-
output.push(
|
11137
|
+
output.push(token);
|
11132
11138
|
}
|
11133
11139
|
}
|
11134
11140
|
return output;
|
@@ -11428,6 +11434,36 @@ const uSubsAndSups = Object.freeze({
|
|
11428
11434
|
'\u1DBF': 'θ'
|
11429
11435
|
});
|
11430
11436
|
|
11437
|
+
// Used for Unicode input of calligraphic and script letters
|
11438
|
+
const asciiFromScript = Object.freeze({
|
11439
|
+
"\ud835\udc9c": "A",
|
11440
|
+
"\u212c": "B",
|
11441
|
+
"\ud835\udc9e": "C",
|
11442
|
+
"\ud835\udc9f": "D",
|
11443
|
+
"\u2130": "E",
|
11444
|
+
"\u2131": "F",
|
11445
|
+
"\ud835\udca2": "G",
|
11446
|
+
"\u210B": "H",
|
11447
|
+
"\u2110": "I",
|
11448
|
+
"\ud835\udca5": "J",
|
11449
|
+
"\ud835\udca6": "K",
|
11450
|
+
"\u2112": "L",
|
11451
|
+
"\u2113": "M",
|
11452
|
+
"\ud835\udca9": "N",
|
11453
|
+
"\ud835\udcaa": "O",
|
11454
|
+
"\ud835\udcab": "P",
|
11455
|
+
"\ud835\udcac": "Q",
|
11456
|
+
"\u211B": "R",
|
11457
|
+
"\ud835\udcae": "S",
|
11458
|
+
"\ud835\udcaf": "T",
|
11459
|
+
"\ud835\udcb0": "U",
|
11460
|
+
"\ud835\udcb1": "V",
|
11461
|
+
"\ud835\udcb2": "W",
|
11462
|
+
"\ud835\udcb3": "X",
|
11463
|
+
"\ud835\udcb4": "Y",
|
11464
|
+
"\ud835\udcb5": "Z"
|
11465
|
+
});
|
11466
|
+
|
11431
11467
|
// Mapping of Unicode accent characters to their LaTeX equivalent in text and
|
11432
11468
|
// math mode (when they exist).
|
11433
11469
|
var unicodeAccents = {
|
@@ -11926,7 +11962,7 @@ class Parser {
|
|
11926
11962
|
* Parses an "expression", which is a list of atoms.
|
11927
11963
|
*
|
11928
11964
|
* `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
|
11929
|
-
* happens when functions have higher
|
11965
|
+
* happens when functions have higher precedence han infix
|
11930
11966
|
* nodes in implicit parses.
|
11931
11967
|
*
|
11932
11968
|
* `breakOnTokenText`: The text of the token that the expression should end
|
@@ -12177,12 +12213,16 @@ class Parser {
|
|
12177
12213
|
return base
|
12178
12214
|
} else {
|
12179
12215
|
// We got either a superscript or subscript, create a supsub
|
12216
|
+
const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname")
|
12217
|
+
? undefined
|
12218
|
+
: isDelimiter(this.nextToken.text);
|
12180
12219
|
return {
|
12181
12220
|
type: "supsub",
|
12182
12221
|
mode: this.mode,
|
12183
12222
|
base: base,
|
12184
12223
|
sup: superscript,
|
12185
|
-
sub: subscript
|
12224
|
+
sub: subscript,
|
12225
|
+
isFollowedByDelimiter
|
12186
12226
|
}
|
12187
12227
|
}
|
12188
12228
|
} else {
|
@@ -12343,7 +12383,7 @@ class Parser {
|
|
12343
12383
|
while (true) {
|
12344
12384
|
const ch = this.fetch().text;
|
12345
12385
|
// \ufe0e is the Unicode variation selector to supress emoji. Ignore it.
|
12346
|
-
if (ch === " " || ch === "\ufe0e") {
|
12386
|
+
if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") {
|
12347
12387
|
this.consume();
|
12348
12388
|
} else {
|
12349
12389
|
break
|
@@ -12663,6 +12703,22 @@ class Parser {
|
|
12663
12703
|
text
|
12664
12704
|
};
|
12665
12705
|
} else {
|
12706
|
+
if (asciiFromScript[text]) {
|
12707
|
+
// Unicode 14 disambiguates chancery from roundhand.
|
12708
|
+
// See https://www.unicode.org/charts/PDF/U1D400.pdf
|
12709
|
+
this.consume();
|
12710
|
+
const nextCode = this.fetch().text.charCodeAt(0);
|
12711
|
+
// mathcal is Temml default. Use mathscript if called for.
|
12712
|
+
const font = nextCode === 0xfe01 ? "mathscr" : "mathcal";
|
12713
|
+
if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); }
|
12714
|
+
return {
|
12715
|
+
type: "font",
|
12716
|
+
mode: "math",
|
12717
|
+
font,
|
12718
|
+
body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] }
|
12719
|
+
}
|
12720
|
+
}
|
12721
|
+
// Default ord character. No disambiguation necessary.
|
12666
12722
|
s = {
|
12667
12723
|
type: group,
|
12668
12724
|
mode: this.mode,
|
@@ -12919,7 +12975,7 @@ class Style {
|
|
12919
12975
|
* https://mit-license.org/
|
12920
12976
|
*/
|
12921
12977
|
|
12922
|
-
const version = "0.
|
12978
|
+
const version = "0.10.2";
|
12923
12979
|
|
12924
12980
|
function postProcess(block) {
|
12925
12981
|
const labelMap = {};
|
package/dist/temmlPostProcess.js
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "temml",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.10.2",
|
4
4
|
"description": "TeX to MathML conversion in JavaScript.",
|
5
5
|
"main": "dist/temml.js",
|
6
6
|
"homepage": "https://temml.org",
|
@@ -8,6 +8,7 @@
|
|
8
8
|
"type": "git",
|
9
9
|
"url": "git://github.com/ronkok/Temml"
|
10
10
|
},
|
11
|
+
"packageManager": "yarn@3.3.1",
|
11
12
|
"files": [
|
12
13
|
"temml.js",
|
13
14
|
"src/",
|
package/src/MacroExpander.js
CHANGED
@@ -230,15 +230,15 @@ export default class MacroExpander {
|
|
230
230
|
* Expand the next token only once if possible.
|
231
231
|
*
|
232
232
|
* If the token is expanded, the resulting tokens will be pushed onto
|
233
|
-
* the stack in reverse order and
|
234
|
-
*
|
233
|
+
* the stack in reverse order, and the number of such tokens will be
|
234
|
+
* returned. This number might be zero or positive.
|
235
235
|
*
|
236
|
-
* If not, the
|
237
|
-
*
|
238
|
-
* instead of an `Array` return value.
|
236
|
+
* If not, the return value is `false`, and the next token remains at the
|
237
|
+
* top of the stack.
|
239
238
|
*
|
240
239
|
* In either case, the next token will be on the top of the stack,
|
241
|
-
* or the stack will be empty
|
240
|
+
* or the stack will be empty (in case of empty expansion
|
241
|
+
* and no other tokens).
|
242
242
|
*
|
243
243
|
* Used to implement `expandAfterFuture` and `expandNextToken`.
|
244
244
|
*
|
@@ -254,7 +254,7 @@ export default class MacroExpander {
|
|
254
254
|
throw new ParseError("Undefined control sequence: " + name);
|
255
255
|
}
|
256
256
|
this.pushToken(topToken);
|
257
|
-
return
|
257
|
+
return false;
|
258
258
|
}
|
259
259
|
this.expansionCount++;
|
260
260
|
if (this.expansionCount > this.settings.maxExpand) {
|
@@ -288,7 +288,7 @@ export default class MacroExpander {
|
|
288
288
|
}
|
289
289
|
// Concatenate expansion onto top of stack.
|
290
290
|
this.pushTokens(tokens);
|
291
|
-
return tokens;
|
291
|
+
return tokens.length;
|
292
292
|
}
|
293
293
|
|
294
294
|
/**
|
@@ -307,14 +307,13 @@ export default class MacroExpander {
|
|
307
307
|
*/
|
308
308
|
expandNextToken() {
|
309
309
|
for (;;) {
|
310
|
-
|
311
|
-
|
312
|
-
if (expanded instanceof Token) {
|
310
|
+
if (this.expandOnce() === false) { // fully expanded
|
311
|
+
const token = this.stack.pop();
|
313
312
|
// The token after \noexpand is interpreted as if its meaning were ‘\relax’
|
314
|
-
if (
|
315
|
-
|
313
|
+
if (token.treatAsRelax) {
|
314
|
+
token.text = "\\relax"
|
316
315
|
}
|
317
|
-
return
|
316
|
+
return token
|
318
317
|
}
|
319
318
|
}
|
320
319
|
|
@@ -340,15 +339,15 @@ export default class MacroExpander {
|
|
340
339
|
const oldStackLength = this.stack.length;
|
341
340
|
this.pushTokens(tokens);
|
342
341
|
while (this.stack.length > oldStackLength) {
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
if (
|
342
|
+
// Expand only expandable tokens
|
343
|
+
if (this.expandOnce(true) === false) { // fully expanded
|
344
|
+
const token = this.stack.pop();
|
345
|
+
if (token.treatAsRelax) {
|
347
346
|
// the expansion of \noexpand is the token itself
|
348
|
-
|
349
|
-
|
347
|
+
token.noexpand = false;
|
348
|
+
token.treatAsRelax = false;
|
350
349
|
}
|
351
|
-
output.push(
|
350
|
+
output.push(token);
|
352
351
|
}
|
353
352
|
}
|
354
353
|
return output;
|
package/src/Parser.js
CHANGED
@@ -7,8 +7,10 @@ import { supportedCodepoint } from "./unicodeScripts";
|
|
7
7
|
import ParseError from "./ParseError";
|
8
8
|
import { combiningDiacriticalMarksEndRegex } from "./Lexer";
|
9
9
|
import { uSubsAndSups, unicodeSubRegEx } from "./unicodeSupOrSub"
|
10
|
+
import { asciiFromScript } from "./asciiFromScript"
|
10
11
|
import SourceLocation from "./SourceLocation";
|
11
12
|
import { Token } from "./Token";
|
13
|
+
import { isDelimiter } from "./functions/delimsizing"
|
12
14
|
|
13
15
|
// Pre-evaluate both modules as unicodeSymbols require String.normalize()
|
14
16
|
import unicodeAccents from /*preval*/ "./unicodeAccents";
|
@@ -172,7 +174,7 @@ export default class Parser {
|
|
172
174
|
* Parses an "expression", which is a list of atoms.
|
173
175
|
*
|
174
176
|
* `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
|
175
|
-
* happens when functions have higher
|
177
|
+
* happens when functions have higher precedence han infix
|
176
178
|
* nodes in implicit parses.
|
177
179
|
*
|
178
180
|
* `breakOnTokenText`: The text of the token that the expression should end
|
@@ -423,12 +425,16 @@ export default class Parser {
|
|
423
425
|
return base
|
424
426
|
} else {
|
425
427
|
// We got either a superscript or subscript, create a supsub
|
428
|
+
const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname")
|
429
|
+
? undefined
|
430
|
+
: isDelimiter(this.nextToken.text);
|
426
431
|
return {
|
427
432
|
type: "supsub",
|
428
433
|
mode: this.mode,
|
429
434
|
base: base,
|
430
435
|
sup: superscript,
|
431
|
-
sub: subscript
|
436
|
+
sub: subscript,
|
437
|
+
isFollowedByDelimiter
|
432
438
|
}
|
433
439
|
}
|
434
440
|
} else {
|
@@ -589,7 +595,7 @@ export default class Parser {
|
|
589
595
|
while (true) {
|
590
596
|
const ch = this.fetch().text
|
591
597
|
// \ufe0e is the Unicode variation selector to supress emoji. Ignore it.
|
592
|
-
if (ch === " " || ch === "\ufe0e") {
|
598
|
+
if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") {
|
593
599
|
this.consume()
|
594
600
|
} else {
|
595
601
|
break
|
@@ -909,6 +915,22 @@ export default class Parser {
|
|
909
915
|
text
|
910
916
|
};
|
911
917
|
} else {
|
918
|
+
if (asciiFromScript[text]) {
|
919
|
+
// Unicode 14 disambiguates chancery from roundhand.
|
920
|
+
// See https://www.unicode.org/charts/PDF/U1D400.pdf
|
921
|
+
this.consume()
|
922
|
+
const nextCode = this.fetch().text.charCodeAt(0)
|
923
|
+
// mathcal is Temml default. Use mathscript if called for.
|
924
|
+
const font = nextCode === 0xfe01 ? "mathscr" : "mathcal";
|
925
|
+
if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume() }
|
926
|
+
return {
|
927
|
+
type: "font",
|
928
|
+
mode: "math",
|
929
|
+
font,
|
930
|
+
body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] }
|
931
|
+
}
|
932
|
+
}
|
933
|
+
// Default ord character. No disambiguation necessary.
|
912
934
|
s = {
|
913
935
|
type: group,
|
914
936
|
mode: this.mode,
|
@@ -0,0 +1,29 @@
|
|
1
|
+
// Used for Unicode input of calligraphic and script letters
|
2
|
+
export const asciiFromScript = Object.freeze({
|
3
|
+
"\ud835\udc9c": "A",
|
4
|
+
"\u212c": "B",
|
5
|
+
"\ud835\udc9e": "C",
|
6
|
+
"\ud835\udc9f": "D",
|
7
|
+
"\u2130": "E",
|
8
|
+
"\u2131": "F",
|
9
|
+
"\ud835\udca2": "G",
|
10
|
+
"\u210B": "H",
|
11
|
+
"\u2110": "I",
|
12
|
+
"\ud835\udca5": "J",
|
13
|
+
"\ud835\udca6": "K",
|
14
|
+
"\u2112": "L",
|
15
|
+
"\u2113": "M",
|
16
|
+
"\ud835\udca9": "N",
|
17
|
+
"\ud835\udcaa": "O",
|
18
|
+
"\ud835\udcab": "P",
|
19
|
+
"\ud835\udcac": "Q",
|
20
|
+
"\u211B": "R",
|
21
|
+
"\ud835\udcae": "S",
|
22
|
+
"\ud835\udcaf": "T",
|
23
|
+
"\ud835\udcb0": "U",
|
24
|
+
"\ud835\udcb1": "V",
|
25
|
+
"\ud835\udcb2": "W",
|
26
|
+
"\ud835\udcb3": "X",
|
27
|
+
"\ud835\udcb4": "Y",
|
28
|
+
"\ud835\udcb5": "Z"
|
29
|
+
})
|
package/src/buildMathML.js
CHANGED
package/src/functions/cr.js
CHANGED
@@ -11,13 +11,12 @@ defineFunction({
|
|
11
11
|
names: ["\\\\"],
|
12
12
|
props: {
|
13
13
|
numArgs: 0,
|
14
|
-
numOptionalArgs:
|
15
|
-
argTypes: ["size"],
|
14
|
+
numOptionalArgs: 0,
|
16
15
|
allowedInText: true
|
17
16
|
},
|
18
17
|
|
19
18
|
handler({ parser }, args, optArgs) {
|
20
|
-
const size =
|
19
|
+
const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null;
|
21
20
|
const newLine = !parser.settings.displayMode;
|
22
21
|
return {
|
23
22
|
type: "cr",
|
@@ -89,6 +89,11 @@ export const delimiters = [
|
|
89
89
|
"."
|
90
90
|
];
|
91
91
|
|
92
|
+
// Export isDelimiter for benefit of parser.
|
93
|
+
const dels = ["}", "\\left", "\\middle", "\\right"]
|
94
|
+
export const isDelimiter = str => str.length > 0 &&
|
95
|
+
(delimiters.includes(str) || delimiterSizes[str] || dels.includes(str))
|
96
|
+
|
92
97
|
// Metrics of the different sizes. Found by looking at TeX's output of
|
93
98
|
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
94
99
|
// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
|