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/flags.rs b/cli/flags.rs index 3075eda406e418..df17c08dab0d1d 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> { @@ -4453,7 +4454,8 @@ 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 { @@ -4461,6 +4463,7 @@ mod tests { script: "foo.js".to_string(), }), compat: true, + unstable: true, ..Flags::default() } ); diff --git a/cli/main.rs b/cli/main.rs index d7601249d8ae51..b444f101e816c1 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/proc_state.rs b/cli/proc_state.rs index 48dc335f0bf00d..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; @@ -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(); 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);