@gunshi/plugin-renderer 1.0.0-beta.0 → 1.0.0-beta.1
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/index.d.ts +577 -52
- package/lib/index.js +29 -6
- package/package.json +5 -5
package/lib/index.d.ts
CHANGED
|
@@ -1,18 +1,567 @@
|
|
|
1
1
|
import { Args, Command, CommandContext, DefaultGunshiParams, GunshiParams, PluginWithExtension } from "@gunshi/plugin";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
//#region
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import "@gunshi/plugin-i18n";
|
|
3
|
+
//#region ../../node_modules/.pnpm/args-tokens@1.0.0-beta.1/node_modules/args-tokens/lib/resolver.d.ts
|
|
4
|
+
//#region src/resolver.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* An argument schema definition for command-line argument parsing.
|
|
7
|
+
*
|
|
8
|
+
* This schema is similar to the schema of Node.js `util.parseArgs` but with extended features:
|
|
9
|
+
* - Additional `required`, `description`, and `hidden` properties
|
|
10
|
+
* - Extended `type` support: 'string', 'boolean', 'number', 'enum', 'positional', 'custom'
|
|
11
|
+
* - Simplified `default` property (single type, not union types)
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* Basic string argument:
|
|
15
|
+
* ```ts
|
|
16
|
+
* const schema: ArgSchema = {
|
|
17
|
+
* type: 'string',
|
|
18
|
+
* description: 'Server hostname',
|
|
19
|
+
* default: 'localhost'
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* Required number argument with alias:
|
|
25
|
+
* ```ts
|
|
26
|
+
* const schema: ArgSchema = {
|
|
27
|
+
* type: 'number',
|
|
28
|
+
* short: 'p',
|
|
29
|
+
* description: 'Port number to listen on',
|
|
30
|
+
* required: true
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* Enum argument with choices:
|
|
36
|
+
* ```ts
|
|
37
|
+
* const schema: ArgSchema = {
|
|
38
|
+
* type: 'enum',
|
|
39
|
+
* choices: ['info', 'warn', 'error'],
|
|
40
|
+
* description: 'Logging level',
|
|
41
|
+
* default: 'info'
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
interface ArgSchema {
|
|
46
|
+
/**
|
|
47
|
+
* Type of the argument value.
|
|
48
|
+
*
|
|
49
|
+
* - `'string'`: Text value
|
|
50
|
+
* - `'boolean'`: `true`/`false` flag (can be negatable with `--no-` prefix). `--flag=true` and
|
|
51
|
+
* `--flag=false` set the value explicitly; any other value after `=` is a type error
|
|
52
|
+
* - `'number'`: Numeric value (parsed as integer or float)
|
|
53
|
+
* - `'enum'`: One of predefined string values (requires `choices` property, unless the argument
|
|
54
|
+
* has a `parse` function)
|
|
55
|
+
* - `'positional'`: Non-option argument by position
|
|
56
|
+
* - `'custom'`: Custom parsing with user-defined `parse` function
|
|
57
|
+
*
|
|
58
|
+
* Any other `type`, or no `type`, is a mistake that only untyped code can make: if the argument
|
|
59
|
+
* has no `parse` function, {@link resolveArgs} and `parse()` throw an `Error`, whether or not the
|
|
60
|
+
* argument is given.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* Different argument types:
|
|
64
|
+
* ```ts
|
|
65
|
+
* {
|
|
66
|
+
* name: { type: 'string' }, // --name value
|
|
67
|
+
* verbose: { type: 'boolean' }, // --verbose (--no-verbose needs negatable: true)
|
|
68
|
+
* port: { type: 'number' }, // --port 3000
|
|
69
|
+
* level: { type: 'enum', choices: ['debug', 'info'] },
|
|
70
|
+
* file: { type: 'positional' }, // first positional arg
|
|
71
|
+
* config: { type: 'custom', parse: JSON.parse }
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
type: 'string' | 'boolean' | 'number' | 'enum' | 'positional' | 'custom';
|
|
76
|
+
/**
|
|
77
|
+
* Single character alias for the long option name.
|
|
78
|
+
*
|
|
79
|
+
* As example, allows users to use `-x` instead of `--extended-option`.
|
|
80
|
+
* Only valid for non-positional argument types.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* Short alias usage:
|
|
84
|
+
* ```ts
|
|
85
|
+
* {
|
|
86
|
+
* verbose: {
|
|
87
|
+
* type: 'boolean',
|
|
88
|
+
* short: 'v' // Enables both --verbose and -v
|
|
89
|
+
* },
|
|
90
|
+
* port: {
|
|
91
|
+
* type: 'number',
|
|
92
|
+
* short: 'p' // Enables both --port 3000 and -p 3000
|
|
93
|
+
* }
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
short?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Human-readable description of the argument's purpose.
|
|
100
|
+
*
|
|
101
|
+
* Used for help text generation and documentation.
|
|
102
|
+
* Should be concise but descriptive enough to understand the argument's role.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* Descriptive help text:
|
|
106
|
+
* ```ts
|
|
107
|
+
* {
|
|
108
|
+
* config: {
|
|
109
|
+
* type: 'string',
|
|
110
|
+
* description: 'Path to configuration file'
|
|
111
|
+
* },
|
|
112
|
+
* timeout: {
|
|
113
|
+
* type: 'number',
|
|
114
|
+
* description: 'Request timeout in milliseconds'
|
|
115
|
+
* }
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
description?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Hide the argument from generated help or usage output.
|
|
122
|
+
*
|
|
123
|
+
* This is metadata for renderers. It does not affect parsing, validation,
|
|
124
|
+
* required checks, defaults, conflicts, or resolved values.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* Hidden compatibility option:
|
|
128
|
+
* ```ts
|
|
129
|
+
* {
|
|
130
|
+
* legacy: {
|
|
131
|
+
* type: 'string',
|
|
132
|
+
* hidden: true,
|
|
133
|
+
* description: 'Deprecated compatibility option'
|
|
134
|
+
* }
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
hidden?: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Marks the argument as required.
|
|
141
|
+
*
|
|
142
|
+
* When `true`, the argument must be provided by the user. If it is missing, the error is an
|
|
143
|
+
* `ArgResolveError` with type 'required' and the code `err:arg:required-option`
|
|
144
|
+
* ({@link ArgsValidationErrorKeys}.requiredOption), or `err:arg:required-positional`
|
|
145
|
+
* ({@link ArgsValidationErrorKeys}.requiredPositional) for a positional argument. Its
|
|
146
|
+
* `values` has the `displayName` as in the message, such as `'--name'` for an option
|
|
147
|
+
* (`'--name' or '-n'` with the short name `n`) and `'file'` for a positional argument, and
|
|
148
|
+
* the `name`, which is the schema key.
|
|
149
|
+
* An option that is given without a value is reported as `err:arg:missing-value`
|
|
150
|
+
* ({@link ArgsValidationErrorKeys}.missingValue) instead, because the option itself was given.
|
|
151
|
+
* An explicit empty value, such as `--name=` or `-n ''`, is still reported as required, but the
|
|
152
|
+
* option counts as given: it is `true` in `explicit` and takes part in conflicts, as any other
|
|
153
|
+
* given option does.
|
|
154
|
+
*
|
|
155
|
+
* For single-value positional arguments, omitting `required` keeps the argument required for
|
|
156
|
+
* compatibility, unless it has a `default`, which makes it optional. A `multiple` positional
|
|
157
|
+
* argument is optional unless `required: true` is set. Set `required: false` to make a positional
|
|
158
|
+
* argument explicitly optional. Optional positional arguments leave enough input values for later
|
|
159
|
+
* required positional arguments before consuming a value.
|
|
160
|
+
*
|
|
161
|
+
* In the type of the values, such as {@link ArgValues}, a single-value positional argument whose
|
|
162
|
+
* `required` may be `false`, such as one of type `boolean`, is optional, as it may be missing,
|
|
163
|
+
* unless it has a `default`. An optional `required` of type `boolean`, as declared here, says
|
|
164
|
+
* nothing, and keeps it required. TypeScript widens a `required: true` to `boolean` in a schema
|
|
165
|
+
* written apart from the call, such as `{ type: 'positional' as const, required: true }`, which
|
|
166
|
+
* types the argument as optional: write such a schema `as const`.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* Required arguments:
|
|
170
|
+
* ```ts
|
|
171
|
+
* {
|
|
172
|
+
* input: {
|
|
173
|
+
* type: 'string',
|
|
174
|
+
* required: true, // Must be provided: --input file.txt
|
|
175
|
+
* description: 'Input file path'
|
|
176
|
+
* },
|
|
177
|
+
* source: {
|
|
178
|
+
* type: 'positional',
|
|
179
|
+
* required: true // First positional argument must exist
|
|
180
|
+
* }
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
required?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Allows the argument to accept multiple values.
|
|
187
|
+
*
|
|
188
|
+
* When `true`, the resolved value becomes an array. When the argument is not given and has no
|
|
189
|
+
* `default`, its value is `undefined`, not an empty array.
|
|
190
|
+
* For options: can be specified multiple times (--tags foo --tags bar)
|
|
191
|
+
* For positional: collects remaining positional arguments after preserving values for
|
|
192
|
+
* later required positional arguments.
|
|
193
|
+
*
|
|
194
|
+
* Note: Only `true` is allowed (not `false`) to make intent explicit.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* Multiple values:
|
|
198
|
+
* ```ts
|
|
199
|
+
* {
|
|
200
|
+
* tags: {
|
|
201
|
+
* type: 'string',
|
|
202
|
+
* multiple: true, // --tags foo --tags bar → ['foo', 'bar']
|
|
203
|
+
* description: 'Tags to apply'
|
|
204
|
+
* },
|
|
205
|
+
* files: {
|
|
206
|
+
* type: 'positional',
|
|
207
|
+
* multiple: true // Collects all remaining positional args
|
|
208
|
+
* }
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
multiple?: true;
|
|
213
|
+
/**
|
|
214
|
+
* Enables negation for boolean arguments using `--no-` prefix.
|
|
215
|
+
*
|
|
216
|
+
* When `true`, allows users to explicitly set the boolean to `false`
|
|
217
|
+
* using `--no-option-name`. When `false` or omitted, only positive
|
|
218
|
+
* form is available.
|
|
219
|
+
*
|
|
220
|
+
* Only applicable to `type: 'boolean'` arguments.
|
|
221
|
+
*
|
|
222
|
+
* The negated name is always `no-` followed by the full option name. An option named
|
|
223
|
+
* `no-cache` is negated by `--no-no-cache`, and `--no-cache` sets it to `true`.
|
|
224
|
+
*
|
|
225
|
+
* The negated form does not take a value. `--no-flag=<value>` is reported as
|
|
226
|
+
* `err:arg:unexpected-value` ({@link ArgsValidationErrorKeys}.unexpectedValue).
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* Negatable boolean:
|
|
230
|
+
* ```ts
|
|
231
|
+
* {
|
|
232
|
+
* color: {
|
|
233
|
+
* type: 'boolean',
|
|
234
|
+
* negatable: true,
|
|
235
|
+
* default: true,
|
|
236
|
+
* description: 'Enable colorized output'
|
|
237
|
+
* }
|
|
238
|
+
* // Usage: --color (true), --no-color (false)
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
negatable?: boolean;
|
|
243
|
+
/**
|
|
244
|
+
* Array of allowed string values for enum-type arguments.
|
|
245
|
+
*
|
|
246
|
+
* Required when `type: 'enum'`, unless the argument has a `parse` function: if `choices` is
|
|
247
|
+
* missing or not an array, {@link resolveArgs} and `parse()` throw a `TypeError`, whether or not
|
|
248
|
+
* the argument is given. With a `parse` function and no `choices`, the value is passed to the
|
|
249
|
+
* function as for a `string` argument with a `parse` function.
|
|
250
|
+
*
|
|
251
|
+
* The argument value must be one of these choices, otherwise the error is an `ArgResolveError`
|
|
252
|
+
* with type 'type' and the code `err:arg:invalid-choice`
|
|
253
|
+
* ({@link ArgsValidationErrorKeys}.invalidChoice).
|
|
254
|
+
*
|
|
255
|
+
* The value is checked before `parse` is called, so a `parse` function receives only one of
|
|
256
|
+
* these choices and can change it, for example to upper case.
|
|
257
|
+
*
|
|
258
|
+
* Supports both mutable arrays and readonly arrays for type safety.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* Enum choices:
|
|
262
|
+
* ```ts
|
|
263
|
+
* {
|
|
264
|
+
* logLevel: {
|
|
265
|
+
* type: 'enum',
|
|
266
|
+
* choices: ['debug', 'info', 'warn', 'error'] as const,
|
|
267
|
+
* default: 'info',
|
|
268
|
+
* description: 'Logging verbosity level'
|
|
269
|
+
* },
|
|
270
|
+
* format: {
|
|
271
|
+
* type: 'enum',
|
|
272
|
+
* choices: ['json', 'yaml', 'toml'],
|
|
273
|
+
* description: 'Output format'
|
|
274
|
+
* }
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
choices?: string[] | readonly string[];
|
|
279
|
+
/**
|
|
280
|
+
* Default value used when the argument is not provided. An option that is given without a value,
|
|
281
|
+
* or with a value that is rejected, also gets its default, along with the error.
|
|
282
|
+
*
|
|
283
|
+
* The type must match the argument's `type` property:
|
|
284
|
+
* - `string` type: string default
|
|
285
|
+
* - `boolean` type: boolean default
|
|
286
|
+
* - `number` type: number default
|
|
287
|
+
* - `enum` type: one of the `choices` values, or a value that a `parse` of your own returns
|
|
288
|
+
* - `positional`/`custom` type: string, boolean, or number default
|
|
289
|
+
*
|
|
290
|
+
* The default is used as is and never goes through `parse`, including when an option is given
|
|
291
|
+
* without a value. An explicit empty value, such as `--name=` or `-n ''`, is a value, not a
|
|
292
|
+
* missing one: a `string` option without `parse` gets `''` instead of the default, unless it is
|
|
293
|
+
* `required`. What `parse` returns is a value too, even `undefined` or `null`, and the default
|
|
294
|
+
* does not replace it.
|
|
295
|
+
*
|
|
296
|
+
* The value of a `multiple` argument is an array, so its default becomes the only element of the
|
|
297
|
+
* array: `default: 'latest'` gives `['latest']`.
|
|
298
|
+
*
|
|
299
|
+
* The default of an `enum` option with `choices` is checked when it would be used, that is, when
|
|
300
|
+
* no value from the command line is used: one that is not one of the choices is reported as an
|
|
301
|
+
* `ArgResolveError` with type 'type' and the code `err:arg:invalid-default`
|
|
302
|
+
* ({@link ArgsValidationErrorKeys}.invalidDefault), and is not used. With a `parse` function of
|
|
303
|
+
* your own, or a `map()` transform, the default is a value that the function returns, which need
|
|
304
|
+
* not be one of the choices, and it is not checked. `choice()` returns the value as is, so its
|
|
305
|
+
* default is checked.
|
|
306
|
+
*
|
|
307
|
+
* For positional arguments, `multiple` ones included, the default is used when no value is left
|
|
308
|
+
* for the argument: when the positional values run out, or when the remaining ones are preserved
|
|
309
|
+
* for later required positional arguments. With `required: true`, the default is not used, and
|
|
310
|
+
* the argument is reported as required instead.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* Default values by type:
|
|
314
|
+
* ```ts
|
|
315
|
+
* {
|
|
316
|
+
* host: {
|
|
317
|
+
* type: 'string',
|
|
318
|
+
* default: 'localhost' // string default
|
|
319
|
+
* },
|
|
320
|
+
* verbose: {
|
|
321
|
+
* type: 'boolean',
|
|
322
|
+
* default: false // boolean default
|
|
323
|
+
* },
|
|
324
|
+
* port: {
|
|
325
|
+
* type: 'number',
|
|
326
|
+
* default: 8080 // number default
|
|
327
|
+
* },
|
|
328
|
+
* level: {
|
|
329
|
+
* type: 'enum',
|
|
330
|
+
* choices: ['low', 'high'],
|
|
331
|
+
* default: 'low' // must be in choices
|
|
332
|
+
* }
|
|
333
|
+
* }
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
default?: string | boolean | number;
|
|
337
|
+
/**
|
|
338
|
+
* Converts the argument name from camelCase to kebab-case for CLI usage.
|
|
339
|
+
*
|
|
340
|
+
* When `true`, a property like `maxCount` becomes available as `--max-count`.
|
|
341
|
+
* This allows [CAC](https://github.com/cacjs/cac) user-friendly property names while maintaining CLI conventions.
|
|
342
|
+
*
|
|
343
|
+
* The `toKebab` option of {@link resolveArgs} and `parse()` applies it to all arguments, as in
|
|
344
|
+
* `resolveArgs(args, tokens, { toKebab: true })`.
|
|
345
|
+
*
|
|
346
|
+
* Note: Only `true` is allowed (not `false`) to make intent explicit.
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* Kebab-case conversion:
|
|
350
|
+
* ```ts
|
|
351
|
+
* {
|
|
352
|
+
* maxRetries: {
|
|
353
|
+
* type: 'number',
|
|
354
|
+
* toKebab: true, // Accessible as --max-retries
|
|
355
|
+
* description: 'Maximum retry attempts'
|
|
356
|
+
* },
|
|
357
|
+
* enableLogging: {
|
|
358
|
+
* type: 'boolean',
|
|
359
|
+
* toKebab: true // Accessible as --enable-logging
|
|
360
|
+
* }
|
|
361
|
+
* }
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
toKebab?: true;
|
|
365
|
+
/**
|
|
366
|
+
* Names of other options that conflict with this option.
|
|
367
|
+
*
|
|
368
|
+
* When this option is used together with any of the conflicting options, the error is an
|
|
369
|
+
* `ArgResolveError` with type 'conflict' and the code `err:arg:conflict`
|
|
370
|
+
* ({@link ArgsValidationErrorKeys}.conflict). Its `values` has the `displayName` and `name` of
|
|
371
|
+
* the argument whose `conflicts` names the other one, and the `conflictDisplayName` and
|
|
372
|
+
* `conflictName` of the other one. `displayName` and `conflictDisplayName` show an option as
|
|
373
|
+
* it was written, such as `'-p'`, and `name` and `conflictName` are the schema keys. When both
|
|
374
|
+
* name each other, `name` is the one that comes first in the schema.
|
|
375
|
+
*
|
|
376
|
+
* A positional argument can be on either side, such as `[file]` and `--stdin`. It conflicts when
|
|
377
|
+
* it is given, and it is shown by its name, such as `'file'` (in kebab-case with `toKebab`), as
|
|
378
|
+
* in its other errors. The message starts with the kind of the argument given as `name`:
|
|
379
|
+
* `Positional argument 'file' conflicts with '--stdin'` or
|
|
380
|
+
* `Optional argument '--stdin' conflicts with 'file'`.
|
|
381
|
+
*
|
|
382
|
+
* Conflicts only need to be defined on one side - if option A defines a conflict
|
|
383
|
+
* with option B, the conflict is automatically detected when both are used,
|
|
384
|
+
* regardless of whether B also defines a conflict with A.
|
|
385
|
+
*
|
|
386
|
+
* Supports both single option name or array of option names.
|
|
387
|
+
* Option names must match the property keys in the schema object exactly
|
|
388
|
+
* (no automatic conversion between camelCase and kebab-case).
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* Single conflict (bidirectional definition):
|
|
392
|
+
* ```ts
|
|
393
|
+
* {
|
|
394
|
+
* summer: {
|
|
395
|
+
* type: 'boolean',
|
|
396
|
+
* conflicts: 'autumn' // Cannot use --summer with --autumn
|
|
397
|
+
* },
|
|
398
|
+
* autumn: {
|
|
399
|
+
* type: 'boolean',
|
|
400
|
+
* conflicts: 'summer' // Can define on both sides for clarity
|
|
401
|
+
* }
|
|
402
|
+
* }
|
|
403
|
+
* ```
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* Single conflict (one-way definition):
|
|
407
|
+
* ```ts
|
|
408
|
+
* {
|
|
409
|
+
* summer: {
|
|
410
|
+
* type: 'boolean',
|
|
411
|
+
* conflicts: 'autumn' // Only defined on summer side
|
|
412
|
+
* },
|
|
413
|
+
* autumn: {
|
|
414
|
+
* type: 'boolean'
|
|
415
|
+
* // No conflicts defined, but still cannot use with --summer
|
|
416
|
+
* }
|
|
417
|
+
* }
|
|
418
|
+
* // Usage: --summer --autumn reports an error
|
|
419
|
+
* // Error: "Optional argument '--summer' conflicts with '--autumn'"
|
|
420
|
+
* ```
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* Multiple conflicts:
|
|
424
|
+
* ```ts
|
|
425
|
+
* {
|
|
426
|
+
* port: {
|
|
427
|
+
* type: 'number',
|
|
428
|
+
* conflicts: ['socket', 'pipe'], // Cannot use with --socket or --pipe
|
|
429
|
+
* description: 'TCP port number'
|
|
430
|
+
* },
|
|
431
|
+
* socket: {
|
|
432
|
+
* type: 'string',
|
|
433
|
+
* conflicts: ['port', 'pipe'], // Cannot use with --port or --pipe
|
|
434
|
+
* description: 'Unix socket path'
|
|
435
|
+
* },
|
|
436
|
+
* pipe: {
|
|
437
|
+
* type: 'string',
|
|
438
|
+
* conflicts: ['port', 'socket'], // Cannot use with --port or --socket
|
|
439
|
+
* description: 'Named pipe path'
|
|
440
|
+
* }
|
|
441
|
+
* }
|
|
442
|
+
* // These three options are mutually exclusive
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* With kebab-case conversion:
|
|
447
|
+
* ```ts
|
|
448
|
+
* {
|
|
449
|
+
* summerSeason: {
|
|
450
|
+
* type: 'boolean',
|
|
451
|
+
* toKebab: true, // Accessible as --summer-season
|
|
452
|
+
* conflicts: 'autumnSeason' // Must use property key, not CLI name
|
|
453
|
+
* },
|
|
454
|
+
* autumnSeason: {
|
|
455
|
+
* type: 'boolean',
|
|
456
|
+
* toKebab: true // Accessible as --autumn-season
|
|
457
|
+
* }
|
|
458
|
+
* }
|
|
459
|
+
* // Error: "Optional argument '--summer-season' conflicts with '--autumn-season'"
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
conflicts?: string | string[];
|
|
463
|
+
/**
|
|
464
|
+
* Display name hint for help text generation.
|
|
465
|
+
*
|
|
466
|
+
* Provides a meaningful type hint for the argument value in help output.
|
|
467
|
+
* Particularly useful for `type: 'custom'` arguments where the type
|
|
468
|
+
* name would otherwise be unhelpful.
|
|
469
|
+
*
|
|
470
|
+
* For a `custom` option that is given without a value, it is also the `expected` in the `values`
|
|
471
|
+
* of the `err:arg:missing-value` error ({@link ArgsValidationErrorKeys}.missingValue), which is
|
|
472
|
+
* `'custom'` without it.
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* Metavar usage:
|
|
476
|
+
* ```ts
|
|
477
|
+
* {
|
|
478
|
+
* port: {
|
|
479
|
+
* type: 'custom',
|
|
480
|
+
* parse: (v: string) => parseInt(v, 10),
|
|
481
|
+
* metavar: 'integer',
|
|
482
|
+
* description: 'Port number (1-65535)'
|
|
483
|
+
* }
|
|
484
|
+
* }
|
|
485
|
+
* // Help output: --port <integer> Port number (1-65535)
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
metavar?: string;
|
|
489
|
+
/**
|
|
490
|
+
* Custom parsing function, used in place of the parsing of the argument's `type`.
|
|
491
|
+
*
|
|
492
|
+
* Required when `type: 'custom'`: if it is missing or not a function, {@link resolveArgs} and
|
|
493
|
+
* `parse()` throw a `TypeError`, whether or not the argument is given. The function receives the
|
|
494
|
+
* raw string value and must return the parsed result. It should throw an Error (or subclass) if
|
|
495
|
+
* parsing fails.
|
|
496
|
+
*
|
|
497
|
+
* The function's return type becomes the resolved argument type.
|
|
498
|
+
*
|
|
499
|
+
* `parse` is called synchronously, and what it returns becomes the value, even `undefined` or
|
|
500
|
+
* `null`, so throw to reject a value. An `async` function returns a promise, and the promise
|
|
501
|
+
* becomes the value as is: it is not awaited, and its rejection is not reported as an error.
|
|
502
|
+
* Await the value, or each of its elements with `multiple` (for example with `Promise.all()`),
|
|
503
|
+
* and handle the rejection yourself: a rejection that nothing handles is an unhandled rejection,
|
|
504
|
+
* which ends a Node.js process by default.
|
|
505
|
+
*
|
|
506
|
+
* A `boolean` option calls `parse` with `'true'`, or `'false'` for the negated form. Other
|
|
507
|
+
* options call it only with a value from the command line: when the option is given without a
|
|
508
|
+
* value, `parse` is not called and the missing value is reported as `err:arg:missing-value`
|
|
509
|
+
* ({@link ArgsValidationErrorKeys}.missingValue). When that error may suggest the argument after
|
|
510
|
+
* the option as its value, such as `--port=-5` for `--port -5`, a `parse` function of your own
|
|
511
|
+
* is not called to check it either: only the `parse` functions of `string()`, `number()`,
|
|
512
|
+
* `integer()`, `float()` and `choice()`, which have no side effects, are called for that.
|
|
513
|
+
* An explicit empty value, such as `--name=` or `-n=`, is passed as `''` unless
|
|
514
|
+
* `required: true` is set.
|
|
515
|
+
*
|
|
516
|
+
* An `enum` option with `choices` calls it only with one of them. Any other value, an explicit
|
|
517
|
+
* empty one included, is reported as `err:arg:invalid-choice`
|
|
518
|
+
* ({@link ArgsValidationErrorKeys}.invalidChoice), except that a required option reports an
|
|
519
|
+
* explicit empty value as required.
|
|
520
|
+
*
|
|
521
|
+
* @param value - Raw string value from command line
|
|
522
|
+
* @returns Parsed value of any type
|
|
523
|
+
* @throws {Error} Error or subclass when value is invalid
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* Custom parsing functions:
|
|
527
|
+
* ```ts
|
|
528
|
+
* {
|
|
529
|
+
* config: {
|
|
530
|
+
* type: 'custom',
|
|
531
|
+
* parse: (value: string) => {
|
|
532
|
+
* try {
|
|
533
|
+
* return JSON.parse(value) // Parse JSON config
|
|
534
|
+
* } catch {
|
|
535
|
+
* throw new Error('Invalid JSON configuration')
|
|
536
|
+
* }
|
|
537
|
+
* },
|
|
538
|
+
* description: 'JSON configuration object'
|
|
539
|
+
* },
|
|
540
|
+
* date: {
|
|
541
|
+
* type: 'custom',
|
|
542
|
+
* parse: (value: string) => {
|
|
543
|
+
* const date = new Date(value)
|
|
544
|
+
* if (isNaN(date.getTime())) {
|
|
545
|
+
* throw new Error('Invalid date format')
|
|
546
|
+
* }
|
|
547
|
+
* return date
|
|
548
|
+
* }
|
|
549
|
+
* }
|
|
550
|
+
* }
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
parse?: (value: string) => any;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* An object that contains {@link ArgSchema | argument schema}.
|
|
557
|
+
*
|
|
558
|
+
* This type is used to define the structure and validation rules for command line arguments.
|
|
559
|
+
*/
|
|
560
|
+
interface Args$1 {
|
|
561
|
+
[option: string]: ArgSchema;
|
|
562
|
+
}
|
|
10
563
|
//#endregion
|
|
11
564
|
//#region ../shared/src/constants.d.ts
|
|
12
|
-
/**
|
|
13
|
-
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
14
|
-
* @license MIT
|
|
15
|
-
*/
|
|
16
565
|
/**
|
|
17
566
|
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
18
567
|
* @license MIT
|
|
@@ -36,35 +585,20 @@ type CommonArgType = {
|
|
|
36
585
|
declare const COMMON_ARGS: CommonArgType;
|
|
37
586
|
declare const COMMAND_BUILTIN_RESOURCE_KEYS: readonly ["USAGE", "COMMAND", "SUBCOMMAND", "COMMANDS", "ARGUMENTS", "OPTIONS", "EXAMPLES", "FORMORE", "NEGATABLE", "DEFAULT", "CHOICES"];
|
|
38
587
|
declare const ARG_ERROR_RESOURCE_KEYS: readonly ["err:arg:required-option", "err:arg:required-positional", "err:arg:invalid-type", "err:arg:invalid-choice", "err:arg:custom-parse", "err:arg:unknown-option", "err:arg:unexpected-value", "err:arg:missing-value", "err:arg:conflict", "err:arg:invalid-default"];
|
|
588
|
+
declare const ARG_ERROR_HINT_RESOURCE_KEYS: readonly ["err:arg:missing-value:hint"];
|
|
39
589
|
declare const COMMAND_ERROR_RESOURCE_KEYS: readonly ["err:cmd:not-found", "err:cmd:ambiguous", "err:cmd:inconsistent-options", "err:cmd:lazy-schema-mismatch"];
|
|
40
590
|
declare const SUGGESTION_ERROR_RESOURCE_KEYS: readonly ["err:suggestion:did-you-mean"];
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region ../plugin-i18n/src/types.d.ts
|
|
43
|
-
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region ../plugin-i18n/src/helpers.d.ts
|
|
46
|
-
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region ../plugin-i18n/src/translation.d.ts
|
|
49
|
-
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region ../gunshi/src/index.d.ts
|
|
52
|
-
|
|
53
591
|
//#endregion
|
|
54
592
|
//#region ../shared/src/types.d.ts
|
|
55
|
-
type RemoveIndexSignature<T> = { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] };
|
|
56
|
-
/**
|
|
57
|
-
* Make all properties in T deeply writeable (not readonly)
|
|
58
|
-
*/
|
|
59
|
-
|
|
593
|
+
type RemoveIndexSignature<T> = { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]; };
|
|
60
594
|
/**
|
|
61
595
|
* Remove index signature from object or record type.
|
|
62
596
|
*/
|
|
63
|
-
type RemovedIndex<T> = RemoveIndexSignature<{ [K in keyof T]: T[K] }>;
|
|
597
|
+
type RemovedIndex<T> = RemoveIndexSignature<{ [K in keyof T]: T[K]; }>;
|
|
64
598
|
/**
|
|
65
599
|
* Resolve a key on {@link Args}.
|
|
66
600
|
*/
|
|
67
|
-
type KeyOfArgs<A extends Args$1> = keyof A | { [K in keyof A]: A[K]['type'] extends 'boolean' ? A[K]['negatable'] extends true ? `no-${Extract<K, string>}` : never : never }[keyof A];
|
|
601
|
+
type KeyOfArgs<A extends Args$1> = keyof A | { [K in keyof A]: A[K]['type'] extends 'boolean' ? A[K]['negatable'] extends true ? `no-${Extract<K, string>}` : never : never; }[keyof A];
|
|
68
602
|
/**
|
|
69
603
|
* Generate a namespaced key.
|
|
70
604
|
*/
|
|
@@ -81,6 +615,10 @@ type CommandBuiltinResourceKeys = (typeof COMMAND_BUILTIN_RESOURCE_KEYS)[number]
|
|
|
81
615
|
* Args validation error resource keys.
|
|
82
616
|
*/
|
|
83
617
|
type ArgErrorResourceKeys = (typeof ARG_ERROR_RESOURCE_KEYS)[number];
|
|
618
|
+
/**
|
|
619
|
+
* Resource keys of the hints that follow an args validation error.
|
|
620
|
+
*/
|
|
621
|
+
type ArgErrorHintResourceKeys = (typeof ARG_ERROR_HINT_RESOURCE_KEYS)[number];
|
|
84
622
|
/**
|
|
85
623
|
* Command validation error resource keys.
|
|
86
624
|
*/
|
|
@@ -92,7 +630,7 @@ type SuggestionErrorResourceKeys = (typeof SUGGESTION_ERROR_RESOURCE_KEYS)[numbe
|
|
|
92
630
|
/**
|
|
93
631
|
* Error resource keys.
|
|
94
632
|
*/
|
|
95
|
-
type ErrorResourceKeys = ArgErrorResourceKeys | CommandErrorResourceKeys | SuggestionErrorResourceKeys;
|
|
633
|
+
type ErrorResourceKeys = ArgErrorResourceKeys | ArgErrorHintResourceKeys | CommandErrorResourceKeys | SuggestionErrorResourceKeys;
|
|
96
634
|
/**
|
|
97
635
|
* Command built-in keys.
|
|
98
636
|
*/
|
|
@@ -107,22 +645,11 @@ type CommandArgKeys<A extends Args$1, C = {}, K extends string = GenerateNamespa
|
|
|
107
645
|
/**
|
|
108
646
|
* Resolve translation keys for command context.
|
|
109
647
|
*/
|
|
110
|
-
type ResolveTranslationKeys<A extends Args$1, C = {}
|
|
111
|
-
// for
|
|
112
|
-
|
|
113
|
-
// for extended resources
|
|
114
|
-
R extends string = keyof RemovedIndex<E>, T extends string = (C extends {
|
|
648
|
+
type ResolveTranslationKeys<A extends Args$1, C = {} // for CommandContext
|
|
649
|
+
, E extends Record<string, string> = {} // for extended resources
|
|
650
|
+
, R extends string = keyof RemovedIndex<E>, T extends string = C extends {
|
|
115
651
|
name: infer N;
|
|
116
|
-
} ? N extends string ? GenerateNamespacedKey<R, N> : R : R | CommandBuiltinKeys
|
|
117
|
-
//#endregion
|
|
118
|
-
//#region ../shared/src/localization.d.ts
|
|
119
|
-
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region ../shared/src/utils.d.ts
|
|
122
|
-
|
|
123
|
-
//#endregion
|
|
124
|
-
//#region ../shared/src/index.d.ts
|
|
125
|
-
|
|
652
|
+
} ? N extends string ? GenerateNamespacedKey<R, N> : R : R | CommandBuiltinKeys, O = CommandArgKeys<A, C>> = ErrorResourceKeys | CommandBuiltinKeys | O | T;
|
|
126
653
|
//#endregion
|
|
127
654
|
//#region src/types.d.ts
|
|
128
655
|
/**
|
|
@@ -151,11 +678,9 @@ interface UsageRendererExtension<G extends GunshiParams<any> = DefaultGunshiPara
|
|
|
151
678
|
* @param values - An optional record of values to interpolate into the translation string.
|
|
152
679
|
* @returns The resolved translation string with interpolated values if provided.
|
|
153
680
|
*/
|
|
154
|
-
text: <A extends Args = G['args'], C = {}
|
|
155
|
-
// for
|
|
156
|
-
E
|
|
157
|
-
// for extended resources
|
|
158
|
-
K = ResolveTranslationKeys<A, C, E>>(key: K, values?: Record<string, unknown>) => Promise<string>;
|
|
681
|
+
text: <A extends Args = G['args'], C = {} // for CommandContext
|
|
682
|
+
, E extends Record<string, string> = {} // for extended resources
|
|
683
|
+
, K = ResolveTranslationKeys<A, C, E>>(key: K, values?: Record<string, unknown>) => Promise<string>;
|
|
159
684
|
/**
|
|
160
685
|
* Load commands
|
|
161
686
|
*
|
package/lib/index.js
CHANGED
|
@@ -153,13 +153,14 @@ var en_US_default = {
|
|
|
153
153
|
help: "Display this help message",
|
|
154
154
|
version: "Display this version",
|
|
155
155
|
"err:arg:required-option": "Optional argument {$displayName} is required",
|
|
156
|
-
"err:arg:required-positional": "Positional argument {$
|
|
156
|
+
"err:arg:required-positional": "Positional argument {$displayName} is required",
|
|
157
157
|
"err:arg:invalid-type": "Invalid value for {$displayName}: expected {$expected}",
|
|
158
158
|
"err:arg:invalid-choice": "Invalid value for {$displayName}: expected one of {$choices}",
|
|
159
159
|
"err:arg:custom-parse": "Invalid value for {$displayName}: {$reason}",
|
|
160
160
|
"err:arg:unknown-option": "Unknown option: {$rawName}",
|
|
161
161
|
"err:arg:unexpected-value": "Optional argument {$displayName} does not take a value",
|
|
162
162
|
"err:arg:missing-value": "Optional argument {$displayName} requires a value",
|
|
163
|
+
"err:arg:missing-value:hint": "(to pass '{$next}' as its value, write '{$suggestion}')",
|
|
163
164
|
"err:arg:conflict": "{$displayName} conflicts with {$conflictDisplayName}",
|
|
164
165
|
"err:arg:invalid-default": "Invalid default for {$displayName}: {$actual} is not one of {$choices}",
|
|
165
166
|
"err:cmd:not-found": "Command not found: {$commandName}",
|
|
@@ -442,10 +443,10 @@ function isHiddenArg(schema) {
|
|
|
442
443
|
return schema.hidden === true;
|
|
443
444
|
}
|
|
444
445
|
function getVisibleOptionalArgs(args) {
|
|
445
|
-
return Object.entries(args).filter(([
|
|
446
|
+
return Object.entries(args).filter(([, schema]) => schema.type !== "positional" && !isHiddenArg(schema));
|
|
446
447
|
}
|
|
447
448
|
function getVisiblePositionalArgs(args) {
|
|
448
|
-
return Object.entries(args).filter(([
|
|
449
|
+
return Object.entries(args).filter(([, schema]) => schema.type === "positional" && !isHiddenArg(schema));
|
|
449
450
|
}
|
|
450
451
|
/**
|
|
451
452
|
* Render the usage.
|
|
@@ -661,7 +662,7 @@ function hasAllDefaultOptions(args) {
|
|
|
661
662
|
* NOTE(kazupon): an argument has a default when one is declared, whatever its value. `0`, `''` and
|
|
662
663
|
* `false` are defaults like any other, and an option that has one is not required (#750).
|
|
663
664
|
*/
|
|
664
|
-
return visibleOptionalArgs.length > 0 && visibleOptionalArgs.every(([
|
|
665
|
+
return visibleOptionalArgs.length > 0 && visibleOptionalArgs.every(([, arg]) => arg.default !== void 0);
|
|
665
666
|
}
|
|
666
667
|
/**
|
|
667
668
|
* Generate options symbols for usage
|
|
@@ -731,7 +732,7 @@ async function resolveDisplayValue(ctx, key) {
|
|
|
731
732
|
async function generateOptionalArgsUsage(ctx, optionsPairs) {
|
|
732
733
|
const optionsPairsEntries = Object.entries(optionsPairs);
|
|
733
734
|
if (optionsPairsEntries.length === 0) return "";
|
|
734
|
-
const optionsMaxLength = Math.max(...optionsPairsEntries.map(([
|
|
735
|
+
const optionsMaxLength = Math.max(...optionsPairsEntries.map(([, value]) => displayWidth(value)));
|
|
735
736
|
const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...optionsPairsEntries.map(([key]) => displayWidth(resolveNegatableType(key, ctx)))) : 0;
|
|
736
737
|
return (await Promise.all(optionsPairsEntries.map(async ([key, value]) => {
|
|
737
738
|
let rawDesc = await ctx.extensions[pluginId].text(resolveArgKey(key, ctx.name));
|
|
@@ -790,6 +791,7 @@ function isRequiredSinglePositionalArg(arg) {
|
|
|
790
791
|
* @license MIT
|
|
791
792
|
*/
|
|
792
793
|
const i18nPluginId$1 = namespacedId("i18n");
|
|
794
|
+
const missingValueHintKey = "err:arg:missing-value:hint";
|
|
793
795
|
/**
|
|
794
796
|
* Render the validation errors.
|
|
795
797
|
*
|
|
@@ -814,10 +816,31 @@ async function renderValidationError(ctx, error) {
|
|
|
814
816
|
if (isArgsValidationError(error) && error.code) {
|
|
815
817
|
const values = await resolveValidationValues(ctx, error);
|
|
816
818
|
const message = await localize(ctx, error.code, values);
|
|
817
|
-
if (message && message !== error.code)
|
|
819
|
+
if (message && message !== error.code) {
|
|
820
|
+
const hint = await localizeHint(ctx, error, values);
|
|
821
|
+
return hint ? `${message} ${hint}` : message;
|
|
822
|
+
}
|
|
818
823
|
}
|
|
819
824
|
return error.message;
|
|
820
825
|
}
|
|
826
|
+
/**
|
|
827
|
+
* Localize the hint that args-tokens adds to the message of an error.
|
|
828
|
+
*
|
|
829
|
+
* A translation replaces the whole message, hint included, so the hint is translated by a key of
|
|
830
|
+
* its own and follows the translated error. args-tokens gives one today: for an option given without
|
|
831
|
+
* a value, when the argument after it may be the value, the long form with `=` (`--port=-5` for
|
|
832
|
+
* `--port -5`), in `values.next` and `values.suggestion`.
|
|
833
|
+
*
|
|
834
|
+
* @param ctx - A {@link CommandContext | command context}
|
|
835
|
+
* @param error - An args validation error
|
|
836
|
+
* @param values - The values of the error, as given to its translation
|
|
837
|
+
* @returns The localized hint, or `undefined` when the error has none.
|
|
838
|
+
*/
|
|
839
|
+
async function localizeHint(ctx, error, values) {
|
|
840
|
+
if (error.code !== ArgsValidationErrorKeys.missingValue || typeof values.next !== "string" || typeof values.suggestion !== "string") return;
|
|
841
|
+
const hint = await localize(ctx, missingValueHintKey, values);
|
|
842
|
+
return hint && hint !== missingValueHintKey ? hint : void 0;
|
|
843
|
+
}
|
|
821
844
|
async function resolveValidationValues(ctx, error) {
|
|
822
845
|
if (error.code !== ArgsValidationErrorKeys.customParse) return error.values;
|
|
823
846
|
const { reasonKey, reasonValues } = error.values;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gunshi/plugin-renderer",
|
|
3
3
|
"description": "usage renderer plugin for gunshi",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "kazuya kawaguchi",
|
|
7
7
|
"email": "kawakazu80@gmail.com"
|
|
@@ -53,18 +53,18 @@
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@gunshi/plugin": "1.0.0-beta.
|
|
56
|
+
"@gunshi/plugin": "1.0.0-beta.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@gunshi/plugin-i18n": "1.0.0-beta.
|
|
59
|
+
"@gunshi/plugin-i18n": "1.0.0-beta.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
+
"@gunshi/shared": "1.0.0-beta.1",
|
|
62
63
|
"deno": "^2.7.14",
|
|
63
64
|
"jsr": "^0.14.3",
|
|
64
65
|
"jsr-exports-lint": "^0.4.2",
|
|
65
66
|
"publint": "^0.3.20",
|
|
66
|
-
"tsdown": "0.
|
|
67
|
-
"@gunshi/shared": "1.0.0-beta.0"
|
|
67
|
+
"tsdown": "0.22.14"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"build": "tsdown",
|