mirror of
https://github.com/denoland/deno.git
synced 2025-02-07 23:06:50 -05:00
refactor: add WorkspaceFactory
and ResolverFactory
(#27766)
Allows easily constructing a `DenoResolver` using the exact same logic that we use in the CLI (useful for dnt and for external bundlers). This code is then used in the CLI to ensure the logic is always up-to-date. ```rs use std::rc::Rc; use deno_resolver:🏭:ResolverFactory; use deno_resolver:🏭:WorkspaceFactory; use sys_traits::impls::RealSys; let sys = RealSys; let cwd = sys.env_current_dir()?; let workspace_factory = Rc::new(WorkspaceFactory::new(sys, cwd, Default::default())); let resolver_factory = ResolverFactory::new(workspace_factory.clone(), Default::default()); let deno_resolver = resolver_factory.deno_resolver().await?; ```
This commit is contained in:
parent
f81debe9f6
commit
a63f614ba1
47 changed files with 1902 additions and 1166 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -284,6 +284,12 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-once-cell"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a"
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
|
@ -1460,9 +1466,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache_dir"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e73ed17f285731a23df9779ca1e0e721de866db6776ed919ebd9235e0a107c4c"
|
||||
checksum = "27429da4d0e601baaa41415a43468d49a586645d13497f12e8a9346f9f6b1347"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base32",
|
||||
|
@ -2219,9 +2225,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_path_util"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "420e8211aaba7fde83ccaa9a5dad855c3b940ed988d70c95159acd600a70dc87"
|
||||
checksum = "c87b8996966ae1b13ee9c20219b1d10fc53905b9570faae6adfa34614fd15224"
|
||||
dependencies = [
|
||||
"deno_error",
|
||||
"percent-encoding",
|
||||
|
@ -2282,6 +2288,7 @@ name = "deno_resolver"
|
|||
version = "0.18.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-once-cell",
|
||||
"async-trait",
|
||||
"base32",
|
||||
"boxed_error",
|
||||
|
@ -2294,8 +2301,11 @@ dependencies = [
|
|||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_semver",
|
||||
"deno_terminal 0.2.0",
|
||||
"futures",
|
||||
"log",
|
||||
"node_resolver",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"sys_traits",
|
||||
"test_server",
|
||||
|
|
|
@ -54,11 +54,11 @@ deno_ast = { version = "=0.44.0", features = ["transpiling"] }
|
|||
deno_core = { version = "0.331.0" }
|
||||
|
||||
deno_bench_util = { version = "0.181.0", path = "./bench_util" }
|
||||
deno_config = { version = "=0.45.0", features = ["workspace", "sync"] }
|
||||
deno_config = { version = "=0.45.0", features = ["workspace"] }
|
||||
deno_lockfile = "=0.24.0"
|
||||
deno_media_type = { version = "=0.2.5", features = ["module_specifier"] }
|
||||
deno_npm = "=0.27.2"
|
||||
deno_path_util = "=0.3.0"
|
||||
deno_path_util = "=0.3.1"
|
||||
deno_permissions = { version = "0.46.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.195.0", path = "./runtime" }
|
||||
deno_semver = "=0.7.1"
|
||||
|
@ -107,6 +107,7 @@ node_resolver = { version = "0.25.0", path = "./resolvers/node" }
|
|||
|
||||
aes = "=0.8.3"
|
||||
anyhow = "1.0.57"
|
||||
async-once-cell = "0.5.4"
|
||||
async-trait = "0.1.73"
|
||||
base32 = "=0.5.1"
|
||||
base64 = "0.21.7"
|
||||
|
@ -125,7 +126,7 @@ console_static_text = "=0.8.1"
|
|||
dashmap = "5.5.3"
|
||||
data-encoding = "2.3.3"
|
||||
data-url = "=0.3.1"
|
||||
deno_cache_dir = "=0.16.0"
|
||||
deno_cache_dir = "=0.17.0"
|
||||
deno_error = "=0.5.5"
|
||||
deno_package_json = { version = "0.4.0", default-features = false }
|
||||
deno_unsync = "0.4.2"
|
||||
|
|
|
@ -67,8 +67,8 @@ winres.workspace = true
|
|||
|
||||
[dependencies]
|
||||
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
||||
deno_cache_dir.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_cache_dir = { workspace = true, features = ["sync"] }
|
||||
deno_config = { workspace = true, features = ["sync", "workspace"] }
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_doc = { version = "=0.164.0", features = ["rust", "comrak"] }
|
||||
deno_error.workspace = true
|
||||
|
@ -79,7 +79,7 @@ deno_lockfile.workspace = true
|
|||
deno_media_type = { workspace = true, features = ["data_url", "decoding", "module_specifier"] }
|
||||
deno_npm.workspace = true
|
||||
deno_npm_cache.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_package_json = { workspace = true, features = ["sync"] }
|
||||
deno_path_util.workspace = true
|
||||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
|
|
|
@ -34,6 +34,7 @@ use deno_graph::GraphKind;
|
|||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::UnstableConfig;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_permissions::SysDescriptor;
|
||||
|
@ -500,6 +501,52 @@ impl DenoSubcommand {
|
|||
| Self::Lsp
|
||||
)
|
||||
}
|
||||
|
||||
pub fn npm_system_info(&self) -> NpmSystemInfo {
|
||||
match self {
|
||||
DenoSubcommand::Compile(CompileFlags {
|
||||
target: Some(target),
|
||||
..
|
||||
}) => {
|
||||
// the values of NpmSystemInfo align with the possible values for the
|
||||
// `arch` and `platform` fields of Node.js' `process` global:
|
||||
// https://nodejs.org/api/process.html
|
||||
match target.as_str() {
|
||||
"aarch64-apple-darwin" => NpmSystemInfo {
|
||||
os: "darwin".into(),
|
||||
cpu: "arm64".into(),
|
||||
},
|
||||
"aarch64-unknown-linux-gnu" => NpmSystemInfo {
|
||||
os: "linux".into(),
|
||||
cpu: "arm64".into(),
|
||||
},
|
||||
"x86_64-apple-darwin" => NpmSystemInfo {
|
||||
os: "darwin".into(),
|
||||
cpu: "x64".into(),
|
||||
},
|
||||
"x86_64-unknown-linux-gnu" => NpmSystemInfo {
|
||||
os: "linux".into(),
|
||||
cpu: "x64".into(),
|
||||
},
|
||||
"x86_64-pc-windows-msvc" => NpmSystemInfo {
|
||||
os: "win32".into(),
|
||||
cpu: "x64".into(),
|
||||
},
|
||||
value => {
|
||||
log::warn!(
|
||||
concat!(
|
||||
"Not implemented npm system info for target '{}'. Using current ",
|
||||
"system default. This may impact architecture specific dependencies."
|
||||
),
|
||||
value,
|
||||
);
|
||||
NpmSystemInfo::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => NpmSystemInfo::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DenoSubcommand {
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::file_fetcher::TextDecodedFile;
|
||||
|
||||
pub async fn resolve_import_map_value_from_specifier(
|
||||
specifier: &Url,
|
||||
file_fetcher: &CliFileFetcher,
|
||||
) -> Result<serde_json::Value, AnyError> {
|
||||
if specifier.scheme() == "data" {
|
||||
let data_url_text =
|
||||
deno_media_type::data_url::RawDataUrl::parse(specifier)?.decode()?;
|
||||
Ok(serde_json::from_str(&data_url_text)?)
|
||||
} else {
|
||||
let file = TextDecodedFile::decode(
|
||||
file_fetcher.fetch_bypass_permissions(specifier).await?,
|
||||
)?;
|
||||
Ok(serde_json::from_str(&file.source)?)
|
||||
}
|
||||
}
|
633
cli/args/mod.rs
633
cli/args/mod.rs
|
@ -3,7 +3,6 @@
|
|||
pub mod deno_json;
|
||||
mod flags;
|
||||
mod flags_net;
|
||||
mod import_map;
|
||||
mod lockfile;
|
||||
mod package_json;
|
||||
|
||||
|
@ -35,17 +34,9 @@ pub use deno_config::deno_json::TsConfigForEmit;
|
|||
pub use deno_config::deno_json::TsConfigType;
|
||||
pub use deno_config::deno_json::TsTypeLib;
|
||||
pub use deno_config::glob::FilePatterns;
|
||||
use deno_config::workspace::CreateResolverOptions;
|
||||
use deno_config::workspace::FolderConfigs;
|
||||
use deno_config::workspace::PackageJsonDepResolution;
|
||||
use deno_config::workspace::VendorEnablement;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_config::workspace::WorkspaceDirectoryEmptyOptions;
|
||||
use deno_config::workspace::WorkspaceDiscoverOptions;
|
||||
use deno_config::workspace::WorkspaceDiscoverStart;
|
||||
use deno_config::workspace::WorkspaceLintConfig;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
|
@ -57,16 +48,11 @@ pub use deno_json::check_warn_tsconfig;
|
|||
use deno_lib::args::has_flag_env_var;
|
||||
use deno_lib::args::npm_pkg_req_ref_to_binary_command;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::NpmProcessStateKind;
|
||||
use deno_lib::args::NPM_PROCESS_STATE;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_lib::worker::StorageKeyResolver;
|
||||
use deno_lint::linter::LintConfig as DenoLintConfig;
|
||||
use deno_npm::npm_rc::NpmRc;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
|
@ -75,46 +61,16 @@ use deno_telemetry::OtelConfig;
|
|||
use deno_terminal::colors;
|
||||
use dotenvy::from_filename;
|
||||
pub use flags::*;
|
||||
use import_map::resolve_import_map_value_from_specifier;
|
||||
pub use lockfile::AtomicWriteFileWithRetriesError;
|
||||
pub use lockfile::CliLockfile;
|
||||
pub use lockfile::CliLockfileReadFromPathOptions;
|
||||
use once_cell::sync::Lazy;
|
||||
pub use package_json::NpmInstallDepsProvider;
|
||||
pub use package_json::PackageJsonDepValueParseWithLocationError;
|
||||
use sys_traits::EnvHomeDir;
|
||||
use sys_traits::FsRead;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::cache::DenoDirProvider;
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::sys::CliSys;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
|
||||
pub fn npm_registry_url() -> &'static Url {
|
||||
static NPM_REGISTRY_DEFAULT_URL: Lazy<Url> = Lazy::new(|| {
|
||||
let env_var_name = "NPM_CONFIG_REGISTRY";
|
||||
if let Ok(registry_url) = std::env::var(env_var_name) {
|
||||
// ensure there is a trailing slash for the directory
|
||||
let registry_url = format!("{}/", registry_url.trim_end_matches('/'));
|
||||
match Url::parse(®istry_url) {
|
||||
Ok(url) => {
|
||||
return url;
|
||||
}
|
||||
Err(err) => {
|
||||
log::debug!(
|
||||
"Invalid {} environment variable: {:#}",
|
||||
env_var_name,
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Url::parse("https://registry.npmjs.org").unwrap()
|
||||
});
|
||||
|
||||
&NPM_REGISTRY_DEFAULT_URL
|
||||
}
|
||||
|
||||
pub static DENO_DISABLE_PEDANTIC_NODE_WARNINGS: Lazy<bool> = Lazy::new(|| {
|
||||
std::env::var("DENO_DISABLE_PEDANTIC_NODE_WARNINGS")
|
||||
|
@ -214,6 +170,53 @@ pub fn ts_config_to_transpile_and_emit_options(
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExternalImportMap {
|
||||
pub path: PathBuf,
|
||||
pub value: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WorkspaceExternalImportMapLoader {
|
||||
sys: CliSys,
|
||||
workspace: Arc<Workspace>,
|
||||
maybe_external_import_map:
|
||||
once_cell::sync::OnceCell<Option<ExternalImportMap>>,
|
||||
}
|
||||
|
||||
impl WorkspaceExternalImportMapLoader {
|
||||
pub fn new(sys: CliSys, workspace: Arc<Workspace>) -> Self {
|
||||
Self {
|
||||
sys,
|
||||
workspace,
|
||||
maybe_external_import_map: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_load(&self) -> Result<Option<&ExternalImportMap>, AnyError> {
|
||||
self
|
||||
.maybe_external_import_map
|
||||
.get_or_try_init(|| {
|
||||
let Some(deno_json) = self.workspace.root_deno_json() else {
|
||||
return Ok(None);
|
||||
};
|
||||
if deno_json.is_an_import_map() {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(path) = deno_json.to_import_map_path()? else {
|
||||
return Ok(None);
|
||||
};
|
||||
let contents =
|
||||
self.sys.fs_read_to_string(&path).with_context(|| {
|
||||
format!("Unable to read import map at '{}'", path.display())
|
||||
})?;
|
||||
let value = serde_json::from_str(&contents)?;
|
||||
Ok(Some(ExternalImportMap { path, value }))
|
||||
})
|
||||
.map(|v| v.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkspaceBenchOptions {
|
||||
pub filter: Option<String>,
|
||||
pub json: bool,
|
||||
|
@ -480,162 +483,26 @@ fn resolve_lint_rules_options(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn discover_npmrc_from_workspace(
|
||||
workspace: &Workspace,
|
||||
) -> Result<(Arc<ResolvedNpmRc>, Option<PathBuf>), AnyError> {
|
||||
let root_folder = workspace.root_folder_configs();
|
||||
discover_npmrc(
|
||||
root_folder.pkg_json.as_ref().map(|p| p.path.clone()),
|
||||
root_folder.deno_json.as_ref().and_then(|cf| {
|
||||
if cf.specifier.scheme() == "file" {
|
||||
Some(cf.specifier.to_file_path().unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Discover `.npmrc` file - currently we only support it next to `package.json`
|
||||
/// or next to `deno.json`.
|
||||
///
|
||||
/// In the future we will need to support it in user directory or global directory
|
||||
/// as per https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#files.
|
||||
fn discover_npmrc(
|
||||
maybe_package_json_path: Option<PathBuf>,
|
||||
maybe_deno_json_path: Option<PathBuf>,
|
||||
) -> Result<(Arc<ResolvedNpmRc>, Option<PathBuf>), AnyError> {
|
||||
const NPMRC_NAME: &str = ".npmrc";
|
||||
|
||||
fn get_env_var(var_name: &str) -> Option<String> {
|
||||
std::env::var(var_name).ok()
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Error loading .npmrc at {}.", path.display())]
|
||||
struct NpmRcLoadError {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
}
|
||||
|
||||
fn try_to_read_npmrc(
|
||||
dir: &Path,
|
||||
) -> Result<Option<(String, PathBuf)>, NpmRcLoadError> {
|
||||
let path = dir.join(NPMRC_NAME);
|
||||
let maybe_source = match std::fs::read_to_string(&path) {
|
||||
Ok(source) => Some(source),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
|
||||
Err(err) => return Err(NpmRcLoadError { path, source: err }),
|
||||
};
|
||||
|
||||
Ok(maybe_source.map(|source| (source, path)))
|
||||
}
|
||||
|
||||
fn try_to_parse_npmrc(
|
||||
source: String,
|
||||
path: &Path,
|
||||
) -> Result<Arc<ResolvedNpmRc>, AnyError> {
|
||||
let npmrc = NpmRc::parse(&source, &get_env_var).with_context(|| {
|
||||
format!("Failed to parse .npmrc at {}", path.display())
|
||||
})?;
|
||||
let resolved = npmrc
|
||||
.as_resolved(npm_registry_url())
|
||||
.context("Failed to resolve .npmrc options")?;
|
||||
log::debug!(".npmrc found at: '{}'", path.display());
|
||||
Ok(Arc::new(resolved))
|
||||
}
|
||||
|
||||
// 1. Try `.npmrc` next to `package.json`
|
||||
if let Some(package_json_path) = maybe_package_json_path {
|
||||
if let Some(package_json_dir) = package_json_path.parent() {
|
||||
if let Some((source, path)) = try_to_read_npmrc(package_json_dir)? {
|
||||
return try_to_parse_npmrc(source, &path).map(|r| (r, Some(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try `.npmrc` next to `deno.json(c)`
|
||||
if let Some(deno_json_path) = maybe_deno_json_path {
|
||||
if let Some(deno_json_dir) = deno_json_path.parent() {
|
||||
if let Some((source, path)) = try_to_read_npmrc(deno_json_dir)? {
|
||||
return try_to_parse_npmrc(source, &path).map(|r| (r, Some(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bartlomieju): update to read both files - one in the project root and one and
|
||||
// home dir and then merge them.
|
||||
// 3. Try `.npmrc` in the user's home directory
|
||||
if let Some(home_dir) = crate::sys::CliSys::default().env_home_dir() {
|
||||
match try_to_read_npmrc(&home_dir) {
|
||||
Ok(Some((source, path))) => {
|
||||
return try_to_parse_npmrc(source, &path).map(|r| (r, Some(path)));
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(err) if err.source.kind() == std::io::ErrorKind::PermissionDenied => {
|
||||
log::debug!(
|
||||
"Skipping .npmrc in home directory due to permission denied error. {:#}",
|
||||
err
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("No .npmrc file found");
|
||||
Ok((create_default_npmrc(), None))
|
||||
}
|
||||
|
||||
pub fn create_default_npmrc() -> Arc<ResolvedNpmRc> {
|
||||
Arc::new(ResolvedNpmRc {
|
||||
default_config: deno_npm::npm_rc::RegistryConfigWithUrl {
|
||||
registry_url: npm_registry_url().clone(),
|
||||
config: Default::default(),
|
||||
},
|
||||
scopes: Default::default(),
|
||||
registry_configs: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Overrides for the options below that when set will
|
||||
/// use these values over the values derived from the
|
||||
/// CLI flags or config file.
|
||||
#[derive(Default, Clone)]
|
||||
struct CliOptionOverrides {
|
||||
import_map_specifier: Option<Option<ModuleSpecifier>>,
|
||||
}
|
||||
|
||||
/// Holds the resolved options of many sources used by subcommands
|
||||
/// and provides some helper function for creating common objects.
|
||||
#[derive(Debug)]
|
||||
pub struct CliOptions {
|
||||
// the source of the options is a detail the rest of the
|
||||
// application need not concern itself with, so keep these private
|
||||
flags: Arc<Flags>,
|
||||
initial_cwd: PathBuf,
|
||||
main_module_cell: std::sync::OnceLock<Result<ModuleSpecifier, AnyError>>,
|
||||
maybe_node_modules_folder: Option<PathBuf>,
|
||||
npmrc: Arc<ResolvedNpmRc>,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
||||
overrides: CliOptionOverrides,
|
||||
pub start_dir: Arc<WorkspaceDirectory>,
|
||||
pub deno_dir_provider: Arc<DenoDirProvider>,
|
||||
}
|
||||
|
||||
impl CliOptions {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
sys: &CliSys,
|
||||
flags: Arc<Flags>,
|
||||
initial_cwd: PathBuf,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
npmrc: Arc<ResolvedNpmRc>,
|
||||
start_dir: Arc<WorkspaceDirectory>,
|
||||
force_global_cache: bool,
|
||||
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
||||
) -> Result<Self, AnyError> {
|
||||
if let Some(insecure_allowlist) =
|
||||
flags.unsafely_ignore_certificate_errors.as_ref()
|
||||
|
@ -652,154 +519,38 @@ impl CliOptions {
|
|||
}
|
||||
}
|
||||
|
||||
let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache);
|
||||
let deno_dir_provider = Arc::new(DenoDirProvider::new(
|
||||
sys.clone(),
|
||||
flags.internal.cache_path.clone(),
|
||||
));
|
||||
let maybe_node_modules_folder = resolve_node_modules_folder(
|
||||
&initial_cwd,
|
||||
&flags,
|
||||
&start_dir.workspace,
|
||||
&deno_dir_provider,
|
||||
)
|
||||
.with_context(|| "Resolving node_modules folder.")?;
|
||||
|
||||
load_env_variables_from_env_file(flags.env_file.as_ref());
|
||||
|
||||
Ok(Self {
|
||||
flags,
|
||||
initial_cwd,
|
||||
maybe_lockfile,
|
||||
npmrc,
|
||||
maybe_node_modules_folder,
|
||||
overrides: Default::default(),
|
||||
main_module_cell: std::sync::OnceLock::new(),
|
||||
maybe_external_import_map,
|
||||
start_dir,
|
||||
deno_dir_provider,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_flags(sys: &CliSys, flags: Arc<Flags>) -> Result<Self, AnyError> {
|
||||
let initial_cwd =
|
||||
std::env::current_dir().with_context(|| "Failed getting cwd.")?;
|
||||
let maybe_vendor_override = flags.vendor.map(|v| match v {
|
||||
true => VendorEnablement::Enable { cwd: &initial_cwd },
|
||||
false => VendorEnablement::Disable,
|
||||
});
|
||||
let resolve_workspace_discover_options = || {
|
||||
let additional_config_file_names: &'static [&'static str] =
|
||||
if matches!(flags.subcommand, DenoSubcommand::Publish(..)) {
|
||||
&["jsr.json", "jsr.jsonc"]
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
let discover_pkg_json = flags.config_flag != ConfigFlag::Disabled
|
||||
&& !flags.no_npm
|
||||
&& !has_flag_env_var("DENO_NO_PACKAGE_JSON");
|
||||
if !discover_pkg_json {
|
||||
log::debug!("package.json auto-discovery is disabled");
|
||||
}
|
||||
WorkspaceDiscoverOptions {
|
||||
deno_json_cache: None,
|
||||
pkg_json_cache: Some(&node_resolver::PackageJsonThreadLocalCache),
|
||||
workspace_cache: None,
|
||||
additional_config_file_names,
|
||||
discover_pkg_json,
|
||||
maybe_vendor_override,
|
||||
}
|
||||
};
|
||||
let resolve_empty_options = || WorkspaceDirectoryEmptyOptions {
|
||||
root_dir: Arc::new(
|
||||
ModuleSpecifier::from_directory_path(&initial_cwd).unwrap(),
|
||||
),
|
||||
use_vendor_dir: maybe_vendor_override
|
||||
.unwrap_or(VendorEnablement::Disable),
|
||||
};
|
||||
|
||||
let start_dir = match &flags.config_flag {
|
||||
ConfigFlag::Discover => {
|
||||
if let Some(start_paths) = flags.config_path_args(&initial_cwd) {
|
||||
WorkspaceDirectory::discover(
|
||||
sys,
|
||||
WorkspaceDiscoverStart::Paths(&start_paths),
|
||||
&resolve_workspace_discover_options(),
|
||||
)?
|
||||
} else {
|
||||
WorkspaceDirectory::empty(resolve_empty_options())
|
||||
}
|
||||
}
|
||||
ConfigFlag::Path(path) => {
|
||||
let config_path = normalize_path(initial_cwd.join(path));
|
||||
WorkspaceDirectory::discover(
|
||||
sys,
|
||||
WorkspaceDiscoverStart::ConfigFile(&config_path),
|
||||
&resolve_workspace_discover_options(),
|
||||
)?
|
||||
}
|
||||
ConfigFlag::Disabled => {
|
||||
WorkspaceDirectory::empty(resolve_empty_options())
|
||||
}
|
||||
};
|
||||
|
||||
pub fn from_flags(
|
||||
sys: &CliSys,
|
||||
flags: Arc<Flags>,
|
||||
initial_cwd: PathBuf,
|
||||
maybe_external_import_map: Option<&ExternalImportMap>,
|
||||
start_dir: Arc<WorkspaceDirectory>,
|
||||
) -> Result<Self, AnyError> {
|
||||
for diagnostic in start_dir.workspace.diagnostics() {
|
||||
log::warn!("{} {}", colors::yellow("Warning"), diagnostic);
|
||||
}
|
||||
|
||||
let (npmrc, _) = discover_npmrc_from_workspace(&start_dir.workspace)?;
|
||||
|
||||
fn load_external_import_map(
|
||||
deno_json: &ConfigFile,
|
||||
) -> Result<Option<(PathBuf, serde_json::Value)>, AnyError> {
|
||||
if !deno_json.is_an_import_map() {
|
||||
if let Some(path) = deno_json.to_import_map_path()? {
|
||||
let contents = std::fs::read_to_string(&path).with_context(|| {
|
||||
format!("Unable to read import map at '{}'", path.display())
|
||||
})?;
|
||||
let map = serde_json::from_str(&contents)?;
|
||||
return Ok(Some((path, map)));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
let external_import_map =
|
||||
if let Some(deno_json) = start_dir.workspace.root_deno_json() {
|
||||
load_external_import_map(deno_json)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let maybe_lock_file = CliLockfile::discover(
|
||||
sys,
|
||||
&flags,
|
||||
&start_dir.workspace,
|
||||
external_import_map.as_ref().map(|(_, v)| v),
|
||||
maybe_external_import_map.as_ref().map(|v| &v.value),
|
||||
)?;
|
||||
|
||||
log::debug!("Finished config loading.");
|
||||
|
||||
Self::new(
|
||||
sys,
|
||||
flags,
|
||||
initial_cwd,
|
||||
maybe_lock_file.map(Arc::new),
|
||||
npmrc,
|
||||
Arc::new(start_dir),
|
||||
false,
|
||||
external_import_map,
|
||||
)
|
||||
}
|
||||
|
||||
/// This method is purposefully verbose to disourage its use. Do not use it
|
||||
/// except in the factory structs. Instead, prefer specific methods on `CliOptions`
|
||||
/// that can take all sources of information into account (ex. config files or env vars).
|
||||
pub fn into_self_and_flags(
|
||||
self: Arc<CliOptions>,
|
||||
) -> (Arc<CliOptions>, Arc<Flags>) {
|
||||
let flags = self.flags.clone();
|
||||
(self, flags)
|
||||
Self::new(flags, initial_cwd, maybe_lock_file.map(Arc::new), start_dir)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -842,49 +593,7 @@ impl CliOptions {
|
|||
}
|
||||
|
||||
pub fn npm_system_info(&self) -> NpmSystemInfo {
|
||||
match self.sub_command() {
|
||||
DenoSubcommand::Compile(CompileFlags {
|
||||
target: Some(target),
|
||||
..
|
||||
}) => {
|
||||
// the values of NpmSystemInfo align with the possible values for the
|
||||
// `arch` and `platform` fields of Node.js' `process` global:
|
||||
// https://nodejs.org/api/process.html
|
||||
match target.as_str() {
|
||||
"aarch64-apple-darwin" => NpmSystemInfo {
|
||||
os: "darwin".into(),
|
||||
cpu: "arm64".into(),
|
||||
},
|
||||
"aarch64-unknown-linux-gnu" => NpmSystemInfo {
|
||||
os: "linux".into(),
|
||||
cpu: "arm64".into(),
|
||||
},
|
||||
"x86_64-apple-darwin" => NpmSystemInfo {
|
||||
os: "darwin".into(),
|
||||
cpu: "x64".into(),
|
||||
},
|
||||
"x86_64-unknown-linux-gnu" => NpmSystemInfo {
|
||||
os: "linux".into(),
|
||||
cpu: "x64".into(),
|
||||
},
|
||||
"x86_64-pc-windows-msvc" => NpmSystemInfo {
|
||||
os: "win32".into(),
|
||||
cpu: "x64".into(),
|
||||
},
|
||||
value => {
|
||||
log::warn!(
|
||||
concat!(
|
||||
"Not implemented npm system info for target '{}'. Using current ",
|
||||
"system default. This may impact architecture specific dependencies."
|
||||
),
|
||||
value,
|
||||
);
|
||||
NpmSystemInfo::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => NpmSystemInfo::default(),
|
||||
}
|
||||
self.sub_command().npm_system_info()
|
||||
}
|
||||
|
||||
/// Resolve the specifier for a specified import map.
|
||||
|
@ -893,72 +602,12 @@ impl CliOptions {
|
|||
/// happens to be an import map.
|
||||
pub fn resolve_specified_import_map_specifier(
|
||||
&self,
|
||||
) -> Result<Option<ModuleSpecifier>, AnyError> {
|
||||
match self.overrides.import_map_specifier.clone() {
|
||||
Some(maybe_url) => Ok(maybe_url),
|
||||
None => resolve_import_map_specifier(
|
||||
self.flags.import_map_path.as_deref(),
|
||||
self.workspace().root_deno_json().map(|c| c.as_ref()),
|
||||
&self.initial_cwd,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_workspace_resolver(
|
||||
&self,
|
||||
file_fetcher: &CliFileFetcher,
|
||||
pkg_json_dep_resolution: PackageJsonDepResolution,
|
||||
) -> Result<WorkspaceResolver, AnyError> {
|
||||
let overrode_no_import_map: bool = self
|
||||
.overrides
|
||||
.import_map_specifier
|
||||
.as_ref()
|
||||
.map(|s| s.is_none())
|
||||
== Some(true);
|
||||
let cli_arg_specified_import_map = if overrode_no_import_map {
|
||||
// use a fake empty import map
|
||||
Some(deno_config::workspace::SpecifiedImportMap {
|
||||
base_url: self.workspace().root_dir().join("import_map.json").unwrap(),
|
||||
value: serde_json::Value::Object(Default::default()),
|
||||
})
|
||||
} else {
|
||||
let maybe_import_map_specifier =
|
||||
self.resolve_specified_import_map_specifier()?;
|
||||
match maybe_import_map_specifier {
|
||||
Some(specifier) => {
|
||||
let value =
|
||||
resolve_import_map_value_from_specifier(&specifier, file_fetcher)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!("Unable to load '{}' import map", specifier)
|
||||
})?;
|
||||
Some(deno_config::workspace::SpecifiedImportMap {
|
||||
base_url: specifier,
|
||||
value,
|
||||
})
|
||||
}
|
||||
None => {
|
||||
if let Some((path, import_map)) =
|
||||
self.maybe_external_import_map.as_ref()
|
||||
{
|
||||
let path_url = deno_path_util::url_from_file_path(path)?;
|
||||
Some(deno_config::workspace::SpecifiedImportMap {
|
||||
base_url: path_url,
|
||||
value: import_map.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(self.workspace().create_resolver(
|
||||
&CliSys::default(),
|
||||
CreateResolverOptions {
|
||||
pkg_json_dep_resolution,
|
||||
specified_import_map: cli_arg_specified_import_map,
|
||||
},
|
||||
)?)
|
||||
) -> Result<Option<ModuleSpecifier>, ImportMapSpecifierResolveError> {
|
||||
resolve_import_map_specifier(
|
||||
self.flags.import_map_path.as_deref(),
|
||||
self.workspace().root_deno_json().map(|c| c.as_ref()),
|
||||
&self.initial_cwd,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn node_ipc_fd(&self) -> Option<i64> {
|
||||
|
@ -1068,19 +717,6 @@ impl CliOptions {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resolve_npm_resolution_snapshot(
|
||||
&self,
|
||||
) -> Result<Option<ValidSerializedNpmResolutionSnapshot>, AnyError> {
|
||||
if let Some(NpmProcessStateKind::Snapshot(snapshot)) =
|
||||
NPM_PROCESS_STATE.as_ref().map(|s| &s.kind)
|
||||
{
|
||||
// TODO(bartlomieju): remove this clone
|
||||
Ok(Some(snapshot.clone().into_valid()?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_storage_key_resolver(&self) -> StorageKeyResolver {
|
||||
if let Some(location) = &self.flags.location {
|
||||
StorageKeyResolver::from_flag(location)
|
||||
|
@ -1099,14 +735,6 @@ impl CliOptions {
|
|||
NPM_PROCESS_STATE.is_some()
|
||||
}
|
||||
|
||||
pub fn has_node_modules_dir(&self) -> bool {
|
||||
self.maybe_node_modules_folder.is_some()
|
||||
}
|
||||
|
||||
pub fn node_modules_dir_path(&self) -> Option<&PathBuf> {
|
||||
self.maybe_node_modules_folder.as_ref()
|
||||
}
|
||||
|
||||
pub fn node_modules_dir(
|
||||
&self,
|
||||
) -> Result<
|
||||
|
@ -1170,10 +798,6 @@ impl CliOptions {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn npmrc(&self) -> &Arc<ResolvedNpmRc> {
|
||||
&self.npmrc
|
||||
}
|
||||
|
||||
pub fn resolve_fmt_options_for_members(
|
||||
&self,
|
||||
fmt_flags: &FmtFlags,
|
||||
|
@ -1571,41 +1195,6 @@ impl CliOptions {
|
|||
self.workspace().package_jsons().next().is_some() || self.is_node_main()
|
||||
}
|
||||
|
||||
fn byonm_enabled(&self) -> bool {
|
||||
// check if enabled via unstable
|
||||
self.node_modules_dir().ok().flatten() == Some(NodeModulesDirMode::Manual)
|
||||
|| NPM_PROCESS_STATE
|
||||
.as_ref()
|
||||
.map(|s| matches!(s.kind, NpmProcessStateKind::Byonm))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn use_byonm(&self) -> bool {
|
||||
if matches!(
|
||||
self.sub_command(),
|
||||
DenoSubcommand::Install(_)
|
||||
| DenoSubcommand::Add(_)
|
||||
| DenoSubcommand::Remove(_)
|
||||
| DenoSubcommand::Init(_)
|
||||
| DenoSubcommand::Outdated(_)
|
||||
) {
|
||||
// For `deno install/add/remove/init` we want to force the managed resolver so it can set up `node_modules/` directory.
|
||||
return false;
|
||||
}
|
||||
if self.node_modules_dir().ok().flatten().is_none()
|
||||
&& self.maybe_node_modules_folder.is_some()
|
||||
&& self
|
||||
.workspace()
|
||||
.config_folders()
|
||||
.values()
|
||||
.any(|f| f.pkg_json.is_some())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
self.byonm_enabled()
|
||||
}
|
||||
|
||||
pub fn unstable_sloppy_imports(&self) -> bool {
|
||||
self.flags.unstable_config.sloppy_imports
|
||||
|| self.workspace().has_unstable("sloppy-imports")
|
||||
|
@ -1730,63 +1319,6 @@ impl CliOptions {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resolves the path to use for a local node_modules folder.
|
||||
fn resolve_node_modules_folder(
|
||||
cwd: &Path,
|
||||
flags: &Flags,
|
||||
workspace: &Workspace,
|
||||
deno_dir_provider: &Arc<DenoDirProvider>,
|
||||
) -> Result<Option<PathBuf>, AnyError> {
|
||||
fn resolve_from_root(root_folder: &FolderConfigs, cwd: &Path) -> PathBuf {
|
||||
root_folder
|
||||
.deno_json
|
||||
.as_ref()
|
||||
.map(|c| Cow::Owned(c.dir_path()))
|
||||
.or_else(|| {
|
||||
root_folder
|
||||
.pkg_json
|
||||
.as_ref()
|
||||
.map(|c| Cow::Borrowed(c.dir_path()))
|
||||
})
|
||||
.unwrap_or(Cow::Borrowed(cwd))
|
||||
.join("node_modules")
|
||||
}
|
||||
|
||||
let root_folder = workspace.root_folder_configs();
|
||||
let use_node_modules_dir = if let Some(mode) = flags.node_modules_dir {
|
||||
Some(mode.uses_node_modules_dir())
|
||||
} else {
|
||||
workspace
|
||||
.node_modules_dir()?
|
||||
.map(|m| m.uses_node_modules_dir())
|
||||
.or(flags.vendor)
|
||||
.or_else(|| root_folder.deno_json.as_ref().and_then(|c| c.json.vendor))
|
||||
};
|
||||
let path = if use_node_modules_dir == Some(false) {
|
||||
return Ok(None);
|
||||
} else if let Some(state) = &*NPM_PROCESS_STATE {
|
||||
return Ok(state.local_node_modules_path.as_ref().map(PathBuf::from));
|
||||
} else if root_folder.pkg_json.is_some() {
|
||||
let node_modules_dir = resolve_from_root(root_folder, cwd);
|
||||
if let Ok(deno_dir) = deno_dir_provider.get_or_create() {
|
||||
// `deno_dir.root` can be symlink in macOS
|
||||
if let Ok(root) = canonicalize_path_maybe_not_exists(&deno_dir.root) {
|
||||
if node_modules_dir.starts_with(root) {
|
||||
// if the package.json is in deno_dir, then do not use node_modules
|
||||
// next to it as local node_modules dir
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
node_modules_dir
|
||||
} else if use_node_modules_dir.is_none() {
|
||||
return Ok(None);
|
||||
} else {
|
||||
resolve_from_root(root_folder, cwd)
|
||||
};
|
||||
Ok(Some(canonicalize_path_maybe_not_exists(&path)?))
|
||||
}
|
||||
|
||||
fn try_resolve_node_binary_main_entrypoint(
|
||||
specifier: &str,
|
||||
initial_cwd: &Path,
|
||||
|
@ -1817,22 +1349,31 @@ fn try_resolve_node_binary_main_entrypoint(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Bad URL for import map.")]
|
||||
pub struct ImportMapSpecifierResolveError {
|
||||
#[source]
|
||||
source: deno_path_util::ResolveUrlOrPathError,
|
||||
}
|
||||
|
||||
fn resolve_import_map_specifier(
|
||||
maybe_import_map_path: Option<&str>,
|
||||
maybe_config_file: Option<&ConfigFile>,
|
||||
current_dir: &Path,
|
||||
) -> Result<Option<ModuleSpecifier>, AnyError> {
|
||||
) -> Result<Option<Url>, ImportMapSpecifierResolveError> {
|
||||
if let Some(import_map_path) = maybe_import_map_path {
|
||||
if let Some(config_file) = &maybe_config_file {
|
||||
if config_file.json.import_map.is_some() {
|
||||
log::warn!("{} the configuration file \"{}\" contains an entry for \"importMap\" that is being ignored.", colors::yellow("Warning"), config_file.specifier);
|
||||
log::warn!(
|
||||
"{} the configuration file \"{}\" contains an entry for \"importMap\" that is being ignored.",
|
||||
colors::yellow("Warning"),
|
||||
config_file.specifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
let specifier =
|
||||
deno_core::resolve_url_or_path(import_map_path, current_dir)
|
||||
.with_context(|| {
|
||||
format!("Bad URL (\"{import_map_path}\") for import map.")
|
||||
})?;
|
||||
deno_path_util::resolve_url_or_path(import_map_path, current_dir)
|
||||
.map_err(|source| ImportMapSpecifierResolveError { source })?;
|
||||
Ok(Some(specifier))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -1873,9 +1414,9 @@ fn load_env_variables_from_env_file(filename: Option<&Vec<String>>) {
|
|||
Ok(_) => (),
|
||||
Err(error) => {
|
||||
match error {
|
||||
dotenvy::Error::LineParse(line, index)=> log::info!("{} Parsing failed within the specified environment file: {} at index: {} of the value: {}",colors::yellow("Warning"), env_file_name, index, line),
|
||||
dotenvy::Error::Io(_)=> log::info!("{} The `--env-file` flag was used, but the environment file specified '{}' was not found.",colors::yellow("Warning"),env_file_name),
|
||||
dotenvy::Error::EnvVar(_)=> log::info!("{} One or more of the environment variables isn't present or not unicode within the specified environment file: {}",colors::yellow("Warning"),env_file_name),
|
||||
dotenvy::Error::LineParse(line, index)=> log::info!("{} Parsing failed within the specified environment file: {} at index: {} of the value: {}", colors::yellow("Warning"), env_file_name, index, line),
|
||||
dotenvy::Error::Io(_)=> log::info!("{} The `--env-file` flag was used, but the environment file specified '{}' was not found.", colors::yellow("Warning"), env_file_name),
|
||||
dotenvy::Error::EnvVar(_)=> log::info!("{} One or more of the environment variables isn't present or not unicode within the specified environment file: {}", colors::yellow("Warning"), env_file_name),
|
||||
_ => log::info!("{} Unknown failure occurred with the specified environment file: {}", colors::yellow("Warning"), env_file_name),
|
||||
}
|
||||
}
|
||||
|
@ -1916,8 +1457,7 @@ mod test {
|
|||
"importMap": "import_map.json"
|
||||
}"#;
|
||||
let cwd = &std::env::current_dir().unwrap();
|
||||
let config_specifier =
|
||||
ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap();
|
||||
let config_specifier = Url::parse("file:///deno/deno.jsonc").unwrap();
|
||||
let config_file = ConfigFile::new(config_text, config_specifier).unwrap();
|
||||
let actual = resolve_import_map_specifier(
|
||||
Some("import-map.json"),
|
||||
|
@ -1926,7 +1466,7 @@ mod test {
|
|||
);
|
||||
let import_map_path = cwd.join("import-map.json");
|
||||
let expected_specifier =
|
||||
ModuleSpecifier::from_file_path(import_map_path).unwrap();
|
||||
deno_path_util::url_from_file_path(&import_map_path).unwrap();
|
||||
assert!(actual.is_ok());
|
||||
let actual = actual.unwrap();
|
||||
assert_eq!(actual, Some(expected_specifier));
|
||||
|
@ -1935,8 +1475,7 @@ mod test {
|
|||
#[test]
|
||||
fn resolve_import_map_none() {
|
||||
let config_text = r#"{}"#;
|
||||
let config_specifier =
|
||||
ModuleSpecifier::parse("file:///deno/deno.jsonc").unwrap();
|
||||
let config_specifier = Url::parse("file:///deno/deno.jsonc").unwrap();
|
||||
let config_file = ConfigFile::new(config_text, config_specifier).unwrap();
|
||||
let actual = resolve_import_map_specifier(
|
||||
None,
|
||||
|
|
50
cli/cache/deno_dir.rs
vendored
50
cli/cache/deno_dir.rs
vendored
|
@ -2,46 +2,39 @@
|
|||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_cache_dir::DenoDirResolutionError;
|
||||
|
||||
use super::DiskCache;
|
||||
use crate::factory::CliDenoDirPathProvider;
|
||||
use crate::sys::CliSys;
|
||||
|
||||
/// Lazily creates the deno dir which might be useful in scenarios
|
||||
/// where functionality wants to continue if the DENO_DIR can't be created.
|
||||
pub struct DenoDirProvider {
|
||||
deno_dir_path_provider: Arc<CliDenoDirPathProvider>,
|
||||
sys: CliSys,
|
||||
maybe_custom_root: Option<PathBuf>,
|
||||
deno_dir: std::sync::OnceLock<Result<DenoDir, DenoDirResolutionError>>,
|
||||
deno_dir: once_cell::sync::OnceCell<DenoDir>,
|
||||
}
|
||||
|
||||
impl DenoDirProvider {
|
||||
pub fn new(sys: CliSys, maybe_custom_root: Option<PathBuf>) -> Self {
|
||||
pub fn new(
|
||||
sys: CliSys,
|
||||
deno_dir_path_provider: Arc<CliDenoDirPathProvider>,
|
||||
) -> Self {
|
||||
Self {
|
||||
sys,
|
||||
maybe_custom_root,
|
||||
deno_dir_path_provider,
|
||||
deno_dir: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_create(&self) -> Result<&DenoDir, DenoDirResolutionError> {
|
||||
self
|
||||
.deno_dir
|
||||
.get_or_init(|| {
|
||||
DenoDir::new(self.sys.clone(), self.maybe_custom_root.clone())
|
||||
})
|
||||
.as_ref()
|
||||
.map_err(|err| match err {
|
||||
DenoDirResolutionError::NoCacheOrHomeDir => {
|
||||
DenoDirResolutionError::NoCacheOrHomeDir
|
||||
}
|
||||
DenoDirResolutionError::FailedCwd { source } => {
|
||||
DenoDirResolutionError::FailedCwd {
|
||||
source: std::io::Error::new(source.kind(), source.to_string()),
|
||||
}
|
||||
}
|
||||
})
|
||||
self.deno_dir.get_or_try_init(|| {
|
||||
let path = self.deno_dir_path_provider.get_or_create()?;
|
||||
Ok(DenoDir::new(self.sys.clone(), path.clone()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,23 +49,14 @@ pub struct DenoDir {
|
|||
}
|
||||
|
||||
impl DenoDir {
|
||||
pub fn new(
|
||||
sys: CliSys,
|
||||
maybe_custom_root: Option<PathBuf>,
|
||||
) -> Result<Self, deno_cache_dir::DenoDirResolutionError> {
|
||||
let root = deno_cache_dir::resolve_deno_dir(
|
||||
&sys_traits::impls::RealSys,
|
||||
maybe_custom_root,
|
||||
)?;
|
||||
pub fn new(sys: CliSys, root: PathBuf) -> Self {
|
||||
assert!(root.is_absolute());
|
||||
let gen_path = root.join("gen");
|
||||
|
||||
let deno_dir = Self {
|
||||
Self {
|
||||
root,
|
||||
gen_cache: DiskCache::new(sys, &gen_path),
|
||||
};
|
||||
|
||||
Ok(deno_dir)
|
||||
gen_cache: DiskCache::new(sys, gen_path),
|
||||
}
|
||||
}
|
||||
|
||||
/// The root directory of the DENO_DIR for display purposes only.
|
||||
|
|
19
cli/cache/disk_cache.rs
vendored
19
cli/cache/disk_cache.rs
vendored
|
@ -1,7 +1,6 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -13,6 +12,7 @@ use deno_cache_dir::CACHE_PERM;
|
|||
use deno_core::url::Host;
|
||||
use deno_core::url::Url;
|
||||
use deno_path_util::fs::atomic_write_file_with_retries;
|
||||
use sys_traits::FsRead;
|
||||
|
||||
use crate::sys::CliSys;
|
||||
|
||||
|
@ -24,12 +24,9 @@ pub struct DiskCache {
|
|||
|
||||
impl DiskCache {
|
||||
/// `location` must be an absolute path.
|
||||
pub fn new(sys: CliSys, location: &Path) -> Self {
|
||||
pub fn new(sys: CliSys, location: PathBuf) -> Self {
|
||||
assert!(location.is_absolute());
|
||||
Self {
|
||||
sys,
|
||||
location: location.to_owned(),
|
||||
}
|
||||
Self { sys, location }
|
||||
}
|
||||
|
||||
fn get_cache_filename(&self, url: &Url) -> Option<PathBuf> {
|
||||
|
@ -119,7 +116,7 @@ impl DiskCache {
|
|||
|
||||
pub fn get(&self, filename: &Path) -> std::io::Result<Vec<u8>> {
|
||||
let path = self.location.join(filename);
|
||||
fs::read(path)
|
||||
Ok(self.sys.fs_read(path)?.into_owned())
|
||||
}
|
||||
|
||||
pub fn set(&self, filename: &Path, data: &[u8]) -> std::io::Result<()> {
|
||||
|
@ -141,7 +138,7 @@ mod tests {
|
|||
fn test_set_get_cache_file() {
|
||||
let temp_dir = TempDir::new();
|
||||
let sub_dir = temp_dir.path().join("sub_dir");
|
||||
let cache = DiskCache::new(RealSys, &sub_dir.to_path_buf());
|
||||
let cache = DiskCache::new(RealSys, sub_dir.to_path_buf());
|
||||
let path = PathBuf::from("foo/bar.txt");
|
||||
cache.set(&path, b"hello").unwrap();
|
||||
assert_eq!(cache.get(&path).unwrap(), b"hello");
|
||||
|
@ -155,7 +152,7 @@ mod tests {
|
|||
PathBuf::from("/deno_dir/")
|
||||
};
|
||||
|
||||
let cache = DiskCache::new(RealSys, &cache_location);
|
||||
let cache = DiskCache::new(RealSys, cache_location);
|
||||
|
||||
let mut test_cases = vec![
|
||||
(
|
||||
|
@ -211,7 +208,7 @@ mod tests {
|
|||
} else {
|
||||
"/foo"
|
||||
};
|
||||
let cache = DiskCache::new(RealSys, &PathBuf::from(p));
|
||||
let cache = DiskCache::new(RealSys, PathBuf::from(p));
|
||||
|
||||
let mut test_cases = vec![
|
||||
(
|
||||
|
@ -259,7 +256,7 @@ mod tests {
|
|||
PathBuf::from("/deno_dir/")
|
||||
};
|
||||
|
||||
let cache = DiskCache::new(RealSys, &cache_location);
|
||||
let cache = DiskCache::new(RealSys, cache_location);
|
||||
|
||||
let mut test_cases = vec!["unknown://localhost/test.ts"];
|
||||
|
||||
|
|
2
cli/cache/emit.rs
vendored
2
cli/cache/emit.rs
vendored
|
@ -167,7 +167,7 @@ mod test {
|
|||
pub fn emit_cache_general_use() {
|
||||
let temp_dir = TempDir::new();
|
||||
let disk_cache =
|
||||
DiskCache::new(CliSys::default(), temp_dir.path().as_path());
|
||||
DiskCache::new(CliSys::default(), temp_dir.path().to_path_buf());
|
||||
let cache = EmitCache {
|
||||
disk_cache: disk_cache.clone(),
|
||||
file_serializer: EmitFileSerializer {
|
||||
|
|
7
cli/cache/mod.rs
vendored
7
cli/cache/mod.rs
vendored
|
@ -57,7 +57,6 @@ pub use parsed_source::LazyGraphSourceParser;
|
|||
pub use parsed_source::ParsedSourceCache;
|
||||
|
||||
pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache<CliSys>;
|
||||
pub type LocalHttpCache = deno_cache_dir::LocalHttpCache<CliSys>;
|
||||
pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache<CliSys>;
|
||||
pub use deno_cache_dir::HttpCache;
|
||||
use deno_error::JsErrorBox;
|
||||
|
@ -120,11 +119,7 @@ impl FetchCacher {
|
|||
} else if specifier.scheme() == "file" {
|
||||
specifier.to_file_path().ok()
|
||||
} else {
|
||||
#[allow(deprecated)]
|
||||
self
|
||||
.global_http_cache
|
||||
.get_global_cache_filepath(specifier)
|
||||
.ok()
|
||||
self.global_http_cache.local_path_for_url(specifier).ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
597
cli/factory.rs
597
cli/factory.rs
|
@ -1,37 +1,44 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::future::Future;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_config::workspace::PackageJsonDepResolution;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::FeatureChecker;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_lib::args::get_root_cert_store;
|
||||
use deno_lib::args::resolve_npm_resolution_snapshot;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::args::NpmProcessStateKind;
|
||||
use deno_lib::args::NPM_PROCESS_STATE;
|
||||
use deno_lib::loader::NpmModuleLoader;
|
||||
use deno_lib::npm::create_npm_process_state_provider;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionChecker;
|
||||
use deno_lib::npm::NpmRegistryReadPermissionCheckerMode;
|
||||
use deno_lib::worker::LibMainWorkerFactory;
|
||||
use deno_lib::worker::LibMainWorkerOptions;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm_cache::NpmCacheSetting;
|
||||
use deno_resolver::cjs::IsCjsResolutionMode;
|
||||
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
|
||||
use deno_resolver::factory::ConfigDiscoveryOption;
|
||||
use deno_resolver::factory::DenoDirPathProviderOptions;
|
||||
use deno_resolver::factory::NpmProcessStateOptions;
|
||||
use deno_resolver::factory::ResolverFactoryOptions;
|
||||
use deno_resolver::factory::SpecifiedImportMapProvider;
|
||||
use deno_resolver::npm::managed::NpmResolutionCell;
|
||||
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::npm::NpmReqResolverOptions;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
|
||||
use deno_resolver::DenoResolverOptions;
|
||||
use deno_resolver::NodeAndNpmReqResolver;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_fs::RealFs;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
|
@ -39,16 +46,18 @@ use deno_runtime::deno_tls::RootCertStoreProvider;
|
|||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use log::warn;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use once_cell::sync::OnceCell;
|
||||
use sys_traits::EnvCurrentDir;
|
||||
|
||||
use crate::args::check_warn_tsconfig;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::ConfigFlag;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::Flags;
|
||||
use crate::args::NpmInstallDepsProvider;
|
||||
use crate::args::TsConfigType;
|
||||
use crate::args::WorkspaceExternalImportMapLoader;
|
||||
use crate::cache::Caches;
|
||||
use crate::cache::CodeCache;
|
||||
use crate::cache::DenoDir;
|
||||
|
@ -56,12 +65,12 @@ use crate::cache::DenoDirProvider;
|
|||
use crate::cache::EmitCache;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
use crate::cache::HttpCache;
|
||||
use crate::cache::LocalHttpCache;
|
||||
use crate::cache::ModuleInfoCache;
|
||||
use crate::cache::NodeAnalysisCache;
|
||||
use crate::cache::ParsedSourceCache;
|
||||
use crate::emit::Emitter;
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::file_fetcher::TextDecodedFile;
|
||||
use crate::graph_container::MainModuleGraphContainer;
|
||||
use crate::graph_util::FileWatcherReporter;
|
||||
use crate::graph_util::ModuleGraphBuilder;
|
||||
|
@ -75,13 +84,10 @@ use crate::node::CliNodeResolver;
|
|||
use crate::node::CliPackageJsonResolver;
|
||||
use crate::npm::installer::NpmInstaller;
|
||||
use crate::npm::installer::NpmResolutionInstaller;
|
||||
use crate::npm::CliByonmNpmResolverCreateOptions;
|
||||
use crate::npm::CliManagedNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmCache;
|
||||
use crate::npm::CliNpmCacheHttpClient;
|
||||
use crate::npm::CliNpmRegistryInfoProvider;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::CliNpmTarballCache;
|
||||
use crate::npm::NpmResolutionInitializer;
|
||||
|
@ -100,7 +106,6 @@ use crate::tools::lint::LintRuleProvider;
|
|||
use crate::tools::run::hmr::HmrRunner;
|
||||
use crate::tsc::TypeCheckingCjsTracker;
|
||||
use crate::util::file_watcher::WatcherCommunicator;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
use crate::worker::CliMainWorkerFactory;
|
||||
|
@ -143,6 +148,74 @@ impl RootCertStoreProvider for CliRootCertStoreProvider {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CliSpecifiedImportMapProvider {
|
||||
cli_options: Arc<CliOptions>,
|
||||
file_fetcher: Arc<CliFileFetcher>,
|
||||
workspace_external_import_map_loader: Arc<WorkspaceExternalImportMapLoader>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl SpecifiedImportMapProvider for CliSpecifiedImportMapProvider {
|
||||
async fn get(
|
||||
&self,
|
||||
) -> Result<Option<deno_config::workspace::SpecifiedImportMap>, AnyError> {
|
||||
async fn resolve_import_map_value_from_specifier(
|
||||
specifier: &Url,
|
||||
file_fetcher: &CliFileFetcher,
|
||||
) -> Result<serde_json::Value, AnyError> {
|
||||
if specifier.scheme() == "data" {
|
||||
let data_url_text =
|
||||
deno_media_type::data_url::RawDataUrl::parse(specifier)?.decode()?;
|
||||
Ok(serde_json::from_str(&data_url_text)?)
|
||||
} else {
|
||||
let file = TextDecodedFile::decode(
|
||||
file_fetcher.fetch_bypass_permissions(specifier).await?,
|
||||
)?;
|
||||
Ok(serde_json::from_str(&file.source)?)
|
||||
}
|
||||
}
|
||||
|
||||
let maybe_import_map_specifier =
|
||||
self.cli_options.resolve_specified_import_map_specifier()?;
|
||||
match maybe_import_map_specifier {
|
||||
Some(specifier) => {
|
||||
let value = resolve_import_map_value_from_specifier(
|
||||
&specifier,
|
||||
&self.file_fetcher,
|
||||
)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!("Unable to load '{}' import map", specifier)
|
||||
})?;
|
||||
Ok(Some(deno_config::workspace::SpecifiedImportMap {
|
||||
base_url: specifier,
|
||||
value,
|
||||
}))
|
||||
}
|
||||
None => {
|
||||
if let Some(import_map) =
|
||||
self.workspace_external_import_map_loader.get_or_load()?
|
||||
{
|
||||
let path_url = deno_path_util::url_from_file_path(&import_map.path)?;
|
||||
Ok(Some(deno_config::workspace::SpecifiedImportMap {
|
||||
base_url: path_url,
|
||||
value: import_map.value.clone(),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type CliWorkspaceFactory = deno_resolver::factory::WorkspaceFactory<CliSys>;
|
||||
pub type CliDenoDirPathProvider =
|
||||
deno_resolver::factory::DenoDirPathProvider<CliSys>;
|
||||
|
||||
pub type CliResolverFactory = deno_resolver::factory::ResolverFactory<CliSys>;
|
||||
|
||||
pub struct Deferred<T>(once_cell::unsync::OnceCell<T>);
|
||||
|
||||
impl<T> Default for Deferred<T> {
|
||||
|
@ -152,10 +225,6 @@ impl<T> Default for Deferred<T> {
|
|||
}
|
||||
|
||||
impl<T> Deferred<T> {
|
||||
pub fn from_value(value: T) -> Self {
|
||||
Self(once_cell::unsync::OnceCell::from(value))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_or_try_init(
|
||||
&self,
|
||||
|
@ -194,17 +263,15 @@ struct CliFactoryServices {
|
|||
cjs_tracker: Deferred<Arc<CliCjsTracker>>,
|
||||
cli_options: Deferred<Arc<CliOptions>>,
|
||||
code_cache: Deferred<Arc<CodeCache>>,
|
||||
deno_resolver: Deferred<Arc<CliDenoResolver>>,
|
||||
deno_dir_path_provider: Deferred<Arc<CliDenoDirPathProvider>>,
|
||||
deno_dir_provider: Deferred<Arc<DenoDirProvider>>,
|
||||
emit_cache: Deferred<Arc<EmitCache>>,
|
||||
emitter: Deferred<Arc<Emitter>>,
|
||||
feature_checker: Deferred<Arc<FeatureChecker>>,
|
||||
file_fetcher: Deferred<Arc<CliFileFetcher>>,
|
||||
found_pkg_json_dep_flag: Arc<FoundPackageJsonDepFlag>,
|
||||
fs: Deferred<Arc<dyn deno_fs::FileSystem>>,
|
||||
global_http_cache: Deferred<Arc<GlobalHttpCache>>,
|
||||
http_cache: Deferred<Arc<dyn HttpCache>>,
|
||||
http_client_provider: Deferred<Arc<HttpClientProvider>>,
|
||||
in_npm_pkg_checker: Deferred<DenoInNpmPackageChecker>,
|
||||
main_graph_container: Deferred<Arc<MainModuleGraphContainer>>,
|
||||
maybe_file_watcher_reporter: Deferred<Option<FileWatcherReporter>>,
|
||||
maybe_inspector_server: Deferred<Option<Arc<InspectorServer>>>,
|
||||
|
@ -213,36 +280,39 @@ struct CliFactoryServices {
|
|||
module_info_cache: Deferred<Arc<ModuleInfoCache>>,
|
||||
module_load_preparer: Deferred<Arc<ModuleLoadPreparer>>,
|
||||
node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>,
|
||||
node_resolver: Deferred<Arc<CliNodeResolver>>,
|
||||
npm_cache: Deferred<Arc<CliNpmCache>>,
|
||||
npm_cache_dir: Deferred<Arc<NpmCacheDir>>,
|
||||
npm_cache_http_client: Deferred<Arc<CliNpmCacheHttpClient>>,
|
||||
npm_graph_resolver: Deferred<Arc<CliNpmGraphResolver>>,
|
||||
npm_installer: Deferred<Arc<NpmInstaller>>,
|
||||
npm_registry_info_provider: Deferred<Arc<CliNpmRegistryInfoProvider>>,
|
||||
npm_req_resolver: Deferred<Arc<CliNpmReqResolver>>,
|
||||
npm_resolution: Arc<NpmResolutionCell>,
|
||||
npm_resolution_initializer: Deferred<Arc<NpmResolutionInitializer>>,
|
||||
npm_resolution_installer: Deferred<Arc<NpmResolutionInstaller>>,
|
||||
npm_resolver: Deferred<CliNpmResolver>,
|
||||
npm_tarball_cache: Deferred<Arc<CliNpmTarballCache>>,
|
||||
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
|
||||
permission_desc_parser:
|
||||
Deferred<Arc<RuntimePermissionDescriptorParser<CliSys>>>,
|
||||
pkg_json_resolver: Deferred<Arc<CliPackageJsonResolver>>,
|
||||
resolver: Deferred<Arc<CliResolver>>,
|
||||
resolver_factory: Deferred<Arc<CliResolverFactory>>,
|
||||
root_cert_store_provider: Deferred<Arc<dyn RootCertStoreProvider>>,
|
||||
root_permissions_container: Deferred<PermissionsContainer>,
|
||||
sloppy_imports_resolver: Deferred<Option<Arc<CliSloppyImportsResolver>>>,
|
||||
text_only_progress_bar: Deferred<ProgressBar>,
|
||||
type_checker: Deferred<Arc<TypeChecker>>,
|
||||
workspace_resolver: Deferred<Arc<WorkspaceResolver>>,
|
||||
workspace_factory: Deferred<Arc<CliWorkspaceFactory>>,
|
||||
workspace_external_import_map_loader:
|
||||
Deferred<Arc<WorkspaceExternalImportMapLoader>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct CliFactoryOverrides {
|
||||
initial_cwd: Option<PathBuf>,
|
||||
workspace_directory: Option<Arc<WorkspaceDirectory>>,
|
||||
}
|
||||
|
||||
pub struct CliFactory {
|
||||
watcher_communicator: Option<Arc<WatcherCommunicator>>,
|
||||
flags: Arc<Flags>,
|
||||
services: CliFactoryServices,
|
||||
overrides: CliFactoryOverrides,
|
||||
}
|
||||
|
||||
impl CliFactory {
|
||||
|
@ -251,18 +321,7 @@ impl CliFactory {
|
|||
flags,
|
||||
watcher_communicator: None,
|
||||
services: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_cli_options(cli_options: Arc<CliOptions>) -> Self {
|
||||
let (cli_options, flags) = cli_options.into_self_and_flags();
|
||||
CliFactory {
|
||||
watcher_communicator: None,
|
||||
flags,
|
||||
services: CliFactoryServices {
|
||||
cli_options: Deferred::from_value(cli_options),
|
||||
..Default::default()
|
||||
},
|
||||
overrides: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,27 +333,63 @@ impl CliFactory {
|
|||
watcher_communicator: Some(watcher_communicator),
|
||||
flags,
|
||||
services: Default::default(),
|
||||
overrides: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_initial_cwd(&mut self, initial_cwd: PathBuf) {
|
||||
self.overrides.initial_cwd = Some(initial_cwd);
|
||||
}
|
||||
|
||||
pub fn set_workspace_dir(&mut self, dir: Arc<WorkspaceDirectory>) {
|
||||
self.overrides.workspace_directory = Some(dir);
|
||||
}
|
||||
|
||||
pub fn cli_options(&self) -> Result<&Arc<CliOptions>, AnyError> {
|
||||
self.services.cli_options.get_or_try_init(|| {
|
||||
CliOptions::from_flags(&self.sys(), self.flags.clone()).map(Arc::new)
|
||||
let workspace_factory = self.workspace_factory()?;
|
||||
let workspace_directory = workspace_factory.workspace_directory()?;
|
||||
let maybe_external_import_map =
|
||||
self.workspace_external_import_map_loader()?.get_or_load()?;
|
||||
CliOptions::from_flags(
|
||||
&self.sys(),
|
||||
self.flags.clone(),
|
||||
workspace_factory.initial_cwd().clone(),
|
||||
maybe_external_import_map,
|
||||
workspace_directory.clone(),
|
||||
)
|
||||
.map(Arc::new)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn deno_dir_provider(&self) -> Result<&Arc<DenoDirProvider>, AnyError> {
|
||||
Ok(&self.cli_options()?.deno_dir_provider)
|
||||
pub fn deno_dir_path_provider(&self) -> &Arc<CliDenoDirPathProvider> {
|
||||
self.services.deno_dir_path_provider.get_or_init(|| {
|
||||
Arc::new(CliDenoDirPathProvider::new(
|
||||
self.sys(),
|
||||
DenoDirPathProviderOptions {
|
||||
maybe_custom_root: self.flags.internal.cache_path.clone(),
|
||||
},
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn deno_dir_provider(&self) -> &Arc<DenoDirProvider> {
|
||||
self.services.deno_dir_provider.get_or_init(|| {
|
||||
Arc::new(DenoDirProvider::new(
|
||||
self.sys(),
|
||||
self.deno_dir_path_provider().clone(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn deno_dir(&self) -> Result<&DenoDir, AnyError> {
|
||||
Ok(self.deno_dir_provider()?.get_or_create()?)
|
||||
Ok(self.deno_dir_provider().get_or_create()?)
|
||||
}
|
||||
|
||||
pub fn caches(&self) -> Result<&Arc<Caches>, AnyError> {
|
||||
self.services.caches.get_or_try_init(|| {
|
||||
let cli_options = self.cli_options()?;
|
||||
let caches = Arc::new(Caches::new(self.deno_dir_provider()?.clone()));
|
||||
let caches = Arc::new(Caches::new(self.deno_dir_provider().clone()));
|
||||
// Warm up the caches we know we'll likely need based on the CLI mode
|
||||
match cli_options.sub_command() {
|
||||
DenoSubcommand::Run(_)
|
||||
|
@ -340,29 +435,11 @@ impl CliFactory {
|
|||
}
|
||||
|
||||
pub fn global_http_cache(&self) -> Result<&Arc<GlobalHttpCache>, AnyError> {
|
||||
self.services.global_http_cache.get_or_try_init(|| {
|
||||
Ok(Arc::new(GlobalHttpCache::new(
|
||||
self.sys(),
|
||||
self.deno_dir()?.remote_folder_path(),
|
||||
)))
|
||||
})
|
||||
Ok(self.workspace_factory()?.global_http_cache()?)
|
||||
}
|
||||
|
||||
pub fn http_cache(&self) -> Result<&Arc<dyn HttpCache>, AnyError> {
|
||||
self.services.http_cache.get_or_try_init(|| {
|
||||
let global_cache = self.global_http_cache()?.clone();
|
||||
match self.cli_options()?.vendor_dir_path() {
|
||||
Some(local_path) => {
|
||||
let local_cache = LocalHttpCache::new(
|
||||
local_path.clone(),
|
||||
global_cache,
|
||||
deno_cache_dir::GlobalToLocalCopy::Allow,
|
||||
);
|
||||
Ok(Arc::new(local_cache))
|
||||
}
|
||||
None => Ok(global_cache),
|
||||
}
|
||||
})
|
||||
Ok(self.workspace_factory()?.http_cache()?)
|
||||
}
|
||||
|
||||
pub fn http_client_provider(&self) -> &Arc<HttpClientProvider> {
|
||||
|
@ -401,22 +478,7 @@ impl CliFactory {
|
|||
pub fn in_npm_pkg_checker(
|
||||
&self,
|
||||
) -> Result<&DenoInNpmPackageChecker, AnyError> {
|
||||
self.services.in_npm_pkg_checker.get_or_try_init(|| {
|
||||
let cli_options = self.cli_options()?;
|
||||
let options = if cli_options.use_byonm() {
|
||||
CreateInNpmPkgCheckerOptions::Byonm
|
||||
} else {
|
||||
CreateInNpmPkgCheckerOptions::Managed(
|
||||
ManagedInNpmPkgCheckerCreateOptions {
|
||||
root_cache_dir_url: self.npm_cache_dir()?.root_dir_url(),
|
||||
maybe_node_modules_path: cli_options
|
||||
.node_modules_dir_path()
|
||||
.map(|p| p.as_path()),
|
||||
},
|
||||
)
|
||||
};
|
||||
Ok(DenoInNpmPackageChecker::new(options))
|
||||
})
|
||||
self.resolver_factory()?.in_npm_package_checker()
|
||||
}
|
||||
|
||||
pub fn npm_cache(&self) -> Result<&Arc<CliNpmCache>, AnyError> {
|
||||
|
@ -426,21 +488,13 @@ impl CliFactory {
|
|||
self.npm_cache_dir()?.clone(),
|
||||
self.sys(),
|
||||
NpmCacheSetting::from_cache_setting(&cli_options.cache_setting()),
|
||||
cli_options.npmrc().clone(),
|
||||
self.npmrc()?.clone(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npm_cache_dir(&self) -> Result<&Arc<NpmCacheDir>, AnyError> {
|
||||
self.services.npm_cache_dir.get_or_try_init(|| {
|
||||
let global_path = self.deno_dir()?.npm_folder_path();
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(NpmCacheDir::new(
|
||||
&self.sys(),
|
||||
global_path,
|
||||
cli_options.npmrc().get_all_known_registries_urls(),
|
||||
)))
|
||||
})
|
||||
Ok(self.workspace_factory()?.npm_cache_dir()?)
|
||||
}
|
||||
|
||||
pub fn npm_cache_http_client(&self) -> &Arc<CliNpmCacheHttpClient> {
|
||||
|
@ -469,8 +523,7 @@ impl CliFactory {
|
|||
pub fn npm_installer_if_managed(
|
||||
&self,
|
||||
) -> Result<Option<&Arc<NpmInstaller>>, AnyError> {
|
||||
let options = self.cli_options()?;
|
||||
if options.use_byonm() || options.no_npm() {
|
||||
if self.resolver_factory()?.use_byonm()? || self.cli_options()?.no_npm() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(self.npm_installer()?))
|
||||
|
@ -480,19 +533,22 @@ impl CliFactory {
|
|||
pub fn npm_installer(&self) -> Result<&Arc<NpmInstaller>, AnyError> {
|
||||
self.services.npm_installer.get_or_try_init(|| {
|
||||
let cli_options = self.cli_options()?;
|
||||
let workspace_factory = self.workspace_factory()?;
|
||||
Ok(Arc::new(NpmInstaller::new(
|
||||
self.npm_cache()?.clone(),
|
||||
Arc::new(NpmInstallDepsProvider::from_workspace(
|
||||
cli_options.workspace(),
|
||||
)),
|
||||
self.npm_resolution().clone(),
|
||||
self.npm_resolution()?.clone(),
|
||||
self.npm_resolution_initializer()?.clone(),
|
||||
self.npm_resolution_installer()?.clone(),
|
||||
self.text_only_progress_bar(),
|
||||
self.sys(),
|
||||
self.npm_tarball_cache()?.clone(),
|
||||
cli_options.maybe_lockfile().cloned(),
|
||||
cli_options.node_modules_dir_path().cloned(),
|
||||
workspace_factory
|
||||
.node_modules_dir_path()?
|
||||
.map(|p| p.to_path_buf()),
|
||||
cli_options.lifecycle_scripts_config(),
|
||||
cli_options.npm_system_info(),
|
||||
)))
|
||||
|
@ -506,17 +562,16 @@ impl CliFactory {
|
|||
.services
|
||||
.npm_registry_info_provider
|
||||
.get_or_try_init(|| {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(CliNpmRegistryInfoProvider::new(
|
||||
self.npm_cache()?.clone(),
|
||||
self.npm_cache_http_client().clone(),
|
||||
cli_options.npmrc().clone(),
|
||||
self.npmrc()?.clone(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npm_resolution(&self) -> &Arc<NpmResolutionCell> {
|
||||
&self.services.npm_resolution
|
||||
pub fn npm_resolution(&self) -> Result<&Arc<NpmResolutionCell>, AnyError> {
|
||||
Ok(self.resolver_factory()?.npm_resolution())
|
||||
}
|
||||
|
||||
pub fn npm_resolution_initializer(
|
||||
|
@ -529,8 +584,8 @@ impl CliFactory {
|
|||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(NpmResolutionInitializer::new(
|
||||
self.npm_registry_info_provider()?.clone(),
|
||||
self.npm_resolution().clone(),
|
||||
match cli_options.resolve_npm_resolution_snapshot()? {
|
||||
self.npm_resolution()?.clone(),
|
||||
match resolve_npm_resolution_snapshot()? {
|
||||
Some(snapshot) => {
|
||||
CliNpmResolverManagedSnapshotOption::Specified(Some(snapshot))
|
||||
}
|
||||
|
@ -554,71 +609,59 @@ impl CliFactory {
|
|||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(NpmResolutionInstaller::new(
|
||||
self.npm_registry_info_provider()?.clone(),
|
||||
self.npm_resolution().clone(),
|
||||
self.npm_resolution()?.clone(),
|
||||
cli_options.maybe_lockfile().cloned(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn npm_resolver(&self) -> Result<&CliNpmResolver, AnyError> {
|
||||
self
|
||||
.services
|
||||
.npm_resolver
|
||||
.get_or_try_init_async(
|
||||
async {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(CliNpmResolver::new(if cli_options.use_byonm() {
|
||||
CliNpmResolverCreateOptions::Byonm(
|
||||
CliByonmNpmResolverCreateOptions {
|
||||
sys: self.sys(),
|
||||
pkg_json_resolver: self.pkg_json_resolver().clone(),
|
||||
root_node_modules_dir: Some(
|
||||
match cli_options.node_modules_dir_path() {
|
||||
Some(node_modules_path) => node_modules_path.to_path_buf(),
|
||||
// path needs to be canonicalized for node resolution
|
||||
// (node_modules_dir_path above is already canonicalized)
|
||||
None => canonicalize_path_maybe_not_exists(
|
||||
cli_options.initial_cwd(),
|
||||
)?
|
||||
.join("node_modules"),
|
||||
},
|
||||
),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
self
|
||||
.npm_resolution_initializer()?
|
||||
.ensure_initialized()
|
||||
.await?;
|
||||
CliNpmResolverCreateOptions::Managed(
|
||||
CliManagedNpmResolverCreateOptions {
|
||||
sys: self.sys(),
|
||||
npm_resolution: self.npm_resolution().clone(),
|
||||
npm_cache_dir: self.npm_cache_dir()?.clone(),
|
||||
maybe_node_modules_path: cli_options
|
||||
.node_modules_dir_path()
|
||||
.cloned(),
|
||||
npm_system_info: cli_options.npm_system_info(),
|
||||
npmrc: cli_options.npmrc().clone(),
|
||||
},
|
||||
)
|
||||
}))
|
||||
}
|
||||
.boxed_local(),
|
||||
)
|
||||
.await
|
||||
self.initialize_npm_resolution_if_managed().await?;
|
||||
self.resolver_factory()?.npm_resolver()
|
||||
}
|
||||
|
||||
pub fn npm_tarball_cache(
|
||||
&self,
|
||||
) -> Result<&Arc<CliNpmTarballCache>, AnyError> {
|
||||
self.services.npm_tarball_cache.get_or_try_init(|| {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(CliNpmTarballCache::new(
|
||||
self.npm_cache()?.clone(),
|
||||
self.npm_cache_http_client().clone(),
|
||||
self.sys(),
|
||||
cli_options.npmrc().clone(),
|
||||
self.npmrc()?.clone(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npmrc(&self) -> Result<&Arc<ResolvedNpmRc>, AnyError> {
|
||||
Ok(self.workspace_factory()?.npmrc()?)
|
||||
}
|
||||
|
||||
pub fn resolver_factory(&self) -> Result<&Arc<CliResolverFactory>, AnyError> {
|
||||
self.services.resolver_factory.get_or_try_init(|| {
|
||||
Ok(Arc::new(CliResolverFactory::new(
|
||||
self.workspace_factory()?.clone(),
|
||||
ResolverFactoryOptions {
|
||||
conditions_from_resolution_mode: Default::default(),
|
||||
no_sloppy_imports_cache: false,
|
||||
npm_system_info: self.flags.subcommand.npm_system_info(),
|
||||
specified_import_map: Some(Box::new(CliSpecifiedImportMapProvider {
|
||||
cli_options: self.cli_options()?.clone(),
|
||||
file_fetcher: self.file_fetcher()?.clone(),
|
||||
workspace_external_import_map_loader: self
|
||||
.workspace_external_import_map_loader()?
|
||||
.clone(),
|
||||
})),
|
||||
unstable_sloppy_imports: self.flags.unstable_config.sloppy_imports,
|
||||
package_json_dep_resolution: match &self.flags.subcommand {
|
||||
DenoSubcommand::Publish(_) => {
|
||||
// the node_modules directory is not published to jsr, so resolve
|
||||
// dependencies via the package.json rather than using node resolution
|
||||
Some(deno_config::workspace::PackageJsonDepResolution::Enabled)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
},
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
@ -626,82 +669,48 @@ impl CliFactory {
|
|||
pub fn sloppy_imports_resolver(
|
||||
&self,
|
||||
) -> Result<Option<&Arc<CliSloppyImportsResolver>>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.sloppy_imports_resolver
|
||||
.get_or_try_init(|| {
|
||||
Ok(self.cli_options()?.unstable_sloppy_imports().then(|| {
|
||||
Arc::new(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new(
|
||||
self.sys(),
|
||||
)))
|
||||
}))
|
||||
})
|
||||
.map(|maybe| maybe.as_ref())
|
||||
self.resolver_factory()?.sloppy_imports_resolver()
|
||||
}
|
||||
|
||||
pub fn workspace_directory(
|
||||
&self,
|
||||
) -> Result<&Arc<WorkspaceDirectory>, AnyError> {
|
||||
Ok(self.workspace_factory()?.workspace_directory()?)
|
||||
}
|
||||
|
||||
fn workspace_factory(&self) -> Result<&Arc<CliWorkspaceFactory>, AnyError> {
|
||||
self.services.workspace_factory.get_or_try_init(|| {
|
||||
let initial_cwd = match self.overrides.initial_cwd.clone() {
|
||||
Some(v) => v,
|
||||
None => self
|
||||
.sys()
|
||||
.env_current_dir()
|
||||
.with_context(|| "Failed getting cwd.")?,
|
||||
};
|
||||
let options = new_workspace_factory_options(
|
||||
&initial_cwd,
|
||||
&self.flags,
|
||||
self.deno_dir_path_provider().clone(),
|
||||
);
|
||||
let mut factory =
|
||||
CliWorkspaceFactory::new(self.sys(), initial_cwd, options);
|
||||
if let Some(workspace_dir) = &self.overrides.workspace_directory {
|
||||
factory.set_workspace_directory(workspace_dir.clone());
|
||||
}
|
||||
Ok(Arc::new(factory))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn workspace_resolver(
|
||||
&self,
|
||||
) -> Result<&Arc<WorkspaceResolver>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.workspace_resolver
|
||||
.get_or_try_init_async(async {
|
||||
let cli_options = self.cli_options()?;
|
||||
let resolver = cli_options
|
||||
.create_workspace_resolver(
|
||||
self.file_fetcher()?,
|
||||
if cli_options.use_byonm()
|
||||
&& !matches!(
|
||||
cli_options.sub_command(),
|
||||
DenoSubcommand::Publish(_)
|
||||
)
|
||||
{
|
||||
PackageJsonDepResolution::Disabled
|
||||
} else {
|
||||
// todo(dsherret): this should be false for nodeModulesDir: true
|
||||
PackageJsonDepResolution::Enabled
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
if !resolver.diagnostics().is_empty() {
|
||||
warn!(
|
||||
"Import map diagnostics:\n{}",
|
||||
resolver
|
||||
.diagnostics()
|
||||
.iter()
|
||||
.map(|d| format!(" - {d}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
);
|
||||
}
|
||||
Ok(Arc::new(resolver))
|
||||
})
|
||||
.await
|
||||
self.initialize_npm_resolution_if_managed().await?;
|
||||
self.resolver_factory()?.workspace_resolver().await
|
||||
}
|
||||
|
||||
pub async fn deno_resolver(&self) -> Result<&Arc<CliDenoResolver>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.deno_resolver
|
||||
.get_or_try_init_async(async {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(CliDenoResolver::new(DenoResolverOptions {
|
||||
in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(),
|
||||
node_and_req_resolver: if cli_options.no_npm() {
|
||||
None
|
||||
} else {
|
||||
Some(NodeAndNpmReqResolver {
|
||||
node_resolver: self.node_resolver().await?.clone(),
|
||||
npm_req_resolver: self.npm_req_resolver().await?.clone(),
|
||||
})
|
||||
},
|
||||
sloppy_imports_resolver: self.sloppy_imports_resolver()?.cloned(),
|
||||
workspace_resolver: self.workspace_resolver().await?.clone(),
|
||||
is_byonm: cli_options.use_byonm(),
|
||||
maybe_vendor_dir: cli_options.vendor_dir_path(),
|
||||
})))
|
||||
})
|
||||
.await
|
||||
self.initialize_npm_resolution_if_managed().await?;
|
||||
self.resolver_factory()?.deno_resolver().await
|
||||
}
|
||||
|
||||
pub async fn resolver(&self) -> Result<&Arc<CliResolver>, AnyError> {
|
||||
|
@ -787,23 +796,19 @@ impl CliFactory {
|
|||
}
|
||||
|
||||
pub async fn node_resolver(&self) -> Result<&Arc<CliNodeResolver>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.node_resolver
|
||||
.get_or_try_init_async(
|
||||
async {
|
||||
Ok(Arc::new(CliNodeResolver::new(
|
||||
self.in_npm_pkg_checker()?.clone(),
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
self.npm_resolver().await?.clone(),
|
||||
self.pkg_json_resolver().clone(),
|
||||
self.sys(),
|
||||
node_resolver::ConditionsFromResolutionMode::default(),
|
||||
)))
|
||||
}
|
||||
.boxed_local(),
|
||||
)
|
||||
.await
|
||||
self.initialize_npm_resolution_if_managed().await?;
|
||||
self.resolver_factory()?.node_resolver()
|
||||
}
|
||||
|
||||
async fn initialize_npm_resolution_if_managed(&self) -> Result<(), AnyError> {
|
||||
let npm_resolver = self.resolver_factory()?.npm_resolver()?;
|
||||
if npm_resolver.is_managed() {
|
||||
self
|
||||
.npm_resolution_initializer()?
|
||||
.ensure_initialized()
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn node_code_translator(
|
||||
|
@ -821,7 +826,7 @@ impl CliFactory {
|
|||
self.in_npm_pkg_checker()?.clone(),
|
||||
node_resolver,
|
||||
self.npm_resolver().await?.clone(),
|
||||
self.pkg_json_resolver().clone(),
|
||||
self.pkg_json_resolver()?.clone(),
|
||||
self.sys(),
|
||||
)))
|
||||
})
|
||||
|
@ -839,29 +844,14 @@ impl CliFactory {
|
|||
))
|
||||
}
|
||||
|
||||
pub async fn npm_req_resolver(
|
||||
&self,
|
||||
) -> Result<&Arc<CliNpmReqResolver>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.npm_req_resolver
|
||||
.get_or_try_init_async(async {
|
||||
let npm_resolver = self.npm_resolver().await?;
|
||||
Ok(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions {
|
||||
sys: self.sys(),
|
||||
in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(),
|
||||
node_resolver: self.node_resolver().await?.clone(),
|
||||
npm_resolver: npm_resolver.clone(),
|
||||
})))
|
||||
})
|
||||
.await
|
||||
pub fn npm_req_resolver(&self) -> Result<&Arc<CliNpmReqResolver>, AnyError> {
|
||||
self.resolver_factory()?.npm_req_resolver()
|
||||
}
|
||||
|
||||
pub fn pkg_json_resolver(&self) -> &Arc<CliPackageJsonResolver> {
|
||||
self
|
||||
.services
|
||||
.pkg_json_resolver
|
||||
.get_or_init(|| Arc::new(CliPackageJsonResolver::new(self.sys())))
|
||||
pub fn pkg_json_resolver(
|
||||
&self,
|
||||
) -> Result<&Arc<CliPackageJsonResolver>, AnyError> {
|
||||
Ok(self.resolver_factory()?.pkg_json_resolver())
|
||||
}
|
||||
|
||||
pub async fn type_checker(&self) -> Result<&Arc<TypeChecker>, AnyError> {
|
||||
|
@ -987,7 +977,7 @@ impl CliFactory {
|
|||
let options = self.cli_options()?;
|
||||
Ok(Arc::new(CliCjsTracker::new(
|
||||
self.in_npm_pkg_checker()?.clone(),
|
||||
self.pkg_json_resolver().clone(),
|
||||
self.pkg_json_resolver()?.clone(),
|
||||
if options.is_node_main() || options.unstable_detect_cjs() {
|
||||
IsCjsResolutionMode::ImplicitTypeCommonJs
|
||||
} else if options.detect_cjs() {
|
||||
|
@ -1056,6 +1046,20 @@ impl CliFactory {
|
|||
})
|
||||
}
|
||||
|
||||
fn workspace_external_import_map_loader(
|
||||
&self,
|
||||
) -> Result<&Arc<WorkspaceExternalImportMapLoader>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.workspace_external_import_map_loader
|
||||
.get_or_try_init(|| {
|
||||
Ok(Arc::new(WorkspaceExternalImportMapLoader::new(
|
||||
self.sys(),
|
||||
self.workspace_directory()?.workspace.clone(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn create_cli_main_worker_factory(
|
||||
&self,
|
||||
) -> Result<CliMainWorkerFactory, AnyError> {
|
||||
|
@ -1072,14 +1076,18 @@ impl CliFactory {
|
|||
};
|
||||
let node_code_translator = self.node_code_translator().await?;
|
||||
let cjs_tracker = self.cjs_tracker()?.clone();
|
||||
let pkg_json_resolver = self.pkg_json_resolver().clone();
|
||||
let npm_req_resolver = self.npm_req_resolver().await?;
|
||||
let pkg_json_resolver = self.pkg_json_resolver()?.clone();
|
||||
let npm_req_resolver = self.npm_req_resolver()?;
|
||||
let workspace_factory = self.workspace_factory()?;
|
||||
let npm_registry_permission_checker = {
|
||||
let mode = if cli_options.use_byonm() {
|
||||
let mode = if self.resolver_factory()?.use_byonm()? {
|
||||
NpmRegistryReadPermissionCheckerMode::Byonm
|
||||
} else if let Some(node_modules_dir) = cli_options.node_modules_dir_path()
|
||||
} else if let Some(node_modules_dir) =
|
||||
workspace_factory.node_modules_dir_path()?
|
||||
{
|
||||
NpmRegistryReadPermissionCheckerMode::Local(node_modules_dir.clone())
|
||||
NpmRegistryReadPermissionCheckerMode::Local(
|
||||
node_modules_dir.to_path_buf(),
|
||||
)
|
||||
} else {
|
||||
NpmRegistryReadPermissionCheckerMode::Global(
|
||||
self.npm_cache_dir()?.root_dir().to_path_buf(),
|
||||
|
@ -1151,6 +1159,7 @@ impl CliFactory {
|
|||
&self,
|
||||
) -> Result<LibMainWorkerOptions, AnyError> {
|
||||
let cli_options = self.cli_options()?;
|
||||
let workspace_factory = self.workspace_factory()?;
|
||||
Ok(LibMainWorkerOptions {
|
||||
argv: cli_options.argv().clone(),
|
||||
// This optimization is only available for "run" subcommand
|
||||
|
@ -1160,7 +1169,9 @@ impl CliFactory {
|
|||
log_level: cli_options.log_level().unwrap_or(log::Level::Info).into(),
|
||||
enable_op_summary_metrics: cli_options.enable_op_summary_metrics(),
|
||||
enable_testing_features: cli_options.enable_testing_features(),
|
||||
has_node_modules_dir: cli_options.has_node_modules_dir(),
|
||||
has_node_modules_dir: workspace_factory
|
||||
.node_modules_dir_path()?
|
||||
.is_some(),
|
||||
inspect_brk: cli_options.inspect_brk().is_some(),
|
||||
inspect_wait: cli_options.inspect_wait().is_some(),
|
||||
strace_ops: cli_options.strace_ops().clone(),
|
||||
|
@ -1223,3 +1234,57 @@ impl CliFactory {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn new_workspace_factory_options(
|
||||
initial_cwd: &Path,
|
||||
flags: &Flags,
|
||||
deno_dir_path_provider: Arc<CliDenoDirPathProvider>,
|
||||
) -> deno_resolver::factory::WorkspaceFactoryOptions<CliSys> {
|
||||
deno_resolver::factory::WorkspaceFactoryOptions {
|
||||
additional_config_file_names: if matches!(
|
||||
flags.subcommand,
|
||||
DenoSubcommand::Publish(..)
|
||||
) {
|
||||
&["jsr.json", "jsr.jsonc"]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
config_discovery: match &flags.config_flag {
|
||||
ConfigFlag::Discover => {
|
||||
if let Some(start_paths) = flags.config_path_args(initial_cwd) {
|
||||
ConfigDiscoveryOption::Discover { start_paths }
|
||||
} else {
|
||||
ConfigDiscoveryOption::Disabled
|
||||
}
|
||||
}
|
||||
ConfigFlag::Path(path) => {
|
||||
ConfigDiscoveryOption::Path(PathBuf::from(path))
|
||||
}
|
||||
ConfigFlag::Disabled => ConfigDiscoveryOption::Disabled,
|
||||
},
|
||||
deno_dir_path_provider: Some(deno_dir_path_provider),
|
||||
// For `deno install/add/remove/init` we want to force the managed
|
||||
// resolver so it can set up the `node_modules/` directory.
|
||||
is_package_manager_subcommand: matches!(
|
||||
flags.subcommand,
|
||||
DenoSubcommand::Install(_)
|
||||
| DenoSubcommand::Add(_)
|
||||
| DenoSubcommand::Remove(_)
|
||||
| DenoSubcommand::Init(_)
|
||||
| DenoSubcommand::Outdated(_)
|
||||
),
|
||||
no_npm: flags.no_npm,
|
||||
node_modules_dir: flags.node_modules_dir,
|
||||
|
||||
npm_process_state: NPM_PROCESS_STATE.as_ref().map(|s| {
|
||||
NpmProcessStateOptions {
|
||||
node_modules_dir: s
|
||||
.local_node_modules_path
|
||||
.as_ref()
|
||||
.map(|s| Cow::Borrowed(s.as_str())),
|
||||
is_byonm: matches!(s.kind, NpmProcessStateKind::Byonm),
|
||||
}
|
||||
}),
|
||||
vendor: flags.vendor,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
capacity_builder.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_config = { workspace = true, features = ["sync", "workspace"] }
|
||||
deno_error.workspace = true
|
||||
deno_fs = { workspace = true, features = ["sync_fs"] }
|
||||
deno_media_type.workspace = true
|
||||
|
|
|
@ -7,6 +7,8 @@ use std::io::Seek;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use deno_npm::resolution::PackageIdNotFoundError;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_tls::deno_native_certs::load_native_certs;
|
||||
use deno_runtime::deno_tls::rustls;
|
||||
|
@ -32,8 +34,10 @@ pub fn has_trace_permissions_enabled() -> bool {
|
|||
}
|
||||
|
||||
pub fn has_flag_env_var(name: &str) -> bool {
|
||||
let value = std::env::var(name);
|
||||
matches!(value.as_ref().map(|s| s.as_str()), Ok("1"))
|
||||
match std::env::var_os(name) {
|
||||
Some(value) => value == "1",
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
|
@ -187,6 +191,19 @@ pub static NPM_PROCESS_STATE: LazyLock<Option<NpmProcessState>> =
|
|||
Some(state)
|
||||
});
|
||||
|
||||
pub fn resolve_npm_resolution_snapshot(
|
||||
) -> Result<Option<ValidSerializedNpmResolutionSnapshot>, PackageIdNotFoundError>
|
||||
{
|
||||
if let Some(NpmProcessStateKind::Snapshot(snapshot)) =
|
||||
NPM_PROCESS_STATE.as_ref().map(|s| &s.kind)
|
||||
{
|
||||
// TODO(bartlomieju): remove this clone
|
||||
Ok(Some(snapshot.clone().into_valid()?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UnstableConfig {
|
||||
// TODO(bartlomieju): remove in Deno 2.5
|
||||
|
|
|
@ -94,8 +94,10 @@ impl LspCache {
|
|||
.ok()
|
||||
});
|
||||
let sys = CliSys::default();
|
||||
let deno_dir = DenoDir::new(sys.clone(), global_cache_path)
|
||||
.expect("should be infallible with absolute custom root");
|
||||
let deno_dir_root =
|
||||
deno_cache_dir::resolve_deno_dir(&sys, global_cache_path)
|
||||
.expect("should be infallible with absolute custom root");
|
||||
let deno_dir = DenoDir::new(sys.clone(), deno_dir_root);
|
||||
let global =
|
||||
Arc::new(GlobalHttpCache::new(sys, deno_dir.remote_folder_path()));
|
||||
Self {
|
||||
|
|
|
@ -47,6 +47,7 @@ use deno_lint::linter::LintConfig as DenoLintConfig;
|
|||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonCache;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_resolver::npmrc::discover_npmrc_from_workspace;
|
||||
use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use indexmap::IndexSet;
|
||||
|
@ -56,7 +57,6 @@ use tower_lsp::lsp_types as lsp;
|
|||
use super::logging::lsp_log;
|
||||
use super::lsp_custom;
|
||||
use super::urls::url_to_uri;
|
||||
use crate::args::discover_npmrc_from_workspace;
|
||||
use crate::args::CliLockfile;
|
||||
use crate::args::CliLockfileReadFromPathOptions;
|
||||
use crate::args::ConfigFile;
|
||||
|
@ -1362,21 +1362,22 @@ impl ConfigData {
|
|||
}
|
||||
|
||||
// todo(dsherret): cache this so we don't load this so many times
|
||||
let npmrc = discover_npmrc_from_workspace(&member_dir.workspace)
|
||||
.inspect(|(_, path)| {
|
||||
if let Some(path) = path {
|
||||
lsp_log!(" Resolved .npmrc: \"{}\"", path.display());
|
||||
let npmrc =
|
||||
discover_npmrc_from_workspace(&CliSys::default(), &member_dir.workspace)
|
||||
.inspect(|(_, path)| {
|
||||
if let Some(path) = path {
|
||||
lsp_log!(" Resolved .npmrc: \"{}\"", path.display());
|
||||
|
||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
|
||||
add_watched_file(specifier, ConfigWatchedFileType::NpmRc);
|
||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
|
||||
add_watched_file(specifier, ConfigWatchedFileType::NpmRc);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.inspect_err(|err| {
|
||||
lsp_warn!(" Couldn't read .npmrc for \"{scope}\": {err}");
|
||||
})
|
||||
.map(|(r, _)| r)
|
||||
.ok();
|
||||
})
|
||||
.inspect_err(|err| {
|
||||
lsp_warn!(" Couldn't read .npmrc for \"{scope}\": {err}");
|
||||
})
|
||||
.map(|(r, _)| Arc::new(r))
|
||||
.ok();
|
||||
let default_file_pattern_base =
|
||||
scope.to_file_path().unwrap_or_else(|_| PathBuf::from("/"));
|
||||
let fmt_config = Arc::new(
|
||||
|
|
|
@ -13,8 +13,6 @@ use std::sync::Arc;
|
|||
|
||||
use deno_ast::MediaType;
|
||||
use deno_cache_dir::file_fetcher::CacheSetting;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_config::workspace::WorkspaceDiscoverOptions;
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::resolve_url;
|
||||
|
@ -28,7 +26,6 @@ use deno_core::ModuleSpecifier;
|
|||
use deno_graph::GraphKind;
|
||||
use deno_graph::Resolution;
|
||||
use deno_lib::args::get_root_cert_store;
|
||||
use deno_lib::args::has_flag_env_var;
|
||||
use deno_lib::args::CaData;
|
||||
use deno_lib::version::DENO_VERSION_INFO;
|
||||
use deno_path_util::url_to_file_path;
|
||||
|
@ -97,8 +94,6 @@ use super::tsc::TsServer;
|
|||
use super::urls;
|
||||
use super::urls::uri_to_url;
|
||||
use super::urls::url_to_uri;
|
||||
use crate::args::create_default_npmrc;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::Flags;
|
||||
use crate::args::InternalFlags;
|
||||
use crate::args::UnstableFmtOptions;
|
||||
|
@ -255,7 +250,7 @@ impl LanguageServer {
|
|||
force_global_cache: bool,
|
||||
) -> LspResult<Option<Value>> {
|
||||
async fn create_graph_for_caching(
|
||||
cli_options: CliOptions,
|
||||
factory: CliFactory,
|
||||
roots: Vec<ModuleSpecifier>,
|
||||
open_docs: Vec<Arc<Document>>,
|
||||
) -> Result<(), AnyError> {
|
||||
|
@ -263,8 +258,6 @@ impl LanguageServer {
|
|||
.into_iter()
|
||||
.map(|d| (d.specifier().clone(), d))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let cli_options = Arc::new(cli_options);
|
||||
let factory = CliFactory::from_cli_options(cli_options.clone());
|
||||
let module_graph_builder = factory.module_graph_builder().await?;
|
||||
let module_graph_creator = factory.module_graph_creator().await?;
|
||||
let mut inner_loader = module_graph_builder.create_graph_loader();
|
||||
|
@ -293,9 +286,11 @@ impl LanguageServer {
|
|||
|
||||
// Update the lockfile on the file system with anything new
|
||||
// found after caching
|
||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||
if let Err(err) = &lockfile.write_if_changed() {
|
||||
lsp_warn!("{:#}", err);
|
||||
if let Ok(cli_options) = factory.cli_options() {
|
||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||
if let Err(err) = &lockfile.write_if_changed() {
|
||||
lsp_warn!("{:#}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,11 +314,11 @@ impl LanguageServer {
|
|||
match prepare_cache_result {
|
||||
Ok(result) => {
|
||||
// cache outside the lock
|
||||
let cli_options = result.cli_options;
|
||||
let cli_factory = result.cli_factory;
|
||||
let roots = result.roots;
|
||||
let open_docs = result.open_docs;
|
||||
let handle = spawn(async move {
|
||||
create_graph_for_caching(cli_options, roots, open_docs).await
|
||||
create_graph_for_caching(cli_factory, roots, open_docs).await
|
||||
});
|
||||
|
||||
if let Err(err) = handle.await.unwrap() {
|
||||
|
@ -3492,7 +3487,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
|||
}
|
||||
|
||||
struct PrepareCacheResult {
|
||||
cli_options: CliOptions,
|
||||
cli_factory: CliFactory,
|
||||
roots: Vec<ModuleSpecifier>,
|
||||
open_docs: Vec<Arc<Document>>,
|
||||
}
|
||||
|
@ -3626,66 +3621,44 @@ impl Inner {
|
|||
let initial_cwd = config_data
|
||||
.and_then(|d| d.scope.to_file_path().ok())
|
||||
.unwrap_or_else(|| self.initial_cwd.clone());
|
||||
let workspace = match config_data {
|
||||
Some(d) => d.member_dir.clone(),
|
||||
None => Arc::new(WorkspaceDirectory::discover(
|
||||
&CliSys::default(),
|
||||
deno_config::workspace::WorkspaceDiscoverStart::Paths(&[
|
||||
initial_cwd.clone()
|
||||
]),
|
||||
&WorkspaceDiscoverOptions {
|
||||
deno_json_cache: None,
|
||||
pkg_json_cache: None,
|
||||
workspace_cache: None,
|
||||
additional_config_file_names: &[],
|
||||
discover_pkg_json: !has_flag_env_var("DENO_NO_PACKAGE_JSON"),
|
||||
maybe_vendor_override: if force_global_cache {
|
||||
Some(deno_config::workspace::VendorEnablement::Disable)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
},
|
||||
)?),
|
||||
};
|
||||
let cli_options = CliOptions::new(
|
||||
&CliSys::default(),
|
||||
Arc::new(Flags {
|
||||
internal: InternalFlags {
|
||||
cache_path: Some(self.cache.deno_dir().root.clone()),
|
||||
..Default::default()
|
||||
},
|
||||
ca_stores: workspace_settings.certificate_stores.clone(),
|
||||
ca_data: workspace_settings.tls_certificate.clone().map(CaData::File),
|
||||
unsafely_ignore_certificate_errors: workspace_settings
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
import_map_path: config_data.and_then(|d| {
|
||||
d.import_map_from_settings
|
||||
.as_ref()
|
||||
.map(|url| url.to_string())
|
||||
}),
|
||||
// bit of a hack to force the lsp to cache the @types/node package
|
||||
type_check_mode: crate::args::TypeCheckMode::Local,
|
||||
permissions: crate::args::PermissionFlags {
|
||||
// allow remote import permissions in the lsp for now
|
||||
allow_import: Some(vec![]),
|
||||
..Default::default()
|
||||
},
|
||||
let mut cli_factory = CliFactory::from_flags(Arc::new(Flags {
|
||||
internal: InternalFlags {
|
||||
cache_path: Some(self.cache.deno_dir().root.clone()),
|
||||
..Default::default()
|
||||
},
|
||||
ca_stores: workspace_settings.certificate_stores.clone(),
|
||||
ca_data: workspace_settings.tls_certificate.clone().map(CaData::File),
|
||||
unsafely_ignore_certificate_errors: workspace_settings
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
import_map_path: config_data.and_then(|d| {
|
||||
d.import_map_from_settings
|
||||
.as_ref()
|
||||
.map(|url| url.to_string())
|
||||
}),
|
||||
initial_cwd,
|
||||
config_data.and_then(|d| d.lockfile.clone()),
|
||||
config_data
|
||||
.and_then(|d| d.npmrc.clone())
|
||||
.unwrap_or_else(create_default_npmrc),
|
||||
workspace,
|
||||
force_global_cache,
|
||||
None,
|
||||
)?;
|
||||
// bit of a hack to force the lsp to cache the @types/node package
|
||||
type_check_mode: crate::args::TypeCheckMode::Local,
|
||||
permissions: crate::args::PermissionFlags {
|
||||
// allow remote import permissions in the lsp for now
|
||||
allow_import: Some(vec![]),
|
||||
..Default::default()
|
||||
},
|
||||
vendor: if force_global_cache {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
no_lock: force_global_cache,
|
||||
..Default::default()
|
||||
}));
|
||||
cli_factory.set_initial_cwd(initial_cwd);
|
||||
if let Some(d) = &config_data {
|
||||
cli_factory.set_workspace_dir(d.member_dir.clone());
|
||||
};
|
||||
|
||||
let open_docs = self.documents.documents(DocumentsFilter::OpenDiagnosable);
|
||||
Ok(PrepareCacheResult {
|
||||
cli_options,
|
||||
cli_factory,
|
||||
open_docs,
|
||||
roots,
|
||||
})
|
||||
|
|
|
@ -6,16 +6,18 @@ use dashmap::DashMap;
|
|||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_npm::npm_rc::NpmRc;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::search::PackageSearchApi;
|
||||
use crate::args::npm_registry_url;
|
||||
use crate::file_fetcher::CliFileFetcher;
|
||||
use crate::file_fetcher::TextDecodedFile;
|
||||
use crate::npm::NpmFetchResolver;
|
||||
use crate::sys::CliSys;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliNpmSearchApi {
|
||||
|
@ -111,6 +113,14 @@ fn parse_npm_search_response(source: &str) -> Result<Vec<String>, AnyError> {
|
|||
Ok(objects.into_iter().map(|o| o.package.name).collect())
|
||||
}
|
||||
|
||||
// this is buried here because generally you want to use the ResolvedNpmRc instead of this.
|
||||
fn npm_registry_url() -> &'static Url {
|
||||
static NPM_REGISTRY_DEFAULT_URL: Lazy<Url> =
|
||||
Lazy::new(|| deno_resolver::npmrc::npm_registry_url(&CliSys::default()));
|
||||
|
||||
&NPM_REGISTRY_DEFAULT_URL
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -28,20 +28,20 @@ use deno_resolver::npm::managed::NpmResolutionCell;
|
|||
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::npm::NpmReqResolverOptions;
|
||||
use deno_resolver::npmrc::create_default_npmrc;
|
||||
use deno_resolver::DenoResolverOptions;
|
||||
use deno_resolver::NodeAndNpmReqResolver;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use indexmap::IndexMap;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::ResolutionMode;
|
||||
|
||||
use super::cache::LspCache;
|
||||
use super::jsr::JsrCacheResolver;
|
||||
use crate::args::create_default_npmrc;
|
||||
use crate::args::CliLockfile;
|
||||
use crate::args::LifecycleScriptsConfig;
|
||||
use crate::args::NpmCachingStrategy;
|
||||
|
@ -263,18 +263,19 @@ impl LspScopeResolver {
|
|||
}
|
||||
CliNpmResolver::Managed(managed_npm_resolver) => {
|
||||
CliNpmResolverCreateOptions::Managed({
|
||||
let sys = CliSys::default();
|
||||
let npmrc = self
|
||||
.config_data
|
||||
.as_ref()
|
||||
.and_then(|d| d.npmrc.clone())
|
||||
.unwrap_or_else(create_default_npmrc);
|
||||
.unwrap_or_else(|| Arc::new(create_default_npmrc(&sys)));
|
||||
let npm_cache_dir = Arc::new(NpmCacheDir::new(
|
||||
&CliSys::default(),
|
||||
&sys,
|
||||
managed_npm_resolver.global_cache_root_path().to_path_buf(),
|
||||
npmrc.get_all_known_registries_urls(),
|
||||
));
|
||||
CliManagedNpmResolverCreateOptions {
|
||||
sys: CliSys::default(),
|
||||
sys,
|
||||
npm_cache_dir,
|
||||
maybe_node_modules_path: managed_npm_resolver
|
||||
.root_node_modules_path()
|
||||
|
@ -710,7 +711,7 @@ impl<'a> ResolverFactory<'a> {
|
|||
let npmrc = self
|
||||
.config_data
|
||||
.and_then(|d| d.npmrc.clone())
|
||||
.unwrap_or_else(create_default_npmrc);
|
||||
.unwrap_or_else(|| Arc::new(create_default_npmrc(&sys)));
|
||||
let npm_cache_dir = Arc::new(NpmCacheDir::new(
|
||||
&sys,
|
||||
cache.deno_dir().npm_folder_path(),
|
||||
|
@ -917,7 +918,7 @@ impl<'a> ResolverFactory<'a> {
|
|||
let npm_resolver = self.services.npm_resolver.as_ref()?;
|
||||
Some(Arc::new(CliNodeResolver::new(
|
||||
self.in_npm_pkg_checker().clone(),
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
npm_resolver.clone(),
|
||||
self.pkg_json_resolver.clone(),
|
||||
self.sys.clone(),
|
||||
|
|
|
@ -134,7 +134,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
tools::check::check(flags, check_flags).await
|
||||
}),
|
||||
DenoSubcommand::Clean => spawn_subcommand(async move {
|
||||
tools::clean::clean()
|
||||
tools::clean::clean(flags)
|
||||
}),
|
||||
DenoSubcommand::Compile(compile_flags) => spawn_subcommand(async {
|
||||
tools::compile::compile(flags, compile_flags).await
|
||||
|
|
|
@ -49,10 +49,10 @@ use deno_runtime::code_cache;
|
|||
use deno_runtime::deno_node::create_host_defined_options;
|
||||
use deno_runtime::deno_node::ops::require::UnableToGetCwdError;
|
||||
use deno_runtime::deno_node::NodeRequireLoader;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::InNpmPackageChecker;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::ResolutionMode;
|
||||
|
@ -91,7 +91,7 @@ use crate::util::text_encoding::source_map_from_code;
|
|||
pub type CliNpmModuleLoader = deno_lib::loader::NpmModuleLoader<
|
||||
CliCjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver,
|
||||
CliSys,
|
||||
>;
|
||||
|
|
|
@ -9,11 +9,11 @@ use deno_error::JsErrorBox;
|
|||
use deno_graph::ParsedSourceStore;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
|
||||
use node_resolver::analyze::CjsAnalysisExports;
|
||||
use node_resolver::analyze::CjsCodeAnalyzer;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
|
@ -27,7 +27,7 @@ use crate::sys::CliSys;
|
|||
pub type CliNodeCodeTranslator = NodeCodeTranslator<
|
||||
CliCjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver,
|
||||
CliSys,
|
||||
>;
|
||||
|
|
|
@ -18,8 +18,8 @@ use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
|
|||
use deno_resolver::sloppy_imports::SloppyImportsResolver;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_node::is_builtin_node_module;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::ResolutionMode;
|
||||
|
||||
|
@ -40,14 +40,14 @@ pub type CliSloppyImportsResolver =
|
|||
SloppyImportsResolver<CliSloppyImportsCachedFs>;
|
||||
pub type CliDenoResolver = deno_resolver::DenoResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver,
|
||||
CliSloppyImportsCachedFs,
|
||||
CliSys,
|
||||
>;
|
||||
pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver,
|
||||
CliSys,
|
||||
>;
|
||||
|
|
|
@ -26,14 +26,14 @@ deno_runtime = { workspace = true, features = ["include_js_files_for_snapshottin
|
|||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
|
||||
[dependencies]
|
||||
deno_cache_dir.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_cache_dir = { workspace = true, features = ["sync"] }
|
||||
deno_config = { workspace = true, features = ["sync", "workspace"] }
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_error.workspace = true
|
||||
deno_lib.workspace = true
|
||||
deno_media_type = { workspace = true, features = ["data_url", "decoding"] }
|
||||
deno_npm.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_package_json = { workspace = true, features = ["sync"] }
|
||||
deno_path_util.workspace = true
|
||||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
|
|
|
@ -11,10 +11,10 @@ use deno_media_type::MediaType;
|
|||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::npm::NpmReqResolver;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::analyze::CjsAnalysis;
|
||||
use node_resolver::analyze::CjsAnalysisExports;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
|
||||
use crate::binary::StandaloneModules;
|
||||
use crate::file_system::DenoRtSys;
|
||||
|
@ -25,14 +25,14 @@ pub type DenoRtNpmResolver = deno_resolver::npm::NpmResolver<DenoRtSys>;
|
|||
pub type DenoRtNpmModuleLoader = NpmModuleLoader<
|
||||
CjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
pub type DenoRtNodeCodeTranslator = NodeCodeTranslator<
|
||||
CjsCodeAnalyzer,
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
|
@ -43,7 +43,7 @@ pub type DenoRtNodeResolver = deno_runtime::deno_node::NodeResolver<
|
|||
>;
|
||||
pub type DenoRtNpmReqResolver = NpmReqResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
DenoRtNpmResolver,
|
||||
DenoRtSys,
|
||||
>;
|
||||
|
|
|
@ -63,7 +63,6 @@ use deno_runtime::code_cache::CodeCache;
|
|||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::create_host_defined_options;
|
||||
use deno_runtime::deno_node::NodeRequireLoader;
|
||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
|
@ -75,6 +74,7 @@ use deno_runtime::WorkerLogLevel;
|
|||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::NodeResolver;
|
||||
use node_resolver::PackageJsonResolver;
|
||||
|
@ -760,7 +760,7 @@ pub async fn run(
|
|||
let has_node_modules_dir = npm_resolver.root_node_modules_path().is_some();
|
||||
let node_resolver = Arc::new(NodeResolver::new(
|
||||
in_npm_pkg_checker.clone(),
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
npm_resolver.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
sys.clone(),
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
|
||||
use crate::cache::DenoDir;
|
||||
use crate::args::Flags;
|
||||
use crate::colors;
|
||||
use crate::display;
|
||||
use crate::sys::CliSys;
|
||||
use crate::factory::CliFactory;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
use crate::util::progress_bar::ProgressMessagePrompt;
|
||||
|
@ -29,8 +30,9 @@ impl CleanState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn clean() -> Result<(), AnyError> {
|
||||
let deno_dir = DenoDir::new(CliSys::default(), None)?;
|
||||
pub fn clean(flags: Arc<Flags>) -> Result<(), AnyError> {
|
||||
let factory = CliFactory::from_flags(flags);
|
||||
let deno_dir = factory.deno_dir()?;
|
||||
if deno_dir.root.exists() {
|
||||
let no_of_files = walkdir::WalkDir::new(&deno_dir.root).into_iter().count();
|
||||
let progress_bar = ProgressBar::new(ProgressBarStyle::ProgressBars);
|
||||
|
|
|
@ -59,7 +59,8 @@ pub async fn format(
|
|||
fmt_flags: FmtFlags,
|
||||
) -> Result<(), AnyError> {
|
||||
if fmt_flags.is_stdin() {
|
||||
let cli_options = CliOptions::from_flags(&CliSys::default(), flags)?;
|
||||
let factory = CliFactory::from_flags(flags);
|
||||
let cli_options = factory.cli_options()?;
|
||||
let start_dir = &cli_options.start_dir;
|
||||
let fmt_config = start_dir
|
||||
.to_fmt_config(FilePatterns::new_with_base(start_dir.dir_path()))?;
|
||||
|
|
|
@ -50,7 +50,7 @@ pub async fn info(
|
|||
let npm_resolver = factory.npm_resolver().await?;
|
||||
let maybe_lockfile = cli_options.maybe_lockfile();
|
||||
let resolver = factory.workspace_resolver().await?.clone();
|
||||
let npmrc = cli_options.npmrc();
|
||||
let npmrc = factory.npmrc()?;
|
||||
let node_resolver = factory.node_resolver().await?;
|
||||
|
||||
let cwd_url =
|
||||
|
@ -185,7 +185,7 @@ fn print_cache_info(
|
|||
) -> Result<(), AnyError> {
|
||||
let dir = factory.deno_dir()?;
|
||||
#[allow(deprecated)]
|
||||
let modules_cache = factory.global_http_cache()?.get_global_cache_location();
|
||||
let modules_cache = factory.global_http_cache()?.dir_path();
|
||||
let npm_cache = factory.deno_dir()?.npm_folder_path();
|
||||
let typescript_cache = &dir.gen_cache.location;
|
||||
let registry_cache = dir.registries_folder_path();
|
||||
|
|
|
@ -306,9 +306,7 @@ async fn install_local(
|
|||
InstallFlagsLocal::TopLevel => {
|
||||
let factory = CliFactory::from_flags(flags);
|
||||
// surface any errors in the package.json
|
||||
if let Some(npm_installer) = factory.npm_installer_if_managed()? {
|
||||
npm_installer.ensure_no_pkg_json_dep_errors()?;
|
||||
}
|
||||
factory.npm_installer()?.ensure_no_pkg_json_dep_errors()?;
|
||||
crate::tools::registry::cache_top_level_deps(&factory, None).await?;
|
||||
|
||||
if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() {
|
||||
|
@ -375,7 +373,7 @@ async fn install_global(
|
|||
log::Level::Trace,
|
||||
);
|
||||
|
||||
let npmrc = factory.cli_options().unwrap().npmrc();
|
||||
let npmrc = factory.npmrc()?;
|
||||
|
||||
let deps_file_fetcher = Arc::new(deps_file_fetcher);
|
||||
let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone()));
|
||||
|
|
|
@ -423,7 +423,7 @@ pub async fn add(
|
|||
log::Level::Trace,
|
||||
);
|
||||
|
||||
let npmrc = cli_factory.cli_options().unwrap().npmrc();
|
||||
let npmrc = cli_factory.npmrc()?;
|
||||
|
||||
let deps_file_fetcher = Arc::new(deps_file_fetcher);
|
||||
let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone()));
|
||||
|
|
|
@ -19,15 +19,13 @@ pub async fn cache_top_level_deps(
|
|||
factory: &CliFactory,
|
||||
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
|
||||
) -> Result<(), AnyError> {
|
||||
let npm_installer = factory.npm_installer_if_managed()?;
|
||||
let npm_installer = factory.npm_installer()?;
|
||||
let cli_options = factory.cli_options()?;
|
||||
if let Some(npm_installer) = &npm_installer {
|
||||
npm_installer
|
||||
.ensure_top_level_package_json_install()
|
||||
.await?;
|
||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||
lockfile.error_if_changed()?;
|
||||
}
|
||||
npm_installer
|
||||
.ensure_top_level_package_json_install()
|
||||
.await?;
|
||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||
lockfile.error_if_changed()?;
|
||||
}
|
||||
// cache as many entries in the import map as we can
|
||||
let resolver = factory.workspace_resolver().await?;
|
||||
|
@ -141,9 +139,7 @@ pub async fn cache_top_level_deps(
|
|||
maybe_graph_error = graph_builder.graph_roots_valid(graph, &roots);
|
||||
}
|
||||
|
||||
if let Some(npm_installer) = &npm_installer {
|
||||
npm_installer.cache_packages(PackageCaching::All).await?;
|
||||
}
|
||||
npm_installer.cache_packages(PackageCaching::All).await?;
|
||||
|
||||
maybe_graph_error?;
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ pub async fn outdated(
|
|||
let file_fetcher = Arc::new(file_fetcher);
|
||||
let npm_fetch_resolver = Arc::new(NpmFetchResolver::new(
|
||||
file_fetcher.clone(),
|
||||
cli_options.npmrc().clone(),
|
||||
factory.npmrc()?.clone(),
|
||||
));
|
||||
let jsr_fetch_resolver =
|
||||
Arc::new(JsrFetchResolver::new(file_fetcher.clone()));
|
||||
|
|
|
@ -15,6 +15,7 @@ use deno_core::v8;
|
|||
use deno_core::v8::ExternalReference;
|
||||
use deno_error::JsErrorBox;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::InNpmPackageChecker;
|
||||
use node_resolver::IsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NpmPackageFolderResolver;
|
||||
|
@ -25,24 +26,25 @@ extern crate libz_sys as zlib;
|
|||
|
||||
mod global;
|
||||
pub mod ops;
|
||||
mod polyfill;
|
||||
|
||||
pub use deno_package_json::PackageJson;
|
||||
use deno_permissions::PermissionCheckError;
|
||||
pub use node_resolver::PathClean;
|
||||
pub use node_resolver::DENO_SUPPORTED_BUILTIN_NODE_MODULES as SUPPORTED_BUILTIN_NODE_MODULES;
|
||||
pub use ops::ipc::ChildPipeFd;
|
||||
use ops::vm;
|
||||
pub use ops::vm::create_v8_context;
|
||||
pub use ops::vm::init_global_template;
|
||||
pub use ops::vm::ContextInitMode;
|
||||
pub use ops::vm::VM_CONTEXT_INDEX;
|
||||
pub use polyfill::is_builtin_node_module;
|
||||
pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES;
|
||||
pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX;
|
||||
|
||||
use crate::global::global_object_middleware;
|
||||
use crate::global::global_template_middleware;
|
||||
|
||||
pub fn is_builtin_node_module(module_name: &str) -> bool {
|
||||
DenoIsBuiltInNodeModuleChecker.is_builtin_node_module(module_name)
|
||||
}
|
||||
|
||||
pub trait NodePermissions {
|
||||
fn check_net_url(
|
||||
&mut self,
|
||||
|
@ -813,16 +815,6 @@ deno_core::extension!(deno_node,
|
|||
},
|
||||
);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RealIsBuiltInNodeModuleChecker;
|
||||
|
||||
impl IsBuiltInNodeModuleChecker for RealIsBuiltInNodeModuleChecker {
|
||||
#[inline]
|
||||
fn is_builtin_node_module(&self, specifier: &str) -> bool {
|
||||
is_builtin_node_module(specifier)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExtNodeSys:
|
||||
sys_traits::BaseFsCanonicalize
|
||||
+ sys_traits::BaseFsMetadata
|
||||
|
@ -837,7 +829,7 @@ impl ExtNodeSys for sys_traits::impls::RealSys {}
|
|||
pub type NodeResolver<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys> =
|
||||
node_resolver::NodeResolver<
|
||||
TInNpmPackageChecker,
|
||||
RealIsBuiltInNodeModuleChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>;
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
/// e.g. `is_builtin_node_module("assert")`
|
||||
pub fn is_builtin_node_module(module_name: &str) -> bool {
|
||||
SUPPORTED_BUILTIN_NODE_MODULES
|
||||
.iter()
|
||||
.any(|m| *m == module_name)
|
||||
}
|
||||
|
||||
macro_rules! generate_builtin_node_module_lists {
|
||||
($( $module_name:literal ,)+) => {
|
||||
pub static SUPPORTED_BUILTIN_NODE_MODULES: &[&str] = &[
|
||||
$(
|
||||
$module_name,
|
||||
)+
|
||||
];
|
||||
|
||||
pub static SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX: &[&str] = &[
|
||||
$(
|
||||
concat!("node:", $module_name),
|
||||
)+
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE(bartlomieju): keep this list in sync with `ext/node/polyfills/01_require.js`
|
||||
generate_builtin_node_module_lists! {
|
||||
"_http_agent",
|
||||
"_http_common",
|
||||
"_http_outgoing",
|
||||
"_http_server",
|
||||
"_stream_duplex",
|
||||
"_stream_passthrough",
|
||||
"_stream_readable",
|
||||
"_stream_transform",
|
||||
"_stream_writable",
|
||||
"_tls_common",
|
||||
"_tls_wrap",
|
||||
"assert",
|
||||
"assert/strict",
|
||||
"async_hooks",
|
||||
"buffer",
|
||||
"child_process",
|
||||
"cluster",
|
||||
"console",
|
||||
"constants",
|
||||
"crypto",
|
||||
"dgram",
|
||||
"diagnostics_channel",
|
||||
"dns",
|
||||
"dns/promises",
|
||||
"domain",
|
||||
"events",
|
||||
"fs",
|
||||
"fs/promises",
|
||||
"http",
|
||||
"http2",
|
||||
"https",
|
||||
"inspector",
|
||||
"inspector/promises",
|
||||
"module",
|
||||
"net",
|
||||
"os",
|
||||
"path",
|
||||
"path/posix",
|
||||
"path/win32",
|
||||
"perf_hooks",
|
||||
"process",
|
||||
"punycode",
|
||||
"querystring",
|
||||
"readline",
|
||||
"readline/promises",
|
||||
"repl",
|
||||
"stream",
|
||||
"stream/consumers",
|
||||
"stream/promises",
|
||||
"stream/web",
|
||||
"string_decoder",
|
||||
"sys",
|
||||
"test",
|
||||
"timers",
|
||||
"timers/promises",
|
||||
"tls",
|
||||
"tty",
|
||||
"url",
|
||||
"util",
|
||||
"util/types",
|
||||
"v8",
|
||||
"vm",
|
||||
"wasi",
|
||||
"worker_threads",
|
||||
"zlib",
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builtins_are_sorted() {
|
||||
let mut builtins_list = SUPPORTED_BUILTIN_NODE_MODULES.to_vec();
|
||||
builtins_list.sort();
|
||||
assert_eq!(SUPPORTED_BUILTIN_NODE_MODULES, builtins_list);
|
||||
}
|
|
@ -14,10 +14,11 @@ description = "Deno resolution algorithm"
|
|||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
sync = ["dashmap", "deno_package_json/sync", "node_resolver/sync"]
|
||||
sync = ["dashmap", "deno_package_json/sync", "node_resolver/sync", "deno_config/sync", "deno_cache_dir/sync"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
async-once-cell.workspace = true
|
||||
async-trait.workspace = true
|
||||
base32.workspace = true
|
||||
boxed_error.workspace = true
|
||||
|
@ -30,8 +31,11 @@ deno_npm.workspace = true
|
|||
deno_package_json.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_semver.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
futures.workspace = true
|
||||
log.workspace = true
|
||||
node_resolver.workspace = true
|
||||
once_cell.workspace = true
|
||||
parking_lot.workspace = true
|
||||
sys_traits.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
|
893
resolvers/deno/factory.rs
Normal file
893
resolvers/deno/factory.rs
Normal file
|
@ -0,0 +1,893 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use boxed_error::Boxed;
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_cache_dir::DenoDirResolutionError;
|
||||
use deno_cache_dir::GlobalHttpCacheRc;
|
||||
use deno_cache_dir::HttpCacheRc;
|
||||
use deno_cache_dir::LocalHttpCache;
|
||||
use deno_config::deno_json::NodeModulesDirMode;
|
||||
use deno_config::workspace::FolderConfigs;
|
||||
use deno_config::workspace::PackageJsonDepResolution;
|
||||
use deno_config::workspace::VendorEnablement;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_config::workspace::WorkspaceDirectoryEmptyOptions;
|
||||
use deno_config::workspace::WorkspaceDiscoverError;
|
||||
use deno_config::workspace::WorkspaceDiscoverOptions;
|
||||
use deno_config::workspace::WorkspaceDiscoverStart;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
|
||||
use deno_path_util::normalize_path;
|
||||
use futures::future::FutureExt;
|
||||
use node_resolver::ConditionsFromResolutionMode;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolver;
|
||||
use node_resolver::NodeResolverRc;
|
||||
use node_resolver::PackageJsonResolver;
|
||||
use node_resolver::PackageJsonResolverRc;
|
||||
use sys_traits::EnvCacheDir;
|
||||
use sys_traits::EnvCurrentDir;
|
||||
use sys_traits::EnvHomeDir;
|
||||
use sys_traits::EnvVar;
|
||||
use sys_traits::FsCanonicalize;
|
||||
use sys_traits::FsCreateDirAll;
|
||||
use sys_traits::FsMetadata;
|
||||
use sys_traits::FsOpen;
|
||||
use sys_traits::FsRead;
|
||||
use sys_traits::FsReadDir;
|
||||
use sys_traits::FsRemoveFile;
|
||||
use sys_traits::FsRename;
|
||||
use sys_traits::SystemRandom;
|
||||
use sys_traits::SystemTimeNow;
|
||||
use sys_traits::ThreadSleep;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
|
||||
use crate::npm::managed::ManagedNpmResolverCreateOptions;
|
||||
use crate::npm::managed::NpmResolutionCellRc;
|
||||
use crate::npm::ByonmNpmResolverCreateOptions;
|
||||
use crate::npm::CreateInNpmPkgCheckerOptions;
|
||||
use crate::npm::DenoInNpmPackageChecker;
|
||||
use crate::npm::NpmReqResolver;
|
||||
use crate::npm::NpmReqResolverOptions;
|
||||
use crate::npm::NpmReqResolverRc;
|
||||
use crate::npm::NpmResolver;
|
||||
use crate::npm::NpmResolverCreateOptions;
|
||||
use crate::npmrc::discover_npmrc_from_workspace;
|
||||
use crate::npmrc::NpmRcDiscoverError;
|
||||
use crate::npmrc::ResolvedNpmRcRc;
|
||||
use crate::sloppy_imports::SloppyImportsCachedFs;
|
||||
use crate::sloppy_imports::SloppyImportsResolver;
|
||||
use crate::sloppy_imports::SloppyImportsResolverRc;
|
||||
use crate::sync::new_rc;
|
||||
use crate::sync::MaybeSend;
|
||||
use crate::sync::MaybeSync;
|
||||
use crate::DefaultDenoResolverRc;
|
||||
use crate::DenoResolver;
|
||||
use crate::DenoResolverOptions;
|
||||
use crate::NodeAndNpmReqResolver;
|
||||
use crate::NpmCacheDirRc;
|
||||
use crate::WorkspaceResolverRc;
|
||||
|
||||
// todo(https://github.com/rust-lang/rust/issues/109737): remove once_cell after get_or_try_init is stabilized
|
||||
#[cfg(feature = "sync")]
|
||||
type Deferred<T> = once_cell::sync::OnceCell<T>;
|
||||
#[cfg(not(feature = "sync"))]
|
||||
type Deferred<T> = once_cell::unsync::OnceCell<T>;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type WorkspaceDirectoryRc = crate::sync::MaybeArc<WorkspaceDirectory>;
|
||||
|
||||
#[derive(Debug, Boxed)]
|
||||
pub struct HttpCacheCreateError(pub Box<HttpCacheCreateErrorKind>);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum HttpCacheCreateErrorKind {
|
||||
#[error(transparent)]
|
||||
DenoDirResolution(#[from] DenoDirResolutionError),
|
||||
#[error(transparent)]
|
||||
WorkspaceDiscover(#[from] WorkspaceDiscoverError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Boxed)]
|
||||
pub struct NpmCacheDirCreateError(pub Box<NpmCacheDirCreateErrorKind>);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NpmCacheDirCreateErrorKind {
|
||||
#[error(transparent)]
|
||||
DenoDirResolution(#[from] DenoDirResolutionError),
|
||||
#[error(transparent)]
|
||||
NpmRcCreate(#[from] NpmRcCreateError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Boxed)]
|
||||
pub struct NpmRcCreateError(pub Box<NpmRcCreateErrorKind>);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NpmRcCreateErrorKind {
|
||||
#[error(transparent)]
|
||||
WorkspaceDiscover(#[from] WorkspaceDiscoverError),
|
||||
#[error(transparent)]
|
||||
NpmRcDiscover(#[from] NpmRcDiscoverError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum ConfigDiscoveryOption {
|
||||
#[default]
|
||||
DiscoverCwd,
|
||||
Discover {
|
||||
start_paths: Vec<PathBuf>,
|
||||
},
|
||||
Path(PathBuf),
|
||||
Disabled,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
pub trait SpecifiedImportMapProvider:
|
||||
std::fmt::Debug + MaybeSend + MaybeSync
|
||||
{
|
||||
async fn get(
|
||||
&self,
|
||||
) -> Result<Option<deno_config::workspace::SpecifiedImportMap>, anyhow::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DenoDirPathProviderOptions {
|
||||
pub maybe_custom_root: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type DenoDirPathProviderRc<TSys> =
|
||||
crate::sync::MaybeArc<DenoDirPathProvider<TSys>>;
|
||||
|
||||
/// Lazily creates the deno dir which might be useful in scenarios
|
||||
/// where functionality wants to continue if the DENO_DIR can't be created.
|
||||
#[derive(Debug)]
|
||||
pub struct DenoDirPathProvider<
|
||||
TSys: EnvCacheDir + EnvHomeDir + EnvVar + EnvCurrentDir,
|
||||
> {
|
||||
sys: TSys,
|
||||
options: DenoDirPathProviderOptions,
|
||||
deno_dir: Deferred<PathBuf>,
|
||||
}
|
||||
|
||||
impl<TSys: EnvCacheDir + EnvHomeDir + EnvVar + EnvCurrentDir>
|
||||
DenoDirPathProvider<TSys>
|
||||
{
|
||||
pub fn new(sys: TSys, options: DenoDirPathProviderOptions) -> Self {
|
||||
Self {
|
||||
sys,
|
||||
options,
|
||||
deno_dir: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_create(&self) -> Result<&PathBuf, DenoDirResolutionError> {
|
||||
self.deno_dir.get_or_try_init(|| {
|
||||
deno_cache_dir::resolve_deno_dir(
|
||||
&self.sys,
|
||||
self.options.maybe_custom_root.clone(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NpmProcessStateOptions {
|
||||
pub node_modules_dir: Option<Cow<'static, str>>,
|
||||
pub is_byonm: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WorkspaceFactoryOptions<
|
||||
TSys: EnvCacheDir + EnvHomeDir + EnvVar + EnvCurrentDir + FsCanonicalize,
|
||||
> {
|
||||
pub additional_config_file_names: &'static [&'static str],
|
||||
pub config_discovery: ConfigDiscoveryOption,
|
||||
pub deno_dir_path_provider: Option<DenoDirPathProviderRc<TSys>>,
|
||||
pub is_package_manager_subcommand: bool,
|
||||
pub node_modules_dir: Option<NodeModulesDirMode>,
|
||||
pub no_npm: bool,
|
||||
/// The process sate if using ext/node and the current process was "forked".
|
||||
/// This value is found at `deno_lib::args::NPM_PROCESS_STATE`
|
||||
/// but in most scenarios this can probably just be `None`.
|
||||
pub npm_process_state: Option<NpmProcessStateOptions>,
|
||||
pub vendor: Option<bool>,
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type WorkspaceFactoryRc<TSys> =
|
||||
crate::sync::MaybeArc<WorkspaceFactory<TSys>>;
|
||||
|
||||
pub struct WorkspaceFactory<
|
||||
TSys: EnvCacheDir
|
||||
+ EnvHomeDir
|
||||
+ EnvVar
|
||||
+ EnvCurrentDir
|
||||
+ FsCanonicalize
|
||||
+ FsCreateDirAll
|
||||
+ FsMetadata
|
||||
+ FsOpen
|
||||
+ FsRead
|
||||
+ FsReadDir
|
||||
+ FsRemoveFile
|
||||
+ FsRename
|
||||
+ SystemRandom
|
||||
+ SystemTimeNow
|
||||
+ ThreadSleep
|
||||
+ std::fmt::Debug
|
||||
+ MaybeSend
|
||||
+ MaybeSync
|
||||
+ Clone
|
||||
+ 'static,
|
||||
> {
|
||||
sys: TSys,
|
||||
deno_dir_path: DenoDirPathProviderRc<TSys>,
|
||||
global_http_cache: Deferred<GlobalHttpCacheRc<TSys>>,
|
||||
http_cache: Deferred<HttpCacheRc>,
|
||||
node_modules_dir_path: Deferred<Option<PathBuf>>,
|
||||
npm_cache_dir: Deferred<NpmCacheDirRc>,
|
||||
npmrc: Deferred<ResolvedNpmRcRc>,
|
||||
node_modules_dir_mode: Deferred<NodeModulesDirMode>,
|
||||
workspace_directory: Deferred<WorkspaceDirectoryRc>,
|
||||
initial_cwd: PathBuf,
|
||||
options: WorkspaceFactoryOptions<TSys>,
|
||||
}
|
||||
|
||||
impl<
|
||||
TSys: EnvCacheDir
|
||||
+ EnvHomeDir
|
||||
+ EnvVar
|
||||
+ EnvCurrentDir
|
||||
+ FsCanonicalize
|
||||
+ FsCreateDirAll
|
||||
+ FsMetadata
|
||||
+ FsOpen
|
||||
+ FsRead
|
||||
+ FsReadDir
|
||||
+ FsRemoveFile
|
||||
+ FsRename
|
||||
+ SystemRandom
|
||||
+ SystemTimeNow
|
||||
+ ThreadSleep
|
||||
+ std::fmt::Debug
|
||||
+ MaybeSend
|
||||
+ MaybeSync
|
||||
+ Clone
|
||||
+ 'static,
|
||||
> WorkspaceFactory<TSys>
|
||||
{
|
||||
pub fn new(
|
||||
sys: TSys,
|
||||
initial_cwd: PathBuf,
|
||||
mut options: WorkspaceFactoryOptions<TSys>,
|
||||
) -> Self {
|
||||
Self {
|
||||
deno_dir_path: options.deno_dir_path_provider.take().unwrap_or_else(
|
||||
|| {
|
||||
new_rc(DenoDirPathProvider::new(
|
||||
sys.clone(),
|
||||
DenoDirPathProviderOptions {
|
||||
maybe_custom_root: None,
|
||||
},
|
||||
))
|
||||
},
|
||||
),
|
||||
sys,
|
||||
global_http_cache: Default::default(),
|
||||
http_cache: Default::default(),
|
||||
node_modules_dir_path: Default::default(),
|
||||
npm_cache_dir: Default::default(),
|
||||
npmrc: Default::default(),
|
||||
node_modules_dir_mode: Default::default(),
|
||||
workspace_directory: Default::default(),
|
||||
initial_cwd,
|
||||
options,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_workspace_directory(
|
||||
&mut self,
|
||||
workspace_directory: WorkspaceDirectoryRc,
|
||||
) {
|
||||
self.workspace_directory = Deferred::from(workspace_directory);
|
||||
}
|
||||
|
||||
pub fn initial_cwd(&self) -> &PathBuf {
|
||||
&self.initial_cwd
|
||||
}
|
||||
|
||||
pub fn no_npm(&self) -> bool {
|
||||
self.options.no_npm
|
||||
}
|
||||
|
||||
pub fn node_modules_dir_mode(
|
||||
&self,
|
||||
) -> Result<NodeModulesDirMode, anyhow::Error> {
|
||||
self
|
||||
.node_modules_dir_mode
|
||||
.get_or_try_init(|| {
|
||||
let raw_resolve = || -> Result<_, anyhow::Error> {
|
||||
if let Some(process_state) = &self.options.npm_process_state {
|
||||
if process_state.is_byonm {
|
||||
return Ok(NodeModulesDirMode::Manual);
|
||||
}
|
||||
if process_state.node_modules_dir.is_some() {
|
||||
return Ok(NodeModulesDirMode::Auto);
|
||||
} else {
|
||||
return Ok(NodeModulesDirMode::None);
|
||||
}
|
||||
}
|
||||
if let Some(flag) = self.options.node_modules_dir {
|
||||
return Ok(flag);
|
||||
}
|
||||
let workspace = &self.workspace_directory()?.workspace;
|
||||
if let Some(mode) = workspace.node_modules_dir()? {
|
||||
return Ok(mode);
|
||||
}
|
||||
|
||||
let workspace = &self.workspace_directory()?.workspace;
|
||||
|
||||
if let Some(pkg_json) = workspace.root_pkg_json() {
|
||||
if let Ok(deno_dir) = self.deno_dir_path() {
|
||||
// `deno_dir` can be symlink in macOS or on the CI
|
||||
if let Ok(deno_dir) =
|
||||
canonicalize_path_maybe_not_exists(&self.sys, deno_dir)
|
||||
{
|
||||
if pkg_json.path.starts_with(deno_dir) {
|
||||
// if the package.json is in deno_dir, then do not use node_modules
|
||||
// next to it as local node_modules dir
|
||||
return Ok(NodeModulesDirMode::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(NodeModulesDirMode::Manual)
|
||||
} else if workspace.vendor_dir_path().is_some() {
|
||||
Ok(NodeModulesDirMode::Auto)
|
||||
} else {
|
||||
// use the global cache
|
||||
Ok(NodeModulesDirMode::None)
|
||||
}
|
||||
};
|
||||
|
||||
let mode = raw_resolve()?;
|
||||
if mode == NodeModulesDirMode::Manual
|
||||
&& self.options.is_package_manager_subcommand
|
||||
{
|
||||
// force using the managed resolver for package management
|
||||
// sub commands so that it sets up the node_modules directory
|
||||
Ok(NodeModulesDirMode::Auto)
|
||||
} else {
|
||||
Ok(mode)
|
||||
}
|
||||
})
|
||||
.copied()
|
||||
}
|
||||
|
||||
/// Resolves the path to use for a local node_modules folder.
|
||||
pub fn node_modules_dir_path(&self) -> Result<Option<&Path>, anyhow::Error> {
|
||||
fn resolve_from_root(root_folder: &FolderConfigs, cwd: &Path) -> PathBuf {
|
||||
root_folder
|
||||
.deno_json
|
||||
.as_ref()
|
||||
.map(|c| Cow::Owned(c.dir_path()))
|
||||
.or_else(|| {
|
||||
root_folder
|
||||
.pkg_json
|
||||
.as_ref()
|
||||
.map(|c| Cow::Borrowed(c.dir_path()))
|
||||
})
|
||||
.unwrap_or(Cow::Borrowed(cwd))
|
||||
.join("node_modules")
|
||||
}
|
||||
|
||||
self
|
||||
.node_modules_dir_path
|
||||
.get_or_try_init(|| {
|
||||
if let Some(process_state) = &self.options.npm_process_state {
|
||||
return Ok(
|
||||
process_state
|
||||
.node_modules_dir
|
||||
.as_ref()
|
||||
.map(|p| PathBuf::from(p.as_ref())),
|
||||
);
|
||||
}
|
||||
|
||||
let mode = self.node_modules_dir_mode()?;
|
||||
let workspace = &self.workspace_directory()?.workspace;
|
||||
let root_folder = workspace.root_folder_configs();
|
||||
if !mode.uses_node_modules_dir() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let node_modules_dir =
|
||||
resolve_from_root(root_folder, &self.initial_cwd);
|
||||
|
||||
Ok(Some(canonicalize_path_maybe_not_exists(
|
||||
&self.sys,
|
||||
&node_modules_dir,
|
||||
)?))
|
||||
})
|
||||
.map(|p| p.as_deref())
|
||||
}
|
||||
|
||||
pub fn deno_dir_path(&self) -> Result<&PathBuf, DenoDirResolutionError> {
|
||||
self.deno_dir_path.get_or_create()
|
||||
}
|
||||
|
||||
pub fn global_http_cache(
|
||||
&self,
|
||||
) -> Result<&GlobalHttpCacheRc<TSys>, DenoDirResolutionError> {
|
||||
self.global_http_cache.get_or_try_init(|| {
|
||||
let global_cache_dir = self.deno_dir_path()?.join("remote");
|
||||
let global_http_cache = new_rc(deno_cache_dir::GlobalHttpCache::new(
|
||||
self.sys.clone(),
|
||||
global_cache_dir,
|
||||
));
|
||||
Ok(global_http_cache)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn http_cache(&self) -> Result<&HttpCacheRc, HttpCacheCreateError> {
|
||||
self.http_cache.get_or_try_init(|| {
|
||||
let global_cache = self.global_http_cache()?.clone();
|
||||
match self.workspace_directory()?.workspace.vendor_dir_path() {
|
||||
Some(local_path) => {
|
||||
let local_cache = LocalHttpCache::new(
|
||||
local_path.clone(),
|
||||
global_cache,
|
||||
deno_cache_dir::GlobalToLocalCopy::Allow,
|
||||
);
|
||||
Ok(new_rc(local_cache))
|
||||
}
|
||||
None => Ok(global_cache),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npm_cache_dir(
|
||||
&self,
|
||||
) -> Result<&NpmCacheDirRc, NpmCacheDirCreateError> {
|
||||
self.npm_cache_dir.get_or_try_init(|| {
|
||||
let npm_cache_dir = self.deno_dir_path()?.join("npm");
|
||||
Ok(new_rc(NpmCacheDir::new(
|
||||
&self.sys,
|
||||
npm_cache_dir,
|
||||
self.npmrc()?.get_all_known_registries_urls(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npmrc(&self) -> Result<&ResolvedNpmRcRc, NpmRcCreateError> {
|
||||
self.npmrc.get_or_try_init(|| {
|
||||
let (npmrc, _) = discover_npmrc_from_workspace(
|
||||
&self.sys,
|
||||
&self.workspace_directory()?.workspace,
|
||||
)?;
|
||||
Ok(new_rc(npmrc))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sys(&self) -> &TSys {
|
||||
&self.sys
|
||||
}
|
||||
|
||||
pub fn workspace_directory(
|
||||
&self,
|
||||
) -> Result<&WorkspaceDirectoryRc, WorkspaceDiscoverError> {
|
||||
self.workspace_directory.get_or_try_init(|| {
|
||||
let maybe_vendor_override = self.options.vendor.map(|v| match v {
|
||||
true => VendorEnablement::Enable {
|
||||
cwd: &self.initial_cwd,
|
||||
},
|
||||
false => VendorEnablement::Disable,
|
||||
});
|
||||
let resolve_workspace_discover_options = || {
|
||||
let discover_pkg_json = !self.options.no_npm
|
||||
&& !self.has_flag_env_var("DENO_NO_PACKAGE_JSON");
|
||||
if !discover_pkg_json {
|
||||
log::debug!("package.json auto-discovery is disabled");
|
||||
}
|
||||
WorkspaceDiscoverOptions {
|
||||
deno_json_cache: None,
|
||||
pkg_json_cache: Some(&node_resolver::PackageJsonThreadLocalCache),
|
||||
workspace_cache: None,
|
||||
additional_config_file_names: self
|
||||
.options
|
||||
.additional_config_file_names,
|
||||
discover_pkg_json,
|
||||
maybe_vendor_override,
|
||||
}
|
||||
};
|
||||
let resolve_empty_options = || WorkspaceDirectoryEmptyOptions {
|
||||
root_dir: new_rc(
|
||||
deno_path_util::url_from_directory_path(&self.initial_cwd).unwrap(),
|
||||
),
|
||||
use_vendor_dir: maybe_vendor_override
|
||||
.unwrap_or(VendorEnablement::Disable),
|
||||
};
|
||||
|
||||
let dir = match &self.options.config_discovery {
|
||||
ConfigDiscoveryOption::DiscoverCwd => WorkspaceDirectory::discover(
|
||||
&self.sys,
|
||||
WorkspaceDiscoverStart::Paths(&[self.initial_cwd.clone()]),
|
||||
&resolve_workspace_discover_options(),
|
||||
)?,
|
||||
ConfigDiscoveryOption::Discover { start_paths } => {
|
||||
WorkspaceDirectory::discover(
|
||||
&self.sys,
|
||||
WorkspaceDiscoverStart::Paths(start_paths),
|
||||
&resolve_workspace_discover_options(),
|
||||
)?
|
||||
}
|
||||
ConfigDiscoveryOption::Path(path) => {
|
||||
let config_path = normalize_path(self.initial_cwd.join(path));
|
||||
WorkspaceDirectory::discover(
|
||||
&self.sys,
|
||||
WorkspaceDiscoverStart::ConfigFile(&config_path),
|
||||
&resolve_workspace_discover_options(),
|
||||
)?
|
||||
}
|
||||
ConfigDiscoveryOption::Disabled => {
|
||||
WorkspaceDirectory::empty(resolve_empty_options())
|
||||
}
|
||||
};
|
||||
Ok(new_rc(dir))
|
||||
})
|
||||
}
|
||||
|
||||
fn has_flag_env_var(&self, name: &str) -> bool {
|
||||
let value = self.sys.env_var_os(name);
|
||||
match value {
|
||||
Some(value) => value == "1",
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ResolverFactoryOptions {
|
||||
pub conditions_from_resolution_mode: ConditionsFromResolutionMode,
|
||||
pub no_sloppy_imports_cache: bool,
|
||||
pub npm_system_info: NpmSystemInfo,
|
||||
pub package_json_dep_resolution: Option<PackageJsonDepResolution>,
|
||||
pub specified_import_map: Option<Box<dyn SpecifiedImportMapProvider>>,
|
||||
pub unstable_sloppy_imports: bool,
|
||||
}
|
||||
|
||||
pub struct ResolverFactory<
|
||||
TSys: EnvCacheDir
|
||||
+ EnvCurrentDir
|
||||
+ EnvHomeDir
|
||||
+ EnvVar
|
||||
+ FsCanonicalize
|
||||
+ FsCreateDirAll
|
||||
+ FsMetadata
|
||||
+ FsOpen
|
||||
+ FsRead
|
||||
+ FsReadDir
|
||||
+ FsRemoveFile
|
||||
+ FsRename
|
||||
+ ThreadSleep
|
||||
+ SystemRandom
|
||||
+ SystemTimeNow
|
||||
+ std::fmt::Debug
|
||||
+ MaybeSend
|
||||
+ MaybeSync
|
||||
+ Clone
|
||||
+ 'static,
|
||||
> {
|
||||
options: ResolverFactoryOptions,
|
||||
deno_resolver: async_once_cell::OnceCell<DefaultDenoResolverRc<TSys>>,
|
||||
in_npm_package_checker: Deferred<DenoInNpmPackageChecker>,
|
||||
node_resolver: Deferred<
|
||||
NodeResolverRc<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
NpmResolver<TSys>,
|
||||
TSys,
|
||||
>,
|
||||
>,
|
||||
npm_req_resolver: Deferred<
|
||||
NpmReqResolverRc<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
NpmResolver<TSys>,
|
||||
TSys,
|
||||
>,
|
||||
>,
|
||||
npm_resolver: Deferred<NpmResolver<TSys>>,
|
||||
npm_resolution: NpmResolutionCellRc,
|
||||
pkg_json_resolver: Deferred<PackageJsonResolverRc<TSys>>,
|
||||
sloppy_imports_resolver:
|
||||
Deferred<Option<SloppyImportsResolverRc<SloppyImportsCachedFs<TSys>>>>,
|
||||
workspace_factory: WorkspaceFactoryRc<TSys>,
|
||||
workspace_resolver: async_once_cell::OnceCell<WorkspaceResolverRc>,
|
||||
}
|
||||
|
||||
impl<
|
||||
TSys: EnvCacheDir
|
||||
+ EnvCurrentDir
|
||||
+ EnvHomeDir
|
||||
+ EnvVar
|
||||
+ FsCanonicalize
|
||||
+ FsCreateDirAll
|
||||
+ FsMetadata
|
||||
+ FsOpen
|
||||
+ FsRead
|
||||
+ FsReadDir
|
||||
+ FsRemoveFile
|
||||
+ FsRename
|
||||
+ ThreadSleep
|
||||
+ SystemRandom
|
||||
+ SystemTimeNow
|
||||
+ std::fmt::Debug
|
||||
+ MaybeSend
|
||||
+ MaybeSync
|
||||
+ Clone
|
||||
+ 'static,
|
||||
> ResolverFactory<TSys>
|
||||
{
|
||||
pub fn new(
|
||||
workspace_factory: WorkspaceFactoryRc<TSys>,
|
||||
options: ResolverFactoryOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
options,
|
||||
deno_resolver: Default::default(),
|
||||
in_npm_package_checker: Default::default(),
|
||||
node_resolver: Default::default(),
|
||||
npm_req_resolver: Default::default(),
|
||||
npm_resolution: Default::default(),
|
||||
npm_resolver: Default::default(),
|
||||
pkg_json_resolver: Default::default(),
|
||||
sloppy_imports_resolver: Default::default(),
|
||||
workspace_factory,
|
||||
workspace_resolver: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn deno_resolver(
|
||||
&self,
|
||||
) -> Result<&DefaultDenoResolverRc<TSys>, anyhow::Error> {
|
||||
self
|
||||
.deno_resolver
|
||||
.get_or_try_init(
|
||||
async {
|
||||
Ok(new_rc(DenoResolver::new(DenoResolverOptions {
|
||||
in_npm_pkg_checker: self.in_npm_package_checker()?.clone(),
|
||||
node_and_req_resolver: if self.workspace_factory.no_npm() {
|
||||
None
|
||||
} else {
|
||||
Some(NodeAndNpmReqResolver {
|
||||
node_resolver: self.node_resolver()?.clone(),
|
||||
npm_req_resolver: self.npm_req_resolver()?.clone(),
|
||||
})
|
||||
},
|
||||
is_byonm: self.use_byonm()?,
|
||||
maybe_vendor_dir: self
|
||||
.workspace_factory
|
||||
.workspace_directory()?
|
||||
.workspace
|
||||
.vendor_dir_path(),
|
||||
sloppy_imports_resolver: self.sloppy_imports_resolver()?.cloned(),
|
||||
workspace_resolver: self.workspace_resolver().await?.clone(),
|
||||
})))
|
||||
}
|
||||
// boxed to prevent the futures getting big and exploding the stack
|
||||
.boxed_local(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn in_npm_package_checker(
|
||||
&self,
|
||||
) -> Result<&DenoInNpmPackageChecker, anyhow::Error> {
|
||||
self.in_npm_package_checker.get_or_try_init(|| {
|
||||
let options = match self.use_byonm()? {
|
||||
true => CreateInNpmPkgCheckerOptions::Byonm,
|
||||
false => CreateInNpmPkgCheckerOptions::Managed(
|
||||
ManagedInNpmPkgCheckerCreateOptions {
|
||||
root_cache_dir_url: self
|
||||
.workspace_factory
|
||||
.npm_cache_dir()?
|
||||
.root_dir_url(),
|
||||
maybe_node_modules_path: self
|
||||
.workspace_factory
|
||||
.node_modules_dir_path()?,
|
||||
},
|
||||
),
|
||||
};
|
||||
Ok(DenoInNpmPackageChecker::new(options))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn node_resolver(
|
||||
&self,
|
||||
) -> Result<
|
||||
&NodeResolverRc<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
NpmResolver<TSys>,
|
||||
TSys,
|
||||
>,
|
||||
anyhow::Error,
|
||||
> {
|
||||
self.node_resolver.get_or_try_init(|| {
|
||||
Ok(new_rc(NodeResolver::new(
|
||||
self.in_npm_package_checker()?.clone(),
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
self.npm_resolver()?.clone(),
|
||||
self.pkg_json_resolver().clone(),
|
||||
self.workspace_factory.sys.clone(),
|
||||
self.options.conditions_from_resolution_mode.clone(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npm_resolution(&self) -> &NpmResolutionCellRc {
|
||||
&self.npm_resolution
|
||||
}
|
||||
|
||||
pub fn npm_req_resolver(
|
||||
&self,
|
||||
) -> Result<
|
||||
&NpmReqResolverRc<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
NpmResolver<TSys>,
|
||||
TSys,
|
||||
>,
|
||||
anyhow::Error,
|
||||
> {
|
||||
self.npm_req_resolver.get_or_try_init(|| {
|
||||
Ok(new_rc(NpmReqResolver::new(NpmReqResolverOptions {
|
||||
in_npm_pkg_checker: self.in_npm_package_checker()?.clone(),
|
||||
node_resolver: self.node_resolver()?.clone(),
|
||||
npm_resolver: self.npm_resolver()?.clone(),
|
||||
sys: self.workspace_factory.sys.clone(),
|
||||
})))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn npm_resolver(&self) -> Result<&NpmResolver<TSys>, anyhow::Error> {
|
||||
self.npm_resolver.get_or_try_init(|| {
|
||||
Ok(NpmResolver::<TSys>::new::<TSys>(if self.use_byonm()? {
|
||||
NpmResolverCreateOptions::Byonm(ByonmNpmResolverCreateOptions {
|
||||
sys: self.workspace_factory.sys.clone(),
|
||||
pkg_json_resolver: self.pkg_json_resolver().clone(),
|
||||
root_node_modules_dir: Some(
|
||||
match self.workspace_factory.node_modules_dir_path()? {
|
||||
Some(node_modules_path) => node_modules_path.to_path_buf(),
|
||||
// path needs to be canonicalized for node resolution
|
||||
// (node_modules_dir_path above is already canonicalized)
|
||||
None => canonicalize_path_maybe_not_exists(
|
||||
&self.workspace_factory.sys,
|
||||
self.workspace_factory.initial_cwd(),
|
||||
)?
|
||||
.join("node_modules"),
|
||||
},
|
||||
),
|
||||
})
|
||||
} else {
|
||||
NpmResolverCreateOptions::Managed(ManagedNpmResolverCreateOptions {
|
||||
sys: self.workspace_factory.sys.clone(),
|
||||
npm_resolution: self.npm_resolution().clone(),
|
||||
npm_cache_dir: self.workspace_factory.npm_cache_dir()?.clone(),
|
||||
maybe_node_modules_path: self
|
||||
.workspace_factory
|
||||
.node_modules_dir_path()?
|
||||
.map(|p| p.to_path_buf()),
|
||||
npm_system_info: self.options.npm_system_info.clone(),
|
||||
npmrc: self.workspace_factory.npmrc()?.clone(),
|
||||
})
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pkg_json_resolver(&self) -> &PackageJsonResolverRc<TSys> {
|
||||
self.pkg_json_resolver.get_or_init(|| {
|
||||
new_rc(PackageJsonResolver::new(self.workspace_factory.sys.clone()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sloppy_imports_resolver(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<&SloppyImportsResolverRc<SloppyImportsCachedFs<TSys>>>,
|
||||
anyhow::Error,
|
||||
> {
|
||||
self
|
||||
.sloppy_imports_resolver
|
||||
.get_or_try_init(|| {
|
||||
let enabled = self.options.unstable_sloppy_imports
|
||||
|| self
|
||||
.workspace_factory
|
||||
.workspace_directory()?
|
||||
.workspace
|
||||
.has_unstable("sloppy-imports");
|
||||
if enabled {
|
||||
Ok(Some(new_rc(SloppyImportsResolver::new(
|
||||
if self.options.no_sloppy_imports_cache {
|
||||
SloppyImportsCachedFs::new_without_stat_cache(
|
||||
self.workspace_factory.sys.clone(),
|
||||
)
|
||||
} else {
|
||||
SloppyImportsCachedFs::new(self.workspace_factory.sys.clone())
|
||||
},
|
||||
))))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
.map(|v| v.as_ref())
|
||||
}
|
||||
|
||||
pub async fn workspace_resolver(
|
||||
&self,
|
||||
) -> Result<&WorkspaceResolverRc, anyhow::Error> {
|
||||
self
|
||||
.workspace_resolver
|
||||
.get_or_try_init(
|
||||
async {
|
||||
let directory = self.workspace_factory.workspace_directory()?;
|
||||
let workspace = &directory.workspace;
|
||||
let specified_import_map = match &self.options.specified_import_map {
|
||||
Some(import_map) => import_map.get().await?,
|
||||
None => None,
|
||||
};
|
||||
let options = deno_config::workspace::CreateResolverOptions {
|
||||
pkg_json_dep_resolution: match self
|
||||
.options
|
||||
.package_json_dep_resolution
|
||||
{
|
||||
Some(value) => value,
|
||||
None => {
|
||||
match self.workspace_factory.node_modules_dir_mode()? {
|
||||
NodeModulesDirMode::Manual => {
|
||||
PackageJsonDepResolution::Disabled
|
||||
}
|
||||
NodeModulesDirMode::Auto | NodeModulesDirMode::None => {
|
||||
// todo(dsherret): should this be disabled for auto?
|
||||
PackageJsonDepResolution::Enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
specified_import_map,
|
||||
};
|
||||
let resolver =
|
||||
workspace.create_resolver(&self.workspace_factory.sys, options)?;
|
||||
if !resolver.diagnostics().is_empty() {
|
||||
// todo(dsherret): do not log this in this crate... that should be
|
||||
// a CLI responsibility
|
||||
log::warn!(
|
||||
"Import map diagnostics:\n{}",
|
||||
resolver
|
||||
.diagnostics()
|
||||
.iter()
|
||||
.map(|d| format!(" - {d}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
);
|
||||
}
|
||||
Ok(new_rc(resolver))
|
||||
}
|
||||
// boxed to prevent the futures getting big and exploding the stack
|
||||
.boxed_local(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn use_byonm(&self) -> Result<bool, anyhow::Error> {
|
||||
Ok(
|
||||
self.workspace_factory.node_modules_dir_mode()?
|
||||
== NodeModulesDirMode::Manual,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ use deno_config::workspace::MappedResolutionError;
|
|||
use deno_config::workspace::WorkspaceResolvePkgJsonFolderError;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_error::JsError;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_package_json::PackageJsonDepValueParseError;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
|
@ -43,16 +42,15 @@ use thiserror::Error;
|
|||
use url::Url;
|
||||
|
||||
pub mod cjs;
|
||||
pub mod factory;
|
||||
pub mod npm;
|
||||
pub mod npmrc;
|
||||
pub mod sloppy_imports;
|
||||
mod sync;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type WorkspaceResolverRc = crate::sync::MaybeArc<WorkspaceResolver>;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub(crate) type ResolvedNpmRcRc = crate::sync::MaybeArc<ResolvedNpmRc>;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub(crate) type NpmCacheDirRc = crate::sync::MaybeArc<NpmCacheDir>;
|
||||
|
||||
|
@ -148,6 +146,33 @@ pub struct DenoResolverOptions<
|
|||
pub maybe_vendor_dir: Option<&'a PathBuf>,
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type DenoResolverRc<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSloppyImportResolverFs,
|
||||
TSys,
|
||||
> = crate::sync::MaybeArc<
|
||||
DenoResolver<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSloppyImportResolverFs,
|
||||
TSys,
|
||||
>,
|
||||
>;
|
||||
|
||||
/// Helper type for a DenoResolverRc that has the implementations
|
||||
/// used by the Deno CLI.
|
||||
pub type DefaultDenoResolverRc<TSys> = DenoResolverRc<
|
||||
npm::DenoInNpmPackageChecker,
|
||||
node_resolver::DenoIsBuiltInNodeModuleChecker,
|
||||
npm::NpmResolver<TSys>,
|
||||
sloppy_imports::SloppyImportsCachedFs<TSys>,
|
||||
TSys,
|
||||
>;
|
||||
|
||||
/// A resolver that takes care of resolution, taking into account loaded
|
||||
/// import map, JSX settings.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -17,7 +17,7 @@ use url::Url;
|
|||
|
||||
use super::resolution::NpmResolutionCellRc;
|
||||
use super::NpmCacheDirRc;
|
||||
use crate::ResolvedNpmRcRc;
|
||||
use crate::npmrc::ResolvedNpmRcRc;
|
||||
|
||||
/// Resolves packages from the global npm cache.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -28,8 +28,8 @@ use self::global::GlobalNpmPackageResolver;
|
|||
use self::local::LocalNpmPackageResolver;
|
||||
pub use self::resolution::NpmResolutionCell;
|
||||
pub use self::resolution::NpmResolutionCellRc;
|
||||
use crate::npmrc::ResolvedNpmRcRc;
|
||||
use crate::NpmCacheDirRc;
|
||||
use crate::ResolvedNpmRcRc;
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
pub enum ResolvePkgFolderFromDenoModuleError {
|
||||
|
@ -268,6 +268,7 @@ impl InNpmPackageChecker for ManagedInNpmPackageChecker {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ManagedInNpmPkgCheckerCreateOptions<'a> {
|
||||
pub root_cache_dir_url: &'a Url,
|
||||
pub maybe_node_modules_path: Option<&'a Path>,
|
||||
|
|
|
@ -50,6 +50,7 @@ mod byonm;
|
|||
mod local;
|
||||
pub mod managed;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CreateInNpmPkgCheckerOptions<'a> {
|
||||
Managed(ManagedInNpmPkgCheckerCreateOptions<'a>),
|
||||
Byonm,
|
||||
|
|
200
resolvers/deno/npmrc.rs
Normal file
200
resolvers/deno/npmrc.rs
Normal file
|
@ -0,0 +1,200 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use boxed_error::Boxed;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_npm::npm_rc::NpmRc;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use sys_traits::EnvHomeDir;
|
||||
use sys_traits::EnvVar;
|
||||
use sys_traits::FsRead;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type ResolvedNpmRcRc = crate::sync::MaybeArc<ResolvedNpmRc>;
|
||||
|
||||
#[derive(Debug, Boxed)]
|
||||
pub struct NpmRcDiscoverError(pub Box<NpmRcDiscoverErrorKind>);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NpmRcDiscoverErrorKind {
|
||||
#[error(transparent)]
|
||||
Load(#[from] NpmRcLoadError),
|
||||
#[error(transparent)]
|
||||
Parse(#[from] NpmRcParseError),
|
||||
#[error(transparent)]
|
||||
Resolve(#[from] NpmRcOptionsResolveError),
|
||||
#[error(transparent)]
|
||||
UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Error loading .npmrc at {}.", path.display())]
|
||||
pub struct NpmRcLoadError {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Failed to parse .npmrc at {}.", path.display())]
|
||||
pub struct NpmRcParseError {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Failed to resolve .npmrc options at {}.", path.display())]
|
||||
pub struct NpmRcOptionsResolveError {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: deno_npm::npm_rc::ResolveError,
|
||||
}
|
||||
|
||||
/// Discover `.npmrc` file - currently we only support it next to `package.json`,
|
||||
/// next to `deno.json`, or in the user's home directory.
|
||||
///
|
||||
/// In the future we will need to support it in the global directory
|
||||
/// as per https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#files.
|
||||
pub fn discover_npmrc_from_workspace<TSys: EnvVar + EnvHomeDir + FsRead>(
|
||||
sys: &TSys,
|
||||
workspace: &Workspace,
|
||||
) -> Result<(ResolvedNpmRc, Option<PathBuf>), NpmRcDiscoverError> {
|
||||
let root_folder = workspace.root_folder_configs();
|
||||
discover_npmrc(
|
||||
sys,
|
||||
root_folder.pkg_json.as_ref().map(|p| p.path.clone()),
|
||||
match &root_folder.deno_json {
|
||||
Some(cf) if cf.specifier.scheme() == "file" => {
|
||||
Some(deno_path_util::url_to_file_path(&cf.specifier)?)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn discover_npmrc<TSys: EnvVar + EnvHomeDir + FsRead>(
|
||||
sys: &TSys,
|
||||
maybe_package_json_path: Option<PathBuf>,
|
||||
maybe_deno_json_path: Option<PathBuf>,
|
||||
) -> Result<(ResolvedNpmRc, Option<PathBuf>), NpmRcDiscoverError> {
|
||||
const NPMRC_NAME: &str = ".npmrc";
|
||||
|
||||
fn try_to_read_npmrc(
|
||||
sys: &impl FsRead,
|
||||
dir: &Path,
|
||||
) -> Result<Option<(Cow<'static, str>, PathBuf)>, NpmRcLoadError> {
|
||||
let path = dir.join(NPMRC_NAME);
|
||||
let maybe_source = match sys.fs_read_to_string(&path) {
|
||||
Ok(source) => Some(source),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
|
||||
Err(err) => return Err(NpmRcLoadError { path, source: err }),
|
||||
};
|
||||
|
||||
Ok(maybe_source.map(|source| (source, path)))
|
||||
}
|
||||
|
||||
fn try_to_parse_npmrc(
|
||||
sys: &impl EnvVar,
|
||||
source: &str,
|
||||
path: &Path,
|
||||
) -> Result<ResolvedNpmRc, NpmRcDiscoverError> {
|
||||
let npmrc = NpmRc::parse(source, &|name| sys.env_var(name).ok()).map_err(
|
||||
|source| {
|
||||
NpmRcParseError {
|
||||
path: path.to_path_buf(),
|
||||
// todo(dsherret): use source directly here once it's no longer an internal type
|
||||
source: std::io::Error::new(std::io::ErrorKind::InvalidData, source),
|
||||
}
|
||||
},
|
||||
)?;
|
||||
let resolved =
|
||||
npmrc
|
||||
.as_resolved(&npm_registry_url(sys))
|
||||
.map_err(|source| NpmRcOptionsResolveError {
|
||||
path: path.to_path_buf(),
|
||||
source,
|
||||
})?;
|
||||
log::debug!(".npmrc found at: '{}'", path.display());
|
||||
Ok(resolved)
|
||||
}
|
||||
|
||||
// 1. Try `.npmrc` next to `package.json`
|
||||
if let Some(package_json_path) = maybe_package_json_path {
|
||||
if let Some(package_json_dir) = package_json_path.parent() {
|
||||
if let Some((source, path)) = try_to_read_npmrc(sys, package_json_dir)? {
|
||||
return try_to_parse_npmrc(sys, &source, &path)
|
||||
.map(|r| (r, Some(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try `.npmrc` next to `deno.json(c)`
|
||||
if let Some(deno_json_path) = maybe_deno_json_path {
|
||||
if let Some(deno_json_dir) = deno_json_path.parent() {
|
||||
if let Some((source, path)) = try_to_read_npmrc(sys, deno_json_dir)? {
|
||||
return try_to_parse_npmrc(sys, &source, &path)
|
||||
.map(|r| (r, Some(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bartlomieju): update to read both files - one in the project root and one and
|
||||
// home dir and then merge them.
|
||||
// 3. Try `.npmrc` in the user's home directory
|
||||
if let Some(home_dir) = sys.env_home_dir() {
|
||||
match try_to_read_npmrc(sys, &home_dir) {
|
||||
Ok(Some((source, path))) => {
|
||||
return try_to_parse_npmrc(sys, &source, &path)
|
||||
.map(|r| (r, Some(path)));
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(err) if err.source.kind() == std::io::ErrorKind::PermissionDenied => {
|
||||
log::debug!(
|
||||
"Skipping .npmrc in home directory due to permission denied error. {:#}",
|
||||
err
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("No .npmrc file found");
|
||||
Ok((create_default_npmrc(sys), None))
|
||||
}
|
||||
|
||||
pub fn create_default_npmrc(sys: &impl EnvVar) -> ResolvedNpmRc {
|
||||
ResolvedNpmRc {
|
||||
default_config: deno_npm::npm_rc::RegistryConfigWithUrl {
|
||||
registry_url: npm_registry_url(sys).clone(),
|
||||
config: Default::default(),
|
||||
},
|
||||
scopes: Default::default(),
|
||||
registry_configs: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn npm_registry_url(sys: &impl EnvVar) -> Url {
|
||||
let env_var_name = "NPM_CONFIG_REGISTRY";
|
||||
if let Ok(registry_url) = sys.env_var(env_var_name) {
|
||||
// ensure there is a trailing slash for the directory
|
||||
let registry_url = format!("{}/", registry_url.trim_end_matches('/'));
|
||||
match Url::parse(®istry_url) {
|
||||
Ok(url) => {
|
||||
return url;
|
||||
}
|
||||
Err(err) => {
|
||||
log::debug!("Invalid {} environment variable: {:#}", env_var_name, err,);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Url::parse("https://registry.npmjs.org").unwrap()
|
||||
}
|
103
resolvers/node/builtin_modules.rs
Normal file
103
resolvers/node/builtin_modules.rs
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
pub trait IsBuiltInNodeModuleChecker: std::fmt::Debug {
|
||||
/// e.g. `is_builtin_node_module("assert")`
|
||||
fn is_builtin_node_module(&self, module_name: &str) -> bool;
|
||||
}
|
||||
|
||||
/// An implementation of IsBuiltInNodeModuleChecker that uses
|
||||
/// the list of built-in node_modules that are supported by Deno
|
||||
/// in the `deno_node` crate (ext/node).
|
||||
#[derive(Debug)]
|
||||
pub struct DenoIsBuiltInNodeModuleChecker;
|
||||
|
||||
impl IsBuiltInNodeModuleChecker for DenoIsBuiltInNodeModuleChecker {
|
||||
#[inline(always)]
|
||||
fn is_builtin_node_module(&self, module_name: &str) -> bool {
|
||||
DENO_SUPPORTED_BUILTIN_NODE_MODULES
|
||||
.binary_search(&module_name)
|
||||
.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Collection of built-in node_modules supported by Deno.
|
||||
pub static DENO_SUPPORTED_BUILTIN_NODE_MODULES: &[&str] = &[
|
||||
// NOTE(bartlomieju): keep this list in sync with `ext/node/polyfills/01_require.js`
|
||||
"_http_agent",
|
||||
"_http_common",
|
||||
"_http_outgoing",
|
||||
"_http_server",
|
||||
"_stream_duplex",
|
||||
"_stream_passthrough",
|
||||
"_stream_readable",
|
||||
"_stream_transform",
|
||||
"_stream_writable",
|
||||
"_tls_common",
|
||||
"_tls_wrap",
|
||||
"assert",
|
||||
"assert/strict",
|
||||
"async_hooks",
|
||||
"buffer",
|
||||
"child_process",
|
||||
"cluster",
|
||||
"console",
|
||||
"constants",
|
||||
"crypto",
|
||||
"dgram",
|
||||
"diagnostics_channel",
|
||||
"dns",
|
||||
"dns/promises",
|
||||
"domain",
|
||||
"events",
|
||||
"fs",
|
||||
"fs/promises",
|
||||
"http",
|
||||
"http2",
|
||||
"https",
|
||||
"inspector",
|
||||
"inspector/promises",
|
||||
"module",
|
||||
"net",
|
||||
"os",
|
||||
"path",
|
||||
"path/posix",
|
||||
"path/win32",
|
||||
"perf_hooks",
|
||||
"process",
|
||||
"punycode",
|
||||
"querystring",
|
||||
"readline",
|
||||
"readline/promises",
|
||||
"repl",
|
||||
"stream",
|
||||
"stream/consumers",
|
||||
"stream/promises",
|
||||
"stream/web",
|
||||
"string_decoder",
|
||||
"sys",
|
||||
"test",
|
||||
"timers",
|
||||
"timers/promises",
|
||||
"tls",
|
||||
"tty",
|
||||
"url",
|
||||
"util",
|
||||
"util/types",
|
||||
"v8",
|
||||
"vm",
|
||||
"wasi",
|
||||
"worker_threads",
|
||||
"zlib",
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_builtins_are_sorted() {
|
||||
let mut builtins_list = DENO_SUPPORTED_BUILTIN_NODE_MODULES.to_vec();
|
||||
builtins_list.sort();
|
||||
assert_eq!(DENO_SUPPORTED_BUILTIN_NODE_MODULES, builtins_list);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#![deny(clippy::print_stdout)]
|
||||
|
||||
pub mod analyze;
|
||||
mod builtin_modules;
|
||||
pub mod errors;
|
||||
mod npm;
|
||||
mod package_json;
|
||||
|
@ -12,6 +13,9 @@ mod resolution;
|
|||
|
||||
mod sync;
|
||||
|
||||
pub use builtin_modules::DenoIsBuiltInNodeModuleChecker;
|
||||
pub use builtin_modules::IsBuiltInNodeModuleChecker;
|
||||
pub use builtin_modules::DENO_SUPPORTED_BUILTIN_NODE_MODULES;
|
||||
pub use deno_package_json::PackageJson;
|
||||
pub use npm::InNpmPackageChecker;
|
||||
pub use npm::NpmPackageFolderResolver;
|
||||
|
@ -22,7 +26,6 @@ pub use path::PathClean;
|
|||
pub use resolution::parse_npm_pkg_name;
|
||||
pub use resolution::resolve_specifier_into_node_modules;
|
||||
pub use resolution::ConditionsFromResolutionMode;
|
||||
pub use resolution::IsBuiltInNodeModuleChecker;
|
||||
pub use resolution::NodeResolution;
|
||||
pub use resolution::NodeResolutionKind;
|
||||
pub use resolution::NodeResolver;
|
||||
|
|
|
@ -47,6 +47,7 @@ use crate::errors::TypesNotFoundErrorData;
|
|||
use crate::errors::UnsupportedDirImportError;
|
||||
use crate::errors::UnsupportedEsmUrlSchemeError;
|
||||
use crate::InNpmPackageChecker;
|
||||
use crate::IsBuiltInNodeModuleChecker;
|
||||
use crate::NpmPackageFolderResolver;
|
||||
use crate::PackageJsonResolverRc;
|
||||
use crate::PathClean;
|
||||
|
@ -55,11 +56,12 @@ pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"];
|
|||
pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"];
|
||||
static TYPES_ONLY_CONDITIONS: &[&str] = &["types"];
|
||||
|
||||
type ConditionsFromResolutionModeFn = Box<
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type ConditionsFromResolutionModeFn = crate::sync::MaybeArc<
|
||||
dyn Fn(ResolutionMode) -> &'static [&'static str] + Send + Sync + 'static,
|
||||
>;
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ConditionsFromResolutionMode(Option<ConditionsFromResolutionModeFn>);
|
||||
|
||||
impl Debug for ConditionsFromResolutionMode {
|
||||
|
@ -132,10 +134,6 @@ impl NodeResolution {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait IsBuiltInNodeModuleChecker: std::fmt::Debug {
|
||||
fn is_builtin_node_module(&self, specifier: &str) -> bool;
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NodeResolverRc<
|
||||
TInNpmPackageChecker,
|
||||
|
|
|
@ -17,7 +17,7 @@ path = "lib.rs"
|
|||
async-trait.workspace = true
|
||||
base64.workspace = true
|
||||
boxed_error.workspace = true
|
||||
deno_cache_dir.workspace = true
|
||||
deno_cache_dir = { workspace = true, features = ["sync"] }
|
||||
deno_error = { workspace = true, features = ["serde", "serde_json", "tokio"] }
|
||||
deno_npm.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
|
|
|
@ -65,7 +65,7 @@ deno_os.workspace = true
|
|||
deno_path_util.workspace = true
|
||||
deno_permissions.workspace = true
|
||||
deno_process.workspace = true
|
||||
deno_resolver.workspace = true
|
||||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_telemetry.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
deno_tls.workspace = true
|
||||
|
|
|
@ -41,6 +41,7 @@ itest!(require_resolve_url_paths {
|
|||
cwd: Some("npm/require_resolve_url/"),
|
||||
copy_temp_dir: Some("npm/require_resolve_url/"),
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn parallel_downloading() {
|
||||
let (out, _err) = util::run_and_collect_output_with_args(
|
||||
|
|
Loading…
Add table
Reference in a new issue