nest-commander
Version:
A module for making CLI applications with NestJS. Decorators for running commands and separating out config parsers included. This package works on top of commander.
139 lines • 6.05 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompletionFactory = void 0;
const commander_1 = require("commander");
const constants_1 = require("./constants");
/**
* @description Factory to generate completion script for BASH and ZSH
*/
class CompletionFactory {
/**
* @description Register the completion command for either Bash, ZSH or Fig
* @usage
* ### Fig completion
* Applying new command to generate the completion spec
* @see https://fig.io/docs/guides/private-autocomplete
*
* @see https://fig.io/docs/guides/autocomplete-for-internal-tools
*
* ### Bash & ZSH completion
* Put this script in your .bashrc or .zshrc
* ```bash
* source <(YOUR-CLI-NAMESPACE completion-script)
* ```
* @param options - {@link CompletionFactoryOptions}
*/
static async registerCompletionCommand(app, options) {
const commander = app.get(constants_1.Commander);
const parsedOptions = CompletionFactory.getOptions(options);
const { cmd } = parsedOptions;
if (!cmd) {
throw new Error('cmd is required');
}
if (parsedOptions.nativeShell) {
const { executablePath } = parsedOptions.nativeShell;
CompletionFactory.setupNativeShellCompletion(commander, cmd, executablePath);
}
if (parsedOptions.fig) {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { addCompletionSpecCommand } = require('@fig/complete-commander');
addCompletionSpecCommand(commander);
}
catch (_a) {
throw new Error(`There was a problem creating the fig completion. Did you make sure to install "@fig/complete-commander"?`);
}
}
}
static getOptions(options) {
const parsedOptions = Object.assign({ fig: false, nativeShell: false }, options);
return parsedOptions;
}
static setupNativeShellCompletion(commander, cmd, executablePath) {
var _a, _b;
const isZsh = (_b = (_a = process.env.SHELL) === null || _a === void 0 ? void 0 : _a.includes('zsh')) !== null && _b !== void 0 ? _b : false;
const script = CompletionFactory.generateCompletionScript(executablePath, cmd, cmd, isZsh);
const completionScriptCommand = new commander_1.Command()
.command('completion-script', { hidden: true })
.action(() => {
console.log(script);
});
const completionCommand = new commander_1.Command()
.command('completion', { hidden: true })
.action(() => {
var _a;
// @ts-expect-error - _prepareUserArgs is not a public property
const _prepareUserArgs = commander._prepareUserArgs(process.argv);
const parsed = commander.parseOptions(_prepareUserArgs);
const { operands } = parsed;
const filteredOperands = operands.filter((operand) => !['completion', cmd].includes(operand));
const [firstCommandName, ...restOperands] = filteredOperands;
const firstCommand =
// @ts-expect-error - _findCommand is not a public property
(_a = commander._findCommand(firstCommandName)) !== null && _a !== void 0 ? _a : commander;
const lastKnownCommand = restOperands.reduce((acc, operand) => {
var _a;
// @ts-expect-error - _findCommand is not a public property
return (_a = acc === null || acc === void 0 ? void 0 : acc._findCommand(operand)) !== null && _a !== void 0 ? _a : acc;
}, firstCommand);
const completions = CompletionFactory.getCompletion(lastKnownCommand);
console.log(completions.join('\n'));
});
commander.addCommand(completionCommand);
commander.addCommand(completionScriptCommand);
}
static generateCompletionScript(executablePath, cliName, command, isZsh) {
let scriptTemplate = isZsh
? constants_1.COMPLETION_ZSH_TEMPLATE
: constants_1.COMPLETION_SH_TEMPLATE;
// apply ./ execution prefix if the executable path is a js file
if (executablePath.match(/\.js$/)) {
executablePath = `./${executablePath}`;
}
scriptTemplate = scriptTemplate.replace(/{{app_name}}/g, cliName);
scriptTemplate = scriptTemplate.replace(/{{completion_command}}/g, command);
scriptTemplate = scriptTemplate.replace(/{{app_path}}/g, executablePath);
return scriptTemplate;
}
static defaultCompletion(command) {
const completions = [];
if (!command) {
return [];
}
CompletionFactory.commandCompletions(completions, command);
CompletionFactory.optionCompletions(completions, command);
return completions;
}
static commandCompletions(completions, command) {
const { commands } = command;
for (const subcommand of commands) {
// @ts-expect-error - _hidden is not a public property
if (subcommand._hidden) {
continue;
}
completions.push(subcommand.name());
}
}
static optionCompletions(completions, command) {
var _a;
const { options } = command;
for (const option of options) {
if (option.hidden) {
continue;
}
const key = (_a = option.long) !== null && _a !== void 0 ? _a : option.short;
if (!key) {
continue;
}
completions.push(key);
}
}
static getCompletion(command) {
const defaultCompletion = CompletionFactory.defaultCompletion(command);
const unique = new Set([...defaultCompletion, '--help']);
const res = Array.from(unique);
return res;
}
}
exports.CompletionFactory = CompletionFactory;
//# sourceMappingURL=completion.factory.js.map
;