@navios/commander 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +24 -13
- package/dist/src/commander.application.d.mts +124 -6
- package/dist/src/commander.application.d.mts.map +1 -1
- package/dist/src/commander.factory.d.mts +31 -3
- package/dist/src/commander.factory.d.mts.map +1 -1
- package/dist/src/decorators/cli-module.decorator.d.mts +36 -1
- package/dist/src/decorators/cli-module.decorator.d.mts.map +1 -1
- package/dist/src/decorators/command.decorator.d.mts +44 -1
- package/dist/src/decorators/command.decorator.d.mts.map +1 -1
- package/dist/src/index.d.mts +1 -1
- package/dist/src/index.d.mts.map +1 -1
- package/dist/src/interfaces/command-handler.interface.d.mts +33 -0
- package/dist/src/interfaces/command-handler.interface.d.mts.map +1 -1
- package/dist/src/interfaces/commander-execution-context.interface.d.mts +43 -0
- package/dist/src/interfaces/commander-execution-context.interface.d.mts.map +1 -1
- package/dist/src/interfaces/index.d.mts +0 -1
- package/dist/src/interfaces/index.d.mts.map +1 -1
- package/dist/src/interfaces/module.interface.d.mts +1 -4
- package/dist/src/interfaces/module.interface.d.mts.map +1 -1
- package/dist/src/metadata/cli-module.metadata.d.mts +46 -1
- package/dist/src/metadata/cli-module.metadata.d.mts.map +1 -1
- package/dist/src/metadata/command.metadata.d.mts +48 -1
- package/dist/src/metadata/command.metadata.d.mts.map +1 -1
- package/dist/src/services/cli-parser.service.d.mts +32 -1
- package/dist/src/services/cli-parser.service.d.mts.map +1 -1
- package/dist/src/services/module-loader.service.d.mts +44 -5
- package/dist/src/services/module-loader.service.d.mts.map +1 -1
- package/dist/src/tokens/execution-context.token.d.mts +25 -3
- package/dist/src/tokens/execution-context.token.d.mts.map +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsdown.config.d.mts +3 -0
- package/dist/tsdown.config.d.mts.map +1 -0
- package/lib/index.cjs +7721 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +670 -0
- package/lib/index.d.cts.map +1 -0
- package/lib/index.d.mts +670 -101
- package/lib/index.d.mts.map +1 -0
- package/lib/index.mjs +7509 -598
- package/lib/index.mjs.map +1 -1
- package/package.json +5 -5
- package/project.json +2 -2
- package/src/commander.application.mts +138 -18
- package/src/commander.factory.mts +32 -4
- package/src/decorators/cli-module.decorator.mts +37 -2
- package/src/decorators/command.decorator.mts +45 -2
- package/src/index.mts +4 -1
- package/src/interfaces/command-handler.interface.mts +33 -0
- package/src/interfaces/commander-execution-context.interface.mts +43 -0
- package/src/interfaces/index.mts +0 -1
- package/src/metadata/cli-module.metadata.mts +48 -7
- package/src/metadata/command.metadata.mts +48 -1
- package/src/services/__tests__/cli-parser.service.spec.mts +15 -11
- package/src/services/cli-parser.service.mts +35 -3
- package/src/services/module-loader.service.mts +45 -6
- package/src/tokens/execution-context.token.mts +29 -5
- package/tsdown.config.mts +33 -0
- package/lib/_tsup-dts-rollup.d.mts +0 -489
- package/lib/_tsup-dts-rollup.d.ts +0 -489
- package/lib/index.d.ts +0 -101
- package/lib/index.js +0 -642
- package/lib/index.js.map +0 -1
- package/src/interfaces/module.interface.mts +0 -4
- package/tsup.config.mts +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navios/commander",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Oleksandr Hanzha",
|
|
6
6
|
"email": "alex@granted.name"
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"tsx": "^4.
|
|
34
|
-
"typescript": "^5.9.
|
|
35
|
-
"zod": "^4.1.
|
|
33
|
+
"tsx": "^4.21.0",
|
|
34
|
+
"typescript": "^5.9.3",
|
|
35
|
+
"zod": "^4.1.13"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@navios/di": "^0.
|
|
38
|
+
"@navios/di": "^0.6.0"
|
|
39
39
|
}
|
|
40
40
|
}
|
package/project.json
CHANGED
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
},
|
|
39
39
|
"build": {
|
|
40
40
|
"executor": "nx:run-commands",
|
|
41
|
-
"inputs": ["projectSources", "{projectRoot}/
|
|
41
|
+
"inputs": ["projectSources", "{projectRoot}/tsdown.config.mts"],
|
|
42
42
|
"outputs": ["{projectRoot}/lib"],
|
|
43
43
|
"dependsOn": ["check", "test:ci", "lint"],
|
|
44
44
|
"options": {
|
|
45
|
-
"command": "
|
|
45
|
+
"command": "tsdown",
|
|
46
46
|
"cwd": "packages/commander"
|
|
47
47
|
}
|
|
48
48
|
},
|
|
@@ -1,38 +1,94 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ClassTypeWithInstance,
|
|
3
|
+
InjectionToken,
|
|
4
|
+
NaviosModule,
|
|
5
|
+
} from '@navios/core'
|
|
2
6
|
|
|
3
|
-
import { Container, inject, Injectable } from '@navios/
|
|
7
|
+
import { Container, inject, Injectable } from '@navios/core'
|
|
4
8
|
|
|
5
|
-
import type { CommandHandler
|
|
9
|
+
import type { CommandHandler } from './interfaces/index.mjs'
|
|
6
10
|
|
|
7
11
|
import { CommanderExecutionContext } from './interfaces/index.mjs'
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
12
|
+
import { CliModuleLoaderService, CliParserService } from './services/index.mjs'
|
|
13
|
+
import { CommandExecutionContext } from './tokens/index.mjs'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration options for CommanderApplication.
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
11
20
|
export interface CommanderApplicationOptions {}
|
|
12
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Main application class for managing CLI command execution.
|
|
24
|
+
*
|
|
25
|
+
* This class handles module loading, command registration, and command execution.
|
|
26
|
+
* It provides both programmatic and CLI-based command execution capabilities.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const app = await CommanderFactory.create(AppModule)
|
|
31
|
+
* await app.init()
|
|
32
|
+
* await app.run(process.argv)
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
13
35
|
@Injectable()
|
|
14
36
|
export class CommanderApplication {
|
|
15
|
-
private moduleLoader = inject(
|
|
37
|
+
private moduleLoader = inject(CliModuleLoaderService)
|
|
16
38
|
private cliParser = inject(CliParserService)
|
|
17
39
|
protected container = inject(Container)
|
|
18
40
|
|
|
19
|
-
private appModule: ClassTypeWithInstance<
|
|
41
|
+
private appModule: ClassTypeWithInstance<NaviosModule> | null = null
|
|
20
42
|
private options: CommanderApplicationOptions = {}
|
|
21
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Indicates whether the application has been initialized.
|
|
46
|
+
* Set to `true` after `init()` is called successfully.
|
|
47
|
+
*/
|
|
22
48
|
isInitialized = false
|
|
23
49
|
|
|
50
|
+
/**
|
|
51
|
+
* @internal
|
|
52
|
+
* Sets up the application with the provided module and options.
|
|
53
|
+
* This is called automatically by CommanderFactory.create().
|
|
54
|
+
*/
|
|
24
55
|
async setup(
|
|
25
|
-
appModule: ClassTypeWithInstance<
|
|
56
|
+
appModule: ClassTypeWithInstance<NaviosModule>,
|
|
26
57
|
options: CommanderApplicationOptions = {},
|
|
27
58
|
) {
|
|
28
59
|
this.appModule = appModule
|
|
29
60
|
this.options = options
|
|
30
61
|
}
|
|
31
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Gets the dependency injection container used by this application.
|
|
65
|
+
*
|
|
66
|
+
* @returns The Container instance
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const container = app.getContainer()
|
|
71
|
+
* const service = await container.get(MyService)
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
32
74
|
getContainer() {
|
|
33
75
|
return this.container
|
|
34
76
|
}
|
|
35
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Initializes the application by loading all modules and registering commands.
|
|
80
|
+
*
|
|
81
|
+
* This method must be called before executing commands or running the CLI.
|
|
82
|
+
* It traverses the module tree, loads all imported modules, and collects command metadata.
|
|
83
|
+
*
|
|
84
|
+
* @throws {Error} If the app module is not set (setup() was not called)
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const app = await CommanderFactory.create(AppModule)
|
|
89
|
+
* await app.init() // Must be called before run() or executeCommand()
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
36
92
|
async init() {
|
|
37
93
|
if (!this.appModule) {
|
|
38
94
|
throw new Error(
|
|
@@ -43,6 +99,27 @@ export class CommanderApplication {
|
|
|
43
99
|
this.isInitialized = true
|
|
44
100
|
}
|
|
45
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Executes a command programmatically with the provided options.
|
|
104
|
+
*
|
|
105
|
+
* This method is useful for testing, automation, or programmatic workflows.
|
|
106
|
+
* The options will be validated against the command's Zod schema if one is provided.
|
|
107
|
+
*
|
|
108
|
+
* @param commandPath - The command path (e.g., 'greet', 'user:create')
|
|
109
|
+
* @param options - The command options object (will be validated if schema exists)
|
|
110
|
+
* @throws {Error} If the application is not initialized
|
|
111
|
+
* @throws {Error} If the command is not found
|
|
112
|
+
* @throws {Error} If the command does not implement the execute method
|
|
113
|
+
* @throws {ZodError} If options validation fails
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* await app.executeCommand('greet', {
|
|
118
|
+
* name: 'World',
|
|
119
|
+
* greeting: 'Hi'
|
|
120
|
+
* })
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
46
123
|
async executeCommand(commandPath: string, options: any = {}) {
|
|
47
124
|
if (!this.isInitialized) {
|
|
48
125
|
throw new Error(
|
|
@@ -76,15 +153,12 @@ export class CommanderApplication {
|
|
|
76
153
|
const requestId = `cmd-${Date.now()}-${Math.random().toString(36).substring(7)}`
|
|
77
154
|
|
|
78
155
|
// Begin request context and add ExecutionContext
|
|
79
|
-
const
|
|
80
|
-
|
|
156
|
+
const scopeContainer = this.container.beginRequest(requestId)
|
|
157
|
+
scopeContainer.addInstance(CommandExecutionContext, executionContext)
|
|
81
158
|
|
|
82
159
|
try {
|
|
83
|
-
// Set current request context
|
|
84
|
-
this.container.setCurrentRequestContext(requestId)
|
|
85
|
-
|
|
86
160
|
// Get command instance and execute
|
|
87
|
-
const commandInstance = await
|
|
161
|
+
const commandInstance = await scopeContainer.get<CommandHandler>(
|
|
88
162
|
commandClass as unknown as InjectionToken<CommandHandler>,
|
|
89
163
|
)
|
|
90
164
|
|
|
@@ -97,10 +171,23 @@ export class CommanderApplication {
|
|
|
97
171
|
await commandInstance.execute(validatedOptions)
|
|
98
172
|
} finally {
|
|
99
173
|
// Clean up request context
|
|
100
|
-
await
|
|
174
|
+
await scopeContainer.endRequest()
|
|
101
175
|
}
|
|
102
176
|
}
|
|
103
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Gets all registered commands with their paths and class references.
|
|
180
|
+
*
|
|
181
|
+
* @returns An array of objects containing the command path and class
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const commands = app.getAllCommands()
|
|
186
|
+
* commands.forEach(({ path }) => {
|
|
187
|
+
* console.log(`Available: ${path}`)
|
|
188
|
+
* })
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
104
191
|
getAllCommands() {
|
|
105
192
|
// Use pre-collected command metadata from module loading
|
|
106
193
|
const commandsMap = this.moduleLoader.getAllCommandsWithMetadata()
|
|
@@ -120,8 +207,26 @@ export class CommanderApplication {
|
|
|
120
207
|
}
|
|
121
208
|
|
|
122
209
|
/**
|
|
123
|
-
* Runs the CLI application by parsing
|
|
124
|
-
*
|
|
210
|
+
* Runs the CLI application by parsing command-line arguments and executing the appropriate command.
|
|
211
|
+
*
|
|
212
|
+
* This is the main entry point for CLI usage. It parses `argv`, validates options,
|
|
213
|
+
* and executes the matching command. Supports help command (`help`, `--help`, `-h`)
|
|
214
|
+
* which displays all available commands.
|
|
215
|
+
*
|
|
216
|
+
* @param argv - Command-line arguments array (defaults to `process.argv`)
|
|
217
|
+
* @throws {Error} If the application is not initialized
|
|
218
|
+
* @throws {Error} If no command is provided
|
|
219
|
+
* @throws {Error} If the command is not found
|
|
220
|
+
* @throws {ZodError} If options validation fails
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* // Parse and execute from process.argv
|
|
225
|
+
* await app.run()
|
|
226
|
+
*
|
|
227
|
+
* // Or provide custom arguments
|
|
228
|
+
* await app.run(['node', 'cli.js', 'greet', '--name', 'World'])
|
|
229
|
+
* ```
|
|
125
230
|
*/
|
|
126
231
|
async run(argv: string[] = process.argv) {
|
|
127
232
|
if (!this.isInitialized) {
|
|
@@ -171,12 +276,27 @@ export class CommanderApplication {
|
|
|
171
276
|
}
|
|
172
277
|
}
|
|
173
278
|
|
|
279
|
+
/**
|
|
280
|
+
* @internal
|
|
281
|
+
* Disposes of resources used by the application.
|
|
282
|
+
*/
|
|
174
283
|
async dispose() {
|
|
175
284
|
if (this.moduleLoader) {
|
|
176
285
|
this.moduleLoader.dispose()
|
|
177
286
|
}
|
|
178
287
|
}
|
|
179
288
|
|
|
289
|
+
/**
|
|
290
|
+
* Closes the application and cleans up resources.
|
|
291
|
+
*
|
|
292
|
+
* This should be called when the application is no longer needed to free up resources.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* await app.run(process.argv)
|
|
297
|
+
* await app.close()
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
180
300
|
async close() {
|
|
181
301
|
await this.dispose()
|
|
182
302
|
}
|
|
@@ -1,15 +1,43 @@
|
|
|
1
|
-
import type { ClassTypeWithInstance } from '@navios/
|
|
1
|
+
import type { ClassTypeWithInstance, NaviosModule } from '@navios/core'
|
|
2
2
|
|
|
3
|
-
import { Container } from '@navios/
|
|
3
|
+
import { Container } from '@navios/core'
|
|
4
4
|
|
|
5
5
|
import type { CommanderApplicationOptions } from './commander.application.mjs'
|
|
6
|
-
import type { Module } from './interfaces/index.mjs'
|
|
7
6
|
|
|
8
7
|
import { CommanderApplication } from './commander.application.mjs'
|
|
9
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Factory class for creating and configuring CLI applications.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { CommanderFactory } from '@navios/commander'
|
|
15
|
+
* import { AppModule } from './app.module'
|
|
16
|
+
*
|
|
17
|
+
* async function bootstrap() {
|
|
18
|
+
* const app = await CommanderFactory.create(AppModule)
|
|
19
|
+
* await app.init()
|
|
20
|
+
* await app.run(process.argv)
|
|
21
|
+
* await app.close()
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
10
25
|
export class CommanderFactory {
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new CommanderApplication instance and configures it with the provided module.
|
|
28
|
+
*
|
|
29
|
+
* @param appModule - The root CLI module class that contains commands and/or imports other modules
|
|
30
|
+
* @param options - Optional configuration options for the application
|
|
31
|
+
* @returns A promise that resolves to a configured CommanderApplication instance
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const app = await CommanderFactory.create(AppModule)
|
|
36
|
+
* await app.init()
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
11
39
|
static async create(
|
|
12
|
-
appModule: ClassTypeWithInstance<
|
|
40
|
+
appModule: ClassTypeWithInstance<NaviosModule>,
|
|
13
41
|
options: CommanderApplicationOptions = {},
|
|
14
42
|
) {
|
|
15
43
|
const container = new Container()
|
|
@@ -1,14 +1,49 @@
|
|
|
1
|
-
import type { ClassType } from '@navios/
|
|
1
|
+
import type { ClassType } from '@navios/core'
|
|
2
2
|
|
|
3
|
-
import { Injectable, InjectableScope, InjectionToken } from '@navios/
|
|
3
|
+
import { Injectable, InjectableScope, InjectionToken } from '@navios/core'
|
|
4
4
|
|
|
5
5
|
import { getCliModuleMetadata } from '../metadata/index.mjs'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Options for the `@CliModule` decorator.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
7
12
|
export interface CliModuleOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Array or Set of command classes to register in this module.
|
|
15
|
+
* Commands must be decorated with `@Command`.
|
|
16
|
+
*/
|
|
8
17
|
commands?: ClassType[] | Set<ClassType>
|
|
18
|
+
/**
|
|
19
|
+
* Array or Set of other CLI modules to import.
|
|
20
|
+
* Imported modules' commands will be available in this module.
|
|
21
|
+
*/
|
|
9
22
|
imports?: ClassType[] | Set<ClassType>
|
|
10
23
|
}
|
|
11
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Decorator that marks a class as a CLI module.
|
|
27
|
+
*
|
|
28
|
+
* Modules organize commands and can import other modules to compose larger CLI applications.
|
|
29
|
+
* The module can optionally implement `NaviosModule` interface for lifecycle hooks.
|
|
30
|
+
*
|
|
31
|
+
* @param options - Configuration options for the module
|
|
32
|
+
* @returns A class decorator function
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { CliModule } from '@navios/commander'
|
|
37
|
+
* import { GreetCommand } from './greet.command'
|
|
38
|
+
* import { UserModule } from './user.module'
|
|
39
|
+
*
|
|
40
|
+
* @CliModule({
|
|
41
|
+
* commands: [GreetCommand],
|
|
42
|
+
* imports: [UserModule]
|
|
43
|
+
* })
|
|
44
|
+
* export class AppModule {}
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
12
47
|
export function CliModule(
|
|
13
48
|
{ commands = [], imports = [] }: CliModuleOptions = {
|
|
14
49
|
commands: [],
|
|
@@ -1,15 +1,58 @@
|
|
|
1
|
-
import type { ClassType } from '@navios/
|
|
1
|
+
import type { ClassType } from '@navios/core'
|
|
2
2
|
import type { ZodObject } from 'zod'
|
|
3
3
|
|
|
4
|
-
import { Injectable, InjectableScope, InjectionToken } from '@navios/
|
|
4
|
+
import { Injectable, InjectableScope, InjectionToken } from '@navios/core'
|
|
5
5
|
|
|
6
6
|
import { getCommandMetadata } from '../metadata/index.mjs'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Options for the `@Command` decorator.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
8
13
|
export interface CommandOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The command path that users will invoke from the CLI.
|
|
16
|
+
* Can be a single word (e.g., 'greet') or multi-word with colons (e.g., 'user:create', 'db:migrate').
|
|
17
|
+
*/
|
|
9
18
|
path: string
|
|
19
|
+
/**
|
|
20
|
+
* Optional Zod schema for validating command options.
|
|
21
|
+
* If provided, options will be validated and parsed according to this schema.
|
|
22
|
+
*/
|
|
10
23
|
optionsSchema?: ZodObject
|
|
11
24
|
}
|
|
12
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Decorator that marks a class as a CLI command.
|
|
28
|
+
*
|
|
29
|
+
* The decorated class must implement the `CommandHandler` interface with an `execute` method.
|
|
30
|
+
* The command will be automatically registered when its module is loaded.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Configuration options for the command
|
|
33
|
+
* @returns A class decorator function
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { Command, CommandHandler } from '@navios/commander'
|
|
38
|
+
* import { z } from 'zod'
|
|
39
|
+
*
|
|
40
|
+
* const optionsSchema = z.object({
|
|
41
|
+
* name: z.string(),
|
|
42
|
+
* greeting: z.string().optional().default('Hello')
|
|
43
|
+
* })
|
|
44
|
+
*
|
|
45
|
+
* @Command({
|
|
46
|
+
* path: 'greet',
|
|
47
|
+
* optionsSchema: optionsSchema
|
|
48
|
+
* })
|
|
49
|
+
* export class GreetCommand implements CommandHandler<z.infer<typeof optionsSchema>> {
|
|
50
|
+
* async execute(options) {
|
|
51
|
+
* console.log(`${options.greeting}, ${options.name}!`)
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
13
56
|
export function Command({ path, optionsSchema }: CommandOptions) {
|
|
14
57
|
return function (target: ClassType, context: ClassDecoratorContext) {
|
|
15
58
|
if (context.kind !== 'class') {
|
package/src/index.mts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
// Re-export DI types and values that users might need
|
|
2
|
+
export * from '@navios/core'
|
|
3
|
+
|
|
4
|
+
// Export commander-specific exports
|
|
2
5
|
export * from './commander.application.mjs'
|
|
3
6
|
export * from './commander.factory.mjs'
|
|
4
7
|
export * from './decorators/index.mjs'
|
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface that all command classes must implement.
|
|
3
|
+
*
|
|
4
|
+
* Commands decorated with `@Command` must implement this interface.
|
|
5
|
+
* The `execute` method is called when the command is invoked.
|
|
6
|
+
*
|
|
7
|
+
* @template TOptions - The type of options that the command accepts
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { Command, CommandHandler } from '@navios/commander'
|
|
12
|
+
* import { z } from 'zod'
|
|
13
|
+
*
|
|
14
|
+
* const optionsSchema = z.object({
|
|
15
|
+
* name: z.string()
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* type Options = z.infer<typeof optionsSchema>
|
|
19
|
+
*
|
|
20
|
+
* @Command({ path: 'greet', optionsSchema })
|
|
21
|
+
* export class GreetCommand implements CommandHandler<Options> {
|
|
22
|
+
* async execute(options: Options) {
|
|
23
|
+
* console.log(`Hello, ${options.name}!`)
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
1
28
|
export interface CommandHandler<TOptions = any> {
|
|
29
|
+
/**
|
|
30
|
+
* Executes the command with the provided options.
|
|
31
|
+
*
|
|
32
|
+
* @param options - The validated command options (validated against the command's schema if provided)
|
|
33
|
+
* @returns A promise or void
|
|
34
|
+
*/
|
|
2
35
|
execute(options: TOptions): void | Promise<void>
|
|
3
36
|
}
|
|
@@ -1,20 +1,63 @@
|
|
|
1
1
|
import type { CommandMetadata } from '../metadata/command.metadata.mjs'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Execution context for a command execution.
|
|
5
|
+
*
|
|
6
|
+
* Provides access to command metadata, path, and validated options during command execution.
|
|
7
|
+
* This context is automatically injected and available via the `CommandExecutionContext` token.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { inject, Injectable } from '@navios/di'
|
|
12
|
+
* import { CommandExecutionContext } from '@navios/commander'
|
|
13
|
+
*
|
|
14
|
+
* @Injectable()
|
|
15
|
+
* class CommandLogger {
|
|
16
|
+
* private ctx = inject(CommandExecutionContext)
|
|
17
|
+
*
|
|
18
|
+
* log() {
|
|
19
|
+
* console.log('Command:', this.ctx.getCommandPath())
|
|
20
|
+
* console.log('Options:', this.ctx.getOptions())
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
3
25
|
export class CommanderExecutionContext {
|
|
26
|
+
/**
|
|
27
|
+
* @internal
|
|
28
|
+
* Creates a new execution context.
|
|
29
|
+
*/
|
|
4
30
|
constructor(
|
|
5
31
|
private readonly command: CommandMetadata,
|
|
6
32
|
private readonly commandPath: string,
|
|
7
33
|
private readonly options: any,
|
|
8
34
|
) {}
|
|
9
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Gets the command metadata.
|
|
38
|
+
*
|
|
39
|
+
* @returns The command metadata including path and options schema
|
|
40
|
+
*/
|
|
10
41
|
getCommand(): CommandMetadata {
|
|
11
42
|
return this.command
|
|
12
43
|
}
|
|
13
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Gets the command path that was invoked.
|
|
47
|
+
*
|
|
48
|
+
* @returns The command path (e.g., 'greet', 'user:create')
|
|
49
|
+
*/
|
|
14
50
|
getCommandPath(): string {
|
|
15
51
|
return this.commandPath
|
|
16
52
|
}
|
|
17
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Gets the validated command options.
|
|
56
|
+
*
|
|
57
|
+
* Options are validated against the command's Zod schema if one was provided.
|
|
58
|
+
*
|
|
59
|
+
* @returns The validated options object
|
|
60
|
+
*/
|
|
18
61
|
getOptions(): any {
|
|
19
62
|
return this.options
|
|
20
63
|
}
|
package/src/interfaces/index.mts
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
import type { ClassType } from '@navios/
|
|
1
|
+
import type { ClassType } from '@navios/core'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
* Symbol key used to store CLI module metadata on classes.
|
|
6
|
+
*/
|
|
3
7
|
export const CliModuleMetadataKey = Symbol('CliModuleMetadataKey')
|
|
4
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Metadata associated with a CLI module.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
5
14
|
export interface CliModuleMetadata {
|
|
15
|
+
/**
|
|
16
|
+
* Set of command classes registered in this module.
|
|
17
|
+
*/
|
|
6
18
|
commands: Set<ClassType>
|
|
19
|
+
/**
|
|
20
|
+
* Set of other modules imported by this module.
|
|
21
|
+
*/
|
|
7
22
|
imports: Set<ClassType>
|
|
23
|
+
/**
|
|
24
|
+
* Map of custom attributes that can be attached to the module.
|
|
25
|
+
*/
|
|
8
26
|
customAttributes: Map<string | symbol, any>
|
|
9
27
|
}
|
|
10
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Gets or creates CLI module metadata for a class.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
* @param target - The module class
|
|
34
|
+
* @param context - The decorator context
|
|
35
|
+
* @returns The module metadata
|
|
36
|
+
*/
|
|
11
37
|
export function getCliModuleMetadata(
|
|
12
38
|
target: ClassType,
|
|
13
39
|
context: ClassDecoratorContext,
|
|
@@ -33,13 +59,22 @@ export function getCliModuleMetadata(
|
|
|
33
59
|
throw new Error('[Navios Commander] Wrong environment.')
|
|
34
60
|
}
|
|
35
61
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Extracts CLI module metadata from a class.
|
|
64
|
+
*
|
|
65
|
+
* @param target - The module class
|
|
66
|
+
* @returns The module metadata
|
|
67
|
+
* @throws {Error} If the class is not decorated with @CliModule
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const metadata = extractCliModuleMetadata(AppModule)
|
|
72
|
+
* console.log(metadata.commands.size) // Number of commands
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function extractCliModuleMetadata(target: ClassType): CliModuleMetadata {
|
|
39
76
|
// @ts-expect-error We add a custom metadata key to the target
|
|
40
|
-
const metadata = target[CliModuleMetadataKey] as
|
|
41
|
-
| CliModuleMetadata
|
|
42
|
-
| undefined
|
|
77
|
+
const metadata = target[CliModuleMetadataKey] as CliModuleMetadata | undefined
|
|
43
78
|
if (!metadata) {
|
|
44
79
|
throw new Error(
|
|
45
80
|
`[Navios Commander] Module metadata not found for ${target.name}. Make sure to use @CliModule decorator.`,
|
|
@@ -48,6 +83,12 @@ export function extractCliModuleMetadata(
|
|
|
48
83
|
return metadata
|
|
49
84
|
}
|
|
50
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Checks if a class has CLI module metadata.
|
|
88
|
+
*
|
|
89
|
+
* @param target - The class to check
|
|
90
|
+
* @returns `true` if the class is decorated with @CliModule, `false` otherwise
|
|
91
|
+
*/
|
|
51
92
|
export function hasCliModuleMetadata(target: ClassType): boolean {
|
|
52
93
|
// @ts-expect-error We add a custom metadata key to the target
|
|
53
94
|
return !!target[CliModuleMetadataKey]
|