diff --git a/packages/cli/src/utils/compositionCensus.test.ts b/packages/cli/src/utils/compositionCensus.test.ts index ec9ee5224..0996ad938 100644 --- a/packages/cli/src/utils/compositionCensus.test.ts +++ b/packages/cli/src/utils/compositionCensus.test.ts @@ -112,6 +112,60 @@ describe("buildCompositionCensus", () => { expect(c.timelineShape.nested).toBe(true); expect(c.timelineShape.subCompositionCount).toBe(2); }); + + describe("value-scoped structural probes", () => { + it("positionFixed is false for inline position:absolute (name-vs-value scope)", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.positionFixed).toBe(false); + }); + + it("positionFixed is true for inline position:fixed", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.positionFixed).toBe(true); + }); + + it("overflowHidden catches inline overflow:hidden (symmetric with style-tag path)", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.overflowHidden).toBe(true); + }); + + it("overflowHidden is false for inline overflow:visible", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.overflowHidden).toBe(false); + }); + + it("backgroundImage catches the inline shorthand `background: url(...)`", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.backgroundImage).toBe(true); + }); + + it("maskImage catches the inline shorthand `mask: url(...)`", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.maskImage).toBe(true); + }); + + it("does not count `inherit` / `revert` as authored intent", () => { + const html = `
`; + const c = buildCompositionCensus(html); + expect(c.structuralAttributes.positionFixed).toBe(false); + expect(c.structuralAttributes.filter).toBe(false); + }); + }); + + it("short-circuits on HTML over the size cap without throwing", () => { + const huge = "a".repeat(21 * 1024 * 1024); + const c = buildCompositionCensus(huge); + // Guard-rail returns a zero census — no OOM, no crash. + expect(c.elementCensus.video).toBe(0); + expect(c.timelineShape.subCompositionCount).toBe(0); + expect(c.structuralAttributes.positionFixed).toBe(false); + }); }); describe("renderCompositionCensusBlock", () => { diff --git a/packages/cli/src/utils/compositionCensus.ts b/packages/cli/src/utils/compositionCensus.ts index fdefd048f..fc8bb8d71 100644 --- a/packages/cli/src/utils/compositionCensus.ts +++ b/packages/cli/src/utils/compositionCensus.ts @@ -48,7 +48,12 @@ export interface CompositionCensus { nested: boolean; /** Count of sub-composition mounts (`data-composition-src` count). */ subCompositionCount: number; - /** Any GSAP timeline usage (script tags referencing gsap or data-gsap-*). */ + /** + * Any GSAP timeline usage detected via `