From afe647a81b3187d69141af431db0ba6ebfae1982 Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Tue, 29 Oct 2024 10:20:17 -0400 Subject: [PATCH] update to use commander at the tree level Signed-off-by: aramissennyeydd --- packages/cli/src/modules/config/alpha.ts | 26 ++++--- packages/cli/src/wiring/CliInitializer.ts | 83 +++++++++-------------- 2 files changed, 44 insertions(+), 65 deletions(-) diff --git a/packages/cli/src/modules/config/alpha.ts b/packages/cli/src/modules/config/alpha.ts index 0caad2afee..4ced91e6b2 100644 --- a/packages/cli/src/modules/config/alpha.ts +++ b/packages/cli/src/modules/config/alpha.ts @@ -15,6 +15,8 @@ */ import { createCliPlugin } from '../../wiring/factory'; import yargs from 'yargs'; +import { Command } from 'commander'; +import { lazy } from '../../lib/lazy'; export default createCliPlugin({ pluginId: 'config', @@ -23,21 +25,17 @@ export default createCliPlugin({ path: ['config:docs'], description: 'Browse the configuration reference documentation', execute: async ({ args }) => { - await yargs - .options({ - package: { type: 'string' }, - }) - .command( - '$0', - '', - async () => {}, - async argv => { - const m = await import('./commands/docs'); - await m.default(argv); - }, + console.log(args); + const command = new Command(); + const defaultCommand = command + .option( + '--package ', + 'Only include the schema that applies to the given package', ) - .help() - .parse(args); + .description('Browse the configuration reference documentation') + .action(lazy(() => import('./commands/docs').then(m => m.default))); + + await defaultCommand.parseAsync(args, { from: 'user' }); }, }); reg.addCommand({ diff --git a/packages/cli/src/wiring/CliInitializer.ts b/packages/cli/src/wiring/CliInitializer.ts index 7eeaca83cd..c52e8c313d 100644 --- a/packages/cli/src/wiring/CliInitializer.ts +++ b/packages/cli/src/wiring/CliInitializer.ts @@ -14,25 +14,15 @@ * limitations under the License. */ -import yargs from 'yargs'; import { CommandGraph } from './CommandGraph'; import { CliFeature, InternalCliFeature, InternalCliPlugin } from './types'; import { CommandRegistry } from './CommandRegistry'; +import { program } from 'commander'; +import { version } from '../lib/version'; +import chalk from 'chalk'; type UninitializedFeature = CliFeature | Promise; -function checkCommands( - nestedYargs: yargs.Argv, - argv: Awaited, - numRequired: number, -) { - if (argv._.length < numRequired) { - nestedYargs.showHelp(); - } else { - // check for unknown command - } -} - export class CliInitializer { private graph = new CommandGraph(); private commandRegistry = new CommandRegistry(this.graph); @@ -62,61 +52,52 @@ export class CliInitializer { */ async run() { await this.#doInit(); - - const root = yargs.usage('usage: $0 ').wrap(null).help('help'); - const rootArgv = process.argv.slice(2); + program + .name('backstage-cli') + .version(version) + .allowUnknownOption(true) + .allowExcessArguments(true); const queue = this.graph.atDepth(0).map(node => ({ node, - argParser: root, - depth: 0, + argParser: program, })); while (queue.length) { - const { node, argParser, depth } = queue.shift()!; + const { node, argParser } = queue.shift()!; if (node.$$type === '@tree/root') { - let commandYargs = undefined; - argParser - .recommendCommands() - .demandCommand() - .command(node.name, node.name, async nestedYargs => { - commandYargs = nestedYargs; - nestedYargs.usage(`usage: $0 ${node.name}`).wrap(null).help('help'); - checkCommands( - nestedYargs, - await nestedYargs.argv, - node.children.length, - ); - }); + const treeParser = argParser + .command(`${node.name} [command]`) + .description(node.name); queue.push( ...node.children.map(child => ({ node: child, - argParser, - depth: depth + 1, + argParser: treeParser, })), ); } else { - argParser.command( - node.name, - node.command.description, - async nestedYargs => { - nestedYargs.help(false); - }, - async argv => { + argParser + .command(node.name) + .description(node.command.description) + .helpOption(false) + .allowUnknownOption(true) + .allowExcessArguments(true) + .action(async () => { await node.command.execute({ - args: process.argv.slice(2 + depth + 1), + args: program.parseOptions(process.argv).unknown, }); - checkCommands(argParser, argv, 1); - }, - ); + }); } } - const argv = await root - .demandCommand() - .recommendCommands() - .strictCommands() - .parse(rootArgv); - checkCommands(root, argv, 1); + program.on('command:*', () => { + console.log(); + console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`)); + console.log(); + program.outputHelp(); + process.exit(1); + }); + + program.parse(process.argv); } }