From 54079fccac6c11e18312421dbcacf822399df0f5 Mon Sep 17 00:00:00 2001 From: jlenon7 Date: Fri, 5 Jan 2024 23:23:46 +0000 Subject: [PATCH] feat(option): add isFromGlobal option --- package-lock.json | 4 +-- package.json | 2 +- src/annotations/Option.ts | 2 +- src/artisan/ArtisanImpl.ts | 2 +- src/artisan/BaseCommand.ts | 1 - src/handlers/CommanderHandler.ts | 32 ++++++++++++++------- src/types/OptionOptions.ts | 2 +- tests/fixtures/GlobalAnnotatedCommand.ts | 26 +++++++++++++++++ tests/unit/annotations/OptionTest.ts | 13 ++++++--- tests/unit/artisan/ArtisanTest.ts | 14 +++++++++ tests/unit/handlers/CommanderHandlerTest.ts | 2 +- 11 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 tests/fixtures/GlobalAnnotatedCommand.ts diff --git a/package-lock.json b/package-lock.json index 89ed0be..530904f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@athenna/artisan", - "version": "4.21.0", + "version": "4.23.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@athenna/artisan", - "version": "4.21.0", + "version": "4.23.0", "license": "MIT", "dependencies": { "chalk-rainbow": "^1.0.0", diff --git a/package.json b/package.json index 4f59d10..b33cbb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/artisan", - "version": "4.22.0", + "version": "4.23.0", "description": "The Athenna CLI application. Built on top of commander and inspired in @adonisjs/ace.", "license": "MIT", "author": "João Lenon ", diff --git a/src/annotations/Option.ts b/src/annotations/Option.ts index b634b8c..5cd0b86 100644 --- a/src/annotations/Option.ts +++ b/src/annotations/Option.ts @@ -21,7 +21,7 @@ export function Option(options?: OptionOptions): PropertyDecorator { key = key.toString() options = Options.create(options, { - isGlobal: false, + isFromGlobal: false, signature: `--${String.toDashCase(key)}` }) diff --git a/src/artisan/ArtisanImpl.ts b/src/artisan/ArtisanImpl.ts index 58cf8a8..ac9adf6 100644 --- a/src/artisan/ArtisanImpl.ts +++ b/src/artisan/ArtisanImpl.ts @@ -40,7 +40,7 @@ export class ArtisanImpl { /** Set options */ Annotation.getOptions(command).forEach(option => { - if (option.isGlobal) { + if (option.isFromGlobal) { return } diff --git a/src/artisan/BaseCommand.ts b/src/artisan/BaseCommand.ts index 5f3a7a4..ffc94ba 100644 --- a/src/artisan/BaseCommand.ts +++ b/src/artisan/BaseCommand.ts @@ -94,7 +94,6 @@ export abstract class BaseCommand { argsMeta.forEach(arg => (this[arg.key] = args.shift())) optsMeta.forEach(opt => (this[opt.key] = optsValues[opt.signatureName])) - // TODO test if handle will receive the args properly return this.handle(...args) } diff --git a/src/handlers/CommanderHandler.ts b/src/handlers/CommanderHandler.ts index f6bae3a..ae4659c 100644 --- a/src/handlers/CommanderHandler.ts +++ b/src/handlers/CommanderHandler.ts @@ -20,19 +20,19 @@ export class CommanderHandler { /** * The commander instance. */ - public static commander = new Commander() + public static commander = this.instantiate() /** - * Simple helper to reconstruct the commander instance. + * Get a new commander instance with default options. */ - public static reconstruct(): void { - CommanderHandler.commander = new Commander() + public static instantiate() { + return new Commander() .addHelpCommand('help [command]', 'Display help for [command]') .usage('[command] [arguments] [options]') .option( - '--env', + '--env ', 'The environment the command should run under.', - Env('APP_ENV') + Env('APP_ENV') || Env('NODE_ENV', 'local') ) .configureHelp({ sortSubcommands: true, @@ -49,6 +49,13 @@ export class CommanderHandler { }) } + /** + * Simple helper to reconstruct the commander instance. + */ + public static reconstruct(): void { + CommanderHandler.commander = this.instantiate() + } + /** * Parse the command called in the console and execute. */ @@ -81,14 +88,19 @@ export class CommanderHandler { } if (version) { - CommanderHandler.commander.version(version, '-v, --version') + CommanderHandler.commander.version( + version, + '-v, --version', + 'Output the application version.' + ) return this } CommanderHandler.commander.version( 'Athenna Framework v3.0.0', - '-v, --version' + '-v, --version', + 'Output the framework version.' ) return this @@ -116,9 +128,9 @@ export class CommanderHandler { * Get the option values of a command. */ public static getCommandOptsValues(name: string): OptionValues { - const commander: any = this.getCommand(name) + const commander = this.getCommand(name) - return commander.opts() + return commander.optsWithGlobals() } /** diff --git a/src/types/OptionOptions.ts b/src/types/OptionOptions.ts index caa57d4..6113d43 100644 --- a/src/types/OptionOptions.ts +++ b/src/types/OptionOptions.ts @@ -10,6 +10,6 @@ export type OptionOptions = { signature?: string default?: any - isGlobal?: boolean + isFromGlobal?: boolean description?: string } diff --git a/tests/fixtures/GlobalAnnotatedCommand.ts b/tests/fixtures/GlobalAnnotatedCommand.ts new file mode 100644 index 0000000..dd9f094 --- /dev/null +++ b/tests/fixtures/GlobalAnnotatedCommand.ts @@ -0,0 +1,26 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Option, BaseCommand } from '#src' +import { FixtureDatabase } from './FixtureDatabase.js' + +export class GlobalAnnotatedCommand extends BaseCommand { + @Option({ isFromGlobal: true, signature: '--env ' }) + public env: string + + public static signature() { + return 'globalAnnotated' + } + + public async handle() { + FixtureDatabase.set('globalAnnotated:command', this.env) + } +} + +export const globalAnnotatedCommand = new GlobalAnnotatedCommand() diff --git a/tests/unit/annotations/OptionTest.ts b/tests/unit/annotations/OptionTest.ts index ef8d0d1..8fe8d82 100644 --- a/tests/unit/annotations/OptionTest.ts +++ b/tests/unit/annotations/OptionTest.ts @@ -18,17 +18,22 @@ export default class OptionTest extends BaseTest { const opts = Reflect.getMetadata(OPTIONS_KEY, annotatedCommand) - assert.deepEqual(opts[0], { key: 'withName', isGlobal: false, signature: '--with-name', signatureName: 'withName' }) + assert.deepEqual(opts[0], { + key: 'withName', + isFromGlobal: false, + signature: '--with-name', + signatureName: 'withName' + }) assert.deepEqual(opts[1], { key: 'withAge', - isGlobal: false, + isFromGlobal: false, signature: '--with-age', signatureName: 'withAge', description: 'Add the age of the person' }) assert.deepEqual(opts[2], { default: true, - isGlobal: false, + isFromGlobal: false, key: 'withEmail', signatureName: 'addEmail', signature: '-am, --add-email', @@ -36,7 +41,7 @@ export default class OptionTest extends BaseTest { }) assert.deepEqual(opts[3], { key: 'withFoo', - isGlobal: false, + isFromGlobal: false, default: false, signature: '--no-foo', signatureName: 'foo' diff --git a/tests/unit/artisan/ArtisanTest.ts b/tests/unit/artisan/ArtisanTest.ts index d831374..6670a61 100644 --- a/tests/unit/artisan/ArtisanTest.ts +++ b/tests/unit/artisan/ArtisanTest.ts @@ -197,4 +197,18 @@ export default class ArtisanTest extends BaseTest { assert.isTrue(FixtureDatabase.has('simple:command')) } + + @Test() + public async shouldBeAbleToRegisterAnArtisanCommandWithGlobalOptions({ assert }: Context) { + const { GlobalAnnotatedCommand } = await this.import('#tests/fixtures/GlobalAnnotatedCommand') + + Artisan.register(GlobalAnnotatedCommand) + + const opts = CommanderHandler.getCommandOpts(GlobalAnnotatedCommand.signature()) + + await Artisan.parse(['node', 'artisan', 'globalAnnotated']) + + assert.isEmpty(opts) + assert.deepEqual(FixtureDatabase.get('globalAnnotated:command'), 'local') + } } diff --git a/tests/unit/handlers/CommanderHandlerTest.ts b/tests/unit/handlers/CommanderHandlerTest.ts index 2233f61..cd9c2cc 100644 --- a/tests/unit/handlers/CommanderHandlerTest.ts +++ b/tests/unit/handlers/CommanderHandlerTest.ts @@ -133,7 +133,7 @@ export default class CommanderHandlerTest { .action(() => { const opts = CommanderHandler.getCommandOptsValues('test') - assert.deepEqual(opts, { age: true }) + assert.deepEqual(opts, { age: true, env: 'local' }) }) await CommanderHandler.parse(['node', 'artisan', 'test', 'João Lenon', '--age'])