From 4156fe7ed2836d66a7d09e3534add8d7d0737446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Oct 2021 04:53:52 +0200 Subject: [PATCH 1/6] feat(compat): inject Node globals --- cli/compat.rs | 13 ++++++- cli/main.rs | 39 ++++++++++++++----- cli/tests/integration/compat_tests.rs | 7 +++- .../testdata/compat/existing_import_map.out | 3 +- cli/tests/testdata/compat/globals.out | 7 ++++ cli/tests/testdata/compat/globals.ts | 8 ++++ 6 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 cli/tests/testdata/compat/globals.out create mode 100644 cli/tests/testdata/compat/globals.ts diff --git a/cli/compat.rs b/cli/compat.rs index eb67f4d12d8bdb..4b64a501d73c59 100644 --- a/cli/compat.rs +++ b/cli/compat.rs @@ -1,7 +1,10 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +use deno_core::url::Url; use std::collections::HashMap; +static STD_NODE: &str = "https://deno.land/std/node/"; + static SUPPORTED_MODULES: &[&str] = &[ "assert", "assert/strict", @@ -47,12 +50,20 @@ static SUPPORTED_MODULES: &[&str] = &[ "zlib", ]; +pub fn get_node_globals_url() -> Url { + Url::parse(&format!("{}global.ts", STD_NODE)).unwrap() +} + +/// Create a map that can be used to update import map. +/// +/// Keys are built-in Node modules (and built-ins prefixed with "node:"), while +/// values are URLs pointing to relevant files in deno.land/std/node/ directory. pub fn get_mapped_node_builtins() -> HashMap { let mut mappings = HashMap::new(); for module in SUPPORTED_MODULES { // TODO(bartlomieju): this is unversioned, and should be fixed to use latest stable? - let module_url = format!("https://deno.land/std/node/{}.ts", module); + let module_url = format!("{}{}.ts", STD_NODE, module); mappings.insert(module.to_string(), module_url.clone()); // Support for `node:` diff --git a/cli/main.rs b/cli/main.rs index dc2f2f5787c6f6..f94e329e2251c1 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -568,7 +568,7 @@ async fn eval_command( // Force TypeScript compile. let main_module = resolve_url_or_path("./$deno$eval.ts").unwrap(); let permissions = Permissions::from_options(&flags.clone().into()); - let ps = ProcState::build(flags).await?; + let ps = ProcState::build(flags.clone()).await?; let mut worker = create_main_worker(&ps, main_module.clone(), permissions, None); // Create a dummy source file. @@ -600,6 +600,11 @@ async fn eval_command( // to allow module access by TS compiler. ps.file_fetcher.insert_cached(file); debug!("main_module {}", &main_module); + if flags.compat { + worker + .execute_side_module(&compat::get_node_globals_url()) + .await?; + } worker.execute_main_module(&main_module).await?; worker.execute_script( &located_script_name!(), @@ -845,6 +850,11 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { ps.file_fetcher.insert_cached(source_file); debug!("main_module {}", main_module); + if flags.compat { + worker + .execute_side_module(&compat::get_node_globals_url()) + .await?; + } worker.execute_main_module(&main_module).await?; worker.execute_script( &located_script_name!(), @@ -912,13 +922,15 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { struct FileWatcherModuleExecutor { worker: MainWorker, pending_unload: bool, + compat: bool, } impl FileWatcherModuleExecutor { - pub fn new(worker: MainWorker) -> FileWatcherModuleExecutor { + pub fn new(worker: MainWorker, compat: bool) -> FileWatcherModuleExecutor { FileWatcherModuleExecutor { worker, pending_unload: false, + compat, } } @@ -928,6 +940,12 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { &mut self, main_module: &ModuleSpecifier, ) -> Result<(), AnyError> { + if self.compat { + self + .worker + .execute_side_module(&compat::get_node_globals_url()) + .await?; + } self.worker.execute_main_module(main_module).await?; self.worker.execute_script( &located_script_name!(), @@ -967,16 +985,14 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { let operation = |(ps, main_module): (ProcState, ModuleSpecifier)| { let flags = flags.clone(); - let permissions = Permissions::from_options(&flags.into()); + let permissions = Permissions::from_options(&flags.clone().into()); async move { // We make use an module executor guard to ensure that unload is always fired when an // operation is called. - let mut executor = FileWatcherModuleExecutor::new(create_main_worker( - &ps, - main_module.clone(), - permissions, - None, - )); + let mut executor = FileWatcherModuleExecutor::new( + create_main_worker(&ps, main_module.clone(), permissions, None), + flags.compat, + ); executor.execute(&main_module).await?; @@ -1022,6 +1038,11 @@ async fn run_command( }; debug!("main_module {}", main_module); + if flags.compat { + worker + .execute_side_module(&compat::get_node_globals_url()) + .await?; + } worker.execute_main_module(&main_module).await?; worker.execute_script( &located_script_name!(), diff --git a/cli/tests/integration/compat_tests.rs b/cli/tests/integration/compat_tests.rs index e1da32cafdca32..6743dada15e3f6 100644 --- a/cli/tests/integration/compat_tests.rs +++ b/cli/tests/integration/compat_tests.rs @@ -2,6 +2,11 @@ use crate::itest; +itest!(globals { + args: "run --compat --unstable --allow-read --allow-env compat/globals.ts", + output: "compat/globals.out", +}); + itest!(fs_promises { args: "run --compat --unstable -A compat/fs_promises.js", output: "compat/fs_promises.out", @@ -13,7 +18,7 @@ itest!(node_prefix_fs_promises { }); itest!(existing_import_map { - args: "run --compat --import-map compat/existing_import_map.json compat/fs_promises.js", + args: "run --compat --unstable --import-map compat/existing_import_map.json compat/fs_promises.js", output: "compat/existing_import_map.out", exit_code: 1, }); diff --git a/cli/tests/testdata/compat/existing_import_map.out b/cli/tests/testdata/compat/existing_import_map.out index 0e319b11509f50..cbff0cc5104af0 100644 --- a/cli/tests/testdata/compat/existing_import_map.out +++ b/cli/tests/testdata/compat/existing_import_map.out @@ -2,4 +2,5 @@ Some Node built-ins were not added to the import map: - "fs/promises" already exists and is mapped to "[WILDCARD]non_existent_file.js" If you want to use Node built-ins provided by Deno remove listed specifiers from "imports" mapping in the import map file. -error: Cannot resolve module [WILDCARD] \ No newline at end of file +[WILDCARD] +error: Cannot resolve module [WILDCARD] diff --git a/cli/tests/testdata/compat/globals.out b/cli/tests/testdata/compat/globals.out new file mode 100644 index 00000000000000..0bc09137be019b --- /dev/null +++ b/cli/tests/testdata/compat/globals.out @@ -0,0 +1,7 @@ +[WILDCARD] +process { +[WILDCARD] +} +[Function: Buffer] +[Function: setImmediate] +[Function: clearTimeout] diff --git a/cli/tests/testdata/compat/globals.ts b/cli/tests/testdata/compat/globals.ts new file mode 100644 index 00000000000000..39a555cbf38d13 --- /dev/null +++ b/cli/tests/testdata/compat/globals.ts @@ -0,0 +1,8 @@ +if (global != window) { + throw new Error("global is not equal to window"); +} + +console.log(process); +console.log(Buffer); +console.log(setImmediate); +console.log(clearImmediate); From d86ff312671612cbf9b53af1506c18321745eb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Oct 2021 05:03:40 +0200 Subject: [PATCH 2/6] add node global for type checking --- cli/proc_state.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/proc_state.rs b/cli/proc_state.rs index 48dc335f0bf00d..9fad02a4fff6be 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -15,6 +15,7 @@ use crate::module_graph::TypeLib; use crate::source_maps::SourceMapGetter; use crate::specifier_handler::FetchHandler; use crate::version; +use crate::compat; use deno_core::error::anyhow; use deno_core::error::get_custom_error_class; @@ -217,7 +218,7 @@ impl ProcState { .unwrap() } }; - let node_builtins = crate::compat::get_mapped_node_builtins(); + let node_builtins = compat::get_mapped_node_builtins(); let diagnostics = import_map.update_imports(node_builtins)?; if !diagnostics.is_empty() { @@ -353,6 +354,9 @@ impl ProcState { )?)); let mut builder = GraphBuilder::new(handler, maybe_import_map, self.lockfile.clone()); + if self.flags.compat { + builder.add(&compat::get_node_globals_url(), false).await?; + } builder.add(&specifier, is_dynamic).await?; builder.analyze_config_file(&self.maybe_config_file).await?; let mut graph = builder.get_graph(); From 7df7ceb5aff1085b7b6170842bc2853d0d9f92ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Oct 2021 05:06:28 +0200 Subject: [PATCH 3/6] add missed file --- cli/proc_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/proc_state.rs b/cli/proc_state.rs index 9fad02a4fff6be..2e1fb0e317d451 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use crate::colors; +use crate::compat; use crate::config_file::ConfigFile; use crate::deno_dir; use crate::file_fetcher::CacheSetting; @@ -15,7 +16,6 @@ use crate::module_graph::TypeLib; use crate::source_maps::SourceMapGetter; use crate::specifier_handler::FetchHandler; use crate::version; -use crate::compat; use deno_core::error::anyhow; use deno_core::error::get_custom_error_class; From 1ab12b066925a52579893ae236494938b8c0de7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Oct 2021 05:13:02 +0200 Subject: [PATCH 4/6] require --unstable with --compat --- cli/flags.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/flags.rs b/cli/flags.rs index 3075eda406e418..331915aabc99d9 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -1627,7 +1627,8 @@ fn seed_arg<'a, 'b>() -> Arg<'a, 'b> { fn compat_arg<'a, 'b>() -> Arg<'a, 'b> { Arg::with_name("compat") .long("compat") - .help("Node compatibility mode. Currently only enables built-in node modules like 'fs'.") + .requires("unstable") + .help("Node compatibility mode. Currently only enables built-in node modules like 'fs' and globals like 'process'.") } fn watch_arg<'a, 'b>() -> Arg<'a, 'b> { From a2d22a801333a78bf928be7a6ef008b43cdd681d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Oct 2021 05:21:45 +0200 Subject: [PATCH 5/6] fix flags tests --- cli/flags.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/flags.rs b/cli/flags.rs index 331915aabc99d9..5f19f480bf6b71 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -4454,7 +4454,7 @@ mod tests { #[test] fn compat() { - let r = flags_from_vec(svec!["deno", "run", "--compat", "foo.js"]); + let r = flags_from_vec(svec!["deno", "run", "--compat", "--unstable", "foo.js"]); assert_eq!( r.unwrap(), Flags { @@ -4462,6 +4462,7 @@ mod tests { script: "foo.js".to_string(), }), compat: true, + unstable: true, ..Flags::default() } ); From 7f4b8560986e2aa6ec06fa90249dde7541ae1794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Oct 2021 05:23:50 +0200 Subject: [PATCH 6/6] fmt --- cli/flags.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/flags.rs b/cli/flags.rs index 5f19f480bf6b71..df17c08dab0d1d 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -4454,7 +4454,8 @@ mod tests { #[test] fn compat() { - let r = flags_from_vec(svec!["deno", "run", "--compat", "--unstable", "foo.js"]); + let r = + flags_from_vec(svec!["deno", "run", "--compat", "--unstable", "foo.js"]); assert_eq!( r.unwrap(), Flags {