summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/flags.rs279
-rw-r--r--cli/main.rs26
-rw-r--r--cli/standalone.rs4
-rw-r--r--cli/tests/070_location.ts10
-rw-r--r--cli/tests/070_location.ts.out22
-rw-r--r--cli/tests/071_location_unset.ts5
-rw-r--r--cli/tests/071_location_unset.ts.out4
-rw-r--r--cli/tests/072_location_relative_fetch.ts2
-rw-r--r--cli/tests/072_location_relative_fetch.ts.out2
-rw-r--r--cli/tests/077_fetch_empty.ts1
-rw-r--r--cli/tests/077_fetch_empty.ts.out2
-rw-r--r--cli/tests/complex_permissions_test.ts4
-rw-r--r--cli/tests/fetch/hello.txt1
-rw-r--r--cli/tests/integration_tests.rs39
-rw-r--r--cli/tests/subdir/worker_location.ts4
-rw-r--r--cli/tests/unit/fetch_test.ts11
-rw-r--r--cli/tests/unit/request_test.ts8
-rwxr-xr-xcli/tests/unit/unit_test_runner.ts1
-rw-r--r--cli/tests/workers_test.ts38
-rw-r--r--cli/tools/installer.rs4
-rw-r--r--docs/runtime/location_api.md76
-rw-r--r--docs/runtime/workers.md9
-rw-r--r--docs/toc.json1
-rw-r--r--op_crates/fetch/26_fetch.js21
-rw-r--r--op_crates/fetch/lib.rs16
-rw-r--r--op_crates/web/12_location.js227
-rw-r--r--op_crates/web/lib.deno_web.d.ts66
-rw-r--r--op_crates/web/lib.rs4
-rw-r--r--runtime/examples/hello_runtime.rs1
-rw-r--r--runtime/js/11_workers.js12
-rw-r--r--runtime/js/99_main.js22
-rw-r--r--runtime/js/README.md2
-rw-r--r--runtime/web_worker.rs3
-rw-r--r--runtime/worker.rs3
34 files changed, 737 insertions, 193 deletions
diff --git a/cli/flags.rs b/cli/flags.rs
index da0f8ad0e..6b4e5aa5f 100644
--- a/cli/flags.rs
+++ b/cli/flags.rs
@@ -11,6 +11,7 @@ use deno_core::serde::Deserialize;
use deno_core::serde::Deserializer;
use deno_core::serde::Serialize;
use deno_core::serde::Serializer;
+use deno_core::url::Url;
use deno_runtime::permissions::PermissionsOptions;
use log::Level;
use std::fmt;
@@ -172,6 +173,7 @@ pub struct Flags {
pub allow_read: Option<Vec<PathBuf>>,
pub allow_run: bool,
pub allow_write: Option<Vec<PathBuf>>,
+ pub location: Option<Url>,
pub cache_blocklist: Vec<String>,
pub ca_file: Option<String>,
pub cached_only: bool,
@@ -324,19 +326,13 @@ lazy_static! {
}
/// Main entry point for parsing deno's command line flags.
-/// Exits the process on error.
-pub fn flags_from_vec(args: Vec<String>) -> Flags {
- 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<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.get_matches_from_safe(args)?;
+ let matches = app.get_matches_from_safe(args).map_err(|e| clap::Error {
+ message: e.message.trim_start_matches("error: ").to_string(),
+ ..e
+ })?;
let mut flags = Flags::default();
@@ -597,7 +593,7 @@ fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
print,
code,
as_typescript,
- }
+ };
}
fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
@@ -671,6 +667,7 @@ fn runtime_args<'a, 'b>(
};
app
.arg(cached_only_arg())
+ .arg(location_arg())
.arg(v8_flags_arg())
.arg(seed_arg())
}
@@ -689,8 +686,10 @@ fn runtime_args_parse(
if include_inspector {
inspect_arg_parse(flags, matches);
}
+ location_arg_parse(flags, matches);
v8_flags_arg_parse(flags, matches);
seed_arg_parse(flags, matches);
+ inspect_arg_parse(flags, matches);
}
fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
@@ -1487,6 +1486,30 @@ fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned);
}
+fn location_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.location = matches
+ .value_of("location")
+ .map(|href| Url::parse(href).unwrap());
+}
+
+fn location_arg<'a, 'b>() -> Arg<'a, 'b> {
+ Arg::with_name("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());
+ }
+ if !["http", "https"].contains(&url.unwrap().scheme()) {
+ return Err("Expected protocol \"http\" or \"https\"".to_string());
+ }
+ Ok(())
+ })
+ .help("Value of 'globalThis.location' used by some web APIs")
+}
+
fn inspect_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
app
.arg(
@@ -1729,7 +1752,6 @@ fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
// 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 deno_core::url::Url;
let mut out: Vec<String> = vec![];
for urlstr in urls.iter() {
if let Ok(mut url) = Url::from_str(urlstr) {
@@ -1758,7 +1780,7 @@ mod tests {
#[test]
fn global_flags() {
#[rustfmt::skip]
- let r = flags_from_vec_safe(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]);
let flags = r.unwrap();
assert_eq!(
flags,
@@ -1772,15 +1794,14 @@ mod tests {
}
);
#[rustfmt::skip]
- let r2 = flags_from_vec_safe(svec!["deno", "run", "--unstable", "--log-level", "debug", "--quiet", "script.ts"]);
+ 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_safe(svec!["deno", "upgrade", "--dry-run", "--force"]);
+ let r = flags_from_vec(svec!["deno", "upgrade", "--dry-run", "--force"]);
let flags = r.unwrap();
assert_eq!(
flags,
@@ -1800,15 +1821,15 @@ mod tests {
#[test]
fn version() {
- let r = flags_from_vec_safe(svec!["deno", "--version"]);
+ let r = flags_from_vec(svec!["deno", "--version"]);
assert_eq!(r.unwrap_err().kind, clap::ErrorKind::VersionDisplayed);
- let r = flags_from_vec_safe(svec!["deno", "-V"]);
+ let r = flags_from_vec(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 r = flags_from_vec(svec!["deno", "run", "-r", "script.ts"]);
let flags = r.unwrap();
assert_eq!(
flags,
@@ -1824,7 +1845,7 @@ mod tests {
#[test]
fn run_watch() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--unstable",
@@ -1847,13 +1868,8 @@ mod tests {
#[test]
fn run_reload_allow_write() {
- let r = flags_from_vec_safe(svec![
- "deno",
- "run",
- "-r",
- "--allow-write",
- "script.ts"
- ]);
+ let r =
+ flags_from_vec(svec!["deno", "run", "-r", "--allow-write", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -1869,7 +1885,7 @@ mod tests {
#[test]
fn run_v8_flags() {
- let r = flags_from_vec_safe(svec!["deno", "run", "--v8-flags=--help"]);
+ let r = flags_from_vec(svec!["deno", "run", "--v8-flags=--help"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -1881,7 +1897,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--v8-flags=--expose-gc,--gc-stats=1",
@@ -1901,7 +1917,7 @@ mod tests {
#[test]
fn script_args() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net",
@@ -1924,7 +1940,7 @@ mod tests {
#[test]
fn allow_all() {
- let r = flags_from_vec_safe(svec!["deno", "run", "--allow-all", "gist.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--allow-all", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -1945,8 +1961,7 @@ mod tests {
#[test]
fn allow_read() {
- let r =
- flags_from_vec_safe(svec!["deno", "run", "--allow-read", "gist.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--allow-read", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -1961,8 +1976,7 @@ mod tests {
#[test]
fn allow_hrtime() {
- let r =
- flags_from_vec_safe(svec!["deno", "run", "--allow-hrtime", "gist.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--allow-hrtime", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -1980,7 +1994,7 @@ mod tests {
// 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_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--allow-write",
@@ -2004,8 +2018,7 @@ mod tests {
#[test]
fn fmt() {
- let r =
- flags_from_vec_safe(svec!["deno", "fmt", "script_1.ts", "script_2.ts"]);
+ let r = flags_from_vec(svec!["deno", "fmt", "script_1.ts", "script_2.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2021,7 +2034,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "fmt", "--check"]);
+ let r = flags_from_vec(svec!["deno", "fmt", "--check"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2034,7 +2047,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "fmt"]);
+ let r = flags_from_vec(svec!["deno", "fmt"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2047,7 +2060,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "fmt", "--watch", "--unstable"]);
+ let r = flags_from_vec(svec!["deno", "fmt", "--watch", "--unstable"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2062,7 +2075,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"fmt",
"--check",
@@ -2088,7 +2101,7 @@ mod tests {
#[test]
fn language_server() {
- let r = flags_from_vec_safe(svec!["deno", "lsp"]);
+ let r = flags_from_vec(svec!["deno", "lsp"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2100,7 +2113,7 @@ mod tests {
#[test]
fn lint() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"lint",
"--unstable",
@@ -2124,7 +2137,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"lint",
"--unstable",
@@ -2147,7 +2160,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "lint", "--unstable", "--rules"]);
+ let r = flags_from_vec(svec!["deno", "lint", "--unstable", "--rules"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2162,7 +2175,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"lint",
"--unstable",
@@ -2186,7 +2199,7 @@ mod tests {
#[test]
fn types() {
- let r = flags_from_vec_safe(svec!["deno", "types"]);
+ let r = flags_from_vec(svec!["deno", "types"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2198,7 +2211,7 @@ mod tests {
#[test]
fn cache() {
- let r = flags_from_vec_safe(svec!["deno", "cache", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "cache", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2212,7 +2225,7 @@ mod tests {
#[test]
fn info() {
- let r = flags_from_vec_safe(svec!["deno", "info", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "info", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2224,7 +2237,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "info", "--reload", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "info", "--reload", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2237,7 +2250,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "info", "--json", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "info", "--json", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2249,7 +2262,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "info"]);
+ let r = flags_from_vec(svec!["deno", "info"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2261,7 +2274,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "info", "--json"]);
+ let r = flags_from_vec(svec!["deno", "info", "--json"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2276,13 +2289,8 @@ mod tests {
#[test]
fn tsconfig() {
- let r = flags_from_vec_safe(svec![
- "deno",
- "run",
- "-c",
- "tsconfig.json",
- "script.ts"
- ]);
+ let r =
+ flags_from_vec(svec!["deno", "run", "-c", "tsconfig.json", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2297,8 +2305,7 @@ mod tests {
#[test]
fn eval() {
- let r =
- flags_from_vec_safe(svec!["deno", "eval", "'console.log(\"hello\")'"]);
+ let r = flags_from_vec(svec!["deno", "eval", "'console.log(\"hello\")'"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2321,7 +2328,7 @@ mod tests {
#[test]
fn eval_p() {
- let r = flags_from_vec_safe(svec!["deno", "eval", "-p", "1+2"]);
+ let r = flags_from_vec(svec!["deno", "eval", "-p", "1+2"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2344,12 +2351,8 @@ mod tests {
#[test]
fn eval_typescript() {
- let r = flags_from_vec_safe(svec![
- "deno",
- "eval",
- "-T",
- "'console.log(\"hello\")'"
- ]);
+ let r =
+ flags_from_vec(svec!["deno", "eval", "-T", "'console.log(\"hello\")'"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2373,7 +2376,7 @@ mod tests {
#[test]
fn eval_with_flags() {
#[rustfmt::skip]
- let r = flags_from_vec_safe(svec!["deno", "eval", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "42"]);
+ let r = flags_from_vec(svec!["deno", "eval", "--unstable", "--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 {
@@ -2392,6 +2395,7 @@ mod tests {
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()),
@@ -2409,7 +2413,7 @@ mod tests {
#[test]
fn eval_args() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"eval",
"console.log(Deno.args)",
@@ -2439,7 +2443,7 @@ mod tests {
#[test]
fn repl() {
- let r = flags_from_vec_safe(svec!["deno"]);
+ let r = flags_from_vec(svec!["deno"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2460,7 +2464,7 @@ mod tests {
#[test]
fn repl_with_flags() {
#[rustfmt::skip]
- let r = flags_from_vec_safe(svec!["deno", "repl", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229"]);
+ let r = flags_from_vec(svec!["deno", "repl", "--unstable", "--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"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2476,6 +2480,7 @@ mod tests {
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()),
@@ -2496,7 +2501,7 @@ mod tests {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
format!("--allow-read=.,{}", temp_dir.to_str().unwrap()),
@@ -2519,7 +2524,7 @@ mod tests {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
format!("--allow-write=.,{}", temp_dir.to_str().unwrap()),
@@ -2539,7 +2544,7 @@ mod tests {
#[test]
fn allow_net_allowlist() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net=127.0.0.1",
@@ -2559,7 +2564,7 @@ mod tests {
#[test]
fn bundle() {
- let r = flags_from_vec_safe(svec!["deno", "bundle", "source.ts"]);
+ let r = flags_from_vec(svec!["deno", "bundle", "source.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2574,7 +2579,7 @@ mod tests {
#[test]
fn bundle_with_config() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"bundle",
"--no-remote",
@@ -2600,8 +2605,7 @@ mod tests {
#[test]
fn bundle_with_output() {
- let r =
- flags_from_vec_safe(svec!["deno", "bundle", "source.ts", "bundle.js"]);
+ let r = flags_from_vec(svec!["deno", "bundle", "source.ts", "bundle.js"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2617,7 +2621,7 @@ mod tests {
#[test]
fn bundle_with_lock() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"bundle",
"--lock-write",
@@ -2640,8 +2644,7 @@ mod tests {
#[test]
fn bundle_with_reload() {
- let r =
- flags_from_vec_safe(svec!["deno", "bundle", "--reload", "source.ts"]);
+ let r = flags_from_vec(svec!["deno", "bundle", "--reload", "source.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2657,9 +2660,8 @@ mod tests {
#[test]
fn bundle_nocheck() {
- let r =
- flags_from_vec_safe(svec!["deno", "bundle", "--no-check", "script.ts"])
- .unwrap();
+ let r = flags_from_vec(svec!["deno", "bundle", "--no-check", "script.ts"])
+ .unwrap();
assert_eq!(
r,
Flags {
@@ -2675,7 +2677,7 @@ mod tests {
#[test]
fn bundle_watch() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"bundle",
"--watch",
@@ -2698,7 +2700,7 @@ mod tests {
#[test]
fn run_import_map() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--unstable",
@@ -2720,7 +2722,7 @@ mod tests {
#[test]
fn info_import_map() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"info",
"--unstable",
@@ -2743,7 +2745,7 @@ mod tests {
#[test]
fn cache_import_map() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"cache",
"--unstable",
@@ -2765,7 +2767,7 @@ mod tests {
#[test]
fn doc_import_map() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"doc",
"--unstable",
@@ -2791,7 +2793,7 @@ mod tests {
#[test]
fn cache_multiple() {
let r =
- flags_from_vec_safe(svec!["deno", "cache", "script.ts", "script_two.ts"]);
+ flags_from_vec(svec!["deno", "cache", "script.ts", "script_two.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2805,8 +2807,7 @@ mod tests {
#[test]
fn run_seed() {
- let r =
- flags_from_vec_safe(svec!["deno", "run", "--seed", "250", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--seed", "250", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2822,7 +2823,7 @@ mod tests {
#[test]
fn run_seed_with_v8_flags() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--seed",
@@ -2845,7 +2846,7 @@ mod tests {
#[test]
fn install() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"install",
"https://deno.land/std/examples/colors.ts"
@@ -2868,7 +2869,7 @@ mod tests {
#[test]
fn install_with_flags() {
#[rustfmt::skip]
- let r = flags_from_vec_safe(svec!["deno", "install", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--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"]);
+ let r = flags_from_vec(svec!["deno", "install", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--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 {
@@ -2901,12 +2902,8 @@ mod tests {
#[test]
fn log_level() {
- let r = flags_from_vec_safe(svec![
- "deno",
- "run",
- "--log-level=debug",
- "script.ts"
- ]);
+ let r =
+ flags_from_vec(svec!["deno", "run", "--log-level=debug", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2921,7 +2918,7 @@ mod tests {
#[test]
fn quiet() {
- let r = flags_from_vec_safe(svec!["deno", "run", "-q", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "-q", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2936,7 +2933,7 @@ mod tests {
#[test]
fn completions() {
- let r = flags_from_vec_safe(svec!["deno", "completions", "zsh"]).unwrap();
+ let r = flags_from_vec(svec!["deno", "completions", "zsh"]).unwrap();
match r.subcommand {
DenoSubcommand::Completions { buf } => assert!(!buf.is_empty()),
@@ -2946,7 +2943,7 @@ mod tests {
#[test]
fn run_with_args() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"script.ts",
@@ -2963,9 +2960,11 @@ mod tests {
..Flags::default()
}
);
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
+ "--location",
+ "https:foo",
"--allow-read",
"script.ts",
"--allow-net",
@@ -2980,14 +2979,14 @@ mod tests {
subcommand: DenoSubcommand::Run {
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_safe(svec!["deno", "run", "script.ts", "foo", "bar"]);
+ let r = flags_from_vec(svec!["deno", "run", "script.ts", "foo", "bar"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -2998,7 +2997,7 @@ mod tests {
..Flags::default()
}
);
- let r = flags_from_vec_safe(svec!["deno", "run", "script.ts", "-"]);
+ let r = flags_from_vec(svec!["deno", "run", "script.ts", "-"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3011,7 +3010,7 @@ mod tests {
);
let r =
- flags_from_vec_safe(svec!["deno", "run", "script.ts", "-", "foo", "bar"]);
+ flags_from_vec(svec!["deno", "run", "script.ts", "-", "foo", "bar"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3026,8 +3025,7 @@ mod tests {
#[test]
fn no_check() {
- let r =
- flags_from_vec_safe(svec!["deno", "run", "--no-check", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--no-check", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3042,8 +3040,7 @@ mod tests {
#[test]
fn no_remote() {
- let r =
- flags_from_vec_safe(svec!["deno", "run", "--no-remote", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--no-remote", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3058,8 +3055,7 @@ mod tests {
#[test]
fn cached_only() {
- let r =
- flags_from_vec_safe(svec!["deno", "run", "--cached-only", "script.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "--cached-only", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3074,7 +3070,7 @@ mod tests {
#[test]
fn allow_net_allowlist_with_ports() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net=deno.land,:8000,:4545",
@@ -3102,7 +3098,7 @@ mod tests {
#[test]
fn allow_net_allowlist_with_ipv6_address() {
- let r = flags_from_vec_safe(svec![
+ 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",
@@ -3133,7 +3129,7 @@ mod tests {
#[test]
fn lock_write() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--lock-write",
@@ -3156,7 +3152,7 @@ mod tests {
#[test]
fn test_with_flags() {
#[rustfmt::skip]
- let r = flags_from_vec_safe(svec!["deno", "test", "--unstable", "--no-run", "--filter", "- foo", "--coverage=cov", "--allow-net", "--allow-none", "dir1/", "dir2/", "--", "arg1", "arg2"]);
+ let r = flags_from_vec(svec!["deno", "test", "--unstable", "--no-run", "--filter", "- foo", "--coverage=cov", "--location", "https:foo", "--allow-net", "--allow-none", "dir1/", "dir2/", "--", "arg1", "arg2"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3170,6 +3166,7 @@ mod tests {
},
unstable: true,
coverage_dir: Some("cov".to_string()),
+ location: Some(Url::parse("https://foo/").unwrap()),
allow_net: Some(vec![]),
argv: svec!["arg1", "arg2"],
..Flags::default()
@@ -3179,7 +3176,7 @@ mod tests {
#[test]
fn run_with_cafile() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"run",
"--cert",
@@ -3200,7 +3197,7 @@ mod tests {
#[test]
fn bundle_with_cafile() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"bundle",
"--cert",
@@ -3222,8 +3219,7 @@ mod tests {
#[test]
fn upgrade_with_ca_file() {
- let r =
- flags_from_vec_safe(svec!["deno", "upgrade", "--cert", "example.crt"]);
+ let r = flags_from_vec(svec!["deno", "upgrade", "--cert", "example.crt"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3243,7 +3239,7 @@ mod tests {
#[test]
fn cache_with_cafile() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"cache",
"--cert",
@@ -3265,7 +3261,7 @@ mod tests {
#[test]
fn info_with_cafile() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"info",
"--cert",
@@ -3287,8 +3283,7 @@ mod tests {
#[test]
fn doc() {
- let r =
- flags_from_vec_safe(svec!["deno", "doc", "--json", "path/to/module.ts"]);
+ let r = flags_from_vec(svec!["deno", "doc", "--json", "path/to/module.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3302,7 +3297,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"doc",
"path/to/module.ts",
@@ -3321,7 +3316,7 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec!["deno", "doc"]);
+ let r = flags_from_vec(svec!["deno", "doc"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3335,8 +3330,7 @@ mod tests {
}
);
- let r =
- flags_from_vec_safe(svec!["deno", "doc", "--builtin", "Deno.Listener"]);
+ let r = flags_from_vec(svec!["deno", "doc", "--builtin", "Deno.Listener"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3350,12 +3344,8 @@ mod tests {
}
);
- let r = flags_from_vec_safe(svec![
- "deno",
- "doc",
- "--private",
- "path/to/module.js"
- ]);
+ let r =
+ flags_from_vec(svec!["deno", "doc", "--private", "path/to/module.js"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3372,7 +3362,7 @@ mod tests {
#[test]
fn inspect_default_host() {
- let r = flags_from_vec_safe(svec!["deno", "run", "--inspect", "foo.js"]);
+ let r = flags_from_vec(svec!["deno", "run", "--inspect", "foo.js"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -3387,7 +3377,7 @@ mod tests {
#[test]
fn compile() {
- let r = flags_from_vec_safe(svec![
+ let r = flags_from_vec(svec![
"deno",
"compile",
"https://deno.land/std/examples/colors.ts"
@@ -3408,7 +3398,7 @@ mod tests {
#[test]
fn compile_with_flags() {
#[rustfmt::skip]
- let r = flags_from_vec_safe(svec!["deno", "compile", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--output", "colors", "https://deno.land/std/examples/colors.ts", "foo", "bar"]);
+ let r = flags_from_vec(svec!["deno", "compile", "--unstable", "--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", "--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 {
@@ -3427,6 +3417,7 @@ mod tests {
lock_write: true,
ca_file: Some("example.crt".to_string()),
cached_only: true,
+ location: Some(Url::parse("https://foo/").unwrap()),
allow_read: Some(vec![]),
allow_net: Some(vec![]),
v8_flags: svec!["--help", "--random-seed=1"],
diff --git a/cli/main.rs b/cli/main.rs
index 8210eb5c7..066991624 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -204,6 +204,7 @@ pub fn create_main_worker(
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
get_error_class_fn: Some(&crate::errors::get_error_class_name),
+ location: program_state.flags.location.clone(),
};
let mut worker = MainWorker::from_options(main_module, permissions, &options);
@@ -1223,6 +1224,21 @@ fn get_subcommand(
}
}
+fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
+ match result {
+ Ok(value) => value,
+ Err(error) => {
+ let msg = format!(
+ "{}: {}",
+ colors::red_bold("error"),
+ error.to_string().trim()
+ );
+ eprintln!("{}", msg);
+ std::process::exit(1);
+ }
+ }
+}
+
pub fn main() {
#[cfg(windows)]
colors::enable_ansi(); // For Windows 10
@@ -1233,16 +1249,12 @@ pub fn main() {
std::process::exit(1);
}
- let flags = flags::flags_from_vec(args);
+ let flags =
+ unwrap_or_exit(flags::flags_from_vec(args).map_err(AnyError::from));
if !flags.v8_flags.is_empty() {
init_v8_flags(&*flags.v8_flags);
}
init_logger(flags.log_level);
- let subcommand_future = get_subcommand(flags);
- let result = tokio_util::run_basic(subcommand_future);
- if let Err(err) = result {
- eprintln!("{}: {}", colors::red_bold("error"), err.to_string());
- std::process::exit(1);
- }
+ unwrap_or_exit(tokio_util::run_basic(get_subcommand(flags)));
}
diff --git a/cli/standalone.rs b/cli/standalone.rs
index 8379358a0..8d95d30f2 100644
--- a/cli/standalone.rs
+++ b/cli/standalone.rs
@@ -167,7 +167,7 @@ async fn run(source_code: String, metadata: Metadata) -> Result<(), AnyError> {
// TODO(nayeemrmn): Unify this Flags -> WorkerOptions mapping with `deno run`.
let options = WorkerOptions {
apply_source_maps: false,
- args: flags.argv.clone(),
+ args: flags.argv,
debug_flag: flags.log_level.map_or(false, |l| l == log::Level::Debug),
user_agent: crate::http_util::get_user_agent(),
unstable: flags.unstable,
@@ -183,6 +183,7 @@ async fn run(source_code: String, metadata: Metadata) -> Result<(), AnyError> {
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
get_error_class_fn: Some(&crate::errors::get_error_class_name),
+ location: flags.location,
};
let mut worker =
MainWorker::from_options(main_module.clone(), permissions, &options);
@@ -297,6 +298,7 @@ pub fn compile_to_runtime_flags(
import_map_path: None,
inspect: None,
inspect_brk: None,
+ location: flags.location,
lock: None,
lock_write: false,
log_level: flags.log_level,
diff --git a/cli/tests/070_location.ts b/cli/tests/070_location.ts
new file mode 100644
index 000000000..62fd34af2
--- /dev/null
+++ b/cli/tests/070_location.ts
@@ -0,0 +1,10 @@
+// TODO(nayeemrmn): Add `Location` and `location` to `dlint`'s globals.
+// deno-lint-ignore-file no-undef
+console.log(Location);
+console.log(Location.prototype);
+console.log(location);
+try {
+ location.hostname = "bar";
+} catch (error) {
+ console.log(error);
+}
diff --git a/cli/tests/070_location.ts.out b/cli/tests/070_location.ts.out
new file mode 100644
index 000000000..66d470b6f
--- /dev/null
+++ b/cli/tests/070_location.ts.out
@@ -0,0 +1,22 @@
+[WILDCARD][Function: Location]
+Location { [Symbol(Symbol.toStringTag)]: "Location" }
+Location {
+ hash: [Getter/Setter],
+ host: [Getter/Setter],
+ hostname: [Getter/Setter],
+ href: [Getter/Setter],
+ origin: [Getter],
+ password: [Getter/Setter],
+ pathname: [Getter/Setter],
+ port: [Getter/Setter],
+ protocol: [Getter/Setter],
+ search: [Getter/Setter],
+ username: [Getter/Setter],
+ ancestorOrigins: [Getter],
+ assign: [Function: assign],
+ reload: [Function: reload],
+ replace: [Function: replace],
+ toString: [Function: toString]
+}
+NotSupportedError: Cannot set "location.hostname".
+[WILDCARD]
diff --git a/cli/tests/071_location_unset.ts b/cli/tests/071_location_unset.ts
new file mode 100644
index 000000000..5c0518940
--- /dev/null
+++ b/cli/tests/071_location_unset.ts
@@ -0,0 +1,5 @@
+// TODO(nayeemrmn): Add `Location` and `location` to `dlint`'s globals.
+// deno-lint-ignore-file no-undef
+console.log(Location);
+console.log(Location.prototype);
+console.log(location);
diff --git a/cli/tests/071_location_unset.ts.out b/cli/tests/071_location_unset.ts.out
new file mode 100644
index 000000000..2c030a773
--- /dev/null
+++ b/cli/tests/071_location_unset.ts.out
@@ -0,0 +1,4 @@
+[WILDCARD][Function: Location]
+Location { [Symbol(Symbol.toStringTag)]: "Location" }
+error: Uncaught ReferenceError: Access to "location", run again with --location <href>.
+[WILDCARD]
diff --git a/cli/tests/072_location_relative_fetch.ts b/cli/tests/072_location_relative_fetch.ts
new file mode 100644
index 000000000..d4764bf7f
--- /dev/null
+++ b/cli/tests/072_location_relative_fetch.ts
@@ -0,0 +1,2 @@
+const response = await fetch("fetch/hello.txt");
+console.log(await response.text());
diff --git a/cli/tests/072_location_relative_fetch.ts.out b/cli/tests/072_location_relative_fetch.ts.out
new file mode 100644
index 000000000..8151f6f88
--- /dev/null
+++ b/cli/tests/072_location_relative_fetch.ts.out
@@ -0,0 +1,2 @@
+[WILDCARD]Hello, world!
+
diff --git a/cli/tests/077_fetch_empty.ts b/cli/tests/077_fetch_empty.ts
new file mode 100644
index 000000000..b10a9094e
--- /dev/null
+++ b/cli/tests/077_fetch_empty.ts
@@ -0,0 +1 @@
+await fetch("");
diff --git a/cli/tests/077_fetch_empty.ts.out b/cli/tests/077_fetch_empty.ts.out
new file mode 100644
index 000000000..9dfccf10c
--- /dev/null
+++ b/cli/tests/077_fetch_empty.ts.out
@@ -0,0 +1,2 @@
+[WILDCARD]error: Uncaught (in promise) URIError: relative URL without a base
+[WILDCARD]
diff --git a/cli/tests/complex_permissions_test.ts b/cli/tests/complex_permissions_test.ts
index fba761a2c..002d33540 100644
--- a/cli/tests/complex_permissions_test.ts
+++ b/cli/tests/complex_permissions_test.ts
@@ -10,8 +10,8 @@ const test: { [key: string]: (...args: any[]) => void | Promise<void> } = {
Deno.writeFileSync(file, new Uint8Array(0), { append: true })
);
},
- netFetch(hosts: string[]): void {
- hosts.forEach((host) => fetch(host));
+ netFetch(urls: string[]): void {
+ urls.forEach((url) => fetch(url));
},
netListen(endpoints: string[]): void {
endpoints.forEach((endpoint) => {
diff --git a/cli/tests/fetch/hello.txt b/cli/tests/fetch/hello.txt
new file mode 100644
index 000000000..af5626b4a
--- /dev/null
+++ b/cli/tests/fetch/hello.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs
index 68cfe0b50..aabeb1f77 100644
--- a/cli/tests/integration_tests.rs
+++ b/cli/tests/integration_tests.rs
@@ -1246,7 +1246,7 @@ fn bundle_import_map_no_check() {
.current_dir(util::root_path())
.arg("bundle")
.arg("--no-check")
- .arg("--importmap")
+ .arg("--import-map")
.arg(import_map_path)
.arg("--unstable")
.arg(import)
@@ -1689,7 +1689,7 @@ fn repl_test_pty_bad_input() {
#[test]
#[ignore]
-fn run_watch_with_importmap_and_relative_paths() {
+fn run_watch_with_import_map_and_relative_paths() {
fn create_relative_tmp_file(
directory: &TempDir,
filename: &'static str,
@@ -1722,7 +1722,7 @@ fn run_watch_with_importmap_and_relative_paths() {
.arg("run")
.arg("--unstable")
.arg("--watch")
- .arg("--importmap")
+ .arg("--import-map")
.arg(&import_map_path)
.arg(&file_to_watch)
.env("NO_COLOR", "1")
@@ -2307,6 +2307,8 @@ fn workers() {
.current_dir(util::tests_path())
.arg("test")
.arg("--reload")
+ .arg("--location")
+ .arg("http://127.0.0.1:4545/cli/tests/")
.arg("--allow-net")
.arg("--allow-read")
.arg("--unstable")
@@ -2548,6 +2550,23 @@ itest!(_067_test_no_run_type_error {
exit_code: 1,
});
+itest!(_070_location {
+ args: "run --location https://foo/bar?baz#bat 070_location.ts",
+ output: "070_location.ts.out",
+});
+
+itest!(_071_location_unset {
+ args: "run 071_location_unset.ts",
+ output: "071_location_unset.ts.out",
+ exit_code: 1,
+});
+
+itest!(_072_location_relative_fetch {
+ args: "run --location http://127.0.0.1:4545/cli/tests/ --allow-net 072_location_relative_fetch.ts",
+ output: "072_location_relative_fetch.ts.out",
+ http_server: true,
+});
+
itest!(_073_worker_error {
args: "run -A 073_worker_error.ts",
output: "073_worker_error.ts.out",
@@ -2570,6 +2589,12 @@ itest!(_076_info_json_deps_order {
output: "076_info_json_deps_order.out",
});
+itest!(_077_fetch_empty {
+ args: "run -A 077_fetch_empty.ts",
+ output: "077_fetch_empty.ts.out",
+ exit_code: 1,
+});
+
itest!(js_import_detect {
args: "run --quiet --reload js_import_detect.ts",
output: "js_import_detect.ts.out",
@@ -5200,16 +5225,14 @@ fn web_platform_tests() {
.tempfile()
.unwrap();
- let bundle = concat_bundle(
- files,
- file.path(),
- format!("window.location = {{search: \"{}\"}};\n", variant),
- );
+ let bundle = concat_bundle(files, file.path(), "".to_string());
file.write_all(bundle.as_bytes()).unwrap();
let child = util::deno_cmd()
.current_dir(test_file_path.parent().unwrap())
.arg("run")
+ .arg("--location")
+ .arg(&format!("http://web-platform-tests/?{}", variant))
.arg("-A")
.arg(file.path())
.arg(deno_core::serde_json::to_string(&expect_fail).unwrap())
diff --git a/cli/tests/subdir/worker_location.ts b/cli/tests/subdir/worker_location.ts
new file mode 100644
index 000000000..480032350
--- /dev/null
+++ b/cli/tests/subdir/worker_location.ts
@@ -0,0 +1,4 @@
+onmessage = function (): void {
+ postMessage(self.location.href);
+ close();
+};
diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts
index e5389d024..6945b2e2a 100644
--- a/cli/tests/unit/fetch_test.ts
+++ b/cli/tests/unit/fetch_test.ts
@@ -221,17 +221,6 @@ unitTest({ perms: { net: true } }, async function responseClone(): Promise<
}
});
-unitTest({ perms: { net: true } }, async function fetchEmptyInvalid(): Promise<
- void
-> {
- await assertThrowsAsync(
- async () => {
- await fetch("");
- },
- URIError,
- );
-});
-
unitTest(
{ perms: { net: true } },
async function fetchMultipartFormDataSuccess(): Promise<void> {
diff --git a/cli/tests/unit/request_test.ts b/cli/tests/unit/request_test.ts
index 8132e0184..da6a0e15b 100644
--- a/cli/tests/unit/request_test.ts
+++ b/cli/tests/unit/request_test.ts
@@ -1,5 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertThrows, unitTest } from "./test_util.ts";
+import { assert, assertEquals, unitTest } from "./test_util.ts";
unitTest(function fromInit(): void {
const req = new Request("http://foo/", {
@@ -46,8 +46,10 @@ unitTest(function methodNonString(): void {
});
unitTest(function requestRelativeUrl(): void {
- // TODO(nayeemrmn): Base from `--location` when implemented and set.
- assertThrows(() => new Request("relative-url"), TypeError, "Invalid URL.");
+ assertEquals(
+ new Request("relative-url").url,
+ "http://js-unit-tests/foo/relative-url",
+ );
});
unitTest(async function cloneRequestBodyStream(): Promise<void> {
diff --git a/cli/tests/unit/unit_test_runner.ts b/cli/tests/unit/unit_test_runner.ts
index 35a691ebd..1f347ec9a 100755
--- a/cli/tests/unit/unit_test_runner.ts
+++ b/cli/tests/unit/unit_test_runner.ts
@@ -97,6 +97,7 @@ function spawnWorkerRunner(
Deno.execPath(),
"run",
"--unstable", // TODO(ry) be able to test stable vs unstable
+ "--location=http://js-unit-tests/foo/bar",
"-A",
"cli/tests/unit/unit_test_runner.ts",
"--worker",
diff --git a/cli/tests/workers_test.ts b/cli/tests/workers_test.ts
index c35ea72f5..9cbc864bd 100644
--- a/cli/tests/workers_test.ts
+++ b/cli/tests/workers_test.ts
@@ -614,3 +614,41 @@ Deno.test("Worker with disabled permissions", async function () {
await promise;
worker.terminate();
});
+
+Deno.test({
+ name: "worker location",
+ fn: async function (): Promise<void> {
+ const promise = deferred();
+ const workerModuleHref =
+ new URL("subdir/worker_location.ts", import.meta.url).href;
+ const w = new Worker(workerModuleHref, { type: "module" });
+ w.onmessage = (e): void => {
+ assertEquals(e.data, workerModuleHref);
+ promise.resolve();
+ };
+ w.postMessage("Hello, world!");
+ await promise;
+ w.terminate();
+ },
+});
+
+Deno.test({
+ name: "worker with relative specifier",
+ fn: async function (): Promise<void> {
+ // TODO(nayeemrmn): Add `Location` and `location` to `dlint`'s globals.
+ // deno-lint-ignore no-undef
+ assertEquals(location.href, "http://127.0.0.1:4545/cli/tests/");
+ const promise = deferred();
+ const w = new Worker(
+ "./workers/test_worker.ts",
+ { type: "module", name: "tsWorker" },
+ );
+ w.onmessage = (e): void => {
+ assertEquals(e.data, "Hello, world!");
+ promise.resolve();
+ };
+ w.postMessage("Hello, world!");
+ await promise;
+ w.terminate();
+ },
+});
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs
index f6eb33112..e04763172 100644
--- a/cli/tools/installer.rs
+++ b/cli/tools/installer.rs
@@ -202,6 +202,10 @@ pub fn install(
let mut executable_args = vec!["run".to_string()];
executable_args.extend_from_slice(&flags.to_permission_args());
+ if let Some(url) = flags.location.as_ref() {
+ executable_args.push("--location".to_string());
+ executable_args.push(url.to_string());
+ }
if let Some(ca_file) = flags.ca_file {
executable_args.push("--cert".to_string());
executable_args.push(ca_file)
diff --git a/docs/runtime/location_api.md b/docs/runtime/location_api.md
new file mode 100644
index 000000000..6e7341828
--- /dev/null
+++ b/docs/runtime/location_api.md
@@ -0,0 +1,76 @@
+## Location API
+
+Deno supports the
+[`location`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location)
+global from the web. Please read on.
+
+### Location flag
+
+There is no "web page" whose URL we can use for a location in a Deno process. We
+instead allow users to emulate a document location by specifying one on the CLI
+using the `--location` flag. It can be a `http` or `https` URL.
+
+```ts
+// deno run --location https://example.com/path main.ts
+
+console.log(location.href);
+// "https://example.com/path"
+```
+
+You must pass `--location <href>` for this to work. If you don't, any access to
+the `location` global will throw an error.
+
+```ts
+// deno run main.ts
+
+console.log(location.href);
+// error: Uncaught ReferenceError: Access to "location", run again with --location <href>.
+```
+
+Setting `location` or any of its fields will normally cause navigation in
+browsers. This is not applicable in Deno, so it will throw in this situation.
+
+```ts
+// deno run --location https://example.com/path main.ts
+
+location.pathname = "./foo";
+// error: Uncaught NotSupportedError: Cannot set "location.pathname".
+```
+
+### Extended usage
+
+On the web, resource resolution (excluding modules) typically uses the value of
+`location.href` as the root on which to base any relative URLs. This affects
+some web APIs adopted by Deno.
+
+#### Fetch API
+
+```ts
+// deno run --location https://api.github.com/ --allow-net main.ts
+
+const response = await fetch("./orgs/denoland");
+// Fetches "https://api.github.com/orgs/denoland".
+```
+
+The `fetch()` call above would throw if the `--location` flag was not passed,
+since there is no web-analogous location to base it onto.
+
+#### Worker modules
+
+```ts
+// deno run --location https://example.com/index.html --allow-net main.ts
+
+const worker = new Worker("./workers/hello.ts", { type: "module" });
+// Fetches worker module at "https://example.com/workers/hello.ts".
+```
+
+### Only use if necessary
+
+For the above use cases, it is preferable to pass URLs in full rather than
+relying on `--location`. You can manually base a relative URL using the `URL`
+constructor if needed.
+
+The `--location` flag is intended for those who have some specific purpose in
+mind for emulating a document location and are aware that this will only work at
+application-level. However, you may also use it to silence errors from a
+dependency which is frivolously accessing the `location` global.
diff --git a/docs/runtime/workers.md b/docs/runtime/workers.md
index 14e028705..82e1e5b2d 100644
--- a/docs/runtime/workers.md
+++ b/docs/runtime/workers.md
@@ -9,10 +9,11 @@ is run on a separate thread, dedicated only to that worker.
Currently Deno supports only `module` type workers; thus it's essential to pass
the `type: "module"` option when creating a new worker.
-Relative module specifiers are
-[not supported](https://github.com/denoland/deno/issues/5216) at the moment. You
-can instead use the `URL` constructor and `import.meta.url` to easily create a
-specifier for some nearby script.
+Use of relative module specifiers in the main worker are only supported with
+`--location <href>` passed on the CLI. This is not recommended for portability.
+You can instead use the `URL` contructor and `import.meta.url` to easily create
+a specifier for some nearby script. Dedicated workers, however, have a location
+and this capability by default.
```ts
// Good
diff --git a/docs/toc.json b/docs/toc.json
index df2c004c5..6d1896999 100644
--- a/docs/toc.json
+++ b/docs/toc.json
@@ -23,6 +23,7 @@
"permission_apis": "Permission APIs",
"compiler_apis": "Compiler APIs",
"web_platform_apis": "Web Platform APIs",
+ "location_api": "Location API",
"workers": "Workers"
}
},
diff --git a/op_crates/fetch/26_fetch.js b/op_crates/fetch/26_fetch.js
index 379c88e2f..0d405d4ec 100644
--- a/op_crates/fetch/26_fetch.js
+++ b/op_crates/fetch/26_fetch.js
@@ -5,6 +5,7 @@
// provided by "deno_web"
const { URLSearchParams } = window.__bootstrap.url;
+ const { getLocationHref } = window.__bootstrap.location;
const { requiredArguments } = window.__bootstrap.fetchUtil;
const { ReadableStream, isReadableStreamDisturbed } =
@@ -987,8 +988,10 @@
this.credentials = input.credentials;
this._stream = input._stream;
} else {
- // TODO(nayeemrmn): Base from `--location` when implemented and set.
- this.url = new URL(String(input)).href;
+ const baseUrl = getLocationHref();
+ this.url = baseUrl != null
+ ? new URL(String(input), baseUrl).href
+ : new URL(String(input)).href;
}
if (init && "method" in init && init.method) {
@@ -1175,20 +1178,25 @@
}
}
+ let baseUrl = null;
+
+ function setBaseUrl(href) {
+ baseUrl = href;
+ }
+
function sendFetchReq(url, method, headers, body, clientRid) {
let headerArray = [];
if (headers) {
headerArray = Array.from(headers.entries());
}
- const args = {
+ return opFetch({
method,
url,
+ baseUrl,
headers: headerArray,
clientRid,
- };
-
- return opFetch(args, body);
+ }, body);
}
async function fetch(input, init) {
@@ -1385,6 +1393,7 @@
Blob,
DomFile,
FormData,
+ setBaseUrl,
fetch,
Request,
Response,
diff --git a/op_crates/fetch/lib.rs b/op_crates/fetch/lib.rs
index 91e44f75c..c2e458d89 100644
--- a/op_crates/fetch/lib.rs
+++ b/op_crates/fetch/lib.rs
@@ -100,12 +100,12 @@ where
struct FetchArgs {
method: Option<String>,
url: String,
+ base_url: Option<String>,
headers: Vec<(String, String)>,
client_rid: Option<u32>,
}
let args: FetchArgs = serde_json::from_value(args)?;
- let url = args.url;
let client = if let Some(rid) = args.client_rid {
let state_ = state.borrow();
@@ -125,10 +125,16 @@ where
None => Method::GET,
};
- let url_ = Url::parse(&url)?;
+ let base_url = match args.base_url {
+ Some(base_url) => Some(Url::parse(&base_url)?),
+ _ => None,
+ };
+ let url = Url::options()
+ .base_url(base_url.as_ref())
+ .parse(&args.url)?;
// Check scheme before asking for net permission
- let scheme = url_.scheme();
+ let scheme = url.scheme();
if scheme != "http" && scheme != "https" {
return Err(type_error(format!("scheme '{}' not supported", scheme)));
}
@@ -136,10 +142,10 @@ where
{
let state_ = state.borrow();
let permissions = state_.borrow::<FP>();
- permissions.check_net_url(&url_)?;
+ permissions.check_net_url(&url)?;
}
- let mut request = client.request(method, url_);
+ let mut request = client.request(method, url);
match data.len() {
0 => {}
diff --git a/op_crates/web/12_location.js b/op_crates/web/12_location.js
new file mode 100644
index 000000000..d56ccc1e4
--- /dev/null
+++ b/op_crates/web/12_location.js
@@ -0,0 +1,227 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+((window) => {
+ const { URL } = window.__bootstrap.url;
+ const locationConstructorKey = Symbol("locationConstuctorKey");
+
+ class Location {
+ constructor(href, key) {
+ if (key != locationConstructorKey) {
+ throw new TypeError("Illegal constructor.");
+ }
+ const url = new URL(href);
+ Object.defineProperties(this, {
+ hash: {
+ get() {
+ return url.hash;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.hash".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ host: {
+ get() {
+ return url.host;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.host".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ hostname: {
+ get() {
+ return url.hostname;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.hostname".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ href: {
+ get() {
+ return href;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.href".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ origin: {
+ get() {
+ return url.origin;
+ },
+ enumerable: true,
+ },
+ password: {
+ get() {
+ return url.password;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.password".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ pathname: {
+ get() {
+ return url.pathname;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.pathname".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ port: {
+ get() {
+ return url.port;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.port".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ protocol: {
+ get() {
+ return url.protocol;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.protocol".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ search: {
+ get() {
+ return url.search;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.search".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ username: {
+ get() {
+ return url.username;
+ },
+ set() {
+ throw new DOMException(
+ `Cannot set "location.username".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ ancestorOrigins: {
+ get() {
+ // TODO(nayeemrmn): Replace with a `DOMStringList` instance.
+ return {
+ length: 0,
+ item: () => null,
+ contains: () => false,
+ };
+ },
+ enumerable: true,
+ },
+ assign: {
+ value: function assign() {
+ throw new DOMException(
+ `Cannot call "location.assign()".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ reload: {
+ value: function reload() {
+ throw new DOMException(
+ `Cannot call "location.reload()".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ replace: {
+ value: function replace() {
+ throw new DOMException(
+ `Cannot call "location.replace()".`,
+ "NotSupportedError",
+ );
+ },
+ enumerable: true,
+ },
+ toString: {
+ value: function toString() {
+ return href;
+ },
+ enumerable: true,
+ },
+ });
+ }
+ }
+
+ Object.defineProperties(Location.prototype, {
+ [Symbol.toStringTag]: {
+ value: "Location",
+ configurable: true,
+ },
+ });
+
+ let location = null;
+
+ function setLocationHref(href) {
+ location = new Location(href, locationConstructorKey);
+ }
+
+ window.__bootstrap = (window.__bootstrap || {});
+ window.__bootstrap.location = {
+ locationConstructorDescriptor: {
+ value: Location,
+ configurable: true,
+ writable: true,
+ },
+ locationDescriptor: {
+ get() {
+ if (location == null) {
+ throw new ReferenceError(
+ `Access to "location", run again with --location <href>.`,
+ );
+ }
+ return location;
+ },
+ set() {
+ throw new DOMException(`Cannot set "location".`, "NotSupportedError");
+ },
+ enumerable: true,
+ },
+ setLocationHref,
+ getLocationHref() {
+ return location?.href;
+ },
+ };
+})(this);
diff --git a/op_crates/web/lib.deno_web.d.ts b/op_crates/web/lib.deno_web.d.ts
index 33d867753..491a0ee84 100644
--- a/op_crates/web/lib.deno_web.d.ts
+++ b/op_crates/web/lib.deno_web.d.ts
@@ -312,3 +312,69 @@ declare var FileReader: {
readonly EMPTY: number;
readonly LOADING: number;
};
+
+/** The location (URL) of the object it is linked to. Changes done on it are
+ * reflected on the object it relates to. Accessible via
+ * `globalThis.location`. */
+declare class Location {
+ constructor();
+ /** Returns a DOMStringList object listing the origins of the ancestor
+ * browsing contexts, from the parent browsing context to the top-level
+ * browsing context.
+ *
+ * Always empty in Deno. */
+ readonly ancestorOrigins: DOMStringList;
+ /** Returns the Location object's URL's fragment (includes leading "#" if non-empty).
+ *
+ * Cannot be set in Deno. */
+ hash: string;
+ /** Returns the Location object's URL's host and port (if different from the default port for the scheme).
+ *
+ * Cannot be set in Deno. */
+ host: string;
+ /** Returns the Location object's URL's host.
+ *
+ * Cannot be set in Deno. */
+ hostname: string;
+ /** Returns the Location object's URL.
+ *
+ * Cannot be set in Deno. */
+ href: string;
+ toString(): string;
+ /** Returns the Location object's URL's origin. */
+ readonly origin: string;
+ /** Returns the Location object's URL's path.
+ *
+ * Cannot be set in Deno. */
+ pathname: string;
+ /** Returns the Location object's URL's port.
+ *
+ * Cannot be set in Deno. */
+ port: string;
+ /** Returns the Location object's URL's scheme.
+ *
+ * Cannot be set in Deno. */
+ protocol: string;
+ /** Returns the Location object's URL's query (includes leading "?" if
+ * non-empty).
+ *
+ * Cannot be set in Deno. */
+ search: string;
+ /** Navigates to the given URL.
+ *
+ * Cannot be set in Deno. */
+ assign(url: string): void;
+ /** Reloads the current page.
+ *
+ * Disabled in Deno. */
+ reload(): void;
+ /** @deprecated */
+ reload(forcedReload: boolean): void;
+ /** Removes the current page from the session history and navigates to the
+ * given URL.
+ *
+ * Disabled in Deno. */
+ replace(url: string): void;
+}
+
+declare var location: Location;
diff --git a/op_crates/web/lib.rs b/op_crates/web/lib.rs
index 958d11177..33bb0a33f 100644
--- a/op_crates/web/lib.rs
+++ b/op_crates/web/lib.rs
@@ -62,6 +62,10 @@ pub fn init(isolate: &mut JsRuntime) {
),
("deno:op_crates/web/11_url.js", include_str!("11_url.js")),
(
+ "deno:op_crates/web/12_location.js",
+ include_str!("12_location.js"),
+ ),
+ (
"deno:op_crates/web/21_filereader.js",
include_str!("21_filereader.js"),
),
diff --git a/runtime/examples/hello_runtime.rs b/runtime/examples/hello_runtime.rs
index c93bbc90b..829b2d36c 100644
--- a/runtime/examples/hello_runtime.rs
+++ b/runtime/examples/hello_runtime.rs
@@ -39,6 +39,7 @@ async fn main() -> Result<(), AnyError> {
ts_version: "x".to_string(),
no_color: false,
get_error_class_fn: Some(&get_error_class_name),
+ location: None,
};
let js_path =
diff --git a/runtime/js/11_workers.js b/runtime/js/11_workers.js
index 4989cd4b5..57f420728 100644
--- a/runtime/js/11_workers.js
+++ b/runtime/js/11_workers.js
@@ -3,6 +3,7 @@
((window) => {
const core = window.Deno.core;
const { Window } = window.__bootstrap.globalInterfaces;
+ const { getLocationHref } = window.__bootstrap.location;
const { log, pathFromURL } = window.__bootstrap.util;
const { defineEventHandler } = window.__bootstrap.webUtil;
const build = window.__bootstrap.build.build;
@@ -127,6 +128,7 @@
constructor(specifier, options = {}) {
super();
+ specifier = String(specifier);
const {
deno = {},
name = "unknown",
@@ -177,6 +179,16 @@
const hasSourceCode = false;
const sourceCode = decoder.decode(new Uint8Array());
+ if (
+ specifier.startsWith("./") || specifier.startsWith("../") ||
+ specifier.startsWith("/") || type == "classic"
+ ) {
+ const baseUrl = getLocationHref();
+ if (baseUrl != null) {
+ specifier = new URL(specifier, baseUrl).href;
+ }
+ }
+
const { id } = createWorker(
specifier,
hasSourceCode,
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index f38d51936..284bef48c 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -9,6 +9,7 @@ delete Object.prototype.__proto__;
const util = window.__bootstrap.util;
const eventTarget = window.__bootstrap.eventTarget;
const globalInterfaces = window.__bootstrap.globalInterfaces;
+ const location = window.__bootstrap.location;
const dispatchMinimal = window.__bootstrap.dispatchMinimal;
const build = window.__bootstrap.build;
const version = window.__bootstrap.version;
@@ -196,6 +197,8 @@ delete Object.prototype.__proto__;
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
+ Location: location.locationConstructorDescriptor,
+ location: location.locationDescriptor,
Blob: util.nonEnumerable(fetch.Blob),
ByteLengthQueuingStrategy: util.nonEnumerable(
streams.ByteLengthQueuingStrategy,
@@ -290,7 +293,19 @@ delete Object.prototype.__proto__;
defineEventHandler(window, "unload", null);
runtimeStart(runtimeOptions);
- const { args, noColor, pid, ppid, unstableFlag } = runtimeOptions;
+ const {
+ args,
+ location: locationHref,
+ noColor,
+ pid,
+ ppid,
+ unstableFlag,
+ } = runtimeOptions;
+
+ if (locationHref != null) {
+ location.setLocationHref(locationHref);
+ fetch.setBaseUrl(locationHref);
+ }
registerErrors();
@@ -349,8 +364,11 @@ delete Object.prototype.__proto__;
runtimeOptions,
internalName ?? name,
);
- const { unstableFlag, pid, noColor, args } = runtimeOptions;
+ const { unstableFlag, pid, noColor, args, location: locationHref } =
+ runtimeOptions;
+ location.setLocationHref(locationHref);
+ fetch.setBaseUrl(locationHref);
registerErrors();
const finalDenoNs = {
diff --git a/runtime/js/README.md b/runtime/js/README.md
index b17fa22e5..7e3fe4345 100644
--- a/runtime/js/README.md
+++ b/runtime/js/README.md
@@ -38,6 +38,8 @@ Some Web APIs are using ops under the hood, eg. `console`, `performance`.
[Body](https://developer.mozilla.org/en-US/docs/Web/API/Body) and
[Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers): modern
Promise-based HTTP Request API.
+- [location](https://developer.mozilla.org/en-US/docs/Web/API/Window/location)
+ and [Location](https://developer.mozilla.org/en-US/docs/Web/API/Location).
- [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData): access
to a `multipart/form-data` serialization.
- [Performance](https://developer.mozilla.org/en-US/docs/Web/API/Performance):
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index 313c71177..3a1f5316c 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -130,6 +130,7 @@ pub struct WebWorker {
terminate_rx: mpsc::Receiver<()>,
handle: WebWorkerHandle,
pub use_deno_namespace: bool,
+ pub main_module: ModuleSpecifier,
}
pub struct WebWorkerOptions {
@@ -197,6 +198,7 @@ impl WebWorker {
terminate_rx,
handle,
use_deno_namespace: options.use_deno_namespace,
+ main_module: main_module.clone(),
};
{
@@ -286,6 +288,7 @@ impl WebWorker {
"tsVersion": options.ts_version,
"unstableFlag": options.unstable,
"v8Version": deno_core::v8_version(),
+ "location": self.main_module,
});
let runtime_options_str =
diff --git a/runtime/worker.rs b/runtime/worker.rs
index 9326d632e..6ebb2fb36 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -63,6 +63,7 @@ pub struct WorkerOptions {
/// Sets `Deno.noColor` in JS runtime.
pub no_color: bool,
pub get_error_class_fn: Option<GetErrorClassFn>,
+ pub location: Option<Url>,
}
impl MainWorker {
@@ -179,6 +180,7 @@ impl MainWorker {
"tsVersion": options.ts_version,
"unstableFlag": options.unstable,
"v8Version": deno_core::v8_version(),
+ "location": options.location,
});
let script = format!(
@@ -282,6 +284,7 @@ mod tests {
ts_version: "x".to_string(),
no_color: true,
get_error_class_fn: None,
+ location: None,
};
MainWorker::from_options(main_module, permissions, &options)