Fix detector URL scans and advisory handling (#709)

* Fix detector URL and advisory handling

Recover joined URL arguments without splitting local paths, derive advisory behavior from registry severity across consumers, inspect readable linked CSS in URL scans, and report only the dominant primary font.

AI assistance disclosure: Implemented and verified with Codex under maintainer direction.

* Filter linked CSS to rendered selectors

Flatten linked stylesheet grouping rules and collect only selector rules that target the live DOM, preventing unused grouped and selector-less patterns from leaking into URL findings.

AI assistance disclosure: Implemented and verified with Codex under maintainer direction.

* Fix detector review edge cases

AI assistance disclosure: Codex implemented and verified these fixes under maintainer direction.

* Preserve unresolved linked CSS selectors

AI assistance disclosure: Codex implemented and verified this fix under maintainer direction.

* Fix linked CSS selector filtering

Resolve pseudo-element selectors to live hosts, reject unresolvable linked CSS findings, and make the regression assertions independent. Also ignore comment delimiters when recovering CSS rule selectors.

AI assistance disclosure: This commit was prepared with Codex under maintainer direction.

* Skip unresolved container query CSS

Exclude linked container-query groups when their current applicability cannot be resolved, with a browser regression proving inactive styles do not leak.

AI assistance disclosure: This commit was prepared with Codex under maintainer direction.

* Detect active container query CSS

Use a temporary custom-property probe so the browser decides whether a nested style rule actually applies in the current container layout.

AI assistance disclosure: Codex helped implement and test this fix under maintainer direction.

* Filter inactive linked CSS states

Keep valid empty pseudo-class matches authoritative and omit selector-less linked at-rules that cannot be tied to rendered nodes.

AI assistance disclosure: Codex helped implement and test this fix under maintainer direction.

* Parse pseudo-elements without rewriting literals

Preserve quoted attribute values and escaped identifiers while resolving real pseudo-elements to live hosts.

AI assistance disclosure: Codex helped implement and test this fix under maintainer direction.

* Restore live linked keyframes

AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction.

* Handle grouped linked keyframes

AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction.

* Respect keyframe definition order

AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction.

* Resolve effective linked keyframes

AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction.

* Fix keyframe easing detection

Serialize effective per-keyframe easing back into the linked stylesheet corpus so overshoot motion is detected. Add a browser regression with a neutral animation name.\n\nAI assistance disclosure: Codex helped implement and test this fix under maintainer direction.
This commit is contained in:
Paul Bakaus
2026-09-02 15:45:34 -04:00
committed by GitHub
parent 54f0e641c6
commit fa44839f72
16 changed files with 1302 additions and 72 deletions
+14 -8
View File
@@ -688,7 +688,10 @@ function enclosingCssSelector(cssText, index) {
// `{` belongs to some other selector.
const closeBeforeIndex = cssText.lastIndexOf('}', index);
if (closeBeforeIndex > open) return null;
const prevClose = Math.max(cssText.lastIndexOf('}', open - 1), cssText.lastIndexOf(';', open - 1));
// Ignore delimiters inside comments when locating the previous declaration.
// Keeping comment length intact preserves indices into the original source.
const beforeOpen = cssText.slice(0, open).replace(/\/\*[\s\S]*?\*\//g, comment => ' '.repeat(comment.length));
const prevClose = Math.max(beforeOpen.lastIndexOf('}'), beforeOpen.lastIndexOf(';'));
const raw = cssText.slice(prevClose + 1, open).replace(/\/\*[\s\S]*?\*\//g, '').trim().replace(/\s+/g, ' ');
if (!raw || raw.startsWith('@') || /^\d/.test(raw) || /[{}<]/.test(raw)) return null;
// Keyframe steps: percentage steps fail the digit test above, but `from`
@@ -4020,14 +4023,17 @@ function checkTypography() {
}
if (totalTextElements >= 20) {
// A font is "primary" if it's used by at least 15% of text elements
const PRIMARY_THRESHOLD = 0.15;
for (const [font, count] of fontUsage) {
// Report the actual primary face: the uniquely most-used family. The old
// 15% threshold labeled secondary faces as primary (e.g. an 82/18 split).
const ranked = [...fontUsage.entries()].sort((a, b) => b[1] - a[1]);
const [primary] = ranked;
const tied = ranked[1]?.[1] === primary?.[1];
if (primary && !tied) {
const [font, count] = primary;
const share = count / totalTextElements;
if (share < PRIMARY_THRESHOLD) continue;
if (!OVERUSED_FONTS.has(font)) continue;
if (isBrandFontOnOwnDomain(font)) continue;
findings.push({ type: 'overused-font', detail: `Primary font: ${font} (${Math.round(share * 100)}% of text)` });
if (OVERUSED_FONTS.has(font) && !isBrandFontOnOwnDomain(font)) {
findings.push({ type: 'overused-font', detail: `Primary font: ${font} (${Math.round(share * 100)}% of text)` });
}
}
}