UNPKG

@openapi-qraft/cli

Version:

CLI for generating typed TanStack Query React Hooks and services from OpenAPI Document, improving type safety in React apps

121 lines (102 loc) 3.64 kB
#!/usr/bin/env node import type { QraftCommandPlugin } from '@openapi-qraft/plugin/lib/QraftCommandPlugin'; import { QraftCommand } from '@openapi-qraft/plugin'; import { RedoclyConfigCommand } from '@openapi-qraft/plugin/lib/RedoclyConfigCommand'; import { Option, ParseOptions } from 'commander'; import { builtInPlugins } from './builtInPlugins.js'; export async function main( processArgv: string[], processArgvParseOptions?: ParseOptions ) { const redoclyConfigParseResult = await new RedoclyConfigCommand().parseConfig( qraft, processArgv, processArgvParseOptions ); if (redoclyConfigParseResult?.length) return; await qraft(processArgv, processArgvParseOptions); } async function qraft( processArgv: string[], processArgvParseOptions?: ParseOptions ) { const command = new QraftCommand(); const { argv, plugins } = extractArgvPluginOptions(processArgv); if (plugins) { await setupPlugins(command, plugins); } else { // Default - set up the tanstack-query-react plugin await setupPlugins(command, [ 'tanstack-query-react', ] satisfies (keyof typeof builtInPlugins)[]); // Option to display help with all available plugins command.addOption( new Option( '--plugin <name_1> --plugin <name_2>', `Specifies which generator plugins should be used for code generation` ) .choices(Object.keys(builtInPlugins)) .argParser(() => { // Fallback handler for when plugin parsing fails throw new Error( 'The plugin option must be processed before command parsing and should not be directly passed to the commander' ); }) ); } await command.parseAsync(argv, processArgvParseOptions); } async function setupPlugins(command: QraftCommand, plugins: string[]) { const pluginList: QraftCommandPlugin[] = []; for (const pluginName of plugins) { if (!(pluginName in builtInPlugins)) throw new Error(`Unknown plugin: '${pluginName}'`); pluginList.push( (await builtInPlugins[pluginName as keyof typeof builtInPlugins]()) .default ); addCommandUsageWithPlugins(command, plugins); } await Promise.all(pluginList.map((plugin) => plugin.setupCommand(command))); await Promise.all( pluginList.map((plugin) => plugin.postSetupCommand?.(command, plugins)) ); } /** * Adds plugin usage instructions by calling `command.usage(...)` */ function addCommandUsageWithPlugins(command: QraftCommand, plugins: string[]) { const pluginUsage = plugins.map((plugin) => `--plugin ${plugin}`).join(' '); command.usage(`${pluginUsage} [input] [options]`); } /** * Extracts multiple `--plugin <name>` options from `argv` * and returns both the filtered `argv` and the extracted plugins list. */ export function extractArgvPluginOptions(argv: string[]) { const pluginIndex = argv.indexOf('--plugin'); if (pluginIndex === -1) return { argv }; const filteredArgv: string[] = argv.slice(0, pluginIndex); const plugins: string[] = []; for (let i = pluginIndex; i < argv.length; i++) { if (argv[i] === '--plugin') { const pluginName = argv.at(i + 1); if (!pluginName) throw new Error( `A plugin name must be specified after the '--plugin' option` ); if (pluginName?.startsWith('--')) throw new Error( `Invalid plugin name: '${pluginName}'. Plugin names cannot start with '--'` ); plugins.push(pluginName); i++; // Skip next item } else { filteredArgv.push(argv[i]); } } return { argv: filteredArgv, plugins, }; }