@hyperframes/lint 0.8.142 → 0.8.143

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/index.js CHANGED
@@ -108,10 +108,7 @@ function hasUnquotedLessThan(attrs) {
108
108
  return false;
109
109
  }
110
110
  function readAttr(tagSource, attr) {
111
- if (!tagSource) return null;
112
- const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
113
- const match = tagSource.match(new RegExp(`(?<![\\w-])${escaped}\\s*=\\s*["']([^"']+)["']`, "i"));
114
- return match?.[1] || null;
111
+ return readAttributeValue(tagSource, attr, false) || null;
115
112
  }
116
113
  function hasAttrName(tagSource, attr) {
117
114
  return readDecodedAttr(tagSource, attr) !== null;
@@ -134,15 +131,18 @@ function mediaWindowsOverlap(a, b) {
134
131
  return a.start < b.end && b.start < a.end;
135
132
  }
136
133
  function readDecodedAttr(tagSource, attr) {
134
+ return readAttributeValue(tagSource, attr, true);
135
+ }
136
+ function readAttributeValue(tagSource, attr, decodeEntities) {
137
137
  if (!tagSource) return null;
138
138
  let value = null;
139
139
  const parser = new Parser(
140
140
  {
141
- onattribute(name, decodedValue) {
142
- if (value === null && name.toLowerCase() === attr.toLowerCase()) value = decodedValue;
141
+ onattribute(name, attributeValue) {
142
+ if (value === null && name.toLowerCase() === attr.toLowerCase()) value = attributeValue;
143
143
  }
144
144
  },
145
- { decodeEntities: true, lowerCaseAttributeNames: false, lowerCaseTags: true }
145
+ { decodeEntities, lowerCaseAttributeNames: false, lowerCaseTags: true }
146
146
  );
147
147
  parser.end(tagSource);
148
148
  return value;
@@ -748,6 +748,12 @@ import {
748
748
  HTML_BODY_CSS_HEIGHT_FIRST_RE,
749
749
  VIEWPORT_META_SIZE_RE
750
750
  } from "@hyperframes/parsers/composition";
751
+ var SCRIPT_SYNTAX_EXEMPT_TYPES = /* @__PURE__ */ new Set([
752
+ "application/json",
753
+ "application/hyperframes-slideshow+json",
754
+ "importmap",
755
+ "module"
756
+ ]);
751
757
  function repeatedDescendantId(selector) {
752
758
  let repeated = null;
753
759
  const requiredPseudoIds = (pseudo) => {
@@ -1366,10 +1372,8 @@ var coreRules = [
1366
1372
  ({ scripts, locate }) => {
1367
1373
  const findings = [];
1368
1374
  for (const script of scripts) {
1369
- const attrs = script.attrs || "";
1370
- if (/\bsrc\s*=/.test(attrs) || /\btype\s*=\s*["'](?:application\/json|application\/hyperframes-slideshow\+json|importmap|module)["']/.test(
1371
- attrs
1372
- ))
1375
+ const type = readDecodedAttr(script.raw, "type")?.trim().toLowerCase() ?? "";
1376
+ if (readDecodedAttr(script.raw, "src") !== null || SCRIPT_SYNTAX_EXEMPT_TYPES.has(type))
1373
1377
  continue;
1374
1378
  const syntaxError = getInlineScriptSyntaxError(script.content);
1375
1379
  if (!syntaxError) continue;
@@ -1786,6 +1790,7 @@ function findImperativeMediaControlFindings(ctx) {
1786
1790
  };
1787
1791
  if (mediaTags.length === 0 || ctx.scripts.length === 0) return findings;
1788
1792
  for (const script of ctx.scripts) {
1793
+ const code = stripJsCode(script.content);
1789
1794
  const mediaVars = /* @__PURE__ */ new Map();
1790
1795
  const assignmentPatterns = [
1791
1796
  {
@@ -1802,6 +1807,7 @@ function findImperativeMediaControlFindings(ctx) {
1802
1807
  for (const { pattern, variableIndex, targetIndex } of assignmentPatterns) {
1803
1808
  let match;
1804
1809
  while ((match = pattern.exec(script.content)) !== null) {
1810
+ if (code[match.index] !== script.content[match.index]) continue;
1805
1811
  const variableName = match[variableIndex];
1806
1812
  const target = match[targetIndex];
1807
1813
  if (!variableName || !target) continue;
@@ -1812,12 +1818,12 @@ function findImperativeMediaControlFindings(ctx) {
1812
1818
  }
1813
1819
  const directIdPatterns = [
1814
1820
  {
1815
- pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.play\s*\(/g,
1821
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\s*(?:\?\.|\.)\s*play\s*(?:\?\.\s*)?\(/g,
1816
1822
  kind: "play()",
1817
1823
  targetIndex: 1
1818
1824
  },
1819
1825
  {
1820
- pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.pause\s*\(/g,
1826
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\s*(?:\?\.|\.)\s*pause\s*(?:\?\.\s*)?\(/g,
1821
1827
  kind: "pause()",
1822
1828
  targetIndex: 1
1823
1829
  },
@@ -1832,12 +1838,12 @@ function findImperativeMediaControlFindings(ctx) {
1832
1838
  targetIndex: 1
1833
1839
  },
1834
1840
  {
1835
- pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\.play\s*\(/g,
1841
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\s*(?:\?\.|\.)\s*play\s*(?:\?\.\s*)?\(/g,
1836
1842
  kind: "play()",
1837
1843
  targetIndex: 2
1838
1844
  },
1839
1845
  {
1840
- pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\.pause\s*\(/g,
1846
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\s*(?:\?\.|\.)\s*pause\s*(?:\?\.\s*)?\(/g,
1841
1847
  kind: "pause()",
1842
1848
  targetIndex: 2
1843
1849
  },
@@ -1855,6 +1861,7 @@ function findImperativeMediaControlFindings(ctx) {
1855
1861
  for (const { pattern, kind, targetIndex } of directIdPatterns) {
1856
1862
  let match;
1857
1863
  while ((match = pattern.exec(script.content)) !== null) {
1864
+ if (code[match.index] !== script.content[match.index]) continue;
1858
1865
  const target = match[targetIndex];
1859
1866
  if (!target) continue;
1860
1867
  const elementId = mediaIndex.ids.has(target) ? target : selectorTargetsManagedMedia(target, mediaIndex) ? void 0 : null;
@@ -1872,8 +1879,20 @@ function findImperativeMediaControlFindings(ctx) {
1872
1879
  for (const [variableName, elementId] of mediaVars) {
1873
1880
  const escapedVar = escapeRegExp(variableName);
1874
1881
  const variablePatterns = [
1875
- { pattern: new RegExp(`\\b${escapedVar}\\.play\\s*\\(`, "g"), kind: "play()" },
1876
- { pattern: new RegExp(`\\b${escapedVar}\\.pause\\s*\\(`, "g"), kind: "pause()" },
1882
+ {
1883
+ pattern: new RegExp(
1884
+ `\\b${escapedVar}\\s*(?:\\?\\.|\\.)\\s*play\\s*(?:\\?\\.\\s*)?\\(`,
1885
+ "g"
1886
+ ),
1887
+ kind: "play()"
1888
+ },
1889
+ {
1890
+ pattern: new RegExp(
1891
+ `\\b${escapedVar}\\s*(?:\\?\\.|\\.)\\s*pause\\s*(?:\\?\\.\\s*)?\\(`,
1892
+ "g"
1893
+ ),
1894
+ kind: "pause()"
1895
+ },
1877
1896
  { pattern: new RegExp(`\\b${escapedVar}\\.currentTime\\s*=`, "g"), kind: "currentTime" },
1878
1897
  {
1879
1898
  pattern: new RegExp(`\\b${escapedVar}\\.muted\\s*=`, "g"),
@@ -1883,6 +1902,7 @@ function findImperativeMediaControlFindings(ctx) {
1883
1902
  for (const { pattern, kind } of variablePatterns) {
1884
1903
  let match;
1885
1904
  while ((match = pattern.exec(script.content)) !== null) {
1905
+ if (code[match.index] !== script.content[match.index]) continue;
1886
1906
  findings.push({
1887
1907
  code: "imperative_media_control",
1888
1908
  severity: "error",