From 7e3b5b1a13922dadc5acd73fa0b00ba6622aad0d Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Mon, 12 Jun 2023 13:54:04 +0200 Subject: [PATCH] chore: update clap (#19467) Also switches to use defer for all subcommands besides run. --- Cargo.lock | 93 +++- cli/Cargo.toml | 6 +- cli/args/flags.rs | 1308 +++++++++++++++++++++++---------------------- 3 files changed, 747 insertions(+), 660 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fca7aff20..edb0a6e124 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,55 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "anyhow" version = "1.0.70" @@ -474,31 +523,40 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.10" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce38afc168d8665cfc75c7b1dd9672e50716a137f433f070991619744a67342a" +checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" +dependencies = [ + "anstream", + "anstyle", "bitflags 1.3.2", "clap_lex", - "is-terminal", "strsim", - "termcolor", ] [[package]] name = "clap_complete" -version = "4.1.5" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37686beaba5ac9f3ab01ee3172f792fc6ffdd685bfb9e63cfef02c0571a4e8e1" +checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b" dependencies = [ "clap", ] [[package]] name = "clap_complete_fig" -version = "4.1.2" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2171bc6242ad7a1801422bff039574449b5bd832b715222e500714ce10f91a54" +checksum = "99fee1d30a51305a6c2ed3fc5709be3c8af626c9c958e04dd9ae94e27bcbce9f" dependencies = [ "clap", "clap_complete", @@ -506,12 +564,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "clipboard-win" @@ -524,6 +579,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "console_static_text" version = "0.8.1" @@ -3219,12 +3280,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "output_vt100" version = "0.1.3" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 34720bbcc0..fe9f358445 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -60,9 +60,9 @@ base32 = "=0.4.0" base64.workspace = true cache_control.workspace = true chrono = { version = "=0.4.22", default-features = false, features = ["std"] } -clap = { version = "=4.1.10", features = ["string"] } -clap_complete = "=4.1.5" -clap_complete_fig = "=4.1.2" +clap = { version = "=4.3.3", features = ["string"] } +clap_complete = "=4.3.1" +clap_complete_fig = "=4.3.1" console_static_text.workspace = true data-url.workspace = true dissimilar = "=1.0.4" diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 2e4d826f92..837bfe3159 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -759,76 +759,80 @@ fn clap_root() -> Command { .action(ArgAction::SetTrue) .global(true), ) - .subcommand(bench_subcommand()) - .subcommand(bundle_subcommand()) - .subcommand(cache_subcommand()) - .subcommand(check_subcommand()) - .subcommand(compile_subcommand()) - .subcommand(completions_subcommand()) - .subcommand(coverage_subcommand()) - .subcommand(doc_subcommand()) - .subcommand(eval_subcommand()) - .subcommand(fmt_subcommand()) - .subcommand(init_subcommand()) - .subcommand(info_subcommand()) - .subcommand(install_subcommand()) - .subcommand(uninstall_subcommand()) - .subcommand(lsp_subcommand()) - .subcommand(lint_subcommand()) - .subcommand(repl_subcommand()) .subcommand(run_subcommand()) - .subcommand(task_subcommand()) - .subcommand(test_subcommand()) - .subcommand(types_subcommand()) - .subcommand(upgrade_subcommand()) - .subcommand(vendor_subcommand()) + .defer(|cmd| { + cmd + .subcommand(bench_subcommand()) + .subcommand(bundle_subcommand()) + .subcommand(cache_subcommand()) + .subcommand(check_subcommand()) + .subcommand(compile_subcommand()) + .subcommand(completions_subcommand()) + .subcommand(coverage_subcommand()) + .subcommand(doc_subcommand()) + .subcommand(eval_subcommand()) + .subcommand(fmt_subcommand()) + .subcommand(init_subcommand()) + .subcommand(info_subcommand()) + .subcommand(install_subcommand()) + .subcommand(uninstall_subcommand()) + .subcommand(lsp_subcommand()) + .subcommand(lint_subcommand()) + .subcommand(repl_subcommand()) + .subcommand(task_subcommand()) + .subcommand(test_subcommand()) + .subcommand(types_subcommand()) + .subcommand(upgrade_subcommand()) + .subcommand(vendor_subcommand()) + }) .long_about(DENO_HELP) .after_help(ENV_VARIABLES_HELP) } fn bench_subcommand() -> Command { - runtime_args(Command::new("bench"), true, false) - .arg(check_arg(true)) - .arg( - Arg::new("json") - .long("json") - .action(ArgAction::SetTrue) - .help("UNSTABLE: Output benchmark result in JSON format"), - ) - .arg( - Arg::new("ignore") - .long("ignore") - .num_args(1..) - .use_value_delimiter(true) - .require_equals(true) - .help("Ignore files") - .value_parser(value_parser!(PathBuf)), - ) - .arg( - Arg::new("filter") - .long("filter") - .allow_hyphen_values(true) - .help("Run benchmarks with this string or pattern in the bench name"), - ) - .arg( - Arg::new("files") - .help("List of file names to run") - .num_args(..) - .value_parser(value_parser!(PathBuf)) - .action(ArgAction::Append), - ) - .arg( - Arg::new("no-run") - .long("no-run") - .help("Cache bench modules, but don't run benchmarks") - .action(ArgAction::SetTrue), - ) - .arg(watch_arg(false)) - .arg(no_clear_screen_arg()) - .arg(script_arg().last(true)) - .about("Run benchmarks") - .long_about( - "Run benchmarks using Deno's built-in bench tool. + Command::new("bench").defer(|cmd| { + runtime_args(cmd, true, false) + .arg(check_arg(true)) + .arg( + Arg::new("json") + .long("json") + .action(ArgAction::SetTrue) + .help("UNSTABLE: Output benchmark result in JSON format"), + ) + .arg( + Arg::new("ignore") + .long("ignore") + .num_args(1..) + .use_value_delimiter(true) + .require_equals(true) + .help("Ignore files") + .value_parser(value_parser!(PathBuf)), + ) + .arg( + Arg::new("filter") + .long("filter") + .allow_hyphen_values(true) + .help("Run benchmarks with this string or pattern in the bench name"), + ) + .arg( + Arg::new("files") + .help("List of file names to run") + .num_args(..) + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Append), + ) + .arg( + Arg::new("no-run") + .long("no-run") + .help("Cache bench modules, but don't run benchmarks") + .action(ArgAction::SetTrue), + ) + .arg(watch_arg(false)) + .arg(no_clear_screen_arg()) + .arg(script_arg().last(true)) + .about("Run benchmarks") + .long_about( + "Run benchmarks using Deno's built-in bench tool. Evaluate the given modules, run all benches declared with 'Deno.bench()' and report results to standard output: @@ -839,50 +843,54 @@ Directory arguments are expanded to all contained files matching the glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: deno bench src/", - ) + ) + }) } fn bundle_subcommand() -> Command { - compile_args(Command::new("bundle")) - .hide(true) - .arg(check_arg(true)) - .arg( - Arg::new("source_file") - .required(true) - .value_hint(ValueHint::FilePath), - ) - .arg( - Arg::new("out_file") - .value_parser(value_parser!(PathBuf)) - .value_hint(ValueHint::FilePath), - ) - .arg(watch_arg(false)) - .arg(no_clear_screen_arg()) - .arg(executable_ext_arg()) - .about("Bundle module and dependencies into single file") - .long_about( - "Output a single JavaScript file with all dependencies. + Command::new("bundle").defer(|cmd| { + compile_args(cmd) + .hide(true) + .arg(check_arg(true)) + .arg( + Arg::new("source_file") + .required(true) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("out_file") + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::FilePath), + ) + .arg(watch_arg(false)) + .arg(no_clear_screen_arg()) + .arg(executable_ext_arg()) + .about("Bundle module and dependencies into single file") + .long_about( + "Output a single JavaScript file with all dependencies. deno bundle https://deno.land/std/examples/colors.ts colors.bundle.js If no output file is given, the output is written to standard output: deno bundle https://deno.land/std/examples/colors.ts", - ) + ) + }) } fn cache_subcommand() -> Command { - compile_args(Command::new("cache")) - .arg(check_arg(false)) - .arg( - Arg::new("file") - .num_args(1..) - .required(true) - .value_hint(ValueHint::FilePath), - ) - .about("Cache the dependencies") - .long_about( - "Cache and compile remote dependencies recursively. + Command::new("cache").defer(|cmd| { + compile_args(cmd) + .arg(check_arg(false)) + .arg( + Arg::new("file") + .num_args(1..) + .required(true) + .value_hint(ValueHint::FilePath), + ) + .about("Cache the dependencies") + .long_about( + "Cache and compile remote dependencies recursively. Download and compile a module with all of its static dependencies and save them in the local cache, without running any code: @@ -891,83 +899,85 @@ them in the local cache, without running any code: Future runs of this module will trigger no downloads or compilation unless --reload is specified.", - ) + ) + }) } fn check_subcommand() -> Command { - compile_args_without_check_args(Command::new("check")) - .arg( + Command::new("check") + .defer(|cmd| compile_args_without_check_args(cmd).arg( Arg::new("all") .long("all") .help("Type-check all code, including remote modules and npm packages") .action(ArgAction::SetTrue) .conflicts_with("no-remote") ) - .arg( - // past alias for --all - Arg::new("remote") - .long("remote") - .help("Type-check all modules, including remote") - .action(ArgAction::SetTrue) - .conflicts_with("no-remote") - .hide(true) + .arg( + // past alias for --all + Arg::new("remote") + .long("remote") + .help("Type-check all modules, including remote") + .action(ArgAction::SetTrue) + .conflicts_with("no-remote") + .hide(true) ) - .arg( - Arg::new("file") - .num_args(1..) - .required(true) - .value_hint(ValueHint::FilePath), - ) - .about("Type-check the dependencies") - .long_about( - "Download and type-check without execution. + .arg( + Arg::new("file") + .num_args(1..) + .required(true) + .value_hint(ValueHint::FilePath), + ) + .about("Type-check the dependencies") + .long_about( + "Download and type-check without execution. deno check https://deno.land/std/http/file_server.ts Unless --reload is specified, this command will not re-download already cached dependencies.", - ) + )) } fn compile_subcommand() -> Command { - runtime_args(Command::new("compile"), true, false) - .arg(script_arg().required(true)) - .arg(check_arg(true)) - .arg( - Arg::new("include") - .long("include") - .help("UNSTABLE: Additional module to include in the module graph") - .long_help( - "Includes an additional module in the compiled executable's module + Command::new("compile").defer(|cmd| { + runtime_args(cmd, true, false) + .arg(script_arg().required(true)) + .arg(check_arg(true)) + .arg( + Arg::new("include") + .long("include") + .help("UNSTABLE: Additional module to include in the module graph") + .long_help( + "Includes an additional module in the compiled executable's module graph. Use this flag if a dynamically imported module or a web worker main module fails to load in the executable. This flag can be passed multiple times, to include multiple additional modules.", - ) - .action(ArgAction::Append) - .value_hint(ValueHint::FilePath), - ) - .arg( - Arg::new("output") - .long("output") - .short('o') - .value_parser(value_parser!(PathBuf)) - .help("Output file (defaults to $PWD/)") - .value_hint(ValueHint::FilePath), - ) - .arg( - Arg::new("target") - .long("target") - .help("Target OS architecture") - .value_parser([ - "x86_64-unknown-linux-gnu", - "x86_64-pc-windows-msvc", - "x86_64-apple-darwin", - "aarch64-apple-darwin", - ]), - ) - .arg(executable_ext_arg()) - .about("UNSTABLE: Compile the script into a self contained executable") - .long_about( - "UNSTABLE: Compiles the given script into a self contained executable. + ) + .action(ArgAction::Append) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("output") + .long("output") + .short('o') + .value_parser(value_parser!(PathBuf)) + .help("Output file (defaults to $PWD/)") + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("target") + .long("target") + .help("Target OS architecture") + .value_parser([ + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "x86_64-apple-darwin", + "aarch64-apple-darwin", + ]), + ) + .arg(executable_ext_arg()) + .about("UNSTABLE: Compile the script into a self contained executable") + .long_about( + "UNSTABLE: Compiles the given script into a self contained executable. deno compile -A https://deno.land/std/http/file_server.ts deno compile --output color_util https://deno.land/std/examples/colors.ts @@ -987,31 +997,35 @@ Cross-compiling to different target architectures is supported using the binary and cache it in $DENO_DIR. The aarch64-apple-darwin target is not supported in canary. ", - ) + ) + }) } fn completions_subcommand() -> Command { - Command::new("completions") - .disable_help_subcommand(true) - .arg( - Arg::new("shell") - .value_parser(["bash", "fish", "powershell", "zsh", "fig"]) - .required(true), - ) - .about("Generate shell completions") - .long_about( - "Output shell completion script to standard output. + Command::new("completions").defer(|cmd| { + cmd + .disable_help_subcommand(true) + .arg( + Arg::new("shell") + .value_parser(["bash", "fish", "powershell", "zsh", "fig"]) + .required(true), + ) + .about("Generate shell completions") + .long_about( + "Output shell completion script to standard output. deno completions bash > /usr/local/etc/bash_completion.d/deno.bash source /usr/local/etc/bash_completion.d/deno.bash", - ) + ) + }) } fn coverage_subcommand() -> Command { - Command::new("coverage") - .about("Print coverage reports") - .long_about( - "Print coverage reports from coverage profiles. + Command::new("coverage").defer(|cmd| { + cmd + .about("Print coverage reports") + .long_about( + "Print coverage reports from coverage profiles. Collect a coverage profile with deno test: @@ -1043,71 +1057,73 @@ Generate html reports from lcov: genhtml -o html_cov cov.lcov ", - ) - .arg( - Arg::new("ignore") - .long("ignore") - .num_args(1..) - .use_value_delimiter(true) - .require_equals(true) - .help("Ignore coverage files") - .value_hint(ValueHint::AnyPath), - ) - .arg( - Arg::new("include") - .long("include") - .num_args(1..) - .action(ArgAction::Append) - .value_name("regex") - .require_equals(true) - .default_value(r"^file:") - .help("Include source files in the report"), - ) - .arg( - Arg::new("exclude") - .long("exclude") - .num_args(1..) - .action(ArgAction::Append) - .value_name("regex") - .require_equals(true) - .default_value(r"test\.(js|mjs|ts|jsx|tsx)$") - .help("Exclude source files from the report"), - ) - .arg( - Arg::new("lcov") - .long("lcov") - .help("Output coverage report in lcov format") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("output") - .requires("lcov") - .long("output") - .value_parser(value_parser!(PathBuf)) - .help("Output file (defaults to stdout) for lcov") - .long_help( - "Exports the coverage report in lcov format to the given file. + ) + .arg( + Arg::new("ignore") + .long("ignore") + .num_args(1..) + .use_value_delimiter(true) + .require_equals(true) + .help("Ignore coverage files") + .value_hint(ValueHint::AnyPath), + ) + .arg( + Arg::new("include") + .long("include") + .num_args(1..) + .action(ArgAction::Append) + .value_name("regex") + .require_equals(true) + .default_value(r"^file:") + .help("Include source files in the report"), + ) + .arg( + Arg::new("exclude") + .long("exclude") + .num_args(1..) + .action(ArgAction::Append) + .value_name("regex") + .require_equals(true) + .default_value(r"test\.(js|mjs|ts|jsx|tsx)$") + .help("Exclude source files from the report"), + ) + .arg( + Arg::new("lcov") + .long("lcov") + .help("Output coverage report in lcov format") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("output") + .requires("lcov") + .long("output") + .value_parser(value_parser!(PathBuf)) + .help("Output file (defaults to stdout) for lcov") + .long_help( + "Exports the coverage report in lcov format to the given file. Filename should be passed along with '=' For example '--output=foo.lcov' If no --output arg is specified then the report is written to stdout.", - ) - .require_equals(true) - .value_hint(ValueHint::FilePath), - ) - .arg( - Arg::new("files") - .num_args(1..) - .value_parser(value_parser!(PathBuf)) - .action(ArgAction::Append) - .required(true) - .value_hint(ValueHint::AnyPath), - ) + ) + .require_equals(true) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("files") + .num_args(1..) + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Append) + .required(true) + .value_hint(ValueHint::AnyPath), + ) + }) } fn doc_subcommand() -> Command { - Command::new("doc") - .about("Show documentation for a module") - .long_about( - "Show documentation for a module. + Command::new("doc").defer(|cmd| { + cmd + .about("Show documentation for a module") + .long_about( + "Show documentation for a module. Output documentation to standard output: @@ -1129,44 +1145,46 @@ Show documentation for runtime built-ins: deno doc deno doc --builtin Deno.Listener", - ) - .arg(import_map_arg()) - .arg(reload_arg()) - .arg(lock_arg()) - .arg(no_lock_arg()) - .arg(no_npm_arg()) - .arg(no_remote_arg()) - .arg( - Arg::new("json") - .long("json") - .help("Output documentation in JSON format") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("private") - .long("private") - .help("Output private documentation") - .action(ArgAction::SetTrue), - ) - // TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by - // https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is - // just a possible value of `source_file` so leading hyphens must be - // enabled. - .allow_hyphen_values(true) - .arg(Arg::new("source_file").value_hint(ValueHint::FilePath)) - .arg( - Arg::new("filter") - .help("Dot separated path to symbol") - .required(false) - .conflicts_with("json"), - ) + ) + .arg(import_map_arg()) + .arg(reload_arg()) + .arg(lock_arg()) + .arg(no_lock_arg()) + .arg(no_npm_arg()) + .arg(no_remote_arg()) + .arg( + Arg::new("json") + .long("json") + .help("Output documentation in JSON format") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("private") + .long("private") + .help("Output private documentation") + .action(ArgAction::SetTrue), + ) + // TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by + // https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is + // just a possible value of `source_file` so leading hyphens must be + // enabled. + .allow_hyphen_values(true) + .arg(Arg::new("source_file").value_hint(ValueHint::FilePath)) + .arg( + Arg::new("filter") + .help("Dot separated path to symbol") + .required(false) + .conflicts_with("json"), + ) + }) } fn eval_subcommand() -> Command { - runtime_args(Command::new("eval"), false, true) - .about("Eval script") - .long_about( - "Evaluate JavaScript from the command line. + Command::new("eval").defer(|cmd| { + runtime_args(cmd, false, true) + .about("Eval script") + .long_about( + "Evaluate JavaScript from the command line. deno eval \"console.log('hello world')\" @@ -1175,41 +1193,43 @@ To evaluate as TypeScript: deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" This command has implicit access to all permissions (--allow-all).", - ) - .arg(check_arg(false)) - .arg( - // TODO(@satyarohith): remove this argument in 2.0. - Arg::new("ts") - .conflicts_with("ext") - .long("ts") - .short('T') - .help("deprecated: Treat eval input as TypeScript") - .action(ArgAction::SetTrue) - .hide(true), - ) - .arg(executable_ext_arg()) - .arg( - Arg::new("print") - .long("print") - .short('p') - .help("print result to stdout") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("code_arg") - .num_args(1..) - .action(ArgAction::Append) - .help("Code arg") - .value_name("CODE_ARG") - .required(true), - ) + ) + .arg(check_arg(false)) + .arg( + // TODO(@satyarohith): remove this argument in 2.0. + Arg::new("ts") + .conflicts_with("ext") + .long("ts") + .short('T') + .help("deprecated: Treat eval input as TypeScript") + .action(ArgAction::SetTrue) + .hide(true), + ) + .arg(executable_ext_arg()) + .arg( + Arg::new("print") + .long("print") + .short('p') + .help("print result to stdout") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("code_arg") + .num_args(1..) + .action(ArgAction::Append) + .help("Code arg") + .value_name("CODE_ARG") + .required(true), + ) + }) } fn fmt_subcommand() -> Command { - Command::new("fmt") - .about("Format source files") - .long_about( - "Auto-format JavaScript, TypeScript, Markdown, and JSON files. + Command::new("fmt").defer(|cmd| { + cmd + .about("Format source files") + .long_about( + "Auto-format JavaScript, TypeScript, Markdown, and JSON files. deno fmt deno fmt myfile1.ts myfile2.ts @@ -1226,109 +1246,114 @@ Ignore formatting code by preceding it with an ignore comment: Ignore formatting a file by adding an ignore comment at the top of the file: // deno-fmt-ignore-file", - ) - .arg(config_arg()) - .arg(no_config_arg()) - .arg( - Arg::new("check") - .long("check") - .help("Check if the source files are formatted") - .num_args(0), - ) - .arg( - Arg::new("ext") - .long("ext") - .help("Set content type of the supplied file") - // prefer using ts for formatting instead of js because ts works in more scenarios - .default_value("ts") - .value_parser(["ts", "tsx", "js", "jsx", "md", "json", "jsonc"]), - ) - .arg( - Arg::new("ignore") - .long("ignore") - .value_parser(value_parser!(PathBuf)) - .num_args(1..) - .use_value_delimiter(true) - .require_equals(true) - .help("Ignore formatting particular source files") - .value_hint(ValueHint::AnyPath), - ) - .arg( - Arg::new("files") - .value_parser(value_parser!(PathBuf)) - .num_args(1..) - .action(ArgAction::Append) - .required(false) - .value_hint(ValueHint::AnyPath), - ) - .arg(watch_arg(false)) - .arg(no_clear_screen_arg()) - .arg( - Arg::new("use-tabs") - .long("use-tabs") - .alias("options-use-tabs") - .num_args(0..=1) - .value_parser(value_parser!(bool)) - .default_missing_value("true") - .require_equals(true) - .help("Use tabs instead of spaces for indentation. Defaults to false."), - ) - .arg( - Arg::new("line-width") - .long("line-width") - .alias("options-line-width") - .help("Define maximum line width. Defaults to 80.") - .value_parser(value_parser!(NonZeroU32)), - ) - .arg( - Arg::new("indent-width") - .long("indent-width") - .alias("options-indent-width") - .help("Define indentation width. Defaults to 2.") - .value_parser(value_parser!(NonZeroU8)), - ) - .arg( - Arg::new("single-quote") - .long("single-quote") - .alias("options-single-quote") - .num_args(0..=1) - .value_parser(value_parser!(bool)) - .default_missing_value("true") - .require_equals(true) - .help("Use single quotes. Defaults to false."), - ) - .arg( - Arg::new("prose-wrap") - .long("prose-wrap") - .alias("options-prose-wrap") - .value_parser(["always", "never", "preserve"]) - .help("Define how prose should be wrapped. Defaults to always."), - ) - .arg( - Arg::new("no-semicolons") - .long("no-semicolons") - .alias("options-no-semicolons") - .num_args(0..=1) - .value_parser(value_parser!(bool)) - .default_missing_value("true") - .require_equals(true) - .help("Don't use semicolons except where necessary."), - ) + ) + .arg(config_arg()) + .arg(no_config_arg()) + .arg( + Arg::new("check") + .long("check") + .help("Check if the source files are formatted") + .num_args(0), + ) + .arg( + Arg::new("ext") + .long("ext") + .help("Set content type of the supplied file") + // prefer using ts for formatting instead of js because ts works in more scenarios + .default_value("ts") + .value_parser(["ts", "tsx", "js", "jsx", "md", "json", "jsonc"]), + ) + .arg( + Arg::new("ignore") + .long("ignore") + .value_parser(value_parser!(PathBuf)) + .num_args(1..) + .use_value_delimiter(true) + .require_equals(true) + .help("Ignore formatting particular source files") + .value_hint(ValueHint::AnyPath), + ) + .arg( + Arg::new("files") + .value_parser(value_parser!(PathBuf)) + .num_args(1..) + .action(ArgAction::Append) + .required(false) + .value_hint(ValueHint::AnyPath), + ) + .arg(watch_arg(false)) + .arg(no_clear_screen_arg()) + .arg( + Arg::new("use-tabs") + .long("use-tabs") + .alias("options-use-tabs") + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") + .require_equals(true) + .help( + "Use tabs instead of spaces for indentation. Defaults to false.", + ), + ) + .arg( + Arg::new("line-width") + .long("line-width") + .alias("options-line-width") + .help("Define maximum line width. Defaults to 80.") + .value_parser(value_parser!(NonZeroU32)), + ) + .arg( + Arg::new("indent-width") + .long("indent-width") + .alias("options-indent-width") + .help("Define indentation width. Defaults to 2.") + .value_parser(value_parser!(NonZeroU8)), + ) + .arg( + Arg::new("single-quote") + .long("single-quote") + .alias("options-single-quote") + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") + .require_equals(true) + .help("Use single quotes. Defaults to false."), + ) + .arg( + Arg::new("prose-wrap") + .long("prose-wrap") + .alias("options-prose-wrap") + .value_parser(["always", "never", "preserve"]) + .help("Define how prose should be wrapped. Defaults to always."), + ) + .arg( + Arg::new("no-semicolons") + .long("no-semicolons") + .alias("options-no-semicolons") + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") + .require_equals(true) + .help("Don't use semicolons except where necessary."), + ) + }) } fn init_subcommand() -> Command { - Command::new("init").about("Initialize a new project").arg( - Arg::new("dir") - .required(false) - .value_hint(ValueHint::DirPath), - ) + Command::new("init").defer(|cmd| { + cmd.about("Initialize a new project").arg( + Arg::new("dir") + .required(false) + .value_hint(ValueHint::DirPath), + ) + }) } fn info_subcommand() -> Command { Command::new("info") - .about("Show info about cache or info related to source file") - .long_about( - "Information about a module or the cache directories. + .defer(|cmd| cmd.about("Show info about cache or info related to source file") + .long_about( + "Information about a module or the cache directories. Get information about a module: @@ -1346,57 +1371,57 @@ Without any additional arguments, 'deno info' shows: DENO_DIR: Directory containing Deno-managed files. Remote modules cache: Subdirectory containing downloaded remote modules. TypeScript compiler cache: Subdirectory containing TS compiler output.", - ) - .arg(Arg::new("file").required(false).value_hint(ValueHint::FilePath)) - .arg(reload_arg().requires("file")) - .arg(ca_file_arg()) - .arg( - location_arg() - .conflicts_with("file") - .help("Show files used for origin bound APIs like the Web Storage API when running a script with '--location='") - ) - .arg(no_check_arg().hide(true)) // TODO(lucacasonato): remove for 2.0 - .arg(no_config_arg()) - .arg(no_remote_arg()) - .arg(no_npm_arg()) - .arg(no_lock_arg()) - .arg(lock_arg()) - .arg(config_arg()) - .arg(import_map_arg()) - .arg(node_modules_dir_arg()) - .arg( - Arg::new("json") - .long("json") - .help("UNSTABLE: Outputs the information in JSON format") - .action(ArgAction::SetTrue), - ) + ) + .arg(Arg::new("file").required(false).value_hint(ValueHint::FilePath)) + .arg(reload_arg().requires("file")) + .arg(ca_file_arg()) + .arg( + location_arg() + .conflicts_with("file") + .help("Show files used for origin bound APIs like the Web Storage API when running a script with '--location='") + ) + .arg(no_check_arg().hide(true)) // TODO(lucacasonato): remove for 2.0 + .arg(no_config_arg()) + .arg(no_remote_arg()) + .arg(no_npm_arg()) + .arg(no_lock_arg()) + .arg(lock_arg()) + .arg(config_arg()) + .arg(import_map_arg()) + .arg(node_modules_dir_arg()) + .arg( + Arg::new("json") + .long("json") + .help("UNSTABLE: Outputs the information in JSON format") + .action(ArgAction::SetTrue), + )) } fn install_subcommand() -> Command { - runtime_args(Command::new("install"), true, true) - .arg(Arg::new("cmd").required(true).num_args(1..).value_hint(ValueHint::FilePath)) - .arg(check_arg(true)) - .arg( - Arg::new("name") - .long("name") - .short('n') - .help("Executable file name") - .required(false)) - .arg( - Arg::new("root") - .long("root") - .help("Installation root") - .value_parser(value_parser!(PathBuf)) - .value_hint(ValueHint::DirPath)) - .arg( - Arg::new("force") - .long("force") - .short('f') - .help("Forcefully overwrite existing installation") - .action(ArgAction::SetTrue)) - .about("Install script as an executable") - .long_about( - "Installs a script as an executable in the installation root's bin directory. + Command::new("install") + .defer(|cmd| runtime_args(cmd, true, true).arg(Arg::new("cmd").required(true).num_args(1..).value_hint(ValueHint::FilePath)) + .arg(check_arg(true)) + .arg( + Arg::new("name") + .long("name") + .short('n') + .help("Executable file name") + .required(false)) + .arg( + Arg::new("root") + .long("root") + .help("Installation root") + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::DirPath)) + .arg( + Arg::new("force") + .long("force") + .short('f') + .help("Forcefully overwrite existing installation") + .action(ArgAction::SetTrue)) + .about("Install script as an executable") + .long_about( + "Installs a script as an executable in the installation root's bin directory. deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts deno install https://deno.land/std/examples/colors.ts @@ -1422,21 +1447,21 @@ The installation root is determined, in order of precedence: - DENO_INSTALL_ROOT environment variable - $HOME/.deno -These must be added to the path manually if required.") +These must be added to the path manually if required.")) } fn uninstall_subcommand() -> Command { Command::new("uninstall") - .arg(Arg::new("name").required(true)) - .arg( - Arg::new("root") - .long("root") - .help("Installation root") - .value_parser(value_parser!(PathBuf)) - .value_hint(ValueHint::DirPath)) - .about("Uninstall a script previously installed with deno install") - .long_about( - "Uninstalls an executable script in the installation root's bin directory. + .defer(|cmd| cmd.arg(Arg::new("name").required(true)) + .arg( + Arg::new("root") + .long("root") + .help("Installation root") + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::DirPath)) + .about("Uninstall a script previously installed with deno install") + .long_about( + "Uninstalls an executable script in the installation root's bin directory. deno uninstall serve @@ -1447,7 +1472,7 @@ To change the installation root, use --root: The installation root is determined, in order of precedence: - --root option - DENO_INSTALL_ROOT environment variable - - $HOME/.deno") + - $HOME/.deno")) } static LSP_HELP: &str = concat!( @@ -1464,15 +1489,15 @@ https://deno.land/manual@v", fn lsp_subcommand() -> Command { Command::new("lsp") - .about("Start the language server") - .long_about(LSP_HELP) + .defer(|cmd| cmd.about("Start the language server").long_about(LSP_HELP)) } fn lint_subcommand() -> Command { - Command::new("lint") - .about("Lint source files") - .long_about( - "Lint JavaScript/TypeScript source code. + Command::new("lint").defer(|cmd| { + cmd + .about("Lint source files") + .long_about( + "Lint JavaScript/TypeScript source code. deno lint deno lint myfile1.ts myfile2.js @@ -1502,97 +1527,98 @@ Ignore linting a file by adding an ignore comment at the top of the file: // deno-lint-ignore-file ", - ) - .arg( - Arg::new("rules") - .long("rules") - .help("List available rules") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("rules-tags") - .long("rules-tags") - .require_equals(true) - .num_args(1..) - .action(ArgAction::Append) - .use_value_delimiter(true) - .conflicts_with("rules") - .help("Use set of rules with a tag"), - ) - .arg( - Arg::new("rules-include") - .long("rules-include") - .require_equals(true) - .num_args(1..) - .use_value_delimiter(true) - .conflicts_with("rules") - .help("Include lint rules"), - ) - .arg( - Arg::new("rules-exclude") - .long("rules-exclude") - .require_equals(true) - .num_args(1..) - .use_value_delimiter(true) - .conflicts_with("rules") - .help("Exclude lint rules"), - ) - .arg(no_config_arg()) - .arg(config_arg()) - .arg( - Arg::new("ignore") - .long("ignore") - .num_args(1..) - .value_parser(value_parser!(PathBuf)) - .use_value_delimiter(true) - .require_equals(true) - .help("Ignore linting particular source files") - .value_hint(ValueHint::AnyPath), - ) - .arg( - Arg::new("json") - .long("json") - .help("Output lint result in JSON format") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("compact") - .long("compact") - .help("Output lint result in compact format") - .action(ArgAction::SetTrue) - .conflicts_with("json"), - ) - .arg( - Arg::new("files") - .value_parser(value_parser!(PathBuf)) - .num_args(1..) - .action(ArgAction::Append) - .required(false) - .value_hint(ValueHint::AnyPath), - ) - .arg(watch_arg(false)) - .arg(no_clear_screen_arg()) + ) + .arg( + Arg::new("rules") + .long("rules") + .help("List available rules") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("rules-tags") + .long("rules-tags") + .require_equals(true) + .num_args(1..) + .action(ArgAction::Append) + .use_value_delimiter(true) + .conflicts_with("rules") + .help("Use set of rules with a tag"), + ) + .arg( + Arg::new("rules-include") + .long("rules-include") + .require_equals(true) + .num_args(1..) + .use_value_delimiter(true) + .conflicts_with("rules") + .help("Include lint rules"), + ) + .arg( + Arg::new("rules-exclude") + .long("rules-exclude") + .require_equals(true) + .num_args(1..) + .use_value_delimiter(true) + .conflicts_with("rules") + .help("Exclude lint rules"), + ) + .arg(no_config_arg()) + .arg(config_arg()) + .arg( + Arg::new("ignore") + .long("ignore") + .num_args(1..) + .value_parser(value_parser!(PathBuf)) + .use_value_delimiter(true) + .require_equals(true) + .help("Ignore linting particular source files") + .value_hint(ValueHint::AnyPath), + ) + .arg( + Arg::new("json") + .long("json") + .help("Output lint result in JSON format") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("compact") + .long("compact") + .help("Output lint result in compact format") + .action(ArgAction::SetTrue) + .conflicts_with("json"), + ) + .arg( + Arg::new("files") + .value_parser(value_parser!(PathBuf)) + .num_args(1..) + .action(ArgAction::Append) + .required(false) + .value_hint(ValueHint::AnyPath), + ) + .arg(watch_arg(false)) + .arg(no_clear_screen_arg()) + }) } fn repl_subcommand() -> Command { - runtime_args(Command::new("repl"), true, true) - .about("Read Eval Print Loop") - .arg(check_arg(false)) - .arg( - Arg::new("eval-file") - .long("eval-file") - .num_args(1..) - .use_value_delimiter(true) - .require_equals(true) - .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs.") - .value_hint(ValueHint::AnyPath), - ) - .arg( - Arg::new("eval") - .long("eval") - .help("Evaluates the provided code when the REPL starts.") - .value_name("code"), - ) + Command::new("repl") + .defer(|cmd| runtime_args(cmd, true, true).about("Read Eval Print Loop") + .arg(check_arg(false)) + .arg( + Arg::new("eval-file") + .long("eval-file") + .num_args(1..) + .use_value_delimiter(true) + .require_equals(true) + .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs.") + .value_hint(ValueHint::AnyPath), + ) + .arg( + Arg::new("eval") + .long("eval") + .help("Evaluates the provided code when the REPL starts.") + .value_name("code"), + )) } fn run_subcommand() -> Command { @@ -1639,27 +1665,29 @@ Specifying the filename '-' to read the file from stdin. } fn task_subcommand() -> Command { - Command::new("task") - .allow_external_subcommands(true) - .subcommand_value_name("TASK") - .arg(config_arg()) - .arg( - Arg::new("cwd") - .long("cwd") - .value_name("DIR") - .help("Specify the directory to run the task in") - .value_hint(ValueHint::DirPath), - ) - .about("Run a task defined in the configuration file") - .long_about( - "Run a task defined in the configuration file + Command::new("task").defer(|cmd| { + cmd + .allow_external_subcommands(true) + .subcommand_value_name("TASK") + .arg(config_arg()) + .arg( + Arg::new("cwd") + .long("cwd") + .value_name("DIR") + .help("Specify the directory to run the task in") + .value_hint(ValueHint::DirPath), + ) + .about("Run a task defined in the configuration file") + .long_about( + "Run a task defined in the configuration file deno task build", - ) + ) + }) } fn test_subcommand() -> Command { - runtime_args(Command::new("test"), true, true) + Command::new("test").defer(|cmd| runtime_args(cmd, true, true) .arg(check_arg(true)) .arg( Arg::new("ignore") @@ -1774,26 +1802,29 @@ Directory arguments are expanded to all contained files matching the glob {*_,*.,}test.{js,mjs,ts,mts,jsx,tsx}: deno test src/", - ) + )) } fn types_subcommand() -> Command { - Command::new("types") - .about("Print runtime TypeScript declarations") - .long_about( - "Print runtime TypeScript declarations. + Command::new("types").defer(|cmd| { + cmd + .about("Print runtime TypeScript declarations") + .long_about( + "Print runtime TypeScript declarations. deno types > lib.deno.d.ts The declaration file could be saved and used for typing information.", - ) + ) + }) } fn upgrade_subcommand() -> Command { - Command::new("upgrade") - .about("Upgrade deno executable to given version") - .long_about( - "Upgrade deno executable to the given version. + Command::new("upgrade").defer(|cmd| { + cmd + .about("Upgrade deno executable to given version") + .long_about( + "Upgrade deno executable to the given version. Defaults to latest. The version is downloaded from @@ -1804,46 +1835,47 @@ If you want to not replace the current Deno executable but instead download an update to a different location, use the --output flag deno upgrade --output $HOME/my_deno", - ) - .arg( - Arg::new("version") - .long("version") - .help("The version to upgrade to"), - ) - .arg( - Arg::new("output") - .long("output") - .help("The path to output the updated version to") - .value_parser(value_parser!(PathBuf)) - .value_hint(ValueHint::FilePath), - ) - .arg( - Arg::new("dry-run") - .long("dry-run") - .help("Perform all checks without replacing old exe") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("force") - .long("force") - .short('f') - .help("Replace current exe even if not out-of-date") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("canary") - .long("canary") - .help("Upgrade to canary builds") - .action(ArgAction::SetTrue), - ) - .arg(ca_file_arg()) + ) + .arg( + Arg::new("version") + .long("version") + .help("The version to upgrade to"), + ) + .arg( + Arg::new("output") + .long("output") + .help("The path to output the updated version to") + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("dry-run") + .long("dry-run") + .help("Perform all checks without replacing old exe") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("force") + .long("force") + .short('f') + .help("Replace current exe even if not out-of-date") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("canary") + .long("canary") + .help("Upgrade to canary builds") + .action(ArgAction::SetTrue), + ) + .arg(ca_file_arg()) + }) } fn vendor_subcommand() -> Command { Command::new("vendor") - .about("Vendor remote modules into a local directory") - .long_about( - "Vendor remote modules into a local directory. + .defer(|cmd| cmd.about("Vendor remote modules into a local directory") + .long_about( + "Vendor remote modules into a local directory. Analyzes the provided modules along with their dependencies, downloads remote modules to the output directory, and produces an import map that @@ -1855,36 +1887,36 @@ maps remote specifiers to the downloaded files. Remote modules and multiple modules may also be specified: deno vendor main.ts test.deps.ts https://deno.land/std/path/mod.ts", - ) - .arg( - Arg::new("specifiers") - .num_args(1..) - .action(ArgAction::Append) - .required(true), - ) - .arg( - Arg::new("output") - .long("output") - .help("The directory to output the vendored modules to") - .value_parser(value_parser!(PathBuf)) - .value_hint(ValueHint::DirPath), - ) - .arg( - Arg::new("force") - .long("force") - .short('f') - .help( - "Forcefully overwrite conflicting files in existing output directory", - ) - .action(ArgAction::SetTrue), - ) - .arg(no_config_arg()) - .arg(config_arg()) - .arg(import_map_arg()) - .arg(lock_arg()) - .arg(node_modules_dir_arg()) - .arg(reload_arg()) - .arg(ca_file_arg()) + ) + .arg( + Arg::new("specifiers") + .num_args(1..) + .action(ArgAction::Append) + .required(true), + ) + .arg( + Arg::new("output") + .long("output") + .help("The directory to output the vendored modules to") + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::DirPath), + ) + .arg( + Arg::new("force") + .long("force") + .short('f') + .help( + "Forcefully overwrite conflicting files in existing output directory", + ) + .action(ArgAction::SetTrue), + ) + .arg(no_config_arg()) + .arg(config_arg()) + .arg(import_map_arg()) + .arg(lock_arg()) + .arg(node_modules_dir_arg()) + .arg(reload_arg()) + .arg(ca_file_arg())) } fn compile_args(app: Command) -> Command {