temml 0.9.1

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.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/contrib/auto-render/README.md +89 -0
  4. package/contrib/auto-render/auto-render.js +128 -0
  5. package/contrib/auto-render/dist/auto-render.js +217 -0
  6. package/contrib/auto-render/dist/auto-render.min.js +1 -0
  7. package/contrib/auto-render/splitAtDelimiters.js +84 -0
  8. package/contrib/auto-render/test/auto-render-spec.js +234 -0
  9. package/contrib/auto-render/test/auto-render.js +217 -0
  10. package/contrib/auto-render/test/test_page.html +59 -0
  11. package/contrib/mhchem/README.md +26 -0
  12. package/contrib/mhchem/mhchem.js +1705 -0
  13. package/contrib/mhchem/mhchem.min.js +1 -0
  14. package/contrib/physics/README.md +20 -0
  15. package/contrib/physics/physics.js +131 -0
  16. package/contrib/texvc/README.md +23 -0
  17. package/contrib/texvc/texvc.js +61 -0
  18. package/dist/Temml-Asana.css +201 -0
  19. package/dist/Temml-Latin-Modern.css +216 -0
  20. package/dist/Temml-Libertinus.css +214 -0
  21. package/dist/Temml-Local.css +194 -0
  22. package/dist/Temml-STIX2.css +203 -0
  23. package/dist/Temml.woff2 +0 -0
  24. package/dist/temml.cjs +13122 -0
  25. package/dist/temml.js +11225 -0
  26. package/dist/temml.min.js +1 -0
  27. package/dist/temml.mjs +13120 -0
  28. package/dist/temmlPostProcess.js +70 -0
  29. package/package.json +34 -0
  30. package/src/Lexer.js +121 -0
  31. package/src/MacroExpander.js +437 -0
  32. package/src/Namespace.js +107 -0
  33. package/src/ParseError.js +64 -0
  34. package/src/Parser.js +977 -0
  35. package/src/Settings.js +49 -0
  36. package/src/SourceLocation.js +29 -0
  37. package/src/Style.js +144 -0
  38. package/src/Token.js +40 -0
  39. package/src/buildMathML.js +235 -0
  40. package/src/constants.js +25 -0
  41. package/src/defineEnvironment.js +25 -0
  42. package/src/defineFunction.js +69 -0
  43. package/src/defineMacro.js +11 -0
  44. package/src/domTree.js +185 -0
  45. package/src/environments/array.js +791 -0
  46. package/src/environments/cd.js +252 -0
  47. package/src/environments.js +8 -0
  48. package/src/functions/accent.js +127 -0
  49. package/src/functions/accentunder.js +38 -0
  50. package/src/functions/arrow.js +204 -0
  51. package/src/functions/cancelto.js +36 -0
  52. package/src/functions/char.js +33 -0
  53. package/src/functions/color.js +253 -0
  54. package/src/functions/cr.js +46 -0
  55. package/src/functions/def.js +259 -0
  56. package/src/functions/delimsizing.js +304 -0
  57. package/src/functions/enclose.js +193 -0
  58. package/src/functions/envTag.js +38 -0
  59. package/src/functions/environment.js +59 -0
  60. package/src/functions/font.js +123 -0
  61. package/src/functions/genfrac.js +333 -0
  62. package/src/functions/hbox.js +29 -0
  63. package/src/functions/horizBrace.js +32 -0
  64. package/src/functions/href.js +90 -0
  65. package/src/functions/html.js +95 -0
  66. package/src/functions/includegraphics.js +131 -0
  67. package/src/functions/kern.js +75 -0
  68. package/src/functions/label.js +29 -0
  69. package/src/functions/lap.js +75 -0
  70. package/src/functions/math.js +40 -0
  71. package/src/functions/mathchoice.js +41 -0
  72. package/src/functions/mclass.js +201 -0
  73. package/src/functions/multiscript.js +91 -0
  74. package/src/functions/not.js +46 -0
  75. package/src/functions/op.js +338 -0
  76. package/src/functions/operatorname.js +139 -0
  77. package/src/functions/ordgroup.js +9 -0
  78. package/src/functions/phantom.js +73 -0
  79. package/src/functions/pmb.js +31 -0
  80. package/src/functions/raise.js +68 -0
  81. package/src/functions/ref.js +28 -0
  82. package/src/functions/relax.js +16 -0
  83. package/src/functions/rule.js +52 -0
  84. package/src/functions/sizing.js +64 -0
  85. package/src/functions/smash.js +66 -0
  86. package/src/functions/sqrt.js +31 -0
  87. package/src/functions/styling.js +58 -0
  88. package/src/functions/supsub.js +135 -0
  89. package/src/functions/symbolsOp.js +53 -0
  90. package/src/functions/symbolsOrd.js +102 -0
  91. package/src/functions/symbolsSpacing.js +53 -0
  92. package/src/functions/tag.js +8 -0
  93. package/src/functions/text.js +75 -0
  94. package/src/functions/tip.js +63 -0
  95. package/src/functions/toggle.js +13 -0
  96. package/src/functions/verb.js +33 -0
  97. package/src/functions.js +57 -0
  98. package/src/linebreaking.js +159 -0
  99. package/src/macros.js +708 -0
  100. package/src/mathMLTree.js +175 -0
  101. package/src/parseNode.js +42 -0
  102. package/src/parseTree.js +40 -0
  103. package/src/postProcess.js +57 -0
  104. package/src/replace.js +225 -0
  105. package/src/stretchy.js +66 -0
  106. package/src/svg.js +110 -0
  107. package/src/symbols.js +972 -0
  108. package/src/tree.js +50 -0
  109. package/src/unicodeAccents.js +16 -0
  110. package/src/unicodeScripts.js +119 -0
  111. package/src/unicodeSupOrSub.js +108 -0
  112. package/src/unicodeSymbolBuilder.js +31 -0
  113. package/src/unicodeSymbols.js +320 -0
  114. package/src/units.js +109 -0
  115. package/src/utils.js +109 -0
  116. package/src/variant.js +103 -0
  117. package/temml.js +181 -0
package/src/units.js ADDED
@@ -0,0 +1,109 @@
1
+ /**
2
+ * This file does conversion between units. In particular, it provides
3
+ * calculateSize to convert other units into CSS units.
4
+ */
5
+
6
+ import ParseError from "./ParseError"
7
+ import utils from "./utils"
8
+
9
+ const ptPerUnit = {
10
+ // Convert to CSS (Postscipt) points, not TeX points
11
+ // https://en.wikibooks.org/wiki/LaTeX/Lengths and
12
+ // https://tex.stackexchange.com/a/8263
13
+ pt: 800 / 803, // convert TeX point to CSS (Postscript) point
14
+ pc: (12 * 800) / 803, // pica
15
+ dd: ((1238 / 1157) * 800) / 803, // didot
16
+ cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot)
17
+ nd: ((685 / 642) * 800) / 803, // new didot
18
+ nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot)
19
+ sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit)
20
+ mm: (25.4 / 72),
21
+ cm: (2.54 / 72),
22
+ in: (1 / 72),
23
+ px: (96 / 72)
24
+ }
25
+
26
+ /**
27
+ * Determine whether the specified unit (either a string defining the unit
28
+ * or a "size" parse node containing a unit field) is valid.
29
+ */
30
+ const validUnits = [
31
+ "em",
32
+ "ex",
33
+ "mu",
34
+ "pt",
35
+ "mm",
36
+ "cm",
37
+ "in",
38
+ "px",
39
+ "bp",
40
+ "pc",
41
+ "dd",
42
+ "cc",
43
+ "nd",
44
+ "nc",
45
+ "sp"
46
+ ]
47
+
48
+ export const validUnit = function(unit) {
49
+ if (typeof unit !== "string") {
50
+ unit = unit.unit
51
+ }
52
+ return validUnits.indexOf(unit) > -1
53
+ }
54
+
55
+ export const emScale = styleLevel => {
56
+ const scriptLevel = Math.max(styleLevel - 1, 0)
57
+ return [1, 0.7, 0.5][scriptLevel]
58
+ };
59
+
60
+ /*
61
+ * Convert a "size" parse node (with numeric "number" and string "unit" fields,
62
+ * as parsed by functions.js argType "size") into a CSS value.
63
+ */
64
+ export const calculateSize = function(sizeValue, style) {
65
+ let number = sizeValue.number
66
+ if (style.maxSize[0] < 0 && number > 0) {
67
+ return { number: 0, unit: "em" }
68
+ }
69
+ const unit = sizeValue.unit
70
+ switch (unit) {
71
+ case "mm":
72
+ case "cm":
73
+ case "in":
74
+ case "px": {
75
+ const numInCssPts = number * ptPerUnit[unit];
76
+ if (numInCssPts > style.maxSize[1]) {
77
+ return { number: style.maxSize[1], unit: "pt" }
78
+ }
79
+ return { number, unit }; // absolute CSS units.
80
+ }
81
+ case "em":
82
+ case "ex": {
83
+ // In TeX, em and ex do not change size in \scriptstyle.
84
+ if (unit === "ex") { number *= 0.431 }
85
+ number = Math.min(number / emScale(style.level), style.maxSize[0])
86
+ return { number: utils.round(number), unit: "em" };
87
+ }
88
+ case "bp": {
89
+ if (number > style.maxSize[1]) { number = style.maxSize[1] }
90
+ return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch).
91
+ }
92
+ case "pt":
93
+ case "pc":
94
+ case "dd":
95
+ case "cc":
96
+ case "nd":
97
+ case "nc":
98
+ case "sp": {
99
+ number = Math.min(number * ptPerUnit[unit], style.maxSize[1])
100
+ return { number: utils.round(number), unit: "pt" }
101
+ }
102
+ case "mu": {
103
+ number = Math.min(number / 18, style.maxSize[0])
104
+ return { number: utils.round(number), unit: "em" }
105
+ }
106
+ default:
107
+ throw new ParseError("Invalid unit: '" + unit + "'")
108
+ }
109
+ }
package/src/utils.js ADDED
@@ -0,0 +1,109 @@
1
+ //
2
+ /**
3
+ * This file contains a list of utility functions which are useful in other
4
+ * files.
5
+ */
6
+
7
+ /**
8
+ * Provide a default value if a setting is undefined
9
+ */
10
+ const deflt = function(setting, defaultIfUndefined) {
11
+ return setting === undefined ? defaultIfUndefined : setting;
12
+ };
13
+
14
+ // hyphenate and escape adapted from Facebook's React under Apache 2 license
15
+
16
+ const uppercase = /([A-Z])/g;
17
+ const hyphenate = function(str) {
18
+ return str.replace(uppercase, "-$1").toLowerCase();
19
+ };
20
+
21
+ const ESCAPE_LOOKUP = {
22
+ "&": "&amp;",
23
+ ">": "&gt;",
24
+ "<": "&lt;",
25
+ '"': "&quot;",
26
+ "'": "&#x27;"
27
+ };
28
+
29
+ const ESCAPE_REGEX = /[&><"']/g;
30
+
31
+ /**
32
+ * Escapes text to prevent scripting attacks.
33
+ */
34
+ function escape(text) {
35
+ return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
36
+ }
37
+
38
+ /**
39
+ * Sometimes we want to pull out the innermost element of a group. In most
40
+ * cases, this will just be the group itself, but when ordgroups and colors have
41
+ * a single element, we want to pull that out.
42
+ */
43
+ const getBaseElem = function(group) {
44
+ if (group.type === "ordgroup") {
45
+ if (group.body.length === 1) {
46
+ return getBaseElem(group.body[0]);
47
+ } else {
48
+ return group;
49
+ }
50
+ } else if (group.type === "color") {
51
+ if (group.body.length === 1) {
52
+ return getBaseElem(group.body[0]);
53
+ } else {
54
+ return group;
55
+ }
56
+ } else if (group.type === "font") {
57
+ return getBaseElem(group.body);
58
+ } else {
59
+ return group;
60
+ }
61
+ };
62
+
63
+ /**
64
+ * TeXbook algorithms often reference "character boxes", which are simply groups
65
+ * with a single character in them. To decide if something is a character box,
66
+ * we find its innermost group, and see if it is a single character.
67
+ */
68
+ const isCharacterBox = function(group) {
69
+ const baseElem = getBaseElem(group);
70
+
71
+ // These are all the types of groups which hold single characters
72
+ return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom"
73
+ };
74
+
75
+ export const assert = function(value) {
76
+ if (!value) {
77
+ throw new Error("Expected non-null, but got " + String(value));
78
+ }
79
+ return value;
80
+ };
81
+
82
+ /**
83
+ * Return the protocol of a URL, or "_relative" if the URL does not specify a
84
+ * protocol (and thus is relative).
85
+ */
86
+ export const protocolFromUrl = function(url) {
87
+ const protocol = /^\s*([^\\/#]*?)(?::|&#0*58|&#x0*3a)/i.exec(url);
88
+ return protocol != null ? protocol[1] : "_relative";
89
+ };
90
+
91
+ /**
92
+ * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook
93
+ * gives an acceptable rounding error of 100sp (which would be the nearest
94
+ * 1/6551.6em with our ptPerEm = 10):
95
+ * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69
96
+ */
97
+ const round = function(n) {
98
+ return +n.toFixed(4);
99
+ };
100
+
101
+ export default {
102
+ deflt,
103
+ escape,
104
+ hyphenate,
105
+ getBaseElem,
106
+ isCharacterBox,
107
+ protocolFromUrl,
108
+ round
109
+ };
package/src/variant.js ADDED
@@ -0,0 +1,103 @@
1
+ import symbols from "./symbols";
2
+
3
+ /**
4
+ * Maps TeX font commands to "mathvariant" attribute in buildMathML.js
5
+ */
6
+ const fontMap = {
7
+ // styles
8
+ mathbf: "bold",
9
+ mathrm: "normal",
10
+ textit: "italic",
11
+ mathit: "italic",
12
+ mathnormal: "italic",
13
+
14
+ // families
15
+ mathbb: "double-struck",
16
+ mathcal: "script",
17
+ mathfrak: "fraktur",
18
+ mathscr: "script",
19
+ mathsf: "sans-serif",
20
+ mathtt: "monospace",
21
+ oldstylenums: "oldstylenums"
22
+ }
23
+
24
+ /**
25
+ * Returns the math variant as a string or null if none is required.
26
+ */
27
+ export const getVariant = function(group, style) {
28
+ // Handle font specifiers as best we can.
29
+ // Chromium does not support the MathML mathvariant attribute.
30
+ // So we'll use Unicode replacement characters instead.
31
+ // But first, determine the math variant.
32
+
33
+ // Deal with the \textit, \textbf, etc., functions.
34
+ if (style.fontFamily === "texttt") {
35
+ return "monospace"
36
+ } else if (style.fontFamily === "textsc") {
37
+ return "normal"; // handled via character substitution in symbolsOrd.js.
38
+ } else if (style.fontFamily === "textsf") {
39
+ if (style.fontShape === "textit" && style.fontWeight === "textbf") {
40
+ return "sans-serif-bold-italic"
41
+ } else if (style.fontShape === "textit") {
42
+ return "sans-serif-italic"
43
+ } else if (style.fontWeight === "textbf") {
44
+ return "sans-serif-bold"
45
+ } else {
46
+ return "sans-serif"
47
+ }
48
+ } else if (style.fontShape === "textit" && style.fontWeight === "textbf") {
49
+ return "bold-italic"
50
+ } else if (style.fontShape === "textit") {
51
+ return "italic"
52
+ } else if (style.fontWeight === "textbf") {
53
+ return "bold"
54
+ }
55
+
56
+ // Deal with the \mathit, mathbf, etc, functions.
57
+ const font = style.font
58
+ if (!font || font === "mathnormal") {
59
+ return null
60
+ }
61
+
62
+ const mode = group.mode;
63
+ switch (font) {
64
+ case "mathit":
65
+ return "italic"
66
+ case "mathrm": {
67
+ const codePoint = group.text.codePointAt(0)
68
+ // LaTeX \mathrm returns italic for Greek characters.
69
+ return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal"
70
+ }
71
+ case "greekItalic":
72
+ return "italic"
73
+ case "up@greek":
74
+ return "normal"
75
+ case "boldsymbol":
76
+ case "mathboldsymbol":
77
+ return "bold-italic"
78
+ case "mathbf":
79
+ return "bold"
80
+ case "mathbb":
81
+ return "double-struck"
82
+ case "mathfrak":
83
+ return "fraktur"
84
+ case "mathscr":
85
+ case "mathcal":
86
+ return "script"
87
+ case "mathsf":
88
+ return "sans-serif"
89
+ case "mathtt":
90
+ return "monospace"
91
+ case "oldstylenums":
92
+ return "oldstylenums"
93
+ default:
94
+ break
95
+ }
96
+
97
+ let text = group.text;
98
+ if (symbols[mode][text] && symbols[mode][text].replace) {
99
+ text = symbols[mode][text].replace
100
+ }
101
+
102
+ return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null
103
+ };
package/temml.js ADDED
@@ -0,0 +1,181 @@
1
+ /* eslint no-console:0 */
2
+ /**
3
+ * This is the main entry point for Temml. Here, we expose functions for
4
+ * rendering expressions either to DOM nodes or to markup strings.
5
+ *
6
+ * We also expose the ParseError class to check if errors thrown from Temml are
7
+ * errors in the expression, or errors in javascript handling.
8
+ */
9
+
10
+ import ParseError from "./src/ParseError";
11
+ import Settings from "./src/Settings";
12
+
13
+ import Parser from "./src/Parser";
14
+ import parseTree from "./src/parseTree";
15
+ import buildMathML from "./src/buildMathML";
16
+ import { StyleLevel } from "./src/constants";
17
+ import Style from "./src/Style";
18
+ import { Span, TextNode } from "./src/domTree";
19
+ import { defineSymbol } from "./src/symbols";
20
+ import defineMacro from "./src/defineMacro";
21
+ import { postProcess, version } from "./src/postProcess";
22
+
23
+ /**
24
+ * Parse and build an expression, and place that expression in the DOM node
25
+ * given.
26
+ */
27
+ let render = function(expression, baseNode, options) {
28
+ baseNode.textContent = "";
29
+ const alreadyInMathElement = baseNode.tagName === "MATH"
30
+ if (alreadyInMathElement) { options.wrap = "none" }
31
+ const math = renderToMathMLTree(expression, options)
32
+ if (alreadyInMathElement) {
33
+ // The <math> element already exists. Populate it.
34
+ baseNode.textContent = ""
35
+ math.children.forEach(e => { baseNode.appendChild(e.toNode()) })
36
+ } else if (math.children.length > 1) {
37
+ baseNode.textContent = ""
38
+ math.children.forEach(e => { baseNode.appendChild(e.toNode()) })
39
+ } else {
40
+ baseNode.appendChild(math.toNode())
41
+ }
42
+ };
43
+
44
+ // Temml's styles don't work properly in quirks mode. Print out an error, and
45
+ // disable rendering.
46
+ if (typeof document !== "undefined") {
47
+ if (document.compatMode !== "CSS1Compat") {
48
+ typeof console !== "undefined" &&
49
+ console.warn(
50
+ "Warning: Temml doesn't work in quirks mode. Make sure your " +
51
+ "website has a suitable doctype."
52
+ );
53
+
54
+ render = function() {
55
+ throw new ParseError("Temml doesn't work in quirks mode.");
56
+ };
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Parse and build an expression, and return the markup for that.
62
+ */
63
+ const renderToString = function(expression, options) {
64
+ const markup = renderToMathMLTree(expression, options).toMarkup();
65
+ return markup;
66
+ };
67
+
68
+ /**
69
+ * Parse an expression and return the parse tree.
70
+ */
71
+ const generateParseTree = function(expression, options) {
72
+ const settings = new Settings(options);
73
+ return parseTree(expression, settings);
74
+ };
75
+
76
+ /**
77
+ * Take an expression which contains a preamble.
78
+ * Parse it and return the macros.
79
+ */
80
+ const definePreamble = function(expression, options) {
81
+ const settings = new Settings(options);
82
+ settings.macros = {};
83
+ if (!(typeof expression === "string" || expression instanceof String)) {
84
+ throw new TypeError("Temml can only parse string typed expression")
85
+ }
86
+ const parser = new Parser(expression, settings, true)
87
+ // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
88
+ delete parser.gullet.macros.current["\\df@tag"]
89
+ const macros = parser.parse()
90
+ return macros
91
+ };
92
+
93
+ /**
94
+ * If the given error is a Temml ParseError,
95
+ * renders the invalid LaTeX as a span with hover title giving the Temml
96
+ * error message. Otherwise, simply throws the error.
97
+ */
98
+ const renderError = function(error, expression, options) {
99
+ if (options.throwOnError || !(error instanceof ParseError)) {
100
+ throw error;
101
+ }
102
+ const node = new Span(["temml-error"], [new TextNode(expression + "\n" + error.toString())]);
103
+ node.style.color = options.errorColor
104
+ node.style.whiteSpace = "pre-line"
105
+ return node;
106
+ };
107
+
108
+ /**
109
+ * Generates and returns the Temml build tree. This is used for advanced
110
+ * use cases (like rendering to custom output).
111
+ */
112
+ const renderToMathMLTree = function(expression, options) {
113
+ const settings = new Settings(options);
114
+ try {
115
+ const tree = parseTree(expression, settings);
116
+ const style = new Style({
117
+ level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT,
118
+ maxSize: settings.maxSize
119
+ });
120
+ return buildMathML(tree, expression, style, settings);
121
+ } catch (error) {
122
+ return renderError(error, expression, settings);
123
+ }
124
+ };
125
+
126
+ export default {
127
+ /**
128
+ * Current Temml version
129
+ */
130
+ version: version,
131
+ /**
132
+ * Renders the given LaTeX into MathML, and adds
133
+ * it as a child to the specified DOM node.
134
+ */
135
+ render,
136
+ /**
137
+ * Renders the given LaTeX into MathML string,
138
+ * for sending to the client.
139
+ */
140
+ renderToString,
141
+ /**
142
+ * Post-process an entire HTML block.
143
+ * Writes AMS auto-numbers and implements \ref{}.
144
+ * Typcally called once, after a loop has rendered many individual spans.
145
+ */
146
+ postProcess,
147
+ /**
148
+ * Temml error, usually during parsing.
149
+ */
150
+ ParseError,
151
+ /**
152
+ * Creates a set of macros with document-wide scope.
153
+ */
154
+ definePreamble,
155
+ /**
156
+ * Parses the given LaTeX into Temml's internal parse tree structure,
157
+ * without rendering to HTML or MathML.
158
+ *
159
+ * NOTE: This method is not currently recommended for public use.
160
+ * The internal tree representation is unstable and is very likely
161
+ * to change. Use at your own risk.
162
+ */
163
+ __parse: generateParseTree,
164
+ /**
165
+ * Renders the given LaTeX into a MathML internal DOM tree
166
+ * representation, without flattening that representation to a string.
167
+ *
168
+ * NOTE: This method is not currently recommended for public use.
169
+ * The internal tree representation is unstable and is very likely
170
+ * to change. Use at your own risk.
171
+ */
172
+ __renderToMathMLTree: renderToMathMLTree,
173
+ /**
174
+ * adds a new symbol to builtin symbols table
175
+ */
176
+ __defineSymbol: defineSymbol,
177
+ /**
178
+ * adds a new macro to builtin macro list
179
+ */
180
+ __defineMacro: defineMacro
181
+ }