htmljs-parser 5.6.1 → 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 */:
@@ -1195,7 +1197,6 @@ function handleDelimitedBlockEOL(parser, newLineLength, {
1195
1197
  parser.endText();
1196
1198
  parser.pos += endHtmlBlockLookahead.length;
1197
1199
  if (parser.consumeWhitespaceOnLine(0)) {
1198
- parser.endText();
1199
1200
  parser.exitState();
1200
1201
  parser.exitState();
1201
1202
  } else {
@@ -1212,7 +1213,7 @@ function handleDelimitedBlockEOL(parser, newLineLength, {
1212
1213
  parser.endText();
1213
1214
  parser.exitState();
1214
1215
  parser.exitState();
1215
- } else {
1216
+ } else if (parser.pos + newLineLength !== parser.maxPos) {
1216
1217
  parser.startText();
1217
1218
  }
1218
1219
  }
@@ -1619,20 +1620,26 @@ var DTD = {
1619
1620
  // src/states/EXPRESSION.ts
1620
1621
  var shouldTerminate = () => false;
1621
1622
  var unaryKeywords = [
1623
+ "asserts",
1622
1624
  "async",
1623
1625
  "await",
1624
- "keyof",
1625
1626
  "class",
1626
1627
  "function",
1628
+ "infer",
1629
+ "is",
1630
+ "keyof",
1627
1631
  "new",
1632
+ "readonly",
1628
1633
  "typeof",
1634
+ "unique",
1629
1635
  "void"
1630
1636
  ];
1631
1637
  var binaryKeywords = [
1632
- "instanceof",
1633
- "in",
1634
1638
  "as",
1635
1639
  "extends",
1640
+ "instanceof",
1641
+ // Note: instanceof must be checked before `in`
1642
+ "in",
1636
1643
  "satisfies"
1637
1644
  ];
1638
1645
  var EXPRESSION = {
@@ -1647,6 +1654,9 @@ var EXPRESSION = {
1647
1654
  shouldTerminate,
1648
1655
  operators: false,
1649
1656
  wasComment: false,
1657
+ inType: false,
1658
+ forceType: false,
1659
+ ternaryDepth: 0,
1650
1660
  terminatedByEOL: false,
1651
1661
  terminatedByWhitespace: false,
1652
1662
  consumeIndentedContent: false
@@ -1662,7 +1672,7 @@ var EXPRESSION = {
1662
1672
  }
1663
1673
  return;
1664
1674
  }
1665
- if (expression.shouldTerminate(code, this.data, this.pos)) {
1675
+ if (expression.shouldTerminate(code, this.data, this.pos, expression)) {
1666
1676
  let wasExpression = false;
1667
1677
  if (expression.operators) {
1668
1678
  const prevNonWhitespacePos = lookBehindWhile(
@@ -1671,7 +1681,11 @@ var EXPRESSION = {
1671
1681
  this.pos - 1
1672
1682
  );
1673
1683
  if (prevNonWhitespacePos > expression.start) {
1674
- wasExpression = lookBehindForOperator(this.data, prevNonWhitespacePos) !== -1;
1684
+ wasExpression = lookBehindForOperator(
1685
+ expression,
1686
+ this.data,
1687
+ prevNonWhitespacePos
1688
+ ) !== -1;
1675
1689
  }
1676
1690
  }
1677
1691
  if (!wasExpression) {
@@ -1690,6 +1704,38 @@ var EXPRESSION = {
1690
1704
  case 96 /* BACKTICK */:
1691
1705
  this.enterState(states_exports.TEMPLATE_STRING);
1692
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;
1693
1739
  case 47 /* FORWARD_SLASH */:
1694
1740
  switch (this.lookAtCharCodeAhead(1)) {
1695
1741
  case 47 /* FORWARD_SLASH */:
@@ -1721,9 +1767,19 @@ var EXPRESSION = {
1721
1767
  case 123 /* OPEN_CURLY_BRACE */:
1722
1768
  expression.groupStack.push(125 /* CLOSE_CURLY_BRACE */);
1723
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;
1724
1779
  case 41 /* CLOSE_PAREN */:
1725
1780
  case 93 /* CLOSE_SQUARE_BRACKET */:
1726
- case 125 /* CLOSE_CURLY_BRACE */: {
1781
+ case 125 /* CLOSE_CURLY_BRACE */:
1782
+ case (expression.inType && 62 /* CLOSE_ANGLE_BRACKET */): {
1727
1783
  if (!expression.groupStack.length) {
1728
1784
  return this.emitError(
1729
1785
  expression,
@@ -1800,7 +1856,7 @@ function checkForOperators(parser, expression, eol) {
1800
1856
  if (!expression.operators)
1801
1857
  return false;
1802
1858
  const { pos, data } = parser;
1803
- if (lookBehindForOperator(data, pos) !== -1) {
1859
+ if (lookBehindForOperator(expression, data, pos) !== -1) {
1804
1860
  parser.consumeWhitespace();
1805
1861
  parser.forward = 0;
1806
1862
  return true;
@@ -1815,9 +1871,10 @@ function checkForOperators(parser, expression, eol) {
1815
1871
  if (!expression.shouldTerminate(
1816
1872
  data.charCodeAt(nextNonSpace),
1817
1873
  data,
1818
- nextNonSpace
1874
+ nextNonSpace,
1875
+ expression
1819
1876
  )) {
1820
- const lookAheadPos = lookAheadForOperator(data, nextNonSpace);
1877
+ const lookAheadPos = lookAheadForOperator(expression, data, nextNonSpace);
1821
1878
  if (lookAheadPos !== -1) {
1822
1879
  parser.pos = lookAheadPos;
1823
1880
  parser.forward = 0;
@@ -1827,7 +1884,7 @@ function checkForOperators(parser, expression, eol) {
1827
1884
  }
1828
1885
  return false;
1829
1886
  }
1830
- function lookBehindForOperator(data, pos) {
1887
+ function lookBehindForOperator(expression, data, pos) {
1831
1888
  const curPos = pos - 1;
1832
1889
  const code = data.charCodeAt(curPos);
1833
1890
  switch (code) {
@@ -1838,12 +1895,13 @@ function lookBehindForOperator(data, pos) {
1838
1895
  case 61 /* EQUAL */:
1839
1896
  case 33 /* EXCLAMATION */:
1840
1897
  case 60 /* OPEN_ANGLE_BRACKET */:
1841
- case 62 /* CLOSE_ANGLE_BRACKET */:
1842
1898
  case 37 /* PERCENT */:
1843
1899
  case 124 /* PIPE */:
1844
1900
  case 63 /* QUESTION */:
1845
1901
  case 126 /* TILDE */:
1846
1902
  return curPos;
1903
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1904
+ return data.charCodeAt(curPos - 1) === 61 /* EQUAL */ ? curPos - 1 : expression.inType ? -1 : curPos;
1847
1905
  case 46 /* PERIOD */: {
1848
1906
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos);
1849
1907
  return isWordCode(data.charCodeAt(nextPos)) ? nextPos : -1;
@@ -1852,6 +1910,7 @@ function lookBehindForOperator(data, pos) {
1852
1910
  case 45 /* HYPHEN */: {
1853
1911
  if (data.charCodeAt(curPos - 1) === code) {
1854
1912
  return lookBehindForOperator(
1913
+ expression,
1855
1914
  data,
1856
1915
  lookBehindWhile(isWhitespaceCode, data, curPos - 2)
1857
1916
  );
@@ -1862,15 +1921,14 @@ function lookBehindForOperator(data, pos) {
1862
1921
  for (const keyword of unaryKeywords) {
1863
1922
  const keywordPos = lookBehindFor(data, curPos, keyword);
1864
1923
  if (keywordPos !== -1) {
1865
- const prevCode = data.charCodeAt(keywordPos - 1);
1866
- return prevCode === 46 /* PERIOD */ || isWordCode(prevCode) ? -1 : keywordPos;
1924
+ return isWordOrPeriodCode(data.charCodeAt(keywordPos - 1)) ? -1 : keywordPos;
1867
1925
  }
1868
1926
  }
1869
1927
  return -1;
1870
1928
  }
1871
1929
  }
1872
1930
  }
1873
- function lookAheadForOperator(data, pos) {
1931
+ function lookAheadForOperator(expression, data, pos) {
1874
1932
  switch (data.charCodeAt(pos)) {
1875
1933
  case 38 /* AMPERSAND */:
1876
1934
  case 42 /* ASTERISK */:
@@ -1879,17 +1937,17 @@ function lookAheadForOperator(data, pos) {
1879
1937
  case 60 /* OPEN_ANGLE_BRACKET */:
1880
1938
  case 37 /* PERCENT */:
1881
1939
  case 124 /* PIPE */:
1882
- case 63 /* QUESTION */:
1883
1940
  case 126 /* TILDE */:
1884
1941
  case 43 /* PLUS */:
1885
1942
  case 45 /* HYPHEN */:
1886
- case 58 /* COLON */:
1887
- case 62 /* CLOSE_ANGLE_BRACKET */:
1888
- case 61 /* EQUAL */:
1889
1943
  return pos + 1;
1890
1944
  case 47 /* FORWARD_SLASH */:
1891
1945
  case 123 /* OPEN_CURLY_BRACE */:
1892
1946
  case 40 /* OPEN_PAREN */:
1947
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1948
+ case 63 /* QUESTION */:
1949
+ case 58 /* COLON */:
1950
+ case 61 /* EQUAL */:
1893
1951
  return pos;
1894
1952
  case 46 /* PERIOD */: {
1895
1953
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos + 1);
@@ -1897,30 +1955,29 @@ function lookAheadForOperator(data, pos) {
1897
1955
  }
1898
1956
  default: {
1899
1957
  for (const keyword of binaryKeywords) {
1900
- let nextPos = lookAheadFor(data, pos, keyword);
1901
- if (nextPos === -1)
1958
+ const keywordPos = lookAheadFor(data, pos, keyword);
1959
+ if (keywordPos === -1)
1902
1960
  continue;
1903
- const max = data.length - 1;
1904
- if (nextPos === max)
1905
- return -1;
1906
- let nextCode = data.charCodeAt(nextPos + 1);
1907
- if (isWhitespaceCode(nextCode)) {
1908
- nextPos = lookAheadWhile(isWhitespaceCode, data, nextPos + 2);
1909
- if (nextPos === max)
1910
- return -1;
1911
- nextCode = data.charCodeAt(nextPos);
1912
- } else {
1913
- return -1;
1914
- }
1915
- 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)) {
1916
1967
  case 58 /* COLON */:
1917
1968
  case 44 /* COMMA */:
1918
1969
  case 61 /* EQUAL */:
1919
1970
  case 47 /* FORWARD_SLASH */:
1920
1971
  case 62 /* CLOSE_ANGLE_BRACKET */:
1921
1972
  case 59 /* SEMICOLON */:
1922
- return -1;
1973
+ break;
1923
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
+ }
1924
1981
  return nextPos;
1925
1982
  }
1926
1983
  }
@@ -1946,6 +2003,9 @@ function canFollowDivision(code) {
1946
2003
  return false;
1947
2004
  }
1948
2005
  }
2006
+ function isWordOrPeriodCode(code) {
2007
+ return code === 46 /* PERIOD */ || isWordCode(code);
2008
+ }
1949
2009
  function isWordCode(code) {
1950
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 */;
1951
2011
  }
@@ -2454,15 +2514,22 @@ var REGULAR_EXPRESSION = {
2454
2514
  exit() {
2455
2515
  },
2456
2516
  char(code, regExp) {
2457
- if (code === 92 /* BACK_SLASH */) {
2458
- this.pos++;
2459
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */ && regExp.isInCharSet) {
2460
- regExp.isInCharSet = true;
2461
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */ && regExp.isInCharSet) {
2462
- regExp.isInCharSet = false;
2463
- } else if (code === 47 /* FORWARD_SLASH */ && !regExp.isInCharSet) {
2464
- this.pos++;
2465
- 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;
2466
2533
  }
2467
2534
  },
2468
2535
  eol(_, regExp) {
@@ -2600,6 +2667,14 @@ var TAG_NAME = {
2600
2667
  expr.operators = true;
2601
2668
  expr.terminatedByEOL = true;
2602
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
+ }
2603
2678
  }
2604
2679
  }
2605
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 */:
@@ -1170,7 +1172,6 @@ function handleDelimitedBlockEOL(parser, newLineLength, {
1170
1172
  parser.endText();
1171
1173
  parser.pos += endHtmlBlockLookahead.length;
1172
1174
  if (parser.consumeWhitespaceOnLine(0)) {
1173
- parser.endText();
1174
1175
  parser.exitState();
1175
1176
  parser.exitState();
1176
1177
  } else {
@@ -1187,7 +1188,7 @@ function handleDelimitedBlockEOL(parser, newLineLength, {
1187
1188
  parser.endText();
1188
1189
  parser.exitState();
1189
1190
  parser.exitState();
1190
- } else {
1191
+ } else if (parser.pos + newLineLength !== parser.maxPos) {
1191
1192
  parser.startText();
1192
1193
  }
1193
1194
  }
@@ -1594,20 +1595,26 @@ var DTD = {
1594
1595
  // src/states/EXPRESSION.ts
1595
1596
  var shouldTerminate = () => false;
1596
1597
  var unaryKeywords = [
1598
+ "asserts",
1597
1599
  "async",
1598
1600
  "await",
1599
- "keyof",
1600
1601
  "class",
1601
1602
  "function",
1603
+ "infer",
1604
+ "is",
1605
+ "keyof",
1602
1606
  "new",
1607
+ "readonly",
1603
1608
  "typeof",
1609
+ "unique",
1604
1610
  "void"
1605
1611
  ];
1606
1612
  var binaryKeywords = [
1607
- "instanceof",
1608
- "in",
1609
1613
  "as",
1610
1614
  "extends",
1615
+ "instanceof",
1616
+ // Note: instanceof must be checked before `in`
1617
+ "in",
1611
1618
  "satisfies"
1612
1619
  ];
1613
1620
  var EXPRESSION = {
@@ -1622,6 +1629,9 @@ var EXPRESSION = {
1622
1629
  shouldTerminate,
1623
1630
  operators: false,
1624
1631
  wasComment: false,
1632
+ inType: false,
1633
+ forceType: false,
1634
+ ternaryDepth: 0,
1625
1635
  terminatedByEOL: false,
1626
1636
  terminatedByWhitespace: false,
1627
1637
  consumeIndentedContent: false
@@ -1637,7 +1647,7 @@ var EXPRESSION = {
1637
1647
  }
1638
1648
  return;
1639
1649
  }
1640
- if (expression.shouldTerminate(code, this.data, this.pos)) {
1650
+ if (expression.shouldTerminate(code, this.data, this.pos, expression)) {
1641
1651
  let wasExpression = false;
1642
1652
  if (expression.operators) {
1643
1653
  const prevNonWhitespacePos = lookBehindWhile(
@@ -1646,7 +1656,11 @@ var EXPRESSION = {
1646
1656
  this.pos - 1
1647
1657
  );
1648
1658
  if (prevNonWhitespacePos > expression.start) {
1649
- wasExpression = lookBehindForOperator(this.data, prevNonWhitespacePos) !== -1;
1659
+ wasExpression = lookBehindForOperator(
1660
+ expression,
1661
+ this.data,
1662
+ prevNonWhitespacePos
1663
+ ) !== -1;
1650
1664
  }
1651
1665
  }
1652
1666
  if (!wasExpression) {
@@ -1665,6 +1679,38 @@ var EXPRESSION = {
1665
1679
  case 96 /* BACKTICK */:
1666
1680
  this.enterState(states_exports.TEMPLATE_STRING);
1667
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;
1668
1714
  case 47 /* FORWARD_SLASH */:
1669
1715
  switch (this.lookAtCharCodeAhead(1)) {
1670
1716
  case 47 /* FORWARD_SLASH */:
@@ -1696,9 +1742,19 @@ var EXPRESSION = {
1696
1742
  case 123 /* OPEN_CURLY_BRACE */:
1697
1743
  expression.groupStack.push(125 /* CLOSE_CURLY_BRACE */);
1698
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;
1699
1754
  case 41 /* CLOSE_PAREN */:
1700
1755
  case 93 /* CLOSE_SQUARE_BRACKET */:
1701
- case 125 /* CLOSE_CURLY_BRACE */: {
1756
+ case 125 /* CLOSE_CURLY_BRACE */:
1757
+ case (expression.inType && 62 /* CLOSE_ANGLE_BRACKET */): {
1702
1758
  if (!expression.groupStack.length) {
1703
1759
  return this.emitError(
1704
1760
  expression,
@@ -1775,7 +1831,7 @@ function checkForOperators(parser, expression, eol) {
1775
1831
  if (!expression.operators)
1776
1832
  return false;
1777
1833
  const { pos, data } = parser;
1778
- if (lookBehindForOperator(data, pos) !== -1) {
1834
+ if (lookBehindForOperator(expression, data, pos) !== -1) {
1779
1835
  parser.consumeWhitespace();
1780
1836
  parser.forward = 0;
1781
1837
  return true;
@@ -1790,9 +1846,10 @@ function checkForOperators(parser, expression, eol) {
1790
1846
  if (!expression.shouldTerminate(
1791
1847
  data.charCodeAt(nextNonSpace),
1792
1848
  data,
1793
- nextNonSpace
1849
+ nextNonSpace,
1850
+ expression
1794
1851
  )) {
1795
- const lookAheadPos = lookAheadForOperator(data, nextNonSpace);
1852
+ const lookAheadPos = lookAheadForOperator(expression, data, nextNonSpace);
1796
1853
  if (lookAheadPos !== -1) {
1797
1854
  parser.pos = lookAheadPos;
1798
1855
  parser.forward = 0;
@@ -1802,7 +1859,7 @@ function checkForOperators(parser, expression, eol) {
1802
1859
  }
1803
1860
  return false;
1804
1861
  }
1805
- function lookBehindForOperator(data, pos) {
1862
+ function lookBehindForOperator(expression, data, pos) {
1806
1863
  const curPos = pos - 1;
1807
1864
  const code = data.charCodeAt(curPos);
1808
1865
  switch (code) {
@@ -1813,12 +1870,13 @@ function lookBehindForOperator(data, pos) {
1813
1870
  case 61 /* EQUAL */:
1814
1871
  case 33 /* EXCLAMATION */:
1815
1872
  case 60 /* OPEN_ANGLE_BRACKET */:
1816
- case 62 /* CLOSE_ANGLE_BRACKET */:
1817
1873
  case 37 /* PERCENT */:
1818
1874
  case 124 /* PIPE */:
1819
1875
  case 63 /* QUESTION */:
1820
1876
  case 126 /* TILDE */:
1821
1877
  return curPos;
1878
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1879
+ return data.charCodeAt(curPos - 1) === 61 /* EQUAL */ ? curPos - 1 : expression.inType ? -1 : curPos;
1822
1880
  case 46 /* PERIOD */: {
1823
1881
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos);
1824
1882
  return isWordCode(data.charCodeAt(nextPos)) ? nextPos : -1;
@@ -1827,6 +1885,7 @@ function lookBehindForOperator(data, pos) {
1827
1885
  case 45 /* HYPHEN */: {
1828
1886
  if (data.charCodeAt(curPos - 1) === code) {
1829
1887
  return lookBehindForOperator(
1888
+ expression,
1830
1889
  data,
1831
1890
  lookBehindWhile(isWhitespaceCode, data, curPos - 2)
1832
1891
  );
@@ -1837,15 +1896,14 @@ function lookBehindForOperator(data, pos) {
1837
1896
  for (const keyword of unaryKeywords) {
1838
1897
  const keywordPos = lookBehindFor(data, curPos, keyword);
1839
1898
  if (keywordPos !== -1) {
1840
- const prevCode = data.charCodeAt(keywordPos - 1);
1841
- return prevCode === 46 /* PERIOD */ || isWordCode(prevCode) ? -1 : keywordPos;
1899
+ return isWordOrPeriodCode(data.charCodeAt(keywordPos - 1)) ? -1 : keywordPos;
1842
1900
  }
1843
1901
  }
1844
1902
  return -1;
1845
1903
  }
1846
1904
  }
1847
1905
  }
1848
- function lookAheadForOperator(data, pos) {
1906
+ function lookAheadForOperator(expression, data, pos) {
1849
1907
  switch (data.charCodeAt(pos)) {
1850
1908
  case 38 /* AMPERSAND */:
1851
1909
  case 42 /* ASTERISK */:
@@ -1854,17 +1912,17 @@ function lookAheadForOperator(data, pos) {
1854
1912
  case 60 /* OPEN_ANGLE_BRACKET */:
1855
1913
  case 37 /* PERCENT */:
1856
1914
  case 124 /* PIPE */:
1857
- case 63 /* QUESTION */:
1858
1915
  case 126 /* TILDE */:
1859
1916
  case 43 /* PLUS */:
1860
1917
  case 45 /* HYPHEN */:
1861
- case 58 /* COLON */:
1862
- case 62 /* CLOSE_ANGLE_BRACKET */:
1863
- case 61 /* EQUAL */:
1864
1918
  return pos + 1;
1865
1919
  case 47 /* FORWARD_SLASH */:
1866
1920
  case 123 /* OPEN_CURLY_BRACE */:
1867
1921
  case 40 /* OPEN_PAREN */:
1922
+ case 62 /* CLOSE_ANGLE_BRACKET */:
1923
+ case 63 /* QUESTION */:
1924
+ case 58 /* COLON */:
1925
+ case 61 /* EQUAL */:
1868
1926
  return pos;
1869
1927
  case 46 /* PERIOD */: {
1870
1928
  const nextPos = lookAheadWhile(isWhitespaceCode, data, pos + 1);
@@ -1872,30 +1930,29 @@ function lookAheadForOperator(data, pos) {
1872
1930
  }
1873
1931
  default: {
1874
1932
  for (const keyword of binaryKeywords) {
1875
- let nextPos = lookAheadFor(data, pos, keyword);
1876
- if (nextPos === -1)
1933
+ const keywordPos = lookAheadFor(data, pos, keyword);
1934
+ if (keywordPos === -1)
1877
1935
  continue;
1878
- const max = data.length - 1;
1879
- if (nextPos === max)
1880
- return -1;
1881
- let nextCode = data.charCodeAt(nextPos + 1);
1882
- if (isWhitespaceCode(nextCode)) {
1883
- nextPos = lookAheadWhile(isWhitespaceCode, data, nextPos + 2);
1884
- if (nextPos === max)
1885
- return -1;
1886
- nextCode = data.charCodeAt(nextPos);
1887
- } else {
1888
- return -1;
1889
- }
1890
- 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)) {
1891
1942
  case 58 /* COLON */:
1892
1943
  case 44 /* COMMA */:
1893
1944
  case 61 /* EQUAL */:
1894
1945
  case 47 /* FORWARD_SLASH */:
1895
1946
  case 62 /* CLOSE_ANGLE_BRACKET */:
1896
1947
  case 59 /* SEMICOLON */:
1897
- return -1;
1948
+ break;
1898
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
+ }
1899
1956
  return nextPos;
1900
1957
  }
1901
1958
  }
@@ -1921,6 +1978,9 @@ function canFollowDivision(code) {
1921
1978
  return false;
1922
1979
  }
1923
1980
  }
1981
+ function isWordOrPeriodCode(code) {
1982
+ return code === 46 /* PERIOD */ || isWordCode(code);
1983
+ }
1924
1984
  function isWordCode(code) {
1925
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 */;
1926
1986
  }
@@ -2429,15 +2489,22 @@ var REGULAR_EXPRESSION = {
2429
2489
  exit() {
2430
2490
  },
2431
2491
  char(code, regExp) {
2432
- if (code === 92 /* BACK_SLASH */) {
2433
- this.pos++;
2434
- } else if (code === 91 /* OPEN_SQUARE_BRACKET */ && regExp.isInCharSet) {
2435
- regExp.isInCharSet = true;
2436
- } else if (code === 93 /* CLOSE_SQUARE_BRACKET */ && regExp.isInCharSet) {
2437
- regExp.isInCharSet = false;
2438
- } else if (code === 47 /* FORWARD_SLASH */ && !regExp.isInCharSet) {
2439
- this.pos++;
2440
- 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;
2441
2508
  }
2442
2509
  },
2443
2510
  eol(_, regExp) {
@@ -2575,6 +2642,14 @@ var TAG_NAME = {
2575
2642
  expr.operators = true;
2576
2643
  expr.terminatedByEOL = true;
2577
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
+ }
2578
2653
  }
2579
2654
  }
2580
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.1",
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"