temml 0.10.2 → 0.10.4
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 +3 -4
- package/dist/Temml-Asana.css +17 -1
- package/dist/Temml-Latin-Modern.css +17 -5
- package/dist/Temml-Libertinus.css +17 -5
- package/dist/Temml-Local.css +16 -0
- package/dist/Temml-STIX2.css +16 -0
- package/dist/temml.cjs +56 -36
- package/dist/temml.js +56 -36
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +56 -36
- package/dist/temmlPostProcess.js +1 -1
- package/package.json +8 -2
- package/src/Lexer.js +2 -8
- package/src/Parser.js +0 -11
- package/src/Settings.js +1 -1
- package/src/buildMathML.js +47 -12
- package/src/functions/symbolsOrd.js +1 -1
- package/src/linebreaking.js +3 -1
- package/src/postProcess.js +1 -1
package/dist/temml.mjs
CHANGED
@@ -188,7 +188,7 @@ class Settings {
|
|
188
188
|
this.leqno = utils.deflt(options.leqno, false); // boolean
|
189
189
|
this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string
|
190
190
|
this.macros = options.macros || {};
|
191
|
-
this.wrap = utils.deflt(options.wrap, "
|
191
|
+
this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "="
|
192
192
|
this.xml = utils.deflt(options.xml, false); // boolean
|
193
193
|
this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean
|
194
194
|
this.strict = utils.deflt(options.strict, false); // boolean
|
@@ -1747,10 +1747,12 @@ for (let i = 0; i < 10; i++) {
|
|
1747
1747
|
* Then the top level of a <math> element can be occupied by <mrow> elements, and the browser
|
1748
1748
|
* will break after a <mrow> if the expression extends beyond the container limit.
|
1749
1749
|
*
|
1750
|
-
*
|
1750
|
+
* The default is for soft line breaks after each top-level binary or
|
1751
1751
|
* relational operator, per TeXbook p. 173. So we gather the expression into <mrow>s so that
|
1752
1752
|
* each <mrow> ends in a binary or relational operator.
|
1753
1753
|
*
|
1754
|
+
* An option is for soft line breaks before an "=" sign. That changes the <mrow>s.
|
1755
|
+
*
|
1754
1756
|
* Soft line breaks will not work in Chromium and Safari, only Firefox.
|
1755
1757
|
*
|
1756
1758
|
* Hopefully browsers will someday do their own linebreaking and we will be able to delete
|
@@ -1962,6 +1964,48 @@ const consolidateText = mrow => {
|
|
1962
1964
|
return mtext
|
1963
1965
|
};
|
1964
1966
|
|
1967
|
+
const numberRegEx$1 = /^[0-9]$/;
|
1968
|
+
const isCommaOrDot = node => {
|
1969
|
+
return (node.type === "atom" && node.text === ",") ||
|
1970
|
+
(node.type === "textord" && node.text === ".")
|
1971
|
+
};
|
1972
|
+
const consolidateNumbers = expression => {
|
1973
|
+
// Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
|
1974
|
+
// not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
|
1975
|
+
if (expression.length < 2) { return }
|
1976
|
+
const nums = [];
|
1977
|
+
let inNum = false;
|
1978
|
+
// Find adjacent numerals
|
1979
|
+
for (let i = 0; i < expression.length; i++) {
|
1980
|
+
const node = expression[i];
|
1981
|
+
if (node.type === "textord" && numberRegEx$1.test(node.text)) {
|
1982
|
+
if (!inNum) { nums.push({ start: i }); }
|
1983
|
+
inNum = true;
|
1984
|
+
} else {
|
1985
|
+
if (inNum) { nums[nums.length - 1].end = i - 1; }
|
1986
|
+
inNum = false;
|
1987
|
+
}
|
1988
|
+
}
|
1989
|
+
if (inNum) { nums[nums.length - 1].end = expression.length - 1; }
|
1990
|
+
|
1991
|
+
// Determine if numeral groups are separated by a comma or dot.
|
1992
|
+
for (let i = nums.length - 1; i > 0; i--) {
|
1993
|
+
if (nums[i - 1].end === nums[i].start - 2 && isCommaOrDot(expression[nums[i].start - 1])) {
|
1994
|
+
// Merge the two groups.
|
1995
|
+
nums[i - 1].end = nums[i].end;
|
1996
|
+
nums.splice(i, 1);
|
1997
|
+
}
|
1998
|
+
}
|
1999
|
+
|
2000
|
+
// Consolidate the number nodes
|
2001
|
+
for (let i = nums.length - 1; i >= 0; i--) {
|
2002
|
+
for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
|
2003
|
+
expression[nums[i].start].text += expression[j].text;
|
2004
|
+
}
|
2005
|
+
expression.splice(nums[i].start + 1, nums[i].end - nums[i].start);
|
2006
|
+
}
|
2007
|
+
};
|
2008
|
+
|
1965
2009
|
/**
|
1966
2010
|
* Wrap the given array of nodes in an <mrow> node if needed, i.e.,
|
1967
2011
|
* unless the array has length 1. Always returns a single node.
|
@@ -1997,6 +2041,8 @@ const buildExpression = function(expression, style, isOrdgroup) {
|
|
1997
2041
|
return [group];
|
1998
2042
|
}
|
1999
2043
|
|
2044
|
+
consolidateNumbers(expression);
|
2045
|
+
|
2000
2046
|
const groups = [];
|
2001
2047
|
for (let i = 0; i < expression.length; i++) {
|
2002
2048
|
const group = buildGroup$1(expression[i], style);
|
@@ -2096,18 +2142,6 @@ function buildMathML(tree, texExpression, style, settings) {
|
|
2096
2142
|
wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]);
|
2097
2143
|
}
|
2098
2144
|
|
2099
|
-
if (wrap !== "none" && wrapper.children.length > 1) {
|
2100
|
-
const maths = [];
|
2101
|
-
for (let i = 0; i < wrapper.children.length; i++) {
|
2102
|
-
const math = new mathMLTree.MathNode("math", [wrapper.children[i]]);
|
2103
|
-
if (settings.xml) {
|
2104
|
-
math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");
|
2105
|
-
}
|
2106
|
-
maths.push(math);
|
2107
|
-
}
|
2108
|
-
return mathMLTree.newDocumentFragment(maths)
|
2109
|
-
}
|
2110
|
-
|
2111
2145
|
const math = new mathMLTree.MathNode("math", [wrapper]);
|
2112
2146
|
|
2113
2147
|
if (settings.xml) {
|
@@ -2115,6 +2149,9 @@ function buildMathML(tree, texExpression, style, settings) {
|
|
2115
2149
|
}
|
2116
2150
|
if (settings.displayMode) {
|
2117
2151
|
math.setAttribute("display", "block");
|
2152
|
+
math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
|
2153
|
+
? "inline"
|
2154
|
+
: "inline-block";
|
2118
2155
|
}
|
2119
2156
|
return math;
|
2120
2157
|
}
|
@@ -7648,7 +7685,7 @@ const smallCaps = Object.freeze({
|
|
7648
7685
|
// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
|
7649
7686
|
// src/symbols.js.
|
7650
7687
|
|
7651
|
-
const numberRegEx
|
7688
|
+
const numberRegEx = /^\d(?:[\d,.]*\d)?$/;
|
7652
7689
|
const latinRegEx = /[A-Ba-z]/;
|
7653
7690
|
|
7654
7691
|
const italicNumber = (text, variant, tag) => {
|
@@ -7702,7 +7739,7 @@ defineFunctionBuilders({
|
|
7702
7739
|
const variant = getVariant(group, style) || "normal";
|
7703
7740
|
|
7704
7741
|
let node;
|
7705
|
-
if (numberRegEx
|
7742
|
+
if (numberRegEx.test(group.text)) {
|
7706
7743
|
const tag = group.mode === "text" ? "mtext" : "mn";
|
7707
7744
|
if (variant === "italic" || variant === "bold-italic") {
|
7708
7745
|
return italicNumber(text, variant, tag)
|
@@ -8015,8 +8052,7 @@ const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMark
|
|
8015
8052
|
const tokenRegexString =
|
8016
8053
|
`(${spaceRegexString}+)|` + // whitespace
|
8017
8054
|
`${controlSpaceRegexString}|` + // whitespace
|
8018
|
-
"(
|
8019
|
-
"|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
|
8055
|
+
"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
|
8020
8056
|
`${combiningDiacriticalMarkString}*` + // ...plus accents
|
8021
8057
|
"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
|
8022
8058
|
`${combiningDiacriticalMarkString}*` + // ...plus accents
|
@@ -8031,12 +8067,7 @@ class Lexer {
|
|
8031
8067
|
// Separate accents from characters
|
8032
8068
|
this.input = input;
|
8033
8069
|
this.settings = settings;
|
8034
|
-
this.tokenRegex = new RegExp(
|
8035
|
-
// Strict Temml, like TeX, lexes one numeral at a time.
|
8036
|
-
// Default Temml lexes contiguous numerals into a single <mn> element.
|
8037
|
-
tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"),
|
8038
|
-
"g"
|
8039
|
-
);
|
8070
|
+
this.tokenRegex = new RegExp(tokenRegexString, 'g');
|
8040
8071
|
// Category codes. The lexer only supports comment characters (14) for now.
|
8041
8072
|
// MacroExpander additionally distinguishes active (13).
|
8042
8073
|
this.catcodes = {
|
@@ -11804,8 +11835,6 @@ var unicodeSymbols = {
|
|
11804
11835
|
|
11805
11836
|
/* eslint no-constant-condition:0 */
|
11806
11837
|
|
11807
|
-
const numberRegEx = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in symbolsOrd.js
|
11808
|
-
|
11809
11838
|
/**
|
11810
11839
|
* This file contains the parser used to parse out a TeX expression from the
|
11811
11840
|
* input. Since TeX isn't context-free, standard parsers don't work particularly
|
@@ -12727,15 +12756,6 @@ class Parser {
|
|
12727
12756
|
};
|
12728
12757
|
}
|
12729
12758
|
symbol = s;
|
12730
|
-
} else if (!this.strict && numberRegEx.test(text)) {
|
12731
|
-
// A number. Wrap in a <mn> if in math mode; <mtext> otherwise.
|
12732
|
-
this.consume();
|
12733
|
-
return {
|
12734
|
-
type: "textord",
|
12735
|
-
mode: this.mode,
|
12736
|
-
loc: SourceLocation.range(nucleus),
|
12737
|
-
text
|
12738
|
-
}
|
12739
12759
|
} else if (text.charCodeAt(0) >= 0x80) {
|
12740
12760
|
// no symbol for e.g. ^
|
12741
12761
|
if (this.settings.strict) {
|
@@ -12975,7 +12995,7 @@ class Style {
|
|
12975
12995
|
* https://mit-license.org/
|
12976
12996
|
*/
|
12977
12997
|
|
12978
|
-
const version = "0.10.
|
12998
|
+
const version = "0.10.4";
|
12979
12999
|
|
12980
13000
|
function postProcess(block) {
|
12981
13001
|
const labelMap = {};
|
package/dist/temmlPostProcess.js
CHANGED
package/package.json
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
{
|
2
2
|
"name": "temml",
|
3
|
-
"version": "0.10.
|
3
|
+
"version": "0.10.4",
|
4
4
|
"description": "TeX to MathML conversion in JavaScript.",
|
5
5
|
"main": "dist/temml.js",
|
6
|
+
"exports": {
|
7
|
+
".": {
|
8
|
+
"require": "./dist/temml.cjs"
|
9
|
+
},
|
10
|
+
"./*": "./*"
|
11
|
+
},
|
6
12
|
"homepage": "https://temml.org",
|
7
13
|
"repository": {
|
8
14
|
"type": "git",
|
@@ -24,7 +30,7 @@
|
|
24
30
|
},
|
25
31
|
"scripts": {
|
26
32
|
"lint": "eslint temml.js src",
|
27
|
-
"unit-test": "node
|
33
|
+
"unit-test": "node ./test/unit-test.cjs",
|
28
34
|
"visual-test": "node utils/buildTests.js",
|
29
35
|
"test": "yarn lint && node utils/buildTests.js && yarn unit-test",
|
30
36
|
"minify": "terser test/temml.js -o site/assets/temml.min.js -c -m && terser contrib/mhchem/mhchem.js -o site/assets/mhchem.min.js -c -m",
|
package/src/Lexer.js
CHANGED
@@ -49,8 +49,7 @@ export const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriti
|
|
49
49
|
const tokenRegexString =
|
50
50
|
`(${spaceRegexString}+)|` + // whitespace
|
51
51
|
`${controlSpaceRegexString}|` + // whitespace
|
52
|
-
"(
|
53
|
-
"|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
|
52
|
+
"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
|
54
53
|
`${combiningDiacriticalMarkString}*` + // ...plus accents
|
55
54
|
"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
|
56
55
|
`${combiningDiacriticalMarkString}*` + // ...plus accents
|
@@ -65,12 +64,7 @@ export default class Lexer {
|
|
65
64
|
// Separate accents from characters
|
66
65
|
this.input = input;
|
67
66
|
this.settings = settings;
|
68
|
-
this.tokenRegex = new RegExp(
|
69
|
-
// Strict Temml, like TeX, lexes one numeral at a time.
|
70
|
-
// Default Temml lexes contiguous numerals into a single <mn> element.
|
71
|
-
tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"),
|
72
|
-
"g"
|
73
|
-
);
|
67
|
+
this.tokenRegex = new RegExp(tokenRegexString, 'g');
|
74
68
|
// Category codes. The lexer only supports comment characters (14) for now.
|
75
69
|
// MacroExpander additionally distinguishes active (13).
|
76
70
|
this.catcodes = {
|
package/src/Parser.js
CHANGED
@@ -16,8 +16,6 @@ import { isDelimiter } from "./functions/delimsizing"
|
|
16
16
|
import unicodeAccents from /*preval*/ "./unicodeAccents";
|
17
17
|
import unicodeSymbols from /*preval*/ "./unicodeSymbols";
|
18
18
|
|
19
|
-
const numberRegEx = /^\d(?:[\d,.]*\d)?$/ // Keep in sync with numberRegEx in symbolsOrd.js
|
20
|
-
|
21
19
|
/**
|
22
20
|
* This file contains the parser used to parse out a TeX expression from the
|
23
21
|
* input. Since TeX isn't context-free, standard parsers don't work particularly
|
@@ -939,15 +937,6 @@ export default class Parser {
|
|
939
937
|
};
|
940
938
|
}
|
941
939
|
symbol = s;
|
942
|
-
} else if (!this.strict && numberRegEx.test(text)) {
|
943
|
-
// A number. Wrap in a <mn> if in math mode; <mtext> otherwise.
|
944
|
-
this.consume()
|
945
|
-
return {
|
946
|
-
type: "textord",
|
947
|
-
mode: this.mode,
|
948
|
-
loc: SourceLocation.range(nucleus),
|
949
|
-
text
|
950
|
-
}
|
951
940
|
} else if (text.charCodeAt(0) >= 0x80) {
|
952
941
|
// no symbol for e.g. ^
|
953
942
|
if (this.settings.strict) {
|
package/src/Settings.js
CHANGED
@@ -17,7 +17,7 @@ export default class Settings {
|
|
17
17
|
this.leqno = utils.deflt(options.leqno, false); // boolean
|
18
18
|
this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string
|
19
19
|
this.macros = options.macros || {};
|
20
|
-
this.wrap = utils.deflt(options.wrap, "
|
20
|
+
this.wrap = utils.deflt(options.wrap, "tex") // "tex" | "="
|
21
21
|
this.xml = utils.deflt(options.xml, false); // boolean
|
22
22
|
this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean
|
23
23
|
this.strict = utils.deflt(options.strict, false); // boolean
|
package/src/buildMathML.js
CHANGED
@@ -75,6 +75,48 @@ export const consolidateText = mrow => {
|
|
75
75
|
return mtext
|
76
76
|
}
|
77
77
|
|
78
|
+
const numberRegEx = /^[0-9]$/
|
79
|
+
const isCommaOrDot = node => {
|
80
|
+
return (node.type === "atom" && node.text === ",") ||
|
81
|
+
(node.type === "textord" && node.text === ".")
|
82
|
+
}
|
83
|
+
const consolidateNumbers = expression => {
|
84
|
+
// Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
|
85
|
+
// not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
|
86
|
+
if (expression.length < 2) { return }
|
87
|
+
const nums = [];
|
88
|
+
let inNum = false
|
89
|
+
// Find adjacent numerals
|
90
|
+
for (let i = 0; i < expression.length; i++) {
|
91
|
+
const node = expression[i];
|
92
|
+
if (node.type === "textord" && numberRegEx.test(node.text)) {
|
93
|
+
if (!inNum) { nums.push({ start: i }) }
|
94
|
+
inNum = true
|
95
|
+
} else {
|
96
|
+
if (inNum) { nums[nums.length - 1].end = i - 1 }
|
97
|
+
inNum = false
|
98
|
+
}
|
99
|
+
}
|
100
|
+
if (inNum) { nums[nums.length - 1].end = expression.length - 1 }
|
101
|
+
|
102
|
+
// Determine if numeral groups are separated by a comma or dot.
|
103
|
+
for (let i = nums.length - 1; i > 0; i--) {
|
104
|
+
if (nums[i - 1].end === nums[i].start - 2 && isCommaOrDot(expression[nums[i].start - 1])) {
|
105
|
+
// Merge the two groups.
|
106
|
+
nums[i - 1].end = nums[i].end
|
107
|
+
nums.splice(i, 1)
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
// Consolidate the number nodes
|
112
|
+
for (let i = nums.length - 1; i >= 0; i--) {
|
113
|
+
for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
|
114
|
+
expression[nums[i].start].text += expression[j].text
|
115
|
+
}
|
116
|
+
expression.splice(nums[i].start + 1, nums[i].end - nums[i].start)
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
78
120
|
/**
|
79
121
|
* Wrap the given array of nodes in an <mrow> node if needed, i.e.,
|
80
122
|
* unless the array has length 1. Always returns a single node.
|
@@ -110,6 +152,8 @@ export const buildExpression = function(expression, style, isOrdgroup) {
|
|
110
152
|
return [group];
|
111
153
|
}
|
112
154
|
|
155
|
+
consolidateNumbers(expression)
|
156
|
+
|
113
157
|
const groups = [];
|
114
158
|
for (let i = 0; i < expression.length; i++) {
|
115
159
|
const group = buildGroup(expression[i], style);
|
@@ -209,18 +253,6 @@ export default function buildMathML(tree, texExpression, style, settings) {
|
|
209
253
|
wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]);
|
210
254
|
}
|
211
255
|
|
212
|
-
if (wrap !== "none" && wrapper.children.length > 1) {
|
213
|
-
const maths = []
|
214
|
-
for (let i = 0; i < wrapper.children.length; i++) {
|
215
|
-
const math = new mathMLTree.MathNode("math", [wrapper.children[i]])
|
216
|
-
if (settings.xml) {
|
217
|
-
math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML")
|
218
|
-
}
|
219
|
-
maths.push(math)
|
220
|
-
}
|
221
|
-
return mathMLTree.newDocumentFragment(maths)
|
222
|
-
}
|
223
|
-
|
224
256
|
const math = new mathMLTree.MathNode("math", [wrapper])
|
225
257
|
|
226
258
|
if (settings.xml) {
|
@@ -228,6 +260,9 @@ export default function buildMathML(tree, texExpression, style, settings) {
|
|
228
260
|
}
|
229
261
|
if (settings.displayMode) {
|
230
262
|
math.setAttribute("display", "block");
|
263
|
+
math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
|
264
|
+
? "inline"
|
265
|
+
: "inline-block"
|
231
266
|
}
|
232
267
|
return math;
|
233
268
|
}
|
@@ -7,7 +7,7 @@ import * as mml from "../buildMathML"
|
|
7
7
|
// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
|
8
8
|
// src/symbols.js.
|
9
9
|
|
10
|
-
const numberRegEx = /^\d(?:[\d,.]*\d)?$/
|
10
|
+
const numberRegEx = /^\d(?:[\d,.]*\d)?$/
|
11
11
|
const latinRegEx = /[A-Ba-z]/
|
12
12
|
|
13
13
|
const italicNumber = (text, variant, tag) => {
|
package/src/linebreaking.js
CHANGED
@@ -13,10 +13,12 @@ import mathMLTree from "./mathMLTree"
|
|
13
13
|
* Then the top level of a <math> element can be occupied by <mrow> elements, and the browser
|
14
14
|
* will break after a <mrow> if the expression extends beyond the container limit.
|
15
15
|
*
|
16
|
-
*
|
16
|
+
* The default is for soft line breaks after each top-level binary or
|
17
17
|
* relational operator, per TeXbook p. 173. So we gather the expression into <mrow>s so that
|
18
18
|
* each <mrow> ends in a binary or relational operator.
|
19
19
|
*
|
20
|
+
* An option is for soft line breaks before an "=" sign. That changes the <mrow>s.
|
21
|
+
*
|
20
22
|
* Soft line breaks will not work in Chromium and Safari, only Firefox.
|
21
23
|
*
|
22
24
|
* Hopefully browsers will someday do their own linebreaking and we will be able to delete
|