cli-kiss 0.0.2 → 0.0.4

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.
@@ -1,10 +1,10 @@
1
1
  import { ArgumentUsage } from "./Argument";
2
+ import { Execution } from "./Execution";
2
3
  import { OptionUsage } from "./Option";
3
- import { Process } from "./Process";
4
4
  import { ReaderTokenizer } from "./Reader";
5
5
 
6
6
  export type Command<Context, Result> = {
7
- getTitle(): string | undefined;
7
+ getDescription(): string | undefined;
8
8
  prepareRunner(
9
9
  readerTokenizer: ReaderTokenizer,
10
10
  ): CommandRunner<Context, Result>;
@@ -17,54 +17,52 @@ export type CommandRunner<Context, Result> = {
17
17
 
18
18
  export type CommandUsage = {
19
19
  breadcrumbs: Array<CommandUsageBreadcrumb>;
20
- title: string;
21
- description: Array<string> | undefined;
20
+ description: string;
21
+ details: Array<string> | undefined;
22
22
  options: Array<OptionUsage>;
23
23
  arguments: Array<ArgumentUsage>;
24
- subcommands: Array<{ name: string; title: string | undefined }>;
24
+ subcommands: Array<{ name: string; description: string | undefined }>;
25
25
  };
26
26
 
27
- export type CommandUsageBreadcrumb = {
28
- kind: "command" | "argument";
29
- value: string;
30
- };
27
+ export type CommandUsageBreadcrumb = { argument: string } | { command: string };
31
28
 
32
29
  export function command<Context, Result>(
33
30
  metadata: {
34
- title: string;
35
- description?: Array<string>;
31
+ description: string;
32
+ details?: Array<string>;
33
+ // TODO - examples ?
36
34
  },
37
- process: Process<Context, Result>,
35
+ execution: Execution<Context, Result>,
38
36
  ): Command<Context, Result> {
39
37
  return {
40
- getTitle() {
41
- return metadata.title;
38
+ getDescription() {
39
+ return metadata.description;
42
40
  },
43
41
  prepareRunner(readerTokenizer: ReaderTokenizer) {
44
42
  function computeUsage(): CommandUsage {
45
- const processUsage = process.computeUsage();
43
+ const executionUsage = execution.computeUsage();
46
44
  return {
47
- breadcrumbs: processUsage.arguments.map((argument) =>
45
+ breadcrumbs: executionUsage.arguments.map((argument) =>
48
46
  breadcrumbArgument(argument.label),
49
47
  ),
50
- title: metadata.title,
51
48
  description: metadata.description,
52
- options: processUsage.options,
53
- arguments: processUsage.arguments,
49
+ details: metadata.details,
50
+ options: executionUsage.options,
51
+ arguments: executionUsage.arguments,
54
52
  subcommands: [],
55
53
  };
56
54
  }
57
55
  try {
58
- const processResolver = process.prepareResolver(readerTokenizer);
56
+ const executionResolver = execution.prepareResolver(readerTokenizer);
59
57
  const lastPositional = readerTokenizer.consumePositional();
60
58
  if (lastPositional !== undefined) {
61
59
  throw Error(`Unprocessed positional: ${lastPositional}`);
62
60
  }
63
- const processRunner = processResolver();
61
+ const executionCallback = executionResolver();
64
62
  return {
65
63
  computeUsage,
66
64
  async execute(context: Context) {
67
- return await processRunner.execute(context);
65
+ return await executionCallback(context);
68
66
  },
69
67
  };
70
68
  } catch (error) {
@@ -81,19 +79,19 @@ export function command<Context, Result>(
81
79
 
82
80
  export function commandWithSubcommands<Context, Payload, Result>(
83
81
  metadata: {
84
- title: string;
85
- description?: Array<string>;
82
+ description: string;
83
+ details?: Array<string>;
86
84
  },
87
- process: Process<Context, Payload>,
85
+ execution: Execution<Context, Payload>,
88
86
  subcommands: { [subcommand: Lowercase<string>]: Command<Payload, Result> },
89
87
  ): Command<Context, Result> {
90
88
  return {
91
- getTitle() {
92
- return metadata.title;
89
+ getDescription() {
90
+ return metadata.description;
93
91
  },
94
92
  prepareRunner(readerTokenizer: ReaderTokenizer) {
95
93
  try {
96
- const processResolver = process.prepareResolver(readerTokenizer);
94
+ const executionResolver = execution.prepareResolver(readerTokenizer);
97
95
  const subcommandName = readerTokenizer.consumePositional();
98
96
  if (subcommandName === undefined) {
99
97
  throw new Error("Expected a subcommand");
@@ -104,46 +102,46 @@ export function commandWithSubcommands<Context, Payload, Result>(
104
102
  throw new Error(`Unknown subcommand: ${subcommandName}`);
105
103
  }
106
104
  const subcommandRunner = subcommandInput.prepareRunner(readerTokenizer);
107
- const processRunner = processResolver();
105
+ const executionCallback = executionResolver();
108
106
  return {
109
107
  computeUsage() {
110
- const processUsage = process.computeUsage();
108
+ const executionUsage = execution.computeUsage();
111
109
  const subcommandUsage = subcommandRunner.computeUsage();
112
110
  return {
113
- breadcrumbs: processUsage.arguments
111
+ breadcrumbs: executionUsage.arguments
114
112
  .map((argument) => breadcrumbArgument(argument.label))
115
113
  .concat([breadcrumbCommand(subcommandName)])
116
114
  .concat(subcommandUsage.breadcrumbs),
117
- title: subcommandUsage.title,
118
115
  description: subcommandUsage.description,
119
- options: processUsage.options.concat(subcommandUsage.options),
120
- arguments: processUsage.arguments.concat(
116
+ details: subcommandUsage.details,
117
+ options: executionUsage.options.concat(subcommandUsage.options),
118
+ arguments: executionUsage.arguments.concat(
121
119
  subcommandUsage.arguments,
122
120
  ),
123
121
  subcommands: subcommandUsage.subcommands,
124
122
  };
125
123
  },
126
124
  async execute(context: Context) {
127
- const payload = await processRunner.execute(context);
125
+ const payload = await executionCallback(context);
128
126
  return await subcommandRunner.execute(payload);
129
127
  },
130
128
  };
131
129
  } catch (error) {
132
130
  return {
133
131
  computeUsage() {
134
- const processUsage = process.computeUsage();
132
+ const executionUsage = execution.computeUsage();
135
133
  return {
136
- breadcrumbs: processUsage.arguments
134
+ breadcrumbs: executionUsage.arguments
137
135
  .map((argument) => breadcrumbArgument(argument.label))
138
136
  .concat([breadcrumbCommand("<SUBCOMMAND>")]),
139
- title: metadata.title,
140
137
  description: metadata.description,
141
- options: processUsage.options,
142
- arguments: processUsage.arguments,
138
+ details: metadata.details,
139
+ options: executionUsage.options,
140
+ arguments: executionUsage.arguments,
143
141
  subcommands: Object.entries(subcommands).map(
144
142
  ([name, subcommand]) => ({
145
143
  name,
146
- title: subcommand.getTitle(),
144
+ description: subcommand.getDescription(),
147
145
  }),
148
146
  ),
149
147
  };
@@ -157,10 +155,10 @@ export function commandWithSubcommands<Context, Payload, Result>(
157
155
  };
158
156
  }
159
157
 
160
- function breadcrumbArgument(label: string): CommandUsageBreadcrumb {
161
- return { kind: "argument", value: label };
158
+ function breadcrumbArgument(value: string): CommandUsageBreadcrumb {
159
+ return { argument: value };
162
160
  }
163
161
 
164
- function breadcrumbCommand(name: string): CommandUsageBreadcrumb {
165
- return { kind: "command", value: name };
162
+ function breadcrumbCommand(value: string): CommandUsageBreadcrumb {
163
+ return { command: value };
166
164
  }
@@ -2,48 +2,45 @@ import { Argument, ArgumentUsage } from "./Argument";
2
2
  import { Option, OptionUsage } from "./Option";
3
3
  import { ReaderTokenizer } from "./Reader";
4
4
 
5
- export type Process<Context, Result> = {
6
- computeUsage(): ProcessUsage;
5
+ export type Execution<Context, Result> = {
6
+ computeUsage(): ExecutionUsage;
7
7
  prepareResolver(
8
8
  readerTokenizer: ReaderTokenizer,
9
- ): ProcessResolver<Context, Result>;
9
+ ): ExecutionResolver<Context, Result>;
10
10
  };
11
11
 
12
- export type ProcessResolver<Context, Result> = () => ProcessRunner<
12
+ export type ExecutionResolver<Context, Result> = () => ExecutionCallback<
13
13
  Context,
14
14
  Result
15
15
  >;
16
16
 
17
- export type ProcessRunner<Context, Result> = {
18
- execute(context: Context): Promise<Result>;
19
- };
17
+ export type ExecutionCallback<Context, Result> = (
18
+ context: Context,
19
+ ) => Promise<Result>;
20
20
 
21
- export type ProcessUsage = {
21
+ export type ExecutionUsage = {
22
22
  options: Array<OptionUsage>;
23
23
  arguments: Array<ArgumentUsage>;
24
24
  };
25
25
 
26
- export function process<
26
+ export function execution<
27
27
  Context,
28
28
  Result,
29
- Options extends { [option: string]: Option<any> },
30
- const Arguments extends Array<Argument<any>>,
29
+ Options extends { [option: string]: any },
30
+ const Arguments extends Array<any>,
31
31
  >(
32
- inputs: { options: Options; arguments: Arguments },
32
+ inputs: {
33
+ options: { [K in keyof Options]: Option<Options[K]> };
34
+ arguments: { [K in keyof Arguments]: Argument<Arguments[K]> };
35
+ },
33
36
  handler: (
34
37
  context: Context,
35
38
  inputs: {
36
- options: {
37
- [K in keyof Options]: ReturnType<
38
- ReturnType<Options[K]["prepareConsumer"]>
39
- >;
40
- };
41
- arguments: {
42
- [K in keyof Arguments]: ReturnType<Arguments[K]["consumeValue"]>;
43
- };
39
+ options: Options;
40
+ arguments: Arguments;
44
41
  },
45
42
  ) => Promise<Result>,
46
- ): Process<Context, Result> {
43
+ ): Execution<Context, Result> {
47
44
  return {
48
45
  computeUsage() {
49
46
  const optionsUsage = new Array<OptionUsage>();
@@ -73,13 +70,11 @@ export function process<
73
70
  for (const optionKey in optionsConsumers) {
74
71
  optionsValues[optionKey] = optionsConsumers[optionKey]!();
75
72
  }
76
- return {
77
- async execute(context: Context) {
78
- return await handler(context, {
79
- options: optionsValues,
80
- arguments: argumentsValues,
81
- });
82
- },
73
+ return async (context: Context) => {
74
+ return await handler(context, {
75
+ options: optionsValues,
76
+ arguments: argumentsValues,
77
+ });
83
78
  };
84
79
  };
85
80
  },
package/src/lib/Grid.ts CHANGED
@@ -4,7 +4,11 @@ export type Grid = Array<GridRow>;
4
4
  export type GridRow = Array<GridCell>;
5
5
  export type GridCell = Array<TypoText>;
6
6
 
7
- export function gridToPrintableLines(grid: Grid, typoSupport: TypoSupport) {
7
+ export function gridToPrintableLines(
8
+ grid: Grid,
9
+ typoSupport: TypoSupport,
10
+ delimiter: string = "",
11
+ ): Array<string> {
8
12
  const lines = new Array<string>();
9
13
  const gridWidths = new Array<number>();
10
14
  for (const gridRow of grid) {
@@ -42,7 +46,7 @@ export function gridToPrintableLines(grid: Grid, typoSupport: TypoSupport) {
42
46
  lineColumns.push(parts.join(""));
43
47
  }
44
48
  }
45
- lines.push(lineColumns.join(" "));
49
+ lines.push(lineColumns.join(delimiter));
46
50
  }
47
51
  return lines;
48
52
  }
package/src/lib/Run.ts CHANGED
@@ -3,18 +3,17 @@ import { ReaderTokenizer } from "./Reader";
3
3
  import { typoInferSupport } from "./Typo";
4
4
  import { usageToPrintableLines } from "./Usage";
5
5
 
6
- export async function runWithArgv<Context, Result>(
7
- argv: string[],
6
+ export async function runCommand<Context, Result>(
7
+ cliName: Lowercase<string>,
8
+ cliArgs: Array<string>,
8
9
  context: Context,
9
10
  command: Command<Context, Result>,
10
11
  cliInfo?: {
11
- name?: Lowercase<string>;
12
12
  version?: string;
13
13
  helpOnError?: boolean;
14
14
  },
15
15
  ): Promise<Result> {
16
- const cliName = cliInfo?.name ?? argv[1]!;
17
- const readerTokenizer = new ReaderTokenizer(argv.slice(2));
16
+ const readerTokenizer = new ReaderTokenizer(cliArgs);
18
17
  if (cliInfo?.version) {
19
18
  readerTokenizer.registerFlag({
20
19
  key: "version",
@@ -65,7 +64,7 @@ export async function runWithArgv<Context, Result>(
65
64
  }).join("\n"),
66
65
  );
67
66
  }
68
- console.error(error);
67
+ console.error(error); // TODO - better, prettier errors
69
68
  process.exit(1);
70
69
  }
71
70
  } catch (error) {
package/src/lib/Type.ts CHANGED
@@ -48,10 +48,35 @@ export const typeBigInt: Type<bigint> = {
48
48
  },
49
49
  };
50
50
 
51
- export function typeCommaArray(elementType: Type<any>): Type<Array<any>> {
51
+ export function typeCommaTuple<
52
+ const Elements extends Array<any>,
53
+ >(elementTypes: {
54
+ [K in keyof Elements]: Type<Elements[K]>;
55
+ }): Type<Elements> {
56
+ return {
57
+ label: elementTypes
58
+ .map((elementType) => elementType.label)
59
+ .join(",") as Uppercase<string>,
60
+ decoder(value: string) {
61
+ const parts = value.split(",", elementTypes.length);
62
+ if (parts.length !== elementTypes.length) {
63
+ throw new Error(
64
+ `Invalid tuple value: ${value}, expected ${elementTypes.length} parts`,
65
+ );
66
+ }
67
+ return parts.map((part, index) =>
68
+ elementTypes[index]!.decoder(part),
69
+ ) as Elements;
70
+ },
71
+ };
72
+ }
73
+
74
+ export function typeCommaList<Value>(
75
+ elementType: Type<Value>,
76
+ ): Type<Array<Value>> {
52
77
  return {
53
78
  label:
54
- `${elementType.label}[${elementType.label},...]` as Uppercase<string>,
79
+ `${elementType.label}[,${elementType.label}...]` as Uppercase<string>,
55
80
  decoder(value: string) {
56
81
  return value.split(",").map(elementType.decoder);
57
82
  },
package/src/lib/Typo.ts CHANGED
@@ -63,11 +63,20 @@ export function typoInferSupport(): TypoSupport {
63
63
  const resetCode = "\x1b[0m";
64
64
  const boldCode = "\x1b[1m";
65
65
  const colorCodes = {
66
- red: "\x1b[31m",
67
- green: "\x1b[32m",
68
- yellow: "\x1b[33m",
69
- blue: "\x1b[34m",
70
- magenta: "\x1b[35m",
71
- cyan: "\x1b[36m",
72
- grey: "\x1b[90m",
66
+ darkBlack: "\x1b[30m",
67
+ darkRed: "\x1b[31m",
68
+ darkGreen: "\x1b[32m",
69
+ darkYellow: "\x1b[33m",
70
+ darkBlue: "\x1b[34m",
71
+ darkMagenta: "\x1b[35m",
72
+ darkCyan: "\x1b[36m",
73
+ darkWhite: "\x1b[37m",
74
+ brightBlack: "\x1b[90m",
75
+ brightRed: "\x1b[91m",
76
+ brightGreen: "\x1b[92m",
77
+ brightYellow: "\x1b[93m",
78
+ brightBlue: "\x1b[94m",
79
+ brightMagenta: "\x1b[95m",
80
+ brightCyan: "\x1b[96m",
81
+ brightWhite: "\x1b[97m",
73
82
  };
package/src/lib/Usage.ts CHANGED
@@ -3,7 +3,7 @@ import { GridCell, GridRow, gridToPrintableLines } from "./Grid";
3
3
  import { TypoSupport, TypoText, typoPrintableString } from "./Typo";
4
4
 
5
5
  export function usageToPrintableLines(params: {
6
- cliName: string;
6
+ cliName: Lowercase<string>;
7
7
  commandUsage: CommandUsage;
8
8
  typoSupport: TypoSupport;
9
9
  }) {
@@ -11,42 +11,61 @@ export function usageToPrintableLines(params: {
11
11
 
12
12
  const lines = new Array<string>();
13
13
 
14
- lines.push("");
15
- lines.push(typoPrintableString(typoSupport, textDesc(commandUsage.title)));
16
- if (commandUsage.description) {
17
- for (const descriptionLine of commandUsage.description) {
18
- lines.push(typoPrintableString(typoSupport, textSubs(descriptionLine)));
14
+ lines.push(
15
+ typoPrintableString(typoSupport, textDescription(commandUsage.description)),
16
+ );
17
+ if (commandUsage.details) {
18
+ for (const detailLine of commandUsage.details) {
19
+ lines.push(typoPrintableString(typoSupport, textDetails(detailLine)));
19
20
  }
20
21
  }
21
22
 
22
- const breadcrumbPrefix = typoPrintableString(
23
- typoSupport,
24
- textTitle("Usage:"),
25
- );
26
- const breadcrumbsItems = [
27
- typoPrintableString(typoSupport, textName(cliName)),
23
+ lines.push("");
24
+ lines.push(typoPrintableString(typoSupport, textCategory("Usage:")));
25
+ const breadcrumbs = [
26
+ " ",
27
+ typoPrintableString(typoSupport, textFixed(cliName)),
28
28
  ].concat(
29
29
  commandUsage.breadcrumbs.map((breadcrumb) => {
30
- if (breadcrumb.kind === "argument") {
31
- return typoPrintableString(typoSupport, textValue(breadcrumb.value));
30
+ if ("argument" in breadcrumb) {
31
+ return typoPrintableString(typoSupport, textInput(breadcrumb.argument));
32
+ }
33
+ if ("command" in breadcrumb) {
34
+ return typoPrintableString(typoSupport, textFixed(breadcrumb.command));
32
35
  }
33
- return typoPrintableString(typoSupport, textName(breadcrumb.value));
36
+ throw new Error(`Unknown breadcrumb: ${JSON.stringify(breadcrumb)}`);
34
37
  }),
35
38
  );
36
- lines.push("");
37
- lines.push(`${breadcrumbPrefix} ${breadcrumbsItems.join(" ")}`);
39
+ lines.push(breadcrumbs.join(" "));
38
40
 
39
41
  if (commandUsage.arguments.length > 0) {
40
42
  lines.push("");
41
- lines.push(typoPrintableString(typoSupport, textTitle("Arguments:")));
43
+ lines.push(typoPrintableString(typoSupport, textCategory("Arguments:")));
42
44
  const grid = new Array<GridRow>();
43
45
  for (const argumentUsage of commandUsage.arguments) {
44
46
  const gridRow = new Array<GridCell>();
45
- gridRow.push([]);
46
- gridRow.push([textValue(argumentUsage.label)]);
47
- gridRow.push([]);
47
+ gridRow.push([textDelimiter()]);
48
+ gridRow.push([textInput(argumentUsage.label)]);
48
49
  if (argumentUsage.description) {
49
- gridRow.push([textDesc(argumentUsage.description)]);
50
+ gridRow.push([textDelimiter()]);
51
+ gridRow.push([textDescription(argumentUsage.description)]);
52
+ }
53
+ grid.push(gridRow);
54
+ }
55
+ lines.push(...gridToPrintableLines(grid, typoSupport));
56
+ }
57
+
58
+ if (commandUsage.subcommands.length > 0) {
59
+ lines.push("");
60
+ lines.push(typoPrintableString(typoSupport, textCategory("Subcommands:")));
61
+ const grid = new Array<GridRow>();
62
+ for (const subcommand of commandUsage.subcommands) {
63
+ const gridRow = new Array<GridCell>();
64
+ gridRow.push([textDelimiter()]);
65
+ gridRow.push([textFixed(subcommand.name)]);
66
+ if (subcommand.description) {
67
+ gridRow.push([textDelimiter()]);
68
+ gridRow.push([textDescription(subcommand.description)]);
50
69
  }
51
70
  grid.push(gridRow);
52
71
  }
@@ -55,72 +74,57 @@ export function usageToPrintableLines(params: {
55
74
 
56
75
  if (commandUsage.options.length > 0) {
57
76
  lines.push("");
58
- lines.push(typoPrintableString(typoSupport, textTitle("Options:")));
77
+ lines.push(typoPrintableString(typoSupport, textCategory("Options:")));
59
78
  const grid = new Array<GridRow>();
60
79
  for (const optionUsage of commandUsage.options) {
61
80
  const gridRow = new Array<GridCell>();
62
- gridRow.push([]);
81
+ gridRow.push([textDelimiter()]);
63
82
  if (optionUsage.short) {
64
- gridRow.push([textName(`-${optionUsage.short}`), { value: "," }]);
83
+ gridRow.push([textFixed(`-${optionUsage.short}`), { value: ", " }]);
65
84
  } else {
66
85
  gridRow.push([]);
67
86
  }
68
87
  if (optionUsage.label) {
69
88
  gridRow.push([
70
- textName(`--${optionUsage.long} `),
71
- textValue(optionUsage.label),
89
+ textFixed(`--${optionUsage.long} `),
90
+ textInput(optionUsage.label),
72
91
  ]);
73
92
  } else {
74
- gridRow.push([
75
- textName(`--${optionUsage.long}`),
76
- { value: "[=yes|no]", color: "grey" },
77
- ]);
93
+ gridRow.push([textFixed(`--${optionUsage.long}`)]);
78
94
  }
79
- gridRow.push([]);
80
95
  if (optionUsage.description) {
81
- gridRow.push([textDesc(optionUsage.description)]);
96
+ gridRow.push([textDelimiter()]);
97
+ gridRow.push([textDescription(optionUsage.description)]);
82
98
  }
83
99
  grid.push(gridRow);
84
100
  }
85
101
  lines.push(...gridToPrintableLines(grid, typoSupport));
86
102
  }
87
103
 
88
- if (commandUsage.subcommands.length > 0) {
89
- lines.push("");
90
- lines.push(typoPrintableString(typoSupport, textTitle("Subcommands:")));
91
- const grid = new Array<GridRow>();
92
- for (const subcommand of commandUsage.subcommands) {
93
- const gridRow = new Array<GridCell>();
94
- gridRow.push([]);
95
- gridRow.push([textName(subcommand.name)]);
96
- gridRow.push([]);
97
- if (subcommand.title) {
98
- gridRow.push([textDesc(subcommand.title)]);
99
- }
100
- grid.push(gridRow);
101
- }
102
- lines.push(...gridToPrintableLines(grid, typoSupport));
103
- }
104
104
  lines.push("");
105
105
  return lines;
106
106
  }
107
107
 
108
- function textTitle(text: string): TypoText {
109
- return { value: text, color: "green", bold: true };
108
+ function textCategory(text: string): TypoText {
109
+ return { value: text, color: "brightGreen", bold: true };
110
110
  }
111
111
 
112
- function textSubs(text: string): TypoText {
113
- return { value: text, color: "grey" };
112
+ function textDescription(text: string): TypoText {
113
+ return { value: text, bold: true };
114
114
  }
115
115
 
116
- function textDesc(text: string): TypoText {
117
- return { value: text, bold: true };
116
+ function textDetails(text: string): TypoText {
117
+ return { value: text, color: "brightBlack" };
118
+ }
119
+
120
+ function textFixed(text: string): TypoText {
121
+ return { value: text, color: "brightCyan", bold: true };
118
122
  }
119
123
 
120
- function textName(text: string): TypoText {
121
- return { value: text, color: "cyan", bold: true };
124
+ function textInput(text: string): TypoText {
125
+ return { value: text, color: "brightBlue" };
122
126
  }
123
127
 
124
- function textValue(text: string): TypoText {
125
- return { value: text, color: "cyan" };
128
+ function textDelimiter(): TypoText {
129
+ return { value: " " };
126
130
  }
@@ -5,18 +5,19 @@ import {
5
5
  argumentVariadics,
6
6
  command,
7
7
  commandWithSubcommands,
8
+ execution,
8
9
  optionFlag,
9
10
  optionRepeatable,
10
11
  optionSingleValue,
11
- process,
12
- runWithArgv,
12
+ runCommand,
13
+ typeCommaList,
13
14
  typeNumber,
14
15
  typeString,
15
16
  } from "../src";
16
17
 
17
18
  const cmd = commandWithSubcommands<string, any, any>(
18
- { title: "Root command title" },
19
- process(
19
+ { description: "Root command description" },
20
+ execution(
20
21
  {
21
22
  options: {
22
23
  booleanFlag: optionFlag({ long: "boolean-flag", default: () => false }),
@@ -27,7 +28,7 @@ const cmd = commandWithSubcommands<string, any, any>(
27
28
  }),
28
29
  numberOption: optionRepeatable({
29
30
  long: "number-option",
30
- type: typeNumber,
31
+ type: typeCommaList(typeNumber),
31
32
  }),
32
33
  },
33
34
  arguments: [
@@ -41,8 +42,8 @@ const cmd = commandWithSubcommands<string, any, any>(
41
42
  ),
42
43
  {
43
44
  sub1: command(
44
- { title: "Subcommand 1 title" },
45
- process(
45
+ { description: "Subcommand 1 description" },
46
+ execution(
46
47
  {
47
48
  options: {},
48
49
  arguments: [argumentRequired({ type: typeString })],
@@ -53,8 +54,8 @@ const cmd = commandWithSubcommands<string, any, any>(
53
54
  ),
54
55
  ),
55
56
  sub2: command(
56
- { title: "Subcommand 2 title" },
57
- process(
57
+ { description: "Subcommand 2 description" },
58
+ execution(
58
59
  {
59
60
  options: {},
60
61
  arguments: [
@@ -72,8 +73,9 @@ const cmd = commandWithSubcommands<string, any, any>(
72
73
  );
73
74
 
74
75
  it("run", async () => {
75
- const res1 = await runWithArgv(
76
- ["node", "script", "50", "51", "sub1", "final"],
76
+ const res1 = await runCommand(
77
+ "script",
78
+ ["50", "51", "sub1", "final"],
77
79
  "Run Context Input",
78
80
  cmd,
79
81
  );
@@ -97,18 +99,17 @@ it("run", async () => {
97
99
  at: "sub1",
98
100
  });
99
101
 
100
- const res2 = await runWithArgv(
102
+ const res2 = await runCommand(
103
+ "script",
101
104
  [
102
- "node",
103
- "script",
104
105
  "40",
105
106
  "41",
106
107
  "sub2",
107
108
  "--string-option=hello",
108
109
  "--number-option",
109
- "123",
110
+ "123.1,123.2",
110
111
  "--number-option",
111
- "1234",
112
+ "123.3",
112
113
  "88.88",
113
114
  "a,b",
114
115
  "final",
@@ -124,7 +125,7 @@ it("run", async () => {
124
125
  options: {
125
126
  booleanFlag: true,
126
127
  stringOption: "hello",
127
- numberOption: [123, 1234],
128
+ numberOption: [[123.1, 123.2], [123.3]],
128
129
  },
129
130
  arguments: [40, 41],
130
131
  },