diff --git a/src/lib/filter-entries.test.ts b/src/lib/filter-entries.test.ts
index 78ffafc..8de45af 100644
--- a/src/lib/filter-entries.test.ts
+++ b/src/lib/filter-entries.test.ts
@@ -1,5 +1,6 @@
import { test, expect } from '@playwright/test'
import { filter_coverage } from './filter-entries.js'
+import { Coverage } from './parse-coverage.js'
test('filters out JS files', () => {
let entries = [
@@ -8,7 +9,7 @@ test('filters out JS files', () => {
text: 'console.log("Hello world")',
ranges: [{ start: 0, end: 25 }],
},
- ]
+ ] satisfies Coverage[]
expect(filter_coverage(entries)).toEqual([])
})
@@ -19,7 +20,7 @@ test('keeps files with CSS extension', () => {
text: 'a{color:red}',
ranges: [{ start: 0, end: 13 }],
},
- ]
+ ] satisfies Coverage[]
expect(filter_coverage(entries)).toEqual(entries)
})
@@ -37,7 +38,7 @@ test('keeps extension-less URL with HTML text', () => {
text: 'a{color:red;}',
ranges: [{ start: 0, end: 13 }], // ranges are remapped
},
- ]
+ ] satisfies Coverage[]
expect(filter_coverage(entries)).toEqual(expected)
})
@@ -48,6 +49,17 @@ test('keeps extension-less URL with CSS text (running coverage in vite dev mode)
text: 'a{color:red;}',
ranges: [{ start: 0, end: 13 }],
},
- ]
+ ] satisfies Coverage[]
expect(filter_coverage(entries)).toEqual(entries)
})
+
+test('filters out extension-less JS', () => {
+ let entries = [
+ {
+ url: 'http://example.com',
+ text: 'var a = 10; console.log(a);',
+ ranges: [{ start: 0, end: 29 }],
+ },
+ ] satisfies Coverage[]
+ expect(filter_coverage(entries)).toEqual([])
+})
diff --git a/src/lib/filter-entries.ts b/src/lib/filter-entries.ts
index ca9ea82..2b3d63c 100644
--- a/src/lib/filter-entries.ts
+++ b/src/lib/filter-entries.ts
@@ -6,6 +6,26 @@ function is_html(text: string): boolean {
return /<\/?(html|body|head|div|span|script|style)/i.test(text)
}
+// Matches: element selectors, class/id selectors, attribute selectors, @rules
+const SELECTOR_REGEX = /(@[a-z-]+|\[[^\]]+\]|[a-zA-Z_#.-][a-zA-Z0-9_-]*)\s*\{/
+// Check for CSS properties (property: value pattern)
+const DECLARATION_REGEX = /^\s*[a-zA-Z-]+\s*:\s*.+;?\s*$/m
+
+function is_css_like(text: string): boolean {
+ return SELECTOR_REGEX.test(text) || DECLARATION_REGEX.test(text)
+}
+
+function is_js_like(text: string): boolean {
+ try {
+ // Only parses the input, does not execute it.
+ // NEVER EXECUTE THIS UNTRUSTED CODE!!!
+ new Function(text)
+ return true
+ } catch {
+ return false
+ }
+}
+
export function filter_coverage(coverage: Coverage[]): Coverage[] {
let result = []
@@ -29,13 +49,13 @@ export function filter_coverage(coverage: Coverage[]): Coverage[] {
continue
}
- // At this point it can only be CSS
- // TODO: that's not true, check if it's css-like of js-like
- result.push({
- url: entry.url,
- text: entry.text,
- ranges: entry.ranges,
- })
+ if (is_css_like(entry.text) && !is_js_like(entry.text)) {
+ result.push({
+ url: entry.url,
+ text: entry.text,
+ ranges: entry.ranges,
+ })
+ }
}
return result
diff --git a/src/lib/html-parser.test.ts b/src/lib/html-parser.test.ts
index bd04d9b..297b773 100644
--- a/src/lib/html-parser.test.ts
+++ b/src/lib/html-parser.test.ts
@@ -36,10 +36,16 @@ test('finds style tags with attributes', () => {
expect(parse('')).toEqual([{ textContent: '.css{}' }])
})
-test('ignores style tags without end tag', () => {
- expect(parse('