From d2f1adc2affea69e33550d60945a237e92602eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Thu, 2 Jul 2026 17:45:05 -0700 Subject: [PATCH] fix(lint): recognize computed-key window.__timelines registrations (#1874) WINDOW_TIMELINE_ASSIGN_PATTERN only matched window.__timelines["literal"] or window.__timelines.prop, so registrations via a computed key like window.__timelines[spec.id] (used by the code-particle-assemble and code-3d-extrude registry blocks) went undetected. That made gsap_timeline_not_registered false-fire on correctly registered timelines, and let root_composition_missing_duration_source wrongly demand an explicit data-duration on compositions that already have one. --- packages/lint/src/rules/composition.test.ts | 14 ++++++++++++++ packages/lint/src/rules/gsap.test.ts | 20 ++++++++++++++++++++ packages/lint/src/utils.ts | 10 +++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/lint/src/rules/composition.test.ts b/packages/lint/src/rules/composition.test.ts index fcf7457d6..5ac2ad48d 100644 --- a/packages/lint/src/rules/composition.test.ts +++ b/packages/lint/src/rules/composition.test.ts @@ -1159,6 +1159,20 @@ describe("composition rules", () => { expect(find(result.findings)).toBeUndefined(); }); + it("does not error when a GSAP timeline is registered with a computed bracket key", async () => { + const html = ` +
+ + `; + const result = await lintHyperframeHtml(html); + expect(find(result.findings)).toBeUndefined(); + }); + it("does not error for a finite CSS animation (runtime auto-infers duration)", async () => { const html = `
diff --git a/packages/lint/src/rules/gsap.test.ts b/packages/lint/src/rules/gsap.test.ts index d60992b2d..51f90ff22 100644 --- a/packages/lint/src/rules/gsap.test.ts +++ b/packages/lint/src/rules/gsap.test.ts @@ -1296,6 +1296,26 @@ describe("GSAP rules", () => { expect(finding).toBeUndefined(); }); + it("does NOT warn when timeline is registered with a computed bracket key", async () => { + const html = ` + +
+
Hello
+
+ + +`; + const result = await lintHyperframeHtml(html); + const finding = result.findings.find((f) => f.code === "gsap_timeline_not_registered"); + expect(finding).toBeUndefined(); + }); + it("does NOT warn for sub-compositions (template-based)", async () => { const html = `