diff --git a/packages/core/src/lint/hyperframeLinter.test.ts b/packages/core/src/lint/hyperframeLinter.test.ts
index c6546c298..a3fe608e2 100644
--- a/packages/core/src/lint/hyperframeLinter.test.ts
+++ b/packages/core/src/lint/hyperframeLinter.test.ts
@@ -218,3 +218,60 @@ describe("lintScriptUrls", () => {
vi.unstubAllGlobals();
});
});
+
+describe("template_literal_selector rule", () => {
+ it("reports error when querySelector uses template literal variable", () => {
+ const html = `
+
+
+
+`;
+ const result = lintHyperframeHtml(html);
+ const finding = result.findings.find((f) => f.code === "template_literal_selector");
+ expect(finding).toBeDefined();
+ expect(finding?.severity).toBe("error");
+ });
+
+ it("reports error for querySelectorAll with template literal variable", () => {
+ const html = `
+
+
+
+`;
+ const result = lintHyperframeHtml(html);
+ const finding = result.findings.find((f) => f.code === "template_literal_selector");
+ expect(finding).toBeDefined();
+ });
+
+ it("does not report error for hardcoded querySelector strings", () => {
+ const html = `
+
+
+
+`;
+ const result = lintHyperframeHtml(html);
+ const finding = result.findings.find((f) => f.code === "template_literal_selector");
+ expect(finding).toBeUndefined();
+ });
+});
diff --git a/packages/core/src/lint/hyperframeLinter.ts b/packages/core/src/lint/hyperframeLinter.ts
index 081dc67d3..f43deb70c 100644
--- a/packages/core/src/lint/hyperframeLinter.ts
+++ b/packages/core/src/lint/hyperframeLinter.ts
@@ -502,6 +502,26 @@ export function lintHyperframeHtml(
}
}
+ // ── Template literal variables in querySelector (breaks cheerio bundler) ──
+ for (const script of scripts) {
+ const templateLiteralSelectorPattern =
+ /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
+ let tlMatch: RegExpExecArray | null;
+ while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
+ pushFinding({
+ code: "template_literal_selector",
+ severity: "error",
+ message:
+ "querySelector uses a template literal variable (e.g. `${compId}`). " +
+ "The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
+ file: filePath,
+ fixHint:
+ "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
+ snippet: truncateSnippet(tlMatch[0]),
+ });
+ }
+ }
+
const errorCount = findings.filter((finding) => finding.severity === "error").length;
const warningCount = findings.length - errorCount;