@gunshi/plugin 0.27.0-alpha.5 → 0.27.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/index.d.ts +490 -239
  2. package/lib/index.js +107 -1
  3. package/package.json +2 -2
package/lib/index.d.ts CHANGED
@@ -1,151 +1,382 @@
1
- //#region ../../node_modules/.pnpm/args-tokens@0.20.1/node_modules/args-tokens/lib/parser-FiQIAw-2.d.ts
1
+ //#region ../../node_modules/.pnpm/args-tokens@0.22.0/node_modules/args-tokens/lib/parser-Cbxholql.d.ts
2
2
  //#region src/parser.d.ts
3
3
  /**
4
- * Entry point of argument parser.
5
- * @module
6
- */
7
- /**
8
- * forked from `nodejs/node` (`pkgjs/parseargs`)
9
- * repository url: https://github.com/nodejs/node (https://github.com/pkgjs/parseargs)
10
- * code url: https://github.com/nodejs/node/blob/main/lib/internal/util/parse_args/parse_args.js
11
- *
12
- * @author kazuya kawaguchi (a.k.a. kazupon)
13
- * @license MIT
14
- */
15
- /**
16
- * Argument token Kind.
17
- * - `option`: option token, support short option (e.g. `-x`) and long option (e.g. `--foo`)
18
- * - `option-terminator`: option terminator (`--`) token, see guideline 10 in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
19
- * - `positional`: positional token
20
- */
21
- type ArgTokenKind = "option" | "option-terminator" | "positional";
22
- /**
23
- * Argument token.
24
- */
4
+ * Entry point of argument parser.
5
+ * @module
6
+ */
7
+ /**
8
+ * forked from `nodejs/node` (`pkgjs/parseargs`)
9
+ * repository url: https://github.com/nodejs/node (https://github.com/pkgjs/parseargs)
10
+ * code url: https://github.com/nodejs/node/blob/main/lib/internal/util/parse_args/parse_args.js
11
+ *
12
+ * @author kazuya kawaguchi (a.k.a. kazupon)
13
+ * @license MIT
14
+ */
15
+ /**
16
+ * Argument token Kind.
17
+ * - `option`: option token, support short option (e.g. `-x`) and long option (e.g. `--foo`)
18
+ * - `option-terminator`: option terminator (`--`) token, see guideline 10 in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
19
+ * - `positional`: positional token
20
+ */
21
+ type ArgTokenKind = 'option' | 'option-terminator' | 'positional';
22
+ /**
23
+ * Argument token.
24
+ */
25
25
  interface ArgToken {
26
26
  /**
27
- * Argument token kind.
28
- */
27
+ * Argument token kind.
28
+ */
29
29
  kind: ArgTokenKind;
30
30
  /**
31
- * Argument token index, e.g `--foo bar` => `--foo` index is 0, `bar` index is 1.
32
- */
31
+ * Argument token index, e.g `--foo bar` => `--foo` index is 0, `bar` index is 1.
32
+ */
33
33
  index: number;
34
34
  /**
35
- * Option name, e.g. `--foo` => `foo`, `-x` => `x`.
36
- */
35
+ * Option name, e.g. `--foo` => `foo`, `-x` => `x`.
36
+ */
37
37
  name?: string;
38
38
  /**
39
- * Raw option name, e.g. `--foo` => `--foo`, `-x` => `-x`.
40
- */
39
+ * Raw option name, e.g. `--foo` => `--foo`, `-x` => `-x`.
40
+ */
41
41
  rawName?: string;
42
42
  /**
43
- * Option value, e.g. `--foo=bar` => `bar`, `-x=bar` => `bar`.
44
- * If the `allowCompatible` option is `true`, short option value will be same as Node.js `parseArgs` behavior.
45
- */
43
+ * Option value, e.g. `--foo=bar` => `bar`, `-x=bar` => `bar`.
44
+ * If the `allowCompatible` option is `true`, short option value will be same as Node.js `parseArgs` behavior.
45
+ */
46
46
  value?: string;
47
47
  /**
48
- * Inline value, e.g. `--foo=bar` => `true`, `-x=bar` => `true`.
49
- */
48
+ * Inline value, e.g. `--foo=bar` => `true`, `-x=bar` => `true`.
49
+ */
50
50
  inlineValue?: boolean;
51
51
  }
52
52
  /**
53
- * Parser Options.
54
- */
53
+ * Parser Options.
54
+ */
55
55
  //#endregion
56
- //#region ../../node_modules/.pnpm/args-tokens@0.20.1/node_modules/args-tokens/lib/resolver-U72Jg6Ll.d.ts
56
+ //#region ../../node_modules/.pnpm/args-tokens@0.22.0/node_modules/args-tokens/lib/resolver-BoS-UnqX.d.ts
57
57
  //#region src/resolver.d.ts
58
58
 
59
59
  /**
60
- * An argument schema
61
- * This schema is similar to the schema of the `node:utils`.
62
- * difference is that:
63
- * - `required` property and `description` property are added
64
- * - `type` is not only 'string' and 'boolean', but also 'number', 'enum', 'positional', 'custom' too.
65
- * - `default` property type, not support multiple types
66
- */
60
+ * An argument schema
61
+ * This schema is similar to the schema of the `node:utils`.
62
+ * difference is that:
63
+ * - `required` property and `description` property are added
64
+ * - `type` is not only 'string' and 'boolean', but also 'number', 'enum', 'positional', 'custom' too.
65
+ * - `default` property type, not support multiple types
66
+ */
67
67
  interface ArgSchema {
68
68
  /**
69
- * Type of argument.
70
- */
71
- type: "string" | "boolean" | "number" | "enum" | "positional" | "custom";
69
+ * Type of argument.
70
+ */
71
+ type: 'string' | 'boolean' | 'number' | 'enum' | 'positional' | 'custom';
72
72
  /**
73
- * A single character alias for the argument.
74
- */
73
+ * A single character alias for the argument.
74
+ */
75
75
  short?: string;
76
76
  /**
77
- * A description of the argument.
78
- */
77
+ * A description of the argument.
78
+ */
79
79
  description?: string;
80
80
  /**
81
- * Whether the argument is required or not.
82
- */
81
+ * Whether the argument is required or not.
82
+ */
83
83
  required?: true;
84
84
  /**
85
- * Whether the argument allow multiple values or not.
86
- */
85
+ * Whether the argument allow multiple values or not.
86
+ */
87
87
  multiple?: true;
88
88
  /**
89
- * Whether the negatable option for `boolean` type
90
- */
89
+ * Whether the negatable option for `boolean` type
90
+ */
91
91
  negatable?: boolean;
92
92
  /**
93
- * The allowed values of the argument, and string only. This property is only used when the type is 'enum'.
94
- */
93
+ * The allowed values of the argument, and string only. This property is only used when the type is 'enum'.
94
+ */
95
95
  choices?: string[] | readonly string[];
96
96
  /**
97
- * The default value of the argument.
98
- * if the type is 'enum', the default value must be one of the allowed values.
99
- */
97
+ * The default value of the argument.
98
+ * if the type is 'enum', the default value must be one of the allowed values.
99
+ */
100
100
  default?: string | boolean | number;
101
101
  /**
102
- * Whether to convert the argument name to kebab-case.
103
- */
102
+ * Whether to convert the argument name to kebab-case.
103
+ */
104
104
  toKebab?: true;
105
105
  /**
106
- * A function to parse the value of the argument. if the type is 'custom', this function is required.
107
- * If argument value will be invalid, this function have to throw an error.
108
- * @param value
109
- * @returns Parsed value
110
- * @throws An Error, If the value is invalid. Error type should be `Error` or extends it
111
- */
112
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
+ * A function to parse the value of the argument. if the type is 'custom', this function is required.
107
+ * If argument value will be invalid, this function have to throw an error.
108
+ * @param value
109
+ * @returns Parsed value
110
+ * @throws An Error, If the value is invalid. Error type should be `Error` or extends it
111
+ */
113
112
  parse?: (value: string) => any;
114
113
  }
115
114
  /**
116
- * An object that contains {@link ArgSchema | argument schema}.
117
- */
115
+ * An object that contains {@link ArgSchema | argument schema}.
116
+ */
118
117
  interface Args {
119
118
  [option: string]: ArgSchema;
120
119
  }
121
120
  /**
122
- * An object that contains the values of the arguments.
123
- */
121
+ * An object that contains the values of the arguments.
122
+ */
124
123
  type ArgValues<T> = T extends Args ? ResolveArgValues<T, { [Arg in keyof T]: ExtractOptionValue<T[Arg]> }> : {
125
124
  [option: string]: string | boolean | number | (string | boolean | number)[] | undefined;
126
125
  };
127
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
126
  type IsFunction<T> = T extends ((...args: any[]) => any) ? true : false;
129
127
  /**
130
- * @internal
131
- */
132
- type ExtractOptionValue<A extends ArgSchema> = A["type"] extends "string" ? ResolveOptionValue<A, string> : A["type"] extends "boolean" ? ResolveOptionValue<A, boolean> : A["type"] extends "number" ? ResolveOptionValue<A, number> : A["type"] extends "positional" ? ResolveOptionValue<A, string> : A["type"] extends "enum" ? A["choices"] extends string[] | readonly string[] ? ResolveOptionValue<A, A["choices"][number]> : never : A["type"] extends "custom" ? IsFunction<A["parse"]> extends true ? ResolveOptionValue<A, ReturnType<NonNullable<A["parse"]>>> : never : ResolveOptionValue<A, string | boolean | number>;
133
- type ResolveOptionValue<A extends ArgSchema, T> = A["multiple"] extends true ? T[] : T;
128
+ * @internal
129
+ */
130
+ type ExtractOptionValue<A extends ArgSchema> = A['type'] extends 'string' ? ResolveOptionValue<A, string> : A['type'] extends 'boolean' ? ResolveOptionValue<A, boolean> : A['type'] extends 'number' ? ResolveOptionValue<A, number> : A['type'] extends 'positional' ? ResolveOptionValue<A, string> : A['type'] extends 'enum' ? A['choices'] extends string[] | readonly string[] ? ResolveOptionValue<A, A['choices'][number]> : never : A['type'] extends 'custom' ? IsFunction<A['parse']> extends true ? ResolveOptionValue<A, ReturnType<NonNullable<A['parse']>>> : never : ResolveOptionValue<A, string | boolean | number>;
131
+ type ResolveOptionValue<A extends ArgSchema, T> = A['multiple'] extends true ? T[] : T;
134
132
  /**
135
- * @internal
136
- */
137
- type ResolveArgValues<A extends Args, V extends Record<keyof A, unknown>> = { -readonly [Arg in keyof A]?: V[Arg] } & FilterArgs<A, V, "default"> & FilterArgs<A, V, "required"> & FilterPositionalArgs<A, V> extends infer P ? { [K in keyof P]: P[K] } : never;
133
+ * @internal
134
+ */
135
+ type ResolveArgValues<A extends Args, V extends Record<keyof A, unknown>> = { -readonly [Arg in keyof A]?: V[Arg] } & FilterArgs<A, V, 'default'> & FilterArgs<A, V, 'required'> & FilterPositionalArgs<A, V> extends infer P ? { [K in keyof P]: P[K] } : never;
138
136
  /**
139
- * @internal
140
- */
137
+ * @internal
138
+ */
141
139
  type FilterArgs<A extends Args, V extends Record<keyof A, unknown>, K extends keyof ArgSchema> = { [Arg in keyof A as A[Arg][K] extends {} ? Arg : never]: V[Arg] };
142
140
  /**
143
- * @internal
144
- */
145
- type FilterPositionalArgs<A extends Args, V extends Record<keyof A, unknown>> = { [Arg in keyof A as A[Arg]["type"] extends "positional" ? Arg : never]: V[Arg] };
141
+ * @internal
142
+ */
143
+ type FilterPositionalArgs<A extends Args, V extends Record<keyof A, unknown>> = { [Arg in keyof A as A[Arg]['type'] extends 'positional' ? Arg : never]: V[Arg] };
144
+ /**
145
+ * An arguments for {@link resolveArgs | resolve arguments}.
146
+ */
147
+
148
+ /**
149
+ * Tracks which arguments were explicitly provided by the user.
150
+ *
151
+ * Each property indicates whether the corresponding argument was explicitly
152
+ * provided (true) or is using a default value or not provided (false).
153
+ */
154
+ type ArgExplicitlyProvided<A extends Args> = { [K in keyof A]: boolean };
155
+ /**
156
+ * Resolve command line arguments.
157
+ * @param args - An arguments that contains {@link ArgSchema | arguments schema}.
158
+ * @param tokens - An array of {@link ArgToken | tokens}.
159
+ * @param resolveArgs - An arguments that contains {@link ResolveArgs | resolve arguments}.
160
+ * @returns An object that contains the values of the arguments, positional arguments, rest arguments, {@link AggregateError | validation errors}, and explicit provision status.
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * // passed tokens: --port 3000
165
+ *
166
+ * const { values, explicit } = resolveArgs({
167
+ * port: {
168
+ * type: 'number',
169
+ * default: 8080
170
+ * },
171
+ * host: {
172
+ * type: 'string',
173
+ * default: 'localhost'
174
+ * }
175
+ * }, parsedTokens)
176
+ *
177
+ * values.port // 3000
178
+ * values.host // 'localhost'
179
+ *
180
+ * explicit.port // true (explicitly provided)
181
+ * explicit.host // false (not provided, fallback to default)
182
+ * ```
183
+ */
184
+ //#endregion
185
+ //#region ../gunshi/src/plugin/context.d.ts
186
+ /**
187
+ * Type helper to create GunshiParams from extracted args and extensions
188
+ * @internal
189
+ */
190
+ type ExtractedParams<G extends GunshiParamsConstraint, L extends Record<string, unknown> = {}> = {
191
+ args: ExtractArgs<G>;
192
+ extensions: ExtractExtensions$1<G> & L;
193
+ };
194
+ /**
195
+ * Gunshi plugin context interface.
196
+ * @since v0.27.0
197
+ */
198
+ interface PluginContext<G extends GunshiParamsConstraint = DefaultGunshiParams> {
199
+ /**
200
+ * Get the global options
201
+ * @returns A map of global options.
202
+ */
203
+ readonly globalOptions: Map<string, ArgSchema>;
204
+ /**
205
+ * Get the registered sub commands
206
+ * @returns A map of sub commands.
207
+ */
208
+ readonly subCommands: ReadonlyMap<string, Command<G> | LazyCommand<G>>;
209
+ /**
210
+ * Add a global option.
211
+ * @param name An option name
212
+ * @param schema An {@link ArgSchema} for the option
213
+ */
214
+ addGlobalOption(name: string, schema: ArgSchema): void;
215
+ /**
216
+ * Add a sub command.
217
+ * @param name Command name
218
+ * @param command Command definition
219
+ */
220
+ addCommand(name: string, command: Command<G> | LazyCommand<G>): void;
221
+ /**
222
+ * Check if a command exists.
223
+ * @param name Command name
224
+ * @returns True if the command exists, false otherwise
225
+ */
226
+ hasCommand(name: string): boolean;
227
+ /**
228
+ * Decorate the header renderer.
229
+ * @param decorator - A decorator function that wraps the base header renderer.
230
+ */
231
+ decorateHeaderRenderer<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRenderer: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>, ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>): void;
232
+ /**
233
+ * Decorate the usage renderer.
234
+ * @param decorator - A decorator function that wraps the base usage renderer.
235
+ */
236
+ decorateUsageRenderer<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRenderer: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>, ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>): void;
237
+ /**
238
+ * Decorate the validation errors renderer.
239
+ * @param decorator - A decorator function that wraps the base validation errors renderer.
240
+ */
241
+ decorateValidationErrorsRenderer<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRenderer: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>, error: AggregateError) => Promise<string>, ctx: Readonly<CommandContext<ExtractedParams<G, L>>>, error: AggregateError) => Promise<string>): void;
242
+ /**
243
+ * Decorate the command execution.
244
+ * Decorators are applied in reverse order (last registered is executed first).
245
+ * @param decorator - A decorator function that wraps the command runner
246
+ */
247
+ decorateCommand<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRunner: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Awaitable<void | string>) => (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Awaitable<void | string>): void;
248
+ }
249
+ /**
250
+ * Factory function for creating a plugin context.
251
+ * @param decorators - A {@link Decorators} instance.
252
+ * @param initialSubCommands - Initial sub commands map.
253
+ * @returns A new {@link PluginContext} instance.
254
+ */
255
+ //#endregion
256
+ //#region ../gunshi/src/plugin/core.d.ts
257
+ /**
258
+ * Plugin dependency definition
259
+ * @since v0.27.0
260
+ */
261
+ interface PluginDependency {
262
+ /**
263
+ * Dependency plugin id
264
+ */
265
+ id: string;
266
+ /**
267
+ * Optional dependency flag.
268
+ * If true, the plugin will not throw an error if the dependency is not found.
269
+ */
270
+ optional?: boolean;
271
+ }
272
+ /**
273
+ * Plugin function type
274
+ * @since v0.27.0
275
+ */
276
+ type PluginFunction<G extends GunshiParams = DefaultGunshiParams> = (ctx: Readonly<PluginContext<G>>) => Awaitable<void>;
277
+ /**
278
+ * Plugin extension for CommandContext
279
+ * @since v0.27.0
280
+ */
281
+ type PluginExtension<T = Record<string, unknown>, G extends GunshiParams = DefaultGunshiParams> = (ctx: CommandContextCore<G>, cmd: Command<G>) => T;
282
+ /**
283
+ * Plugin extension callback type
284
+ * @since v0.27.0
285
+ */
286
+ type OnPluginExtension<G extends GunshiParams = DefaultGunshiParams> = (ctx: Readonly<CommandContext<G>>, cmd: Readonly<Command<G>>) => void;
287
+ /**
288
+ * Plugin definition options
289
+ * @since v0.27.0
290
+ */
291
+ interface PluginOptions<T extends Record<string, unknown> = Record<never, never>, G extends GunshiParams = DefaultGunshiParams> {
292
+ /**
293
+ * Plugin unique identifier
294
+ */
295
+ id: string;
296
+ /**
297
+ * Plugin name
298
+ */
299
+ name?: string;
300
+ /**
301
+ * Plugin dependencies
302
+ */
303
+ dependencies?: (PluginDependency | string)[];
304
+ /**
305
+ * Plugin setup function
306
+ */
307
+ setup?: PluginFunction<G>;
308
+ /**
309
+ * Plugin extension
310
+ */
311
+ extension?: PluginExtension<T, G>;
312
+ /**
313
+ * Callback for when the plugin is extended with `extension` option.
314
+ */
315
+ onExtension?: OnPluginExtension<G>;
316
+ }
146
317
  /**
147
- * An arguments for {@link resolveArgs | resolve arguments}.
148
- */
318
+ * Gunshi plugin, which is a function that receives a PluginContext.
319
+ * @param ctx - A {@link PluginContext}.
320
+ * @returns An {@link Awaitable} that resolves when the plugin is loaded.
321
+ * @since v0.27.0
322
+ */
323
+ type Plugin<E extends GunshiParams['extensions'] = DefaultGunshiParams['extensions']> = PluginFunction & {
324
+ id: string;
325
+ name?: string;
326
+ dependencies?: (PluginDependency | string)[];
327
+ extension?: CommandContextExtension<E>;
328
+ };
329
+ /**
330
+ * Plugin return type with extension
331
+ * @internal
332
+ */
333
+ interface PluginWithExtension<E extends GunshiParams['extensions'] = DefaultGunshiParams['extensions']> extends Plugin<E> {
334
+ id: string;
335
+ name: string;
336
+ dependencies?: (PluginDependency | string)[];
337
+ extension: CommandContextExtension<E>;
338
+ }
339
+ /**
340
+ * Plugin return type without extension
341
+ * @internal
342
+ */
343
+ interface PluginWithoutExtension<E extends GunshiParams['extensions'] = DefaultGunshiParams['extensions']> extends Plugin<E> {
344
+ id: string;
345
+ name: string;
346
+ dependencies?: (PluginDependency | string)[];
347
+ }
348
+ /**
349
+ * Define a plugin with extension capabilities
350
+ * @param options - {@link PluginOptions | plugin options}
351
+ * @return A defined plugin with extension capabilities.
352
+ * @since v0.27.0
353
+ */
354
+ declare function plugin<I extends string, P extends PluginExtension<any, DefaultGunshiParams>>(options: {
355
+ id: I;
356
+ name?: string;
357
+ dependencies?: (PluginDependency | string)[];
358
+ setup?: (ctx: Readonly<PluginContext<GunshiParams<{
359
+ args: Args;
360
+ extensions: { [K in I]: ReturnType<P> };
361
+ }>>>) => Awaitable<void>;
362
+ extension: P;
363
+ onExtension?: OnPluginExtension<{
364
+ args: Args;
365
+ extensions: { [K in I]: ReturnType<P> };
366
+ }>;
367
+ }): PluginWithExtension<ReturnType<P>>;
368
+ /**
369
+ * Define a plugin without extension capabilities
370
+ * @param options - {@link PluginOptions | plugin options} without extension
371
+ * @returns A defined plugin without extension capabilities.
372
+ * @since v0.27.0
373
+ */
374
+ declare function plugin(options: {
375
+ id: string;
376
+ name?: string;
377
+ dependencies?: (PluginDependency | string)[];
378
+ setup?: (ctx: Readonly<PluginContext<DefaultGunshiParams>>) => Awaitable<void>;
379
+ }): PluginWithoutExtension<DefaultGunshiParams['extensions']>;
149
380
  //#endregion
150
381
  //#region ../gunshi/src/types.d.ts
151
382
  type Awaitable<T> = T | Promise<T>;
@@ -197,11 +428,16 @@ type GunshiParamsConstraint = GunshiParams<any> | {
197
428
  * @internal
198
429
  */
199
430
  type ExtractArgs<G> = G extends GunshiParams<any> ? G['args'] : Args;
431
+ /**
432
+ * Type helper to extract explicitly provided argument flags from G
433
+ * @internal
434
+ */
435
+ type ExtractArgExplicitlyProvided<G> = ArgExplicitlyProvided<ExtractArgs<G>>;
200
436
  /**
201
437
  * Type helper to extract extensions from G
202
438
  * @internal
203
439
  */
204
- type ExtractExtensions<G> = G extends GunshiParams<any> ? G['extensions'] : G extends {
440
+ type ExtractExtensions$1<G> = G extends GunshiParams<any> ? G['extensions'] : G extends {
205
441
  extensions: infer E;
206
442
  } ? E : {};
207
443
  /**
@@ -308,7 +544,86 @@ interface CommandEnvironment<G extends GunshiParamsConstraint = DefaultGunshiPar
308
544
  /**
309
545
  * CLI options of `cli` function.
310
546
  */
311
-
547
+ interface CliOptions<G extends GunshiParamsConstraint = DefaultGunshiParams> {
548
+ /**
549
+ * Current working directory.
550
+ */
551
+ cwd?: string;
552
+ /**
553
+ * Command program name.
554
+ */
555
+ name?: string;
556
+ /**
557
+ * Command program description.
558
+ *
559
+ */
560
+ description?: string;
561
+ /**
562
+ * Command program version.
563
+ */
564
+ version?: string;
565
+ /**
566
+ * Sub commands.
567
+ */
568
+ subCommands?: Map<string, Command<any> | LazyCommand<any>>;
569
+ /**
570
+ * Left margin of the command output.
571
+ */
572
+ leftMargin?: number;
573
+ /**
574
+ * Middle margin of the command output.
575
+ */
576
+ middleMargin?: number;
577
+ /**
578
+ * Whether to display the usage optional argument type.
579
+ */
580
+ usageOptionType?: boolean;
581
+ /**
582
+ * Whether to display the optional argument value.
583
+ */
584
+ usageOptionValue?: boolean;
585
+ /**
586
+ * Whether to display the command usage.
587
+ */
588
+ usageSilent?: boolean;
589
+ /**
590
+ * Render function the command usage.
591
+ */
592
+ renderUsage?: ((ctx: Readonly<CommandContext<G>>) => Promise<string>) | null;
593
+ /**
594
+ * Render function the header section in the command usage.
595
+ */
596
+ renderHeader?: ((ctx: Readonly<CommandContext<G>>) => Promise<string>) | null;
597
+ /**
598
+ * Render function the validation errors.
599
+ */
600
+ renderValidationErrors?: ((ctx: Readonly<CommandContext<G>>, error: AggregateError) => Promise<string>) | null;
601
+ /**
602
+ * User plugins.
603
+ * @since v0.27.0
604
+ */
605
+ plugins?: Plugin[];
606
+ /**
607
+ * Hook that runs before any command execution
608
+ * @param ctx - The command context
609
+ * @since v0.27.0
610
+ */
611
+ onBeforeCommand?: (ctx: Readonly<CommandContext<G>>) => Awaitable<void>;
612
+ /**
613
+ * Hook that runs after successful command execution
614
+ * @param ctx - The command context
615
+ * @param result - The command execution result
616
+ * @since v0.27.0
617
+ */
618
+ onAfterCommand?: (ctx: Readonly<CommandContext<G>>, result: string | undefined) => Awaitable<void>;
619
+ /**
620
+ * Hook that runs when a command throws an error
621
+ * @param ctx - The command context
622
+ * @param error - The error thrown during execution
623
+ * @since v0.27.0
624
+ */
625
+ onErrorCommand?: (ctx: Readonly<CommandContext<G>>, error: Error) => Awaitable<void>;
626
+ }
312
627
  /**
313
628
  * Command call mode.
314
629
  */
@@ -338,6 +653,15 @@ interface CommandContext<G extends GunshiParamsConstraint = DefaultGunshiParams>
338
653
  * The command arguments is same {@link Command.args}.
339
654
  */
340
655
  args: ExtractArgs<G>;
656
+ /**
657
+ * Whether arguments were explicitly provided by the user.
658
+ *
659
+ * - `true`: The argument was explicitly provided via command line
660
+ * - `false`: The argument was not explicitly provided. This means either:
661
+ * - The value comes from a default value defined in the argument schema
662
+ * - The value is `undefined` (no explicit input and no default value)
663
+ */
664
+ explicit: ExtractArgExplicitlyProvided<G>;
341
665
  /**
342
666
  * Command values, that is the values of the command that is executed.
343
667
  * Resolve values with `resolveArgs` from command arguments and {@link Command.args}.
@@ -387,7 +711,7 @@ interface CommandContext<G extends GunshiParamsConstraint = DefaultGunshiParams>
387
711
  * Command context extensions.
388
712
  * @since v0.27.0
389
713
  */
390
- extensions: keyof ExtractExtensions<G> extends never ? undefined : ExtractExtensions<G>;
714
+ extensions: keyof ExtractExtensions$1<G> extends never ? undefined : ExtractExtensions$1<G>;
391
715
  /**
392
716
  * Validation error from argument parsing.
393
717
  * This will be set if argument validation fails during CLI execution.
@@ -441,6 +765,19 @@ interface Command<G extends GunshiParamsConstraint = DefaultGunshiParams> {
441
765
  * If you will set to `true`, All {@link Command.args} names will be converted to kebab-case.
442
766
  */
443
767
  toKebab?: boolean;
768
+ /**
769
+ * Whether this is an internal command.
770
+ * Internal commands are not shown in help usage.
771
+ * @default false
772
+ * @since v0.27.0
773
+ */
774
+ internal?: boolean;
775
+ /**
776
+ * Whether this command is an entry command.
777
+ * @default undefined
778
+ * @since v0.27.0
779
+ */
780
+ entry?: boolean;
444
781
  }
445
782
  /**
446
783
  * Lazy command interface.
@@ -507,182 +844,96 @@ type RendererDecorator<T, G extends GunshiParamsConstraint = DefaultGunshiParams
507
844
  */
508
845
  type ValidationErrorsDecorator<G extends GunshiParamsConstraint = DefaultGunshiParams> = (baseRenderer: (ctx: Readonly<CommandContext<G>>, error: AggregateError) => Promise<string>, ctx: Readonly<CommandContext<G>>, error: AggregateError) => Promise<string>;
509
846
  //#endregion
510
- //#region ../gunshi/src/plugin/context.d.ts
847
+ //#region ../gunshi/src/constants.d.ts
848
+ declare const CLI_OPTIONS_DEFAULT: CliOptions<DefaultGunshiParams>;
849
+ //#endregion
850
+ //#region ../gunshi/src/context.d.ts
511
851
  /**
512
- * Type helper to create GunshiParams from extracted args and extensions
852
+ * Extract extension return types from extensions record
513
853
  * @internal
514
854
  */
515
- type ExtractedParams<G extends GunshiParamsConstraint, L extends Record<string, unknown> = {}> = {
516
- args: ExtractArgs<G>;
517
- extensions: ExtractExtensions<G> & L;
518
- };
855
+ type ExtractExtensions<E extends Record<string, CommandContextExtension>> = { [K in keyof E]: E[K] extends CommandContextExtension<infer T> ? T : never };
519
856
  /**
520
- * Gunshi plugin context interface.
521
- * @since v0.27.0
857
+ * Parameters of {@link createCommandContext}
522
858
  */
523
- interface PluginContext<G extends GunshiParamsConstraint = DefaultGunshiParams> {
859
+ interface CommandContextParams<G extends GunshiParams | {
860
+ extensions: ExtendContext;
861
+ }, V extends ArgValues<ExtractArgs<G>>, C extends Command<G> | LazyCommand<G> = Command<G>, E extends Record<string, CommandContextExtension> = Record<string, CommandContextExtension>> {
524
862
  /**
525
- * Get the global options
526
- * @returns A map of global options.
863
+ * An arguments of target command
527
864
  */
528
- readonly globalOptions: Map<string, ArgSchema>;
529
- /**
530
- * Add a global option.
531
- * @param name An option name
532
- * @param schema An {@link ArgSchema} for the option
533
- */
534
- addGlobalOption(name: string, schema: ArgSchema): void;
865
+ args: ExtractArgs<G>;
535
866
  /**
536
- * Decorate the header renderer.
537
- * @param decorator - A decorator function that wraps the base header renderer.
867
+ * Explicitly provided arguments
538
868
  */
539
- decorateHeaderRenderer<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRenderer: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>, ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>): void;
869
+ explicit: ExtractArgExplicitlyProvided<G>;
540
870
  /**
541
- * Decorate the usage renderer.
542
- * @param decorator - A decorator function that wraps the base usage renderer.
871
+ * A values of target command
543
872
  */
544
- decorateUsageRenderer<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRenderer: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>, ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Promise<string>): void;
873
+ values: V;
545
874
  /**
546
- * Decorate the validation errors renderer.
547
- * @param decorator - A decorator function that wraps the base validation errors renderer.
875
+ * A positionals arguments, which passed to the target command
548
876
  */
549
- decorateValidationErrorsRenderer<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRenderer: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>, error: AggregateError) => Promise<string>, ctx: Readonly<CommandContext<ExtractedParams<G, L>>>, error: AggregateError) => Promise<string>): void;
877
+ positionals: string[];
550
878
  /**
551
- * Decorate the command execution.
552
- * Decorators are applied in reverse order (last registered is executed first).
553
- * @param decorator - A decorator function that wraps the command runner
879
+ * A rest arguments, which passed to the target command
554
880
  */
555
- decorateCommand<L extends Record<string, unknown> = DefaultGunshiParams['extensions']>(decorator: (baseRunner: (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Awaitable<void | string>) => (ctx: Readonly<CommandContext<ExtractedParams<G, L>>>) => Awaitable<void | string>): void;
556
- }
557
- /**
558
- * Factory function for creating a plugin context.
559
- * @param decorators - A {@link Decorators} instance.
560
- * @returns A new {@link PluginContext} instance.
561
- */
562
- //#endregion
563
- //#region ../gunshi/src/plugin/core.d.ts
564
- /**
565
- * Plugin dependency definition
566
- * @since v0.27.0
567
- */
568
- interface PluginDependency {
881
+ rest: string[];
569
882
  /**
570
- * Dependency plugin id
883
+ * Original command line arguments
571
884
  */
572
- id: string;
885
+ argv: string[];
573
886
  /**
574
- * Optional dependency flag.
575
- * If true, the plugin will not throw an error if the dependency is not found.
887
+ * Argument tokens that are parsed by the `parseArgs` function
576
888
  */
577
- optional?: boolean;
578
- }
579
- /**
580
- * Plugin function type
581
- * @since v0.27.0
582
- */
583
- type PluginFunction<G extends GunshiParams = DefaultGunshiParams> = (ctx: Readonly<PluginContext<G>>) => Awaitable<void>;
584
- /**
585
- * Plugin extension for CommandContext
586
- * @since v0.27.0
587
- */
588
- type PluginExtension<T = Record<string, unknown>, G extends GunshiParams = DefaultGunshiParams> = (ctx: CommandContextCore<G>, cmd: Command<G>) => T;
589
- /**
590
- * Plugin extension callback type
591
- * @since v0.27.0
592
- */
593
- type OnPluginExtension<G extends GunshiParams = DefaultGunshiParams> = (ctx: Readonly<CommandContext<G>>, cmd: Readonly<Command<G>>) => void;
594
- /**
595
- * Plugin definition options
596
- * @since v0.27.0
597
- */
598
- interface PluginOptions<T extends Record<string, unknown> = Record<never, never>, G extends GunshiParams = DefaultGunshiParams> {
889
+ tokens: ArgToken[];
599
890
  /**
600
- * Plugin unique identifier
891
+ * Whether the command is omitted
601
892
  */
602
- id: string;
893
+ omitted: boolean;
603
894
  /**
604
- * Plugin name
895
+ * Command call mode.
605
896
  */
606
- name?: string;
897
+ callMode: CommandCallMode;
607
898
  /**
608
- * Plugin dependencies
899
+ * A target command
609
900
  */
610
- dependencies?: (PluginDependency | string)[];
901
+ command: C;
611
902
  /**
612
- * Plugin setup function
903
+ * Plugin extensions to apply as the command context extension.
613
904
  */
614
- setup?: PluginFunction<G>;
905
+ extensions?: E;
615
906
  /**
616
- * Plugin extension
907
+ * A command options, which is spicialized from `cli` function
617
908
  */
618
- extension?: PluginExtension<T, G>;
909
+ cliOptions: CliOptions<G>;
619
910
  /**
620
- * Callback for when the plugin is extended with `extension` option.
911
+ * Validation error from argument parsing.
621
912
  */
622
- onExtension?: OnPluginExtension<G>;
623
- }
624
- /**
625
- * Gunshi plugin, which is a function that receives a PluginContext.
626
- * @param ctx - A {@link PluginContext}.
627
- * @returns An {@link Awaitable} that resolves when the plugin is loaded.
628
- * @since v0.27.0
629
- */
630
- type Plugin<E extends GunshiParams['extensions'] = DefaultGunshiParams['extensions']> = PluginFunction & {
631
- id: string;
632
- name?: string;
633
- dependencies?: (PluginDependency | string)[];
634
- extension?: CommandContextExtension<E>;
635
- };
636
- /**
637
- * Plugin return type with extension
638
- * @internal
639
- */
640
- interface PluginWithExtension<E extends GunshiParams['extensions'] = DefaultGunshiParams['extensions']> extends Plugin<E> {
641
- id: string;
642
- name: string;
643
- dependencies?: (PluginDependency | string)[];
644
- extension: CommandContextExtension<E>;
645
- }
646
- /**
647
- * Plugin return type without extension
648
- * @internal
649
- */
650
- interface PluginWithoutExtension<E extends GunshiParams['extensions'] = DefaultGunshiParams['extensions']> extends Plugin<E> {
651
- id: string;
652
- name: string;
653
- dependencies?: (PluginDependency | string)[];
913
+ validationError?: AggregateError;
654
914
  }
655
915
  /**
656
- * Define a plugin with extension capabilities
657
- * @param options - {@link PluginOptions | plugin options}
658
- * @return A defined plugin with extension capabilities.
659
- * @since v0.27.0
660
- */
661
- declare function plugin<I extends string, P extends PluginExtension<any, DefaultGunshiParams>>(options: {
662
- id: I;
663
- name?: string;
664
- dependencies?: (PluginDependency | string)[];
665
- setup?: (ctx: Readonly<PluginContext<GunshiParams<{
666
- args: Args;
667
- extensions: { [K in I]: ReturnType<P> };
668
- }>>>) => Awaitable<void>;
669
- extension: P;
670
- onExtension?: OnPluginExtension<{
671
- args: Args;
672
- extensions: { [K in I]: ReturnType<P> };
673
- }>;
674
- }): PluginWithExtension<ReturnType<P>>;
675
- /**
676
- * Define a plugin without extension capabilities
677
- * @param options - {@link PluginOptions | plugin options} without extension
678
- * @returns A defined plugin without extension capabilities.
679
- * @since v0.27.0
680
- */
681
- declare function plugin(options: {
682
- id: string;
683
- name?: string;
684
- dependencies?: (PluginDependency | string)[];
685
- setup?: (ctx: Readonly<PluginContext<DefaultGunshiParams>>) => Awaitable<void>;
686
- }): PluginWithoutExtension<DefaultGunshiParams['extensions']>;
916
+ * Create a {@link CommandContext | command context}
917
+ * @param param A {@link CommandContextParams | parameters} to create a {@link CommandContext | command context}
918
+ * @returns A {@link CommandContext | command context}, which is readonly
919
+ */
920
+ declare function createCommandContext<G extends GunshiParamsConstraint = DefaultGunshiParams, V extends ArgValues<ExtractArgs<G>> = ArgValues<ExtractArgs<G>>, C extends Command<G> | LazyCommand<G> = Command<G>, E extends Record<string, CommandContextExtension> = {}>({
921
+ args,
922
+ explicit,
923
+ values,
924
+ positionals,
925
+ rest,
926
+ argv,
927
+ tokens,
928
+ command,
929
+ extensions,
930
+ cliOptions,
931
+ callMode,
932
+ omitted,
933
+ validationError
934
+ }: CommandContextParams<G, V, C, E>): Promise<{} extends ExtractExtensions<E> ? Readonly<CommandContext<G>> : Readonly<CommandContext<GunshiParams<{
935
+ args: ExtractArgs<G>;
936
+ extensions: ExtractExtensions<E>;
937
+ }>>>>;
687
938
  //#endregion
688
- export { ArgSchema, ArgToken, ArgValues, Args, Awaitable, Command, CommandContext, CommandContextCore, CommandDecorator, CommandExamplesFetcher, CommandRunner, DefaultGunshiParams, ExtendContext, ExtractArgs, GunshiParams, GunshiParamsConstraint, LazyCommand, NormalizeToGunshiParams, OnPluginExtension, Plugin, PluginContext, PluginDependency, PluginExtension, PluginFunction, PluginOptions, PluginWithExtension, PluginWithoutExtension, RendererDecorator, ValidationErrorsDecorator, plugin };
939
+ export { ArgSchema, ArgToken, ArgValues, Args, Awaitable, CLI_OPTIONS_DEFAULT, Command, CommandContext, CommandContextCore, CommandDecorator, CommandExamplesFetcher, CommandRunner, DefaultGunshiParams, ExtendContext, ExtractArgs, GunshiParams, GunshiParamsConstraint, LazyCommand, NormalizeToGunshiParams, OnPluginExtension, Plugin, PluginContext, PluginDependency, PluginExtension, PluginFunction, PluginOptions, PluginWithExtension, PluginWithoutExtension, RendererDecorator, ValidationErrorsDecorator, createCommandContext, plugin };
package/lib/index.js CHANGED
@@ -1,3 +1,109 @@
1
+ //#region ../gunshi/src/constants.ts
2
+ const ANONYMOUS_COMMAND_NAME = "(anonymous)";
3
+ const NOOP = () => {};
4
+ const CLI_OPTIONS_DEFAULT = {
5
+ name: void 0,
6
+ description: void 0,
7
+ version: void 0,
8
+ cwd: void 0,
9
+ usageSilent: false,
10
+ subCommands: void 0,
11
+ leftMargin: 2,
12
+ middleMargin: 10,
13
+ usageOptionType: false,
14
+ usageOptionValue: true,
15
+ renderHeader: void 0,
16
+ renderUsage: void 0,
17
+ renderValidationErrors: void 0,
18
+ plugins: void 0
19
+ };
20
+
21
+ //#endregion
22
+ //#region ../gunshi/src/utils.ts
23
+ function isLazyCommand(cmd) {
24
+ return typeof cmd === "function" && "commandName" in cmd && !!cmd.commandName;
25
+ }
26
+ function create(obj = null) {
27
+ return Object.create(obj);
28
+ }
29
+ function log(...args) {
30
+ console.log(...args);
31
+ }
32
+ function deepFreeze(obj, ignores = []) {
33
+ if (obj === null || typeof obj !== "object") return obj;
34
+ for (const key of Object.keys(obj)) {
35
+ const value = obj[key];
36
+ if (ignores.includes(key)) continue;
37
+ if (typeof value === "object" && value !== null) deepFreeze(value, ignores);
38
+ }
39
+ return Object.freeze(obj);
40
+ }
41
+
42
+ //#endregion
43
+ //#region ../gunshi/src/context.ts
44
+ /**
45
+ * Create a {@link CommandContext | command context}
46
+ * @param param A {@link CommandContextParams | parameters} to create a {@link CommandContext | command context}
47
+ * @returns A {@link CommandContext | command context}, which is readonly
48
+ */
49
+ async function createCommandContext({ args, explicit, values, positionals, rest, argv, tokens, command, extensions = {}, cliOptions, callMode = "entry", omitted = false, validationError }) {
50
+ /**
51
+ * normailize the options schema and values, to avoid prototype pollution
52
+ */
53
+ const _args = Object.entries(args).reduce((acc, [key, value]) => {
54
+ acc[key] = Object.assign(create(), value);
55
+ return acc;
56
+ }, create());
57
+ /**
58
+ * setup the environment
59
+ */
60
+ const env = Object.assign(create(), CLI_OPTIONS_DEFAULT, cliOptions);
61
+ /**
62
+ * create the command context
63
+ */
64
+ const core = Object.assign(create(), {
65
+ name: getCommandName(command),
66
+ description: command.description,
67
+ omitted,
68
+ callMode,
69
+ env,
70
+ args: _args,
71
+ explicit,
72
+ values,
73
+ positionals,
74
+ rest,
75
+ _: argv,
76
+ tokens,
77
+ toKebab: command.toKebab,
78
+ log: cliOptions.usageSilent ? NOOP : log,
79
+ validationError
80
+ });
81
+ /**
82
+ * extend the command context with extensions
83
+ */
84
+ if (Object.keys(extensions).length > 0) {
85
+ const ext = create(null);
86
+ Object.defineProperty(core, "extensions", {
87
+ value: ext,
88
+ writable: false,
89
+ enumerable: true,
90
+ configurable: true
91
+ });
92
+ for (const [key, extension] of Object.entries(extensions)) {
93
+ ext[key] = await extension.factory(core, command);
94
+ if (extension.onFactory) await extension.onFactory(core, command);
95
+ }
96
+ }
97
+ const ctx = deepFreeze(core, ["extensions"]);
98
+ return ctx;
99
+ }
100
+ function getCommandName(cmd) {
101
+ if (isLazyCommand(cmd)) return cmd.commandName || cmd.name || ANONYMOUS_COMMAND_NAME;
102
+ else if (typeof cmd === "object") return cmd.name || ANONYMOUS_COMMAND_NAME;
103
+ else return ANONYMOUS_COMMAND_NAME;
104
+ }
105
+
106
+ //#endregion
1
107
  //#region ../gunshi/src/plugin/core.ts
2
108
  /**
3
109
  * Define a plugin
@@ -43,4 +149,4 @@ function plugin(options) {
43
149
  }
44
150
 
45
151
  //#endregion
46
- export { plugin };
152
+ export { CLI_OPTIONS_DEFAULT, createCommandContext, plugin };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gunshi/plugin",
3
3
  "description": "utilities for gunshi plugin",
4
- "version": "0.27.0-alpha.5",
4
+ "version": "0.27.0-alpha.7",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
@@ -56,7 +56,7 @@
56
56
  "jsr-exports-lint": "^0.4.1",
57
57
  "publint": "^0.3.12",
58
58
  "tsdown": "^0.12.9",
59
- "gunshi": "0.27.0-alpha.5"
59
+ "gunshi": "0.27.0-alpha.7"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "tsdown",