fix(npm): support resolving npm specifiers not in graph with import.meta.resolve for resolved packages (#29732)

This commit is contained in:
David Sherret 2025-06-13 09:23:19 -04:00 committed by GitHub
parent 1f02d34877
commit 3d5ff3cf1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 297 additions and 130 deletions

4
Cargo.lock generated
View file

@ -2716,9 +2716,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_semver" name = "deno_semver"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2d807160e754edb1989b4a19cac1ac5299065a7a89ff98682a2366cbaa25795" checksum = "5a7123b11b66cf19e023372bfcb137498243ef32dd73c725b938c118ac9943f5"
dependencies = [ dependencies = [
"capacity_builder", "capacity_builder",
"deno_error", "deno_error",

View file

@ -70,7 +70,7 @@ deno_native_certs = "0.3.0"
deno_npm = "=0.35.0" deno_npm = "=0.35.0"
deno_package_json = { version = "=0.9.0", default-features = false } deno_package_json = { version = "=0.9.0", default-features = false }
deno_path_util = "=0.4.0" deno_path_util = "=0.4.0"
deno_semver = "=0.8.0" deno_semver = "=0.8.1"
deno_task_shell = "=0.24.0" deno_task_shell = "=0.24.0"
deno_terminal = "=0.2.2" deno_terminal = "=0.2.2"
deno_unsync = { version = "0.4.4", default-features = false } deno_unsync = { version = "0.4.4", default-features = false }

View file

@ -103,7 +103,6 @@ use crate::npm::CliNpmResolver;
use crate::npm::DenoTaskLifeCycleScriptsExecutor; use crate::npm::DenoTaskLifeCycleScriptsExecutor;
use crate::resolver::on_resolve_diagnostic; use crate::resolver::on_resolve_diagnostic;
use crate::resolver::CliCjsTracker; use crate::resolver::CliCjsTracker;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::standalone::binary::DenoCompileBinaryWriter; use crate::standalone::binary::DenoCompileBinaryWriter;
use crate::sys::CliSys; use crate::sys::CliSys;
@ -769,10 +768,6 @@ impl CliFactory {
)) ))
} }
pub fn npm_req_resolver(&self) -> Result<&Arc<CliNpmReqResolver>, AnyError> {
self.resolver_factory()?.npm_req_resolver()
}
pub fn pkg_json_resolver( pub fn pkg_json_resolver(
&self, &self,
) -> Result<&Arc<CliPackageJsonResolver>, AnyError> { ) -> Result<&Arc<CliPackageJsonResolver>, AnyError> {
@ -1017,7 +1012,6 @@ impl CliFactory {
let in_npm_pkg_checker = self.in_npm_pkg_checker()?; let in_npm_pkg_checker = self.in_npm_pkg_checker()?;
let node_code_translator = self.node_code_translator().await?; let node_code_translator = self.node_code_translator().await?;
let cjs_tracker = self.cjs_tracker()?.clone(); let cjs_tracker = self.cjs_tracker()?.clone();
let npm_req_resolver = self.npm_req_resolver()?;
let workspace_factory = self.workspace_factory()?; let workspace_factory = self.workspace_factory()?;
let npm_registry_permission_checker = { let npm_registry_permission_checker = {
let mode = if self.resolver_factory()?.use_byonm()? { let mode = if self.resolver_factory()?.use_byonm()? {
@ -1057,7 +1051,6 @@ impl CliFactory {
self.sys(), self.sys(),
), ),
npm_registry_permission_checker, npm_registry_permission_checker,
npm_req_resolver.clone(),
cli_npm_resolver.clone(), cli_npm_resolver.clone(),
self.parsed_source_cache().clone(), self.parsed_source_cache().clone(),
self.resolver().await?.clone(), self.resolver().await?.clone(),

View file

@ -60,7 +60,6 @@ use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::ops::require::UnableToGetCwdError; use deno_runtime::deno_node::ops::require::UnableToGetCwdError;
use deno_runtime::deno_node::NodeRequireLoader; use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use eszip::EszipV2; use eszip::EszipV2;
use node_resolver::errors::ClosestPkgJsonError; use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::DenoIsBuiltInNodeModuleChecker; use node_resolver::DenoIsBuiltInNodeModuleChecker;
@ -92,7 +91,6 @@ use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker; use crate::resolver::CliCjsTracker;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::sys::CliSys; use crate::sys::CliSys;
use crate::type_checker::CheckError; use crate::type_checker::CheckError;
@ -331,7 +329,6 @@ struct SharedCliModuleLoaderState {
npm_module_loader: CliNpmModuleLoader, npm_module_loader: CliNpmModuleLoader,
npm_registry_permission_checker: npm_registry_permission_checker:
Arc<NpmRegistryReadPermissionChecker<CliSys>>, Arc<NpmRegistryReadPermissionChecker<CliSys>>,
npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: CliNpmResolver, npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
@ -394,7 +391,6 @@ impl CliModuleLoaderFactory {
npm_registry_permission_checker: Arc< npm_registry_permission_checker: Arc<
NpmRegistryReadPermissionChecker<CliSys>, NpmRegistryReadPermissionChecker<CliSys>,
>, >,
npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: CliNpmResolver, npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
@ -421,7 +417,6 @@ impl CliModuleLoaderFactory {
node_code_translator, node_code_translator,
npm_module_loader, npm_module_loader,
npm_registry_permission_checker, npm_registry_permission_checker,
npm_req_resolver,
npm_resolver, npm_resolver,
parsed_source_cache, parsed_source_cache,
resolver, resolver,
@ -789,47 +784,33 @@ impl<TGraphContainer: ModuleGraphContainer>
referrer: &ModuleSpecifier, referrer: &ModuleSpecifier,
) -> Result<ModuleSpecifier, ModuleLoaderError> { ) -> Result<ModuleSpecifier, ModuleLoaderError> {
let graph = self.graph_container.graph(); let graph = self.graph_container.graph();
let specifier = self let result = self.shared.resolver.resolve_with_graph(
.shared
.resolver
.resolve_with_graph(
graph.as_ref(), graph.as_ref(),
raw_specifier, raw_specifier,
referrer, referrer,
deno_graph::Position::zeroed(), deno_graph::Position::zeroed(),
ResolutionMode::Import, ResolutionMode::Import,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) );
.map_err(|err| match err.into_kind() { match result {
Ok(specifier) => Ok(specifier),
Err(err) => match err.into_kind() {
ResolveWithGraphErrorKind::ResolveNpmReqRef(err) => {
// this is a npm specifier not in the graph... we've always
// returned these as-is, so continue to do that even though it's
// questionable and should probably throw
Ok(ModuleSpecifier::parse(&err.npm_req_ref.to_string()).unwrap())
}
ResolveWithGraphErrorKind::Resolution(err) => { ResolveWithGraphErrorKind::Resolution(err) => {
// todo(dsherret): why do we have a newline here? Document it. // todo(dsherret): why do we have a newline here? Document it.
Err(
JsErrorBox::type_error(format!("{}\n", err.to_string_with_range())) JsErrorBox::type_error(format!("{}\n", err.to_string_with_range()))
} .into(),
err => JsErrorBox::from_err(err),
})?;
if self.shared.is_repl {
if let Ok(reference) = NpmPackageReqReference::from_specifier(&specifier)
{
return self
.shared
.npm_req_resolver
.resolve_req_reference(
&reference,
referrer,
ResolutionMode::Import,
NodeResolutionKind::Execution,
) )
.map_err(|e| JsErrorBox::from_err(e).into())
.and_then(|url_or_path| {
url_or_path
.into_url()
.map_err(|e| JsErrorBox::from_err(e).into())
});
} }
err => Err(JsErrorBox::from_err(err).into()),
},
} }
Ok(specifier)
} }
async fn load_prepared_module( async fn load_prepared_module(

View file

@ -40,8 +40,6 @@ use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit; use crate::graph_container::ModuleGraphUpdatePermit;
use crate::module_loader::ModuleLoadPreparer; use crate::module_loader::ModuleLoadPreparer;
use crate::module_loader::PrepareModuleLoadOptions; use crate::module_loader::PrepareModuleLoadOptions;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::tools::bundle::externals::ExternalsMatcher; use crate::tools::bundle::externals::ExternalsMatcher;
@ -73,8 +71,8 @@ pub async fn bundle(
let resolver = factory.resolver().await?.clone(); let resolver = factory.resolver().await?.clone();
let module_load_preparer = factory.module_load_preparer().await?.clone(); let module_load_preparer = factory.module_load_preparer().await?.clone();
let root_permissions = factory.root_permissions_container()?; let root_permissions = factory.root_permissions_container()?;
let npm_resolver = factory.npm_resolver().await?.clone(); let npm_resolver = factory.npm_resolver().await?;
let node_resolver = factory.node_resolver().await?.clone(); let node_resolver = factory.node_resolver().await?;
let cli_options = factory.cli_options()?; let cli_options = factory.cli_options()?;
let module_loader = factory let module_loader = factory
.create_module_loader_factory() .create_module_loader_factory()
@ -93,8 +91,6 @@ pub async fn bundle(
.await? .await?
.clone(), .clone(),
permissions: root_permissions.clone(), permissions: root_permissions.clone(),
npm_resolver: npm_resolver.clone(),
node_resolver: node_resolver.clone(),
module_loader: module_loader.clone(), module_loader: module_loader.clone(),
externals_matcher: if bundle_flags.external.is_empty() { externals_matcher: if bundle_flags.external.is_empty() {
None None
@ -358,8 +354,6 @@ struct DenoPluginHandler {
module_load_preparer: Arc<ModuleLoadPreparer>, module_load_preparer: Arc<ModuleLoadPreparer>,
module_graph_container: Arc<MainModuleGraphContainer>, module_graph_container: Arc<MainModuleGraphContainer>,
permissions: PermissionsContainer, permissions: PermissionsContainer,
npm_resolver: CliNpmResolver,
node_resolver: Arc<CliNodeResolver>,
module_loader: Rc<dyn ModuleLoader>, module_loader: Rc<dyn ModuleLoader>,
externals_matcher: Option<ExternalsMatcher>, externals_matcher: Option<ExternalsMatcher>,
} }
@ -655,21 +649,12 @@ impl DenoPluginHandler {
), ),
deno_graph::Module::Wasm(_) => todo!(), deno_graph::Module::Wasm(_) => todo!(),
deno_graph::Module::Npm(module) => { deno_graph::Module::Npm(module) => {
let package_folder = self let url = self.resolver.resolve_npm_nv_ref(
.npm_resolver &module.nv_reference,
.as_managed()
.unwrap() // byonm won't create a Module::Npm
.resolve_pkg_folder_from_deno_module(module.nv_reference.nv())?;
let path = self
.node_resolver
.resolve_package_subpath_from_deno_module(
&package_folder,
module.nv_reference.sub_path(),
None, None,
ResolutionMode::Import, ResolutionMode::Import,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)?; )?;
let url = path.clone().into_url()?;
let (media_type, _charset) = let (media_type, _charset) =
deno_media_type::resolve_media_type_and_charset_from_content_type( deno_media_type::resolve_media_type_and_charset_from_content_type(
&url, None, &url, None,

View file

@ -7,6 +7,8 @@ use deno_error::JsErrorBox;
use deno_graph::source::ResolveError; use deno_graph::source::ResolveError;
use deno_graph::Module; use deno_graph::Module;
use deno_graph::Resolution; use deno_graph::Resolution;
use deno_semver::npm::NpmPackageNvReference;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_unsync::sync::AtomicFlag; use deno_unsync::sync::AtomicFlag;
use node_resolver::DenoIsBuiltInNodeModuleChecker; use node_resolver::DenoIsBuiltInNodeModuleChecker;
@ -48,6 +50,9 @@ pub enum ResolveWithGraphErrorKind {
), ),
#[error(transparent)] #[error(transparent)]
#[class(inherit)] #[class(inherit)]
ResolveNpmReqRef(#[from] npm::ResolveNpmReqRefError),
#[error(transparent)]
#[class(inherit)]
Resolution(#[from] deno_graph::ResolutionError), Resolution(#[from] deno_graph::ResolutionError),
#[error(transparent)] #[error(transparent)]
#[class(inherit)] #[class(inherit)]
@ -218,29 +223,12 @@ impl<
}; };
let specifier = match graph.get(&specifier) { let specifier = match graph.get(&specifier) {
Some(Module::Npm(module)) => { Some(Module::Npm(module)) => self.resolve_npm_nv_ref(
let node_and_npm_resolver = &module.nv_reference,
self.resolver.node_and_npm_resolver.as_ref().unwrap();
let package_folder = node_and_npm_resolver
.npm_resolver
.as_managed()
.unwrap() // byonm won't create a Module::Npm
.resolve_pkg_folder_from_deno_module(module.nv_reference.nv())?;
node_and_npm_resolver
.node_resolver
.resolve_package_subpath_from_deno_module(
&package_folder,
module.nv_reference.sub_path(),
Some(referrer), Some(referrer),
resolution_mode, resolution_mode,
resolution_kind, resolution_kind,
) )?,
.map_err(|source| CouldNotResolveError {
reference: module.nv_reference.clone(),
source,
})?
.into_url()?
}
Some(Module::Node(module)) => module.specifier.clone(), Some(Module::Node(module)) => module.specifier.clone(),
Some(Module::Js(module)) => module.specifier.clone(), Some(Module::Js(module)) => module.specifier.clone(),
Some(Module::Json(module)) => module.specifier.clone(), Some(Module::Json(module)) => module.specifier.clone(),
@ -251,11 +239,62 @@ impl<
&module.specifier, &module.specifier,
) )
} }
None => specifier.into_owned(), None => {
if let Ok(reference) =
NpmPackageReqReference::from_specifier(&specifier)
{
if let Some(url) =
self.resolver.resolve_non_workspace_npm_req_ref_to_file(
&reference,
referrer,
resolution_mode,
resolution_kind,
)?
{
url.into_url()?
} else {
specifier.into_owned()
}
} else {
specifier.into_owned()
}
}
}; };
Ok(specifier) Ok(specifier)
} }
pub fn resolve_npm_nv_ref(
&self,
nv_ref: &NpmPackageNvReference,
maybe_referrer: Option<&Url>,
resolution_mode: node_resolver::ResolutionMode,
resolution_kind: node_resolver::NodeResolutionKind,
) -> Result<Url, ResolveWithGraphError> {
let node_and_npm_resolver =
self.resolver.node_and_npm_resolver.as_ref().unwrap();
let package_folder = node_and_npm_resolver
.npm_resolver
.as_managed()
.unwrap() // we won't have an nv ref when not managed
.resolve_pkg_folder_from_deno_module(nv_ref.nv())?;
Ok(
node_and_npm_resolver
.node_resolver
.resolve_package_subpath_from_deno_module(
&package_folder,
nv_ref.sub_path(),
maybe_referrer,
resolution_mode,
resolution_kind,
)
.map_err(|source| CouldNotResolveError {
reference: nv_ref.clone(),
source,
})?
.into_url()?,
)
}
pub fn resolve( pub fn resolve(
&self, &self,
raw_specifier: &str, raw_specifier: &str,

View file

@ -23,17 +23,16 @@ pub use node_resolver::NodeResolverOptions;
use node_resolver::NodeResolverRc; use node_resolver::NodeResolverRc;
use node_resolver::NpmPackageFolderResolver; use node_resolver::NpmPackageFolderResolver;
use node_resolver::ResolutionMode; use node_resolver::ResolutionMode;
use npm::MissingPackageNodeModulesFolderError;
use npm::NodeModulesOutOfDateError; use npm::NodeModulesOutOfDateError;
use npm::NpmReqResolverRc; use npm::NpmReqResolverRc;
use npm::ResolveIfForNpmPackageErrorKind; use npm::ResolveIfForNpmPackageErrorKind;
use npm::ResolvePkgFolderFromDenoReqError; use npm::ResolvePkgFolderFromDenoReqError;
use npm::ResolveReqWithSubPathErrorKind;
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
use self::npm::NpmResolver; use self::npm::NpmResolver;
use self::npm::NpmResolverSys; use self::npm::NpmResolverSys;
use self::npm::ResolveNpmReqRefError;
use crate::workspace::MappedResolution; use crate::workspace::MappedResolution;
use crate::workspace::MappedResolutionDiagnostic; use crate::workspace::MappedResolutionDiagnostic;
use crate::workspace::MappedResolutionError; use crate::workspace::MappedResolutionError;
@ -89,9 +88,6 @@ pub enum DenoResolveErrorKind {
MappedResolution(#[from] MappedResolutionError), MappedResolution(#[from] MappedResolutionError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
MissingPackageNodeModulesFolder(#[from] MissingPackageNodeModulesFolderError),
#[class(inherit)]
#[error(transparent)]
Node(#[from] NodeResolveError), Node(#[from] NodeResolveError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
@ -110,6 +106,9 @@ pub enum DenoResolveErrorKind {
PathToUrl(#[from] deno_path_util::PathToUrlError), PathToUrl(#[from] deno_path_util::PathToUrlError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
ResolveNpmReqRef(#[from] ResolveNpmReqRefError),
#[class(inherit)]
#[error(transparent)]
ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
@ -463,7 +462,13 @@ impl<
resolution_mode, resolution_mode,
resolution_kind, resolution_kind,
) )
.map_err(DenoResolveError::from) .map_err(|err| {
DenoResolveErrorKind::ResolveNpmReqRef(ResolveNpmReqRefError {
npm_req_ref: npm_req_ref.clone(),
err: err.into(),
})
.into_box()
})
.and_then(|url_or_path| { .and_then(|url_or_path| {
Ok(DenoResolution { Ok(DenoResolution {
url: url_or_path.into_url()?, url: url_or_path.into_url()?,
@ -473,7 +478,6 @@ impl<
}); });
} }
// do npm resolution for byonm
if self.is_byonm { if self.is_byonm {
return npm_req_resolver return npm_req_resolver
.resolve_req_reference( .resolve_req_reference(
@ -483,23 +487,15 @@ impl<
resolution_kind, resolution_kind,
) )
.map_err(|err| { .map_err(|err| {
match err.into_kind() { DenoResolveErrorKind::ResolveNpmReqRef(err).into_box()
ResolveReqWithSubPathErrorKind::MissingPackageNodeModulesFolder(
err,
) => err.into(),
ResolveReqWithSubPathErrorKind::ResolvePkgFolderFromDenoReq(
err,
) => err.into(),
ResolveReqWithSubPathErrorKind::PackageSubpathResolve(err) => {
err.into()
}
}
}) })
.and_then(|url_or_path| Ok(DenoResolution { .and_then(|url_or_path| {
Ok(DenoResolution {
url: url_or_path.into_url()?, url: url_or_path.into_url()?,
maybe_diagnostic, maybe_diagnostic,
found_package_json_dep, found_package_json_dep,
})); })
});
} }
} }
@ -564,4 +560,28 @@ impl<
} }
} }
} }
#[cfg(feature = "graph")]
pub(crate) fn resolve_non_workspace_npm_req_ref_to_file(
&self,
npm_req_ref: &NpmPackageReqReference,
referrer: &Url,
resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind,
) -> Result<Option<node_resolver::UrlOrPath>, npm::ResolveNpmReqRefError> {
let Some(NodeAndNpmResolvers {
npm_req_resolver, ..
}) = &self.node_and_npm_resolver
else {
return Ok(None);
};
npm_req_resolver
.resolve_req_reference(
npm_req_ref,
referrer,
resolution_mode,
resolution_kind,
)
.map(Some)
}
} }

View file

@ -9,6 +9,7 @@ use deno_error::JsError;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::package::PackageReqReference;
use node_resolver::errors::NodeResolveError; use node_resolver::errors::NodeResolveError;
use node_resolver::errors::NodeResolveErrorKind; use node_resolver::errors::NodeResolveErrorKind;
use node_resolver::errors::PackageFolderResolveErrorKind; use node_resolver::errors::PackageFolderResolveErrorKind;
@ -116,6 +117,26 @@ pub enum ResolveIfForNpmPackageErrorKind {
NodeModulesOutOfDate(#[from] NodeModulesOutOfDateError), NodeModulesOutOfDate(#[from] NodeModulesOutOfDateError),
} }
#[derive(Debug, JsError)]
#[class(inherit)]
pub struct ResolveNpmReqRefError {
pub npm_req_ref: NpmPackageReqReference,
#[inherit]
pub err: ResolveReqWithSubPathError,
}
impl std::error::Error for ResolveNpmReqRefError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.err.source()
}
}
impl std::fmt::Display for ResolveNpmReqRefError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.err, f)
}
}
#[derive(Debug, Boxed, JsError)] #[derive(Debug, Boxed, JsError)]
pub struct ResolveReqWithSubPathError(pub Box<ResolveReqWithSubPathErrorKind>); pub struct ResolveReqWithSubPathError(pub Box<ResolveReqWithSubPathErrorKind>);
@ -336,7 +357,7 @@ impl<
referrer: &Url, referrer: &Url,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<UrlOrPath, ResolveReqWithSubPathError> { ) -> Result<UrlOrPath, ResolveNpmReqRefError> {
self.resolve_req_with_sub_path( self.resolve_req_with_sub_path(
req_ref.req(), req_ref.req(),
req_ref.sub_path(), req_ref.sub_path(),
@ -353,6 +374,31 @@ impl<
referrer: &Url, referrer: &Url,
resolution_mode: ResolutionMode, resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind, resolution_kind: NodeResolutionKind,
) -> Result<UrlOrPath, ResolveNpmReqRefError> {
self
.resolve_req_with_sub_path_inner(
req,
sub_path,
referrer,
resolution_mode,
resolution_kind,
)
.map_err(|source| ResolveNpmReqRefError {
npm_req_ref: NpmPackageReqReference::new(PackageReqReference {
req: req.clone(),
sub_path: sub_path.map(|s| s.into()),
}),
err: source,
})
}
fn resolve_req_with_sub_path_inner(
&self,
req: &PackageReq,
sub_path: Option<&str>,
referrer: &Url,
resolution_mode: ResolutionMode,
resolution_kind: NodeResolutionKind,
) -> Result<UrlOrPath, ResolveReqWithSubPathError> { ) -> Result<UrlOrPath, ResolveReqWithSubPathError> {
let package_folder = self let package_folder = self
.npm_resolver .npm_resolver

View file

@ -907,12 +907,6 @@ itest!(error_local_static_import_from_remote_js {
output: "run/error_local_static_import_from_remote.js.out", output: "run/error_local_static_import_from_remote.js.out",
}); });
itest!(import_meta {
args: "run --allow-import --quiet --reload --import-map=run/import_meta/importmap.json run/import_meta/main.ts",
output: "run/import_meta/main.out",
http_server: true,
});
itest!(no_check_remote { itest!(no_check_remote {
args: "run --allow-import --quiet --reload --no-check=remote run/no_check_remote.ts", args: "run --allow-import --quiet --reload --no-check=remote run/no_check_remote.ts",
output: "run/no_check_remote.ts.enabled.out", output: "run/no_check_remote.ts.enabled.out",

View file

@ -0,0 +1,4 @@
{
"args": "run --allow-import --quiet --reload --import-map=importmap.json main.ts",
"output": "main.out"
}

View file

@ -0,0 +1,16 @@
{
"imports": {
"@std/assert/throws": "../../../util/std/assert/throws.ts",
"@std/internal/styles": "../../../util/std/internal/styles.ts",
"bare": "https://example.com/",
"https://example.com/rewrite": "https://example.com/rewritten",
"1": "https://example.com/PASS-1",
"null": "https://example.com/PASS-null",
"undefined": "https://example.com/PASS-undefined",
"[object Object]": "https://example.com/PASS-object",
"npm:preact": "https://example.com/preact",
"@denotest/add": "npm:@denotest/add@1.0"
}
}

View file

@ -0,0 +1,16 @@
other remote [WILDCARD]other.ts false undefined undefined
other [WILDCARD]other.ts false [WILDCARD]other.ts [WILDCARD]
main [WILDCARD]main.ts true [WILDCARD]main.ts [WILDCARD]
Resolving ./foo.js file:///[WILDCARD]/foo.js
Resolving bare from import map https://example.com/
Resolving https://example.com/rewrite from import map https://example.com/rewritten
Resolving without a value from import map https://example.com/PASS-undefined
Resolving 1 from import map https://example.com/PASS-1
Resolving null from import map https://example.com/PASS-null
Resolving object from import map https://example.com/PASS-object
Resolving npm:cowsay npm:cowsay
Resolving npm:cowsay@1 npm:cowsay@1
Resolving npm:preact from import map https://example.com/preact
Resolving existing npm:@denotest/add@1.0 specifier file:///[WILDLINE]/npm/localhost_4260/@denotest/add/1.0.0/index.js
Resolving compatible npm:@denotest/add@1 specifier file:///[WILDLINE]/npm/localhost_4260/@denotest/add/1.0.0/index.js
Resolving compatible npm:@denotest/add@1.0.0 specifier file:///[WILDLINE]/npm/localhost_4260/@denotest/add/1.0.0/index.js

View file

@ -0,0 +1,66 @@
import { assertThrows } from "@std/assert/throws";
import "http://localhost:4545/run/import_meta/other.ts";
import "./other.ts";
import "@denotest/add";
console.log(
"main",
import.meta.url,
import.meta.main,
import.meta.filename,
import.meta.dirname,
);
console.log("Resolving ./foo.js", import.meta.resolve("./foo.js"));
console.log("Resolving bare from import map", import.meta.resolve("bare"));
console.log(
"Resolving https://example.com/rewrite from import map",
import.meta.resolve("https://example.com/rewrite"),
);
console.log(
"Resolving without a value from import map",
import.meta.resolve(),
);
console.log(
"Resolving 1 from import map",
import.meta.resolve(1),
);
console.log(
"Resolving null from import map",
import.meta.resolve(null),
);
console.log(
"Resolving object from import map",
import.meta.resolve({}),
);
assertThrows(() => {
import.meta.resolve("too", "many", "arguments");
}, TypeError);
assertThrows(() => {
import.meta.resolve("://malformed/url?asdf");
}, TypeError);
console.log(
"Resolving npm:cowsay",
import.meta.resolve("npm:cowsay"),
);
console.log(
"Resolving npm:cowsay@1",
import.meta.resolve("npm:cowsay@1"),
);
console.log(
"Resolving npm:preact from import map",
import.meta.resolve("npm:preact"),
);
console.log(
"Resolving existing npm:@denotest/add@1.0 specifier",
import.meta.resolve("npm:@denotest/add@1.0"),
);
// these ones aren't used anywhere in the graph, but it should still resolve
console.log(
"Resolving compatible npm:@denotest/add@1 specifier",
import.meta.resolve("npm:@denotest/add@1"),
);
console.log(
"Resolving compatible npm:@denotest/add@1.0.0 specifier",
import.meta.resolve("npm:@denotest/add@1.0.0"),
);

View file

@ -0,0 +1,7 @@
console.log(
import.meta.url.startsWith("http") ? "other remote" : "other",
import.meta.url,
import.meta.main,
import.meta.filename,
import.meta.dirname,
);

View file

@ -233,7 +233,7 @@ async function ensureNoNewITests() {
"pm_tests.rs": 0, "pm_tests.rs": 0,
"publish_tests.rs": 0, "publish_tests.rs": 0,
"repl_tests.rs": 0, "repl_tests.rs": 0,
"run_tests.rs": 18, "run_tests.rs": 17,
"shared_library_tests.rs": 0, "shared_library_tests.rs": 0,
"task_tests.rs": 2, "task_tests.rs": 2,
"test_tests.rs": 0, "test_tests.rs": 0,