chore(lint): keep the fallow audit gate green

Extract rootClassStyledSelectors so the subcomposition_root_styled_by_class
rule drops below the complexity threshold, and ignore the music-to-video
reference HTML (template + motion-primitive materials forked by path, not
import-graph reachable) — same treatment as motion-graphics/grounding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Miao Yang
2026-06-23 22:15:20 +08:00
co-authored by Claude Opus 4.8
parent 119284d377
commit 4a8e2f1cd0
2 changed files with 18 additions and 8 deletions
+3
View File
@@ -59,6 +59,9 @@
// prose), not import-graph reachable. // prose), not import-graph reachable.
"skills/motion-graphics/grounding/**", "skills/motion-graphics/grounding/**",
"skills/motion-graphics/categories/**", "skills/motion-graphics/categories/**",
// Agent-invoked reference materials (template + motion-primitive HTML, catalogs),
// forked by path by the frame-worker per SKILL.md prose, not import-graph reachable.
"skills/music-to-video/references/**",
// Bundled @font-face data (read at runtime via fs.readFileSync, invisible // Bundled @font-face data (read at runtime via fs.readFileSync, invisible
// to the import graph) + its manual rebuild tool. // to the import graph) + its manual rebuild tool.
"skills/**/fonts/**", "skills/**/fonts/**",
+15 -8
View File
@@ -1,4 +1,4 @@
import type { LintContext, HyperframeLintFinding } from "../context"; import type { LintContext, HyperframeLintFinding, ExtractedBlock } from "../context";
import { findHtmlTag, readAttr, readJsonAttr, stripJsComments, truncateSnippet } from "../utils"; import { findHtmlTag, readAttr, readJsonAttr, stripJsComments, truncateSnippet } from "../utils";
import { COMPOSITION_VARIABLE_TYPES } from "../../core.types"; import { COMPOSITION_VARIABLE_TYPES } from "../../core.types";
@@ -63,6 +63,19 @@ function leftmostCompoundClasses(selector: string): string[] {
return (leftmost.match(/\.([\w-]+)/g) ?? []).map((c) => c.slice(1)); return (leftmost.match(/\.([\w-]+)/g) ?? []).map((c) => c.slice(1));
} }
// Distinct selectors across all <style> blocks whose leftmost compound keys off one
// of the root element's own classes — the ones that break under id-scoping.
function rootClassStyledSelectors(styles: ExtractedBlock[], rootClasses: string[]): string[] {
const offenders: string[] = [];
for (const style of styles) {
for (const selector of extractCssSelectors(style.content)) {
const hitsRoot = leftmostCompoundClasses(selector).some((c) => rootClasses.includes(c));
if (hitsRoot && !offenders.includes(selector)) offenders.push(selector);
}
}
return offenders;
}
export const compositionRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [ export const compositionRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [
// invalid_capture_path — catches ../capture/ in src/href attributes and scripts. // invalid_capture_path — catches ../capture/ in src/href attributes and scripts.
// Sub-compositions live in compositions/ but are served relative to the project // Sub-compositions live in compositions/ but are served relative to the project
@@ -624,13 +637,7 @@ export const compositionRules: Array<(ctx: LintContext) => HyperframeLintFinding
const rootClasses = (readAttr(rootTag.raw, "class") || "").split(/\s+/).filter(Boolean); const rootClasses = (readAttr(rootTag.raw, "class") || "").split(/\s+/).filter(Boolean);
if (rootClasses.length === 0) return []; if (rootClasses.length === 0) return [];
const offenders: string[] = []; const offenders = rootClassStyledSelectors(styles, rootClasses);
for (const style of styles) {
for (const selector of extractCssSelectors(style.content)) {
const hitsRoot = leftmostCompoundClasses(selector).some((c) => rootClasses.includes(c));
if (hitsRoot && !offenders.includes(selector)) offenders.push(selector);
}
}
if (offenders.length === 0) return []; if (offenders.length === 0) return [];
const example = offenders.slice(0, 3).join(", "); const example = offenders.slice(0, 3).join(", ");