summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2019-02-12 21:14:02 -0500
committerRyan Dahl <ry@tinyclouds.org>2019-02-18 23:04:59 -0500
commit42408febe8cdf9e30ff8d1a3bb13f4994906c53b (patch)
tree92ab3408d426f1d18a511aa16130357ed074410a
parent27afbd135162b435c8af22b18622656ccab12174 (diff)
Add window.location
-rw-r--r--BUILD.gn1
-rw-r--r--js/dom_types.ts70
-rw-r--r--js/globals.ts2
-rw-r--r--js/lib.web_assembly.d.ts5
-rw-r--r--js/location.ts52
-rw-r--r--js/location_test.ts8
-rw-r--r--js/main.ts12
-rw-r--r--js/unit_tests.ts1
-rw-r--r--src/deno_dir.rs61
-rw-r--r--src/isolate.rs16
-rw-r--r--src/main.rs11
-rw-r--r--src/msg.fbs1
-rw-r--r--src/ops.rs3
-rw-r--r--tests/error_010_nonexistent_arg.out2
-rw-r--r--tests/if_main.test2
-rw-r--r--tests/if_main.ts7
-rw-r--r--tests/if_main.ts.out1
-rw-r--r--tests/import_meta.test2
-rw-r--r--tests/import_meta.ts3
-rw-r--r--tests/import_meta.ts.out2
-rw-r--r--tests/import_meta2.ts1
-rw-r--r--tests/imports_meta.js3
-rw-r--r--tests/imports_meta.js.out2
-rw-r--r--tests/imports_meta.test2
-rw-r--r--tests/imports_meta2.js1
-rw-r--r--website/manual.md11
26 files changed, 241 insertions, 41 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 456da61fe..359375152 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -80,6 +80,7 @@ ts_sources = [
"js/io.ts",
"js/libdeno.ts",
"js/lib.web_assembly.d.ts",
+ "js/location.ts",
"js/main.ts",
"js/make_temp_dir.ts",
"js/metrics.ts",
diff --git a/js/dom_types.ts b/js/dom_types.ts
index 0c6814dae..651eece9a 100644
--- a/js/dom_types.ts
+++ b/js/dom_types.ts
@@ -536,3 +536,73 @@ export interface Response extends Body {
/** Creates a clone of a `Response` object. */
clone(): Response;
}
+
+export interface Location {
+ /**
+ * Returns a DOMStringList object listing the origins of the ancestor browsing
+ * contexts, from the parent browsing context to the top-level browsing
+ * context.
+ */
+ readonly ancestorOrigins: string[];
+ /**
+ * Returns the Location object's URL's fragment (includes leading "#" if
+ * non-empty).
+ * Can be set, to navigate to the same URL with a changed fragment (ignores
+ * leading "#").
+ */
+ hash: string;
+ /**
+ * Returns the Location object's URL's host and port (if different from the
+ * default port for the scheme). Can be set, to navigate to the same URL with
+ * a changed host and port.
+ */
+ host: string;
+ /**
+ * Returns the Location object's URL's host. Can be set, to navigate to the
+ * same URL with a changed host.
+ */
+ hostname: string;
+ /**
+ * Returns the Location object's URL. Can be set, to navigate to the given
+ * URL.
+ */
+ href: string;
+ /** Returns the Location object's URL's origin. */
+ readonly origin: string;
+ /**
+ * Returns the Location object's URL's path.
+ * Can be set, to navigate to the same URL with a changed path.
+ */
+ pathname: string;
+ /**
+ * Returns the Location object's URL's port.
+ * Can be set, to navigate to the same URL with a changed port.
+ */
+ port: string;
+ /**
+ * Returns the Location object's URL's scheme.
+ * Can be set, to navigate to the same URL with a changed scheme.
+ */
+ protocol: string;
+ /**
+ * Returns the Location object's URL's query (includes leading "?" if
+ * non-empty). Can be set, to navigate to the same URL with a changed query
+ * (ignores leading "?").
+ */
+ search: string;
+ /**
+ * Navigates to the given URL.
+ */
+ assign(url: string): void;
+ /**
+ * Reloads the current page.
+ */
+ reload(): void;
+ /** @deprecated */
+ reload(forcedReload: boolean): void;
+ /**
+ * Removes the current page from the session history and navigates to the
+ * given URL.
+ */
+ replace(url: string): void;
+}
diff --git a/js/globals.ts b/js/globals.ts
index e0fa6ef12..935890be4 100644
--- a/js/globals.ts
+++ b/js/globals.ts
@@ -58,6 +58,8 @@ window.clearInterval = timers.clearTimer;
window.console = new consoleTypes.Console(libdeno.print);
window.setTimeout = timers.setTimeout;
window.setInterval = timers.setInterval;
+// tslint:disable-next-line:no-any
+window.location = (undefined as unknown) as domTypes.Location;
// When creating the runtime type library, we use modifications to `window` to
// determine what is in the global namespace. When we put a class in the
diff --git a/js/lib.web_assembly.d.ts b/js/lib.web_assembly.d.ts
index a5747b30e..1ec6a7943 100644
--- a/js/lib.web_assembly.d.ts
+++ b/js/lib.web_assembly.d.ts
@@ -161,3 +161,8 @@ declare namespace WebAssembly {
constructor(message: string, fileName?: string, lineNumber?: string);
}
}
+
+// TODO Move ImportMeta intos its own lib.import_meta.d.ts file?
+interface ImportMeta {
+ url: string;
+}
diff --git a/js/location.ts b/js/location.ts
new file mode 100644
index 000000000..5e7cb07b4
--- /dev/null
+++ b/js/location.ts
@@ -0,0 +1,52 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+import { URL } from "./url";
+import { notImplemented } from "./util";
+import { Location } from "./dom_types";
+import { window } from "./globals";
+
+export function setLocation(url: string): void {
+ window.location = new LocationImpl(url);
+ Object.freeze(window.location);
+}
+
+export class LocationImpl implements Location {
+ constructor(url: string) {
+ const u = new URL(url);
+ this.url = u;
+ this.hash = u.hash;
+ this.host = u.host;
+ this.href = u.href;
+ this.hostname = u.hostname;
+ this.origin = u.protocol + "//" + u.host;
+ this.pathname = u.pathname;
+ this.protocol = u.protocol;
+ this.port = u.port;
+ this.search = u.search;
+ }
+
+ private url: URL;
+
+ toString(): string {
+ return this.url.toString();
+ }
+
+ readonly ancestorOrigins: string[] = [];
+ hash: string;
+ host: string;
+ hostname: string;
+ href: string;
+ readonly origin: string;
+ pathname: string;
+ port: string;
+ protocol: string;
+ search: string;
+ assign(url: string): void {
+ throw notImplemented();
+ }
+ reload(): void {
+ throw notImplemented();
+ }
+ replace(url: string): void {
+ throw notImplemented();
+ }
+}
diff --git a/js/location_test.ts b/js/location_test.ts
new file mode 100644
index 000000000..2302c32ed
--- /dev/null
+++ b/js/location_test.ts
@@ -0,0 +1,8 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+import { test, assert } from "./test_util.ts";
+
+test(function locationBasic() {
+ // location example: file:///Users/rld/src/deno/js/unit_tests.ts
+ console.log("location", window.location.toString());
+ assert(window.location.toString().endsWith("unit_tests.ts"));
+});
diff --git a/js/main.ts b/js/main.ts
index a5aae51a1..b67f188ac 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -4,12 +4,13 @@
import "./globals";
-import { log } from "./util";
+import { assert, log } from "./util";
import * as os from "./os";
import { libdeno } from "./libdeno";
import { args } from "./deno";
import { replLoop } from "./repl";
import { setVersions } from "./version";
+import { setLocation } from "./location";
// builtin modules
import * as deno from "./deno";
@@ -42,6 +43,12 @@ export default function denoMain() {
os.exit(0);
}
+ const mainModule = startResMsg.mainModule();
+ if (mainModule) {
+ assert(mainModule.length > 0);
+ setLocation(mainModule);
+ }
+
const cwd = startResMsg.cwd();
log("cwd", cwd);
@@ -51,8 +58,7 @@ export default function denoMain() {
log("args", args);
Object.freeze(args);
- const inputFn = args[0];
- if (!inputFn) {
+ if (!mainModule) {
replLoop();
}
}
diff --git a/js/unit_tests.ts b/js/unit_tests.ts
index c8479145b..91c1745b6 100644
--- a/js/unit_tests.ts
+++ b/js/unit_tests.ts
@@ -22,6 +22,7 @@ import "./files_test.ts";
import "./form_data_test.ts";
import "./globals_test.ts";
import "./headers_test.ts";
+import "./location_test.ts";
import "./make_temp_dir_test.ts";
import "./metrics_test.ts";
import "./mixins/dom_iterable_test.ts";
diff --git a/src/deno_dir.rs b/src/deno_dir.rs
index 9682d9325..1d101dd8a 100644
--- a/src/deno_dir.rs
+++ b/src/deno_dir.rs
@@ -400,14 +400,11 @@ impl DenoDir {
}
/// Returns (module name, local filename)
- pub fn resolve_module(
+ pub fn resolve_module_url(
self: &Self,
specifier: &str,
referrer: &str,
- ) -> Result<(String, String), url::ParseError> {
- let module_name;
- let filename;
-
+ ) -> Result<Url, url::ParseError> {
let specifier = self.src_file_to_url(specifier);
let mut referrer = self.src_file_to_url(referrer);
@@ -422,8 +419,7 @@ impl DenoDir {
referrer = referrer_path.to_str().unwrap().to_string() + "/";
}
- let j: Url = if is_remote(&specifier) || Path::new(&specifier).is_absolute()
- {
+ let j = if is_remote(&specifier) || Path::new(&specifier).is_absolute() {
parse_local_or_remote(&specifier)?
} else if referrer.ends_with('/') {
let r = Url::from_directory_path(&referrer);
@@ -437,21 +433,29 @@ impl DenoDir {
let base = parse_local_or_remote(&referrer)?;
base.join(specifier.as_ref())?
};
+ Ok(j)
+ }
+
+ /// Returns (module name, local filename)
+ pub fn resolve_module(
+ self: &Self,
+ specifier: &str,
+ referrer: &str,
+ ) -> Result<(String, String), url::ParseError> {
+ let j = self.resolve_module_url(specifier, referrer)?;
+ let module_name = j.to_string();
+ let filename;
match j.scheme() {
"file" => {
- let p = deno_fs::normalize_path(j.to_file_path().unwrap().as_ref());
- module_name = p.clone();
- filename = p;
+ filename = deno_fs::normalize_path(j.to_file_path().unwrap().as_ref());
}
"https" => {
- module_name = j.to_string();
filename = deno_fs::normalize_path(
get_cache_filename(self.deps_https.as_path(), &j).as_ref(),
)
}
"http" => {
- module_name = j.to_string();
filename = deno_fs::normalize_path(
get_cache_filename(self.deps_http.as_path(), &j).as_ref(),
)
@@ -517,7 +521,7 @@ fn is_remote(module_name: &str) -> bool {
}
fn parse_local_or_remote(p: &str) -> Result<url::Url, url::ParseError> {
- if is_remote(p) {
+ if is_remote(p) || p.starts_with("file:") {
Url::parse(p)
} else {
Url::from_file_path(p).map_err(|_err| url::ParseError::IdnaError)
@@ -605,6 +609,16 @@ mod tests {
};
}
+ macro_rules! file_url {
+ ($path:expr) => {
+ if cfg!(target_os = "windows") {
+ concat!("file:///C:", $path)
+ } else {
+ concat!("file://", $path)
+ }
+ };
+ }
+
#[test]
fn test_get_cache_filename() {
let url = Url::parse("http://example.com:1234/path/to/file.ts").unwrap();
@@ -1019,25 +1033,25 @@ mod tests {
(
"./subdir/print_hello.ts",
add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/006_url_imports.ts"),
- add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/subdir/print_hello.ts"),
+ file_url!("/Users/rld/go/src/github.com/denoland/deno/testdata/subdir/print_hello.ts"),
add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/subdir/print_hello.ts"),
),
(
"testdata/001_hello.js",
add_root!("/Users/rld/go/src/github.com/denoland/deno/"),
- add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/001_hello.js"),
+ file_url!("/Users/rld/go/src/github.com/denoland/deno/testdata/001_hello.js"),
add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/001_hello.js"),
),
(
add_root!("/Users/rld/src/deno/hello.js"),
".",
- add_root!("/Users/rld/src/deno/hello.js"),
+ file_url!("/Users/rld/src/deno/hello.js"),
add_root!("/Users/rld/src/deno/hello.js"),
),
(
add_root!("/this/module/got/imported.js"),
add_root!("/that/module/did/it.js"),
- add_root!("/this/module/got/imported.js"),
+ file_url!("/this/module/got/imported.js"),
add_root!("/this/module/got/imported.js"),
),
];
@@ -1169,8 +1183,7 @@ mod tests {
let specifier = "http_test.ts";
let referrer = add_root!("/Users/rld/src/deno_net/");
- let expected_module_name =
- add_root!("/Users/rld/src/deno_net/http_test.ts");
+ let expected_module_name = file_url!("/Users/rld/src/deno_net/http_test.ts");
let expected_filename = add_root!("/Users/rld/src/deno_net/http_test.ts");
let (module_name, filename) =
@@ -1187,8 +1200,9 @@ mod tests {
let cwd = std::env::current_dir().unwrap();
let expected_path = cwd.join(specifier);
- let expected_module_name = deno_fs::normalize_path(&expected_path);
- let expected_filename = expected_module_name.clone();
+ let expected_module_name =
+ Url::from_file_path(&expected_path).unwrap().to_string();
+ let expected_filename = deno_fs::normalize_path(&expected_path);
let (module_name, filename) =
deno_dir.resolve_module(specifier, ".").unwrap();
@@ -1209,8 +1223,9 @@ mod tests {
let cwd = std::env::current_dir().unwrap();
let expected_path = cwd.join("..").join(specifier);
- let expected_module_name = deno_fs::normalize_path(&expected_path);
- let expected_filename = expected_module_name.clone();
+ let expected_module_name =
+ Url::from_file_path(&expected_path).unwrap().to_string();
+ let expected_filename = deno_fs::normalize_path(&expected_path);
let (module_name, filename) =
deno_dir.resolve_module(specifier, "..").unwrap();
diff --git a/src/isolate.rs b/src/isolate.rs
index 8775c6f4a..661e49edd 100644
--- a/src/isolate.rs
+++ b/src/isolate.rs
@@ -100,6 +100,22 @@ impl IsolateState {
}
}
+ pub fn main_module(&self) -> Option<String> {
+ if self.argv.len() <= 1 {
+ None
+ } else {
+ let specifier = self.argv[1].clone();
+ let referrer = ".";
+ match self.dir.resolve_module_url(&specifier, referrer) {
+ Ok(url) => Some(url.to_string()),
+ Err(e) => {
+ debug!("Potentially swallowed error {}", e);
+ None
+ }
+ }
+ }
+ }
+
#[cfg(test)]
pub fn mock() -> Arc<IsolateState> {
let argv = vec![String::from("./deno"), String::from("hello.js")];
diff --git a/src/main.rs b/src/main.rs
index d3ec4b721..10ae15065 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -105,19 +105,18 @@ fn main() {
.map_err(errors::RustOrJsError::from)
.unwrap_or_else(print_err_and_exit);
- // Execute input file.
- if isolate.state.argv.len() > 1 {
- let input_filename = isolate.state.argv[1].clone();
+ // Execute main module.
+ if let Some(main_module) = isolate.state.main_module() {
+ debug!("main_module {}", main_module);
isolate
- .execute_mod(&input_filename, should_prefetch)
+ .execute_mod(&main_module, should_prefetch)
.unwrap_or_else(print_err_and_exit);
-
if should_display_info {
// Display file info and exit. Do not run file
modules::print_file_info(
&isolate.modules.borrow(),
&isolate.state.dir,
- input_filename,
+ main_module,
);
std::process::exit(0);
}
diff --git a/src/msg.fbs b/src/msg.fbs
index 9776bb893..da03e00a4 100644
--- a/src/msg.fbs
+++ b/src/msg.fbs
@@ -158,6 +158,7 @@ table StartRes {
pid: uint32;
argv: [string];
exec_path: string;
+ main_module: string; // Absolute URL.
debug_flag: bool;
deps_flag: bool;
types_flag: bool;
diff --git a/src/ops.rs b/src/ops.rs
index c8a005601..8f32ebc03 100644
--- a/src/ops.rs
+++ b/src/ops.rs
@@ -261,12 +261,15 @@ fn op_start(
let deno_version = version::DENO;
let deno_version_off = builder.create_string(deno_version);
+ let main_module = state.main_module().map(|m| builder.create_string(&m));
+
let inner = msg::StartRes::create(
&mut builder,
&msg::StartResArgs {
cwd: Some(cwd_off),
pid: std::process::id(),
argv: Some(argv_off),
+ main_module,
debug_flag: state.flags.log_debug,
types_flag: state.flags.types,
version_flag: state.flags.version,
diff --git a/tests/error_010_nonexistent_arg.out b/tests/error_010_nonexistent_arg.out
index 248cbc329..ef4f7b041 100644
--- a/tests/error_010_nonexistent_arg.out
+++ b/tests/error_010_nonexistent_arg.out
@@ -1 +1 @@
-[WILDCARD]Cannot resolve module "not-a-valid-filename.ts" from "."
+[WILDCARD]Cannot resolve module "file:[WILDCARD]not-a-valid-filename.ts" from "."
diff --git a/tests/if_main.test b/tests/if_main.test
new file mode 100644
index 000000000..5830d00f8
--- /dev/null
+++ b/tests/if_main.test
@@ -0,0 +1,2 @@
+args: tests/if_main.ts --reload
+output: tests/if_main.ts.out
diff --git a/tests/if_main.ts b/tests/if_main.ts
new file mode 100644
index 000000000..b47066b2d
--- /dev/null
+++ b/tests/if_main.ts
@@ -0,0 +1,7 @@
+if (window.location.toString() == import.meta.url) {
+ console.log("main");
+} else {
+ console.log("import.meta.url", import.meta.url);
+ console.log("window.location", window.location.toString());
+ throw Error("not main");
+}
diff --git a/tests/if_main.ts.out b/tests/if_main.ts.out
new file mode 100644
index 000000000..ba2906d06
--- /dev/null
+++ b/tests/if_main.ts.out
@@ -0,0 +1 @@
+main
diff --git a/tests/import_meta.test b/tests/import_meta.test
new file mode 100644
index 000000000..6767cfbb2
--- /dev/null
+++ b/tests/import_meta.test
@@ -0,0 +1,2 @@
+args: tests/import_meta.ts --reload
+output: tests/import_meta.ts.out
diff --git a/tests/import_meta.ts b/tests/import_meta.ts
new file mode 100644
index 000000000..8f2712068
--- /dev/null
+++ b/tests/import_meta.ts
@@ -0,0 +1,3 @@
+console.log("import_meta", import.meta.url);
+
+import "import_meta2.ts";
diff --git a/tests/import_meta.ts.out b/tests/import_meta.ts.out
new file mode 100644
index 000000000..c43cea6fd
--- /dev/null
+++ b/tests/import_meta.ts.out
@@ -0,0 +1,2 @@
+import_meta2 [WILDCARD]import_meta2.ts
+import_meta [WILDCARD]import_meta.ts
diff --git a/tests/import_meta2.ts b/tests/import_meta2.ts
new file mode 100644
index 000000000..b64265b5b
--- /dev/null
+++ b/tests/import_meta2.ts
@@ -0,0 +1 @@
+console.log("import_meta2", import.meta.url);
diff --git a/tests/imports_meta.js b/tests/imports_meta.js
deleted file mode 100644
index 3361d1237..000000000
--- a/tests/imports_meta.js
+++ /dev/null
@@ -1,3 +0,0 @@
-console.log("imports_meta", import.meta.url);
-
-import "imports_meta2.js";
diff --git a/tests/imports_meta.js.out b/tests/imports_meta.js.out
deleted file mode 100644
index ec6e7eaec..000000000
--- a/tests/imports_meta.js.out
+++ /dev/null
@@ -1,2 +0,0 @@
-imports_meta2 [WILDCARD]imports_meta2.js
-imports_meta [WILDCARD]imports_meta.js
diff --git a/tests/imports_meta.test b/tests/imports_meta.test
deleted file mode 100644
index 17591ea33..000000000
--- a/tests/imports_meta.test
+++ /dev/null
@@ -1,2 +0,0 @@
-args: tests/imports_meta.js --reload
-output: tests/imports_meta.js.out
diff --git a/tests/imports_meta2.js b/tests/imports_meta2.js
deleted file mode 100644
index 583861e12..000000000
--- a/tests/imports_meta2.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log("imports_meta2", import.meta.url);
diff --git a/website/manual.md b/website/manual.md
index 5a9add63e..524f1d449 100644
--- a/website/manual.md
+++ b/website/manual.md
@@ -466,6 +466,17 @@ import { test, assertEqual } from "./package.ts";
This design circumvents a plethora of complexity spawned by package management
software, centralized code repositories, and superfluous file formats.
+### Testing if current file is the main program
+
+By using `window.location` and `import.meta.url` one can test if the current
+script has been executed as the main input to the program.
+
+```ts
+if (window.location.toString() == import.meta.url) {
+ console.log("main");
+}
+```
+
## Command line interface
### Flags