@bemoje/cli 1.0.6 → 1.1.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/lib/Command.js CHANGED
@@ -1,7 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { parseArgs } from "node:util";
4
- import { CommandHelpAdapter } from "./CommandHelpAdapter.js";
5
4
  class Command {
6
5
  static {
7
6
  __name(this, "Command");
@@ -41,37 +40,6 @@ class Command {
41
40
  this.helpConfiguration = { showGlobalOptions: true, sortOptions: true, sortSubcommands: true };
42
41
  Object.defineProperty(this, "parent", { enumerable: false });
43
42
  }
44
- /** Updates multiple command properties at once */
45
- setState(state) {
46
- Object.assign(this, state);
47
- if (state.commands) {
48
- state.commands = state.commands.map((cmd) => new Command(cmd.name, this).setState(cmd));
49
- }
50
- return this;
51
- }
52
- /** Serializes command to JSON, maintaining compatibility with previous state-based structure */
53
- toJSON() {
54
- const result = {
55
- name: this.name,
56
- version: this.version,
57
- aliases: this.aliases,
58
- summary: this.summary,
59
- description: this.description,
60
- hidden: this.hidden,
61
- group: this.group,
62
- commands: this.commands,
63
- arguments: this.arguments,
64
- options: this.options,
65
- helpConfiguration: this.helpConfiguration
66
- };
67
- Object.defineProperty(result, "parent", {
68
- value: this.parent,
69
- writable: true,
70
- enumerable: false,
71
- configurable: true
72
- });
73
- return result;
74
- }
75
43
  /** Sets the command name */
76
44
  setName(name) {
77
45
  this.name = name;
@@ -96,7 +64,7 @@ class Command {
96
64
  this.summary = summary;
97
65
  return this;
98
66
  }
99
- /** Sets command description, joining multiple lines */
67
+ /** Sets command description, joining variadic lines */
100
68
  setDescription(...lines) {
101
69
  this.description = lines.join("\n");
102
70
  return this;
@@ -127,59 +95,56 @@ class Command {
127
95
  return this;
128
96
  }
129
97
  /** Creates and adds a subcommand */
130
- subcommand(name) {
131
- const sub = new Command(name, this);
98
+ addSubcommand(name) {
99
+ const sub = this.createCommand(name, this);
132
100
  this.commands.push(sub);
133
101
  return sub;
134
102
  }
135
103
  /**
136
104
  * Adds positional argument with type inference and CLI ordering validation.
137
105
  */
138
- argument(usage, description, options = {}) {
106
+ addArgument(usage, description, options = {}) {
139
107
  const match = usage.match(/^<(.*?)>$|^\[(.*?)\]$/);
140
108
  if (!match) throw new Error(`Invalid argument format: ${usage}`);
141
109
  const nameMatch = match[1] || match[2];
142
110
  const name = nameMatch.replace(/\.\.\.$/, "");
143
111
  this.assertArgumentNameNotInUse(name);
112
+ const props = { name, description };
144
113
  if (usage.startsWith("<")) {
145
114
  if (nameMatch.endsWith("...")) {
146
115
  this.assertNoMultipleVariadicArguments();
147
116
  this.arguments.push({
148
- name,
149
- description,
117
+ ...options,
118
+ ...props,
150
119
  required: true,
151
- multiple: true,
152
- ...options
120
+ variadic: true
153
121
  });
154
122
  } else {
155
123
  this.assertNoOptionalOrVariadicArguments();
156
124
  this.arguments.push({
157
- name,
158
- description,
125
+ ...options,
126
+ ...props,
159
127
  required: true,
160
- multiple: false,
161
- ...options
128
+ variadic: false
162
129
  });
163
130
  }
164
131
  } else if (usage.startsWith("[")) {
165
132
  if (nameMatch.endsWith("...")) {
166
133
  this.assertNoMultipleVariadicArguments();
167
134
  this.arguments.push({
168
- name,
169
- description,
135
+ ...options,
136
+ ...props,
170
137
  required: false,
171
- multiple: true,
172
- defaultValue: options.defaultValue ?? [],
173
- ...options
138
+ variadic: true,
139
+ defaultValue: options.defaultValue ?? []
174
140
  });
175
141
  } else {
176
142
  this.assertNoVariadicArgument();
177
143
  this.arguments.push({
178
- name,
179
- description,
144
+ ...options,
145
+ ...props,
180
146
  required: false,
181
- multiple: false,
182
- ...options
147
+ variadic: false
183
148
  });
184
149
  }
185
150
  }
@@ -188,77 +153,97 @@ class Command {
188
153
  /**
189
154
  * Adds command-line option with type inference. Parses format: `-s, --long [<value>|[value]|<value...>|[value...]]`
190
155
  */
191
- option(usage, description, opts = {}) {
192
- const match = usage.match(/^-(.+?), --([a-zA-Z][\w-]*)(?:\s*(<(.+?)>|\[(.+?)\]))?$/);
193
- if (!match) throw new Error(`Invalid option format: ${usage}`);
156
+ addOption(flags, description, opts = {}) {
157
+ const match = flags.match(/^-(.+?), --([a-zA-Z][\w-]*)(?:\s*(<(.+?)>|\[(.+?)\]))?$/);
158
+ if (!match) throw new Error(`Invalid option format: ${flags}`);
194
159
  const short = match[1];
195
160
  this.assertOptionShortNameIsValid(short);
196
161
  this.assertOptionShortNameNotInUse(short);
197
162
  const name = match[2];
198
163
  const argName = (match[4] || match[5])?.replace(/\.\.\.$/, "");
199
164
  this.assertOptionNameNotInUse(name);
165
+ const props = {
166
+ flags,
167
+ short,
168
+ long: name,
169
+ name,
170
+ description
171
+ };
200
172
  if (!argName) {
201
- this.options.push({
173
+ this._addOption({
202
174
  type: "boolean",
203
- short,
204
- name,
205
- description,
206
- required: false,
207
- multiple: false,
208
- ...opts
175
+ ...opts,
176
+ ...props,
177
+ negate: false,
178
+ optional: true,
179
+ variadic: false,
180
+ get multiple() {
181
+ return this.variadic;
182
+ }
209
183
  });
210
- } else if (usage.endsWith(">")) {
211
- if (usage.endsWith("...>")) {
212
- this.options.push({
184
+ } else if (flags.endsWith(">")) {
185
+ if (flags.endsWith("...>")) {
186
+ this._addOption({
213
187
  type: "string",
214
- short,
215
- name,
188
+ ...opts,
189
+ ...props,
216
190
  argName,
217
- description,
218
191
  required: true,
219
- multiple: true,
220
- ...opts
192
+ optional: false,
193
+ variadic: true,
194
+ get multiple() {
195
+ return this.variadic;
196
+ }
221
197
  });
222
198
  } else {
223
- this.options.push({
199
+ this._addOption({
224
200
  type: "string",
225
- short,
226
- name,
201
+ ...opts,
202
+ ...props,
227
203
  argName,
228
- description,
229
204
  required: true,
230
- multiple: false,
231
- ...opts
205
+ optional: false,
206
+ variadic: false,
207
+ get multiple() {
208
+ return this.variadic;
209
+ }
232
210
  });
233
211
  }
234
- } else if (usage.endsWith("]")) {
235
- if (usage.endsWith("...]")) {
236
- this.options.push({
212
+ } else if (flags.endsWith("]")) {
213
+ if (flags.endsWith("...]")) {
214
+ this._addOption({
237
215
  type: "string",
238
- short,
239
- name,
216
+ ...opts,
217
+ ...props,
240
218
  argName,
241
- description,
242
219
  required: false,
243
- multiple: true,
244
- defaultValue: opts.defaultValue ?? [],
245
- ...opts
220
+ optional: true,
221
+ variadic: true,
222
+ get multiple() {
223
+ return this.variadic;
224
+ },
225
+ defaultValue: opts.defaultValue ?? []
246
226
  });
247
227
  } else {
248
- this.options.push({
228
+ this._addOption({
249
229
  type: "string",
250
- short,
251
- name,
230
+ ...opts,
231
+ ...props,
252
232
  argName,
253
- description,
254
233
  required: false,
255
- multiple: false,
256
- ...opts
234
+ optional: true,
235
+ variadic: false,
236
+ get multiple() {
237
+ return this.variadic;
238
+ }
257
239
  });
258
240
  }
259
241
  }
260
242
  return this;
261
243
  }
244
+ _addOption(opt) {
245
+ this.options.push(opt);
246
+ }
262
247
  /**
263
248
  * Parses command-line arguments with subcommand support and type-safe validation.
264
249
  *
@@ -268,7 +253,7 @@ class Command {
268
253
  * // { arguments: ['input.txt'], options: { verbose: true, format: 'json' } }
269
254
  * ```
270
255
  */
271
- parse(argv = process.argv.slice(2), globalOptions = []) {
256
+ parseArgv(argv = process.argv.slice(2), globalOptions = []) {
272
257
  const maybeSubArg = parseArgs({
273
258
  args: argv,
274
259
  allowPositionals: true,
@@ -278,7 +263,7 @@ class Command {
278
263
  }).positionals[0];
279
264
  const sub = this.findCommand(maybeSubArg);
280
265
  if (sub) {
281
- return sub.parse(
266
+ return sub.parseArgv(
282
267
  argv?.filter((a) => a !== maybeSubArg),
283
268
  [...globalOptions, ...this.options]
284
269
  );
@@ -299,7 +284,7 @@ class Command {
299
284
  const token = parsed.tokens[i];
300
285
  if (token.kind === "option") {
301
286
  const optionDescriptor = this.options.find((o) => o.name === token.name);
302
- if (optionDescriptor && optionDescriptor.multiple && optionDescriptor.type === "string") {
287
+ if (optionDescriptor && optionDescriptor.variadic && optionDescriptor.type === "string") {
303
288
  const values = [token.value];
304
289
  let j = i + 1;
305
290
  while (j < parsed.tokens.length && parsed.tokens[j].kind === "positional") {
@@ -322,13 +307,13 @@ class Command {
322
307
  }
323
308
  }
324
309
  const parsedArguments = this.arguments.map((arg, index) => {
325
- if (arg.multiple) {
310
+ if (arg.variadic) {
326
311
  const remainingArgs = parsed.positionals.slice(index);
327
312
  return remainingArgs.length > 0 ? remainingArgs : arg.defaultValue ?? [];
328
313
  } else {
329
314
  return parsed.positionals[index] ?? arg.defaultValue;
330
315
  }
331
- });
316
+ }).filter((arg) => arg !== void 0);
332
317
  for (const option of this.options) {
333
318
  if (!(option.name in parsed.values) && "defaultValue" in option) {
334
319
  Reflect.set(parsed.values, option.name, option.defaultValue);
@@ -343,6 +328,11 @@ class Command {
343
328
  options: { ...parsed.values }
344
329
  };
345
330
  }
331
+ /** Renders formatted help text using provided help definition */
332
+ renderHelp(help) {
333
+ const helper = Object.assign(help, this.helpConfiguration);
334
+ return helper.formatHelp(this, helper);
335
+ }
346
336
  /** Validates CLI argument ordering */
347
337
  assertNoOptionalOrVariadicArguments() {
348
338
  if (this.arguments.some((arg) => !arg.required)) {
@@ -351,13 +341,13 @@ class Command {
351
341
  }
352
342
  /** Validates optional args don't follow variadic args */
353
343
  assertNoVariadicArgument() {
354
- if (this.arguments.some((arg) => arg.multiple)) {
344
+ if (this.arguments.some((arg) => arg.variadic)) {
355
345
  throw new Error("Cannot add optional argument after variadic argument");
356
346
  }
357
347
  }
358
348
  /** Ensures only one variadic argument per command */
359
349
  assertNoMultipleVariadicArguments() {
360
- if (this.arguments.some((arg) => arg.multiple)) {
350
+ if (this.arguments.some((arg) => arg.variadic)) {
361
351
  throw new Error("Cannot add more than one variadic argument");
362
352
  }
363
353
  }
@@ -419,13 +409,9 @@ class Command {
419
409
  findOption(arg) {
420
410
  return this.options.find((option) => option.short === arg || option.name === arg);
421
411
  }
422
- /** Returns a view that is compliant with the CommandHelp interface */
423
- createHelpAdapter() {
424
- return new CommandHelpAdapter(this);
425
- }
426
- /** Renders formatted help text using provided help definition */
427
- renderHelp(help) {
428
- return this.createHelpAdapter().renderHelp(help);
412
+ /** Returns a new Command instance. Override this method in subclasses. */
413
+ createCommand(name = "", parent = null) {
414
+ return new Command(name, parent);
429
415
  }
430
416
  }
431
417
  export {
package/lib/Help.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ArgumentDescriptorBase, CommandDescriptor, OptionDescriptorBase } from './Command';
1
2
  /**
2
3
  * Although this is a class, methods are static in style to allow override using subclass or just functions.
3
4
  */
@@ -11,72 +12,72 @@ export declare class Help implements IHelp {
11
12
  /**
12
13
  * Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
13
14
  */
14
- visibleCommands(cmd: ICommandHelp): ICommandHelp[];
15
+ visibleCommands(cmd: CommandDescriptor): CommandDescriptor[];
15
16
  /**
16
17
  * Compare options for sort.
17
18
  */
18
- compareOptions(a: IOptionHelp, b: IOptionHelp): number;
19
+ compareOptions(a: OptionDescriptorBase, b: OptionDescriptorBase): number;
19
20
  /**
20
21
  * Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
21
22
  */
22
- visibleOptions(cmd: ICommandHelp): IOptionHelp[];
23
+ visibleOptions(cmd: CommandDescriptor): OptionDescriptorBase[];
23
24
  /**
24
25
  * Get an array of the visible global options. (Not including help.)
25
26
  */
26
- visibleGlobalOptions(cmd: ICommandHelp): IOptionHelp[];
27
+ visibleGlobalOptions(cmd: CommandDescriptor): OptionDescriptorBase[];
27
28
  /**
28
29
  * Get an array of the arguments if any have a description.
29
30
  */
30
- visibleArguments(cmd: ICommandHelp): IArgumentHelp[];
31
+ visibleArguments(cmd: CommandDescriptor): ArgumentDescriptorBase[];
31
32
  /**
32
33
  * Get the command term to show in the list of subcommands.
33
34
  */
34
- subcommandTerm(cmd: ICommandHelp): string;
35
+ subcommandTerm(cmd: CommandDescriptor): string;
35
36
  /**
36
37
  * Get the option term to show in the list of options.
37
38
  */
38
- optionTerm(option: IOptionHelp): string;
39
+ optionTerm(option: OptionDescriptorBase): string;
39
40
  /**
40
41
  * Get the argument term to show in the list of arguments.
41
42
  */
42
- argumentTerm(argument: IArgumentHelp): string;
43
+ argumentTerm(argument: ArgumentDescriptorBase): string;
43
44
  /**
44
45
  * Get the longest command term length.
45
46
  */
46
- longestSubcommandTermLength(cmd: ICommandHelp, helper: Help): number;
47
+ longestSubcommandTermLength(cmd: CommandDescriptor, helper: Help): number;
47
48
  /**
48
49
  * Get the longest option term length.
49
50
  */
50
- longestOptionTermLength(cmd: ICommandHelp, helper: Help): number;
51
+ longestOptionTermLength(cmd: CommandDescriptor, helper: Help): number;
51
52
  /**
52
53
  * Get the longest global option term length.
53
54
  */
54
- longestGlobalOptionTermLength(cmd: ICommandHelp, helper: Help): number;
55
+ longestGlobalOptionTermLength(cmd: CommandDescriptor, helper: Help): number;
55
56
  /**
56
57
  * Get the longest argument term length.
57
58
  */
58
- longestArgumentTermLength(cmd: ICommandHelp, helper: Help): number;
59
+ longestArgumentTermLength(cmd: CommandDescriptor, helper: Help): number;
59
60
  /**
60
61
  * Get the command usage to be displayed at the top of the built-in help.
61
62
  */
62
- commandUsage(cmd: ICommandHelp): string;
63
+ commandUsage(cmd: CommandDescriptor): string;
63
64
  /**
64
65
  * Get the description for the command.
65
66
  */
66
- commandDescription(cmd: ICommandHelp): string;
67
+ commandDescription(cmd: CommandDescriptor): string;
67
68
  /**
68
69
  * Get the subcommand summary to show in the list of subcommands.
69
70
  * (Fallback to description for backwards compatibility.)
70
71
  */
71
- subcommandDescription(cmd: ICommandHelp): string;
72
+ subcommandDescription(cmd: CommandDescriptor): string;
72
73
  /**
73
74
  * Get the option description to show in the list of options.
74
75
  */
75
- optionDescription(option: IOptionHelp): string;
76
+ optionDescription(option: OptionDescriptorBase): string;
76
77
  /**
77
78
  * Get the argument description to show in the list of arguments.
78
79
  */
79
- argumentDescription(argument: IArgumentHelp): string;
80
+ argumentDescription(argument: ArgumentDescriptorBase): string;
80
81
  /**
81
82
  * Format a list of items, given a heading and an array of formatted items.
82
83
  */
@@ -84,11 +85,11 @@ export declare class Help implements IHelp {
84
85
  /**
85
86
  * Group items by their help group heading.
86
87
  */
87
- groupItems<T extends ICommandHelp | IOptionHelp>(unsortedItems: T[], visibleItems: T[], getGroup: (item: T) => string): Map<string, T[]>;
88
+ groupItems<T extends CommandDescriptor | OptionDescriptorBase>(unsortedItems: T[], visibleItems: T[], getGroup: (item: T) => string): Map<string, T[]>;
88
89
  /**
89
90
  * Generate the built-in help text.
90
91
  */
91
- formatHelp(cmd: ICommandHelp, helper: IHelp): string;
92
+ formatHelp(cmd: CommandDescriptor, helper: IHelp): string;
92
93
  /**
93
94
  * Return display width of string, ignoring ANSI escape sequences. Used in padding and wrapping calculations.
94
95
  */
@@ -152,7 +153,7 @@ export declare class Help implements IHelp {
152
153
  /**
153
154
  * Calculate the pad width from the maximum term length.
154
155
  */
155
- padWidth(cmd: ICommandHelp, helper: Help): number;
156
+ padWidth(cmd: CommandDescriptor, helper: Help): number;
156
157
  /**
157
158
  * Detect manually wrapped and indented strings by checking for line break followed by whitespace.
158
159
  */
@@ -171,71 +172,28 @@ export declare class Help implements IHelp {
171
172
  */
172
173
  boxWrap(str: string, width: number): string;
173
174
  }
174
- /**
175
- * Interface for a command object used to generate help.
176
- */
177
- export interface ICommandHelp {
178
- name: string;
179
- aliases: string[];
180
- summary?: string;
181
- description: string;
182
- hidden?: boolean;
183
- usage: string;
184
- group?: string;
185
- commands: ICommandHelp[];
186
- options: IOptionHelp[];
187
- arguments: IArgumentHelp[];
188
- parent: ICommandHelp | null;
189
- helpConfiguration?: Partial<IHelp>;
190
- }
191
- export interface IArgumentHelp {
192
- name: string;
193
- description: string;
194
- required: boolean;
195
- variadic: boolean;
196
- defaultValue?: string | string[];
197
- defaultValueDescription?: string;
198
- choices?: string[];
199
- }
200
- export interface IOptionHelp {
201
- group?: string;
202
- flags: string;
203
- description: string;
204
- short: string;
205
- long: string;
206
- required?: boolean;
207
- optional?: boolean;
208
- variadic?: boolean;
209
- negate?: boolean;
210
- defaultValue?: boolean | string | string[];
211
- defaultValueDescription?: string;
212
- env?: string;
213
- choices?: string[];
214
- hidden?: boolean;
215
- global?: boolean;
216
- }
217
175
  export interface IHelp {
218
176
  helpWidth: number;
219
177
  minWidthToWrap: number;
220
178
  sortSubcommands?: boolean;
221
179
  sortOptions?: boolean;
222
180
  showGlobalOptions?: boolean;
223
- subcommandTerm(cmd: ICommandHelp): string;
224
- subcommandDescription(cmd: ICommandHelp): string;
225
- optionTerm(option: IOptionHelp): string;
226
- optionDescription(option: IOptionHelp): string;
227
- argumentTerm(argument: IArgumentHelp): string;
228
- argumentDescription(argument: IArgumentHelp): string;
229
- commandUsage(cmd: ICommandHelp): string;
230
- commandDescription(cmd: ICommandHelp): string;
231
- visibleCommands(cmd: ICommandHelp): ICommandHelp[];
232
- visibleOptions(cmd: ICommandHelp): IOptionHelp[];
233
- visibleGlobalOptions(cmd: ICommandHelp): IOptionHelp[];
234
- visibleArguments(cmd: ICommandHelp): IArgumentHelp[];
235
- longestSubcommandTermLength(cmd: ICommandHelp, helper: IHelp): number;
236
- longestOptionTermLength(cmd: ICommandHelp, helper: IHelp): number;
237
- longestGlobalOptionTermLength(cmd: ICommandHelp, helper: IHelp): number;
238
- longestArgumentTermLength(cmd: ICommandHelp, helper: IHelp): number;
181
+ subcommandTerm(cmd: CommandDescriptor): string;
182
+ subcommandDescription(cmd: CommandDescriptor): string;
183
+ optionTerm(option: OptionDescriptorBase): string;
184
+ optionDescription(option: OptionDescriptorBase): string;
185
+ argumentTerm(argument: ArgumentDescriptorBase): string;
186
+ argumentDescription(argument: ArgumentDescriptorBase): string;
187
+ commandUsage(cmd: CommandDescriptor): string;
188
+ commandDescription(cmd: CommandDescriptor): string;
189
+ visibleCommands(cmd: CommandDescriptor): CommandDescriptor[];
190
+ visibleOptions(cmd: CommandDescriptor): OptionDescriptorBase[];
191
+ visibleGlobalOptions(cmd: CommandDescriptor): OptionDescriptorBase[];
192
+ visibleArguments(cmd: CommandDescriptor): ArgumentDescriptorBase[];
193
+ longestSubcommandTermLength(cmd: CommandDescriptor, helper: IHelp): number;
194
+ longestOptionTermLength(cmd: CommandDescriptor, helper: IHelp): number;
195
+ longestGlobalOptionTermLength(cmd: CommandDescriptor, helper: IHelp): number;
196
+ longestArgumentTermLength(cmd: CommandDescriptor, helper: IHelp): number;
239
197
  displayWidth(str: string): number;
240
198
  styleTitle(title: string): string;
241
199
  styleUsage(str: string): string;
@@ -251,13 +209,13 @@ export interface IHelp {
251
209
  styleOptionText(str: string): string;
252
210
  styleSubcommandText(str: string): string;
253
211
  styleArgumentText(str: string): string;
254
- compareOptions(a: IOptionHelp, b: IOptionHelp): number;
255
- padWidth(cmd: ICommandHelp, helper: IHelp): number;
212
+ compareOptions(a: OptionDescriptorBase, b: OptionDescriptorBase): number;
213
+ padWidth(cmd: CommandDescriptor, helper: IHelp): number;
256
214
  boxWrap(str: string, width: number): string;
257
215
  preformatted(str: string): boolean;
258
216
  formatItem(term: string, termWidth: number, description: string, helper: IHelp): string;
259
217
  formatItemList(heading: string, items: string[], helper: IHelp): string[];
260
- groupItems<T extends ICommandHelp | IOptionHelp>(unsortedItems: T[], visibleItems: T[], getGroup: (item: T) => string): Map<string, T[]>;
261
- formatHelp(cmd: ICommandHelp, helper: IHelp): string;
218
+ groupItems<T extends CommandDescriptor | OptionDescriptorBase>(unsortedItems: T[], visibleItems: T[], getGroup: (item: T) => string): Map<string, T[]>;
219
+ formatHelp(cmd: CommandDescriptor, helper: IHelp): string;
262
220
  }
263
221
  //# sourceMappingURL=Help.d.ts.map
package/lib/Help.js CHANGED
@@ -69,7 +69,10 @@ class Help {
69
69
  * Get the command term to show in the list of subcommands.
70
70
  */
71
71
  subcommandTerm(cmd) {
72
- const args = cmd.arguments.map((arg) => humanReadableArgName(arg)).join(" ");
72
+ const args = cmd.arguments.map((arg) => {
73
+ const nameOutput = arg.name + (arg.variadic === true ? "..." : "");
74
+ return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
75
+ }).join(" ");
73
76
  return cmd.name + (cmd.aliases[0] ? "|" + cmd.aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option
74
77
  (args ? " " + args : "");
75
78
  }
@@ -129,7 +132,13 @@ class Help {
129
132
  for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
130
133
  ancestorCmdNames = ancestorCmd.name + " " + ancestorCmdNames;
131
134
  }
132
- return ancestorCmdNames + cmdName + " " + cmd.usage;
135
+ return ancestorCmdNames + cmdName + " " + [
136
+ ...cmd.options.length ? ["[options]"] : [],
137
+ ...cmd.commands.length ? ["[command]"] : [],
138
+ ...cmd.arguments.map((arg) => {
139
+ return arg.required ? arg.variadic ? `<${arg.name}...>` : `<${arg.name}>` : arg.variadic ? `[${arg.name}...]` : `[${arg.name}]`;
140
+ })
141
+ ].join(" ");
133
142
  }
134
143
  /**
135
144
  * Get the description for the command.
@@ -142,7 +151,7 @@ class Help {
142
151
  * (Fallback to description for backwards compatibility.)
143
152
  */
144
153
  subcommandDescription(cmd) {
145
- return cmd.summary || cmd.description;
154
+ return cmd.summary || (cmd.description.includes("\n") ? cmd.description.split("\n")[0] : "");
146
155
  }
147
156
  /**
148
157
  * Get the option description to show in the list of options.
@@ -287,7 +296,8 @@ class Help {
287
296
  * Return display width of string, ignoring ANSI escape sequences. Used in padding and wrapping calculations.
288
297
  */
289
298
  displayWidth(str) {
290
- return stripColor(str).length;
299
+ const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
300
+ return str.replace(sgrPattern, "").length;
291
301
  }
292
302
  /**
293
303
  * Style the title for displaying in the help. Called with 'Usage:', 'Options:', etc.
@@ -458,16 +468,6 @@ ${itemIndentStr}`);
458
468
  return wrappedLines.join("\n");
459
469
  }
460
470
  }
461
- function stripColor(str) {
462
- const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
463
- return str.replace(sgrPattern, "");
464
- }
465
- __name(stripColor, "stripColor");
466
- function humanReadableArgName(arg) {
467
- const nameOutput = arg.name + (arg.variadic === true ? "..." : "");
468
- return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
469
- }
470
- __name(humanReadableArgName, "humanReadableArgName");
471
471
  export {
472
472
  Help
473
473
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bemoje/cli",
3
- "description": "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.",
4
- "version": "1.0.6",
3
+ "description": "A type-safe CLI composer that can parse argv and generate help without execution coupling.",
4
+ "version": "1.1.0",
5
5
  "private": false,
6
6
  "sideEffects": false,
7
7
  "type": "module",
@@ -16,7 +16,8 @@
16
16
  "typings": "./index.d.ts",
17
17
  "dependencies": {},
18
18
  "devDependencies": {
19
- "commander": "^14.0.0"
19
+ "commander": "^14.0.0",
20
+ "type-fest": "4.41.0"
20
21
  },
21
22
  "license": "MIT",
22
23
  "repository": {
@@ -26,11 +27,8 @@
26
27
  "keywords": [
27
28
  "cli",
28
29
  "command-line",
29
- "argument-parser",
30
- "options-parser",
31
30
  "typescript",
32
31
  "type-safe",
33
- "fluent-api",
34
32
  "help-generation",
35
33
  "commander",
36
34
  "commander.js",
@@ -38,7 +36,6 @@
38
36
  "validation",
39
37
  "parsing",
40
38
  "composition",
41
- "adapter",
42
39
  "terminal",
43
40
  "console",
44
41
  "args",