Files
bbs/frontend/scripts/generate-types.mjs
T

67 lines
2.3 KiB
JavaScript

import { readdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { codegen } from "@graphql-codegen/core";
import { plugin as typedDocumentNodePlugin } from "@graphql-codegen/typed-document-node";
import { plugin as typescriptOperationsPlugin } from "@graphql-codegen/typescript-operations";
import { plugin as typescriptPlugin } from "@graphql-codegen/typescript";
import { buildASTSchema, parse } from "graphql";
import { parse as parseYaml } from "yaml";
const frontendRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const configPath = path.join(frontendRoot, "codegen.yml");
const config = parseYaml(await readFile(configPath, "utf8"));
const schemaDocument = parse(await readFile(path.resolve(frontendRoot, config.schema), "utf8"));
const outputEntries = Object.entries(config.generates ?? {});
if (outputEntries.length !== 1) {
throw new Error(`Expected one GraphQL Codegen output in ${configPath}`);
}
const [outputName, outputConfig] = outputEntries[0];
const outputPath = path.resolve(frontendRoot, outputName);
const sourceRoot = path.join(frontendRoot, "src");
const plugins = outputConfig.plugins.map((plugin) =>
typeof plugin === "string" ? { [plugin]: {} } : plugin,
);
async function findGraphqlFiles(directory) {
const entries = await readdir(directory, { withFileTypes: true });
const nestedFiles = await Promise.all(
entries.map((entry) => {
const entryPath = path.join(directory, entry.name);
if (entry.isDirectory()) return findGraphqlFiles(entryPath);
return entry.isFile() && entry.name.endsWith(".graphql") ? [entryPath] : [];
}),
);
return nestedFiles.flat();
}
const documents = await Promise.all(
(await findGraphqlFiles(sourceRoot))
.sort()
.map(async (location) => ({
location,
document: parse(await readFile(location, "utf8")),
})),
);
const pluginMap = {
typescript: { plugin: typescriptPlugin },
"typescript-operations": { plugin: typescriptOperationsPlugin },
"typed-document-node": { plugin: typedDocumentNodePlugin },
};
const generated = await codegen({
filename: outputPath,
schema: schemaDocument,
schemaAst: buildASTSchema(schemaDocument),
documents,
config: {},
plugins,
pluginMap,
});
await writeFile(outputPath, generated);