diff options
Diffstat (limited to 'cli/module_graph.rs')
-rw-r--r-- | cli/module_graph.rs | 968 |
1 files changed, 0 insertions, 968 deletions
diff --git a/cli/module_graph.rs b/cli/module_graph.rs deleted file mode 100644 index f0645424e..000000000 --- a/cli/module_graph.rs +++ /dev/null @@ -1,968 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -use crate::ast::Location; -use crate::checksum; -use crate::file_fetcher::SourceFile; -use crate::file_fetcher::SourceFileFetcher; -use crate::import_map::ImportMap; -use crate::media_type::MediaType; -use crate::permissions::Permissions; -use crate::tsc::pre_process_file; -use crate::tsc::ImportDesc; -use crate::tsc::TsReferenceDesc; -use crate::tsc::TsReferenceKind; -use crate::tsc::AVAILABLE_LIBS; -use crate::version; -use deno_core::error::custom_error; -use deno_core::error::generic_error; -use deno_core::error::AnyError; -use deno_core::futures::stream::FuturesUnordered; -use deno_core::futures::stream::StreamExt; -use deno_core::futures::Future; -use deno_core::futures::FutureExt; -use deno_core::ModuleSpecifier; -use serde::Serialize; -use serde::Serializer; -use std::collections::HashMap; -use std::collections::HashSet; -use std::pin::Pin; - -// TODO(bartlomieju): it'd be great if this function returned -// more structured data and possibly format the same as TS diagnostics. -/// Decorate error with location of import that caused the error. -fn err_with_location( - e: AnyError, - maybe_location: Option<&Location>, -) -> AnyError { - if let Some(location) = maybe_location { - let location_str = format!( - "\nImported from \"{}:{}\"", - location.filename, location.line - ); - let err_str = e.to_string(); - generic_error(format!("{}{}", err_str, location_str)) - } else { - e - } -} - -/// Disallow http:// imports from modules loaded over https:// -fn validate_no_downgrade( - module_specifier: &ModuleSpecifier, - maybe_referrer: Option<&ModuleSpecifier>, - maybe_location: Option<&Location>, -) -> Result<(), AnyError> { - if let Some(referrer) = maybe_referrer.as_ref() { - if let "https" = referrer.as_url().scheme() { - if let "http" = module_specifier.as_url().scheme() { - let e = custom_error("PermissionDenied", - "Modules loaded over https:// are not allowed to import modules over http://" - ); - return Err(err_with_location(e, maybe_location)); - }; - }; - }; - - Ok(()) -} - -/// Verify that remote file doesn't try to statically import local file. -fn validate_no_file_from_remote( - module_specifier: &ModuleSpecifier, - maybe_referrer: Option<&ModuleSpecifier>, - maybe_location: Option<&Location>, -) -> Result<(), AnyError> { - if let Some(referrer) = maybe_referrer.as_ref() { - let referrer_url = referrer.as_url(); - match referrer_url.scheme() { - "http" | "https" => { - let specifier_url = module_specifier.as_url(); - match specifier_url.scheme() { - "http" | "https" => {} - _ => { - let e = custom_error( - "PermissionDenied", - "Remote modules are not allowed to statically import local \ - modules. Use dynamic import instead.", - ); - return Err(err_with_location(e, maybe_location)); - } - } - } - _ => {} - } - } - - Ok(()) -} - -// TODO(bartlomieju): handle imports/references in ambient contexts/TS modules -// https://github.com/denoland/deno/issues/6133 -fn resolve_imports_and_references( - referrer: ModuleSpecifier, - maybe_import_map: Option<&ImportMap>, - import_descs: Vec<ImportDesc>, - ref_descs: Vec<TsReferenceDesc>, -) -> Result<(Vec<ImportDescriptor>, Vec<ReferenceDescriptor>), AnyError> { - let mut imports = vec![]; - let mut references = vec![]; - - for import_desc in import_descs { - let maybe_resolved = if let Some(import_map) = maybe_import_map.as_ref() { - import_map.resolve(&import_desc.specifier, &referrer.to_string())? - } else { - None - }; - - let resolved_specifier = if let Some(resolved) = maybe_resolved { - resolved - } else { - ModuleSpecifier::resolve_import( - &import_desc.specifier, - &referrer.to_string(), - )? - }; - - let resolved_type_directive = - if let Some(types_specifier) = import_desc.deno_types.as_ref() { - Some(ModuleSpecifier::resolve_import( - &types_specifier, - &referrer.to_string(), - )?) - } else { - None - }; - - let import_descriptor = ImportDescriptor { - specifier: import_desc.specifier.to_string(), - resolved_specifier, - type_directive: import_desc.deno_types.clone(), - resolved_type_directive, - location: import_desc.location, - }; - - imports.push(import_descriptor); - } - - for ref_desc in ref_descs { - if AVAILABLE_LIBS.contains(&ref_desc.specifier.as_str()) { - continue; - } - - let resolved_specifier = ModuleSpecifier::resolve_import( - &ref_desc.specifier, - &referrer.to_string(), - )?; - - let reference_descriptor = ReferenceDescriptor { - specifier: ref_desc.specifier.to_string(), - resolved_specifier, - kind: ref_desc.kind, - location: ref_desc.location, - }; - - references.push(reference_descriptor); - } - - Ok((imports, references)) -} - -fn serialize_module_specifier<S>( - spec: &ModuleSpecifier, - s: S, -) -> Result<S::Ok, S::Error> -where - S: Serializer, -{ - s.serialize_str(&spec.to_string()) -} - -fn serialize_option_module_specifier<S>( - maybe_spec: &Option<ModuleSpecifier>, - s: S, -) -> Result<S::Ok, S::Error> -where - S: Serializer, -{ - if let Some(spec) = maybe_spec { - serialize_module_specifier(spec, s) - } else { - s.serialize_none() - } -} - -const SUPPORTED_MEDIA_TYPES: [MediaType; 4] = [ - MediaType::JavaScript, - MediaType::TypeScript, - MediaType::JSX, - MediaType::TSX, -]; - -pub type ModuleGraph = HashMap<String, ModuleGraphFile>; - -#[derive(Clone, Debug, Serialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct ImportDescriptor { - pub specifier: String, - #[serde(serialize_with = "serialize_module_specifier")] - pub resolved_specifier: ModuleSpecifier, - // These two fields are for support of @deno-types directive - // directly prepending import statement - pub type_directive: Option<String>, - #[serde(serialize_with = "serialize_option_module_specifier")] - pub resolved_type_directive: Option<ModuleSpecifier>, - #[serde(skip)] - pub location: Location, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ReferenceDescriptor { - pub specifier: String, - #[serde(serialize_with = "serialize_module_specifier")] - pub resolved_specifier: ModuleSpecifier, - #[serde(skip)] - pub kind: TsReferenceKind, - #[serde(skip)] - pub location: Location, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ModuleGraphFile { - pub specifier: String, - pub url: String, - pub redirect: Option<String>, - pub filename: String, - pub version_hash: String, - pub imports: Vec<ImportDescriptor>, - pub referenced_files: Vec<ReferenceDescriptor>, - pub lib_directives: Vec<ReferenceDescriptor>, - pub types_directives: Vec<ReferenceDescriptor>, - pub type_headers: Vec<ReferenceDescriptor>, - pub media_type: MediaType, - pub source_code: String, -} - -type SourceFileFuture = Pin< - Box<dyn Future<Output = Result<(ModuleSpecifier, SourceFile), AnyError>>>, ->; - -pub struct ModuleGraphLoader { - permissions: Permissions, - file_fetcher: SourceFileFetcher, - maybe_import_map: Option<ImportMap>, - pending_downloads: FuturesUnordered<SourceFileFuture>, - has_downloaded: HashSet<ModuleSpecifier>, - graph: ModuleGraph, - is_dyn_import: bool, - analyze_dynamic_imports: bool, -} - -impl ModuleGraphLoader { - pub fn new( - file_fetcher: SourceFileFetcher, - maybe_import_map: Option<ImportMap>, - permissions: Permissions, - is_dyn_import: bool, - analyze_dynamic_imports: bool, - ) -> Self { - Self { - file_fetcher, - permissions, - maybe_import_map, - pending_downloads: FuturesUnordered::new(), - has_downloaded: HashSet::new(), - graph: ModuleGraph::new(), - is_dyn_import, - analyze_dynamic_imports, - } - } - - /// This method is used to add specified module and all of its - /// dependencies to the graph. - /// - /// It resolves when all dependent modules have been fetched and analyzed. - /// - /// This method can be called multiple times. - pub async fn add_to_graph( - &mut self, - specifier: &ModuleSpecifier, - maybe_referrer: Option<ModuleSpecifier>, - ) -> Result<(), AnyError> { - self.download_module(specifier.clone(), maybe_referrer, None)?; - - loop { - let (specifier, source_file) = - self.pending_downloads.next().await.unwrap()?; - self.visit_module(&specifier, source_file)?; - if self.pending_downloads.is_empty() { - break; - } - } - - Ok(()) - } - - /// This method is used to create a graph from in-memory files stored in - /// a hash map. Useful for creating module graph for code received from - /// the runtime. - pub fn build_local_graph( - &mut self, - _root_name: &str, - source_map: &HashMap<String, String>, - ) -> Result<(), AnyError> { - for (spec, source_code) in source_map.iter() { - self.visit_memory_module(spec.to_string(), source_code.to_string())?; - } - - Ok(()) - } - - /// Consumes the loader and returns created graph. - pub fn get_graph(self) -> ModuleGraph { - self.graph - } - - fn visit_memory_module( - &mut self, - specifier: String, - source_code: String, - ) -> Result<(), AnyError> { - let mut referenced_files = vec![]; - let mut lib_directives = vec![]; - let mut types_directives = vec![]; - - // FIXME(bartlomieju): - // The resolveModules op only handles fully qualified URLs for referrer. - // However we will have cases where referrer is "/foo.ts". We add this dummy - // prefix "memory://" in order to use resolution logic. - let module_specifier = - if let Ok(spec) = ModuleSpecifier::resolve_url(&specifier) { - spec - } else { - ModuleSpecifier::resolve_url(&format!("memory://{}", specifier))? - }; - - let (raw_imports, raw_references) = pre_process_file( - &module_specifier.to_string(), - MediaType::from(&specifier), - &source_code, - self.analyze_dynamic_imports, - )?; - let (imports, references) = resolve_imports_and_references( - module_specifier.clone(), - self.maybe_import_map.as_ref(), - raw_imports, - raw_references, - )?; - - for ref_descriptor in references { - match ref_descriptor.kind { - TsReferenceKind::Lib => { - lib_directives.push(ref_descriptor); - } - TsReferenceKind::Types => { - types_directives.push(ref_descriptor); - } - TsReferenceKind::Path => { - referenced_files.push(ref_descriptor); - } - } - } - - self.graph.insert( - module_specifier.to_string(), - ModuleGraphFile { - specifier: specifier.to_string(), - url: specifier.to_string(), - redirect: None, - version_hash: "".to_string(), - media_type: MediaType::from(&specifier), - filename: specifier, - source_code, - imports, - referenced_files, - lib_directives, - types_directives, - type_headers: vec![], - }, - ); - Ok(()) - } - - // TODO(bartlomieju): decorate errors with import location in the source code - // https://github.com/denoland/deno/issues/5080 - fn download_module( - &mut self, - module_specifier: ModuleSpecifier, - maybe_referrer: Option<ModuleSpecifier>, - maybe_location: Option<Location>, - ) -> Result<(), AnyError> { - if self.has_downloaded.contains(&module_specifier) { - return Ok(()); - } - - validate_no_downgrade( - &module_specifier, - maybe_referrer.as_ref(), - maybe_location.as_ref(), - )?; - - if !self.is_dyn_import { - validate_no_file_from_remote( - &module_specifier, - maybe_referrer.as_ref(), - maybe_location.as_ref(), - )?; - } - - self.has_downloaded.insert(module_specifier.clone()); - let spec = module_specifier; - let file_fetcher = self.file_fetcher.clone(); - let perms = self.permissions.clone(); - - let load_future = async move { - let spec_ = spec.clone(); - let source_file = file_fetcher - .fetch_source_file(&spec_, maybe_referrer, perms) - .await - .map_err(|e| err_with_location(e, maybe_location.as_ref()))?; - - Ok((spec_.clone(), source_file)) - } - .boxed_local(); - - self.pending_downloads.push(load_future); - Ok(()) - } - - fn visit_module( - &mut self, - module_specifier: &ModuleSpecifier, - source_file: SourceFile, - ) -> Result<(), AnyError> { - let mut imports = vec![]; - let mut referenced_files = vec![]; - let mut lib_directives = vec![]; - let mut types_directives = vec![]; - let mut type_headers = vec![]; - - // IMPORTANT: source_file.url might be different than requested - // module_specifier because of HTTP redirects. In such - // situation we add an "empty" ModuleGraphFile with 'redirect' - // field set that will be later used in TS worker when building - // map of available source file. It will perform substitution - // for proper URL point to redirect target. - if module_specifier.as_url() != &source_file.url { - // TODO(bartlomieju): refactor, this is a band-aid - self.graph.insert( - module_specifier.to_string(), - ModuleGraphFile { - specifier: module_specifier.to_string(), - url: module_specifier.to_string(), - redirect: Some(source_file.url.to_string()), - filename: source_file.filename.to_str().unwrap().to_string(), - version_hash: checksum::gen(&[ - &source_file.source_code.as_bytes(), - &version::DENO.as_bytes(), - ]), - media_type: source_file.media_type, - source_code: "".to_string(), - imports: vec![], - referenced_files: vec![], - lib_directives: vec![], - types_directives: vec![], - type_headers: vec![], - }, - ); - } - - let module_specifier = ModuleSpecifier::from(source_file.url.clone()); - let version_hash = checksum::gen(&[ - &source_file.source_code.as_bytes(), - &version::DENO.as_bytes(), - ]); - let source_code = source_file.source_code.clone(); - - if SUPPORTED_MEDIA_TYPES.contains(&source_file.media_type) { - if let Some(types_specifier) = source_file.types_header { - let type_header = ReferenceDescriptor { - specifier: types_specifier.to_string(), - resolved_specifier: ModuleSpecifier::resolve_import( - &types_specifier, - &module_specifier.to_string(), - )?, - kind: TsReferenceKind::Types, - // TODO(bartlomieju): location is not needed in here and constructing - // location by hand is bad - location: Location { - filename: module_specifier.to_string(), - line: 0, - col: 0, - }, - }; - self.download_module( - type_header.resolved_specifier.clone(), - Some(module_specifier.clone()), - None, - )?; - type_headers.push(type_header); - } - - let (raw_imports, raw_refs) = pre_process_file( - &module_specifier.to_string(), - source_file.media_type, - &source_code, - self.analyze_dynamic_imports, - )?; - let (imports_, references) = resolve_imports_and_references( - module_specifier.clone(), - self.maybe_import_map.as_ref(), - raw_imports, - raw_refs, - )?; - - for import_descriptor in imports_ { - self.download_module( - import_descriptor.resolved_specifier.clone(), - Some(module_specifier.clone()), - Some(import_descriptor.location.clone()), - )?; - - if let Some(type_dir_url) = - import_descriptor.resolved_type_directive.as_ref() - { - self.download_module( - type_dir_url.clone(), - Some(module_specifier.clone()), - Some(import_descriptor.location.clone()), - )?; - } - - imports.push(import_descriptor); - } - - for ref_descriptor in references { - self.download_module( - ref_descriptor.resolved_specifier.clone(), - Some(module_specifier.clone()), - Some(ref_descriptor.location.clone()), - )?; - - match ref_descriptor.kind { - TsReferenceKind::Lib => { - lib_directives.push(ref_descriptor); - } - TsReferenceKind::Types => { - types_directives.push(ref_descriptor); - } - TsReferenceKind::Path => { - referenced_files.push(ref_descriptor); - } - } - } - } - - self.graph.insert( - module_specifier.to_string(), - ModuleGraphFile { - specifier: module_specifier.to_string(), - url: module_specifier.to_string(), - redirect: None, - version_hash, - filename: source_file.filename.to_str().unwrap().to_string(), - media_type: source_file.media_type, - source_code, - imports, - referenced_files, - lib_directives, - types_directives, - type_headers, - }, - ); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::program_state::ProgramState; - use deno_core::serde_json; - use deno_core::serde_json::json; - - async fn build_graph( - module_specifier: &ModuleSpecifier, - ) -> Result<ModuleGraph, AnyError> { - let program_state = ProgramState::new(Default::default()).unwrap(); - let mut graph_loader = ModuleGraphLoader::new( - program_state.file_fetcher.clone(), - None, - Permissions::allow_all(), - false, - false, - ); - graph_loader.add_to_graph(&module_specifier, None).await?; - Ok(graph_loader.get_graph()) - } - - // TODO(bartlomieju): this test is flaky, because it's using 019_media_types - // file, reenable once Python server is replaced with Rust one. - #[ignore] - #[tokio::test] - async fn source_graph_fetch() { - let _http_server_guard = test_util::http_server(); - - let module_specifier = ModuleSpecifier::resolve_url_or_path( - "http://localhost:4545/cli/tests/019_media_types.ts", - ) - .unwrap(); - let graph = build_graph(&module_specifier) - .await - .expect("Failed to build graph"); - - let a = graph - .get("http://localhost:4545/cli/tests/019_media_types.ts") - .unwrap(); - - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/mt_text_ecmascript.j3.js" - )); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/mt_video_vdn.t2.ts" - )); - assert!(graph.contains_key("http://localhost:4545/cli/tests/subdir/mt_application_x_typescript.t4.ts")); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/mt_video_mp2t.t3.ts" - )); - assert!(graph.contains_key("http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js")); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/mt_application_ecmascript.j2.js" - )); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/mt_text_javascript.j1.js" - )); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/mt_text_typescript.t1.ts" - )); - - assert_eq!( - serde_json::to_value(&a.imports).unwrap(), - json!([ - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_text_typescript.t1.ts", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_text_typescript.t1.ts", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_video_vdn.t2.ts", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_video_vdn.t2.ts", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_video_mp2t.t3.ts", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_video_mp2t.t3.ts", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_application_x_typescript.t4.ts", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_application_x_typescript.t4.ts", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_text_javascript.j1.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_text_javascript.j1.js", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_application_ecmascript.j2.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_application_ecmascript.j2.js", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_text_ecmascript.j3.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_text_ecmascript.j3.js", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - { - "specifier": "http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - ]) - ); - } - - #[tokio::test] - async fn source_graph_type_references() { - let _http_server_guard = test_util::http_server(); - - let module_specifier = ModuleSpecifier::resolve_url_or_path( - "http://localhost:4545/cli/tests/type_definitions.ts", - ) - .unwrap(); - - let graph = build_graph(&module_specifier) - .await - .expect("Failed to build graph"); - - eprintln!("json {:#?}", serde_json::to_value(&graph).unwrap()); - - let a = graph - .get("http://localhost:4545/cli/tests/type_definitions.ts") - .unwrap(); - assert_eq!( - serde_json::to_value(&a.imports).unwrap(), - json!([ - { - "specifier": "./type_definitions/foo.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/type_definitions/foo.js", - "typeDirective": "./type_definitions/foo.d.ts", - "resolvedTypeDirective": "http://localhost:4545/cli/tests/type_definitions/foo.d.ts" - }, - { - "specifier": "./type_definitions/fizz.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/type_definitions/fizz.js", - "typeDirective": "./type_definitions/fizz.d.ts", - "resolvedTypeDirective": "http://localhost:4545/cli/tests/type_definitions/fizz.d.ts" - }, - { - "specifier": "./type_definitions/qat.ts", - "resolvedSpecifier": "http://localhost:4545/cli/tests/type_definitions/qat.ts", - "typeDirective": null, - "resolvedTypeDirective": null, - }, - ]) - ); - assert!(graph - .contains_key("http://localhost:4545/cli/tests/type_definitions/foo.js")); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/type_definitions/foo.d.ts" - )); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/type_definitions/fizz.js" - )); - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/type_definitions/fizz.d.ts" - )); - assert!(graph - .contains_key("http://localhost:4545/cli/tests/type_definitions/qat.ts")); - } - - #[tokio::test] - async fn source_graph_type_references2() { - let _http_server_guard = test_util::http_server(); - - let module_specifier = ModuleSpecifier::resolve_url_or_path( - "http://localhost:4545/cli/tests/type_directives_02.ts", - ) - .unwrap(); - - let graph = build_graph(&module_specifier) - .await - .expect("Failed to build graph"); - - eprintln!("{:#?}", serde_json::to_value(&graph).unwrap()); - - let a = graph - .get("http://localhost:4545/cli/tests/type_directives_02.ts") - .unwrap(); - assert_eq!( - serde_json::to_value(&a.imports).unwrap(), - json!([ - { - "specifier": "./subdir/type_reference.js", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/type_reference.js", - "typeDirective": null, - "resolvedTypeDirective": null, - } - ]) - ); - - assert!(graph.contains_key( - "http://localhost:4545/cli/tests/subdir/type_reference.d.ts" - )); - - let b = graph - .get("http://localhost:4545/cli/tests/subdir/type_reference.js") - .unwrap(); - assert_eq!( - serde_json::to_value(&b.types_directives).unwrap(), - json!([ - { - "specifier": "./type_reference.d.ts", - "resolvedSpecifier": "http://localhost:4545/cli/tests/subdir/type_reference.d.ts", - } - ]) - ); - } - - #[tokio::test] - async fn source_graph_type_references3() { - let _http_server_guard = test_util::http_server(); - - let module_specifier = ModuleSpecifier::resolve_url_or_path( - "http://localhost:4545/cli/tests/type_directives_01.ts", - ) - .unwrap(); - - let graph = build_graph(&module_specifier) - .await - .expect("Failed to build graph"); - - let ts = graph - .get("http://localhost:4545/cli/tests/type_directives_01.ts") - .unwrap(); - assert_eq!( - serde_json::to_value(&ts.imports).unwrap(), - json!([ - { - "specifier": "http://127.0.0.1:4545/xTypeScriptTypes.js", - "resolvedSpecifier": "http://127.0.0.1:4545/xTypeScriptTypes.js", - "typeDirective": null, - "resolvedTypeDirective": null, - } - ]) - ); - - let headers = graph - .get("http://127.0.0.1:4545/xTypeScriptTypes.js") - .unwrap(); - assert_eq!( - serde_json::to_value(&headers.type_headers).unwrap(), - json!([ - { - "specifier": "./xTypeScriptTypes.d.ts", - "resolvedSpecifier": "http://127.0.0.1:4545/xTypeScriptTypes.d.ts" - } - ]) - ); - } - - #[tokio::test] - async fn source_graph_different_langs() { - let _http_server_guard = test_util::http_server(); - - // ModuleGraphLoader was mistakenly parsing this file as TSX - // https://github.com/denoland/deno/issues/5867 - - let module_specifier = ModuleSpecifier::resolve_url_or_path( - "http://localhost:4545/cli/tests/ts_with_generic.ts", - ) - .unwrap(); - - build_graph(&module_specifier) - .await - .expect("Failed to build graph"); - } -} - -// TODO(bartlomieju): use baseline tests from TSC to ensure -// compatibility -#[test] -fn test_pre_process_file() { - let source = r#" -// This comment is placed to make sure that directives are parsed -// even when they start on non-first line - -/// <reference lib="dom" /> -/// <reference types="./type_reference.d.ts" /> -/// <reference path="./type_reference/dep.ts" /> -// @deno-types="./type_definitions/foo.d.ts" -import { foo } from "./type_definitions/foo.js"; -// @deno-types="./type_definitions/fizz.d.ts" -import "./type_definitions/fizz.js"; - -/// <reference path="./type_reference/dep2.ts" /> - -import * as qat from "./type_definitions/qat.ts"; - -console.log(foo); -console.log(fizz); -console.log(qat.qat); -"#; - - let (imports, references) = - pre_process_file("some/file.ts", MediaType::TypeScript, source, true) - .expect("Failed to parse"); - - assert_eq!( - imports, - vec![ - ImportDesc { - specifier: "./type_definitions/foo.js".to_string(), - deno_types: Some("./type_definitions/foo.d.ts".to_string()), - location: Location { - filename: "some/file.ts".to_string(), - line: 9, - col: 0, - }, - }, - ImportDesc { - specifier: "./type_definitions/fizz.js".to_string(), - deno_types: Some("./type_definitions/fizz.d.ts".to_string()), - location: Location { - filename: "some/file.ts".to_string(), - line: 11, - col: 0, - }, - }, - ImportDesc { - specifier: "./type_definitions/qat.ts".to_string(), - deno_types: None, - location: Location { - filename: "some/file.ts".to_string(), - line: 15, - col: 0, - }, - }, - ] - ); - - // According to TS docs (https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) - // directives that are not at the top of the file are ignored, so only - // 3 references should be captured instead of 4. - let file_specifier = - ModuleSpecifier::resolve_url_or_path("some/file.ts").unwrap(); - assert_eq!( - references, - vec![ - TsReferenceDesc { - specifier: "dom".to_string(), - kind: TsReferenceKind::Lib, - location: Location { - filename: file_specifier.to_string(), - line: 5, - col: 0, - }, - }, - TsReferenceDesc { - specifier: "./type_reference.d.ts".to_string(), - kind: TsReferenceKind::Types, - location: Location { - filename: file_specifier.to_string(), - line: 6, - col: 0, - }, - }, - TsReferenceDesc { - specifier: "./type_reference/dep.ts".to_string(), - kind: TsReferenceKind::Path, - location: Location { - filename: file_specifier.to_string(), - line: 7, - col: 0, - }, - }, - ] - ); -} |