Repository navigation
lint rejects a final unquoted font-family without a semicolon #6083
Description
Describe the bug
Valid @font-face CSS is rejected when its final descriptor is an unquoted font-family without a trailing semicolon. This can arise in handwritten or minified CSS. The font_family_without_font_face error blocks lint/check and strict render preflight even though the family is declared.
Minimal reproduction
From a built repository checkout, save this as repro-font.mjs in the repository root:
import { lintHyperframeHtml } from "./packages/lint/src/hyperframeLinter.ts";
const html = `<div data-composition-id="test" data-width="1920" data-height="1080">
<style>
@font-face { src: local('DejaVu Sans'); font-family: ProjectFont }
body { font-family: ProjectFont, sans-serif }
</style>
</div>`;
const result = await lintHyperframeHtml(html, { isSubComposition: true });
console.log(JSON.stringify(result.findings.filter(
(finding) => finding.code === "font_family_without_font_face",
), null, 2));No downloaded font or other asset is required to reproduce the incorrect lint result. This calls the real HTML linter and filters the relevant diagnostic.
Steps to reproduce
- Use main at
10c724bf555f8355199bd89db1a02fc159909dc9(version 0.8.186) with the repository dependencies and packages built. - Run
bun repro-font.mjs. - Add a semicolon immediately after
ProjectFontin the@font-facedescriptor and rerun. Quoting the family also avoids the failure.
Expected behavior
The declaration is recognized with or without its optional final semicolon. The reproduction should print [].
Actual behavior
The first run returns an error with code font_family_without_font_face and message beginning Font family used without @font-face declaration: projectfont. The semicolon and quoted-name controls return no such finding.
Chrome 152 CSSOM accepts both declarations as ProjectFont. The linter's extractFontFaceFamilies matcher includes the closing brace in the unquoted value, recording projectfont} instead of projectfont.
Environment
- Hyperframes 0.8.186; current-main base
10c724bf555f8355199bd89db1a02fc159909dc9. - Linux x86_64, Node 26.11.1, Bun 1.4.1. The repository pins Bun 1.4.4; the reproduction and tests used the already-installed 1.4.1.
- Vitest 4.1.11; lint package builds and typechecks successfully.
- This is a static lint reproduction, not a complete video render. A full workspace build is limited by missing installed inspector/AWS dependencies; no packages were installed for this investigation.
Additional context
The correction is to stop the family-value match at }. Two regressions cover single-word and multiword unquoted families. The existing missing-declaration behavior remains intact.
Related #1534/#1538 concern braces inside CSS comments; #2538 concerns !important; closed #2778 leaves the declaration extractor unchanged. None corrects this case. I have a focused fix prepared.
Activity
miguel-heygen commentedon Oct 24, 2026
Thanks for the precise reproduction. I reproduced it on 0.8.186: a final unquoted
font-family: ProjectFont }with no semicolon raisedfont_family_without_font_face. It is fixed in 0.8.192 and later. The font rule now reads the@font-facedeclarations with a real CSS parser (#5221) instead of pattern matching, andnpx hyperframes@0.8.193 linton the same file reports no font finding, with or without the semicolon.Your #6085 adds regression tests for exactly this case, which are still worth having on top of the fix. Once you've confirmed it on 0.8.192 or later, I think this issue can be closed as resolved.