1
0
mirror of https://github.com/bitwarden/browser synced 2025-01-09 00:50:19 +01:00
bitwarden-estensione-browser/apps/cli/src/commands/completion.command.ts

120 lines
3.0 KiB
TypeScript
Raw Normal View History

2021-12-20 18:04:00 +01:00
import * as program from "commander";
import { Response } from "../models/response";
import { MessageResponse } from "../models/response/message.response";
2020-05-26 15:34:44 +02:00
interface IOption {
2021-12-20 18:04:00 +01:00
long?: string;
short?: string;
description: string;
2020-05-26 15:34:44 +02:00
}
2020-05-26 15:34:44 +02:00
interface ICommand {
2021-12-20 18:04:00 +01:00
commands?: ICommand[];
options?: IOption[];
_name: string;
_description: string;
2020-05-26 15:34:44 +02:00
}
2021-12-20 18:04:00 +01:00
const validShells = ["zsh"];
2020-05-26 15:34:44 +02:00
export class CompletionCommand {
2021-12-20 18:04:00 +01:00
async run(options: program.OptionValues) {
const shell: typeof validShells[number] = options.shell;
2020-05-26 15:34:44 +02:00
2021-12-20 18:04:00 +01:00
if (!shell) {
2022-01-19 16:45:14 +01:00
return Response.badRequest("`shell` option was not provided.");
2021-12-20 18:04:00 +01:00
}
if (!validShells.includes(shell)) {
return Response.badRequest("Unsupported shell.");
}
2020-05-26 15:34:44 +02:00
2021-12-20 18:04:00 +01:00
let content = "";
if (shell === "zsh") {
content = this.zshCompletion("bw", program as any as ICommand).render();
}
2020-05-26 15:34:44 +02:00
2021-12-20 18:04:00 +01:00
const res = new MessageResponse(content, null);
return Response.success(res);
}
private zshCompletion(rootName: string, rootCommand: ICommand) {
return {
render: () => {
return [
`#compdef _${rootName} ${rootName}`,
"",
this.renderCommandBlock(rootName, rootCommand),
].join("\n");
},
};
}
private renderCommandBlock(name: string, command: ICommand): string {
const { commands = [], options = [] } = command;
const hasOptions = options.length > 0;
const hasCommands = commands.length > 0;
const args = options
.map(({ long, short, description }) => {
const aliases = [short, long].filter(Boolean);
const opts = aliases.join(",");
const desc = `[${description.replace(`'`, `'"'"'`)}]`;
return aliases.length > 1
? `'(${aliases.join(" ")})'{${opts}}'${desc}'`
: `'${opts}${desc}'`;
})
.concat(
`'(-h --help)'{-h,--help}'[output usage information]'`,
hasCommands ? '"1: :->cmnds"' : null,
'"*::arg:->args"'
)
.filter(Boolean);
2020-05-26 15:34:44 +02:00
2021-12-20 18:04:00 +01:00
const commandBlockFunctionParts = [];
2020-05-26 15:34:44 +02:00
2021-12-20 18:04:00 +01:00
if (hasCommands) {
commandBlockFunctionParts.push("local -a commands");
2020-05-26 15:34:44 +02:00
}
2021-12-20 18:04:00 +01:00
if (hasOptions) {
commandBlockFunctionParts.push(`_arguments -C \\\n ${args.join(` \\\n `)}`);
2020-05-26 15:34:44 +02:00
}
2021-12-20 18:04:00 +01:00
if (hasCommands) {
commandBlockFunctionParts.push(
`case $state in
cmnds)
commands=(
2021-12-20 18:04:00 +01:00
${commands
.map(({ _name, _description }) => `"${_name}:${_description}"`)
.join("\n ")}
)
_describe "command" commands
;;
esac
case "$words[1]" in
2021-12-20 18:04:00 +01:00
${commands
.map(({ _name }) => [`${_name})`, `_${name}_${_name}`, ";;"].join("\n "))
.join("\n ")}
esac`
);
}
2021-12-20 18:04:00 +01:00
const commandBlocParts = [
`function _${name} {\n ${commandBlockFunctionParts.join("\n\n ")}\n}`,
];
if (hasCommands) {
commandBlocParts.push(
commands.map((c) => this.renderCommandBlock(`${name}_${c._name}`, c)).join("\n\n")
);
}
return commandBlocParts.join("\n\n");
}
}