From 0bd3cea0ff6d2d4840c0df2938b5ae5c5d7cc4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 13 Oct 2020 13:35:35 +0200 Subject: refactor(cli): rename GlobalState to ProgramState (#7914) --- cli/global_state.rs | 538 -------------------------------------------- cli/main.rs | 82 +++---- cli/module_graph.rs | 6 +- cli/module_graph2.rs | 2 +- cli/module_loader.rs | 160 +++++++++++++ cli/ops/errors.rs | 2 +- cli/ops/mod.rs | 14 +- cli/ops/runtime.rs | 2 +- cli/ops/runtime_compiler.rs | 10 +- cli/ops/worker_host.rs | 14 +- cli/permissions.rs | 94 ++++---- cli/program_state.rs | 538 ++++++++++++++++++++++++++++++++++++++++++++ cli/repl.rs | 6 +- cli/specifier_handler.rs | 6 +- cli/state.rs | 160 ------------- cli/tsc.rs | 54 ++--- cli/worker.rs | 49 ++-- 17 files changed, 869 insertions(+), 868 deletions(-) delete mode 100644 cli/global_state.rs create mode 100644 cli/module_loader.rs create mode 100644 cli/program_state.rs delete mode 100644 cli/state.rs diff --git a/cli/global_state.rs b/cli/global_state.rs deleted file mode 100644 index 716c7144a..000000000 --- a/cli/global_state.rs +++ /dev/null @@ -1,538 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -use crate::deno_dir; -use crate::file_fetcher::SourceFileFetcher; -use crate::flags; -use crate::http_cache; -use crate::import_map::ImportMap; -use crate::inspector::InspectorServer; -use crate::lockfile::Lockfile; -use crate::media_type::MediaType; -use crate::module_graph::ModuleGraphFile; -use crate::module_graph::ModuleGraphLoader; -use crate::module_graph2::GraphBuilder2; -use crate::module_graph2::TranspileOptions; -use crate::permissions::Permissions; -use crate::specifier_handler::FetchHandler; -use crate::tsc::CompiledModule; -use crate::tsc::TargetLib; -use crate::tsc::TsCompiler; -use deno_core::error::AnyError; -use deno_core::ModuleSpecifier; -use std::cell::RefCell; -use std::env; -use std::rc::Rc; -use std::sync::Arc; -use std::sync::Mutex; - -pub fn exit_unstable(api_name: &str) { - eprintln!( - "Unstable API '{}'. The --unstable flag must be provided.", - api_name - ); - std::process::exit(70); -} - -/// This structure represents state of single "deno" program. -/// -/// It is shared by all created workers (thus V8 isolates). -pub struct GlobalState { - /// Flags parsed from `argv` contents. - pub flags: flags::Flags, - /// Permissions parsed from `flags`. - pub permissions: Permissions, - pub dir: deno_dir::DenoDir, - pub file_fetcher: SourceFileFetcher, - pub ts_compiler: TsCompiler, - pub lockfile: Option>, - pub maybe_import_map: Option, - pub maybe_inspector_server: Option>, -} - -impl GlobalState { - pub fn new(flags: flags::Flags) -> Result, AnyError> { - let custom_root = env::var("DENO_DIR").map(String::into).ok(); - let dir = deno_dir::DenoDir::new(custom_root)?; - let deps_cache_location = dir.root.join("deps"); - let http_cache = http_cache::HttpCache::new(&deps_cache_location); - let ca_file = flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok()); - - let file_fetcher = SourceFileFetcher::new( - http_cache, - !flags.reload, - flags.cache_blocklist.clone(), - flags.no_remote, - flags.cached_only, - ca_file.as_deref(), - )?; - - let ts_compiler = TsCompiler::new( - file_fetcher.clone(), - flags.clone(), - dir.gen_cache.clone(), - )?; - - let lockfile = if let Some(filename) = &flags.lock { - let lockfile = Lockfile::new(filename.clone(), flags.lock_write)?; - Some(Mutex::new(lockfile)) - } else { - None - }; - - let maybe_import_map: Option = - match flags.import_map_path.as_ref() { - None => None, - Some(file_path) => { - if !flags.unstable { - exit_unstable("--importmap") - } - Some(ImportMap::load(file_path)?) - } - }; - - let maybe_inspect_host = flags.inspect.or(flags.inspect_brk); - let maybe_inspector_server = match maybe_inspect_host { - Some(host) => Some(Arc::new(InspectorServer::new(host))), - None => None, - }; - - let global_state = GlobalState { - dir, - permissions: Permissions::from_flags(&flags), - flags, - file_fetcher, - ts_compiler, - lockfile, - maybe_import_map, - maybe_inspector_server, - }; - Ok(Arc::new(global_state)) - } - - /// This function is called when new module load is - /// initialized by the JsRuntime. Its resposibility is to collect - /// all dependencies and if it is required then also perform TS typecheck - /// and traspilation. - pub async fn prepare_module_load( - self: &Arc, - module_specifier: ModuleSpecifier, - maybe_referrer: Option, - target_lib: TargetLib, - permissions: Permissions, - is_dyn_import: bool, - maybe_import_map: Option, - ) -> Result<(), AnyError> { - let module_specifier = module_specifier.clone(); - - if self.flags.no_check { - debug!("Transpiling root: {}", module_specifier); - // TODO(kitsonk) note that self.permissions != permissions, which is - // something that should be handled better in the future. - let handler = - Rc::new(RefCell::new(FetchHandler::new(self, permissions.clone())?)); - let mut builder = GraphBuilder2::new(handler, maybe_import_map); - builder.insert(&module_specifier).await?; - let mut graph = builder.get_graph(&self.lockfile)?; - - let (stats, maybe_ignored_options) = - graph.transpile(TranspileOptions { - debug: self.flags.log_level == Some(log::Level::Debug), - maybe_config_path: self.flags.config_path.clone(), - })?; - - if let Some(ignored_options) = maybe_ignored_options { - eprintln!("{}", ignored_options); - } - - debug!("{}", stats); - } else { - let mut module_graph_loader = ModuleGraphLoader::new( - self.file_fetcher.clone(), - maybe_import_map, - permissions.clone(), - is_dyn_import, - false, - ); - module_graph_loader - .add_to_graph(&module_specifier, maybe_referrer) - .await?; - let module_graph = module_graph_loader.get_graph(); - - let out = self - .file_fetcher - .fetch_cached_source_file(&module_specifier, permissions.clone()) - .expect("Source file not found"); - - let module_graph_files = module_graph.values().collect::>(); - // Check integrity of every file in module graph - if let Some(ref lockfile) = self.lockfile { - let mut g = lockfile.lock().unwrap(); - - for graph_file in &module_graph_files { - let check_passed = - g.check_or_insert(&graph_file.url, &graph_file.source_code); - - if !check_passed { - eprintln!( - "Subresource integrity check failed --lock={}\n{}", - g.filename, graph_file.url - ); - std::process::exit(10); - } - } - } - - // Check if we need to compile files. - let should_compile = needs_compilation( - self.ts_compiler.compile_js, - out.media_type, - &module_graph_files, - ); - let allow_js = should_allow_js(&module_graph_files); - - if should_compile { - self - .ts_compiler - .compile(self, &out, target_lib, &module_graph, allow_js) - .await?; - } - } - - if let Some(ref lockfile) = self.lockfile { - let g = lockfile.lock().unwrap(); - g.write()?; - } - - Ok(()) - } - - // TODO(bartlomieju): this method doesn't need to be async anymore - /// This method is used after `prepare_module_load` finishes and JsRuntime - /// starts loading source and executing source code. This method shouldn't - /// perform any IO (besides $DENO_DIR) and only operate on sources collected - /// during `prepare_module_load`. - pub async fn fetch_compiled_module( - &self, - module_specifier: ModuleSpecifier, - _maybe_referrer: Option, - ) -> Result { - let out = self - .file_fetcher - .fetch_cached_source_file(&module_specifier, Permissions::allow_all()) - .expect("Cached source file doesn't exist"); - - // Check if we need to compile files - let was_compiled = match out.media_type { - MediaType::TypeScript | MediaType::TSX | MediaType::JSX => true, - MediaType::JavaScript => self.ts_compiler.compile_js, - _ => false, - }; - - let compiled_module = if was_compiled { - match self.ts_compiler.get_compiled_module(&out.url) { - Ok(module) => module, - Err(e) => { - let msg = format!( - "Failed to get compiled source code of \"{}\".\nReason: {}\n\ - If the source file provides only type exports, prefer to use \"import type\" or \"export type\" syntax instead.", - out.url, e.to_string() - ); - info!("{} {}", crate::colors::yellow("Warning"), msg); - - CompiledModule { - code: "".to_string(), - name: out.url.to_string(), - } - } - } - } else { - CompiledModule { - code: out.source_code, - name: out.url.to_string(), - } - }; - - Ok(compiled_module) - } - - /// Quits the process if the --unstable flag was not provided. - /// - /// This is intentionally a non-recoverable check so that people cannot probe - /// for unstable APIs from stable programs. - pub fn check_unstable(&self, api_name: &str) { - if !self.flags.unstable { - exit_unstable(api_name); - } - } - - #[cfg(test)] - pub fn mock( - argv: Vec, - maybe_flags: Option, - ) -> Arc { - GlobalState::new(flags::Flags { - argv, - ..maybe_flags.unwrap_or_default() - }) - .unwrap() - } -} - -/// Determine if TS compiler should be run with `allowJs` setting on. This -/// is the case when there's either: -/// - a JavaScript file with non-JavaScript import -/// - JSX import -fn should_allow_js(module_graph_files: &[&ModuleGraphFile]) -> bool { - module_graph_files.iter().any(|module_file| { - if module_file.media_type == MediaType::JSX { - true - } else if module_file.media_type == MediaType::JavaScript { - module_file.imports.iter().any(|import_desc| { - let import_file = module_graph_files - .iter() - .find(|f| { - f.specifier == import_desc.resolved_specifier.to_string().as_str() - }) - .expect("Failed to find imported file"); - let media_type = import_file.media_type; - media_type == MediaType::TypeScript - || media_type == MediaType::TSX - || media_type == MediaType::JSX - }) - } else { - false - } - }) -} - -// Compilation happens if either: -// - `checkJs` is set to true in TS config -// - entry point is a TS file -// - any dependency in module graph is a TS file -fn needs_compilation( - compile_js: bool, - media_type: MediaType, - module_graph_files: &[&ModuleGraphFile], -) -> bool { - let mut needs_compilation = match media_type { - MediaType::TypeScript | MediaType::TSX | MediaType::JSX => true, - MediaType::JavaScript => compile_js, - _ => false, - }; - - needs_compilation |= module_graph_files.iter().any(|module_file| { - let media_type = module_file.media_type; - - media_type == (MediaType::TypeScript) - || media_type == (MediaType::TSX) - || media_type == (MediaType::JSX) - }); - - needs_compilation -} - -#[test] -fn thread_safe() { - fn f(_: S) {} - f(GlobalState::mock(vec![], None)); -} - -#[test] -fn test_should_allow_js() { - use crate::ast::Location; - use crate::module_graph::ImportDescriptor; - - assert!(should_allow_js(&[ - &ModuleGraphFile { - specifier: "file:///some/file.ts".to_string(), - url: "file:///some/file.ts".to_string(), - redirect: None, - filename: "some/file.ts".to_string(), - imports: vec![], - version_hash: "1".to_string(), - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - media_type: MediaType::TypeScript, - source_code: "function foo() {}".to_string(), - }, - &ModuleGraphFile { - specifier: "file:///some/file1.js".to_string(), - url: "file:///some/file1.js".to_string(), - redirect: None, - filename: "some/file1.js".to_string(), - version_hash: "1".to_string(), - imports: vec![ImportDescriptor { - specifier: "./file.ts".to_string(), - resolved_specifier: ModuleSpecifier::resolve_url( - "file:///some/file.ts", - ) - .unwrap(), - type_directive: None, - resolved_type_directive: None, - location: Location { - filename: "file:///some/file1.js".to_string(), - line: 0, - col: 0, - }, - }], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - media_type: MediaType::JavaScript, - source_code: "function foo() {}".to_string(), - }, - ],)); - - assert!(should_allow_js(&[ - &ModuleGraphFile { - specifier: "file:///some/file.jsx".to_string(), - url: "file:///some/file.jsx".to_string(), - redirect: None, - filename: "some/file.jsx".to_string(), - imports: vec![], - version_hash: "1".to_string(), - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - media_type: MediaType::JSX, - source_code: "function foo() {}".to_string(), - }, - &ModuleGraphFile { - specifier: "file:///some/file.ts".to_string(), - url: "file:///some/file.ts".to_string(), - redirect: None, - filename: "some/file.ts".to_string(), - version_hash: "1".to_string(), - imports: vec![ImportDescriptor { - specifier: "./file.jsx".to_string(), - resolved_specifier: ModuleSpecifier::resolve_url( - "file:///some/file.jsx", - ) - .unwrap(), - type_directive: None, - resolved_type_directive: None, - location: Location { - filename: "file:///some/file1.ts".to_string(), - line: 0, - col: 0, - }, - }], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - media_type: MediaType::TypeScript, - source_code: "function foo() {}".to_string(), - }, - ])); - - assert!(!should_allow_js(&[ - &ModuleGraphFile { - specifier: "file:///some/file.js".to_string(), - url: "file:///some/file.js".to_string(), - redirect: None, - filename: "some/file.js".to_string(), - imports: vec![], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - version_hash: "1".to_string(), - type_headers: vec![], - media_type: MediaType::JavaScript, - source_code: "function foo() {}".to_string(), - }, - &ModuleGraphFile { - specifier: "file:///some/file1.js".to_string(), - url: "file:///some/file1.js".to_string(), - redirect: None, - filename: "some/file1.js".to_string(), - imports: vec![ImportDescriptor { - specifier: "./file.js".to_string(), - resolved_specifier: ModuleSpecifier::resolve_url( - "file:///some/file.js", - ) - .unwrap(), - type_directive: None, - resolved_type_directive: None, - location: Location { - filename: "file:///some/file.js".to_string(), - line: 0, - col: 0, - }, - }], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - version_hash: "1".to_string(), - type_headers: vec![], - media_type: MediaType::JavaScript, - source_code: "function foo() {}".to_string(), - }, - ],)); -} - -#[test] -fn test_needs_compilation() { - assert!(!needs_compilation( - false, - MediaType::JavaScript, - &[&ModuleGraphFile { - specifier: "some/file.js".to_string(), - url: "file:///some/file.js".to_string(), - redirect: None, - filename: "some/file.js".to_string(), - imports: vec![], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - version_hash: "1".to_string(), - media_type: MediaType::JavaScript, - source_code: "function foo() {}".to_string(), - }], - )); - - assert!(!needs_compilation(false, MediaType::JavaScript, &[])); - assert!(needs_compilation(true, MediaType::JavaScript, &[])); - assert!(needs_compilation(false, MediaType::TypeScript, &[])); - assert!(needs_compilation(false, MediaType::JSX, &[])); - assert!(needs_compilation(false, MediaType::TSX, &[])); - assert!(needs_compilation( - false, - MediaType::JavaScript, - &[ - &ModuleGraphFile { - specifier: "file:///some/file.ts".to_string(), - url: "file:///some/file.ts".to_string(), - redirect: None, - filename: "some/file.ts".to_string(), - imports: vec![], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - media_type: MediaType::TypeScript, - version_hash: "1".to_string(), - source_code: "function foo() {}".to_string(), - }, - &ModuleGraphFile { - specifier: "file:///some/file1.js".to_string(), - url: "file:///some/file1.js".to_string(), - redirect: None, - filename: "some/file1.js".to_string(), - imports: vec![], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - version_hash: "1".to_string(), - media_type: MediaType::JavaScript, - source_code: "function foo() {}".to_string(), - }, - ], - )); -} diff --git a/cli/main.rs b/cli/main.rs index f6bef9688..22dad6d25 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -23,7 +23,6 @@ mod flags_allow_net; mod fmt; mod fmt_errors; mod fs; -mod global_state; mod global_timer; mod http_cache; mod http_util; @@ -38,15 +37,16 @@ mod media_type; mod metrics; mod module_graph; mod module_graph2; +mod module_loader; mod op_fetch_asset; mod ops; mod permissions; +mod program_state; mod repl; mod resolve_addr; mod signal; mod source_maps; mod specifier_handler; -mod state; mod test_runner; mod text_encoding; mod tokio_util; @@ -61,9 +61,9 @@ use crate::coverage::PrettyCoverageReporter; use crate::file_fetcher::SourceFile; use crate::file_fetcher::SourceFileFetcher; use crate::fs as deno_fs; -use crate::global_state::GlobalState; use crate::media_type::MediaType; use crate::permissions::Permissions; +use crate::program_state::ProgramState; use crate::worker::MainWorker; use deno_core::error::AnyError; use deno_core::futures::future::FutureExt; @@ -77,10 +77,10 @@ use deno_doc as doc; use deno_doc::parser::DocFileLoader; use flags::DenoSubcommand; use flags::Flags; -use global_state::exit_unstable; use import_map::ImportMap; use log::Level; use log::LevelFilter; +use program_state::exit_unstable; use std::cell::RefCell; use std::env; use std::io::Read; @@ -113,7 +113,7 @@ where } fn print_cache_info( - state: &Arc, + state: &Arc, json: bool, ) -> Result<(), AnyError> { let deno_dir = &state.dir.root; @@ -167,19 +167,19 @@ async fn info_command( if json && !flags.unstable { exit_unstable("--json"); } - let global_state = GlobalState::new(flags)?; + let program_state = ProgramState::new(flags)?; if let Some(specifier) = maybe_specifier { let specifier = ModuleSpecifier::resolve_url_or_path(&specifier)?; let handler = Rc::new(RefCell::new(specifier_handler::FetchHandler::new( - &global_state, + &program_state, Permissions::allow_all(), )?)); let mut builder = module_graph2::GraphBuilder2::new( handler, - global_state.maybe_import_map.clone(), + program_state.maybe_import_map.clone(), ); builder.insert(&specifier).await?; - let graph = builder.get_graph(&global_state.lockfile)?; + let graph = builder.get_graph(&program_state.lockfile)?; let info = graph.info()?; if json { @@ -190,7 +190,7 @@ async fn info_command( Ok(()) } else { // If it was just "deno info" print location of caches and exit - print_cache_info(&global_state, json) + print_cache_info(&program_state, json) } } @@ -202,9 +202,9 @@ async fn install_command( root: Option, force: bool, ) -> Result<(), AnyError> { - let global_state = GlobalState::new(flags.clone())?; + let program_state = ProgramState::new(flags.clone())?; let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?; - let mut worker = MainWorker::new(&global_state, main_module.clone()); + let mut worker = MainWorker::new(&program_state, main_module.clone()); // First, fetch and compile the module; this step ensures that the module exists. worker.preload_module(&main_module).await?; installer::install(flags, &module_url, args, name, root, force) @@ -235,12 +235,12 @@ async fn cache_command( ) -> Result<(), AnyError> { let main_module = ModuleSpecifier::resolve_url_or_path("./$deno$cache.ts").unwrap(); - let global_state = GlobalState::new(flags)?; - let mut worker = MainWorker::new(&global_state, main_module.clone()); + let program_state = ProgramState::new(flags)?; + let mut worker = MainWorker::new(&program_state, main_module.clone()); for file in files { let specifier = ModuleSpecifier::resolve_url_or_path(&file)?; - // TODO(bartlomieju): don't use `preload_module` in favor of calling "GlobalState::prepare_module_load()" + // TODO(bartlomieju): don't use `preload_module` in favor of calling "ProgramState::prepare_module_load()" // explicitly? Seems wasteful to create multiple worker just to run TS compiler worker.preload_module(&specifier).await.map(|_| ())?; } @@ -257,8 +257,8 @@ async fn eval_command( // Force TypeScript compile. let main_module = ModuleSpecifier::resolve_url_or_path("./$deno$eval.ts").unwrap(); - let global_state = GlobalState::new(flags)?; - let mut worker = MainWorker::new(&global_state, main_module.clone()); + let program_state = ProgramState::new(flags)?; + let mut worker = MainWorker::new(&program_state, main_module.clone()); let main_module_url = main_module.as_url().to_owned(); // Create a dummy source file. let source_code = if print { @@ -281,7 +281,7 @@ async fn eval_command( }; // Save our fake file into file fetcher cache // to allow module access by TS compiler. - global_state + program_state .file_fetcher .save_source_file_in_cache(&main_module, source_file); debug!("main_module {}", &main_module); @@ -300,7 +300,7 @@ async fn bundle_command( let module_specifier = ModuleSpecifier::resolve_url_or_path(&source_file)?; debug!(">>>>> bundle START"); - let global_state = GlobalState::new(flags)?; + let program_state = ProgramState::new(flags)?; info!( "{} {}", @@ -308,9 +308,9 @@ async fn bundle_command( module_specifier.to_string() ); - let output = global_state + let output = program_state .ts_compiler - .bundle(&global_state, module_specifier) + .bundle(&program_state, module_specifier) .await?; debug!(">>>>> bundle END"); @@ -391,12 +391,12 @@ async fn doc_command( maybe_filter: Option, private: bool, ) -> Result<(), AnyError> { - let global_state = GlobalState::new(flags.clone())?; + let program_state = ProgramState::new(flags.clone())?; let source_file = source_file.unwrap_or_else(|| "--builtin".to_string()); let loader = Box::new(DocLoader { - fetcher: global_state.file_fetcher.clone(), - maybe_import_map: global_state.maybe_import_map.clone(), + fetcher: program_state.file_fetcher.clone(), + maybe_import_map: program_state.maybe_import_map.clone(), }); let doc_parser = doc::DocParser::new(loader, private); @@ -455,18 +455,18 @@ async fn doc_command( async fn run_repl(flags: Flags) -> Result<(), AnyError> { let main_module = ModuleSpecifier::resolve_url_or_path("./$deno$repl.ts").unwrap(); - let global_state = GlobalState::new(flags)?; - let mut worker = MainWorker::new(&global_state, main_module.clone()); + let program_state = ProgramState::new(flags)?; + let mut worker = MainWorker::new(&program_state, main_module.clone()); worker.run_event_loop().await?; - repl::run(&global_state, worker).await + repl::run(&program_state, worker).await } async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { - let global_state = GlobalState::new(flags.clone())?; + let program_state = ProgramState::new(flags.clone())?; let main_module = ModuleSpecifier::resolve_url_or_path("./$deno$stdin.ts").unwrap(); - let mut worker = MainWorker::new(&global_state.clone(), main_module.clone()); + let mut worker = MainWorker::new(&program_state.clone(), main_module.clone()); let mut source = Vec::new(); std::io::stdin().read_to_end(&mut source)?; @@ -481,7 +481,7 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { }; // Save our fake file into file fetcher cache // to allow module access by TS compiler - global_state + program_state .file_fetcher .save_source_file_in_cache(&main_module, source_file); @@ -495,11 +495,11 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { let main_module = ModuleSpecifier::resolve_url_or_path(&script)?; - let global_state = GlobalState::new(flags.clone())?; + let program_state = ProgramState::new(flags.clone())?; let mut module_graph_loader = module_graph::ModuleGraphLoader::new( - global_state.file_fetcher.clone(), - global_state.maybe_import_map.clone(), + program_state.file_fetcher.clone(), + program_state.maybe_import_map.clone(), Permissions::allow_all(), false, false, @@ -515,7 +515,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { .map(|url| url.to_file_path().unwrap()) .collect(); - if let Some(import_map) = global_state.flags.import_map_path.clone() { + if let Some(import_map) = program_state.flags.import_map_path.clone() { paths_to_watch.push( Url::parse(&format!("file://{}", &import_map))? .to_file_path() @@ -525,9 +525,9 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { // FIXME(bartlomieju): new file watcher is created on after each restart file_watcher::watch_func(&paths_to_watch, move || { - // FIXME(bartlomieju): GlobalState must be created on each restart - otherwise file fetcher + // FIXME(bartlomieju): ProgramState must be created on each restart - otherwise file fetcher // will use cached source files - let gs = GlobalState::new(flags.clone()).unwrap(); + let gs = ProgramState::new(flags.clone()).unwrap(); let main_module = main_module.clone(); async move { let mut worker = MainWorker::new(&gs, main_module.clone()); @@ -554,8 +554,8 @@ async fn run_command(flags: Flags, script: String) -> Result<(), AnyError> { } let main_module = ModuleSpecifier::resolve_url_or_path(&script)?; - let global_state = GlobalState::new(flags.clone())?; - let mut worker = MainWorker::new(&global_state, main_module.clone()); + let program_state = ProgramState::new(flags.clone())?; + let mut worker = MainWorker::new(&program_state, main_module.clone()); debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; @@ -572,7 +572,7 @@ async fn test_command( allow_none: bool, filter: Option, ) -> Result<(), AnyError> { - let global_state = GlobalState::new(flags.clone())?; + let program_state = ProgramState::new(flags.clone())?; let cwd = std::env::current_dir().expect("No current directory"); let include = include.unwrap_or_else(|| vec![".".to_string()]); let test_modules = test_runner::prepare_test_modules_urls(include, &cwd)?; @@ -596,7 +596,7 @@ async fn test_command( ); let main_module = ModuleSpecifier::resolve_url(&test_file_url.to_string()).unwrap(); - let mut worker = MainWorker::new(&global_state, main_module.clone()); + let mut worker = MainWorker::new(&program_state, main_module.clone()); // Create a dummy source file. let source_file = SourceFile { filename: test_file_url.to_file_path().unwrap(), @@ -607,7 +607,7 @@ async fn test_command( }; // Save our fake file into file fetcher cache // to allow module access by TS compiler - global_state + program_state .file_fetcher .save_source_file_in_cache(&main_module, source_file); diff --git a/cli/module_graph.rs b/cli/module_graph.rs index a0ecb6d40..22b629c1a 100644 --- a/cli/module_graph.rs +++ b/cli/module_graph.rs @@ -588,16 +588,16 @@ impl ModuleGraphLoader { #[cfg(test)] mod tests { use super::*; - use crate::global_state::GlobalState; + use crate::program_state::ProgramState; use deno_core::serde_json; use deno_core::serde_json::json; async fn build_graph( module_specifier: &ModuleSpecifier, ) -> Result { - let global_state = GlobalState::new(Default::default()).unwrap(); + let program_state = ProgramState::new(Default::default()).unwrap(); let mut graph_loader = ModuleGraphLoader::new( - global_state.file_fetcher.clone(), + program_state.file_fetcher.clone(), None, Permissions::allow_all(), false, diff --git a/cli/module_graph2.rs b/cli/module_graph2.rs index 5e82632b0..412519178 100644 --- a/cli/module_graph2.rs +++ b/cli/module_graph2.rs @@ -785,7 +785,7 @@ impl GraphBuilder2 { /// graph. /// /// TODO(@kitsonk) this should really be owned by the graph, but currently - /// the lockfile is behind a mutex in global_state, which makes it really + /// the lockfile is behind a mutex in program_state, which makes it really /// hard to not pass around as a reference, which if the Graph owned it, it /// would need lifetime parameters and lifetime parameters are 😭 pub fn get_graph( diff --git a/cli/module_loader.rs b/cli/module_loader.rs new file mode 100644 index 000000000..3cbcade2a --- /dev/null +++ b/cli/module_loader.rs @@ -0,0 +1,160 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use crate::import_map::ImportMap; +use crate::permissions::Permissions; +use crate::program_state::ProgramState; +use crate::tsc::TargetLib; +use deno_core::error::AnyError; +use deno_core::futures::future::FutureExt; +use deno_core::futures::Future; +use deno_core::ModuleLoadId; +use deno_core::ModuleLoader; +use deno_core::ModuleSpecifier; +use deno_core::OpState; +use std::cell::RefCell; +use std::pin::Pin; +use std::rc::Rc; +use std::str; +use std::sync::Arc; + +pub struct CliModuleLoader { + /// When flags contains a `.import_map_path` option, the content of the + /// import map file will be resolved and set. + pub import_map: Option, + pub target_lib: TargetLib, + pub is_main: bool, +} + +impl CliModuleLoader { + pub fn new(maybe_import_map: Option) -> Rc { + Rc::new(CliModuleLoader { + import_map: maybe_import_map, + target_lib: TargetLib::Main, + is_main: true, + }) + } + + pub fn new_for_worker() -> Rc { + Rc::new(CliModuleLoader { + import_map: None, + target_lib: TargetLib::Worker, + is_main: false, + }) + } +} + +impl ModuleLoader for CliModuleLoader { + fn resolve( + &self, + op_state: Rc>, + specifier: &str, + referrer: &str, + is_main: bool, + ) -> Result { + let program_state = { + let state = op_state.borrow(); + state.borrow::>().clone() + }; + + // FIXME(bartlomieju): hacky way to provide compatibility with repl + let referrer = if referrer.is_empty() && program_state.flags.repl { + "" + } else { + referrer + }; + + if !is_main { + if let Some(import_map) = &self.import_map { + let result = import_map.resolve(specifier, referrer)?; + if let Some(r) = result { + return Ok(r); + } + } + } + + let module_specifier = + ModuleSpecifier::resolve_import(specifier, referrer)?; + + Ok(module_specifier) + } + + fn load( + &self, + op_state: Rc>, + module_specifier: &ModuleSpecifier, + maybe_referrer: Option, + _is_dyn_import: bool, + ) -> Pin> { + let module_specifier = module_specifier.to_owned(); + let module_url_specified = module_specifier.to_string(); + let program_state = { + let state = op_state.borrow(); + state.borrow::>().clone() + }; + + // TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param + let fut = async move { + let compiled_module = program_state + .fetch_compiled_module(module_specifier, maybe_referrer) + .await?; + Ok(deno_core::ModuleSource { + // Real module name, might be different from initial specifier + // due to redirections. + code: compiled_module.code, + module_url_specified, + module_url_found: compiled_module.name, + }) + }; + + fut.boxed_local() + } + + fn prepare_load( + &self, + op_state: Rc>, + _load_id: ModuleLoadId, + module_specifier: &ModuleSpecifier, + maybe_referrer: Option, + is_dyn_import: bool, + ) -> Pin>>> { + let module_specifier = module_specifier.clone(); + let target_lib = self.target_lib.clone(); + let maybe_import_map = self.import_map.clone(); + let state = op_state.borrow(); + + // Only "main" module is loaded without permission check, + // ie. module that is associated with "is_main" state + // and is not a dynamic import. + let permissions = if self.is_main && !is_dyn_import { + Permissions::allow_all() + } else { + state.borrow::().clone() + }; + let program_state = state.borrow::>().clone(); + drop(state); + + // TODO(bartlomieju): I'm not sure if it's correct to ignore + // bad referrer - this is the case for `Deno.core.evalContext()` where + // `ref_str` is ``. + let maybe_referrer = if let Some(ref_str) = maybe_referrer { + ModuleSpecifier::resolve_url(&ref_str).ok() + } else { + None + }; + + // TODO(bartlomieju): `prepare_module_load` should take `load_id` param + async move { + program_state + .prepare_module_load( + module_specifier, + maybe_referrer, + target_lib, + permissions, + is_dyn_import, + maybe_import_map, + ) + .await + } + .boxed_local() + } +} diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index 40ea01370..04281e383 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -39,7 +39,7 @@ fn op_apply_source_map( args.line_number.into(), args.column_number.into(), &mut mappings_map, - &super::global_state(state).ts_compiler, + &super::program_state(state).ts_compiler, ); Ok(json!({ diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index b1ec5c344..f5f42a2d7 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -26,8 +26,8 @@ pub mod web_worker; pub mod websocket; pub mod worker_host; -use crate::global_state::GlobalState; use crate::metrics::metrics_op; +use crate::program_state::ProgramState; use deno_core::error::AnyError; use deno_core::json_op_async; use deno_core::json_op_sync; @@ -59,22 +59,22 @@ where /// Helper for checking unstable features. Used for sync ops. pub fn check_unstable(state: &OpState, api_name: &str) { - state.borrow::>().check_unstable(api_name) + state.borrow::>().check_unstable(api_name) } /// Helper for checking unstable features. Used for async ops. pub fn check_unstable2(state: &Rc>, api_name: &str) { let state = state.borrow(); - state.borrow::>().check_unstable(api_name) + state.borrow::>().check_unstable(api_name) } /// Helper for extracting the commonly used state. Used for sync ops. -pub fn global_state(state: &OpState) -> Arc { - state.borrow::>().clone() +pub fn program_state(state: &OpState) -> Arc { + state.borrow::>().clone() } /// Helper for extracting the commonly used state. Used for async ops. -pub fn global_state2(state: &Rc>) -> Arc { +pub fn global_state2(state: &Rc>) -> Arc { let state = state.borrow(); - state.borrow::>().clone() + state.borrow::>().clone() } diff --git a/cli/ops/runtime.rs b/cli/ops/runtime.rs index 3f7398479..3d7350361 100644 --- a/cli/ops/runtime.rs +++ b/cli/ops/runtime.rs @@ -29,7 +29,7 @@ fn op_start( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result { - let gs = &super::global_state(state); + let gs = &super::program_state(state); Ok(json!({ // TODO(bartlomieju): `cwd` field is not used in JS, remove? diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index b06e51157..b01469fa9 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -37,14 +37,14 @@ async fn op_compile( super::check_unstable2(&state, "Deno.compile"); let args: CompileArgs = serde_json::from_value(args)?; let cli_state = super::global_state2(&state); - let global_state = cli_state.clone(); + let program_state = cli_state.clone(); let permissions = { let state = state.borrow(); state.borrow::().clone() }; let fut = if args.bundle { runtime_bundle( - &global_state, + &program_state, permissions, &args.root_name, &args.sources, @@ -53,7 +53,7 @@ async fn op_compile( .boxed_local() } else { runtime_compile( - &global_state, + &program_state, permissions, &args.root_name, &args.sources, @@ -79,8 +79,8 @@ async fn op_transpile( super::check_unstable2(&state, "Deno.transpile"); let args: TranspileArgs = serde_json::from_value(args)?; let cli_state = super::global_state2(&state); - let global_state = cli_state.clone(); + let program_state = cli_state.clone(); let result = - runtime_transpile(global_state, &args.sources, &args.options).await?; + runtime_transpile(program_state, &args.sources, &args.options).await?; Ok(result) } diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index 5de15f153..8ebf8b9e6 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -1,9 +1,9 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::fmt_errors::JsError; -use crate::global_state::GlobalState; use crate::ops::io::get_stdio; use crate::permissions::Permissions; +use crate::program_state::ProgramState; use crate::tokio_util::create_basic_runtime; use crate::worker::WebWorker; use crate::worker::WebWorkerHandle; @@ -48,7 +48,7 @@ pub type WorkerId = u32; fn create_web_worker( worker_id: u32, name: String, - global_state: &Arc, + program_state: &Arc, permissions: Permissions, specifier: ModuleSpecifier, has_deno_namespace: bool, @@ -57,7 +57,7 @@ fn create_web_worker( name.clone(), permissions, specifier, - global_state.clone(), + program_state.clone(), has_deno_namespace, ); @@ -91,13 +91,13 @@ fn create_web_worker( fn run_worker_thread( worker_id: u32, name: String, - global_state: &Arc, + program_state: &Arc, permissions: Permissions, specifier: ModuleSpecifier, has_deno_namespace: bool, maybe_source_code: Option, ) -> Result<(JoinHandle<()>, WebWorkerHandle), AnyError> { - let global_state = global_state.clone(); + let program_state = program_state.clone(); let (handle_sender, handle_receiver) = std::sync::mpsc::sync_channel::>(1); @@ -111,7 +111,7 @@ fn run_worker_thread( let result = create_web_worker( worker_id, name, - &global_state, + &program_state, permissions, specifier.clone(), has_deno_namespace, @@ -211,7 +211,7 @@ fn op_create_worker( let module_specifier = ModuleSpecifier::resolve_url(&specifier)?; let worker_name = args_name.unwrap_or_else(|| "".to_string()); - let cli_state = super::global_state(state); + let cli_state = super::program_state(state); let (join_handle, worker_handle) = run_worker_thread( worker_id, diff --git a/cli/permissions.rs b/cli/permissions.rs index ae020c7af..2eebdba9a 100644 --- a/cli/permissions.rs +++ b/cli/permissions.rs @@ -83,7 +83,7 @@ impl Default for PermissionState { #[derive(Clone, Debug, Default, Deserialize, PartialEq)] pub struct UnaryPermission { - pub global_state: PermissionState, + pub program_state: PermissionState, pub granted_list: HashSet, pub denied_list: HashSet, } @@ -110,17 +110,17 @@ impl Permissions { pub fn from_flags(flags: &Flags) -> Self { Self { read: UnaryPermission:: { - global_state: PermissionState::from(flags.allow_read), + program_state: PermissionState::from(flags.allow_read), granted_list: resolve_fs_allowlist(&flags.read_allowlist), ..Default::default() }, write: UnaryPermission:: { - global_state: PermissionState::from(flags.allow_write), + program_state: PermissionState::from(flags.allow_write), granted_list: resolve_fs_allowlist(&flags.write_allowlist), ..Default::default() }, net: UnaryPermission:: { - global_state: PermissionState::from(flags.allow_net), + program_state: PermissionState::from(flags.allow_net), granted_list: flags.net_allowlist.iter().cloned().collect(), ..Default::default() }, @@ -152,15 +152,15 @@ impl Permissions { pub fn allow_all() -> Self { Self { read: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, write: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, net: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, env: PermissionState::Granted, @@ -172,7 +172,7 @@ impl Permissions { pub fn query_read(&self, path: &Option<&Path>) -> PermissionState { let path = path.map(|p| resolve_from_cwd(p).unwrap()); - if self.read.global_state == PermissionState::Denied + if self.read.program_state == PermissionState::Denied && match path.as_ref() { None => true, Some(path) => check_path_blocklist(path, &self.read.denied_list), @@ -180,7 +180,7 @@ impl Permissions { { return PermissionState::Denied; } - if self.read.global_state == PermissionState::Granted + if self.read.program_state == PermissionState::Granted || match path.as_ref() { None => false, Some(path) => check_path_allowlist(path, &self.read.granted_list), @@ -193,7 +193,7 @@ impl Permissions { pub fn query_write(&self, path: &Option<&Path>) -> PermissionState { let path = path.map(|p| resolve_from_cwd(p).unwrap()); - if self.write.global_state == PermissionState::Denied + if self.write.program_state == PermissionState::Denied && match path.as_ref() { None => true, Some(path) => check_path_blocklist(path, &self.write.denied_list), @@ -201,7 +201,7 @@ impl Permissions { { return PermissionState::Denied; } - if self.write.global_state == PermissionState::Granted + if self.write.program_state == PermissionState::Granted || match path.as_ref() { None => false, Some(path) => check_path_allowlist(path, &self.write.granted_list), @@ -213,12 +213,12 @@ impl Permissions { } pub fn query_net(&self, host: &str, port: Option) -> PermissionState { - if self.net.global_state == PermissionState::Denied + if self.net.program_state == PermissionState::Denied || check_host_and_port_list(host, port, &self.net.denied_list) { return PermissionState::Denied; } - if self.net.global_state == PermissionState::Granted + if self.net.program_state == PermissionState::Granted || check_host_and_port_list(host, port, &self.net.granted_list) { return PermissionState::Granted; @@ -231,7 +231,7 @@ impl Permissions { url: &Option<&str>, ) -> Result { if url.is_none() { - return Ok(self.net.global_state); + return Ok(self.net.program_state); } let url: &str = url.unwrap(); // If url is invalid, then throw a TypeError. @@ -287,7 +287,7 @@ impl Permissions { .denied_list .retain(|path| !resolved_path.starts_with(path)); self.read.denied_list.insert(resolved_path); - self.read.global_state = PermissionState::Denied; + self.read.program_state = PermissionState::Denied; return PermissionState::Denied; } } @@ -297,10 +297,10 @@ impl Permissions { if state == PermissionState::Prompt { if permission_prompt("Deno requests read access") { self.read.granted_list.clear(); - self.read.global_state = PermissionState::Granted; + self.read.program_state = PermissionState::Granted; return PermissionState::Granted; } else { - self.read.global_state = PermissionState::Denied; + self.read.program_state = PermissionState::Denied; return PermissionState::Denied; } } @@ -329,7 +329,7 @@ impl Permissions { .denied_list .retain(|path| !resolved_path.starts_with(path)); self.write.denied_list.insert(resolved_path); - self.write.global_state = PermissionState::Denied; + self.write.program_state = PermissionState::Denied; return PermissionState::Denied; } } @@ -339,10 +339,10 @@ impl Permissions { if state == PermissionState::Prompt { if permission_prompt("Deno requests write access") { self.write.granted_list.clear(); - self.write.global_state = PermissionState::Granted; + self.write.program_state = PermissionState::Granted; return PermissionState::Granted; } else { - self.write.global_state = PermissionState::Denied; + self.write.program_state = PermissionState::Denied; return PermissionState::Denied; } } @@ -365,7 +365,7 @@ impl Permissions { return Ok(PermissionState::Granted); } else { self.net.denied_list.insert(url.to_string()); - self.net.global_state = PermissionState::Denied; + self.net.program_state = PermissionState::Denied; return Ok(PermissionState::Denied); } } @@ -375,10 +375,10 @@ impl Permissions { if state == PermissionState::Prompt { if permission_prompt("Deno requests network access") { self.net.granted_list.clear(); - self.net.global_state = PermissionState::Granted; + self.net.program_state = PermissionState::Granted; return Ok(PermissionState::Granted); } else { - self.net.global_state = PermissionState::Denied; + self.net.program_state = PermissionState::Denied; return Ok(PermissionState::Denied); } } @@ -439,8 +439,8 @@ impl Permissions { .retain(|path_| !path_.starts_with(&path)); } else { self.read.granted_list.clear(); - if self.read.global_state == PermissionState::Granted { - self.read.global_state = PermissionState::Prompt; + if self.read.program_state == PermissionState::Granted { + self.read.program_state = PermissionState::Prompt; } } self.query_read(path) @@ -455,8 +455,8 @@ impl Permissions { .retain(|path_| !path_.starts_with(&path)); } else { self.write.granted_list.clear(); - if self.write.global_state == PermissionState::Granted { - self.write.global_state = PermissionState::Prompt; + if self.write.program_state == PermissionState::Granted { + self.write.program_state = PermissionState::Prompt; } } self.query_write(path) @@ -470,8 +470,8 @@ impl Permissions { self.net.granted_list.remove(*url); } else { self.net.granted_list.clear(); - if self.net.global_state == PermissionState::Granted { - self.net.global_state = PermissionState::Prompt; + if self.net.program_state == PermissionState::Granted { + self.net.program_state = PermissionState::Prompt; } } self.query_net_url(url) @@ -835,17 +835,17 @@ mod tests { let json_perms = r#" { "read": { - "global_state": "Granted", + "program_state": "Granted", "granted_list": [], "denied_list": [] }, "write": { - "global_state": "Granted", + "program_state": "Granted", "granted_list": [], "denied_list": [] }, "net": { - "global_state": "Granted", + "program_state": "Granted", "granted_list": [], "denied_list": [] }, @@ -857,15 +857,15 @@ mod tests { "#; let perms0 = Permissions { read: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, write: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, net: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, env: PermissionState::Granted, @@ -882,15 +882,15 @@ mod tests { fn test_query() { let perms1 = Permissions { read: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, write: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, net: UnaryPermission { - global_state: PermissionState::Granted, + program_state: PermissionState::Granted, ..Default::default() }, env: PermissionState::Granted, @@ -900,17 +900,17 @@ mod tests { }; let perms2 = Permissions { read: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]), ..Default::default() }, write: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]), ..Default::default() }, net: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, granted_list: ["127.0.0.1:8000".to_string()].iter().cloned().collect(), ..Default::default() }, @@ -950,15 +950,15 @@ mod tests { fn test_request() { let mut perms = Permissions { read: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, ..Default::default() }, write: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, ..Default::default() }, net: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, ..Default::default() }, env: PermissionState::Prompt, @@ -1006,17 +1006,17 @@ mod tests { fn test_revoke() { let mut perms = Permissions { read: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]), ..Default::default() }, write: UnaryPermission { - global_state: PermissionState::Prompt, + program_state: PermissionState::Prompt, granted_list: resolve_fs_allowlist(&[PathBuf::from("/foo")]), ..Default::default() }, net: UnaryPermission { - global_state: PermissionState::Denied, + program_state: PermissionState::Denied, ..Default::default() }, env: PermissionState::Granted, diff --git a/cli/program_state.rs b/cli/program_state.rs new file mode 100644 index 000000000..f81ed88bb --- /dev/null +++ b/cli/program_state.rs @@ -0,0 +1,538 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use crate::deno_dir; +use crate::file_fetcher::SourceFileFetcher; +use crate::flags; +use crate::http_cache; +use crate::import_map::ImportMap; +use crate::inspector::InspectorServer; +use crate::lockfile::Lockfile; +use crate::media_type::MediaType; +use crate::module_graph::ModuleGraphFile; +use crate::module_graph::ModuleGraphLoader; +use crate::module_graph2::GraphBuilder2; +use crate::module_graph2::TranspileOptions; +use crate::permissions::Permissions; +use crate::specifier_handler::FetchHandler; +use crate::tsc::CompiledModule; +use crate::tsc::TargetLib; +use crate::tsc::TsCompiler; +use deno_core::error::AnyError; +use deno_core::ModuleSpecifier; +use std::cell::RefCell; +use std::env; +use std::rc::Rc; +use std::sync::Arc; +use std::sync::Mutex; + +pub fn exit_unstable(api_name: &str) { + eprintln!( + "Unstable API '{}'. The --unstable flag must be provided.", + api_name + ); + std::process::exit(70); +} + +/// This structure represents state of single "deno" program. +/// +/// It is shared by all created workers (thus V8 isolates). +pub struct ProgramState { + /// Flags parsed from `argv` contents. + pub flags: flags::Flags, + /// Permissions parsed from `flags`. + pub permissions: Permissions, + pub dir: deno_dir::DenoDir, + pub file_fetcher: SourceFileFetcher, + pub ts_compiler: TsCompiler, + pub lockfile: Option>, + pub maybe_import_map: Option, + pub maybe_inspector_server: Option>, +} + +impl ProgramState { + pub fn new(flags: flags::Flags) -> Result, AnyError> { + let custom_root = env::var("DENO_DIR").map(String::into).ok(); + let dir = deno_dir::DenoDir::new(custom_root)?; + let deps_cache_location = dir.root.join("deps"); + let http_cache = http_cache::HttpCache::new(&deps_cache_location); + let ca_file = flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok()); + + let file_fetcher = SourceFileFetcher::new( + http_cache, + !flags.reload, + flags.cache_blocklist.clone(), + flags.no_remote, + flags.cached_only, + ca_file.as_deref(), + )?; + + let ts_compiler = TsCompiler::new( + file_fetcher.clone(), + flags.clone(), + dir.gen_cache.clone(), + )?; + + let lockfile = if let Some(filename) = &flags.lock { + let lockfile = Lockfile::new(filename.clone(), flags.lock_write)?; + Some(Mutex::new(lockfile)) + } else { + None + }; + + let maybe_import_map: Option = + match flags.import_map_path.as_ref() { + None => None, + Some(file_path) => { + if !flags.unstable { + exit_unstable("--importmap") + } + Some(ImportMap::load(file_path)?) + } + }; + + let maybe_inspect_host = flags.inspect.or(flags.inspect_brk); + let maybe_inspector_server = match maybe_inspect_host { + Some(host) => Some(Arc::new(InspectorServer::new(host))), + None => None, + }; + + let program_state = ProgramState { + dir, + permissions: Permissions::from_flags(&flags), + flags, + file_fetcher, + ts_compiler, + lockfile, + maybe_import_map, + maybe_inspector_server, + }; + Ok(Arc::new(program_state)) + } + + /// This function is called when new module load is + /// initialized by the JsRuntime. Its resposibility is to collect + /// all dependencies and if it is required then also perform TS typecheck + /// and traspilation. + pub async fn prepare_module_load( + self: &Arc, + module_specifier: ModuleSpecifier, + maybe_referrer: Option, + target_lib: TargetLib, + permissions: Permissions, + is_dyn_import: bool, + maybe_import_map: Option, + ) -> Result<(), AnyError> { + let module_specifier = module_specifier.clone(); + + if self.flags.no_check { + debug!("Transpiling root: {}", module_specifier); + // TODO(kitsonk) note that self.permissions != permissions, which is + // something that should be handled better in the future. + let handler = + Rc::new(RefCell::new(FetchHandler::new(self, permissions.clone())?)); + let mut builder = GraphBuilder2::new(handler, maybe_import_map); + builder.insert(&module_specifier).await?; + let mut graph = builder.get_graph(&self.lockfile)?; + + let (stats, maybe_ignored_options) = + graph.transpile(TranspileOptions { + debug: self.flags.log_level == Some(log::Level::Debug), + maybe_config_path: self.flags.config_path.clone(), + })?; + + if let Some(ignored_options) = maybe_ignored_options { + eprintln!("{}", ignored_options); + } + + debug!("{}", stats); + } else { + let mut module_graph_loader = ModuleGraphLoader::new( + self.file_fetcher.clone(), + maybe_import_map, + permissions.clone(), + is_dyn_import, + false, + ); + module_graph_loader + .add_to_graph(&module_specifier, maybe_referrer) + .await?; + let module_graph = module_graph_loader.get_graph(); + + let out = self + .file_fetcher + .fetch_cached_source_file(&module_specifier, permissions.clone()) + .expect("Source file not found"); + + let module_graph_files = module_graph.values().collect::>(); + // Check integrity of every file in module graph + if let Some(ref lockfile) = self.lockfile { + let mut g = lockfile.lock().unwrap(); + + for graph_file in &module_graph_files { + let check_passed = + g.check_or_insert(&graph_file.url, &graph_file.source_code); + + if !check_passed { + eprintln!( + "Subresource integrity check failed --lock={}\n{}", + g.filename, graph_file.url + ); + std::process::exit(10); + } + } + } + + // Check if we need to compile files. + let should_compile = needs_compilation( + self.ts_compiler.compile_js, + out.media_type, + &module_graph_files, + ); + let allow_js = should_allow_js(&module_graph_files); + + if should_compile { + self + .ts_compiler + .compile(self, &out, target_lib, &module_graph, allow_js) + .await?; + } + } + + if let Some(ref lockfile) = self.lockfile { + let g = lockfile.lock().unwrap(); + g.write()?; + } + + Ok(()) + } + + // TODO(bartlomieju): this method doesn't need to be async anymore + /// This method is used after `prepare_module_load` finishes and JsRuntime + /// starts loading source and executing source code. This method shouldn't + /// perform any IO (besides $DENO_DIR) and only operate on sources collected + /// during `prepare_module_load`. + pub async fn fetch_compiled_module( + &self, + module_specifier: ModuleSpecifier, + _maybe_referrer: Option, + ) -> Result { + let out = self + .file_fetcher + .fetch_cached_source_file(&module_specifier, Permissions::allow_all()) + .expect("Cached source file doesn't exist"); + + // Check if we need to compile files + let was_compiled = match out.media_type { + MediaType::TypeScript | MediaType::TSX | MediaType::JSX => true, + MediaType::JavaScript => self.ts_compiler.compile_js, + _ => false, + }; + + let compiled_module = if was_compiled { + match self.ts_compiler.get_compiled_module(&out.url) { + Ok(module) => module, + Err(e) => { + let msg = format!( + "Failed to get compiled source code of \"{}\".\nReason: {}\n\ + If the source file provides only type exports, prefer to use \"import type\" or \"export type\" syntax instead.", + out.url, e.to_string() + ); + info!("{} {}", crate::colors::yellow("Warning"), msg); + + CompiledModule { + code: "".to_string(), + name: out.url.to_string(), + } + } + } + } else { + CompiledModule { + code: out.source_code, + name: out.url.to_string(), + } + }; + + Ok(compiled_module) + } + + /// Quits the process if the --unstable flag was not provided. + /// + /// This is intentionally a non-recoverable check so that people cannot probe + /// for unstable APIs from stable programs. + pub fn check_unstable(&self, api_name: &str) { + if !self.flags.unstable { + exit_unstable(api_name); + } + } + + #[cfg(test)] + pub fn mock( + argv: Vec, + maybe_flags: Option, + ) -> Arc { + ProgramState::new(flags::Flags { + argv, + ..maybe_flags.unwrap_or_default() + }) + .unwrap() + } +} + +/// Determine if TS compiler should be run with `allowJs` setting on. This +/// is the case when there's either: +/// - a JavaScript file with non-JavaScript import +/// - JSX import +fn should_allow_js(module_graph_files: &[&ModuleGraphFile]) -> bool { + module_graph_files.iter().any(|module_file| { + if module_file.media_type == MediaType::JSX { + true + } else if module_file.media_type == MediaType::JavaScript { + module_file.imports.iter().any(|import_desc| { + let import_file = module_graph_files + .iter() + .find(|f| { + f.specifier == import_desc.resolved_specifier.to_string().as_str() + }) + .expect("Failed to find imported file"); + let media_type = import_file.media_type; + media_type == MediaType::TypeScript + || media_type == MediaType::TSX + || media_type == MediaType::JSX + }) + } else { + false + } + }) +} + +// Compilation happens if either: +// - `checkJs` is set to true in TS config +// - entry point is a TS file +// - any dependency in module graph is a TS file +fn needs_compilation( + compile_js: bool, + media_type: MediaType, + module_graph_files: &[&ModuleGraphFile], +) -> bool { + let mut needs_compilation = match media_type { + MediaType::TypeScript | MediaType::TSX | MediaType::JSX => true, + MediaType::JavaScript => compile_js, + _ => false, + }; + + needs_compilation |= module_graph_files.iter().any(|module_file| { + let media_type = module_file.media_type; + + media_type == (MediaType::TypeScript) + || media_type == (MediaType::TSX) + || media_type == (MediaType::JSX) + }); + + needs_compilation +} + +#[test] +fn thread_safe() { + fn f(_: S) {} + f(ProgramState::mock(vec![], None)); +} + +#[test] +fn test_should_allow_js() { + use crate::ast::Location; + use crate::module_graph::ImportDescriptor; + + assert!(should_allow_js(&[ + &ModuleGraphFile { + specifier: "file:///some/file.ts".to_string(), + url: "file:///some/file.ts".to_string(), + redirect: None, + filename: "some/file.ts".to_string(), + imports: vec![], + version_hash: "1".to_string(), + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + media_type: MediaType::TypeScript, + source_code: "function foo() {}".to_string(), + }, + &ModuleGraphFile { + specifier: "file:///some/file1.js".to_string(), + url: "file:///some/file1.js".to_string(), + redirect: None, + filename: "some/file1.js".to_string(), + version_hash: "1".to_string(), + imports: vec![ImportDescriptor { + specifier: "./file.ts".to_string(), + resolved_specifier: ModuleSpecifier::resolve_url( + "file:///some/file.ts", + ) + .unwrap(), + type_directive: None, + resolved_type_directive: None, + location: Location { + filename: "file:///some/file1.js".to_string(), + line: 0, + col: 0, + }, + }], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + media_type: MediaType::JavaScript, + source_code: "function foo() {}".to_string(), + }, + ],)); + + assert!(should_allow_js(&[ + &ModuleGraphFile { + specifier: "file:///some/file.jsx".to_string(), + url: "file:///some/file.jsx".to_string(), + redirect: None, + filename: "some/file.jsx".to_string(), + imports: vec![], + version_hash: "1".to_string(), + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + media_type: MediaType::JSX, + source_code: "function foo() {}".to_string(), + }, + &ModuleGraphFile { + specifier: "file:///some/file.ts".to_string(), + url: "file:///some/file.ts".to_string(), + redirect: None, + filename: "some/file.ts".to_string(), + version_hash: "1".to_string(), + imports: vec![ImportDescriptor { + specifier: "./file.jsx".to_string(), + resolved_specifier: ModuleSpecifier::resolve_url( + "file:///some/file.jsx", + ) + .unwrap(), + type_directive: None, + resolved_type_directive: None, + location: Location { + filename: "file:///some/file1.ts".to_string(), + line: 0, + col: 0, + }, + }], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + media_type: MediaType::TypeScript, + source_code: "function foo() {}".to_string(), + }, + ])); + + assert!(!should_allow_js(&[ + &ModuleGraphFile { + specifier: "file:///some/file.js".to_string(), + url: "file:///some/file.js".to_string(), + redirect: None, + filename: "some/file.js".to_string(), + imports: vec![], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + version_hash: "1".to_string(), + type_headers: vec![], + media_type: MediaType::JavaScript, + source_code: "function foo() {}".to_string(), + }, + &ModuleGraphFile { + specifier: "file:///some/file1.js".to_string(), + url: "file:///some/file1.js".to_string(), + redirect: None, + filename: "some/file1.js".to_string(), + imports: vec![ImportDescriptor { + specifier: "./file.js".to_string(), + resolved_specifier: ModuleSpecifier::resolve_url( + "file:///some/file.js", + ) + .unwrap(), + type_directive: None, + resolved_type_directive: None, + location: Location { + filename: "file:///some/file.js".to_string(), + line: 0, + col: 0, + }, + }], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + version_hash: "1".to_string(), + type_headers: vec![], + media_type: MediaType::JavaScript, + source_code: "function foo() {}".to_string(), + }, + ],)); +} + +#[test] +fn test_needs_compilation() { + assert!(!needs_compilation( + false, + MediaType::JavaScript, + &[&ModuleGraphFile { + specifier: "some/file.js".to_string(), + url: "file:///some/file.js".to_string(), + redirect: None, + filename: "some/file.js".to_string(), + imports: vec![], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + version_hash: "1".to_string(), + media_type: MediaType::JavaScript, + source_code: "function foo() {}".to_string(), + }], + )); + + assert!(!needs_compilation(false, MediaType::JavaScript, &[])); + assert!(needs_compilation(true, MediaType::JavaScript, &[])); + assert!(needs_compilation(false, MediaType::TypeScript, &[])); + assert!(needs_compilation(false, MediaType::JSX, &[])); + assert!(needs_compilation(false, MediaType::TSX, &[])); + assert!(needs_compilation( + false, + MediaType::JavaScript, + &[ + &ModuleGraphFile { + specifier: "file:///some/file.ts".to_string(), + url: "file:///some/file.ts".to_string(), + redirect: None, + filename: "some/file.ts".to_string(), + imports: vec![], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + media_type: MediaType::TypeScript, + version_hash: "1".to_string(), + source_code: "function foo() {}".to_string(), + }, + &ModuleGraphFile { + specifier: "file:///some/file1.js".to_string(), + url: "file:///some/file1.js".to_string(), + redirect: None, + filename: "some/file1.js".to_string(), + imports: vec![], + referenced_files: vec![], + lib_directives: vec![], + types_directives: vec![], + type_headers: vec![], + version_hash: "1".to_string(), + media_type: MediaType::JavaScript, + source_code: "function foo() {}".to_string(), + }, + ], + )); +} diff --git a/cli/repl.rs b/cli/repl.rs index 697f679f6..3355bbac0 100644 --- a/cli/repl.rs +++ b/cli/repl.rs @@ -1,7 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::global_state::GlobalState; use crate::inspector::InspectorSession; +use crate::program_state::ProgramState; use crate::worker::MainWorker; use crate::worker::Worker; use deno_core::error::AnyError; @@ -86,12 +86,12 @@ async fn read_line_and_poll( } pub async fn run( - global_state: &GlobalState, + program_state: &ProgramState, mut worker: MainWorker, ) -> Result<(), AnyError> { let mut session = worker.create_inspector_session(); - let history_file = global_state.dir.root.join("deno_history.txt"); + let history_file = program_state.dir.root.join("deno_history.txt"); post_message_and_poll(&mut *worker, &mut session, "Runtime.enable", None) .await?; diff --git a/cli/specifier_handler.rs b/cli/specifier_handler.rs index 2b81e1a2f..0671112f9 100644 --- a/cli/specifier_handler.rs +++ b/cli/specifier_handler.rs @@ -3,9 +3,9 @@ use crate::deno_dir::DenoDir; use crate::disk_cache::DiskCache; use crate::file_fetcher::SourceFileFetcher; -use crate::global_state::GlobalState; use crate::media_type::MediaType; use crate::permissions::Permissions; +use crate::program_state::ProgramState; use deno_core::error::AnyError; use deno_core::futures::Future; @@ -175,13 +175,13 @@ pub struct FetchHandler { impl FetchHandler { pub fn new( - global_state: &Arc, + program_state: &Arc, permissions: Permissions, ) -> Result { let custom_root = env::var("DENO_DIR").map(String::into).ok(); let deno_dir = DenoDir::new(custom_root)?; let disk_cache = deno_dir.gen_cache; - let file_fetcher = global_state.file_fetcher.clone(); + let file_fetcher = program_state.file_fetcher.clone(); Ok(FetchHandler { disk_cache, diff --git a/cli/state.rs b/cli/state.rs deleted file mode 100644 index ef63dad97..000000000 --- a/cli/state.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -use crate::global_state::GlobalState; -use crate::import_map::ImportMap; -use crate::permissions::Permissions; -use crate::tsc::TargetLib; -use deno_core::error::AnyError; -use deno_core::futures::future::FutureExt; -use deno_core::futures::Future; -use deno_core::ModuleLoadId; -use deno_core::ModuleLoader; -use deno_core::ModuleSpecifier; -use deno_core::OpState; -use std::cell::RefCell; -use std::pin::Pin; -use std::rc::Rc; -use std::str; -use std::sync::Arc; - -pub struct CliModuleLoader { - /// When flags contains a `.import_map_path` option, the content of the - /// import map file will be resolved and set. - pub import_map: Option, - pub target_lib: TargetLib, - pub is_main: bool, -} - -impl CliModuleLoader { - pub fn new(maybe_import_map: Option) -> Rc { - Rc::new(CliModuleLoader { - import_map: maybe_import_map, - target_lib: TargetLib::Main, - is_main: true, - }) - } - - pub fn new_for_worker() -> Rc { - Rc::new(CliModuleLoader { - import_map: None, - target_lib: TargetLib::Worker, - is_main: false, - }) - } -} - -impl ModuleLoader for CliModuleLoader { - fn resolve( - &self, - op_state: Rc>, - specifier: &str, - referrer: &str, - is_main: bool, - ) -> Result { - let global_state = { - let state = op_state.borrow(); - state.borrow::>().clone() - }; - - // FIXME(bartlomieju): hacky way to provide compatibility with repl - let referrer = if referrer.is_empty() && global_state.flags.repl { - "" - } else { - referrer - }; - - if !is_main { - if let Some(import_map) = &self.import_map { - let result = import_map.resolve(specifier, referrer)?; - if let Some(r) = result { - return Ok(r); - } - } - } - - let module_specifier = - ModuleSpecifier::resolve_import(specifier, referrer)?; - - Ok(module_specifier) - } - - fn load( - &self, - op_state: Rc>, - module_specifier: &ModuleSpecifier, - maybe_referrer: Option, - _is_dyn_import: bool, - ) -> Pin> { - let module_specifier = module_specifier.to_owned(); - let module_url_specified = module_specifier.to_string(); - let global_state = { - let state = op_state.borrow(); - state.borrow::>().clone() - }; - - // TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param - let fut = async move { - let compiled_module = global_state - .fetch_compiled_module(module_specifier, maybe_referrer) - .await?; - Ok(deno_core::ModuleSource { - // Real module name, might be different from initial specifier - // due to redirections. - code: compiled_module.code, - module_url_specified, - module_url_found: compiled_module.name, - }) - }; - - fut.boxed_local() - } - - fn prepare_load( - &self, - op_state: Rc>, - _load_id: ModuleLoadId, - module_specifier: &ModuleSpecifier, - maybe_referrer: Option, - is_dyn_import: bool, - ) -> Pin>>> { - let module_specifier = module_specifier.clone(); - let target_lib = self.target_lib.clone(); - let maybe_import_map = self.import_map.clone(); - let state = op_state.borrow(); - - // Only "main" module is loaded without permission check, - // ie. module that is associated with "is_main" state - // and is not a dynamic import. - let permissions = if self.is_main && !is_dyn_import { - Permissions::allow_all() - } else { - state.borrow::().clone() - }; - let global_state = state.borrow::>().clone(); - drop(state); - - // TODO(bartlomieju): I'm not sure if it's correct to ignore - // bad referrer - this is the case for `Deno.core.evalContext()` where - // `ref_str` is ``. - let maybe_referrer = if let Some(ref_str) = maybe_referrer { - ModuleSpecifier::resolve_url(&ref_str).ok() - } else { - None - }; - - // TODO(bartlomieju): `prepare_module_load` should take `load_id` param - async move { - global_state - .prepare_module_load( - module_specifier, - maybe_referrer, - target_lib, - permissions, - is_dyn_import, - maybe_import_map, - ) - .await - } - .boxed_local() - } -} diff --git a/cli/tsc.rs b/cli/tsc.rs index aa83da280..24511fe6a 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -8,12 +8,12 @@ use crate::disk_cache::DiskCache; use crate::file_fetcher::SourceFile; use crate::file_fetcher::SourceFileFetcher; use crate::flags::Flags; -use crate::global_state::GlobalState; use crate::js; use crate::media_type::MediaType; use crate::module_graph::ModuleGraph; use crate::module_graph::ModuleGraphLoader; use crate::permissions::Permissions; +use crate::program_state::ProgramState; use crate::source_maps::SourceMapGetter; use crate::tsc_config; use crate::version; @@ -449,7 +449,7 @@ impl TsCompiler { /// compiler. pub async fn compile( &self, - global_state: &Arc, + program_state: &Arc, source_file: &SourceFile, target: TargetLib, module_graph: &ModuleGraph, @@ -533,7 +533,7 @@ impl TsCompiler { let req_msg = j.to_string(); - let json_str = execute_in_tsc(global_state.clone(), req_msg)?; + let json_str = execute_in_tsc(program_state.clone(), req_msg)?; let compile_response: CompileResponse = serde_json::from_str(&json_str)?; @@ -554,7 +554,7 @@ impl TsCompiler { /// all the dependencies for that module. pub async fn bundle( &self, - global_state: &Arc, + program_state: &Arc, module_specifier: ModuleSpecifier, ) -> Result { debug!( @@ -565,7 +565,7 @@ impl TsCompiler { let permissions = Permissions::allow_all(); let mut module_graph_loader = ModuleGraphLoader::new( self.file_fetcher.clone(), - global_state.maybe_import_map.clone(), + program_state.maybe_import_map.clone(), permissions.clone(), false, true, @@ -576,7 +576,7 @@ impl TsCompiler { let module_graph = module_graph_loader.get_graph(); let module_graph_files = module_graph.values().collect::>(); // Check integrity of every file in module graph - if let Some(ref lockfile) = global_state.lockfile { + if let Some(ref lockfile) = program_state.lockfile { let mut g = lockfile.lock().unwrap(); for graph_file in &module_graph_files { @@ -592,7 +592,7 @@ impl TsCompiler { } } } - if let Some(ref lockfile) = global_state.lockfile { + if let Some(ref lockfile) = program_state.lockfile { let g = lockfile.lock().unwrap(); g.write()?; } @@ -602,7 +602,7 @@ impl TsCompiler { let root_names = vec![module_specifier.to_string()]; let target = "main"; let performance = - matches!(global_state.flags.log_level, Some(Level::Debug)); + matches!(program_state.flags.log_level, Some(Level::Debug)); let unstable = self.flags.unstable; let mut lib = if target == "main" { @@ -649,7 +649,7 @@ impl TsCompiler { let req_msg = j.to_string(); - let json_str = execute_in_tsc(global_state.clone(), req_msg)?; + let json_str = execute_in_tsc(program_state.clone(), req_msg)?; let bundle_response: BundleResponse = serde_json::from_str(&json_str)?; @@ -945,7 +945,7 @@ struct CreateHashArgs { } fn execute_in_tsc( - global_state: Arc, + program_state: Arc, req: String, ) -> Result { let mut js_runtime = JsRuntime::new(RuntimeOptions { @@ -953,7 +953,7 @@ fn execute_in_tsc( ..Default::default() }); - let debug_flag = global_state + let debug_flag = program_state .flags .log_level .map_or(false, |l| l == log::Level::Debug); @@ -1006,7 +1006,7 @@ fn execute_in_tsc( } async fn create_runtime_module_graph( - global_state: &Arc, + program_state: &Arc, permissions: Permissions, root_name: &str, sources: &Option>, @@ -1014,7 +1014,7 @@ async fn create_runtime_module_graph( ) -> Result<(Vec, ModuleGraph), AnyError> { let mut root_names = vec![]; let mut module_graph_loader = ModuleGraphLoader::new( - global_state.file_fetcher.clone(), + program_state.file_fetcher.clone(), None, permissions, false, @@ -1057,7 +1057,7 @@ fn extract_js_error(error: AnyError) -> AnyError { /// This function is used by `Deno.compile()` API. pub async fn runtime_compile( - global_state: &Arc, + program_state: &Arc, permissions: Permissions, root_name: &str, sources: &Option>, @@ -1082,7 +1082,7 @@ pub async fn runtime_compile( vec![] }; - let unstable = global_state.flags.unstable; + let unstable = program_state.flags.unstable; let mut lib = vec![]; if let Some(user_libs) = user_options["lib"].take().as_array() { @@ -1119,7 +1119,7 @@ pub async fn runtime_compile( tsc_config::json_merge(&mut compiler_options, &json!({ "lib": lib })); let (root_names, module_graph) = create_runtime_module_graph( - &global_state, + &program_state, permissions.clone(), root_name, sources, @@ -1138,10 +1138,10 @@ pub async fn runtime_compile( }) .to_string(); - let compiler = global_state.ts_compiler.clone(); + let compiler = program_state.ts_compiler.clone(); let json_str = - execute_in_tsc(global_state.clone(), req_msg).map_err(extract_js_error)?; + execute_in_tsc(program_state.clone(), req_msg).map_err(extract_js_error)?; let response: RuntimeCompileResponse = serde_json::from_str(&json_str)?; if response.diagnostics.0.is_empty() && sources.is_none() { @@ -1156,7 +1156,7 @@ pub async fn runtime_compile( /// This function is used by `Deno.bundle()` API. pub async fn runtime_bundle( - global_state: &Arc, + program_state: &Arc, permissions: Permissions, root_name: &str, sources: &Option>, @@ -1182,7 +1182,7 @@ pub async fn runtime_bundle( }; let (root_names, module_graph) = create_runtime_module_graph( - &global_state, + &program_state, permissions.clone(), root_name, sources, @@ -1192,7 +1192,7 @@ pub async fn runtime_bundle( let module_graph_json = serde_json::to_value(module_graph).expect("Failed to serialize data"); - let unstable = global_state.flags.unstable; + let unstable = program_state.flags.unstable; let mut lib = vec![]; if let Some(user_libs) = user_options["lib"].take().as_array() { @@ -1248,7 +1248,7 @@ pub async fn runtime_bundle( .to_string(); let json_str = - execute_in_tsc(global_state.clone(), req_msg).map_err(extract_js_error)?; + execute_in_tsc(program_state.clone(), req_msg).map_err(extract_js_error)?; let _response: RuntimeBundleResponse = serde_json::from_str(&json_str)?; // We're returning `Ok()` instead of `Err()` because it's not runtime // error if there were diagnostics produced; we want to let user handle @@ -1258,7 +1258,7 @@ pub async fn runtime_bundle( /// This function is used by `Deno.transpileOnly()` API. pub async fn runtime_transpile( - global_state: Arc, + program_state: Arc, sources: &HashMap, maybe_options: &Option, ) -> Result { @@ -1285,7 +1285,7 @@ pub async fn runtime_transpile( .to_string(); let json_str = - execute_in_tsc(global_state, req_msg).map_err(extract_js_error)?; + execute_in_tsc(program_state, req_msg).map_err(extract_js_error)?; let v = serde_json::from_str::(&json_str) .expect("Error decoding JSON string."); Ok(v) @@ -1451,8 +1451,8 @@ mod tests { use super::*; use crate::deno_dir; use crate::fs as deno_fs; - use crate::global_state::GlobalState; use crate::http_cache; + use crate::program_state::ProgramState; use deno_core::ModuleSpecifier; use std::path::PathBuf; use tempfile::TempDir; @@ -1533,7 +1533,7 @@ mod tests { deno_dir::DenoDir::new(Some(test_util::new_deno_dir().path().to_owned())) .unwrap(); let http_cache = http_cache::HttpCache::new(&dir.root.join("deps")); - let mock_state = GlobalState::mock( + let mock_state = ProgramState::mock( vec![String::from("deno"), String::from("hello.ts")], None, ); @@ -1593,7 +1593,7 @@ mod tests { let module_name = ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap(); - let mock_state = GlobalState::mock( + let mock_state = ProgramState::mock( vec![ String::from("deno"), p.to_string_lossy().into(), diff --git a/cli/worker.rs b/cli/worker.rs index 8cf175cc5..97e39d20c 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -1,15 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::fmt_errors::JsError; -use crate::global_state::GlobalState; use crate::inspector::DenoInspector; use crate::inspector::InspectorSession; use crate::js; use crate::metrics::Metrics; +use crate::module_loader::CliModuleLoader; use crate::ops; use crate::ops::io::get_stdio; use crate::permissions::Permissions; -use crate::state::CliModuleLoader; +use crate::program_state::ProgramState; use deno_core::error::AnyError; use deno_core::futures::channel::mpsc; use deno_core::futures::future::poll_fn; @@ -110,11 +110,11 @@ impl Worker { pub fn new( name: String, startup_snapshot: Snapshot, - global_state: Arc, + program_state: Arc, module_loader: Rc, is_main: bool, ) -> Self { - let global_state_ = global_state.clone(); + let global_state_ = program_state.clone(); let mut js_runtime = JsRuntime::new(RuntimeOptions { module_loader: Some(module_loader), @@ -131,12 +131,12 @@ impl Worker { } let inspector = - if let Some(inspector_server) = &global_state.maybe_inspector_server { + if let Some(inspector_server) = &program_state.maybe_inspector_server { Some(DenoInspector::new( &mut js_runtime, Some(inspector_server.clone()), )) - } else if global_state.flags.coverage || global_state.flags.repl { + } else if program_state.flags.coverage || program_state.flags.repl { Some(DenoInspector::new(&mut js_runtime, None)) } else { None @@ -144,7 +144,7 @@ impl Worker { let should_break_on_first_statement = inspector.is_some() && is_main - && global_state.flags.inspect_brk.is_some(); + && program_state.flags.inspect_brk.is_some(); let (internal_channels, external_channels) = create_channels(); @@ -250,14 +250,14 @@ pub struct MainWorker(Worker); impl MainWorker { pub fn new( - global_state: &Arc, + program_state: &Arc, main_module: ModuleSpecifier, ) -> Self { - let loader = CliModuleLoader::new(global_state.maybe_import_map.clone()); + let loader = CliModuleLoader::new(program_state.maybe_import_map.clone()); let mut worker = Worker::new( "main".to_string(), js::deno_isolate_init(), - global_state.clone(), + program_state.clone(), loader, true, ); @@ -268,15 +268,15 @@ impl MainWorker { let op_state = js_runtime.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put::(Default::default()); - op_state.put::>(global_state.clone()); - op_state.put::(global_state.permissions.clone()); + op_state.put::>(program_state.clone()); + op_state.put::(program_state.permissions.clone()); } ops::runtime::init(js_runtime, main_module); - ops::fetch::init(js_runtime, global_state.flags.ca_file.as_deref()); + ops::fetch::init(js_runtime, program_state.flags.ca_file.as_deref()); ops::timers::init(js_runtime); ops::worker_host::init(js_runtime); - ops::random::init(js_runtime, global_state.flags.seed); + ops::random::init(js_runtime, program_state.flags.seed); ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close); ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources); ops::reg_json_sync( @@ -399,14 +399,14 @@ impl WebWorker { name: String, permissions: Permissions, main_module: ModuleSpecifier, - global_state: Arc, + program_state: Arc, has_deno_namespace: bool, ) -> Self { let loader = CliModuleLoader::new_for_worker(); let mut worker = Worker::new( name, js::deno_isolate_init(), - global_state.clone(), + program_state.clone(), loader, false, ); @@ -439,13 +439,13 @@ impl WebWorker { let op_state = js_runtime.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put::(Default::default()); - op_state.put::>(global_state.clone()); + op_state.put::>(program_state.clone()); op_state.put::(permissions); } ops::web_worker::init(js_runtime, sender, handle); ops::runtime::init(js_runtime, main_module); - ops::fetch::init(js_runtime, global_state.flags.ca_file.as_deref()); + ops::fetch::init(js_runtime, program_state.flags.ca_file.as_deref()); ops::timers::init(js_runtime); ops::worker_host::init(js_runtime); ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close); @@ -467,7 +467,7 @@ impl WebWorker { ops::permissions::init(js_runtime); ops::plugin::init(js_runtime); ops::process::init(js_runtime); - ops::random::init(js_runtime, global_state.flags.seed); + ops::random::init(js_runtime, program_state.flags.seed); ops::runtime_compiler::init(js_runtime); ops::signal::init(js_runtime); ops::tls::init(js_runtime); @@ -579,7 +579,7 @@ mod tests { use super::*; use crate::flags::DenoSubcommand; use crate::flags::Flags; - use crate::global_state::GlobalState; + use crate::program_state::ProgramState; use crate::tokio_util; use crate::worker::WorkerEvent; use deno_core::serde_json::json; @@ -593,8 +593,9 @@ mod tests { }, ..Default::default() }; - let global_state = GlobalState::mock(vec!["deno".to_string()], Some(flags)); - MainWorker::new(&global_state, main_module) + let program_state = + ProgramState::mock(vec!["deno".to_string()], Some(flags)); + MainWorker::new(&program_state, main_module) } #[tokio::test] @@ -680,12 +681,12 @@ mod tests { fn create_test_web_worker() -> WebWorker { let main_module = ModuleSpecifier::resolve_url_or_path("./hello.js").unwrap(); - let global_state = GlobalState::mock(vec!["deno".to_string()], None); + let program_state = ProgramState::mock(vec!["deno".to_string()], None); let mut worker = WebWorker::new( "TEST".to_string(), Permissions::allow_all(), main_module, - global_state, + program_state, false, ); worker -- cgit v1.2.3