1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 01:03:35 +00:00
Files
browser/apps/cli/src/commands/completion.command.ts
renovate[bot] 83812d471c [deps] Vault: Update commander to v11 (#7329)
* [deps] Vault: Update commander to v11

* [deps] Vault: Update commander to v11

* [deps] Vault: Update commander to v11

* [deps] Vault: Update commander to v11

* removed unused interfaces

* fix shell completions (#7756)

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: gbubemismith <gsmithwalter@gmail.com>
Co-authored-by: tangowithfoxtrot <5676771+tangowithfoxtrot@users.noreply.github.com>
Co-authored-by: SmithThe4th <gsmith@bitwarden.com>
2024-01-31 17:17:04 -05:00

108 lines
2.9 KiB
TypeScript

import { program, OptionValues, Command } from "commander";
import { Response } from "../models/response";
import { MessageResponse } from "../models/response/message.response";
const validShells = ["zsh"];
export class CompletionCommand {
async run(options: OptionValues) {
const shell: (typeof validShells)[number] = options.shell;
if (!shell) {
return Response.badRequest("`shell` option was not provided.");
}
if (!validShells.includes(shell)) {
return Response.badRequest("Unsupported shell.");
}
let content = "";
if (shell === "zsh") {
content = this.zshCompletion("bw", program).render();
}
const res = new MessageResponse(content, null);
return Response.success(res);
}
private zshCompletion(rootName: string, rootCommand: Command) {
return {
render: () => {
return [
`#compdef _${rootName} ${rootName}`,
"",
this.renderCommandBlock(rootName, rootCommand),
].join("\n");
},
};
}
private renderCommandBlock(name: string, command: Command): 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);
const commandBlockFunctionParts = [];
if (hasCommands) {
commandBlockFunctionParts.push("local -a commands");
}
if (hasOptions) {
commandBlockFunctionParts.push(`_arguments -C \\\n ${args.join(` \\\n `)}`);
}
if (hasCommands) {
commandBlockFunctionParts.push(
`case $state in
cmnds)
commands=(
${commands
.map((command) => `"${command.name().split(" ")[0]}:${command.description()}"`)
.join("\n ")}
)
_describe "command" commands
;;\n esac
case "$words[1]" in
${commands
.map((command) => {
const commandName = command.name().split(" ")[0];
return [`${commandName})`, `_${name}_${commandName}`, ";;"].join("\n ");
})
.join("\n ")}\n esac`,
);
}
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");
}
}