diff --git a/graphql/codegen/src/core/codegen/cli/index.ts b/graphql/codegen/src/core/codegen/cli/index.ts index 5acbe7e21..4a2d747a4 100644 --- a/graphql/codegen/src/core/codegen/cli/index.ts +++ b/graphql/codegen/src/core/codegen/cli/index.ts @@ -11,7 +11,7 @@ import { generateMultiTargetContextCommand, } from './infra-generator'; import { generateTableCommand } from './table-command-generator'; -import { generateUtilsFile, generateNodeFetchFile } from './utils-generator'; +import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile } from './utils-generator'; export interface GenerateCliOptions { tables: CleanTable[]; @@ -91,6 +91,13 @@ export function generateCli(options: GenerateCliOptions): GenerateCliResult { ); files.push(commandMapFile); + // Generate entry point if configured + const generateEntryPoint = + typeof cliConfig === 'object' && !!cliConfig.entryPoint; + if (generateEntryPoint) { + files.push(generateEntryPointFile()); + } + return { files, stats: { @@ -123,6 +130,8 @@ export interface GenerateMultiTargetCliOptions { targets: MultiTargetCliTarget[]; /** Enable NodeHttpAdapter for *.localhost subdomain routing */ nodeHttpAdapter?: boolean; + /** Generate a runnable index.ts entry point */ + entryPoint?: boolean; } export function resolveBuiltinNames( @@ -232,6 +241,11 @@ export function generateMultiTargetCli( }); files.push(commandMapFile); + // Generate entry point if configured + if (options.entryPoint) { + files.push(generateEntryPointFile()); + } + return { files, stats: { @@ -267,5 +281,5 @@ export { export type { MultiTargetDocsInput } from './docs-generator'; export { resolveDocsConfig } from '../docs-utils'; export type { GeneratedDocFile, McpTool } from '../docs-utils'; -export { generateUtilsFile } from './utils-generator'; +export { generateUtilsFile, generateEntryPointFile } from './utils-generator'; export type { GeneratedFile, MultiTargetExecutorInput } from './executor-generator'; diff --git a/graphql/codegen/src/core/codegen/cli/utils-generator.ts b/graphql/codegen/src/core/codegen/cli/utils-generator.ts index a669132cb..5eb59fffc 100644 --- a/graphql/codegen/src/core/codegen/cli/utils-generator.ts +++ b/graphql/codegen/src/core/codegen/cli/utils-generator.ts @@ -76,3 +76,21 @@ export function generateNodeFetchFile(): GeneratedFile { ), }; } + +/** + * Generate an index.ts entry point file for the CLI. + * + * Creates a runnable entry point that imports the command map, + * handles --version and --tty flags, and starts the CLI. + * This is off by default (cliEntryPoint: false) since many projects + * provide their own entry point with custom configuration. + */ +export function generateEntryPointFile(): GeneratedFile { + return { + fileName: 'index.ts', + content: readTemplateFile( + 'cli-entry.ts', + 'CLI entry point', + ), + }; +} diff --git a/graphql/codegen/src/core/codegen/templates/cli-entry.ts b/graphql/codegen/src/core/codegen/templates/cli-entry.ts new file mode 100644 index 000000000..b0a68394c --- /dev/null +++ b/graphql/codegen/src/core/codegen/templates/cli-entry.ts @@ -0,0 +1,33 @@ +/** + * CLI entry point for running the generated CLI application. + * + * Creates an inquirerer CLI instance with the generated command map, + * handles --version and --tty flags, and runs the CLI. + * + * NOTE: This file is read at codegen time and written to output. + * Any changes here will affect all generated CLI entry points. + */ + +import { CLI, CLIOptions, getPackageJson } from 'inquirerer'; +import { commands } from './commands'; + +if (process.argv.includes('--version') || process.argv.includes('-v')) { + const pkg = getPackageJson(__dirname); + console.log(pkg.version); + process.exit(0); +} + +// Check for --tty false to enable non-interactive mode (noTty) +const ttyIdx = process.argv.indexOf('--tty'); +const noTty = ttyIdx !== -1 && process.argv[ttyIdx + 1] === 'false'; + +const options: Partial = { + noTty, + minimistOpts: { alias: { v: 'version', h: 'help' } }, +}; + +const app = new CLI(commands, options); +app.run().catch((e) => { + console.error('Unexpected error:', e); + process.exit(1); +}); diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index f8fb73179..a61344bdb 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -696,6 +696,7 @@ export async function generateMulti( builtinNames: cliConfig.builtinNames, targets: cliTargets, nodeHttpAdapter: multiNodeHttpAdapter, + entryPoint: cliConfig.entryPoint, }); const cliFilesToWrite = files.map((file) => ({ diff --git a/graphql/codegen/src/types/config.ts b/graphql/codegen/src/types/config.ts index 7f572a564..aadc50bb8 100644 --- a/graphql/codegen/src/types/config.ts +++ b/graphql/codegen/src/types/config.ts @@ -199,6 +199,15 @@ export interface CliConfig { * context -> 'context' (renamed to 'env' on collision) */ builtinNames?: BuiltinNames; + + /** + * Generate a runnable index.ts entry point for the CLI. + * When true, generates an index.ts that imports the command map, + * handles --version and --tty flags, and starts the inquirerer CLI. + * Useful for projects that want a ready-to-run CLI without a custom entry point. + * @default false + */ + entryPoint?: boolean; } /**