diff options
Diffstat (limited to 'cli/args')
-rw-r--r-- | cli/args/config_file.rs | 17 | ||||
-rw-r--r-- | cli/args/import_map.rs | 35 | ||||
-rw-r--r-- | cli/args/mod.rs | 80 |
3 files changed, 127 insertions, 5 deletions
diff --git a/cli/args/config_file.rs b/cli/args/config_file.rs index c31f09960..82ae7e5d7 100644 --- a/cli/args/config_file.rs +++ b/cli/args/config_file.rs @@ -465,6 +465,8 @@ pub enum LockConfig { pub struct ConfigFileJson { pub compiler_options: Option<Value>, pub import_map: Option<String>, + pub imports: Option<Value>, + pub scopes: Option<Value>, pub lint: Option<Value>, pub fmt: Option<Value>, pub tasks: Option<Value>, @@ -667,6 +669,21 @@ impl ConfigFile { self.json.import_map.clone() } + pub fn to_import_map_value(&self) -> Value { + let mut value = serde_json::Map::with_capacity(2); + if let Some(imports) = &self.json.imports { + value.insert("imports".to_string(), imports.clone()); + } + if let Some(scopes) = &self.json.scopes { + value.insert("scopes".to_string(), scopes.clone()); + } + value.into() + } + + pub fn is_an_import_map(&self) -> bool { + self.json.imports.is_some() || self.json.scopes.is_some() + } + pub fn to_fmt_config(&self) -> Result<Option<FmtConfig>, AnyError> { if let Some(config) = self.json.fmt.clone() { let fmt_config: SerializedFmtConfig = serde_json::from_value(config) diff --git a/cli/args/import_map.rs b/cli/args/import_map.rs new file mode 100644 index 000000000..200336c43 --- /dev/null +++ b/cli/args/import_map.rs @@ -0,0 +1,35 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::serde_json; +use deno_core::url::Url; +use import_map::ImportMap; +use import_map::ImportMapDiagnostic; +use log::warn; + +pub fn import_map_from_value( + specifier: &Url, + json_value: serde_json::Value, +) -> Result<ImportMap, AnyError> { + debug_assert!( + !specifier.as_str().contains("../"), + "Import map specifier incorrectly contained ../: {}", + specifier.as_str() + ); + let result = import_map::parse_from_value(specifier, json_value)?; + print_import_map_diagnostics(&result.diagnostics); + Ok(result.import_map) +} + +fn print_import_map_diagnostics(diagnostics: &[ImportMapDiagnostic]) { + if !diagnostics.is_empty() { + warn!( + "Import map diagnostics:\n{}", + diagnostics + .iter() + .map(|d| format!(" - {}", d)) + .collect::<Vec<_>>() + .join("\n") + ); + } +} diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 4cb960238..1bf294018 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -2,10 +2,12 @@ mod config_file; mod flags; -mod lockfile; - mod flags_allow_net; +mod import_map; +mod lockfile; +pub use self::import_map::import_map_from_value; +use ::import_map::ImportMap; pub use config_file::BenchConfig; pub use config_file::CompilerOptions; pub use config_file::ConfigFile; @@ -19,6 +21,8 @@ pub use config_file::TsConfig; pub use config_file::TsConfigForEmit; pub use config_file::TsConfigType; pub use config_file::TsTypeLib; +use deno_core::serde_json; +use deno_runtime::permissions::PermissionsContainer; pub use flags::*; pub use lockfile::Lockfile; pub use lockfile::LockfileError; @@ -49,6 +53,7 @@ use std::path::PathBuf; use std::sync::Arc; use crate::cache::DenoDir; +use crate::file_fetcher::FileFetcher; use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::version; @@ -547,12 +552,13 @@ impl CliOptions { } /// Based on an optional command line import map path and an optional - /// configuration file, return a resolved module specifier to an import map. + /// configuration file, return a resolved module specifier to an import map + /// and a boolean indicating if unknown keys should not result in diagnostics. pub fn resolve_import_map_specifier( &self, ) -> Result<Option<ModuleSpecifier>, AnyError> { match self.overrides.import_map_specifier.clone() { - Some(path) => Ok(path), + Some(maybe_path) => Ok(maybe_path), None => resolve_import_map_specifier( self.flags.import_map_path.as_deref(), self.maybe_config_file.as_ref(), @@ -560,6 +566,45 @@ impl CliOptions { } } + pub async fn resolve_import_map( + &self, + file_fetcher: &FileFetcher, + ) -> Result<Option<ImportMap>, AnyError> { + let import_map_specifier = match self.resolve_import_map_specifier()? { + Some(specifier) => specifier, + None => return Ok(None), + }; + self + .resolve_import_map_from_specifier(&import_map_specifier, file_fetcher) + .await + .context(format!( + "Unable to load '{}' import map", + import_map_specifier + )) + .map(Some) + } + + async fn resolve_import_map_from_specifier( + &self, + import_map_specifier: &ModuleSpecifier, + file_fetcher: &FileFetcher, + ) -> Result<ImportMap, AnyError> { + let import_map_config = self + .get_maybe_config_file() + .as_ref() + .filter(|c| c.specifier == *import_map_specifier); + let value: serde_json::Value = match import_map_config { + Some(config) => config.to_import_map_value(), + None => { + let file = file_fetcher + .fetch(import_map_specifier, PermissionsContainer::allow_all()) + .await?; + serde_json::from_str(&file.source)? + } + }; + import_map_from_value(import_map_specifier, value) + } + /// Overrides the import map specifier to use. pub fn set_import_map_specifier(&mut self, path: Option<ModuleSpecifier>) { self.overrides.import_map_specifier = Some(path); @@ -907,6 +952,16 @@ fn resolve_import_map_specifier( .context(format!("Bad URL (\"{}\") for import map.", import_map_path))?; return Ok(Some(specifier)); } else if let Some(config_file) = &maybe_config_file { + // if the config file is an import map we prefer to use it, over `importMap` + // field + if config_file.is_an_import_map() { + if let Some(_import_map_path) = config_file.to_import_map_path() { + log::warn!("{} \"importMap\" setting is ignored when \"imports\" or \"scopes\" are specified in the config file.", colors::yellow("Warning")); + } + + return Ok(Some(config_file.specifier.clone())); + } + // when the import map is specifier in a config file, it needs to be // resolved relative to the config file, versus the CWD like with the flag // and with config files, we support both local and remote config files, @@ -990,7 +1045,7 @@ mod test { let actual = actual.unwrap(); assert_eq!( actual, - Some(ModuleSpecifier::parse("file:///deno/import_map.json").unwrap()) + Some(ModuleSpecifier::parse("file:///deno/import_map.json").unwrap(),) ); } @@ -1052,6 +1107,21 @@ mod test { } #[test] + fn resolve_import_map_embedded_take_precedence() { + let config_text = r#"{ + "importMap": "import_map.json", + "imports": {}, + }"#; + let config_specifier = + ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap(); + let config_file = ConfigFile::new(config_text, &config_specifier).unwrap(); + let actual = resolve_import_map_specifier(None, Some(&config_file)); + assert!(actual.is_ok()); + let actual = actual.unwrap(); + assert_eq!(actual, Some(config_specifier)); + } + + #[test] fn resolve_import_map_none() { let config_text = r#"{}"#; let config_specifier = |