使用 --experimental-specifier-resolution=node 时如何让 yargs 自动完成工作
How to get yargs auto-complete working, when using --experimental-specifier-resolution=node
我的 objective 是用 Typescript/node.js 编写一个 CLI,它使用 --experimental-specifier-resolution=node
,用 yargs 编写,支持自动完成。
为了完成这项工作,我使用了这个 entry.sh
文件,感谢这个有用的 (package.json 中的 bin: {eddy: "./entry.sh"}
选项指向这个文件)
#!/usr/bin/env bash
full_path=$(realpath [=10=])
dir_path=$(dirname $full_path)
script_path="$dir_path/dist/src/cli/entry.js"
# Path is made thanks to: https://code-maven.com/bash-shell-relative-path
# Combined with knowledge from:
/usr/bin/env node --experimental-specifier-resolution=node $script_path "$@"
效果很好,我可以使用 CLI。但是,自动完成不起作用。根据 yargs,我应该能够通过将 ./entry.sh completion
的结果输出到 ~/.bashrc
配置文件来获得自动完成功能。然而,这似乎不起作用。
来自./entry.sh completion
的输出:
###-begin-entry.js-completions-###
#
# yargs command completion script
#
# Installation: ./dist/src/cli/entry.js completion >> ~/.bashrc
# or ./dist/src/cli/entry.js completion >> ~/.bash_profile on OSX.
#
_entry.js_yargs_completions()
{
local cur_word args type_list
cur_word="${COMP_WORDS[COMP_CWORD]}"
args=("${COMP_WORDS[@]}")
# ask yargs to generate completions.
type_list=$(./dist/src/cli/entry.js --get-yargs-completions "${args[@]}")
COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) )
# if no match was found, fall back to filename completion
if [ ${#COMPREPLY[@]} -eq 0 ]; then
COMPREPLY=()
fi
return 0
}
complete -o default -F _entry.js_yargs_completions entry.js
###-end-entry.js-completions-###
我尝试修改 completion
输出,但我不太明白 bash - 只是
更新
正在研究可重现的示例 (WIP)。
回购是 here.
目前最大的区别之一是 npm link
在 2 个不同的环境中的工作方式不同。只有在我试图重现 /usr/local/share/npm-global/bin/
的回购协议中才实际更新。目前正试图对此进行调查。
您可以尝试将 entry.js
文件中的 scriptName 指定为包装脚本的名称。这可能会强制使用它生成完成名称。我没有尝试过,但是查看 yargs 的源代码,看起来 [=17=]
参数可以使用 scriptName
进行更改,这反过来会影响完成生成函数如何生成完成代码:
在yargs-factor.ts
中:
scriptName(scriptName: string): YargsInstance {
this.customScriptName = true;
this.[=10=] = scriptName;
return this;
}
在completion.ts
中:
generateCompletionScript([=11=]: string, cmd: string): string {
let script = this.zshShell
? templates.completionZshTemplate
: templates.completionShTemplate;
const name = this.shim.path.basename([=11=]);
// add ./ to applications not yet installed as bin.
if ([=11=].match(/\.js$/)) [=11=] = `./${[=11=]}`;
script = script.replace(/{{app_name}}/g, name);
script = script.replace(/{{completion_command}}/g, cmd);
return script.replace(/{{app_path}}/g, [=11=]);
}
我也不确定 "bin"
配置如何工作,但可能是因为 scriptName
你不再需要包装器。
确保您使用的 yargs 版本支持此功能。
此外,作为旁注,我考虑过建议直接修改生成的完成脚本,但除了骇人听闻之外,还可能导致脚本名称在完成过程中无法识别。无论如何,我只是先看看正确的方法。
修改后的版本是这样的:
_entry.sh_yargs_completions()
{
local cur_word args type_list
cur_word="${COMP_WORDS[COMP_CWORD]}"
args=("${COMP_WORDS[@]}")
# ask yargs to generate completions.
type_list=$(/path/to/entry.sh --get-yargs-completions "${args[@]}")
COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) )
# if no match was found, fall back to filename completion
if [ ${#COMPREPLY[@]} -eq 0 ]; then
COMPREPLY=()
fi
return 0
}
complete -o default -F _entry.sh_yargs_completions entry.sh
另请注意:如果脚本名称需要根据其调用者的名称动态变化,您可以通过环境变量使其可识别,因此在entry.sh
中您可以这样声明:
export ENTRY_JS_SCRIPT_NAME=entry.sh
node ...
然后在entry.js
的某个地方,你可以通过这个访问变量名:
process.env.ENTRY_JS_SCRIPT_NAME
甚至可以指定 [=17=]
或 ${0##*/}
任何有效的方法:
export ENTRY_JS_SCRIPT_NAME=[=15=]
谢谢大家。我最终得到的解决方案是 2 倍:
- 我在 yargs 配置中添加了
scriptName
- 在
.sh
文件“wrapping”中,我使用 which node
大概设置了 --experimental-specifier-resolution=node
标志。
测试-cli.js
#!/usr/bin/env node
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import { someOtherModule } from './some-other-module';
someOtherModule();
yargs(hideBin(process.argv))
.command('curl <url>', 'fetch the contents of the URL', () => {}, (argv) => {
console.info(argv)
})
.command('curlAgain <url>', 'fetch the contents of the URL', () => {}, (argv) => {
console.info(argv)
})
.demandCommand(1)
.help()
.completion()
.scriptName('eddy') // <== Added thanks to konsolebox
.parse()
测试-cli.sh
#!/usr/bin/env bash
full_path="$(realpath "[=11=]")"
dir_path="$(dirname $full_path)"
script_path="$dir_path/test-cli.js"
node_path="$(which node)" # <== Makes it work on github codespaces
$node_path --experimental-specifier-resolution=node $script_path "$@"
package.json
{
"name": "lets-reproduce",
"type": "module",
"dependencies": {
"yargs": "^17.3.1"
},
"bin": {
"eddy": "./test-cli.sh"
}
}
安装自动补全的步骤:
- 运行
npm link
- 运行
eddy completion >> ~/.bashrc
source ~/.bashrc
- 利润
我的 objective 是用 Typescript/node.js 编写一个 CLI,它使用 --experimental-specifier-resolution=node
,用 yargs 编写,支持自动完成。
为了完成这项工作,我使用了这个 entry.sh
文件,感谢这个有用的 bin: {eddy: "./entry.sh"}
选项指向这个文件)
#!/usr/bin/env bash
full_path=$(realpath [=10=])
dir_path=$(dirname $full_path)
script_path="$dir_path/dist/src/cli/entry.js"
# Path is made thanks to: https://code-maven.com/bash-shell-relative-path
# Combined with knowledge from:
/usr/bin/env node --experimental-specifier-resolution=node $script_path "$@"
效果很好,我可以使用 CLI。但是,自动完成不起作用。根据 yargs,我应该能够通过将 ./entry.sh completion
的结果输出到 ~/.bashrc
配置文件来获得自动完成功能。然而,这似乎不起作用。
来自./entry.sh completion
的输出:
###-begin-entry.js-completions-###
#
# yargs command completion script
#
# Installation: ./dist/src/cli/entry.js completion >> ~/.bashrc
# or ./dist/src/cli/entry.js completion >> ~/.bash_profile on OSX.
#
_entry.js_yargs_completions()
{
local cur_word args type_list
cur_word="${COMP_WORDS[COMP_CWORD]}"
args=("${COMP_WORDS[@]}")
# ask yargs to generate completions.
type_list=$(./dist/src/cli/entry.js --get-yargs-completions "${args[@]}")
COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) )
# if no match was found, fall back to filename completion
if [ ${#COMPREPLY[@]} -eq 0 ]; then
COMPREPLY=()
fi
return 0
}
complete -o default -F _entry.js_yargs_completions entry.js
###-end-entry.js-completions-###
我尝试修改 completion
输出,但我不太明白 bash - 只是
更新
正在研究可重现的示例 (WIP)。 回购是 here.
目前最大的区别之一是 npm link
在 2 个不同的环境中的工作方式不同。只有在我试图重现 /usr/local/share/npm-global/bin/
的回购协议中才实际更新。目前正试图对此进行调查。
您可以尝试将 entry.js
文件中的 scriptName 指定为包装脚本的名称。这可能会强制使用它生成完成名称。我没有尝试过,但是查看 yargs 的源代码,看起来 [=17=]
参数可以使用 scriptName
进行更改,这反过来会影响完成生成函数如何生成完成代码:
在yargs-factor.ts
中:
scriptName(scriptName: string): YargsInstance {
this.customScriptName = true;
this.[=10=] = scriptName;
return this;
}
在completion.ts
中:
generateCompletionScript([=11=]: string, cmd: string): string {
let script = this.zshShell
? templates.completionZshTemplate
: templates.completionShTemplate;
const name = this.shim.path.basename([=11=]);
// add ./ to applications not yet installed as bin.
if ([=11=].match(/\.js$/)) [=11=] = `./${[=11=]}`;
script = script.replace(/{{app_name}}/g, name);
script = script.replace(/{{completion_command}}/g, cmd);
return script.replace(/{{app_path}}/g, [=11=]);
}
我也不确定 "bin"
配置如何工作,但可能是因为 scriptName
你不再需要包装器。
确保您使用的 yargs 版本支持此功能。
此外,作为旁注,我考虑过建议直接修改生成的完成脚本,但除了骇人听闻之外,还可能导致脚本名称在完成过程中无法识别。无论如何,我只是先看看正确的方法。
修改后的版本是这样的:
_entry.sh_yargs_completions()
{
local cur_word args type_list
cur_word="${COMP_WORDS[COMP_CWORD]}"
args=("${COMP_WORDS[@]}")
# ask yargs to generate completions.
type_list=$(/path/to/entry.sh --get-yargs-completions "${args[@]}")
COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) )
# if no match was found, fall back to filename completion
if [ ${#COMPREPLY[@]} -eq 0 ]; then
COMPREPLY=()
fi
return 0
}
complete -o default -F _entry.sh_yargs_completions entry.sh
另请注意:如果脚本名称需要根据其调用者的名称动态变化,您可以通过环境变量使其可识别,因此在entry.sh
中您可以这样声明:
export ENTRY_JS_SCRIPT_NAME=entry.sh
node ...
然后在entry.js
的某个地方,你可以通过这个访问变量名:
process.env.ENTRY_JS_SCRIPT_NAME
甚至可以指定 [=17=]
或 ${0##*/}
任何有效的方法:
export ENTRY_JS_SCRIPT_NAME=[=15=]
谢谢大家。我最终得到的解决方案是 2 倍:
- 我在 yargs 配置中添加了
scriptName
- 在
.sh
文件“wrapping”中,我使用which node
大概设置了--experimental-specifier-resolution=node
标志。
测试-cli.js
#!/usr/bin/env node
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import { someOtherModule } from './some-other-module';
someOtherModule();
yargs(hideBin(process.argv))
.command('curl <url>', 'fetch the contents of the URL', () => {}, (argv) => {
console.info(argv)
})
.command('curlAgain <url>', 'fetch the contents of the URL', () => {}, (argv) => {
console.info(argv)
})
.demandCommand(1)
.help()
.completion()
.scriptName('eddy') // <== Added thanks to konsolebox
.parse()
测试-cli.sh
#!/usr/bin/env bash
full_path="$(realpath "[=11=]")"
dir_path="$(dirname $full_path)"
script_path="$dir_path/test-cli.js"
node_path="$(which node)" # <== Makes it work on github codespaces
$node_path --experimental-specifier-resolution=node $script_path "$@"
package.json
{
"name": "lets-reproduce",
"type": "module",
"dependencies": {
"yargs": "^17.3.1"
},
"bin": {
"eddy": "./test-cli.sh"
}
}
安装自动补全的步骤:
- 运行
npm link
- 运行
eddy completion >> ~/.bashrc
source ~/.bashrc
- 利润