From b7eb0dfb5a87d53bb542f5f70723110ea60c6990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Thu, 2 Jul 2026 17:45:01 -0700 Subject: [PATCH] fix(lint): mention src: local() for system fonts in font_family_without_font_face (#1859) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two independent post-release feedback reports of this rule hard-erroring on OS system fonts (Hiragino Sans, Microsoft YaHei) that have no downloadable file. Both asked for the same thing, in slightly different words: a documented way to satisfy the check for a font that's genuinely OS-bundled, not missing. That way already exists and already works — extractFontFaceFamilies only looks at the font-family declaration inside @font-face, never the src value, so `@font-face { font-family: 'X'; src: local('X'); }` already passes. One report found this themselves; the other didn't. The gap was discoverability: the fixHint only described bundling a real font file, so nobody would think to try `local()` unless they already knew about it. Considered and rejected a broader fix: adding CJK system-font names to the shared FONT_ALIAS_MAP (the mechanism that already exempts Latin system fonts like Segoe UI/Verdana by aliasing them to a bundled fallback font). That map has no CJK-equivalent bundled font to alias to (only Japanese has one, noto-sans-jp) — aliasing "Microsoft YaHei" (Simplified Chinese) to a Japanese font would silently swap in the wrong glyph shapes for shared Han characters, and would specifically break distributed/Lambda rendering (where system-font capture is disabled, per system_font_will_alias's own comment) by removing the warning that currently prompts a real fix. The local() message fix has none of that risk: it changes no detection logic, only points at an already-correct existing escape hatch. Tests: local() font-face no longer flags (proves the advice is accurate, not just documented); fixHint contains "local(". 308 lint tests pass. --- packages/lint/src/rules/fonts.test.ts | 24 ++++++++++++++++++++++++ packages/lint/src/rules/fonts.ts | 5 ++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/lint/src/rules/fonts.test.ts b/packages/lint/src/rules/fonts.test.ts index 8a22f53f3..fc5c3ddb2 100644 --- a/packages/lint/src/rules/fonts.test.ts +++ b/packages/lint/src/rules/fonts.test.ts @@ -146,6 +146,30 @@ describe("font rules", () => { expect(findings).toHaveLength(0); }); + it("does not flag a system font declared via @font-face src: local()", async () => { + // Regression: two independent reports of this rule hard-erroring on OS + // system fonts (Hiragino Sans, Microsoft YaHei) that have no downloadable + // file. src: local(...) already satisfies the check (extractFontFaceFamilies + // only looks at the font-family declaration, not the src value) — the gap + // was that the fixHint didn't mention this as an option. + const html = `
+ +
`; + const findings = await findByCode(html, "font_family_without_font_face"); + expect(findings).toHaveLength(0); + }); + + it("fixHint mentions the local() pattern for system fonts", async () => { + const html = `
+ +
`; + const findings = await findByCode(html, "font_family_without_font_face"); + expect(findings[0]!.fixHint).toContain("local("); + }); + it("does not flag generic font families", async () => { const html = `
diff --git a/packages/lint/src/rules/fonts.ts b/packages/lint/src/rules/fonts.ts index 611fb4a18..f7c7a8818 100644 --- a/packages/lint/src/rules/fonts.ts +++ b/packages/lint/src/rules/fonts.ts @@ -232,7 +232,10 @@ export const fontRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [ "Text will fall back to a generic font, producing incorrect typography in the video.", fixHint: "Add @font-face { font-family: '...'; src: url('capture/assets/fonts/...woff2'); } " + - "for each font family, pointing to the captured .woff2 files.", + "for each font family, pointing to the captured .woff2 files. For an OS-bundled " + + "system font (e.g. Hiragino Sans, Microsoft YaHei) that has no downloadable file, " + + "use src: local('Exact Font Name') instead — the declaration alone satisfies this " + + "check without needing a font file.", }); return findings; },