cli-kiss 0.1.0 → 0.1.2
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/dist/index.d.ts +28 -13
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/Command.ts +75 -52
- package/src/lib/Operation.ts +16 -8
- package/src/lib/Option.ts +17 -12
- package/src/lib/Positional.ts +15 -8
- package/src/lib/Reader.ts +2 -5
- package/src/lib/Run.ts +32 -31
- package/src/lib/Type.ts +2 -2
- package/src/lib/Usage.ts +47 -41
- package/tests/unit.command.execute.ts +3 -2
- package/tests/unit.command.usage.ts +15 -20
- package/tests/{unit.runner.test1.ts → unit.runner.cycle.ts} +102 -68
package/src/lib/Command.ts
CHANGED
|
@@ -5,24 +5,29 @@ import { ReaderArgs } from "./Reader";
|
|
|
5
5
|
import { TypoError, TypoString, typoStyleConstants, TypoText } from "./Typo";
|
|
6
6
|
|
|
7
7
|
export type Command<Context, Result> = {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
getInformation(): CommandInformation;
|
|
9
|
+
createFactory(readerArgs: ReaderArgs): CommandFactory<Context, Result>;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
export type
|
|
12
|
+
export type CommandFactory<Context, Result> = {
|
|
13
13
|
generateUsage(): CommandUsage;
|
|
14
|
+
createInstance(): CommandInstance<Context, Result>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type CommandInstance<Context, Result> = {
|
|
14
18
|
executeWithContext(context: Context): Promise<Result>;
|
|
15
19
|
};
|
|
16
20
|
|
|
17
|
-
export type
|
|
21
|
+
export type CommandInformation = {
|
|
18
22
|
description: string;
|
|
23
|
+
hint?: string;
|
|
19
24
|
details?: string;
|
|
20
25
|
// TODO - printable examples ?
|
|
21
26
|
};
|
|
22
27
|
|
|
23
28
|
export type CommandUsage = {
|
|
24
|
-
metadata: CommandMetadata;
|
|
25
29
|
breadcrumbs: Array<CommandUsageBreadcrumb>;
|
|
30
|
+
information: CommandInformation;
|
|
26
31
|
positionals: Array<PositionalUsage>;
|
|
27
32
|
subcommands: Array<CommandUsageSubcommand>;
|
|
28
33
|
options: Array<OptionUsage>;
|
|
@@ -35,45 +40,51 @@ export type CommandUsageBreadcrumb =
|
|
|
35
40
|
export type CommandUsageSubcommand = {
|
|
36
41
|
name: string;
|
|
37
42
|
description: string | undefined;
|
|
43
|
+
hint: string | undefined;
|
|
38
44
|
};
|
|
39
45
|
|
|
40
46
|
export function command<Context, Result>(
|
|
41
|
-
|
|
47
|
+
information: CommandInformation,
|
|
42
48
|
operation: Operation<Context, Result>,
|
|
43
49
|
): Command<Context, Result> {
|
|
44
50
|
return {
|
|
45
|
-
|
|
46
|
-
return
|
|
51
|
+
getInformation() {
|
|
52
|
+
return information;
|
|
47
53
|
},
|
|
48
|
-
|
|
54
|
+
createFactory(readerArgs: ReaderArgs) {
|
|
49
55
|
function generateUsage(): CommandUsage {
|
|
50
56
|
const operationUsage = operation.generateUsage();
|
|
51
57
|
return {
|
|
52
|
-
metadata,
|
|
53
58
|
breadcrumbs: operationUsage.positionals.map((positional) =>
|
|
54
59
|
breadcrumbPositional(positional.label),
|
|
55
60
|
),
|
|
61
|
+
information: information,
|
|
56
62
|
positionals: operationUsage.positionals,
|
|
57
63
|
subcommands: [],
|
|
58
64
|
options: operationUsage.options,
|
|
59
65
|
};
|
|
60
66
|
}
|
|
61
67
|
try {
|
|
62
|
-
const
|
|
68
|
+
const operationFactory = operation.createFactory(readerArgs);
|
|
63
69
|
const endPositional = readerArgs.consumePositional();
|
|
64
70
|
if (endPositional !== undefined) {
|
|
65
71
|
throw Error(`Unexpected argument: "${endPositional}"`);
|
|
66
72
|
}
|
|
67
73
|
return {
|
|
68
74
|
generateUsage,
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
createInstance() {
|
|
76
|
+
const operationInstance = operationFactory.createInstance();
|
|
77
|
+
return {
|
|
78
|
+
async executeWithContext(context: Context) {
|
|
79
|
+
return await operationInstance.executeWithContext(context);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
71
82
|
},
|
|
72
83
|
};
|
|
73
84
|
} catch (error) {
|
|
74
85
|
return {
|
|
75
86
|
generateUsage,
|
|
76
|
-
|
|
87
|
+
createInstance() {
|
|
77
88
|
throw error;
|
|
78
89
|
},
|
|
79
90
|
};
|
|
@@ -83,23 +94,23 @@ export function command<Context, Result>(
|
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
export function commandWithSubcommands<Context, Payload, Result>(
|
|
86
|
-
|
|
97
|
+
information: CommandInformation,
|
|
87
98
|
operation: Operation<Context, Payload>,
|
|
88
99
|
subcommands: { [subcommand: Lowercase<string>]: Command<Payload, Result> },
|
|
89
100
|
): Command<Context, Result> {
|
|
90
101
|
return {
|
|
91
|
-
|
|
92
|
-
return
|
|
102
|
+
getInformation() {
|
|
103
|
+
return information;
|
|
93
104
|
},
|
|
94
|
-
|
|
105
|
+
createFactory(readerArgs: ReaderArgs) {
|
|
95
106
|
try {
|
|
96
|
-
const
|
|
107
|
+
const operationFactory = operation.createFactory(readerArgs);
|
|
97
108
|
const subcommandName = readerArgs.consumePositional();
|
|
98
109
|
if (subcommandName === undefined) {
|
|
99
110
|
throw new TypoError(
|
|
100
111
|
new TypoText(
|
|
101
|
-
new TypoString(
|
|
102
|
-
new TypoString(`
|
|
112
|
+
new TypoString(`<SUBCOMMAND>`, typoStyleConstants),
|
|
113
|
+
new TypoString(`: Is required, but was not provided`),
|
|
103
114
|
),
|
|
104
115
|
);
|
|
105
116
|
}
|
|
@@ -108,24 +119,22 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
108
119
|
if (subcommandInput === undefined) {
|
|
109
120
|
throw new TypoError(
|
|
110
121
|
new TypoText(
|
|
111
|
-
new TypoString(
|
|
112
|
-
new TypoString(`
|
|
113
|
-
new TypoString(`: "${subcommandName}"`),
|
|
122
|
+
new TypoString(`<SUBCOMMAND>`, typoStyleConstants),
|
|
123
|
+
new TypoString(`: Invalid value: "${subcommandName}"`),
|
|
114
124
|
),
|
|
115
125
|
);
|
|
116
126
|
}
|
|
117
|
-
const
|
|
118
|
-
subcommandInput.createRunnerFromArgs(readerArgs);
|
|
127
|
+
const subcommandFactory = subcommandInput.createFactory(readerArgs);
|
|
119
128
|
return {
|
|
120
129
|
generateUsage() {
|
|
121
130
|
const operationUsage = operation.generateUsage();
|
|
122
|
-
const subcommandUsage =
|
|
131
|
+
const subcommandUsage = subcommandFactory.generateUsage();
|
|
123
132
|
return {
|
|
124
|
-
metadata: subcommandUsage.metadata,
|
|
125
133
|
breadcrumbs: operationUsage.positionals
|
|
126
134
|
.map((positional) => breadcrumbPositional(positional.label))
|
|
127
135
|
.concat([breadcrumbCommand(subcommandName)])
|
|
128
136
|
.concat(subcommandUsage.breadcrumbs),
|
|
137
|
+
information: subcommandUsage.information,
|
|
129
138
|
positionals: operationUsage.positionals.concat(
|
|
130
139
|
subcommandUsage.positionals,
|
|
131
140
|
),
|
|
@@ -133,10 +142,16 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
133
142
|
options: operationUsage.options.concat(subcommandUsage.options),
|
|
134
143
|
};
|
|
135
144
|
},
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
createInstance() {
|
|
146
|
+
const operationInstance = operationFactory.createInstance();
|
|
147
|
+
const subcommandInstance = subcommandFactory.createInstance();
|
|
148
|
+
return {
|
|
149
|
+
async executeWithContext(context: Context) {
|
|
150
|
+
return await subcommandInstance.executeWithContext(
|
|
151
|
+
await operationInstance.executeWithContext(context),
|
|
152
|
+
);
|
|
153
|
+
},
|
|
154
|
+
};
|
|
140
155
|
},
|
|
141
156
|
};
|
|
142
157
|
} catch (error) {
|
|
@@ -144,21 +159,23 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
144
159
|
generateUsage() {
|
|
145
160
|
const operationUsage = operation.generateUsage();
|
|
146
161
|
return {
|
|
147
|
-
metadata,
|
|
148
162
|
breadcrumbs: operationUsage.positionals
|
|
149
163
|
.map((positional) => breadcrumbPositional(positional.label))
|
|
150
164
|
.concat([breadcrumbCommand("<SUBCOMMAND>")]),
|
|
165
|
+
information: information,
|
|
151
166
|
positionals: operationUsage.positionals,
|
|
152
|
-
subcommands: Object.entries(subcommands).map(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
subcommands: Object.entries(subcommands).map((subcommand) => {
|
|
168
|
+
const metadata = subcommand[1].getInformation();
|
|
169
|
+
return {
|
|
170
|
+
name: subcommand[0],
|
|
171
|
+
description: metadata.description,
|
|
172
|
+
hint: metadata.hint,
|
|
173
|
+
};
|
|
174
|
+
}),
|
|
158
175
|
options: operationUsage.options,
|
|
159
176
|
};
|
|
160
177
|
},
|
|
161
|
-
|
|
178
|
+
createInstance() {
|
|
162
179
|
throw error;
|
|
163
180
|
},
|
|
164
181
|
};
|
|
@@ -168,23 +185,23 @@ export function commandWithSubcommands<Context, Payload, Result>(
|
|
|
168
185
|
}
|
|
169
186
|
|
|
170
187
|
export function commandChained<Context, Payload, Result>(
|
|
171
|
-
metadata:
|
|
188
|
+
metadata: CommandInformation,
|
|
172
189
|
operation: Operation<Context, Payload>,
|
|
173
190
|
nextCommand: Command<Payload, Result>,
|
|
174
191
|
): Command<Context, Result> {
|
|
175
192
|
return {
|
|
176
|
-
|
|
177
|
-
return metadata
|
|
193
|
+
getInformation() {
|
|
194
|
+
return metadata;
|
|
178
195
|
},
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
196
|
+
createFactory(readerArgs: ReaderArgs) {
|
|
197
|
+
const operationFactory = operation.createFactory(readerArgs);
|
|
198
|
+
const nextCommandFactory = nextCommand.createFactory(readerArgs);
|
|
182
199
|
return {
|
|
183
200
|
generateUsage() {
|
|
184
201
|
const operationUsage = operation.generateUsage();
|
|
185
|
-
const nextCommandUsage =
|
|
202
|
+
const nextCommandUsage = nextCommandFactory.generateUsage();
|
|
186
203
|
return {
|
|
187
|
-
|
|
204
|
+
information: nextCommandUsage.information,
|
|
188
205
|
breadcrumbs: operationUsage.positionals
|
|
189
206
|
.map((positional) => breadcrumbPositional(positional.label))
|
|
190
207
|
.concat(nextCommandUsage.breadcrumbs),
|
|
@@ -195,10 +212,16 @@ export function commandChained<Context, Payload, Result>(
|
|
|
195
212
|
options: operationUsage.options.concat(nextCommandUsage.options),
|
|
196
213
|
};
|
|
197
214
|
},
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
215
|
+
createInstance() {
|
|
216
|
+
const operationInstance = operationFactory.createInstance();
|
|
217
|
+
const nextCommandInstance = nextCommandFactory.createInstance();
|
|
218
|
+
return {
|
|
219
|
+
async executeWithContext(context: Context) {
|
|
220
|
+
return await nextCommandInstance.executeWithContext(
|
|
221
|
+
await operationInstance.executeWithContext(context),
|
|
222
|
+
);
|
|
223
|
+
},
|
|
224
|
+
};
|
|
202
225
|
},
|
|
203
226
|
};
|
|
204
227
|
},
|
package/src/lib/Operation.ts
CHANGED
|
@@ -4,10 +4,14 @@ import { ReaderArgs } from "./Reader";
|
|
|
4
4
|
|
|
5
5
|
export type Operation<Input, Output> = {
|
|
6
6
|
generateUsage(): OperationUsage;
|
|
7
|
-
|
|
7
|
+
createFactory(readerArgs: ReaderArgs): OperationFactory<Input, Output>;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export type
|
|
10
|
+
export type OperationFactory<Input, Output> = {
|
|
11
|
+
createInstance(): OperationInstance<Input, Output>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type OperationInstance<Input, Output> = {
|
|
11
15
|
executeWithContext(input: Input): Promise<Output>;
|
|
12
16
|
};
|
|
13
17
|
|
|
@@ -46,7 +50,7 @@ export function operation<
|
|
|
46
50
|
}
|
|
47
51
|
return { options: optionsUsage, positionals: positionalsUsage };
|
|
48
52
|
},
|
|
49
|
-
|
|
53
|
+
createFactory(readerArgs: ReaderArgs) {
|
|
50
54
|
const optionsGetters: any = {};
|
|
51
55
|
for (const optionKey in inputs.options) {
|
|
52
56
|
const optionInput = inputs.options[optionKey]!;
|
|
@@ -57,15 +61,19 @@ export function operation<
|
|
|
57
61
|
positionalsValues.push(positionalInput.consumePositionals(readerArgs));
|
|
58
62
|
}
|
|
59
63
|
return {
|
|
60
|
-
|
|
64
|
+
createInstance() {
|
|
61
65
|
const optionsValues: any = {};
|
|
62
66
|
for (const optionKey in optionsGetters) {
|
|
63
67
|
optionsValues[optionKey] = optionsGetters[optionKey]!.getValue();
|
|
64
68
|
}
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
return {
|
|
70
|
+
executeWithContext(context: Context) {
|
|
71
|
+
return handler(context, {
|
|
72
|
+
options: optionsValues,
|
|
73
|
+
positionals: positionalsValues,
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
};
|
|
69
77
|
},
|
|
70
78
|
};
|
|
71
79
|
},
|
package/src/lib/Option.ts
CHANGED
|
@@ -15,10 +15,10 @@ export type Option<Value> = {
|
|
|
15
15
|
|
|
16
16
|
export type OptionUsage = {
|
|
17
17
|
description: string | undefined;
|
|
18
|
+
hint: string | undefined;
|
|
18
19
|
long: Lowercase<string>; // TODO - better type for long option names ?
|
|
19
20
|
short: string | undefined;
|
|
20
21
|
label: Uppercase<string> | undefined;
|
|
21
|
-
// TODO - default value for usage ? but it can be dynamic, so maybe not
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
export type OptionGetter<Value> = {
|
|
@@ -29,13 +29,16 @@ export function optionFlag(definition: {
|
|
|
29
29
|
long: Lowercase<string>;
|
|
30
30
|
short?: string;
|
|
31
31
|
description?: string;
|
|
32
|
+
hint?: string;
|
|
32
33
|
aliases?: { longs?: Array<Lowercase<string>>; shorts?: Array<string> };
|
|
33
34
|
default?: () => boolean;
|
|
34
35
|
}): Option<boolean> {
|
|
36
|
+
const label = `<${typeBoolean.label}>` as Uppercase<string>;
|
|
35
37
|
return {
|
|
36
38
|
generateUsage() {
|
|
37
39
|
return {
|
|
38
40
|
description: definition.description,
|
|
41
|
+
hint: definition.hint,
|
|
39
42
|
long: definition.long,
|
|
40
43
|
short: definition.short,
|
|
41
44
|
label: undefined,
|
|
@@ -52,9 +55,8 @@ export function optionFlag(definition: {
|
|
|
52
55
|
if (optionValues.length > 1) {
|
|
53
56
|
throw new TypoError(
|
|
54
57
|
new TypoText(
|
|
55
|
-
new TypoString(`Option value for: `),
|
|
56
58
|
new TypoString(`--${definition.long}`, typoStyleConstants),
|
|
57
|
-
new TypoString(`:
|
|
59
|
+
new TypoString(`: Must not be set multiple times`),
|
|
58
60
|
),
|
|
59
61
|
);
|
|
60
62
|
}
|
|
@@ -66,8 +68,8 @@ export function optionFlag(definition: {
|
|
|
66
68
|
} catch (error) {
|
|
67
69
|
throw new TypoError(
|
|
68
70
|
new TypoText(
|
|
69
|
-
new TypoString(`Failed to compute default value for: `),
|
|
70
71
|
new TypoString(`--${definition.long}`, typoStyleConstants),
|
|
72
|
+
new TypoString(`: Failed to compute default value`),
|
|
71
73
|
),
|
|
72
74
|
error,
|
|
73
75
|
);
|
|
@@ -80,7 +82,7 @@ export function optionFlag(definition: {
|
|
|
80
82
|
new TypoText(
|
|
81
83
|
new TypoString(`--${definition.long}`, typoStyleConstants),
|
|
82
84
|
new TypoString(`: `),
|
|
83
|
-
new TypoString(
|
|
85
|
+
new TypoString(label, typoStyleUserInput),
|
|
84
86
|
),
|
|
85
87
|
);
|
|
86
88
|
},
|
|
@@ -93,19 +95,21 @@ export function optionSingleValue<Value>(definition: {
|
|
|
93
95
|
long: Lowercase<string>;
|
|
94
96
|
short?: string;
|
|
95
97
|
description?: string;
|
|
98
|
+
hint?: string;
|
|
96
99
|
aliases?: { longs?: Array<Lowercase<string>>; shorts?: Array<string> };
|
|
97
100
|
label?: Uppercase<string>;
|
|
98
101
|
type: Type<Value>;
|
|
99
102
|
default: () => Value;
|
|
100
103
|
}): Option<Value> {
|
|
101
|
-
const label = definition.label ?? definition.type.label
|
|
104
|
+
const label = `<${definition.label ?? definition.type.label}>`;
|
|
102
105
|
return {
|
|
103
106
|
generateUsage() {
|
|
104
107
|
return {
|
|
105
108
|
description: definition.description,
|
|
109
|
+
hint: definition.hint,
|
|
106
110
|
long: definition.long,
|
|
107
111
|
short: definition.short,
|
|
108
|
-
label:
|
|
112
|
+
label: label as Uppercase<string>,
|
|
109
113
|
};
|
|
110
114
|
},
|
|
111
115
|
createGetter(readerOptions: ReaderOptions) {
|
|
@@ -119,9 +123,8 @@ export function optionSingleValue<Value>(definition: {
|
|
|
119
123
|
if (optionValues.length > 1) {
|
|
120
124
|
throw new TypoError(
|
|
121
125
|
new TypoText(
|
|
122
|
-
new TypoString(`Option value for: `),
|
|
123
126
|
new TypoString(`--${definition.long}`, typoStyleConstants),
|
|
124
|
-
new TypoString(`:
|
|
127
|
+
new TypoString(`: Must not be set multiple times`),
|
|
125
128
|
),
|
|
126
129
|
);
|
|
127
130
|
}
|
|
@@ -132,8 +135,8 @@ export function optionSingleValue<Value>(definition: {
|
|
|
132
135
|
} catch (error) {
|
|
133
136
|
throw new TypoError(
|
|
134
137
|
new TypoText(
|
|
135
|
-
new TypoString(`Failed to compute default value for: `),
|
|
136
138
|
new TypoString(`--${definition.long}`, typoStyleConstants),
|
|
139
|
+
new TypoString(`: Failed to compute default value`),
|
|
137
140
|
),
|
|
138
141
|
error,
|
|
139
142
|
);
|
|
@@ -159,19 +162,21 @@ export function optionRepeatable<Value>(definition: {
|
|
|
159
162
|
long: Lowercase<string>;
|
|
160
163
|
short?: string;
|
|
161
164
|
description?: string;
|
|
165
|
+
hint?: string;
|
|
162
166
|
aliases?: { longs?: Array<Lowercase<string>>; shorts?: Array<string> };
|
|
163
167
|
label?: Uppercase<string>;
|
|
164
168
|
type: Type<Value>;
|
|
165
169
|
}): Option<Array<Value>> {
|
|
166
|
-
const label = definition.label ?? definition.type.label
|
|
170
|
+
const label = `<${definition.label ?? definition.type.label}>`;
|
|
167
171
|
return {
|
|
168
172
|
generateUsage() {
|
|
169
173
|
// TODO - showcase that it can be repeated ?
|
|
170
174
|
return {
|
|
171
175
|
description: definition.description,
|
|
176
|
+
hint: definition.hint,
|
|
172
177
|
long: definition.long,
|
|
173
178
|
short: definition.short,
|
|
174
|
-
label:
|
|
179
|
+
label: label as Uppercase<string>,
|
|
175
180
|
};
|
|
176
181
|
},
|
|
177
182
|
createGetter(readerOptions: ReaderOptions) {
|
package/src/lib/Positional.ts
CHANGED
|
@@ -9,20 +9,23 @@ export type Positional<Value> = {
|
|
|
9
9
|
|
|
10
10
|
export type PositionalUsage = {
|
|
11
11
|
description: string | undefined;
|
|
12
|
+
hint: string | undefined;
|
|
12
13
|
label: Uppercase<string>;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export function positionalRequired<Value>(definition: {
|
|
16
17
|
description?: string;
|
|
18
|
+
hint?: string;
|
|
17
19
|
label?: Uppercase<string>;
|
|
18
20
|
type: Type<Value>;
|
|
19
21
|
}): Positional<Value> {
|
|
20
|
-
const label = definition.label ?? definition.type.label
|
|
22
|
+
const label = `<${definition.label ?? definition.type.label}>`;
|
|
21
23
|
return {
|
|
22
24
|
generateUsage() {
|
|
23
25
|
return {
|
|
24
26
|
description: definition.description,
|
|
25
|
-
|
|
27
|
+
hint: definition.hint,
|
|
28
|
+
label: label as Uppercase<string>,
|
|
26
29
|
};
|
|
27
30
|
},
|
|
28
31
|
consumePositionals(readerPositionals: ReaderPositionals) {
|
|
@@ -30,8 +33,8 @@ export function positionalRequired<Value>(definition: {
|
|
|
30
33
|
if (positional === undefined) {
|
|
31
34
|
throw new TypoError(
|
|
32
35
|
new TypoText(
|
|
33
|
-
new TypoString(`Missing required positional argument: `),
|
|
34
36
|
new TypoString(label, typoStyleUserInput),
|
|
37
|
+
new TypoString(`: Is required, but was not provided`),
|
|
35
38
|
),
|
|
36
39
|
);
|
|
37
40
|
}
|
|
@@ -46,16 +49,18 @@ export function positionalRequired<Value>(definition: {
|
|
|
46
49
|
|
|
47
50
|
export function positionalOptional<Value>(definition: {
|
|
48
51
|
description?: string;
|
|
52
|
+
hint?: string;
|
|
49
53
|
label?: Uppercase<string>;
|
|
50
54
|
type: Type<Value>;
|
|
51
55
|
default: () => Value;
|
|
52
56
|
}): Positional<Value> {
|
|
53
|
-
const label = definition.label ?? definition.type.label
|
|
57
|
+
const label = `[${definition.label ?? definition.type.label}]`;
|
|
54
58
|
return {
|
|
55
59
|
generateUsage() {
|
|
56
60
|
return {
|
|
57
61
|
description: definition.description,
|
|
58
|
-
|
|
62
|
+
hint: definition.hint,
|
|
63
|
+
label: label as Uppercase<string>,
|
|
59
64
|
};
|
|
60
65
|
},
|
|
61
66
|
consumePositionals(readerPositionals: ReaderPositionals) {
|
|
@@ -66,8 +71,8 @@ export function positionalOptional<Value>(definition: {
|
|
|
66
71
|
} catch (error) {
|
|
67
72
|
throw new TypoError(
|
|
68
73
|
new TypoText(
|
|
69
|
-
new TypoString(`Failed to compute default value for: `),
|
|
70
74
|
new TypoString(label, typoStyleUserInput),
|
|
75
|
+
new TypoString(`: Failed to compute default value`),
|
|
71
76
|
),
|
|
72
77
|
error,
|
|
73
78
|
);
|
|
@@ -85,15 +90,17 @@ export function positionalOptional<Value>(definition: {
|
|
|
85
90
|
export function positionalVariadics<Value>(definition: {
|
|
86
91
|
endDelimiter?: string;
|
|
87
92
|
description?: string;
|
|
93
|
+
hint?: string;
|
|
88
94
|
label?: Uppercase<string>;
|
|
89
95
|
type: Type<Value>;
|
|
90
96
|
}): Positional<Array<Value>> {
|
|
91
|
-
const label = definition.label ?? definition.type.label
|
|
97
|
+
const label = `[${definition.label ?? definition.type.label}]`;
|
|
92
98
|
return {
|
|
93
99
|
generateUsage() {
|
|
94
100
|
return {
|
|
95
101
|
description: definition.description,
|
|
96
|
-
|
|
102
|
+
hint: definition.hint,
|
|
103
|
+
label: (`${label}...` +
|
|
97
104
|
(definition.endDelimiter
|
|
98
105
|
? `["${definition.endDelimiter}"]`
|
|
99
106
|
: "")) as Uppercase<string>,
|
package/src/lib/Reader.ts
CHANGED
|
@@ -146,8 +146,8 @@ export class ReaderArgs {
|
|
|
146
146
|
}
|
|
147
147
|
throw new TypoError(
|
|
148
148
|
new TypoText(
|
|
149
|
-
new TypoString(`Unknown option: `),
|
|
150
149
|
new TypoString(`-${arg.slice(shortIndexStart)}`, typoStyleConstants),
|
|
150
|
+
new TypoString(`: Unexpected unknown option`),
|
|
151
151
|
),
|
|
152
152
|
);
|
|
153
153
|
}
|
|
@@ -169,8 +169,8 @@ export class ReaderArgs {
|
|
|
169
169
|
}
|
|
170
170
|
throw new TypoError(
|
|
171
171
|
new TypoText(
|
|
172
|
-
new TypoString(`Unknown option: `),
|
|
173
172
|
new TypoString(constant, typoStyleConstants),
|
|
173
|
+
new TypoString(`: Unexpected unknown option`),
|
|
174
174
|
),
|
|
175
175
|
);
|
|
176
176
|
}
|
|
@@ -202,7 +202,6 @@ export class ReaderArgs {
|
|
|
202
202
|
if (arg === null) {
|
|
203
203
|
throw new TypoError(
|
|
204
204
|
new TypoText(
|
|
205
|
-
new TypoString(`Option parsing: `),
|
|
206
205
|
new TypoString(constant, typoStyleConstants),
|
|
207
206
|
new TypoString(`: requires a value, but got end of input`),
|
|
208
207
|
),
|
|
@@ -211,7 +210,6 @@ export class ReaderArgs {
|
|
|
211
210
|
if (this.#parsedDouble) {
|
|
212
211
|
throw new TypoError(
|
|
213
212
|
new TypoText(
|
|
214
|
-
new TypoString(`Option parsing: `),
|
|
215
213
|
new TypoString(constant, typoStyleConstants),
|
|
216
214
|
new TypoString(`: requires a value before "--"`),
|
|
217
215
|
),
|
|
@@ -221,7 +219,6 @@ export class ReaderArgs {
|
|
|
221
219
|
if (arg.startsWith("-")) {
|
|
222
220
|
throw new TypoError(
|
|
223
221
|
new TypoText(
|
|
224
|
-
new TypoString(`Option parsing: `),
|
|
225
222
|
new TypoString(constant, typoStyleConstants),
|
|
226
223
|
new TypoString(`: requires a value, but got: "${arg}"`),
|
|
227
224
|
),
|