mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
fix(lint): stop a leading <svg> defs block from being mistaken for the composition root (#1867)
Two independent post-release feedback reports of the same mechanism: a leading <svg> block (icon/gradient/filter <defs>, referenced by url(#id) elsewhere in the document) placed before the real [data-composition-id] root manufactures root_missing_composition_id + root_missing_dimensions on an otherwise-correct composition. Moving the <svg> after the root cleared both findings for each reporter. findRootTag returned the first body child that wasn't script/style/meta/ link/title, unconditionally — <svg> was never in that skip list, so a leading defs-only <svg> got treated as the root. Fix: skip a leading <svg> when it carries none of the composition markers itself (data-composition-id/data-width/data-height), so an intentionally SVG-rooted composition is still eligible as the root. The first attempt at this only skipped the <svg> open tag, which surfaced a second bug: extractOpenTags is a flat, nesting-unaware scan, so the very next tag it returns after skipping <svg> is the svg's own nested child (<defs>, <filter>, ...), not the sibling after </svg>. Track the svg's closing tag position and skip every tag before it, not just the <svg> tag itself. Tests: skips a leading svg defs block (no false root findings); still treats an <svg> as the root when data-composition-id/data-width/ data-height are declared directly on it. Full lint suite (308 tests) passes.
This commit is contained in:
@@ -112,6 +112,37 @@ describe("core rules", () => {
|
||||
expect(result.findings.find((f) => f.code === "root_missing_dimensions")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("skips a leading <svg> defs block when detecting the composition root", async () => {
|
||||
// Regression: two independent reports of a leading <svg><defs><filter>...
|
||||
// block (icon/gradient/filter plumbing referenced via url(#id) elsewhere)
|
||||
// getting mistaken for the composition root, since findRootTag returned
|
||||
// the first non-script/style/meta/link/title body child unconditionally.
|
||||
// The <svg> here carries no composition markers, so it must be skipped in
|
||||
// favor of the real root that follows it.
|
||||
const html = `
|
||||
<html><body>
|
||||
<svg width="0" height="0" style="position:absolute">
|
||||
<defs><filter id="glow"><feGaussianBlur stdDeviation="4" /></filter></defs>
|
||||
</svg>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080"></div>
|
||||
<script>window.__timelines = window.__timelines || {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
expect(result.findings.find((f) => f.code === "root_missing_composition_id")).toBeUndefined();
|
||||
expect(result.findings.find((f) => f.code === "root_missing_dimensions")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("still treats an <svg> as the root when it carries composition markers itself", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<svg id="root" data-composition-id="c1" data-width="1920" data-height="1080"></svg>
|
||||
<script>window.__timelines = window.__timelines || {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
expect(result.findings.find((f) => f.code === "root_missing_composition_id")).toBeUndefined();
|
||||
expect(result.findings.find((f) => f.code === "root_missing_dimensions")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("reports error when timeline registry is missing", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
|
||||
Reference in New Issue
Block a user