// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::url::Url; use deno_runtime::deno_permissions::PermissionsContainer; use import_map::ImportMap; use import_map::ImportMapDiagnostic; use log::warn; use super::ConfigFile; use crate::file_fetcher::FileFetcher; pub async fn resolve_import_map( specified_specifier: Option<&Url>, maybe_config_file: Option<&ConfigFile>, file_fetcher: &FileFetcher, ) -> Result, AnyError> { if let Some(specifier) = specified_specifier { resolve_import_map_from_specifier(specifier.clone(), file_fetcher) .await .with_context(|| format!("Unable to load '{}' import map", specifier)) .map(Some) } else if let Some(config_file) = maybe_config_file { let maybe_url_and_value = config_file .to_import_map_value(|specifier| { let specifier = specifier.clone(); async move { let file = file_fetcher .fetch(&specifier, &PermissionsContainer::allow_all()) .await? .into_text_decoded()?; Ok(file.source.to_string()) } }) .await .with_context(|| { format!( "Unable to resolve import map in '{}'", config_file.specifier ) })?; match maybe_url_and_value { Some((url, value)) => { import_map_from_value(url.into_owned(), value).map(Some) } None => Ok(None), } } else { Ok(None) } } async fn resolve_import_map_from_specifier( specifier: Url, file_fetcher: &FileFetcher, ) -> Result { let value: serde_json::Value = if specifier.scheme() == "data" { let data_url_text = deno_graph::source::RawDataUrl::parse(&specifier)?.decode()?; serde_json::from_str(&data_url_text)? } else { let file = file_fetcher .fetch(&specifier, &PermissionsContainer::allow_all()) .await? .into_text_decoded()?; serde_json::from_str(&file.source)? }; import_map_from_value(specifier, value) } pub fn import_map_from_value( specifier: Url, json_value: serde_json::Value, ) -> Result { 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::>() .join("\n") ); } } pub fn enhance_import_map_value_with_workspace_members( mut import_map_value: serde_json::Value, workspace_members: &[deno_config::WorkspaceMemberConfig], ) -> serde_json::Value { let mut imports = if let Some(imports) = import_map_value.get("imports").as_ref() { imports.as_object().unwrap().clone() } else { serde_json::Map::new() }; for workspace_member in workspace_members { let name = &workspace_member.package_name; let version = &workspace_member.package_version; // Don't override existings, explicit imports if imports.contains_key(name) { continue; } imports.insert( name.to_string(), serde_json::Value::String(format!("jsr:{}@^{}", name, version)), ); } import_map_value["imports"] = serde_json::Value::Object(imports); ::import_map::ext::expand_import_map_value(import_map_value) }