120 lines
3.9 KiB
JavaScript
120 lines
3.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Usage: npm run endpoint:generate -- [slug]
|
|
* Example: npm run endpoint:generate -- home-page
|
|
* Expects src/.../slug.gql.ts with export const name = gql`...`
|
|
* Runs graphql-codegen, then writes slug.gql.generated.ts beside it.
|
|
*/
|
|
|
|
import { execSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.resolve(__dirname, "..");
|
|
|
|
const slug = process.argv[2];
|
|
if (!slug || slug.startsWith("-")) {
|
|
console.error("Usage: npm run endpoint:generate -- <slug>");
|
|
console.error('Example: npm run endpoint:generate -- home-page');
|
|
process.exit(1);
|
|
}
|
|
|
|
function findGqlFile() {
|
|
const exact = path.join(root, "src", `${slug}.gql.ts`);
|
|
if (fs.existsSync(exact)) return path.relative(root, exact);
|
|
|
|
const stack = [path.join(root, "src")];
|
|
while (stack.length) {
|
|
const dir = stack.pop();
|
|
if (!fs.existsSync(dir)) continue;
|
|
for (const name of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const p = path.join(dir, name.name);
|
|
if (name.isDirectory()) stack.push(p);
|
|
else if (name.name === `${slug}.gql.ts`) return path.relative(root, p);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const gqlPath = findGqlFile();
|
|
if (!gqlPath) {
|
|
console.error(`No file named "${slug}.gql.ts" found under src/`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const absGql = path.join(root, gqlPath);
|
|
const source = fs.readFileSync(absGql, "utf8");
|
|
|
|
const exportMatch = source.match(/export\s+const\s+(\w+)\s*=\s*gql\s*`/);
|
|
if (!exportMatch) {
|
|
console.error(`${gqlPath}: expected: export const SomeName = gql\`...\``);
|
|
process.exit(1);
|
|
}
|
|
const documentExport = exportMatch[1];
|
|
|
|
const opMatch = source.match(/\b(query|mutation|subscription)\s+(\w+)\s*[\({]/);
|
|
if (!opMatch) {
|
|
console.error(`${gqlPath}: could not find operation name (query|mutation|subscription Name)`);
|
|
process.exit(1);
|
|
}
|
|
const operationKind = opMatch[1];
|
|
const operationName = opMatch[2];
|
|
|
|
const resultType =
|
|
operationKind === "mutation"
|
|
? `${operationName}Mutation`
|
|
: operationKind === "subscription"
|
|
? `${operationName}Subscription`
|
|
: `${operationName}Query`;
|
|
const variablesType = `${resultType}Variables`;
|
|
|
|
const endpointName =
|
|
operationKind === "mutation"
|
|
? operationName[0].toLowerCase() + operationName.slice(1) + "Mutation"
|
|
: operationKind === "subscription"
|
|
? operationName[0].toLowerCase() + operationName.slice(1) + "Subscription"
|
|
: operationName[0].toLowerCase() + operationName.slice(1) + "Query";
|
|
|
|
const outPath = absGql.replace(/\.gql\.ts$/, ".gql.generated.ts");
|
|
const outRel = path.relative(root, outPath);
|
|
|
|
const gqlDir = path.dirname(absGql);
|
|
const executeRel = path
|
|
.relative(gqlDir, path.join(root, "src", "graphql", "execute.ts"))
|
|
.replace(/\\/g, "/")
|
|
.replace(/\.ts$/, "");
|
|
const typesRel = path
|
|
.relative(gqlDir, path.join(root, "src", "graphql", "graphql.ts"))
|
|
.replace(/\\/g, "/")
|
|
.replace(/\.ts$/, "");
|
|
const gqlBase = path.basename(gqlPath);
|
|
const gqlImportStem = gqlBase.replace(/\.ts$/, "");
|
|
|
|
console.log("Running graphql-codegen…");
|
|
execSync("npx graphql-codegen", { cwd: root, stdio: "inherit" });
|
|
|
|
function quoteImport(rel) {
|
|
if (rel.startsWith(".")) return rel;
|
|
return `./${rel}`;
|
|
}
|
|
|
|
const body = `/* eslint-disable */
|
|
/* Generated by scripts/endpoint-generate.mjs — do not edit by hand */
|
|
import type { ExecutionResult } from "graphql";
|
|
|
|
import { execute } from "${quoteImport(executeRel)}";
|
|
import type { ${resultType}, ${variablesType} } from "${quoteImport(typesRel)}";
|
|
import { ${documentExport} } from "./${gqlImportStem}";
|
|
|
|
export const ${endpointName} = {
|
|
async execute(variables?: ${variablesType}): Promise<ExecutionResult<${resultType}>> {
|
|
return execute<${resultType}, ${variablesType}>(${documentExport}, variables);
|
|
},
|
|
};
|
|
`;
|
|
|
|
fs.writeFileSync(outPath, body, "utf8");
|
|
console.log(`Wrote ${outRel}`);
|