diff --git a/packages/cli/bin/hyperframes-localize-fonts.mjs b/packages/cli/bin/hyperframes-localize-fonts.mjs index 7c341a2af..099260305 100644 --- a/packages/cli/bin/hyperframes-localize-fonts.mjs +++ b/packages/cli/bin/hyperframes-localize-fonts.mjs @@ -7,5 +7,6 @@ if (error) { console.error(error); process.exitCode = 1; } else { - await import("../dist/fontLocalizeCli.js"); + const { main } = await import("../dist/fontLocalizeCli.js"); + process.exitCode = await main(); } diff --git a/packages/cli/src/fontLocalizeCli.ts b/packages/cli/src/fontLocalizeCli.ts index e44b93a73..eb6bef8aa 100644 --- a/packages/cli/src/fontLocalizeCli.ts +++ b/packages/cli/src/fontLocalizeCli.ts @@ -1,3 +1,4 @@ +// fallow-ignore-file unused-file import { injectDeterministicFontFaces } from "@hyperframes/producer"; import { runFontLocalize } from "./fontLocalize.js"; @@ -9,15 +10,18 @@ async function readStdin(): Promise { return Buffer.concat(chunks).toString("utf8"); } -process.exitCode = await runFontLocalize( - { - readInput: readStdin, - writeOutput: (value) => process.stdout.write(value), - writeError: (value) => process.stderr.write(value), - }, - (html) => - injectDeterministicFontFaces(html, { - failClosedFontFetch: true, - allowSystemFontCapture: false, - }), -); +/** Standalone-entry main; the bin wrapper owns the actual process exit code. */ +export async function main(): Promise { + return runFontLocalize( + { + readInput: readStdin, + writeOutput: (value) => process.stdout.write(value), + writeError: (value) => process.stderr.write(value), + }, + (html) => + injectDeterministicFontFaces(html, { + failClosedFontFetch: true, + allowSystemFontCapture: false, + }), + ); +} diff --git a/packages/producer/src/services/deterministicFonts-textSubset.test.ts b/packages/producer/src/services/deterministicFonts-textSubset.test.ts index ec3552e76..d9285ea0d 100644 --- a/packages/producer/src/services/deterministicFonts-textSubset.test.ts +++ b/packages/producer/src/services/deterministicFonts-textSubset.test.ts @@ -1,22 +1,28 @@ import { describe, expect, it } from "bun:test"; import { injectDeterministicFontFaces } from "./deterministicFonts.js"; +async function requestedGoogleFontUrl(html: string): Promise { + let requestedUrl = ""; + const fetchImpl = (async (input: unknown) => { + requestedUrl = String(input); + return new Response("", { status: 400 }); + }) as unknown as typeof fetch; + + await injectDeterministicFontFaces(html, { + fetchImpl, + allowSystemFontCapture: false, + }); + return new URL(requestedUrl); +} + describe("Google Fonts text subsetting", () => { it("sends the composition character set to the CSS API", async () => { - let requestedUrl = ""; - const fetchImpl = (async (input: unknown) => { - requestedUrl = String(input); - return new Response("", { status: 400 }); - }) as unknown as typeof fetch; - - await injectDeterministicFontFaces( + const url = await requestedGoogleFontUrl( `

旅行ランキング

`, - { fetchImpl, allowSystemFontCapture: false }, ); - const url = new URL(requestedUrl); const text = url.searchParams.get("text") ?? ""; for (const character of new Set("旅行ランキング")) { expect(text).toContain(character); @@ -24,48 +30,29 @@ describe("Google Fonts text subsetting", () => { }); it("includes decoded HTML entities from visible composition text", async () => { - let requestedUrl = ""; - const fetchImpl = (async (input: unknown) => { - requestedUrl = String(input); - return new Response("", { status: 400 }); - }) as unknown as typeof fetch; - - await injectDeterministicFontFaces( + const url = await requestedGoogleFontUrl( `

旅行

`, - { fetchImpl, allowSystemFontCapture: false }, ); - expect(new URL(requestedUrl).searchParams.get("text")).toContain("旅行"); + expect(url.searchParams.get("text")).toContain("旅行"); }); it("includes case variants for transformed supplemental alias weights", async () => { - let requestedUrl = ""; - const fetchImpl = (async (input: unknown) => { - requestedUrl = String(input); - return new Response("", { status: 400 }); - }) as unknown as typeof fetch; - - await injectDeterministicFontFaces( + const url = await requestedGoogleFontUrl( `

Your Kidney Transplant:
What Happens Next

`, - { fetchImpl, allowSystemFontCapture: false }, ); - const text = new URL(requestedUrl).searchParams.get("text") ?? ""; + const text = url.searchParams.get("text") ?? ""; for (const character of new Set("YOUR KIDNEY TRANSPLANT:WHAT HAPPENS NEXT")) { expect(text).toContain(character); } }); it("falls back to the full font when case closure exceeds the text URL budget", async () => { - let requestedUrl = ""; - const fetchImpl = (async (input: unknown) => { - requestedUrl = String(input); - return new Response("", { status: 400 }); - }) as unknown as typeof fetch; const caseChangingCharacters = Array.from({ length: 0x500 }, (_, index) => String.fromCodePoint(index), ) @@ -73,13 +60,12 @@ describe("Google Fonts text subsetting", () => { .slice(0, 300) .join(""); - await injectDeterministicFontFaces( + const url = await requestedGoogleFontUrl( `

${caseChangingCharacters}

`, - { fetchImpl, allowSystemFontCapture: false }, ); - expect(new URL(requestedUrl).searchParams.has("text")).toBe(false); + expect(url.searchParams.has("text")).toBe(false); }); });