gunshi 0.35.1 → 0.35.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 +2 -2
- package/lib/bone.js +1 -1
- package/lib/{cli-DoX4INTi.js → cli-DnXk5aCq.js} +8 -3
- package/lib/combinators.d.ts +2 -10
- package/lib/combinators.js +80 -7
- package/lib/context-CAPhwgJJ.js +119 -0
- package/lib/context.d.ts +2 -2
- package/lib/context.js +1 -90
- package/lib/core-CbE1I4Jl.js +518 -0
- package/lib/definition.d.ts +2 -2
- package/lib/definition.js +1 -1
- package/lib/error-6srXBX7u.d.ts +87 -0
- package/lib/error-xSnOOdnr.js +65 -0
- package/lib/generator.d.ts +1 -1
- package/lib/generator.js +2 -2
- package/lib/index.d.ts +4 -4
- package/lib/index.js +7 -7
- package/lib/{core-CFEvRYOJ.js → plugin-DhJZVIbl.js} +7 -0
- package/lib/plugin.d.ts +4 -4
- package/lib/plugin.js +5 -10
- package/lib/renderer.d.ts +3 -3
- package/lib/renderer.js +1 -1
- package/lib/{resolver-mxPNDBm_.d.ts → resolver-CgkhQ6Tt.d.ts} +62 -4
- package/lib/{core-xgWIcbHL.js → resolver-UFOtObbe.js} +158 -456
- package/lib/{src-B4uHG_qb.js → src-DbfZvEe0.js} +74 -9
- package/lib/{types-DZ0S_FSe.d.ts → types-CD5eRJFK.d.ts} +18 -1
- package/lib/utils-BKhsrjPW.js +32 -0
- package/lib/utils.d.ts +8 -3
- package/lib/utils.js +109 -1
- package/package.json +7 -7
- package/lib/constants-BkgP86Yw.d.ts +0 -11
- package/lib/constants-CQq1R_68.js +0 -29
- package/lib/utils-DNVHO9MQ.js +0 -131
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import { i as NOOP, r as CLI_OPTIONS_DEFAULT, t as createCommandContext } from "./context-CAPhwgJJ.js";
|
|
2
|
+
import { n as kebabnize } from "./utils-BKhsrjPW.js";
|
|
3
|
+
import { create, getCommandSubCommands, isLazyCommand, resolveLazyCommand } from "./utils.js";
|
|
4
|
+
import { a as parseArgs, i as resolveArgs, n as ArgsValidationErrorKeys, t as ArgsValidationError } from "./resolver-UFOtObbe.js";
|
|
5
|
+
import { n as CommandNotFoundErrorKeys, r as hasPriorityValidationError, t as CommandNotFoundError } from "./error-xSnOOdnr.js";
|
|
6
|
+
//#region src/decorators.ts
|
|
7
|
+
/**
|
|
8
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
const EMPTY_RENDERER = () => Promise.resolve("");
|
|
12
|
+
/**
|
|
13
|
+
* Factory function for creating a decorators manager.
|
|
14
|
+
*
|
|
15
|
+
* @returns A new decorators manager instance
|
|
16
|
+
*/
|
|
17
|
+
function createDecorators() {
|
|
18
|
+
/**
|
|
19
|
+
* private states
|
|
20
|
+
*/
|
|
21
|
+
const headerDecorators = [];
|
|
22
|
+
const usageDecorators = [];
|
|
23
|
+
const validationDecorators = [];
|
|
24
|
+
const commandDecorators = [];
|
|
25
|
+
/**
|
|
26
|
+
* helper function for building renderers
|
|
27
|
+
*/
|
|
28
|
+
function buildRenderer(decorators, defaultRenderer) {
|
|
29
|
+
if (decorators.length === 0) return defaultRenderer;
|
|
30
|
+
let renderer = defaultRenderer;
|
|
31
|
+
for (const decorator of decorators) {
|
|
32
|
+
const previousRenderer = renderer;
|
|
33
|
+
renderer = (ctx) => decorator(previousRenderer, ctx);
|
|
34
|
+
}
|
|
35
|
+
return renderer;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* public interfaces
|
|
39
|
+
*/
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
addHeaderDecorator(decorator) {
|
|
42
|
+
headerDecorators.push(decorator);
|
|
43
|
+
},
|
|
44
|
+
addUsageDecorator(decorator) {
|
|
45
|
+
usageDecorators.push(decorator);
|
|
46
|
+
},
|
|
47
|
+
addValidationErrorsDecorator(decorator) {
|
|
48
|
+
validationDecorators.push(decorator);
|
|
49
|
+
},
|
|
50
|
+
addCommandDecorator(decorator) {
|
|
51
|
+
commandDecorators.push(decorator);
|
|
52
|
+
},
|
|
53
|
+
get commandDecorators() {
|
|
54
|
+
return [...commandDecorators];
|
|
55
|
+
},
|
|
56
|
+
getHeaderRenderer() {
|
|
57
|
+
return buildRenderer(headerDecorators, EMPTY_RENDERER);
|
|
58
|
+
},
|
|
59
|
+
getUsageRenderer() {
|
|
60
|
+
return buildRenderer(usageDecorators, EMPTY_RENDERER);
|
|
61
|
+
},
|
|
62
|
+
getValidationErrorsRenderer() {
|
|
63
|
+
if (validationDecorators.length === 0) return EMPTY_RENDERER;
|
|
64
|
+
let renderer = EMPTY_RENDERER;
|
|
65
|
+
for (const decorator of validationDecorators) {
|
|
66
|
+
const previousRenderer = renderer;
|
|
67
|
+
renderer = (ctx, error) => decorator(previousRenderer, ctx, error);
|
|
68
|
+
}
|
|
69
|
+
return renderer;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/plugin/context.ts
|
|
75
|
+
/**
|
|
76
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
77
|
+
* @license MIT
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* Factory function for creating a plugin context.
|
|
81
|
+
*
|
|
82
|
+
* @typeParam G - A type extending {@linkcode GunshiParams} to specify the shape of command parameters.
|
|
83
|
+
*
|
|
84
|
+
* @param decorators - A {@linkcode Decorators} instance.
|
|
85
|
+
* @param initialSubCommands - Initial sub commands map.
|
|
86
|
+
* @returns A new {@linkcode PluginContext} instance.
|
|
87
|
+
*/
|
|
88
|
+
function createPluginContext(decorators, initialSubCommands) {
|
|
89
|
+
/**
|
|
90
|
+
* private states
|
|
91
|
+
*/
|
|
92
|
+
const globalOptions = /* @__PURE__ */ new Map();
|
|
93
|
+
const subCommands = new Map(initialSubCommands || []);
|
|
94
|
+
/**
|
|
95
|
+
* public interfaces
|
|
96
|
+
*/
|
|
97
|
+
return Object.freeze({
|
|
98
|
+
get globalOptions() {
|
|
99
|
+
return new Map(globalOptions);
|
|
100
|
+
},
|
|
101
|
+
addGlobalOption(name, schema) {
|
|
102
|
+
if (!name) throw new Error("Option name must be a non-empty string");
|
|
103
|
+
if (globalOptions.has(name)) throw new Error(`Global option '${name}' is already registered`);
|
|
104
|
+
globalOptions.set(name, schema);
|
|
105
|
+
},
|
|
106
|
+
get subCommands() {
|
|
107
|
+
return new Map(subCommands);
|
|
108
|
+
},
|
|
109
|
+
addCommand(name, command) {
|
|
110
|
+
if (!name) throw new Error("Command name must be a non-empty string");
|
|
111
|
+
if (subCommands.has(name)) throw new Error(`Command '${name}' is already registered`);
|
|
112
|
+
subCommands.set(name, command);
|
|
113
|
+
},
|
|
114
|
+
hasCommand(name) {
|
|
115
|
+
return subCommands.has(name);
|
|
116
|
+
},
|
|
117
|
+
decorateHeaderRenderer(decorator) {
|
|
118
|
+
decorators.addHeaderDecorator(decorator);
|
|
119
|
+
},
|
|
120
|
+
decorateUsageRenderer(decorator) {
|
|
121
|
+
decorators.addUsageDecorator(decorator);
|
|
122
|
+
},
|
|
123
|
+
decorateValidationErrorsRenderer(decorator) {
|
|
124
|
+
decorators.addValidationErrorsDecorator(decorator);
|
|
125
|
+
},
|
|
126
|
+
decorateCommand(decorator) {
|
|
127
|
+
decorators.addCommandDecorator(decorator);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/plugin/dependency.ts
|
|
133
|
+
/**
|
|
134
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
135
|
+
* @license MIT
|
|
136
|
+
*/
|
|
137
|
+
/**
|
|
138
|
+
* Resolve plugin dependencies using topological sort
|
|
139
|
+
*
|
|
140
|
+
* @param plugins - Array of plugins to resolve
|
|
141
|
+
* @returns Array of plugins sorted by dependencies
|
|
142
|
+
*/
|
|
143
|
+
function resolveDependencies(plugins) {
|
|
144
|
+
const sorted = [];
|
|
145
|
+
const visited = /* @__PURE__ */ new Set();
|
|
146
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
147
|
+
const pluginMap = /* @__PURE__ */ new Map();
|
|
148
|
+
for (const plugin of plugins) if (plugin.id) {
|
|
149
|
+
if (pluginMap.has(plugin.id)) console.warn(`Duplicate plugin id detected: \`${plugin.id}\``);
|
|
150
|
+
pluginMap.set(plugin.id, plugin);
|
|
151
|
+
}
|
|
152
|
+
function visit(plugin) {
|
|
153
|
+
if (!plugin.id) return;
|
|
154
|
+
if (visited.has(plugin.id)) return;
|
|
155
|
+
if (visiting.has(plugin.id)) throw new Error(`Circular dependency detected: \`${[...visiting].join(` -> `) + " -> " + plugin.id}\``);
|
|
156
|
+
visiting.add(plugin.id);
|
|
157
|
+
const deps = plugin.dependencies || [];
|
|
158
|
+
for (const dep of deps) {
|
|
159
|
+
const depId = typeof dep === "string" ? dep : dep.id;
|
|
160
|
+
const isOptional = typeof dep === "string" ? false : dep.optional || false;
|
|
161
|
+
const depPlugin = pluginMap.get(depId);
|
|
162
|
+
if (!depPlugin && !isOptional) throw new Error(`Missing required dependency: \`${depId}\` on \`${plugin.id}\``);
|
|
163
|
+
if (depPlugin) visit(depPlugin);
|
|
164
|
+
}
|
|
165
|
+
visiting.delete(plugin.id);
|
|
166
|
+
visited.add(plugin.id);
|
|
167
|
+
sorted.push(plugin);
|
|
168
|
+
}
|
|
169
|
+
for (const plugin of plugins) visit(plugin);
|
|
170
|
+
return sorted;
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/cli/core.ts
|
|
174
|
+
/**
|
|
175
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
176
|
+
* @license MIT
|
|
177
|
+
*/
|
|
178
|
+
/**
|
|
179
|
+
* Run the command.
|
|
180
|
+
*
|
|
181
|
+
* @typeParam G - A type extending {@linkcode GunshiParams} to specify the shape of command and cli options.
|
|
182
|
+
*
|
|
183
|
+
* @param argv - Command line arguments
|
|
184
|
+
* @param entry - A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
|
|
185
|
+
* @param options - A {@link CliOptions | CLI options}
|
|
186
|
+
* @param plugins - An array of {@link Plugin | plugins} to be applied
|
|
187
|
+
* @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
|
|
188
|
+
*/
|
|
189
|
+
async function cliCore(argv, entry, options, plugins) {
|
|
190
|
+
const decorators = createDecorators();
|
|
191
|
+
const pluginContext = createPluginContext(decorators, createInitialSubCommands(options, entry));
|
|
192
|
+
const resolvedPlugins = await applyPlugins(pluginContext, [...plugins, ...options.plugins || []]);
|
|
193
|
+
const cliOptions = normalizeCliOptions(options, decorators, pluginContext);
|
|
194
|
+
const tokens = parseArgs(argv);
|
|
195
|
+
const resolved = resolveCommandTree(tokens, entry, cliOptions);
|
|
196
|
+
const { commandName: name, command, callMode, commandPath, depth, levelSubCommands } = resolved;
|
|
197
|
+
let targetCommand = command;
|
|
198
|
+
let targetCommandName = name;
|
|
199
|
+
let targetCallMode = callMode;
|
|
200
|
+
let targetCommandPath = commandPath;
|
|
201
|
+
let targetDepth = depth;
|
|
202
|
+
let targetOmitted = resolved.omitted;
|
|
203
|
+
let targetLevelSubCommands = levelSubCommands;
|
|
204
|
+
const additionalValidationErrors = [];
|
|
205
|
+
if (!targetCommand) {
|
|
206
|
+
if (!resolved.parentCommand || !resolved.unresolvedCommandName) throw new Error(`Command not found: ${name || ""}`);
|
|
207
|
+
targetCommand = resolved.parentCommand;
|
|
208
|
+
targetCommandName = resolved.parentCommandName;
|
|
209
|
+
targetCommandPath = resolved.parentCommandPath || [];
|
|
210
|
+
targetDepth = targetCommandPath.length;
|
|
211
|
+
targetCallMode = targetDepth > 0 ? "subCommand" : "entry";
|
|
212
|
+
targetOmitted = false;
|
|
213
|
+
targetLevelSubCommands = resolved.parentSubCommands;
|
|
214
|
+
additionalValidationErrors.push(createCommandNotFoundError(resolved));
|
|
215
|
+
}
|
|
216
|
+
if (targetLevelSubCommands) cliOptions.subCommands = targetLevelSubCommands;
|
|
217
|
+
const resolvedCommand = isLazyCommand(targetCommand) ? await resolveLazyCommand(targetCommand, targetCommandName, true) : targetCommand;
|
|
218
|
+
const args = resolveArguments(pluginContext, getCommandArgs(resolvedCommand));
|
|
219
|
+
const skipPositional = targetDepth > 0 ? targetDepth - 1 : -1;
|
|
220
|
+
const { explicit, values, positionals, rest, error } = resolveArgs(args, tokens, {
|
|
221
|
+
shortGrouping: true,
|
|
222
|
+
toKebab: resolvedCommand.toKebab,
|
|
223
|
+
skipPositional
|
|
224
|
+
});
|
|
225
|
+
const validationError = mergeValidationErrors(error, [...additionalValidationErrors, ...cliOptions.strict ? createUnknownOptionErrors(findUnknownOptions(args, tokens, { toKebab: resolvedCommand.toKebab })) : []]);
|
|
226
|
+
return await executeCommand(resolvedCommand, await createCommandContext({
|
|
227
|
+
args,
|
|
228
|
+
explicit,
|
|
229
|
+
values,
|
|
230
|
+
positionals,
|
|
231
|
+
rest,
|
|
232
|
+
argv,
|
|
233
|
+
tokens,
|
|
234
|
+
omitted: targetOmitted,
|
|
235
|
+
callMode: targetCallMode,
|
|
236
|
+
commandPath: targetCommandPath,
|
|
237
|
+
command: resolvedCommand,
|
|
238
|
+
extensions: getPluginExtensions(resolvedPlugins),
|
|
239
|
+
validationError,
|
|
240
|
+
cliOptions
|
|
241
|
+
}), decorators.commandDecorators);
|
|
242
|
+
}
|
|
243
|
+
async function applyPlugins(pluginContext, plugins) {
|
|
244
|
+
const sortedPlugins = resolveDependencies(plugins);
|
|
245
|
+
try {
|
|
246
|
+
for (const plugin of sortedPlugins)
|
|
247
|
+
/**
|
|
248
|
+
* NOTE(kazupon):
|
|
249
|
+
* strictly `Args` are not required for plugin installation.
|
|
250
|
+
* because the strictly `Args` required by each plugin are unknown,
|
|
251
|
+
* and the plugin side can not know what the user will specify.
|
|
252
|
+
*/
|
|
253
|
+
await plugin(pluginContext);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
console.error("Error loading plugin:", error.message);
|
|
256
|
+
}
|
|
257
|
+
return sortedPlugins;
|
|
258
|
+
}
|
|
259
|
+
function getCommandArgs(cmd) {
|
|
260
|
+
if (isLazyCommand(cmd)) return cmd.args || create();
|
|
261
|
+
else if (typeof cmd === "object") return cmd.args || create();
|
|
262
|
+
else return create();
|
|
263
|
+
}
|
|
264
|
+
function resolveArguments(pluginContext, args) {
|
|
265
|
+
return Object.assign(create(), Object.fromEntries(pluginContext.globalOptions), args);
|
|
266
|
+
}
|
|
267
|
+
const NEGATABLE_OPTION_PREFIX = "no-";
|
|
268
|
+
function findUnknownOptions(args, tokens, options) {
|
|
269
|
+
const knownLongOptions = /* @__PURE__ */ new Set();
|
|
270
|
+
const knownShortOptions = /* @__PURE__ */ new Set();
|
|
271
|
+
const knownNegatableOptions = /* @__PURE__ */ new Set();
|
|
272
|
+
const knownLongOptionCandidates = /* @__PURE__ */ new Set();
|
|
273
|
+
const longOptionCandidates = [];
|
|
274
|
+
function addLongOptionCandidate(name) {
|
|
275
|
+
const candidate = `--${name}`;
|
|
276
|
+
if (knownLongOptionCandidates.has(candidate)) return;
|
|
277
|
+
knownLongOptionCandidates.add(candidate);
|
|
278
|
+
longOptionCandidates.push(candidate);
|
|
279
|
+
}
|
|
280
|
+
for (const [name, schema] of Object.entries(args)) {
|
|
281
|
+
if (schema.type === "positional") continue;
|
|
282
|
+
const optionName = resolveOptionName(name, schema, options);
|
|
283
|
+
knownLongOptions.add(optionName);
|
|
284
|
+
addLongOptionCandidate(optionName);
|
|
285
|
+
if (schema.short) knownShortOptions.add(schema.short);
|
|
286
|
+
if (schema.type === "boolean" && schema.negatable) {
|
|
287
|
+
const negatableOptionName = `${NEGATABLE_OPTION_PREFIX}${optionName}`;
|
|
288
|
+
knownNegatableOptions.add(negatableOptionName);
|
|
289
|
+
addLongOptionCandidate(negatableOptionName);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const unknownOptions = [];
|
|
293
|
+
for (const token of tokens) {
|
|
294
|
+
if (token.kind === "option-terminator") break;
|
|
295
|
+
if (token.kind !== "option" || !token.name || !token.rawName) continue;
|
|
296
|
+
const isLongOption = token.rawName.startsWith("--");
|
|
297
|
+
if (isLongOption) {
|
|
298
|
+
if (knownLongOptions.has(token.name) || knownNegatableOptions.has(token.name)) continue;
|
|
299
|
+
} else if (knownShortOptions.has(token.name)) continue;
|
|
300
|
+
unknownOptions.push({
|
|
301
|
+
rawName: token.rawName,
|
|
302
|
+
name: token.name,
|
|
303
|
+
candidates: isLongOption ? longOptionCandidates : []
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return unknownOptions;
|
|
307
|
+
}
|
|
308
|
+
function resolveOptionName(name, schema, options) {
|
|
309
|
+
return options.toKebab || schema.toKebab ? kebabnize(name) : name;
|
|
310
|
+
}
|
|
311
|
+
function createUnknownOptionErrors(unknownOptions) {
|
|
312
|
+
return unknownOptions.map(({ rawName, name, candidates }) => {
|
|
313
|
+
return new ArgsValidationError(`Unknown option: ${rawName}`, {
|
|
314
|
+
code: ArgsValidationErrorKeys.unknownOption,
|
|
315
|
+
values: {
|
|
316
|
+
rawName,
|
|
317
|
+
name,
|
|
318
|
+
candidates
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
function mergeValidationErrors(error, additionalErrors) {
|
|
324
|
+
if (additionalErrors.length === 0) return error;
|
|
325
|
+
return new AggregateError(error ? [...error.errors, ...additionalErrors] : additionalErrors, error?.message || additionalErrors[0]?.message);
|
|
326
|
+
}
|
|
327
|
+
const isObject = (val) => val !== null && typeof val === "object";
|
|
328
|
+
function createInitialSubCommands(options, entryCmd) {
|
|
329
|
+
const hasSubCommands = options.subCommands ? options.subCommands instanceof Map ? options.subCommands.size > 0 : isObject(options.subCommands) && Object.keys(options.subCommands).length > 0 : false;
|
|
330
|
+
const subCommands = new Map(options.subCommands instanceof Map ? options.subCommands : []);
|
|
331
|
+
if (!(options.subCommands instanceof Map) && isObject(options.subCommands)) for (const [name, cmd] of Object.entries(options.subCommands)) subCommands.set(name, cmd);
|
|
332
|
+
if (hasSubCommands) {
|
|
333
|
+
if (isLazyCommand(entryCmd)) {
|
|
334
|
+
const entryCopy = Object.assign((...args) => entryCmd(...args), entryCmd, { entry: true });
|
|
335
|
+
subCommands.set(resolveEntryName(entryCopy), entryCopy);
|
|
336
|
+
} else if (typeof entryCmd === "object") {
|
|
337
|
+
const entryCopy = Object.assign(create(), entryCmd, { entry: true });
|
|
338
|
+
subCommands.set(resolveEntryName(entryCopy), entryCopy);
|
|
339
|
+
} else if (typeof entryCmd === "function") {
|
|
340
|
+
const name = entryCmd.name || "(anonymous)";
|
|
341
|
+
subCommands.set(name, {
|
|
342
|
+
run: entryCmd,
|
|
343
|
+
name,
|
|
344
|
+
entry: true
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return subCommands;
|
|
349
|
+
}
|
|
350
|
+
function normalizeCliOptions(options, decorators, pluginContext) {
|
|
351
|
+
const subCommands = new Map(pluginContext.subCommands);
|
|
352
|
+
const resolvedOptions = Object.assign(create(), CLI_OPTIONS_DEFAULT, options, { subCommands });
|
|
353
|
+
if (resolvedOptions.renderHeader === void 0) resolvedOptions.renderHeader = decorators.getHeaderRenderer();
|
|
354
|
+
if (resolvedOptions.renderUsage === void 0) resolvedOptions.renderUsage = decorators.getUsageRenderer();
|
|
355
|
+
if (resolvedOptions.renderValidationErrors === void 0) resolvedOptions.renderValidationErrors = decorators.getValidationErrorsRenderer();
|
|
356
|
+
return resolvedOptions;
|
|
357
|
+
}
|
|
358
|
+
function getPositionalTokens(tokens) {
|
|
359
|
+
return tokens.filter((t) => t.kind === "positional").map((t) => t.value).filter((v) => !!v);
|
|
360
|
+
}
|
|
361
|
+
function resolveCommandTree(tokens, entry, options) {
|
|
362
|
+
const positionals = getPositionalTokens(tokens);
|
|
363
|
+
function resolveAsEntry() {
|
|
364
|
+
if (typeof entry === "function") if ("commandName" in entry && entry.commandName) return {
|
|
365
|
+
commandName: entry.commandName,
|
|
366
|
+
command: entry,
|
|
367
|
+
callMode: "entry",
|
|
368
|
+
commandPath: [],
|
|
369
|
+
depth: 0,
|
|
370
|
+
omitted: options.subCommands.size > 0 && !positionals[0],
|
|
371
|
+
levelSubCommands: options.subCommands.size > 0 ? options.subCommands : void 0
|
|
372
|
+
};
|
|
373
|
+
else return {
|
|
374
|
+
command: {
|
|
375
|
+
run: entry,
|
|
376
|
+
entry: true
|
|
377
|
+
},
|
|
378
|
+
callMode: "entry",
|
|
379
|
+
commandPath: [],
|
|
380
|
+
depth: 0,
|
|
381
|
+
omitted: options.subCommands.size > 0 && !positionals[0],
|
|
382
|
+
levelSubCommands: options.subCommands.size > 0 ? options.subCommands : void 0
|
|
383
|
+
};
|
|
384
|
+
else if (typeof entry === "object") return {
|
|
385
|
+
commandName: resolveEntryName(entry),
|
|
386
|
+
command: entry,
|
|
387
|
+
callMode: "entry",
|
|
388
|
+
commandPath: [],
|
|
389
|
+
depth: 0,
|
|
390
|
+
omitted: options.subCommands.size > 0 && !positionals[0],
|
|
391
|
+
levelSubCommands: options.subCommands.size > 0 ? options.subCommands : void 0
|
|
392
|
+
};
|
|
393
|
+
else return {
|
|
394
|
+
callMode: "unexpected",
|
|
395
|
+
commandPath: [],
|
|
396
|
+
depth: 0,
|
|
397
|
+
omitted: false,
|
|
398
|
+
levelSubCommands: void 0
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
if (positionals.length === 0 || options.subCommands.size === 0) return resolveAsEntry();
|
|
402
|
+
let currentSubCommands = options.subCommands;
|
|
403
|
+
let resolvedCommand;
|
|
404
|
+
let resolvedName;
|
|
405
|
+
const commandPath = [];
|
|
406
|
+
let depth = 0;
|
|
407
|
+
for (let i = 0; i < positionals.length; i++) {
|
|
408
|
+
const token = positionals[i];
|
|
409
|
+
const cmd = currentSubCommands.get(token);
|
|
410
|
+
if (cmd == null) {
|
|
411
|
+
if (depth === 0) {
|
|
412
|
+
if (options.fallbackToEntry) return resolveAsEntry();
|
|
413
|
+
const parent = resolveAsEntry();
|
|
414
|
+
return {
|
|
415
|
+
commandName: token,
|
|
416
|
+
callMode: "unexpected",
|
|
417
|
+
commandPath: [],
|
|
418
|
+
depth: 0,
|
|
419
|
+
omitted: false,
|
|
420
|
+
levelSubCommands: void 0,
|
|
421
|
+
unresolvedCommandName: token,
|
|
422
|
+
parentCommand: parent.command,
|
|
423
|
+
parentCommandName: parent.commandName,
|
|
424
|
+
parentCommandPath: [],
|
|
425
|
+
parentSubCommands: options.subCommands
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
commandName: token,
|
|
430
|
+
callMode: "unexpected",
|
|
431
|
+
commandPath: [...commandPath],
|
|
432
|
+
depth,
|
|
433
|
+
omitted: false,
|
|
434
|
+
levelSubCommands: void 0,
|
|
435
|
+
unresolvedCommandName: token,
|
|
436
|
+
parentCommand: resolvedCommand,
|
|
437
|
+
parentCommandName: resolvedName,
|
|
438
|
+
parentCommandPath: [...commandPath],
|
|
439
|
+
parentSubCommands: currentSubCommands
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
let resolved = cmd;
|
|
443
|
+
if (typeof cmd === "function" && cmd.commandName == null) resolved = Object.assign((...args) => cmd(...args), cmd, { commandName: token });
|
|
444
|
+
else if (typeof cmd === "object" && cmd.name == null) resolved = Object.assign(create(), cmd, { name: token });
|
|
445
|
+
resolvedCommand = resolved;
|
|
446
|
+
resolvedName = token;
|
|
447
|
+
commandPath.push(token);
|
|
448
|
+
depth++;
|
|
449
|
+
const nestedSubCommands = getCommandSubCommands(cmd);
|
|
450
|
+
if (nestedSubCommands && nestedSubCommands.size > 0) currentSubCommands = nestedSubCommands;
|
|
451
|
+
else break;
|
|
452
|
+
}
|
|
453
|
+
if (!resolvedCommand) return resolveAsEntry();
|
|
454
|
+
const resolvedSubCommands = getCommandSubCommands(resolvedCommand);
|
|
455
|
+
const omitted = resolvedSubCommands != null && resolvedSubCommands.size > 0;
|
|
456
|
+
let levelSubCommands;
|
|
457
|
+
if (omitted && resolvedSubCommands) {
|
|
458
|
+
levelSubCommands = new Map(resolvedSubCommands);
|
|
459
|
+
let entryCopy;
|
|
460
|
+
if (typeof resolvedCommand === "function") entryCopy = Object.assign((...args) => resolvedCommand(...args), resolvedCommand, { entry: true });
|
|
461
|
+
else entryCopy = Object.assign(create(), resolvedCommand, { entry: true });
|
|
462
|
+
levelSubCommands.set(resolvedName || resolveEntryName(entryCopy), entryCopy);
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
commandName: resolvedName,
|
|
466
|
+
command: resolvedCommand,
|
|
467
|
+
callMode: depth > 0 ? "subCommand" : "entry",
|
|
468
|
+
commandPath,
|
|
469
|
+
depth,
|
|
470
|
+
omitted,
|
|
471
|
+
levelSubCommands
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function createCommandNotFoundError(resolved) {
|
|
475
|
+
const commandName = resolved.unresolvedCommandName || resolved.commandName || "";
|
|
476
|
+
return new CommandNotFoundError(`Command not found: ${commandName}`, {
|
|
477
|
+
code: CommandNotFoundErrorKeys.notFound,
|
|
478
|
+
values: { commandName },
|
|
479
|
+
commandName,
|
|
480
|
+
candidates: [...resolved.parentSubCommands?.keys() || []],
|
|
481
|
+
commandPath: resolved.parentCommandPath || []
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
function resolveEntryName(entry) {
|
|
485
|
+
return isLazyCommand(entry) ? entry.commandName || "(anonymous)" : entry.name || "(anonymous)";
|
|
486
|
+
}
|
|
487
|
+
function getPluginExtensions(plugins) {
|
|
488
|
+
const extensions = create();
|
|
489
|
+
for (const plugin of plugins) if (plugin.extension) {
|
|
490
|
+
const key = plugin.id;
|
|
491
|
+
if (extensions[key]) console.warn(`Plugin "${key}" is already installed. Ignore it for command context extending.`);
|
|
492
|
+
else extensions[key] = plugin.extension;
|
|
493
|
+
}
|
|
494
|
+
return extensions;
|
|
495
|
+
}
|
|
496
|
+
async function executeCommand(cmd, ctx, decorators) {
|
|
497
|
+
const commandRunner = cmd.run || NOOP;
|
|
498
|
+
const baseRunner = (ctx) => {
|
|
499
|
+
if (hasPriorityValidationError(ctx.validationError)) throw ctx.validationError;
|
|
500
|
+
return commandRunner(ctx);
|
|
501
|
+
};
|
|
502
|
+
const decoratedRunner = decorators.reduceRight((runner, decorator) => decorator(runner), baseRunner);
|
|
503
|
+
try {
|
|
504
|
+
if (ctx.env.onBeforeCommand) await ctx.env.onBeforeCommand(ctx);
|
|
505
|
+
const result = await decoratedRunner(ctx);
|
|
506
|
+
if (ctx.env.onAfterCommand) await ctx.env.onAfterCommand(ctx, result);
|
|
507
|
+
return typeof result === "string" ? result : void 0;
|
|
508
|
+
} catch (error) {
|
|
509
|
+
if (ctx.env.onErrorCommand) try {
|
|
510
|
+
await ctx.env.onErrorCommand(ctx, error);
|
|
511
|
+
} catch (hookError) {
|
|
512
|
+
console.error("Error in onErrorCommand hook:", hookError);
|
|
513
|
+
}
|
|
514
|
+
throw error;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
//#endregion
|
|
518
|
+
export { cliCore as t };
|
package/lib/definition.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as Args, n as ArgSchema, r as ArgValues } from "./resolver-
|
|
2
|
-
import { C as NormalizeToGunshiParams, _ as ExtractArgs, b as GunshiParamsConstraint, d as CommandLoader, f as CommandRunner, h as ExtendContext, m as DefaultGunshiParams, r as Command, v as ExtractExtensions, w as Prettify, x as LazyCommand, y as GunshiParams } from "./types-
|
|
1
|
+
import { i as Args, n as ArgSchema, r as ArgValues } from "./resolver-CgkhQ6Tt.js";
|
|
2
|
+
import { C as NormalizeToGunshiParams, _ as ExtractArgs, b as GunshiParamsConstraint, d as CommandLoader, f as CommandRunner, h as ExtendContext, m as DefaultGunshiParams, r as Command, v as ExtractExtensions, w as Prettify, x as LazyCommand, y as GunshiParams } from "./types-CD5eRJFK.js";
|
|
3
3
|
import { CommandContextParams, createCommandContext } from "./context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/definition.d.ts
|
package/lib/definition.js
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { m as DefaultGunshiParams, n as CliOptions } from "./types-CD5eRJFK.js";
|
|
2
|
+
|
|
3
|
+
//#region src/constants.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
declare const ANONYMOUS_COMMAND_NAME = "(anonymous)";
|
|
9
|
+
declare const CLI_OPTIONS_DEFAULT: CliOptions<DefaultGunshiParams>;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/error.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
14
|
+
* @license MIT
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Command not found error resource keys.
|
|
18
|
+
*/
|
|
19
|
+
declare const CommandNotFoundErrorKeys: {
|
|
20
|
+
readonly notFound: "err:cmd:not-found";
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Command not found error code.
|
|
24
|
+
*/
|
|
25
|
+
type CommandNotFoundErrorCode = (typeof CommandNotFoundErrorKeys)[keyof typeof CommandNotFoundErrorKeys];
|
|
26
|
+
/**
|
|
27
|
+
* Options for {@link CommandNotFoundError}.
|
|
28
|
+
*/
|
|
29
|
+
type CommandNotFoundErrorOptions = {
|
|
30
|
+
/**
|
|
31
|
+
* Localization resource key for command-not-found rendering.
|
|
32
|
+
*/
|
|
33
|
+
code?: CommandNotFoundErrorCode;
|
|
34
|
+
/**
|
|
35
|
+
* Values used when localizing the message.
|
|
36
|
+
*/
|
|
37
|
+
values?: Record<string, unknown>;
|
|
38
|
+
/**
|
|
39
|
+
* The command name that could not be resolved.
|
|
40
|
+
*/
|
|
41
|
+
commandName: string;
|
|
42
|
+
/**
|
|
43
|
+
* Command names available at the same level.
|
|
44
|
+
*/
|
|
45
|
+
candidates?: readonly string[];
|
|
46
|
+
/**
|
|
47
|
+
* Parent command path where resolution failed.
|
|
48
|
+
*/
|
|
49
|
+
commandPath?: readonly string[];
|
|
50
|
+
/**
|
|
51
|
+
* Underlying cause.
|
|
52
|
+
*/
|
|
53
|
+
cause?: unknown;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Error raised when a command cannot be resolved.
|
|
57
|
+
*/
|
|
58
|
+
declare class CommandNotFoundError extends Error {
|
|
59
|
+
readonly code?: CommandNotFoundErrorCode;
|
|
60
|
+
readonly values: Record<string, unknown>;
|
|
61
|
+
readonly commandName: string;
|
|
62
|
+
readonly candidates: readonly string[];
|
|
63
|
+
readonly commandPath: readonly string[];
|
|
64
|
+
/**
|
|
65
|
+
* Create a command-not-found error.
|
|
66
|
+
*
|
|
67
|
+
* @param message - Fallback error message
|
|
68
|
+
* @param options - Command-not-found metadata
|
|
69
|
+
*/
|
|
70
|
+
constructor(message: string, options: CommandNotFoundErrorOptions);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check whether an error is a {@link CommandNotFoundError}.
|
|
74
|
+
*
|
|
75
|
+
* @param error - An unknown error
|
|
76
|
+
* @returns `true` if the error is a {@link CommandNotFoundError}
|
|
77
|
+
*/
|
|
78
|
+
declare function isCommandNotFoundError(error: unknown): error is CommandNotFoundError;
|
|
79
|
+
/**
|
|
80
|
+
* Check whether validation errors should be handled before version, help, or command execution.
|
|
81
|
+
*
|
|
82
|
+
* @param error - An aggregate validation error
|
|
83
|
+
* @returns `true` if the validation error must be handled with priority
|
|
84
|
+
*/
|
|
85
|
+
declare function hasPriorityValidationError(error: AggregateError | undefined): boolean;
|
|
86
|
+
//#endregion
|
|
87
|
+
export { hasPriorityValidationError as a, CLI_OPTIONS_DEFAULT as c, CommandNotFoundErrorOptions as i, CommandNotFoundErrorCode as n, isCommandNotFoundError as o, CommandNotFoundErrorKeys as r, ANONYMOUS_COMMAND_NAME as s, CommandNotFoundError as t };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { n as ArgsValidationErrorKeys, r as isArgsValidationError } from "./resolver-UFOtObbe.js";
|
|
2
|
+
//#region ../../node_modules/.pnpm/args-tokens@0.28.0/node_modules/args-tokens/lib/index.js
|
|
3
|
+
/**
|
|
4
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/error.ts
|
|
13
|
+
/**
|
|
14
|
+
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
15
|
+
* @license MIT
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Command not found error resource keys.
|
|
19
|
+
*/
|
|
20
|
+
const CommandNotFoundErrorKeys = { notFound: "err:cmd:not-found" };
|
|
21
|
+
/**
|
|
22
|
+
* Error raised when a command cannot be resolved.
|
|
23
|
+
*/
|
|
24
|
+
var CommandNotFoundError = class extends Error {
|
|
25
|
+
code;
|
|
26
|
+
values;
|
|
27
|
+
commandName;
|
|
28
|
+
candidates;
|
|
29
|
+
commandPath;
|
|
30
|
+
/**
|
|
31
|
+
* Create a command-not-found error.
|
|
32
|
+
*
|
|
33
|
+
* @param message - Fallback error message
|
|
34
|
+
* @param options - Command-not-found metadata
|
|
35
|
+
*/
|
|
36
|
+
constructor(message, options) {
|
|
37
|
+
super(message, { cause: options.cause });
|
|
38
|
+
this.name = "CommandNotFoundError";
|
|
39
|
+
this.code = options.code;
|
|
40
|
+
this.values = options.values || {};
|
|
41
|
+
this.commandName = options.commandName;
|
|
42
|
+
this.candidates = options.candidates || [];
|
|
43
|
+
this.commandPath = options.commandPath || [];
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Check whether an error is a {@link CommandNotFoundError}.
|
|
48
|
+
*
|
|
49
|
+
* @param error - An unknown error
|
|
50
|
+
* @returns `true` if the error is a {@link CommandNotFoundError}
|
|
51
|
+
*/
|
|
52
|
+
function isCommandNotFoundError(error) {
|
|
53
|
+
return error instanceof CommandNotFoundError;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check whether validation errors should be handled before version, help, or command execution.
|
|
57
|
+
*
|
|
58
|
+
* @param error - An aggregate validation error
|
|
59
|
+
* @returns `true` if the validation error must be handled with priority
|
|
60
|
+
*/
|
|
61
|
+
function hasPriorityValidationError(error) {
|
|
62
|
+
return error?.errors.some((error) => isCommandNotFoundError(error) || isArgsValidationError(error) && error.code === ArgsValidationErrorKeys.unknownOption) ?? false;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { isCommandNotFoundError as i, CommandNotFoundErrorKeys as n, hasPriorityValidationError as r, CommandNotFoundError as t };
|
package/lib/generator.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as GunshiParamsConstraint, m as DefaultGunshiParams, n as CliOptions, r as Command, x as LazyCommand } from "./types-
|
|
1
|
+
import { b as GunshiParamsConstraint, m as DefaultGunshiParams, n as CliOptions, r as Command, x as LazyCommand } from "./types-CD5eRJFK.js";
|
|
2
2
|
|
|
3
3
|
//#region src/generator.d.ts
|
|
4
4
|
|