148 lines
5.9 KiB
JavaScript
Executable File
148 lines
5.9 KiB
JavaScript
Executable File
import { positional } from './positional';
|
|
import chalk from 'chalk';
|
|
import { createCircuitBreaker, handleCircuitBreaker } from './circuitbreaker';
|
|
import * as Result from './Result';
|
|
import didYouMean from 'didyoumean';
|
|
/**
|
|
* Combine multiple `command`s into one
|
|
*/
|
|
export function subcommands(config) {
|
|
const circuitbreaker = createCircuitBreaker(!!config.version);
|
|
const type = {
|
|
async from(str) {
|
|
const commands = Object.entries(config.cmds)
|
|
.map(([name, cmd]) => {
|
|
var _a;
|
|
return {
|
|
cmdName: name,
|
|
names: [name, ...((_a = cmd.aliases) !== null && _a !== void 0 ? _a : [])],
|
|
};
|
|
});
|
|
const cmd = commands
|
|
.find(x => x.names.includes(str));
|
|
if (cmd) {
|
|
return cmd.cmdName;
|
|
}
|
|
let errorMessage = `Not a valid subcommand name`;
|
|
const closeOptions = didYouMean(str, flatMap(commands, x => x.names));
|
|
if (closeOptions) {
|
|
const option = Array.isArray(closeOptions) ? closeOptions[0] : closeOptions;
|
|
errorMessage += `\nDid you mean ${chalk.italic(option)}?`;
|
|
}
|
|
throw new Error(errorMessage);
|
|
},
|
|
};
|
|
const subcommand = positional({
|
|
displayName: 'subcommand',
|
|
description: 'one of ' + Object.keys(config.cmds).join(', '),
|
|
type,
|
|
});
|
|
return {
|
|
version: config.version,
|
|
description: config.description,
|
|
name: config.name,
|
|
handler: value => {
|
|
const cmd = config.cmds[value.command];
|
|
return cmd.handler(value.args);
|
|
},
|
|
register(opts) {
|
|
for (const cmd of Object.values(config.cmds)) {
|
|
cmd.register(opts);
|
|
}
|
|
circuitbreaker.register(opts);
|
|
},
|
|
printHelp(context) {
|
|
var _a, _b, _c, _d;
|
|
const lines = [];
|
|
const argsSoFar = (_b = (_a = context.hotPath) === null || _a === void 0 ? void 0 : _a.join(' ')) !== null && _b !== void 0 ? _b : 'cli';
|
|
lines.push(chalk.bold(argsSoFar + chalk.italic(' <subcommand>')));
|
|
if (config.description) {
|
|
lines.push(chalk.dim('> ') + config.description);
|
|
}
|
|
lines.push('');
|
|
lines.push(`where ${chalk.italic('<subcommand>')} can be one of:`);
|
|
lines.push('');
|
|
for (const key of Object.keys(config.cmds)) {
|
|
const cmd = config.cmds[key];
|
|
let description = (_c = cmd.description) !== null && _c !== void 0 ? _c : '';
|
|
description = description && ' - ' + description + ' ';
|
|
if ((_d = cmd.aliases) === null || _d === void 0 ? void 0 : _d.length) {
|
|
const aliasTxt = cmd.aliases.length === 1 ? 'alias' : 'aliases';
|
|
const aliases = cmd.aliases.join(', ');
|
|
description += chalk.dim(`[${aliasTxt}: ${aliases}]`);
|
|
}
|
|
const row = chalk.dim('- ') + key + description;
|
|
lines.push(row.trim());
|
|
}
|
|
const helpCommand = chalk.yellow(`${argsSoFar} <subcommand> --help`);
|
|
lines.push('');
|
|
lines.push(chalk.dim(`For more help, try running \`${helpCommand}\``));
|
|
return lines.join('\n');
|
|
},
|
|
async parse(context) {
|
|
var _a, _b;
|
|
if (((_a = context.hotPath) === null || _a === void 0 ? void 0 : _a.length) === 0) {
|
|
context.hotPath.push(config.name);
|
|
}
|
|
const parsed = await subcommand.parse(context);
|
|
if (Result.isErr(parsed)) {
|
|
return Result.err({
|
|
errors: parsed.error.errors,
|
|
partialValue: {},
|
|
});
|
|
}
|
|
(_b = context.hotPath) === null || _b === void 0 ? void 0 : _b.push(parsed.value);
|
|
const cmd = config.cmds[parsed.value];
|
|
const parsedCommand = await cmd.parse(context);
|
|
if (Result.isErr(parsedCommand)) {
|
|
return Result.err({
|
|
errors: parsedCommand.error.errors,
|
|
partialValue: {
|
|
command: parsed.value,
|
|
args: parsedCommand.error.partialValue,
|
|
},
|
|
});
|
|
}
|
|
return Result.ok({
|
|
args: parsedCommand.value,
|
|
command: parsed.value,
|
|
});
|
|
},
|
|
async run(context) {
|
|
var _a, _b;
|
|
if (((_a = context.hotPath) === null || _a === void 0 ? void 0 : _a.length) === 0) {
|
|
context.hotPath.push(config.name);
|
|
}
|
|
const parsedSubcommand = await subcommand.parse(context);
|
|
if (Result.isErr(parsedSubcommand)) {
|
|
const breaker = await circuitbreaker.parse(context);
|
|
handleCircuitBreaker(context, this, breaker);
|
|
return Result.err({ ...parsedSubcommand.error, partialValue: {} });
|
|
}
|
|
(_b = context.hotPath) === null || _b === void 0 ? void 0 : _b.push(parsedSubcommand.value);
|
|
const cmd = config.cmds[parsedSubcommand.value];
|
|
const commandRun = await cmd.run(context);
|
|
if (Result.isOk(commandRun)) {
|
|
return Result.ok({
|
|
command: parsedSubcommand.value,
|
|
value: commandRun.value,
|
|
});
|
|
}
|
|
return Result.err({
|
|
...commandRun.error,
|
|
partialValue: {
|
|
command: parsedSubcommand.value,
|
|
value: commandRun.error.partialValue,
|
|
},
|
|
});
|
|
},
|
|
};
|
|
}
|
|
function flatMap(array, f) {
|
|
const rs = [];
|
|
for (const item of array) {
|
|
rs.push(...f(item));
|
|
}
|
|
return rs;
|
|
}
|
|
//# sourceMappingURL=subcommands.js.map
|