htmljs-parser 5.6.2 → 5.7.0

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 CHANGED
@@ -201,15 +201,18 @@ const parser = createParser({
201
201
  // TagType.void makes this a void element (cannot have children).
202
202
  return TagType.void;
203
203
  case "html-comment":
204
+ case "html-script":
205
+ case "html-style":
204
206
  case "script":
205
207
  case "style":
206
208
  case "textarea":
207
209
  // TagType.text makes the child content text only (with placeholders).
208
210
  return TagType.text;
209
- case "class":
210
211
  case "export":
211
212
  case "import":
212
213
  case "static":
214
+ case "client":
215
+ case "server":
213
216
  // TagType.statement makes this a statement tag where the content following the tag name will be parsed as script code until we reach a new line, eg for `import x from "y"`).
214
217
  return TagType.statement;
215
218
  }
package/dist/index.js CHANGED
@@ -793,15 +793,16 @@ var OPEN_TAG = {
793
793
  }
794
794
  }
795
795
  };
796
- function shouldTerminateConciseTagVar(code, data, pos) {
796
+ function shouldTerminateConciseTagVar(code, data, pos, expression) {
797
797
  switch (code) {
798
798
  case 44 /* COMMA */:
799
799
  case 61 /* EQUAL */:
800
800
  case 124 /* PIPE */:
801
801
  case 40 /* OPEN_PAREN */:
802
802
  case 59 /* SEMICOLON */:
803
- case 60 /* OPEN_ANGLE_BRACKET */:
804
803
  return true;
804
+ case 60 /* OPEN_ANGLE_BRACKET */:
805
+ return !expression.inType;
805
806
  case 45 /* HYPHEN */:
806
807
  return data.charCodeAt(pos + 1) === 45 /* HYPHEN */;
807
808
  case 58 /* COLON */:
@@ -810,15 +811,16 @@ function shouldTerminateConciseTagVar(code, data, pos) {
810
811
  return false;
811
812
  }
812
813
  }
813
- function shouldTerminateHtmlTagVar(code, data, pos) {
814
+ function shouldTerminateHtmlTagVar(code, data, pos, expression) {
814
815
  switch (code) {
815
816
  case 124 /* PIPE */:
816
817
  case 44 /* COMMA */:
817
818
  case 61 /* EQUAL */:
818
819
  case 40 /* OPEN_PAREN */:
819
820
  case 62 /* CLOSE_ANGLE_BRACKET */:
820
- case 60 /* OPEN_ANGLE_BRACKET */:
821
821
  return true;
822
+ case 60 /* OPEN_ANGLE_BRACKET */:
823
+ return !expression.inType;
822
824
  case 58 /* COLON */:
823
825
  return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
824
826
  case 47 /* FORWARD_SLASH */:
@@ -1618,20 +1620,26 @@ var DTD = {
1618
1620
  // src/states/EXPRESSION.ts
1619
1621
  var shouldTerminate = () => false;
1620
1622
  var unaryKeywords = [
1623
+ "asserts",
1621
1624
  "async",
1622
1625
  "await",
1623
- "keyof",
1624
1626
  "class",
1625
1627
  "function",
1628
+ "infer",
1629
+ "is",
1630
+ "keyof",
1626
1631
  "new",
1632
+ "readonly",
1627
1633
  "typeof",
1634
+ "unique",
1628
1635
  "void"
1629
1636
  ];
1630
1637
  var binaryKeywords = [
1631
- "instanceof",
1632
- "in",
1633
1638
  "as",
1634
1639
  "extends",
1640
+ "instanceof",
1641
+ // Note: instanceof must be checked before `in`
1642
+ "in",
1635
1643
  "satisfies"
1636
1644
  ];
1637
1645
  var EXPRESSION = {
@@ -1646,6 +1654,9 @@ var EXPRESSION = {
1646
1654
  shouldTerminate,
1647
1655
  operators: false,
1648
1656
  wasComment: false,
1657
+ inType: false,
1658
+ forceType: false,
1659
+ ternaryDepth: 0,
1649
1660
  terminatedByEOL: false,
1650
1661
  terminatedByWhitespace: false,
1651
1662
  consumeIndentedContent: false
@@ -1661,7 +1672,7 @@ var EXPRESSION = {
1661
1672
  }
1662
1673
  return;
1663
1674
  }
1664
- if (expression.shouldTerminate(code, this.data, this.pos)) {
1675
+ if (expression.shouldTerminate(code, this.data, this.pos, expression)) {
1665
1676
  let wasExpression = false;
1666
1677
  if (expression.operators) {
1667
1678
  const prevNonWhitespacePos = lookBehindWhile(
@@ -1670,7 +1681,11 @@ var EXPRESSION = {
1670
1681
  this.pos - 1
1671
1682
  );
1672
1683
  if (prevNonWhitespacePos > expression.start) {
1673
- wasExpression = lookBehindForOperator(this.data, prevNonWhitespacePos) !== -1;
1684
+ wasExpression = lookBehindForOperator(
1685
+ expression,
1686
+ this.data,
1687
+ prevNonWhitespacePos
1688
+ ) !== -1;
1674
1689
  }
1675
1690
  }
1676
1691
  if (!wasExpression) {
@@ -1689,6 +1704,38 @@ var EXPRESSION = {
1689
1704
  case 96 /* BACKTICK */:
1690
1705
  this.enterState(states_exports.TEMPLATE_STRING);
1691
1706
  break;
1707
+ case 63 /* QUESTION */:
1708
+ if (expression.operators && !expression.groupStack.length) {
1709
+ expression.ternaryDepth++;
1710
+ this.pos++;
1711
+ this.forward = 0;
1712
+ this.consumeWhitespace();
1713
+ }
1714
+ break;
1715
+ case 58 /* COLON */:
1716
+ if (expression.operators && !expression.groupStack.length) {
1717
+ if (expression.ternaryDepth) {
1718
+ expression.ternaryDepth--;
1719
+ } else {
1720
+ expression.inType = true;
1721
+ }
1722
+ this.pos++;
1723
+ this.forward = 0;
1724
+ this.consumeWhitespace();
1725
+ }
1726
+ break;
1727
+ case 61 /* EQUAL */:
1728
+ if (expression.operators && !expression.groupStack.length) {
1729
+ if (this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
1730
+ this.pos++;
1731
+ } else if (!expression.forceType) {
1732
+ expression.inType = false;
1733
+ }
1734
+ this.pos++;
1735
+ this.forward = 0;
1736
+ this.consumeWhitespace();
1737
+ }
1738
+ break;
1692
1739
  case 47 /* FORWARD_SLASH */:
1693
1740
  switch (this.lookAtCharCodeAhead(1)) {
1694
1741
  case 47 /* FORWARD_SLASH */:
@@ -1720,9 +1767,19 @@ var EXPRESSION = {
1720
1767
  case 123 /* OPEN_CURLY_BRACE */:
1721
1768
  expression.groupStack.push(125 /* CLOSE_CURLY_BRACE */);
1722
1769
  break;
1770
+ case 60 /* OPEN_ANGLE_BRACKET */:
1771
+ if (expression.inType) {
1772
+ expression.groupStack.push(62 /* CLOSE_ANGLE_BRACKET */);
1773
+ } else if (expression.operators && !expression.groupStack.length) {
1774
+ this.pos++;
1775
+ this.forward = 0;
1776
+ this.consumeWhitespace();
1777
+ }
1778
+ break;
1723
1779
  case 41 /* CLOSE_PAREN */:
1724
1780
  case 93 /* CLOSE_SQUARE_BRACKET */:
1725
- case 125 /* CLOSE_CURLY_BRACE */: {
1781
+ case 125 /* CLOSE_CURLY_BRACE */:
1782
+ case (expression.inType && 62 /* CLOSE_ANGLE_BRACKET */): {
1726
1783
  if (!expression.groupStack.length) {
1727
1784
  return this.emitError(
1728
1785
  expression,
@@ -1799,7 +1856,7 @@ function checkForOperators(parser, expression, eol) {
1799
1856
  if (!expression.operators)
1800
1857
  return false;
1801
1858
  const { pos, data } = parser;
1802
- if (lookBehindForOperator(data, pos) !== -1) {
1859
+ if (lookBehindForOperator(expression, data, pos) !== -1) {
1803
1860
  parser.consumeWhitespace();
1804
1861
  parser.forward = 0;
1805
1862
  return true;
@@ -1814,9 +1871,10 @@ function checkForOperators(parser, expression, eol) {
1814
1871
  if (!expression.shouldTerminate(
1815
1872
  data.charCodeAt(nextNonSpace),
1816
1873
  data,
1817
- nextNonSpace
1874
+ nextNonSpace,
1875
+ expression
1818
1876
  )) {
1819
- const lookAheadPos = lookAheadForOperator(data, nextNonSpace);
1877
+ const lookAheadPos = lookAheadForOperator(expression, data, nextNonSpace);
1820
1878
  if (lookAheadPos !== -1) {
1821
1879
  parser.pos = lookAheadPos;
1822
1880
  parser.forward = 0;
@@ -1826,7 +1884,7 @@ function checkForOperators(parser, expression, eol) {
1826
1884
  }
1827
1885
  return false;
1828
1886
  }
1829
- function lookBehindForOperator(data, pos) {
1887
+ function lookBehindForOperator(expression, data, pos) {
1830
1888
  const curPos = pos - 1;
1831
1889
  const code = data.charCodeAt(curPos);
1832
1890
  switch (code) {
@@ -1837,12 +1895,13 @@ function lookBehindForOperator(data, pos) {
1837
1895
  case 61 /* EQUAL */:
1838
1896
  case 33 /* EXCLAMATION */:
1839
1897
  case 60 /* OPEN_ANGLE_BRACKET */:
1840
- case 62 /* CLOSE_ANGLE_BRACKET */:
1841
1898
  case 37 /* PERCENT */:
1842
1899
  case 124 /* PIPE */:
1843
1900
  case 63 /* QUESTION */:
1844
1901
  case 126 /* TILDE */:
1845
1902
  return curPos;
1903
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1904
+ return data.charCodeAt(curPos - 1) === 61 /* EQUAL */ ? curPos - 1 : expression.inType ? -1 : curPos;
1846
1905
  case 46 /* PERIOD */: {
1847
1906
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos);
1848
1907
  return isWordCode(data.charCodeAt(nextPos)) ? nextPos : -1;
@@ -1851,6 +1910,7 @@ function lookBehindForOperator(data, pos) {
1851
1910
  case 45 /* HYPHEN */: {
1852
1911
  if (data.charCodeAt(curPos - 1) === code) {
1853
1912
  return lookBehindForOperator(
1913
+ expression,
1854
1914
  data,
1855
1915
  lookBehindWhile(isWhitespaceCode, data, curPos - 2)
1856
1916
  );
@@ -1861,15 +1921,14 @@ function lookBehindForOperator(data, pos) {
1861
1921
  for (const keyword of unaryKeywords) {
1862
1922
  const keywordPos = lookBehindFor(data, curPos, keyword);
1863
1923
  if (keywordPos !== -1) {
1864
- const prevCode = data.charCodeAt(keywordPos - 1);
1865
- return prevCode === 46 /* PERIOD */ || isWordCode(prevCode) ? -1 : keywordPos;
1924
+ return isWordOrPeriodCode(data.charCodeAt(keywordPos - 1)) ? -1 : keywordPos;
1866
1925
  }
1867
1926
  }
1868
1927
  return -1;
1869
1928
  }
1870
1929
  }
1871
1930
  }
1872
- function lookAheadForOperator(data, pos) {
1931
+ function lookAheadForOperator(expression, data, pos) {
1873
1932
  switch (data.charCodeAt(pos)) {
1874
1933
  case 38 /* AMPERSAND */:
1875
1934
  case 42 /* ASTERISK */:
@@ -1878,17 +1937,17 @@ function lookAheadForOperator(data, pos) {
1878
1937
  case 60 /* OPEN_ANGLE_BRACKET */:
1879
1938
  case 37 /* PERCENT */:
1880
1939
  case 124 /* PIPE */:
1881
- case 63 /* QUESTION */:
1882
1940
  case 126 /* TILDE */:
1883
1941
  case 43 /* PLUS */:
1884
1942
  case 45 /* HYPHEN */:
1885
- case 58 /* COLON */:
1886
- case 62 /* CLOSE_ANGLE_BRACKET */:
1887
- case 61 /* EQUAL */:
1888
1943
  return pos + 1;
1889
1944
  case 47 /* FORWARD_SLASH */:
1890
1945
  case 123 /* OPEN_CURLY_BRACE */:
1891
1946
  case 40 /* OPEN_PAREN */:
1947
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1948
+ case 63 /* QUESTION */:
1949
+ case 58 /* COLON */:
1950
+ case 61 /* EQUAL */:
1892
1951
  return pos;
1893
1952
  case 46 /* PERIOD */: {
1894
1953
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos + 1);
@@ -1896,30 +1955,29 @@ function lookAheadForOperator(data, pos) {
1896
1955
  }
1897
1956
  default: {
1898
1957
  for (const keyword of binaryKeywords) {
1899
- let nextPos = lookAheadFor(data, pos, keyword);
1900
- if (nextPos === -1)
1958
+ const keywordPos = lookAheadFor(data, pos, keyword);
1959
+ if (keywordPos === -1)
1901
1960
  continue;
1902
- const max = data.length - 1;
1903
- if (nextPos === max)
1904
- return -1;
1905
- let nextCode = data.charCodeAt(nextPos + 1);
1906
- if (isWhitespaceCode(nextCode)) {
1907
- nextPos = lookAheadWhile(isWhitespaceCode, data, nextPos + 2);
1908
- if (nextPos === max)
1909
- return -1;
1910
- nextCode = data.charCodeAt(nextPos);
1911
- } else {
1912
- return -1;
1913
- }
1914
- switch (nextCode) {
1961
+ if (!isWhitespaceCode(data.charCodeAt(keywordPos + 1)))
1962
+ break;
1963
+ const nextPos = lookAheadWhile(isWhitespaceCode, data, keywordPos + 2);
1964
+ if (nextPos === data.length - 1)
1965
+ break;
1966
+ switch (data.charCodeAt(nextPos)) {
1915
1967
  case 58 /* COLON */:
1916
1968
  case 44 /* COMMA */:
1917
1969
  case 61 /* EQUAL */:
1918
1970
  case 47 /* FORWARD_SLASH */:
1919
1971
  case 62 /* CLOSE_ANGLE_BRACKET */:
1920
1972
  case 59 /* SEMICOLON */:
1921
- return -1;
1973
+ break;
1922
1974
  default:
1975
+ if (!expression.inType && (keyword === "as" || keyword === "satisfies")) {
1976
+ expression.inType = true;
1977
+ if (!(expression.ternaryDepth || expression.groupStack.length)) {
1978
+ expression.forceType = true;
1979
+ }
1980
+ }
1923
1981
  return nextPos;
1924
1982
  }
1925
1983
  }
@@ -1945,6 +2003,9 @@ function canFollowDivision(code) {
1945
2003
  return false;
1946
2004
  }
1947
2005
  }
2006
+ function isWordOrPeriodCode(code) {
2007
+ return code === 46 /* PERIOD */ || isWordCode(code);
2008
+ }
1948
2009
  function isWordCode(code) {
1949
2010
  return code >= 65 /* UPPER_A */ && code <= 90 /* UPPER_Z */ || code >= 97 /* LOWER_A */ && code <= 122 /* LOWER_Z */ || code >= 48 /* NUMBER_0 */ && code <= 57 /* NUMBER_9 */ || code == 36 /* DOLLAR */ || code === 95 /* UNDERSCORE */;
1950
2011
  }
@@ -2453,15 +2514,22 @@ var REGULAR_EXPRESSION = {
2453
2514
  exit() {
2454
2515
  },
2455
2516
  char(code, regExp) {
2456
- if (code === 92 /* BACK_SLASH */) {
2457
- this.pos++;
2458
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */ && regExp.isInCharSet) {
2459
- regExp.isInCharSet = true;
2460
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */ && regExp.isInCharSet) {
2461
- regExp.isInCharSet = false;
2462
- } else if (code === 47 /* FORWARD_SLASH */ && !regExp.isInCharSet) {
2463
- this.pos++;
2464
- this.exitState();
2517
+ switch (code) {
2518
+ case 92 /* BACK_SLASH */:
2519
+ this.pos++;
2520
+ break;
2521
+ case 91 /* OPEN_SQUARE_BRACKET */:
2522
+ regExp.isInCharSet = true;
2523
+ break;
2524
+ case 93 /* CLOSE_SQUARE_BRACKET */:
2525
+ regExp.isInCharSet = false;
2526
+ break;
2527
+ case 47 /* FORWARD_SLASH */:
2528
+ if (!regExp.isInCharSet) {
2529
+ this.pos++;
2530
+ this.exitState();
2531
+ }
2532
+ break;
2465
2533
  }
2466
2534
  },
2467
2535
  eol(_, regExp) {
@@ -2599,6 +2667,14 @@ var TAG_NAME = {
2599
2667
  expr.operators = true;
2600
2668
  expr.terminatedByEOL = true;
2601
2669
  expr.consumeIndentedContent = true;
2670
+ const typeStatementMatch = this.lookAheadFor("declare ") || this.lookAheadFor("interface ") || this.lookAheadFor("type ");
2671
+ if (typeStatementMatch) {
2672
+ expr.inType = true;
2673
+ expr.forceType = true;
2674
+ this.pos += typeStatementMatch.length;
2675
+ this.forward = 0;
2676
+ this.consumeWhitespace();
2677
+ }
2602
2678
  }
2603
2679
  }
2604
2680
  break;
package/dist/index.mjs CHANGED
@@ -768,15 +768,16 @@ var OPEN_TAG = {
768
768
  }
769
769
  }
770
770
  };
771
- function shouldTerminateConciseTagVar(code, data, pos) {
771
+ function shouldTerminateConciseTagVar(code, data, pos, expression) {
772
772
  switch (code) {
773
773
  case 44 /* COMMA */:
774
774
  case 61 /* EQUAL */:
775
775
  case 124 /* PIPE */:
776
776
  case 40 /* OPEN_PAREN */:
777
777
  case 59 /* SEMICOLON */:
778
- case 60 /* OPEN_ANGLE_BRACKET */:
779
778
  return true;
779
+ case 60 /* OPEN_ANGLE_BRACKET */:
780
+ return !expression.inType;
780
781
  case 45 /* HYPHEN */:
781
782
  return data.charCodeAt(pos + 1) === 45 /* HYPHEN */;
782
783
  case 58 /* COLON */:
@@ -785,15 +786,16 @@ function shouldTerminateConciseTagVar(code, data, pos) {
785
786
  return false;
786
787
  }
787
788
  }
788
- function shouldTerminateHtmlTagVar(code, data, pos) {
789
+ function shouldTerminateHtmlTagVar(code, data, pos, expression) {
789
790
  switch (code) {
790
791
  case 124 /* PIPE */:
791
792
  case 44 /* COMMA */:
792
793
  case 61 /* EQUAL */:
793
794
  case 40 /* OPEN_PAREN */:
794
795
  case 62 /* CLOSE_ANGLE_BRACKET */:
795
- case 60 /* OPEN_ANGLE_BRACKET */:
796
796
  return true;
797
+ case 60 /* OPEN_ANGLE_BRACKET */:
798
+ return !expression.inType;
797
799
  case 58 /* COLON */:
798
800
  return data.charCodeAt(pos + 1) === 61 /* EQUAL */;
799
801
  case 47 /* FORWARD_SLASH */:
@@ -1593,20 +1595,26 @@ var DTD = {
1593
1595
  // src/states/EXPRESSION.ts
1594
1596
  var shouldTerminate = () => false;
1595
1597
  var unaryKeywords = [
1598
+ "asserts",
1596
1599
  "async",
1597
1600
  "await",
1598
- "keyof",
1599
1601
  "class",
1600
1602
  "function",
1603
+ "infer",
1604
+ "is",
1605
+ "keyof",
1601
1606
  "new",
1607
+ "readonly",
1602
1608
  "typeof",
1609
+ "unique",
1603
1610
  "void"
1604
1611
  ];
1605
1612
  var binaryKeywords = [
1606
- "instanceof",
1607
- "in",
1608
1613
  "as",
1609
1614
  "extends",
1615
+ "instanceof",
1616
+ // Note: instanceof must be checked before `in`
1617
+ "in",
1610
1618
  "satisfies"
1611
1619
  ];
1612
1620
  var EXPRESSION = {
@@ -1621,6 +1629,9 @@ var EXPRESSION = {
1621
1629
  shouldTerminate,
1622
1630
  operators: false,
1623
1631
  wasComment: false,
1632
+ inType: false,
1633
+ forceType: false,
1634
+ ternaryDepth: 0,
1624
1635
  terminatedByEOL: false,
1625
1636
  terminatedByWhitespace: false,
1626
1637
  consumeIndentedContent: false
@@ -1636,7 +1647,7 @@ var EXPRESSION = {
1636
1647
  }
1637
1648
  return;
1638
1649
  }
1639
- if (expression.shouldTerminate(code, this.data, this.pos)) {
1650
+ if (expression.shouldTerminate(code, this.data, this.pos, expression)) {
1640
1651
  let wasExpression = false;
1641
1652
  if (expression.operators) {
1642
1653
  const prevNonWhitespacePos = lookBehindWhile(
@@ -1645,7 +1656,11 @@ var EXPRESSION = {
1645
1656
  this.pos - 1
1646
1657
  );
1647
1658
  if (prevNonWhitespacePos > expression.start) {
1648
- wasExpression = lookBehindForOperator(this.data, prevNonWhitespacePos) !== -1;
1659
+ wasExpression = lookBehindForOperator(
1660
+ expression,
1661
+ this.data,
1662
+ prevNonWhitespacePos
1663
+ ) !== -1;
1649
1664
  }
1650
1665
  }
1651
1666
  if (!wasExpression) {
@@ -1664,6 +1679,38 @@ var EXPRESSION = {
1664
1679
  case 96 /* BACKTICK */:
1665
1680
  this.enterState(states_exports.TEMPLATE_STRING);
1666
1681
  break;
1682
+ case 63 /* QUESTION */:
1683
+ if (expression.operators && !expression.groupStack.length) {
1684
+ expression.ternaryDepth++;
1685
+ this.pos++;
1686
+ this.forward = 0;
1687
+ this.consumeWhitespace();
1688
+ }
1689
+ break;
1690
+ case 58 /* COLON */:
1691
+ if (expression.operators && !expression.groupStack.length) {
1692
+ if (expression.ternaryDepth) {
1693
+ expression.ternaryDepth--;
1694
+ } else {
1695
+ expression.inType = true;
1696
+ }
1697
+ this.pos++;
1698
+ this.forward = 0;
1699
+ this.consumeWhitespace();
1700
+ }
1701
+ break;
1702
+ case 61 /* EQUAL */:
1703
+ if (expression.operators && !expression.groupStack.length) {
1704
+ if (this.lookAtCharCodeAhead(1) === 62 /* CLOSE_ANGLE_BRACKET */) {
1705
+ this.pos++;
1706
+ } else if (!expression.forceType) {
1707
+ expression.inType = false;
1708
+ }
1709
+ this.pos++;
1710
+ this.forward = 0;
1711
+ this.consumeWhitespace();
1712
+ }
1713
+ break;
1667
1714
  case 47 /* FORWARD_SLASH */:
1668
1715
  switch (this.lookAtCharCodeAhead(1)) {
1669
1716
  case 47 /* FORWARD_SLASH */:
@@ -1695,9 +1742,19 @@ var EXPRESSION = {
1695
1742
  case 123 /* OPEN_CURLY_BRACE */:
1696
1743
  expression.groupStack.push(125 /* CLOSE_CURLY_BRACE */);
1697
1744
  break;
1745
+ case 60 /* OPEN_ANGLE_BRACKET */:
1746
+ if (expression.inType) {
1747
+ expression.groupStack.push(62 /* CLOSE_ANGLE_BRACKET */);
1748
+ } else if (expression.operators && !expression.groupStack.length) {
1749
+ this.pos++;
1750
+ this.forward = 0;
1751
+ this.consumeWhitespace();
1752
+ }
1753
+ break;
1698
1754
  case 41 /* CLOSE_PAREN */:
1699
1755
  case 93 /* CLOSE_SQUARE_BRACKET */:
1700
- case 125 /* CLOSE_CURLY_BRACE */: {
1756
+ case 125 /* CLOSE_CURLY_BRACE */:
1757
+ case (expression.inType && 62 /* CLOSE_ANGLE_BRACKET */): {
1701
1758
  if (!expression.groupStack.length) {
1702
1759
  return this.emitError(
1703
1760
  expression,
@@ -1774,7 +1831,7 @@ function checkForOperators(parser, expression, eol) {
1774
1831
  if (!expression.operators)
1775
1832
  return false;
1776
1833
  const { pos, data } = parser;
1777
- if (lookBehindForOperator(data, pos) !== -1) {
1834
+ if (lookBehindForOperator(expression, data, pos) !== -1) {
1778
1835
  parser.consumeWhitespace();
1779
1836
  parser.forward = 0;
1780
1837
  return true;
@@ -1789,9 +1846,10 @@ function checkForOperators(parser, expression, eol) {
1789
1846
  if (!expression.shouldTerminate(
1790
1847
  data.charCodeAt(nextNonSpace),
1791
1848
  data,
1792
- nextNonSpace
1849
+ nextNonSpace,
1850
+ expression
1793
1851
  )) {
1794
- const lookAheadPos = lookAheadForOperator(data, nextNonSpace);
1852
+ const lookAheadPos = lookAheadForOperator(expression, data, nextNonSpace);
1795
1853
  if (lookAheadPos !== -1) {
1796
1854
  parser.pos = lookAheadPos;
1797
1855
  parser.forward = 0;
@@ -1801,7 +1859,7 @@ function checkForOperators(parser, expression, eol) {
1801
1859
  }
1802
1860
  return false;
1803
1861
  }
1804
- function lookBehindForOperator(data, pos) {
1862
+ function lookBehindForOperator(expression, data, pos) {
1805
1863
  const curPos = pos - 1;
1806
1864
  const code = data.charCodeAt(curPos);
1807
1865
  switch (code) {
@@ -1812,12 +1870,13 @@ function lookBehindForOperator(data, pos) {
1812
1870
  case 61 /* EQUAL */:
1813
1871
  case 33 /* EXCLAMATION */:
1814
1872
  case 60 /* OPEN_ANGLE_BRACKET */:
1815
- case 62 /* CLOSE_ANGLE_BRACKET */:
1816
1873
  case 37 /* PERCENT */:
1817
1874
  case 124 /* PIPE */:
1818
1875
  case 63 /* QUESTION */:
1819
1876
  case 126 /* TILDE */:
1820
1877
  return curPos;
1878
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1879
+ return data.charCodeAt(curPos - 1) === 61 /* EQUAL */ ? curPos - 1 : expression.inType ? -1 : curPos;
1821
1880
  case 46 /* PERIOD */: {
1822
1881
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos);
1823
1882
  return isWordCode(data.charCodeAt(nextPos)) ? nextPos : -1;
@@ -1826,6 +1885,7 @@ function lookBehindForOperator(data, pos) {
1826
1885
  case 45 /* HYPHEN */: {
1827
1886
  if (data.charCodeAt(curPos - 1) === code) {
1828
1887
  return lookBehindForOperator(
1888
+ expression,
1829
1889
  data,
1830
1890
  lookBehindWhile(isWhitespaceCode, data, curPos - 2)
1831
1891
  );
@@ -1836,15 +1896,14 @@ function lookBehindForOperator(data, pos) {
1836
1896
  for (const keyword of unaryKeywords) {
1837
1897
  const keywordPos = lookBehindFor(data, curPos, keyword);
1838
1898
  if (keywordPos !== -1) {
1839
- const prevCode = data.charCodeAt(keywordPos - 1);
1840
- return prevCode === 46 /* PERIOD */ || isWordCode(prevCode) ? -1 : keywordPos;
1899
+ return isWordOrPeriodCode(data.charCodeAt(keywordPos - 1)) ? -1 : keywordPos;
1841
1900
  }
1842
1901
  }
1843
1902
  return -1;
1844
1903
  }
1845
1904
  }
1846
1905
  }
1847
- function lookAheadForOperator(data, pos) {
1906
+ function lookAheadForOperator(expression, data, pos) {
1848
1907
  switch (data.charCodeAt(pos)) {
1849
1908
  case 38 /* AMPERSAND */:
1850
1909
  case 42 /* ASTERISK */:
@@ -1853,17 +1912,17 @@ function lookAheadForOperator(data, pos) {
1853
1912
  case 60 /* OPEN_ANGLE_BRACKET */:
1854
1913
  case 37 /* PERCENT */:
1855
1914
  case 124 /* PIPE */:
1856
- case 63 /* QUESTION */:
1857
1915
  case 126 /* TILDE */:
1858
1916
  case 43 /* PLUS */:
1859
1917
  case 45 /* HYPHEN */:
1860
- case 58 /* COLON */:
1861
- case 62 /* CLOSE_ANGLE_BRACKET */:
1862
- case 61 /* EQUAL */:
1863
1918
  return pos + 1;
1864
1919
  case 47 /* FORWARD_SLASH */:
1865
1920
  case 123 /* OPEN_CURLY_BRACE */:
1866
1921
  case 40 /* OPEN_PAREN */:
1922
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1923
+ case 63 /* QUESTION */:
1924
+ case 58 /* COLON */:
1925
+ case 61 /* EQUAL */:
1867
1926
  return pos;
1868
1927
  case 46 /* PERIOD */: {
1869
1928
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos + 1);
@@ -1871,30 +1930,29 @@ function lookAheadForOperator(data, pos) {
1871
1930
  }
1872
1931
  default: {
1873
1932
  for (const keyword of binaryKeywords) {
1874
- let nextPos = lookAheadFor(data, pos, keyword);
1875
- if (nextPos === -1)
1933
+ const keywordPos = lookAheadFor(data, pos, keyword);
1934
+ if (keywordPos === -1)
1876
1935
  continue;
1877
- const max = data.length - 1;
1878
- if (nextPos === max)
1879
- return -1;
1880
- let nextCode = data.charCodeAt(nextPos + 1);
1881
- if (isWhitespaceCode(nextCode)) {
1882
- nextPos = lookAheadWhile(isWhitespaceCode, data, nextPos + 2);
1883
- if (nextPos === max)
1884
- return -1;
1885
- nextCode = data.charCodeAt(nextPos);
1886
- } else {
1887
- return -1;
1888
- }
1889
- switch (nextCode) {
1936
+ if (!isWhitespaceCode(data.charCodeAt(keywordPos + 1)))
1937
+ break;
1938
+ const nextPos = lookAheadWhile(isWhitespaceCode, data, keywordPos + 2);
1939
+ if (nextPos === data.length - 1)
1940
+ break;
1941
+ switch (data.charCodeAt(nextPos)) {
1890
1942
  case 58 /* COLON */:
1891
1943
  case 44 /* COMMA */:
1892
1944
  case 61 /* EQUAL */:
1893
1945
  case 47 /* FORWARD_SLASH */:
1894
1946
  case 62 /* CLOSE_ANGLE_BRACKET */:
1895
1947
  case 59 /* SEMICOLON */:
1896
- return -1;
1948
+ break;
1897
1949
  default:
1950
+ if (!expression.inType && (keyword === "as" || keyword === "satisfies")) {
1951
+ expression.inType = true;
1952
+ if (!(expression.ternaryDepth || expression.groupStack.length)) {
1953
+ expression.forceType = true;
1954
+ }
1955
+ }
1898
1956
  return nextPos;
1899
1957
  }
1900
1958
  }
@@ -1920,6 +1978,9 @@ function canFollowDivision(code) {
1920
1978
  return false;
1921
1979
  }
1922
1980
  }
1981
+ function isWordOrPeriodCode(code) {
1982
+ return code === 46 /* PERIOD */ || isWordCode(code);
1983
+ }
1923
1984
  function isWordCode(code) {
1924
1985
  return code >= 65 /* UPPER_A */ && code <= 90 /* UPPER_Z */ || code >= 97 /* LOWER_A */ && code <= 122 /* LOWER_Z */ || code >= 48 /* NUMBER_0 */ && code <= 57 /* NUMBER_9 */ || code == 36 /* DOLLAR */ || code === 95 /* UNDERSCORE */;
1925
1986
  }
@@ -2428,15 +2489,22 @@ var REGULAR_EXPRESSION = {
2428
2489
  exit() {
2429
2490
  },
2430
2491
  char(code, regExp) {
2431
- if (code === 92 /* BACK_SLASH */) {
2432
- this.pos++;
2433
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */ && regExp.isInCharSet) {
2434
- regExp.isInCharSet = true;
2435
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */ && regExp.isInCharSet) {
2436
- regExp.isInCharSet = false;
2437
- } else if (code === 47 /* FORWARD_SLASH */ && !regExp.isInCharSet) {
2438
- this.pos++;
2439
- this.exitState();
2492
+ switch (code) {
2493
+ case 92 /* BACK_SLASH */:
2494
+ this.pos++;
2495
+ break;
2496
+ case 91 /* OPEN_SQUARE_BRACKET */:
2497
+ regExp.isInCharSet = true;
2498
+ break;
2499
+ case 93 /* CLOSE_SQUARE_BRACKET */:
2500
+ regExp.isInCharSet = false;
2501
+ break;
2502
+ case 47 /* FORWARD_SLASH */:
2503
+ if (!regExp.isInCharSet) {
2504
+ this.pos++;
2505
+ this.exitState();
2506
+ }
2507
+ break;
2440
2508
  }
2441
2509
  },
2442
2510
  eol(_, regExp) {
@@ -2574,6 +2642,14 @@ var TAG_NAME = {
2574
2642
  expr.operators = true;
2575
2643
  expr.terminatedByEOL = true;
2576
2644
  expr.consumeIndentedContent = true;
2645
+ const typeStatementMatch = this.lookAheadFor("declare ") || this.lookAheadFor("interface ") || this.lookAheadFor("type ");
2646
+ if (typeStatementMatch) {
2647
+ expr.inType = true;
2648
+ expr.forceType = true;
2649
+ this.pos += typeStatementMatch.length;
2650
+ this.forward = 0;
2651
+ this.consumeWhitespace();
2652
+ }
2577
2653
  }
2578
2654
  }
2579
2655
  break;
@@ -3,9 +3,12 @@ export interface ExpressionMeta extends Meta {
3
3
  groupStack: number[];
4
4
  operators: boolean;
5
5
  wasComment: boolean;
6
+ inType: boolean;
7
+ forceType: boolean;
8
+ ternaryDepth: number;
6
9
  terminatedByEOL: boolean;
7
10
  terminatedByWhitespace: boolean;
8
11
  consumeIndentedContent: boolean;
9
- shouldTerminate(code: number, data: string, pos: number): boolean;
12
+ shouldTerminate(code: number, data: string, pos: number, expression: ExpressionMeta): boolean;
10
13
  }
11
14
  export declare const EXPRESSION: StateDefinition<ExpressionMeta>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "htmljs-parser",
3
3
  "description": "An HTML parser recognizes content and string placeholders and allows JavaScript expressions as attribute values",
4
- "version": "5.6.2",
4
+ "version": "5.7.0",
5
5
  "devDependencies": {
6
6
  "@changesets/changelog-github": "^0.5.0",
7
7
  "@changesets/cli": "^2.27.1",
@@ -63,18 +63,16 @@
63
63
  "bench": "tsx bench.mts",
64
64
  "build": "tsc -b && tsx build.mts",
65
65
  "change": "changeset add",
66
- "ci:test": "nyc npm run mocha -- --forbid-only",
66
+ "ci:test": "nyc npm test -- --forbid-only",
67
67
  "format": "npm run lint:eslint -- --fix && npm run lint:prettier -- --write && (fixpack || true)",
68
68
  "lint": "tsc -b && npm run lint:eslint && npm run lint:prettier -- -l && fixpack",
69
69
  "lint:eslint": "eslint -f visualstudio .",
70
70
  "lint:prettier": "prettier \"./**/*{.ts,.js,.json,.md,.yml,rc}\"",
71
- "mocha": "cross-env NODE_ENV=test mocha \"./src/**/__tests__/*.test.ts\"",
72
71
  "prepare": "husky",
73
72
  "release": "npm run build && changeset publish",
74
73
  "report": "open ./coverage/lcov-report/index.html",
75
- "test": "npm run mocha -- --watch",
76
- "test:inspect": "npm test -- --inspect",
77
- "test:update": "npm run mocha -- --update",
74
+ "test": "cross-env NODE_ENV=test mocha \"./src/**/__tests__/*.test.ts\"",
75
+ "test:update": "npm test -- --update",
78
76
  "version": "changeset version && npm i --package-lock-only"
79
77
  },
80
78
  "types": "dist/index.d.ts"