mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(lint): a scene child hidden at zero through a scoped query is not an overlay that starts visible
This commit is contained in:
@@ -3721,6 +3721,43 @@ describe("SVG draw-on rules", () => {
|
||||
expect(finding).toBeUndefined();
|
||||
});
|
||||
|
||||
describe("gsap_fullscreen_overlay_starts_visible — a scene child hidden through a scoped query", () => {
|
||||
const scene = (hide: string) => `
|
||||
<html><body>
|
||||
<div data-composition-id="scene" data-width="1920" data-height="1080">
|
||||
<div class="ov" style="position:absolute;inset:0;background:#fff"></div>
|
||||
</div>
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
const root = document.querySelector('[data-composition-id="scene"]');
|
||||
${hide}
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
tl.to(".ov", { opacity: 1, duration: 0.5 }, 1).to(".ov", { opacity: 0, duration: 0.5 }, 3);
|
||||
window.__timelines["scene"] = tl;
|
||||
</script>
|
||||
</body></html>`;
|
||||
const flagged = async (html: string) =>
|
||||
(await lintHyperframeHtml(html)).findings.some(
|
||||
(f) => f.code === "gsap_fullscreen_overlay_starts_visible",
|
||||
);
|
||||
|
||||
it("accepts gsap.set on a querySelector call with a literal selector", async () => {
|
||||
expect(await flagged(scene('gsap.set(root.querySelector(".ov"), { opacity: 0 });'))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts gsap.set on a variable bound to a querySelector call", async () => {
|
||||
expect(
|
||||
await flagged(scene('const ov = root.querySelector(".ov"); gsap.set(ov, { opacity: 0 });')),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("still flags an overlay nothing hides at zero", async () => {
|
||||
expect(await flagged(scene(""))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("gsap_fullscreen_overlay_starts_visible — the from() shape is not a defect", () => {
|
||||
const overlay = (style: string, script: string) => `
|
||||
<html><body>
|
||||
|
||||
@@ -253,7 +253,10 @@ function hiddenSetTargetSelectors(target: string, aliases: Map<string, string>):
|
||||
return parts
|
||||
.flatMap((part) => {
|
||||
const trimmed = part.trim();
|
||||
const resolved = /^(["'`])([^"'`]+)\1$/.exec(trimmed)?.[2] ?? aliases.get(trimmed);
|
||||
const resolved =
|
||||
/^(["'`])([^"'`]+)\1$/.exec(trimmed)?.[2] ??
|
||||
/^[\w$.]+\.querySelector(?:All)?\(\s*(["'`])([^"'`]+)\1\s*\)$/.exec(trimmed)?.[2] ??
|
||||
aliases.get(trimmed);
|
||||
return resolved === undefined ? [] : resolved.split(",");
|
||||
})
|
||||
.map((selector) => selector.trim())
|
||||
@@ -270,8 +273,13 @@ function extractStandaloneHiddenSelectors(script: string): Set<string> {
|
||||
)) {
|
||||
aliases.set(match[1] ?? "", match[3] ?? "");
|
||||
}
|
||||
for (const match of source.matchAll(
|
||||
/(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*[\w$.]+\.querySelector(?:All)?\(\s*(["'`])([^"'`]+)\2\s*\)\s*;/g,
|
||||
)) {
|
||||
aliases.set(match[1] ?? "", match[3] ?? "");
|
||||
}
|
||||
const pattern =
|
||||
/gsap\.set\s*\(\s*(\[[^[\]]*\]|"[^"]*"|'[^']*'|`[^`]*`|[^,()[\]]+?)\s*,\s*\{([\s\S]*?)\}\s*\)/g;
|
||||
/gsap\.set\s*\(\s*(\[[^[\]]*\]|"[^"]*"|'[^']*'|`[^`]*`|[\w$.]+\.querySelector(?:All)?\(\s*(?:"[^"]*"|'[^']*'|`[^`]*`)\s*\)|[^,()[\]]+?)\s*,\s*\{([\s\S]*?)\}\s*\)/g;
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = pattern.exec(source)) !== null) {
|
||||
// Skip callback/handler bodies; keep IIFEs (they run at parse time).
|
||||
|
||||
Reference in New Issue
Block a user