fix(lint): stop gsap_repeated_fromto_without_baseline flagging a load-time gsap.set() baseline - #3895
Open
miga-heygen wants to merge 1 commit into
Open
fix(lint): stop gsap_repeated_fromto_without_baseline flagging a load-time gsap.set() baseline#3895miga-heygen wants to merge 1 commit into
miga-heygen wants to merge 1 commit into
Conversation
…-time gsap.set() baseline
Its own fixHint recommended two fixes: `immediateRender: false`, or an
earlier in-timeline `tl.set(sel, {...}, 0)` baseline. That second option
collides with gsap_timeline_set_initial_hide, which independently warns on
exactly that shape whenever the values hide the element — the common
hide-until-reveal case both rules exist for. Following one rule's advice
trips the other.
gsap_timeline_set_initial_hide already treats a load-time `gsap.set(...)`
as a reliable baseline (it exempts `global` sets outright), but
gsap_repeated_fromto_without_baseline's own baseline check rejected any
`global` set unconditionally. Aligns the two: a preceding load-time
`gsap.set(...)` now satisfies the baseline check too, gated on a new
reliability scan (factored out of the existing hidden-selector scan) that
excludes a set deferred behind a callback or event handler, since the GSAP
parser flags any bare `gsap.set(...)` as load-time regardless of where it
sits in the AST. The fixHint now recommends the load-time route first and
cross-references the other rule.
Co-Authored-By: Miguel Ángel <miguel.sierra@heygen.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two GSAP lint rules gave contradictory fix guidance for the common "hide the element until it's revealed" pattern:
gsap_repeated_fromto_without_baselinewarns when ≥2tl.fromTo()calls target the same element with no stable resting-state baseline established beforehand (GSAP applies afromTo's "from" values at authoring time, so without a baseline, whicheverfromTowas authored last silently becomes the resting state for any seek before the timeline actually starts). Its fixHint offered two options:immediateRender: falseon each futurefromTo, or an earlier in-timelinetl.set(sel, {...}, 0).gsap_timeline_set_initial_hideindependently warns on exactly that second shape — an in-timelinetl.set(...)at position 0 whose values hide the element (a zero-duration set at the exact position-0 playhead doesn't render on frame 0 in this engine, so the element pops hidden a frame later).Following the first rule's own advice trips the second rule, since a "safe resting state" for a hide-until-reveal animation is, almost by definition, a hidden state.
Fix
gsap_timeline_set_initial_hidealready treats a load-timegsap.set(...)(as opposed to an in-timelinetl.set(...)) as a reliable baseline — it exempts it from firing at all.gsap_repeated_fromto_without_baseline's own baseline check didn't recognize the same thing, rejecting any load-time set unconditionally. This aligns the two:packages/lint/src/rules/gsap.ts:gsap_repeated_fromto_without_baseline's baseline check now also accepts a preceding load-timegsap.set(...)call as valid — gated on a new reliability scan (extractStandaloneSetSelectors, factored out of the pre-existingextractStandaloneHiddenSelectors) that excludes agsap.set(...)deferred behind a callback or event handler. That distinction is needed because the GSAP parser flags any baregsap.set(...)as load-time regardless of where it sits in the AST — a set inside a click handler only runs on user interaction, not at load, so it can't stand in for a resting state before the first tween.fixHintnow recommends the load-timegsap.set(...)route ahead of the in-timelinetl.set(...,0)route, and notes the latter can trip the other rule.Known, accepted limitation (documented in a code comment at the check site): the reliability scan reports selectors, not specific occurrences, across the whole composition's scripts. A composition with two
gsap.set(...)calls for the same selector — one deferred+earlier-in-source, one genuinely load-time+later — could false-accept the deferred one as a baseline. This requires an unusual duplicate-declaration shape and is a warning-severity, advice-quality rule (not a build-blocking correctness check), so it's left as a documented boundary rather than a blocker.Test plan
packages/lint/src/rules/gsap.test.ts: updated the one existing test that encoded the old (now-corrected) behavior, and added new tests: a load-timegsap.set(...)baseline is now accepted; a load-timegsap.set(...)baseline satisfies both rules simultaneously (the actual contradiction, now resolved); agsap.set(...)deferred behind a callback is still correctly rejected as a baseline. Full suite: 194/194 passing.gsap.ts(kept the tests), reran — the two new/changed tests failed exactly as expected against the old behavior; restored the fix, reran — all 194 pass again.bunx tsc --noEmit -p packages/lintclean.bunx oxlint/bunx oxfmt --checkclean on both changed files.extractStandaloneHiddenSelectorsinto a sharedextractStandaloneSetSelectorsbase doesn't change its existing behavior (same regex, same match-group handling, only the value filter moved to a parameter) — full pre-existing suite still green.