deno/cli/flags.rs
Bartek Iwańczuk a3bfbccead
refactor: rewrite deno test, add Deno.test() (#3865)
* rewrite test runner in Rust
* migrate "test" and "runTests" functions from std to "Deno" namespace
* use "Deno.test()" to run internal JS unit tests
* remove std downloads for Deno subcommands
2020-02-11 12:01:56 +01:00

2056 lines
51 KiB
Rust

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::fs::resolve_from_cwd;
use clap::App;
use clap::AppSettings;
use clap::Arg;
use clap::ArgMatches;
use clap::SubCommand;
use log::Level;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
/// Creates vector of strings, Vec<String>
macro_rules! svec {
($($x:expr),*) => (vec![$($x.to_string()),*]);
}
/// Creates HashSet<String> from string literals
macro_rules! sset {
($($x:expr),*) => {{
let _v = svec![$($x.to_string()),*];
let hash_set: HashSet<String> = _v.iter().cloned().collect();
hash_set
}}
}
#[derive(Clone, Debug, PartialEq)]
pub enum DenoSubcommand {
Bundle {
source_file: String,
out_file: Option<PathBuf>,
},
Completions {
buf: Box<[u8]>,
},
Eval {
code: String,
},
Fetch {
files: Vec<String>,
},
Format {
check: bool,
files: Option<Vec<PathBuf>>,
},
Help,
Info {
file: Option<String>,
},
Install {
dir: Option<PathBuf>,
exe_name: String,
module_url: String,
args: Vec<String>,
force: bool,
},
Repl,
Run {
script: String,
},
Test {
fail_fast: bool,
quiet: bool,
allow_none: bool,
include: Option<Vec<String>>,
},
Types,
}
impl Default for DenoSubcommand {
fn default() -> DenoSubcommand {
DenoSubcommand::Repl
}
}
#[derive(Clone, Debug, PartialEq, Default)]
pub struct DenoFlags {
/// Vector of CLI arguments - these are user script arguments, all Deno
/// specific flags are removed.
pub argv: Vec<String>,
pub subcommand: DenoSubcommand,
pub log_level: Option<Level>,
pub version: bool,
pub reload: bool,
pub config_path: Option<String>,
pub import_map_path: Option<String>,
pub allow_read: bool,
pub read_whitelist: Vec<PathBuf>,
pub cache_blacklist: Vec<String>,
pub allow_write: bool,
pub write_whitelist: Vec<PathBuf>,
pub allow_net: bool,
pub net_whitelist: Vec<String>,
pub allow_env: bool,
pub allow_run: bool,
pub allow_plugin: bool,
pub allow_hrtime: bool,
pub no_prompts: bool,
pub no_remote: bool,
pub cached_only: bool,
pub seed: Option<u64>,
pub v8_flags: Option<Vec<String>>,
pub lock: Option<String>,
pub lock_write: bool,
}
fn join_paths(whitelist: &[PathBuf], d: &str) -> String {
whitelist
.iter()
.map(|path| path.to_str().unwrap().to_string())
.collect::<Vec<String>>()
.join(d)
}
impl DenoFlags {
/// 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.read_whitelist.is_empty() {
let s = format!("--allow-read={}", join_paths(&self.read_whitelist, ","));
args.push(s);
}
if self.allow_read {
args.push("--allow-read".to_string());
}
if !self.write_whitelist.is_empty() {
let s =
format!("--allow-write={}", join_paths(&self.write_whitelist, ","));
args.push(s);
}
if self.allow_write {
args.push("--allow-write".to_string());
}
if !self.net_whitelist.is_empty() {
let s = format!("--allow-net={}", self.net_whitelist.join(","));
args.push(s);
}
if self.allow_net {
args.push("--allow-net".to_string());
}
if self.allow_env {
args.push("--allow-env".to_string());
}
if self.allow_run {
args.push("--allow-run".to_string());
}
if self.allow_plugin {
args.push("--allow-plugin".to_string());
}
if self.allow_hrtime {
args.push("--allow-hrtime".to_string());
}
args
}
}
static ENV_VARIABLES_HELP: &str = "ENVIRONMENT VARIABLES:
DENO_DIR Set deno's base directory
NO_COLOR Set to disable color
HTTP_PROXY Proxy address for HTTP requests (module downloads, fetch)
HTTPS_PROXY Same but for HTTPS";
static DENO_HELP: &str = "A secure JavaScript and TypeScript runtime
Docs: https://deno.land/std/manual.md
Modules: https://deno.land/x/
Bugs: https://github.com/denoland/deno/issues
To run the REPL supply no arguments:
deno
To evaluate code from the command line:
deno eval \"console.log(30933 + 404)\"
To execute a script:
deno https://deno.land/std/examples/welcome.ts
The default subcommand is 'run'. The above is equivalent to
deno run https://deno.land/std/examples/welcome.ts
See 'deno help run' for run specific flags.";
lazy_static! {
static ref LONG_VERSION: String = format!(
"{}\nv8 {}\ntypescript {}",
crate::version::DENO,
crate::version::v8(),
crate::version::TYPESCRIPT
);
}
/// Main entry point for parsing deno's command line flags.
/// Exits the process on error.
pub fn flags_from_vec(args: Vec<String>) -> DenoFlags {
match flags_from_vec_safe(args) {
Ok(flags) => flags,
Err(err) => err.exit(),
}
}
/// Same as flags_from_vec but does not exit on error.
pub fn flags_from_vec_safe(args: Vec<String>) -> clap::Result<DenoFlags> {
let args = arg_hacks(args);
let app = clap_root();
let matches = app.get_matches_from_safe(args)?;
let mut flags = DenoFlags::default();
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 let Some(m) = matches.subcommand_matches("run") {
run_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("fmt") {
fmt_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("types") {
types_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("fetch") {
fetch_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("info") {
info_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("eval") {
eval_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("repl") {
repl_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("bundle") {
bundle_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("install") {
install_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("completions") {
completions_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("test") {
test_parse(&mut flags, m);
} else {
unimplemented!();
}
Ok(flags)
}
fn clap_root<'a, 'b>() -> App<'a, 'b> {
clap::App::new("deno")
.bin_name("deno")
.global_settings(&[
AppSettings::UnifiedHelpMessage,
AppSettings::ColorNever,
AppSettings::VersionlessSubcommands,
])
// Disable clap's auto-detection of terminal width
.set_term_width(0)
// Disable each subcommand having its own version.
.version(crate::version::DENO)
.long_version(LONG_VERSION.as_str())
.arg(
Arg::with_name("log-level")
.short("L")
.long("log-level")
.help("Set log level")
.takes_value(true)
.possible_values(&["debug", "info"])
.global(true),
)
.subcommand(bundle_subcommand())
.subcommand(completions_subcommand())
.subcommand(eval_subcommand())
.subcommand(fetch_subcommand())
.subcommand(fmt_subcommand())
.subcommand(info_subcommand())
.subcommand(install_subcommand())
.subcommand(repl_subcommand())
.subcommand(run_subcommand())
.subcommand(test_subcommand())
.subcommand(types_subcommand())
.long_about(DENO_HELP)
.after_help(ENV_VARIABLES_HELP)
}
fn types_parse(flags: &mut DenoFlags, _matches: &clap::ArgMatches) {
flags.subcommand = DenoSubcommand::Types;
}
fn fmt_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
let maybe_files = match matches.values_of("files") {
Some(f) => {
let files: Vec<PathBuf> = f.map(PathBuf::from).collect();
Some(files)
}
None => None,
};
let check = matches.is_present("check");
flags.subcommand = DenoSubcommand::Format {
check,
files: maybe_files,
}
}
fn install_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
permission_args_parse(flags, matches);
let dir = if matches.is_present("dir") {
let install_dir = matches.value_of("dir").unwrap();
Some(PathBuf::from(install_dir))
} else {
None
};
let force = matches.is_present("force");
let exe_name = matches.value_of("exe_name").unwrap().to_string();
let cmd_values = matches.values_of("cmd").unwrap();
let mut cmd_args = vec![];
for value in cmd_values {
cmd_args.push(value.to_string());
}
let module_url = cmd_args[0].to_string();
let args = cmd_args[1..].to_vec();
flags.subcommand = DenoSubcommand::Install {
dir,
exe_name,
module_url,
args,
force,
};
}
fn bundle_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
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 = true;
Some(PathBuf::from(out_file))
} else {
None
};
flags.subcommand = DenoSubcommand::Bundle {
source_file,
out_file,
};
}
fn completions_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
let shell: &str = matches.value_of("shell").unwrap();
let mut buf: Vec<u8> = vec![];
use std::str::FromStr;
clap_root().gen_completions_to(
"deno",
clap::Shell::from_str(shell).unwrap(),
&mut buf,
);
flags.subcommand = DenoSubcommand::Completions {
buf: buf.into_boxed_slice(),
};
}
fn repl_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
v8_flags_arg_parse(flags, matches);
flags.subcommand = DenoSubcommand::Repl;
flags.allow_net = true;
flags.allow_env = true;
flags.allow_run = true;
flags.allow_read = true;
flags.allow_write = true;
flags.allow_plugin = true;
flags.allow_hrtime = true;
}
fn eval_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
v8_flags_arg_parse(flags, matches);
flags.allow_net = true;
flags.allow_env = true;
flags.allow_run = true;
flags.allow_read = true;
flags.allow_write = true;
flags.allow_plugin = true;
flags.allow_hrtime = true;
let code = matches.value_of("code").unwrap().to_string();
flags.subcommand = DenoSubcommand::Eval { code }
}
fn info_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
flags.subcommand = DenoSubcommand::Info {
file: matches.value_of("file").map(|f| f.to_string()),
};
}
fn fetch_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
reload_arg_parse(flags, matches);
lock_args_parse(flags, matches);
importmap_arg_parse(flags, matches);
config_arg_parse(flags, matches);
no_remote_arg_parse(flags, matches);
let files = matches
.values_of("file")
.unwrap()
.map(String::from)
.collect();
flags.subcommand = DenoSubcommand::Fetch { files };
}
fn lock_args_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
if matches.is_present("lock") {
let lockfile = matches.value_of("lock").unwrap();
flags.lock = Some(lockfile.to_string());
}
if matches.is_present("lock-write") {
flags.lock_write = true;
}
}
fn resolve_fs_whitelist(whitelist: &[PathBuf]) -> Vec<PathBuf> {
whitelist
.iter()
.map(|raw_path| resolve_from_cwd(Path::new(&raw_path)).unwrap())
.collect()
}
// Shared between the run and test subcommands. They both take similar options.
fn run_test_args_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
reload_arg_parse(flags, matches);
lock_args_parse(flags, matches);
importmap_arg_parse(flags, matches);
config_arg_parse(flags, matches);
v8_flags_arg_parse(flags, matches);
no_remote_arg_parse(flags, matches);
permission_args_parse(flags, matches);
if matches.is_present("cached-only") {
flags.cached_only = true;
}
if matches.is_present("seed") {
let seed_string = matches.value_of("seed").unwrap();
let seed = seed_string.parse::<u64>().unwrap();
flags.seed = Some(seed);
let v8_seed_flag = format!("--random-seed={}", seed);
match flags.v8_flags {
Some(ref mut v8_flags) => {
v8_flags.push(v8_seed_flag);
}
None => {
flags.v8_flags = Some(svec![v8_seed_flag]);
}
}
}
}
fn run_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
run_test_args_parse(flags, matches);
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);
}
flags.subcommand = DenoSubcommand::Run { script };
}
fn test_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
flags.allow_read = true;
run_test_args_parse(flags, matches);
let quiet = matches.is_present("quiet");
let failfast = matches.is_present("failfast");
let allow_none = matches.is_present("allow_none");
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.subcommand = DenoSubcommand::Test {
quiet,
fail_fast: failfast,
include,
allow_none,
};
}
fn types_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("types")
.about("Print runtime TypeScript declarations")
.long_about(
"Print runtime TypeScript declarations.
deno types > lib.deno_runtime.d.ts
The declaration file could be saved and used for typing information.",
)
}
fn fmt_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("fmt")
.about("Format files")
.long_about(
"Auto-format JavaScript/TypeScript source code
deno fmt
deno fmt myfile1.ts myfile2.ts
deno fmt --check
# Format stdin and write to stdout
cat file.ts | deno fmt -",
)
.arg(
Arg::with_name("check")
.long("check")
.help("Check if the source files are formatted.")
.takes_value(false),
)
.arg(
Arg::with_name("files")
.takes_value(true)
.multiple(true)
.required(false),
)
}
fn repl_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("repl")
.about("Read Eval Print Loop")
.arg(v8_flags_arg())
}
fn install_subcommand<'a, 'b>() -> App<'a, 'b> {
permission_args(SubCommand::with_name("install"))
.setting(AppSettings::TrailingVarArg)
.arg(
Arg::with_name("dir")
.long("dir")
.short("d")
.help("Installation directory (defaults to $HOME/.deno/bin)")
.takes_value(true)
.multiple(false))
.arg(
Arg::with_name("force")
.long("force")
.short("f")
.help("Forcefully overwrite existing installation")
.takes_value(false))
.arg(
Arg::with_name("exe_name")
.required(true)
)
.arg(
Arg::with_name("cmd")
.required(true)
.multiple(true)
.allow_hyphen_values(true)
)
.about("Install script as executable")
.long_about(
"Installs a script as executable. The default installation directory is
$HOME/.deno/bin and it must be added to the path manually.
deno install --allow-net --allow-read file_server https://deno.land/std/http/file_server.ts
deno install colors https://deno.land/std/examples/colors.ts
To change installation directory use -d/--dir flag
deno install --allow-net --allow-read -d /usr/local/bin file_server https://deno.land/std/http/file_server.ts")
}
fn bundle_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("bundle")
.arg(
Arg::with_name("source_file")
.takes_value(true)
.required(true),
)
.arg(Arg::with_name("out_file").takes_value(true).required(false))
.about("Bundle module and dependencies into single file")
.long_about(
"Output a single JavaScript file with all dependencies.
If a out_file argument is omitted, the output of the bundle will be sent to
standard out. Examples:
deno bundle https://deno.land/std/examples/colors.ts
deno bundle https://deno.land/std/examples/colors.ts colors.bundle.js",
)
}
fn completions_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("completions")
.setting(AppSettings::DisableHelpSubcommand)
.arg(
Arg::with_name("shell")
.possible_values(&clap::Shell::variants())
.required(true),
)
.about("Generate shell completions")
.long_about(
"Output shell completion script to standard output.
Example:
deno completions bash > /usr/local/etc/bash_completion.d/deno.bash
source /usr/local/etc/bash_completion.d/deno.bash",
)
}
fn eval_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("eval")
.about("Eval script")
.long_about(
"Evaluate JavaScript from command-line
This command has implicit access to all permissions (--allow-all)
deno eval \"console.log('hello world')\"",
)
.arg(Arg::with_name("code").takes_value(true).required(true))
.arg(v8_flags_arg())
}
fn info_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("info")
.about("Show info about cache or info related to source file")
.long_about(
"Information about source file and cache
Example: 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.
compiled: Local path of compiled source code (TypeScript only)
map: Local path of source map (TypeScript only)
deps: Dependency tree of the source file.
Without any additional arguments 'deno info' shows:
DENO_DIR: directory containing Deno-related files
Remote modules cache: directory containing remote modules
TypeScript compiler cache: directory containing TS compiler output",
)
.arg(Arg::with_name("file").takes_value(true).required(false))
}
fn fetch_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("fetch")
.arg(reload_arg())
.arg(lock_arg())
.arg(lock_write_arg())
.arg(importmap_arg())
.arg(config_arg())
.arg(no_remote_arg())
.arg(
Arg::with_name("file")
.takes_value(true)
.required(true)
.min_values(1),
)
.about("Fetch the dependencies")
.long_about(
"Fetch and compile remote dependencies recursively.
Downloads all statically imported scripts and save them in local
cache, without running the code. No future import network requests
would be made unless --reload is specified.
Downloads all dependencies
deno fetch https://deno.land/std/http/file_server.ts
Once cached, static imports no longer send network requests
deno run -A https://deno.land/std/http/file_server.ts",
)
}
fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
app
.arg(
Arg::with_name("allow-read")
.long("allow-read")
.min_values(0)
.takes_value(true)
.use_delimiter(true)
.require_equals(true)
.help("Allow file system read access"),
)
.arg(
Arg::with_name("allow-write")
.long("allow-write")
.min_values(0)
.takes_value(true)
.use_delimiter(true)
.require_equals(true)
.help("Allow file system write access"),
)
.arg(
Arg::with_name("allow-net")
.long("allow-net")
.min_values(0)
.takes_value(true)
.use_delimiter(true)
.require_equals(true)
.help("Allow network access"),
)
.arg(
Arg::with_name("allow-env")
.long("allow-env")
.help("Allow environment access"),
)
.arg(
Arg::with_name("allow-run")
.long("allow-run")
.help("Allow running subprocesses"),
)
.arg(
Arg::with_name("allow-plugin")
.long("allow-plugin")
.help("Allow loading plugins"),
)
.arg(
Arg::with_name("allow-hrtime")
.long("allow-hrtime")
.help("Allow high resolution time measurement"),
)
.arg(
Arg::with_name("allow-all")
.short("A")
.long("allow-all")
.help("Allow all permissions"),
)
}
fn run_test_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
permission_args(app)
.arg(importmap_arg())
.arg(reload_arg())
.arg(config_arg())
.arg(lock_arg())
.arg(lock_write_arg())
.arg(no_remote_arg())
.arg(v8_flags_arg())
.arg(
Arg::with_name("cached-only")
.long("cached-only")
.help("Require that remote dependencies are already cached"),
)
.arg(
Arg::with_name("seed")
.long("seed")
.value_name("NUMBER")
.help("Seed Math.random()")
.takes_value(true)
.validator(|val: String| match val.parse::<u64>() {
Ok(_) => Ok(()),
Err(_) => Err("Seed should be a number".to_string()),
}),
)
}
fn run_subcommand<'a, 'b>() -> App<'a, 'b> {
run_test_args(SubCommand::with_name("run"))
.setting(AppSettings::TrailingVarArg)
.arg(script_arg())
.about("Run a program given a filename or url to the source code")
.long_about(
"Run a program given a filename or url to the source code.
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
With all permissions
deno run -A https://deno.land/std/http/file_server.ts
With only permission to read from disk and listen to network
deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts
With only permission to read whitelist files from disk
deno run --allow-read=/etc https://deno.land/std/http/file_server.ts",
)
}
fn test_subcommand<'a, 'b>() -> App<'a, 'b> {
run_test_args(SubCommand::with_name("test"))
.arg(
Arg::with_name("failfast")
.short("f")
.long("failfast")
.help("Stop on first error")
.takes_value(false),
)
.arg(
Arg::with_name("quiet")
.short("q")
.long("quiet")
.help("Don't show output from test cases")
.takes_value(false),
)
.arg(
Arg::with_name("allow_none")
.long("allow-none")
.help("Don't return error code if no test files are found")
.takes_value(false),
)
.arg(
Arg::with_name("files")
.help("List of file names to run")
.takes_value(true)
.multiple(true),
)
.about("Run tests")
.long_about(
"Run tests using test runner
Searches the specified directories for all files that end in _test.ts or
_test.js and executes them.
deno test src/",
)
}
fn script_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("script_arg")
.multiple(true)
.required(true)
.help("script args")
.value_name("SCRIPT_ARG")
}
fn lock_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("lock")
.long("lock")
.value_name("FILE")
.help("Check the specified lock file")
.takes_value(true)
}
fn lock_write_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("lock-write")
.long("lock-write")
.help("Write lock file. Use with --lock.")
}
fn config_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("config")
.short("c")
.long("config")
.value_name("FILE")
.help("Load tsconfig.json configuration file")
.takes_value(true)
}
fn config_arg_parse(flags: &mut DenoFlags, matches: &ArgMatches) {
flags.config_path = matches.value_of("config").map(ToOwned::to_owned);
}
fn reload_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("reload")
.short("r")
.min_values(0)
.takes_value(true)
.use_delimiter(true)
.require_equals(true)
.long("reload")
.help("Reload source code cache (recompile TypeScript)")
.value_name("CACHE_BLACKLIST")
.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",
)
}
fn reload_arg_parse(flags: &mut DenoFlags, matches: &ArgMatches) {
if matches.is_present("reload") {
if matches.value_of("reload").is_some() {
let cache_bl = matches.values_of("reload").unwrap();
let raw_cache_blacklist: Vec<String> =
cache_bl.map(std::string::ToString::to_string).collect();
flags.cache_blacklist = resolve_urls(raw_cache_blacklist);
debug!("cache blacklist: {:#?}", &flags.cache_blacklist);
flags.reload = false;
} else {
flags.reload = true;
}
}
}
fn importmap_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("importmap")
.long("importmap")
.value_name("FILE")
.help("Load import map file")
.long_help(
"Load import map file
Docs: https://deno.land/std/manual.md#import-maps
Specification: https://wicg.github.io/import-maps/
Examples: https://github.com/WICG/import-maps#the-import-map",
)
.takes_value(true)
}
fn importmap_arg_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
flags.import_map_path = matches.value_of("importmap").map(ToOwned::to_owned);
}
fn v8_flags_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("v8-flags")
.long("v8-flags")
.takes_value(true)
.use_delimiter(true)
.require_equals(true)
.help("Set V8 command line options. For help: --v8-flags=--help")
}
fn v8_flags_arg_parse(flags: &mut DenoFlags, matches: &ArgMatches) {
if let Some(v8_flags) = matches.values_of("v8-flags") {
let s: Vec<String> = v8_flags.map(String::from).collect();
flags.v8_flags = Some(s);
}
}
fn no_remote_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("no-remote")
.long("no-remote")
.help("Do not resolve remote modules")
}
fn no_remote_arg_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
if matches.is_present("no-remote") {
flags.no_remote = true;
}
}
fn permission_args_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
if matches.is_present("allow-read") {
if matches.value_of("allow-read").is_some() {
let read_wl = matches.values_of("allow-read").unwrap();
let raw_read_whitelist: Vec<PathBuf> =
read_wl.map(PathBuf::from).collect();
flags.read_whitelist = resolve_fs_whitelist(&raw_read_whitelist);
debug!("read whitelist: {:#?}", &flags.read_whitelist);
} else {
flags.allow_read = true;
}
}
if matches.is_present("allow-write") {
if matches.value_of("allow-write").is_some() {
let write_wl = matches.values_of("allow-write").unwrap();
let raw_write_whitelist: Vec<PathBuf> =
write_wl.map(PathBuf::from).collect();
flags.write_whitelist = resolve_fs_whitelist(&raw_write_whitelist);
debug!("write whitelist: {:#?}", &flags.write_whitelist);
} else {
flags.allow_write = true;
}
}
if matches.is_present("allow-net") {
if matches.value_of("allow-net").is_some() {
let net_wl = matches.values_of("allow-net").unwrap();
let raw_net_whitelist =
net_wl.map(std::string::ToString::to_string).collect();
flags.net_whitelist = resolve_hosts(raw_net_whitelist);
debug!("net whitelist: {:#?}", &flags.net_whitelist);
} else {
flags.allow_net = true;
}
}
if matches.is_present("allow-env") {
flags.allow_env = true;
}
if matches.is_present("allow-run") {
flags.allow_run = true;
}
if matches.is_present("allow-plugin") {
flags.allow_plugin = true;
}
if matches.is_present("allow-hrtime") {
flags.allow_hrtime = true;
}
if matches.is_present("allow-all") {
flags.allow_read = true;
flags.allow_env = true;
flags.allow_net = true;
flags.allow_run = true;
flags.allow_read = true;
flags.allow_write = true;
flags.allow_plugin = true;
flags.allow_hrtime = 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> {
use url::Url;
let mut out: Vec<String> = vec![];
for urlstr in urls.iter() {
use std::str::FromStr;
let result = Url::from_str(urlstr);
if result.is_err() {
panic!("Bad Url: {}", urlstr);
}
let mut url = result.unwrap();
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);
}
out
}
/// Expands "bare port" paths (eg. ":8080") into full paths with hosts. It
/// expands to such paths into 3 paths with following hosts: `0.0.0.0:port`,
/// `127.0.0.1:port` and `localhost:port`.
fn resolve_hosts(paths: Vec<String>) -> Vec<String> {
let mut out: Vec<String> = vec![];
for host_and_port in paths.iter() {
let parts = host_and_port.split(':').collect::<Vec<&str>>();
match parts.len() {
// host only
1 => {
out.push(host_and_port.to_owned());
}
// host and port (NOTE: host might be empty string)
2 => {
let host = parts[0];
let port = parts[1];
if !host.is_empty() {
out.push(host_and_port.to_owned());
continue;
}
// we got bare port, let's add default hosts
for host in ["0.0.0.0", "127.0.0.1", "localhost"].iter() {
out.push(format!("{}:{}", host, port));
}
}
_ => panic!("Bad host:port pair: {}", host_and_port),
}
}
out
}
fn arg_hacks(mut args: Vec<String>) -> Vec<String> {
// Hack #1 We want to default the subcommand to "run"
// Clap does not let us have a default sub-command. But we want to allow users
// to do "deno script.js" instead of "deno run script.js".
// This function insert the "run" into the second position of the args.
assert!(!args.is_empty());
// Rational:
// deno -> deno repl
if args.len() == 1 {
args.insert(1, "repl".to_string());
return args;
}
let subcommands = sset![
"bundle",
"completions",
"eval",
"fetch",
"fmt",
"test",
"info",
"repl",
"run",
"types",
"install",
"help",
"version"
];
let modifier_flags = sset!["-h", "--help", "-V", "--version"];
// deno [subcommand|behavior modifier flags] -> do nothing
if subcommands.contains(&args[1]) || modifier_flags.contains(&args[1]) {
return args;
}
// This is not perfect either, since originally we should also
// support e.g. `-L debug` which `debug` would be treated as main module.
// Instead `-L=debug` must be used
let mut has_main_module = false;
for arg in args.iter().skip(1) {
if !arg.starts_with('-') {
has_main_module = true;
break;
}
}
if has_main_module {
// deno ...-[flags] NAME ... -> deno run ...-[flags] NAME ...
args.insert(1, "run".to_string());
} else {
// deno ...-[flags] -> deno repl ...-[flags]
args.insert(1, "repl".to_string());
}
args
}
#[cfg(test)]
mod tests {
use super::*;
use std::env::current_dir;
#[test]
fn arg_hacks_test() {
let args0 = arg_hacks(svec!["deno", "--version"]);
assert_eq!(args0, ["deno", "--version"]);
let args1 = arg_hacks(svec!["deno"]);
assert_eq!(args1, ["deno", "repl"]);
let args2 = arg_hacks(svec!["deno", "-L=debug", "-h"]);
assert_eq!(args2, ["deno", "repl", "-L=debug", "-h"]);
let args3 = arg_hacks(svec!["deno", "script.js"]);
assert_eq!(args3, ["deno", "run", "script.js"]);
let args4 = arg_hacks(svec!["deno", "-A", "script.js", "-L=info"]);
assert_eq!(args4, ["deno", "run", "-A", "script.js", "-L=info"]);
}
#[test]
fn version() {
let r = flags_from_vec_safe(svec!["deno", "--version"]);
assert_eq!(r.unwrap_err().kind, clap::ErrorKind::VersionDisplayed);
let r = flags_from_vec_safe(svec!["deno", "-V"]);
assert_eq!(r.unwrap_err().kind, clap::ErrorKind::VersionDisplayed);
}
#[test]
fn run_reload() {
let r = flags_from_vec_safe(svec!["deno", "run", "-r", "script.ts"]);
let flags = r.unwrap();
assert_eq!(
flags,
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
reload: true,
..DenoFlags::default()
}
);
}
#[test]
fn run_reload_allow_write() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"-r",
"--allow-write",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
reload: true,
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
allow_write: true,
..DenoFlags::default()
}
);
}
#[test]
fn run_v8_flags() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--v8-flags=--help",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
v8_flags: Some(svec!["--help"]),
..DenoFlags::default()
}
);
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--v8-flags=--expose-gc,--gc-stats=1",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
v8_flags: Some(svec!["--expose-gc", "--gc-stats=1"]),
..DenoFlags::default()
}
);
}
#[test]
fn script_args() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--allow-net",
"gist.ts",
"--title",
"X"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "gist.ts".to_string(),
},
argv: svec!["--title", "X"],
allow_net: true,
..DenoFlags::default()
}
);
}
#[test]
fn allow_all() {
let r = flags_from_vec_safe(svec!["deno", "run", "--allow-all", "gist.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "gist.ts".to_string(),
},
allow_net: true,
allow_env: true,
allow_run: true,
allow_read: true,
allow_write: true,
allow_plugin: true,
allow_hrtime: true,
..DenoFlags::default()
}
);
}
#[test]
fn allow_read() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--allow-read", "gist.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "gist.ts".to_string(),
},
allow_read: true,
..DenoFlags::default()
}
);
}
#[test]
fn allow_hrtime() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--allow-hrtime", "gist.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "gist.ts".to_string(),
},
allow_hrtime: true,
..DenoFlags::default()
}
);
}
#[test]
fn double_hyphen() {
// notice that flags passed after double dash will not
// be parsed to DenoFlags but instead forwarded to
// script args as Deno.args
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--allow-write",
"script.ts",
"--",
"-D",
"--allow-net"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
argv: svec!["--", "-D", "--allow-net"],
allow_write: true,
..DenoFlags::default()
}
);
}
#[test]
fn fmt() {
let r =
flags_from_vec_safe(svec!["deno", "fmt", "script_1.ts", "script_2.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Format {
check: false,
files: Some(vec![
PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts")
])
},
..DenoFlags::default()
}
);
let r = flags_from_vec_safe(svec!["deno", "fmt", "--check"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Format {
check: true,
files: None
},
..DenoFlags::default()
}
);
let r = flags_from_vec_safe(svec!["deno", "fmt"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Format {
check: false,
files: None
},
..DenoFlags::default()
}
);
}
#[test]
fn types() {
let r = flags_from_vec_safe(svec!["deno", "types"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Types,
..DenoFlags::default()
}
);
}
#[test]
fn fetch() {
let r = flags_from_vec_safe(svec!["deno", "fetch", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Fetch {
files: svec!["script.ts"],
},
..DenoFlags::default()
}
);
}
#[test]
fn info() {
let r = flags_from_vec_safe(svec!["deno", "info", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Info {
file: Some("script.ts".to_string()),
},
..DenoFlags::default()
}
);
let r = flags_from_vec_safe(svec!["deno", "info"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Info { file: None },
..DenoFlags::default()
}
);
}
#[test]
fn tsconfig() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"-c",
"tsconfig.json",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
config_path: Some("tsconfig.json".to_owned()),
..DenoFlags::default()
}
);
}
#[test]
fn eval() {
let r =
flags_from_vec_safe(svec!["deno", "eval", "'console.log(\"hello\")'"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Eval {
code: "'console.log(\"hello\")'".to_string(),
},
allow_net: true,
allow_env: true,
allow_run: true,
allow_read: true,
allow_write: true,
allow_plugin: true,
allow_hrtime: true,
..DenoFlags::default()
}
);
}
#[test]
fn eval_with_v8_flags() {
let r =
flags_from_vec_safe(svec!["deno", "eval", "--v8-flags=--help", "42"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Eval {
code: "42".to_string(),
},
v8_flags: Some(svec!["--help"]),
allow_net: true,
allow_env: true,
allow_run: true,
allow_read: true,
allow_write: true,
allow_plugin: true,
allow_hrtime: true,
..DenoFlags::default()
}
);
}
#[test]
fn repl() {
let r = flags_from_vec_safe(svec!["deno"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Repl,
allow_net: true,
allow_env: true,
allow_run: true,
allow_read: true,
allow_write: true,
allow_plugin: true,
allow_hrtime: true,
..DenoFlags::default()
}
);
}
#[test]
fn allow_read_whitelist() {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
let r = flags_from_vec_safe(svec![
"deno",
"run",
format!("--allow-read=.,{}", temp_dir.to_str().unwrap()),
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
allow_read: false,
read_whitelist: vec![current_dir().unwrap(), temp_dir],
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
..DenoFlags::default()
}
);
}
#[test]
fn allow_write_whitelist() {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
let r = flags_from_vec_safe(svec![
"deno",
"run",
format!("--allow-write=.,{}", temp_dir.to_str().unwrap()),
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
allow_write: false,
write_whitelist: vec![current_dir().unwrap(), temp_dir],
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
..DenoFlags::default()
}
);
}
#[test]
fn allow_net_whitelist() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--allow-net=127.0.0.1",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
allow_net: false,
net_whitelist: svec!["127.0.0.1"],
..DenoFlags::default()
}
);
}
#[test]
fn default_to_run() {
let r = flags_from_vec_safe(svec!["deno", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
..DenoFlags::default()
}
);
}
#[test]
fn default_to_run_with_permissions() {
let r = flags_from_vec_safe(svec![
"deno",
"--allow-net",
"--allow-read",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
allow_net: true,
allow_read: true,
..DenoFlags::default()
}
);
}
#[test]
fn bundle() {
let r = flags_from_vec_safe(svec!["deno", "bundle", "source.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Bundle {
source_file: "source.ts".to_string(),
out_file: None,
},
..DenoFlags::default()
}
);
}
#[test]
fn bundle_with_output() {
let r =
flags_from_vec_safe(svec!["deno", "bundle", "source.ts", "bundle.js"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Bundle {
source_file: "source.ts".to_string(),
out_file: Some(PathBuf::from("bundle.js")),
},
allow_write: true,
..DenoFlags::default()
}
);
}
#[test]
fn run_importmap() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--importmap=importmap.json",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
import_map_path: Some("importmap.json".to_owned()),
..DenoFlags::default()
}
);
}
#[test]
fn default_to_run_importmap() {
let r = flags_from_vec_safe(svec![
"deno",
"--importmap=importmap.json",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
import_map_path: Some("importmap.json".to_owned()),
..DenoFlags::default()
}
);
}
#[test]
fn fetch_importmap() {
let r = flags_from_vec_safe(svec![
"deno",
"fetch",
"--importmap=importmap.json",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Fetch {
files: svec!["script.ts"],
},
import_map_path: Some("importmap.json".to_owned()),
..DenoFlags::default()
}
);
}
#[test]
fn fetch_multiple() {
let r =
flags_from_vec_safe(svec!["deno", "fetch", "script.ts", "script_two.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Fetch {
files: svec!["script.ts", "script_two.ts"],
},
..DenoFlags::default()
}
);
}
#[test]
fn run_seed() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--seed", "250", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
seed: Some(250 as u64),
v8_flags: Some(svec!["--random-seed=250"]),
..DenoFlags::default()
}
);
}
#[test]
fn run_seed_with_v8_flags() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--seed",
"250",
"--v8-flags=--expose-gc",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
seed: Some(250 as u64),
v8_flags: Some(svec!["--expose-gc", "--random-seed=250"]),
..DenoFlags::default()
}
);
}
#[test]
fn install() {
let r = flags_from_vec_safe(svec![
"deno",
"install",
"deno_colors",
"https://deno.land/std/examples/colors.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Install {
dir: None,
exe_name: "deno_colors".to_string(),
module_url: "https://deno.land/std/examples/colors.ts".to_string(),
args: vec![],
force: false,
},
..DenoFlags::default()
}
);
}
#[test]
fn install_with_args() {
let r = flags_from_vec_safe(svec![
"deno",
"install",
"--allow-net",
"--allow-read",
"file_server",
"https://deno.land/std/http/file_server.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Install {
dir: None,
exe_name: "file_server".to_string(),
module_url: "https://deno.land/std/http/file_server.ts".to_string(),
args: vec![],
force: false,
},
allow_net: true,
allow_read: true,
..DenoFlags::default()
}
);
}
#[test]
fn install_with_args_and_dir_and_force() {
let r = flags_from_vec_safe(svec![
"deno",
"install",
"-d",
"/usr/local/bin",
"-f",
"--allow-net",
"--allow-read",
"file_server",
"https://deno.land/std/http/file_server.ts",
"arg1",
"arg2"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Install {
dir: Some(PathBuf::from("/usr/local/bin")),
exe_name: "file_server".to_string(),
module_url: "https://deno.land/std/http/file_server.ts".to_string(),
args: svec!["arg1", "arg2"],
force: true,
},
allow_net: true,
allow_read: true,
..DenoFlags::default()
}
);
}
#[test]
fn log_level() {
let r =
flags_from_vec_safe(svec!["deno", "--log-level=debug", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
log_level: Some(Level::Debug),
..DenoFlags::default()
}
);
}
#[test]
fn completions() {
let r = flags_from_vec_safe(svec!["deno", "completions", "bash"]).unwrap();
match r.subcommand {
DenoSubcommand::Completions { buf } => assert!(!buf.is_empty()),
_ => unreachable!(),
}
}
/* TODO(ry) Fix this test
#[test]
fn test_flags_from_vec_33() {
let (flags, subcommand, argv) =
flags_from_vec_safe(svec!["deno", "script.ts", "--allow-read", "--allow-net"]);
assert_eq!(
flags,
DenoFlags {
allow_net: true,
allow_read: true,
..DenoFlags::default()
}
);
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["script.ts"]);
let (flags, subcommand, argv) = flags_from_vec_safe(svec![
"deno",
"run",
"--allow-read",
"script.ts",
"--allow-net",
"-r",
"--help",
"--foo",
"bar"
]);
assert_eq!(
flags,
DenoFlags {
allow_net: true,
allow_read: true,
reload: true,
..DenoFlags::default()
}
);
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["deno", "script.ts", "--help", "--foo", "bar"]);
let (flags, subcommand, argv) =
flags_from_vec_safe(svec!["deno""script.ts", "foo", "bar"]);
assert_eq!(flags, DenoFlags::default());
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["script.ts", "foo", "bar"]);
let (flags, subcommand, argv) =
flags_from_vec_safe(svec!["deno""script.ts", "-"]);
assert_eq!(flags, DenoFlags::default());
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["script.ts", "-"]);
let (flags, subcommand, argv) =
flags_from_vec_safe(svec!["deno""script.ts", "-", "foo", "bar"]);
assert_eq!(flags, DenoFlags::default());
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["script.ts", "-", "foo", "bar"]);
}
*/
#[test]
fn no_remote() {
let r = flags_from_vec_safe(svec!["deno", "--no-remote", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
no_remote: true,
..DenoFlags::default()
}
);
}
#[test]
fn cached_only() {
let r = flags_from_vec_safe(svec!["deno", "--cached-only", "script.ts"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
cached_only: true,
..DenoFlags::default()
}
);
}
#[test]
fn allow_net_whitelist_with_ports() {
let r = flags_from_vec_safe(svec![
"deno",
"--allow-net=deno.land,:8000,:4545",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
net_whitelist: 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"
],
..DenoFlags::default()
}
);
}
#[test]
fn lock_write() {
let r = flags_from_vec_safe(svec![
"deno",
"--lock-write",
"--lock=lock.json",
"script.ts"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
lock_write: true,
lock: Some("lock.json".to_string()),
..DenoFlags::default()
}
);
}
#[test]
fn test_with_allow_net() {
let r = flags_from_vec_safe(svec![
"deno",
"test",
"--allow-net",
"--allow-none",
"dir1/",
"dir2/"
]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Test {
fail_fast: false,
quiet: false,
allow_none: true,
include: Some(svec!["dir1/", "dir2/"]),
},
allow_read: true,
allow_net: true,
..DenoFlags::default()
}
);
}
}