summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2024-02-27 16:13:16 +0100
committerGitHub <noreply@github.com>2024-02-27 15:13:16 +0000
commit8d5c2313495014a6af842e21da802e01e11b8e08 (patch)
tree5468374eb98b48b012b15c3afc2fd133b379bb43
parent47c2a63d872886ae1d0576f3cbf630151c8ff129 (diff)
feat(publish): support sloppy imports and bare node built-ins (#22588)
-rw-r--r--cli/factory.rs2
-rw-r--r--cli/tools/registry/diagnostics.rs32
-rw-r--r--cli/tools/registry/mod.rs23
-rw-r--r--cli/tools/registry/tar.rs8
-rw-r--r--cli/tools/registry/unfurl.rs (renamed from cli/util/import_map.rs)316
-rw-r--r--cli/util/mod.rs1
-rw-r--r--tests/integration/publish_tests.rs16
-rw-r--r--tests/testdata/publish/bare_node_builtins.out11
-rw-r--r--tests/testdata/publish/bare_node_builtins/deno.json7
-rw-r--r--tests/testdata/publish/bare_node_builtins/mod.ts5
-rw-r--r--tests/testdata/publish/sloppy_imports.out12
-rw-r--r--tests/testdata/publish/sloppy_imports/b/index.ts1
-rw-r--r--tests/testdata/publish/sloppy_imports/deno.json7
-rw-r--r--tests/testdata/publish/sloppy_imports/mod.ts1
-rw-r--r--tests/testdata/publish/unanalyzable_dynamic_import.out4
-rw-r--r--tests/testdata/unfurl/b.ts0
-rw-r--r--tests/testdata/unfurl/baz/index.js0
17 files changed, 316 insertions, 130 deletions
diff --git a/cli/factory.rs b/cli/factory.rs
index 7302c0312..bee3ea5f6 100644
--- a/cli/factory.rs
+++ b/cli/factory.rs
@@ -44,10 +44,10 @@ use crate::resolver::SloppyImportsResolver;
use crate::standalone::DenoCompileBinaryWriter;
use crate::tools::check::TypeChecker;
use crate::tools::coverage::CoverageCollector;
+use crate::tools::registry::deno_json_deps;
use crate::tools::run::hmr::HmrRunner;
use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path_maybe_not_exists;
-use crate::util::import_map::deno_json_deps;
use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle;
use crate::worker::CliMainWorkerFactory;
diff --git a/cli/tools/registry/diagnostics.rs b/cli/tools/registry/diagnostics.rs
index b605c293b..78cc6f555 100644
--- a/cli/tools/registry/diagnostics.rs
+++ b/cli/tools/registry/diagnostics.rs
@@ -20,7 +20,7 @@ use deno_core::error::AnyError;
use deno_graph::FastCheckDiagnostic;
use lsp_types::Url;
-use crate::util::import_map::ImportMapUnfurlDiagnostic;
+use super::unfurl::SpecifierUnfurlerDiagnostic;
#[derive(Clone, Default)]
pub struct PublishDiagnosticsCollector {
@@ -74,7 +74,7 @@ impl PublishDiagnosticsCollector {
pub enum PublishDiagnostic {
FastCheck(FastCheckDiagnostic),
- ImportMapUnfurl(ImportMapUnfurlDiagnostic),
+ SpecifierUnfurl(SpecifierUnfurlerDiagnostic),
InvalidPath {
path: PathBuf,
message: String,
@@ -102,7 +102,7 @@ impl Diagnostic for PublishDiagnostic {
..
}) => DiagnosticLevel::Warning,
FastCheck(_) => DiagnosticLevel::Error,
- ImportMapUnfurl(_) => DiagnosticLevel::Warning,
+ SpecifierUnfurl(_) => DiagnosticLevel::Warning,
InvalidPath { .. } => DiagnosticLevel::Error,
DuplicatePath { .. } => DiagnosticLevel::Error,
UnsupportedFileType { .. } => DiagnosticLevel::Warning,
@@ -114,7 +114,7 @@ impl Diagnostic for PublishDiagnostic {
use PublishDiagnostic::*;
match &self {
FastCheck(diagnostic) => diagnostic.code(),
- ImportMapUnfurl(diagnostic) => Cow::Borrowed(diagnostic.code()),
+ SpecifierUnfurl(diagnostic) => Cow::Borrowed(diagnostic.code()),
InvalidPath { .. } => Cow::Borrowed("invalid-path"),
DuplicatePath { .. } => Cow::Borrowed("case-insensitive-duplicate-path"),
UnsupportedFileType { .. } => Cow::Borrowed("unsupported-file-type"),
@@ -126,7 +126,7 @@ impl Diagnostic for PublishDiagnostic {
use PublishDiagnostic::*;
match &self {
FastCheck(diagnostic) => diagnostic.message(),
- ImportMapUnfurl(diagnostic) => Cow::Borrowed(diagnostic.message()),
+ SpecifierUnfurl(diagnostic) => Cow::Borrowed(diagnostic.message()),
InvalidPath { message, .. } => Cow::Borrowed(message.as_str()),
DuplicatePath { .. } => {
Cow::Borrowed("package path is a case insensitive duplicate of another path in the package")
@@ -142,8 +142,8 @@ impl Diagnostic for PublishDiagnostic {
use PublishDiagnostic::*;
match &self {
FastCheck(diagnostic) => diagnostic.location(),
- ImportMapUnfurl(diagnostic) => match diagnostic {
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport {
+ SpecifierUnfurl(diagnostic) => match diagnostic {
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport {
specifier,
text_info,
range,
@@ -180,8 +180,8 @@ impl Diagnostic for PublishDiagnostic {
fn snippet(&self) -> Option<DiagnosticSnippet<'_>> {
match &self {
PublishDiagnostic::FastCheck(diagnostic) => diagnostic.snippet(),
- PublishDiagnostic::ImportMapUnfurl(diagnostic) => match diagnostic {
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport {
+ PublishDiagnostic::SpecifierUnfurl(diagnostic) => match diagnostic {
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport {
text_info,
range,
..
@@ -227,7 +227,7 @@ impl Diagnostic for PublishDiagnostic {
fn hint(&self) -> Option<Cow<'_, str>> {
match &self {
PublishDiagnostic::FastCheck(diagnostic) => diagnostic.hint(),
- PublishDiagnostic::ImportMapUnfurl(_) => None,
+ PublishDiagnostic::SpecifierUnfurl(_) => None,
PublishDiagnostic::InvalidPath { .. } => Some(
Cow::Borrowed("rename or remove the file, or add it to 'publish.exclude' in the config file"),
),
@@ -250,11 +250,11 @@ impl Diagnostic for PublishDiagnostic {
PublishDiagnostic::FastCheck(diagnostic) => {
diagnostic.info()
}
- PublishDiagnostic::ImportMapUnfurl(diagnostic) => match diagnostic {
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { .. } => Cow::Borrowed(&[
- Cow::Borrowed("after publishing this package, imports from the local import map do not work"),
+ PublishDiagnostic::SpecifierUnfurl(diagnostic) => match diagnostic {
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => Cow::Borrowed(&[
+ Cow::Borrowed("after publishing this package, imports from the local import map / package.json do not work"),
Cow::Borrowed("dynamic imports that can not be analyzed at publish time will not be rewritten automatically"),
- Cow::Borrowed("make sure the dynamic import is resolvable at runtime without an import map")
+ Cow::Borrowed("make sure the dynamic import is resolvable at runtime without an import map / package.json")
]),
},
PublishDiagnostic::InvalidPath { .. } => Cow::Borrowed(&[
@@ -278,8 +278,8 @@ impl Diagnostic for PublishDiagnostic {
fn docs_url(&self) -> Option<Cow<'_, str>> {
match &self {
PublishDiagnostic::FastCheck(diagnostic) => diagnostic.docs_url(),
- PublishDiagnostic::ImportMapUnfurl(diagnostic) => match diagnostic {
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { .. } => None,
+ PublishDiagnostic::SpecifierUnfurl(diagnostic) => match diagnostic {
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. } => None,
},
PublishDiagnostic::InvalidPath { .. } => {
Some(Cow::Borrowed("https://jsr.io/go/invalid-path"))
diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs
index 52d303ae1..eadd0e44d 100644
--- a/cli/tools/registry/mod.rs
+++ b/cli/tools/registry/mod.rs
@@ -35,13 +35,13 @@ use crate::factory::CliFactory;
use crate::graph_util::ModuleGraphCreator;
use crate::http_util::HttpClient;
use crate::resolver::MappedSpecifierResolver;
+use crate::resolver::SloppyImportsResolver;
use crate::tools::check::CheckOptions;
use crate::tools::lint::no_slow_types;
use crate::tools::registry::diagnostics::PublishDiagnostic;
use crate::tools::registry::diagnostics::PublishDiagnosticsCollector;
use crate::tools::registry::graph::collect_invalid_external_imports;
use crate::util::display::human_size;
-use crate::util::import_map::ImportMapUnfurler;
mod api;
mod auth;
@@ -50,10 +50,13 @@ mod graph;
mod paths;
mod publish_order;
mod tar;
+mod unfurl;
use auth::get_auth_method;
use auth::AuthMethod;
use publish_order::PublishOrderGraph;
+pub use unfurl::deno_json_deps;
+use unfurl::SpecifierUnfurler;
use super::check::TypeChecker;
@@ -81,12 +84,15 @@ impl PreparedPublishPackage {
static SUGGESTED_ENTRYPOINTS: [&str; 4] =
["mod.ts", "mod.js", "index.ts", "index.js"];
+#[allow(clippy::too_many_arguments)]
async fn prepare_publish(
package_name: &str,
deno_json: &ConfigFile,
source_cache: Arc<ParsedSourceCache>,
graph: Arc<deno_graph::ModuleGraph>,
mapped_resolver: Arc<MappedSpecifierResolver>,
+ sloppy_imports_resolver: Option<SloppyImportsResolver>,
+ bare_node_builtins: bool,
diagnostics_collector: &PublishDiagnosticsCollector,
) -> Result<Rc<PreparedPublishPackage>, AnyError> {
let config_path = deno_json.specifier.to_file_path().unwrap();
@@ -132,7 +138,11 @@ async fn prepare_publish(
let diagnostics_collector = diagnostics_collector.clone();
let tarball = deno_core::unsync::spawn_blocking(move || {
- let unfurler = ImportMapUnfurler::new(&mapped_resolver);
+ let unfurler = SpecifierUnfurler::new(
+ &mapped_resolver,
+ sloppy_imports_resolver.as_ref(),
+ bare_node_builtins,
+ );
tar::create_gzipped_tarball(
&dir_path,
LazyGraphSourceParser::new(&source_cache, &graph),
@@ -661,7 +671,9 @@ async fn prepare_packages_for_publishing(
let module_graph_creator = cli_factory.module_graph_creator().await?.as_ref();
let source_cache = cli_factory.parsed_source_cache();
let type_checker = cli_factory.type_checker().await?;
+ let fs = cli_factory.fs();
let cli_options = cli_factory.cli_options();
+ let bare_node_builtins = cli_options.unstable_bare_node_builtins();
if members.len() > 1 {
println!("Publishing a workspace...");
@@ -686,6 +698,11 @@ async fn prepare_packages_for_publishing(
.into_iter()
.map(|member| {
let mapped_resolver = mapped_resolver.clone();
+ let sloppy_imports_resolver = if cli_options.unstable_sloppy_imports() {
+ Some(SloppyImportsResolver::new(fs.clone()))
+ } else {
+ None
+ };
let graph = graph.clone();
async move {
let package = prepare_publish(
@@ -694,6 +711,8 @@ async fn prepare_packages_for_publishing(
source_cache.clone(),
graph,
mapped_resolver,
+ sloppy_imports_resolver,
+ bare_node_builtins,
diagnostics_collector,
)
.await
diff --git a/cli/tools/registry/tar.rs b/cli/tools/registry/tar.rs
index 66d15b5a6..a8519fe02 100644
--- a/cli/tools/registry/tar.rs
+++ b/cli/tools/registry/tar.rs
@@ -18,10 +18,10 @@ use tar::Header;
use crate::cache::LazyGraphSourceParser;
use crate::tools::registry::paths::PackagePath;
-use crate::util::import_map::ImportMapUnfurler;
use super::diagnostics::PublishDiagnostic;
use super::diagnostics::PublishDiagnosticsCollector;
+use super::unfurl::SpecifierUnfurler;
#[derive(Debug, Clone, PartialEq)]
pub struct PublishableTarballFile {
@@ -40,7 +40,7 @@ pub fn create_gzipped_tarball(
dir: &Path,
source_parser: LazyGraphSourceParser,
diagnostics_collector: &PublishDiagnosticsCollector,
- unfurler: &ImportMapUnfurler,
+ unfurler: &SpecifierUnfurler,
file_patterns: Option<FilePatterns>,
) -> Result<PublishableTarball, AnyError> {
let mut tar = TarGzArchive::new();
@@ -192,7 +192,7 @@ pub fn create_gzipped_tarball(
fn resolve_content_maybe_unfurling(
path: &Path,
specifier: &Url,
- unfurler: &ImportMapUnfurler,
+ unfurler: &SpecifierUnfurler,
source_parser: LazyGraphSourceParser,
diagnostics_collector: &PublishDiagnosticsCollector,
) -> Result<Vec<u8>, AnyError> {
@@ -241,7 +241,7 @@ fn resolve_content_maybe_unfurling(
log::debug!("Unfurling {}", specifier);
let mut reporter = |diagnostic| {
- diagnostics_collector.push(PublishDiagnostic::ImportMapUnfurl(diagnostic));
+ diagnostics_collector.push(PublishDiagnostic::SpecifierUnfurl(diagnostic));
};
let content = unfurler.unfurl(specifier, &parsed_source, &mut reporter);
Ok(content.into_bytes())
diff --git a/cli/util/import_map.rs b/cli/tools/registry/unfurl.rs
index a075443ba..abea2bd0c 100644
--- a/cli/util/import_map.rs
+++ b/cli/tools/registry/unfurl.rs
@@ -11,11 +11,13 @@ use deno_graph::DefaultModuleAnalyzer;
use deno_graph::DependencyDescriptor;
use deno_graph::DynamicTemplatePart;
use deno_graph::TypeScriptReference;
+use deno_runtime::deno_node::is_builtin_node_module;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
use crate::resolver::MappedSpecifierResolver;
+use crate::resolver::SloppyImportsResolver;
pub fn deno_json_deps(
config: &deno_config::ConfigFile,
@@ -61,7 +63,7 @@ fn values_to_set<'a>(
}
#[derive(Debug, Clone)]
-pub enum ImportMapUnfurlDiagnostic {
+pub enum SpecifierUnfurlerDiagnostic {
UnanalyzableDynamicImport {
specifier: ModuleSpecifier,
text_info: SourceTextInfo,
@@ -69,7 +71,7 @@ pub enum ImportMapUnfurlDiagnostic {
},
}
-impl ImportMapUnfurlDiagnostic {
+impl SpecifierUnfurlerDiagnostic {
pub fn code(&self) -> &'static str {
match self {
Self::UnanalyzableDynamicImport { .. } => "unanalyzable-dynamic-import",
@@ -85,20 +87,153 @@ impl ImportMapUnfurlDiagnostic {
}
}
-pub struct ImportMapUnfurler<'a> {
- import_map: &'a MappedSpecifierResolver,
+pub struct SpecifierUnfurler<'a> {
+ mapped_resolver: &'a MappedSpecifierResolver,
+ sloppy_imports_resolver: Option<&'a SloppyImportsResolver>,
+ bare_node_builtins: bool,
}
-impl<'a> ImportMapUnfurler<'a> {
- pub fn new(import_map: &'a MappedSpecifierResolver) -> Self {
- Self { import_map }
+impl<'a> SpecifierUnfurler<'a> {
+ pub fn new(
+ mapped_resolver: &'a MappedSpecifierResolver,
+ sloppy_imports_resolver: Option<&'a SloppyImportsResolver>,
+ bare_node_builtins: bool,
+ ) -> Self {
+ Self {
+ mapped_resolver,
+ sloppy_imports_resolver,
+ bare_node_builtins,
+ }
+ }
+
+ fn unfurl_specifier(
+ &self,
+ referrer: &ModuleSpecifier,
+ specifier: &str,
+ ) -> Option<String> {
+ let resolved =
+ if let Ok(resolved) = self.mapped_resolver.resolve(specifier, referrer) {
+ resolved.into_specifier()
+ } else {
+ None
+ };
+ let resolved = match resolved {
+ Some(resolved) => resolved,
+ None if self.bare_node_builtins && is_builtin_node_module(specifier) => {
+ format!("node:{specifier}").parse().unwrap()
+ }
+ None => ModuleSpecifier::options()
+ .base_url(Some(referrer))
+ .parse(specifier)
+ .ok()?,
+ };
+ // TODO(lucacasonato): this requires integration in deno_graph first
+ // let resolved = if let Ok(specifier) =
+ // NpmPackageReqReference::from_specifier(&resolved)
+ // {
+ // if let Some(scope_name) = specifier.req().name.strip_prefix("@jsr/") {
+ // let (scope, name) = scope_name.split_once("__")?;
+ // let new_specifier = JsrPackageReqReference::new(PackageReqReference {
+ // req: PackageReq {
+ // name: format!("@{scope}/{name}"),
+ // version_req: specifier.req().version_req.clone(),
+ // },
+ // sub_path: specifier.sub_path().map(ToOwned::to_owned),
+ // })
+ // .to_string();
+ // ModuleSpecifier::parse(&new_specifier).unwrap()
+ // } else {
+ // resolved
+ // }
+ // } else {
+ // resolved
+ // };
+ let resolved =
+ if let Some(sloppy_imports_resolver) = self.sloppy_imports_resolver {
+ sloppy_imports_resolver
+ .resolve(&resolved)
+ .as_specifier()
+ .clone()
+ } else {
+ resolved
+ };
+ relative_url(&resolved, referrer, specifier)
+ }
+
+ /// Attempts to unfurl the dynamic dependency returning `true` on success
+ /// or `false` when the import was not analyzable.
+ fn try_unfurl_dynamic_dep(
+ &self,
+ module_url: &lsp_types::Url,
+ parsed_source: &ParsedSource,
+ dep: &deno_graph::DynamicDependencyDescriptor,
+ text_changes: &mut Vec<deno_ast::TextChange>,
+ ) -> bool {
+ match &dep.argument {
+ deno_graph::DynamicArgument::String(specifier) => {
+ let range = to_range(parsed_source, &dep.argument_range);
+ let maybe_relative_index =
+ parsed_source.text_info().text_str()[range.start..].find(specifier);
+ let Some(relative_index) = maybe_relative_index else {
+ return false;
+ };
+ let unfurled = self.unfurl_specifier(module_url, specifier);
+ let Some(unfurled) = unfurled else {
+ return false;
+ };
+ let start = range.start + relative_index;
+ text_changes.push(deno_ast::TextChange {
+ range: start..start + specifier.len(),
+ new_text: unfurled,
+ });
+ true
+ }
+ deno_graph::DynamicArgument::Template(parts) => match parts.first() {
+ Some(DynamicTemplatePart::String { value: specifier }) => {
+ // relative doesn't need to be modified
+ let is_relative =
+ specifier.starts_with("./") || specifier.starts_with("../");
+ if is_relative {
+ return true;
+ }
+ if !specifier.ends_with('/') {
+ return false;
+ }
+ let unfurled = self.unfurl_specifier(module_url, specifier);
+ let Some(unfurled) = unfurled else {
+ return false;
+ };
+ let range = to_range(parsed_source, &dep.argument_range);
+ let maybe_relative_index =
+ parsed_source.text_info().text_str()[range.start..].find(specifier);
+ let Some(relative_index) = maybe_relative_index else {
+ return false;
+ };
+ let start = range.start + relative_index;
+ text_changes.push(deno_ast::TextChange {
+ range: start..start + specifier.len(),
+ new_text: unfurled,
+ });
+ true
+ }
+ Some(DynamicTemplatePart::Expr) => {
+ false // failed analyzing
+ }
+ None => {
+ true // ignore
+ }
+ },
+ deno_graph::DynamicArgument::Expr => {
+ false // failed analyzing
+ }
+ }
}
pub fn unfurl(
&self,
url: &ModuleSpecifier,
parsed_source: &ParsedSource,
- diagnostic_reporter: &mut dyn FnMut(ImportMapUnfurlDiagnostic),
+ diagnostic_reporter: &mut dyn FnMut(SpecifierUnfurlerDiagnostic),
) -> String {
let mut text_changes = Vec::new();
let module_info = DefaultModuleAnalyzer::module_info(parsed_source);
@@ -106,14 +241,11 @@ impl<'a> ImportMapUnfurler<'a> {
|specifier: &str,
range: &deno_graph::PositionRange,
text_changes: &mut Vec<deno_ast::TextChange>| {
- let resolved = self.import_map.resolve(specifier, url);
- if let Ok(resolved) = resolved {
- if let Some(resolved) = resolved.into_specifier() {
- text_changes.push(deno_ast::TextChange {
- range: to_range(parsed_source, range),
- new_text: make_relative_to(url, &resolved),
- });
- }
+ if let Some(unfurled) = self.unfurl_specifier(url, specifier) {
+ text_changes.push(deno_ast::TextChange {
+ range: to_range(parsed_source, range),
+ new_text: unfurled,
+ });
}
};
for dep in &module_info.dependencies {
@@ -126,8 +258,7 @@ impl<'a> ImportMapUnfurler<'a> {
);
}
DependencyDescriptor::Dynamic(dep) => {
- let success = try_unfurl_dynamic_dep(
- self.import_map,
+ let success = self.try_unfurl_dynamic_dep(
url,
parsed_source,
dep,
@@ -144,7 +275,7 @@ impl<'a> ImportMapUnfurler<'a> {
.line_start(dep.argument_range.end.line)
+ dep.argument_range.end.character;
diagnostic_reporter(
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport {
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport {
specifier: url.to_owned(),
range: SourceRange::new(start_pos, end_pos),
text_info: parsed_source.text_info().clone(),
@@ -188,85 +319,20 @@ impl<'a> ImportMapUnfurler<'a> {
}
}
-fn make_relative_to(from: &ModuleSpecifier, to: &ModuleSpecifier) -> String {
- if to.scheme() == "file" {
- format!("./{}", from.make_relative(to).unwrap())
+fn relative_url(
+ resolved: &ModuleSpecifier,
+ referrer: &ModuleSpecifier,
+ specifier: &str,
+) -> Option<String> {
+ let new_specifier = if resolved.scheme() == "file" {
+ format!("./{}", referrer.make_relative(resolved).unwrap())
} else {
- to.to_string()
- }
-}
-
-/// Attempts to unfurl the dynamic dependency returning `true` on success
-/// or `false` when the import was not analyzable.
-fn try_unfurl_dynamic_dep(
- mapped_resolver: &MappedSpecifierResolver,
- module_url: &lsp_types::Url,
- parsed_source: &ParsedSource,
- dep: &deno_graph::DynamicDependencyDescriptor,
- text_changes: &mut Vec<deno_ast::TextChange>,
-) -> bool {
- match &dep.argument {
- deno_graph::DynamicArgument::String(value) => {
- let range = to_range(parsed_source, &dep.argument_range);
- let maybe_relative_index =
- parsed_source.text_info().text_str()[range.start..].find(value);
- let Some(relative_index) = maybe_relative_index else {
- return false;
- };
- let resolved = mapped_resolver.resolve(value, module_url);
- let Ok(resolved) = resolved else {
- return false;
- };
- let Some(resolved) = resolved.into_specifier() else {
- return false;
- };
- let start = range.start + relative_index;
- text_changes.push(deno_ast::TextChange {
- range: start..start + value.len(),
- new_text: make_relative_to(module_url, &resolved),
- });
- true
- }
- deno_graph::DynamicArgument::Template(parts) => match parts.first() {
- Some(DynamicTemplatePart::String { value }) => {
- // relative doesn't need to be modified
- let is_relative = value.starts_with("./") || value.starts_with("../");
- if is_relative {
- return true;
- }
- if !value.ends_with('/') {
- return false;
- }
- let Ok(resolved) = mapped_resolver.resolve(value, module_url) else {
- return false;
- };
- let Some(resolved) = resolved.into_specifier() else {
- return false;
- };
- let range = to_range(parsed_source, &dep.argument_range);
- let maybe_relative_index =
- parsed_source.text_info().text_str()[range.start..].find(value);
- let Some(relative_index) = maybe_relative_index else {
- return false;
- };
- let start = range.start + relative_index;
- text_changes.push(deno_ast::TextChange {
- range: start..start + value.len(),
- new_text: make_relative_to(module_url, &resolved),
- });
- true
- }
- Some(DynamicTemplatePart::Expr) => {
- false // failed analyzing
- }
- None => {
- true // ignore
- }
- },
- deno_graph::DynamicArgument::Expr => {
- false // failed analyzing
- }
+ resolved.to_string()
+ };
+ if new_specifier == specifier {
+ return None;
}
+ Some(new_specifier)
}
fn to_range(
@@ -290,6 +356,7 @@ fn to_range(
mod tests {
use std::sync::Arc;
+ use crate::args::package_json::get_local_package_json_version_reqs;
use crate::args::PackageJsonDepsProvider;
use super::*;
@@ -297,8 +364,12 @@ mod tests {
use deno_ast::ModuleSpecifier;
use deno_core::serde_json::json;
use deno_core::url::Url;
+ use deno_runtime::deno_fs::RealFs;
+ use deno_runtime::deno_node::PackageJson;
use import_map::ImportMapWithDiagnostics;
+ use indexmap::IndexMap;
use pretty_assertions::assert_eq;
+ use test_util::testdata_path;
fn parse_ast(specifier: &Url, source_code: &str) -> ParsedSource {
let media_type = MediaType::from_specifier(specifier);
@@ -315,22 +386,38 @@ mod tests {
#[test]
fn test_unfurling() {
+ let cwd = testdata_path().join("unfurl").to_path_buf();
+
let deno_json_url =
- ModuleSpecifier::parse("file:///dev/deno.json").unwrap();
+ ModuleSpecifier::from_file_path(cwd.join("deno.json")).unwrap();
let value = json!({
"imports": {
"express": "npm:express@5",
"lib/": "./lib/",
- "fizz": "./fizz/mod.ts"
+ "fizz": "./fizz/mod.ts",
+ "@std/fs": "npm:@jsr/std__fs@1",
}
});
let ImportMapWithDiagnostics { import_map, .. } =
import_map::parse_from_value(deno_json_url, value).unwrap();
- let mapped_resolved = MappedSpecifierResolver::new(
+ let mut package_json = PackageJson::empty(cwd.join("package.json"));
+ package_json.dependencies =
+ Some(IndexMap::from([("chalk".to_string(), "5".to_string())]));
+ let mapped_resolver = MappedSpecifierResolver::new(
Some(Arc::new(import_map)),
- Arc::new(PackageJsonDepsProvider::new(None)),
+ Arc::new(PackageJsonDepsProvider::new(Some(
+ get_local_package_json_version_reqs(&package_json),
+ ))),
+ );
+
+ let fs = Arc::new(RealFs);
+ let sloppy_imports_resolver = SloppyImportsResolver::new(fs);
+
+ let unfurler = SpecifierUnfurler::new(
+ &mapped_resolver,
+ Some(&sloppy_imports_resolver),
+ true,
);
- let unfurler = ImportMapUnfurler::new(&mapped_resolved);
// Unfurling TS file should apply changes.
{
@@ -338,6 +425,16 @@ mod tests {
import foo from "lib/foo.ts";
import bar from "lib/bar.ts";
import fizz from "fizz";
+import chalk from "chalk";
+import baz from "./baz";
+import b from "./b.js";
+import b2 from "./b";
+import url from "url";
+// TODO: unfurl these to jsr
+// import "npm:@jsr/std__fs@1/file";
+// import "npm:@jsr/std__fs@1";
+// import "npm:@jsr/std__fs";
+// import "@std/fs";
const test1 = await import("lib/foo.ts");
const test2 = await import(`lib/foo.ts`);
@@ -347,7 +444,8 @@ const test4 = await import(`./lib/${expr}`);
const test5 = await import(`lib${expr}`);
const test6 = await import(`${expr}`);
"#;
- let specifier = ModuleSpecifier::parse("file:///dev/mod.ts").unwrap();
+ let specifier =
+ ModuleSpecifier::from_file_path(cwd.join("mod.ts")).unwrap();
let source = parse_ast(&specifier, source_code);
let mut d = Vec::new();
let mut reporter = |diagnostic| d.push(diagnostic);
@@ -356,7 +454,7 @@ const test6 = await import(`${expr}`);
assert!(
matches!(
d[0],
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { .. }
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. }
),
"{:?}",
d[0]
@@ -364,7 +462,7 @@ const test6 = await import(`${expr}`);
assert!(
matches!(
d[1],
- ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { .. }
+ SpecifierUnfurlerDiagnostic::UnanalyzableDynamicImport { .. }
),
"{:?}",
d[1]
@@ -373,6 +471,16 @@ const test6 = await import(`${expr}`);
import foo from "./lib/foo.ts";
import bar from "./lib/bar.ts";
import fizz from "./fizz/mod.ts";
+import chalk from "npm:chalk@5";
+import baz from "./baz/index.js";
+import b from "./b.ts";
+import b2 from "./b.ts";
+import url from "node:url";
+// TODO: unfurl these to jsr
+// import "npm:@jsr/std__fs@1/file";
+// import "npm:@jsr/std__fs@1";
+// import "npm:@jsr/std__fs";
+// import "@std/fs";
const test1 = await import("./lib/foo.ts");
const test2 = await import(`./lib/foo.ts`);
diff --git a/cli/util/mod.rs b/cli/util/mod.rs
index a3f4a5aa4..a6f72bc04 100644
--- a/cli/util/mod.rs
+++ b/cli/util/mod.rs
@@ -8,7 +8,6 @@ pub mod display;
pub mod draw_thread;
pub mod file_watcher;
pub mod fs;
-pub mod import_map;
pub mod logger;
pub mod path;
pub mod progress_bar;
diff --git a/tests/integration/publish_tests.rs b/tests/integration/publish_tests.rs
index d2ea27906..ae7a332c4 100644
--- a/tests/integration/publish_tests.rs
+++ b/tests/integration/publish_tests.rs
@@ -224,6 +224,22 @@ itest!(config_flag {
http_server: true,
});
+itest!(bare_node_builtins {
+ args: "publish --token 'sadfasdf' --dry-run --unstable-bare-node-builtins",
+ output: "publish/bare_node_builtins.out",
+ cwd: Some("publish/bare_node_builtins"),
+ envs: env_vars_for_jsr_npm_tests(),
+ http_server: true,
+});
+
+itest!(sloppy_imports {
+ args: "publish --token 'sadfasdf' --dry-run --unstable-sloppy-imports",
+ output: "publish/sloppy_imports.out",
+ cwd: Some("publish/sloppy_imports"),
+ envs: env_vars_for_jsr_tests(),
+ http_server: true,
+});
+
itest!(jsr_jsonc {
args: "publish --token 'sadfasdf'",
cwd: Some("publish/jsr_jsonc"),
diff --git a/tests/testdata/publish/bare_node_builtins.out b/tests/testdata/publish/bare_node_builtins.out
new file mode 100644
index 000000000..99d7e4cf9
--- /dev/null
+++ b/tests/testdata/publish/bare_node_builtins.out
@@ -0,0 +1,11 @@
+Warning: Resolving "url" as "node:url" at file:///[WILDCARD]/publish/bare_node_builtins/mod.ts:1:22. If you want to use a built-in Node module, add a "node:" prefix.
+Warning: Resolving "url" as "node:url" at file:///[WILDCARD]/publish/bare_node_builtins/mod.ts:1:22. If you want to use a built-in Node module, add a "node:" prefix.
+Download http://localhost:4545/npm/registry/@types/node
+Download http://localhost:4545/npm/registry/@types/node/node-18.8.2.tgz
+Check file:///[WILDCARD]/publish/bare_node_builtins/mod.ts
+Checking for slow types in the public API...
+Check file:///[WILDCARD]/publish/bare_node_builtins/mod.ts
+Simulating publish of @foo/bar@1.0.0 with files:
+ file:///[WILDCARD]/publish/bare_node_builtins/deno.json (87B)
+ file:///[WILDCARD]/publish/bare_node_builtins/mod.ts (121B)
+Warning Aborting due to --dry-run
diff --git a/tests/testdata/publish/bare_node_builtins/deno.json b/tests/testdata/publish/bare_node_builtins/deno.json
new file mode 100644
index 000000000..213a7cec6
--- /dev/null
+++ b/tests/testdata/publish/bare_node_builtins/deno.json
@@ -0,0 +1,7 @@
+{
+ "name": "@foo/bar",
+ "version": "1.0.0",
+ "exports": {
+ ".": "./mod.ts"
+ }
+}
diff --git a/tests/testdata/publish/bare_node_builtins/mod.ts b/tests/testdata/publish/bare_node_builtins/mod.ts
new file mode 100644
index 000000000..04374d8b7
--- /dev/null
+++ b/tests/testdata/publish/bare_node_builtins/mod.ts
@@ -0,0 +1,5 @@
+import * as url from "url";
+
+export function foobar(): { href: string } {
+ return url.pathToFileURL("/foo/bar");
+}
diff --git a/tests/testdata/publish/sloppy_imports.out b/tests/testdata/publish/sloppy_imports.out
new file mode 100644
index 000000000..a3af86575
--- /dev/null
+++ b/tests/testdata/publish/sloppy_imports.out
@@ -0,0 +1,12 @@
+Warning Sloppy module resolution (hint: specify path to index.ts file in directory instead)
+ at file:///[WILDCARD]/publish/sloppy_imports/mod.ts:1:20
+Warning Sloppy module resolution (hint: specify path to index.ts file in directory instead)
+ at file:///[WILDCARD]/publish/sloppy_imports/mod.ts:1:20
+Check file:///[WILDCARD]/publish/sloppy_imports/mod.ts
+Checking for slow types in the public API...
+Check file:///[WILDCARD]/publish/sloppy_imports/mod.ts
+Simulating publish of @foo/bar@1.0.0 with files:
+ file:///[WILDCARD]/publish/sloppy_imports/b/index.ts (27B)
+ file:///[WILDCARD]/publish/sloppy_imports/deno.json (87B)
+ file:///[WILDCARD]/publish/sloppy_imports/mod.ts (35B)
+Warning Aborting due to --dry-run
diff --git a/tests/testdata/publish/sloppy_imports/b/index.ts b/tests/testdata/publish/sloppy_imports/b/index.ts
new file mode 100644
index 000000000..1392bf6ba
--- /dev/null
+++ b/tests/testdata/publish/sloppy_imports/b/index.ts
@@ -0,0 +1 @@
+export const PI = Math.PI;
diff --git a/tests/testdata/publish/sloppy_imports/deno.json b/tests/testdata/publish/sloppy_imports/deno.json
new file mode 100644
index 000000000..213a7cec6
--- /dev/null
+++ b/tests/testdata/publish/sloppy_imports/deno.json
@@ -0,0 +1,7 @@
+{
+ "name": "@foo/bar",
+ "version": "1.0.0",
+ "exports": {
+ ".": "./mod.ts"
+ }
+}
diff --git a/tests/testdata/publish/sloppy_imports/mod.ts b/tests/testdata/publish/sloppy_imports/mod.ts
new file mode 100644
index 000000000..f5084bb3b
--- /dev/null
+++ b/tests/testdata/publish/sloppy_imports/mod.ts
@@ -0,0 +1 @@
+export { PI } from "./b";
diff --git a/tests/testdata/publish/unanalyzable_dynamic_import.out b/tests/testdata/publish/unanalyzable_dynamic_import.out
index da6a6f902..7f3ca5555 100644
--- a/tests/testdata/publish/unanalyzable_dynamic_import.out
+++ b/tests/testdata/publish/unanalyzable_dynamic_import.out
@@ -7,9 +7,9 @@ warning[unanalyzable-dynamic-import]: unable to analyze dynamic import
2 | await import("asd " + asd);
| ^^^^^^^^^^^^ the unanalyzable dynamic import
- info: after publishing this package, imports from the local import map do not work
+ info: after publishing this package, imports from the local import map / package.json do not work
info: dynamic imports that can not be analyzed at publish time will not be rewritten automatically
- info: make sure the dynamic import is resolvable at runtime without an import map
+ info: make sure the dynamic import is resolvable at runtime without an import map / package.json
Publishing @foo/bar@1.0.0 ...
Successfully published @foo/bar@1.0.0
diff --git a/tests/testdata/unfurl/b.ts b/tests/testdata/unfurl/b.ts
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testdata/unfurl/b.ts
diff --git a/tests/testdata/unfurl/baz/index.js b/tests/testdata/unfurl/baz/index.js
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testdata/unfurl/baz/index.js