1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

refactor(npm): add CliNodeResolver (#18742)

This commit is contained in:
David Sherret 2023-04-17 15:36:23 -04:00 committed by Levente Kurusa
parent 7762566a6a
commit 772e4c033f
No known key found for this signature in database
GPG key ID: 9F72F3C05BA137C4
16 changed files with 474 additions and 442 deletions

View file

@ -17,11 +17,9 @@ use crate::file_fetcher::get_source_from_bytes;
use crate::file_fetcher::map_content_type; use crate::file_fetcher::map_content_type;
use crate::file_fetcher::SUPPORTED_SCHEMES; use crate::file_fetcher::SUPPORTED_SCHEMES;
use crate::lsp::logging::lsp_warn; use crate::lsp::logging::lsp_warn;
use crate::node; use crate::node::CliNodeResolver;
use crate::node::node_resolve_npm_reference;
use crate::node::NodeResolution; use crate::node::NodeResolution;
use crate::npm::CliNpmRegistryApi; use crate::npm::CliNpmRegistryApi;
use crate::npm::NpmPackageResolver;
use crate::npm::NpmResolution; use crate::npm::NpmResolution;
use crate::npm::PackageJsonDepsInstaller; use crate::npm::PackageJsonDepsInstaller;
use crate::resolver::CliGraphResolver; use crate::resolver::CliGraphResolver;
@ -1057,7 +1055,7 @@ impl Documents {
&self, &self,
specifiers: Vec<String>, specifiers: Vec<String>,
referrer_doc: &AssetOrDocument, referrer_doc: &AssetOrDocument,
maybe_npm_resolver: Option<&Arc<NpmPackageResolver>>, maybe_node_resolver: Option<&Arc<CliNodeResolver>>,
) -> Vec<Option<(ModuleSpecifier, MediaType)>> { ) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
let referrer = referrer_doc.specifier(); let referrer = referrer_doc.specifier();
let dependencies = match referrer_doc { let dependencies = match referrer_doc {
@ -1066,19 +1064,19 @@ impl Documents {
}; };
let mut results = Vec::new(); let mut results = Vec::new();
for specifier in specifiers { for specifier in specifiers {
if let Some(npm_resolver) = maybe_npm_resolver { if let Some(node_resolver) = maybe_node_resolver {
if npm_resolver.in_npm_package(referrer) { if node_resolver.in_npm_package(referrer) {
// we're in an npm package, so use node resolution // we're in an npm package, so use node resolution
results.push(Some(NodeResolution::into_specifier_and_media_type( results.push(Some(NodeResolution::into_specifier_and_media_type(
node::node_resolve( node_resolver
&specifier, .resolve(
referrer, &specifier,
NodeResolutionMode::Types, referrer,
&npm_resolver.as_require_npm_resolver(), NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(), &mut PermissionsContainer::allow_all(),
) )
.ok() .ok()
.flatten(), .flatten(),
))); )));
continue; continue;
} }
@ -1106,9 +1104,9 @@ impl Documents {
dependencies.as_ref().and_then(|d| d.deps.get(&specifier)) dependencies.as_ref().and_then(|d| d.deps.get(&specifier))
{ {
if let Some(specifier) = dep.maybe_type.maybe_specifier() { if let Some(specifier) = dep.maybe_type.maybe_specifier() {
results.push(self.resolve_dependency(specifier, maybe_npm_resolver)); results.push(self.resolve_dependency(specifier, maybe_node_resolver));
} else if let Some(specifier) = dep.maybe_code.maybe_specifier() { } else if let Some(specifier) = dep.maybe_code.maybe_specifier() {
results.push(self.resolve_dependency(specifier, maybe_npm_resolver)); results.push(self.resolve_dependency(specifier, maybe_node_resolver));
} else { } else {
results.push(None); results.push(None);
} }
@ -1116,11 +1114,12 @@ impl Documents {
.resolve_imports_dependency(&specifier) .resolve_imports_dependency(&specifier)
.and_then(|r| r.maybe_specifier()) .and_then(|r| r.maybe_specifier())
{ {
results.push(self.resolve_dependency(specifier, maybe_npm_resolver)); results.push(self.resolve_dependency(specifier, maybe_node_resolver));
} else if let Ok(npm_req_ref) = } else if let Ok(npm_req_ref) =
NpmPackageReqReference::from_str(&specifier) NpmPackageReqReference::from_str(&specifier)
{ {
results.push(node_resolve_npm_req_ref(npm_req_ref, maybe_npm_resolver)); results
.push(node_resolve_npm_req_ref(npm_req_ref, maybe_node_resolver));
} else { } else {
results.push(None); results.push(None);
} }
@ -1418,10 +1417,10 @@ impl Documents {
fn resolve_dependency( fn resolve_dependency(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
maybe_npm_resolver: Option<&Arc<NpmPackageResolver>>, maybe_node_resolver: Option<&Arc<CliNodeResolver>>,
) -> Option<(ModuleSpecifier, MediaType)> { ) -> Option<(ModuleSpecifier, MediaType)> {
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(specifier) { if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(specifier) {
return node_resolve_npm_req_ref(npm_ref, maybe_npm_resolver); return node_resolve_npm_req_ref(npm_ref, maybe_node_resolver);
} }
let doc = self.get(specifier)?; let doc = self.get(specifier)?;
let maybe_module = doc.maybe_esm_module().and_then(|r| r.as_ref().ok()); let maybe_module = doc.maybe_esm_module().and_then(|r| r.as_ref().ok());
@ -1430,7 +1429,7 @@ impl Documents {
if let Some(specifier) = if let Some(specifier) =
maybe_types_dependency.and_then(|d| d.maybe_specifier()) maybe_types_dependency.and_then(|d| d.maybe_specifier())
{ {
self.resolve_dependency(specifier, maybe_npm_resolver) self.resolve_dependency(specifier, maybe_node_resolver)
} else { } else {
let media_type = doc.media_type(); let media_type = doc.media_type();
Some((specifier.clone(), media_type)) Some((specifier.clone(), media_type))
@ -1453,23 +1452,18 @@ impl Documents {
fn node_resolve_npm_req_ref( fn node_resolve_npm_req_ref(
npm_req_ref: NpmPackageReqReference, npm_req_ref: NpmPackageReqReference,
maybe_npm_resolver: Option<&Arc<NpmPackageResolver>>, maybe_node_resolver: Option<&Arc<CliNodeResolver>>,
) -> Option<(ModuleSpecifier, MediaType)> { ) -> Option<(ModuleSpecifier, MediaType)> {
maybe_npm_resolver.map(|npm_resolver| { maybe_node_resolver.map(|node_resolver| {
NodeResolution::into_specifier_and_media_type( NodeResolution::into_specifier_and_media_type(
npm_resolver node_resolver
.pkg_req_ref_to_nv_ref(npm_req_ref) .resolve_npm_req_reference(
&npm_req_ref,
NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(),
)
.ok() .ok()
.and_then(|pkg_id_ref| { .flatten(),
node_resolve_npm_reference(
&pkg_id_ref,
NodeResolutionMode::Types,
npm_resolver,
&mut PermissionsContainer::allow_all(),
)
.ok()
.flatten()
}),
) )
}) })
} }

View file

@ -78,6 +78,7 @@ use crate::file_fetcher::FileFetcher;
use crate::graph_util; use crate::graph_util;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::lsp::urls::LspUrlKind; use crate::lsp::urls::LspUrlKind;
use crate::node::CliNodeResolver;
use crate::npm::create_npm_fs_resolver; use crate::npm::create_npm_fs_resolver;
use crate::npm::CliNpmRegistryApi; use crate::npm::CliNpmRegistryApi;
use crate::npm::NpmCache; use crate::npm::NpmCache;
@ -101,6 +102,7 @@ pub struct StateSnapshot {
pub cache_metadata: cache::CacheMetadata, pub cache_metadata: cache::CacheMetadata,
pub documents: Documents, pub documents: Documents,
pub maybe_import_map: Option<Arc<ImportMap>>, pub maybe_import_map: Option<Arc<ImportMap>>,
pub maybe_node_resolver: Option<Arc<CliNodeResolver>>,
pub maybe_npm_resolver: Option<Arc<NpmPackageResolver>>, pub maybe_npm_resolver: Option<Arc<NpmPackageResolver>>,
} }
@ -695,30 +697,32 @@ impl Inner {
} }
pub fn snapshot(&self) -> Arc<StateSnapshot> { pub fn snapshot(&self) -> Arc<StateSnapshot> {
// create a new snapshotted npm resolution and resolver
let npm_resolution = Arc::new(NpmResolution::new(
self.npm_api.clone(),
self.npm_resolution.snapshot(),
None,
));
let npm_resolver = Arc::new(NpmPackageResolver::new(
npm_resolution.clone(),
create_npm_fs_resolver(
self.npm_cache.clone(),
&ProgressBar::new(ProgressBarStyle::TextOnly),
self.npm_api.base_url().clone(),
npm_resolution.clone(),
None,
),
None,
));
let node_resolver =
Arc::new(CliNodeResolver::new(npm_resolution, npm_resolver.clone()));
Arc::new(StateSnapshot { Arc::new(StateSnapshot {
assets: self.assets.snapshot(), assets: self.assets.snapshot(),
cache_metadata: self.cache_metadata.clone(), cache_metadata: self.cache_metadata.clone(),
documents: self.documents.clone(), documents: self.documents.clone(),
maybe_import_map: self.maybe_import_map.clone(), maybe_import_map: self.maybe_import_map.clone(),
maybe_npm_resolver: Some({ maybe_node_resolver: Some(node_resolver),
// create a new snapshotted npm resolution and resolver maybe_npm_resolver: Some(npm_resolver),
let resolution = Arc::new(NpmResolution::new(
self.npm_api.clone(),
self.npm_resolution.snapshot(),
None,
));
Arc::new(NpmPackageResolver::new(
resolution.clone(),
create_npm_fs_resolver(
self.npm_cache.clone(),
&ProgressBar::new(ProgressBarStyle::TextOnly),
self.npm_api.base_url().clone(),
resolution,
None,
),
None,
))
}),
}) })
} }

View file

@ -2763,7 +2763,7 @@ fn op_resolve(
let resolved = state.state_snapshot.documents.resolve( let resolved = state.state_snapshot.documents.resolve(
args.specifiers, args.specifiers,
&referrer_doc, &referrer_doc,
state.state_snapshot.maybe_npm_resolver.as_ref(), state.state_snapshot.maybe_node_resolver.as_ref(),
); );
Ok( Ok(
resolved resolved

View file

@ -11,10 +11,9 @@ use crate::graph_util::graph_valid_with_cli_options;
use crate::graph_util::ModuleGraphBuilder; use crate::graph_util::ModuleGraphBuilder;
use crate::graph_util::ModuleGraphContainer; use crate::graph_util::ModuleGraphContainer;
use crate::node; use crate::node;
use crate::node::CliNodeResolver;
use crate::node::NodeCodeTranslator; use crate::node::NodeCodeTranslator;
use crate::node::NodeResolution; use crate::node::NodeResolution;
use crate::npm::NpmPackageResolver;
use crate::npm::NpmResolution;
use crate::proc_state::CjsResolutionStore; use crate::proc_state::CjsResolutionStore;
use crate::proc_state::FileWatcherReporter; use crate::proc_state::FileWatcherReporter;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
@ -243,8 +242,7 @@ pub struct CliModuleLoader {
graph_container: Arc<ModuleGraphContainer>, graph_container: Arc<ModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>, module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<NodeCodeTranslator>, node_code_translator: Arc<NodeCodeTranslator>,
npm_resolution: Arc<NpmResolution>, node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<NpmPackageResolver>,
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliGraphResolver>, resolver: Arc<CliGraphResolver>,
} }
@ -265,8 +263,7 @@ impl CliModuleLoader {
graph_container: ps.graph_container.clone(), graph_container: ps.graph_container.clone(),
module_load_preparer: ps.module_load_preparer.clone(), module_load_preparer: ps.module_load_preparer.clone(),
node_code_translator: ps.node_code_translator.clone(), node_code_translator: ps.node_code_translator.clone(),
npm_resolution: ps.npm_resolution.clone(), node_resolver: ps.node_resolver.clone(),
npm_resolver: ps.npm_resolver.clone(),
parsed_source_cache: ps.parsed_source_cache.clone(), parsed_source_cache: ps.parsed_source_cache.clone(),
resolver: ps.resolver.clone(), resolver: ps.resolver.clone(),
}) })
@ -287,8 +284,7 @@ impl CliModuleLoader {
graph_container: ps.graph_container.clone(), graph_container: ps.graph_container.clone(),
module_load_preparer: ps.module_load_preparer.clone(), module_load_preparer: ps.module_load_preparer.clone(),
node_code_translator: ps.node_code_translator.clone(), node_code_translator: ps.node_code_translator.clone(),
npm_resolution: ps.npm_resolution.clone(), node_resolver: ps.node_resolver.clone(),
npm_resolver: ps.npm_resolver.clone(),
parsed_source_cache: ps.parsed_source_cache.clone(), parsed_source_cache: ps.parsed_source_cache.clone(),
resolver: ps.resolver.clone(), resolver: ps.resolver.clone(),
}) })
@ -370,7 +366,7 @@ impl CliModuleLoader {
maybe_referrer: Option<&ModuleSpecifier>, maybe_referrer: Option<&ModuleSpecifier>,
is_dynamic: bool, is_dynamic: bool,
) -> Result<ModuleSource, AnyError> { ) -> Result<ModuleSource, AnyError> {
let code_source = if self.npm_resolver.in_npm_package(specifier) { let code_source = if self.node_resolver.in_npm_package(specifier) {
let file_path = specifier.to_file_path().unwrap(); let file_path = specifier.to_file_path().unwrap();
let code = std::fs::read_to_string(&file_path).with_context(|| { let code = std::fs::read_to_string(&file_path).with_context(|| {
let mut msg = "Unable to load ".to_string(); let mut msg = "Unable to load ".to_string();
@ -466,14 +462,13 @@ impl ModuleLoader for CliModuleLoader {
let referrer_result = deno_core::resolve_url_or_path(referrer, &cwd); let referrer_result = deno_core::resolve_url_or_path(referrer, &cwd);
if let Ok(referrer) = referrer_result.as_ref() { if let Ok(referrer) = referrer_result.as_ref() {
if self.npm_resolver.in_npm_package(referrer) { if self.node_resolver.in_npm_package(referrer) {
// we're in an npm package, so use node resolution // we're in an npm package, so use node resolution
return self return self
.handle_node_resolve_result(node::node_resolve( .handle_node_resolve_result(self.node_resolver.resolve(
specifier, specifier,
referrer, referrer,
NodeResolutionMode::Execution, NodeResolutionMode::Execution,
&self.npm_resolver.as_require_npm_resolver(),
&mut permissions, &mut permissions,
)) ))
.with_context(|| { .with_context(|| {
@ -495,12 +490,13 @@ impl ModuleLoader for CliModuleLoader {
return match graph.get(specifier) { return match graph.get(specifier) {
Some(Module::Npm(module)) => self Some(Module::Npm(module)) => self
.handle_node_resolve_result(node::node_resolve_npm_reference( .handle_node_resolve_result(
&module.nv_reference, self.node_resolver.resolve_npm_reference(
NodeResolutionMode::Execution, &module.nv_reference,
&self.npm_resolver, NodeResolutionMode::Execution,
&mut permissions, &mut permissions,
)) ),
)
.with_context(|| { .with_context(|| {
format!("Could not resolve '{}'.", module.nv_reference) format!("Could not resolve '{}'.", module.nv_reference)
}), }),
@ -555,15 +551,14 @@ impl ModuleLoader for CliModuleLoader {
if let Ok(reference) = if let Ok(reference) =
NpmPackageReqReference::from_specifier(&specifier) NpmPackageReqReference::from_specifier(&specifier)
{ {
let reference =
self.npm_resolution.pkg_req_ref_to_nv_ref(reference)?;
return self return self
.handle_node_resolve_result(node::node_resolve_npm_reference( .handle_node_resolve_result(
&reference, self.node_resolver.resolve_npm_req_reference(
deno_runtime::deno_node::NodeResolutionMode::Execution, &reference,
&self.npm_resolver, deno_runtime::deno_node::NodeResolutionMode::Execution,
&mut permissions, &mut permissions,
)) ),
)
.with_context(|| format!("Could not resolve '{reference}'.")); .with_context(|| format!("Could not resolve '{reference}'."));
} }
} }
@ -595,7 +590,7 @@ impl ModuleLoader for CliModuleLoader {
_maybe_referrer: Option<String>, _maybe_referrer: Option<String>,
is_dynamic: bool, is_dynamic: bool,
) -> Pin<Box<dyn Future<Output = Result<(), AnyError>>>> { ) -> Pin<Box<dyn Future<Output = Result<(), AnyError>>>> {
if self.npm_resolver.in_npm_package(specifier) { if self.node_resolver.in_npm_package(specifier) {
// nothing to prepare // nothing to prepare
return Box::pin(deno_core::futures::future::ready(Ok(()))); return Box::pin(deno_core::futures::future::ready(Ok(())));
} }

View file

@ -31,8 +31,11 @@ use deno_runtime::deno_node::DEFAULT_CONDITIONS;
use deno_runtime::permissions::PermissionsContainer; use deno_runtime::permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageNv; use deno_semver::npm::NpmPackageNv;
use deno_semver::npm::NpmPackageNvReference; use deno_semver::npm::NpmPackageNvReference;
use deno_semver::npm::NpmPackageReqReference;
use crate::npm::NpmPackageResolver; use crate::npm::NpmPackageResolver;
use crate::npm::NpmResolution;
use crate::npm::RequireNpmPackageResolver;
use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::util::fs::canonicalize_path_maybe_not_exists;
mod analyze; mod analyze;
@ -109,127 +112,305 @@ pub fn resolve_builtin_node_module(module_name: &str) -> Result<Url, AnyError> {
))) )))
} }
/// This function is an implementation of `defaultResolve` in #[derive(Debug)]
/// `lib/internal/modules/esm/resolve.js` from Node. pub struct CliNodeResolver {
pub fn node_resolve( npm_resolution: Arc<NpmResolution>,
specifier: &str, npm_resolver: Arc<NpmPackageResolver>,
referrer: &ModuleSpecifier, require_npm_resolver: RequireNpmPackageResolver,
mode: NodeResolutionMode,
npm_resolver: &dyn RequireNpmResolver,
permissions: &mut dyn NodePermissions,
) -> Result<Option<NodeResolution>, AnyError> {
// Note: if we are here, then the referrer is an esm module
// TODO(bartlomieju): skipped "policy" part as we don't plan to support it
if deno_node::is_builtin_node_module(specifier) {
return Ok(Some(NodeResolution::BuiltIn(specifier.to_string())));
}
if let Ok(url) = Url::parse(specifier) {
if url.scheme() == "data" {
return Ok(Some(NodeResolution::Esm(url)));
}
let protocol = url.scheme();
if protocol == "node" {
let split_specifier = url.as_str().split(':');
let specifier = split_specifier.skip(1).collect::<String>();
if deno_node::is_builtin_node_module(&specifier) {
return Ok(Some(NodeResolution::BuiltIn(specifier)));
}
}
if protocol != "file" && protocol != "data" {
return Err(errors::err_unsupported_esm_url_scheme(&url));
}
// todo(dsherret): this seems wrong
if referrer.scheme() == "data" {
let url = referrer.join(specifier).map_err(AnyError::from)?;
return Ok(Some(NodeResolution::Esm(url)));
}
}
let url = module_resolve(
specifier,
referrer,
DEFAULT_CONDITIONS,
mode,
npm_resolver,
permissions,
)?;
let url = match url {
Some(url) => url,
None => return Ok(None),
};
let url = match mode {
NodeResolutionMode::Execution => url,
NodeResolutionMode::Types => {
let path = url.to_file_path().unwrap();
// todo(16370): the module kind is not correct here. I think we need
// typescript to tell us if the referrer is esm or cjs
let path =
match path_to_declaration_path::<RealFs>(path, NodeModuleKind::Esm) {
Some(path) => path,
None => return Ok(None),
};
ModuleSpecifier::from_file_path(path).unwrap()
}
};
let resolve_response = url_to_node_resolution(url, npm_resolver)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(Some(resolve_response))
} }
pub fn node_resolve_npm_reference( impl CliNodeResolver {
reference: &NpmPackageNvReference, pub fn new(
mode: NodeResolutionMode, npm_resolution: Arc<NpmResolution>,
npm_resolver: &Arc<NpmPackageResolver>, npm_package_resolver: Arc<NpmPackageResolver>,
permissions: &mut dyn NodePermissions, ) -> Self {
) -> Result<Option<NodeResolution>, AnyError> { Self {
let package_folder = npm_resolution,
npm_resolver.resolve_package_folder_from_deno_module(&reference.nv)?; require_npm_resolver: npm_package_resolver.as_require_npm_resolver(),
let node_module_kind = NodeModuleKind::Esm; npm_resolver: npm_package_resolver,
let maybe_resolved_path = package_config_resolve( }
&reference }
.sub_path
.as_ref() pub fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
.map(|s| format!("./{s}")) self.npm_resolver.in_npm_package(specifier)
.unwrap_or_else(|| ".".to_string()), }
&package_folder,
node_module_kind, /// This function is an implementation of `defaultResolve` in
DEFAULT_CONDITIONS, /// `lib/internal/modules/esm/resolve.js` from Node.
mode, pub fn resolve(
&npm_resolver.as_require_npm_resolver(), &self,
permissions, specifier: &str,
) referrer: &ModuleSpecifier,
.with_context(|| { mode: NodeResolutionMode,
format!("Error resolving package config for '{reference}'") permissions: &mut dyn NodePermissions,
})?; ) -> Result<Option<NodeResolution>, AnyError> {
let resolved_path = match maybe_resolved_path { // Note: if we are here, then the referrer is an esm module
Some(resolved_path) => resolved_path, // TODO(bartlomieju): skipped "policy" part as we don't plan to support it
None => return Ok(None),
}; if deno_node::is_builtin_node_module(specifier) {
let resolved_path = match mode { return Ok(Some(NodeResolution::BuiltIn(specifier.to_string())));
NodeResolutionMode::Execution => resolved_path, }
NodeResolutionMode::Types => {
match path_to_declaration_path::<RealFs>(resolved_path, node_module_kind) if let Ok(url) = Url::parse(specifier) {
{ if url.scheme() == "data" {
Some(path) => path, return Ok(Some(NodeResolution::Esm(url)));
None => return Ok(None), }
let protocol = url.scheme();
if protocol == "node" {
let split_specifier = url.as_str().split(':');
let specifier = split_specifier.skip(1).collect::<String>();
if deno_node::is_builtin_node_module(&specifier) {
return Ok(Some(NodeResolution::BuiltIn(specifier)));
}
}
if protocol != "file" && protocol != "data" {
return Err(errors::err_unsupported_esm_url_scheme(&url));
}
// todo(dsherret): this seems wrong
if referrer.scheme() == "data" {
let url = referrer.join(specifier).map_err(AnyError::from)?;
return Ok(Some(NodeResolution::Esm(url)));
} }
} }
};
let url = ModuleSpecifier::from_file_path(resolved_path).unwrap(); let url = self.module_resolve(
let resolve_response = specifier,
url_to_node_resolution(url, &npm_resolver.as_require_npm_resolver())?; referrer,
// TODO(bartlomieju): skipped checking errors for commonJS resolution and DEFAULT_CONDITIONS,
// "preserveSymlinksMain"/"preserveSymlinks" options. mode,
Ok(Some(resolve_response)) permissions,
)?;
let url = match url {
Some(url) => url,
None => return Ok(None),
};
let url = match mode {
NodeResolutionMode::Execution => url,
NodeResolutionMode::Types => {
let path = url.to_file_path().unwrap();
// todo(16370): the module kind is not correct here. I think we need
// typescript to tell us if the referrer is esm or cjs
let path =
match path_to_declaration_path::<RealFs>(path, NodeModuleKind::Esm) {
Some(path) => path,
None => return Ok(None),
};
ModuleSpecifier::from_file_path(path).unwrap()
}
};
let resolve_response = self.url_to_node_resolution(url)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(Some(resolve_response))
}
fn module_resolve(
&self,
specifier: &str,
referrer: &ModuleSpecifier,
conditions: &[&str],
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<ModuleSpecifier>, AnyError> {
// note: if we're here, the referrer is an esm module
let url = if should_be_treated_as_relative_or_absolute_path(specifier) {
let resolved_specifier = referrer.join(specifier)?;
if mode.is_types() {
let file_path = to_file_path(&resolved_specifier);
// todo(dsherret): the node module kind is not correct and we
// should use the value provided by typescript instead
let declaration_path =
path_to_declaration_path::<RealFs>(file_path, NodeModuleKind::Esm);
declaration_path.map(|declaration_path| {
ModuleSpecifier::from_file_path(declaration_path).unwrap()
})
} else {
Some(resolved_specifier)
}
} else if specifier.starts_with('#') {
Some(
package_imports_resolve::<RealFs>(
specifier,
referrer,
NodeModuleKind::Esm,
conditions,
mode,
&self.require_npm_resolver,
permissions,
)
.map(|p| ModuleSpecifier::from_file_path(p).unwrap())?,
)
} else if let Ok(resolved) = Url::parse(specifier) {
Some(resolved)
} else {
package_resolve::<RealFs>(
specifier,
referrer,
NodeModuleKind::Esm,
conditions,
mode,
&self.require_npm_resolver,
permissions,
)?
.map(|p| ModuleSpecifier::from_file_path(p).unwrap())
};
Ok(match url {
Some(url) => Some(finalize_resolution(url, referrer)?),
None => None,
})
}
pub fn resolve_npm_req_reference(
&self,
reference: &NpmPackageReqReference,
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<NodeResolution>, AnyError> {
let reference = self.npm_resolution.pkg_req_ref_to_nv_ref(reference)?;
self.resolve_npm_reference(&reference, mode, permissions)
}
pub fn resolve_npm_reference(
&self,
reference: &NpmPackageNvReference,
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<NodeResolution>, AnyError> {
let package_folder = self
.npm_resolver
.resolve_package_folder_from_deno_module(&reference.nv)?;
let node_module_kind = NodeModuleKind::Esm;
let maybe_resolved_path = package_config_resolve(
&reference
.sub_path
.as_ref()
.map(|s| format!("./{s}"))
.unwrap_or_else(|| ".".to_string()),
&package_folder,
node_module_kind,
DEFAULT_CONDITIONS,
mode,
&self.require_npm_resolver,
permissions,
)
.with_context(|| {
format!("Error resolving package config for '{reference}'")
})?;
let resolved_path = match maybe_resolved_path {
Some(resolved_path) => resolved_path,
None => return Ok(None),
};
let resolved_path = match mode {
NodeResolutionMode::Execution => resolved_path,
NodeResolutionMode::Types => {
match path_to_declaration_path::<RealFs>(
resolved_path,
node_module_kind,
) {
Some(path) => path,
None => return Ok(None),
}
}
};
let url = ModuleSpecifier::from_file_path(resolved_path).unwrap();
let resolve_response = self.url_to_node_resolution(url)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(Some(resolve_response))
}
pub fn resolve_binary_commands(
&self,
pkg_nv: &NpmPackageNv,
) -> Result<Vec<String>, AnyError> {
let package_folder = self
.npm_resolver
.resolve_package_folder_from_deno_module(pkg_nv)?;
let package_json_path = package_folder.join("package.json");
let package_json = PackageJson::load::<RealFs>(
&self.require_npm_resolver,
&mut PermissionsContainer::allow_all(),
package_json_path,
)?;
Ok(match package_json.bin {
Some(Value::String(_)) => vec![pkg_nv.name.to_string()],
Some(Value::Object(o)) => {
o.into_iter().map(|(key, _)| key).collect::<Vec<_>>()
}
_ => Vec::new(),
})
}
pub fn resolve_binary_export(
&self,
pkg_ref: &NpmPackageReqReference,
) -> Result<NodeResolution, AnyError> {
let pkg_nv = self
.npm_resolution
.resolve_pkg_id_from_pkg_req(&pkg_ref.req)?
.nv;
let bin_name = pkg_ref.sub_path.as_deref();
let package_folder = self
.npm_resolver
.resolve_package_folder_from_deno_module(&pkg_nv)?;
let package_json_path = package_folder.join("package.json");
let package_json = PackageJson::load::<RealFs>(
&self.require_npm_resolver,
&mut PermissionsContainer::allow_all(),
package_json_path,
)?;
let bin = match &package_json.bin {
Some(bin) => bin,
None => bail!(
"package '{}' did not have a bin property in its package.json",
&pkg_nv.name,
),
};
let bin_entry = resolve_bin_entry_value(&pkg_nv, bin_name, bin)?;
let url =
ModuleSpecifier::from_file_path(package_folder.join(bin_entry)).unwrap();
let resolve_response = self.url_to_node_resolution(url)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(resolve_response)
}
pub fn url_to_node_resolution(
&self,
url: ModuleSpecifier,
) -> Result<NodeResolution, AnyError> {
let url_str = url.as_str().to_lowercase();
if url_str.starts_with("http") {
Ok(NodeResolution::Esm(url))
} else if url_str.ends_with(".js") || url_str.ends_with(".d.ts") {
let package_config = get_closest_package_json::<RealFs>(
&url,
&self.require_npm_resolver,
&mut PermissionsContainer::allow_all(),
)?;
if package_config.typ == "module" {
Ok(NodeResolution::Esm(url))
} else {
Ok(NodeResolution::CommonJs(url))
}
} else if url_str.ends_with(".mjs") || url_str.ends_with(".d.mts") {
Ok(NodeResolution::Esm(url))
} else if url_str.ends_with(".ts") {
Err(generic_error(format!(
"TypeScript files are not supported in npm packages: {url}"
)))
} else {
Ok(NodeResolution::CommonJs(url))
}
}
} }
/// Resolves a specifier that is pointing into a node_modules folder. /// Resolves a specifier that is pointing into a node_modules folder.
@ -251,59 +432,6 @@ pub fn resolve_specifier_into_node_modules(
.unwrap_or_else(|| specifier.clone()) .unwrap_or_else(|| specifier.clone())
} }
pub fn node_resolve_binary_commands(
pkg_nv: &NpmPackageNv,
npm_resolver: &Arc<NpmPackageResolver>,
) -> Result<Vec<String>, AnyError> {
let package_folder =
npm_resolver.resolve_package_folder_from_deno_module(pkg_nv)?;
let package_json_path = package_folder.join("package.json");
let package_json = PackageJson::load::<RealFs>(
&npm_resolver.as_require_npm_resolver(),
&mut PermissionsContainer::allow_all(),
package_json_path,
)?;
Ok(match package_json.bin {
Some(Value::String(_)) => vec![pkg_nv.name.to_string()],
Some(Value::Object(o)) => {
o.into_iter().map(|(key, _)| key).collect::<Vec<_>>()
}
_ => Vec::new(),
})
}
pub fn node_resolve_binary_export(
pkg_nv: &NpmPackageNv,
bin_name: Option<&str>,
npm_resolver: &Arc<NpmPackageResolver>,
) -> Result<NodeResolution, AnyError> {
let package_folder =
npm_resolver.resolve_package_folder_from_deno_module(pkg_nv)?;
let package_json_path = package_folder.join("package.json");
let package_json = PackageJson::load::<RealFs>(
&npm_resolver.as_require_npm_resolver(),
&mut PermissionsContainer::allow_all(),
package_json_path,
)?;
let bin = match &package_json.bin {
Some(bin) => bin,
None => bail!(
"package '{}' did not have a bin property in its package.json",
&pkg_nv.name,
),
};
let bin_entry = resolve_bin_entry_value(pkg_nv, bin_name, bin)?;
let url =
ModuleSpecifier::from_file_path(package_folder.join(bin_entry)).unwrap();
let resolve_response =
url_to_node_resolution(url, &npm_resolver.as_require_npm_resolver())?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(resolve_response)
}
fn resolve_bin_entry_value<'a>( fn resolve_bin_entry_value<'a>(
pkg_nv: &NpmPackageNv, pkg_nv: &NpmPackageNv,
bin_name: Option<&str>, bin_name: Option<&str>,
@ -411,35 +539,6 @@ fn package_config_resolve(
Ok(Some(package_dir.join(package_subpath))) Ok(Some(package_dir.join(package_subpath)))
} }
pub fn url_to_node_resolution(
url: ModuleSpecifier,
npm_resolver: &dyn RequireNpmResolver,
) -> Result<NodeResolution, AnyError> {
let url_str = url.as_str().to_lowercase();
if url_str.starts_with("http") {
Ok(NodeResolution::Esm(url))
} else if url_str.ends_with(".js") || url_str.ends_with(".d.ts") {
let package_config = get_closest_package_json::<RealFs>(
&url,
npm_resolver,
&mut PermissionsContainer::allow_all(),
)?;
if package_config.typ == "module" {
Ok(NodeResolution::Esm(url))
} else {
Ok(NodeResolution::CommonJs(url))
}
} else if url_str.ends_with(".mjs") || url_str.ends_with(".d.mts") {
Ok(NodeResolution::Esm(url))
} else if url_str.ends_with(".ts") {
Err(generic_error(format!(
"TypeScript files are not supported in npm packages: {url}"
)))
} else {
Ok(NodeResolution::CommonJs(url))
}
}
fn finalize_resolution( fn finalize_resolution(
resolved: ModuleSpecifier, resolved: ModuleSpecifier,
base: &ModuleSpecifier, base: &ModuleSpecifier,
@ -489,62 +588,6 @@ fn finalize_resolution(
Ok(resolved) Ok(resolved)
} }
fn module_resolve(
specifier: &str,
referrer: &ModuleSpecifier,
conditions: &[&str],
mode: NodeResolutionMode,
npm_resolver: &dyn RequireNpmResolver,
permissions: &mut dyn NodePermissions,
) -> Result<Option<ModuleSpecifier>, AnyError> {
// note: if we're here, the referrer is an esm module
let url = if should_be_treated_as_relative_or_absolute_path(specifier) {
let resolved_specifier = referrer.join(specifier)?;
if mode.is_types() {
let file_path = to_file_path(&resolved_specifier);
// todo(dsherret): the node module kind is not correct and we
// should use the value provided by typescript instead
let declaration_path =
path_to_declaration_path::<RealFs>(file_path, NodeModuleKind::Esm);
declaration_path.map(|declaration_path| {
ModuleSpecifier::from_file_path(declaration_path).unwrap()
})
} else {
Some(resolved_specifier)
}
} else if specifier.starts_with('#') {
Some(
package_imports_resolve::<RealFs>(
specifier,
referrer,
NodeModuleKind::Esm,
conditions,
mode,
npm_resolver,
permissions,
)
.map(|p| ModuleSpecifier::from_file_path(p).unwrap())?,
)
} else if let Ok(resolved) = Url::parse(specifier) {
Some(resolved)
} else {
package_resolve::<RealFs>(
specifier,
referrer,
NodeModuleKind::Esm,
conditions,
mode,
npm_resolver,
permissions,
)?
.map(|p| ModuleSpecifier::from_file_path(p).unwrap())
};
Ok(match url {
Some(url) => Some(finalize_resolution(url, referrer)?),
None => None,
})
}
fn to_file_path(url: &ModuleSpecifier) -> PathBuf { fn to_file_path(url: &ModuleSpecifier) -> PathBuf {
url url
.to_file_path() .to_file_path()

View file

@ -15,3 +15,4 @@ pub use resolution::NpmResolution;
pub use resolvers::create_npm_fs_resolver; pub use resolvers::create_npm_fs_resolver;
pub use resolvers::NpmPackageResolver; pub use resolvers::NpmPackageResolver;
pub use resolvers::NpmProcessState; pub use resolvers::NpmProcessState;
pub use resolvers::RequireNpmPackageResolver;

View file

@ -156,12 +156,12 @@ impl NpmResolution {
pub fn pkg_req_ref_to_nv_ref( pub fn pkg_req_ref_to_nv_ref(
&self, &self,
req_ref: NpmPackageReqReference, req_ref: &NpmPackageReqReference,
) -> Result<NpmPackageNvReference, PackageReqNotFoundError> { ) -> Result<NpmPackageNvReference, PackageReqNotFoundError> {
let node_id = self.resolve_pkg_id_from_pkg_req(&req_ref.req)?; let node_id = self.resolve_pkg_id_from_pkg_req(&req_ref.req)?;
Ok(NpmPackageNvReference { Ok(NpmPackageNvReference {
nv: node_id.nv, nv: node_id.nv,
sub_path: req_ref.sub_path, sub_path: req_ref.sub_path.clone(),
}) })
} }

View file

@ -23,9 +23,7 @@ use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::PathClean; use deno_runtime::deno_node::PathClean;
use deno_runtime::deno_node::RequireNpmResolver; use deno_runtime::deno_node::RequireNpmResolver;
use deno_semver::npm::NpmPackageNv; use deno_semver::npm::NpmPackageNv;
use deno_semver::npm::NpmPackageNvReference;
use deno_semver::npm::NpmPackageReq; use deno_semver::npm::NpmPackageReq;
use deno_semver::npm::NpmPackageReqReference;
use global::GlobalNpmPackageResolver; use global::GlobalNpmPackageResolver;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@ -87,13 +85,6 @@ impl NpmPackageResolver {
self.resolution.resolve_pkg_id_from_pkg_req(req) self.resolution.resolve_pkg_id_from_pkg_req(req)
} }
pub fn pkg_req_ref_to_nv_ref(
&self,
req_ref: NpmPackageReqReference,
) -> Result<NpmPackageNvReference, PackageReqNotFoundError> {
self.resolution.pkg_req_ref_to_nv_ref(req_ref)
}
/// Resolves an npm package folder path from a Deno module. /// Resolves an npm package folder path from a Deno module.
pub fn resolve_package_folder_from_deno_module( pub fn resolve_package_folder_from_deno_module(
&self, &self,
@ -245,6 +236,7 @@ impl NpmPackageResolver {
} }
} }
#[derive(Debug)]
pub struct RequireNpmPackageResolver(Arc<NpmPackageResolver>); pub struct RequireNpmPackageResolver(Arc<NpmPackageResolver>);
impl RequireNpmResolver for RequireNpmPackageResolver { impl RequireNpmResolver for RequireNpmPackageResolver {

View file

@ -1,6 +1,8 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use crate::proc_state::ProcState; use std::sync::Arc;
use crate::npm::NpmPackageResolver;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::op; use deno_core::op;
use deno_core::Extension; use deno_core::Extension;
@ -9,17 +11,17 @@ use deno_core::OpState;
pub mod bench; pub mod bench;
pub mod testing; pub mod testing;
pub fn cli_exts(ps: ProcState) -> Vec<Extension> { pub fn cli_exts(npm_resolver: Arc<NpmPackageResolver>) -> Vec<Extension> {
vec![deno_cli::init_ops(ps)] vec![deno_cli::init_ops(npm_resolver)]
} }
deno_core::extension!(deno_cli, deno_core::extension!(deno_cli,
ops = [op_npm_process_state], ops = [op_npm_process_state],
options = { options = {
ps: ProcState, npm_resolver: Arc<NpmPackageResolver>,
}, },
state = |state, options| { state = |state, options| {
state.put(options.ps); state.put(options.npm_resolver);
}, },
customizer = |ext: &mut deno_core::ExtensionBuilder| { customizer = |ext: &mut deno_core::ExtensionBuilder| {
ext.force_op_registration(); ext.force_op_registration();
@ -28,6 +30,6 @@ deno_core::extension!(deno_cli,
#[op] #[op]
fn op_npm_process_state(state: &mut OpState) -> Result<String, AnyError> { fn op_npm_process_state(state: &mut OpState) -> Result<String, AnyError> {
let proc_state = state.borrow_mut::<ProcState>(); let npm_resolver = state.borrow_mut::<Arc<NpmPackageResolver>>();
Ok(proc_state.npm_resolver.get_npm_process_state()) Ok(npm_resolver.get_npm_process_state())
} }

View file

@ -17,6 +17,7 @@ use crate::graph_util::ModuleGraphBuilder;
use crate::graph_util::ModuleGraphContainer; use crate::graph_util::ModuleGraphContainer;
use crate::http_util::HttpClient; use crate::http_util::HttpClient;
use crate::module_loader::ModuleLoadPreparer; use crate::module_loader::ModuleLoadPreparer;
use crate::node::CliNodeResolver;
use crate::node::NodeCodeTranslator; use crate::node::NodeCodeTranslator;
use crate::npm::create_npm_fs_resolver; use crate::npm::create_npm_fs_resolver;
use crate::npm::CliNpmRegistryApi; use crate::npm::CliNpmRegistryApi;
@ -75,6 +76,7 @@ pub struct Inner {
pub module_graph_builder: Arc<ModuleGraphBuilder>, pub module_graph_builder: Arc<ModuleGraphBuilder>,
pub module_load_preparer: Arc<ModuleLoadPreparer>, pub module_load_preparer: Arc<ModuleLoadPreparer>,
pub node_code_translator: Arc<NodeCodeTranslator>, pub node_code_translator: Arc<NodeCodeTranslator>,
pub node_resolver: Arc<CliNodeResolver>,
pub npm_api: Arc<CliNpmRegistryApi>, pub npm_api: Arc<CliNpmRegistryApi>,
pub npm_cache: Arc<NpmCache>, pub npm_cache: Arc<NpmCache>,
pub npm_resolver: Arc<NpmPackageResolver>, pub npm_resolver: Arc<NpmPackageResolver>,
@ -145,6 +147,7 @@ impl ProcState {
module_graph_builder: self.module_graph_builder.clone(), module_graph_builder: self.module_graph_builder.clone(),
module_load_preparer: self.module_load_preparer.clone(), module_load_preparer: self.module_load_preparer.clone(),
node_code_translator: self.node_code_translator.clone(), node_code_translator: self.node_code_translator.clone(),
node_resolver: self.node_resolver.clone(),
npm_api: self.npm_api.clone(), npm_api: self.npm_api.clone(),
npm_cache: self.npm_cache.clone(), npm_cache: self.npm_cache.clone(),
npm_resolver: self.npm_resolver.clone(), npm_resolver: self.npm_resolver.clone(),
@ -306,10 +309,15 @@ impl ProcState {
file_fetcher.clone(), file_fetcher.clone(),
npm_resolver.clone(), npm_resolver.clone(),
)); ));
let node_resolver = Arc::new(CliNodeResolver::new(
npm_resolution.clone(),
npm_resolver.clone(),
));
let type_checker = Arc::new(TypeChecker::new( let type_checker = Arc::new(TypeChecker::new(
dir.clone(), dir.clone(),
caches.clone(), caches.clone(),
cli_options.clone(), cli_options.clone(),
node_resolver.clone(),
npm_resolver.clone(), npm_resolver.clone(),
)); ));
let module_graph_builder = Arc::new(ModuleGraphBuilder::new( let module_graph_builder = Arc::new(ModuleGraphBuilder::new(
@ -357,6 +365,7 @@ impl ProcState {
maybe_file_watcher_reporter, maybe_file_watcher_reporter,
module_graph_builder, module_graph_builder,
node_code_translator, node_code_translator,
node_resolver,
npm_api, npm_api,
npm_cache, npm_cache,
npm_resolver, npm_resolver,

View file

@ -265,7 +265,7 @@ fn create_web_worker_callback(
user_agent: version::get_user_agent().to_string(), user_agent: version::get_user_agent().to_string(),
inspect: ps.options.is_inspecting(), inspect: ps.options.is_inspecting(),
}, },
extensions: ops::cli_exts(ps.clone()), extensions: ops::cli_exts(ps.npm_resolver.clone()),
startup_snapshot: Some(crate::js::deno_isolate_init()), startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: ps unsafely_ignore_certificate_errors: ps
.options .options
@ -354,7 +354,7 @@ pub async fn run(
user_agent: version::get_user_agent().to_string(), user_agent: version::get_user_agent().to_string(),
inspect: ps.options.is_inspecting(), inspect: ps.options.is_inspecting(),
}, },
extensions: ops::cli_exts(ps.clone()), extensions: ops::cli_exts(ps.npm_resolver.clone()),
startup_snapshot: Some(crate::js::deno_isolate_init()), startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: metadata unsafely_ignore_certificate_errors: metadata
.unsafely_ignore_certificate_errors, .unsafely_ignore_certificate_errors,

View file

@ -21,6 +21,7 @@ use crate::cache::Caches;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::cache::TypeCheckCache; use crate::cache::TypeCheckCache;
use crate::node::CliNodeResolver;
use crate::npm::NpmPackageResolver; use crate::npm::NpmPackageResolver;
use crate::tsc; use crate::tsc;
use crate::version; use crate::version;
@ -41,6 +42,7 @@ pub struct TypeChecker {
deno_dir: DenoDir, deno_dir: DenoDir,
caches: Arc<Caches>, caches: Arc<Caches>,
cli_options: Arc<CliOptions>, cli_options: Arc<CliOptions>,
node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<NpmPackageResolver>, npm_resolver: Arc<NpmPackageResolver>,
} }
@ -49,12 +51,14 @@ impl TypeChecker {
deno_dir: DenoDir, deno_dir: DenoDir,
caches: Arc<Caches>, caches: Arc<Caches>,
cli_options: Arc<CliOptions>, cli_options: Arc<CliOptions>,
node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<NpmPackageResolver>, npm_resolver: Arc<NpmPackageResolver>,
) -> Self { ) -> Self {
Self { Self {
deno_dir, deno_dir,
caches, caches,
cli_options, cli_options,
node_resolver,
npm_resolver, npm_resolver,
} }
} }
@ -133,7 +137,7 @@ impl TypeChecker {
debug, debug,
graph: graph.clone(), graph: graph.clone(),
hash_data, hash_data,
maybe_npm_resolver: Some(self.npm_resolver.clone()), maybe_node_resolver: Some(self.node_resolver.clone()),
maybe_tsbuildinfo, maybe_tsbuildinfo,
root_names, root_names,
check_mode: type_check_mode, check_mode: type_check_mode,
@ -144,7 +148,7 @@ impl TypeChecker {
if let Some(file_name) = &d.file_name { if let Some(file_name) = &d.file_name {
if !file_name.starts_with("http") { if !file_name.starts_with("http") {
if ModuleSpecifier::parse(file_name) if ModuleSpecifier::parse(file_name)
.map(|specifier| !self.npm_resolver.in_npm_package(&specifier)) .map(|specifier| !self.node_resolver.in_npm_package(&specifier))
.unwrap_or(true) .unwrap_or(true)
{ {
Some(d.clone()) Some(d.clone())

View file

@ -1,8 +1,11 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
use crate::args::TaskFlags; use crate::args::TaskFlags;
use crate::colors; use crate::colors;
use crate::node::CliNodeResolver;
use crate::npm::NpmPackageResolver;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
@ -50,7 +53,7 @@ pub async fn execute_script(
Some(path) => canonicalize_path(&PathBuf::from(path))?, Some(path) => canonicalize_path(&PathBuf::from(path))?,
None => config_file_path.parent().unwrap().to_owned(), None => config_file_path.parent().unwrap().to_owned(),
}; };
let script = get_script_with_args(script, &ps); let script = get_script_with_args(script, &ps.options);
output_task(task_name, &script); output_task(task_name, &script);
let seq_list = deno_task_shell::parser::parse(&script) let seq_list = deno_task_shell::parser::parse(&script)
.with_context(|| format!("Error parsing script '{task_name}'."))?; .with_context(|| format!("Error parsing script '{task_name}'."))?;
@ -92,11 +95,12 @@ pub async fn execute_script(
.unwrap() .unwrap()
.to_owned(), .to_owned(),
}; };
let script = get_script_with_args(script, &ps); let script = get_script_with_args(script, &ps.options);
output_task(task_name, &script); output_task(task_name, &script);
let seq_list = deno_task_shell::parser::parse(&script) let seq_list = deno_task_shell::parser::parse(&script)
.with_context(|| format!("Error parsing script '{task_name}'."))?; .with_context(|| format!("Error parsing script '{task_name}'."))?;
let npx_commands = resolve_npm_commands(&ps)?; let npx_commands =
resolve_npm_commands(&ps.npm_resolver, &ps.node_resolver)?;
let env_vars = collect_env_vars(); let env_vars = collect_env_vars();
let exit_code = let exit_code =
deno_task_shell::execute(seq_list, env_vars, &cwd, npx_commands).await; deno_task_shell::execute(seq_list, env_vars, &cwd, npx_commands).await;
@ -108,9 +112,8 @@ pub async fn execute_script(
} }
} }
fn get_script_with_args(script: &str, ps: &ProcState) -> String { fn get_script_with_args(script: &str, options: &CliOptions) -> String {
let additional_args = ps let additional_args = options
.options
.argv() .argv()
.iter() .iter()
// surround all the additional arguments in double quotes // surround all the additional arguments in double quotes
@ -231,13 +234,13 @@ impl ShellCommand for NpmPackageBinCommand {
} }
fn resolve_npm_commands( fn resolve_npm_commands(
ps: &ProcState, npm_resolver: &NpmPackageResolver,
node_resolver: &CliNodeResolver,
) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> { ) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> {
let mut result = HashMap::new(); let mut result = HashMap::new();
let snapshot = ps.npm_resolver.snapshot(); let snapshot = npm_resolver.snapshot();
for id in snapshot.top_level_packages() { for id in snapshot.top_level_packages() {
let bin_commands = let bin_commands = node_resolver.resolve_binary_commands(&id.nv)?;
crate::node::node_resolve_binary_commands(&id.nv, &ps.npm_resolver)?;
for bin_command in bin_commands { for bin_command in bin_commands {
result.insert( result.insert(
bin_command.to_string(), bin_command.to_string(),

View file

@ -15,6 +15,7 @@ use crate::args::CliOptions;
use crate::args::Flags; use crate::args::Flags;
use crate::args::FmtOptionsConfig; use crate::args::FmtOptionsConfig;
use crate::args::VendorFlags; use crate::args::VendorFlags;
use crate::graph_util::ModuleGraphBuilder;
use crate::proc_state::ProcState; use crate::proc_state::ProcState;
use crate::tools::fmt::format_json; use crate::tools::fmt::format_json;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
@ -43,7 +44,12 @@ pub async fn vendor(
validate_output_dir(&output_dir, &vendor_flags)?; validate_output_dir(&output_dir, &vendor_flags)?;
validate_options(&mut cli_options, &output_dir)?; validate_options(&mut cli_options, &output_dir)?;
let ps = ProcState::from_cli_options(Arc::new(cli_options)).await?; let ps = ProcState::from_cli_options(Arc::new(cli_options)).await?;
let graph = create_graph(&ps, &vendor_flags).await?; let graph = create_graph(
&ps.module_graph_builder,
&vendor_flags,
ps.options.initial_cwd(),
)
.await?;
let vendored_count = build::build( let vendored_count = build::build(
graph, graph,
&ps.parsed_source_cache, &ps.parsed_source_cache,
@ -261,16 +267,17 @@ fn is_dir_empty(dir_path: &Path) -> Result<bool, AnyError> {
} }
async fn create_graph( async fn create_graph(
ps: &ProcState, module_graph_builder: &ModuleGraphBuilder,
flags: &VendorFlags, flags: &VendorFlags,
initial_cwd: &Path,
) -> Result<deno_graph::ModuleGraph, AnyError> { ) -> Result<deno_graph::ModuleGraph, AnyError> {
let entry_points = flags let entry_points = flags
.specifiers .specifiers
.iter() .iter()
.map(|p| resolve_url_or_path(p, ps.options.initial_cwd())) .map(|p| resolve_url_or_path(p, initial_cwd))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
ps.module_graph_builder.create_graph(entry_points).await module_graph_builder.create_graph(entry_points).await
} }
#[cfg(test)] #[cfg(test)]

View file

@ -4,9 +4,8 @@ use crate::args::TsConfig;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::cache::FastInsecureHasher; use crate::cache::FastInsecureHasher;
use crate::node; use crate::node;
use crate::node::node_resolve_npm_reference; use crate::node::CliNodeResolver;
use crate::node::NodeResolution; use crate::node::NodeResolution;
use crate::npm::NpmPackageResolver;
use crate::util::checksum; use crate::util::checksum;
use crate::util::path::mapped_specifier_for_tsc; use crate::util::path::mapped_specifier_for_tsc;
@ -36,7 +35,6 @@ use deno_graph::ModuleGraph;
use deno_graph::ResolutionResolved; use deno_graph::ResolutionResolved;
use deno_runtime::deno_node::NodeResolutionMode; use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::permissions::PermissionsContainer; use deno_runtime::permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageNvReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use lsp_types::Url; use lsp_types::Url;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -307,7 +305,7 @@ pub struct Request {
pub debug: bool, pub debug: bool,
pub graph: Arc<ModuleGraph>, pub graph: Arc<ModuleGraph>,
pub hash_data: u64, pub hash_data: u64,
pub maybe_npm_resolver: Option<Arc<NpmPackageResolver>>, pub maybe_node_resolver: Option<Arc<CliNodeResolver>>,
pub maybe_tsbuildinfo: Option<String>, pub maybe_tsbuildinfo: Option<String>,
/// A vector of strings that represent the root/entry point modules for the /// A vector of strings that represent the root/entry point modules for the
/// program. /// program.
@ -331,7 +329,7 @@ struct State {
graph: Arc<ModuleGraph>, graph: Arc<ModuleGraph>,
maybe_tsbuildinfo: Option<String>, maybe_tsbuildinfo: Option<String>,
maybe_response: Option<RespondArgs>, maybe_response: Option<RespondArgs>,
maybe_npm_resolver: Option<Arc<NpmPackageResolver>>, maybe_node_resolver: Option<Arc<CliNodeResolver>>,
remapped_specifiers: HashMap<String, ModuleSpecifier>, remapped_specifiers: HashMap<String, ModuleSpecifier>,
root_map: HashMap<String, ModuleSpecifier>, root_map: HashMap<String, ModuleSpecifier>,
current_dir: PathBuf, current_dir: PathBuf,
@ -341,7 +339,7 @@ impl State {
pub fn new( pub fn new(
graph: Arc<ModuleGraph>, graph: Arc<ModuleGraph>,
hash_data: u64, hash_data: u64,
maybe_npm_resolver: Option<Arc<NpmPackageResolver>>, maybe_node_resolver: Option<Arc<CliNodeResolver>>,
maybe_tsbuildinfo: Option<String>, maybe_tsbuildinfo: Option<String>,
root_map: HashMap<String, ModuleSpecifier>, root_map: HashMap<String, ModuleSpecifier>,
remapped_specifiers: HashMap<String, ModuleSpecifier>, remapped_specifiers: HashMap<String, ModuleSpecifier>,
@ -350,7 +348,7 @@ impl State {
State { State {
hash_data, hash_data,
graph, graph,
maybe_npm_resolver, maybe_node_resolver,
maybe_tsbuildinfo, maybe_tsbuildinfo,
maybe_response: None, maybe_response: None,
remapped_specifiers, remapped_specifiers,
@ -483,7 +481,7 @@ fn op_load(state: &mut OpState, args: Value) -> Result<Value, AnyError> {
} }
} }
} else if state } else if state
.maybe_npm_resolver .maybe_node_resolver
.as_ref() .as_ref()
.map(|resolver| resolver.in_npm_package(specifier)) .map(|resolver| resolver.in_npm_package(specifier))
.unwrap_or(false) .unwrap_or(false)
@ -636,24 +634,26 @@ fn resolve_graph_specifier_types(
Ok(Some((module.specifier.clone(), module.media_type))) Ok(Some((module.specifier.clone(), module.media_type)))
} }
Some(Module::Npm(module)) => { Some(Module::Npm(module)) => {
if let Some(npm_resolver) = &state.maybe_npm_resolver { if let Some(node_resolver) = &state.maybe_node_resolver {
resolve_npm_package_reference_types(&module.nv_reference, npm_resolver) let maybe_resolution = node_resolver.resolve_npm_reference(
.map(Some) &module.nv_reference,
NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(),
)?;
Ok(Some(NodeResolution::into_specifier_and_media_type(
maybe_resolution,
)))
} else { } else {
Ok(None) Ok(None)
} }
} }
Some(Module::External(module)) => { Some(Module::External(module)) => {
// we currently only use "External" for when the module is in an npm package // we currently only use "External" for when the module is in an npm package
Ok(state.maybe_npm_resolver.as_ref().map(|npm_resolver| { Ok(state.maybe_node_resolver.as_ref().map(|node_resolver| {
let specifier = let specifier =
node::resolve_specifier_into_node_modules(&module.specifier); node::resolve_specifier_into_node_modules(&module.specifier);
NodeResolution::into_specifier_and_media_type( NodeResolution::into_specifier_and_media_type(
node::url_to_node_resolution( node_resolver.url_to_node_resolution(specifier).ok(),
specifier,
&npm_resolver.as_require_npm_resolver(),
)
.ok(),
) )
})) }))
} }
@ -666,60 +666,47 @@ fn resolve_non_graph_specifier_types(
referrer: &ModuleSpecifier, referrer: &ModuleSpecifier,
state: &State, state: &State,
) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> { ) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> {
let npm_resolver = match state.maybe_npm_resolver.as_ref() { let node_resolver = match state.maybe_node_resolver.as_ref() {
Some(npm_resolver) => npm_resolver, Some(node_resolver) => node_resolver,
None => return Ok(None), // we only support non-graph types for npm packages None => return Ok(None), // we only support non-graph types for npm packages
}; };
if npm_resolver.in_npm_package(referrer) { if node_resolver.in_npm_package(referrer) {
// we're in an npm package, so use node resolution // we're in an npm package, so use node resolution
Ok(Some(NodeResolution::into_specifier_and_media_type( Ok(Some(NodeResolution::into_specifier_and_media_type(
node::node_resolve( node_resolver
specifier, .resolve(
referrer, specifier,
NodeResolutionMode::Types, referrer,
&npm_resolver.as_require_npm_resolver(), NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(), &mut PermissionsContainer::allow_all(),
) )
.ok() .ok()
.flatten(), .flatten(),
))) )))
} else if let Ok(npm_ref) = NpmPackageReqReference::from_str(specifier) { } else if let Ok(npm_ref) = NpmPackageReqReference::from_str(specifier) {
// todo(dsherret): add support for injecting this in the graph so // todo(dsherret): add support for injecting this in the graph so
// we don't need this special code here. // we don't need this special code here.
// This could occur when resolving npm:@types/node when it is // This could occur when resolving npm:@types/node when it is
// injected and not part of the graph // injected and not part of the graph
let node_id = npm_resolver.resolve_pkg_id_from_pkg_req(&npm_ref.req)?; let maybe_resolution = node_resolver.resolve_npm_req_reference(
let npm_id_ref = NpmPackageNvReference { &npm_ref,
nv: node_id.nv, NodeResolutionMode::Types,
sub_path: npm_ref.sub_path, &mut PermissionsContainer::allow_all(),
}; )?;
resolve_npm_package_reference_types(&npm_id_ref, npm_resolver).map(Some) Ok(Some(NodeResolution::into_specifier_and_media_type(
maybe_resolution,
)))
} else { } else {
Ok(None) Ok(None)
} }
} }
pub fn resolve_npm_package_reference_types(
npm_ref: &NpmPackageNvReference,
npm_resolver: &Arc<NpmPackageResolver>,
) -> Result<(ModuleSpecifier, MediaType), AnyError> {
let maybe_resolution = node_resolve_npm_reference(
npm_ref,
NodeResolutionMode::Types,
npm_resolver,
&mut PermissionsContainer::allow_all(),
)?;
Ok(NodeResolution::into_specifier_and_media_type(
maybe_resolution,
))
}
#[op] #[op]
fn op_is_node_file(state: &mut OpState, path: &str) -> bool { fn op_is_node_file(state: &mut OpState, path: &str) -> bool {
let state = state.borrow::<State>(); let state = state.borrow::<State>();
match ModuleSpecifier::parse(path) { match ModuleSpecifier::parse(path) {
Ok(specifier) => state Ok(specifier) => state
.maybe_npm_resolver .maybe_node_resolver
.as_ref() .as_ref()
.map(|r| r.in_npm_package(&specifier)) .map(|r| r.in_npm_package(&specifier))
.unwrap_or(false), .unwrap_or(false),
@ -783,7 +770,7 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
state.put(State::new( state.put(State::new(
options.request.graph, options.request.graph,
options.request.hash_data, options.request.hash_data,
options.request.maybe_npm_resolver, options.request.maybe_node_resolver,
options.request.maybe_tsbuildinfo, options.request.maybe_tsbuildinfo,
options.root_map, options.root_map,
options.remapped_specifiers, options.remapped_specifiers,
@ -955,7 +942,7 @@ mod tests {
debug: false, debug: false,
graph: Arc::new(graph), graph: Arc::new(graph),
hash_data, hash_data,
maybe_npm_resolver: None, maybe_node_resolver: None,
maybe_tsbuildinfo: None, maybe_tsbuildinfo: None,
root_names: vec![(specifier.clone(), MediaType::TypeScript)], root_names: vec![(specifier.clone(), MediaType::TypeScript)],
check_mode: TypeCheckMode::All, check_mode: TypeCheckMode::All,

View file

@ -258,23 +258,14 @@ pub async fn create_custom_worker(
ps.npm_resolver ps.npm_resolver
.add_package_reqs(vec![package_ref.req.clone()]) .add_package_reqs(vec![package_ref.req.clone()])
.await?; .await?;
let pkg_nv = ps let node_resolution =
.npm_resolution ps.node_resolver.resolve_binary_export(&package_ref)?;
.resolve_pkg_id_from_pkg_req(&package_ref.req)?
.nv;
let node_resolution = node::node_resolve_binary_export(
&pkg_nv,
package_ref.sub_path.as_deref(),
&ps.npm_resolver,
)?;
let is_main_cjs = let is_main_cjs =
matches!(node_resolution, node::NodeResolution::CommonJs(_)); matches!(node_resolution, node::NodeResolution::CommonJs(_));
(node_resolution.into_url(), is_main_cjs) (node_resolution.into_url(), is_main_cjs)
} else if ps.options.is_npm_main() { } else if ps.options.is_npm_main() {
let node_resolution = node::url_to_node_resolution( let node_resolution =
main_module, ps.node_resolver.url_to_node_resolution(main_module)?;
&ps.npm_resolver.as_require_npm_resolver(),
)?;
let is_main_cjs = let is_main_cjs =
matches!(node_resolution, node::NodeResolution::CommonJs(_)); matches!(node_resolution, node::NodeResolution::CommonJs(_));
(node_resolution.into_url(), is_main_cjs) (node_resolution.into_url(), is_main_cjs)
@ -311,7 +302,7 @@ pub async fn create_custom_worker(
.join(checksum::gen(&[key.as_bytes()])) .join(checksum::gen(&[key.as_bytes()]))
}); });
let mut extensions = ops::cli_exts(ps.clone()); let mut extensions = ops::cli_exts(ps.npm_resolver.clone());
extensions.append(&mut custom_extensions); extensions.append(&mut custom_extensions);
let options = WorkerOptions { let options = WorkerOptions {
@ -429,7 +420,7 @@ fn create_web_worker_callback(
let pre_execute_module_cb = let pre_execute_module_cb =
create_web_worker_pre_execute_module_callback(ps.clone()); create_web_worker_pre_execute_module_callback(ps.clone());
let extensions = ops::cli_exts(ps.clone()); let extensions = ops::cli_exts(ps.npm_resolver.clone());
let maybe_storage_key = ps.options.resolve_storage_key(&args.main_module); let maybe_storage_key = ps.options.resolve_storage_key(&args.main_module);
let cache_storage_dir = maybe_storage_key.map(|key| { let cache_storage_dir = maybe_storage_key.map(|key| {