@hyperframes/lint 0.8.141 → 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/browser.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;
@@ -745,6 +745,12 @@ import {
745
745
  HTML_BODY_CSS_HEIGHT_FIRST_RE,
746
746
  VIEWPORT_META_SIZE_RE
747
747
  } from "@hyperframes/parsers/composition";
748
+ var SCRIPT_SYNTAX_EXEMPT_TYPES = /* @__PURE__ */ new Set([
749
+ "application/json",
750
+ "application/hyperframes-slideshow+json",
751
+ "importmap",
752
+ "module"
753
+ ]);
748
754
  function repeatedDescendantId(selector) {
749
755
  let repeated = null;
750
756
  const requiredPseudoIds = (pseudo) => {
@@ -1363,10 +1369,8 @@ var coreRules = [
1363
1369
  ({ scripts, locate }) => {
1364
1370
  const findings = [];
1365
1371
  for (const script of scripts) {
1366
- const attrs = script.attrs || "";
1367
- if (/\bsrc\s*=/.test(attrs) || /\btype\s*=\s*["'](?:application\/json|application\/hyperframes-slideshow\+json|importmap|module)["']/.test(
1368
- attrs
1369
- ))
1372
+ const type = readDecodedAttr(script.raw, "type")?.trim().toLowerCase() ?? "";
1373
+ if (readDecodedAttr(script.raw, "src") !== null || SCRIPT_SYNTAX_EXEMPT_TYPES.has(type))
1370
1374
  continue;
1371
1375
  const syntaxError = getInlineScriptSyntaxError(script.content);
1372
1376
  if (!syntaxError) continue;
@@ -1783,6 +1787,7 @@ function findImperativeMediaControlFindings(ctx) {
1783
1787
  };
1784
1788
  if (mediaTags.length === 0 || ctx.scripts.length === 0) return findings;
1785
1789
  for (const script of ctx.scripts) {
1790
+ const code = stripJsCode(script.content);
1786
1791
  const mediaVars = /* @__PURE__ */ new Map();
1787
1792
  const assignmentPatterns = [
1788
1793
  {
@@ -1799,6 +1804,7 @@ function findImperativeMediaControlFindings(ctx) {
1799
1804
  for (const { pattern, variableIndex, targetIndex } of assignmentPatterns) {
1800
1805
  let match;
1801
1806
  while ((match = pattern.exec(script.content)) !== null) {
1807
+ if (code[match.index] !== script.content[match.index]) continue;
1802
1808
  const variableName = match[variableIndex];
1803
1809
  const target = match[targetIndex];
1804
1810
  if (!variableName || !target) continue;
@@ -1809,12 +1815,12 @@ function findImperativeMediaControlFindings(ctx) {
1809
1815
  }
1810
1816
  const directIdPatterns = [
1811
1817
  {
1812
- pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.play\s*\(/g,
1818
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\s*(?:\?\.|\.)\s*play\s*(?:\?\.\s*)?\(/g,
1813
1819
  kind: "play()",
1814
1820
  targetIndex: 1
1815
1821
  },
1816
1822
  {
1817
- pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.pause\s*\(/g,
1823
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\s*(?:\?\.|\.)\s*pause\s*(?:\?\.\s*)?\(/g,
1818
1824
  kind: "pause()",
1819
1825
  targetIndex: 1
1820
1826
  },
@@ -1829,12 +1835,12 @@ function findImperativeMediaControlFindings(ctx) {
1829
1835
  targetIndex: 1
1830
1836
  },
1831
1837
  {
1832
- pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\.play\s*\(/g,
1838
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\s*(?:\?\.|\.)\s*play\s*(?:\?\.\s*)?\(/g,
1833
1839
  kind: "play()",
1834
1840
  targetIndex: 2
1835
1841
  },
1836
1842
  {
1837
- pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\.pause\s*\(/g,
1843
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*(["'])([\s\S]*?)\1\s*\)\s*(?:\?\.|\.)\s*pause\s*(?:\?\.\s*)?\(/g,
1838
1844
  kind: "pause()",
1839
1845
  targetIndex: 2
1840
1846
  },
@@ -1852,6 +1858,7 @@ function findImperativeMediaControlFindings(ctx) {
1852
1858
  for (const { pattern, kind, targetIndex } of directIdPatterns) {
1853
1859
  let match;
1854
1860
  while ((match = pattern.exec(script.content)) !== null) {
1861
+ if (code[match.index] !== script.content[match.index]) continue;
1855
1862
  const target = match[targetIndex];
1856
1863
  if (!target) continue;
1857
1864
  const elementId = mediaIndex.ids.has(target) ? target : selectorTargetsManagedMedia(target, mediaIndex) ? void 0 : null;
@@ -1869,8 +1876,20 @@ function findImperativeMediaControlFindings(ctx) {
1869
1876
  for (const [variableName, elementId] of mediaVars) {
1870
1877
  const escapedVar = escapeRegExp(variableName);
1871
1878
  const variablePatterns = [
1872
- { pattern: new RegExp(`\\b${escapedVar}\\.play\\s*\\(`, "g"), kind: "play()" },
1873
- { pattern: new RegExp(`\\b${escapedVar}\\.pause\\s*\\(`, "g"), kind: "pause()" },
1879
+ {
1880
+ pattern: new RegExp(
1881
+ `\\b${escapedVar}\\s*(?:\\?\\.|\\.)\\s*play\\s*(?:\\?\\.\\s*)?\\(`,
1882
+ "g"
1883
+ ),
1884
+ kind: "play()"
1885
+ },
1886
+ {
1887
+ pattern: new RegExp(
1888
+ `\\b${escapedVar}\\s*(?:\\?\\.|\\.)\\s*pause\\s*(?:\\?\\.\\s*)?\\(`,
1889
+ "g"
1890
+ ),
1891
+ kind: "pause()"
1892
+ },
1874
1893
  { pattern: new RegExp(`\\b${escapedVar}\\.currentTime\\s*=`, "g"), kind: "currentTime" },
1875
1894
  {
1876
1895
  pattern: new RegExp(`\\b${escapedVar}\\.muted\\s*=`, "g"),
@@ -1880,6 +1899,7 @@ function findImperativeMediaControlFindings(ctx) {
1880
1899
  for (const { pattern, kind } of variablePatterns) {
1881
1900
  let match;
1882
1901
  while ((match = pattern.exec(script.content)) !== null) {
1902
+ if (code[match.index] !== script.content[match.index]) continue;
1883
1903
  findings.push({
1884
1904
  code: "imperative_media_control",
1885
1905
  severity: "error",