This commit is contained in:
Rajan Pantha
2026-08-30 02:16:16 -07:00
committed by GitHub
2 changed files with 30 additions and 1 deletions
+26
View File
@@ -480,6 +480,32 @@ describe("GSAP rules", () => {
expect(finding?.selector).toBe("#hero");
});
it("quotes a combined scale+translate declaration once", async () => {
const html = `
<html><body>
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
<div class="scene-1"></div>
</div>
<style>
.scene-1 { transform: scale(1.08) translate3d(1.5%, 0, 0); }
</style>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
tl.to(".scene-1", { duration: 1, x: 100, scale: 1.2 });
window.__timelines["c1"] = tl;
</script>
</body></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 = `
<html><body>
+4 -1
View File
@@ -1332,7 +1332,10 @@ export const gsapRules: LintRule<LintContext>[] = [
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<string>(),
raw: call.raw,
};