@gunshi/plugin-renderer 0.26.3 → 0.27.0-alpha.10

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 +29 -18
  2. package/lib/index.js +147 -70
  3. package/package.json +9 -9
package/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Command, CommandContext, DefaultGunshiParams, GunshiParams, PluginWithExtension } from "@gunshi/plugin";
2
- import { Args } from "args-tokens";
1
+ import { Args, Command, CommandContext, DefaultGunshiParams, GunshiParams, PluginWithExtension } from "@gunshi/plugin";
2
+ import { Args as Args$1 } from "args-tokens";
3
3
 
4
4
  //#region rolldown:runtime
5
5
  declare namespace constants_d_exports {
@@ -30,7 +30,6 @@ type CommonArgType = {
30
30
  };
31
31
  declare const COMMON_ARGS: CommonArgType;
32
32
  declare const COMMAND_BUILTIN_RESOURCE_KEYS: readonly ["USAGE", "COMMAND", "SUBCOMMAND", "COMMANDS", "ARGUMENTS", "OPTIONS", "EXAMPLES", "FORMORE", "NEGATABLE", "DEFAULT", "CHOICES"];
33
-
34
33
  //#endregion
35
34
  //#region ../shared/src/types.d.ts
36
35
  type RemoveIndexSignature<T> = { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] };
@@ -38,7 +37,7 @@ type RemoveIndexSignature<T> = { [K in keyof T as string extends K ? never : num
38
37
  * Remove index signature from object or record type.
39
38
  */
40
39
  type RemovedIndex<T> = RemoveIndexSignature<{ [K in keyof T]: T[K] }>;
41
- type KeyOfArgs<A extends Args> = keyof A | { [K in keyof A]: A[K]['type'] extends 'boolean' ? A[K]['negatable'] extends true ? `no-${Extract<K, string>}` : never : never }[keyof A];
40
+ type KeyOfArgs<A extends Args$1> = keyof A | { [K in keyof A]: A[K]['type'] extends 'boolean' ? A[K]['negatable'] extends true ? `no-${Extract<K, string>}` : never : never }[keyof A];
42
41
  /**
43
42
  * Generate a namespaced key.
44
43
  */
@@ -52,20 +51,33 @@ type CommandBuiltinArgsKeys = keyof (typeof constants_d_exports)['COMMON_ARGS'];
52
51
  */
53
52
  type CommandBuiltinResourceKeys = (typeof constants_d_exports)['COMMAND_BUILTIN_RESOURCE_KEYS'][number];
54
53
  /**
55
- * i18n built-in resource keys.
54
+ * Built-in resource keys.
56
55
  */
57
56
  type BuiltinResourceKeys = CommandBuiltinArgsKeys | CommandBuiltinResourceKeys;
58
57
  /**
59
- * Command i18n built-in keys.
60
- * The command i18n built-in keys are used by the i18n plugin for translation.
58
+ * Command built-in keys.
61
59
  */
62
- type CommandBuiltinKeys = GenerateNamespacedKey<BuiltinResourceKeys> | 'description' | 'examples';
60
+ type CommandBuiltinKeys = GenerateNamespacedKey<BuiltinResourceKeys>;
63
61
  /**
64
62
  * Command i18n option keys.
65
63
  * The command i18n option keys are used by the i18n plugin for translation.
66
64
  */
67
- type CommandArgKeys<A extends Args> = GenerateNamespacedKey<KeyOfArgs<RemovedIndex<A>>, typeof ARG_PREFIX>;
68
-
65
+ type CommandArgKeys<A extends Args$1, C = {}, K extends string = GenerateNamespacedKey<Extract<KeyOfArgs<RemovedIndex<A>>, string>, typeof ARG_PREFIX>> = C extends {
66
+ name: infer N;
67
+ } ? (N extends string ? GenerateNamespacedKey<K, N> : K) : K;
68
+ /**
69
+ * Resolve translation keys for command context.
70
+ */
71
+ type ResolveTranslationKeys<A extends Args$1, C = {},
72
+ // for CommandContext
73
+ E extends Record<string, string> = {},
74
+ // for extended resources
75
+ R extends string = keyof RemovedIndex<E>, T extends string = (C extends {
76
+ name: infer N;
77
+ } ? N extends string ? GenerateNamespacedKey<R, N> : R : R | CommandBuiltinKeys), O = CommandArgKeys<A, C>> = CommandBuiltinKeys | O | T;
78
+ /**
79
+ * Translation function interface
80
+ */
69
81
  //#endregion
70
82
  //#region src/types.d.ts
71
83
  /**
@@ -76,14 +88,17 @@ interface UsageRendererCommandContext<G extends GunshiParams<any> = DefaultGunsh
76
88
  /**
77
89
  * Render the text message
78
90
  */
79
- text: <T extends string = CommandBuiltinKeys, O = CommandArgKeys<G['args']>, K = CommandBuiltinKeys | O | T>(key: K, values?: Record<string, unknown>) => Promise<string>;
91
+ text: <A extends Args = G['args'], C = {},
92
+ // for CommandContext
93
+ E extends Record<string, string> = {},
94
+ // for extended resources
95
+ K = ResolveTranslationKeys<A, C, E>>(key: K, values?: Record<string, unknown>) => string;
80
96
  /**
81
97
  * Load commands
82
- * @returns A list of commands loaded from the command loader plugin.
98
+ * @returns A list of commands loaded from the usage renderert plugin.
83
99
  */
84
100
  loadCommands: <G extends GunshiParams = DefaultGunshiParams>() => Promise<Command<G>[]>;
85
101
  }
86
-
87
102
  //#endregion
88
103
  //#region src/header.d.ts
89
104
  /**
@@ -92,7 +107,6 @@ interface UsageRendererCommandContext<G extends GunshiParams<any> = DefaultGunsh
92
107
  * @returns A rendered header.
93
108
  */
94
109
  declare function renderHeader<G extends GunshiParams = DefaultGunshiParams>(ctx: Readonly<CommandContext<G>>): Promise<string>;
95
-
96
110
  //#endregion
97
111
  //#region src/usage.d.ts
98
112
  /**
@@ -101,7 +115,6 @@ declare function renderHeader<G extends GunshiParams = DefaultGunshiParams>(ctx:
101
115
  * @returns A rendered usage.
102
116
  */
103
117
  declare function renderUsage<G extends GunshiParams = DefaultGunshiParams>(ctx: Readonly<CommandContext<G>>): Promise<string>;
104
-
105
118
  //#endregion
106
119
  //#region src/validation.d.ts
107
120
  /**
@@ -111,13 +124,11 @@ declare function renderUsage<G extends GunshiParams = DefaultGunshiParams>(ctx:
111
124
  * @returns A rendered validation error.
112
125
  */
113
126
  declare function renderValidationErrors<G extends GunshiParams = DefaultGunshiParams>(_ctx: CommandContext<G>, error: AggregateError): Promise<string>;
114
-
115
127
  //#endregion
116
128
  //#region src/index.d.ts
117
129
  /**
118
130
  * usage renderer plugin
119
131
  */
120
132
  declare function renderer(): PluginWithExtension<UsageRendererCommandContext>;
121
-
122
133
  //#endregion
123
- export { UsageRendererCommandContext, renderer as default, renderHeader, renderUsage, renderValidationErrors };
134
+ export { type UsageRendererCommandContext, renderer as default, renderHeader, renderUsage, renderValidationErrors };
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { plugin } from "@gunshi/plugin";
1
+ import { ANONYMOUS_COMMAND_NAME, plugin } from "@gunshi/plugin";
2
2
 
3
- //#region ../../node_modules/.pnpm/args-tokens@0.20.1/node_modules/args-tokens/lib/utils-N7UlhLbz.js
3
+ //#region ../../node_modules/.pnpm/args-tokens@0.22.0/node_modules/args-tokens/lib/utils-N7UlhLbz.js
4
4
  /**
5
5
  * Entry point of utils.
6
6
  *
@@ -28,7 +28,9 @@ async function resolveLazyCommand(cmd, name, needRunResolving = false) {
28
28
  name: cmd.commandName,
29
29
  description: cmd.description,
30
30
  args: cmd.args,
31
- examples: cmd.examples
31
+ examples: cmd.examples,
32
+ internal: cmd.internal,
33
+ entry: cmd.entry
32
34
  };
33
35
  if ("resource" in cmd && cmd.resource) baseCommand.resource = cmd.resource;
34
36
  command = Object.assign(create(), baseCommand);
@@ -42,6 +44,8 @@ async function resolveLazyCommand(cmd, name, needRunResolving = false) {
42
44
  command.description = loaded.description;
43
45
  command.args = loaded.args;
44
46
  command.examples = loaded.examples;
47
+ command.internal = loaded.internal;
48
+ command.entry = loaded.entry;
45
49
  if ("resource" in loaded && loaded.resource) command.resource = loaded.resource;
46
50
  } else throw new TypeError(`Cannot resolve command: ${cmd.name || name}`);
47
51
  }
@@ -121,11 +125,35 @@ var en_US_default = {
121
125
 
122
126
  //#endregion
123
127
  //#region ../shared/src/utils.ts
128
+ /**
129
+ * Resolve a namespaced key for built-in resources.
130
+ * Built-in keys are prefixed with "_:".
131
+ * @param key The built-in key to resolve.
132
+ * @returns Prefixed built-in key.
133
+ */
124
134
  function resolveBuiltInKey(key) {
125
135
  return `${BUILT_IN_PREFIX}${BUILT_IN_KEY_SEPARATOR}${key}`;
126
136
  }
127
- function resolveArgKey(key) {
128
- return `${ARG_PREFIX}${BUILT_IN_KEY_SEPARATOR}${key}`;
137
+ /**
138
+ * Resolve a namespaced key for argument resources.
139
+ * Argument keys are prefixed with "arg:".
140
+ * If the command name is provided, it will be prefixed with the command name (e.g. "cmd1:arg:foo").
141
+ * @param key The argument key to resolve.
142
+ * @param ctx The command context.
143
+ * @returns Prefixed argument key.
144
+ */
145
+ function resolveArgKey(key, ctx) {
146
+ return `${ctx?.name ? `${ctx.name}${BUILT_IN_KEY_SEPARATOR}` : ""}${ARG_PREFIX}${BUILT_IN_KEY_SEPARATOR}${key}`;
147
+ }
148
+ /**
149
+ * Resolve a namespaced key for non-built-in resources.
150
+ * Non-built-in keys are not prefixed with any special characters. If the command name is provided, it will be prefixed with the command name (e.g. "cmd1:foo").
151
+ * @param key The non-built-in key to resolve.
152
+ * @param ctx The command context.
153
+ * @returns Prefixed non-built-in key.
154
+ */
155
+ function resolveKey(key, ctx) {
156
+ return `${ctx?.name ? `${ctx.name}${BUILT_IN_KEY_SEPARATOR}` : ""}${key}`;
129
157
  }
130
158
  async function resolveExamples$1(ctx, examples) {
131
159
  return typeof examples === "string" ? examples : typeof examples === "function" ? await examples(ctx) : "";
@@ -133,6 +161,48 @@ async function resolveExamples$1(ctx, examples) {
133
161
  function namespacedId(id) {
134
162
  return `${PLUGIN_PREFIX}${BUILT_IN_KEY_SEPARATOR}${id}`;
135
163
  }
164
+ function makeShortLongOptionPair(schema, name, toKebab) {
165
+ const displayName = toKebab || schema.toKebab ? kebabnize(name) : name;
166
+ let key = `--${displayName}`;
167
+ if (schema.short) key = `-${schema.short}, ${key}`;
168
+ return key;
169
+ }
170
+
171
+ //#endregion
172
+ //#region ../shared/src/localization.ts
173
+ /**
174
+ * Create a localizable function for a command.
175
+ * This function will resolve the translation key based on the command context and the provided translation function.
176
+ * @param ctx Command context
177
+ * @param cmd Command
178
+ * @param translate Translation function
179
+ * @returns Localizable function
180
+ */
181
+ function localizable(ctx, cmd, translate) {
182
+ async function localize(key, values) {
183
+ if (translate) return translate(key, values);
184
+ if (key.startsWith(BUILD_IN_PREFIX_AND_KEY_SEPARATOR)) {
185
+ const resKey = key.slice(BUILD_IN_PREFIX_AND_KEY_SEPARATOR.length);
186
+ return en_US_default[resKey] || key;
187
+ }
188
+ const namaspacedArgKey = resolveKey(ARG_PREFIX_AND_KEY_SEPARATOR, ctx);
189
+ if (key.startsWith(namaspacedArgKey)) {
190
+ let argKey = key.slice(namaspacedArgKey.length);
191
+ let negatable = false;
192
+ if (argKey.startsWith(ARG_NEGATABLE_PREFIX)) {
193
+ argKey = argKey.slice(ARG_NEGATABLE_PREFIX.length);
194
+ negatable = true;
195
+ }
196
+ const schema = ctx.args[argKey];
197
+ if (!schema) return argKey;
198
+ return negatable && schema.type === "boolean" && schema.negatable ? `${en_US_default["NEGATABLE"]} ${makeShortLongOptionPair(schema, argKey, ctx.toKebab)}` : schema.description || "";
199
+ }
200
+ if (key === resolveKey("description", ctx)) return "";
201
+ else if (key === resolveKey("examples", ctx)) return await resolveExamples$1(ctx, cmd.examples);
202
+ else return key;
203
+ }
204
+ return localize;
205
+ }
136
206
 
137
207
  //#endregion
138
208
  //#region src/header.ts
@@ -169,8 +239,8 @@ async function renderUsage(ctx) {
169
239
  }
170
240
  messages.push(...await renderUsageSection(ctx), "");
171
241
  if (ctx.omitted && await hasCommands(ctx)) messages.push(...await renderCommandsSection(ctx), "");
172
- if (hasPositionalArgs(ctx)) messages.push(...await renderPositionalArgsSection(ctx), "");
173
- if (hasOptionalArgs(ctx)) messages.push(...await renderOptionalArgsSection(ctx), "");
242
+ if (hasPositionalArgs(ctx.args)) messages.push(...await renderPositionalArgsSection(ctx), "");
243
+ if (hasOptionalArgs(ctx.args)) messages.push(...await renderOptionalArgsSection(ctx), "");
174
244
  const examples = await renderExamplesSection(ctx);
175
245
  if (examples.length > 0) messages.push(...examples, "");
176
246
  return messages.join("\n");
@@ -218,19 +288,21 @@ async function renderExamplesSection(ctx) {
218
288
  */
219
289
  async function renderUsageSection(ctx) {
220
290
  const messages = [`${await ctx.extensions[pluginId].text(resolveBuiltInKey("USAGE"))}:`];
221
- if (ctx.omitted) {
222
- const defaultCommand = `${await resolveEntry(ctx)}${await hasCommands(ctx) ? ` [${await resolveSubCommand(ctx)}]` : ""} ${[await generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`;
223
- messages.push(defaultCommand.padStart(ctx.env.leftMargin + defaultCommand.length));
224
- if (await hasCommands(ctx)) {
225
- const commandsUsage = `${await resolveEntry(ctx)} <${await ctx.extensions[pluginId].text(resolveBuiltInKey("COMMANDS"))}>`;
226
- messages.push(commandsUsage.padStart(ctx.env.leftMargin + commandsUsage.length));
227
- }
228
- } else {
229
- const usageStr = `${await resolveEntry(ctx)} ${await resolveSubCommand(ctx)} ${[await generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`;
230
- messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
231
- }
291
+ const usageStr = await makeUsageSymbols(ctx);
292
+ messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
232
293
  return messages;
233
294
  }
295
+ async function makeUsageSymbols(ctx) {
296
+ const messages = [await resolveEntry(ctx)];
297
+ if (ctx.omitted) if (await hasCommands(ctx)) messages.push(` [${await ctx.extensions[pluginId].text(resolveBuiltInKey("COMMANDS"))}]`);
298
+ else messages.push(`${ctx.callMode === "subCommand" ? ` ${await resolveSubCommand(ctx)}` : ""}`);
299
+ else messages.push(`${ctx.callMode === "subCommand" ? ` ${await resolveSubCommand(ctx)}` : ""}`);
300
+ const optionsSymbols = await generateOptionsSymbols(ctx, ctx.args);
301
+ if (optionsSymbols) messages.push(" ", optionsSymbols);
302
+ const positionalSymbols = generatePositionalSymbols(ctx.args);
303
+ if (positionalSymbols) messages.push(" ", positionalSymbols);
304
+ return messages.join("");
305
+ }
234
306
  /**
235
307
  * Render the commands section
236
308
  * @param ctx A {@link CommandContext | command context}
@@ -240,19 +312,38 @@ async function renderCommandsSection(ctx) {
240
312
  const messages = [`${await ctx.extensions[pluginId].text(resolveBuiltInKey("COMMANDS"))}:`];
241
313
  const loadedCommands = await ctx.extensions?.[pluginId].loadCommands() || [];
242
314
  const commandMaxLength = Math.max(...loadedCommands.map((cmd) => (cmd.name || "").length));
243
- const commandsStr = await Promise.all(loadedCommands.map((cmd) => {
244
- const key = cmd.name || "";
315
+ const commandsStr = await Promise.all(loadedCommands.map(async (cmd) => {
245
316
  const desc = cmd.description || "";
246
- const command = `${key.padEnd(commandMaxLength + ctx.env.middleMargin)}${desc} `;
247
- return `${command.padStart(ctx.env.leftMargin + command.length)} `;
317
+ const optionSymbol = await generateOptionsSymbols(ctx, ctx.args);
318
+ const positionalSymbol = generatePositionalSymbols(ctx.args);
319
+ const commandStr = await makeCommandSymbol(ctx, cmd);
320
+ const symbolLength = desc.length > 0 ? commandMaxLength + optionSymbol.length + positionalSymbol.length : 0;
321
+ const command = `${commandStr.padEnd(symbolLength + ctx.env.middleMargin)}${desc}`;
322
+ return `${command.padStart(ctx.env.leftMargin + command.length)}`;
248
323
  }));
249
324
  messages.push(...commandsStr, "", `${await ctx.extensions[pluginId].text(resolveBuiltInKey("FORMORE"))}:`);
250
325
  messages.push(...loadedCommands.map((cmd) => {
251
- const commandHelp = `${ctx.env.name} ${cmd.name} --help`;
326
+ let commandStr = cmd.entry ? "" : cmd.name || "";
327
+ if (commandStr) commandStr += " ";
328
+ const commandHelp = `${ctx.env.name} ${commandStr}--help`;
252
329
  return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`;
253
330
  }));
254
331
  return messages;
255
332
  }
333
+ async function makeCommandSymbol(ctx, cmd) {
334
+ const optionSymbol = await generateOptionsSymbols(ctx, ctx.args);
335
+ const positionalSymbol = generatePositionalSymbols(ctx.args);
336
+ let commandStr = cmd.entry ? cmd.name === void 0 || cmd.name === ANONYMOUS_COMMAND_NAME ? "" : `[${cmd.name}]` : cmd.name || "";
337
+ if (optionSymbol) {
338
+ if (commandStr) commandStr += " ";
339
+ commandStr += `${optionSymbol}`;
340
+ }
341
+ if (positionalSymbol) {
342
+ if (commandStr) commandStr += " ";
343
+ commandStr += `${positionalSymbol}`;
344
+ }
345
+ return commandStr;
346
+ }
256
347
  /**
257
348
  * Resolve the entry command name
258
349
  * @param ctx A {@link CommandContext | command context}
@@ -275,7 +366,7 @@ async function resolveSubCommand(ctx) {
275
366
  * @returns resolved command description
276
367
  */
277
368
  async function resolveDescription(ctx) {
278
- return await ctx.extensions[pluginId].text("description") || ctx.description || "";
369
+ return await ctx.extensions[pluginId].text(resolveKey("description", ctx)) || ctx.description || "";
279
370
  }
280
371
  /**
281
372
  * Resolve the command examples
@@ -283,7 +374,7 @@ async function resolveDescription(ctx) {
283
374
  * @returns resolved command examples, if not resolved, return empty string
284
375
  */
285
376
  async function resolveExamples(ctx) {
286
- const ret = await ctx.extensions[pluginId].text("examples");
377
+ const ret = await ctx.extensions[pluginId].text(resolveKey("examples", ctx));
287
378
  if (ret) return ret;
288
379
  const command = ctx.env.subCommands?.get(ctx.name || "");
289
380
  return await resolveExamples$1(ctx, command?.examples);
@@ -299,41 +390,35 @@ async function hasCommands(ctx) {
299
390
  }
300
391
  /**
301
392
  * Check if the command has optional arguments
302
- * @param ctx A {@link CommandContext | command context}
393
+ * @param args A {@link Args | command optional arguments}
303
394
  * @returns True if the command has options
304
395
  */
305
- function hasOptionalArgs(ctx) {
306
- return !!(ctx.args && Object.values(ctx.args).some((arg) => arg.type !== "positional"));
396
+ function hasOptionalArgs(args) {
397
+ return Object.values(args).some((arg) => arg.type !== "positional");
307
398
  }
308
399
  /**
309
400
  * Check if the command has positional arguments
310
- * @param ctx A {@link CommandContext | command context}
401
+ * @param args A {@link Args | command positional arguments}
311
402
  * @returns True if the command has options
312
403
  */
313
- function hasPositionalArgs(ctx) {
314
- return !!(ctx.args && Object.values(ctx.args).some((arg) => arg.type === "positional"));
404
+ function hasPositionalArgs(args) {
405
+ return Object.values(args).some((arg) => arg.type === "positional");
315
406
  }
316
407
  /**
317
408
  * Check if all options have default values
318
- * @param ctx A {@link CommandContext | command context}
409
+ * @param args An {@link Args | command argument}
319
410
  * @returns True if all options have default values
320
411
  */
321
- function hasAllDefaultOptions(ctx) {
322
- return !!(ctx.args && Object.values(ctx.args).every((arg) => arg.default));
412
+ function hasAllDefaultOptions(args) {
413
+ return !!(args && Object.values(args).every((arg) => arg.default));
323
414
  }
324
415
  /**
325
416
  * Generate options symbols for usage
326
417
  * @param ctx A {@link CommandContext | command context}
327
418
  * @returns Options symbols for usage
328
419
  */
329
- async function generateOptionsSymbols(ctx) {
330
- return hasOptionalArgs(ctx) ? hasAllDefaultOptions(ctx) ? `[${await ctx.extensions[pluginId].text(resolveBuiltInKey("OPTIONS"))}]` : `<${await ctx.extensions[pluginId].text(resolveBuiltInKey("OPTIONS"))}>` : "";
331
- }
332
- function makeShortLongOptionPair(schema, name, toKebab) {
333
- const displayName = toKebab || schema.toKebab ? kebabnize(name) : name;
334
- let key = `--${displayName}`;
335
- if (schema.short) key = `-${schema.short}, ${key}`;
336
- return key;
420
+ async function generateOptionsSymbols(ctx, args) {
421
+ return hasOptionalArgs(args) ? hasAllDefaultOptions(args) ? `[${await ctx.extensions[pluginId].text(resolveBuiltInKey("OPTIONS"))}]` : `<${await ctx.extensions[pluginId].text(resolveBuiltInKey("OPTIONS"))}>` : "";
337
422
  }
338
423
  /**
339
424
  * Get optional arguments pairs for usage
@@ -384,7 +469,7 @@ async function generateOptionalArgsUsage(ctx, optionsPairs) {
384
469
  const optionsMaxLength = Math.max(...Object.entries(optionsPairs).map(([_, value]) => value.length));
385
470
  const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...Object.entries(optionsPairs).map(([key]) => resolveNegatableType(key, ctx).length)) : 0;
386
471
  const usages = await Promise.all(Object.entries(optionsPairs).map(async ([key, value]) => {
387
- let rawDesc = await ctx.extensions[pluginId].text(resolveArgKey(key));
472
+ let rawDesc = await ctx.extensions[pluginId].text(resolveArgKey(key, ctx));
388
473
  if (!rawDesc && key.startsWith(ARG_NEGATABLE_PREFIX)) {
389
474
  const name = resolveNegatableKey(key);
390
475
  const schema = ctx.args[name];
@@ -394,26 +479,27 @@ async function generateOptionalArgsUsage(ctx, optionsPairs) {
394
479
  const optionsSchema = ctx.env.usageOptionType ? `[${resolveNegatableType(key, ctx)}] ` : "";
395
480
  const valueDesc = key.startsWith(ARG_NEGATABLE_PREFIX) ? "" : await resolveDisplayValue(ctx, key);
396
481
  const desc = `${optionsSchema ? optionsSchema.padEnd(optionSchemaMaxLength + 3) : ""}${rawDesc}`;
397
- const option = `${value.padEnd(optionsMaxLength + ctx.env.middleMargin)}${desc}${valueDesc ? ` ${valueDesc}` : ""}`;
482
+ const descLength = desc.length + valueDesc.length;
483
+ const option = `${value.padEnd((descLength > 0 ? optionsMaxLength : 0) + ctx.env.middleMargin)}${desc}${valueDesc ? ` ${valueDesc}` : ""}`;
398
484
  return `${option.padStart(ctx.env.leftMargin + option.length)}`;
399
485
  }));
400
486
  return usages.join("\n");
401
487
  }
402
- function getPositionalArgs(ctx) {
403
- return Object.entries(ctx.args).filter(([_, schema]) => schema.type === "positional");
488
+ function getPositionalArgs(args) {
489
+ return Object.entries(args).filter(([_, schema]) => schema.type === "positional");
404
490
  }
405
491
  async function generatePositionalArgsUsage(ctx) {
406
- const positionals = getPositionalArgs(ctx);
492
+ const positionals = getPositionalArgs(ctx.args);
407
493
  const argsMaxLength = Math.max(...positionals.map(([name]) => name.length));
408
494
  const usages = await Promise.all(positionals.map(async ([name]) => {
409
- const desc = await ctx.extensions[pluginId].text(resolveArgKey(name)) || ctx.args[name].description || "";
495
+ const desc = await ctx.extensions[pluginId].text(resolveArgKey(name, ctx)) || ctx.args[name].description || "";
410
496
  const arg = `${name.padEnd(argsMaxLength + ctx.env.middleMargin)} ${desc}`;
411
497
  return `${arg.padStart(ctx.env.leftMargin + arg.length)}`;
412
498
  }));
413
499
  return usages.join("\n");
414
500
  }
415
- function generatePositionalSymbols(ctx) {
416
- return hasPositionalArgs(ctx) ? getPositionalArgs(ctx).map(([name]) => `<${name}>`).join(" ") : "";
501
+ function generatePositionalSymbols(args) {
502
+ return hasPositionalArgs(args) ? getPositionalArgs(args).map(([name]) => `<${name}>`).join(" ") : "";
417
503
  }
418
504
 
419
505
  //#endregion
@@ -450,29 +536,20 @@ function renderer() {
450
536
  async function loadCommands() {
451
537
  if (cachedCommands) return cachedCommands;
452
538
  const subCommands = [...ctx.env.subCommands || []];
453
- cachedCommands = await Promise.all(subCommands.map(async ([name, cmd$1]) => await resolveLazyCommand(cmd$1, name)));
539
+ const allCommands = await Promise.all(subCommands.map(async ([name, cmd$1]) => await resolveLazyCommand(cmd$1, name)));
540
+ cachedCommands = allCommands.filter((cmd$1) => !cmd$1.internal).filter(Boolean);
541
+ cachedCommands.sort((a, b) => {
542
+ if (a.entry && !b.entry) return -1;
543
+ if (!a.entry && b.entry) return 1;
544
+ if (a.name && b.name) return a.name.localeCompare(b.name);
545
+ if (a.name && !b.name) return -1;
546
+ if (!a.name && b.name) return 1;
547
+ return 0;
548
+ });
454
549
  return cachedCommands;
455
550
  }
456
- async function text(key, values = Object.create(null)) {
457
- if (i18n) return i18n.translate(key, values);
458
- else if (key.startsWith(BUILD_IN_PREFIX_AND_KEY_SEPARATOR)) {
459
- const resKey = key.slice(BUILD_IN_PREFIX_AND_KEY_SEPARATOR.length);
460
- return en_US_default[resKey] || key;
461
- } else if (key.startsWith(ARG_PREFIX_AND_KEY_SEPARATOR)) {
462
- let argKey = key.slice(ARG_PREFIX_AND_KEY_SEPARATOR.length);
463
- let negatable = false;
464
- if (argKey.startsWith(ARG_NEGATABLE_PREFIX)) {
465
- argKey = argKey.slice(ARG_NEGATABLE_PREFIX.length);
466
- negatable = true;
467
- }
468
- const schema = ctx.args[argKey];
469
- return negatable && schema.type === "boolean" && schema.negatable ? `${en_US_default["NEGATABLE"]} ${makeShortLongOptionPair(schema, argKey, ctx.toKebab)}` : schema.description || "";
470
- } else if (key === "description") return "";
471
- else if (key === "examples") return await resolveExamples$1(ctx, cmd.examples);
472
- else return key;
473
- }
474
551
  return {
475
- text,
552
+ text: localizable(ctx, cmd, i18n?.translate),
476
553
  loadCommands
477
554
  };
478
555
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gunshi/plugin-renderer",
3
3
  "description": "usage renderer plugin for gunshi",
4
- "version": "0.26.3",
4
+ "version": "0.27.0-alpha.10",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
@@ -53,20 +53,20 @@
53
53
  }
54
54
  },
55
55
  "dependencies": {
56
- "@gunshi/plugin": "0.26.3"
56
+ "@gunshi/plugin": "0.27.0-alpha.10"
57
57
  },
58
58
  "peerDependencies": {
59
- "@gunshi/plugin-i18n": "0.26.3"
59
+ "@gunshi/plugin-i18n": "0.27.0-alpha.10"
60
60
  },
61
61
  "devDependencies": {
62
- "deno": "^2.3.3",
63
- "jsr": "^0.13.4",
62
+ "deno": "^2.4.2",
63
+ "jsr": "^0.13.5",
64
64
  "jsr-exports-lint": "^0.4.1",
65
65
  "publint": "^0.3.12",
66
- "tsdown": "^0.12.3",
67
- "typedoc": "^0.28.4",
68
- "typedoc-plugin-markdown": "^4.6.3",
69
- "@gunshi/shared": "0.26.3"
66
+ "tsdown": "^0.13.0",
67
+ "typedoc": "^0.28.7",
68
+ "typedoc-plugin-markdown": "^4.7.1",
69
+ "@gunshi/shared": "0.27.0-alpha.10"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "tsdown",