mirror of
https://github.com/denoland/deno.git
synced 2024-11-30 16:40:57 -05:00
35220f0069
This commit changes the workspace support to provide all workspace members to be available as imports based on their names and versions. Closes https://github.com/denoland/deno/issues/23343
127 lines
3.6 KiB
Rust
127 lines
3.6 KiB
Rust
// 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::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<Option<ImportMap>, 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<ImportMap, AnyError> {
|
|
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<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")
|
|
);
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|