@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.
- package/lib/index.d.ts +29 -18
- package/lib/index.js +147 -70
- 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
|
-
*
|
|
54
|
+
* Built-in resource keys.
|
|
56
55
|
*/
|
|
57
56
|
type BuiltinResourceKeys = CommandBuiltinArgsKeys | CommandBuiltinResourceKeys;
|
|
58
57
|
/**
|
|
59
|
-
* Command
|
|
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
|
|
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
|
|
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: <
|
|
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
|
|
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.
|
|
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
|
-
|
|
128
|
-
|
|
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
|
-
|
|
222
|
-
|
|
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
|
|
247
|
-
|
|
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
|
-
|
|
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
|
|
393
|
+
* @param args A {@link Args | command optional arguments}
|
|
303
394
|
* @returns True if the command has options
|
|
304
395
|
*/
|
|
305
|
-
function hasOptionalArgs(
|
|
306
|
-
return
|
|
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
|
|
401
|
+
* @param args A {@link Args | command positional arguments}
|
|
311
402
|
* @returns True if the command has options
|
|
312
403
|
*/
|
|
313
|
-
function hasPositionalArgs(
|
|
314
|
-
return
|
|
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
|
|
409
|
+
* @param args An {@link Args | command argument}
|
|
319
410
|
* @returns True if all options have default values
|
|
320
411
|
*/
|
|
321
|
-
function hasAllDefaultOptions(
|
|
322
|
-
return !!(
|
|
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(
|
|
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
|
|
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(
|
|
403
|
-
return Object.entries(
|
|
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(
|
|
416
|
-
return hasPositionalArgs(
|
|
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
|
-
|
|
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.
|
|
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.
|
|
56
|
+
"@gunshi/plugin": "0.27.0-alpha.10"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@gunshi/plugin-i18n": "0.
|
|
59
|
+
"@gunshi/plugin-i18n": "0.27.0-alpha.10"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"deno": "^2.
|
|
63
|
-
"jsr": "^0.13.
|
|
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.
|
|
67
|
-
"typedoc": "^0.28.
|
|
68
|
-
"typedoc-plugin-markdown": "^4.
|
|
69
|
-
"@gunshi/shared": "0.
|
|
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",
|