summaryrefslogtreecommitdiff
path: root/cli/args
diff options
context:
space:
mode:
Diffstat (limited to 'cli/args')
-rw-r--r--cli/args/config_file.rs17
-rw-r--r--cli/args/import_map.rs35
-rw-r--r--cli/args/mod.rs80
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 =