From 82a29afd2cdf410280f177a4963967a480144d1a Mon Sep 17 00:00:00 2001 From: rajanpanth Date: Sun, 23 Aug 2026 21:20:09 +0545 Subject: [PATCH] fix(lint): quote a combined scale+translate declaration once gsap_css_transform_conflict looks the selector up in the translate map and the scale map separately, then joins both results. A single declaration such as `transform: scale(1.08) translate3d(1.5%, 0, 0)` matches both maps, so the two lookups return the same text and the join repeated it: ".scene-1" has CSS `transform: scale(1.08) translate3d(1.5%, 0, 0) scale(1.08) translate3d(1.5%, 0, 0)` and a GSAP tween animates x/scale. The same doubling appeared in fixHint. Dedupe the two lookups before joining, which leaves the separate-declaration case unchanged. Fixes #3263 --- packages/lint/src/rules/gsap.test.ts | 26 ++++++++++++++++++++++++++ packages/lint/src/rules/gsap.ts | 5 ++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/lint/src/rules/gsap.test.ts b/packages/lint/src/rules/gsap.test.ts index 33f3083c60..ebb0e7e7dc 100644 --- a/packages/lint/src/rules/gsap.test.ts +++ b/packages/lint/src/rules/gsap.test.ts @@ -480,6 +480,32 @@ describe("GSAP rules", () => { expect(finding?.selector).toBe("#hero"); }); + it("quotes a combined scale+translate declaration once", async () => { + const html = ` + +
+
+
+ + +`; + const result = await lintHyperframeHtml(html); + const finding = result.findings.find((f) => f.code === "gsap_css_transform_conflict"); + expect(finding).toBeDefined(); + // One declaration matches both the translate and the scale selector map, + // so the two lookups return the same text and it must not be repeated. + const transform = "scale(1.08) translate3d(1.5%, 0, 0)"; + expect(finding?.message.split(transform)).toHaveLength(2); + expect(finding?.fixHint?.split(transform)).toHaveLength(2); + }); + it("does NOT warn when tl.to targets element without CSS transform", async () => { const html = ` diff --git a/packages/lint/src/rules/gsap.ts b/packages/lint/src/rules/gsap.ts index c87d75e136..9584e14a32 100644 --- a/packages/lint/src/rules/gsap.ts +++ b/packages/lint/src/rules/gsap.ts @@ -1332,7 +1332,10 @@ export const gsapRules: LintRule[] = [ scaleProps.length > 0 ? matchCssTransform(sel, cssScaleSelectors) : undefined; if (!cssFromTranslate && !cssFromScale) continue; const existing = conflicts.get(sel) ?? { - cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "), + // A single declaration such as `transform: scale(...) translate3d(...)` + // matches both selector maps, so the two lookups return the same text. + // Dedupe before joining, or the message quotes it twice. + cssTransform: [...new Set([cssFromTranslate, cssFromScale].filter(Boolean))].join(" "), props: new Set(), raw: call.raw, };