mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
fix(lint): catch fromTo from-object layout/reflow props in gsap_non_transform_motion
The rule sourced a tween's animated props from anim.properties only — the acorn
parser's to-vars. A fromTo() exposes its first ("from") vars object separately as
anim.fromProperties, so a layout or reflow prop animated only in the from-object
(e.g. tl.fromTo("#t", { left: 100, letterSpacing: "0.3em" }, { opacity: 1 }))
escaped the rule entirely and shipped stuttering. fromTo is the most common tween
form, so this was a real recall hole.
Union fromProperties into the checked property set; add the field to the lint
parse type. Registry re-scan unchanged (0 comps animate a layout prop only in a
from-object today), so no collateral.
Known remaining gaps (documented, not fixed): standalone gsap.fromTo only scans
its first vars object via regex (and aborts on nested braces); roundProps:true
(boolean form) is dropped by the parser. Both are rare and the clean fix is
disproportionate to the rule's planned sunset when drawElement render lands.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
6e21072f44
commit
189d8582f4
@@ -1499,6 +1499,22 @@ describe("GSAP rules", () => {
|
||||
expect(finding).toBeDefined();
|
||||
});
|
||||
|
||||
it("gsap_non_transform_motion: fires on a layout/reflow prop that appears only in a fromTo's from-object", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div data-composition-id="c1" data-width="1920" data-height="1080"><div id="t"></div></div>
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
tl.fromTo("#t", { left: 100, letterSpacing: "0.3em" }, { opacity: 1, duration: 1 }, 0);
|
||||
window.__timelines["c1"] = tl;
|
||||
</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
const finding = result.findings.find((f) => f.code === "gsap_non_transform_motion");
|
||||
expect(finding).toBeDefined();
|
||||
});
|
||||
|
||||
it("gsap_non_transform_motion: fires on text-reflow props (letterSpacing / fontSize)", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
|
||||
@@ -4,6 +4,9 @@ interface LintParsedGsap {
|
||||
method: string;
|
||||
position: number | string;
|
||||
properties: Record<string, number | string>;
|
||||
// fromTo() exposes its first ("from") vars object separately; a layout/reflow prop
|
||||
// that appears only here still animates and must be checked.
|
||||
fromProperties?: Record<string, number | string>;
|
||||
duration?: number;
|
||||
ease?: string;
|
||||
extras?: Record<string, unknown>;
|
||||
@@ -1198,7 +1201,14 @@ export const gsapRules: LintRule<LintContext>[] = [
|
||||
...parsed.animations.map((anim) => ({
|
||||
method: anim.method,
|
||||
selector: anim.targetSelector,
|
||||
properties: Object.keys(anim.properties),
|
||||
// Union the from-vars: a fromTo() can animate a layout/reflow prop that appears
|
||||
// only in its first ("from") object, which is just as stutter-prone as the to-vars.
|
||||
properties: [
|
||||
...new Set([
|
||||
...Object.keys(anim.properties),
|
||||
...Object.keys(anim.fromProperties ?? {}),
|
||||
]),
|
||||
],
|
||||
raw: synthesizeWindowRaw(parsed.timelineVar, anim),
|
||||
})),
|
||||
...extractStandaloneGsapTransformCalls(stripJsComments(script.content)),
|
||||
|
||||
Reference in New Issue
Block a user