@gunshi/plugin-renderer 0.27.0-alpha.8 → 0.27.0-alpha.9

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 +25 -58
  2. package/lib/index.js +115 -49
  3. package/package.json +7 -7
package/lib/index.d.ts CHANGED
@@ -1,50 +1,7 @@
1
- import { Command, CommandContext, DefaultGunshiParams, GunshiParams, PluginWithExtension } from "@gunshi/plugin";
2
- import { Args, Args as Args$1 } 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
-
6
- //#endregion
7
- //#region ../gunshi/src/types.d.ts
8
- /**
9
- * Extend command context type. This type is used to extend the command context with additional properties at {@link CommandContext.extensions}.
10
- * @since v0.27.0
11
- */
12
- type ExtendContext = Record<string, unknown>;
13
- /**
14
- * Gunshi unified parameter type.
15
- * This type combines both argument definitions and command context extensions.
16
- * @since v0.27.0
17
- */
18
- interface GunshiParams$1<P extends {
19
- args?: Args;
20
- extensions?: ExtendContext;
21
- } = {
22
- args: Args;
23
- extensions: {};
24
- }> {
25
- /**
26
- * Command argument definitions
27
- */
28
- args: P extends {
29
- args: infer A extends Args;
30
- } ? A : Args;
31
- /**
32
- * Command context extensions
33
- */
34
- extensions: P extends {
35
- extensions: infer E extends ExtendContext;
36
- } ? E : {};
37
- }
38
- /**
39
- * Default Gunshi parameters
40
- * @since v0.27.0
41
- */
42
- type DefaultGunshiParams$1 = GunshiParams$1;
43
- /**
44
- * Generic constraint for command-related types.
45
- * This type constraint allows both GunshiParams and objects with extensions.
46
- * @since v0.27.0
47
- */
48
5
  declare namespace constants_d_exports {
49
6
  export { ARG_NEGATABLE_PREFIX, ARG_PREFIX, ARG_PREFIX_AND_KEY_SEPARATOR, BUILD_IN_PREFIX_AND_KEY_SEPARATOR, BUILT_IN_KEY_SEPARATOR, BUILT_IN_PREFIX, COMMAND_BUILTIN_RESOURCE_KEYS, COMMON_ARGS, PLUGIN_PREFIX };
50
7
  }
@@ -94,28 +51,34 @@ type CommandBuiltinArgsKeys = keyof (typeof constants_d_exports)['COMMON_ARGS'];
94
51
  */
95
52
  type CommandBuiltinResourceKeys = (typeof constants_d_exports)['COMMAND_BUILTIN_RESOURCE_KEYS'][number];
96
53
  /**
97
- * i18n built-in resource keys.
54
+ * Built-in resource keys.
98
55
  */
99
56
  type BuiltinResourceKeys = CommandBuiltinArgsKeys | CommandBuiltinResourceKeys;
100
57
  /**
101
- * Command i18n built-in keys.
102
- * The command i18n built-in keys are used by the i18n plugin for translation.
58
+ * Command built-in keys.
103
59
  */
104
- type CommandBuiltinKeys = GenerateNamespacedKey<BuiltinResourceKeys> | 'description' | 'examples';
60
+ type CommandBuiltinKeys = GenerateNamespacedKey<BuiltinResourceKeys>;
105
61
  /**
106
62
  * Command i18n option keys.
107
63
  * The command i18n option keys are used by the i18n plugin for translation.
108
64
  */
109
- type CommandArgKeys<A extends Args$1> = GenerateNamespacedKey<KeyOfArgs<RemovedIndex<A>>, typeof ARG_PREFIX>;
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;
110
78
  /**
111
79
  * Translation function interface
112
80
  */
113
81
  //#endregion
114
- //#region ../shared/src/localize.d.ts
115
- interface Localization<T extends string = CommandBuiltinKeys, G extends GunshiParams$1<any> = DefaultGunshiParams$1> {
116
- <O = CommandArgKeys<G['args']>, K = CommandBuiltinKeys | O | T>(key: K, values?: Record<string, unknown>): Promise<string>;
117
- }
118
- //#endregion
119
82
  //#region src/types.d.ts
120
83
  /**
121
84
  * Extended command context which provides utilities via usage renderer plugin.
@@ -125,10 +88,14 @@ interface UsageRendererCommandContext<G extends GunshiParams<any> = DefaultGunsh
125
88
  /**
126
89
  * Render the text message
127
90
  */
128
- text: Localization<CommandBuiltinKeys, G>;
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;
129
96
  /**
130
97
  * Load commands
131
- * @returns A list of commands loaded from the command loader plugin.
98
+ * @returns A list of commands loaded from the usage renderert plugin.
132
99
  */
133
100
  loadCommands: <G extends GunshiParams = DefaultGunshiParams>() => Promise<Command<G>[]>;
134
101
  }
@@ -164,4 +131,4 @@ declare function renderValidationErrors<G extends GunshiParams = DefaultGunshiPa
164
131
  */
165
132
  declare function renderer(): PluginWithExtension<UsageRendererCommandContext>;
166
133
  //#endregion
167
- export { UsageRendererCommandContext, renderer as default, renderHeader, renderUsage, renderValidationErrors };
134
+ export { type UsageRendererCommandContext, renderer as default, renderHeader, renderUsage, renderValidationErrors };
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { plugin } from "@gunshi/plugin";
1
+ import { ANONYMOUS_COMMAND_NAME, plugin } from "@gunshi/plugin";
2
2
 
3
3
  //#region ../../node_modules/.pnpm/args-tokens@0.22.0/node_modules/args-tokens/lib/utils-N7UlhLbz.js
4
4
  /**
@@ -125,11 +125,35 @@ var en_US_default = {
125
125
 
126
126
  //#endregion
127
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
+ */
128
134
  function resolveBuiltInKey(key) {
129
135
  return `${BUILT_IN_PREFIX}${BUILT_IN_KEY_SEPARATOR}${key}`;
130
136
  }
131
- function resolveArgKey(key) {
132
- 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}`;
133
157
  }
134
158
  async function resolveExamples$1(ctx, examples) {
135
159
  return typeof examples === "string" ? examples : typeof examples === "function" ? await examples(ctx) : "";
@@ -145,15 +169,25 @@ function makeShortLongOptionPair(schema, name, toKebab) {
145
169
  }
146
170
 
147
171
  //#endregion
148
- //#region ../shared/src/localize.ts
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
+ */
149
181
  function localizable(ctx, cmd, translate) {
150
182
  async function localize(key, values) {
151
183
  if (translate) return translate(key, values);
152
- else if (key.startsWith(BUILD_IN_PREFIX_AND_KEY_SEPARATOR)) {
184
+ if (key.startsWith(BUILD_IN_PREFIX_AND_KEY_SEPARATOR)) {
153
185
  const resKey = key.slice(BUILD_IN_PREFIX_AND_KEY_SEPARATOR.length);
154
186
  return en_US_default[resKey] || key;
155
- } else if (key.startsWith(ARG_PREFIX_AND_KEY_SEPARATOR)) {
156
- let argKey = key.slice(ARG_PREFIX_AND_KEY_SEPARATOR.length);
187
+ }
188
+ const namaspacedArgKey = resolveKey(ARG_PREFIX_AND_KEY_SEPARATOR, ctx);
189
+ if (key.startsWith(namaspacedArgKey)) {
190
+ let argKey = key.slice(namaspacedArgKey.length);
157
191
  let negatable = false;
158
192
  if (argKey.startsWith(ARG_NEGATABLE_PREFIX)) {
159
193
  argKey = argKey.slice(ARG_NEGATABLE_PREFIX.length);
@@ -162,8 +196,9 @@ function localizable(ctx, cmd, translate) {
162
196
  const schema = ctx.args[argKey];
163
197
  if (!schema) return argKey;
164
198
  return negatable && schema.type === "boolean" && schema.negatable ? `${en_US_default["NEGATABLE"]} ${makeShortLongOptionPair(schema, argKey, ctx.toKebab)}` : schema.description || "";
165
- } else if (key === "description") return "";
166
- else if (key === "examples") return await resolveExamples$1(ctx, cmd.examples);
199
+ }
200
+ if (key === resolveKey("description", ctx)) return "";
201
+ else if (key === resolveKey("examples", ctx)) return await resolveExamples$1(ctx, cmd.examples);
167
202
  else return key;
168
203
  }
169
204
  return localize;
@@ -204,8 +239,8 @@ async function renderUsage(ctx) {
204
239
  }
205
240
  messages.push(...await renderUsageSection(ctx), "");
206
241
  if (ctx.omitted && await hasCommands(ctx)) messages.push(...await renderCommandsSection(ctx), "");
207
- if (hasPositionalArgs(ctx)) messages.push(...await renderPositionalArgsSection(ctx), "");
208
- 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), "");
209
244
  const examples = await renderExamplesSection(ctx);
210
245
  if (examples.length > 0) messages.push(...examples, "");
211
246
  return messages.join("\n");
@@ -253,19 +288,21 @@ async function renderExamplesSection(ctx) {
253
288
  */
254
289
  async function renderUsageSection(ctx) {
255
290
  const messages = [`${await ctx.extensions[pluginId].text(resolveBuiltInKey("USAGE"))}:`];
256
- if (ctx.omitted) {
257
- const defaultCommand = `${await resolveEntry(ctx)}${await hasCommands(ctx) ? ` [${await resolveSubCommand(ctx)}]` : ""} ${[await generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`;
258
- messages.push(defaultCommand.padStart(ctx.env.leftMargin + defaultCommand.length));
259
- if (await hasCommands(ctx)) {
260
- const commandsUsage = `${await resolveEntry(ctx)} <${await ctx.extensions[pluginId].text(resolveBuiltInKey("COMMANDS"))}>`;
261
- messages.push(commandsUsage.padStart(ctx.env.leftMargin + commandsUsage.length));
262
- }
263
- } else {
264
- const usageStr = `${await resolveEntry(ctx)} ${await resolveSubCommand(ctx)} ${[await generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`;
265
- messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
266
- }
291
+ const usageStr = await makeUsageSymbols(ctx);
292
+ messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
267
293
  return messages;
268
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
+ }
269
306
  /**
270
307
  * Render the commands section
271
308
  * @param ctx A {@link CommandContext | command context}
@@ -275,19 +312,38 @@ async function renderCommandsSection(ctx) {
275
312
  const messages = [`${await ctx.extensions[pluginId].text(resolveBuiltInKey("COMMANDS"))}:`];
276
313
  const loadedCommands = await ctx.extensions?.[pluginId].loadCommands() || [];
277
314
  const commandMaxLength = Math.max(...loadedCommands.map((cmd) => (cmd.name || "").length));
278
- const commandsStr = await Promise.all(loadedCommands.map((cmd) => {
279
- const key = cmd.name || "";
315
+ const commandsStr = await Promise.all(loadedCommands.map(async (cmd) => {
280
316
  const desc = cmd.description || "";
281
- const command = `${key.padEnd(commandMaxLength + ctx.env.middleMargin)}${desc} `;
282
- 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)}`;
283
323
  }));
284
324
  messages.push(...commandsStr, "", `${await ctx.extensions[pluginId].text(resolveBuiltInKey("FORMORE"))}:`);
285
325
  messages.push(...loadedCommands.map((cmd) => {
286
- 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`;
287
329
  return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`;
288
330
  }));
289
331
  return messages;
290
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
+ }
291
347
  /**
292
348
  * Resolve the entry command name
293
349
  * @param ctx A {@link CommandContext | command context}
@@ -310,7 +366,7 @@ async function resolveSubCommand(ctx) {
310
366
  * @returns resolved command description
311
367
  */
312
368
  async function resolveDescription(ctx) {
313
- return await ctx.extensions[pluginId].text("description") || ctx.description || "";
369
+ return await ctx.extensions[pluginId].text(resolveKey("description", ctx)) || ctx.description || "";
314
370
  }
315
371
  /**
316
372
  * Resolve the command examples
@@ -318,7 +374,7 @@ async function resolveDescription(ctx) {
318
374
  * @returns resolved command examples, if not resolved, return empty string
319
375
  */
320
376
  async function resolveExamples(ctx) {
321
- const ret = await ctx.extensions[pluginId].text("examples");
377
+ const ret = await ctx.extensions[pluginId].text(resolveKey("examples", ctx));
322
378
  if (ret) return ret;
323
379
  const command = ctx.env.subCommands?.get(ctx.name || "");
324
380
  return await resolveExamples$1(ctx, command?.examples);
@@ -334,35 +390,35 @@ async function hasCommands(ctx) {
334
390
  }
335
391
  /**
336
392
  * Check if the command has optional arguments
337
- * @param ctx A {@link CommandContext | command context}
393
+ * @param args A {@link Args | command optional arguments}
338
394
  * @returns True if the command has options
339
395
  */
340
- function hasOptionalArgs(ctx) {
341
- 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");
342
398
  }
343
399
  /**
344
400
  * Check if the command has positional arguments
345
- * @param ctx A {@link CommandContext | command context}
401
+ * @param args A {@link Args | command positional arguments}
346
402
  * @returns True if the command has options
347
403
  */
348
- function hasPositionalArgs(ctx) {
349
- 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");
350
406
  }
351
407
  /**
352
408
  * Check if all options have default values
353
- * @param ctx A {@link CommandContext | command context}
409
+ * @param args An {@link Args | command argument}
354
410
  * @returns True if all options have default values
355
411
  */
356
- function hasAllDefaultOptions(ctx) {
357
- 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));
358
414
  }
359
415
  /**
360
416
  * Generate options symbols for usage
361
417
  * @param ctx A {@link CommandContext | command context}
362
418
  * @returns Options symbols for usage
363
419
  */
364
- async function generateOptionsSymbols(ctx) {
365
- return hasOptionalArgs(ctx) ? hasAllDefaultOptions(ctx) ? `[${await ctx.extensions[pluginId].text(resolveBuiltInKey("OPTIONS"))}]` : `<${await ctx.extensions[pluginId].text(resolveBuiltInKey("OPTIONS"))}>` : "";
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"))}>` : "";
366
422
  }
367
423
  /**
368
424
  * Get optional arguments pairs for usage
@@ -413,7 +469,7 @@ async function generateOptionalArgsUsage(ctx, optionsPairs) {
413
469
  const optionsMaxLength = Math.max(...Object.entries(optionsPairs).map(([_, value]) => value.length));
414
470
  const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...Object.entries(optionsPairs).map(([key]) => resolveNegatableType(key, ctx).length)) : 0;
415
471
  const usages = await Promise.all(Object.entries(optionsPairs).map(async ([key, value]) => {
416
- let rawDesc = await ctx.extensions[pluginId].text(resolveArgKey(key));
472
+ let rawDesc = await ctx.extensions[pluginId].text(resolveArgKey(key, ctx));
417
473
  if (!rawDesc && key.startsWith(ARG_NEGATABLE_PREFIX)) {
418
474
  const name = resolveNegatableKey(key);
419
475
  const schema = ctx.args[name];
@@ -423,26 +479,27 @@ async function generateOptionalArgsUsage(ctx, optionsPairs) {
423
479
  const optionsSchema = ctx.env.usageOptionType ? `[${resolveNegatableType(key, ctx)}] ` : "";
424
480
  const valueDesc = key.startsWith(ARG_NEGATABLE_PREFIX) ? "" : await resolveDisplayValue(ctx, key);
425
481
  const desc = `${optionsSchema ? optionsSchema.padEnd(optionSchemaMaxLength + 3) : ""}${rawDesc}`;
426
- 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}` : ""}`;
427
484
  return `${option.padStart(ctx.env.leftMargin + option.length)}`;
428
485
  }));
429
486
  return usages.join("\n");
430
487
  }
431
- function getPositionalArgs(ctx) {
432
- return Object.entries(ctx.args).filter(([_, schema]) => schema.type === "positional");
488
+ function getPositionalArgs(args) {
489
+ return Object.entries(args).filter(([_, schema]) => schema.type === "positional");
433
490
  }
434
491
  async function generatePositionalArgsUsage(ctx) {
435
- const positionals = getPositionalArgs(ctx);
492
+ const positionals = getPositionalArgs(ctx.args);
436
493
  const argsMaxLength = Math.max(...positionals.map(([name]) => name.length));
437
494
  const usages = await Promise.all(positionals.map(async ([name]) => {
438
- 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 || "";
439
496
  const arg = `${name.padEnd(argsMaxLength + ctx.env.middleMargin)} ${desc}`;
440
497
  return `${arg.padStart(ctx.env.leftMargin + arg.length)}`;
441
498
  }));
442
499
  return usages.join("\n");
443
500
  }
444
- function generatePositionalSymbols(ctx) {
445
- return hasPositionalArgs(ctx) ? getPositionalArgs(ctx).map(([name]) => `<${name}>`).join(" ") : "";
501
+ function generatePositionalSymbols(args) {
502
+ return hasPositionalArgs(args) ? getPositionalArgs(args).map(([name]) => `<${name}>`).join(" ") : "";
446
503
  }
447
504
 
448
505
  //#endregion
@@ -480,7 +537,16 @@ function renderer() {
480
537
  if (cachedCommands) return cachedCommands;
481
538
  const subCommands = [...ctx.env.subCommands || []];
482
539
  const allCommands = await Promise.all(subCommands.map(async ([name, cmd$1]) => await resolveLazyCommand(cmd$1, name)));
483
- return cachedCommands = allCommands.filter((cmd$1) => !cmd$1.internal).filter(Boolean);
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
+ });
549
+ return cachedCommands;
484
550
  }
485
551
  return {
486
552
  text: localizable(ctx, cmd, i18n?.translate),
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.27.0-alpha.8",
4
+ "version": "0.27.0-alpha.9",
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.27.0-alpha.8"
56
+ "@gunshi/plugin": "0.27.0-alpha.9"
57
57
  },
58
58
  "peerDependencies": {
59
- "@gunshi/plugin-i18n": "0.27.0-alpha.8"
59
+ "@gunshi/plugin-i18n": "0.27.0-alpha.9"
60
60
  },
61
61
  "devDependencies": {
62
- "deno": "^2.4.0",
62
+ "deno": "^2.4.2",
63
63
  "jsr": "^0.13.5",
64
64
  "jsr-exports-lint": "^0.4.1",
65
65
  "publint": "^0.3.12",
66
- "tsdown": "^0.12.9",
66
+ "tsdown": "^0.13.0",
67
67
  "typedoc": "^0.28.7",
68
- "typedoc-plugin-markdown": "^4.7.0",
69
- "@gunshi/shared": "0.27.0-alpha.8"
68
+ "typedoc-plugin-markdown": "^4.7.1",
69
+ "@gunshi/shared": "0.27.0-alpha.9"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "tsdown",