refactor: use parsed source cache when unfurling import map (#22001)

This commit is contained in:
Luca Casonato 2024-01-23 12:40:23 +01:00 committed by GitHub
parent e49973d96d
commit 052fd78690
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 91 deletions

View file

@ -27,6 +27,7 @@ use crate::args::deno_registry_url;
use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::PublishFlags;
use crate::cache::ParsedSourceCache;
use crate::factory::CliFactory;
use crate::graph_util::ModuleGraphBuilder;
use crate::http_util::HttpClient;
@ -84,6 +85,7 @@ fn get_deno_json_package_name(
async fn prepare_publish(
deno_json: &ConfigFile,
source_cache: Arc<ParsedSourceCache>,
import_map: Arc<ImportMap>,
) -> Result<Rc<PreparedPublishPackage>, AnyError> {
let config_path = deno_json.specifier.to_file_path().unwrap();
@ -132,8 +134,13 @@ async fn prepare_publish(
let tarball = deno_core::unsync::spawn_blocking(move || {
let unfurler = ImportMapUnfurler::new(&import_map);
tar::create_gzipped_tarball(&dir_path, &unfurler, &exclude_patterns)
.context("Failed to create a tarball")
tar::create_gzipped_tarball(
&dir_path,
&*source_cache,
&unfurler,
&exclude_patterns,
)
.context("Failed to create a tarball")
})
.await??;
@ -683,6 +690,7 @@ async fn prepare_packages_for_publishing(
> {
let maybe_workspace_config = deno_json.to_workspace_config()?;
let module_graph_builder = cli_factory.module_graph_builder().await?.as_ref();
let source_cache = cli_factory.parsed_source_cache();
let type_checker = cli_factory.type_checker().await?;
let cli_options = cli_factory.cli_options();
@ -700,7 +708,8 @@ async fn prepare_packages_for_publishing(
)
.await?;
let mut prepared_package_by_name = HashMap::with_capacity(1);
let package = prepare_publish(&deno_json, import_map).await?;
let package =
prepare_publish(&deno_json, source_cache.clone(), import_map).await?;
let package_name = format!("@{}/{}", package.scope, package.package);
let publish_order_graph =
PublishOrderGraph::new_single(package_name.clone());
@ -731,8 +740,9 @@ async fn prepare_packages_for_publishing(
.cloned()
.map(|member| {
let import_map = import_map.clone();
let source_cache = source_cache.clone();
deno_core::unsync::spawn(async move {
let package = prepare_publish(&member.config_file, import_map)
let package = prepare_publish(&member.config_file, source_cache, import_map)
.await
.with_context(|| {
format!("Failed preparing '{}'.", member.package_name)

View file

@ -31,8 +31,7 @@ pub struct PublishableTarball {
pub fn create_gzipped_tarball(
dir: &Path,
// TODO(bartlomieju): this is too specific, factor it out into a callback that
// returns data
source_cache: &dyn deno_graph::ParsedSourceStore,
unfurler: &ImportMapUnfurler,
exclude_patterns: &PathOrPatternSet,
) -> Result<PublishableTarball, AnyError> {
@ -71,12 +70,15 @@ pub fn create_gzipped_tarball(
path: relative_path.to_path_buf(),
size: data.len(),
});
let (content, unfurl_diagnostics) =
unfurler.unfurl(&url, data).with_context(|| {
format!("Unable to unfurl file '{}'", entry.path().display())
})?;
diagnostics.extend_from_slice(&unfurl_diagnostics);
let content = match source_cache.get_parsed_source(&url) {
Some(parsed_source) => {
let (content, unfurl_diagnostics) =
unfurler.unfurl(&url, &parsed_source);
diagnostics.extend_from_slice(&unfurl_diagnostics);
content.into_bytes()
}
None => data,
};
tar
.add_file(relative_path_str.to_string(), &content)
.with_context(|| {

View file

@ -3,13 +3,11 @@
use std::collections::HashSet;
use deno_ast::ParsedSource;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::ModuleSpecifier;
use deno_graph::DefaultModuleAnalyzer;
use deno_graph::DependencyDescriptor;
use deno_graph::DynamicTemplatePart;
use deno_graph::MediaType;
use deno_graph::TypeScriptReference;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::jsr::JsrPackageReqReference;
@ -83,46 +81,11 @@ impl<'a> ImportMapUnfurler<'a> {
pub fn unfurl(
&self,
url: &ModuleSpecifier,
data: Vec<u8>,
) -> Result<(Vec<u8>, Vec<String>), AnyError> {
let mut diagnostics = vec![];
let media_type = MediaType::from_specifier(url);
match media_type {
MediaType::JavaScript
| MediaType::Jsx
| MediaType::Mjs
| MediaType::Cjs
| MediaType::TypeScript
| MediaType::Mts
| MediaType::Cts
| MediaType::Dts
| MediaType::Dmts
| MediaType::Dcts
| MediaType::Tsx => {
// continue
}
MediaType::SourceMap
| MediaType::Unknown
| MediaType::Json
| MediaType::Wasm
| MediaType::TsBuildInfo => {
// not unfurlable data
return Ok((data, diagnostics));
}
}
let text = String::from_utf8(data)?;
let parsed_source = deno_ast::parse_module(deno_ast::ParseParams {
specifier: url.to_string(),
text_info: deno_ast::SourceTextInfo::from_string(text),
media_type,
capture_tokens: false,
maybe_syntax: None,
scope_analysis: false,
})?;
parsed_source: &ParsedSource,
) -> (String, Vec<String>) {
let mut diagnostics = Vec::new();
let mut text_changes = Vec::new();
let module_info = DefaultModuleAnalyzer::module_info(&parsed_source);
let module_info = DefaultModuleAnalyzer::module_info(parsed_source);
let analyze_specifier =
|specifier: &str,
range: &deno_graph::PositionRange,
@ -130,7 +93,7 @@ impl<'a> ImportMapUnfurler<'a> {
let resolved = self.import_map.resolve(specifier, url);
if let Ok(resolved) = resolved {
text_changes.push(deno_ast::TextChange {
range: to_range(&parsed_source, range),
range: to_range(parsed_source, range),
new_text: make_relative_to(url, &resolved),
});
}
@ -148,7 +111,7 @@ impl<'a> ImportMapUnfurler<'a> {
let success = try_unfurl_dynamic_dep(
self.import_map,
url,
&parsed_source,
parsed_source,
dep,
&mut text_changes,
);
@ -192,25 +155,12 @@ impl<'a> ImportMapUnfurler<'a> {
&mut text_changes,
);
}
Ok((
deno_ast::apply_text_changes(
parsed_source.text_info().text_str(),
text_changes,
)
.into_bytes(),
diagnostics,
))
}
#[cfg(test)]
fn unfurl_to_string(
&self,
url: &ModuleSpecifier,
data: Vec<u8>,
) -> Result<(String, Vec<String>), AnyError> {
let (data, diagnostics) = self.unfurl(url, data)?;
let content = String::from_utf8(data)?;
Ok((content, diagnostics))
let rewritten_text = deno_ast::apply_text_changes(
parsed_source.text_info().text_str(),
text_changes,
);
(rewritten_text, diagnostics)
}
}
@ -309,11 +259,26 @@ fn to_range(
#[cfg(test)]
mod tests {
use super::*;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::serde_json::json;
use deno_core::url::Url;
use import_map::ImportMapWithDiagnostics;
use pretty_assertions::assert_eq;
fn parse_ast(specifier: &Url, source_code: &str) -> ParsedSource {
let media_type = MediaType::from_specifier(specifier);
deno_ast::parse_module(deno_ast::ParseParams {
specifier: specifier.to_string(),
media_type,
capture_tokens: false,
maybe_syntax: None,
scope_analysis: false,
text_info: deno_ast::SourceTextInfo::new(source_code.into()),
})
.unwrap()
}
#[test]
fn test_unfurling() {
let deno_json_url =
@ -345,9 +310,8 @@ const test5 = await import(`lib${expr}`);
const test6 = await import(`${expr}`);
"#;
let specifier = ModuleSpecifier::parse("file:///dev/mod.ts").unwrap();
let (unfurled_source, d) = unfurler
.unfurl_to_string(&specifier, source_code.as_bytes().to_vec())
.unwrap();
let source = parse_ast(&specifier, source_code);
let (unfurled_source, d) = unfurler.unfurl(&specifier, &source);
assert_eq!(d.len(), 2);
assert!(d[0].starts_with("Dynamic import was not analyzable and won't use the import map once published."));
assert!(d[1].starts_with("Dynamic import was not analyzable and won't use the import map once published."));
@ -366,20 +330,5 @@ const test6 = await import(`${expr}`);
"#;
assert_eq!(unfurled_source, expected_source);
}
// Unfurling file with "unknown" media type should leave it as is
{
let source_code = r#"import express from "express";"
import foo from "lib/foo.ts";
import bar from "lib/bar.ts";
import fizz from "fizz";
"#;
let specifier = ModuleSpecifier::parse("file:///dev/mod").unwrap();
let (unfurled_source, d) = unfurler
.unfurl_to_string(&specifier, source_code.as_bytes().to_vec())
.unwrap();
assert!(d.is_empty());
assert_eq!(unfurled_source, source_code);
}
}
}