diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2023-03-26 06:06:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-26 06:06:18 +0200 |
commit | 33362b88c3ef14c1ed36994f8740cb6e05c6e2fe (patch) | |
tree | b60e11febd57047606c16a5b52bd26d7dc4ef06b /cli/args/flags.rs | |
parent | 8a4865c3790a6eb93d95189e129b3ee98f349b45 (diff) |
chore: upgrade clap to v4 (#17333)
Diffstat (limited to 'cli/args/flags.rs')
-rw-r--r-- | cli/args/flags.rs | 1336 |
1 files changed, 567 insertions, 769 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs index e85938822..dd2a40913 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1,11 +1,12 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +use clap::value_parser; use clap::Arg; +use clap::ArgAction; use clap::ArgMatches; use clap::ColorChoice; use clap::Command; use clap::ValueHint; -use deno_core::error::AnyError; use deno_core::resolve_url_or_path; use deno_core::url::Url; use deno_runtime::permissions::parse_sys_kind; @@ -639,59 +640,62 @@ To evaluate code in the shell: }); /// Main entry point for parsing deno's command line flags. -pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> { - let version = crate::version::deno(); - let mut app = clap_root(version); - let matches = app.try_get_matches_from_mut(&args)?; +pub fn flags_from_vec(args: Vec<String>) -> clap::error::Result<Flags> { + let mut app = clap_root(); + let mut matches = app.try_get_matches_from_mut(&args)?; let mut flags = Flags::default(); - if matches.is_present("unstable") { + if matches.get_flag("unstable") { flags.unstable = true; } - if matches.is_present("quiet") { + if matches.get_flag("quiet") { flags.log_level = Some(Level::Error); - } else { - match matches.value_of("log-level") { - Some("debug") => flags.log_level = Some(Level::Debug), - Some("info") => flags.log_level = Some(Level::Info), - _ => {} - } + } else if let Some(log_level) = matches.get_one::<String>("log-level") { + flags.log_level = match log_level.as_str() { + "debug" => Some(Level::Debug), + "info" => Some(Level::Info), + _ => unreachable!(), + }; } - match matches.subcommand() { - Some(("bench", m)) => bench_parse(&mut flags, m), - Some(("bundle", m)) => bundle_parse(&mut flags, m), - Some(("cache", m)) => cache_parse(&mut flags, m), - Some(("check", m)) => check_parse(&mut flags, m), - Some(("compile", m)) => compile_parse(&mut flags, m), - Some(("completions", m)) => completions_parse(&mut flags, m, app), - Some(("coverage", m)) => coverage_parse(&mut flags, m), - Some(("doc", m)) => doc_parse(&mut flags, m), - Some(("eval", m)) => eval_parse(&mut flags, m), - Some(("fmt", m)) => fmt_parse(&mut flags, m), - Some(("init", m)) => init_parse(&mut flags, m), - Some(("info", m)) => info_parse(&mut flags, m), - Some(("install", m)) => install_parse(&mut flags, m), - Some(("lint", m)) => lint_parse(&mut flags, m), - Some(("lsp", m)) => lsp_parse(&mut flags, m), - Some(("repl", m)) => repl_parse(&mut flags, m), - Some(("run", m)) => run_parse(&mut flags, m), - Some(("task", m)) => task_parse(&mut flags, m, &args), - Some(("test", m)) => test_parse(&mut flags, m), - Some(("types", m)) => types_parse(&mut flags, m), - Some(("uninstall", m)) => uninstall_parse(&mut flags, m), - Some(("upgrade", m)) => upgrade_parse(&mut flags, m), - Some(("vendor", m)) => vendor_parse(&mut flags, m), - _ => handle_repl_flags( + if let Some((subcommand, mut m)) = matches.remove_subcommand() { + match subcommand.as_str() { + "bench" => bench_parse(&mut flags, &mut m), + "bundle" => bundle_parse(&mut flags, &mut m), + "cache" => cache_parse(&mut flags, &mut m), + "check" => check_parse(&mut flags, &mut m), + "compile" => compile_parse(&mut flags, &mut m), + "completions" => completions_parse(&mut flags, &mut m, app), + "coverage" => coverage_parse(&mut flags, &mut m), + "doc" => doc_parse(&mut flags, &mut m), + "eval" => eval_parse(&mut flags, &mut m), + "fmt" => fmt_parse(&mut flags, &mut m), + "init" => init_parse(&mut flags, &mut m), + "info" => info_parse(&mut flags, &mut m), + "install" => install_parse(&mut flags, &mut m), + "lint" => lint_parse(&mut flags, &mut m), + "lsp" => lsp_parse(&mut flags, &mut m), + "repl" => repl_parse(&mut flags, &mut m), + "run" => run_parse(&mut flags, &mut m), + "task" => task_parse(&mut flags, &mut m), + "test" => test_parse(&mut flags, &mut m), + "types" => types_parse(&mut flags, &mut m), + "uninstall" => uninstall_parse(&mut flags, &mut m), + "upgrade" => upgrade_parse(&mut flags, &mut m), + "vendor" => vendor_parse(&mut flags, &mut m), + _ => unreachable!(), + } + } else { + handle_repl_flags( &mut flags, ReplFlags { eval_files: None, eval: None, is_default_command: true, }, - ), + ) } Ok(flags) @@ -712,17 +716,18 @@ fn handle_repl_flags(flags: &mut Flags, repl_flags: ReplFlags) { flags.subcommand = DenoSubcommand::Repl(repl_flags); } -fn clap_root(version: &'static str) -> Command { - clap::Command::new("deno") +fn clap_root() -> Command { + Command::new("deno") .bin_name("deno") .color(ColorChoice::Never) .max_term_width(80) - .version(version) + .version(crate::version::deno()) .long_version(LONG_VERSION.as_str()) .arg( Arg::new("unstable") .long("unstable") .help("Enable unstable features and APIs") + .action(ArgAction::SetTrue) .global(true), ) .arg( @@ -731,8 +736,7 @@ fn clap_root(version: &'static str) -> Command { .long("log-level") .help("Set log level") .hide(true) - .takes_value(true) - .possible_values(["debug", "info"]) + .value_parser(["debug", "info"]) .global(true), ) .arg( @@ -740,6 +744,7 @@ fn clap_root(version: &'static str) -> Command { .short('q') .long("quiet") .help("Suppress diagnostic output") + .action(ArgAction::SetTrue) .global(true), ) .subcommand(bench_subcommand()) @@ -769,36 +774,35 @@ fn clap_root(version: &'static str) -> Command { .after_help(ENV_VARIABLES_HELP) } -fn bench_subcommand<'a>() -> Command<'a> { +fn bench_subcommand() -> Command { runtime_args(Command::new("bench"), true, false) - .trailing_var_arg(true) .arg( Arg::new("json") .long("json") - .help("UNSTABLE: Output benchmark result in JSON format") - .takes_value(false), + .action(ArgAction::SetTrue) + .help("UNSTABLE: Output benchmark result in JSON format"), ) .arg( Arg::new("ignore") .long("ignore") - .takes_value(true) + .num_args(1..) .use_value_delimiter(true) .require_equals(true) - .help("Ignore files"), + .help("Ignore files") + .value_parser(value_parser!(PathBuf)), ) .arg( Arg::new("filter") - .allow_hyphen_values(true) .long("filter") - .takes_value(true) + .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") - .takes_value(true) - .multiple_values(true) - .multiple_occurrences(true), + .num_args(..) + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Append), ) .arg(watch_arg(false)) .arg(no_clear_screen_arg()) @@ -819,19 +823,17 @@ glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: ) } -fn bundle_subcommand<'a>() -> Command<'a> { +fn bundle_subcommand() -> Command { compile_args(Command::new("bundle")) .hide(true) .arg( Arg::new("source_file") - .takes_value(true) .required(true) .value_hint(ValueHint::FilePath), ) .arg( Arg::new("out_file") - .takes_value(true) - .required(false) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::FilePath), ) .arg(watch_arg(false)) @@ -849,13 +851,12 @@ If no output file is given, the output is written to standard output: ) } -fn cache_subcommand<'a>() -> Command<'a> { +fn cache_subcommand() -> Command { compile_args(Command::new("cache")) .arg( Arg::new("file") - .takes_value(true) + .num_args(1..) .required(true) - .min_values(1) .value_hint(ValueHint::FilePath), ) .about("Cache the dependencies") @@ -872,12 +873,13 @@ Future runs of this module will trigger no downloads or compilation unless \ ) } -fn check_subcommand<'a>() -> Command<'a> { +fn check_subcommand() -> Command { compile_args_without_check_args(Command::new("check")) .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( @@ -885,14 +887,14 @@ fn check_subcommand<'a>() -> Command<'a> { 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") - .takes_value(true) + .num_args(1..) .required(true) - .min_values(1) .value_hint(ValueHint::FilePath), ) .about("Type-check the dependencies") @@ -905,9 +907,8 @@ Unless --reload is specified, this command will not re-download already cached d ) } -fn compile_subcommand<'a>() -> Command<'a> { +fn compile_subcommand() -> Command { runtime_args(Command::new("compile"), true, false) - .trailing_var_arg(true) .arg(script_arg().required(true)) .arg( Arg::new("include") @@ -919,24 +920,22 @@ fn compile_subcommand<'a>() -> Command<'a> { module fails to load in the executable. This flag can be passed multiple \ times, to include multiple additional modules.", ) - .takes_value(true) - .multiple_occurrences(true) + .action(ArgAction::Append) .value_hint(ValueHint::FilePath), ) .arg( Arg::new("output") .long("output") .short('o') + .value_parser(value_parser!(PathBuf)) .help("Output file (defaults to $PWD/<inferred-name>)") - .takes_value(true) .value_hint(ValueHint::FilePath), ) .arg( Arg::new("target") .long("target") .help("Target OS architecture") - .takes_value(true) - .possible_values([ + .value_parser([ "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc", "x86_64-apple-darwin", @@ -969,12 +968,12 @@ supported in canary. ) } -fn completions_subcommand<'a>() -> Command<'a> { +fn completions_subcommand() -> Command { Command::new("completions") .disable_help_subcommand(true) .arg( Arg::new("shell") - .possible_values(["bash", "fish", "powershell", "zsh", "fig"]) + .value_parser(["bash", "fish", "powershell", "zsh", "fig"]) .required(true), ) .about("Generate shell completions") @@ -986,7 +985,7 @@ fn completions_subcommand<'a>() -> Command<'a> { ) } -fn coverage_subcommand<'a>() -> Command<'a> { +fn coverage_subcommand() -> Command { Command::new("coverage") .about("Print coverage reports") .long_about( @@ -1026,7 +1025,7 @@ Generate html reports from lcov: .arg( Arg::new("ignore") .long("ignore") - .takes_value(true) + .num_args(1..) .use_value_delimiter(true) .require_equals(true) .help("Ignore coverage files") @@ -1035,10 +1034,9 @@ Generate html reports from lcov: .arg( Arg::new("include") .long("include") - .takes_value(true) + .num_args(1..) + .action(ArgAction::Append) .value_name("regex") - .multiple_values(true) - .multiple_occurrences(true) .require_equals(true) .default_value(r"^file:") .help("Include source files in the report"), @@ -1046,10 +1044,9 @@ Generate html reports from lcov: .arg( Arg::new("exclude") .long("exclude") - .takes_value(true) + .num_args(1..) + .action(ArgAction::Append) .value_name("regex") - .multiple_values(true) - .multiple_occurrences(true) .require_equals(true) .default_value(r"test\.(js|mjs|ts|jsx|tsx)$") .help("Exclude source files from the report"), @@ -1058,33 +1055,33 @@ Generate html reports from lcov: Arg::new("lcov") .long("lcov") .help("Output coverage report in lcov format") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("output") .requires("lcov") .long("output") + .value_parser(value_parser!(PathBuf)) .help("Output file (defaults to stdout) for lcov") .long_help( "Exports the coverage report in lcov format to the given file. \ Filename should be passed along with '=' For example '--output=foo.lcov' \ If no --output arg is specified then the report is written to stdout.", ) - .takes_value(true) .require_equals(true) .value_hint(ValueHint::FilePath), ) .arg( Arg::new("files") - .takes_value(true) - .multiple_values(true) - .multiple_occurrences(true) + .num_args(1..) + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Append) .required(true) .value_hint(ValueHint::AnyPath), ) } -fn doc_subcommand<'a>() -> Command<'a> { +fn doc_subcommand() -> Command { Command::new("doc") .about("Show documentation for a module") .long_about( @@ -1121,34 +1118,29 @@ Show documentation for runtime built-ins: Arg::new("json") .long("json") .help("Output documentation in JSON format") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("private") .long("private") .help("Output private documentation") - .takes_value(false), + .action(ArgAction::SetTrue), ) // TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by // https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is // just a possible value of `source_file` so leading hyphens must be // enabled. .allow_hyphen_values(true) - .arg( - Arg::new("source_file") - .takes_value(true) - .value_hint(ValueHint::FilePath), - ) + .arg(Arg::new("source_file").value_hint(ValueHint::FilePath)) .arg( Arg::new("filter") .help("Dot separated path to symbol") - .takes_value(true) .required(false) .conflicts_with("json"), ) } -fn eval_subcommand<'a>() -> Command<'a> { +fn eval_subcommand() -> Command { runtime_args(Command::new("eval"), false, true) .about("Eval script") .long_about( @@ -1169,9 +1161,7 @@ This command has implicit access to all permissions (--allow-all).", .long("ts") .short('T') .help("deprecated: Treat eval input as TypeScript") - .takes_value(false) - .multiple_occurrences(false) - .multiple_values(false) + .action(ArgAction::SetTrue) .hide(true), ) .arg(executable_ext_arg()) @@ -1180,21 +1170,19 @@ This command has implicit access to all permissions (--allow-all).", .long("print") .short('p') .help("print result to stdout") - .takes_value(false) - .multiple_occurrences(false) - .multiple_values(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("code_arg") - .multiple_values(true) - .multiple_occurrences(true) + .num_args(1..) + .action(ArgAction::Append) .help("Code arg") .value_name("CODE_ARG") .required(true), ) } -fn fmt_subcommand<'a>() -> Command<'a> { +fn fmt_subcommand() -> Command { Command::new("fmt") .about("Format source files") .long_about( @@ -1222,21 +1210,21 @@ Ignore formatting a file by adding an ignore comment at the top of the file: Arg::new("check") .long("check") .help("Check if the source files are formatted") - .takes_value(false), + .num_args(0), ) .arg( Arg::new("ext") .long("ext") .help("Set content type of the supplied file") - .takes_value(true) // prefer using ts for formatting instead of js because ts works in more scenarios .default_value("ts") - .possible_values(["ts", "tsx", "js", "jsx", "md", "json", "jsonc"]), + .value_parser(["ts", "tsx", "js", "jsx", "md", "json", "jsonc"]), ) .arg( Arg::new("ignore") .long("ignore") - .takes_value(true) + .value_parser(value_parser!(PathBuf)) + .num_args(1..) .use_value_delimiter(true) .require_equals(true) .help("Ignore formatting particular source files") @@ -1244,9 +1232,9 @@ Ignore formatting a file by adding an ignore comment at the top of the file: ) .arg( Arg::new("files") - .takes_value(true) - .multiple_values(true) - .multiple_occurrences(true) + .value_parser(value_parser!(PathBuf)) + .num_args(1..) + .action(ArgAction::Append) .required(false) .value_hint(ValueHint::AnyPath), ) @@ -1256,11 +1244,10 @@ Ignore formatting a file by adding an ignore comment at the top of the file: Arg::new("use-tabs") .long("use-tabs") .alias("options-use-tabs") - .takes_value(true) - .min_values(0) - .max_values(1) + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") .require_equals(true) - .possible_values(["true", "false"]) .help("Use tabs instead of spaces for indentation. Defaults to false."), ) .arg( @@ -1268,67 +1255,53 @@ Ignore formatting a file by adding an ignore comment at the top of the file: .long("line-width") .alias("options-line-width") .help("Define maximum line width. Defaults to 80.") - .takes_value(true) - .validator(|val: &str| match val.parse::<NonZeroUsize>() { - Ok(_) => Ok(()), - Err(_) => Err("line-width should be a non zero integer".to_string()), - }), + .value_parser(value_parser!(NonZeroU32)), ) .arg( Arg::new("indent-width") .long("indent-width") .alias("options-indent-width") .help("Define indentation width. Defaults to 2.") - .takes_value(true) - .validator(|val: &str| match val.parse::<NonZeroUsize>() { - Ok(_) => Ok(()), - Err(_) => { - Err("indent-width should be a non zero integer".to_string()) - } - }), + .value_parser(value_parser!(NonZeroU8)), ) .arg( Arg::new("single-quote") .long("single-quote") .alias("options-single-quote") - .min_values(0) - .max_values(1) - .takes_value(true) + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") .require_equals(true) - .possible_values(["true", "false"]) .help("Use single quotes. Defaults to false."), ) .arg( Arg::new("prose-wrap") .long("prose-wrap") .alias("options-prose-wrap") - .takes_value(true) - .possible_values(["always", "never", "preserve"]) + .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") - .min_values(0) - .max_values(1) - .takes_value(true) + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") .require_equals(true) - .possible_values(["true", "false"]) .help("Don't use semicolons except where necessary."), ) } -fn init_subcommand<'a>() -> Command<'a> { +fn init_subcommand() -> Command { Command::new("init").about("Initialize a new project").arg( Arg::new("dir") - .takes_value(true) .required(false) .value_hint(ValueHint::DirPath), ) } -fn info_subcommand<'a>() -> Command<'a> { +fn info_subcommand() -> Command { Command::new("info") .about("Show info about cache or info related to source file") .long_about( @@ -1351,7 +1324,7 @@ DENO_DIR: Directory containing Deno-managed files. Remote modules cache: Subdirectory containing downloaded remote modules. TypeScript compiler cache: Subdirectory containing TS compiler output.", ) - .arg(Arg::new("file").takes_value(true).required(false).value_hint(ValueHint::FilePath)) + .arg(Arg::new("file").required(false).value_hint(ValueHint::FilePath)) .arg(reload_arg().requires("file")) .arg(ca_file_arg()) .arg( @@ -1372,35 +1345,31 @@ TypeScript compiler cache: Subdirectory containing TS compiler output.", Arg::new("json") .long("json") .help("UNSTABLE: Outputs the information in JSON format") - .takes_value(false), + .action(ArgAction::SetTrue), ) } -fn install_subcommand<'a>() -> Command<'a> { +fn install_subcommand() -> Command { runtime_args(Command::new("install"), true, true) - .trailing_var_arg(true) - .arg(Arg::new("cmd").required(true).multiple_values(true).value_hint(ValueHint::FilePath)) + .arg(Arg::new("cmd").required(true).num_args(1..).value_hint(ValueHint::FilePath)) .arg( Arg::new("name") .long("name") .short('n') .help("Executable file name") - .takes_value(true) .required(false)) .arg( Arg::new("root") .long("root") .help("Installation root") - .takes_value(true) - .multiple_occurrences(false) - .multiple_values(false) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::DirPath)) .arg( Arg::new("force") .long("force") .short('f') .help("Forcefully overwrite existing installation") - .takes_value(false)) + .action(ArgAction::SetTrue)) .about("Install script as an executable") .long_about( "Installs a script as an executable in the installation root's bin directory. @@ -1432,19 +1401,14 @@ The installation root is determined, in order of precedence: These must be added to the path manually if required.") } -fn uninstall_subcommand<'a>() -> Command<'a> { +fn uninstall_subcommand() -> Command { Command::new("uninstall") - .trailing_var_arg(true) - .arg( - Arg::new("name") - .required(true) - .multiple_occurrences(false)) + .arg(Arg::new("name").required(true)) .arg( Arg::new("root") .long("root") .help("Installation root") - .takes_value(true) - .multiple_occurrences(false) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::DirPath)) .about("Uninstall a script previously installed with deno install") .long_about( @@ -1475,13 +1439,13 @@ https://deno.land/manual@v{}/getting_started/setup_your_environment#editors-and- ) }); -fn lsp_subcommand<'a>() -> Command<'a> { +fn lsp_subcommand() -> Command { Command::new("lsp") .about("Start the language server") .long_about(LSP_HELP.as_str()) } -fn lint_subcommand<'a>() -> Command<'a> { +fn lint_subcommand() -> Command { Command::new("lint") .about("Lint source files") .long_about( @@ -1516,12 +1480,18 @@ Ignore linting a file by adding an ignore comment at the top of the file: // deno-lint-ignore-file ", ) - .arg(Arg::new("rules").long("rules").help("List available rules")) + .arg( + Arg::new("rules") + .long("rules") + .help("List available rules") + .action(ArgAction::SetTrue), + ) .arg( Arg::new("rules-tags") .long("rules-tags") .require_equals(true) - .takes_value(true) + .num_args(1..) + .action(ArgAction::Append) .use_value_delimiter(true) .conflicts_with("rules") .help("Use set of rules with a tag"), @@ -1530,7 +1500,7 @@ Ignore linting a file by adding an ignore comment at the top of the file: Arg::new("rules-include") .long("rules-include") .require_equals(true) - .takes_value(true) + .num_args(1..) .use_value_delimiter(true) .conflicts_with("rules") .help("Include lint rules"), @@ -1539,7 +1509,7 @@ Ignore linting a file by adding an ignore comment at the top of the file: Arg::new("rules-exclude") .long("rules-exclude") .require_equals(true) - .takes_value(true) + .num_args(1..) .use_value_delimiter(true) .conflicts_with("rules") .help("Exclude lint rules"), @@ -1549,7 +1519,8 @@ Ignore linting a file by adding an ignore comment at the top of the file: .arg( Arg::new("ignore") .long("ignore") - .takes_value(true) + .num_args(1..) + .value_parser(value_parser!(PathBuf)) .use_value_delimiter(true) .require_equals(true) .help("Ignore linting particular source files") @@ -1559,20 +1530,20 @@ Ignore linting a file by adding an ignore comment at the top of the file: Arg::new("json") .long("json") .help("Output lint result in JSON format") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("compact") .long("compact") .help("Output lint result in compact format") - .takes_value(false) + .action(ArgAction::SetTrue) .conflicts_with("json"), ) .arg( Arg::new("files") - .takes_value(true) - .multiple_values(true) - .multiple_occurrences(true) + .value_parser(value_parser!(PathBuf)) + .num_args(1..) + .action(ArgAction::Append) .required(false) .value_hint(ValueHint::AnyPath), ) @@ -1580,14 +1551,13 @@ Ignore linting a file by adding an ignore comment at the top of the file: .arg(no_clear_screen_arg()) } -fn repl_subcommand<'a>() -> Command<'a> { +fn repl_subcommand() -> Command { runtime_args(Command::new("repl"), true, true) .about("Read Eval Print Loop") .arg( Arg::new("eval-file") .long("eval-file") - .min_values(1) - .takes_value(true) + .num_args(1..) .use_value_delimiter(true) .require_equals(true) .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs.") @@ -1597,12 +1567,11 @@ fn repl_subcommand<'a>() -> Command<'a> { Arg::new("eval") .long("eval") .help("Evaluates the provided code when the REPL starts.") - .takes_value(true) .value_name("code"), ) } -fn run_subcommand<'a>() -> Command<'a> { +fn run_subcommand() -> Command { runtime_args(Command::new("run"), true, true) .arg( watch_arg(true) @@ -1612,8 +1581,11 @@ fn run_subcommand<'a>() -> Command<'a> { ) .arg(no_clear_screen_arg()) .arg(executable_ext_arg()) - .trailing_var_arg(true) - .arg(script_arg().required(true)) + .arg( + script_arg() + .required_unless_present("v8-flags") + .trailing_var_arg(true), + ) .about("Run a JavaScript or TypeScript program") .long_about( "Run a JavaScript or TypeScript program @@ -1641,27 +1613,18 @@ Specifying the filename '-' to read the file from stdin. ) } -fn task_subcommand<'a>() -> Command<'a> { +fn task_subcommand() -> Command { Command::new("task") - .trailing_var_arg(true) + .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") - .takes_value(true) - .value_hint(ValueHint::DirPath) + .value_hint(ValueHint::DirPath), ) - // Ideally the task name and trailing arguments should be two separate clap - // arguments, but there is a bug in clap that's preventing us from doing - // this (https://github.com/clap-rs/clap/issues/1538). Once that's fixed, - // then we can revert this back to what it used to be. - .arg(Arg::new("task_name_and_args") - .multiple_values(true) - .multiple_occurrences(true) - .allow_hyphen_values(true) - .help("Task to be executed with any additional arguments passed to the task")) .about("Run a task defined in the configuration file") .long_about( "Run a task defined in the configuration file @@ -1670,13 +1633,13 @@ fn task_subcommand<'a>() -> Command<'a> { ) } -fn test_subcommand<'a>() -> Command<'a> { +fn test_subcommand() -> Command { runtime_args(Command::new("test"), true, true) - .trailing_var_arg(true) .arg( Arg::new("ignore") .long("ignore") - .takes_value(true) + .num_args(1..) + .value_parser(value_parser!(PathBuf)) .use_value_delimiter(true) .require_equals(true) .help("Ignore files") @@ -1686,46 +1649,40 @@ fn test_subcommand<'a>() -> Command<'a> { Arg::new("no-run") .long("no-run") .help("Cache test modules, but don't run tests") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("trace-ops") .long("trace-ops") .help("Enable tracing of async ops. Useful when debugging leaking ops in test, but impacts test execution time.") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("doc") .long("doc") .help("Type-check code blocks in JSDoc and Markdown") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("fail-fast") .long("fail-fast") .alias("failfast") .help("Stop after N errors. Defaults to stopping after first failure.") - .min_values(0) - .required(false) - .takes_value(true) + .num_args(0..=1) .require_equals(true) .value_name("N") - .validator(|val: &str| match val.parse::<NonZeroUsize>() { - Ok(_) => Ok(()), - Err(_) => Err("fail-fast should be a non zero integer".to_string()), - }), + .value_parser(value_parser!(NonZeroUsize)), ) .arg( Arg::new("allow-none") .long("allow-none") .help("Don't return error code if no test files are found") - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg( Arg::new("filter") .allow_hyphen_values(true) .long("filter") - .takes_value(true) .help("Run tests with this string or pattern in the test name"), ) .arg( @@ -1733,20 +1690,14 @@ fn test_subcommand<'a>() -> Command<'a> { .long("shuffle") .value_name("NUMBER") .help("Shuffle the order in which the tests are run") - .min_values(0) - .max_values(1) + .num_args(0..=1) .require_equals(true) - .takes_value(true) - .validator(|val: &str| match val.parse::<u64>() { - Ok(_) => Ok(()), - Err(_) => Err("Shuffle seed should be a number".to_string()), - }), + .value_parser(value_parser!(u64)), ) .arg( Arg::new("coverage") .long("coverage") .require_equals(true) - .takes_value(true) .value_name("DIR") .conflicts_with("inspect") .conflicts_with("inspect-wait") @@ -1758,7 +1709,7 @@ fn test_subcommand<'a>() -> Command<'a> { .long("parallel") .help("Run test modules in parallel. Parallelism defaults to the number of available CPUs or the value in the DENO_JOBS environment variable.") .conflicts_with("jobs") - .takes_value(false) + .action(ArgAction::SetTrue) ) .arg( Arg::new("jobs") @@ -1766,20 +1717,15 @@ fn test_subcommand<'a>() -> Command<'a> { .long("jobs") .help("deprecated: Number of parallel workers, defaults to number of available CPUs when no value is provided. Defaults to 1 when the option is not present.") .hide(true) - .min_values(0) - .max_values(1) - .takes_value(true) - .validator(|val: &str| match val.parse::<NonZeroUsize>() { - Ok(_) => Ok(()), - Err(_) => Err("jobs should be a non zero unsigned integer".to_string()), - }), + .num_args(0..=1) + .value_parser(value_parser!(NonZeroUsize)), ) .arg( Arg::new("files") .help("List of file names to run") - .takes_value(true) - .multiple_values(true) - .multiple_occurrences(true) + .num_args(0..) + .action(ArgAction::Append) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::AnyPath), ) .arg( @@ -1805,7 +1751,7 @@ Directory arguments are expanded to all contained files matching the glob ) } -fn types_subcommand<'a>() -> Command<'a> { +fn types_subcommand() -> Command { Command::new("types") .about("Print runtime TypeScript declarations") .long_about( @@ -1817,7 +1763,7 @@ The declaration file could be saved and used for typing information.", ) } -fn upgrade_subcommand<'a>() -> Command<'a> { +fn upgrade_subcommand() -> Command { Command::new("upgrade") .about("Upgrade deno executable to given version") .long_about( @@ -1836,36 +1782,38 @@ update to a different location, use the --output flag .arg( Arg::new("version") .long("version") - .help("The version to upgrade to") - .takes_value(true), + .help("The version to upgrade to"), ) .arg( Arg::new("output") .long("output") .help("The path to output the updated version to") - .takes_value(true) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::FilePath), ) .arg( Arg::new("dry-run") .long("dry-run") - .help("Perform all checks without replacing old exe"), + .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"), + .help("Replace current exe even if not out-of-date") + .action(ArgAction::SetTrue), ) .arg( Arg::new("canary") .long("canary") - .help("Upgrade to canary builds"), + .help("Upgrade to canary builds") + .action(ArgAction::SetTrue), ) .arg(ca_file_arg()) } -fn vendor_subcommand<'a>() -> Command<'a> { +fn vendor_subcommand() -> Command { Command::new("vendor") .about("Vendor remote modules into a local directory") .long_about( @@ -1884,16 +1832,15 @@ Remote modules and multiple modules may also be specified: ) .arg( Arg::new("specifiers") - .takes_value(true) - .multiple_values(true) - .multiple_occurrences(true) + .num_args(1..) + .action(ArgAction::Append) .required(true), ) .arg( Arg::new("output") .long("output") .help("The directory to output the vendored modules to") - .takes_value(true) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::DirPath), ) .arg( @@ -1903,7 +1850,7 @@ Remote modules and multiple modules may also be specified: .help( "Forcefully overwrite conflicting files in existing output directory", ) - .takes_value(false), + .action(ArgAction::SetTrue), ) .arg(no_config_arg()) .arg(config_arg()) @@ -1937,71 +1884,65 @@ fn permission_args(app: Command) -> Command { .arg( Arg::new("allow-read") .long("allow-read") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow file system read access") + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::AnyPath), ) .arg( Arg::new("allow-write") .long("allow-write") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow file system write access") + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::AnyPath), ) .arg( Arg::new("allow-net") .long("allow-net") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow network access") - .validator(flags_allow_net::validator), + .value_parser(flags_allow_net::validator), ) .arg(unsafely_ignore_certificate_errors_arg()) .arg( Arg::new("allow-env") .long("allow-env") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow environment access") - .validator(|keys| { - for key in keys.split(',') { - if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { - return Err(format!("invalid key \"{key}\"")); - } + .value_parser(|key: &str| { + if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { + return Err(format!("invalid key \"{key}\"")); } - Ok(()) + + Ok(if cfg!(windows) { + key.to_uppercase() + } else { + key.to_string() + }) }), ) .arg( Arg::new("allow-sys") .long("allow-sys") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow access to system info") - .validator(|keys| { - for key in keys.split(',') { - parse_sys_kind(key)?; - } - Ok::<(), AnyError>(()) - }), + .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)), ) .arg( Arg::new("allow-run") .long("allow-run") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow running subprocesses"), @@ -2009,30 +1950,39 @@ fn permission_args(app: Command) -> Command { .arg( Arg::new("allow-ffi") .long("allow-ffi") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .help("Allow loading dynamic libraries") + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::AnyPath), ) .arg( Arg::new("allow-hrtime") .long("allow-hrtime") + .action(ArgAction::SetTrue) .help("Allow high resolution time measurement"), ) .arg( Arg::new("allow-all") .short('A') .long("allow-all") + .action(ArgAction::SetTrue) .help("Allow all permissions"), ) - .arg(Arg::new("prompt").long("prompt").hide(true).help( - "deprecated: Fallback to prompt if required permission wasn't passed", - )) + .arg( + Arg::new("prompt") + .long("prompt") + .action(ArgAction::SetTrue) + .hide(true) + .help( + "deprecated: Fallback to prompt if required permission wasn't passed", + ), + ) .arg( Arg::new("no-prompt") .long("no-prompt") + .action(ArgAction::SetTrue) .help("Always throw if required permission wasn't passed"), ) } @@ -2068,11 +2018,9 @@ fn inspect_args(app: Command) -> Command { .long("inspect") .value_name("HOST_AND_PORT") .help("Activate inspector on host:port (default: 127.0.0.1:9229)") - .min_values(0) - .max_values(1) + .num_args(0..=1) .require_equals(true) - .takes_value(true) - .validator(inspect_arg_validate), + .value_parser(value_parser!(SocketAddr)), ) .arg( Arg::new("inspect-brk") @@ -2081,11 +2029,9 @@ fn inspect_args(app: Command) -> Command { .help( "Activate inspector on host:port, wait for debugger to connect and break at the start of user script", ) - .min_values(0) - .max_values(1) + .num_args(0..=1) .require_equals(true) - .takes_value(true) - .validator(inspect_arg_validate), + .value_parser(value_parser!(SocketAddr)), ) .arg( Arg::new("inspect-wait") @@ -2094,11 +2040,9 @@ fn inspect_args(app: Command) -> Command { .help( "Activate inspector on host:port and wait for debugger to connect before running user code", ) - .min_values(0) - .max_values(1) + .num_args(0..=1) .require_equals(true) - .takes_value(true) - .validator(inspect_arg_validate), + .value_parser(value_parser!(SocketAddr)), ) } @@ -2112,22 +2056,20 @@ static IMPORT_MAP_HELP: Lazy<String> = Lazy::new(|| { ) }); -fn import_map_arg<'a>() -> Arg<'a> { +fn import_map_arg() -> Arg { Arg::new("import-map") .long("import-map") .alias("importmap") .value_name("FILE") .help("Load import map file") .long_help(IMPORT_MAP_HELP.as_str()) - .takes_value(true) .value_hint(ValueHint::FilePath) } -fn reload_arg<'a>() -> Arg<'a> { +fn reload_arg() -> Arg { Arg::new("reload") .short('r') - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .long("reload") @@ -2147,21 +2089,21 @@ fn reload_arg<'a>() -> Arg<'a> { Reload specific npm module", ) .value_hint(ValueHint::FilePath) - .validator(reload_arg_validate) + .value_parser(reload_arg_validate) } -fn ca_file_arg<'a>() -> Arg<'a> { +fn ca_file_arg() -> Arg { Arg::new("cert") .long("cert") .value_name("FILE") .help("Load certificate authority from PEM encoded file") - .takes_value(true) .value_hint(ValueHint::FilePath) } -fn cached_only_arg<'a>() -> Arg<'a> { +fn cached_only_arg() -> Arg { Arg::new("cached-only") .long("cached-only") + .action(ArgAction::SetTrue) .help("Require that remote dependencies are already cached") } @@ -2169,20 +2111,18 @@ fn cached_only_arg<'a>() -> Arg<'a> { /// `deno fmt` has its own `--ext` arg because its possible values differ. /// If --ext is not provided and the script doesn't have a file extension, /// deno_graph::parse_module() defaults to js. -fn executable_ext_arg<'a>() -> Arg<'a> { +fn executable_ext_arg() -> Arg { Arg::new("ext") .long("ext") .help("Set content type of the supplied file") - .takes_value(true) - .possible_values(["ts", "tsx", "js", "jsx"]) + .value_parser(["ts", "tsx", "js", "jsx"]) } -fn location_arg<'a>() -> Arg<'a> { +fn location_arg() -> Arg { Arg::new("location") .long("location") - .takes_value(true) .value_name("HREF") - .validator(|href| { + .value_parser(|href: &str| -> Result<Url, String> { let url = Url::parse(href); if url.is_err() { return Err("Failed to parse URL".to_string()); @@ -2193,23 +2133,24 @@ fn location_arg<'a>() -> Arg<'a> { } url.set_username("").unwrap(); url.set_password(None).unwrap(); - Ok(()) + Ok(url) }) .help("Value of 'globalThis.location' used by some web APIs") .value_hint(ValueHint::Url) } -fn enable_testing_features_arg<'a>() -> Arg<'a> { +fn enable_testing_features_arg() -> Arg { Arg::new("enable-testing-features-do-not-use") .long("enable-testing-features-do-not-use") .help("INTERNAL: Enable internal features used during integration testing") + .action(ArgAction::SetTrue) .hide(true) } -fn v8_flags_arg<'a>() -> Arg<'a> { +fn v8_flags_arg() -> Arg { Arg::new("v8-flags") .long("v8-flags") - .takes_value(true) + .num_args(..) .use_value_delimiter(true) .require_equals(true) .help("Set V8 command line options") @@ -2217,19 +2158,15 @@ fn v8_flags_arg<'a>() -> Arg<'a> { Any flags set with this flag are appended after the DENO_V8_FLAGS environmental variable") } -fn seed_arg<'a>() -> Arg<'a> { +fn seed_arg() -> Arg { Arg::new("seed") .long("seed") .value_name("NUMBER") .help("Set the random number generator seed") - .takes_value(true) - .validator(|val| match val.parse::<u64>() { - Ok(_) => Ok(()), - Err(_) => Err("Seed should be a number".to_string()), - }) + .value_parser(value_parser!(u64)) } -fn watch_arg<'a>(takes_files: bool) -> Arg<'a> { +fn watch_arg(takes_files: bool) -> Arg { let arg = Arg::new("watch") .long("watch") .help("Watch for file changes and restart automatically"); @@ -2237,8 +2174,8 @@ fn watch_arg<'a>(takes_files: bool) -> Arg<'a> { if takes_files { arg .value_name("FILES") - .min_values(0) - .takes_value(true) + .num_args(0..) + .value_parser(value_parser!(PathBuf)) .use_value_delimiter(true) .require_equals(true) .long_help( @@ -2248,25 +2185,25 @@ Additional paths might be watched by passing them as arguments to this flag.", ) .value_hint(ValueHint::AnyPath) } else { - arg.long_help( + arg.action(ArgAction::SetTrue).long_help( "Watch for file changes and restart process automatically. \ Only local files from entry point module graph are watched.", ) } } -fn no_clear_screen_arg<'a>() -> Arg<'a> { +fn no_clear_screen_arg() -> Arg { Arg::new("no-clear-screen") .requires("watch") .long("no-clear-screen") + .action(ArgAction::SetTrue) .help("Do not clear terminal screen when under watch mode") } -fn no_check_arg<'a>() -> Arg<'a> { +fn no_check_arg() -> Arg { Arg::new("no-check") - .takes_value(true) + .num_args(0..=1) .require_equals(true) - .min_values(0) .value_name("NO_CHECK_TYPE") .long("no-check") .help("Skip type-checking modules") @@ -2276,13 +2213,12 @@ fn no_check_arg<'a>() -> Arg<'a> { ) } -fn check_arg<'a>() -> Arg<'a> { +fn check_arg() -> Arg { Arg::new("check") .conflicts_with("no-check") .long("check") - .takes_value(true) + .num_args(0..=1) .require_equals(true) - .min_values(0) .value_name("CHECK_TYPE") .help("Type-check modules") .long_help( @@ -2296,43 +2232,44 @@ will be included.", ) } -fn script_arg<'a>() -> Arg<'a> { +fn script_arg() -> Arg { Arg::new("script_arg") - .multiple_values(true) - .multiple_occurrences(true) + .num_args(0..) + .action(ArgAction::Append) // NOTE: these defaults are provided // so `deno run --v8-flags=--help` works // without specifying file to run. - .default_value_ifs(&[ - ("v8-flags", Some("--help"), Some("_")), - ("v8-flags", Some("-help"), Some("_")), + .default_value_ifs([ + ("v8-flags", "--help", Some("_")), + ("v8-flags", "-help", Some("_")), ]) .help("Script arg") .value_name("SCRIPT_ARG") .value_hint(ValueHint::FilePath) } -fn lock_arg<'a>() -> Arg<'a> { +fn lock_arg() -> Arg { Arg::new("lock") .long("lock") .value_name("FILE") .help("Check the specified lock file. If value is not provided, defaults to \"deno.lock\" in the current working directory.") - .takes_value(true) - .min_values(0) - .max_values(1) + .num_args(0..=1) + .value_parser(value_parser!(PathBuf)) .value_hint(ValueHint::FilePath) } -fn lock_write_arg<'a>() -> Arg<'a> { +fn lock_write_arg() -> Arg { Arg::new("lock-write") + .action(ArgAction::SetTrue) .long("lock-write") .help("Force overwriting the lock file.") .conflicts_with("no-lock") } -fn no_lock_arg<'a>() -> Arg<'a> { +fn no_lock_arg() -> Arg { Arg::new("no-lock") .long("no-lock") + .action(ArgAction::SetTrue) .help("Disable auto discovery of the lock file.") .conflicts_with("lock") } @@ -2348,60 +2285,60 @@ static CONFIG_HELP: Lazy<String> = Lazy::new(|| { ) }); -fn config_arg<'a>() -> Arg<'a> { +fn config_arg() -> Arg { Arg::new("config") .short('c') .long("config") .value_name("FILE") .help("Specify the configuration file") .long_help(CONFIG_HELP.as_str()) - .takes_value(true) .value_hint(ValueHint::FilePath) } -fn no_config_arg<'a>() -> Arg<'a> { +fn no_config_arg() -> Arg { Arg::new("no-config") .long("no-config") + .action(ArgAction::SetTrue) .help("Disable automatic loading of the configuration file.") .conflicts_with("config") } -fn no_remote_arg<'a>() -> Arg<'a> { +fn no_remote_arg() -> Arg { Arg::new("no-remote") .long("no-remote") + .action(ArgAction::SetTrue) .help("Do not resolve remote modules") } -fn no_npm_arg<'a>() -> Arg<'a> { +fn no_npm_arg() -> Arg { Arg::new("no-npm") .long("no-npm") + .action(ArgAction::SetTrue) .help("Do not resolve npm modules") } -fn local_npm_arg<'a>() -> Arg<'a> { +fn local_npm_arg() -> Arg { Arg::new("node-modules-dir") .long("node-modules-dir") - .min_values(0) - .max_values(1) - .takes_value(true) + .num_args(0..=1) + .value_parser(value_parser!(bool)) + .default_missing_value("true") .require_equals(true) - .possible_values(["true", "false"]) - .help("Creates a local node_modules folder. This option is implicitly true when a package.json is auto-discovered.") + .help("Creates a local node_modules folder") } -fn unsafely_ignore_certificate_errors_arg<'a>() -> Arg<'a> { +fn unsafely_ignore_certificate_errors_arg() -> Arg { Arg::new("unsafely-ignore-certificate-errors") .long("unsafely-ignore-certificate-errors") - .min_values(0) - .takes_value(true) + .num_args(0..) .use_value_delimiter(true) .require_equals(true) .value_name("HOSTNAMES") .help("DANGER: Disables verification of TLS certificates") - .validator(flags_allow_net::validator) + .value_parser(flags_allow_net::validator) } -fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn bench_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; runtime_args_parse(flags, matches, true, false); @@ -2410,34 +2347,23 @@ fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) { // interactive prompts, unless done by user code flags.no_prompt = true; - let json = matches.is_present("json"); + let json = matches.get_flag("json"); - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), + let ignore = match matches.remove_many::<PathBuf>("ignore") { + Some(f) => f.collect(), None => vec![], }; - let filter = matches.value_of("filter").map(String::from); - - if matches.is_present("script_arg") { - let script_arg: Vec<String> = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); + let filter = matches.remove_one::<String>("filter"); - for v in script_arg { - flags.argv.push(v); - } + if matches.contains_id("script_arg") { + flags + .argv + .extend(matches.remove_many::<String>("script_arg").unwrap()); } - let include = if matches.is_present("files") { - let files = matches - .values_of("files") - .unwrap() - .map(PathBuf::from) - .collect(); - files + let include = if let Some(files) = matches.remove_many::<PathBuf>("files") { + files.collect() } else { Vec::new() }; @@ -2450,19 +2376,20 @@ fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn bundle_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn bundle_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; compile_args_parse(flags, matches); - let source_file = matches.value_of("source_file").unwrap().to_string(); + let source_file = matches.remove_one::<String>("source_file").unwrap(); - let out_file = if let Some(out_file) = matches.value_of("out_file") { - flags.allow_write = Some(vec![]); - Some(PathBuf::from(out_file)) - } else { - None - }; + let out_file = + if let Some(out_file) = matches.remove_one::<PathBuf>("out_file") { + flags.allow_write = Some(vec![]); + Some(out_file) + } else { + None + }; watch_arg_parse(flags, matches, false); ext_arg_parse(flags, matches); @@ -2473,46 +2400,33 @@ fn bundle_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn cache_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn cache_parse(flags: &mut Flags, matches: &mut ArgMatches) { compile_args_parse(flags, matches); - let files = matches - .values_of("file") - .unwrap() - .map(String::from) - .collect(); + let files = matches.remove_many::<String>("file").unwrap().collect(); flags.subcommand = DenoSubcommand::Cache(CacheFlags { files }); } -fn check_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn check_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; compile_args_without_check_parse(flags, matches); - let files = matches - .values_of("file") - .unwrap() - .map(String::from) - .collect(); - if matches.is_present("all") || matches.is_present("remote") { + let files = matches.remove_many::<String>("file").unwrap().collect(); + if matches.get_flag("all") || matches.get_flag("remote") { flags.type_check_mode = TypeCheckMode::All; } flags.subcommand = DenoSubcommand::Check(CheckFlags { files }); } -fn compile_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn compile_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; runtime_args_parse(flags, matches, true, false); - let mut script: Vec<String> = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); - assert!(!script.is_empty()); - let args = script.split_off(1); - let source_file = script[0].to_string(); - let output = matches.value_of("output").map(PathBuf::from); - let target = matches.value_of("target").map(String::from); - let include = match matches.values_of("include") { - Some(f) => f.map(String::from).collect(), + let mut script = matches.remove_many::<String>("script_arg").unwrap(); + let source_file = script.next().unwrap(); + let args = script.collect(); + let output = matches.remove_one::<PathBuf>("output"); + let target = matches.remove_one::<String>("target"); + let include = match matches.remove_many::<String>("include") { + Some(f) => f.collect(), None => vec![], }; ext_arg_parse(flags, matches); @@ -2528,8 +2442,8 @@ fn compile_parse(flags: &mut Flags, matches: &clap::ArgMatches) { fn completions_parse( flags: &mut Flags, - matches: &clap::ArgMatches, - mut app: clap::Command, + matches: &mut ArgMatches, + mut app: Command, ) { use clap_complete::generate; use clap_complete::shells::Bash; @@ -2541,7 +2455,7 @@ fn completions_parse( let mut buf: Vec<u8> = vec![]; let name = "deno"; - match matches.value_of("shell").unwrap() { + match matches.get_one::<String>("shell").unwrap().as_str() { "bash" => generate(Bash, &mut app, name, &mut buf), "fish" => generate(Fish, &mut app, name, &mut buf), "powershell" => generate(PowerShell, &mut app, name, &mut buf), @@ -2555,25 +2469,25 @@ fn completions_parse( }); } -fn coverage_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - let files = match matches.values_of("files") { - Some(f) => f.map(PathBuf::from).collect(), +fn coverage_parse(flags: &mut Flags, matches: &mut ArgMatches) { + let files = match matches.remove_many::<PathBuf>("files") { + Some(f) => f.collect(), None => vec![], }; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), + let ignore = match matches.remove_many::<PathBuf>("ignore") { + Some(f) => f.collect(), None => vec![], }; - let include = match matches.values_of("include") { - Some(f) => f.map(String::from).collect(), + let include = match matches.remove_many::<String>("include") { + Some(f) => f.collect(), None => vec![], }; - let exclude = match matches.values_of("exclude") { - Some(f) => f.map(String::from).collect(), + let exclude = match matches.remove_many::<String>("exclude") { + Some(f) => f.collect(), None => vec![], }; - let lcov = matches.is_present("lcov"); - let output = matches.value_of("output").map(PathBuf::from); + let lcov = matches.get_flag("lcov"); + let output = matches.remove_one::<PathBuf>("output"); flags.subcommand = DenoSubcommand::Coverage(CoverageFlags { files: FileFlags { include: files, @@ -2586,7 +2500,7 @@ fn coverage_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn doc_parse(flags: &mut Flags, matches: &mut ArgMatches) { import_map_arg_parse(flags, matches); reload_arg_parse(flags, matches); lock_arg_parse(flags, matches); @@ -2595,18 +2509,18 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { no_remote_arg_parse(flags, matches); let source_file = matches - .value_of("source_file") + .remove_one::<String>("source_file") .map(|value| { if value == "--builtin" { DocSourceFileFlag::Builtin } else { - DocSourceFileFlag::Path(value.to_string()) + DocSourceFileFlag::Path(value) } }) .unwrap_or_default(); - let private = matches.is_present("private"); - let json = matches.is_present("json"); - let filter = matches.value_of("filter").map(String::from); + let private = matches.get_flag("private"); + let json = matches.get_flag("json"); + let filter = matches.remove_one::<String>("filter"); flags.subcommand = DenoSubcommand::Doc(DocFlags { source_file, json, @@ -2615,7 +2529,7 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn eval_parse(flags: &mut Flags, matches: &mut ArgMatches) { runtime_args_parse(flags, matches, false, true); flags.allow_net = Some(vec![]); flags.allow_env = Some(vec![]); @@ -2629,7 +2543,7 @@ fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) { ext_arg_parse(flags, matches); // TODO(@satyarohith): remove this flag in 2.0. - let as_typescript = matches.is_present("ts"); + let as_typescript = matches.get_flag("ts"); if as_typescript { eprintln!( @@ -2642,58 +2556,37 @@ fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) { flags.ext = Some("ts".to_string()); } - let print = matches.is_present("print"); - let mut code: Vec<String> = matches - .values_of("code_arg") - .unwrap() - .map(String::from) - .collect(); - assert!(!code.is_empty()); - let code_args = code.split_off(1); - let code = code[0].to_string(); - for v in code_args { - flags.argv.push(v); - } + let print = matches.get_flag("print"); + let mut code_args = matches.remove_many::<String>("code_arg").unwrap(); + let code = code_args.next().unwrap(); + flags.argv.extend(code_args); + flags.subcommand = DenoSubcommand::Eval(EvalFlags { print, code }); } -fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn fmt_parse(flags: &mut Flags, matches: &mut ArgMatches) { config_args_parse(flags, matches); watch_arg_parse(flags, matches, false); ext_arg_parse(flags, matches); - let include = match matches.values_of("files") { - Some(f) => f.map(PathBuf::from).collect(), + let include = match matches.remove_many::<PathBuf>("files") { + Some(f) => f.collect(), None => vec![], }; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), + let ignore = match matches.remove_many::<PathBuf>("ignore") { + Some(f) => f.collect(), None => vec![], }; - let use_tabs = optional_bool_parse(matches, "use-tabs"); - let line_width = if matches.is_present("line-width") { - Some(matches.value_of("line-width").unwrap().parse().unwrap()) - } else { - None - }; - let indent_width = if matches.is_present("indent-width") { - Some( - matches - .value_of("indent-width") - .unwrap_or("true") - .parse() - .unwrap(), - ) - } else { - None - }; - let single_quote = optional_bool_parse(matches, "single-quote"); - let prose_wrap = matches.value_of("prose-wrap").map(ToString::to_string); - let no_semicolons = optional_bool_parse(matches, "no-semicolons"); + let use_tabs = matches.remove_one::<bool>("use-tabs"); + let line_width = matches.remove_one::<NonZeroU32>("line-width"); + let indent_width = matches.remove_one::<NonZeroU8>("indent-width"); + let single_quote = matches.remove_one::<bool>("single-quote"); + let prose_wrap = matches.remove_one::<String>("prose-wrap"); + let no_semicolons = matches.remove_one::<bool>("no-semicolons"); flags.subcommand = DenoSubcommand::Fmt(FmtFlags { - check: matches.is_present("check"), + check: matches.get_flag("check"), files: FileFlags { include, ignore }, use_tabs, line_width, @@ -2704,21 +2597,13 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn optional_bool_parse(matches: &ArgMatches, name: &str) -> Option<bool> { - if matches.is_present(name) { - Some(matches.value_of(name).unwrap_or("true").parse().unwrap()) - } else { - None - } -} - -fn init_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn init_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.subcommand = DenoSubcommand::Init(InitFlags { - dir: matches.value_of("dir").map(|f| f.to_string()), + dir: matches.remove_one::<String>("dir"), }); } -fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn info_parse(flags: &mut Flags, matches: &mut ArgMatches) { reload_arg_parse(flags, matches); config_args_parse(flags, matches); import_map_arg_parse(flags, matches); @@ -2729,28 +2614,24 @@ fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) { no_lock_arg_parse(flags, matches); no_remote_arg_parse(flags, matches); no_npm_arg_parse(flags, matches); - let json = matches.is_present("json"); + let json = matches.get_flag("json"); flags.subcommand = DenoSubcommand::Info(InfoFlags { - file: matches.value_of("file").map(|f| f.to_string()), + file: matches.remove_one::<String>("file"), json, }); } -fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn install_parse(flags: &mut Flags, matches: &mut ArgMatches) { runtime_args_parse(flags, matches, true, true); - let root = matches.value_of("root").map(PathBuf::from); + let root = matches.remove_one::<PathBuf>("root"); - let force = matches.is_present("force"); - let name = matches.value_of("name").map(|s| s.to_string()); - let cmd_values = matches.values_of("cmd").unwrap(); - let mut cmd = vec![]; - for value in cmd_values { - cmd.push(value.to_string()); - } + let force = matches.get_flag("force"); + let name = matches.remove_one::<String>("name"); + let mut cmd_values = matches.remove_many::<String>("cmd").unwrap(); - let module_url = cmd[0].to_string(); - let args = cmd[1..].to_vec(); + let module_url = cmd_values.next().unwrap(); + let args = cmd_values.collect(); flags.subcommand = DenoSubcommand::Install(InstallFlags { name, @@ -2761,43 +2642,43 @@ fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn uninstall_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - let root = matches.value_of("root").map(PathBuf::from); +fn uninstall_parse(flags: &mut Flags, matches: &mut ArgMatches) { + let root = matches.remove_one::<PathBuf>("root"); - let name = matches.value_of("name").unwrap().to_string(); + let name = matches.remove_one::<String>("name").unwrap(); flags.subcommand = DenoSubcommand::Uninstall(UninstallFlags { name, root }); } -fn lsp_parse(flags: &mut Flags, _matches: &clap::ArgMatches) { +fn lsp_parse(flags: &mut Flags, _matches: &mut ArgMatches) { flags.subcommand = DenoSubcommand::Lsp; } -fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn lint_parse(flags: &mut Flags, matches: &mut ArgMatches) { config_args_parse(flags, matches); watch_arg_parse(flags, matches, false); - let files = match matches.values_of("files") { - Some(f) => f.map(PathBuf::from).collect(), + let files = match matches.remove_many::<PathBuf>("files") { + Some(f) => f.collect(), None => vec![], }; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), + let ignore = match matches.remove_many::<PathBuf>("ignore") { + Some(f) => f.collect(), None => vec![], }; - let rules = matches.is_present("rules"); + let rules = matches.get_flag("rules"); let maybe_rules_tags = matches - .values_of("rules-tags") - .map(|f| f.map(String::from).collect()); + .remove_many::<String>("rules-tags") + .map(|f| f.collect()); let maybe_rules_include = matches - .values_of("rules-include") - .map(|f| f.map(String::from).collect()); + .remove_many::<String>("rules-include") + .map(|f| f.collect()); let maybe_rules_exclude = matches - .values_of("rules-exclude") - .map(|f| f.map(String::from).collect()); + .remove_many::<String>("rules-exclude") + .map(|f| f.collect()); - let json = matches.is_present("json"); - let compact = matches.is_present("compact"); + let json = matches.get_flag("json"); + let compact = matches.get_flag("compact"); flags.subcommand = DenoSubcommand::Lint(LintFlags { files: FileFlags { include: files, @@ -2813,38 +2694,31 @@ fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn repl_parse(flags: &mut Flags, matches: &mut ArgMatches) { runtime_args_parse(flags, matches, true, true); unsafely_ignore_certificate_errors_parse(flags, matches); - let eval_files: Option<Vec<String>> = matches - .values_of("eval-file") - .map(|values| values.map(String::from).collect()); + let eval_files = matches + .remove_many::<String>("eval-file") + .map(|values| values.collect()); handle_repl_flags( flags, ReplFlags { eval_files, - eval: matches.value_of("eval").map(ToOwned::to_owned), + eval: matches.remove_one::<String>("eval"), is_default_command: false, }, ); } -fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn run_parse(flags: &mut Flags, matches: &mut ArgMatches) { runtime_args_parse(flags, matches, true, true); - let mut script: Vec<String> = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); - assert!(!script.is_empty()); - let script_args = script.split_off(1); - let script = script[0].to_string(); - for v in script_args { - flags.argv.push(v); - } + let mut script_arg = matches.remove_many::<String>("script_arg").unwrap(); + + let script = script_arg.next().unwrap(); + flags.argv.extend(script_arg); ext_arg_parse(flags, matches); @@ -2852,127 +2726,80 @@ fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { flags.subcommand = DenoSubcommand::Run(RunFlags { script }); } -fn task_parse( - flags: &mut Flags, - matches: &clap::ArgMatches, - raw_args: &[String], -) { - flags.config_flag = if let Some(config) = matches.value_of("config") { - ConfigFlag::Path(config.to_string()) - } else { - ConfigFlag::Discover - }; +fn task_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.config_flag = matches + .remove_one::<String>("config") + .map_or(ConfigFlag::Discover, ConfigFlag::Path); let mut task_flags = TaskFlags { - cwd: None, + cwd: matches.remove_one::<String>("cwd"), task: None, }; - if let Some(cwd) = matches.value_of("cwd") { - task_flags.cwd = Some(cwd.to_string()); - } - - if let Some(mut index) = matches.index_of("task_name_and_args") { - let task_word_index = raw_args.iter().position(|el| el == "task").unwrap(); - let raw_args = &raw_args[task_word_index..]; - - // temporary workaround until https://github.com/clap-rs/clap/issues/1538 is fixed - while index < raw_args.len() { - match raw_args[index].as_str() { - "-c" | "--config" => { - flags.config_flag = ConfigFlag::Path(raw_args[index + 1].to_string()); - index += 2; - } - "--cwd" => { - task_flags.cwd = Some(raw_args[index + 1].to_string()); - index += 2; - } - "--no-config" => { - flags.config_flag = ConfigFlag::Disabled; - index += 1; - } - "-q" | "--quiet" => { - flags.log_level = Some(Level::Error); - index += 1; - } - _ => break, - } - } - - if index < raw_args.len() { - task_flags.task = Some(raw_args[index].to_string()); - index += 1; + if let Some((task, mut matches)) = matches.remove_subcommand() { + task_flags.task = Some(task); - if index < raw_args.len() { - flags - .argv - .extend(raw_args[index..].iter().map(String::from)); - } - } + flags.argv.extend( + matches + .remove_many::<std::ffi::OsString>("") + .into_iter() + .flatten() + .filter_map(|arg| arg.into_string().ok()), + ); } flags.subcommand = DenoSubcommand::Task(task_flags); } -fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn test_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.type_check_mode = TypeCheckMode::Local; runtime_args_parse(flags, matches, true, true); // NOTE: `deno test` always uses `--no-prompt`, tests shouldn't ever do // interactive prompts, unless done by user code flags.no_prompt = true; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), + let ignore = match matches.remove_many::<PathBuf>("ignore") { + Some(f) => f.collect(), None => vec![], }; - let no_run = matches.is_present("no-run"); - let trace_ops = matches.is_present("trace-ops"); - let doc = matches.is_present("doc"); - let allow_none = matches.is_present("allow-none"); - let filter = matches.value_of("filter").map(String::from); + let no_run = matches.get_flag("no-run"); + let trace_ops = matches.get_flag("trace-ops"); + let doc = matches.get_flag("doc"); + let allow_none = matches.get_flag("allow-none"); + let filter = matches.remove_one::<String>("filter"); - let fail_fast = if matches.is_present("fail-fast") { - if let Some(value) = matches.value_of("fail-fast") { - Some(value.parse().unwrap()) - } else { - Some(NonZeroUsize::new(1).unwrap()) - } + let fail_fast = if matches.contains_id("fail-fast") { + Some( + matches + .remove_one::<NonZeroUsize>("fail-fast") + .unwrap_or_else(|| NonZeroUsize::new(1).unwrap()), + ) } else { None }; - let shuffle = if matches.is_present("shuffle") { - let value = if let Some(value) = matches.value_of("shuffle") { - value.parse::<u64>().unwrap() - } else { - rand::random::<u64>() - }; - - Some(value) + let shuffle = if matches.contains_id("shuffle") { + Some( + matches + .remove_one::<u64>("shuffle") + .unwrap_or_else(rand::random), + ) } else { None }; - if matches.is_present("script_arg") { - let script_arg: Vec<String> = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); - - for v in script_arg { - flags.argv.push(v); - } + if let Some(script_arg) = matches.remove_many::<String>("script_arg") { + flags.argv.extend(script_arg); } - let concurrent_jobs = if matches.is_present("parallel") { + let concurrent_jobs = if matches.get_flag("parallel") { if let Ok(value) = env::var("DENO_JOBS") { value.parse::<NonZeroUsize>().ok() } else { std::thread::available_parallelism().ok() } - } else if matches.is_present("jobs") { + } else if matches.contains_id("jobs") { // We can't change this to use the log crate because its not configured // yet at this point since the flags haven't been parsed. This flag is // deprecated though so it's not worth changing the code to use the log @@ -2981,8 +2808,8 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { "{}", crate::colors::yellow("Warning: --jobs flag is deprecated. Use the --parallel flag with possibly the 'DENO_JOBS' environment variable."), ); - if let Some(value) = matches.value_of("jobs") { - Some(value.parse().unwrap()) + if let Some(value) = matches.remove_one::<NonZeroUsize>("jobs") { + Some(value) } else { std::thread::available_parallelism().ok() } @@ -2990,17 +2817,13 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { None }; - let include = if matches.is_present("files") { - matches - .values_of("files") - .unwrap() - .map(PathBuf::from) - .collect::<Vec<_>>() + let include = if let Some(files) = matches.remove_many::<PathBuf>("files") { + files.collect() } else { Vec::new() }; - flags.coverage_dir = matches.value_of("coverage").map(String::from); + flags.coverage_dir = matches.remove_one::<String>("coverage"); watch_arg_parse(flags, matches, false); flags.subcommand = DenoSubcommand::Test(TestFlags { no_run, @@ -3015,23 +2838,18 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn types_parse(flags: &mut Flags, _matches: &clap::ArgMatches) { +fn types_parse(flags: &mut Flags, _matches: &mut ArgMatches) { flags.subcommand = DenoSubcommand::Types; } -fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn upgrade_parse(flags: &mut Flags, matches: &mut ArgMatches) { ca_file_arg_parse(flags, matches); - let dry_run = matches.is_present("dry-run"); - let force = matches.is_present("force"); - let canary = matches.is_present("canary"); - let version = matches.value_of("version").map(|s| s.to_string()); - let output = if matches.is_present("output") { - let install_root = matches.value_of("output").unwrap(); - Some(PathBuf::from(install_root)) - } else { - None - }; + let dry_run = matches.get_flag("dry-run"); + let force = matches.get_flag("force"); + let canary = matches.get_flag("canary"); + let version = matches.remove_one::<String>("version"); + let output = matches.remove_one::<PathBuf>("output"); flags.subcommand = DenoSubcommand::Upgrade(UpgradeFlags { dry_run, force, @@ -3041,7 +2859,7 @@ fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }); } -fn vendor_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn vendor_parse(flags: &mut Flags, matches: &mut ArgMatches) { ca_file_arg_parse(flags, matches); config_args_parse(flags, matches); import_map_arg_parse(flags, matches); @@ -3050,15 +2868,15 @@ fn vendor_parse(flags: &mut Flags, matches: &clap::ArgMatches) { flags.subcommand = DenoSubcommand::Vendor(VendorFlags { specifiers: matches - .values_of("specifiers") - .map(|p| p.map(ToString::to_string).collect()) + .remove_many::<String>("specifiers") + .map(|p| p.collect()) .unwrap_or_default(), - output_path: matches.value_of("output").map(PathBuf::from), - force: matches.is_present("force"), + output_path: matches.remove_one::<PathBuf>("output"), + force: matches.get_flag("force"), }); } -fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn compile_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { compile_args_without_check_parse(flags, matches); no_check_arg_parse(flags, matches); check_arg_parse(flags, matches); @@ -3066,7 +2884,7 @@ fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { fn compile_args_without_check_parse( flags: &mut Flags, - matches: &clap::ArgMatches, + matches: &mut ArgMatches, ) { import_map_arg_parse(flags, matches); no_remote_arg_parse(flags, matches); @@ -3078,61 +2896,45 @@ fn compile_args_without_check_parse( ca_file_arg_parse(flags, matches); } -fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn permission_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { unsafely_ignore_certificate_errors_parse(flags, matches); - if let Some(read_wl) = matches.values_of("allow-read") { - let read_allowlist: Vec<PathBuf> = read_wl.map(PathBuf::from).collect(); - flags.allow_read = Some(read_allowlist); + if let Some(read_wl) = matches.remove_many::<PathBuf>("allow-read") { + flags.allow_read = Some(read_wl.collect()); } - if let Some(write_wl) = matches.values_of("allow-write") { - let write_allowlist: Vec<PathBuf> = write_wl.map(PathBuf::from).collect(); - flags.allow_write = Some(write_allowlist); + if let Some(write_wl) = matches.remove_many::<PathBuf>("allow-write") { + flags.allow_write = Some(write_wl.collect()); } - if let Some(net_wl) = matches.values_of("allow-net") { - let net_allowlist: Vec<String> = - flags_allow_net::parse(net_wl.map(ToString::to_string).collect()) - .unwrap(); + if let Some(net_wl) = matches.remove_many::<String>("allow-net") { + let net_allowlist = flags_allow_net::parse(net_wl.collect()).unwrap(); flags.allow_net = Some(net_allowlist); } - if let Some(env_wl) = matches.values_of("allow-env") { - let env_allowlist: Vec<String> = env_wl - .map(|env: &str| { - if cfg!(windows) { - env.to_uppercase() - } else { - env.to_string() - } - }) - .collect(); - flags.allow_env = Some(env_allowlist); + if let Some(env_wl) = matches.remove_many::<String>("allow-env") { + flags.allow_env = Some(env_wl.collect()); debug!("env allowlist: {:#?}", &flags.allow_env); } - if let Some(run_wl) = matches.values_of("allow-run") { - let run_allowlist: Vec<String> = run_wl.map(ToString::to_string).collect(); - flags.allow_run = Some(run_allowlist); + if let Some(run_wl) = matches.remove_many::<String>("allow-run") { + flags.allow_run = Some(run_wl.collect()); debug!("run allowlist: {:#?}", &flags.allow_run); } - if let Some(sys_wl) = matches.values_of("allow-sys") { - let sys_allowlist: Vec<String> = sys_wl.map(ToString::to_string).collect(); - flags.allow_sys = Some(sys_allowlist); + if let Some(sys_wl) = matches.remove_many::<String>("allow-sys") { + flags.allow_sys = Some(sys_wl.collect()); debug!("sys info allowlist: {:#?}", &flags.allow_sys); } - if let Some(ffi_wl) = matches.values_of("allow-ffi") { - let ffi_allowlist: Vec<PathBuf> = ffi_wl.map(PathBuf::from).collect(); - flags.allow_ffi = Some(ffi_allowlist); + if let Some(ffi_wl) = matches.remove_many::<PathBuf>("allow-ffi") { + flags.allow_ffi = Some(ffi_wl.collect()); debug!("ffi allowlist: {:#?}", &flags.allow_ffi); } - if matches.is_present("allow-hrtime") { + if matches.get_flag("allow-hrtime") { flags.allow_hrtime = true; } - if matches.is_present("allow-all") { + if matches.get_flag("allow-all") { flags.allow_all = true; flags.allow_read = Some(vec![]); flags.allow_env = Some(vec![]); @@ -3143,24 +2945,25 @@ fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { flags.allow_ffi = Some(vec![]); flags.allow_hrtime = true; } - if matches.is_present("no-prompt") { + if matches.get_flag("no-prompt") { flags.no_prompt = true; } } fn unsafely_ignore_certificate_errors_parse( flags: &mut Flags, - matches: &clap::ArgMatches, + matches: &mut ArgMatches, ) { - if let Some(ic_wl) = matches.values_of("unsafely-ignore-certificate-errors") { - let ic_allowlist: Vec<String> = - flags_allow_net::parse(ic_wl.map(ToString::to_string).collect()).unwrap(); + if let Some(ic_wl) = + matches.remove_many::<String>("unsafely-ignore-certificate-errors") + { + let ic_allowlist = flags_allow_net::parse(ic_wl.collect()).unwrap(); flags.unsafely_ignore_certificate_errors = Some(ic_allowlist); } } fn runtime_args_parse( flags: &mut Flags, - matches: &clap::ArgMatches, + matches: &mut ArgMatches, include_perms: bool, include_inspector: bool, ) { @@ -3178,45 +2981,44 @@ fn runtime_args_parse( enable_testing_features_arg_parse(flags, matches); } -fn inspect_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn inspect_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { let default = || "127.0.0.1:9229".parse::<SocketAddr>().unwrap(); - flags.inspect = if matches.is_present("inspect") { - if let Some(host) = matches.value_of("inspect") { - Some(host.parse().unwrap()) - } else { - Some(default()) - } + flags.inspect = if matches.contains_id("inspect") { + Some( + matches + .remove_one::<SocketAddr>("inspect") + .unwrap_or_else(default), + ) } else { None }; - flags.inspect_brk = if matches.is_present("inspect-brk") { - if let Some(host) = matches.value_of("inspect-brk") { - Some(host.parse().unwrap()) - } else { - Some(default()) - } + flags.inspect_brk = if matches.contains_id("inspect-brk") { + Some( + matches + .remove_one::<SocketAddr>("inspect-brk") + .unwrap_or_else(default), + ) } else { None }; - flags.inspect_wait = if matches.is_present("inspect-wait") { - if let Some(host) = matches.value_of("inspect-wait") { - Some(host.parse().unwrap()) - } else { - Some(default()) - } + flags.inspect_wait = if matches.contains_id("inspect-wait") { + Some( + matches + .remove_one::<SocketAddr>("inspect-wait") + .unwrap_or_else(default), + ) } else { None }; } -fn import_map_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.import_map_path = matches.value_of("import-map").map(ToOwned::to_owned); +fn import_map_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.import_map_path = matches.remove_one::<String>("import-map"); } -fn reload_arg_parse(flags: &mut Flags, matches: &ArgMatches) { - if let Some(cache_bl) = matches.values_of("reload") { - let raw_cache_blocklist: Vec<String> = - cache_bl.map(ToString::to_string).collect(); +fn reload_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if let Some(cache_bl) = matches.remove_many::<String>("reload") { + let raw_cache_blocklist: Vec<String> = cache_bl.collect(); if raw_cache_blocklist.is_empty() { flags.reload = true; } else { @@ -3227,164 +3029,148 @@ fn reload_arg_parse(flags: &mut Flags, matches: &ArgMatches) { } } -fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.ca_data = matches - .value_of("cert") - .map(ToOwned::to_owned) - .map(CaData::File); +fn ca_file_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.ca_data = matches.remove_one::<String>("cert").map(CaData::File); } fn enable_testing_features_arg_parse( flags: &mut Flags, - matches: &clap::ArgMatches, + matches: &mut ArgMatches, ) { - if matches.is_present("enable-testing-features-do-not-use") { + if matches.get_flag("enable-testing-features-do-not-use") { flags.enable_testing_features = true } } -fn cached_only_arg_parse(flags: &mut Flags, matches: &ArgMatches) { - if matches.is_present("cached-only") { +fn cached_only_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if matches.get_flag("cached-only") { flags.cached_only = true; } } -fn ext_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.ext = matches.value_of("ext").map(String::from); +fn ext_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.ext = matches.remove_one::<String>("ext"); } -fn location_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.location = matches - .value_of("location") - .map(|href| Url::parse(href).unwrap()); +fn location_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.location = matches.remove_one::<Url>("location"); } -fn v8_flags_arg_parse(flags: &mut Flags, matches: &ArgMatches) { - if let Some(v8_flags) = matches.values_of("v8-flags") { - flags.v8_flags = v8_flags.map(String::from).collect(); +fn v8_flags_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if let Some(v8_flags) = matches.remove_many::<String>("v8-flags") { + flags.v8_flags = v8_flags.collect(); } } -fn seed_arg_parse(flags: &mut Flags, matches: &ArgMatches) { - if matches.is_present("seed") { - let seed_string = matches.value_of("seed").unwrap(); - let seed = seed_string.parse::<u64>().unwrap(); +fn seed_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if let Some(seed) = matches.remove_one::<u64>("seed") { flags.seed = Some(seed); flags.v8_flags.push(format!("--random-seed={seed}")); } } -fn no_check_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if let Some(cache_type) = matches.value_of("no-check") { - match cache_type { +fn no_check_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if let Some(cache_type) = matches.get_one::<String>("no-check") { + match cache_type.as_str() { "remote" => flags.type_check_mode = TypeCheckMode::Local, _ => debug!( "invalid value for 'no-check' of '{}' using default", cache_type ), } - } else if matches.is_present("no-check") { + } else if matches.contains_id("no-check") { flags.type_check_mode = TypeCheckMode::None; } } -fn check_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if let Some(cache_type) = matches.value_of("check") { - match cache_type { +fn check_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if let Some(cache_type) = matches.get_one::<String>("check") { + match cache_type.as_str() { "all" => flags.type_check_mode = TypeCheckMode::All, _ => debug!( "invalid value for 'check' of '{}' using default", cache_type ), } - } else if matches.is_present("check") { + } else if matches.contains_id("check") { flags.type_check_mode = TypeCheckMode::Local; } } -fn lock_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { +fn lock_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { lock_arg_parse(flags, matches); no_lock_arg_parse(flags, matches); - if matches.is_present("lock-write") { + if matches.get_flag("lock-write") { flags.lock_write = true; } } -fn lock_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if matches.is_present("lock") { - let lockfile = if let Some(path) = matches.value_of("lock") { - path - } else { - "./deno.lock" - }; - flags.lock = Some(PathBuf::from(lockfile)); +fn lock_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if matches.contains_id("lock") { + let lockfile = matches + .remove_one::<PathBuf>("lock") + .unwrap_or_else(|| PathBuf::from("./deno.lock")); + flags.lock = Some(lockfile); } } -fn no_lock_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if matches.is_present("no-lock") { +fn no_lock_arg_parse(flags: &mut Flags, matches: &ArgMatches) { + if matches.get_flag("no-lock") { flags.no_lock = true; } } -fn config_args_parse(flags: &mut Flags, matches: &ArgMatches) { - flags.config_flag = if matches.is_present("no-config") { +fn config_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.config_flag = if matches.get_flag("no-config") { ConfigFlag::Disabled - } else if let Some(config) = matches.value_of("config") { - ConfigFlag::Path(config.to_string()) + } else if let Some(config) = matches.remove_one::<String>("config") { + ConfigFlag::Path(config) } else { ConfigFlag::Discover }; } -fn no_remote_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if matches.is_present("no-remote") { +fn no_remote_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if matches.get_flag("no-remote") { flags.no_remote = true; } } -fn no_npm_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if matches.is_present("no-npm") { +fn no_npm_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) { + if matches.get_flag("no-npm") { flags.no_npm = true; } } -fn local_npm_args_parse(flags: &mut Flags, matches: &ArgMatches) { - flags.node_modules_dir = optional_bool_parse(matches, "node-modules-dir"); -} - -fn inspect_arg_validate(val: &str) -> Result<(), String> { - match val.parse::<SocketAddr>() { - Ok(_) => Ok(()), - Err(e) => Err(e.to_string()), - } +fn local_npm_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { + flags.node_modules_dir = matches.remove_one::<bool>("node-modules-dir"); } -fn reload_arg_validate(urlstr: &str) -> Result<(), String> { +fn reload_arg_validate(urlstr: &str) -> Result<String, String> { if urlstr.is_empty() { return Err(String::from("Missing url. Check for extra commas.")); } match Url::from_str(urlstr) { - Ok(_) => Ok(()), + Ok(_) => Ok(urlstr.to_string()), Err(e) => Err(e.to_string()), } } fn watch_arg_parse( flags: &mut Flags, - matches: &clap::ArgMatches, + matches: &mut ArgMatches, allow_extra: bool, ) { if allow_extra { - if let Some(f) = matches.values_of("watch") { - flags.watch = Some(f.map(PathBuf::from).collect()); + if let Some(f) = matches.remove_many::<PathBuf>("watch") { + flags.watch = Some(f.collect()); } - } else if matches.is_present("watch") { + } else if matches.get_flag("watch") { flags.watch = Some(vec![]); } - if matches.is_present("no-clear-screen") { + if matches.get_flag("no-clear-screen") { flags.no_clear_screen = true; } } @@ -3463,9 +3249,15 @@ mod tests { #[test] fn version() { let r = flags_from_vec(svec!["deno", "--version"]); - assert_eq!(r.unwrap_err().kind(), clap::ErrorKind::DisplayVersion); + assert_eq!( + r.unwrap_err().kind(), + clap::error::ErrorKind::DisplayVersion + ); let r = flags_from_vec(svec!["deno", "-V"]); - assert_eq!(r.unwrap_err().kind(), clap::ErrorKind::DisplayVersion); + assert_eq!( + r.unwrap_err().kind(), + clap::error::ErrorKind::DisplayVersion + ); } #[test] @@ -4272,7 +4064,10 @@ mod tests { "--no-remote", "script.ts" ]); - assert_eq!(r.unwrap_err().kind(), clap::ErrorKind::ArgumentConflict); + assert_eq!( + r.unwrap_err().kind(), + clap::error::ErrorKind::ArgumentConflict + ); } } @@ -5257,7 +5052,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::ErrorKind::DisplayHelp); + assert_eq!(r.err().unwrap().kind(), clap::error::ErrorKind::DisplayHelp); } #[test] @@ -6418,7 +6213,7 @@ mod tests { assert!(r.is_err()); let error_message = r.unwrap_err().to_string(); assert!(&error_message - .contains("error: The following required arguments were not provided:")); + .contains("error: the following required arguments were not provided:")); assert!(&error_message.contains("--watch[=<FILES>...]")); } @@ -6672,7 +6467,10 @@ mod tests { #[test] fn task_subcommand_noconfig_invalid() { let r = flags_from_vec(svec!["deno", "task", "--no-config"]); - assert_eq!(r.unwrap_err().kind(), clap::ErrorKind::UnknownArgument); + assert_eq!( + r.unwrap_err().kind(), + clap::error::ErrorKind::UnknownArgument + ); } #[test] |