UNPKG

@7nohe/openapi-react-query-codegen

Version:
111 lines (110 loc) 4.55 kB
import { readdirSync } from "node:fs"; import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { createClient } from "@hey-api/openapi-ts"; import { buildQueriesOutputPath, buildRequestsOutputPath, formatOptions, } from "./common.mjs"; import { createSource } from "./createSource.mjs"; import { formatOutput, processOutput } from "./format.mjs"; import { print } from "./print.mjs"; // openapi-ts's own tsconfig auto-detection walks up from its *install* // location, which in this monorepo reaches this repo's own root tsconfig // (NodeNext) instead of the caller's project config. Anchoring the search // at cwd instead finds the tsconfig that actually applies to the generated // output, matching the resolution the caller's own `tsc` will use. export function findNearestTsConfigPath(startDir) { let dir = startDir; while (true) { const candidates = readdirSync(dir).filter((file) => file.startsWith("tsconfig") && file.endsWith(".json")); if (candidates.length > 0) { candidates.sort((a) => (a === "tsconfig.json" ? -1 : 1)); return path.join(dir, candidates[0]); } const parent = path.dirname(dir); if (parent === dir) return undefined; dir = parent; } } export async function generate(options, version) { const openApiOutputPath = buildRequestsOutputPath(options.output); const formattedOptions = formatOptions(options); // Map CLI options to new plugins system const clientPlugin = formattedOptions.client === "@hey-api/client-axios" ? "@hey-api/client-axios" : "@hey-api/client-fetch"; const typescriptPlugin = formattedOptions.enums ? { name: "@hey-api/typescript", enums: formattedOptions.enums, } : "@hey-api/typescript"; const sdkPlugin = { name: "@hey-api/sdk", ...(formattedOptions.noOperationId ? { // `operationId: false` was deprecated in favor of `operations.nesting` operations: { nesting: "id", }, } : {}), ...(formattedOptions.useDateType ? { transformer: "@hey-api/transformers" } : {}), }; const plugins = [ clientPlugin, typescriptPlugin, sdkPlugin, ]; if (formattedOptions.useDateType) { plugins.push({ name: "@hey-api/transformers", dates: "date", }); } // Conditionally add schemas plugin if (!formattedOptions.noSchemas) { plugins.push(formattedOptions.schemaType ? { name: "@hey-api/schemas", type: formattedOptions.schemaType, } : "@hey-api/schemas"); } const config = { dryRun: false, input: formattedOptions.input, output: { path: openApiOutputPath, tsConfigPath: findNearestTsConfigPath(process.cwd()) ?? null, }, plugins, }; await createClient(config); // Generate backward-compatible services.gen.ts shim // client.gen.ts has the `client` instance; sdk.gen.ts has SDK functions. // Mirror whatever extension convention openapi-ts used for its own // cross-file imports (e.g. `.js` for NodeNext, none for bundler resolution). const sdkGenContent = await readFile(path.join(openApiOutputPath, "sdk.gen.ts"), "utf-8"); const importExtension = sdkGenContent.match(/from ['"]\.\/client\.gen(\.\S*)?['"]/)?.[1] ?? ""; const shimContent = `// This file is auto-generated for backward compatibility\nexport * from './client.gen${importExtension}';\nexport * from './sdk.gen${importExtension}';\n`; await writeFile(path.join(openApiOutputPath, "services.gen.ts"), shimContent); const source = await createSource({ outputPath: openApiOutputPath, client: clientPlugin, version, pageParam: formattedOptions.pageParam, nextPageParam: formattedOptions.nextPageParam, initialPageParam: formattedOptions.initialPageParam.toString(), omitInitialPageParam: formattedOptions.omitInitialPageParam ?? false, }); await print(source, formattedOptions); const queriesOutputPath = buildQueriesOutputPath(options.output); await formatOutput(queriesOutputPath); await processOutput({ output: queriesOutputPath, format: formattedOptions.format, lint: formattedOptions.lint, }); }