@navios/commander 0.5.1 → 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.
Files changed (69) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +56 -8
  3. package/dist/src/commander.application.d.mts +124 -6
  4. package/dist/src/commander.application.d.mts.map +1 -1
  5. package/dist/src/commander.factory.d.mts +31 -3
  6. package/dist/src/commander.factory.d.mts.map +1 -1
  7. package/dist/src/decorators/cli-module.decorator.d.mts +36 -1
  8. package/dist/src/decorators/cli-module.decorator.d.mts.map +1 -1
  9. package/dist/src/decorators/command.decorator.d.mts +44 -1
  10. package/dist/src/decorators/command.decorator.d.mts.map +1 -1
  11. package/dist/src/index.d.mts +2 -1
  12. package/dist/src/index.d.mts.map +1 -1
  13. package/dist/src/interfaces/command-handler.interface.d.mts +33 -0
  14. package/dist/src/interfaces/command-handler.interface.d.mts.map +1 -1
  15. package/dist/src/interfaces/commander-execution-context.interface.d.mts +54 -0
  16. package/dist/src/interfaces/commander-execution-context.interface.d.mts.map +1 -0
  17. package/dist/src/interfaces/index.d.mts +1 -1
  18. package/dist/src/interfaces/index.d.mts.map +1 -1
  19. package/dist/src/interfaces/module.interface.d.mts +1 -4
  20. package/dist/src/interfaces/module.interface.d.mts.map +1 -1
  21. package/dist/src/metadata/cli-module.metadata.d.mts +46 -1
  22. package/dist/src/metadata/cli-module.metadata.d.mts.map +1 -1
  23. package/dist/src/metadata/command.metadata.d.mts +48 -1
  24. package/dist/src/metadata/command.metadata.d.mts.map +1 -1
  25. package/dist/src/services/cli-parser.service.d.mts +32 -1
  26. package/dist/src/services/cli-parser.service.d.mts.map +1 -1
  27. package/dist/src/services/module-loader.service.d.mts +44 -5
  28. package/dist/src/services/module-loader.service.d.mts.map +1 -1
  29. package/dist/src/tokens/execution-context.token.d.mts +27 -0
  30. package/dist/src/tokens/execution-context.token.d.mts.map +1 -0
  31. package/dist/src/tokens/index.d.mts +2 -0
  32. package/dist/src/tokens/index.d.mts.map +1 -0
  33. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/dist/tsdown.config.d.mts +3 -0
  36. package/dist/tsdown.config.d.mts.map +1 -0
  37. package/lib/index.cjs +7721 -0
  38. package/lib/index.cjs.map +1 -0
  39. package/lib/index.d.cts +670 -0
  40. package/lib/index.d.cts.map +1 -0
  41. package/lib/index.d.mts +670 -98
  42. package/lib/index.d.mts.map +1 -0
  43. package/lib/index.mjs +7511 -565
  44. package/lib/index.mjs.map +1 -1
  45. package/package.json +5 -5
  46. package/project.json +2 -2
  47. package/src/commander.application.mts +161 -17
  48. package/src/commander.factory.mts +32 -4
  49. package/src/decorators/cli-module.decorator.mts +37 -2
  50. package/src/decorators/command.decorator.mts +45 -2
  51. package/src/index.mts +5 -1
  52. package/src/interfaces/command-handler.interface.mts +33 -0
  53. package/src/interfaces/commander-execution-context.interface.mts +64 -0
  54. package/src/interfaces/index.mts +1 -1
  55. package/src/metadata/cli-module.metadata.mts +48 -7
  56. package/src/metadata/command.metadata.mts +48 -1
  57. package/src/services/__tests__/cli-parser.service.spec.mts +15 -11
  58. package/src/services/cli-parser.service.mts +35 -3
  59. package/src/services/module-loader.service.mts +45 -6
  60. package/src/tokens/execution-context.token.mts +34 -0
  61. package/src/tokens/index.mts +1 -0
  62. package/tsdown.config.mts +33 -0
  63. package/lib/_tsup-dts-rollup.d.mts +0 -466
  64. package/lib/_tsup-dts-rollup.d.ts +0 -466
  65. package/lib/index.d.ts +0 -98
  66. package/lib/index.js +0 -604
  67. package/lib/index.js.map +0 -1
  68. package/src/interfaces/module.interface.mts +0 -4
  69. package/tsup.config.mts +0 -12
@@ -1,14 +1,42 @@
1
- import type { ClassType } from '@navios/di'
1
+ import type { ClassType } from '@navios/core'
2
2
  import type { ZodObject } from 'zod'
3
3
 
4
+ /**
5
+ * @internal
6
+ * Symbol key used to store command metadata on classes.
7
+ */
4
8
  export const CommandMetadataKey = Symbol('CommandMetadataKey')
5
9
 
10
+ /**
11
+ * Metadata associated with a command.
12
+ *
13
+ * @public
14
+ */
6
15
  export interface CommandMetadata {
16
+ /**
17
+ * The command path (e.g., 'greet', 'user:create').
18
+ */
7
19
  path: string
20
+ /**
21
+ * Optional Zod schema for validating command options.
22
+ */
8
23
  optionsSchema?: ZodObject
24
+ /**
25
+ * Map of custom attributes that can be attached to the command.
26
+ */
9
27
  customAttributes: Map<string | symbol, any>
10
28
  }
11
29
 
30
+ /**
31
+ * Gets or creates command metadata for a class.
32
+ *
33
+ * @internal
34
+ * @param target - The command class
35
+ * @param context - The decorator context
36
+ * @param path - The command path
37
+ * @param optionsSchema - Optional Zod schema
38
+ * @returns The command metadata
39
+ */
12
40
  export function getCommandMetadata(
13
41
  target: ClassType,
14
42
  context: ClassDecoratorContext,
@@ -36,6 +64,19 @@ export function getCommandMetadata(
36
64
  throw new Error('[Navios Commander] Wrong environment.')
37
65
  }
38
66
 
67
+ /**
68
+ * Extracts command metadata from a class.
69
+ *
70
+ * @param target - The command class
71
+ * @returns The command metadata
72
+ * @throws {Error} If the class is not decorated with @Command
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const metadata = extractCommandMetadata(GreetCommand)
77
+ * console.log(metadata.path) // 'greet'
78
+ * ```
79
+ */
39
80
  export function extractCommandMetadata(target: ClassType): CommandMetadata {
40
81
  // @ts-expect-error We add a custom metadata key to the target
41
82
  const metadata = target[CommandMetadataKey] as CommandMetadata | undefined
@@ -47,6 +88,12 @@ export function extractCommandMetadata(target: ClassType): CommandMetadata {
47
88
  return metadata
48
89
  }
49
90
 
91
+ /**
92
+ * Checks if a class has command metadata.
93
+ *
94
+ * @param target - The class to check
95
+ * @returns `true` if the class is decorated with @Command, `false` otherwise
96
+ */
50
97
  export function hasCommandMetadata(target: ClassType): boolean {
51
98
  // @ts-expect-error We add a custom metadata key to the target
52
99
  const metadata = target[CommandMetadataKey] as CommandMetadata | undefined
@@ -1,4 +1,4 @@
1
- import { Container } from '@navios/di'
1
+ import { Container } from '@navios/core'
2
2
 
3
3
  import { beforeEach, describe, expect, it } from 'vitest'
4
4
  import { z } from 'zod'
@@ -434,14 +434,7 @@ describe('CliParserService', () => {
434
434
  })
435
435
 
436
436
  const result = parser.parse(
437
- [
438
- 'node',
439
- 'script.js',
440
- 'test',
441
- '--tags=foo',
442
- '--tags=bar',
443
- '--tags=baz',
444
- ],
437
+ ['node', 'script.js', 'test', '--tags=foo', '--tags=bar', '--tags=baz'],
445
438
  schema,
446
439
  )
447
440
 
@@ -600,12 +593,23 @@ describe('CliParserService', () => {
600
593
  })
601
594
 
602
595
  const result = parser.parse(
603
- ['node', 'script.js', 'test', '--items', '[1,2,3]', '--items', '["a","b"]'],
596
+ [
597
+ 'node',
598
+ 'script.js',
599
+ 'test',
600
+ '--items',
601
+ '[1,2,3]',
602
+ '--items',
603
+ '["a","b"]',
604
+ ],
604
605
  schema,
605
606
  )
606
607
 
607
608
  expect(result.options).toEqual({
608
- items: [[1, 2, 3], ['a', 'b']],
609
+ items: [
610
+ [1, 2, 3],
611
+ ['a', 'b'],
612
+ ],
609
613
  })
610
614
  })
611
615
 
@@ -1,13 +1,41 @@
1
1
  import type { ZodObject, ZodType } from 'zod'
2
2
 
3
- import { Injectable } from '@navios/di'
3
+ import { Injectable } from '@navios/core'
4
4
 
5
+ /**
6
+ * Result of parsing command-line arguments.
7
+ *
8
+ * @public
9
+ */
5
10
  export interface ParsedCliArgs {
11
+ /**
12
+ * The command path (e.g., 'greet', 'user:create').
13
+ * Multi-word commands are joined with spaces.
14
+ */
6
15
  command: string
16
+ /**
17
+ * Parsed options as key-value pairs.
18
+ * Keys are converted from kebab-case to camelCase.
19
+ */
7
20
  options: Record<string, any>
21
+ /**
22
+ * Positional arguments that don't match any option flags.
23
+ */
8
24
  positionals: string[]
9
25
  }
10
26
 
27
+ /**
28
+ * Service for parsing command-line arguments.
29
+ *
30
+ * Handles parsing of various CLI argument formats including:
31
+ * - Long options: `--key value` or `--key=value`
32
+ * - Short options: `-k value` or `-abc` (multiple flags)
33
+ * - Boolean flags
34
+ * - Array options
35
+ * - Positional arguments
36
+ *
37
+ * @public
38
+ */
11
39
  @Injectable()
12
40
  export class CliParserService {
13
41
  /**
@@ -63,7 +91,8 @@ export class CliParserService {
63
91
  const optionName = key.slice(0, equalIndex)
64
92
  const optionValue = key.slice(equalIndex + 1)
65
93
  const camelCaseKey = this.camelCase(optionName)
66
- const isArray = arrayFields.has(camelCaseKey) || arrayFields.has(optionName)
94
+ const isArray =
95
+ arrayFields.has(camelCaseKey) || arrayFields.has(optionName)
67
96
 
68
97
  if (isArray) {
69
98
  // For array fields, accumulate values
@@ -298,7 +327,10 @@ export class CliParserService {
298
327
  }
299
328
 
300
329
  /**
301
- * Formats help text for available commands
330
+ * Formats help text listing all available commands.
331
+ *
332
+ * @param commands - Array of command objects with path and class
333
+ * @returns Formatted string listing all commands
302
334
  */
303
335
  formatCommandList(commands: Array<{ path: string; class: any }>): string {
304
336
  const lines = ['Available commands:', '']
@@ -1,8 +1,8 @@
1
- import type { ClassTypeWithInstance } from '@navios/di'
1
+ import type { ClassTypeWithInstance, NaviosModule } from '@navios/core'
2
2
 
3
- import { Container, inject, Injectable } from '@navios/di'
3
+ import { Container, inject, Injectable } from '@navios/core'
4
4
 
5
- import type { CommandHandler, Module } from '../interfaces/index.mjs'
5
+ import type { CommandHandler } from '../interfaces/index.mjs'
6
6
  import type { CliModuleMetadata, CommandMetadata } from '../metadata/index.mjs'
7
7
 
8
8
  import {
@@ -10,20 +10,46 @@ import {
10
10
  extractCommandMetadata,
11
11
  } from '../metadata/index.mjs'
12
12
 
13
+ /**
14
+ * Command class with its associated metadata.
15
+ *
16
+ * @public
17
+ */
13
18
  export interface CommandWithMetadata {
19
+ /**
20
+ * The command class constructor.
21
+ */
14
22
  class: ClassTypeWithInstance<CommandHandler>
23
+ /**
24
+ * The command metadata including path and options schema.
25
+ */
15
26
  metadata: CommandMetadata
16
27
  }
17
28
 
29
+ /**
30
+ * Service for loading and managing CLI modules and commands.
31
+ *
32
+ * Handles module traversal, command registration, and metadata collection.
33
+ * This service is used internally by CommanderApplication.
34
+ *
35
+ * @public
36
+ */
18
37
  @Injectable()
19
- export class ModuleLoaderService {
38
+ export class CliModuleLoaderService {
20
39
  protected container = inject(Container)
21
40
  private modulesMetadata: Map<string, CliModuleMetadata> = new Map()
22
41
  private loadedModules: Map<string, any> = new Map()
23
42
  private commandsMetadata: Map<string, CommandWithMetadata> = new Map()
24
43
  private initialized = false
25
44
 
26
- async loadModules(appModule: ClassTypeWithInstance<Module>) {
45
+ /**
46
+ * Loads all modules starting from the root app module.
47
+ *
48
+ * Traverses the module tree, loads imported modules, and collects command metadata.
49
+ *
50
+ * @param appModule - The root CLI module
51
+ */
52
+ async loadModules(appModule: ClassTypeWithInstance<NaviosModule>) {
27
53
  if (this.initialized) {
28
54
  return
29
55
  }
@@ -32,7 +58,7 @@ export class ModuleLoaderService {
32
58
  }
33
59
 
34
60
  private async traverseModules(
35
- module: ClassTypeWithInstance<Module>,
61
+ module: ClassTypeWithInstance<NaviosModule>,
36
62
  parentMetadata?: CliModuleMetadata,
37
63
  ) {
38
64
  const metadata = extractCliModuleMetadata(module)
@@ -80,10 +106,20 @@ export class ModuleLoaderService {
80
106
  }
81
107
  }
82
108
 
109
+ /**
110
+ * Gets all loaded module metadata.
111
+ *
112
+ * @returns Map of module names to their metadata
113
+ */
83
114
  getAllModules(): Map<string, CliModuleMetadata> {
84
115
  return this.modulesMetadata
85
116
  }
86
117
 
118
+ /**
119
+ * Gets all command classes indexed by command class name.
120
+ *
121
+ * @returns Map of command class names to command classes
122
+ */
87
123
  getAllCommands(): Map<string, ClassTypeWithInstance<any>> {
88
124
  const commands = new Map<string, ClassTypeWithInstance<any>>()
89
125
  for (const metadata of this.modulesMetadata.values()) {
@@ -111,6 +147,9 @@ export class ModuleLoaderService {
111
147
  return this.commandsMetadata.get(path)
112
148
  }
113
149
 
150
+ /**
151
+ * Disposes of all loaded modules and commands, clearing internal state.
152
+ */
114
153
  dispose() {
115
154
  this.modulesMetadata.clear()
116
155
  this.loadedModules.clear()
@@ -0,0 +1,34 @@
1
+ import { InjectionToken } from '@navios/core'
2
+
3
+ import type { CommanderExecutionContext } from '../interfaces/index.mjs'
4
+
5
+ const CommandExecutionContextInjectionToken =
6
+ 'CommanderExecutionContextInjectionToken'
7
+
8
+ /**
9
+ * Injection token for accessing the current command execution context.
10
+ *
11
+ * Use this token with `inject()` to access the `CommanderExecutionContext` in services
12
+ * that need information about the currently executing command.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { inject, Injectable } from '@navios/di'
17
+ * import { CommandExecutionContext } from '@navios/commander'
18
+ *
19
+ * @Injectable()
20
+ * class MyService {
21
+ * private ctx = inject(CommandExecutionContext)
22
+ *
23
+ * doSomething() {
24
+ * const commandPath = this.ctx.getCommandPath()
25
+ * const options = this.ctx.getOptions()
26
+ * // Use context information...
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+ export const CommandExecutionContext =
32
+ InjectionToken.create<CommanderExecutionContext>(
33
+ CommandExecutionContextInjectionToken,
34
+ )
@@ -0,0 +1 @@
1
+ export * from './execution-context.token.mjs'
@@ -0,0 +1,33 @@
1
+ import { withFilter } from 'rolldown/filter'
2
+ import { defineConfig } from 'tsdown'
3
+ import swc from 'unplugin-swc'
4
+
5
+ export default defineConfig({
6
+ entry: ['src/index.mts'],
7
+ outDir: 'lib',
8
+ format: ['esm', 'cjs'],
9
+ clean: true,
10
+ treeshake: true,
11
+ sourcemap: true,
12
+ platform: 'node',
13
+ dts: true,
14
+ target: 'es2022',
15
+ plugins: [
16
+ withFilter(
17
+ swc.rolldown({
18
+ jsc: {
19
+ target: 'es2022',
20
+ parser: {
21
+ syntax: 'typescript',
22
+ decorators: true,
23
+ },
24
+ transform: {
25
+ decoratorVersion: '2022-03',
26
+ },
27
+ },
28
+ }),
29
+ // Only run this transform if the file contains a decorator.
30
+ { transform: { code: '@' } },
31
+ ),
32
+ ],
33
+ })