gunshi 0.27.6 → 0.28.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/lib/bone.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as SubCommandable, C as GunshiParams, D as Prettify, E as NormalizeToGunshiParams, O as RendererDecorator, S as ExtractExtensions, T as LazyCommand, _ as Commandable, a as Awaitable, b as ExtractArgExplicitlyProvided, c as CommandCallMode, d as CommandContextExtension, f as CommandDecorator, g as CommandRunner, h as CommandLoader, i as Args, j as ValidationErrorsDecorator, k as RenderingOptions, l as CommandContext, m as CommandExamplesFetcher, n as ArgToken, o as CliOptions, p as CommandEnvironment, r as ArgValues, s as Command, t as ArgSchema, u as CommandContextCore, v as DefaultGunshiParams, w as GunshiParamsConstraint, x as ExtractArgs, y as ExtendContext } from "./types-RXstkMKh.js";
1
+ import { B as Args, C as Prettify, D as ValidationErrorsDecorator, E as SubCommandable, H as ArgToken, R as ArgSchema, S as NormalizeToGunshiParams, T as RenderingOptions, _ as ExtractArgs, a as CommandContext, b as GunshiParamsConstraint, c as CommandDecorator, d as CommandLoader, f as CommandRunner, g as ExtractArgExplicitlyProvided, h as ExtendContext, i as CommandCallMode, l as CommandEnvironment, m as DefaultGunshiParams, n as CliOptions, o as CommandContextCore, p as Commandable, r as Command, s as CommandContextExtension, t as Awaitable, u as CommandExamplesFetcher, v as ExtractExtensions, w as RendererDecorator, x as LazyCommand, y as GunshiParams, z as ArgValues } from "./types-Doxo8g3Y.js";
2
2
 
3
3
  //#region src/cli/bone.d.ts
4
4
  /**
package/lib/bone.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as cliCore } from "./core-BEHAY3pE.js";
1
+ import { t as cliCore } from "./core-C9P_Gd_f.js";
2
2
 
3
3
  //#region src/cli/bone.ts
4
4
  /**
@@ -1,6 +1,6 @@
1
- import { t as cliCore } from "./core-BEHAY3pE.js";
1
+ import { t as cliCore } from "./core-C9P_Gd_f.js";
2
2
  import { t as plugin } from "./core-eN5xmB3s.js";
3
- import { a as namespacedId, s as COMMON_ARGS, t as renderer } from "./src-DulE0ns5.js";
3
+ import { a as namespacedId, s as COMMON_ARGS, t as renderer } from "./src-CfO5ab2f.js";
4
4
 
5
5
  //#region ../plugin-global/src/types.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { o as CliOptions, v as DefaultGunshiParams } from "./types-RXstkMKh.js";
1
+ import { m as DefaultGunshiParams, n as CliOptions } from "./types-Doxo8g3Y.js";
2
2
 
3
3
  //#region src/constants.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { i as log, n as deepFreeze, r as isLazyCommand, t as create } from "./utils-A01g1U8-.js";
1
+ import { a as log, i as isLazyCommand, n as deepFreeze, t as create } from "./utils-DNS9AIR_.js";
2
2
  import { n as CLI_OPTIONS_DEFAULT, r as NOOP, t as ANONYMOUS_COMMAND_NAME } from "./constants-WviiKqbt.js";
3
3
 
4
4
  //#region src/context.ts
@@ -23,7 +23,7 @@ import { n as CLI_OPTIONS_DEFAULT, r as NOOP, t as ANONYMOUS_COMMAND_NAME } from
23
23
  * @param param - A {@link CommandContextParams | parameters} to create a command context.
24
24
  * @returns A {@link CommandContext | command context}, which is readonly.
25
25
  */
26
- async function createCommandContext({ args = {}, explicit = {}, values = {}, positionals = [], rest = [], argv = [], tokens = [], command = {}, extensions = {}, cliOptions = {}, callMode = "entry", omitted = false, validationError = void 0 }) {
26
+ async function createCommandContext({ args = {}, explicit = {}, values = {}, positionals = [], rest = [], argv = [], tokens = [], command = {}, extensions = {}, cliOptions = {}, callMode = "entry", commandPath = [], omitted = false, validationError = void 0 }) {
27
27
  /**
28
28
  * normailize the options schema and values, to avoid prototype pollution
29
29
  */
@@ -52,6 +52,7 @@ async function createCommandContext({ args = {}, explicit = {}, values = {}, pos
52
52
  description: command.description,
53
53
  omitted,
54
54
  callMode,
55
+ commandPath,
55
56
  env,
56
57
  args: _args,
57
58
  explicit,
package/lib/context.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as GunshiParams, T as LazyCommand, b as ExtractArgExplicitlyProvided, c as CommandCallMode, d as CommandContextExtension, i as Args, l as CommandContext, n as ArgToken, o as CliOptions, r as ArgValues, s as Command, v as DefaultGunshiParams, w as GunshiParamsConstraint, x as ExtractArgs, y as ExtendContext } from "./types-RXstkMKh.js";
1
+ import { B as Args, H as ArgToken, _ as ExtractArgs, a as CommandContext, b as GunshiParamsConstraint, g as ExtractArgExplicitlyProvided, h as ExtendContext, i as CommandCallMode, m as DefaultGunshiParams, n as CliOptions, r as Command, s as CommandContextExtension, x as LazyCommand, y as GunshiParams, z as ArgValues } from "./types-Doxo8g3Y.js";
2
2
 
3
3
  //#region src/context.d.ts
4
4
 
@@ -52,6 +52,10 @@ interface CommandContextParams<G extends GunshiParams | {
52
52
  * Command call mode.
53
53
  */
54
54
  callMode?: CommandCallMode;
55
+ /**
56
+ * The path of nested sub-commands resolved to reach the current command.
57
+ */
58
+ commandPath?: string[];
55
59
  /**
56
60
  * A target command
57
61
  */
@@ -87,6 +91,7 @@ declare function createCommandContext<G extends GunshiParamsConstraint = Default
87
91
  extensions,
88
92
  cliOptions,
89
93
  callMode,
94
+ commandPath,
90
95
  omitted,
91
96
  validationError
92
97
  }: CommandContextParams<G, V, C, E>): Promise<{} extends ExtractExtensions<E> ? Readonly<CommandContext<G>> : Readonly<CommandContext<GunshiParams<{
package/lib/context.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as createCommandContext } from "./context-2cGqZAlo.js";
1
+ import { t as createCommandContext } from "./context-CHDIbgwd.js";
2
2
 
3
3
  export { createCommandContext };
@@ -1,6 +1,6 @@
1
- import { a as resolveLazyCommand, o as kebabnize, r as isLazyCommand, t as create } from "./utils-A01g1U8-.js";
1
+ import { i as isLazyCommand, o as resolveLazyCommand, r as getCommandSubCommands, s as kebabnize, t as create } from "./utils-DNS9AIR_.js";
2
2
  import { n as CLI_OPTIONS_DEFAULT, r as NOOP, t as ANONYMOUS_COMMAND_NAME } from "./constants-WviiKqbt.js";
3
- import { t as createCommandContext } from "./context-2cGqZAlo.js";
3
+ import { t as createCommandContext } from "./context-CHDIbgwd.js";
4
4
 
5
5
  //#region ../../node_modules/.pnpm/args-tokens@0.23.1/node_modules/args-tokens/lib/parser.js
6
6
  const HYPHEN_CHAR = "-";
@@ -664,16 +664,18 @@ async function cliCore(argv, entry, options, plugins) {
664
664
  const resolvedPlugins = await applyPlugins(pluginContext, [...plugins, ...options.plugins || []]);
665
665
  const cliOptions = normalizeCliOptions(options, decorators, pluginContext);
666
666
  const tokens = parseArgs(argv);
667
- const subCommand = getSubCommand(tokens);
668
- const { commandName: name, command, callMode } = resolveCommand(subCommand, entry, cliOptions);
667
+ const resolved = resolveCommandTree(tokens, entry, cliOptions);
668
+ const { commandName: name, command, callMode, commandPath, depth, levelSubCommands } = resolved;
669
669
  if (!command) throw new Error(`Command not found: ${name || ""}`);
670
670
  const args = resolveArguments(pluginContext, getCommandArgs(command));
671
+ const skipPositional = depth > 0 ? depth - 1 : -1;
671
672
  const { explicit, values, positionals, rest, error } = resolveArgs(args, tokens, {
672
673
  shortGrouping: true,
673
674
  toKebab: command.toKebab,
674
- skipPositional: callMode === "subCommand" && cliOptions.subCommands.size > 0 ? 0 : -1
675
+ skipPositional
675
676
  });
676
- const omitted = !subCommand;
677
+ const omitted = resolved.omitted;
678
+ if (levelSubCommands) cliOptions.subCommands = levelSubCommands;
677
679
  const resolvedCommand = isLazyCommand(command) ? await resolveLazyCommand(command, name, true) : command;
678
680
  return await executeCommand(resolvedCommand, await createCommandContext({
679
681
  args,
@@ -685,6 +687,7 @@ async function cliCore(argv, entry, options, plugins) {
685
687
  tokens,
686
688
  omitted,
687
689
  callMode,
690
+ commandPath,
688
691
  command: resolvedCommand,
689
692
  extensions: getPluginExtensions(resolvedPlugins),
690
693
  validationError: error,
@@ -721,9 +724,12 @@ function createInitialSubCommands(options, entryCmd) {
721
724
  const subCommands = new Map(options.subCommands instanceof Map ? options.subCommands : []);
722
725
  if (!(options.subCommands instanceof Map) && isObject(options.subCommands)) for (const [name, cmd] of Object.entries(options.subCommands)) subCommands.set(name, cmd);
723
726
  if (hasSubCommands) {
724
- if (isLazyCommand(entryCmd) || typeof entryCmd === "object") {
725
- entryCmd.entry = true;
726
- subCommands.set(resolveEntryName(entryCmd), entryCmd);
727
+ if (isLazyCommand(entryCmd)) {
728
+ const entryCopy = Object.assign((...args) => entryCmd(...args), entryCmd, { entry: true });
729
+ subCommands.set(resolveEntryName(entryCopy), entryCopy);
730
+ } else if (typeof entryCmd === "object") {
731
+ const entryCopy = Object.assign(create(), entryCmd, { entry: true });
732
+ subCommands.set(resolveEntryName(entryCopy), entryCopy);
727
733
  } else if (typeof entryCmd === "function") {
728
734
  const name = entryCmd.name || ANONYMOUS_COMMAND_NAME;
729
735
  subCommands.set(name, {
@@ -743,48 +749,102 @@ function normalizeCliOptions(options, decorators, pluginContext) {
743
749
  if (resolvedOptions.renderValidationErrors === void 0) resolvedOptions.renderValidationErrors = decorators.getValidationErrorsRenderer();
744
750
  return resolvedOptions;
745
751
  }
746
- function getSubCommand(tokens) {
747
- const firstToken = tokens[0];
748
- return firstToken && firstToken.kind === "positional" && firstToken.index === 0 && firstToken.value ? firstToken.value : "";
752
+ function getPositionalTokens(tokens) {
753
+ return tokens.filter((t) => t.kind === "positional").map((t) => t.value).filter((v) => !!v);
749
754
  }
750
- const CANNOT_RESOLVE_COMMAND = { callMode: "unexpected" };
751
- function resolveCommand(sub, entry, options) {
752
- const omitted = !sub;
753
- function doResolveCommand() {
755
+ function resolveCommandTree(tokens, entry, options) {
756
+ const positionals = getPositionalTokens(tokens);
757
+ function resolveAsEntry() {
754
758
  if (typeof entry === "function") if ("commandName" in entry && entry.commandName) return {
755
759
  commandName: entry.commandName,
756
760
  command: entry,
757
- callMode: "entry"
761
+ callMode: "entry",
762
+ commandPath: [],
763
+ depth: 0,
764
+ omitted: options.subCommands.size > 0 && !positionals[0],
765
+ levelSubCommands: options.subCommands.size > 0 ? options.subCommands : void 0
758
766
  };
759
767
  else return {
760
768
  command: {
761
769
  run: entry,
762
770
  entry: true
763
771
  },
764
- callMode: "entry"
772
+ callMode: "entry",
773
+ commandPath: [],
774
+ depth: 0,
775
+ omitted: options.subCommands.size > 0 && !positionals[0],
776
+ levelSubCommands: options.subCommands.size > 0 ? options.subCommands : void 0
765
777
  };
766
778
  else if (typeof entry === "object") return {
767
779
  commandName: resolveEntryName(entry),
768
780
  command: entry,
769
- callMode: "entry"
781
+ callMode: "entry",
782
+ commandPath: [],
783
+ depth: 0,
784
+ omitted: options.subCommands.size > 0 && !positionals[0],
785
+ levelSubCommands: options.subCommands.size > 0 ? options.subCommands : void 0
770
786
  };
771
- else return CANNOT_RESOLVE_COMMAND;
772
- }
773
- if (omitted || options.subCommands?.size === 0) return doResolveCommand();
774
- const cmd = options.subCommands?.get(sub);
775
- if (cmd == null) {
776
- if (options.fallbackToEntry) return doResolveCommand();
777
- return {
778
- commandName: sub,
779
- callMode: "unexpected"
787
+ else return {
788
+ callMode: "unexpected",
789
+ commandPath: [],
790
+ depth: 0,
791
+ omitted: false,
792
+ levelSubCommands: void 0
780
793
  };
781
794
  }
782
- if (isLazyCommand(cmd) && cmd.commandName == null) cmd.commandName = sub;
783
- else if (typeof cmd === "object" && cmd.name == null) cmd.name = sub;
795
+ if (positionals.length === 0 || options.subCommands.size === 0) return resolveAsEntry();
796
+ let currentSubCommands = options.subCommands;
797
+ let resolvedCommand;
798
+ let resolvedName;
799
+ const commandPath = [];
800
+ let depth = 0;
801
+ for (let i = 0; i < positionals.length; i++) {
802
+ const token = positionals[i];
803
+ const cmd = currentSubCommands.get(token);
804
+ if (cmd == null) {
805
+ if (depth === 0) {
806
+ if (options.fallbackToEntry) return resolveAsEntry();
807
+ return {
808
+ commandName: token,
809
+ callMode: "unexpected",
810
+ commandPath: [],
811
+ depth: 0,
812
+ omitted: false,
813
+ levelSubCommands: void 0
814
+ };
815
+ }
816
+ break;
817
+ }
818
+ let resolved = cmd;
819
+ if (typeof cmd === "function" && cmd.commandName == null) resolved = Object.assign((...args) => cmd(...args), cmd, { commandName: token });
820
+ else if (typeof cmd === "object" && cmd.name == null) resolved = Object.assign(create(), cmd, { name: token });
821
+ resolvedCommand = resolved;
822
+ resolvedName = token;
823
+ commandPath.push(token);
824
+ depth++;
825
+ const nestedSubCommands = getCommandSubCommands(cmd);
826
+ if (nestedSubCommands && nestedSubCommands.size > 0) currentSubCommands = nestedSubCommands;
827
+ else break;
828
+ }
829
+ if (!resolvedCommand) return resolveAsEntry();
830
+ const resolvedSubCommands = getCommandSubCommands(resolvedCommand);
831
+ const omitted = resolvedSubCommands != null && resolvedSubCommands.size > 0;
832
+ let levelSubCommands;
833
+ if (omitted && resolvedSubCommands) {
834
+ levelSubCommands = new Map(resolvedSubCommands);
835
+ let entryCopy;
836
+ if (typeof resolvedCommand === "function") entryCopy = Object.assign((...args) => resolvedCommand(...args), resolvedCommand, { entry: true });
837
+ else entryCopy = Object.assign(create(), resolvedCommand, { entry: true });
838
+ levelSubCommands.set(resolvedName || resolveEntryName(entryCopy), entryCopy);
839
+ }
784
840
  return {
785
- commandName: sub,
786
- command: cmd,
787
- callMode: "subCommand"
841
+ commandName: resolvedName,
842
+ command: resolvedCommand,
843
+ callMode: depth > 0 ? "subCommand" : "entry",
844
+ commandPath,
845
+ depth,
846
+ omitted,
847
+ levelSubCommands
788
848
  };
789
849
  }
790
850
  function resolveEntryName(entry) {
@@ -1,4 +1,4 @@
1
- import { C as GunshiParams, D as Prettify, S as ExtractExtensions, T as LazyCommand, g as CommandRunner, h as CommandLoader, i as Args, r as ArgValues, s as Command, t as ArgSchema, v as DefaultGunshiParams, w as GunshiParamsConstraint, x as ExtractArgs, y as ExtendContext } from "./types-RXstkMKh.js";
1
+ import { B as Args, C as Prettify, R as ArgSchema, _ as ExtractArgs, b as GunshiParamsConstraint, d as CommandLoader, f as CommandRunner, h as ExtendContext, m as DefaultGunshiParams, r as Command, v as ExtractExtensions, x as LazyCommand, y as GunshiParams, z as ArgValues } from "./types-Doxo8g3Y.js";
2
2
  import { CommandContextParams, createCommandContext } from "./context.js";
3
3
 
4
4
  //#region src/definition.d.ts
package/lib/definition.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createCommandContext } from "./context-2cGqZAlo.js";
1
+ import { t as createCommandContext } from "./context-CHDIbgwd.js";
2
2
 
3
3
  //#region src/definition.ts
4
4
  /**
@@ -63,6 +63,7 @@ function lazy(loader, definition) {
63
63
  lazyCommand.internal = definition.internal;
64
64
  lazyCommand.entry = definition.entry;
65
65
  lazyCommand.toKebab = definition.toKebab;
66
+ if (definition.subCommands) lazyCommand.subCommands = definition.subCommands;
66
67
  if ("resource" in definition) lazyCommand.resource = definition.resource;
67
68
  }
68
69
  return lazyCommand;
@@ -1,4 +1,4 @@
1
- import { T as LazyCommand, o as CliOptions, s as Command, v as DefaultGunshiParams, w as GunshiParamsConstraint } from "./types-RXstkMKh.js";
1
+ import { b as GunshiParamsConstraint, m as DefaultGunshiParams, n as CliOptions, r as Command, x as LazyCommand } from "./types-Doxo8g3Y.js";
2
2
 
3
3
  //#region src/generator.d.ts
4
4
 
@@ -18,6 +18,6 @@ type GenerateOptions<G extends GunshiParamsConstraint = DefaultGunshiParams> = C
18
18
  * @param options - A {@linkcode GenerateOptions | cli options}
19
19
  * @returns A rendered usage.
20
20
  */
21
- declare function generate<G extends GunshiParamsConstraint = DefaultGunshiParams>(command: string | null, entry: Command<G> | LazyCommand<G>, options?: GenerateOptions<G>): Promise<string>;
21
+ declare function generate<G extends GunshiParamsConstraint = DefaultGunshiParams>(command: string | string[] | null, entry: Command<G> | LazyCommand<G>, options?: GenerateOptions<G>): Promise<string>;
22
22
  //#endregion
23
23
  export { GenerateOptions, generate };
package/lib/generator.js CHANGED
@@ -1,7 +1,7 @@
1
- import "./core-BEHAY3pE.js";
2
- import { t as create } from "./utils-A01g1U8-.js";
3
- import "./src-DulE0ns5.js";
4
- import { t as cli } from "./cli-BzfnVXOV.js";
1
+ import "./core-C9P_Gd_f.js";
2
+ import { t as create } from "./utils-DNS9AIR_.js";
3
+ import "./src-CfO5ab2f.js";
4
+ import { t as cli } from "./cli-l4AYjN-O.js";
5
5
 
6
6
  //#region src/generator.ts
7
7
  /**
@@ -30,7 +30,10 @@ import { t as cli } from "./cli-BzfnVXOV.js";
30
30
  */
31
31
  async function generate(command, entry, options = {}) {
32
32
  const args = ["-h"];
33
- if (command != null) args.unshift(command);
33
+ if (command != null) {
34
+ const parts = Array.isArray(command) ? command : command.split(" ");
35
+ args.unshift(...parts);
36
+ }
34
37
  return await cli(args, entry, {
35
38
  ...create(),
36
39
  ...options,
package/lib/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { A as SubCommandable, B as plugin, C as GunshiParams, D as Prettify, E as NormalizeToGunshiParams, F as PluginExtension, I as PluginFunction, L as PluginOptions, M as OnPluginExtension, N as Plugin, O as RendererDecorator, P as PluginDependency, R as PluginWithExtension, S as ExtractExtensions, T as LazyCommand, V as PluginContext, _ as Commandable, a as Awaitable, b as ExtractArgExplicitlyProvided, c as CommandCallMode, d as CommandContextExtension, f as CommandDecorator, g as CommandRunner, h as CommandLoader, i as Args, j as ValidationErrorsDecorator, k as RenderingOptions, l as CommandContext, m as CommandExamplesFetcher, n as ArgToken, o as CliOptions, p as CommandEnvironment, r as ArgValues, s as Command, t as ArgSchema, u as CommandContextCore, v as DefaultGunshiParams, w as GunshiParamsConstraint, x as ExtractArgs, y as ExtendContext, z as PluginWithoutExtension } from "./types-RXstkMKh.js";
1
+ import { A as PluginDependency, B as Args, C as Prettify, D as ValidationErrorsDecorator, E as SubCommandable, F as PluginWithoutExtension, H as ArgToken, I as plugin, L as PluginContext, M as PluginFunction, N as PluginOptions, O as OnPluginExtension, P as PluginWithExtension, R as ArgSchema, S as NormalizeToGunshiParams, T as RenderingOptions, U as parseArgs, V as resolveArgs, _ as ExtractArgs, a as CommandContext, b as GunshiParamsConstraint, c as CommandDecorator, d as CommandLoader, f as CommandRunner, g as ExtractArgExplicitlyProvided, h as ExtendContext, i as CommandCallMode, j as PluginExtension, k as Plugin, l as CommandEnvironment, m as DefaultGunshiParams, n as CliOptions, o as CommandContextCore, p as Commandable, r as Command, s as CommandContextExtension, t as Awaitable, u as CommandExamplesFetcher, v as ExtractExtensions, w as RendererDecorator, x as LazyCommand, y as GunshiParams, z as ArgValues } from "./types-Doxo8g3Y.js";
2
2
  import { CommandContextParams, createCommandContext } from "./context.js";
3
3
  import { define, defineWithTypes, lazy, lazyWithTypes } from "./definition.js";
4
- import { t as ANONYMOUS_COMMAND_NAME } from "./constants-BbfDN8vC.js";
5
- import { parseArgs, resolveArgs } from "args-tokens";
4
+ import { t as ANONYMOUS_COMMAND_NAME } from "./constants-C7V6-RNo.js";
6
5
 
7
6
  //#region ../plugin-i18n/src/types.d.ts
8
7
 
package/lib/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { n as resolveArgs, r as parseArgs } from "./core-BEHAY3pE.js";
1
+ import { n as resolveArgs, r as parseArgs } from "./core-C9P_Gd_f.js";
2
2
  import { t as ANONYMOUS_COMMAND_NAME } from "./constants-WviiKqbt.js";
3
- import { t as createCommandContext } from "./context-2cGqZAlo.js";
3
+ import { t as createCommandContext } from "./context-CHDIbgwd.js";
4
4
  import { define, defineWithTypes, lazy, lazyWithTypes } from "./definition.js";
5
5
  import { t as plugin } from "./core-eN5xmB3s.js";
6
- import { a as namespacedId, o as BUILT_IN_PREFIX } from "./src-DulE0ns5.js";
7
- import { t as cli } from "./cli-BzfnVXOV.js";
6
+ import { a as namespacedId, o as BUILT_IN_PREFIX } from "./src-CfO5ab2f.js";
7
+ import { t as cli } from "./cli-l4AYjN-O.js";
8
8
 
9
9
  //#region ../plugin-i18n/src/translation.ts
10
10
  /**
package/lib/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as plugin, C as GunshiParams, D as Prettify, E as NormalizeToGunshiParams, F as PluginExtension, I as PluginFunction, L as PluginOptions, M as OnPluginExtension, N as Plugin, O as RendererDecorator, P as PluginDependency, R as PluginWithExtension, S as ExtractExtensions, T as LazyCommand, V as PluginContext, a as Awaitable, d as CommandContextExtension, f as CommandDecorator, g as CommandRunner, i as Args, j as ValidationErrorsDecorator, l as CommandContext, m as CommandExamplesFetcher, n as ArgToken, r as ArgValues, s as Command, t as ArgSchema, u as CommandContextCore, v as DefaultGunshiParams, w as GunshiParamsConstraint, x as ExtractArgs, y as ExtendContext, z as PluginWithoutExtension } from "./types-RXstkMKh.js";
1
+ import { A as PluginDependency, B as Args, C as Prettify, D as ValidationErrorsDecorator, F as PluginWithoutExtension, H as ArgToken, I as plugin, L as PluginContext, M as PluginFunction, N as PluginOptions, O as OnPluginExtension, P as PluginWithExtension, R as ArgSchema, S as NormalizeToGunshiParams, _ as ExtractArgs, a as CommandContext, b as GunshiParamsConstraint, c as CommandDecorator, f as CommandRunner, h as ExtendContext, j as PluginExtension, k as Plugin, m as DefaultGunshiParams, o as CommandContextCore, r as Command, s as CommandContextExtension, t as Awaitable, u as CommandExamplesFetcher, v as ExtractExtensions, w as RendererDecorator, x as LazyCommand, y as GunshiParams, z as ArgValues } from "./types-Doxo8g3Y.js";
2
2
  import { CommandContextParams, createCommandContext } from "./context.js";
3
- import { n as CLI_OPTIONS_DEFAULT, t as ANONYMOUS_COMMAND_NAME } from "./constants-BbfDN8vC.js";
3
+ import { n as CLI_OPTIONS_DEFAULT, t as ANONYMOUS_COMMAND_NAME } from "./constants-C7V6-RNo.js";
4
4
  export { ANONYMOUS_COMMAND_NAME, type ArgSchema, type ArgToken, type ArgValues, type Args, type Awaitable, CLI_OPTIONS_DEFAULT, type Command, type CommandContext, type CommandContextCore, type CommandContextExtension, type CommandContextParams, type CommandDecorator, type CommandExamplesFetcher, type CommandRunner, type DefaultGunshiParams, type ExtendContext, type ExtractArgs, type ExtractExtensions, type GunshiParams, type GunshiParamsConstraint, type LazyCommand, type NormalizeToGunshiParams, type OnPluginExtension, type Plugin, type PluginContext, type PluginDependency, type PluginExtension, type PluginFunction, type PluginOptions, type PluginWithExtension, type PluginWithoutExtension, type Prettify, type RendererDecorator, type ValidationErrorsDecorator, createCommandContext, plugin };
package/lib/plugin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as CLI_OPTIONS_DEFAULT, t as ANONYMOUS_COMMAND_NAME } from "./constants-WviiKqbt.js";
2
- import { t as createCommandContext } from "./context-2cGqZAlo.js";
2
+ import { t as createCommandContext } from "./context-CHDIbgwd.js";
3
3
  import { t as plugin } from "./core-eN5xmB3s.js";
4
4
 
5
5
  export { ANONYMOUS_COMMAND_NAME, CLI_OPTIONS_DEFAULT, createCommandContext, plugin };
package/lib/renderer.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as GunshiParams, l as CommandContext, v as DefaultGunshiParams } from "./types-RXstkMKh.js";
1
+ import { a as CommandContext, m as DefaultGunshiParams, y as GunshiParams } from "./types-Doxo8g3Y.js";
2
2
 
3
3
  //#region ../plugin-renderer/src/header.d.ts
4
4
  /**
package/lib/renderer.js CHANGED
@@ -1,3 +1,3 @@
1
- import { i as renderHeader, n as renderValidationErrors, r as renderUsage } from "./src-DulE0ns5.js";
1
+ import { i as renderHeader, n as renderValidationErrors, r as renderUsage } from "./src-CfO5ab2f.js";
2
2
 
3
3
  export { renderHeader, renderUsage, renderValidationErrors };
@@ -1,4 +1,4 @@
1
- import { a as resolveLazyCommand, o as kebabnize } from "./utils-A01g1U8-.js";
1
+ import { o as resolveLazyCommand, s as kebabnize } from "./utils-DNS9AIR_.js";
2
2
  import { t as ANONYMOUS_COMMAND_NAME } from "./constants-WviiKqbt.js";
3
3
  import { t as plugin } from "./core-eN5xmB3s.js";
4
4
 
@@ -213,7 +213,7 @@ const COMMON_ARGS_KEYS = Object.keys(COMMON_ARGS);
213
213
  */
214
214
  async function renderUsage(ctx) {
215
215
  const messages = [];
216
- if (!ctx.omitted) {
216
+ if (ctx.callMode === "subCommand") {
217
217
  const description = await resolveDescription(ctx);
218
218
  if (description) messages.push(description, "");
219
219
  }
@@ -307,10 +307,11 @@ async function renderCommandsSection(ctx) {
307
307
  return `${command.padStart(ctx.env.leftMargin + command.length)}`;
308
308
  }));
309
309
  messages.push(...commandsStr, "", `${await ctx.extensions[pluginId].text(resolveBuiltInKey("FORMORE"))}:`);
310
+ const basePath = ctx.commandPath && ctx.commandPath.length > 0 ? `${ctx.env.name} ${ctx.commandPath.join(" ")}` : ctx.env.name;
310
311
  messages.push(...loadedCommands.map((cmd) => {
311
312
  let commandStr = cmd.entry ? "" : cmd.name || "";
312
313
  if (commandStr) commandStr += " ";
313
- const commandHelp = `${ctx.env.name} ${commandStr}--help`;
314
+ const commandHelp = `${basePath} ${commandStr}--help`;
314
315
  return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`;
315
316
  }));
316
317
  return messages;
@@ -345,6 +346,7 @@ async function resolveEntry(ctx) {
345
346
  * @returns The sub command name
346
347
  */
347
348
  async function resolveSubCommand(ctx) {
349
+ if (ctx.commandPath && ctx.commandPath.length > 0) return ctx.commandPath.join(" ");
348
350
  return ctx.name || await ctx.extensions[pluginId].text(resolveBuiltInKey("SUBCOMMAND"));
349
351
  }
350
352
  /**
@@ -1,11 +1,633 @@
1
- import { ArgExplicitlyProvided, ArgSchema, ArgSchema as ArgSchema$1, ArgToken, ArgToken as ArgToken$1, ArgValues, ArgValues as ArgValues$1, Args, Args as Args$1 } from "args-tokens";
2
-
3
- //#region src/plugin/context.d.ts
1
+ //#region ../../node_modules/.pnpm/args-tokens@0.23.1/node_modules/args-tokens/lib/parser.d.ts
2
+ //#region src/parser.d.ts
3
+ /**
4
+ * Entry point of argument parser.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * forked from `nodejs/node` (`pkgjs/parseargs`)
10
+ * repository url: https://github.com/nodejs/node (https://github.com/pkgjs/parseargs)
11
+ * code url: https://github.com/nodejs/node/blob/main/lib/internal/util/parse_args/parse_args.js
12
+ *
13
+ * @author kazuya kawaguchi (a.k.a. kazupon)
14
+ * @license MIT
15
+ */
16
+ /**
17
+ * Argument token Kind.
18
+ *
19
+ * - `option`: option token, support short option (e.g. `-x`) and long option (e.g. `--foo`)
20
+ * - `option-terminator`: option terminator (`--`) token, see guideline 10 in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
21
+ * - `positional`: positional token
22
+ */
23
+ type ArgTokenKind = 'option' | 'option-terminator' | 'positional';
24
+ /**
25
+ * Argument token.
26
+ */
27
+ interface ArgToken {
28
+ /**
29
+ * Argument token kind.
30
+ */
31
+ kind: ArgTokenKind;
32
+ /**
33
+ * Argument token index, e.g `--foo bar` => `--foo` index is 0, `bar` index is 1.
34
+ */
35
+ index: number;
36
+ /**
37
+ * Option name, e.g. `--foo` => `foo`, `-x` => `x`.
38
+ */
39
+ name?: string;
40
+ /**
41
+ * Raw option name, e.g. `--foo` => `--foo`, `-x` => `-x`.
42
+ */
43
+ rawName?: string;
44
+ /**
45
+ * Option value, e.g. `--foo=bar` => `bar`, `-x=bar` => `bar`.
46
+ * If the `allowCompatible` option is `true`, short option value will be same as Node.js `parseArgs` behavior.
47
+ */
48
+ value?: string;
49
+ /**
50
+ * Inline value, e.g. `--foo=bar` => `true`, `-x=bar` => `true`.
51
+ */
52
+ inlineValue?: boolean;
53
+ }
4
54
  /**
5
- * @author kazuya kawaguchi (a.k.a. kazupon)
6
- * @license MIT
7
- */
8
-
55
+ * Parser Options.
56
+ */
57
+ interface ParserOptions {
58
+ /**
59
+ * [Node.js parseArgs](https://nodejs.org/api/util.html#parseargs-tokens) tokens compatible mode.
60
+ *
61
+ * @default false
62
+ */
63
+ allowCompatible?: boolean;
64
+ }
65
+ /**
66
+ * Parse command line arguments.
67
+ *
68
+ * @param args - command line arguments
69
+ * @param options - parse options, about details see {@link ParserOptions}
70
+ * @returns Argument tokens.
71
+ *
72
+ * @example
73
+ * ```js
74
+ * import { parseArgs } from 'args-tokens' // for Node.js and Bun
75
+ * // import { parseArgs } from 'jsr:@kazupon/args-tokens' // for Deno
76
+ *
77
+ * const tokens = parseArgs(['--foo', 'bar', '-x', '--bar=baz'])
78
+ * // do something with using tokens
79
+ * // ...
80
+ * console.log('tokens:', tokens)
81
+ * ```
82
+ */
83
+ declare function parseArgs(args: string[], options?: ParserOptions): ArgToken[];
84
+ /**
85
+ * Check if `arg` is a short option (e.g. `-f`).
86
+ *
87
+ * @param arg - An argument to check
88
+ * @returns Whether `arg` is a short option.
89
+ */
90
+ //#endregion
91
+ //#region ../../node_modules/.pnpm/args-tokens@0.23.1/node_modules/args-tokens/lib/resolver.d.ts
92
+ //#region src/resolver.d.ts
93
+ /**
94
+ * An argument schema definition for command-line argument parsing.
95
+ *
96
+ * This schema is similar to the schema of Node.js `util.parseArgs` but with extended features:
97
+ * - Additional `required` and `description` properties
98
+ * - Extended `type` support: 'string', 'boolean', 'number', 'enum', 'positional', 'custom'
99
+ * - Simplified `default` property (single type, not union types)
100
+ *
101
+ * @example
102
+ * Basic string argument:
103
+ * ```ts
104
+ * const schema: ArgSchema = {
105
+ * type: 'string',
106
+ * description: 'Server hostname',
107
+ * default: 'localhost'
108
+ * }
109
+ * ```
110
+ *
111
+ * @example
112
+ * Required number argument with alias:
113
+ * ```ts
114
+ * const schema: ArgSchema = {
115
+ * type: 'number',
116
+ * short: 'p',
117
+ * description: 'Port number to listen on',
118
+ * required: true
119
+ * }
120
+ * ```
121
+ *
122
+ * @example
123
+ * Enum argument with choices:
124
+ * ```ts
125
+ * const schema: ArgSchema = {
126
+ * type: 'enum',
127
+ * choices: ['info', 'warn', 'error'],
128
+ * description: 'Logging level',
129
+ * default: 'info'
130
+ * }
131
+ * ```
132
+ */
133
+ interface ArgSchema {
134
+ /**
135
+ * Type of the argument value.
136
+ *
137
+ * - `'string'`: Text value (default if not specified)
138
+ * - `'boolean'`: `true`/`false` flag (can be negatable with `--no-` prefix)
139
+ * - `'number'`: Numeric value (parsed as integer or float)
140
+ * - `'enum'`: One of predefined string values (requires `choices` property)
141
+ * - `'positional'`: Non-option argument by position
142
+ * - `'custom'`: Custom parsing with user-defined `parse` function
143
+ *
144
+ * @example
145
+ * Different argument types:
146
+ * ```ts
147
+ * {
148
+ * name: { type: 'string' }, // --name value
149
+ * verbose: { type: 'boolean' }, // --verbose or --no-verbose
150
+ * port: { type: 'number' }, // --port 3000
151
+ * level: { type: 'enum', choices: ['debug', 'info'] },
152
+ * file: { type: 'positional' }, // first positional arg
153
+ * config: { type: 'custom', parse: JSON.parse }
154
+ * }
155
+ * ```
156
+ */
157
+ type: 'string' | 'boolean' | 'number' | 'enum' | 'positional' | 'custom';
158
+ /**
159
+ * Single character alias for the long option name.
160
+ *
161
+ * As example, allows users to use `-x` instead of `--extended-option`.
162
+ * Only valid for non-positional argument types.
163
+ *
164
+ * @example
165
+ * Short alias usage:
166
+ * ```ts
167
+ * {
168
+ * verbose: {
169
+ * type: 'boolean',
170
+ * short: 'v' // Enables both --verbose and -v
171
+ * },
172
+ * port: {
173
+ * type: 'number',
174
+ * short: 'p' // Enables both --port 3000 and -p 3000
175
+ * }
176
+ * }
177
+ * ```
178
+ */
179
+ short?: string;
180
+ /**
181
+ * Human-readable description of the argument's purpose.
182
+ *
183
+ * Used for help text generation and documentation.
184
+ * Should be concise but descriptive enough to understand the argument's role.
185
+ *
186
+ * @example
187
+ * Descriptive help text:
188
+ * ```ts
189
+ * {
190
+ * config: {
191
+ * type: 'string',
192
+ * description: 'Path to configuration file'
193
+ * },
194
+ * timeout: {
195
+ * type: 'number',
196
+ * description: 'Request timeout in milliseconds'
197
+ * }
198
+ * }
199
+ * ```
200
+ */
201
+ description?: string;
202
+ /**
203
+ * Marks the argument as required.
204
+ *
205
+ * When `true`, the argument must be provided by the user.
206
+ * If missing, an `ArgResolveError` with type 'required' will be thrown.
207
+ *
208
+ * Note: Only `true` is allowed (not `false`) to make intent explicit.
209
+ *
210
+ * @example
211
+ * Required arguments:
212
+ * ```ts
213
+ * {
214
+ * input: {
215
+ * type: 'string',
216
+ * required: true, // Must be provided: --input file.txt
217
+ * description: 'Input file path'
218
+ * },
219
+ * source: {
220
+ * type: 'positional',
221
+ * required: true // First positional argument must exist
222
+ * }
223
+ * }
224
+ * ```
225
+ */
226
+ required?: true;
227
+ /**
228
+ * Allows the argument to accept multiple values.
229
+ *
230
+ * When `true`, the resolved value becomes an array.
231
+ * For options: can be specified multiple times (--tag foo --tag bar)
232
+ * For positional: collects remaining positional arguments
233
+ *
234
+ * Note: Only `true` is allowed (not `false`) to make intent explicit.
235
+ *
236
+ * @example
237
+ * Multiple values:
238
+ * ```ts
239
+ * {
240
+ * tags: {
241
+ * type: 'string',
242
+ * multiple: true, // --tags foo --tags bar → ['foo', 'bar']
243
+ * description: 'Tags to apply'
244
+ * },
245
+ * files: {
246
+ * type: 'positional',
247
+ * multiple: true // Collects all remaining positional args
248
+ * }
249
+ * }
250
+ * ```
251
+ */
252
+ multiple?: true;
253
+ /**
254
+ * Enables negation for boolean arguments using `--no-` prefix.
255
+ *
256
+ * When `true`, allows users to explicitly set the boolean to `false`
257
+ * using `--no-option-name`. When `false` or omitted, only positive
258
+ * form is available.
259
+ *
260
+ * Only applicable to `type: 'boolean'` arguments.
261
+ *
262
+ * @example
263
+ * Negatable boolean:
264
+ * ```ts
265
+ * {
266
+ * color: {
267
+ * type: 'boolean',
268
+ * negatable: true,
269
+ * default: true,
270
+ * description: 'Enable colorized output'
271
+ * }
272
+ * // Usage: --color (true), --no-color (false)
273
+ * }
274
+ * ```
275
+ */
276
+ negatable?: boolean;
277
+ /**
278
+ * Array of allowed string values for enum-type arguments.
279
+ *
280
+ * Required when `type: 'enum'`. The argument value must be one of these choices,
281
+ * otherwise an `ArgResolveError` with type 'type' will be thrown.
282
+ *
283
+ * Supports both mutable arrays and readonly arrays for type safety.
284
+ *
285
+ * @example
286
+ * Enum choices:
287
+ * ```ts
288
+ * {
289
+ * logLevel: {
290
+ * type: 'enum',
291
+ * choices: ['debug', 'info', 'warn', 'error'] as const,
292
+ * default: 'info',
293
+ * description: 'Logging verbosity level'
294
+ * },
295
+ * format: {
296
+ * type: 'enum',
297
+ * choices: ['json', 'yaml', 'toml'],
298
+ * description: 'Output format'
299
+ * }
300
+ * }
301
+ * ```
302
+ */
303
+ choices?: string[] | readonly string[];
304
+ /**
305
+ * Default value used when the argument is not provided.
306
+ *
307
+ * The type must match the argument's `type` property:
308
+ * - `string` type: string default
309
+ * - `boolean` type: boolean default
310
+ * - `number` type: number default
311
+ * - `enum` type: must be one of the `choices` values
312
+ * - `positional`/`custom` type: any appropriate default
313
+ *
314
+ * @example
315
+ * Default values by type:
316
+ * ```ts
317
+ * {
318
+ * host: {
319
+ * type: 'string',
320
+ * default: 'localhost' // string default
321
+ * },
322
+ * verbose: {
323
+ * type: 'boolean',
324
+ * default: false // boolean default
325
+ * },
326
+ * port: {
327
+ * type: 'number',
328
+ * default: 8080 // number default
329
+ * },
330
+ * level: {
331
+ * type: 'enum',
332
+ * choices: ['low', 'high'],
333
+ * default: 'low' // must be in choices
334
+ * }
335
+ * }
336
+ * ```
337
+ */
338
+ default?: string | boolean | number;
339
+ /**
340
+ * Converts the argument name from camelCase to kebab-case for CLI usage.
341
+ *
342
+ * When `true`, a property like `maxCount` becomes available as `--max-count`.
343
+ * This allows [CAC](https://github.com/cacjs/cac) user-friendly property names while maintaining CLI conventions.
344
+ *
345
+ * Can be overridden globally with `resolveArgs({ toKebab: true })`.
346
+ *
347
+ * Note: Only `true` is allowed (not `false`) to make intent explicit.
348
+ *
349
+ * @example
350
+ * Kebab-case conversion:
351
+ * ```ts
352
+ * {
353
+ * maxRetries: {
354
+ * type: 'number',
355
+ * toKebab: true, // Accessible as --max-retries
356
+ * description: 'Maximum retry attempts'
357
+ * },
358
+ * enableLogging: {
359
+ * type: 'boolean',
360
+ * toKebab: true // Accessible as --enable-logging
361
+ * }
362
+ * }
363
+ * ```
364
+ */
365
+ toKebab?: true;
366
+ /**
367
+ * Names of other options that conflict with this option.
368
+ *
369
+ * When this option is used together with any of the conflicting options,
370
+ * an `ArgResolveError` with type 'conflict' will be thrown.
371
+ *
372
+ * Conflicts only need to be defined on one side - if option A defines a conflict
373
+ * with option B, the conflict is automatically detected when both are used,
374
+ * regardless of whether B also defines a conflict with A.
375
+ *
376
+ * Supports both single option name or array of option names.
377
+ * Option names must match the property keys in the schema object exactly
378
+ * (no automatic conversion between camelCase and kebab-case).
379
+ *
380
+ * @example
381
+ * Single conflict (bidirectional definition):
382
+ * ```ts
383
+ * {
384
+ * summer: {
385
+ * type: 'boolean',
386
+ * conflicts: 'autumn' // Cannot use --summer with --autumn
387
+ * },
388
+ * autumn: {
389
+ * type: 'boolean',
390
+ * conflicts: 'summer' // Can define on both sides for clarity
391
+ * }
392
+ * }
393
+ * ```
394
+ *
395
+ * @example
396
+ * Single conflict (one-way definition):
397
+ * ```ts
398
+ * {
399
+ * summer: {
400
+ * type: 'boolean',
401
+ * conflicts: 'autumn' // Only defined on summer side
402
+ * },
403
+ * autumn: {
404
+ * type: 'boolean'
405
+ * // No conflicts defined, but still cannot use with --summer
406
+ * }
407
+ * }
408
+ * // Usage: --summer --autumn will throw error
409
+ * // Error: "Optional argument '--summer' conflicts with '--autumn'"
410
+ * ```
411
+ *
412
+ * @example
413
+ * Multiple conflicts:
414
+ * ```ts
415
+ * {
416
+ * port: {
417
+ * type: 'number',
418
+ * conflicts: ['socket', 'pipe'], // Cannot use with --socket or --pipe
419
+ * description: 'TCP port number'
420
+ * },
421
+ * socket: {
422
+ * type: 'string',
423
+ * conflicts: ['port', 'pipe'], // Cannot use with --port or --pipe
424
+ * description: 'Unix socket path'
425
+ * },
426
+ * pipe: {
427
+ * type: 'string',
428
+ * conflicts: ['port', 'socket'], // Cannot use with --port or --socket
429
+ * description: 'Named pipe path'
430
+ * }
431
+ * }
432
+ * // These three options are mutually exclusive
433
+ * ```
434
+ *
435
+ * @example
436
+ * With kebab-case conversion:
437
+ * ```ts
438
+ * {
439
+ * summerSeason: {
440
+ * type: 'boolean',
441
+ * toKebab: true, // Accessible as --summer-season
442
+ * conflicts: 'autumnSeason' // Must use property key, not CLI name
443
+ * },
444
+ * autumnSeason: {
445
+ * type: 'boolean',
446
+ * toKebab: true // Accessible as --autumn-season
447
+ * }
448
+ * }
449
+ * // Error: "Optional argument '--summer-season' conflicts with '--autumn-season'"
450
+ * ```
451
+ */
452
+ conflicts?: string | string[];
453
+ /**
454
+ * Custom parsing function for `type: 'custom'` arguments.
455
+ *
456
+ * Required when `type: 'custom'`. Receives the raw string value and must
457
+ * return the parsed result. Should throw an Error (or subclass) if parsing fails.
458
+ *
459
+ * The function's return type becomes the resolved argument type.
460
+ *
461
+ * @param value - Raw string value from command line
462
+ * @returns Parsed value of any type
463
+ * @throws Error or subclass when value is invalid
464
+ *
465
+ * @example
466
+ * Custom parsing functions:
467
+ * ```ts
468
+ * {
469
+ * config: {
470
+ * type: 'custom',
471
+ * parse: (value: string) => {
472
+ * try {
473
+ * return JSON.parse(value) // Parse JSON config
474
+ * } catch {
475
+ * throw new Error('Invalid JSON configuration')
476
+ * }
477
+ * },
478
+ * description: 'JSON configuration object'
479
+ * },
480
+ * date: {
481
+ * type: 'custom',
482
+ * parse: (value: string) => {
483
+ * const date = new Date(value)
484
+ * if (isNaN(date.getTime())) {
485
+ * throw new Error('Invalid date format')
486
+ * }
487
+ * return date
488
+ * }
489
+ * }
490
+ * }
491
+ * ```
492
+ */
493
+ parse?: (value: string) => any;
494
+ }
495
+ /**
496
+ * An object that contains {@link ArgSchema | argument schema}.
497
+ *
498
+ * This type is used to define the structure and validation rules for command line arguments.
499
+ */
500
+ interface Args {
501
+ [option: string]: ArgSchema;
502
+ }
503
+ /**
504
+ * An object that contains the values of the arguments.
505
+ *
506
+ * @typeParam T - {@link Args | Arguments} which is an object that defines the command line arguments.
507
+ */
508
+ type ArgValues<T> = T extends Args ? ResolveArgValues<T, { [Arg in keyof T]: ExtractOptionValue<T[Arg]> }> : {
509
+ [option: string]: string | boolean | number | (string | boolean | number)[] | undefined;
510
+ };
511
+ type IsFunction<T> = T extends ((...args: any[]) => any) ? true : false;
512
+ /**
513
+ * Extracts the value type from the argument schema.
514
+ *
515
+ * @typeParam A - {@link ArgSchema | Argument schema} which is an object that defines command line arguments.
516
+ *
517
+ * @internal
518
+ */
519
+ 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>;
520
+ type ResolveOptionValue<A extends ArgSchema, T> = A['multiple'] extends true ? T[] : T;
521
+ /**
522
+ * Resolved argument values.
523
+ *
524
+ * @typeParam A - {@link Arguments | Args} which is an object that defines the command line arguments.
525
+ * @typeParam V - Resolvable argument values.
526
+ *
527
+ * @internal
528
+ */
529
+ 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;
530
+ /**
531
+ * Filters the arguments based on their default values.
532
+ *
533
+ * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
534
+ * @typeParam V - Resolvable argument values.
535
+ * @typeParam K - Key of the {@link ArgSchema | argument schema} to filter by.
536
+ *
537
+ * @internal
538
+ */
539
+ 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] };
540
+ /**
541
+ * Filters positional arguments from the argument schema.
542
+ *
543
+ * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
544
+ * @typeParam V - Resolvable argument values.
545
+ *
546
+ * @internal
547
+ */
548
+ 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] };
549
+ /**
550
+ * An arguments for {@link resolveArgs | resolve arguments}.
551
+ */
552
+ interface ResolveArgs {
553
+ /**
554
+ * Whether to group short arguments.
555
+ *
556
+ * @see guideline 5 in https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html
557
+ *
558
+ * @default false
559
+ */
560
+ shortGrouping?: boolean;
561
+ /**
562
+ * Skip positional arguments index.
563
+ *
564
+ * @default -1
565
+ */
566
+ skipPositional?: number;
567
+ /**
568
+ * Whether to convert the argument name to kebab-case. This option is applied to all arguments as `toKebab: true`, if set to `true`.
569
+ *
570
+ * @default false
571
+ */
572
+ toKebab?: boolean;
573
+ }
574
+ /**
575
+ * Tracks which arguments were explicitly provided by the user.
576
+ *
577
+ * Each property indicates whether the corresponding argument was explicitly
578
+ * provided (true) or is using a default value or not provided (false).
579
+ *
580
+ * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
581
+ */
582
+ type ArgExplicitlyProvided<A extends Args> = { [K in keyof A]: boolean };
583
+ /**
584
+ * Resolve command line arguments.
585
+ *
586
+ * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
587
+ *
588
+ * @param args - An arguments that contains {@link ArgSchema | arguments schema}.
589
+ * @param tokens - An array of {@link ArgToken | tokens}.
590
+ * @param resolveArgs - An arguments that contains {@link ResolveArgs | resolve arguments}.
591
+ * @returns An object that contains the values of the arguments, positional arguments, rest arguments, {@link AggregateError | validation errors}, and explicit provision status.
592
+ *
593
+ * @example
594
+ * ```typescript
595
+ * // passed tokens: --port 3000
596
+ *
597
+ * const { values, explicit } = resolveArgs({
598
+ * port: {
599
+ * type: 'number',
600
+ * default: 8080
601
+ * },
602
+ * host: {
603
+ * type: 'string',
604
+ * default: 'localhost'
605
+ * }
606
+ * }, parsedTokens)
607
+ *
608
+ * values.port // 3000
609
+ * values.host // 'localhost'
610
+ *
611
+ * explicit.port // true (explicitly provided)
612
+ * explicit.host // false (not provided, fallback to default)
613
+ * ```
614
+ */
615
+ declare function resolveArgs<A extends Args>(args: A, tokens: ArgToken[], {
616
+ shortGrouping,
617
+ skipPositional,
618
+ toKebab
619
+ }?: ResolveArgs): {
620
+ values: ArgValues<A>;
621
+ positionals: string[];
622
+ rest: string[];
623
+ error: AggregateError | undefined;
624
+ explicit: ArgExplicitlyProvided<A>;
625
+ };
626
+ /**
627
+ * An error type for {@link ArgResolveError}.
628
+ */
629
+ //#endregion
630
+ //#region src/plugin/context.d.ts
9
631
  /**
10
632
  * Type helper to create GunshiParams from extracted args and extensions
11
633
  *
@@ -718,6 +1340,15 @@ interface CommandContext<G extends GunshiParamsConstraint = DefaultGunshiParams>
718
1340
  * The command call mode is `entry` when the command is executed as an entry command, and `subCommand` when the command is executed as a sub-command.
719
1341
  */
720
1342
  callMode: CommandCallMode;
1343
+ /**
1344
+ * The path of nested sub-commands that were resolved to reach the current command.
1345
+ *
1346
+ * For example, if the user runs `git remote add`, `commandPath` would be `['remote', 'add']`.
1347
+ * For the entry command, this is an empty array.
1348
+ *
1349
+ * @since v0.28.0
1350
+ */
1351
+ commandPath: string[];
721
1352
  /**
722
1353
  * Whether to convert the camel-case style argument name to kebab-case.
723
1354
  * This context value is set from {@linkcode Command.toKebab} option.
@@ -859,6 +1490,15 @@ interface Command<G extends GunshiParamsConstraint = DefaultGunshiParams> {
859
1490
  * @since v0.27.0
860
1491
  */
861
1492
  rendering?: RenderingOptions<G>;
1493
+ /**
1494
+ * Nested sub-commands for this command.
1495
+ *
1496
+ * Allows building command trees like `git remote add`.
1497
+ * Each key is the sub-command name, and the value is a command or lazy command.
1498
+ *
1499
+ * @since v0.28.0
1500
+ */
1501
+ subCommands?: Record<string, SubCommandable> | Map<string, SubCommandable>;
862
1502
  }
863
1503
  /**
864
1504
  * Lazy command interface.
@@ -935,6 +1575,13 @@ interface SubCommandable {
935
1575
  * see {@link LazyCommand.commandName}
936
1576
  */
937
1577
  commandName?: string;
1578
+ /**
1579
+ * Nested sub-commands for this command.
1580
+ *
1581
+ * @see {@link Command.subCommands}
1582
+ * @since v0.28.0
1583
+ */
1584
+ subCommands?: Record<string, any> | Map<string, any>;
938
1585
  /**
939
1586
  * Index signature to allow additional properties
940
1587
  */
@@ -1012,4 +1659,4 @@ type RendererDecorator<T, G extends GunshiParamsConstraint = DefaultGunshiParams
1012
1659
  */
1013
1660
  type ValidationErrorsDecorator<G extends GunshiParamsConstraint = DefaultGunshiParams> = (baseRenderer: (ctx: Readonly<CommandContext<G>>, error: AggregateError) => Promise<string>, ctx: Readonly<CommandContext<G>>, error: AggregateError) => Promise<string>;
1014
1661
  //#endregion
1015
- export { SubCommandable as A, plugin as B, GunshiParams as C, Prettify as D, NormalizeToGunshiParams as E, PluginExtension as F, PluginFunction as I, PluginOptions as L, OnPluginExtension as M, Plugin as N, RendererDecorator as O, PluginDependency as P, PluginWithExtension as R, ExtractExtensions as S, LazyCommand as T, PluginContext as V, Commandable as _, Awaitable as a, ExtractArgExplicitlyProvided as b, CommandCallMode as c, CommandContextExtension as d, CommandDecorator as f, CommandRunner as g, CommandLoader as h, Args$1 as i, ValidationErrorsDecorator as j, RenderingOptions as k, CommandContext as l, CommandExamplesFetcher as m, ArgToken$1 as n, CliOptions as o, CommandEnvironment as p, ArgValues$1 as r, Command as s, ArgSchema$1 as t, CommandContextCore as u, DefaultGunshiParams as v, GunshiParamsConstraint as w, ExtractArgs as x, ExtendContext as y, PluginWithoutExtension as z };
1662
+ export { PluginDependency as A, Args as B, Prettify as C, ValidationErrorsDecorator as D, SubCommandable as E, PluginWithoutExtension as F, ArgToken as H, plugin as I, PluginContext as L, PluginFunction as M, PluginOptions as N, OnPluginExtension as O, PluginWithExtension as P, ArgSchema as R, NormalizeToGunshiParams as S, RenderingOptions as T, parseArgs as U, resolveArgs as V, ExtractArgs as _, CommandContext as a, GunshiParamsConstraint as b, CommandDecorator as c, CommandLoader as d, CommandRunner as f, ExtractArgExplicitlyProvided as g, ExtendContext as h, CommandCallMode as i, PluginExtension as j, Plugin as k, CommandEnvironment as l, DefaultGunshiParams as m, CliOptions as n, CommandContextCore as o, Commandable as p, Command as r, CommandContextExtension as s, Awaitable as t, CommandExamplesFetcher as u, ExtractExtensions as v, RendererDecorator as w, LazyCommand as x, GunshiParams as y, ArgValues as z };
@@ -48,7 +48,8 @@ async function resolveLazyCommand(cmd, name, needRunResolving = false) {
48
48
  args: cmd.args,
49
49
  examples: cmd.examples,
50
50
  internal: cmd.internal,
51
- entry: cmd.entry
51
+ entry: cmd.entry,
52
+ subCommands: cmd.subCommands
52
53
  };
53
54
  if ("resource" in cmd && cmd.resource) baseCommand.resource = cmd.resource;
54
55
  command = Object.assign(create(), baseCommand);
@@ -64,6 +65,7 @@ async function resolveLazyCommand(cmd, name, needRunResolving = false) {
64
65
  command.examples = loaded.examples;
65
66
  command.internal = loaded.internal;
66
67
  command.entry = loaded.entry;
68
+ command.subCommands = loaded.subCommands || cmd.subCommands;
67
69
  if ("resource" in loaded && loaded.resource) command.resource = loaded.resource;
68
70
  } else throw new TypeError(`Cannot resolve command: ${cmd.name || name}`);
69
71
  }
@@ -89,6 +91,24 @@ function log(...args) {
89
91
  console.log(...args);
90
92
  }
91
93
  /**
94
+ * Get the sub-commands of a command as a normalized Map.
95
+ *
96
+ * @param cmd - A command or lazy command
97
+ * @returns A Map of sub-commands, or undefined if the command has no sub-commands.
98
+ */
99
+ function getCommandSubCommands(cmd) {
100
+ const subCommands = isLazyCommand(cmd) ? cmd.subCommands : typeof cmd === "object" ? cmd.subCommands : void 0;
101
+ if (!subCommands) return;
102
+ if (subCommands instanceof Map) return subCommands.size > 0 ? subCommands : void 0;
103
+ if (typeof subCommands === "object") {
104
+ const entries = Object.entries(subCommands);
105
+ if (entries.length === 0) return;
106
+ const map = /* @__PURE__ */ new Map();
107
+ for (const [name, cmd] of entries) map.set(name, cmd);
108
+ return map;
109
+ }
110
+ }
111
+ /**
92
112
  * Deep freeze an object, making it immutable.
93
113
  *
94
114
  * @param obj - The object to freeze
@@ -106,4 +126,4 @@ function deepFreeze(obj, ignores = []) {
106
126
  }
107
127
 
108
128
  //#endregion
109
- export { resolveLazyCommand as a, log as i, deepFreeze as n, kebabnize as o, isLazyCommand as r, create as t };
129
+ export { log as a, isLazyCommand as i, deepFreeze as n, resolveLazyCommand as o, getCommandSubCommands as r, kebabnize as s, create as t };
package/lib/utils.d.ts CHANGED
@@ -1,12 +1,29 @@
1
- import { T as LazyCommand, _ as Commandable, s as Command, v as DefaultGunshiParams, w as GunshiParamsConstraint } from "./types-RXstkMKh.js";
2
- import { kebabnize } from "args-tokens/utils";
1
+ import { b as GunshiParamsConstraint, m as DefaultGunshiParams, p as Commandable, r as Command, x as LazyCommand } from "./types-Doxo8g3Y.js";
2
+
3
+ //#region ../../node_modules/.pnpm/args-tokens@0.23.1/node_modules/args-tokens/lib/utils.d.ts
3
4
 
4
5
  //#region src/utils.d.ts
5
6
  /**
6
- * @author kazuya kawaguchi (a.k.a. kazupon)
7
- * @license MIT
8
- */
9
-
7
+ * Entry point of utils.
8
+ *
9
+ * Note that this entry point is used by gunshi to import utility functions.
10
+ *
11
+ * @module
12
+ */
13
+ /**
14
+ * @author kazuya kawaguchi (a.k.a. kazupon)
15
+ * @license MIT
16
+ */
17
+ /**
18
+ * Convert a string to kebab-case.
19
+ *
20
+ * @param str - A string to convert
21
+ * @returns Converted string into kebab-case.
22
+ */
23
+ declare function kebabnize(str: string): string;
24
+ //#endregion
25
+ //#endregion
26
+ //#region src/utils.d.ts
10
27
  /**
11
28
  * Check if the given command is a {@link LazyCommand}.
12
29
  *
@@ -36,6 +53,13 @@ declare function create<T>(obj?: object | null): T;
36
53
  * @param args - Arguments to log
37
54
  */
38
55
  declare function log(...args: unknown[]): void;
56
+ /**
57
+ * Get the sub-commands of a command as a normalized Map.
58
+ *
59
+ * @param cmd - A command or lazy command
60
+ * @returns A Map of sub-commands, or undefined if the command has no sub-commands.
61
+ */
62
+ declare function getCommandSubCommands<G extends GunshiParamsConstraint = DefaultGunshiParams>(cmd: Commandable<G> | Command<G> | LazyCommand<G>): Map<string, Command<G> | LazyCommand<G>> | undefined;
39
63
  /**
40
64
  * Deep freeze an object, making it immutable.
41
65
  *
@@ -45,4 +69,4 @@ declare function log(...args: unknown[]): void;
45
69
  */
46
70
  declare function deepFreeze<T extends Record<string, any>>(obj: T, ignores?: string[]): Readonly<T>;
47
71
  //#endregion
48
- export { create, deepFreeze, isLazyCommand, kebabnize, log, resolveLazyCommand };
72
+ export { create, deepFreeze, getCommandSubCommands, isLazyCommand, kebabnize, log, resolveLazyCommand };
package/lib/utils.js CHANGED
@@ -1,3 +1,3 @@
1
- import { a as resolveLazyCommand, i as log, n as deepFreeze, o as kebabnize, r as isLazyCommand, t as create } from "./utils-A01g1U8-.js";
1
+ import { a as log, i as isLazyCommand, n as deepFreeze, o as resolveLazyCommand, r as getCommandSubCommands, s as kebabnize, t as create } from "./utils-DNS9AIR_.js";
2
2
 
3
- export { create, deepFreeze, isLazyCommand, kebabnize, log, resolveLazyCommand };
3
+ export { create, deepFreeze, getCommandSubCommands, isLazyCommand, kebabnize, log, resolveLazyCommand };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gunshi",
3
3
  "description": "Modern javascript command-line library",
4
- "version": "0.27.6",
4
+ "version": "0.28.2",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
@@ -103,11 +103,11 @@
103
103
  "publint": "^0.3.16",
104
104
  "tsdown": "0.15.12",
105
105
  "zod": "^4.2.1",
106
- "@gunshi/plugin-global": "0.27.6",
107
- "@gunshi/plugin-renderer": "0.27.6",
108
- "@gunshi/resources": "0.27.6",
109
- "@gunshi/plugin-i18n": "0.27.6",
110
- "@gunshi/shared": "0.27.6"
106
+ "@gunshi/plugin-global": "0.28.2",
107
+ "@gunshi/plugin-i18n": "0.28.2",
108
+ "@gunshi/resources": "0.28.2",
109
+ "@gunshi/plugin-renderer": "0.28.2",
110
+ "@gunshi/shared": "0.28.2"
111
111
  },
112
112
  "scripts": {
113
113
  "build": "tsdown",