mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
7325f0fc7d
Reworks the font-catalog removal from #262 using per-import virtual modules so named imports keep normal ESM semantics, aliased/default calls still self-host in build mode, and dependency imports are transformed too. Credit to @yunus25jmi1 for the original PR and direction in #262.
120 lines
3.3 KiB
JavaScript
120 lines
3.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
|
|
const METADATA_URL = "https://fonts.google.com/metadata/fonts";
|
|
|
|
function toExportName(family) {
|
|
return family
|
|
.replace(/[^0-9A-Za-z]+/g, "_")
|
|
.replace(/^_+|_+$/g, "")
|
|
.replace(/_+/g, "_");
|
|
}
|
|
|
|
function assertValidExports(names) {
|
|
const invalid = names.filter((name) => !/^[A-Za-z_$][0-9A-Za-z_$]*$/.test(name));
|
|
if (invalid.length > 0) {
|
|
throw new Error(`Invalid export identifiers: ${invalid.slice(0, 10).join(", ")}`);
|
|
}
|
|
const seen = new Set();
|
|
const dupes = new Set();
|
|
for (const name of names) {
|
|
if (seen.has(name)) dupes.add(name);
|
|
seen.add(name);
|
|
}
|
|
if (dupes.size > 0) {
|
|
throw new Error(`Duplicate export identifiers: ${Array.from(dupes).slice(0, 10).join(", ")}`);
|
|
}
|
|
}
|
|
|
|
function stripXssiPrefix(text) {
|
|
if (text.startsWith(")]}'")) {
|
|
return text.replace(/^\)\]\}'\n?/, "");
|
|
}
|
|
return text;
|
|
}
|
|
|
|
async function loadMetadata(metadataPath) {
|
|
if (metadataPath) {
|
|
const text = fs.readFileSync(metadataPath, "utf-8");
|
|
return JSON.parse(stripXssiPrefix(text));
|
|
}
|
|
const res = await fetch(METADATA_URL);
|
|
if (!res.ok) {
|
|
throw new Error(`Failed to fetch metadata: ${res.status} ${res.statusText}`);
|
|
}
|
|
const text = await res.text();
|
|
return JSON.parse(stripXssiPrefix(text));
|
|
}
|
|
|
|
function writeFixture(families) {
|
|
const fixturePath = path.join(process.cwd(), "tests/fixtures/google-fonts.json");
|
|
const data = {
|
|
source: METADATA_URL,
|
|
generatedAt: new Date().toISOString().slice(0, 10),
|
|
count: families.length,
|
|
families,
|
|
};
|
|
fs.mkdirSync(path.dirname(fixturePath), { recursive: true });
|
|
fs.writeFileSync(fixturePath, JSON.stringify(data, null, 2) + "\n");
|
|
}
|
|
|
|
function writeGeneratedDts(exportNames) {
|
|
const outPath = path.join(
|
|
process.cwd(),
|
|
"packages/vinext/src/shims/next-shims-font-google.generated.d.ts",
|
|
);
|
|
const lines = [];
|
|
lines.push("// Generated by scripts/generate-google-fonts.js");
|
|
lines.push(`// Source: ${METADATA_URL}`);
|
|
lines.push("// @generated");
|
|
lines.push('declare module "next/font/google" {');
|
|
lines.push(" export function createFontLoader(family: string): FontLoader;");
|
|
for (const name of exportNames) {
|
|
lines.push(` export const ${name}: FontLoader;`);
|
|
}
|
|
lines.push("}");
|
|
lines.push("");
|
|
fs.writeFileSync(outPath, lines.join("\n"));
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
let metadataPath;
|
|
for (let i = 0; i < args.length; i += 1) {
|
|
if (args[i] === "--metadata-path") {
|
|
metadataPath = args[i + 1];
|
|
i += 1;
|
|
}
|
|
}
|
|
if (!metadataPath && process.env.GOOGLE_FONTS_METADATA_PATH) {
|
|
metadataPath = process.env.GOOGLE_FONTS_METADATA_PATH;
|
|
}
|
|
|
|
const metadata = await loadMetadata(metadataPath);
|
|
const families = metadata.familyMetadataList?.map((f) => f.family) ?? [];
|
|
if (families.length === 0) {
|
|
throw new Error("No font families found in metadata");
|
|
}
|
|
|
|
const entries = families.map((family) => ({
|
|
family,
|
|
exportName: toExportName(family),
|
|
}));
|
|
entries.sort((a, b) => a.exportName.localeCompare(b.exportName));
|
|
|
|
const exportNames = entries.map((e) => e.exportName);
|
|
assertValidExports(exportNames);
|
|
|
|
writeFixture(families);
|
|
writeGeneratedDts(exportNames);
|
|
|
|
console.log(`Generated ${entries.length} fonts`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|