temml 0.10.3 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
package/dist/temml.cjs CHANGED
@@ -1761,125 +1761,102 @@ for (let i = 0; i < 10; i++) {
1761
1761
  * much of this module.
1762
1762
  */
1763
1763
 
1764
- function setLineBreaks(expression, wrapMode, isDisplayMode, color) {
1765
- if (color === undefined && wrapMode !== "none") {
1766
- // First, make one pass through the expression and split any color nodes.
1767
- const upperLimit = expression.length - 1;
1768
- for (let i = upperLimit; i >= 0; i--) {
1769
- const node = expression[i];
1770
- if (node.type === "mstyle" && node.attributes.mathcolor) {
1771
- const color = node.attributes.mathcolor;
1772
- const fragment = setLineBreaks(node.children, wrapMode, isDisplayMode, color);
1773
- if (!(fragment.type && fragment.type !== "mtable")) {
1774
- expression.splice(i, 1, ...fragment.children);
1775
- }
1776
- }
1777
- }
1778
- }
1779
-
1780
- const tagName = color ? "mstyle" : "mrow";
1781
-
1764
+ function setLineBreaks(expression, wrapMode, isDisplayMode) {
1782
1765
  const mtrs = [];
1783
1766
  let mrows = [];
1784
1767
  let block = [];
1785
1768
  let numTopLevelEquals = 0;
1786
1769
  let canBeBIN = false; // The first node cannot be an infix binary operator.
1787
- for (let i = 0; i < expression.length; i++) {
1788
- const node = expression[i];
1789
- if (node.type && node.type === "mstyle" && node.attributes.mathcolor) {
1790
- if (block.length > 0) {
1791
- // Start a new block. (Insert a soft linebreak.)
1792
- mrows.push(new mathMLTree.MathNode(tagName, block));
1793
- }
1794
- // Insert the mstyle
1795
- mrows.push(node);
1796
- block = [];
1797
- continue
1770
+ let i = 0;
1771
+ while (i < expression.length) {
1772
+ while (expression[i] instanceof DocumentFragment) {
1773
+ expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
1798
1774
  }
1775
+ const node = expression[i];
1799
1776
  if (node.attributes && node.attributes.linebreak &&
1800
1777
  node.attributes.linebreak === "newline") {
1801
1778
  // A hard line break. Create a <mtr> for the current block.
1802
1779
  if (block.length > 0) {
1803
- const element = new mathMLTree.MathNode(tagName, block);
1804
- if (color) { element.setAttribute("mathcolor", color); }
1805
- mrows.push(new mathMLTree.MathNode(tagName, block));
1780
+ mrows.push(new mathMLTree.MathNode("mrow", block));
1806
1781
  }
1807
1782
  mrows.push(node);
1808
1783
  block = [];
1809
1784
  const mtd = new mathMLTree.MathNode("mtd", mrows);
1785
+ mtd.style.textAlign = "left";
1810
1786
  mtrs.push(new mathMLTree.MathNode("mtr", [mtd]));
1811
1787
  mrows = [];
1788
+ i += 1;
1812
1789
  continue
1813
1790
  }
1814
1791
  block.push(node);
1815
- if (node.type && node.type === "mo" && wrapMode === "=") {
1816
- if (node.children.length === 1 && node.children[0].text === "=") {
1792
+ if (node.type && node.type === "mo" && node.children.length === 1) {
1793
+ if (wrapMode === "=" && node.children[0].text === "=") {
1817
1794
  numTopLevelEquals += 1;
1818
1795
  if (numTopLevelEquals > 1) {
1819
1796
  block.pop();
1820
1797
  // Start a new block. (Insert a soft linebreak.)
1821
- const element = new mathMLTree.MathNode(tagName, block);
1822
- if (color) { element.setAttribute("mathcolor", color); }
1798
+ const element = new mathMLTree.MathNode("mrow", block);
1823
1799
  mrows.push(element);
1824
1800
  block = [node];
1825
1801
  }
1826
- }
1827
- } else if (node.type && node.type === "mo" && wrapMode === "tex") {
1828
- // This may be a place for a soft line break.
1829
- if (canBeBIN && !node.attributes.form) {
1830
- // Check if the following node is a \nobreak text node, e.g. "~""
1831
- const next = i < expression.length - 1 ? expression[i + 1] : null;
1832
- let glueIsFreeOfNobreak = true;
1833
- if (
1834
- !(
1835
- next &&
1836
- next.type === "mtext" &&
1837
- next.attributes.linebreak &&
1838
- next.attributes.linebreak === "nobreak"
1839
- )
1840
- ) {
1841
- // We may need to start a new block.
1842
- // First, put any post-operator glue on same line as operator.
1843
- for (let j = i + 1; j < expression.length; j++) {
1844
- const nd = expression[j];
1845
- if (
1846
- nd.type &&
1847
- nd.type === "mspace" &&
1848
- !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1849
- ) {
1850
- block.push(nd);
1851
- i += 1;
1802
+ } else if (wrapMode === "tex") {
1803
+ // This may be a place for a soft line break.
1804
+ if (canBeBIN && !node.attributes.form) {
1805
+ // Check if the following node is a \nobreak text node, e.g. "~""
1806
+ const next = i < expression.length - 1 ? expression[i + 1] : null;
1807
+ let glueIsFreeOfNobreak = true;
1808
+ if (
1809
+ !(
1810
+ next &&
1811
+ next.type === "mtext" &&
1812
+ next.attributes.linebreak &&
1813
+ next.attributes.linebreak === "nobreak"
1814
+ )
1815
+ ) {
1816
+ // We may need to start a new block.
1817
+ // First, put any post-operator glue on same line as operator.
1818
+ for (let j = i + 1; j < expression.length; j++) {
1819
+ const nd = expression[j];
1852
1820
  if (
1853
- nd.attributes &&
1854
- nd.attributes.linebreak &&
1855
- nd.attributes.linebreak === "nobreak"
1821
+ nd.type &&
1822
+ nd.type === "mspace" &&
1823
+ !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1856
1824
  ) {
1857
- glueIsFreeOfNobreak = false;
1825
+ block.push(nd);
1826
+ i += 1;
1827
+ if (
1828
+ nd.attributes &&
1829
+ nd.attributes.linebreak &&
1830
+ nd.attributes.linebreak === "nobreak"
1831
+ ) {
1832
+ glueIsFreeOfNobreak = false;
1833
+ }
1834
+ } else {
1835
+ break;
1858
1836
  }
1859
- } else {
1860
- break;
1861
1837
  }
1862
1838
  }
1839
+ if (glueIsFreeOfNobreak) {
1840
+ // Start a new block. (Insert a soft linebreak.)
1841
+ const element = new mathMLTree.MathNode("mrow", block);
1842
+ mrows.push(element);
1843
+ block = [];
1844
+ }
1845
+ canBeBIN = false;
1863
1846
  }
1864
- if (glueIsFreeOfNobreak) {
1865
- // Start a new block. (Insert a soft linebreak.)
1866
- const element = new mathMLTree.MathNode(tagName, block);
1867
- if (color) { element.setAttribute("mathcolor", color); }
1868
- mrows.push(element);
1869
- block = [];
1870
- }
1871
- canBeBIN = false;
1847
+ const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
1848
+ // Any operator that follows an open delimiter is unary.
1849
+ canBeBIN = !(node.attributes.separator || isOpenDelimiter);
1850
+ } else {
1851
+ canBeBIN = true;
1872
1852
  }
1873
- const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
1874
- // Any operator that follows an open delimiter is unary.
1875
- canBeBIN = !(node.attributes.separator || isOpenDelimiter);
1876
1853
  } else {
1877
1854
  canBeBIN = true;
1878
1855
  }
1856
+ i += 1;
1879
1857
  }
1880
1858
  if (block.length > 0) {
1881
- const element = new mathMLTree.MathNode(tagName, block);
1882
- if (color) { element.setAttribute("mathcolor", color); }
1859
+ const element = new mathMLTree.MathNode("mrow", block);
1883
1860
  mrows.push(element);
1884
1861
  }
1885
1862
  if (mtrs.length > 0) {
@@ -1966,6 +1943,48 @@ const consolidateText = mrow => {
1966
1943
  return mtext
1967
1944
  };
1968
1945
 
1946
+ const numberRegEx$1 = /^[0-9]$/;
1947
+ const isCommaOrDot = node => {
1948
+ return (node.type === "atom" && node.text === ",") ||
1949
+ (node.type === "textord" && node.text === ".")
1950
+ };
1951
+ const consolidateNumbers = expression => {
1952
+ // Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
1953
+ // not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
1954
+ if (expression.length < 2) { return }
1955
+ const nums = [];
1956
+ let inNum = false;
1957
+ // Find adjacent numerals
1958
+ for (let i = 0; i < expression.length; i++) {
1959
+ const node = expression[i];
1960
+ if (node.type === "textord" && numberRegEx$1.test(node.text)) {
1961
+ if (!inNum) { nums.push({ start: i }); }
1962
+ inNum = true;
1963
+ } else {
1964
+ if (inNum) { nums[nums.length - 1].end = i - 1; }
1965
+ inNum = false;
1966
+ }
1967
+ }
1968
+ if (inNum) { nums[nums.length - 1].end = expression.length - 1; }
1969
+
1970
+ // Determine if numeral groups are separated by a comma or dot.
1971
+ for (let i = nums.length - 1; i > 0; i--) {
1972
+ if (nums[i - 1].end === nums[i].start - 2 && isCommaOrDot(expression[nums[i].start - 1])) {
1973
+ // Merge the two groups.
1974
+ nums[i - 1].end = nums[i].end;
1975
+ nums.splice(i, 1);
1976
+ }
1977
+ }
1978
+
1979
+ // Consolidate the number nodes
1980
+ for (let i = nums.length - 1; i >= 0; i--) {
1981
+ for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
1982
+ expression[nums[i].start].text += expression[j].text;
1983
+ }
1984
+ expression.splice(nums[i].start + 1, nums[i].end - nums[i].start);
1985
+ }
1986
+ };
1987
+
1969
1988
  /**
1970
1989
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
1971
1990
  * unless the array has length 1. Always returns a single node.
@@ -2001,6 +2020,8 @@ const buildExpression = function(expression, style, isOrdgroup) {
2001
2020
  return [group];
2002
2021
  }
2003
2022
 
2023
+ consolidateNumbers(expression);
2024
+
2004
2025
  const groups = [];
2005
2026
  for (let i = 0; i < expression.length; i++) {
2006
2027
  const group = buildGroup$1(expression[i], style);
@@ -3038,11 +3059,15 @@ const validateColor = (color, macros, token) => {
3038
3059
  };
3039
3060
 
3040
3061
  const mathmlBuilder$9 = (group, style) => {
3041
- const inner = buildExpression(group.body, style.withColor(group.color));
3042
- // Wrap with an <mstyle> element.
3043
- const node = wrapWithMstyle(inner);
3044
- node.setAttribute("mathcolor", group.color);
3045
- return node
3062
+ // In LaTeX, color is not supposed to change the spacing of any node.
3063
+ // So instead of wrapping the group in an <mstyle>, we apply
3064
+ // the color individually to each node and return a document fragment.
3065
+ let expr = buildExpression(group.body, style.withColor(group.color));
3066
+ expr = expr.map(e => {
3067
+ e.style.color = group.color;
3068
+ return e
3069
+ });
3070
+ return mathMLTree.newDocumentFragment(expr)
3046
3071
  };
3047
3072
 
3048
3073
  defineFunction({
@@ -7643,7 +7668,7 @@ const smallCaps = Object.freeze({
7643
7668
  // "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
7644
7669
  // src/symbols.js.
7645
7670
 
7646
- const numberRegEx$1 = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in Parser.js
7671
+ const numberRegEx = /^\d(?:[\d,.]*\d)?$/;
7647
7672
  const latinRegEx = /[A-Ba-z]/;
7648
7673
 
7649
7674
  const italicNumber = (text, variant, tag) => {
@@ -7697,7 +7722,7 @@ defineFunctionBuilders({
7697
7722
  const variant = getVariant(group, style) || "normal";
7698
7723
 
7699
7724
  let node;
7700
- if (numberRegEx$1.test(group.text)) {
7725
+ if (numberRegEx.test(group.text)) {
7701
7726
  const tag = group.mode === "text" ? "mtext" : "mn";
7702
7727
  if (variant === "italic" || variant === "bold-italic") {
7703
7728
  return italicNumber(text, variant, tag)
@@ -8010,8 +8035,7 @@ const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMark
8010
8035
  const tokenRegexString =
8011
8036
  `(${spaceRegexString}+)|` + // whitespace
8012
8037
  `${controlSpaceRegexString}|` + // whitespace
8013
- "(number" + // numbers (in non-strict mode)
8014
- "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
8038
+ "([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
8015
8039
  `${combiningDiacriticalMarkString}*` + // ...plus accents
8016
8040
  "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
8017
8041
  `${combiningDiacriticalMarkString}*` + // ...plus accents
@@ -8026,12 +8050,7 @@ class Lexer {
8026
8050
  // Separate accents from characters
8027
8051
  this.input = input;
8028
8052
  this.settings = settings;
8029
- this.tokenRegex = new RegExp(
8030
- // Strict Temml, like TeX, lexes one numeral at a time.
8031
- // Default Temml lexes contiguous numerals into a single <mn> element.
8032
- tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"),
8033
- "g"
8034
- );
8053
+ this.tokenRegex = new RegExp(tokenRegexString, 'g');
8035
8054
  // Category codes. The lexer only supports comment characters (14) for now.
8036
8055
  // MacroExpander additionally distinguishes active (13).
8037
8056
  this.catcodes = {
@@ -11799,8 +11818,6 @@ var unicodeSymbols = {
11799
11818
 
11800
11819
  /* eslint no-constant-condition:0 */
11801
11820
 
11802
- const numberRegEx = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in symbolsOrd.js
11803
-
11804
11821
  /**
11805
11822
  * This file contains the parser used to parse out a TeX expression from the
11806
11823
  * input. Since TeX isn't context-free, standard parsers don't work particularly
@@ -12722,15 +12739,6 @@ class Parser {
12722
12739
  };
12723
12740
  }
12724
12741
  symbol = s;
12725
- } else if (!this.strict && numberRegEx.test(text)) {
12726
- // A number. Wrap in a <mn> if in math mode; <mtext> otherwise.
12727
- this.consume();
12728
- return {
12729
- type: "textord",
12730
- mode: this.mode,
12731
- loc: SourceLocation.range(nucleus),
12732
- text
12733
- }
12734
12742
  } else if (text.charCodeAt(0) >= 0x80) {
12735
12743
  // no symbol for e.g. ^
12736
12744
  if (this.settings.strict) {
@@ -12970,7 +12978,7 @@ class Style {
12970
12978
  * https://mit-license.org/
12971
12979
  */
12972
12980
 
12973
- const version = "0.10.3";
12981
+ const version = "0.10.5";
12974
12982
 
12975
12983
  function postProcess(block) {
12976
12984
  const labelMap = {};