diff options
Diffstat (limited to 'cli/lsp/sources.rs')
-rw-r--r-- | cli/lsp/sources.rs | 148 |
1 files changed, 147 insertions, 1 deletions
diff --git a/cli/lsp/sources.rs b/cli/lsp/sources.rs index 1b7d6f3fa..62c76260c 100644 --- a/cli/lsp/sources.rs +++ b/cli/lsp/sources.rs @@ -3,6 +3,7 @@ use super::analysis; use super::text::LineIndex; use super::tsc; +use super::urls::INVALID_SPECIFIER; use crate::config_file::ConfigFile; use crate::file_fetcher::get_source_from_bytes; @@ -105,7 +106,7 @@ fn resolve_specifier( } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] struct Metadata { dependencies: Option<HashMap<String, analysis::Dependency>>, length_utf16: usize, @@ -115,9 +116,27 @@ struct Metadata { maybe_warning: Option<String>, media_type: MediaType, source: String, + specifier: ModuleSpecifier, version: String, } +impl Default for Metadata { + fn default() -> Self { + Self { + dependencies: None, + length_utf16: 0, + line_index: LineIndex::default(), + maybe_navigation_tree: None, + maybe_types: None, + maybe_warning: None, + media_type: MediaType::default(), + source: String::default(), + specifier: INVALID_SPECIFIER.clone(), + version: String::default(), + } + } +} + impl Metadata { fn new( specifier: &ModuleSpecifier, @@ -151,9 +170,28 @@ impl Metadata { maybe_warning, media_type: media_type.to_owned(), source: source.to_string(), + specifier: specifier.clone(), version: version.to_string(), } } + + fn refresh(&mut self, maybe_import_map: &Option<ImportMap>) { + let (dependencies, maybe_types) = if let Ok(parsed_module) = + analysis::parse_module(&self.specifier, &self.source, &self.media_type) + { + let (deps, maybe_types) = analysis::analyze_dependencies( + &self.specifier, + &self.media_type, + &parsed_module, + maybe_import_map, + ); + (Some(deps), maybe_types) + } else { + (None, None) + }; + self.dependencies = dependencies; + self.maybe_types = maybe_types; + } } #[derive(Debug, Clone, Default)] @@ -239,6 +277,10 @@ impl Sources { self.0.lock().metadata.keys().cloned().collect() } + pub fn set_import_map(&self, maybe_import_map: Option<ImportMap>) { + self.0.lock().set_import_map(maybe_import_map) + } + pub fn set_navigation_tree( &self, specifier: &ModuleSpecifier, @@ -483,6 +525,13 @@ impl Inner { } } + fn set_import_map(&mut self, maybe_import_map: Option<ImportMap>) { + for (_, metadata) in self.metadata.iter_mut() { + metadata.refresh(&maybe_import_map); + } + self.maybe_import_map = maybe_import_map; + } + fn set_maybe_type( &mut self, specifier: &str, @@ -517,6 +566,7 @@ mod tests { use super::*; use deno_core::resolve_path; use deno_core::resolve_url; + use deno_core::serde_json::json; use std::env; use tempfile::TempDir; @@ -655,6 +705,102 @@ mod tests { } #[test] + fn test_resolve_with_import_map() { + let (sources, location) = setup(); + let import_map_json = json!({ + "imports": { + "mylib": "https://deno.land/x/myLib/index.js" + } + }); + let import_map = ImportMap::from_json( + "https://deno.land/x/", + &import_map_json.to_string(), + ) + .unwrap(); + sources.set_import_map(Some(import_map)); + let cache = HttpCache::new(&location); + let mylib_specifier = + resolve_url("https://deno.land/x/myLib/index.js").unwrap(); + let mut mylib_headers_map = HashMap::new(); + mylib_headers_map.insert( + "content-type".to_string(), + "application/javascript".to_string(), + ); + cache + .set( + &mylib_specifier, + mylib_headers_map, + b"export const a = \"a\";\n", + ) + .unwrap(); + let referrer = resolve_url("https://deno.land/x/mod.ts").unwrap(); + cache + .set( + &referrer, + Default::default(), + b"export { a } from \"mylib\";", + ) + .unwrap(); + let actual = sources.resolve_import("mylib", &referrer); + assert_eq!(actual, Some((mylib_specifier, MediaType::JavaScript))); + } + + #[test] + fn test_update_import_map() { + let (sources, location) = setup(); + let import_map_json = json!({ + "imports": { + "otherlib": "https://deno.land/x/otherlib/index.js" + } + }); + let import_map = ImportMap::from_json( + "https://deno.land/x/", + &import_map_json.to_string(), + ) + .unwrap(); + sources.set_import_map(Some(import_map)); + let cache = HttpCache::new(&location); + let mylib_specifier = + resolve_url("https://deno.land/x/myLib/index.js").unwrap(); + let mut mylib_headers_map = HashMap::new(); + mylib_headers_map.insert( + "content-type".to_string(), + "application/javascript".to_string(), + ); + cache + .set( + &mylib_specifier, + mylib_headers_map, + b"export const a = \"a\";\n", + ) + .unwrap(); + let referrer = resolve_url("https://deno.land/x/mod.ts").unwrap(); + cache + .set( + &referrer, + Default::default(), + b"export { a } from \"mylib\";", + ) + .unwrap(); + let actual = sources.resolve_import("mylib", &referrer); + assert_eq!(actual, None); + let import_map_json = json!({ + "imports": { + "otherlib": "https://deno.land/x/otherlib/index.js", + "mylib": "https://deno.land/x/myLib/index.js" + } + }); + let import_map = ImportMap::from_json( + "https://deno.land/x/", + &import_map_json.to_string(), + ) + .unwrap(); + sources.set_import_map(Some(import_map)); + let actual = sources.resolve_import("mylib", &referrer); + assert_eq!(actual, Some((mylib_specifier, MediaType::JavaScript))); + } + + #[test] fn test_sources_resolve_specifier_non_supported_schema() { let (sources, _) = setup(); let specifier = |