@clerc/plugin-completions
Version:
Clerc plugin completions
135 lines (124 loc) • 4.24 kB
JavaScript
import { definePlugin } from '@clerc/core';
import { gracefulFlagName, kebabCase } from '@clerc/utils';
const generateCommandCompletion = (name) => `
${name})
cmd+="__${name}"
;;`;
function getBashCompletion(ctx) {
const { cli } = ctx;
const { _scriptName: name, _commands: commands } = cli;
return `_${name}() {
local i cur prev opts cmds
COMPREPLY=()
cur="\${COMP_WORDS[COMP_CWORD]}"
prev="\${COMP_WORDS[COMP_CWORD-1]}"
cmd=""
opts=""
for i in \${COMP_WORDS[@]}
do
case "\${i}" in
"$1")
cmd="${name}"
;;
${Object.keys(commands).map(generateCommandCompletion).join("")}
*)
;;
esac
done
}
complete -F _${name} -o bashdefault -o default ${name}
`;
}
const NO_DESCRIPTION = "(No Description)";
const getCompletionValue = (command) => `[CompletionResult]::new('${command.name}', '${command.name}', [CompletionResultType]::ParameterValue, '${command.description}')`;
const getCompletionFlag = (command) => {
var _a;
return Object.entries((_a = command.flags) != null ? _a : {}).map(([flagName, flag]) => {
const gen = [
`[CompletionResult]::new('${gracefulFlagName(flagName)}', '${kebabCase(
flagName
)}', [CompletionResultType]::ParameterName, '${command.flags[flagName].description || NO_DESCRIPTION}')`
];
if (flag == null ? void 0 : flag.alias) {
gen.push(
`[CompletionResult]::new('${gracefulFlagName(flag.alias)}', '${flag.alias}', [CompletionResultType]::ParameterName, '${command.flags[flagName].description || NO_DESCRIPTION}')`
);
}
return gen.join("\n ");
}).join("\n ");
};
function getPwshCompletion(ctx) {
const { cli } = ctx;
const { _scriptName: name, _commands: commands } = cli;
return `using namespace System.Management.Automation
using namespace System.Management.Automation.Language
Register-ArgumentCompleter -Native -CommandName '${name}' -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
$commandElements = $commandAst.CommandElements
$command = @(
'${name}'
for ($i = 1; $i -lt $commandElements.Count; $i++) {
$element = $commandElements[$i]
if ($element -isnot [StringConstantExpressionAst] -or
$element.StringConstantType -ne [StringConstantType]::BareWord -or
$element.Value.StartsWith('-') -or
$element.Value -eq $wordToComplete) {
break
}
$element.Value
}) -join ';'
$completions = @(switch ($command) {
'${name}' {
${Object.entries(commands).map(([_, command]) => getCompletionValue(command)).join("\n ")}
break
}
${Object.entries(commands).map(
([commandName, command]) => `'${name};${commandName.split(" ").join(";")}' {
${getCompletionFlag(command)}
break
}`
).join("\n ")}
})
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
Sort-Object -Property ListItemText
}`;
}
const completionMap = {
bash: getBashCompletion,
pwsh: getPwshCompletion
};
const completionsPlugin = (options = {}) => definePlugin({
setup: (cli) => {
const { command = true } = options;
if (command) {
cli = cli.command("completions", "Print shell completions to stdout", {
flags: {
shell: {
description: "Shell type",
type: String,
default: ""
}
},
parameters: ["[shell]"]
}).on("completions", (ctx) => {
var _a;
if (!cli._scriptName) {
throw new Error("CLI name is not defined!");
}
const shell = String((_a = ctx.parameters.shell) != null ? _a : ctx.flags.shell);
if (!shell) {
throw new Error("Missing shell name");
}
if (shell in completionMap) {
process.stdout.write(
completionMap[shell](ctx)
);
} else {
throw new Error(`No such shell: ${shell}`);
}
});
}
return cli;
}
});
export { completionsPlugin };