Skip to content

lint rejects a final unquoted font-family without a semicolon #6083

Closed

Description

@AksharP5

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

  1. Use main at 10c724bf555f8355199bd89db1a02fc159909dc9 (version 0.8.186) with the repository dependencies and packages built.
  2. Run bun repro-font.mjs.
  3. Add a semicolon immediately after ProjectFont in the @font-face descriptor 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

  1. added
    triage/readyAccepted scope, current evidence, acceptance criteria, and validation path are recorded.
    on Oct 23, 2026
  2. miguel-heygen commented on Oct 24, 2026

    @miguel-heygen
    Collaborator

    Thanks for the precise reproduction. I reproduced it on 0.8.186: a final unquoted font-family: ProjectFont } with no semicolon raised font_family_without_font_face. It is fixed in 0.8.192 and later. The font rule now reads the @font-face declarations with a real CSS parser (#5221) instead of pattern matching, and npx hyperframes@0.8.193 lint on 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triage/readyAccepted scope, current evidence, acceptance criteria, and validation path are recorded.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions