temml 0.9.2 → 0.10.2
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/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.
|