From 9bc2dd29ad6ba334fd57a20114e367d3c04763d4 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Mon, 19 Aug 2024 00:39:53 +0200 Subject: [PATCH] fix: clean up flag help output (#24686) Permission flags are unified in a clearer and concise output. Unstable flags are hidden by default with exception of the `unstable` flag itself. the remaining unstable flags can be seen with a `--help=unstable`. This also cleans up to show unstable flags only for subcommands that actually need them. Also sorts flags alphabetically, and gorups various flags together in a set of categories. --------- Co-authored-by: crowlkats --- Cargo.lock | 28 +- cli/args/flags.rs | 1901 ++++++++++++++++------------ cli/main.rs | 3 +- cli/tools/jupyter/server.rs | 2 +- cli/tools/task.rs | 2 +- tests/integration/watcher_tests.rs | 2 - 6 files changed, 1100 insertions(+), 838 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb903d00ce..c08fb45a92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -361,9 +361,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -630,9 +630,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.92" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" dependencies = [ "jobserver", "libc", @@ -3209,9 +3209,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gl_generator" @@ -3903,9 +3903,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.29" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f08474e32172238f2827bd160c67871cdb2801430f65c3979184dc362e3ca118" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -4704,9 +4704,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -5879,9 +5879,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 45c407cea6..5518b4b7db 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1114,21 +1114,11 @@ static ENV_VARIABLES_HELP: &str = color_print::cstr!( DENO_DIR Set the cache directory DENO_INSTALL_ROOT Set deno install's output directory (defaults to $HOME/.deno/bin) - DENO_JOBS Number of parallel workers used for the --parallel flag - with the test subcommand. Defaults to number of available CPUs. - DENO_REPL_HISTORY Set REPL history file path - History file is disabled when the value is empty - (defaults to $DENO_DIR/deno_history.txt) DENO_NO_PACKAGE_JSON Disables auto-resolution of package.json - DENO_NO_PROMPT Set to disable permission prompts on access - (alternative to passing --no-prompt on invocation) DENO_NO_UPDATE_CHECK Set to disable checking if a newer Deno version is available DENO_TLS_CA_STORE Comma-separated list of order dependent certificate stores. Possible values: "system", "mozilla". (defaults to "mozilla") - DENO_V8_FLAGS Set V8 command line options - DENO_WEBGPU_TRACE Directory to use for wgpu traces - DENO_WEBGPU_BACKEND Single or list of backend to use for WebGPU HTTP_PROXY Proxy address for HTTP requests (module downloads, fetch) HTTPS_PROXY Proxy address for HTTPS requests @@ -1160,6 +1150,7 @@ static DENO_HELP: &str = color_print::cstr!( deno add @std/assert | deno add npm:express install Install script as an executable uninstall Uninstall a script previously installed with deno install + remove Remove dependencies from the configuration file Tooling: bench Run benchmarks @@ -1197,22 +1188,6 @@ pub fn flags_from_vec(args: Vec) -> clap::error::Result { let mut flags = Flags::default(); - if matches.get_flag("unstable") { - flags.unstable_config.legacy_flag_enabled = true; - } - - for (name, _, _) in crate::UNSTABLE_GRANULAR_FLAGS { - if matches.get_flag(&format!("unstable-{}", name)) { - flags.unstable_config.features.push(name.to_string()); - } - } - - flags.unstable_config.bare_node_builtins = - matches.get_flag("unstable-bare-node-builtins"); - flags.unstable_config.byonm = matches.get_flag("unstable-byonm"); - flags.unstable_config.sloppy_imports = - matches.get_flag("unstable-sloppy-imports"); - if matches.get_flag("quiet") { flags.log_level = Some(Level::Error); } else if let Some(log_level) = matches.get_one::("log-level") { @@ -1224,6 +1199,55 @@ pub fn flags_from_vec(args: Vec) -> clap::error::Result { }; } + if let Some(help_expansion) = matches.get_one::("help").cloned() { + let mut subcommand = if let Some((sub, _)) = matches.remove_subcommand() { + app.find_subcommand(sub).unwrap().clone() + } else { + app + }; + + if help_expansion == "unstable" + && subcommand + .get_arguments() + .any(|arg| arg.get_id().as_str() == "unstable") + { + subcommand = subcommand + .mut_arg("unstable", |arg| { + let new_help = arg + .get_help() + .unwrap() + .to_string() + .split_once("\n") + .unwrap() + .0 + .to_string(); + arg.help_heading(UNSTABLE_HEADING).help(new_help) + }) + .mut_args(|arg| { + // long_help here is being used as a metadata, see unstable args definition + if arg.get_help_heading() == Some(UNSTABLE_HEADING) + && arg.get_long_help().is_some() + { + arg.hide(false) + } else { + arg + } + }); + } + + help_parse(&mut flags, subcommand); + return Ok(flags); + } else if matches.contains_id("help") { + let subcommand = if let Some((sub, _)) = matches.remove_subcommand() { + app.find_subcommand(sub).unwrap().clone() + } else { + app + }; + + help_parse(&mut flags, subcommand); + return Ok(flags); + } + if let Some((subcommand, mut m)) = matches.remove_subcommand() { match subcommand.as_str() { "add" => add_parse(&mut flags, &mut m), @@ -1257,13 +1281,13 @@ pub fn flags_from_vec(args: Vec) -> clap::error::Result { "vendor" => vendor_parse(&mut flags, &mut m), "publish" => publish_parse(&mut flags, &mut m), "help" => { - let help = if let Some((sub, _)) = m.remove_subcommand() { - app.find_subcommand_mut(sub).unwrap().render_help() + let subcommand = if let Some((sub, _)) = matches.remove_subcommand() { + app.find_subcommand(sub).unwrap().clone() } else { - app.render_help() + app }; - flags.subcommand = DenoSubcommand::Help(HelpFlags { help }); + help_parse(&mut flags, subcommand) } _ => unreachable!(), } @@ -1294,6 +1318,74 @@ pub fn flags_from_vec(args: Vec) -> clap::error::Result { Ok(flags) } +macro_rules! heading { + ($($name:ident = $title:expr),+; $total:literal) => { + $(const $name: &str = $title;)+ + const HEADING_ORDER: [&str; $total] = [$($name),+]; + }; +} + +heading! { + // subcommand flags headings + DOC_HEADING = "Documentation options", + FMT_HEADING = "Formatting options", + COMPILE_HEADING = "Compile options", + LINT_HEADING = "Linting options", + TEST_HEADING = "Testing options", + UPGRADE_HEADING = "Upgrade options", + PUBLISH_HEADING = "Publishing options", + + // categorized flags headings + TYPE_CHECKING_HEADING = "Type checking options", + FILE_WATCHING_HEADING = "File watching options", + DEBUGGING_HEADING = "Debugging options", + DEPENDENCY_MANAGEMENT_HEADING = "Dependency management options", + + UNSTABLE_HEADING = "Unstable options"; + 12 +} + +fn help_parse(flags: &mut Flags, mut subcommand: Command) { + let mut args = subcommand + .get_arguments() + .map(|arg| { + ( + arg.get_id().as_str().to_string(), + arg.get_help_heading().map(|h| h.to_string()), + ) + }) + .collect::>(); + args.sort_by(|a, b| { + a.1 + .as_ref() + .map(|heading| HEADING_ORDER.iter().position(|h| h == heading)) + .cmp( + &b.1 + .as_ref() + .map(|heading| HEADING_ORDER.iter().position(|h| h == heading)), + ) + .then(a.0.cmp(&b.0)) + }); + + for (mut i, (arg, heading)) in args.into_iter().enumerate() { + if let Some(heading) = heading { + let heading_i = HEADING_ORDER.iter().position(|h| h == &heading).unwrap(); + i += (if heading == UNSTABLE_HEADING { + // ensures the unstable section is always last + 50 + } else { + heading_i + }) * 100; + } + + subcommand = subcommand.mut_arg(arg, |arg| arg.display_order(i)); + } + + flags.subcommand = DenoSubcommand::Help(HelpFlags { + help: subcommand.render_help(), + }); +} + // copied from clap, https://github.com/clap-rs/clap/blob/4e1a565b8adb4f2ad74a9631565574767fdc37ae/clap_builder/src/parser/features/suggestions.rs#L11-L26 pub fn did_you_mean(v: &str, possible_values: I) -> Vec where @@ -1328,8 +1420,6 @@ fn handle_repl_flags(flags: &mut Flags, repl_flags: ReplFlags) { flags.subcommand = DenoSubcommand::Repl(repl_flags); } -static UNSTABLE_HEADING: &str = "Unstable"; - pub fn clap_root() -> Command { let long_version = format!( "{} ({}, {}, {})\nv8 {}\ntypescript {}", @@ -1341,7 +1431,8 @@ pub fn clap_root() -> Command { crate::version::DENO_VERSION_INFO.typescript ); - let mut cmd = run_args(Command::new("deno"), true) + run_args(Command::new("deno"), true) + .args(unstable_args(UnstableArgsConfig::ResolutionAndRuntime)) .next_line_help(false) .bin_name("deno") .styles( @@ -1349,86 +1440,34 @@ pub fn clap_root() -> Command { .header(AnsiColor::Yellow.on_default()) .usage(AnsiColor::White.on_default()) .literal(AnsiColor::Green.on_default()) - .placeholder(AnsiColor::Green.on_default()) + .placeholder(AnsiColor::Green.on_default()), ) .color(ColorChoice::Auto) .term_width(800) .version(crate::version::DENO_VERSION_INFO.deno) .long_version(long_version) - // cause --unstable flags to display at the bottom of the help text - .next_display_order(1000) .disable_version_flag(true) .disable_help_flag(true) .disable_help_subcommand(true) - .arg(Arg::new("help") - .short('h') - .long("help") - .hide(true) - .action(ArgAction::HelpShort) - .global(true)) + .arg( + Arg::new("help") + .short('h') + .long("help") + .hide(true) + .action(ArgAction::Append) + .num_args(0..=1) + .require_equals(true) + .value_parser(["unstable"]) + .global(true), + ) .arg( Arg::new("version") .short('V') .short_alias('v') .long("version") .action(ArgAction::Version) - .help("Print version") + .help("Print version"), ) - .arg( - Arg::new("unstable") - .long("unstable") - .help("Enable unstable features and APIs") - .action(ArgAction::SetTrue) - .global(true) - .help_heading(UNSTABLE_HEADING), - ) - .arg( - Arg::new("unstable-bare-node-builtins") - .long("unstable-bare-node-builtins") - .help("Enable unstable bare node builtins feature") - .env("DENO_UNSTABLE_BARE_NODE_BUILTINS") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue) - .global(true) - .help_heading(UNSTABLE_HEADING), - ) - .arg( - Arg::new("unstable-byonm") - .long("unstable-byonm") - .help("Enable unstable 'bring your own node_modules' feature") - .env("DENO_UNSTABLE_BYONM") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue) - .global(true) - .help_heading(UNSTABLE_HEADING), - ) - .arg( - Arg::new("unstable-sloppy-imports") - .long("unstable-sloppy-imports") - .help( - "Enable unstable resolving of specifiers by extension probing, .js to .ts, and directory probing.", - ) - .env("DENO_UNSTABLE_SLOPPY_IMPORTS") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue) - .global(true) - .help_heading(UNSTABLE_HEADING), - ); - - for (flag_name, help, _) in crate::UNSTABLE_GRANULAR_FLAGS { - cmd = cmd.arg( - Arg::new(format!("unstable-{}", flag_name)) - .long(format!("unstable-{}", flag_name)) - .help(help) - .action(ArgAction::SetTrue) - .global(true) - .help_heading(UNSTABLE_HEADING), - ); - } - - cmd - // reset the display order after the unstable flags - .next_display_order(0) .arg( Arg::new("log-level") .short('L') @@ -1491,8 +1530,19 @@ pub fn clap_root() -> Command { .next_line_help(false) } +#[inline(always)] +fn command( + name: &'static str, + about: impl clap::builder::IntoResettable, + unstable_args_config: UnstableArgsConfig, +) -> Command { + Command::new(name) + .about(about) + .args(unstable_args(unstable_args_config)) +} + fn help_subcommand(app: &Command) -> Command { - Command::new("help") + command("help", None, UnstableArgsConfig::None) .hide(true) .disable_help_subcommand(true) .subcommands(app.get_subcommands().map(|command| { @@ -1504,56 +1554,55 @@ fn help_subcommand(app: &Command) -> Command { } fn add_subcommand() -> Command { - Command::new("add") - .about( - "Add dependencies to the configuration file. + command( + "add", + "Add dependencies to the configuration file. deno add @std/path You can add multiple dependencies at once: deno add @std/path @std/assert ", + UnstableArgsConfig::None, + ) + .defer(|cmd| { + cmd.arg( + Arg::new("packages") + .help("List of packages to add") + .required_unless_present("help") + .num_args(1..) + .action(ArgAction::Append), ) - .defer(|cmd| { - cmd.arg( - Arg::new("packages") - .help("List of packages to add") - .required(true) - .num_args(1..) - .action(ArgAction::Append), - ) - }) + }) } fn remove_subcommand() -> Command { - Command::new("remove") - .alias("rm") - .about("Remove dependencies") - .long_about( - "Remove dependencies from the configuration file. + command( + "remove", + "Remove dependencies from the configuration file. deno remove @std/path You can remove multiple dependencies at once: - - deno remove @std/path @std/assert + deno remove @std/path @std/assert ", + UnstableArgsConfig::None, + ) + .defer(|cmd| { + cmd.arg( + Arg::new("packages") + .help("List of packages to remove") + .required_unless_present("help") + .num_args(1..) + .action(ArgAction::Append), ) - .defer(|cmd| { - cmd.arg( - Arg::new("packages") - .help("List of packages to remove") - .required(true) - .num_args(1..) - .action(ArgAction::Append), - ) - }) + }) } fn bench_subcommand() -> Command { - Command::new("bench") - .about( - "Run benchmarks using Deno's built-in bench tool. + command( + "bench", + "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: @@ -1562,72 +1611,68 @@ and report results to standard output: Directory arguments are expanded to all contained files matching the glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: deno bench src/", - ) - .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"), - ) - .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(..) - .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(watch_exclude_arg()) - .arg(no_clear_screen_arg()) - .arg(script_arg().last(true)) - .arg(env_file_arg()) - }) + UnstableArgsConfig::ResolutionAndRuntime, + ) + .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"), + ) + .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(..) + .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(watch_exclude_arg()) + .arg(no_clear_screen_arg()) + .arg(script_arg().last(true)) + .arg(env_file_arg()) + }) } fn bundle_subcommand() -> Command { - Command::new("bundle") - .hide(true) - .about( - "⚠️ Warning: `deno bundle` is deprecated and will be removed in Deno 2.0. + command("bundle", "⚠️ Warning: `deno bundle` is deprecated and will be removed in Deno 2.0. Use an alternative bundler like \"deno_emit\", \"esbuild\" or \"rollup\" instead. Output a single JavaScript file with all dependencies. deno bundle jsr:@std/http/file-server file_server.bundle.js If no output file is given, the output is written to standard output: - deno bundle jsr:@std/http/file-server", - ) + deno bundle jsr:@std/http/file-server", UnstableArgsConfig::ResolutionOnly) + .hide(true) .defer(|cmd| { compile_args(cmd) .hide(true) .arg(check_arg(true)) .arg( Arg::new("source_file") - .required(true) + .required_unless_present("help") .value_hint(ValueHint::FilePath), ) .arg(Arg::new("out_file").value_hint(ValueHint::FilePath)) @@ -1639,9 +1684,9 @@ If no output file is given, the output is written to standard output: } fn cache_subcommand() -> Command { - Command::new("cache") - .about( - "Cache and compile remote dependencies recursively. + command( + "cache", + "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: @@ -1649,63 +1694,71 @@ them in the local cache, without running any code: Future runs of this module will trigger no downloads or compilation unless --reload is specified.", - ) - .defer(|cmd| { - compile_args(cmd) - .arg(check_arg(false)) - .arg( - Arg::new("file") - .num_args(1..) - .required(true) - .value_hint(ValueHint::FilePath), - ) - .arg(frozen_lockfile_arg()) - .arg(allow_scripts_arg()) - }) + UnstableArgsConfig::ResolutionOnly, + ) + .defer(|cmd| { + compile_args(cmd) + .arg(check_arg(false)) + .arg( + Arg::new("file") + .num_args(1..) + .required_unless_present("help") + .value_hint(ValueHint::FilePath), + ) + .arg(frozen_lockfile_arg()) + .arg(allow_scripts_arg()) + }) } fn clean_subcommand() -> Command { - Command::new("clean").about("Remove the cache directory ($DENO_DIR)") + command( + "clean", + "Remove the cache directory ($DENO_DIR)", + UnstableArgsConfig::None, + ) } fn check_subcommand() -> Command { - Command::new("check") - .about( + command("check", "Download and type-check without execution. deno check jsr:@std/http/file-server Unless --reload is specified, this command will not re-download already cached dependencies.", + UnstableArgsConfig::ResolutionAndRuntime ) - .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( - Arg::new("file") - .num_args(1..) - .required(true) - .value_hint(ValueHint::FilePath), - ) + .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( + Arg::new("file") + .num_args(1..) + .required_unless_present("help") + .value_hint(ValueHint::FilePath), + ) + } ) } fn compile_subcommand() -> Command { - Command::new("compile") - .about( - "Compiles the given script into a self contained executable. + command( + "compile", + "Compiles the given script into a self contained executable. deno compile -A jsr:@std/http/file-server deno compile --output file_server jsr:@std/http/file-server @@ -1725,81 +1778,92 @@ 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. ", - ) - .defer(|cmd| { - runtime_args(cmd, true, false) - .arg(check_arg(true)) - .arg( - Arg::new("include") - .long("include") - .help( - "Includes an additional module in the compiled executable's module + UnstableArgsConfig::ResolutionAndRuntime, + ) + .defer(|cmd| { + runtime_args(cmd, true, false) + .arg(check_arg(true)) + .arg( + Arg::new("include") + .long("include") + .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!(String)) - .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", - "aarch64-unknown-linux-gnu", - "x86_64-pc-windows-msvc", - "x86_64-apple-darwin", - "aarch64-apple-darwin", - ]), - ) - .arg( - Arg::new("no-terminal") - .long("no-terminal") - .help("Hide terminal on Windows") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("icon") - .long("icon") - .help("Set the icon of the executable on Windows (.ico)") - .value_parser(value_parser!(String)) - ) - .arg(executable_ext_arg()) - .arg(env_file_arg()) - .arg(script_arg().required(true).trailing_var_arg(true)) - }) + ) + .action(ArgAction::Append) + .value_hint(ValueHint::FilePath) + .help_heading(COMPILE_HEADING), + ) + .arg( + Arg::new("output") + .long("output") + .short('o') + .value_parser(value_parser!(String)) + .help("Output file (defaults to $PWD/)") + .value_hint(ValueHint::FilePath) + .help_heading(COMPILE_HEADING), + ) + .arg( + Arg::new("target") + .long("target") + .help("Target OS architecture") + .value_parser([ + "x86_64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "x86_64-apple-darwin", + "aarch64-apple-darwin", + ]) + .help_heading(COMPILE_HEADING), + ) + .arg( + Arg::new("no-terminal") + .long("no-terminal") + .help("Hide terminal on Windows") + .action(ArgAction::SetTrue) + .help_heading(COMPILE_HEADING), + ) + .arg( + Arg::new("icon") + .long("icon") + .help("Set the icon of the executable on Windows (.ico)") + .value_parser(value_parser!(String)) + .help_heading(COMPILE_HEADING), + ) + .arg(executable_ext_arg()) + .arg(env_file_arg()) + .arg( + script_arg() + .required_unless_present("help") + .trailing_var_arg(true), + ) + }) } fn completions_subcommand() -> Command { - Command::new("completions") - .about( - "Output shell completion script to standard output. + command( + "completions", + "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", + UnstableArgsConfig::None, + ) + .defer(|cmd| { + cmd.disable_help_subcommand(true).arg( + Arg::new("shell") + .value_parser(["bash", "fish", "powershell", "zsh", "fig"]) + .required_unless_present("help"), ) - .defer(|cmd| { - cmd.disable_help_subcommand(true).arg( - Arg::new("shell") - .value_parser(["bash", "fish", "powershell", "zsh", "fig"]) - .required(true), - ) - }) + }) } fn coverage_subcommand() -> Command { - Command::new("coverage") - .about( - "Print coverage reports from coverage profiles. + command( + "coverage", + "Print coverage reports from coverage profiles. Collect a coverage profile with deno test: deno test --coverage=cov_profile @@ -1824,83 +1888,81 @@ Write a report using the lcov format: Generate html reports from lcov: genhtml -o html_cov cov.lcov ", - ) - .defer(|cmd| { - cmd - .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!(String)) - .help( - "Exports the coverage report in lcov format to the given file. + UnstableArgsConfig::None, + ) + .defer(|cmd| { + cmd + .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!(String)) + .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("html") - .long("html") - .help( - "Output coverage report in HTML format in the given directory", - ) - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("detailed") - .long("detailed") - .help("Output coverage report in detailed format in the terminal.") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("files") - .num_args(0..) - .action(ArgAction::Append) - .value_hint(ValueHint::AnyPath), - ) - }) + ) + .require_equals(true) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("html") + .long("html") + .help("Output coverage report in HTML format in the given directory") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("detailed") + .long("detailed") + .help("Output coverage report in detailed format in the terminal.") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("files") + .num_args(0..) + .action(ArgAction::Append) + .value_hint(ValueHint::AnyPath), + ) + }) } fn doc_subcommand() -> Command { - Command::new("doc") - .about( + command("doc", "Show documentation for a module. Output documentation to standard output: @@ -1926,6 +1988,7 @@ Target a specific symbol: Show documentation for runtime built-ins: deno doc deno doc --filter Deno.Listener", + UnstableArgsConfig::ResolutionOnly ) .defer(|cmd| { cmd @@ -1939,21 +2002,23 @@ Show documentation for runtime built-ins: Arg::new("json") .long("json") .help("Output documentation in JSON format") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(DOC_HEADING), ) .arg( Arg::new("html") .long("html") .help("Output documentation in HTML format") .action(ArgAction::SetTrue) - .conflicts_with("json") + .display_order(1000) + .conflicts_with("json").help_heading(DOC_HEADING) ) .arg( Arg::new("name") .long("name") .help("The name that will be displayed in the docs") .action(ArgAction::Set) - .require_equals(true) + .require_equals(true).help_heading(DOC_HEADING) ) .arg( Arg::new("category-docs") @@ -1961,7 +2026,7 @@ Show documentation for runtime built-ins: .help("Path to a JSON file keyed by category and an optional value of a markdown doc") .requires("html") .action(ArgAction::Set) - .require_equals(true) + .require_equals(true).help_heading(DOC_HEADING) ) .arg( Arg::new("symbol-redirect-map") @@ -1969,14 +2034,14 @@ Show documentation for runtime built-ins: .help("Path to a JSON file keyed by file, with an inner map of symbol to an external link") .requires("html") .action(ArgAction::Set) - .require_equals(true) + .require_equals(true).help_heading(DOC_HEADING) ) .arg( Arg::new("strip-trailing-html") .long("strip-trailing-html") .help("Remove trailing .html from various links. Will still generate files with a .html extension.") .requires("html") - .action(ArgAction::SetTrue) + .action(ArgAction::SetTrue).help_heading(DOC_HEADING) ) .arg( Arg::new("default-symbol-map") @@ -1984,7 +2049,7 @@ Show documentation for runtime built-ins: .help("Uses the provided mapping of default name to wanted name for usage blocks.") .requires("html") .action(ArgAction::Set) - .require_equals(true) + .require_equals(true).help_heading(DOC_HEADING) ) .arg( Arg::new("output") @@ -1993,28 +2058,27 @@ Show documentation for runtime built-ins: .action(ArgAction::Set) .require_equals(true) .value_hint(ValueHint::DirPath) - .value_parser(value_parser!(String)) + .value_parser(value_parser!(String)).help_heading(DOC_HEADING) ) .arg( Arg::new("private") .long("private") .help("Output private documentation") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue).help_heading(DOC_HEADING), ) .arg( Arg::new("filter") .long("filter") .help("Dot separated path to symbol") - .required(false) .conflicts_with("json") .conflicts_with("lint") - .conflicts_with("html"), + .conflicts_with("html").help_heading(DOC_HEADING), ) .arg( Arg::new("lint") .long("lint") .help("Output documentation diagnostics.") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue).help_heading(DOC_HEADING), ) // TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by // https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is @@ -2032,8 +2096,7 @@ Show documentation for runtime built-ins: } fn eval_subcommand() -> Command { - Command::new("eval") - .about( + command("eval", "Evaluate JavaScript from the command line. deno eval \"console.log('hello world')\" @@ -2042,6 +2105,7 @@ 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).", + UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { runtime_args(cmd, false, true) @@ -2070,16 +2134,16 @@ This command has implicit access to all permissions (--allow-all).", .action(ArgAction::Append) .help("Code arg") .value_name("CODE_ARG") - .required(true), + .required_unless_present("help"), ) .arg(env_file_arg()) }) } fn fmt_subcommand() -> Command { - Command::new("fmt") - .about( - "Auto-format JavaScript, TypeScript, Markdown, and JSON files. + command( + "fmt", + "Auto-format JavaScript, TypeScript, Markdown, and JSON files. deno fmt deno fmt myfile1.ts myfile2.ts @@ -2093,164 +2157,164 @@ 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", - ) - .defer(|cmd| { - cmd - .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", "css", "scss", - "sass", "less", "html", "svelte", "vue", "astro", "yml", "yaml", - "ipynb", - ]), - ) - .arg( - Arg::new("ignore") - .long("ignore") - .num_args(1..) - .use_value_delimiter(true) - .require_equals(true) - .help("Ignore formatting particular source files") - .value_hint(ValueHint::AnyPath), - ) - .arg( - Arg::new("files") - .num_args(1..) - .action(ArgAction::Append) - .required(false) - .value_hint(ValueHint::AnyPath), - ) - .arg(watch_arg(false)) - .arg(watch_exclude_arg()) - .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. Defaults to false.", - ), - ) - .arg( - Arg::new("unstable-css") - .long("unstable-css") - .help("Enable formatting CSS, SCSS, Sass and Less files.") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("unstable-html") - .long("unstable-html") - .help("Enable formatting HTML files.") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("unstable-component") - .long("unstable-component") - .help("Enable formatting Svelte, Vue, Astro and Angular files.") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("unstable-yaml") - .long("unstable-yaml") - .help("Enable formatting YAML files.") - .value_parser(FalseyValueParser::new()) - .action(ArgAction::SetTrue), - ) - }) + UnstableArgsConfig::None, + ) + .defer(|cmd| { + cmd + .arg(config_arg()) + .arg(no_config_arg()) + .arg( + Arg::new("check") + .long("check") + .help("Check if the source files are formatted") + .num_args(0) + .help_heading(FMT_HEADING), + ) + .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", "css", "scss", + "sass", "less", "html", "svelte", "vue", "astro", "yml", "yaml", + "ipynb", + ]) + .help_heading(FMT_HEADING), + ) + .arg( + Arg::new("ignore") + .long("ignore") + .num_args(1..) + .use_value_delimiter(true) + .require_equals(true) + .help("Ignore formatting particular source files") + .value_hint(ValueHint::AnyPath) + .help_heading(FMT_HEADING), + ) + .arg( + Arg::new("files") + .num_args(1..) + .action(ArgAction::Append) + .value_hint(ValueHint::AnyPath), + ) + .arg(watch_arg(false)) + .arg(watch_exclude_arg()) + .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.", + ) + .help_heading(FMT_HEADING), + ) + .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)) + .help_heading(FMT_HEADING), + ) + .arg( + Arg::new("indent-width") + .long("indent-width") + .alias("options-indent-width") + .help("Define indentation width. Defaults to 2.") + .value_parser(value_parser!(NonZeroU8)) + .help_heading(FMT_HEADING), + ) + .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.") + .help_heading(FMT_HEADING), + ) + .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.") + .help_heading(FMT_HEADING), + ) + .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. Defaults to false.", + ) + .help_heading(FMT_HEADING), + ) + .arg( + Arg::new("unstable-css") + .long("unstable-css") + .help("Enable formatting CSS, SCSS, Sass and Less files.") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue) + .help_heading(FMT_HEADING), + ) + .arg( + Arg::new("unstable-html") + .long("unstable-html") + .help("Enable formatting HTML files.") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("unstable-component") + .long("unstable-component") + .help("Enable formatting Svelte, Vue, Astro and Angular files.") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("unstable-yaml") + .long("unstable-yaml") + .help("Enable formatting YAML files.") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue) + .help_heading(FMT_HEADING), + ) + }) } fn init_subcommand() -> Command { - Command::new("init") - .about("Initialize a new project") - .defer(|cmd| { + command("init", "Initialize a new project", UnstableArgsConfig::None).defer( + |cmd| { cmd - .arg( - Arg::new("dir") - .required(false) - .value_hint(ValueHint::DirPath), - ) - .arg( - Arg::new("lib") - .long("lib") - .required(false) - .action(ArgAction::SetTrue), - ) + .arg(Arg::new("dir").value_hint(ValueHint::DirPath)) + .arg(Arg::new("lib").long("lib").action(ArgAction::SetTrue)) .arg( Arg::new("serve") .long("serve") - .long_help("Generate an example project for `deno serve`") + .help("Generate an example project for `deno serve`") .conflicts_with("lib") - .required(false) .action(ArgAction::SetTrue), ) - }) + }, + ) } fn info_subcommand() -> Command { - Command::new("info") - .about( + command("info", "Information about a module or the cache directories. Get information about a module: @@ -2268,11 +2332,13 @@ 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.", + UnstableArgsConfig::ResolutionOnly ) .defer(|cmd| cmd - .arg(Arg::new("file").required(false).value_hint(ValueHint::FilePath)) + .arg(Arg::new("file").value_hint(ValueHint::FilePath)) .arg(reload_arg().requires("file")) .arg(ca_file_arg()) + .arg(unsafely_ignore_certificate_errors_arg()) .arg( location_arg() .conflicts_with("file") @@ -2308,7 +2374,7 @@ fn install_args(cmd: Command, deno_future: bool) -> Command { } else { cmd.arg( Arg::new("cmd") - .required(true) + .required_unless_present("help") .num_args(1..) .value_hint(ValueHint::FilePath), ) @@ -2318,8 +2384,7 @@ fn install_args(cmd: Command, deno_future: bool) -> Command { Arg::new("name") .long("name") .short('n') - .help("Executable file name") - .required(false), + .help("Executable file name"), ) .arg( Arg::new("root") @@ -2345,10 +2410,7 @@ fn install_args(cmd: Command, deno_future: bool) -> Command { } fn future_install_subcommand() -> Command { - Command::new("install") - .visible_alias("i") - .about( - "Installs dependencies either in the local project or globally to a bin directory. + command("install", "Installs dependencies either in the local project or globally to a bin directory. Local installation ------------------- @@ -2388,7 +2450,8 @@ 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.", UnstableArgsConfig::ResolutionAndRuntime) + .visible_alias("i") .defer(|cmd| { let cmd = runtime_args(cmd, true, true).arg(check_arg(true)).arg(allow_scripts_arg()); install_args(cmd, true) @@ -2396,8 +2459,7 @@ These must be added to the path manually if required.") } fn install_subcommand() -> Command { - Command::new("install") - .about( + command("install", "Installs a script as an executable in the installation root's bin directory. deno install --global --allow-net --allow-read jsr:@std/http/file-server @@ -2422,7 +2484,7 @@ 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.", UnstableArgsConfig::ResolutionAndRuntime) .defer(|cmd| { let cmd = runtime_args(cmd, true, true).arg(check_arg(true)); install_args(cmd, false) @@ -2461,9 +2523,9 @@ fn jupyter_subcommand() -> Command { } fn uninstall_subcommand() -> Command { - Command::new("uninstall") - .about( - "Uninstalls an executable script in the installation root's bin directory. + command( + "uninstall", + "Uninstalls an executable script in the installation root's bin directory. deno uninstall serve @@ -2473,44 +2535,44 @@ 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") - .defer(|cmd| cmd.arg(Arg::new("name").required(true)) + - $HOME/.deno", + UnstableArgsConfig::None, + ) + .defer(|cmd| { + cmd + .arg(Arg::new("name").required_unless_present("help")) .arg( Arg::new("root") .long("root") .help("Installation root") - .value_hint(ValueHint::DirPath) + .value_hint(ValueHint::DirPath), ) .arg( Arg::new("global") .long("global") .short('g') .help("Remove globally installed package or module") - .action(ArgAction::SetTrue) + .action(ArgAction::SetTrue), ) - ) + }) } -static LSP_HELP: &str = concat!( - "The 'deno lsp' subcommand provides a way for code editors and IDEs to +fn lsp_subcommand() -> Command { + Command::new("lsp").about( + "The 'deno lsp' subcommand provides a way for code editors and IDEs to interact with Deno using the Language Server Protocol. Usually humans do not use this subcommand directly. For example, 'deno lsp' can provide IDEs with go-to-definition support and automatic code formatting. How to connect various editors and IDEs to 'deno lsp': -https://deno.land/manual@v", - env!("CARGO_PKG_VERSION"), - "/getting_started/setup_your_environment#editors-and-ides", -); - -fn lsp_subcommand() -> Command { - Command::new("lsp").about(LSP_HELP) +https://docs.deno.com/go/lsp", + ) } fn lint_subcommand() -> Command { - Command::new("lint") - .about( - "Lint JavaScript/TypeScript source code. + command( + "lint", + "Lint JavaScript/TypeScript source code. deno lint deno lint myfile1.ts myfile2.js @@ -2535,88 +2597,95 @@ Names of rules to ignore must be specified after ignore comment. Ignore linting a file by adding an ignore comment at the top of the file: // deno-lint-ignore-file ", - ) - .defer(|cmd| { - cmd - .arg( - Arg::new("fix") - .long("fix") - .help("Fix any linting errors for rules that support it") - .action(ArgAction::SetTrue), - ) - .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) - .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..) - .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") - .num_args(1..) - .action(ArgAction::Append) - .required(false) - .value_hint(ValueHint::AnyPath), - ) - .arg(watch_arg(false)) - .arg(watch_exclude_arg()) - .arg(no_clear_screen_arg()) - }) + UnstableArgsConfig::ResolutionOnly, + ) + .defer(|cmd| { + cmd + .arg( + Arg::new("fix") + .long("fix") + .help("Fix any linting errors for rules that support it") + .action(ArgAction::SetTrue) + .help_heading(LINT_HEADING), + ) + .arg( + Arg::new("rules") + .long("rules") + .help("List available rules") + .action(ArgAction::SetTrue) + .help_heading(LINT_HEADING), + ) + .arg( + Arg::new("rules-tags") + .long("rules-tags") + .require_equals(true) + .num_args(1..) + .action(ArgAction::Append) + .use_value_delimiter(true) + .help("Use set of rules with a tag") + .help_heading(LINT_HEADING), + ) + .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") + .help_heading(LINT_HEADING), + ) + .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") + .help_heading(LINT_HEADING), + ) + .arg(no_config_arg()) + .arg(config_arg()) + .arg( + Arg::new("ignore") + .long("ignore") + .num_args(1..) + .use_value_delimiter(true) + .require_equals(true) + .help("Ignore linting particular source files") + .value_hint(ValueHint::AnyPath) + .help_heading(LINT_HEADING), + ) + .arg( + Arg::new("json") + .long("json") + .help("Output lint result in JSON format") + .action(ArgAction::SetTrue) + .help_heading(LINT_HEADING), + ) + .arg( + Arg::new("compact") + .long("compact") + .help("Output lint result in compact format") + .action(ArgAction::SetTrue) + .conflicts_with("json") + .help_heading(LINT_HEADING), + ) + .arg( + Arg::new("files") + .num_args(1..) + .action(ArgAction::Append) + .value_hint(ValueHint::AnyPath), + ) + .arg(watch_arg(false)) + .arg(watch_exclude_arg()) + .arg(no_clear_screen_arg()) + }) } fn repl_subcommand() -> Command { - Command::new("repl") - .about("Read Eval Print Loop") + command("repl", "Read Eval Print Loop", UnstableArgsConfig::ResolutionAndRuntime) .defer(|cmd| runtime_args(cmd, true, true) .arg(check_arg(false)) .arg( @@ -2633,7 +2702,11 @@ fn repl_subcommand() -> Command { .long("eval") .help("Evaluates the provided code when the REPL starts.") .value_name("code"), - )) + ) + .after_help(color_print::cstr!("Environment variables: + DENO_REPL_HISTORY Set REPL history file path. History file is disabled when the value is empty. + (defaults to $DENO_DIR/deno_history.txt)")) + ) .arg(env_file_arg()) } @@ -2641,15 +2714,15 @@ fn run_args(command: Command, top_level: bool) -> Command { runtime_args(command, true, true) .arg(check_arg(false)) .arg(watch_arg(true)) - .arg(watch_exclude_arg()) .arg(hmr_arg(true)) + .arg(watch_exclude_arg()) .arg(no_clear_screen_arg()) .arg(executable_ext_arg()) .arg(if top_level { script_arg().trailing_var_arg(true).hide(true) } else { script_arg() - .required_unless_present("v8-flags") + .required_unless_present_any(["help", "v8-flags"]) .trailing_var_arg(true) }) .arg(env_file_arg()) @@ -2657,9 +2730,7 @@ fn run_args(command: Command, top_level: bool) -> Command { } fn run_subcommand() -> Command { - run_args(Command::new("run"), false) - .about( - color_print::cstr!("Run a JavaScript or TypeScript program, or a task or script. + run_args(command("run", color_print::cstr!("Run a JavaScript or TypeScript program, or a task or script. By default all programs are run in sandbox without access to disk, network or ability to spawn subprocesses. deno run https://examples.deno.land/hello-world.ts @@ -2674,7 +2745,7 @@ Grant all permissions: deno run -A jsr:@std/http/file-server Specifying the filename '-' to read the file from stdin. - curl https://examples.deno.land/hello-world.ts | deno run -")) + curl https://examples.deno.land/hello-world.ts | deno run -"), UnstableArgsConfig::ResolutionAndRuntime), false) } fn serve_host_validator(host: &str) -> Result { @@ -2686,7 +2757,7 @@ fn serve_host_validator(host: &str) -> Result { } fn serve_subcommand() -> Command { - runtime_args(Command::new("serve"), true, true) + runtime_args(command("serve", None, UnstableArgsConfig::ResolutionAndRuntime), true, true) .arg( Arg::new("port") .long("port") @@ -2704,13 +2775,13 @@ fn serve_subcommand() -> Command { ) .arg(check_arg(false)) .arg(watch_arg(true)) - .arg(watch_exclude_arg()) .arg(hmr_arg(true)) + .arg(watch_exclude_arg()) .arg(no_clear_screen_arg()) .arg(executable_ext_arg()) .arg( script_arg() - .required_unless_present("v8-flags") + .required_unless_present_any(["help", "v8-flags"]) .trailing_var_arg(true), ) .arg(env_file_arg()) @@ -2733,30 +2804,30 @@ Start a server defined in server.ts, watching for changes and running on port 50 } fn task_subcommand() -> Command { - Command::new("task") - .about( - "Run a task defined in the configuration file + command( + "task", + "Run a task defined in the configuration file deno task build", - ) - .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), - ) - }) + UnstableArgsConfig::ResolutionAndRuntime, + ) + .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), + ) + }) } fn test_subcommand() -> Command { - Command::new("test") - .about( + command("test", "Run tests using Deno's built-in test runner. Evaluate the given modules, run all tests declared with 'Deno.test()' and @@ -2766,8 +2837,10 @@ report results to standard output: Directory arguments are expanded to all contained files matching the glob {*_,*.,}test.{js,mjs,ts,mts,jsx,tsx} or **/__tests__/**: deno test src/", + UnstableArgsConfig::ResolutionAndRuntime ) - .defer(|cmd| runtime_args(cmd, true, true) + .defer(|cmd| + runtime_args(cmd, true, true) .arg(check_arg(true)) .arg( Arg::new("ignore") @@ -2782,26 +2855,30 @@ Directory arguments are expanded to all contained files matching the glob Arg::new("no-run") .long("no-run") .help("Cache test modules, but don't run tests") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(TEST_HEADING), ) .arg( Arg::new("trace-ops") .long("trace-ops") .help("Deprecated alias for --trace-leaks.") .hide(true) - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(TEST_HEADING), ) .arg( Arg::new("trace-leaks") .long("trace-leaks") .help("Enable tracing of leaks. Useful when debugging leaking ops in test, but impacts test execution time.") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(TEST_HEADING), ) .arg( Arg::new("doc") .long("doc") .help("Type-check code blocks in JSDoc and Markdown") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(TEST_HEADING), ) .arg( Arg::new("fail-fast") @@ -2811,8 +2888,8 @@ Directory arguments are expanded to all contained files matching the glob .num_args(0..=1) .require_equals(true) .value_name("N") - .value_parser(value_parser!(NonZeroUsize)), - ) + .value_parser(value_parser!(NonZeroUsize)) + .help_heading(TEST_HEADING)) // TODO(@lucacasonato): remove for Deno 2.0 .arg( Arg::new("allow-none") @@ -2826,13 +2903,15 @@ Directory arguments are expanded to all contained files matching the glob .long("permit-no-files") .help("Don't return an error code if no test files were found") .conflicts_with("allow-none") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(TEST_HEADING), ) .arg( Arg::new("filter") .allow_hyphen_values(true) .long("filter") - .help("Run tests with this string or pattern in the test name"), + .help("Run tests with this string or pattern in the test name") + .help_heading(TEST_HEADING), ) .arg( Arg::new("shuffle") @@ -2841,7 +2920,8 @@ Directory arguments are expanded to all contained files matching the glob .help("Shuffle the order in which the tests are run") .num_args(0..=1) .require_equals(true) - .value_parser(value_parser!(u64)), + .value_parser(value_parser!(u64)) + .help_heading(TEST_HEADING), ) .arg( Arg::new("coverage") @@ -2853,14 +2933,16 @@ Directory arguments are expanded to all contained files matching the glob .conflicts_with("inspect") .conflicts_with("inspect-wait") .conflicts_with("inspect-brk") - .help("Collect coverage profile data into DIR. If DIR is not specified, it uses 'coverage/'."), + .help("Collect coverage profile data into DIR. If DIR is not specified, it uses 'coverage/'.") + .help_heading(TEST_HEADING), ) .arg( Arg::new("clean") .long("clean") .help("Empty the temporary coverage profile data directory before running tests. Note: running multiple `deno test --clean` calls in series or parallel for the same coverage directory may cause race conditions.") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(TEST_HEADING), ) .arg( parallel_arg("test modules", true) @@ -2872,7 +2954,8 @@ Directory arguments are expanded to all contained files matching the glob .help("deprecated: The `--jobs` flag is deprecated and will be removed in Deno 2.0. Use the `--parallel` flag with possibly the `DENO_JOBS` environment variable instead.") .hide(true) .num_args(0..=1) - .value_parser(value_parser!(NonZeroUsize)), + .value_parser(value_parser!(NonZeroUsize)) + .help_heading(TEST_HEADING), ) .arg( Arg::new("files") @@ -2895,12 +2978,14 @@ Directory arguments are expanded to all contained files matching the glob .value_name("PATH") .value_hint(ValueHint::FilePath) .help("Write a JUnit XML test report to PATH. Use '-' to write to stdout which is the default when PATH is not provided.") + .help_heading(TEST_HEADING) ) .arg( Arg::new("reporter") .long("reporter") .help("Select reporter to use. Default to 'pretty'.") .value_parser(["pretty", "dot", "junit", "tap"]) + .help_heading(TEST_HEADING) ) .arg(env_file_arg()) ) @@ -2909,7 +2994,7 @@ Directory arguments are expanded to all contained files matching the glob fn parallel_arg(descr: &str, jobs_fallback: bool) -> Arg { let arg = Arg::new("parallel") .long("parallel") - .help(format!("Run {descr} in parallel. Parallelism defaults to the number of available CPUs or the value in the DENO_JOBS environment variable.")) + .help(format!("Run {descr} in parallel. Parallelism defaults to the number of available CPUs or the value of the DENO_JOBS environment variable.")) .action(ArgAction::SetTrue); if jobs_fallback { arg.conflicts_with("jobs") @@ -2919,19 +3004,21 @@ fn parallel_arg(descr: &str, jobs_fallback: bool) -> Arg { } fn types_subcommand() -> Command { - Command::new("types").about( + command( + "types", "Print runtime TypeScript declarations. deno types > lib.deno.d.ts The declaration file could be saved and used for typing information.", + UnstableArgsConfig::None, ) } fn upgrade_subcommand() -> Command { - Command::new("upgrade") - .about( - "Upgrade deno executable to the given version. + command( + "upgrade", + "Upgrade deno executable to the given version. Defaults to latest. The version is downloaded from @@ -2941,57 +3028,63 @@ and is used to replace the current executable. 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", - ) - .hide(cfg!(not(feature = "upgrade"))) - .defer(|cmd| { - cmd - .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!(String)) - .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( - Arg::new("release-candidate") - .long("rc") - .help("Upgrade to a release candidate") - .conflicts_with_all(["canary", "version"]) - .action(ArgAction::SetTrue), - ) - .arg(ca_file_arg()) - }) + UnstableArgsConfig::None, + ) + .hide(cfg!(not(feature = "upgrade"))) + .defer(|cmd| { + cmd + .arg( + Arg::new("version") + .long("version") + .help("The version to upgrade to") + .help_heading(UPGRADE_HEADING), + ) + .arg( + Arg::new("output") + .long("output") + .help("The path to output the updated version to") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::FilePath) + .help_heading(UPGRADE_HEADING), + ) + .arg( + Arg::new("dry-run") + .long("dry-run") + .help("Perform all checks without replacing old exe") + .action(ArgAction::SetTrue) + .help_heading(UPGRADE_HEADING), + ) + .arg( + Arg::new("force") + .long("force") + .short('f') + .help("Replace current exe even if not out-of-date") + .action(ArgAction::SetTrue) + .help_heading(UPGRADE_HEADING), + ) + .arg( + Arg::new("canary") + .long("canary") + .help("Upgrade to canary builds") + .action(ArgAction::SetTrue) + .help_heading(UPGRADE_HEADING), + ) + .arg( + Arg::new("release-candidate") + .long("rc") + .help("Upgrade to a release candidate") + .conflicts_with_all(["canary", "version"]) + .action(ArgAction::SetTrue) + .help_heading(UPGRADE_HEADING), + ) + .arg(ca_file_arg()) + .arg(unsafely_ignore_certificate_errors_arg()) + }) } // TODO(bartlomieju): this subcommand is now deprecated, remove it in Deno 2. fn vendor_subcommand() -> Command { - Command::new("vendor") - .hide(true) - .about( + command("vendor", "⚠️ Warning: `deno vendor` is deprecated and will be removed in Deno 2.0. Add `\"vendor\": true` to your `deno.json` or use the `--vendor` flag instead. @@ -3005,13 +3098,15 @@ maps remote specifiers to the downloaded files. Remote modules and multiple modules may also be specified: deno vendor main.ts test.deps.ts jsr:@std/path", + UnstableArgsConfig::ResolutionOnly ) + .hide(true) .defer(|cmd| cmd .arg( Arg::new("specifiers") .num_args(1..) .action(ArgAction::Append) - .required(true), + .required_unless_present("help"), ) .arg( Arg::new("output") @@ -3036,18 +3131,20 @@ Remote modules and multiple modules may also be specified: .arg(node_modules_dir_arg()) .arg(vendor_arg()) .arg(reload_arg()) - .arg(ca_file_arg())) + .arg(ca_file_arg()) + .arg(unsafely_ignore_certificate_errors_arg()) + ) } fn publish_subcommand() -> Command { - Command::new("publish") - .about("Publish the current working directory's package or workspace") - // TODO: .long_about() + command("publish", "Publish the current working directory's package or workspace", UnstableArgsConfig::ResolutionOnly) .defer(|cmd| { - cmd.arg( + cmd + .arg( Arg::new("token") .long("token") .help("The API token to use when publishing. If unset, interactive authentication is be used") + .help_heading(PUBLISH_HEADING) ) .arg(config_arg()) .arg(no_config_arg()) @@ -3055,24 +3152,28 @@ fn publish_subcommand() -> Command { Arg::new("dry-run") .long("dry-run") .help("Prepare the package for publishing performing all checks and validations without uploading") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(PUBLISH_HEADING), ) .arg( Arg::new("allow-slow-types") .long("allow-slow-types") .help("Allow publishing with slow types") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(PUBLISH_HEADING), ) .arg( Arg::new("allow-dirty") .long("allow-dirty") .help("Allow publishing if the repository has uncommitted changed") - .action(ArgAction::SetTrue), + .action(ArgAction::SetTrue) + .help_heading(PUBLISH_HEADING), ).arg( Arg::new("no-provenance") .long("no-provenance") .help("Disable provenance attestation. Enabled by default on Github actions, publicly links the package to where it was built and published from.") .action(ArgAction::SetTrue) + .help_heading(PUBLISH_HEADING) ) .arg(check_arg(/* type checks by default */ true)) .arg(no_check_arg()) @@ -3097,12 +3198,40 @@ fn compile_args_without_check_args(app: Command) -> Command { .arg(lock_write_arg()) .arg(no_lock_arg()) .arg(ca_file_arg()) + .arg(unsafely_ignore_certificate_errors_arg()) } -static PERMISSIONS_HEADER: &str = "Permissions"; - fn permission_args(app: Command) -> Command { app + .after_help(color_print::cstr!(r#"Permission options: +Docs: https://docs.deno.com/go/permissions + + -A, --allow-all Allow all permissions. + -R, --{allow,deny}-read[=<...] Allow / deny file system read access. Optionally specify allowed / denied paths. + --allow-read | --allow-read="/etc,/var/log.txt" | --deny-read="/etc/hosts" + -W, --{allow,write}-read[=<...] Allow / deny file system write access. Optionally specify allowed / denied paths. + --allow-write | --allow-write="/etc,/var/log.txt" | --deny-write="/etc/hosts" + -N, --{allow,deny}-net[=<...] Allow / deny network access. Optionally specify allowed IP addresses and host names, with ports as necessary. + --allow-net | --allow-net="localhost:8080,deno.land" | --deny-net="deno.com" + -E --{allow,deny}-env[=<...] Allow / deny access to environment variables. Optionally specify accessible / inacessible environment variables. + --allow-env | --allow-env="PORT,HOME,PATH" | --deny-env="ACCESS_TOKEN" + -S --{allow,deny}-sys[=<...] Allow / deny access to OS information. Optionally allow / deny specific APIs by function name. + --allow-sys | --allow-sys="systemMemoryInfo,osRelease" | --deny-sys="hostname" + --{allow,deny}-run[=<...] Allow / deny running subprocesses. Optionally specify allowed / denied runnable program names. + --allow-run | --allow-run="whoami,ps" | --deny-run="cat" + --{allow,deny}-ffi[=<...] (Unstable) Allow / deny loading dynamic libraries. Optionally specify allowed / denied directories or files. + --allow-ffi | --allow-ffi="./libfoo.so" | --deny-ffi="./libfoo.so" + --{allow,deny}-hrtime Allow / deny high-resolution time measurement. Note: this can enable timing attacks and fingerprinting. + --no-prompt Always throw if required permission wasn't passed. Can also be set via the DENO_NO_PROMPT environment variable. +"#)) + .arg( + Arg::new("allow-all") + .short('A') + .long("allow-all") + .action(ArgAction::SetTrue) + .help("Allow all permissions.") + .hide(true), + ) .arg( Arg::new("allow-read") .long("allow-read") @@ -3111,13 +3240,10 @@ fn permission_args(app: Command) -> Command { .use_value_delimiter(true) .require_equals(true) .value_name("PATH") - .help( - "Allow file system read access. Optionally specify allowed paths.", - ) + .help("Allow file system read access. Optionally specify allowed paths.") .value_parser(value_parser!(String)) .value_hint(ValueHint::AnyPath) - .value_hint(ValueHint::AnyPath) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-read") @@ -3129,7 +3255,7 @@ fn permission_args(app: Command) -> Command { .help("Deny file system read access. Optionally specify denied paths.") .value_parser(value_parser!(String)) .value_hint(ValueHint::AnyPath) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("allow-write") @@ -3139,12 +3265,10 @@ fn permission_args(app: Command) -> Command { .use_value_delimiter(true) .require_equals(true) .value_name("PATH") - .help( - "Allow file system write access. Optionally specify allowed paths.", - ) + .help("Allow file system write access. Optionally specify allowed paths.") .value_parser(value_parser!(String)) .value_hint(ValueHint::AnyPath) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-write") @@ -3156,7 +3280,7 @@ fn permission_args(app: Command) -> Command { .help("Deny file system write access. Optionally specify denied paths.") .value_parser(value_parser!(String)) .value_hint(ValueHint::AnyPath) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("allow-net") @@ -3168,7 +3292,7 @@ fn permission_args(app: Command) -> Command { .value_name("IP_OR_HOSTNAME") .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.") .value_parser(flags_net::validator) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-net") @@ -3179,18 +3303,7 @@ fn permission_args(app: Command) -> Command { .value_name("IP_OR_HOSTNAME") .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary.") .value_parser(flags_net::validator) - .help_heading(PERMISSIONS_HEADER), - ) - .arg( - Arg::new("unsafely-ignore-certificate-errors") - .long("unsafely-ignore-certificate-errors") - .hide(true) - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("HOSTNAMES") - .help("DANGER: Disables verification of TLS certificates") - .value_parser(flags_net::validator), + .hide(true), ) .arg( Arg::new("allow-env") @@ -3212,7 +3325,7 @@ fn permission_args(app: Command) -> Command { key.to_string() }) }) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-env") @@ -3233,7 +3346,7 @@ fn permission_args(app: Command) -> Command { key.to_string() }) }) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("allow-sys") @@ -3245,7 +3358,7 @@ fn permission_args(app: Command) -> Command { .value_name("API_NAME") .help("Allow access to OS information. Optionally allow specific APIs by function name.") .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-sys") @@ -3256,7 +3369,7 @@ fn permission_args(app: Command) -> Command { .value_name("API_NAME") .help("Deny access to OS information. Optionally deny specific APIs by function name.") .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("allow-run") @@ -3266,7 +3379,7 @@ fn permission_args(app: Command) -> Command { .require_equals(true) .value_name("PROGRAM_NAME") .help("Allow running subprocesses. Optionally specify allowed runnable program names.") - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-run") @@ -3276,7 +3389,7 @@ fn permission_args(app: Command) -> Command { .require_equals(true) .value_name("PROGRAM_NAME") .help("Deny running subprocesses. Optionally specify denied runnable program names.") - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("allow-ffi") @@ -3288,7 +3401,7 @@ fn permission_args(app: Command) -> Command { .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.") .value_parser(value_parser!(String)) .value_hint(ValueHint::AnyPath) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-ffi") @@ -3300,36 +3413,28 @@ fn permission_args(app: Command) -> Command { .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.") .value_parser(value_parser!(String)) .value_hint(ValueHint::AnyPath) - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("allow-hrtime") .long("allow-hrtime") .action(ArgAction::SetTrue) .help("Allow high-resolution time measurement. Note: this can enable timing attacks and fingerprinting.") - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("deny-hrtime") .long("deny-hrtime") .action(ArgAction::SetTrue) .help("Deny high-resolution time measurement. Note: this can prevent timing attacks and fingerprinting.") - .help_heading(PERMISSIONS_HEADER), - ) - .arg( - Arg::new("allow-all") - .short('A') - .long("allow-all") - .action(ArgAction::SetTrue) - .help("Allow all permissions.") - .help_heading(PERMISSIONS_HEADER), + .hide(true), ) .arg( Arg::new("no-prompt") .long("no-prompt") .action(ArgAction::SetTrue) - .help("Always throw if required permission wasn't passed") - .help_heading(PERMISSIONS_HEADER), + .hide(true) + .help("Always throw if required permission wasn't passed"), ) } @@ -3368,7 +3473,8 @@ fn inspect_args(app: Command) -> Command { .help("Activate inspector on host:port (default: 127.0.0.1:9229)") .num_args(0..=1) .require_equals(true) - .value_parser(value_parser!(SocketAddr)), + .value_parser(value_parser!(SocketAddr)) + .help_heading(DEBUGGING_HEADING), ) .arg( Arg::new("inspect-brk") @@ -3379,7 +3485,8 @@ fn inspect_args(app: Command) -> Command { ) .num_args(0..=1) .require_equals(true) - .value_parser(value_parser!(SocketAddr)), + .value_parser(value_parser!(SocketAddr)) + .help_heading(DEBUGGING_HEADING), ) .arg( Arg::new("inspect-wait") @@ -3390,7 +3497,8 @@ fn inspect_args(app: Command) -> Command { ) .num_args(0..=1) .require_equals(true) - .value_parser(value_parser!(SocketAddr)), + .value_parser(value_parser!(SocketAddr)) + .help_heading(DEBUGGING_HEADING), ) } @@ -3404,6 +3512,7 @@ fn import_map_arg() -> Arg { Docs: https://docs.deno.com/runtime/manual/basics/import_maps", ) .value_hint(ValueHint::FilePath) + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn env_file_arg() -> Arg { @@ -3412,7 +3521,7 @@ fn env_file_arg() -> Arg { .alias("env") .value_name("FILE") .help( - "UNSTABLE: Load environment variables from local file. + "Load environment variables from local file. Only the first environment variable with a given key is used. Existing process environment variables are not overwritten.", ) @@ -3439,6 +3548,7 @@ fn reload_arg() -> Arg { )) .value_hint(ValueHint::FilePath) .value_parser(reload_arg_validate) + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn ca_file_arg() -> Arg { @@ -3454,6 +3564,7 @@ fn cached_only_arg() -> Arg { .long("cached-only") .action(ArgAction::SetTrue) .help("Require that remote dependencies are already cached") + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn frozen_lockfile_arg() -> Arg { @@ -3466,6 +3577,7 @@ fn frozen_lockfile_arg() -> Arg { .require_equals(true) .default_missing_value("true") .help("Error out if lockfile is out of date") + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } /// Used for subcommands that operate on executable scripts only. @@ -3527,7 +3639,8 @@ fn v8_flags_arg() -> Arg { .require_equals(true) .value_name("V8_FLAGS") .help("To see a list of all available flags use --v8-flags=--help. - Any flags set with this flag are appended after the DENO_V8_FLAGS environmental variable") + Flags can also be set via the DENO_V8_FLAGS environment variable. + Any flags set with this flag are appended after the DENO_V8_FLAGS environment variable") } fn seed_arg() -> Arg { @@ -3544,7 +3657,8 @@ fn hmr_arg(takes_files: bool) -> Arg { // NOTE(bartlomieju): compatibility with Deno pre-1.46 .alias("unstable-hmr") .help("Watch for file changes and hot replace modules") - .conflicts_with("watch"); + .conflicts_with("watch") + .help_heading(FILE_WATCHING_HEADING); if takes_files { arg @@ -3554,21 +3668,24 @@ fn hmr_arg(takes_files: bool) -> Arg { .use_value_delimiter(true) .require_equals(true) .help( - "UNSTABLE: Watch for file changes and restart process automatically. - Local files from entry point module graph are watched by default. - Additional paths might be watched by passing them as arguments to this flag.", + color_print::cstr!( + "Watch for file changes and restart process automatically. + Local files from entry point module graph are watched by default. + Additional paths might be watched by passing them as arguments to this flag."), ) .value_hint(ValueHint::AnyPath) } else { - arg.action(ArgAction::SetTrue).help( - "UNSTABLE: Watch for file changes and restart process automatically. - Only local files from entry point module graph are watched.", - ) + arg.action(ArgAction::SetTrue).help(color_print::cstr!( + "Watch for file changes and restart process automatically. + Only local files from entry point module graph are watched." + )) } } fn watch_arg(takes_files: bool) -> Arg { - let arg = Arg::new("watch").long("watch"); + let arg = Arg::new("watch") + .long("watch") + .help_heading(FILE_WATCHING_HEADING); if takes_files { arg @@ -3578,16 +3695,17 @@ fn watch_arg(takes_files: bool) -> Arg { .use_value_delimiter(true) .require_equals(true) .help( + color_print::cstr!( "Watch for file changes and restart process automatically. - Local files from entry point module graph are watched by default. - Additional paths might be watched by passing them as arguments to this flag.", + Local files from entry point module graph are watched by default. + Additional paths might be watched by passing them as arguments to this flag."), ) .value_hint(ValueHint::AnyPath) } else { - arg.action(ArgAction::SetTrue).help( + arg.action(ArgAction::SetTrue).help(color_print::cstr!( "Watch for file changes and restart process automatically. - Only local files from entry point module graph are watched.", - ) + Only local files from entry point module graph are watched." + )) } } @@ -3597,6 +3715,7 @@ fn no_clear_screen_arg() -> Arg { .long("no-clear-screen") .action(ArgAction::SetTrue) .help("Do not clear terminal screen when under watch mode") + .help_heading(FILE_WATCHING_HEADING) } fn no_code_cache_arg() -> Arg { @@ -3616,6 +3735,7 @@ fn watch_exclude_arg() -> Arg { .use_value_delimiter(true) .require_equals(true) .value_hint(ValueHint::AnyPath) + .help_heading(FILE_WATCHING_HEADING) } fn no_check_arg() -> Arg { @@ -3628,6 +3748,7 @@ fn no_check_arg() -> Arg { "Skip type-checking. If the value of '--no-check=remote' is supplied, diagnostic errors from remote modules will be ignored.", ) + .help_heading(TYPE_CHECKING_HEADING) } fn check_arg(checks_local_by_default: bool) -> Arg { @@ -3636,7 +3757,8 @@ fn check_arg(checks_local_by_default: bool) -> Arg { .long("check") .num_args(0..=1) .require_equals(true) - .value_name("CHECK_TYPE"); + .value_name("CHECK_TYPE") + .help_heading(TYPE_CHECKING_HEADING); if checks_local_by_default { arg.help( @@ -3679,6 +3801,7 @@ fn lock_arg() -> Arg { .num_args(0..=1) .value_parser(value_parser!(String)) .value_hint(ValueHint::FilePath) + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } // TODO(bartlomieju): deprecated, to be removed in Deno 2. @@ -3697,6 +3820,7 @@ fn no_lock_arg() -> Arg { .action(ArgAction::SetTrue) .help("Disable auto discovery of the lock file") .conflicts_with("lock") + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn config_arg() -> Arg { @@ -3724,6 +3848,7 @@ fn no_remote_arg() -> Arg { .long("no-remote") .action(ArgAction::SetTrue) .help("Do not resolve remote modules") + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn no_npm_arg() -> Arg { @@ -3731,6 +3856,7 @@ fn no_npm_arg() -> Arg { .long("no-npm") .action(ArgAction::SetTrue) .help("Do not resolve npm modules") + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn node_modules_dir_arg() -> Arg { @@ -3742,6 +3868,7 @@ fn node_modules_dir_arg() -> Arg { .default_missing_value("true") .require_equals(true) .help("Enables or disables the use of a local node_modules folder for npm packages") + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) } fn vendor_arg() -> Arg { @@ -3752,9 +3879,22 @@ fn vendor_arg() -> Arg { .default_missing_value("true") .require_equals(true) .help( - "UNSTABLE: Enables or disables the use of a local vendor folder + "Enables or disables the use of a local vendor folder for remote modules and node_modules folder for npm packages", ) + .help_heading(DEPENDENCY_MANAGEMENT_HEADING) +} + +fn unsafely_ignore_certificate_errors_arg() -> Arg { + Arg::new("unsafely-ignore-certificate-errors") + .hide(true) + .long("unsafely-ignore-certificate-errors") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("HOSTNAMES") + .help("DANGER: Disables verification of TLS certificates") + .value_parser(flags_net::validator) } fn allow_scripts_arg() -> Arg { @@ -3768,6 +3908,97 @@ fn allow_scripts_arg() -> Arg { .help("Allow running npm lifecycle scripts for the given packages. Note: Scripts will only be executed when using a node_modules directory (`--node-modules-dir`)") } +enum UnstableArgsConfig { + // for backwards-compatability + None, + ResolutionOnly, + ResolutionAndRuntime, +} + +struct UnstableArgsIter { + idx: usize, + cfg: UnstableArgsConfig, +} + +impl Iterator for UnstableArgsIter { + type Item = Arg; + + fn next(&mut self) -> Option { + let arg = if self.idx == 0 { + Arg::new("unstable") + .long("unstable") + .help("Enable all unstable features and APIs. Instead of using this flag, consider enabling individual unstable features.\n To view the list of individual unstable feature flags, run this command again with --help=unstable.") + .action(ArgAction::SetTrue) + .hide(matches!(self.cfg, UnstableArgsConfig::None)) + } else if self.idx == 1 { + Arg::new("unstable-bare-node-builtins") + .long("unstable-bare-node-builtins") + .help("Enable unstable bare node builtins feature") + .env("DENO_UNSTABLE_BARE_NODE_BUILTINS") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue) + .hide(true) + .long_help(match self.cfg { + UnstableArgsConfig::None => None, + UnstableArgsConfig::ResolutionOnly + | UnstableArgsConfig::ResolutionAndRuntime => Some("true"), + }) + .help_heading(UNSTABLE_HEADING) + } else if self.idx == 2 { + Arg::new("unstable-byonm") + .long("unstable-byonm") + .help("Enable unstable 'bring your own node_modules' feature") + .env("DENO_UNSTABLE_BYONM") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue) + .hide(true) + .long_help(match self.cfg { + UnstableArgsConfig::None => None, + UnstableArgsConfig::ResolutionOnly + | UnstableArgsConfig::ResolutionAndRuntime => Some("true"), + }) + .help_heading(UNSTABLE_HEADING) + } else if self.idx == 3 { + Arg::new("unstable-sloppy-imports") + .long("unstable-sloppy-imports") + .help( + "Enable unstable resolving of specifiers by extension probing, .js to .ts, and directory probing.", + ) + .env("DENO_UNSTABLE_SLOPPY_IMPORTS") + .value_parser(FalseyValueParser::new()) + .action(ArgAction::SetTrue) + .hide(true) + .long_help(match self.cfg { + UnstableArgsConfig::None => None, + UnstableArgsConfig::ResolutionOnly | UnstableArgsConfig::ResolutionAndRuntime => Some("true") + }) + .help_heading(UNSTABLE_HEADING) + } else if self.idx > 3 { + let (flag_name, help, _) = + crate::UNSTABLE_GRANULAR_FLAGS.get(self.idx - 4)?; + Arg::new(format!("unstable-{}", flag_name)) + .long(format!("unstable-{}", flag_name)) + .help(help) + .action(ArgAction::SetTrue) + .hide(true) + .help_heading(UNSTABLE_HEADING) + // we don't render long help, so using it here as a sort of metadata + .long_help(match self.cfg { + UnstableArgsConfig::None | UnstableArgsConfig::ResolutionOnly => None, + UnstableArgsConfig::ResolutionAndRuntime => Some("true"), + }) + } else { + return None; + }; + self.idx += 1; + Some(arg.display_order(self.idx + 1000)) + } +} + +fn unstable_args(cfg: UnstableArgsConfig) -> impl IntoIterator { + UnstableArgsIter { idx: 0, cfg } +} + fn allow_scripts_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { let Some(parts) = matches.remove_many::("allow-scripts") else { return; @@ -3844,6 +4075,7 @@ fn bundle_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; compile_args_parse(flags, matches); + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); let source_file = matches.remove_one::("source_file").unwrap(); @@ -3866,6 +4098,7 @@ fn bundle_parse(flags: &mut Flags, matches: &mut ArgMatches) { fn cache_parse(flags: &mut Flags, matches: &mut ArgMatches) { compile_args_parse(flags, matches); + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); frozen_lockfile_arg_parse(flags, matches); allow_scripts_arg_parse(flags, matches); let files = matches.remove_many::("file").unwrap().collect(); @@ -3875,6 +4108,7 @@ fn cache_parse(flags: &mut Flags, matches: &mut ArgMatches) { fn check_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; compile_args_without_check_parse(flags, matches); + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime); let files = matches.remove_many::("file").unwrap().collect(); if matches.get_flag("all") || matches.get_flag("remote") { flags.type_check_mode = TypeCheckMode::All; @@ -3983,6 +4217,7 @@ fn coverage_parse(flags: &mut Flags, matches: &mut ArgMatches) { } fn doc_parse(flags: &mut Flags, matches: &mut ArgMatches) { + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); import_map_arg_parse(flags, matches); reload_arg_parse(flags, matches); lock_arg_parse(flags, matches); @@ -4047,6 +4282,7 @@ fn doc_parse(flags: &mut Flags, matches: &mut ArgMatches) { fn eval_parse(flags: &mut Flags, matches: &mut ArgMatches) { runtime_args_parse(flags, matches, false, true); + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime); flags.allow_all(); ext_arg_parse(flags, matches); @@ -4124,11 +4360,13 @@ fn init_parse(flags: &mut Flags, matches: &mut ArgMatches) { } fn info_parse(flags: &mut Flags, matches: &mut ArgMatches) { + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); reload_arg_parse(flags, matches); config_args_parse(flags, matches); import_map_arg_parse(flags, matches); location_arg_parse(flags, matches); ca_file_arg_parse(flags, matches); + unsafely_ignore_certificate_errors_parse(flags, matches); node_modules_and_vendor_dir_arg_parse(flags, matches); lock_args_parse(flags, matches); no_remote_arg_parse(flags, matches); @@ -4278,6 +4516,8 @@ fn lsp_parse(flags: &mut Flags, _matches: &mut ArgMatches) { } fn lint_parse(flags: &mut Flags, matches: &mut ArgMatches) { + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); + config_args_parse(flags, matches); let files = match matches.remove_many::("files") { Some(f) => f.collect(), @@ -4488,6 +4728,8 @@ fn task_parse(flags: &mut Flags, matches: &mut ArgMatches) { .map(ConfigFlag::Path) .unwrap_or(ConfigFlag::Discover); + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime); + let mut task_flags = TaskFlags { cwd: matches.remove_one::("cwd"), task: None, @@ -4661,6 +4903,7 @@ fn types_parse(flags: &mut Flags, _matches: &mut ArgMatches) { fn upgrade_parse(flags: &mut Flags, matches: &mut ArgMatches) { ca_file_arg_parse(flags, matches); + unsafely_ignore_certificate_errors_parse(flags, matches); let dry_run = matches.get_flag("dry-run"); let force = matches.get_flag("force"); @@ -4679,7 +4922,9 @@ fn upgrade_parse(flags: &mut Flags, matches: &mut ArgMatches) { } fn vendor_parse(flags: &mut Flags, matches: &mut ArgMatches) { + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); ca_file_arg_parse(flags, matches); + unsafely_ignore_certificate_errors_parse(flags, matches); config_args_parse(flags, matches); import_map_arg_parse(flags, matches); lock_arg_parse(flags, matches); @@ -4698,6 +4943,7 @@ fn vendor_parse(flags: &mut Flags, matches: &mut ArgMatches) { fn publish_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; // local by default + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly); no_check_arg_parse(flags, matches); check_arg_parse(flags, matches); config_args_parse(flags, matches); @@ -4729,10 +4975,10 @@ fn compile_args_without_check_parse( reload_arg_parse(flags, matches); lock_args_parse(flags, matches); ca_file_arg_parse(flags, matches); + unsafely_ignore_certificate_errors_parse(flags, matches); } fn permission_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { - unsafely_ignore_certificate_errors_parse(flags, matches); if let Some(read_wl) = matches.remove_many::("allow-read") { flags.permissions.allow_read = Some(read_wl.collect()); } @@ -4834,6 +5080,7 @@ fn runtime_args_parse( include_perms: bool, include_inspector: bool, ) { + unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime); compile_args_parse(flags, matches); cached_only_arg_parse(flags, matches); frozen_lockfile_arg_parse(flags, matches); @@ -5089,6 +5336,30 @@ fn watch_arg_parse_with_paths( }) } +fn unstable_args_parse( + flags: &mut Flags, + matches: &mut ArgMatches, + cfg: UnstableArgsConfig, +) { + if matches.get_flag("unstable") { + flags.unstable_config.legacy_flag_enabled = true; + } + + flags.unstable_config.bare_node_builtins = + matches.get_flag("unstable-bare-node-builtins"); + flags.unstable_config.byonm = matches.get_flag("unstable-byonm"); + flags.unstable_config.sloppy_imports = + matches.get_flag("unstable-sloppy-imports"); + + if matches!(cfg, UnstableArgsConfig::ResolutionAndRuntime) { + for (name, _, _) in crate::UNSTABLE_GRANULAR_FLAGS { + if matches.get_flag(&format!("unstable-{}", name)) { + flags.unstable_config.features.push(name.to_string()); + } + } + } +} + // TODO(ry) move this to utility module and add test. /// Strips fragment part of URL. Panics on bad URL. pub fn resolve_urls(urls: Vec) -> Vec { @@ -5121,7 +5392,7 @@ mod tests { #[test] fn global_flags() { #[rustfmt::skip] - let r = flags_from_vec(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]); + let r = flags_from_vec(svec!["deno", "--log-level", "debug", "--quiet", "run", "script.ts"]); let flags = r.unwrap(); assert_eq!( @@ -5130,17 +5401,13 @@ mod tests { subcommand: DenoSubcommand::Run(RunFlags::new_default( "script.ts".to_string() )), - unstable_config: UnstableConfig { - legacy_flag_enabled: true, - ..Default::default() - }, log_level: Some(Level::Error), code_cache_enabled: true, ..Flags::default() } ); #[rustfmt::skip] - let r2 = flags_from_vec(svec!["deno", "run", "--unstable", "--log-level", "debug", "--quiet", "script.ts"]); + let r2 = flags_from_vec(svec!["deno", "run", "--log-level", "debug", "--quiet", "script.ts"]); let flags2 = r2.unwrap(); assert_eq!(flags2, flags); } @@ -5814,7 +6081,7 @@ mod tests { #[test] fn short_permission_flags() { - let r = flags_from_vec(svec!["deno", "run", "-RW", "gist.ts"]); + let r = flags_from_vec(svec!["deno", "run", "-RNESW", "gist.ts"]); assert_eq!( r.unwrap(), Flags { @@ -5824,6 +6091,9 @@ mod tests { permissions: PermissionFlags { allow_read: Some(vec![]), allow_write: Some(vec![]), + allow_env: Some(vec![]), + allow_net: Some(vec![]), + allow_sys: Some(vec![]), ..Default::default() }, code_cache_enabled: true, @@ -8015,7 +8285,7 @@ mod tests { #[test] fn uninstall_with_help_flag() { let r = flags_from_vec(svec!["deno", "uninstall", "--help"]); - assert_eq!(r.err().unwrap().kind(), clap::error::ErrorKind::DisplayHelp); + assert!(r.is_ok()); } #[test] @@ -9929,8 +10199,7 @@ mod tests { #[test] fn task_with_global_flags() { // can fail if the custom parser in task_parse() starts at the wrong index - let r = - flags_from_vec(svec!["deno", "--quiet", "--unstable", "task", "build"]); + let r = flags_from_vec(svec!["deno", "--quiet", "task", "build"]); assert_eq!( r.unwrap(), Flags { @@ -9938,10 +10207,6 @@ mod tests { cwd: None, task: Some("build".to_string()), }), - unstable_config: UnstableConfig { - legacy_flag_enabled: true, - ..Default::default() - }, log_level: Some(log::Level::Error), ..Flags::default() } diff --git a/cli/main.rs b/cli/main.rs index 9b141c5367..aafa7f009f 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -402,8 +402,7 @@ fn resolve_flags_and_init( let flags = match flags_from_vec(args) { Ok(flags) => flags, Err(err @ clap::Error { .. }) - if err.kind() == clap::error::ErrorKind::DisplayHelp - || err.kind() == clap::error::ErrorKind::DisplayVersion => + if err.kind() == clap::error::ErrorKind::DisplayVersion => { // Ignore results to avoid BrokenPipe errors. let _ = err.print(); diff --git a/cli/tools/jupyter/server.rs b/cli/tools/jupyter/server.rs index bcfc522128..0cd80f7ddd 100644 --- a/cli/tools/jupyter/server.rs +++ b/cli/tools/jupyter/server.rs @@ -683,7 +683,7 @@ fn kernel_info() -> messaging::KernelInfoReply { banner: "Welcome to Deno kernel".to_string(), help_links: vec![messaging::HelpLink { text: "Visit Deno manual".to_string(), - url: "https://deno.land/manual".to_string(), + url: "https://docs.deno.com".to_string(), }], debugger: false, error: None, diff --git a/cli/tools/task.rs b/cli/tools/task.rs index f559ab9b42..0110d17414 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -35,7 +35,7 @@ pub async fn execute_script( let cli_options = factory.cli_options()?; let start_dir = &cli_options.start_dir; if !start_dir.has_deno_or_pkg_json() { - bail!("deno task couldn't find deno.json(c). See https://deno.land/manual@v{}/getting_started/configuration_file", env!("CARGO_PKG_VERSION")) + bail!("deno task couldn't find deno.json(c). See https://docs.deno.com/go/config") } let force_use_pkg_json = std::env::var_os(crate::task_runner::USE_PKG_JSON_HIDDEN_ENV_VAR_NAME) diff --git a/tests/integration/watcher_tests.rs b/tests/integration/watcher_tests.rs index 6203a62d96..9685d7ae8b 100644 --- a/tests/integration/watcher_tests.rs +++ b/tests/integration/watcher_tests.rs @@ -323,7 +323,6 @@ async fn lint_all_files_on_each_change_test() { .arg("lint") .arg(t.path()) .arg("--watch") - .arg("--unstable") .piped_output() .spawn() .unwrap(); @@ -470,7 +469,6 @@ async fn fmt_check_all_files_on_each_change_test() { .arg(t.path()) .arg("--watch") .arg("--check") - .arg("--unstable") .piped_output() .spawn() .unwrap();