temml 0.10.3 → 0.10.5

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/dist/temml.js CHANGED
@@ -1762,125 +1762,102 @@ var temml = (function () {
1762
1762
  * much of this module.
1763
1763
  */
1764
1764
 
1765
- function setLineBreaks(expression, wrapMode, isDisplayMode, color) {
1766
- if (color === undefined && wrapMode !== "none") {
1767
- // First, make one pass through the expression and split any color nodes.
1768
- const upperLimit = expression.length - 1;
1769
- for (let i = upperLimit; i >= 0; i--) {
1770
- const node = expression[i];
1771
- if (node.type === "mstyle" && node.attributes.mathcolor) {
1772
- const color = node.attributes.mathcolor;
1773
- const fragment = setLineBreaks(node.children, wrapMode, isDisplayMode, color);
1774
- if (!(fragment.type && fragment.type !== "mtable")) {
1775
- expression.splice(i, 1, ...fragment.children);
1776
- }
1777
- }
1778
- }
1779
- }
1780
-
1781
- const tagName = color ? "mstyle" : "mrow";
1782
-
1765
+ function setLineBreaks(expression, wrapMode, isDisplayMode) {
1783
1766
  const mtrs = [];
1784
1767
  let mrows = [];
1785
1768
  let block = [];
1786
1769
  let numTopLevelEquals = 0;
1787
1770
  let canBeBIN = false; // The first node cannot be an infix binary operator.
1788
- for (let i = 0; i < expression.length; i++) {
1789
- const node = expression[i];
1790
- if (node.type && node.type === "mstyle" && node.attributes.mathcolor) {
1791
- if (block.length > 0) {
1792
- // Start a new block. (Insert a soft linebreak.)
1793
- mrows.push(new mathMLTree.MathNode(tagName, block));
1794
- }
1795
- // Insert the mstyle
1796
- mrows.push(node);
1797
- block = [];
1798
- continue
1771
+ let i = 0;
1772
+ while (i < expression.length) {
1773
+ while (expression[i] instanceof DocumentFragment) {
1774
+ expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
1799
1775
  }
1776
+ const node = expression[i];
1800
1777
  if (node.attributes && node.attributes.linebreak &&
1801
1778
  node.attributes.linebreak === "newline") {
1802
1779
  // A hard line break. Create a <mtr> for the current block.
1803
1780
  if (block.length > 0) {
1804
- const element = new mathMLTree.MathNode(tagName, block);
1805
- if (color) { element.setAttribute("mathcolor", color); }
1806
- mrows.push(new mathMLTree.MathNode(tagName, block));
1781
+ mrows.push(new mathMLTree.MathNode("mrow", block));
1807
1782
  }
1808
1783
  mrows.push(node);
1809
1784
  block = [];
1810
1785
  const mtd = new mathMLTree.MathNode("mtd", mrows);
1786
+ mtd.style.textAlign = "left";
1811
1787
  mtrs.push(new mathMLTree.MathNode("mtr", [mtd]));
1812
1788
  mrows = [];
1789
+ i += 1;
1813
1790
  continue
1814
1791
  }
1815
1792
  block.push(node);
1816
- if (node.type && node.type === "mo" && wrapMode === "=") {
1817
- if (node.children.length === 1 && node.children[0].text === "=") {
1793
+ if (node.type && node.type === "mo" && node.children.length === 1) {
1794
+ if (wrapMode === "=" && node.children[0].text === "=") {
1818
1795
  numTopLevelEquals += 1;
1819
1796
  if (numTopLevelEquals > 1) {
1820
1797
  block.pop();
1821
1798
  // Start a new block. (Insert a soft linebreak.)
1822
- const element = new mathMLTree.MathNode(tagName, block);
1823
- if (color) { element.setAttribute("mathcolor", color); }
1799
+ const element = new mathMLTree.MathNode("mrow", block);
1824
1800
  mrows.push(element);
1825
1801
  block = [node];
1826
1802
  }
1827
- }
1828
- } else if (node.type && node.type === "mo" && wrapMode === "tex") {
1829
- // This may be a place for a soft line break.
1830
- if (canBeBIN && !node.attributes.form) {
1831
- // Check if the following node is a \nobreak text node, e.g. "~""
1832
- const next = i < expression.length - 1 ? expression[i + 1] : null;
1833
- let glueIsFreeOfNobreak = true;
1834
- if (
1835
- !(
1836
- next &&
1837
- next.type === "mtext" &&
1838
- next.attributes.linebreak &&
1839
- next.attributes.linebreak === "nobreak"
1840
- )
1841
- ) {
1842
- // We may need to start a new block.
1843
- // First, put any post-operator glue on same line as operator.
1844
- for (let j = i + 1; j < expression.length; j++) {
1845
- const nd = expression[j];
1846
- if (
1847
- nd.type &&
1848
- nd.type === "mspace" &&
1849
- !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1850
- ) {
1851
- block.push(nd);
1852
- i += 1;
1803
+ } else if (wrapMode === "tex") {
1804
+ // This may be a place for a soft line break.
1805
+ if (canBeBIN && !node.attributes.form) {
1806
+ // Check if the following node is a \nobreak text node, e.g. "~""
1807
+ const next = i < expression.length - 1 ? expression[i + 1] : null;
1808
+ let glueIsFreeOfNobreak = true;
1809
+ if (
1810
+ !(
1811
+ next &&
1812
+ next.type === "mtext" &&
1813
+ next.attributes.linebreak &&
1814
+ next.attributes.linebreak === "nobreak"
1815
+ )
1816
+ ) {
1817
+ // We may need to start a new block.
1818
+ // First, put any post-operator glue on same line as operator.
1819
+ for (let j = i + 1; j < expression.length; j++) {
1820
+ const nd = expression[j];
1853
1821
  if (
1854
- nd.attributes &&
1855
- nd.attributes.linebreak &&
1856
- nd.attributes.linebreak === "nobreak"
1822
+ nd.type &&
1823
+ nd.type === "mspace" &&
1824
+ !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1857
1825
  ) {
1858
- glueIsFreeOfNobreak = false;
1826
+ block.push(nd);
1827
+ i += 1;
1828
+ if (
1829
+ nd.attributes &&
1830
+ nd.attributes.linebreak &&
1831
+ nd.attributes.linebreak === "nobreak"
1832
+ ) {
1833
+ glueIsFreeOfNobreak = false;
1834
+ }
1835
+ } else {
1836
+ break;
1859
1837
  }
1860
- } else {
1861
- break;
1862
1838
  }
1863
1839
  }
1840
+ if (glueIsFreeOfNobreak) {
1841
+ // Start a new block. (Insert a soft linebreak.)
1842
+ const element = new mathMLTree.MathNode("mrow", block);
1843
+ mrows.push(element);
1844
+ block = [];
1845
+ }
1846
+ canBeBIN = false;
1864
1847
  }
1865
- if (glueIsFreeOfNobreak) {
1866
- // Start a new block. (Insert a soft linebreak.)
1867
- const element = new mathMLTree.MathNode(tagName, block);
1868
- if (color) { element.setAttribute("mathcolor", color); }
1869
- mrows.push(element);
1870
- block = [];
1871
- }
1872
- canBeBIN = false;
1848
+ const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
1849
+ // Any operator that follows an open delimiter is unary.
1850
+ canBeBIN = !(node.attributes.separator || isOpenDelimiter);
1851
+ } else {
1852
+ canBeBIN = true;
1873
1853
  }
1874
- const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
1875
- // Any operator that follows an open delimiter is unary.
1876
- canBeBIN = !(node.attributes.separator || isOpenDelimiter);
1877
1854
  } else {
1878
1855
  canBeBIN = true;
1879
1856
  }
1857
+ i += 1;
1880
1858
  }
1881
1859
  if (block.length > 0) {
1882
- const element = new mathMLTree.MathNode(tagName, block);
1883
- if (color) { element.setAttribute("mathcolor", color); }
1860
+ const element = new mathMLTree.MathNode("mrow", block);
1884
1861
  mrows.push(element);
1885
1862
  }
1886
1863
  if (mtrs.length > 0) {
@@ -1967,6 +1944,48 @@ var temml = (function () {
1967
1944
  return mtext
1968
1945
  };
1969
1946
 
1947
+ const numberRegEx$1 = /^[0-9]$/;
1948
+ const isCommaOrDot = node => {
1949
+ return (node.type === "atom" && node.text === ",") ||
1950
+ (node.type === "textord" && node.text === ".")
1951
+ };
1952
+ const consolidateNumbers = expression => {
1953
+ // Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
1954
+ // not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
1955
+ if (expression.length < 2) { return }
1956
+ const nums = [];
1957
+ let inNum = false;
1958
+ // Find adjacent numerals
1959
+ for (let i = 0; i < expression.length; i++) {
1960
+ const node = expression[i];
1961
+ if (node.type === "textord" && numberRegEx$1.test(node.text)) {
1962
+ if (!inNum) { nums.push({ start: i }); }
1963
+ inNum = true;
1964
+ } else {
1965
+ if (inNum) { nums[nums.length - 1].end = i - 1; }
1966
+ inNum = false;
1967
+ }
1968
+ }
1969
+ if (inNum) { nums[nums.length - 1].end = expression.length - 1; }
1970
+
1971
+ // Determine if numeral groups are separated by a comma or dot.
1972
+ for (let i = nums.length - 1; i > 0; i--) {
1973
+ if (nums[i - 1].end === nums[i].start - 2 && isCommaOrDot(expression[nums[i].start - 1])) {
1974
+ // Merge the two groups.
1975
+ nums[i - 1].end = nums[i].end;
1976
+ nums.splice(i, 1);
1977
+ }
1978
+ }
1979
+
1980
+ // Consolidate the number nodes
1981
+ for (let i = nums.length - 1; i >= 0; i--) {
1982
+ for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
1983
+ expression[nums[i].start].text += expression[j].text;
1984
+ }
1985
+ expression.splice(nums[i].start + 1, nums[i].end - nums[i].start);
1986
+ }
1987
+ };
1988
+
1970
1989
  /**
1971
1990
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
1972
1991
  * unless the array has length 1. Always returns a single node.
@@ -2002,6 +2021,8 @@ var temml = (function () {
2002
2021
  return [group];
2003
2022
  }
2004
2023
 
2024
+ consolidateNumbers(expression);
2025
+
2005
2026
  const groups = [];
2006
2027
  for (let i = 0; i < expression.length; i++) {
2007
2028
  const group = buildGroup$1(expression[i], style);
@@ -3039,11 +3060,15 @@ var temml = (function () {
3039
3060
  };
3040
3061
 
3041
3062
  const mathmlBuilder$9 = (group, style) => {
3042
- const inner = buildExpression(group.body, style.withColor(group.color));
3043
- // Wrap with an <mstyle> element.
3044
- const node = wrapWithMstyle(inner);
3045
- node.setAttribute("mathcolor", group.color);
3046
- return node
3063
+ // In LaTeX, color is not supposed to change the spacing of any node.
3064
+ // So instead of wrapping the group in an <mstyle>, we apply
3065
+ // the color individually to each node and return a document fragment.
3066
+ let expr = buildExpression(group.body, style.withColor(group.color));
3067
+ expr = expr.map(e => {
3068
+ e.style.color = group.color;
3069
+ return e
3070
+ });
3071
+ return mathMLTree.newDocumentFragment(expr)
3047
3072
  };
3048
3073
 
3049
3074
  defineFunction({
@@ -7644,7 +7669,7 @@ var temml = (function () {
7644
7669
  // "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
7645
7670
  // src/symbols.js.
7646
7671
 
7647
- const numberRegEx$1 = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in Parser.js
7672
+ const numberRegEx = /^\d(?:[\d,.]*\d)?$/;
7648
7673
  const latinRegEx = /[A-Ba-z]/;
7649
7674
 
7650
7675
  const italicNumber = (text, variant, tag) => {
@@ -7698,7 +7723,7 @@ var temml = (function () {
7698
7723
  const variant = getVariant(group, style) || "normal";
7699
7724
 
7700
7725
  let node;
7701
- if (numberRegEx$1.test(group.text)) {
7726
+ if (numberRegEx.test(group.text)) {
7702
7727
  const tag = group.mode === "text" ? "mtext" : "mn";
7703
7728
  if (variant === "italic" || variant === "bold-italic") {
7704
7729
  return italicNumber(text, variant, tag)
@@ -8011,8 +8036,7 @@ var temml = (function () {
8011
8036
  const tokenRegexString =
8012
8037
  `(${spaceRegexString}+)|` + // whitespace
8013
8038
  `${controlSpaceRegexString}|` + // whitespace
8014
- "(number" + // numbers (in non-strict mode)
8015
- "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
8039
+ "([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
8016
8040
  `${combiningDiacriticalMarkString}*` + // ...plus accents
8017
8041
  "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
8018
8042
  `${combiningDiacriticalMarkString}*` + // ...plus accents
@@ -8027,12 +8051,7 @@ var temml = (function () {
8027
8051
  // Separate accents from characters
8028
8052
  this.input = input;
8029
8053
  this.settings = settings;
8030
- this.tokenRegex = new RegExp(
8031
- // Strict Temml, like TeX, lexes one numeral at a time.
8032
- // Default Temml lexes contiguous numerals into a single <mn> element.
8033
- tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"),
8034
- "g"
8035
- );
8054
+ this.tokenRegex = new RegExp(tokenRegexString, 'g');
8036
8055
  // Category codes. The lexer only supports comment characters (14) for now.
8037
8056
  // MacroExpander additionally distinguishes active (13).
8038
8057
  this.catcodes = {
@@ -9900,8 +9919,6 @@ var temml = (function () {
9900
9919
 
9901
9920
  /* eslint no-constant-condition:0 */
9902
9921
 
9903
- const numberRegEx = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in symbolsOrd.js
9904
-
9905
9922
  /**
9906
9923
  * This file contains the parser used to parse out a TeX expression from the
9907
9924
  * input. Since TeX isn't context-free, standard parsers don't work particularly
@@ -10823,15 +10840,6 @@ var temml = (function () {
10823
10840
  };
10824
10841
  }
10825
10842
  symbol = s;
10826
- } else if (!this.strict && numberRegEx.test(text)) {
10827
- // A number. Wrap in a <mn> if in math mode; <mtext> otherwise.
10828
- this.consume();
10829
- return {
10830
- type: "textord",
10831
- mode: this.mode,
10832
- loc: SourceLocation.range(nucleus),
10833
- text
10834
- }
10835
10843
  } else if (text.charCodeAt(0) >= 0x80) {
10836
10844
  // no symbol for e.g. ^
10837
10845
  if (this.settings.strict) {
@@ -11071,7 +11079,7 @@ var temml = (function () {
11071
11079
  * https://mit-license.org/
11072
11080
  */
11073
11081
 
11074
- const version = "0.10.3";
11082
+ const version = "0.10.5";
11075
11083
 
11076
11084
  function postProcess(block) {
11077
11085
  const labelMap = {};