@bemoje/cli 0.2.1 → 1.0.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 (121) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +344 -20
  3. package/index.d.ts +6 -0
  4. package/index.js +6 -0
  5. package/lib/Command.d.ts +293 -0
  6. package/lib/Command.js +435 -0
  7. package/lib/CommandHelpAdapter.d.ts +157 -0
  8. package/lib/CommandHelpAdapter.js +100 -0
  9. package/lib/CommanderHelpAdapter.d.ts +56 -0
  10. package/lib/CommanderHelpAdapter.js +90 -0
  11. package/lib/Help.d.ts +263 -0
  12. package/lib/Help.js +477 -0
  13. package/lib/internal/lazyProp.d.ts +5 -0
  14. package/lib/internal/lazyProp.js +24 -0
  15. package/lib/renderHelp.d.ts +6 -0
  16. package/lib/renderHelp.js +12 -0
  17. package/package.json +45 -36
  18. package/cjs/arg/ArgumentBuilder.d.ts +0 -23
  19. package/cjs/arg/ArgumentBuilder.d.ts.map +0 -1
  20. package/cjs/arg/ArgumentBuilder.js +0 -52
  21. package/cjs/arg/ArgumentBuilder.js.map +0 -1
  22. package/cjs/arg/ArgumentParserSelector.d.ts +0 -9
  23. package/cjs/arg/ArgumentParserSelector.d.ts.map +0 -1
  24. package/cjs/arg/ArgumentParserSelector.js +0 -15
  25. package/cjs/arg/ArgumentParserSelector.js.map +0 -1
  26. package/cjs/arg/ArgumentReader.d.ts +0 -15
  27. package/cjs/arg/ArgumentReader.d.ts.map +0 -1
  28. package/cjs/arg/ArgumentReader.js +0 -38
  29. package/cjs/arg/ArgumentReader.js.map +0 -1
  30. package/cjs/arg/ArgumentValidatorSelector.d.ts +0 -8
  31. package/cjs/arg/ArgumentValidatorSelector.d.ts.map +0 -1
  32. package/cjs/arg/ArgumentValidatorSelector.js +0 -16
  33. package/cjs/arg/ArgumentValidatorSelector.js.map +0 -1
  34. package/cjs/cmd/CommandBuilder.d.ts +0 -410
  35. package/cjs/cmd/CommandBuilder.d.ts.map +0 -1
  36. package/cjs/cmd/CommandBuilder.js +0 -1277
  37. package/cjs/cmd/CommandBuilder.js.map +0 -1
  38. package/cjs/cmd/CommandBuilderMetaData.d.ts +0 -26
  39. package/cjs/cmd/CommandBuilderMetaData.d.ts.map +0 -1
  40. package/cjs/cmd/CommandBuilderMetaData.js +0 -45
  41. package/cjs/cmd/CommandBuilderMetaData.js.map +0 -1
  42. package/cjs/cmd/CommandFeatureSelector.d.ts +0 -80
  43. package/cjs/cmd/CommandFeatureSelector.d.ts.map +0 -1
  44. package/cjs/cmd/CommandFeatureSelector.js +0 -114
  45. package/cjs/cmd/CommandFeatureSelector.js.map +0 -1
  46. package/cjs/cmd/DefaultHelpConfig.d.ts +0 -29
  47. package/cjs/cmd/DefaultHelpConfig.d.ts.map +0 -1
  48. package/cjs/cmd/DefaultHelpConfig.js +0 -177
  49. package/cjs/cmd/DefaultHelpConfig.js.map +0 -1
  50. package/cjs/cmd/commanderBackRefs.d.ts +0 -10
  51. package/cjs/cmd/commanderBackRefs.d.ts.map +0 -1
  52. package/cjs/cmd/commanderBackRefs.js +0 -38
  53. package/cjs/cmd/commanderBackRefs.js.map +0 -1
  54. package/cjs/core/OutputManager.d.ts +0 -64
  55. package/cjs/core/OutputManager.d.ts.map +0 -1
  56. package/cjs/core/OutputManager.js +0 -92
  57. package/cjs/core/OutputManager.js.map +0 -1
  58. package/cjs/core/ParserSelector.d.ts +0 -23
  59. package/cjs/core/ParserSelector.d.ts.map +0 -1
  60. package/cjs/core/ParserSelector.js +0 -46
  61. package/cjs/core/ParserSelector.js.map +0 -1
  62. package/cjs/core/ValidatorSelector.d.ts +0 -19
  63. package/cjs/core/ValidatorSelector.d.ts.map +0 -1
  64. package/cjs/core/ValidatorSelector.js +0 -42
  65. package/cjs/core/ValidatorSelector.js.map +0 -1
  66. package/cjs/core/splitCombinedArgvShorts.d.ts +0 -2
  67. package/cjs/core/splitCombinedArgvShorts.d.ts.map +0 -1
  68. package/cjs/core/splitCombinedArgvShorts.js +0 -15
  69. package/cjs/core/splitCombinedArgvShorts.js.map +0 -1
  70. package/cjs/db/AbstractJsonFileSection.d.ts +0 -136
  71. package/cjs/db/AbstractJsonFileSection.d.ts.map +0 -1
  72. package/cjs/db/AbstractJsonFileSection.js +0 -190
  73. package/cjs/db/AbstractJsonFileSection.js.map +0 -1
  74. package/cjs/db/AppDataSection.d.ts +0 -31
  75. package/cjs/db/AppDataSection.d.ts.map +0 -1
  76. package/cjs/db/AppDataSection.js +0 -49
  77. package/cjs/db/AppDataSection.js.map +0 -1
  78. package/cjs/db/ConfigSection.d.ts +0 -46
  79. package/cjs/db/ConfigSection.d.ts.map +0 -1
  80. package/cjs/db/ConfigSection.js +0 -71
  81. package/cjs/db/ConfigSection.js.map +0 -1
  82. package/cjs/db/JsonFile.d.ts +0 -36
  83. package/cjs/db/JsonFile.d.ts.map +0 -1
  84. package/cjs/db/JsonFile.js +0 -60
  85. package/cjs/db/JsonFile.js.map +0 -1
  86. package/cjs/db/PresetsSection.d.ts +0 -45
  87. package/cjs/db/PresetsSection.d.ts.map +0 -1
  88. package/cjs/db/PresetsSection.js +0 -82
  89. package/cjs/db/PresetsSection.js.map +0 -1
  90. package/cjs/index.d.ts +0 -26
  91. package/cjs/index.d.ts.map +0 -1
  92. package/cjs/index.js +0 -29
  93. package/cjs/index.js.map +0 -1
  94. package/cjs/opt/OptionArgumentParserSelector.d.ts +0 -8
  95. package/cjs/opt/OptionArgumentParserSelector.d.ts.map +0 -1
  96. package/cjs/opt/OptionArgumentParserSelector.js +0 -16
  97. package/cjs/opt/OptionArgumentParserSelector.js.map +0 -1
  98. package/cjs/opt/OptionArgumentValidatorSelector.d.ts +0 -8
  99. package/cjs/opt/OptionArgumentValidatorSelector.d.ts.map +0 -1
  100. package/cjs/opt/OptionArgumentValidatorSelector.js +0 -19
  101. package/cjs/opt/OptionArgumentValidatorSelector.js.map +0 -1
  102. package/cjs/opt/OptionBuilder.d.ts +0 -32
  103. package/cjs/opt/OptionBuilder.d.ts.map +0 -1
  104. package/cjs/opt/OptionBuilder.js +0 -97
  105. package/cjs/opt/OptionBuilder.js.map +0 -1
  106. package/cjs/opt/OptionHelpers.d.ts +0 -33
  107. package/cjs/opt/OptionHelpers.d.ts.map +0 -1
  108. package/cjs/opt/OptionHelpers.js +0 -57
  109. package/cjs/opt/OptionHelpers.js.map +0 -1
  110. package/cjs/opt/OptionReader.d.ts +0 -24
  111. package/cjs/opt/OptionReader.d.ts.map +0 -1
  112. package/cjs/opt/OptionReader.js +0 -66
  113. package/cjs/opt/OptionReader.js.map +0 -1
  114. package/cjs/types/IConfig.d.ts +0 -22
  115. package/cjs/types/IConfig.d.ts.map +0 -1
  116. package/cjs/types/IConfig.js +0 -3
  117. package/cjs/types/IConfig.js.map +0 -1
  118. package/cjs/types/IPreset.d.ts +0 -15
  119. package/cjs/types/IPreset.d.ts.map +0 -1
  120. package/cjs/types/IPreset.js +0 -3
  121. package/cjs/types/IPreset.js.map +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Benjamin Møller Jensen
3
+ Copyright (c) 2025 Benjamin Møller Jensen
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,34 +1,358 @@
1
1
  # @bemoje/cli
2
2
 
3
+ A type-safe CLI builder focused on command composition and help generation without execution coupling. Parse arguments, generate help, and integrate with existing CLI frameworks through a clean, fluent API.
3
4
 
5
+ ## Key Features
4
6
 
5
- ![npm (scoped)](https://img.shields.io/npm/v/%40bemoje/trie-map)
6
- ![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/%40bemoje/cli)
7
- ![npm](https://img.shields.io/npm/dt/%40bemoje/cli)
8
- ![NPM](https://img.shields.io/npm/l/%40bemoje%2Fcli)
7
+ - **🎯 Composition-Focused**: Build command structures without execution logic - parse arguments and generate help only
8
+ - **🔒 Type-Safe**: Full TypeScript support with type inference for arguments and options
9
+ - **🚀 Focused API**: Streamlined interface designed specifically for parsing and help generation
10
+ - **🎨 Flexible Help**: Fork of commander.js Help class with enhanced API and adapter support
11
+ - **✅ Validation**: Built-in CLI argument ordering validation and name conflict detection
12
+ - **🔗 Commander.js Compatible**: Adapter allows using this Help system with existing commander.js commands
9
13
 
10
- ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/bemoje/tsmono)
11
- ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/bemoje/tsmono)
12
- ![GitHub top language](https://img.shields.io/github/languages/top/bemoje/tsmono)
14
+ ## Core Philosophy
13
15
 
16
+ While commander.js provides a comprehensive solution that combines command definition with action execution, `@bemoje/cli` takes a different approach by focusing purely on:
14
17
 
15
- ## Documentation
16
- [Documentation Website](https://bemoje.github.io/tsmono/modules/cli.html)
18
+ 1. **Command Structure Definition** - Define arguments, options, and subcommands
19
+ 2. **Argument Parsing** - Parse `process.argv` into structured data
20
+ 3. **Help Generation** - Render formatted help text with customizable styling
17
21
 
18
- ## Installation
19
- This library is published in the NPM registry and can be installed using any compatible package manager.
22
+ This separation of concerns allows for architectures where CLI parsing logic is decoupled from business logic, making it ideal for scenarios where you want to handle argument parsing and action execution in separate layers.
20
23
 
21
- #### NPM
22
- ```sh
23
- npm install @bemoje/cli
24
+ ## Quick Start
25
+
26
+ ```ts
27
+ import { Command } from '@bemoje/cli'
28
+
29
+ // Define command structure
30
+ const cmd = new Command('myapp')
31
+ .setVersion('1.0.0')
32
+ .setDescription('My awesome CLI application')
33
+ .argument('<input>', 'Input file path')
34
+ .argument('[output]', 'Output file path', { defaultValue: 'out.txt' })
35
+ .option('-v, --verbose', 'Enable verbose output')
36
+ .option('-f, --format <type>', 'Output format', { choices: ['json', 'xml', 'yaml'] })
37
+
38
+ // Parse command line arguments
39
+ const result = cmd.parse(process.argv.slice(2))
40
+
41
+ console.log('Arguments:', result.arguments) // ['input.txt', 'out.txt']
42
+ console.log('Options:', result.options) // { verbose: true, format: 'json' }
43
+ console.log('Command:', result.command.name) // 'myapp'
44
+ ```
45
+
46
+ ## Command Definition
47
+
48
+ ### Basic Setup
49
+
50
+ ```ts
51
+ const cmd = new Command('myapp')
52
+ .setVersion('1.0.0')
53
+ .setDescription('Application description')
54
+ .setSummary('Short summary for help')
55
+ .setAliases(['app', 'my-app'])
56
+ ```
57
+
58
+ ### Arguments (Positional)
59
+
60
+ Arguments follow strict ordering rules: required → optional → variadic
61
+
62
+ ```ts
63
+ // Required argument
64
+ cmd.argument('<input>', 'Input file path')
65
+
66
+ // Optional argument with default
67
+ cmd.argument('[output]', 'Output file path', { defaultValue: 'dist/output.txt' })
68
+
69
+ // Required variadic (multiple values)
70
+ cmd.argument('<files...>', 'Multiple input files')
71
+
72
+ // Optional variadic with defaults
73
+ cmd.argument('[patterns...]', 'Glob patterns', { defaultValue: ['**/*.js'] })
74
+ ```
75
+
76
+ ### Options (Named Parameters)
77
+
78
+ ```ts
79
+ // Boolean flag
80
+ cmd.option('-v, --verbose', 'Enable verbose output')
81
+
82
+ // Required string option
83
+ cmd.option('-f, --format <type>', 'Output format')
84
+
85
+ // Optional string option with default
86
+ cmd.option('-o, --output [path]', 'Output directory', { defaultValue: 'dist' })
87
+
88
+ // Required variadic option
89
+ cmd.option('-i, --include <patterns...>', 'Include patterns')
90
+
91
+ // Optional variadic option with defaults
92
+ cmd.option('-e, --exclude [patterns...]', 'Exclude patterns', {
93
+ defaultValue: ['node_modules', '.git'],
94
+ })
95
+
96
+ // Option with choices and environment variable
97
+ cmd.option('-l, --log-level [level]', 'Log level', {
98
+ choices: ['error', 'warn', 'info', 'debug'],
99
+ defaultValue: 'info',
100
+ env: 'LOG_LEVEL',
101
+ })
102
+ ```
103
+
104
+ ### Global Options
105
+
106
+ Options defined on parent commands are available to subcommands:
107
+
108
+ ```ts
109
+ const app = new Command('myapp').option('-c, --config <file>', 'Config file')
110
+
111
+ app.subcommand('build').option('-w, --watch', 'Watch mode')
112
+
113
+ // Both --config and --watch are available to 'build' subcommand
114
+ const result = app.parse(['build', '--config', 'myconfig.json', '--watch'])
115
+ ```
116
+
117
+ ### Subcommands
118
+
119
+ ```ts
120
+ const cmd = new Command('git')
121
+
122
+ // Create subcommand
123
+ const add = cmd
124
+ .subcommand('add')
125
+ .setDescription('Add files to staging area')
126
+ .argument('<files...>', 'Files to add')
127
+ .option('-A, --all', 'Add all files')
128
+
129
+ const commit = cmd
130
+ .subcommand('commit')
131
+ .setDescription('Create a commit')
132
+ .argument('[message]', 'Commit message')
133
+ .option('-m, --message <msg>', 'Commit message')
134
+ .option('-a, --all', 'Commit all changes')
135
+
136
+ // Parsing automatically routes to subcommands
137
+ const result = cmd.parse(['add', 'file1.js', 'file2.js', '-A'])
138
+ // result.command === add subcommand instance
139
+ ```
140
+
141
+ ## Parsing Results
142
+
143
+ The `parse()` method returns a structured result:
144
+
145
+ ```ts
146
+ interface ParseResult {
147
+ command: Command // The command that was executed (handles subcommands)
148
+ arguments: unknown[] // Parsed positional arguments
149
+ options: Record<string, unknown> // Parsed options/flags
150
+ }
151
+ ```
152
+
153
+ ### Argument Types
154
+
155
+ - **Single values**: `string`
156
+ - **Optional with defaults**: `string` (default applied if not provided)
157
+ - **Variadic**: `string[]` (array of values)
158
+
159
+ ### Option Types
160
+
161
+ - **Boolean flags**: `boolean`
162
+ - **String options**: `string`
163
+ - **Variadic options**: `string[]`
164
+
165
+ ## Help System
166
+
167
+ ### Rendering Help
168
+
169
+ ```ts
170
+ import { Help } from '@bemoje/cli'
171
+
172
+ // Use default help formatting
173
+ console.log(cmd.renderHelp())
174
+
175
+ // Customize help configuration
176
+ const customHelp = new Help()
177
+ customHelp.helpWidth = 100
178
+ customHelp.sortOptions = true
179
+ customHelp.showGlobalOptions = true
180
+
181
+ console.log(cmd.renderHelp(customHelp))
182
+ ```
183
+
184
+ ### Help Configuration
185
+
186
+ Configure help behavior per command:
187
+
188
+ ```ts
189
+ cmd.setHelpConfiguration({
190
+ sortOptions: true,
191
+ sortSubcommands: true,
192
+ showGlobalOptions: false,
193
+ helpWidth: 80,
194
+ })
195
+ ```
196
+
197
+ ### Custom Help Styling
198
+
199
+ It may be more convenient to extend the Help class for more extensive customization.
200
+
201
+ ```ts
202
+ import { Help } from '@bemoje/cli'
203
+
204
+ class ColoredHelp extends Help {
205
+ styleTitle(str: string): string {
206
+ return `\x1b[1m${str}\x1b[0m` // Bold
207
+ }
208
+
209
+ styleOptionText(str: string): string {
210
+ return `\x1b[36m${str}\x1b[0m` // Cyan
211
+ }
212
+
213
+ styleArgumentText(str: string): string {
214
+ return `\x1b[33m${str}\x1b[0m` // Yellow
215
+ }
216
+ }
217
+
218
+ console.log(cmd.renderHelp(new ColoredHelp()))
219
+ ```
220
+
221
+ ## Commander.js Integration
222
+
223
+ Use the enhanced Help system with existing commander.js commands:
224
+
225
+ ```ts
226
+ import { Command } from 'commander'
227
+ import { CommanderHelpAdapter } from '@bemoje/cli'
228
+
229
+ // Existing commander.js command
230
+ const commanderCmd = new Command('example')
231
+ .description('Example commander.js command')
232
+ .option('-v, --verbose', 'verbose output')
233
+
234
+ // Use enhanced help system
235
+ const adapter = new CommanderHelpAdapter(commanderCmd)
236
+ console.log(adapter.renderHelp())
237
+ ```
238
+
239
+ ## Custom Adapters
240
+
241
+ You can create your own adapters for any command system by implementing the `ICommandHelp` interface. This allows you to use the enhanced Help system with any CLI library or custom command structure.
242
+
243
+ ### Creating Custom Adapters
244
+
245
+ **Example**: Adapter for a hypothetical CLI library:
246
+
247
+ ```ts
248
+ import { ICommandHelp, IHelp, Help, renderHelp } from '@bemoje/cli'
249
+
250
+ class MyAdapter implements ICommandHelp {
251
+ constructor(private cmd: SomeOtherCliCommand) {}
252
+
253
+ // implement ICommandHelp interface methods
254
+ get name() {
255
+ return this.cmd.getName()
256
+ }
257
+ get commands() {
258
+ return this.cmd.getSubcommands().map((sub) => {
259
+ return new MyAdapter(sub)
260
+ })
261
+ }
262
+ get options() {
263
+ return this.cmd.getOptions().map((opt) => ({
264
+ flags: opt.flags,
265
+ //... map props
266
+ }))
267
+ }
268
+ // etc...
269
+ }
270
+
271
+ const myCommand = new SomeOtherCliCommand('myapp')
272
+ const adapter = new MyAdapter(myCommand)
273
+ console.log(renderHelp(adapter, new Help()))
274
+ ```
275
+
276
+ This pattern allows you to:
277
+
278
+ - **Bridge Different CLI Libraries**: Use the enhanced Help system with any command framework
279
+ - **Migrate Gradually**: Introduce better help formatting without rewriting existing commands
280
+ - **Standardize Help Output**: Consistent help formatting across different CLI tools in your project
281
+ - **Extend Legacy Systems**: Add modern help features to older CLI codebases
282
+
283
+ ## Validation
284
+
285
+ Commands automatically validate:
286
+
287
+ - Argument ordering (required before optional before variadic)
288
+
289
+ ```ts
290
+ cmd.argument('[optional]', 'Optional arg').argument('<required>', 'Required arg')
291
+ //=> ❌ Error!
292
+ ```
293
+
294
+ - Unique option names and short flags, including globals across parent/child commands
295
+
296
+ ```ts
297
+ cmd.option('-v, --verbose', 'Verbose output').option('-v, --video', 'Video mode')
298
+ //=> ❌ Error!
299
+ ```
300
+
301
+ - Single variadic argument per command
302
+
303
+ ```ts
304
+ cmd.argument('<files...>', 'First variadic').argument('<more...>', 'Second variadic')
305
+ //=> ❌ Error!
306
+ ```
307
+
308
+ ## State Management
309
+
310
+ Commands can be serialized and restored:
311
+
312
+ ```ts
313
+ // Serialize command configuration
314
+ const state = cmd.toJSON()
315
+
316
+ // Restore from state
317
+ const restoredCmd = new Command('temp')
318
+ restoredCmd.setState(state)
24
319
  ```
25
320
 
321
+ ## Command Class
26
322
 
27
- ## Issues
28
- Please let me know of any bugs or [issues](https://github.com/bemoje/tsmono/issues).
323
+ **Constructor**:
29
324
 
30
- ## Contribute
31
- Contributors are welcome to open a [pull request](https://github.com/bemoje/tsmono/pulls).
325
+ ```ts
326
+ - new Command(name: string, parent?: Command)
327
+ ```
328
+
329
+ **Structure Methods**:
32
330
 
33
- ## License
34
- Released under the [undefined License](./LICENSE).
331
+ ```ts
332
+ - argument(usage, description, options?): this
333
+ - option(usage, description, options?): this
334
+ - subcommand(name: string): Command
335
+ ```
336
+
337
+ **Configuration Methods**:
338
+
339
+ ```ts
340
+ - setVersion(version?: string): this
341
+ - setName(name: string): this
342
+ - setDescription(...lines: string[]): this
343
+ - setSummary(summary?: string): this
344
+ - setHidden(hidden?: boolean): this
345
+ - setGroup(group?: string): this
346
+ - setHelpConfiguration(config?: Partial<IHelp>): this
347
+ - extendHelpConfiguration(config: Partial<IHelp>): this
348
+ - setAliases(...aliases: (string | string[])[]): this
349
+ - addAliases(...aliases: (string | string[])[]): this
350
+ - setParent(parent: Command | null): this
351
+ ```
352
+
353
+ **Parsing & Help**:
354
+
355
+ ```ts
356
+ - parse(argv?: string[], globalOptions?: OptionDescriptor[]): ParseResult
357
+ - renderHelp(help?: IHelp): string
358
+ ```
package/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './lib/Command';
2
+ export * from './lib/CommandHelpAdapter';
3
+ export * from './lib/CommanderHelpAdapter';
4
+ export * from './lib/Help';
5
+ export * from './lib/renderHelp';
6
+ //# sourceMappingURL=index.d.ts.map
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./lib/Command";
2
+ export * from "./lib/CommandHelpAdapter";
3
+ export * from "./lib/CommanderHelpAdapter";
4
+ export * from "./lib/Help";
5
+ export * from "./lib/renderHelp";
6
+ //# sourceMappingURL=index.js.map