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.
This commit is contained in:
Miguel Ángel
2026-07-02 17:45:05 -07:00
committed by GitHub
parent b7eb0dfb5a
commit d2f1adc2af
3 changed files with 43 additions and 1 deletions
@@ -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 = `<html><body>
<div data-composition-id="main" data-start="0" data-width="1920" data-height="1080"></div>
<script>
var spec = { id: "main" };
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
window.__timelines[spec.id] = tl;
</script>
</body></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 = `<html><body>
<div data-composition-id="main" data-start="0" data-width="1920" data-height="1080">
+20
View File
@@ -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 = `
<html><body>
<div data-composition-id="root" data-width="1920" data-height="1080">
<div id="box">Hello</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
<script>
var spec = { id: "root" };
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
tl.to("#box", { opacity: 0.5, duration: 2 });
window.__timelines[spec.id] = tl;
</script>
</body></html>`;
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 = `
<template>