summaryrefslogtreecommitdiff
path: root/cli/args/flags.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/args/flags.rs')
-rw-r--r--cli/args/flags.rs5897
1 files changed, 5897 insertions, 0 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
new file mode 100644
index 000000000..c61e9ab21
--- /dev/null
+++ b/cli/args/flags.rs
@@ -0,0 +1,5897 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use clap::Arg;
+use clap::ArgMatches;
+use clap::ColorChoice;
+use clap::Command;
+use clap::ValueHint;
+use deno_core::serde::Deserialize;
+use deno_core::serde::Serialize;
+use deno_core::url::Url;
+use deno_runtime::permissions::PermissionsOptions;
+use log::debug;
+use log::Level;
+use once_cell::sync::Lazy;
+use std::env;
+use std::net::SocketAddr;
+use std::num::NonZeroU32;
+use std::num::NonZeroU8;
+use std::num::NonZeroUsize;
+use std::path::PathBuf;
+use std::str::FromStr;
+
+use super::flags_allow_net;
+
+static LONG_VERSION: Lazy<String> = Lazy::new(|| {
+ format!(
+ "{} ({}, {})\nv8 {}\ntypescript {}",
+ crate::version::deno(),
+ if crate::version::is_canary() {
+ "canary"
+ } else {
+ env!("PROFILE")
+ },
+ env!("TARGET"),
+ deno_core::v8_version(),
+ crate::version::TYPESCRIPT
+ )
+});
+
+static SHORT_VERSION: Lazy<String> = Lazy::new(|| {
+ crate::version::deno()
+ .split('+')
+ .next()
+ .unwrap()
+ .to_string()
+});
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct BenchFlags {
+ pub ignore: Vec<PathBuf>,
+ pub include: Option<Vec<String>>,
+ pub filter: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct BundleFlags {
+ pub source_file: String,
+ pub out_file: Option<PathBuf>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct CacheFlags {
+ pub files: Vec<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct CheckFlags {
+ pub files: Vec<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct CompileFlags {
+ pub source_file: String,
+ pub output: Option<PathBuf>,
+ pub args: Vec<String>,
+ pub target: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct CompletionsFlags {
+ pub buf: Box<[u8]>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct CoverageFlags {
+ pub files: Vec<PathBuf>,
+ pub output: Option<PathBuf>,
+ pub ignore: Vec<PathBuf>,
+ pub include: Vec<String>,
+ pub exclude: Vec<String>,
+ pub lcov: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct DocFlags {
+ pub private: bool,
+ pub json: bool,
+ pub source_file: Option<String>,
+ pub filter: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct EvalFlags {
+ pub print: bool,
+ pub code: String,
+ pub ext: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct FmtFlags {
+ pub check: bool,
+ pub files: Vec<PathBuf>,
+ pub ignore: Vec<PathBuf>,
+ pub ext: String,
+ pub use_tabs: Option<bool>,
+ pub line_width: Option<NonZeroU32>,
+ pub indent_width: Option<NonZeroU8>,
+ pub single_quote: Option<bool>,
+ pub prose_wrap: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct InfoFlags {
+ pub json: bool,
+ pub file: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct InstallFlags {
+ pub module_url: String,
+ pub args: Vec<String>,
+ pub name: Option<String>,
+ pub root: Option<PathBuf>,
+ pub force: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct UninstallFlags {
+ pub name: String,
+ pub root: Option<PathBuf>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct LintFlags {
+ pub files: Vec<PathBuf>,
+ pub ignore: Vec<PathBuf>,
+ pub rules: bool,
+ pub maybe_rules_tags: Option<Vec<String>>,
+ pub maybe_rules_include: Option<Vec<String>>,
+ pub maybe_rules_exclude: Option<Vec<String>>,
+ pub json: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct ReplFlags {
+ pub eval_files: Option<Vec<String>>,
+ pub eval: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct RunFlags {
+ pub script: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct TaskFlags {
+ pub cwd: Option<String>,
+ pub task: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct TestFlags {
+ pub ignore: Vec<PathBuf>,
+ pub doc: bool,
+ pub no_run: bool,
+ pub fail_fast: Option<NonZeroUsize>,
+ pub allow_none: bool,
+ pub include: Option<Vec<String>>,
+ pub filter: Option<String>,
+ pub shuffle: Option<u64>,
+ pub concurrent_jobs: NonZeroUsize,
+ pub trace_ops: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct UpgradeFlags {
+ pub dry_run: bool,
+ pub force: bool,
+ pub canary: bool,
+ pub version: Option<String>,
+ pub output: Option<PathBuf>,
+ pub ca_file: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct VendorFlags {
+ pub specifiers: Vec<String>,
+ pub output_path: Option<PathBuf>,
+ pub force: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub enum DenoSubcommand {
+ Bench(BenchFlags),
+ Bundle(BundleFlags),
+ Cache(CacheFlags),
+ Check(CheckFlags),
+ Compile(CompileFlags),
+ Completions(CompletionsFlags),
+ Coverage(CoverageFlags),
+ Doc(DocFlags),
+ Eval(EvalFlags),
+ Fmt(FmtFlags),
+ Info(InfoFlags),
+ Install(InstallFlags),
+ Uninstall(UninstallFlags),
+ Lsp,
+ Lint(LintFlags),
+ Repl(ReplFlags),
+ Run(RunFlags),
+ Task(TaskFlags),
+ Test(TestFlags),
+ Types,
+ Upgrade(UpgradeFlags),
+ Vendor(VendorFlags),
+}
+
+impl Default for DenoSubcommand {
+ fn default() -> DenoSubcommand {
+ DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None,
+ })
+ }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum TypeCheckMode {
+ /// Type-check all modules.
+ All,
+ /// Skip type-checking of all modules. The default value for "deno run" and
+ /// several other subcommands.
+ None,
+ /// Only type-check local modules. The default value for "deno test" and
+ /// several other subcommands.
+ Local,
+}
+
+impl Default for TypeCheckMode {
+ fn default() -> Self {
+ Self::None
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum ConfigFlag {
+ Discover,
+ Path(String),
+ Disabled,
+}
+
+impl Default for ConfigFlag {
+ fn default() -> Self {
+ Self::Discover
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Default)]
+pub struct Flags {
+ /// Vector of CLI arguments - these are user script arguments, all Deno
+ /// specific flags are removed.
+ pub argv: Vec<String>,
+ pub subcommand: DenoSubcommand,
+
+ pub allow_all: bool,
+ pub allow_env: Option<Vec<String>>,
+ pub allow_hrtime: bool,
+ pub allow_net: Option<Vec<String>>,
+ pub allow_ffi: Option<Vec<PathBuf>>,
+ pub allow_read: Option<Vec<PathBuf>>,
+ pub allow_run: Option<Vec<String>>,
+ pub allow_write: Option<Vec<PathBuf>>,
+ pub ca_stores: Option<Vec<String>>,
+ pub ca_file: Option<String>,
+ pub cache_blocklist: Vec<String>,
+ /// This is not exposed as an option in the CLI, it is used internally when
+ /// the language server is configured with an explicit cache option.
+ pub cache_path: Option<PathBuf>,
+ pub cached_only: bool,
+ pub type_check_mode: TypeCheckMode,
+ pub config_flag: ConfigFlag,
+ pub coverage_dir: Option<String>,
+ pub enable_testing_features: bool,
+ pub ignore: Vec<PathBuf>,
+ pub import_map_path: Option<String>,
+ pub inspect_brk: Option<SocketAddr>,
+ pub inspect: Option<SocketAddr>,
+ pub location: Option<Url>,
+ pub lock_write: bool,
+ pub lock: Option<PathBuf>,
+ pub log_level: Option<Level>,
+ pub no_remote: bool,
+ /// If true, a list of Node built-in modules will be injected into
+ /// the import map.
+ pub compat: bool,
+ pub no_prompt: bool,
+ pub reload: bool,
+ pub repl: bool,
+ pub seed: Option<u64>,
+ pub unstable: bool,
+ pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
+ pub v8_flags: Vec<String>,
+ pub version: bool,
+ pub watch: Option<Vec<PathBuf>>,
+ pub no_clear_screen: bool,
+}
+
+fn join_paths(allowlist: &[PathBuf], d: &str) -> String {
+ allowlist
+ .iter()
+ .map(|path| path.to_str().unwrap().to_string())
+ .collect::<Vec<String>>()
+ .join(d)
+}
+
+impl Flags {
+ /// Return list of permission arguments that are equivalent
+ /// to the ones used to create `self`.
+ pub fn to_permission_args(&self) -> Vec<String> {
+ let mut args = vec![];
+
+ if self.allow_all {
+ args.push("--allow-all".to_string());
+ return args;
+ }
+
+ match &self.allow_read {
+ Some(read_allowlist) if read_allowlist.is_empty() => {
+ args.push("--allow-read".to_string());
+ }
+ Some(read_allowlist) => {
+ let s = format!("--allow-read={}", join_paths(read_allowlist, ","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ match &self.allow_write {
+ Some(write_allowlist) if write_allowlist.is_empty() => {
+ args.push("--allow-write".to_string());
+ }
+ Some(write_allowlist) => {
+ let s = format!("--allow-write={}", join_paths(write_allowlist, ","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ match &self.allow_net {
+ Some(net_allowlist) if net_allowlist.is_empty() => {
+ args.push("--allow-net".to_string());
+ }
+ Some(net_allowlist) => {
+ let s = format!("--allow-net={}", net_allowlist.join(","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ match &self.unsafely_ignore_certificate_errors {
+ Some(ic_allowlist) if ic_allowlist.is_empty() => {
+ args.push("--unsafely-ignore-certificate-errors".to_string());
+ }
+ Some(ic_allowlist) => {
+ let s = format!(
+ "--unsafely-ignore-certificate-errors={}",
+ ic_allowlist.join(",")
+ );
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ match &self.allow_env {
+ Some(env_allowlist) if env_allowlist.is_empty() => {
+ args.push("--allow-env".to_string());
+ }
+ Some(env_allowlist) => {
+ let s = format!("--allow-env={}", env_allowlist.join(","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ match &self.allow_run {
+ Some(run_allowlist) if run_allowlist.is_empty() => {
+ args.push("--allow-run".to_string());
+ }
+ Some(run_allowlist) => {
+ let s = format!("--allow-run={}", run_allowlist.join(","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ match &self.allow_ffi {
+ Some(ffi_allowlist) if ffi_allowlist.is_empty() => {
+ args.push("--allow-ffi".to_string());
+ }
+ Some(ffi_allowlist) => {
+ let s = format!("--allow-ffi={}", join_paths(ffi_allowlist, ","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
+ if self.allow_hrtime {
+ args.push("--allow-hrtime".to_string());
+ }
+
+ args
+ }
+
+ /// Extract path arguments for config search paths.
+ /// If it returns Some(vec), the config should be discovered
+ /// from the current dir after trying to discover from each entry in vec.
+ /// If it returns None, the config file shouldn't be discovered at all.
+ pub fn config_path_args(&self) -> Option<Vec<PathBuf>> {
+ use DenoSubcommand::*;
+ if let Fmt(FmtFlags { files, .. }) = &self.subcommand {
+ Some(files.clone())
+ } else if let Lint(LintFlags { files, .. }) = &self.subcommand {
+ Some(files.clone())
+ } else if let Run(RunFlags { script }) = &self.subcommand {
+ if let Ok(module_specifier) = deno_core::resolve_url_or_path(script) {
+ if module_specifier.scheme() == "file" {
+ if let Ok(p) = module_specifier.to_file_path() {
+ Some(vec![p])
+ } else {
+ Some(vec![])
+ }
+ } else {
+ // When the entrypoint doesn't have file: scheme (it's the remote
+ // script), then we don't auto discover config file.
+ None
+ }
+ } else {
+ Some(vec![])
+ }
+ } else {
+ Some(vec![])
+ }
+ }
+
+ pub fn permissions_options(&self) -> PermissionsOptions {
+ PermissionsOptions {
+ allow_env: self.allow_env.clone(),
+ allow_hrtime: self.allow_hrtime,
+ allow_net: self.allow_net.clone(),
+ allow_ffi: self.allow_ffi.clone(),
+ allow_read: self.allow_read.clone(),
+ allow_run: self.allow_run.clone(),
+ allow_write: self.allow_write.clone(),
+ prompt: !self.no_prompt,
+ }
+ }
+}
+
+static ENV_VARIABLES_HELP: &str = r#"ENVIRONMENT VARIABLES:
+ DENO_AUTH_TOKENS A semi-colon separated list of bearer tokens and
+ hostnames to use when fetching remote modules from
+ private repositories
+ (e.g. "abcde12345@deno.land;54321edcba@github.com")
+ DENO_TLS_CA_STORE Comma-separated list of order dependent certificate
+ stores. Possible values: "system", "mozilla".
+ Defaults to "mozilla".
+ DENO_CERT Load certificate authority from PEM encoded file
+ DENO_DIR Set the cache directory
+ DENO_INSTALL_ROOT Set deno install's output directory
+ (defaults to $HOME/.deno/bin)
+ DENO_NO_PROMPT Set to disable permission prompts on access
+ (alternative to passing --no-prompt on invocation)
+ DENO_WEBGPU_TRACE Directory to use for wgpu traces
+ HTTP_PROXY Proxy address for HTTP requests
+ (module downloads, fetch)
+ HTTPS_PROXY Proxy address for HTTPS requests
+ (module downloads, fetch)
+ NO_COLOR Set to disable color
+ NO_PROXY Comma-separated list of hosts which do not use a proxy
+ (module downloads, fetch)"#;
+
+static DENO_HELP: Lazy<String> = Lazy::new(|| {
+ format!(
+ "A modern JavaScript and TypeScript runtime
+
+Docs: https://deno.land/manual@v{}
+Modules: https://deno.land/std/ https://deno.land/x/
+Bugs: https://github.com/denoland/deno/issues
+
+To start the REPL:
+
+ deno
+
+To execute a script:
+
+ deno run https://deno.land/std/examples/welcome.ts
+
+To evaluate code in the shell:
+
+ deno eval \"console.log(30933 + 404)\"
+",
+ SHORT_VERSION.as_str()
+ )
+});
+
+/// 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 app = clap_root(&version);
+ let matches = app.clone().try_get_matches_from(&args)?;
+
+ let mut flags = Flags::default();
+
+ if matches.is_present("unstable") {
+ flags.unstable = true;
+ }
+ if matches.is_present("log-level") {
+ flags.log_level = match matches.value_of("log-level").unwrap() {
+ "debug" => Some(Level::Debug),
+ "info" => Some(Level::Info),
+ _ => unreachable!(),
+ };
+ }
+ if matches.is_present("quiet") {
+ flags.log_level = Some(Level::Error);
+ }
+
+ 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(("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(
+ &mut flags,
+ ReplFlags {
+ eval_files: None,
+ eval: None,
+ },
+ ),
+ }
+
+ Ok(flags)
+}
+
+fn handle_repl_flags(flags: &mut Flags, repl_flags: ReplFlags) {
+ flags.repl = true;
+ flags.subcommand = DenoSubcommand::Repl(repl_flags);
+ flags.allow_net = Some(vec![]);
+ flags.allow_env = Some(vec![]);
+ flags.allow_run = Some(vec![]);
+ flags.allow_read = Some(vec![]);
+ flags.allow_write = Some(vec![]);
+ flags.allow_ffi = Some(vec![]);
+ flags.allow_hrtime = true;
+}
+
+fn clap_root(version: &str) -> Command {
+ clap::Command::new("deno")
+ .bin_name("deno")
+ .color(ColorChoice::Never)
+ .max_term_width(80)
+ .version(version)
+ .long_version(LONG_VERSION.as_str())
+ .arg(
+ Arg::new("unstable")
+ .long("unstable")
+ .help("Enable unstable features and APIs")
+ .global(true),
+ )
+ .arg(
+ Arg::new("log-level")
+ .short('L')
+ .long("log-level")
+ .help("Set log level")
+ .hide(true)
+ .takes_value(true)
+ .possible_values(&["debug", "info"])
+ .global(true),
+ )
+ .arg(
+ Arg::new("quiet")
+ .short('q')
+ .long("quiet")
+ .help("Suppress diagnostic output")
+ .global(true),
+ )
+ .subcommand(bench_subcommand())
+ .subcommand(bundle_subcommand())
+ .subcommand(cache_subcommand())
+ .subcommand(check_subcommand())
+ .subcommand(compile_subcommand())
+ .subcommand(completions_subcommand())
+ .subcommand(coverage_subcommand())
+ .subcommand(doc_subcommand())
+ .subcommand(eval_subcommand())
+ .subcommand(fmt_subcommand())
+ .subcommand(info_subcommand())
+ .subcommand(install_subcommand())
+ .subcommand(uninstall_subcommand())
+ .subcommand(lsp_subcommand())
+ .subcommand(lint_subcommand())
+ .subcommand(repl_subcommand())
+ .subcommand(run_subcommand())
+ .subcommand(task_subcommand())
+ .subcommand(test_subcommand())
+ .subcommand(types_subcommand())
+ .subcommand(upgrade_subcommand())
+ .subcommand(vendor_subcommand())
+ .long_about(DENO_HELP.as_str())
+ .after_help(ENV_VARIABLES_HELP)
+}
+
+fn bench_subcommand<'a>() -> Command<'a> {
+ runtime_args(Command::new("bench"), true, false)
+ .trailing_var_arg(true)
+ .arg(
+ Arg::new("ignore")
+ .long("ignore")
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Ignore files"),
+ )
+ .arg(
+ Arg::new("filter")
+ .allow_hyphen_values(true)
+ .long("filter")
+ .takes_value(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),
+ )
+ .arg(watch_arg(false))
+ .arg(no_clear_screen_arg())
+ .arg(script_arg().last(true))
+ .about("Run benchmarks")
+ .long_about(
+ "Run benchmarks using Deno's built-in bench tool.
+
+Evaluate the given modules, run all benches declared with 'Deno.bench()' \
+and report results to standard output:
+
+ deno bench src/fetch_bench.ts src/signal_bench.ts
+
+Directory arguments are expanded to all contained files matching the \
+glob {*_,*.,}bench.{js,mjs,ts,jsx,tsx}:
+
+ deno bench src/",
+ )
+}
+
+fn bundle_subcommand<'a>() -> Command<'a> {
+ compile_args(Command::new("bundle"))
+ .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_hint(ValueHint::FilePath),
+ )
+ .arg(watch_arg(false))
+ .arg(no_clear_screen_arg())
+ .about("Bundle module and dependencies into single file")
+ .long_about(
+ "Output a single JavaScript file with all dependencies.
+
+ deno bundle https://deno.land/std/examples/colors.ts colors.bundle.js
+
+If no output file is given, the output is written to standard output:
+
+ deno bundle https://deno.land/std/examples/colors.ts",
+ )
+}
+
+fn cache_subcommand<'a>() -> Command<'a> {
+ compile_args(Command::new("cache"))
+ .arg(
+ Arg::new("file")
+ .takes_value(true)
+ .required(true)
+ .min_values(1)
+ .value_hint(ValueHint::FilePath),
+ )
+ .about("Cache the dependencies")
+ .long_about(
+ "Cache and compile remote dependencies recursively.
+
+Download and compile a module with all of its static dependencies and save \
+them in the local cache, without running any code:
+
+ deno cache https://deno.land/std/http/file_server.ts
+
+Future runs of this module will trigger no downloads or compilation unless \
+--reload is specified.",
+ )
+}
+
+fn check_subcommand<'a>() -> Command<'a> {
+ compile_args_without_check_args(Command::new("check"))
+ .arg(
+ Arg::new("remote")
+ .long("remote")
+ .help("Type-check all modules, including remote")
+ )
+ .arg(
+ Arg::new("file")
+ .takes_value(true)
+ .required(true)
+ .min_values(1)
+ .value_hint(ValueHint::FilePath),
+ )
+ .about("Type-check the dependencies")
+ .long_about(
+ "Download and type-check without execution.
+
+ deno check https://deno.land/std/http/file_server.ts
+
+Unless --reload is specified, this command will not re-download already cached dependencies.",
+ )
+}
+
+fn compile_subcommand<'a>() -> Command<'a> {
+ runtime_args(Command::new("compile"), true, false)
+ .trailing_var_arg(true)
+ .arg(script_arg().required(true))
+ .arg(
+ Arg::new("output")
+ .long("output")
+ .short('o')
+ .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(&[
+ "x86_64-unknown-linux-gnu",
+ "x86_64-pc-windows-msvc",
+ "x86_64-apple-darwin",
+ "aarch64-apple-darwin",
+ ]),
+ )
+ .about("UNSTABLE: Compile the script into a self contained executable")
+ .long_about(
+ "UNSTABLE: Compiles the given script into a self contained executable.
+
+ deno compile -A https://deno.land/std/http/file_server.ts
+ deno compile --output color_util https://deno.land/std/examples/colors.ts
+
+Any flags passed which affect runtime behavior, such as '--unstable', \
+'--allow-*', '--v8-flags', etc. are encoded into the output executable and \
+used at runtime as if they were passed to a similar 'deno run' command.
+
+The executable name is inferred by default: Attempt to take the file stem of \
+the URL path. The above example would become 'file_server'. If the file stem \
+is something generic like 'main', 'mod', 'index' or 'cli', and the path has no \
+parent, take the file name of the parent path. Otherwise settle with the \
+generic name. If the resulting name has an '@...' suffix, strip it.
+
+Cross-compiling to different target architectures is supported using the \
+`--target` flag. On the first invocation with deno will download proper \
+binary and cache it in $DENO_DIR. The aarch64-apple-darwin target is not \
+supported in canary.
+",
+ )
+}
+
+fn completions_subcommand<'a>() -> Command<'a> {
+ Command::new("completions")
+ .disable_help_subcommand(true)
+ .arg(
+ Arg::new("shell")
+ .possible_values(&["bash", "fish", "powershell", "zsh", "fig"])
+ .required(true),
+ )
+ .about("Generate shell completions")
+ .long_about(
+ "Output shell completion script to standard output.
+
+ deno completions bash > /usr/local/etc/bash_completion.d/deno.bash
+ source /usr/local/etc/bash_completion.d/deno.bash",
+ )
+}
+
+fn coverage_subcommand<'a>() -> Command<'a> {
+ Command::new("coverage")
+ .about("Print coverage reports")
+ .long_about(
+ "Print coverage reports from coverage profiles.
+
+Collect a coverage profile with deno test:
+
+ deno test --coverage=cov_profile
+
+Print a report to stdout:
+
+ deno coverage cov_profile
+
+Include urls that start with the file schema:
+
+ deno coverage --include=\"^file:\" cov_profile
+
+Exclude urls ending with test.ts and test.js:
+
+ deno coverage --exclude=\"test\\.(ts|js)\" cov_profile
+
+Include urls that start with the file schema and exclude files ending with \
+test.ts and test.js, for an url to match it must match the include pattern and \
+not match the exclude pattern:
+
+ deno coverage --include=\"^file:\" --exclude=\"test\\.(ts|js)\" cov_profile
+
+Write a report using the lcov format:
+
+ deno coverage --lcov --output=cov.lcov cov_profile/
+
+Generate html reports from lcov:
+
+ genhtml -o html_cov cov.lcov
+",
+ )
+ .arg(
+ Arg::new("ignore")
+ .long("ignore")
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Ignore coverage files")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("include")
+ .long("include")
+ .takes_value(true)
+ .value_name("regex")
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ .require_equals(true)
+ .default_value(r"^file:")
+ .help("Include source files in the report"),
+ )
+ .arg(
+ Arg::new("exclude")
+ .long("exclude")
+ .takes_value(true)
+ .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"),
+ )
+ .arg(
+ Arg::new("lcov")
+ .long("lcov")
+ .help("Output coverage report in lcov format")
+ .takes_value(false),
+ )
+ .arg(
+ Arg::new("output")
+ .requires("lcov")
+ .long("output")
+ .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)
+ .required(true)
+ .value_hint(ValueHint::AnyPath),
+ )
+}
+
+fn doc_subcommand<'a>() -> Command<'a> {
+ Command::new("doc")
+ .about("Show documentation for a module")
+ .long_about(
+ "Show documentation for a module.
+
+Output documentation to standard output:
+
+ deno doc ./path/to/module.ts
+
+Output private documentation to standard output:
+
+ deno doc --private ./path/to/module.ts
+
+Output documentation in JSON format:
+
+ deno doc --json ./path/to/module.ts
+
+Target a specific symbol:
+
+ deno doc ./path/to/module.ts MyClass.someField
+
+Show documentation for runtime built-ins:
+
+ deno doc
+ deno doc --builtin Deno.Listener",
+ )
+ .arg(import_map_arg())
+ .arg(reload_arg())
+ .arg(
+ Arg::new("json")
+ .long("json")
+ .help("Output documentation in JSON format")
+ .takes_value(false),
+ )
+ .arg(
+ Arg::new("private")
+ .long("private")
+ .help("Output private documentation")
+ .takes_value(false),
+ )
+ // 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("filter")
+ .help("Dot separated path to symbol")
+ .takes_value(true)
+ .required(false)
+ .conflicts_with("json"),
+ )
+}
+
+fn eval_subcommand<'a>() -> Command<'a> {
+ runtime_args(Command::new("eval"), false, true)
+ .about("Eval script")
+ .long_about(
+ "Evaluate JavaScript from the command line.
+
+ deno eval \"console.log('hello world')\"
+
+To evaluate as TypeScript:
+
+ deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\"
+
+This command has implicit access to all permissions (--allow-all).",
+ )
+ .arg(
+ // TODO(@satyarohith): remove this argument in 2.0.
+ Arg::new("ts")
+ .long("ts")
+ .short('T')
+ .help("Treat eval input as TypeScript")
+ .takes_value(false)
+ .multiple_occurrences(false)
+ .multiple_values(false)
+ .hide(true),
+ )
+ .arg(
+ Arg::new("ext")
+ .long("ext")
+ .help("Set standard input (stdin) content type")
+ .takes_value(true)
+ .default_value("js")
+ .possible_values(&["ts", "tsx", "js", "jsx"]),
+ )
+ .arg(
+ Arg::new("print")
+ .long("print")
+ .short('p')
+ .help("print result to stdout")
+ .takes_value(false)
+ .multiple_occurrences(false)
+ .multiple_values(false),
+ )
+ .arg(
+ Arg::new("code_arg")
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ .help("Code arg")
+ .value_name("CODE_ARG")
+ .required(true),
+ )
+}
+
+fn fmt_subcommand<'a>() -> Command<'a> {
+ Command::new("fmt")
+ .about("Format source files")
+ .long_about(
+ "Auto-format JavaScript, TypeScript, Markdown, and JSON files.
+
+ deno fmt
+ deno fmt myfile1.ts myfile2.ts
+ deno fmt --check
+
+Format stdin and write to stdout:
+
+ cat file.ts | deno fmt -
+
+Ignore formatting code by preceding it with an ignore comment:
+
+ // deno-fmt-ignore
+
+Ignore formatting a file by adding an ignore comment at the top of the file:
+
+ // deno-fmt-ignore-file",
+ )
+ .args(config_args())
+ .arg(
+ Arg::new("check")
+ .long("check")
+ .help("Check if the source files are formatted")
+ .takes_value(false),
+ )
+ .arg(
+ Arg::new("ext")
+ .long("ext")
+ .help("Set standard input (stdin) content type")
+ .takes_value(true)
+ .default_value("ts")
+ .possible_values(&["ts", "tsx", "js", "jsx", "md", "json", "jsonc"]),
+ )
+ .arg(
+ Arg::new("ignore")
+ .long("ignore")
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Ignore formatting particular source files")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("files")
+ .takes_value(true)
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ .required(false)
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(watch_arg(false))
+ .arg(no_clear_screen_arg())
+ .arg(
+ Arg::new("options-use-tabs")
+ .long("options-use-tabs")
+ .help("Use tabs instead of spaces for indentation. Defaults to false."),
+ )
+ .arg(
+ Arg::new("options-line-width")
+ .long("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("options-line-width should be a non zero integer".to_string())
+ }
+ }),
+ )
+ .arg(
+ Arg::new("options-indent-width")
+ .long("options-indent-width")
+ .help("Define indentation width. Defaults to 2.")
+ .takes_value(true)
+ .validator(|val: &str| match val.parse::<NonZeroUsize>() {
+ Ok(_) => Ok(()),
+ Err(_) => {
+ Err("options-indent-width should be a non zero integer".to_string())
+ }
+ }),
+ )
+ .arg(
+ Arg::new("options-single-quote")
+ .long("options-single-quote")
+ .help("Use single quotes. Defaults to false."),
+ )
+ .arg(
+ Arg::new("options-prose-wrap")
+ .long("options-prose-wrap")
+ .takes_value(true)
+ .possible_values(&["always", "never", "preserve"])
+ .help("Define how prose should be wrapped. Defaults to always."),
+ )
+}
+
+fn info_subcommand<'a>() -> Command<'a> {
+ Command::new("info")
+ .about("Show info about cache or info related to source file")
+ .long_about(
+ "Information about a module or the cache directories.
+
+Get information about a module:
+
+ deno info https://deno.land/std/http/file_server.ts
+
+The following information is shown:
+
+local: Local path of the file.
+type: JavaScript, TypeScript, or JSON.
+emit: Local path of compiled source code. (TypeScript only.)
+dependencies: Dependency tree of the source file.
+
+Without any additional arguments, 'deno info' shows:
+
+DENO_DIR: Directory containing Deno-managed files.
+Remote modules cache: Subdirectory containing downloaded remote modules.
+TypeScript compiler cache: Subdirectory containing TS compiler output.",
+ )
+ .arg(Arg::new("file").takes_value(true).required(false).value_hint(ValueHint::FilePath))
+ .arg(reload_arg().requires("file"))
+ .arg(ca_file_arg())
+ .arg(
+ location_arg()
+ .conflicts_with("file")
+ .help("Show files used for origin bound APIs like the Web Storage API when running a script with '--location=<HREF>'")
+ )
+ // TODO(lucacasonato): remove for 2.0
+ .arg(no_check_arg().hide(true))
+ .args(config_args())
+ .arg(import_map_arg())
+ .arg(
+ Arg::new("json")
+ .long("json")
+ .help("UNSTABLE: Outputs the information in JSON format")
+ .takes_value(false),
+ )
+}
+
+fn install_subcommand<'a>() -> Command<'a> {
+ 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("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_hint(ValueHint::DirPath))
+ .arg(
+ Arg::new("force")
+ .long("force")
+ .short('f')
+ .help("Forcefully overwrite existing installation")
+ .takes_value(false))
+ .about("Install script as an executable")
+ .long_about(
+ "Installs a script as an executable in the installation root's bin directory.
+
+ deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts
+ deno install https://deno.land/std/examples/colors.ts
+
+To change the executable name, use -n/--name:
+
+ deno install --allow-net --allow-read -n serve https://deno.land/std/http/file_server.ts
+
+The executable name is inferred by default:
+ - Attempt to take the file stem of the URL path. The above example would
+ become 'file_server'.
+ - If the file stem is something generic like 'main', 'mod', 'index' or 'cli',
+ and the path has no parent, take the file name of the parent path. Otherwise
+ settle with the generic name.
+ - If the resulting name has an '@...' suffix, strip it.
+
+To change the installation root, use --root:
+
+ deno install --allow-net --allow-read --root /usr/local https://deno.land/std/http/file_server.ts
+
+The installation root is determined, in order of precedence:
+ - --root option
+ - DENO_INSTALL_ROOT environment variable
+ - $HOME/.deno
+
+These must be added to the path manually if required.")
+}
+
+fn uninstall_subcommand<'a>() -> Command<'a> {
+ Command::new("uninstall")
+ .trailing_var_arg(true)
+ .arg(
+ Arg::new("name")
+ .required(true)
+ .multiple_occurrences(false)
+ .allow_hyphen_values(true))
+ .arg(
+ Arg::new("root")
+ .long("root")
+ .help("Installation root")
+ .takes_value(true)
+ .multiple_occurrences(false)
+ .value_hint(ValueHint::DirPath))
+ .about("Uninstall a script previously installed with deno install")
+ .long_about(
+ "Uninstalls an executable script in the installation root's bin directory.
+
+ deno uninstall serve
+
+To change the installation root, use --root:
+
+ deno uninstall --root /usr/local serve
+
+The installation root is determined, in order of precedence:
+ - --root option
+ - DENO_INSTALL_ROOT environment variable
+ - $HOME/.deno")
+}
+
+static LSP_HELP: Lazy<String> = Lazy::new(|| {
+ format!(
+ "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{}/getting_started/setup_your_environment#editors-and-ides",
+ SHORT_VERSION.as_str()
+ )
+});
+
+fn lsp_subcommand<'a>() -> Command<'a> {
+ Command::new("lsp")
+ .about("Start the language server")
+ .long_about(LSP_HELP.as_str())
+}
+
+fn lint_subcommand<'a>() -> Command<'a> {
+ Command::new("lint")
+ .about("Lint source files")
+ .long_about(
+ "Lint JavaScript/TypeScript source code.
+
+ deno lint
+ deno lint myfile1.ts myfile2.js
+
+Print result as JSON:
+
+ deno lint --json
+
+Read from stdin:
+
+ cat file.ts | deno lint -
+ cat file.ts | deno lint --json -
+
+List available rules:
+
+ deno lint --rules
+
+Ignore diagnostics on the next line by preceding it with an ignore comment and
+rule name:
+
+ // deno-lint-ignore no-explicit-any
+ // deno-lint-ignore require-await no-empty
+
+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
+",
+ )
+ .arg(Arg::new("rules").long("rules").help("List available rules"))
+ .arg(
+ Arg::new("rules-tags")
+ .long("rules-tags")
+ .require_equals(true)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .conflicts_with("rules")
+ .help("Use set of rules with a tag"),
+ )
+ .arg(
+ Arg::new("rules-include")
+ .long("rules-include")
+ .require_equals(true)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .conflicts_with("rules")
+ .help("Include lint rules"),
+ )
+ .arg(
+ Arg::new("rules-exclude")
+ .long("rules-exclude")
+ .require_equals(true)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .conflicts_with("rules")
+ .help("Exclude lint rules"),
+ )
+ .args(config_args())
+ .arg(
+ Arg::new("ignore")
+ .long("ignore")
+ .takes_value(true)
+ .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")
+ .takes_value(false),
+ )
+ .arg(
+ Arg::new("files")
+ .takes_value(true)
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ .required(false)
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(watch_arg(false))
+ .arg(no_clear_screen_arg())
+}
+
+fn repl_subcommand<'a>() -> Command<'a> {
+ runtime_args(Command::new("repl"), false, true)
+ .about("Read Eval Print Loop")
+ .arg(
+ Arg::new("eval-file")
+ .long("eval-file")
+ .min_values(1)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs.")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("eval")
+ .long("eval")
+ .help("Evaluates the provided code when the REPL starts.")
+ .takes_value(true)
+ .value_name("code"),
+ )
+ .arg(unsafely_ignore_certificate_errors_arg())
+}
+
+fn run_subcommand<'a>() -> Command<'a> {
+ runtime_args(Command::new("run"), true, true)
+ .arg(
+ watch_arg(true)
+ .conflicts_with("inspect")
+ .conflicts_with("inspect-brk"),
+ )
+ .arg(no_clear_screen_arg())
+ .trailing_var_arg(true)
+ .arg(script_arg().required(true))
+ .about("Run a JavaScript or TypeScript program")
+ .long_about(
+ "Run a JavaScript or TypeScript program
+
+By default all programs are run in sandbox without access to disk, network or
+ability to spawn subprocesses.
+
+ deno run https://deno.land/std/examples/welcome.ts
+
+Grant all permissions:
+
+ deno run -A https://deno.land/std/http/file_server.ts
+
+Grant permission to read from disk and listen to network:
+
+ deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts
+
+Grant permission to read allow-listed files from disk:
+
+ deno run --allow-read=/etc https://deno.land/std/http/file_server.ts
+
+Specifying the filename '-' to read the file from stdin.
+
+ curl https://deno.land/std/examples/welcome.ts | deno run -",
+ )
+}
+
+fn task_subcommand<'a>() -> Command<'a> {
+ Command::new("task")
+ .trailing_var_arg(true)
+ .args(config_args())
+ .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)
+ )
+ // 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
+
+ deno task build",
+ )
+}
+
+fn test_subcommand<'a>() -> Command<'a> {
+ runtime_args(Command::new("test"), true, true)
+ .trailing_var_arg(true)
+ .arg(
+ Arg::new("ignore")
+ .long("ignore")
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Ignore files")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("no-run")
+ .long("no-run")
+ .help("Cache test modules, but don't run tests")
+ .takes_value(false),
+ )
+ .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),
+ )
+ .arg(
+ Arg::new("doc")
+ .long("doc")
+ .help("UNSTABLE: type-check code blocks")
+ .takes_value(false),
+ )
+ .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)
+ .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()),
+ }),
+ )
+ .arg(
+ Arg::new("allow-none")
+ .long("allow-none")
+ .help("Don't return error code if no test files are found")
+ .takes_value(false),
+ )
+ .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(
+ Arg::new("shuffle")
+ .long("shuffle")
+ .value_name("NUMBER")
+ .help("(UNSTABLE): Shuffle the order in which the tests are run")
+ .min_values(0)
+ .max_values(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()),
+ }),
+ )
+ .arg(
+ Arg::new("coverage")
+ .long("coverage")
+ .require_equals(true)
+ .takes_value(true)
+ .value_name("DIR")
+ .conflicts_with("inspect")
+ .conflicts_with("inspect-brk")
+ .help("UNSTABLE: Collect coverage profile data into DIR"),
+ )
+ .arg(
+ Arg::new("jobs")
+ .short('j')
+ .long("jobs")
+ .help("Number of parallel workers, defaults to # of CPUs when no value is provided. Defaults to 1 when the option is not present.")
+ .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()),
+ }),
+ )
+ .arg(
+ Arg::new("files")
+ .help("List of file names to run")
+ .takes_value(true)
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ watch_arg(false)
+ .conflicts_with("no-run")
+ .conflicts_with("coverage"),
+ )
+ .arg(no_clear_screen_arg())
+ .arg(script_arg().last(true))
+ .about("Run tests")
+ .long_about(
+ "Run tests using Deno's built-in test runner.
+
+Evaluate the given modules, run all tests declared with 'Deno.test()' and
+report results to standard output:
+
+ deno test src/fetch_test.ts src/signal_test.ts
+
+Directory arguments are expanded to all contained files matching the glob
+{*_,*.,}test.{js,mjs,ts,jsx,tsx}:
+
+ deno test src/",
+ )
+}
+
+fn types_subcommand<'a>() -> Command<'a> {
+ Command::new("types")
+ .about("Print runtime TypeScript declarations")
+ .long_about(
+ "Print runtime TypeScript declarations.
+
+ deno types > lib.deno.d.ts
+
+The declaration file could be saved and used for typing information.",
+ )
+}
+
+fn upgrade_subcommand<'a>() -> Command<'a> {
+ Command::new("upgrade")
+ .about("Upgrade deno executable to given version")
+ .long_about(
+ "Upgrade deno executable to the given version.
+Defaults to latest.
+
+The version is downloaded from
+https://github.com/denoland/deno/releases
+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",
+ )
+ .arg(
+ Arg::new("version")
+ .long("version")
+ .help("The version to upgrade to")
+ .takes_value(true),
+ )
+ .arg(
+ Arg::new("output")
+ .long("output")
+ .help("The path to output the updated version to")
+ .takes_value(true)
+ .value_hint(ValueHint::FilePath),
+ )
+ .arg(
+ Arg::new("dry-run")
+ .long("dry-run")
+ .help("Perform all checks without replacing old exe"),
+ )
+ .arg(
+ Arg::new("force")
+ .long("force")
+ .short('f')
+ .help("Replace current exe even if not out-of-date"),
+ )
+ .arg(
+ Arg::new("canary")
+ .long("canary")
+ .help("Upgrade to canary builds"),
+ )
+ .arg(ca_file_arg())
+}
+
+fn vendor_subcommand<'a>() -> Command<'a> {
+ Command::new("vendor")
+ .about("Vendor remote modules into a local directory")
+ .long_about(
+ "Vendor remote modules into a local directory.
+
+Analyzes the provided modules along with their dependencies, downloads
+remote modules to the output directory, and produces an import map that
+maps remote specifiers to the downloaded files.
+
+ deno vendor main.ts
+ deno run --import-map vendor/import_map.json main.ts
+
+Remote modules and multiple modules may also be specified:
+
+ deno vendor main.ts test.deps.ts https://deno.land/std/path/mod.ts",
+ )
+ .arg(
+ Arg::new("specifiers")
+ .takes_value(true)
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ .required(true),
+ )
+ .arg(
+ Arg::new("output")
+ .long("output")
+ .help("The directory to output the vendored modules to")
+ .takes_value(true)
+ .value_hint(ValueHint::DirPath),
+ )
+ .arg(
+ Arg::new("force")
+ .long("force")
+ .short('f')
+ .help(
+ "Forcefully overwrite conflicting files in existing output directory",
+ )
+ .takes_value(false),
+ )
+ .args(config_args())
+ .arg(import_map_arg())
+ .arg(lock_arg())
+ .arg(reload_arg())
+ .arg(ca_file_arg())
+}
+
+fn compile_args(app: Command) -> Command {
+ app
+ .arg(import_map_arg())
+ .arg(no_remote_arg())
+ .args(config_args())
+ .arg(no_check_arg())
+ .arg(check_arg())
+ .arg(reload_arg())
+ .arg(lock_arg())
+ .arg(lock_write_arg())
+ .arg(ca_file_arg())
+}
+
+fn compile_args_without_check_args(app: Command) -> Command {
+ app
+ .arg(import_map_arg())
+ .arg(no_remote_arg())
+ .args(config_args())
+ .arg(reload_arg())
+ .arg(lock_arg())
+ .arg(lock_write_arg())
+ .arg(ca_file_arg())
+}
+
+fn permission_args(app: Command) -> Command {
+ app
+ .arg(
+ Arg::new("allow-read")
+ .long("allow-read")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Allow file system read access")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("allow-write")
+ .long("allow-write")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Allow file system write access")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("allow-net")
+ .long("allow-net")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Allow network access")
+ .validator(flags_allow_net::validator),
+ )
+ .arg(unsafely_ignore_certificate_errors_arg())
+ .arg(
+ Arg::new("allow-env")
+ .long("allow-env")
+ .min_values(0)
+ .takes_value(true)
+ .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));
+ }
+ }
+ Ok(())
+ }),
+ )
+ .arg(
+ Arg::new("allow-run")
+ .long("allow-run")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Allow running subprocesses"),
+ )
+ .arg(
+ Arg::new("allow-ffi")
+ .long("allow-ffi")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Allow loading dynamic libraries")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
+ Arg::new("allow-hrtime")
+ .long("allow-hrtime")
+ .help("Allow high resolution time measurement"),
+ )
+ .arg(
+ Arg::new("allow-all")
+ .short('A')
+ .long("allow-all")
+ .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("no-prompt")
+ .long("no-prompt")
+ .help("Always throw if required permission wasn't passed"),
+ )
+}
+
+fn runtime_args(
+ app: Command,
+ include_perms: bool,
+ include_inspector: bool,
+) -> Command {
+ let app = compile_args(app);
+ let app = if include_perms {
+ permission_args(app)
+ } else {
+ app
+ };
+ let app = if include_inspector {
+ inspect_args(app)
+ } else {
+ app
+ };
+ app
+ .arg(cached_only_arg())
+ .arg(location_arg())
+ .arg(v8_flags_arg())
+ .arg(seed_arg())
+ .arg(enable_testing_features_arg())
+ .arg(compat_arg())
+}
+
+fn inspect_args(app: Command) -> Command {
+ app
+ .arg(
+ Arg::new("inspect")
+ .long("inspect")
+ .value_name("HOST:PORT")
+ .help("Activate inspector on host:port (default: 127.0.0.1:9229)")
+ .min_values(0)
+ .max_values(1)
+ .require_equals(true)
+ .takes_value(true)
+ .validator(inspect_arg_validate),
+ )
+ .arg(
+ Arg::new("inspect-brk")
+ .long("inspect-brk")
+ .value_name("HOST:PORT")
+ .help(
+ "Activate inspector on host:port and break at start of user script",
+ )
+ .min_values(0)
+ .max_values(1)
+ .require_equals(true)
+ .takes_value(true)
+ .validator(inspect_arg_validate),
+ )
+}
+
+static IMPORT_MAP_HELP: Lazy<String> = Lazy::new(|| {
+ format!(
+ "Load import map file from local file or remote URL.
+ Docs: https://deno.land/manual@v{}/linking_to_external_code/import_maps
+ Specification: https://wicg.github.io/import-maps/
+ Examples: https://github.com/WICG/import-maps#the-import-map",
+ SHORT_VERSION.as_str()
+ )
+});
+
+fn import_map_arg<'a>() -> Arg<'a> {
+ 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> {
+ Arg::new("reload")
+ .short('r')
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .long("reload")
+ .help("Reload source code cache (recompile TypeScript)")
+ .value_name("CACHE_BLOCKLIST")
+ .long_help(
+ "Reload source code cache (recompile TypeScript)
+--reload
+ Reload everything
+--reload=https://deno.land/std
+ Reload only standard modules
+--reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts
+ Reloads specific modules",
+ )
+ .value_hint(ValueHint::FilePath)
+}
+
+fn ca_file_arg<'a>() -> Arg<'a> {
+ 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> {
+ Arg::new("cached-only")
+ .long("cached-only")
+ .help("Require that remote dependencies are already cached")
+}
+
+fn location_arg<'a>() -> Arg<'a> {
+ Arg::new("location")
+ .long("location")
+ .takes_value(true)
+ .value_name("HREF")
+ .validator(|href| {
+ let url = Url::parse(href);
+ if url.is_err() {
+ return Err("Failed to parse URL".to_string());
+ }
+ let mut url = url.unwrap();
+ if !["http", "https"].contains(&url.scheme()) {
+ return Err("Expected protocol \"http\" or \"https\"".to_string());
+ }
+ url.set_username("").unwrap();
+ url.set_password(None).unwrap();
+ Ok(())
+ })
+ .help("Value of 'globalThis.location' used by some web APIs")
+ .value_hint(ValueHint::Url)
+}
+
+fn enable_testing_features_arg<'a>() -> Arg<'a> {
+ Arg::new("enable-testing-features-do-not-use")
+ .long("enable-testing-features-do-not-use")
+ .help("INTERNAL: Enable internal features used during integration testing")
+ .hide(true)
+}
+
+fn v8_flags_arg<'a>() -> Arg<'a> {
+ Arg::new("v8-flags")
+ .long("v8-flags")
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Set V8 command line options")
+ .long_help("To see a list of all available flags use --v8-flags=--help.")
+}
+
+fn seed_arg<'a>() -> Arg<'a> {
+ 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()),
+ })
+}
+
+static COMPAT_HELP: Lazy<String> = Lazy::new(|| {
+ format!(
+ "See https://deno.land/manual@v{}/node/compatibility_mode",
+ SHORT_VERSION.as_str()
+ )
+});
+
+fn compat_arg<'a>() -> Arg<'a> {
+ Arg::new("compat")
+ .long("compat")
+ .requires("unstable")
+ .help("UNSTABLE: Node compatibility mode.")
+ .long_help(COMPAT_HELP.as_str())
+}
+
+fn watch_arg<'a>(takes_files: bool) -> Arg<'a> {
+ let arg = Arg::new("watch")
+ .long("watch")
+ .help("Watch for file changes and restart automatically");
+
+ if takes_files {
+ arg
+ .value_name("FILES")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .long_help(
+ "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.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> {
+ Arg::new("no-clear-screen")
+ .requires("watch")
+ .long("no-clear-screen")
+ .help("Do not clear terminal screen when under watch mode")
+}
+
+fn no_check_arg<'a>() -> Arg<'a> {
+ Arg::new("no-check")
+ .takes_value(true)
+ .require_equals(true)
+ .min_values(0)
+ .value_name("NO_CHECK_TYPE")
+ .long("no-check")
+ .help("Skip type-checking modules")
+ .long_help(
+ "Skip type-checking. If the value of '--no-check=remote' is supplied, \
+ diagnostic errors from remote modules will be ignored.",
+ )
+}
+
+fn check_arg<'a>() -> Arg<'a> {
+ Arg::new("check")
+ .conflicts_with("no-check")
+ .long("check")
+ .takes_value(true)
+ .require_equals(true)
+ .min_values(0)
+ .value_name("CHECK_TYPE")
+ .help("Type-check modules")
+ .long_help(
+ "Type-check modules.
+
+Deno does not type-check modules automatically from v1.23 onwards. Pass this \
+flag to enable type-checking or use the 'deno check' subcommand.
+
+If the value of '--check=all' is supplied, diagnostic errors from remote modules
+will be included.",
+ )
+}
+
+fn script_arg<'a>() -> Arg<'a> {
+ Arg::new("script_arg")
+ .multiple_values(true)
+ .multiple_occurrences(true)
+ // 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("_")),
+ ])
+ .help("Script arg")
+ .value_name("SCRIPT_ARG")
+ .value_hint(ValueHint::FilePath)
+}
+
+fn lock_arg<'a>() -> Arg<'a> {
+ Arg::new("lock")
+ .long("lock")
+ .value_name("FILE")
+ .help("Check the specified lock file")
+ .takes_value(true)
+ .value_hint(ValueHint::FilePath)
+}
+
+fn lock_write_arg<'a>() -> Arg<'a> {
+ Arg::new("lock-write")
+ .long("lock-write")
+ .requires("lock")
+ .help("Write lock file (use with --lock)")
+}
+
+static CONFIG_HELP: Lazy<String> = Lazy::new(|| {
+ format!(
+ "The configuration file can be used to configure different aspects of \
+ deno including TypeScript, linting, and code formatting. Typically the \
+ configuration file will be called `deno.json` or `deno.jsonc` and \
+ automatically detected; in that case this flag is not necessary. \
+ See https://deno.land/manual@v{}/getting_started/configuration_file",
+ SHORT_VERSION.as_str()
+ )
+});
+
+fn config_args<'a>() -> [Arg<'a>; 2] {
+ [
+ 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)
+ .conflicts_with("no-config"),
+ Arg::new("no-config")
+ .long("no-config")
+ .help("Disable automatic loading of the configuration file.")
+ .conflicts_with("config"),
+ ]
+}
+
+fn no_remote_arg<'a>() -> Arg<'a> {
+ Arg::new("no-remote")
+ .long("no-remote")
+ .help("Do not resolve remote modules")
+}
+
+fn unsafely_ignore_certificate_errors_arg<'a>() -> Arg<'a> {
+ Arg::new("unsafely-ignore-certificate-errors")
+ .long("unsafely-ignore-certificate-errors")
+ .min_values(0)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .value_name("HOSTNAMES")
+ .help("DANGER: Disables verification of TLS certificates")
+ .validator(flags_allow_net::validator)
+}
+
+fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.type_check_mode = TypeCheckMode::Local;
+
+ runtime_args_parse(flags, matches, true, false);
+
+ // NOTE: `deno bench` 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(),
+ 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();
+
+ for v in script_arg {
+ flags.argv.push(v);
+ }
+ }
+
+ let include = if matches.is_present("files") {
+ let files: Vec<String> = matches
+ .values_of("files")
+ .unwrap()
+ .map(String::from)
+ .collect();
+ Some(files)
+ } else {
+ None
+ };
+
+ watch_arg_parse(flags, matches, false);
+ flags.subcommand = DenoSubcommand::Bench(BenchFlags {
+ include,
+ ignore,
+ filter,
+ });
+}
+
+fn bundle_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.type_check_mode = TypeCheckMode::Local;
+
+ compile_args_parse(flags, matches);
+
+ let source_file = matches.value_of("source_file").unwrap().to_string();
+
+ 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
+ };
+
+ watch_arg_parse(flags, matches, false);
+
+ flags.subcommand = DenoSubcommand::Bundle(BundleFlags {
+ source_file,
+ out_file,
+ });
+}
+
+fn cache_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ compile_args_parse(flags, matches);
+ let files = matches
+ .values_of("file")
+ .unwrap()
+ .map(String::from)
+ .collect();
+ flags.subcommand = DenoSubcommand::Cache(CacheFlags { files });
+}
+
+fn check_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.type_check_mode = TypeCheckMode::Local;
+ compile_args_without_no_check_parse(flags, matches);
+ let files = matches
+ .values_of("file")
+ .unwrap()
+ .map(String::from)
+ .collect();
+ if matches.is_present("remote") {
+ flags.type_check_mode = TypeCheckMode::All;
+ }
+ flags.subcommand = DenoSubcommand::Check(CheckFlags { files });
+}
+
+fn compile_parse(flags: &mut Flags, matches: &clap::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);
+
+ flags.subcommand = DenoSubcommand::Compile(CompileFlags {
+ source_file,
+ output,
+ args,
+ target,
+ });
+}
+
+fn completions_parse(
+ flags: &mut Flags,
+ matches: &clap::ArgMatches,
+ mut app: clap::Command,
+) {
+ use clap_complete::generate;
+ use clap_complete::shells::{Bash, Fish, PowerShell, Zsh};
+ use clap_complete_fig::Fig;
+
+ let mut buf: Vec<u8> = vec![];
+ let name = "deno";
+
+ match matches.value_of("shell").unwrap() {
+ "bash" => generate(Bash, &mut app, name, &mut buf),
+ "fish" => generate(Fish, &mut app, name, &mut buf),
+ "powershell" => generate(PowerShell, &mut app, name, &mut buf),
+ "zsh" => generate(Zsh, &mut app, name, &mut buf),
+ "fig" => generate(Fig, &mut app, name, &mut buf),
+ _ => unreachable!(),
+ }
+
+ flags.subcommand = DenoSubcommand::Completions(CompletionsFlags {
+ buf: buf.into_boxed_slice(),
+ });
+}
+
+fn coverage_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ let files = match matches.values_of("files") {
+ Some(f) => f.map(PathBuf::from).collect(),
+ None => vec![],
+ };
+ let ignore = match matches.values_of("ignore") {
+ Some(f) => f.map(PathBuf::from).collect(),
+ None => vec![],
+ };
+ let include = match matches.values_of("include") {
+ Some(f) => f.map(String::from).collect(),
+ None => vec![],
+ };
+ let exclude = match matches.values_of("exclude") {
+ Some(f) => f.map(String::from).collect(),
+ None => vec![],
+ };
+ let lcov = matches.is_present("lcov");
+ let output = matches.value_of("output").map(PathBuf::from);
+ flags.subcommand = DenoSubcommand::Coverage(CoverageFlags {
+ files,
+ output,
+ ignore,
+ include,
+ exclude,
+ lcov,
+ });
+}
+
+fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ import_map_arg_parse(flags, matches);
+ reload_arg_parse(flags, matches);
+
+ let source_file = matches.value_of("source_file").map(String::from);
+ let private = matches.is_present("private");
+ let json = matches.is_present("json");
+ let filter = matches.value_of("filter").map(String::from);
+ flags.subcommand = DenoSubcommand::Doc(DocFlags {
+ source_file,
+ json,
+ filter,
+ private,
+ });
+}
+
+fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ runtime_args_parse(flags, matches, false, true);
+ flags.allow_net = Some(vec![]);
+ flags.allow_env = Some(vec![]);
+ flags.allow_run = Some(vec![]);
+ flags.allow_read = Some(vec![]);
+ flags.allow_write = Some(vec![]);
+ flags.allow_ffi = Some(vec![]);
+ flags.allow_hrtime = true;
+ // TODO(@satyarohith): remove this flag in 2.0.
+ let as_typescript = matches.is_present("ts");
+ let ext = if as_typescript {
+ "ts".to_string()
+ } else {
+ matches.value_of("ext").unwrap().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);
+ }
+ flags.subcommand = DenoSubcommand::Eval(EvalFlags { print, code, ext });
+}
+
+fn fmt_parse(flags: &mut Flags, matches: &clap::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(),
+ None => vec![],
+ };
+ let ignore = match matches.values_of("ignore") {
+ Some(f) => f.map(PathBuf::from).collect(),
+ None => vec![],
+ };
+ let ext = matches.value_of("ext").unwrap().to_string();
+
+ let use_tabs = if matches.is_present("options-use-tabs") {
+ Some(true)
+ } else {
+ None
+ };
+ let line_width = if matches.is_present("options-line-width") {
+ Some(
+ matches
+ .value_of("options-line-width")
+ .unwrap()
+ .parse()
+ .unwrap(),
+ )
+ } else {
+ None
+ };
+ let indent_width = if matches.is_present("options-indent-width") {
+ Some(
+ matches
+ .value_of("options-indent-width")
+ .unwrap()
+ .parse()
+ .unwrap(),
+ )
+ } else {
+ None
+ };
+ let single_quote = if matches.is_present("options-single-quote") {
+ Some(true)
+ } else {
+ None
+ };
+ let prose_wrap = if matches.is_present("options-prose-wrap") {
+ Some(matches.value_of("options-prose-wrap").unwrap().to_string())
+ } else {
+ None
+ };
+
+ flags.subcommand = DenoSubcommand::Fmt(FmtFlags {
+ check: matches.is_present("check"),
+ ext,
+ files,
+ ignore,
+ use_tabs,
+ line_width,
+ indent_width,
+ single_quote,
+ prose_wrap,
+ });
+}
+
+fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ 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);
+ let json = matches.is_present("json");
+ flags.subcommand = DenoSubcommand::Info(InfoFlags {
+ file: matches.value_of("file").map(|f| f.to_string()),
+ json,
+ });
+}
+
+fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ runtime_args_parse(flags, matches, true, true);
+
+ let root = if matches.is_present("root") {
+ let install_root = matches.value_of("root").unwrap();
+ Some(PathBuf::from(install_root))
+ } else {
+ None
+ };
+
+ 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 module_url = cmd[0].to_string();
+ let args = cmd[1..].to_vec();
+
+ flags.subcommand = DenoSubcommand::Install(InstallFlags {
+ name,
+ module_url,
+ args,
+ root,
+ force,
+ });
+}
+
+fn uninstall_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ let root = if matches.is_present("root") {
+ let install_root = matches.value_of("root").unwrap();
+ Some(PathBuf::from(install_root))
+ } else {
+ None
+ };
+
+ let name = matches.value_of("name").unwrap().to_string();
+ flags.subcommand = DenoSubcommand::Uninstall(UninstallFlags { name, root });
+}
+
+fn lsp_parse(flags: &mut Flags, _matches: &clap::ArgMatches) {
+ flags.subcommand = DenoSubcommand::Lsp;
+}
+
+fn lint_parse(flags: &mut Flags, matches: &clap::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(),
+ None => vec![],
+ };
+ let ignore = match matches.values_of("ignore") {
+ Some(f) => f.map(PathBuf::from).collect(),
+ None => vec![],
+ };
+ let rules = matches.is_present("rules");
+ let maybe_rules_tags = matches
+ .values_of("rules-tags")
+ .map(|f| f.map(String::from).collect());
+
+ let maybe_rules_include = matches
+ .values_of("rules-include")
+ .map(|f| f.map(String::from).collect());
+
+ let maybe_rules_exclude = matches
+ .values_of("rules-exclude")
+ .map(|f| f.map(String::from).collect());
+
+ let json = matches.is_present("json");
+ flags.subcommand = DenoSubcommand::Lint(LintFlags {
+ files,
+ rules,
+ maybe_rules_tags,
+ maybe_rules_include,
+ maybe_rules_exclude,
+ ignore,
+ json,
+ });
+}
+
+fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ runtime_args_parse(flags, matches, false, 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());
+
+ handle_repl_flags(
+ flags,
+ ReplFlags {
+ eval_files,
+ eval: matches.value_of("eval").map(ToOwned::to_owned),
+ },
+ );
+}
+
+fn run_parse(flags: &mut Flags, matches: &clap::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);
+ }
+
+ watch_arg_parse(flags, matches, true);
+ flags.subcommand = DenoSubcommand::Run(RunFlags { script });
+}
+
+fn task_parse(
+ flags: &mut Flags,
+ matches: &clap::ArgMatches,
+ raw_args: &[String],
+) {
+ config_args_parse(flags, matches);
+
+ let mut task_flags = TaskFlags {
+ cwd: None,
+ task: String::new(),
+ };
+
+ 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") {
+ index += 1; // skip `task`
+
+ // 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 = raw_args[index].to_string();
+ index += 1;
+
+ if index < raw_args.len() {
+ flags
+ .argv
+ .extend(raw_args[index..].iter().map(String::from));
+ }
+ }
+ }
+
+ flags.subcommand = DenoSubcommand::Task(task_flags);
+}
+
+fn test_parse(flags: &mut Flags, matches: &clap::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(),
+ 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 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())
+ }
+ } 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)
+ } 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);
+ }
+ }
+
+ let concurrent_jobs = if matches.is_present("jobs") {
+ if let Some(value) = matches.value_of("jobs") {
+ value.parse().unwrap()
+ } else {
+ std::thread::available_parallelism()
+ .unwrap_or(NonZeroUsize::new(1).unwrap())
+ }
+ } else {
+ NonZeroUsize::new(1).unwrap()
+ };
+
+ let include = if matches.is_present("files") {
+ let files: Vec<String> = matches
+ .values_of("files")
+ .unwrap()
+ .map(String::from)
+ .collect();
+ Some(files)
+ } else {
+ None
+ };
+
+ flags.coverage_dir = matches.value_of("coverage").map(String::from);
+ watch_arg_parse(flags, matches, false);
+ flags.subcommand = DenoSubcommand::Test(TestFlags {
+ no_run,
+ doc,
+ fail_fast,
+ include,
+ ignore,
+ filter,
+ shuffle,
+ allow_none,
+ concurrent_jobs,
+ trace_ops,
+ });
+}
+
+fn types_parse(flags: &mut Flags, _matches: &clap::ArgMatches) {
+ flags.subcommand = DenoSubcommand::Types;
+}
+
+fn upgrade_parse(flags: &mut Flags, matches: &clap::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 ca_file = matches.value_of("cert").map(|s| s.to_string());
+ flags.subcommand = DenoSubcommand::Upgrade(UpgradeFlags {
+ dry_run,
+ force,
+ canary,
+ version,
+ output,
+ ca_file,
+ });
+}
+
+fn vendor_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ ca_file_arg_parse(flags, matches);
+ config_args_parse(flags, matches);
+ import_map_arg_parse(flags, matches);
+ lock_arg_parse(flags, matches);
+ reload_arg_parse(flags, matches);
+
+ flags.subcommand = DenoSubcommand::Vendor(VendorFlags {
+ specifiers: matches
+ .values_of("specifiers")
+ .map(|p| p.map(ToString::to_string).collect())
+ .unwrap_or_default(),
+ output_path: matches.value_of("output").map(PathBuf::from),
+ force: matches.is_present("force"),
+ });
+}
+
+fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ import_map_arg_parse(flags, matches);
+ no_remote_arg_parse(flags, matches);
+ config_args_parse(flags, matches);
+ no_check_arg_parse(flags, matches);
+ check_arg_parse(flags, matches);
+ reload_arg_parse(flags, matches);
+ lock_args_parse(flags, matches);
+ ca_file_arg_parse(flags, matches);
+}
+
+fn compile_args_without_no_check_parse(
+ flags: &mut Flags,
+ matches: &clap::ArgMatches,
+) {
+ import_map_arg_parse(flags, matches);
+ no_remote_arg_parse(flags, matches);
+ config_args_parse(flags, matches);
+ reload_arg_parse(flags, matches);
+ lock_args_parse(flags, matches);
+ ca_file_arg_parse(flags, matches);
+}
+
+fn permission_args_parse(flags: &mut Flags, matches: &clap::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(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(net_wl) = matches.values_of("allow-net") {
+ let net_allowlist: Vec<String> =
+ flags_allow_net::parse(net_wl.map(ToString::to_string).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);
+ 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);
+ debug!("run allowlist: {:#?}", &flags.allow_run);
+ }
+
+ 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);
+ debug!("ffi allowlist: {:#?}", &flags.allow_ffi);
+ }
+
+ if matches.is_present("allow-hrtime") {
+ flags.allow_hrtime = true;
+ }
+ if matches.is_present("allow-all") {
+ flags.allow_all = true;
+ flags.allow_read = Some(vec![]);
+ flags.allow_env = Some(vec![]);
+ flags.allow_net = Some(vec![]);
+ flags.allow_run = Some(vec![]);
+ flags.allow_write = Some(vec![]);
+ flags.allow_ffi = Some(vec![]);
+ flags.allow_hrtime = true;
+ }
+ #[cfg(not(test))]
+ let has_no_prompt_env = env::var("DENO_NO_PROMPT") == Ok("1".to_string());
+ #[cfg(test)]
+ let has_no_prompt_env = false;
+ if has_no_prompt_env || matches.is_present("no-prompt") {
+ flags.no_prompt = true;
+ }
+}
+fn unsafely_ignore_certificate_errors_parse(
+ flags: &mut Flags,
+ matches: &clap::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();
+ flags.unsafely_ignore_certificate_errors = Some(ic_allowlist);
+ }
+}
+fn runtime_args_parse(
+ flags: &mut Flags,
+ matches: &clap::ArgMatches,
+ include_perms: bool,
+ include_inspector: bool,
+) {
+ compile_args_parse(flags, matches);
+ cached_only_arg_parse(flags, matches);
+ if include_perms {
+ permission_args_parse(flags, matches);
+ }
+ if include_inspector {
+ inspect_arg_parse(flags, matches);
+ }
+ location_arg_parse(flags, matches);
+ v8_flags_arg_parse(flags, matches);
+ seed_arg_parse(flags, matches);
+ compat_arg_parse(flags, matches);
+ enable_testing_features_arg_parse(flags, matches);
+}
+
+fn inspect_arg_parse(flags: &mut Flags, matches: &clap::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())
+ }
+ } 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())
+ }
+ } 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 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();
+ if raw_cache_blocklist.is_empty() {
+ flags.reload = true;
+ } else {
+ flags.cache_blocklist = resolve_urls(raw_cache_blocklist);
+ debug!("cache blocklist: {:#?}", &flags.cache_blocklist);
+ flags.reload = false;
+ }
+ }
+}
+
+fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned);
+}
+
+fn enable_testing_features_arg_parse(
+ flags: &mut Flags,
+ matches: &clap::ArgMatches,
+) {
+ if matches.is_present("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") {
+ flags.cached_only = true;
+ }
+}
+
+fn location_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.location = matches
+ .value_of("location")
+ .map(|href| Url::parse(href).unwrap());
+}
+
+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 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();
+ flags.seed = Some(seed);
+
+ flags.v8_flags.push(format!("--random-seed={}", seed));
+ }
+}
+
+fn compat_arg_parse(flags: &mut Flags, matches: &ArgMatches) {
+ if matches.is_present("compat") {
+ flags.compat = true;
+ }
+}
+
+fn no_check_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ if let Some(cache_type) = matches.value_of("no-check") {
+ match cache_type {
+ "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") {
+ 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 {
+ "all" => flags.type_check_mode = TypeCheckMode::All,
+ _ => debug!(
+ "invalid value for 'check' of '{}' using default",
+ cache_type
+ ),
+ }
+ } else if matches.is_present("check") {
+ flags.type_check_mode = TypeCheckMode::Local;
+ }
+}
+
+fn lock_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ lock_arg_parse(flags, matches);
+ if matches.is_present("lock-write") {
+ flags.lock_write = true;
+ }
+}
+
+fn lock_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ if matches.is_present("lock") {
+ let lockfile = matches.value_of("lock").unwrap();
+ flags.lock = Some(PathBuf::from(lockfile));
+ }
+}
+
+fn config_args_parse(flags: &mut Flags, matches: &ArgMatches) {
+ flags.config_flag = if matches.is_present("no-config") {
+ ConfigFlag::Disabled
+ } else if let Some(config) = matches.value_of("config") {
+ ConfigFlag::Path(config.to_string())
+ } else {
+ ConfigFlag::Discover
+ };
+}
+
+fn no_remote_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ if matches.is_present("no-remote") {
+ flags.no_remote = true;
+ }
+}
+
+fn inspect_arg_validate(val: &str) -> Result<(), String> {
+ match val.parse::<SocketAddr>() {
+ Ok(_) => Ok(()),
+ Err(e) => Err(e.to_string()),
+ }
+}
+
+fn watch_arg_parse(
+ flags: &mut Flags,
+ matches: &clap::ArgMatches,
+ allow_extra: bool,
+) {
+ if allow_extra {
+ if let Some(f) = matches.values_of("watch") {
+ flags.watch = Some(f.map(PathBuf::from).collect());
+ }
+ } else if matches.is_present("watch") {
+ flags.watch = Some(vec![]);
+ }
+
+ if matches.is_present("no-clear-screen") {
+ flags.no_clear_screen = true;
+ }
+}
+
+// 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<String>) -> Vec<String> {
+ let mut out: Vec<String> = vec![];
+ for urlstr in urls.iter() {
+ if let Ok(mut url) = Url::from_str(urlstr) {
+ url.set_fragment(None);
+ let mut full_url = String::from(url.as_str());
+ if full_url.len() > 1 && full_url.ends_with('/') {
+ full_url.pop();
+ }
+ out.push(full_url);
+ } else {
+ panic!("Bad Url: {}", urlstr);
+ }
+ }
+ out
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use pretty_assertions::assert_eq;
+
+ /// Creates vector of strings, Vec<String>
+ macro_rules! svec {
+ ($($x:expr),* $(,)?) => (vec![$($x.to_string()),*]);
+ }
+
+ #[test]
+ fn global_flags() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]);
+ let flags = r.unwrap();
+ assert_eq!(
+ flags,
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ unstable: true,
+ log_level: Some(Level::Error),
+ ..Flags::default()
+ }
+ );
+ #[rustfmt::skip]
+ let r2 = flags_from_vec(svec!["deno", "run", "--unstable", "--log-level", "debug", "--quiet", "script.ts"]);
+ let flags2 = r2.unwrap();
+ assert_eq!(flags2, flags);
+ }
+
+ #[test]
+ fn upgrade() {
+ let r = flags_from_vec(svec!["deno", "upgrade", "--dry-run", "--force"]);
+ let flags = r.unwrap();
+ assert_eq!(
+ flags,
+ Flags {
+ subcommand: DenoSubcommand::Upgrade(UpgradeFlags {
+ force: true,
+ dry_run: true,
+ canary: false,
+ version: None,
+ output: None,
+ ca_file: None,
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn version() {
+ let r = flags_from_vec(svec!["deno", "--version"]);
+ assert_eq!(r.unwrap_err().kind(), clap::ErrorKind::DisplayVersion);
+ let r = flags_from_vec(svec!["deno", "-V"]);
+ assert_eq!(r.unwrap_err().kind(), clap::ErrorKind::DisplayVersion);
+ }
+
+ #[test]
+ fn run_reload() {
+ let r = flags_from_vec(svec!["deno", "run", "-r", "script.ts"]);
+ let flags = r.unwrap();
+ assert_eq!(
+ flags,
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ reload: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_watch() {
+ let r = flags_from_vec(svec!["deno", "run", "--watch", "script.ts"]);
+ let flags = r.unwrap();
+ assert_eq!(
+ flags,
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_watch_with_external() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "--watch=file1,file2", "script.ts"]);
+ let flags = r.unwrap();
+ assert_eq!(
+ flags,
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ watch: Some(vec![PathBuf::from("file1"), PathBuf::from("file2")]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_watch_with_no_clear_screen() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--watch",
+ "--no-clear-screen",
+ "script.ts"
+ ]);
+
+ let flags = r.unwrap();
+ assert_eq!(
+ flags,
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ watch: Some(vec![]),
+ no_clear_screen: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_reload_allow_write() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "-r", "--allow-write", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ reload: true,
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ allow_write: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_v8_flags() {
+ let r = flags_from_vec(svec!["deno", "run", "--v8-flags=--help"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "_".to_string(),
+ }),
+ v8_flags: svec!["--help"],
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--v8-flags=--expose-gc,--gc-stats=1",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ v8_flags: svec!["--expose-gc", "--gc-stats=1"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn script_args() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--allow-net",
+ "gist.ts",
+ "--title",
+ "X"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "gist.ts".to_string(),
+ }),
+ argv: svec!["--title", "X"],
+ allow_net: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_all() {
+ let r = flags_from_vec(svec!["deno", "run", "--allow-all", "gist.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "gist.ts".to_string(),
+ }),
+ allow_all: true,
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_read() {
+ let r = flags_from_vec(svec!["deno", "run", "--allow-read", "gist.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "gist.ts".to_string(),
+ }),
+ allow_read: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_hrtime() {
+ let r = flags_from_vec(svec!["deno", "run", "--allow-hrtime", "gist.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "gist.ts".to_string(),
+ }),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn double_hyphen() {
+ // notice that flags passed after double dash will not
+ // be parsed to Flags but instead forwarded to
+ // script args as Deno.args
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--allow-write",
+ "script.ts",
+ "--",
+ "-D",
+ "--allow-net"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ argv: svec!["--", "-D", "--allow-net"],
+ allow_write: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn fmt() {
+ let r = flags_from_vec(svec!["deno", "fmt", "script_1.ts", "script_2.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![
+ PathBuf::from("script_1.ts"),
+ PathBuf::from("script_2.ts")
+ ],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "fmt", "--check"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: true,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "fmt"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "fmt", "--watch"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+
+ let r =
+ flags_from_vec(svec!["deno", "fmt", "--watch", "--no-clear-screen"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ watch: Some(vec![]),
+ no_clear_screen: true,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "fmt",
+ "--check",
+ "--watch",
+ "foo.ts",
+ "--ignore=bar.js"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![PathBuf::from("bar.js")],
+ check: true,
+ files: vec![PathBuf::from("foo.ts")],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "fmt", "--config", "deno.jsonc"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "fmt",
+ "--config",
+ "deno.jsonc",
+ "--watch",
+ "foo.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![PathBuf::from("foo.ts")],
+ ext: "ts".to_string(),
+ use_tabs: None,
+ line_width: None,
+ indent_width: None,
+ single_quote: None,
+ prose_wrap: None,
+ }),
+ config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "fmt",
+ "--options-use-tabs",
+ "--options-line-width",
+ "60",
+ "--options-indent-width",
+ "4",
+ "--options-single-quote",
+ "--options-prose-wrap",
+ "never"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Fmt(FmtFlags {
+ ignore: vec![],
+ check: false,
+ files: vec![],
+ ext: "ts".to_string(),
+ use_tabs: Some(true),
+ line_width: Some(NonZeroU32::new(60).unwrap()),
+ indent_width: Some(NonZeroU8::new(4).unwrap()),
+ single_quote: Some(true),
+ prose_wrap: Some("never".to_string()),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn lint() {
+ let r = flags_from_vec(svec!["deno", "lint", "script_1.ts", "script_2.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![
+ PathBuf::from("script_1.ts"),
+ PathBuf::from("script_2.ts")
+ ],
+ rules: false,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: false,
+ ignore: vec![],
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "lint",
+ "--watch",
+ "script_1.ts",
+ "script_2.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![
+ PathBuf::from("script_1.ts"),
+ PathBuf::from("script_2.ts")
+ ],
+ rules: false,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: false,
+ ignore: vec![],
+ }),
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "lint",
+ "--watch",
+ "--no-clear-screen",
+ "script_1.ts",
+ "script_2.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![
+ PathBuf::from("script_1.ts"),
+ PathBuf::from("script_2.ts")
+ ],
+ rules: false,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: false,
+ ignore: vec![],
+ }),
+ watch: Some(vec![]),
+ no_clear_screen: true,
+ ..Flags::default()
+ }
+ );
+
+ let r =
+ flags_from_vec(svec!["deno", "lint", "--ignore=script_1.ts,script_2.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![],
+ rules: false,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: false,
+ ignore: vec![
+ PathBuf::from("script_1.ts"),
+ PathBuf::from("script_2.ts")
+ ],
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "lint", "--rules"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![],
+ rules: true,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: false,
+ ignore: vec![],
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "lint",
+ "--rules-tags=",
+ "--rules-include=ban-untagged-todo,no-undef",
+ "--rules-exclude=no-const-assign"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![],
+ rules: false,
+ maybe_rules_tags: Some(svec![""]),
+ maybe_rules_include: Some(svec!["ban-untagged-todo", "no-undef"]),
+ maybe_rules_exclude: Some(svec!["no-const-assign"]),
+ json: false,
+ ignore: vec![],
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "lint", "--json", "script_1.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![PathBuf::from("script_1.ts")],
+ rules: false,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: true,
+ ignore: vec![],
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "lint",
+ "--config",
+ "Deno.jsonc",
+ "--json",
+ "script_1.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Lint(LintFlags {
+ files: vec![PathBuf::from("script_1.ts")],
+ rules: false,
+ maybe_rules_tags: None,
+ maybe_rules_include: None,
+ maybe_rules_exclude: None,
+ json: true,
+ ignore: vec![],
+ }),
+ config_flag: ConfigFlag::Path("Deno.jsonc".to_string()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn types() {
+ let r = flags_from_vec(svec!["deno", "types"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Types,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn cache() {
+ let r = flags_from_vec(svec!["deno", "cache", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Cache(CacheFlags {
+ files: svec!["script.ts"],
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn check() {
+ let r = flags_from_vec(svec!["deno", "check", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Check(CheckFlags {
+ files: svec!["script.ts"],
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "check", "--remote", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Check(CheckFlags {
+ files: svec!["script.ts"],
+ }),
+ type_check_mode: TypeCheckMode::All,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn info() {
+ let r = flags_from_vec(svec!["deno", "info", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: false,
+ file: Some("script.ts".to_string()),
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "info", "--reload", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: false,
+ file: Some("script.ts".to_string()),
+ }),
+ reload: true,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "info", "--json", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: true,
+ file: Some("script.ts".to_string()),
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "info"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: false,
+ file: None
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "info", "--json"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: true,
+ file: None
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "info", "--config", "tsconfig.json"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: false,
+ file: None
+ }),
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn tsconfig() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "-c", "tsconfig.json", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn eval() {
+ let r = flags_from_vec(svec!["deno", "eval", "'console.log(\"hello\")'"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Eval(EvalFlags {
+ print: false,
+ code: "'console.log(\"hello\")'".to_string(),
+ ext: "js".to_string(),
+ }),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn eval_p() {
+ let r = flags_from_vec(svec!["deno", "eval", "-p", "1+2"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Eval(EvalFlags {
+ print: true,
+ code: "1+2".to_string(),
+ ext: "js".to_string(),
+ }),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn eval_typescript() {
+ let r =
+ flags_from_vec(svec!["deno", "eval", "-T", "'console.log(\"hello\")'"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Eval(EvalFlags {
+ print: false,
+ code: "'console.log(\"hello\")'".to_string(),
+ ext: "ts".to_string(),
+ }),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn eval_with_flags() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "eval", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "42"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Eval(EvalFlags {
+ print: false,
+ code: "42".to_string(),
+ ext: "js".to_string(),
+ }),
+ import_map_path: Some("import_map.json".to_string()),
+ no_remote: true,
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ type_check_mode: TypeCheckMode::None,
+ reload: true,
+ lock: Some(PathBuf::from("lock.json")),
+ lock_write: true,
+ ca_file: Some("example.crt".to_string()),
+ cached_only: true,
+ location: Some(Url::parse("https://foo/").unwrap()),
+ v8_flags: svec!["--help", "--random-seed=1"],
+ seed: Some(1),
+ inspect: Some("127.0.0.1:9229".parse().unwrap()),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn eval_args() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "eval",
+ "console.log(Deno.args)",
+ "arg1",
+ "arg2"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Eval(EvalFlags {
+ print: false,
+ code: "console.log(Deno.args)".to_string(),
+ ext: "js".to_string(),
+ }),
+ argv: svec!["arg1", "arg2"],
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn repl() {
+ let r = flags_from_vec(svec!["deno"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None
+ }),
+ allow_net: Some(vec![]),
+ unsafely_ignore_certificate_errors: None,
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn repl_with_flags() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "repl", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--unsafely-ignore-certificate-errors"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None
+ }),
+ import_map_path: Some("import_map.json".to_string()),
+ no_remote: true,
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ type_check_mode: TypeCheckMode::None,
+ reload: true,
+ lock: Some(PathBuf::from("lock.json")),
+ lock_write: true,
+ ca_file: Some("example.crt".to_string()),
+ cached_only: true,
+ location: Some(Url::parse("https://foo/").unwrap()),
+ v8_flags: svec!["--help", "--random-seed=1"],
+ seed: Some(1),
+ inspect: Some("127.0.0.1:9229".parse().unwrap()),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ unsafely_ignore_certificate_errors: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn repl_with_eval_flag() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "repl", "--eval", "console.log('hello');"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: Some("console.log('hello');".to_string()),
+ }),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn repl_with_eval_file_flag() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "repl", "--eval-file=./a.js,./b.ts,https://examples.deno.land/hello-world.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: Some(vec![
+ "./a.js".to_string(),
+ "./b.ts".to_string(),
+ "https://examples.deno.land/hello-world.ts".to_string()
+ ]),
+ eval: None,
+ }),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_read_allowlist() {
+ use test_util::TempDir;
+ let temp_dir_guard = TempDir::new();
+ let temp_dir = temp_dir_guard.path().to_path_buf();
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ format!("--allow-read=.,{}", temp_dir.to_str().unwrap()),
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ allow_read: Some(vec![PathBuf::from("."), temp_dir]),
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_write_allowlist() {
+ use test_util::TempDir;
+ let temp_dir_guard = TempDir::new();
+ let temp_dir = temp_dir_guard.path().to_path_buf();
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ format!("--allow-write=.,{}", temp_dir.to_str().unwrap()),
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ allow_write: Some(vec![PathBuf::from("."), temp_dir]),
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_net_allowlist() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--allow-net=127.0.0.1",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ allow_net: Some(svec!["127.0.0.1"]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_env_allowlist() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "--allow-env=HOME", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ allow_env: Some(svec!["HOME"]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_env_allowlist_multiple() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--allow-env=HOME,PATH",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ allow_env: Some(svec!["HOME", "PATH"]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_env_allowlist_validator() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "--allow-env=HOME", "script.ts"]);
+ assert!(r.is_ok());
+ let r =
+ flags_from_vec(svec!["deno", "run", "--allow-env=H=ME", "script.ts"]);
+ assert!(r.is_err());
+ let r =
+ flags_from_vec(svec!["deno", "run", "--allow-env=H\0ME", "script.ts"]);
+ assert!(r.is_err());
+ }
+
+ #[test]
+ fn bundle() {
+ let r = flags_from_vec(svec!["deno", "bundle", "source.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_with_config() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "bundle",
+ "--no-remote",
+ "--config",
+ "tsconfig.json",
+ "source.ts",
+ "bundle.js"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: Some(PathBuf::from("bundle.js")),
+ }),
+ allow_write: Some(vec![]),
+ no_remote: true,
+ type_check_mode: TypeCheckMode::Local,
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_with_output() {
+ let r = flags_from_vec(svec!["deno", "bundle", "source.ts", "bundle.js"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: Some(PathBuf::from("bundle.js")),
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ allow_write: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_with_lock() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "bundle",
+ "--lock-write",
+ "--lock=lock.json",
+ "source.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ lock_write: true,
+ lock: Some(PathBuf::from("lock.json")),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_with_reload() {
+ let r = flags_from_vec(svec!["deno", "bundle", "--reload", "source.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ reload: true,
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_nocheck() {
+ let r = flags_from_vec(svec!["deno", "bundle", "--no-check", "script.ts"])
+ .unwrap();
+ assert_eq!(
+ r,
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "script.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_watch() {
+ let r = flags_from_vec(svec!["deno", "bundle", "--watch", "source.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ )
+ }
+
+ #[test]
+ fn bundle_watch_with_no_clear_screen() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "bundle",
+ "--watch",
+ "--no-clear-screen",
+ "source.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ watch: Some(vec![]),
+ no_clear_screen: true,
+ ..Flags::default()
+ }
+ )
+ }
+
+ #[test]
+ fn run_import_map() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--import-map=import_map.json",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ import_map_path: Some("import_map.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn info_import_map() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "info",
+ "--import-map=import_map.json",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ file: Some("script.ts".to_string()),
+ json: false,
+ }),
+ import_map_path: Some("import_map.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn cache_import_map() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "cache",
+ "--import-map=import_map.json",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Cache(CacheFlags {
+ files: svec!["script.ts"],
+ }),
+ import_map_path: Some("import_map.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn doc_import_map() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "doc",
+ "--import-map=import_map.json",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Doc(DocFlags {
+ source_file: Some("script.ts".to_owned()),
+ private: false,
+ json: false,
+ filter: None,
+ }),
+ import_map_path: Some("import_map.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn cache_multiple() {
+ let r =
+ flags_from_vec(svec!["deno", "cache", "script.ts", "script_two.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Cache(CacheFlags {
+ files: svec!["script.ts", "script_two.ts"],
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_seed() {
+ let r = flags_from_vec(svec!["deno", "run", "--seed", "250", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ seed: Some(250_u64),
+ v8_flags: svec!["--random-seed=250"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_seed_with_v8_flags() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--seed",
+ "250",
+ "--v8-flags=--expose-gc",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ seed: Some(250_u64),
+ v8_flags: svec!["--expose-gc", "--random-seed=250"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn install() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "install",
+ "https://deno.land/std/examples/colors.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Install(InstallFlags {
+ name: None,
+ module_url: "https://deno.land/std/examples/colors.ts".to_string(),
+ args: vec![],
+ root: None,
+ force: false,
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn install_with_flags() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "install", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--name", "file_server", "--root", "/foo", "--force", "https://deno.land/std/http/file_server.ts", "foo", "bar"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Install(InstallFlags {
+ name: Some("file_server".to_string()),
+ module_url: "https://deno.land/std/http/file_server.ts".to_string(),
+ args: svec!["foo", "bar"],
+ root: Some(PathBuf::from("/foo")),
+ force: true,
+ }),
+ import_map_path: Some("import_map.json".to_string()),
+ no_remote: true,
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ type_check_mode: TypeCheckMode::None,
+ reload: true,
+ lock: Some(PathBuf::from("lock.json")),
+ lock_write: true,
+ ca_file: Some("example.crt".to_string()),
+ cached_only: true,
+ v8_flags: svec!["--help", "--random-seed=1"],
+ seed: Some(1),
+ inspect: Some("127.0.0.1:9229".parse().unwrap()),
+ allow_net: Some(vec![]),
+ unsafely_ignore_certificate_errors: Some(vec![]),
+ allow_read: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn log_level() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "--log-level=debug", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ log_level: Some(Level::Debug),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn quiet() {
+ let r = flags_from_vec(svec!["deno", "run", "-q", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ log_level: Some(Level::Error),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn completions() {
+ let r = flags_from_vec(svec!["deno", "completions", "zsh"]).unwrap();
+
+ match r.subcommand {
+ DenoSubcommand::Completions(CompletionsFlags { buf }) => {
+ assert!(!buf.is_empty())
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ #[test]
+ fn run_with_args() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "script.ts",
+ "--allow-read",
+ "--allow-net"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ argv: svec!["--allow-read", "--allow-net"],
+ ..Flags::default()
+ }
+ );
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--location",
+ "https:foo",
+ "--allow-read",
+ "script.ts",
+ "--allow-net",
+ "-r",
+ "--help",
+ "--foo",
+ "bar"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ location: Some(Url::parse("https://foo/").unwrap()),
+ allow_read: Some(vec![]),
+ argv: svec!["--allow-net", "-r", "--help", "--foo", "bar"],
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "run", "script.ts", "foo", "bar"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ argv: svec!["foo", "bar"],
+ ..Flags::default()
+ }
+ );
+ let r = flags_from_vec(svec!["deno", "run", "script.ts", "-"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ argv: svec!["-"],
+ ..Flags::default()
+ }
+ );
+
+ let r =
+ flags_from_vec(svec!["deno", "run", "script.ts", "-", "foo", "bar"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ argv: svec!["-", "foo", "bar"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn no_check() {
+ let r = flags_from_vec(svec!["deno", "run", "--no-check", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn no_check_remote() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "--no-check=remote", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn repl_with_unsafely_ignore_certificate_errors() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "repl",
+ "--eval",
+ "console.log('hello');",
+ "--unsafely-ignore-certificate-errors"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: Some("console.log('hello');".to_string()),
+ }),
+ unsafely_ignore_certificate_errors: Some(vec![]),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_with_unsafely_ignore_certificate_errors() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--unsafely-ignore-certificate-errors",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ unsafely_ignore_certificate_errors: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_with_unsafely_treat_insecure_origin_as_secure_with_ipv6_address() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--unsafely-ignore-certificate-errors=deno.land,localhost,::,127.0.0.1,[::1],1.2.3.4",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ unsafely_ignore_certificate_errors: Some(svec![
+ "deno.land",
+ "localhost",
+ "::",
+ "127.0.0.1",
+ "[::1]",
+ "1.2.3.4"
+ ]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn repl_with_unsafely_treat_insecure_origin_as_secure_with_ipv6_address() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "repl",
+ "--unsafely-ignore-certificate-errors=deno.land,localhost,::,127.0.0.1,[::1],1.2.3.4"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None
+ }),
+ unsafely_ignore_certificate_errors: Some(svec![
+ "deno.land",
+ "localhost",
+ "::",
+ "127.0.0.1",
+ "[::1]",
+ "1.2.3.4"
+ ]),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn no_remote() {
+ let r = flags_from_vec(svec!["deno", "run", "--no-remote", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ no_remote: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn cached_only() {
+ let r = flags_from_vec(svec!["deno", "run", "--cached-only", "script.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ cached_only: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_net_allowlist_with_ports() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--allow-net=deno.land,:8000,:4545",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ allow_net: Some(svec![
+ "deno.land",
+ "0.0.0.0:8000",
+ "127.0.0.1:8000",
+ "localhost:8000",
+ "0.0.0.0:4545",
+ "127.0.0.1:4545",
+ "localhost:4545"
+ ]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn allow_net_allowlist_with_ipv6_address() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--allow-net=deno.land,deno.land:80,::,127.0.0.1,[::1],1.2.3.4:5678,:5678,[::1]:8080",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ allow_net: Some(svec![
+ "deno.land",
+ "deno.land:80",
+ "::",
+ "127.0.0.1",
+ "[::1]",
+ "1.2.3.4:5678",
+ "0.0.0.0:5678",
+ "127.0.0.1:5678",
+ "localhost:5678",
+ "[::1]:8080"
+ ]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn lock_write() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--lock-write",
+ "--lock=lock.json",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ lock_write: true,
+ lock: Some(PathBuf::from("lock.json")),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn test_with_flags() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "test", "--unstable", "--trace-ops", "--no-run", "--filter", "- foo", "--coverage=cov", "--location", "https:foo", "--allow-net", "--allow-none", "dir1/", "dir2/", "--", "arg1", "arg2"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: true,
+ doc: false,
+ fail_fast: None,
+ filter: Some("- foo".to_string()),
+ allow_none: true,
+ include: Some(svec!["dir1/", "dir2/"]),
+ ignore: vec![],
+ shuffle: None,
+ concurrent_jobs: NonZeroUsize::new(1).unwrap(),
+ trace_ops: true,
+ }),
+ unstable: true,
+ no_prompt: true,
+ coverage_dir: Some("cov".to_string()),
+ location: Some(Url::parse("https://foo/").unwrap()),
+ type_check_mode: TypeCheckMode::Local,
+ allow_net: Some(vec![]),
+ argv: svec!["arg1", "arg2"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_with_cafile() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--cert",
+ "example.crt",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ ca_file: Some("example.crt".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_with_enable_testing_features() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--enable-testing-features-do-not-use",
+ "script.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ enable_testing_features: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn test_with_concurrent_jobs() {
+ let r = flags_from_vec(svec!["deno", "test", "--jobs=4"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: false,
+ doc: false,
+ fail_fast: None,
+ filter: None,
+ allow_none: false,
+ shuffle: None,
+ include: None,
+ ignore: vec![],
+ concurrent_jobs: NonZeroUsize::new(4).unwrap(),
+ trace_ops: false,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ no_prompt: true,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "test", "--jobs=0"]);
+ assert!(r.is_err());
+ }
+
+ #[test]
+ fn test_with_fail_fast() {
+ let r = flags_from_vec(svec!["deno", "test", "--fail-fast=3"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: false,
+ doc: false,
+ fail_fast: Some(NonZeroUsize::new(3).unwrap()),
+ filter: None,
+ allow_none: false,
+ shuffle: None,
+ include: None,
+ ignore: vec![],
+ concurrent_jobs: NonZeroUsize::new(1).unwrap(),
+ trace_ops: false,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ no_prompt: true,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "test", "--fail-fast=0"]);
+ assert!(r.is_err());
+ }
+
+ #[test]
+ fn test_with_enable_testing_features() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "test",
+ "--enable-testing-features-do-not-use"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: false,
+ doc: false,
+ fail_fast: None,
+ filter: None,
+ allow_none: false,
+ shuffle: None,
+ include: None,
+ ignore: vec![],
+ concurrent_jobs: NonZeroUsize::new(1).unwrap(),
+ trace_ops: false,
+ }),
+ no_prompt: true,
+ type_check_mode: TypeCheckMode::Local,
+ enable_testing_features: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn test_shuffle() {
+ let r = flags_from_vec(svec!["deno", "test", "--shuffle=1"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: false,
+ doc: false,
+ fail_fast: None,
+ filter: None,
+ allow_none: false,
+ shuffle: Some(1),
+ include: None,
+ ignore: vec![],
+ concurrent_jobs: NonZeroUsize::new(1).unwrap(),
+ trace_ops: false,
+ }),
+ no_prompt: true,
+ watch: None,
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn test_watch() {
+ let r = flags_from_vec(svec!["deno", "test", "--watch"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: false,
+ doc: false,
+ fail_fast: None,
+ filter: None,
+ allow_none: false,
+ shuffle: None,
+ include: None,
+ ignore: vec![],
+ concurrent_jobs: NonZeroUsize::new(1).unwrap(),
+ trace_ops: false,
+ }),
+ no_prompt: true,
+ type_check_mode: TypeCheckMode::Local,
+ watch: Some(vec![]),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn test_watch_with_no_clear_screen() {
+ let r =
+ flags_from_vec(svec!["deno", "test", "--watch", "--no-clear-screen"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Test(TestFlags {
+ no_run: false,
+ doc: false,
+ fail_fast: None,
+ filter: None,
+ allow_none: false,
+ shuffle: None,
+ include: None,
+ ignore: vec![],
+ concurrent_jobs: NonZeroUsize::new(1).unwrap(),
+ trace_ops: false,
+ }),
+ watch: Some(vec![]),
+ type_check_mode: TypeCheckMode::Local,
+ no_clear_screen: true,
+ no_prompt: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bundle_with_cafile() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "bundle",
+ "--cert",
+ "example.crt",
+ "source.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bundle(BundleFlags {
+ source_file: "source.ts".to_string(),
+ out_file: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ca_file: Some("example.crt".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn upgrade_with_ca_file() {
+ let r = flags_from_vec(svec!["deno", "upgrade", "--cert", "example.crt"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Upgrade(UpgradeFlags {
+ force: false,
+ dry_run: false,
+ canary: false,
+ version: None,
+ output: None,
+ ca_file: Some("example.crt".to_owned()),
+ }),
+ ca_file: Some("example.crt".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn cache_with_cafile() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "cache",
+ "--cert",
+ "example.crt",
+ "script.ts",
+ "script_two.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Cache(CacheFlags {
+ files: svec!["script.ts", "script_two.ts"],
+ }),
+ ca_file: Some("example.crt".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn info_with_cafile() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "info",
+ "--cert",
+ "example.crt",
+ "https://example.com"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Info(InfoFlags {
+ json: false,
+ file: Some("https://example.com".to_string()),
+ }),
+ ca_file: Some("example.crt".to_owned()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn doc() {
+ let r = flags_from_vec(svec!["deno", "doc", "--json", "path/to/module.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Doc(DocFlags {
+ private: false,
+ json: true,
+ source_file: Some("path/to/module.ts".to_string()),
+ filter: None,
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "doc",
+ "path/to/module.ts",
+ "SomeClass.someField"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Doc(DocFlags {
+ private: false,
+ json: false,
+ source_file: Some("path/to/module.ts".to_string()),
+ filter: Some("SomeClass.someField".to_string()),
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "doc"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Doc(DocFlags {
+ private: false,
+ json: false,
+ source_file: None,
+ filter: None,
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "doc", "--builtin", "Deno.Listener"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Doc(DocFlags {
+ private: false,
+ json: false,
+ source_file: Some("--builtin".to_string()),
+ filter: Some("Deno.Listener".to_string()),
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r =
+ flags_from_vec(svec!["deno", "doc", "--private", "path/to/module.js"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Doc(DocFlags {
+ private: true,
+ json: false,
+ source_file: Some("path/to/module.js".to_string()),
+ filter: None,
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn inspect_default_host() {
+ let r = flags_from_vec(svec!["deno", "run", "--inspect", "foo.js"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "foo.js".to_string(),
+ }),
+ inspect: Some("127.0.0.1:9229".parse().unwrap()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn compile() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "compile",
+ "https://deno.land/std/examples/colors.ts"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Compile(CompileFlags {
+ source_file: "https://deno.land/std/examples/colors.ts".to_string(),
+ output: None,
+ args: vec![],
+ target: None,
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn compile_with_flags() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--output", "colors", "https://deno.land/std/examples/colors.ts", "foo", "bar"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Compile(CompileFlags {
+ source_file: "https://deno.land/std/examples/colors.ts".to_string(),
+ output: Some(PathBuf::from("colors")),
+ args: svec!["foo", "bar"],
+ target: None,
+ }),
+ import_map_path: Some("import_map.json".to_string()),
+ no_remote: true,
+ config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
+ type_check_mode: TypeCheckMode::None,
+ reload: true,
+ lock: Some(PathBuf::from("lock.json")),
+ lock_write: true,
+ ca_file: Some("example.crt".to_string()),
+ cached_only: true,
+ location: Some(Url::parse("https://foo/").unwrap()),
+ allow_read: Some(vec![]),
+ unsafely_ignore_certificate_errors: Some(vec![]),
+ allow_net: Some(vec![]),
+ v8_flags: svec!["--help", "--random-seed=1"],
+ seed: Some(1),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn coverage() {
+ let r = flags_from_vec(svec!["deno", "coverage", "foo.json"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Coverage(CoverageFlags {
+ files: vec![PathBuf::from("foo.json")],
+ output: None,
+ ignore: vec![],
+ include: vec![r"^file:".to_string()],
+ exclude: vec![r"test\.(js|mjs|ts|jsx|tsx)$".to_string()],
+ lcov: false,
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn coverage_with_lcov_and_out_file() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "coverage",
+ "--lcov",
+ "--output=foo.lcov",
+ "foo.json"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Coverage(CoverageFlags {
+ files: vec![PathBuf::from("foo.json")],
+ ignore: vec![],
+ include: vec![r"^file:".to_string()],
+ exclude: vec![r"test\.(js|mjs|ts|jsx|tsx)$".to_string()],
+ lcov: true,
+ output: Some(PathBuf::from("foo.lcov")),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+ #[test]
+ fn location_with_bad_scheme() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "run", "--location", "foo:", "mod.ts"]);
+ assert!(r.is_err());
+ assert!(r
+ .unwrap_err()
+ .to_string()
+ .contains("Expected protocol \"http\" or \"https\""));
+ }
+
+ #[test]
+ fn compat() {
+ let r =
+ flags_from_vec(svec!["deno", "run", "--compat", "--unstable", "foo.js"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "foo.js".to_string(),
+ }),
+ compat: true,
+ unstable: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn test_config_path_args() {
+ let flags = flags_from_vec(svec!["deno", "run", "foo.js"]).unwrap();
+ assert_eq!(
+ flags.config_path_args(),
+ Some(vec![std::env::current_dir().unwrap().join("foo.js")])
+ );
+
+ let flags =
+ flags_from_vec(svec!["deno", "run", "https://example.com/foo.js"])
+ .unwrap();
+ assert_eq!(flags.config_path_args(), None);
+
+ let flags =
+ flags_from_vec(svec!["deno", "lint", "dir/a.js", "dir/b.js"]).unwrap();
+ assert_eq!(
+ flags.config_path_args(),
+ Some(vec![PathBuf::from("dir/a.js"), PathBuf::from("dir/b.js")])
+ );
+
+ let flags = flags_from_vec(svec!["deno", "lint"]).unwrap();
+ assert!(flags.config_path_args().unwrap().is_empty());
+
+ let flags =
+ flags_from_vec(svec!["deno", "fmt", "dir/a.js", "dir/b.js"]).unwrap();
+ assert_eq!(
+ flags.config_path_args(),
+ Some(vec![PathBuf::from("dir/a.js"), PathBuf::from("dir/b.js")])
+ );
+ }
+
+ #[test]
+ fn test_no_clear_watch_flag_without_watch_flag() {
+ let r = flags_from_vec(svec!["deno", "run", "--no-clear-screen", "foo.js"]);
+ assert!(r.is_err());
+ let error_message = r.unwrap_err().to_string();
+ assert!(&error_message
+ .contains("error: The following required arguments were not provided:"));
+ assert!(&error_message.contains("--watch[=<FILES>...]"));
+ }
+
+ #[test]
+ fn vendor_minimal() {
+ let r = flags_from_vec(svec!["deno", "vendor", "mod.ts",]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Vendor(VendorFlags {
+ specifiers: svec!["mod.ts"],
+ force: false,
+ output_path: None,
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn vendor_all() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "vendor",
+ "--config",
+ "deno.json",
+ "--import-map",
+ "import_map.json",
+ "--lock",
+ "lock.json",
+ "--force",
+ "--output",
+ "out_dir",
+ "--reload",
+ "mod.ts",
+ "deps.test.ts",
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Vendor(VendorFlags {
+ specifiers: svec!["mod.ts", "deps.test.ts"],
+ force: true,
+ output_path: Some(PathBuf::from("out_dir")),
+ }),
+ config_flag: ConfigFlag::Path("deno.json".to_owned()),
+ import_map_path: Some("import_map.json".to_string()),
+ lock: Some(PathBuf::from("lock.json")),
+ reload: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_subcommand() {
+ let r = flags_from_vec(svec!["deno", "task", "build", "hello", "world",]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "build".to_string(),
+ }),
+ argv: svec!["hello", "world"],
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "task", "build"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "build".to_string(),
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "task", "--cwd", "foo", "build"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: Some("foo".to_string()),
+ task: "build".to_string(),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_subcommand_double_hyphen() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "task",
+ "-c",
+ "deno.json",
+ "build",
+ "--",
+ "hello",
+ "world",
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "build".to_string(),
+ }),
+ argv: svec!["--", "hello", "world"],
+ config_flag: ConfigFlag::Path("deno.json".to_owned()),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno", "task", "--cwd", "foo", "build", "--", "hello", "world"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: Some("foo".to_string()),
+ task: "build".to_string(),
+ }),
+ argv: svec!["--", "hello", "world"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_subcommand_double_hyphen_only() {
+ // edge case, but it should forward
+ let r = flags_from_vec(svec!["deno", "task", "build", "--"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "build".to_string(),
+ }),
+ argv: svec!["--"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_following_arg() {
+ let r = flags_from_vec(svec!["deno", "task", "build", "-1", "--test"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "build".to_string(),
+ }),
+ argv: svec!["-1", "--test"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_following_double_hyphen_arg() {
+ let r = flags_from_vec(svec!["deno", "task", "build", "--test"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "build".to_string(),
+ }),
+ argv: svec!["--test"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_subcommand_empty() {
+ let r = flags_from_vec(svec!["deno", "task"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "".to_string(),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_subcommand_config() {
+ let r = flags_from_vec(svec!["deno", "task", "--config", "deno.jsonc"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "".to_string(),
+ }),
+ config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn task_subcommand_config_short() {
+ let r = flags_from_vec(svec!["deno", "task", "-c", "deno.jsonc"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Task(TaskFlags {
+ cwd: None,
+ task: "".to_string(),
+ }),
+ config_flag: ConfigFlag::Path("deno.jsonc".to_string()),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn bench_with_flags() {
+ let r = flags_from_vec(svec![
+ "deno",
+ "bench",
+ "--unstable",
+ "--filter",
+ "- foo",
+ "--location",
+ "https:foo",
+ "--allow-net",
+ "dir1/",
+ "dir2/",
+ "--",
+ "arg1",
+ "arg2"
+ ]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Bench(BenchFlags {
+ filter: Some("- foo".to_string()),
+ include: Some(svec!["dir1/", "dir2/"]),
+ ignore: vec![],
+ }),
+ unstable: true,
+ type_check_mode: TypeCheckMode::Local,
+ location: Some(Url::parse("https://foo/").unwrap()),
+ allow_net: Some(vec![]),
+ no_prompt: true,
+ argv: svec!["arg1", "arg2"],
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
+ fn run_with_check() {
+ let r = flags_from_vec(svec!["deno", "run", "--check", "script.ts",]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ type_check_mode: TypeCheckMode::Local,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "run", "--check=all", "script.ts",]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ type_check_mode: TypeCheckMode::All,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "run", "--check=foo", "script.ts",]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--no-check",
+ "--check",
+ "script.ts",
+ ]);
+ assert!(r.is_err());
+ }
+
+ #[test]
+ fn no_config() {
+ let r = flags_from_vec(svec!["deno", "run", "--no-config", "script.ts",]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Run(RunFlags {
+ script: "script.ts".to_string(),
+ }),
+ config_flag: ConfigFlag::Disabled,
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec![
+ "deno",
+ "run",
+ "--config",
+ "deno.json",
+ "--no-config",
+ "script.ts",
+ ]);
+ assert!(r.is_err());
+ }
+}