fix(lint): flag digit-leading element ids (#2222)

This commit is contained in:
Miguel Ángel
2026-07-10 23:03:17 -04:00
committed by GitHub
parent 5f22209a82
commit d51fa7eba2
2 changed files with 50 additions and 0 deletions
+31
View File
@@ -77,6 +77,37 @@ ${headContent}
}
describe("core rules", () => {
it("warns when an id starts with a digit and is unsafe in a hash selector", async () => {
const html = `
<html><body>
<div data-composition-id="c1" data-width="1920" data-height="1080">
<div id="123-frame"></div>
</div>
<script>window.__timelines = {};</script>
</body></html>`;
const result = await lintHyperframeHtml(html);
const finding = result.findings.find((item) => item.code === "id_requires_css_escape");
expect(finding?.severity).toBe("warning");
expect(finding?.elementId).toBe("123-frame");
expect(finding?.fixHint).toContain("CSS.escape");
});
it("accepts ids that start with a letter", async () => {
const html = `
<html><body>
<div data-composition-id="c1" data-width="1920" data-height="1080">
<div id="frame-123"></div>
</div>
<script>window.__timelines = {};</script>
</body></html>`;
const result = await lintHyperframeHtml(html);
expect(result.findings.find((item) => item.code === "id_requires_css_escape")).toBeUndefined();
});
it("reports error when root is missing data-composition-id", async () => {
const html = `
<html><body>
+19
View File
@@ -181,6 +181,25 @@ function findVisibleMarkupCommentLeak(source: string): string | null {
}
export const coreRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [
// id_requires_css_escape
({ tags }) => {
const findings: HyperframeLintFinding[] = [];
for (const tag of tags) {
const id = readAttr(tag.raw, "id");
if (!id || !/^\d/.test(id)) continue;
findings.push({
code: "id_requires_css_escape",
severity: "warning",
message: `id="${id}" starts with a digit, so the common selector \`#${id}\` throws a SyntaxError in querySelector().`,
elementId: id,
fixHint:
"Rename the id to start with a letter (recommended), or build selectors with `#${CSS.escape(id)}` at runtime.",
snippet: truncateSnippet(tag.raw),
});
}
return findings;
},
// root_missing_composition_id + root_missing_dimensions
({ rootTag }) => {
const findings: HyperframeLintFinding[] = [];