refactor: extract DenoDir, Emitter, EmitCache and ParsedSourceCache from cli crate (#29961)

This commit is contained in:
David Sherret 2025-07-02 08:56:02 -04:00 committed by GitHub
parent 45dfae18ee
commit 7a1e949c47
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 490 additions and 406 deletions

13
cli/cache/mod.rs vendored
View file

@ -4,14 +4,13 @@ mod cache_db;
mod caches; mod caches;
mod check; mod check;
mod code_cache; mod code_cache;
mod deno_dir;
mod disk_cache;
mod emit;
mod fast_check; mod fast_check;
mod incremental; mod incremental;
mod module_info; mod module_info;
mod node; mod node;
mod parsed_source;
pub type DenoDir = deno_resolver::cache::DenoDir<CliSys>;
pub type DenoDirProvider = deno_resolver::cache::DenoDirProvider<CliSys>;
pub use cache_db::CacheDBHash; pub use cache_db::CacheDBHash;
pub use caches::Caches; pub use caches::Caches;
@ -19,16 +18,10 @@ pub use check::TypeCheckCache;
pub use code_cache::CodeCache; pub use code_cache::CodeCache;
/// Permissions used to save a file in the disk caches. /// Permissions used to save a file in the disk caches.
pub use deno_cache_dir::CACHE_PERM; pub use deno_cache_dir::CACHE_PERM;
pub use deno_dir::DenoDir;
pub use deno_dir::DenoDirProvider;
pub use disk_cache::DiskCache;
pub use emit::EmitCache;
pub use fast_check::FastCheckCache; pub use fast_check::FastCheckCache;
pub use incremental::IncrementalCache; pub use incremental::IncrementalCache;
pub use module_info::ModuleInfoCache; pub use module_info::ModuleInfoCache;
pub use node::NodeAnalysisCache; pub use node::NodeAnalysisCache;
pub use parsed_source::LazyGraphSourceParser;
pub use parsed_source::ParsedSourceCache;
use crate::sys::CliSys; use crate::sys::CliSys;

View file

@ -9,13 +9,13 @@ use deno_core::serde_json;
use deno_error::JsErrorBox; use deno_error::JsErrorBox;
use deno_graph::analysis::ModuleInfo; use deno_graph::analysis::ModuleInfo;
use deno_graph::ast::ParserModuleAnalyzer; use deno_graph::ast::ParserModuleAnalyzer;
use deno_resolver::cache::ParsedSourceCache;
use deno_runtime::deno_webstorage::rusqlite::params; use deno_runtime::deno_webstorage::rusqlite::params;
use super::cache_db::CacheDB; use super::cache_db::CacheDB;
use super::cache_db::CacheDBConfiguration; use super::cache_db::CacheDBConfiguration;
use super::cache_db::CacheDBHash; use super::cache_db::CacheDBHash;
use super::cache_db::CacheFailure; use super::cache_db::CacheFailure;
use super::ParsedSourceCache;
const SELECT_MODULE_INFO: &str = " const SELECT_MODULE_INFO: &str = "
SELECT SELECT

View file

@ -31,10 +31,10 @@ use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutor;
use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor; use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor;
use deno_npm_installer::process_state::NpmProcessStateKind; use deno_npm_installer::process_state::NpmProcessStateKind;
use deno_npm_installer::NpmInstallerFactoryOptions; use deno_npm_installer::NpmInstallerFactoryOptions;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::deno_json::CompilerOptionsResolver; use deno_resolver::deno_json::CompilerOptionsResolver;
use deno_resolver::factory::ConfigDiscoveryOption; use deno_resolver::factory::ConfigDiscoveryOption;
use deno_resolver::factory::DenoDirPathProviderOptions;
use deno_resolver::factory::NpmProcessStateOptions; use deno_resolver::factory::NpmProcessStateOptions;
use deno_resolver::factory::ResolverFactoryOptions; use deno_resolver::factory::ResolverFactoryOptions;
use deno_resolver::factory::SpecifiedImportMapProvider; use deno_resolver::factory::SpecifiedImportMapProvider;
@ -70,13 +70,9 @@ use crate::args::InstallFlags;
use crate::cache::Caches; use crate::cache::Caches;
use crate::cache::CodeCache; use crate::cache::CodeCache;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::cache::DenoDirProvider;
use crate::cache::EmitCache;
use crate::cache::GlobalHttpCache; use crate::cache::GlobalHttpCache;
use crate::cache::ModuleInfoCache; use crate::cache::ModuleInfoCache;
use crate::cache::NodeAnalysisCache; use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::file_fetcher::create_cli_file_fetcher; use crate::file_fetcher::create_cli_file_fetcher;
use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::file_fetcher::CreateCliFileFetcherOptions; use crate::file_fetcher::CreateCliFileFetcherOptions;
@ -86,6 +82,7 @@ use crate::graph_util::FileWatcherReporter;
use crate::graph_util::ModuleGraphBuilder; use crate::graph_util::ModuleGraphBuilder;
use crate::graph_util::ModuleGraphCreator; use crate::graph_util::ModuleGraphCreator;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::module_loader::CliEmitter;
use crate::module_loader::CliModuleLoaderFactory; use crate::module_loader::CliModuleLoaderFactory;
use crate::module_loader::EszipModuleLoader; use crate::module_loader::EszipModuleLoader;
use crate::module_loader::ModuleLoadPreparer; use crate::module_loader::ModuleLoadPreparer;
@ -249,9 +246,6 @@ impl SpecifiedImportMapProvider for CliSpecifiedImportMapProvider {
} }
pub type CliWorkspaceFactory = deno_resolver::factory::WorkspaceFactory<CliSys>; 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 type CliResolverFactory = deno_resolver::factory::ResolverFactory<CliSys>;
pub struct Deferred<T>(once_cell::unsync::OnceCell<T>); pub struct Deferred<T>(once_cell::unsync::OnceCell<T>);
@ -307,10 +301,6 @@ struct CliFactoryServices {
cjs_module_export_analyzer: Deferred<Arc<CliCjsModuleExportAnalyzer>>, cjs_module_export_analyzer: Deferred<Arc<CliCjsModuleExportAnalyzer>>,
cli_options: Deferred<Arc<CliOptions>>, cli_options: Deferred<Arc<CliOptions>>,
code_cache: Deferred<Arc<CodeCache>>, code_cache: Deferred<Arc<CodeCache>>,
deno_dir_path_provider: Deferred<Arc<CliDenoDirPathProvider>>,
deno_dir_provider: Deferred<Arc<DenoDirProvider>>,
emit_cache: Deferred<Arc<EmitCache>>,
emitter: Deferred<Arc<Emitter>>,
eszip_module_loader_provider: Deferred<Arc<EszipModuleLoaderProvider>>, eszip_module_loader_provider: Deferred<Arc<EszipModuleLoaderProvider>>,
feature_checker: Deferred<Arc<FeatureChecker>>, feature_checker: Deferred<Arc<FeatureChecker>>,
file_fetcher: Deferred<Arc<CliFileFetcher>>, file_fetcher: Deferred<Arc<CliFileFetcher>>,
@ -325,7 +315,6 @@ struct CliFactoryServices {
module_load_preparer: Deferred<Arc<ModuleLoadPreparer>>, module_load_preparer: Deferred<Arc<ModuleLoadPreparer>>,
node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>, node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>,
npm_installer_factory: Deferred<CliNpmInstallerFactory>, npm_installer_factory: Deferred<CliNpmInstallerFactory>,
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
permission_desc_parser: permission_desc_parser:
Deferred<Arc<RuntimePermissionDescriptorParser<CliSys>>>, Deferred<Arc<RuntimePermissionDescriptorParser<CliSys>>>,
resolver_factory: Deferred<Arc<CliResolverFactory>>, resolver_factory: Deferred<Arc<CliResolverFactory>>,
@ -398,34 +387,21 @@ impl CliFactory {
}) })
} }
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> { pub fn deno_dir(&self) -> Result<&DenoDir, AnyError> {
Ok(self.deno_dir_provider().get_or_create()?) Ok(
self
.workspace_factory()?
.deno_dir_provider()
.get_or_create()?,
)
} }
pub fn caches(&self) -> Result<&Arc<Caches>, AnyError> { pub fn caches(&self) -> Result<&Arc<Caches>, AnyError> {
self.services.caches.get_or_try_init(|| { self.services.caches.get_or_try_init(|| {
let cli_options = self.cli_options()?; let cli_options = self.cli_options()?;
let caches = Arc::new(Caches::new(self.deno_dir_provider().clone())); let caches = Arc::new(Caches::new(
self.workspace_factory()?.deno_dir_provider().clone(),
));
// Warm up the caches we know we'll likely need based on the CLI mode // Warm up the caches we know we'll likely need based on the CLI mode
match cli_options.sub_command() { match cli_options.sub_command() {
DenoSubcommand::Run(_) DenoSubcommand::Run(_)
@ -623,11 +599,7 @@ impl CliFactory {
.env_current_dir() .env_current_dir()
.with_context(|| "Failed getting cwd.")?, .with_context(|| "Failed getting cwd.")?,
}; };
let options = new_workspace_factory_options( let options = new_workspace_factory_options(&initial_cwd, &self.flags);
&initial_cwd,
&self.flags,
self.deno_dir_path_provider().clone(),
);
let mut factory = let mut factory =
CliWorkspaceFactory::new(self.sys(), initial_cwd, options); CliWorkspaceFactory::new(self.sys(), initial_cwd, options);
if let Some(workspace_dir) = &self.overrides.workspace_directory { if let Some(workspace_dir) = &self.overrides.workspace_directory {
@ -660,17 +632,11 @@ impl CliFactory {
.get_or_init(|| maybe_file_watcher_reporter) .get_or_init(|| maybe_file_watcher_reporter)
} }
pub fn emit_cache(&self) -> Result<&Arc<EmitCache>, AnyError> {
self.services.emit_cache.get_or_try_init(|| {
Ok(Arc::new(EmitCache::new(self.deno_dir()?.gen_cache.clone())))
})
}
pub fn module_info_cache(&self) -> Result<&Arc<ModuleInfoCache>, AnyError> { pub fn module_info_cache(&self) -> Result<&Arc<ModuleInfoCache>, AnyError> {
self.services.module_info_cache.get_or_try_init(|| { self.services.module_info_cache.get_or_try_init(|| {
Ok(Arc::new(ModuleInfoCache::new( Ok(Arc::new(ModuleInfoCache::new(
self.caches()?.dep_analysis_db(), self.caches()?.dep_analysis_db(),
self.parsed_source_cache().clone(), self.resolver_factory()?.parsed_source_cache().clone(),
))) )))
}) })
} }
@ -681,22 +647,14 @@ impl CliFactory {
}) })
} }
pub fn parsed_source_cache(&self) -> &Arc<ParsedSourceCache> { pub fn parsed_source_cache(
self &self,
.services ) -> Result<&Arc<ParsedSourceCache>, AnyError> {
.parsed_source_cache Ok(self.resolver_factory()?.parsed_source_cache())
.get_or_init(Default::default)
} }
pub fn emitter(&self) -> Result<&Arc<Emitter>, AnyError> { pub fn emitter(&self) -> Result<&Arc<CliEmitter>, AnyError> {
self.services.emitter.get_or_try_init(|| { self.resolver_factory()?.emitter()
Ok(Arc::new(Emitter::new(
self.cjs_tracker()?.clone(),
self.emit_cache()?.clone(),
self.parsed_source_cache().clone(),
self.compiler_options_resolver()?.clone(),
)))
})
} }
pub async fn lint_rule_provider(&self) -> Result<LintRuleProvider, AnyError> { pub async fn lint_rule_provider(&self) -> Result<LintRuleProvider, AnyError> {
@ -771,7 +729,7 @@ impl CliFactory {
node_analysis_cache, node_analysis_cache,
self.cjs_tracker()?.clone(), self.cjs_tracker()?.clone(),
self.fs().clone(), self.fs().clone(),
Some(self.parsed_source_cache().clone()), Some(self.parsed_source_cache()?.clone()),
)) ))
} }
@ -841,7 +799,7 @@ impl CliFactory {
self.npm_graph_resolver().await?.clone(), self.npm_graph_resolver().await?.clone(),
self.npm_installer_if_managed().await?.cloned(), self.npm_installer_if_managed().await?.cloned(),
self.npm_resolver().await?.clone(), self.npm_resolver().await?.clone(),
self.parsed_source_cache().clone(), self.resolver_factory()?.parsed_source_cache().clone(),
self.resolver().await?.clone(), self.resolver().await?.clone(),
self.root_permissions_container()?.clone(), self.root_permissions_container()?.clone(),
self.sys(), self.sys(),
@ -1021,8 +979,9 @@ impl CliFactory {
let node_code_translator = self.node_code_translator().await?; let node_code_translator = self.node_code_translator().await?;
let cjs_tracker = self.cjs_tracker()?.clone(); let cjs_tracker = self.cjs_tracker()?.clone();
let workspace_factory = self.workspace_factory()?; let workspace_factory = self.workspace_factory()?;
let resolver_factory = self.resolver_factory()?;
let npm_registry_permission_checker = { let npm_registry_permission_checker = {
let mode = if self.resolver_factory()?.use_byonm()? { let mode = if resolver_factory.use_byonm()? {
NpmRegistryReadPermissionCheckerMode::Byonm NpmRegistryReadPermissionCheckerMode::Byonm
} else if let Some(node_modules_dir) = } else if let Some(node_modules_dir) =
workspace_factory.node_modules_dir_path()? workspace_factory.node_modules_dir_path()?
@ -1061,7 +1020,7 @@ impl CliFactory {
), ),
npm_registry_permission_checker, npm_registry_permission_checker,
cli_npm_resolver.clone(), cli_npm_resolver.clone(),
self.parsed_source_cache().clone(), resolver_factory.parsed_source_cache().clone(),
self.resolver().await?.clone(), self.resolver().await?.clone(),
self.sys(), self.sys(),
maybe_eszip_loader, maybe_eszip_loader,
@ -1292,8 +1251,7 @@ impl CliFactory {
fn new_workspace_factory_options( fn new_workspace_factory_options(
initial_cwd: &Path, initial_cwd: &Path,
flags: &Flags, flags: &Flags,
deno_dir_path_provider: Arc<CliDenoDirPathProvider>, ) -> deno_resolver::factory::WorkspaceFactoryOptions {
) -> deno_resolver::factory::WorkspaceFactoryOptions<CliSys> {
deno_resolver::factory::WorkspaceFactoryOptions { deno_resolver::factory::WorkspaceFactoryOptions {
additional_config_file_names: if matches!( additional_config_file_names: if matches!(
flags.subcommand, flags.subcommand,
@ -1316,7 +1274,10 @@ fn new_workspace_factory_options(
} }
ConfigFlag::Disabled => ConfigDiscoveryOption::Disabled, ConfigFlag::Disabled => ConfigDiscoveryOption::Disabled,
}, },
deno_dir_path_provider: Some(deno_dir_path_provider), emit_cache_version: Cow::Borrowed(
deno_lib::version::DENO_VERSION_INFO.deno,
),
maybe_custom_deno_dir_root: flags.internal.cache_path.clone(),
// For `deno install/add/remove/init` we want to force the managed // For `deno install/add/remove/init` we want to force the managed
// resolver so it can set up the `node_modules/` directory. // resolver so it can set up the `node_modules/` directory.
is_package_manager_subcommand: matches!( is_package_manager_subcommand: matches!(

View file

@ -34,6 +34,7 @@ use deno_graph::WorkspaceFastCheckOption;
use deno_npm_installer::graph::NpmCachingStrategy; use deno_npm_installer::graph::NpmCachingStrategy;
use deno_npm_installer::PackageCaching; use deno_npm_installer::PackageCaching;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::deno_json::CompilerOptionsResolver; use deno_resolver::deno_json::CompilerOptionsResolver;
use deno_resolver::deno_json::JsxImportSourceConfigResolver; use deno_resolver::deno_json::JsxImportSourceConfigResolver;
use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::DenoInNpmPackageChecker;
@ -53,7 +54,6 @@ use crate::args::DenoSubcommand;
use crate::cache; use crate::cache;
use crate::cache::GlobalHttpCache; use crate::cache::GlobalHttpCache;
use crate::cache::ModuleInfoCache; use crate::cache::ModuleInfoCache;
use crate::cache::ParsedSourceCache;
use crate::colors; use crate::colors;
use crate::file_fetcher::CliDenoGraphLoader; use crate::file_fetcher::CliDenoGraphLoader;
use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::CliFileFetcher;

View file

@ -1,5 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::collections::HashMap; use std::collections::HashMap;
@ -1451,8 +1452,11 @@ impl ConfigData {
WorkspaceFactoryOptions { WorkspaceFactoryOptions {
additional_config_file_names: &[], additional_config_file_names: &[],
config_discovery: ConfigDiscoveryOption::DiscoverCwd, config_discovery: ConfigDiscoveryOption::DiscoverCwd,
deno_dir_path_provider: None, maybe_custom_deno_dir_root: None,
is_package_manager_subcommand: false, is_package_manager_subcommand: false,
emit_cache_version: Cow::Borrowed(
deno_lib::version::DENO_VERSION_INFO.deno,
),
frozen_lockfile: None, frozen_lockfile: None,
lock_arg: None, lock_arg: None,
lockfile_skip_write: false, lockfile_skip_write: false,

View file

@ -3,7 +3,6 @@
mod args; mod args;
mod cache; mod cache;
mod cdp; mod cdp;
mod emit;
mod factory; mod factory;
mod file_fetcher; mod file_fetcher;
mod graph_container; mod graph_container;

View file

@ -54,6 +54,7 @@ use deno_lib::npm::NpmRegistryReadPermissionChecker;
use deno_lib::util::hash::FastInsecureHasher; use deno_lib::util::hash::FastInsecureHasher;
use deno_lib::worker::CreateModuleLoaderResult; use deno_lib::worker::CreateModuleLoaderResult;
use deno_lib::worker::ModuleLoaderFactory; use deno_lib::worker::ModuleLoaderFactory;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::file_fetcher::FetchOptions; use deno_resolver::file_fetcher::FetchOptions;
use deno_resolver::file_fetcher::FetchPermissionsOptionRef; use deno_resolver::file_fetcher::FetchPermissionsOptionRef;
use deno_resolver::graph::ResolveWithGraphErrorKind; use deno_resolver::graph::ResolveWithGraphErrorKind;
@ -84,8 +85,6 @@ use crate::args::CliOptions;
use crate::args::DenoSubcommand; use crate::args::DenoSubcommand;
use crate::args::TsTypeLib; use crate::args::TsTypeLib;
use crate::cache::CodeCache; use crate::cache::CodeCache;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::graph_container::MainModuleGraphContainer; use crate::graph_container::MainModuleGraphContainer;
use crate::graph_container::ModuleGraphContainer; use crate::graph_container::ModuleGraphContainer;
@ -115,6 +114,8 @@ pub type CliNpmModuleLoader = deno_lib::loader::NpmModuleLoader<
CliNpmResolver, CliNpmResolver,
CliSys, CliSys,
>; >;
pub type CliEmitter =
deno_resolver::emit::Emitter<DenoInNpmPackageChecker, CliSys>;
#[derive(Debug, thiserror::Error, deno_error::JsError)] #[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum PrepareModuleLoadError { pub enum PrepareModuleLoadError {
@ -331,7 +332,7 @@ struct SharedCliModuleLoaderState {
is_repl: bool, is_repl: bool,
cjs_tracker: Arc<CliCjsTracker>, cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<CodeCache>>, code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>, emitter: Arc<CliEmitter>,
file_fetcher: Arc<CliFileFetcher>, file_fetcher: Arc<CliFileFetcher>,
in_npm_pkg_checker: DenoInNpmPackageChecker, in_npm_pkg_checker: DenoInNpmPackageChecker,
main_module_graph_container: Arc<MainModuleGraphContainer>, main_module_graph_container: Arc<MainModuleGraphContainer>,
@ -393,7 +394,7 @@ impl CliModuleLoaderFactory {
options: &CliOptions, options: &CliOptions,
cjs_tracker: Arc<CliCjsTracker>, cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<CodeCache>>, code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>, emitter: Arc<CliEmitter>,
file_fetcher: Arc<CliFileFetcher>, file_fetcher: Arc<CliFileFetcher>,
in_npm_pkg_checker: DenoInNpmPackageChecker, in_npm_pkg_checker: DenoInNpmPackageChecker,
main_module_graph_container: Arc<MainModuleGraphContainer>, main_module_graph_container: Arc<MainModuleGraphContainer>,
@ -459,9 +460,6 @@ impl CliModuleLoaderFactory {
parent_permissions, parent_permissions,
permissions, permissions,
graph_container: graph_container.clone(), graph_container: graph_container.clone(),
node_code_translator: self.shared.node_code_translator.clone(),
emitter: self.shared.emitter.clone(),
parsed_source_cache: self.shared.parsed_source_cache.clone(),
shared: self.shared.clone(), shared: self.shared.clone(),
loaded_files: Default::default(), loaded_files: Default::default(),
}))); })));
@ -527,9 +525,6 @@ impl CliModuleLoaderFactory {
parent_permissions: root_permissions.clone(), parent_permissions: root_permissions.clone(),
permissions: root_permissions, permissions: root_permissions,
graph_container: (*self.shared.main_module_graph_container).clone(), graph_container: (*self.shared.main_module_graph_container).clone(),
node_code_translator: self.shared.node_code_translator.clone(),
emitter: self.shared.emitter.clone(),
parsed_source_cache: self.shared.parsed_source_cache.clone(),
shared: self.shared.clone(), shared: self.shared.clone(),
loaded_files: Default::default(), loaded_files: Default::default(),
})) }))
@ -557,7 +552,7 @@ pub struct EnhancedGraphError {
pub enum LoadPreparedModuleError { pub enum LoadPreparedModuleError {
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
NpmModuleLoad(#[from] crate::emit::EmitParsedSourceHelperError), NpmModuleLoad(#[from] deno_resolver::emit::EmitParsedSourceHelperError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
LoadMaybeCjs(#[from] LoadMaybeCjsError), LoadMaybeCjs(#[from] LoadMaybeCjsError),
@ -576,7 +571,7 @@ pub enum LoadPreparedModuleError {
pub enum LoadMaybeCjsError { pub enum LoadMaybeCjsError {
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
NpmModuleLoad(#[from] crate::emit::EmitParsedSourceHelperError), NpmModuleLoad(#[from] deno_resolver::emit::EmitParsedSourceHelperError),
#[class(inherit)] #[class(inherit)]
#[error(transparent)] #[error(transparent)]
TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError), TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError),
@ -591,9 +586,6 @@ struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
parent_permissions: PermissionsContainer, parent_permissions: PermissionsContainer,
permissions: PermissionsContainer, permissions: PermissionsContainer,
shared: Arc<SharedCliModuleLoaderState>, shared: Arc<SharedCliModuleLoaderState>,
emitter: Arc<Emitter>,
node_code_translator: Arc<CliNodeCodeTranslator>,
parsed_source_cache: Arc<ParsedSourceCache>,
graph_container: TGraphContainer, graph_container: TGraphContainer,
loaded_files: RefCell<HashSet<ModuleSpecifier>>, loaded_files: RefCell<HashSet<ModuleSpecifier>>,
} }
@ -1109,12 +1101,13 @@ impl<TGraphContainer: ModuleGraphContainer>
source, source,
}) => { }) => {
let transpile_result = self let transpile_result = self
.shared
.emitter .emitter
.emit_parsed_source(specifier, media_type, ModuleKind::Esm, source) .emit_parsed_source(specifier, media_type, ModuleKind::Esm, source)
.await?; .await?;
// at this point, we no longer need the parsed source in memory, so free it // at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier); self.shared.parsed_source_cache.free(specifier);
Ok(Some(ModuleCodeStringSource { Ok(Some(ModuleCodeStringSource {
// note: it's faster to provide a string if we know it's a string // note: it's faster to provide a string if we know it's a string
@ -1162,7 +1155,7 @@ impl<TGraphContainer: ModuleGraphContainer>
media_type, media_type,
source, source,
}) => { }) => {
let transpile_result = self.emitter.emit_parsed_source_sync( let transpile_result = self.shared.emitter.emit_parsed_source_sync(
specifier, specifier,
media_type, media_type,
ModuleKind::Esm, ModuleKind::Esm,
@ -1170,7 +1163,7 @@ impl<TGraphContainer: ModuleGraphContainer>
)?; )?;
// at this point, we no longer need the parsed source in memory, so free it // at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier); self.shared.parsed_source_cache.free(specifier);
Ok(Some(ModuleCodeStringSource { Ok(Some(ModuleCodeStringSource {
// note: it's faster to provide a string if we know it's a string // note: it's faster to provide a string if we know it's a string
@ -1180,7 +1173,7 @@ impl<TGraphContainer: ModuleGraphContainer>
})) }))
} }
Some(CodeOrDeferredEmit::Cjs { .. }) => { Some(CodeOrDeferredEmit::Cjs { .. }) => {
self.parsed_source_cache.free(specifier); self.shared.parsed_source_cache.free(specifier);
// todo(dsherret): to make this work, we should probably just // todo(dsherret): to make this work, we should probably just
// rely on the CJS export cache. At the moment this is hard because // rely on the CJS export cache. At the moment this is hard because
@ -1316,7 +1309,7 @@ impl<TGraphContainer: ModuleGraphContainer>
}; };
// at this point, we no longer need the parsed source in memory, so free it // at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier); self.shared.parsed_source_cache.free(specifier);
Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource { Ok(Some(CodeOrDeferredEmit::Code(ModuleCodeStringSource {
code: ModuleSourceCode::String(code), code: ModuleSourceCode::String(code),
@ -1365,6 +1358,7 @@ impl<TGraphContainer: ModuleGraphContainer>
let js_source = if media_type.is_emittable() { let js_source = if media_type.is_emittable() {
Cow::Owned( Cow::Owned(
self self
.shared
.emitter .emitter
.emit_parsed_source( .emit_parsed_source(
specifier, specifier,
@ -1378,11 +1372,12 @@ impl<TGraphContainer: ModuleGraphContainer>
Cow::Borrowed(original_source.as_ref()) Cow::Borrowed(original_source.as_ref())
}; };
let text = self let text = self
.shared
.node_code_translator .node_code_translator
.translate_cjs_to_esm(specifier, Some(js_source)) .translate_cjs_to_esm(specifier, Some(js_source))
.await?; .await?;
// at this point, we no longer need the parsed source in memory, so free it // at this point, we no longer need the parsed source in memory, so free it
self.parsed_source_cache.free(specifier); self.shared.parsed_source_cache.free(specifier);
Ok(ModuleCodeStringSource { Ok(ModuleCodeStringSource {
code: match text { code: match text {
// perf: if the text is borrowed, that means it didn't make any changes // perf: if the text is borrowed, that means it didn't make any changes
@ -1731,7 +1726,7 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit {
#[derive(Debug)] #[derive(Debug)]
struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> { struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
cjs_tracker: Arc<CliCjsTracker>, cjs_tracker: Arc<CliCjsTracker>,
emitter: Arc<Emitter>, emitter: Arc<CliEmitter>,
npm_resolver: CliNpmResolver, npm_resolver: CliNpmResolver,
sys: CliSys, sys: CliSys,
graph_container: TGraphContainer, graph_container: TGraphContainer,

View file

@ -8,6 +8,7 @@ use deno_ast::ModuleExportsAndReExports;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_error::JsErrorBox; use deno_error::JsErrorBox;
use deno_graph::ast::ParsedSourceStore; use deno_graph::ast::ParsedSourceStore;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis; use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
@ -22,7 +23,6 @@ use serde::Serialize;
use crate::cache::CacheDBHash; use crate::cache::CacheDBHash;
use crate::cache::NodeAnalysisCache; use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker; use crate::resolver::CliCjsTracker;
use crate::sys::CliSys; use crate::sys::CliSys;

View file

@ -64,9 +64,9 @@ use crate::args::get_default_v8_flags;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::CompileFlags; use crate::args::CompileFlags;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::emit::Emitter;
use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::CliFileFetcher;
use crate::http_util::HttpClientProvider; use crate::http_util::HttpClientProvider;
use crate::module_loader::CliEmitter;
use crate::node::CliCjsModuleExportAnalyzer; use crate::node::CliCjsModuleExportAnalyzer;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker; use crate::resolver::CliCjsTracker;
@ -201,7 +201,7 @@ pub struct DenoCompileBinaryWriter<'a> {
cjs_tracker: &'a CliCjsTracker, cjs_tracker: &'a CliCjsTracker,
cli_options: &'a CliOptions, cli_options: &'a CliOptions,
deno_dir: &'a DenoDir, deno_dir: &'a DenoDir,
emitter: &'a Emitter, emitter: &'a CliEmitter,
file_fetcher: &'a CliFileFetcher, file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider, http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a CliNpmResolver, npm_resolver: &'a CliNpmResolver,
@ -216,7 +216,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
cjs_tracker: &'a CliCjsTracker, cjs_tracker: &'a CliCjsTracker,
cli_options: &'a CliOptions, cli_options: &'a CliOptions,
deno_dir: &'a DenoDir, deno_dir: &'a DenoDir,
emitter: &'a Emitter, emitter: &'a CliEmitter,
file_fetcher: &'a CliFileFetcher, file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider, http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a CliNpmResolver, npm_resolver: &'a CliNpmResolver,

View file

@ -162,7 +162,7 @@ pub async fn compile_eszip(
let factory = CliFactory::from_flags(flags); let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?; let cli_options = factory.cli_options()?;
let module_graph_creator = factory.module_graph_creator().await?; let module_graph_creator = factory.module_graph_creator().await?;
let parsed_source_cache = factory.parsed_source_cache(); let parsed_source_cache = factory.parsed_source_cache()?;
let compiler_options_resolver = factory.compiler_options_resolver()?; let compiler_options_resolver = factory.compiler_options_resolver()?;
let bin_name_resolver = factory.bin_name_resolver()?; let bin_name_resolver = factory.bin_name_resolver()?;
let entrypoint = cli_options.resolve_main_module()?; let entrypoint = cli_options.resolve_main_module()?;

View file

@ -109,7 +109,7 @@ pub async fn doc(
let factory = CliFactory::from_flags(flags); let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?; let cli_options = factory.cli_options()?;
let module_info_cache = factory.module_info_cache()?; let module_info_cache = factory.module_info_cache()?;
let parsed_source_cache = factory.parsed_source_cache(); let parsed_source_cache = factory.parsed_source_cache()?;
let capturing_parser = parsed_source_cache.as_capturing_parser(); let capturing_parser = parsed_source_cache.as_capturing_parser();
let analyzer = module_info_cache.as_module_analyzer(); let analyzer = module_info_cache.as_module_analyzer();

View file

@ -13,12 +13,12 @@ use deno_graph::ModuleEntryRef;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_graph::ResolutionResolved; use deno_graph::ResolutionResolved;
use deno_graph::WalkOptions; use deno_graph::WalkOptions;
use deno_resolver::cache::ParsedSourceCache;
use deno_semver::jsr::JsrPackageReqReference; use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use super::diagnostics::PublishDiagnostic; use super::diagnostics::PublishDiagnostic;
use super::diagnostics::PublishDiagnosticsCollector; use super::diagnostics::PublishDiagnosticsCollector;
use crate::cache::ParsedSourceCache;
pub struct GraphDiagnosticsCollector { pub struct GraphDiagnosticsCollector {
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: Arc<ParsedSourceCache>,

View file

@ -117,14 +117,15 @@ pub async fn publish(
); );
let diagnostics_collector = PublishDiagnosticsCollector::default(); let diagnostics_collector = PublishDiagnosticsCollector::default();
let parsed_source_cache = cli_factory.parsed_source_cache()?;
let module_content_provider = Arc::new(ModuleContentProvider::new( let module_content_provider = Arc::new(ModuleContentProvider::new(
cli_factory.parsed_source_cache().clone(), parsed_source_cache.clone(),
specifier_unfurler, specifier_unfurler,
cli_factory.sys(), cli_factory.sys(),
cli_factory.compiler_options_resolver()?.clone(), cli_factory.compiler_options_resolver()?.clone(),
)); ));
let publish_preparer = PublishPreparer::new( let publish_preparer = PublishPreparer::new(
GraphDiagnosticsCollector::new(cli_factory.parsed_source_cache().clone()), GraphDiagnosticsCollector::new(parsed_source_cache.clone()),
cli_factory.module_graph_creator().await?.clone(), cli_factory.module_graph_creator().await?.clone(),
cli_factory.type_checker().await?.clone(), cli_factory.type_checker().await?.clone(),
cli_options.clone(), cli_options.clone(),

View file

@ -11,6 +11,8 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::url::Url; use deno_core::url::Url;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_resolver::cache::LazyGraphSourceParser;
use deno_resolver::cache::ParsedSourceCache;
use deno_resolver::deno_json::CompilerOptionsResolver; use deno_resolver::deno_json::CompilerOptionsResolver;
use deno_resolver::workspace::ResolutionKind; use deno_resolver::workspace::ResolutionKind;
use lazy_regex::Lazy; use lazy_regex::Lazy;
@ -21,8 +23,6 @@ use super::diagnostics::PublishDiagnostic;
use super::diagnostics::PublishDiagnosticsCollector; use super::diagnostics::PublishDiagnosticsCollector;
use super::unfurl::SpecifierUnfurler; use super::unfurl::SpecifierUnfurler;
use super::unfurl::SpecifierUnfurlerDiagnostic; use super::unfurl::SpecifierUnfurlerDiagnostic;
use crate::cache::LazyGraphSourceParser;
use crate::cache::ParsedSourceCache;
use crate::sys::CliSys; use crate::sys::CliSys;
struct JsxFolderOptions<'a> { struct JsxFolderOptions<'a> {

View file

@ -15,7 +15,7 @@ use deno_terminal::colors;
use tokio::select; use tokio::select;
use crate::cdp; use crate::cdp;
use crate::emit::Emitter; use crate::module_loader::CliEmitter;
use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherCommunicator;
use crate::util::file_watcher::WatcherRestartMode; use crate::util::file_watcher::WatcherRestartMode;
@ -79,7 +79,7 @@ pub struct HmrRunner {
session: LocalInspectorSession, session: LocalInspectorSession,
watcher_communicator: Arc<WatcherCommunicator>, watcher_communicator: Arc<WatcherCommunicator>,
script_ids: HashMap<String, String>, script_ids: HashMap<String, String>,
emitter: Arc<Emitter>, emitter: Arc<CliEmitter>,
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
@ -159,9 +159,11 @@ impl crate::worker::HmrRunner for HmrRunner {
continue; continue;
}; };
let source_code = self.emitter.load_and_emit_for_hmr( let source_code = tokio::fs::read_to_string(deno_path_util::url_to_file_path(&module_url).unwrap()).await?;
let source_code = self.emitter.emit_for_hmr(
&module_url, &module_url,
).await?; source_code,
)?;
let mut tries = 1; let mut tries = 1;
loop { loop {
@ -193,7 +195,7 @@ impl crate::worker::HmrRunner for HmrRunner {
impl HmrRunner { impl HmrRunner {
pub fn new( pub fn new(
emitter: Arc<Emitter>, emitter: Arc<CliEmitter>,
session: LocalInspectorSession, session: LocalInspectorSession,
watcher_communicator: Arc<WatcherCommunicator>, watcher_communicator: Arc<WatcherCommunicator>,
) -> Self { ) -> Self {

View file

@ -14,7 +14,7 @@ description = "Deno resolution algorithm"
path = "lib.rs" path = "lib.rs"
[features] [features]
deno_ast = ["dep:deno_ast", "twox-hash"] deno_ast = ["dep:deno_ast", "deno_graph/swc"]
graph = ["deno_graph", "node_resolver/graph", "http", "deno_permissions"] graph = ["deno_graph", "node_resolver/graph", "http", "deno_permissions"]
sync = ["dashmap", "deno_package_json/sync", "node_resolver/sync", "deno_config/sync", "deno_cache_dir/sync"] sync = ["dashmap", "deno_package_json/sync", "node_resolver/sync", "deno_config/sync", "deno_cache_dir/sync"]
@ -53,7 +53,7 @@ serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
sys_traits.workspace = true sys_traits.workspace = true
thiserror.workspace = true thiserror.workspace = true
twox-hash = { workspace = true, optional = true } twox-hash.workspace = true
url.workspace = true url.workspace = true
[dev-dependencies] [dev-dependencies]

View file

@ -2,38 +2,50 @@
use std::env; use std::env;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use deno_cache_dir::DenoDirResolutionError; use deno_cache_dir::DenoDirResolutionError;
use deno_cache_dir::ResolveDenoDirSys;
use super::DiskCache; use super::DiskCache;
use crate::factory::CliDenoDirPathProvider; use super::DiskCacheSys;
use crate::sys::CliSys;
#[derive(Debug, Clone)]
pub struct DenoDirOptions {
pub maybe_custom_root: Option<PathBuf>,
}
#[sys_traits::auto_impl]
pub trait DenoDirSys: DiskCacheSys + ResolveDenoDirSys + Clone {}
#[allow(clippy::disallowed_types)]
pub type DenoDirProviderRc<TSys> = crate::sync::MaybeArc<DenoDirProvider<TSys>>;
/// Lazily creates the deno dir which might be useful in scenarios /// Lazily creates the deno dir which might be useful in scenarios
/// where functionality wants to continue if the DENO_DIR can't be created. /// where functionality wants to continue if the DENO_DIR can't be created.
pub struct DenoDirProvider { pub struct DenoDirProvider<TSys: DenoDirSys> {
deno_dir_path_provider: Arc<CliDenoDirPathProvider>, options: DenoDirOptions,
sys: CliSys, sys: TSys,
deno_dir: once_cell::sync::OnceCell<DenoDir>, deno_dir_cell: once_cell::sync::OnceCell<DenoDir<TSys>>,
} }
impl DenoDirProvider { impl<TSys: DenoDirSys> DenoDirProvider<TSys> {
pub fn new( pub fn new(sys: TSys, options: DenoDirOptions) -> Self {
sys: CliSys,
deno_dir_path_provider: Arc<CliDenoDirPathProvider>,
) -> Self {
Self { Self {
options,
sys, sys,
deno_dir_path_provider, deno_dir_cell: Default::default(),
deno_dir: Default::default(),
} }
} }
pub fn get_or_create(&self) -> Result<&DenoDir, DenoDirResolutionError> { pub fn get_or_create(
self.deno_dir.get_or_try_init(|| { &self,
let path = self.deno_dir_path_provider.get_or_create()?; ) -> Result<&DenoDir<TSys>, DenoDirResolutionError> {
Ok(DenoDir::new(self.sys.clone(), path.clone())) self.deno_dir_cell.get_or_try_init(|| {
let path = deno_cache_dir::resolve_deno_dir(
&self.sys,
self.options.maybe_custom_root.clone(),
)?;
Ok(DenoDir::new(self.sys.clone(), path))
}) })
} }
} }
@ -41,18 +53,19 @@ impl DenoDirProvider {
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them /// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
/// in single directory that can be controlled with `$DENO_DIR` env variable. /// in single directory that can be controlled with `$DENO_DIR` env variable.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DenoDir { pub struct DenoDir<TSys: DiskCacheSys> {
/// Example: /Users/rld/.deno/ /// Example: /Users/rld/.deno/
pub root: PathBuf, pub root: PathBuf,
/// Used by TsCompiler to cache compiler output. /// Used by TsCompiler to cache compiler output.
pub gen_cache: DiskCache, pub gen_cache: DiskCache<TSys>,
} }
impl DenoDir { impl<TSys: DiskCacheSys> DenoDir<TSys> {
pub fn new(sys: CliSys, root: PathBuf) -> Self { pub fn new(sys: TSys, root: PathBuf) -> Self {
#[cfg(not(target_arch = "wasm32"))]
assert!(root.is_absolute()); assert!(root.is_absolute());
let gen_path = root.join("gen");
let gen_path = root.join("gen");
Self { Self {
root, root,
gen_cache: DiskCache::new(sys, gen_path), gen_cache: DiskCache::new(sys, gen_path),

View file

@ -9,26 +9,49 @@ use std::str;
use deno_cache_dir::url_to_filename; use deno_cache_dir::url_to_filename;
use deno_cache_dir::CACHE_PERM; 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 deno_path_util::fs::atomic_write_file_with_retries;
use sys_traits::FsRead; use sys_traits::FsRead;
use url::Host;
use url::Url;
use crate::sys::CliSys; #[sys_traits::auto_impl]
pub trait DiskCacheSys:
deno_path_util::fs::AtomicWriteFileWithRetriesSys + FsRead
{
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DiskCache { pub struct DiskCache<TSys: DiskCacheSys> {
sys: CliSys, sys: TSys,
pub location: PathBuf, pub location: PathBuf,
} }
impl DiskCache { impl<TSys: DiskCacheSys> DiskCache<TSys> {
/// `location` must be an absolute path. /// `location` must be an absolute path.
pub fn new(sys: CliSys, location: PathBuf) -> Self { pub fn new(sys: TSys, location: PathBuf) -> Self {
#[cfg(not(target_arch = "wasm32"))]
assert!(location.is_absolute()); assert!(location.is_absolute());
Self { sys, location } Self { sys, location }
} }
pub fn get_cache_filename_with_extension(
&self,
url: &Url,
extension: &str,
) -> Option<PathBuf> {
let base = self.get_cache_filename(url)?;
match base.extension() {
None => Some(base.with_extension(extension)),
Some(ext) => {
let original_extension = OsStr::to_str(ext).unwrap();
let final_extension = format!("{original_extension}.{extension}");
Some(base.with_extension(final_extension))
}
}
}
fn get_cache_filename(&self, url: &Url) -> Option<PathBuf> { fn get_cache_filename(&self, url: &Url) -> Option<PathBuf> {
let mut out = PathBuf::new(); let mut out = PathBuf::new();
@ -52,13 +75,16 @@ impl DiskCache {
} }
"http" | "https" | "data" | "blob" => out = url_to_filename(url).ok()?, "http" | "https" | "data" | "blob" => out = url_to_filename(url).ok()?,
"file" => { "file" => {
let path = match url.to_file_path() { let path = match deno_path_util::url_to_file_path(url) {
Ok(path) => path, Ok(path) => path,
Err(_) => return None, Err(_) => return None,
}; };
let mut path_components = path.components(); let mut path_components = path.components();
if cfg!(target_os = "windows") { if sys_traits::impls::is_windows() {
if url.path() == "/" {
return None; // not a valid windows path
}
if let Some(Component::Prefix(prefix_component)) = if let Some(Component::Prefix(prefix_component)) =
path_components.next() path_components.next()
{ {
@ -97,23 +123,6 @@ impl DiskCache {
Some(out) Some(out)
} }
pub fn get_cache_filename_with_extension(
&self,
url: &Url,
extension: &str,
) -> Option<PathBuf> {
let base = self.get_cache_filename(url)?;
match base.extension() {
None => Some(base.with_extension(extension)),
Some(ext) => {
let original_extension = OsStr::to_str(ext).unwrap();
let final_extension = format!("{original_extension}.{extension}");
Some(base.with_extension(final_extension))
}
}
}
pub fn get(&self, filename: &Path) -> std::io::Result<Vec<u8>> { pub fn get(&self, filename: &Path) -> std::io::Result<Vec<u8>> {
let path = self.location.join(filename); let path = self.location.join(filename);
Ok(self.sys.fs_read(path)?.into_owned()) Ok(self.sys.fs_read(path)?.into_owned())
@ -268,7 +277,7 @@ mod tests {
for test_case in &test_cases { for test_case in &test_cases {
let cache_filename = let cache_filename =
cache.get_cache_filename(&Url::parse(test_case).unwrap()); cache.get_cache_filename(&Url::parse(test_case).unwrap());
assert_eq!(cache_filename, None); assert_eq!(cache_filename, None, "Failed for {:?}", test_case);
} }
} }
} }

View file

@ -1,19 +1,28 @@
// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::hash::Hash;
use std::hash::Hasher;
use std::path::PathBuf; use std::path::PathBuf;
use deno_ast::ModuleSpecifier; use anyhow::anyhow;
use deno_core::anyhow::anyhow; use anyhow::Error as AnyError;
use deno_core::error::AnyError; use deno_unsync::sync::AtomicFlag;
use deno_core::unsync::sync::AtomicFlag; use url::Url;
use deno_lib::version::DENO_VERSION_INFO;
use super::DiskCache; use super::DiskCache;
use super::DiskCacheSys;
#[allow(clippy::disallowed_types)]
pub type EmitCacheRc<TSys> = crate::sync::MaybeArc<EmitCache<TSys>>;
#[sys_traits::auto_impl]
pub trait EmitCacheSys: DiskCacheSys + sys_traits::EnvVar {}
/// The cache that stores previously emitted files. /// The cache that stores previously emitted files.
#[derive(Debug)] #[derive(Debug)]
pub struct EmitCache { pub struct EmitCache<TSys: EmitCacheSys> {
disk_cache: DiskCache, disk_cache: DiskCache<TSys>,
emit_failed_flag: AtomicFlag, emit_failed_flag: AtomicFlag,
file_serializer: EmitFileSerializer, file_serializer: EmitFileSerializer,
mode: Mode, mode: Mode,
@ -25,9 +34,14 @@ enum Mode {
Disable, Disable,
} }
impl EmitCache { impl<TSys: EmitCacheSys> EmitCache<TSys> {
pub fn new(disk_cache: DiskCache) -> Self { pub fn new(
let mode = match std::env::var("DENO_EMIT_CACHE_MODE") sys: &TSys,
disk_cache: DiskCache<TSys>,
cache_version: Cow<'static, str>,
) -> Self {
let mode = match sys
.env_var("DENO_EMIT_CACHE_MODE")
.unwrap_or_default() .unwrap_or_default()
.as_str() .as_str()
{ {
@ -42,9 +56,7 @@ impl EmitCache {
Self { Self {
disk_cache, disk_cache,
emit_failed_flag: Default::default(), emit_failed_flag: Default::default(),
file_serializer: EmitFileSerializer { file_serializer: EmitFileSerializer { cache_version },
cli_version: DENO_VERSION_INFO.deno,
},
mode, mode,
} }
} }
@ -59,7 +71,7 @@ impl EmitCache {
/// or emits that do not match the source. /// or emits that do not match the source.
pub fn get_emit_code( pub fn get_emit_code(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
expected_source_hash: u64, expected_source_hash: u64,
) -> Option<String> { ) -> Option<String> {
if matches!(self.mode, Mode::Disable) { if matches!(self.mode, Mode::Disable) {
@ -74,12 +86,7 @@ impl EmitCache {
} }
/// Sets the emit code in the cache. /// Sets the emit code in the cache.
pub fn set_emit_code( pub fn set_emit_code(&self, specifier: &Url, source_hash: u64, code: &[u8]) {
&self,
specifier: &ModuleSpecifier,
source_hash: u64,
code: &[u8],
) {
if let Err(err) = self.set_emit_code_result(specifier, source_hash, code) { if let Err(err) = self.set_emit_code_result(specifier, source_hash, code) {
// might error in cases such as a readonly file system // might error in cases such as a readonly file system
log::debug!("Error saving emit data ({}): {}", specifier, err); log::debug!("Error saving emit data ({}): {}", specifier, err);
@ -90,7 +97,7 @@ impl EmitCache {
fn set_emit_code_result( fn set_emit_code_result(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
source_hash: u64, source_hash: u64,
code: &[u8], code: &[u8],
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
@ -108,7 +115,7 @@ impl EmitCache {
Ok(()) Ok(())
} }
fn get_emit_filename(&self, specifier: &ModuleSpecifier) -> Option<PathBuf> { fn get_emit_filename(&self, specifier: &Url) -> Option<PathBuf> {
self self
.disk_cache .disk_cache
.get_cache_filename_with_extension(specifier, "js") .get_cache_filename_with_extension(specifier, "js")
@ -119,7 +126,7 @@ const LAST_LINE_PREFIX: &str = "\n// denoCacheMetadata=";
#[derive(Debug)] #[derive(Debug)]
struct EmitFileSerializer { struct EmitFileSerializer {
cli_version: &'static str, cache_version: Cow<'static, str>,
} }
impl EmitFileSerializer { impl EmitFileSerializer {
@ -172,11 +179,11 @@ impl EmitFileSerializer {
// it's ok to use an insecure hash here because // it's ok to use an insecure hash here because
// if someone can change the emit source then they // if someone can change the emit source then they
// can also change the version hash // can also change the version hash
deno_lib::util::hash::FastInsecureHasher::new_without_deno_version() // use cli_version property instead let mut hasher = twox_hash::XxHash64::default();
.write(bytes) bytes.hash(&mut hasher);
// emit should not be re-used between cli versions // emit should not be re-used between cli versions
.write_str(self.cli_version) self.cache_version.hash(&mut hasher);
.finish() hasher.finish()
} }
} }
@ -185,27 +192,28 @@ mod test {
use test_util::TempDir; use test_util::TempDir;
use super::*; use super::*;
use crate::sys::CliSys;
#[test] #[test]
pub fn emit_cache_general_use() { pub fn emit_cache_general_use() {
let temp_dir = TempDir::new(); let temp_dir = TempDir::new();
let disk_cache = let disk_cache =
DiskCache::new(CliSys::default(), temp_dir.path().to_path_buf()); DiskCache::new(sys_traits::impls::RealSys, temp_dir.path().to_path_buf());
let cache = EmitCache { let cache = EmitCache {
disk_cache: disk_cache.clone(), disk_cache: disk_cache.clone(),
file_serializer: EmitFileSerializer { file_serializer: EmitFileSerializer {
cli_version: "1.0.0", cache_version: "1.0.0".into(),
}, },
emit_failed_flag: Default::default(), emit_failed_flag: Default::default(),
mode: Mode::Normal, mode: Mode::Normal,
}; };
let specifier1 = let specifier1 = deno_path_util::url_from_file_path(
ModuleSpecifier::from_file_path(temp_dir.path().join("file1.ts")) temp_dir.path().join("file1.ts").as_path(),
)
.unwrap(); .unwrap();
let specifier2 = let specifier2 = deno_path_util::url_from_file_path(
ModuleSpecifier::from_file_path(temp_dir.path().join("file2.ts")) temp_dir.path().join("file2.ts").as_path(),
)
.unwrap(); .unwrap();
assert_eq!(cache.get_emit_code(&specifier1, 1), None); assert_eq!(cache.get_emit_code(&specifier1, 1), None);
let emit_code1 = "text1".to_string(); let emit_code1 = "text1".to_string();
@ -225,7 +233,7 @@ mod test {
let cache = EmitCache { let cache = EmitCache {
disk_cache: disk_cache.clone(), disk_cache: disk_cache.clone(),
file_serializer: EmitFileSerializer { file_serializer: EmitFileSerializer {
cli_version: "2.0.0", cache_version: "2.0.0".into(),
}, },
emit_failed_flag: Default::default(), emit_failed_flag: Default::default(),
mode: Mode::Normal, mode: Mode::Normal,
@ -237,7 +245,7 @@ mod test {
let cache = EmitCache { let cache = EmitCache {
disk_cache, disk_cache,
file_serializer: EmitFileSerializer { file_serializer: EmitFileSerializer {
cli_version: "2.0.0", cache_version: "2.0.0".into(),
}, },
emit_failed_flag: Default::default(), emit_failed_flag: Default::default(),
mode: Mode::Normal, mode: Mode::Normal,

24
libs/resolver/cache/mod.rs vendored Normal file
View file

@ -0,0 +1,24 @@
// Copyright 2018-2025 the Deno authors. MIT license.
mod deno_dir;
mod disk_cache;
mod emit;
#[cfg(feature = "deno_ast")]
mod parsed_source;
pub use deno_dir::DenoDir;
pub use deno_dir::DenoDirOptions;
pub use deno_dir::DenoDirProvider;
pub use deno_dir::DenoDirProviderRc;
pub use deno_dir::DenoDirSys;
pub use disk_cache::DiskCache;
pub use disk_cache::DiskCacheSys;
pub use emit::EmitCache;
pub use emit::EmitCacheRc;
pub use emit::EmitCacheSys;
#[cfg(feature = "deno_ast")]
pub use parsed_source::LazyGraphSourceParser;
#[cfg(feature = "deno_ast")]
pub use parsed_source::ParsedSourceCache;
#[cfg(feature = "deno_ast")]
pub use parsed_source::ParsedSourceCacheRc;

View file

@ -1,17 +1,12 @@
// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2018-2025 the Deno authors. MIT license.
use std::collections::HashMap;
use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_ast::ParsedSource; use deno_ast::ParsedSource;
use deno_core::parking_lot::Mutex;
use deno_graph::ast::CapturingEsParser; use deno_graph::ast::CapturingEsParser;
use deno_graph::ast::DefaultEsParser; use deno_graph::ast::DefaultEsParser;
use deno_graph::ast::EsParser; use deno_graph::ast::EsParser;
use deno_graph::ast::ParseOptions;
use deno_graph::ast::ParsedSourceStore; use deno_graph::ast::ParsedSourceStore;
use deno_media_type::MediaType;
use url::Url;
/// Lazily parses JS/TS sources from a `deno_graph::ModuleGraph` given /// Lazily parses JS/TS sources from a `deno_graph::ModuleGraph` given
/// a `ParsedSourceCache`. Note that deno_graph doesn't necessarily cause /// a `ParsedSourceCache`. Note that deno_graph doesn't necessarily cause
@ -34,8 +29,8 @@ impl<'a> LazyGraphSourceParser<'a> {
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
pub fn get_or_parse_source( pub fn get_or_parse_source(
&self, &self,
module_specifier: &ModuleSpecifier, module_specifier: &Url,
) -> Result<Option<deno_ast::ParsedSource>, deno_ast::ParseDiagnostic> { ) -> Result<Option<ParsedSource>, deno_ast::ParseDiagnostic> {
let Some(deno_graph::Module::Js(module)) = self.graph.get(module_specifier) let Some(deno_graph::Module::Js(module)) = self.graph.get(module_specifier)
else { else {
return Ok(None); return Ok(None);
@ -47,9 +42,15 @@ impl<'a> LazyGraphSourceParser<'a> {
} }
} }
#[allow(clippy::disallowed_types)] // ok because we always store source text as Arc<str>
type ArcStr = std::sync::Arc<str>;
#[allow(clippy::disallowed_types)]
pub type ParsedSourceCacheRc = crate::sync::MaybeArc<ParsedSourceCache>;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ParsedSourceCache { pub struct ParsedSourceCache {
sources: Mutex<HashMap<ModuleSpecifier, ParsedSource>>, sources: crate::sync::MaybeDashMap<Url, ParsedSource>,
} }
impl ParsedSourceCache { impl ParsedSourceCache {
@ -60,7 +61,7 @@ impl ParsedSourceCache {
) -> Result<ParsedSource, deno_ast::ParseDiagnostic> { ) -> Result<ParsedSource, deno_ast::ParseDiagnostic> {
let parser = self.as_capturing_parser(); let parser = self.as_capturing_parser();
// this will conditionally parse because it's using a CapturingEsParser // this will conditionally parse because it's using a CapturingEsParser
parser.parse_program(ParseOptions { parser.parse_program(deno_graph::ast::ParseOptions {
specifier: &module.specifier, specifier: &module.specifier,
source: module.source.text.clone(), source: module.source.text.clone(),
media_type: module.media_type, media_type: module.media_type,
@ -68,11 +69,11 @@ impl ParsedSourceCache {
}) })
} }
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err, clippy::disallowed_types)]
pub fn remove_or_parse_module( pub fn remove_or_parse_module(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
source: Arc<str>, source: ArcStr,
media_type: MediaType, media_type: MediaType,
) -> Result<ParsedSource, deno_ast::ParseDiagnostic> { ) -> Result<ParsedSource, deno_ast::ParseDiagnostic> {
if let Some(parsed_source) = self.remove_parsed_source(specifier) { if let Some(parsed_source) = self.remove_parsed_source(specifier) {
@ -84,7 +85,7 @@ impl ParsedSourceCache {
return Ok(parsed_source); return Ok(parsed_source);
} }
} }
let options = ParseOptions { let options = deno_graph::ast::ParseOptions {
specifier, specifier,
source, source,
media_type, media_type,
@ -94,13 +95,13 @@ impl ParsedSourceCache {
} }
/// Frees the parsed source from memory. /// Frees the parsed source from memory.
pub fn free(&self, specifier: &ModuleSpecifier) { pub fn free(&self, specifier: &Url) {
self.sources.lock().remove(specifier); self.sources.remove(specifier);
} }
/// Fress all parsed sources from memory. /// Fress all parsed sources from memory.
pub fn free_all(&self) { pub fn free_all(&self) {
self.sources.lock().clear(); self.sources.clear();
} }
/// Creates a parser that will reuse a ParsedSource from the store /// Creates a parser that will reuse a ParsedSource from the store
@ -109,9 +110,9 @@ impl ParsedSourceCache {
CapturingEsParser::new(None, self) CapturingEsParser::new(None, self)
} }
#[cfg(test)] #[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.sources.lock().len() self.sources.len()
} }
} }
@ -120,43 +121,37 @@ impl ParsedSourceCache {
/// and in LSP settings the concurrency will be enforced /// and in LSP settings the concurrency will be enforced
/// at a higher level to ensure this will have the latest /// at a higher level to ensure this will have the latest
/// parsed source. /// parsed source.
impl deno_graph::ast::ParsedSourceStore for ParsedSourceCache { impl ParsedSourceStore for ParsedSourceCache {
fn set_parsed_source( fn set_parsed_source(
&self, &self,
specifier: ModuleSpecifier, specifier: Url,
parsed_source: ParsedSource, parsed_source: ParsedSource,
) -> Option<ParsedSource> { ) -> Option<ParsedSource> {
self.sources.lock().insert(specifier, parsed_source) self.sources.insert(specifier, parsed_source)
} }
fn get_parsed_source( fn get_parsed_source(&self, specifier: &Url) -> Option<ParsedSource> {
&self, self.sources.get(specifier).map(|p| p.clone())
specifier: &ModuleSpecifier,
) -> Option<ParsedSource> {
self.sources.lock().get(specifier).cloned()
} }
fn remove_parsed_source( fn remove_parsed_source(&self, specifier: &Url) -> Option<ParsedSource> {
&self, self.sources.remove(specifier).map(|(_, p)| p)
specifier: &ModuleSpecifier,
) -> Option<ParsedSource> {
self.sources.lock().remove(specifier)
} }
fn get_scope_analysis_parsed_source( fn get_scope_analysis_parsed_source(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
) -> Option<ParsedSource> { ) -> Option<ParsedSource> {
let mut sources = self.sources.lock(); {
let parsed_source = sources.get(specifier)?; let parsed_source = self.sources.get(specifier)?;
if parsed_source.has_scope_analysis() { if parsed_source.has_scope_analysis() {
Some(parsed_source.clone()) return Some(parsed_source.clone());
} else { }
}
// upgrade to have scope analysis // upgrade to have scope analysis
let parsed_source = sources.remove(specifier).unwrap(); let (specifier, parsed_source) = self.sources.remove(specifier)?;
let parsed_source = parsed_source.into_with_scope_analysis(); let parsed_source = parsed_source.into_with_scope_analysis();
sources.insert(specifier.clone(), parsed_source.clone()); self.sources.insert(specifier, parsed_source.clone());
Some(parsed_source) Some(parsed_source)
} }
}
} }

View file

@ -1,7 +1,9 @@
// Copyright 2018-2025 the Deno authors. MIT license. // Copyright 2018-2025 the Deno authors. MIT license.
use std::sync::Arc; use std::hash::Hash;
use std::hash::Hasher;
use anyhow::Error as AnyError;
use deno_ast::EmittedSourceText; use deno_ast::EmittedSourceText;
use deno_ast::ModuleKind; use deno_ast::ModuleKind;
use deno_ast::SourceMapOption; use deno_ast::SourceMapOption;
@ -10,38 +12,51 @@ use deno_ast::SourceRanged;
use deno_ast::SourceRangedForSpanned; use deno_ast::SourceRangedForSpanned;
use deno_ast::TranspileModuleOptions; use deno_ast::TranspileModuleOptions;
use deno_ast::TranspileResult; use deno_ast::TranspileResult;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox; use deno_error::JsErrorBox;
use deno_graph::MediaType; use deno_graph::MediaType;
use deno_graph::Module; use deno_graph::Module;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
use deno_lib::util::hash::FastInsecureHasher; use futures::stream::FuturesUnordered;
use deno_resolver::deno_json::CompilerOptionsResolver; use futures::FutureExt;
use deno_resolver::deno_json::TranspileAndEmitOptions; use futures::StreamExt;
use node_resolver::InNpmPackageChecker;
use url::Url;
use crate::cache::EmitCache; use crate::cache::EmitCacheRc;
use crate::cache::EmitCacheSys;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::resolver::CliCjsTracker; use crate::cache::ParsedSourceCacheRc;
use crate::cjs::CjsTrackerRc;
use crate::deno_json::CompilerOptionsResolverRc;
use crate::deno_json::TranspileAndEmitOptions;
#[allow(clippy::disallowed_types)] // ok because we always store source text as Arc<str>
type ArcStr = std::sync::Arc<str>;
#[allow(clippy::disallowed_types)]
pub type EmitterRc<TInNpmPackageChecker, TSys> =
crate::sync::MaybeArc<Emitter<TInNpmPackageChecker, TSys>>;
#[sys_traits::auto_impl]
pub trait EmitterSys: EmitCacheSys {}
#[derive(Debug)] #[derive(Debug)]
pub struct Emitter { pub struct Emitter<TInNpmPackageChecker: InNpmPackageChecker, TSys: EmitterSys>
cjs_tracker: Arc<CliCjsTracker>, {
emit_cache: Arc<EmitCache>, cjs_tracker: CjsTrackerRc<TInNpmPackageChecker, TSys>,
parsed_source_cache: Arc<ParsedSourceCache>, emit_cache: EmitCacheRc<TSys>,
compiler_options_resolver: Arc<CompilerOptionsResolver>, parsed_source_cache: ParsedSourceCacheRc,
compiler_options_resolver: CompilerOptionsResolverRc,
} }
impl Emitter { impl<TInNpmPackageChecker: InNpmPackageChecker, TSys: EmitterSys>
Emitter<TInNpmPackageChecker, TSys>
{
pub fn new( pub fn new(
cjs_tracker: Arc<CliCjsTracker>, cjs_tracker: CjsTrackerRc<TInNpmPackageChecker, TSys>,
emit_cache: Arc<EmitCache>, emit_cache: EmitCacheRc<TSys>,
parsed_source_cache: Arc<ParsedSourceCache>, parsed_source_cache: ParsedSourceCacheRc,
compiler_options_resolver: Arc<CompilerOptionsResolver>, compiler_options_resolver: CompilerOptionsResolverRc,
) -> Self { ) -> Self {
Self { Self {
cjs_tracker, cjs_tracker,
@ -91,7 +106,7 @@ impl Emitter {
/// Gets a cached emit if the source matches the hash found in the cache. /// Gets a cached emit if the source matches the hash found in the cache.
pub fn maybe_cached_emit( pub fn maybe_cached_emit(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
module_kind: deno_ast::ModuleKind, module_kind: deno_ast::ModuleKind,
source: &str, source: &str,
) -> Result<Option<String>, AnyError> { ) -> Result<Option<String>, AnyError> {
@ -106,10 +121,10 @@ impl Emitter {
pub async fn emit_parsed_source( pub async fn emit_parsed_source(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
media_type: MediaType, media_type: MediaType,
module_kind: ModuleKind, module_kind: ModuleKind,
source: &Arc<str>, source: &ArcStr,
) -> Result<String, EmitParsedSourceHelperError> { ) -> Result<String, EmitParsedSourceHelperError> {
let transpile_and_emit_options = self let transpile_and_emit_options = self
.compiler_options_resolver .compiler_options_resolver
@ -127,11 +142,12 @@ impl Emitter {
PreEmitResult::NotCached { source_hash } => { PreEmitResult::NotCached { source_hash } => {
let parsed_source_cache = self.parsed_source_cache.clone(); let parsed_source_cache = self.parsed_source_cache.clone();
let transpile_and_emit_options = transpile_and_emit_options.clone(); let transpile_and_emit_options = transpile_and_emit_options.clone();
let transpiled_source = deno_core::unsync::spawn_blocking({ #[cfg(feature = "sync")]
let transpiled_source = crate::rt::spawn_blocking({
let specifier = specifier.clone(); let specifier = specifier.clone();
let source = source.clone(); let source = source.clone();
move || { move || {
EmitParsedSourceHelper::transpile( transpile(
&parsed_source_cache, &parsed_source_cache,
&specifier, &specifier,
media_type, media_type,
@ -145,6 +161,17 @@ impl Emitter {
}) })
.await .await
.unwrap()?; .unwrap()?;
#[cfg(not(feature = "sync"))]
let transpiled_source = transpile(
&parsed_source_cache,
&specifier,
media_type,
module_kind,
source.clone(),
&transpile_and_emit_options.transpile,
&transpile_and_emit_options.emit,
)?
.text;
helper.post_emit_parsed_source( helper.post_emit_parsed_source(
specifier, specifier,
&transpiled_source, &transpiled_source,
@ -158,10 +185,10 @@ impl Emitter {
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
pub fn emit_parsed_source_sync( pub fn emit_parsed_source_sync(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
media_type: MediaType, media_type: MediaType,
module_kind: deno_ast::ModuleKind, module_kind: deno_ast::ModuleKind,
source: &Arc<str>, source: &ArcStr,
) -> Result<String, EmitParsedSourceHelperError> { ) -> Result<String, EmitParsedSourceHelperError> {
let transpile_and_emit_options = self let transpile_and_emit_options = self
.compiler_options_resolver .compiler_options_resolver
@ -177,7 +204,7 @@ impl Emitter {
) { ) {
PreEmitResult::Cached(emitted_text) => Ok(emitted_text), PreEmitResult::Cached(emitted_text) => Ok(emitted_text),
PreEmitResult::NotCached { source_hash } => { PreEmitResult::NotCached { source_hash } => {
let transpiled_source = EmitParsedSourceHelper::transpile( let transpiled_source = transpile(
&self.parsed_source_cache, &self.parsed_source_cache,
specifier, specifier,
media_type, media_type,
@ -199,10 +226,10 @@ impl Emitter {
pub fn emit_parsed_source_for_deno_compile( pub fn emit_parsed_source_for_deno_compile(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
media_type: MediaType, media_type: MediaType,
module_kind: deno_ast::ModuleKind, module_kind: deno_ast::ModuleKind,
source: &Arc<str>, source: &ArcStr,
) -> Result<(String, String), AnyError> { ) -> Result<(String, String), AnyError> {
let transpile_and_emit_options = self let transpile_and_emit_options = self
.compiler_options_resolver .compiler_options_resolver
@ -214,7 +241,7 @@ impl Emitter {
// strip off the path to have more deterministic builds as we don't care // strip off the path to have more deterministic builds as we don't care
// about the source name because we manually provide the source map to v8 // about the source name because we manually provide the source map to v8
emit_options.source_map_base = Some(deno_path_util::url_parent(specifier)); emit_options.source_map_base = Some(deno_path_util::url_parent(specifier));
let source = EmitParsedSourceHelper::transpile( let source = transpile(
&self.parsed_source_cache, &self.parsed_source_cache,
specifier, specifier,
media_type, media_type,
@ -227,22 +254,19 @@ impl Emitter {
} }
/// Expects a file URL, panics otherwise. /// Expects a file URL, panics otherwise.
pub async fn load_and_emit_for_hmr( pub fn emit_for_hmr(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
) -> Result<String, CoreError> { source_code: String,
) -> Result<String, JsErrorBox> {
let media_type = MediaType::from_specifier(specifier); let media_type = MediaType::from_specifier(specifier);
let source_code = tokio::fs::read_to_string(
ModuleSpecifier::to_file_path(specifier).unwrap(),
)
.await?;
match media_type { match media_type {
MediaType::TypeScript MediaType::TypeScript
| MediaType::Mts | MediaType::Mts
| MediaType::Cts | MediaType::Cts
| MediaType::Jsx | MediaType::Jsx
| MediaType::Tsx => { | MediaType::Tsx => {
let source_arc: Arc<str> = source_code.into(); let source_arc: ArcStr = source_code.into();
let parsed_source = self let parsed_source = self
.parsed_source_cache .parsed_source_cache
.remove_or_parse_module(specifier, source_arc, media_type) .remove_or_parse_module(specifier, source_arc, media_type)
@ -306,11 +330,11 @@ impl Emitter {
transpile_and_emit: &TranspileAndEmitOptions, transpile_and_emit: &TranspileAndEmitOptions,
source_text: &str, source_text: &str,
) -> u64 { ) -> u64 {
FastInsecureHasher::new_without_deno_version() // stored in the transpile_and_emit_options_hash let mut hasher = twox_hash::XxHash64::default();
.write_str(source_text) source_text.hash(&mut hasher);
.write_u64(transpile_and_emit.pre_computed_hash) transpile_and_emit.pre_computed_hash.hash(&mut hasher);
.write_hashable(module_kind) module_kind.hash(&mut hasher);
.finish() hasher.finish()
} }
} }
@ -338,15 +362,21 @@ pub enum EmitParsedSourceHelperError {
} }
/// Helper to share code between async and sync emit_parsed_source methods. /// Helper to share code between async and sync emit_parsed_source methods.
struct EmitParsedSourceHelper<'a>(&'a Emitter); struct EmitParsedSourceHelper<
'a,
TInNpmPackageChecker: InNpmPackageChecker,
TSys: EmitterSys,
>(&'a Emitter<TInNpmPackageChecker, TSys>);
impl EmitParsedSourceHelper<'_> { impl<TInNpmPackageChecker: InNpmPackageChecker, TSys: EmitterSys>
EmitParsedSourceHelper<'_, TInNpmPackageChecker, TSys>
{
pub fn pre_emit_parsed_source( pub fn pre_emit_parsed_source(
&self, &self,
specifier: &ModuleSpecifier, specifier: &Url,
module_kind: deno_ast::ModuleKind, module_kind: deno_ast::ModuleKind,
transpile_and_emit_options: &TranspileAndEmitOptions, transpile_and_emit_options: &TranspileAndEmitOptions,
source: &Arc<str>, source: &ArcStr,
) -> PreEmitResult { ) -> PreEmitResult {
let source_hash = let source_hash =
self self
@ -362,16 +392,30 @@ impl EmitParsedSourceHelper<'_> {
} }
} }
#[allow(clippy::result_large_err)] pub fn post_emit_parsed_source(
pub fn transpile( &self,
specifier: &Url,
transpiled_source: &str,
source_hash: u64,
) {
self.0.emit_cache.set_emit_code(
specifier,
source_hash,
transpiled_source.as_bytes(),
);
}
}
#[allow(clippy::result_large_err)]
fn transpile(
parsed_source_cache: &ParsedSourceCache, parsed_source_cache: &ParsedSourceCache,
specifier: &ModuleSpecifier, specifier: &Url,
media_type: MediaType, media_type: MediaType,
module_kind: deno_ast::ModuleKind, module_kind: deno_ast::ModuleKind,
source: Arc<str>, source: ArcStr,
transpile_options: &deno_ast::TranspileOptions, transpile_options: &deno_ast::TranspileOptions,
emit_options: &deno_ast::EmitOptions, emit_options: &deno_ast::EmitOptions,
) -> Result<EmittedSourceText, EmitParsedSourceHelperError> { ) -> Result<EmittedSourceText, EmitParsedSourceHelperError> {
// nothing else needs the parsed source at this point, so remove from // nothing else needs the parsed source at this point, so remove from
// the cache in order to not transpile owned // the cache in order to not transpile owned
let parsed_source = parsed_source_cache let parsed_source = parsed_source_cache
@ -392,20 +436,6 @@ impl EmitParsedSourceHelper<'_> {
} }
}; };
Ok(transpiled_source) Ok(transpiled_source)
}
pub fn post_emit_parsed_source(
&self,
specifier: &ModuleSpecifier,
transpiled_source: &str,
source_hash: u64,
) {
self.0.emit_cache.set_emit_code(
specifier,
source_hash,
transpiled_source.as_bytes(),
);
}
} }
// todo(dsherret): this is a temporary measure until we have swc erroring for this // todo(dsherret): this is a temporary measure until we have swc erroring for this

View file

@ -31,13 +31,16 @@ use node_resolver::NodeResolverOptions;
use node_resolver::NodeResolverRc; use node_resolver::NodeResolverRc;
use node_resolver::PackageJsonResolver; use node_resolver::PackageJsonResolver;
use node_resolver::PackageJsonResolverRc; use node_resolver::PackageJsonResolverRc;
use sys_traits::EnvCacheDir;
use sys_traits::EnvCurrentDir;
use sys_traits::EnvHomeDir;
use sys_traits::EnvVar;
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
use crate::cache::DenoDir;
use crate::cache::DenoDirOptions;
use crate::cache::DenoDirProvider;
use crate::cache::DenoDirProviderRc;
use crate::cache::DenoDirSys;
use crate::cache::EmitCache;
use crate::cache::EmitCacheRc;
use crate::cjs::CjsTracker; use crate::cjs::CjsTracker;
use crate::cjs::CjsTrackerRc; use crate::cjs::CjsTrackerRc;
use crate::cjs::IsCjsResolutionMode; use crate::cjs::IsCjsResolutionMode;
@ -163,49 +166,6 @@ pub trait SpecifiedImportMapProvider:
) -> Result<Option<crate::workspace::SpecifiedImportMap>, anyhow::Error>; ) -> Result<Option<crate::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>>;
#[sys_traits::auto_impl]
pub trait DenoDirPathProviderSys:
EnvCacheDir + EnvHomeDir + EnvVar + EnvCurrentDir
{
}
/// 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: DenoDirPathProviderSys> {
sys: TSys,
options: DenoDirPathProviderOptions,
deno_dir: Deferred<PathBuf>,
}
impl<TSys: DenoDirPathProviderSys> 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)] #[derive(Debug)]
pub struct NpmProcessStateOptions { pub struct NpmProcessStateOptions {
pub node_modules_dir: Option<Cow<'static, str>>, pub node_modules_dir: Option<Cow<'static, str>>,
@ -213,15 +173,18 @@ pub struct NpmProcessStateOptions {
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct WorkspaceFactoryOptions<TSys: WorkspaceFactorySys> { pub struct WorkspaceFactoryOptions {
pub additional_config_file_names: &'static [&'static str], pub additional_config_file_names: &'static [&'static str],
pub config_discovery: ConfigDiscoveryOption, pub config_discovery: ConfigDiscoveryOption,
pub deno_dir_path_provider: Option<DenoDirPathProviderRc<TSys>>,
pub is_package_manager_subcommand: bool, pub is_package_manager_subcommand: bool,
/// Version to use for the emit cache. This is something that
/// should change when the version of the underlying emit changes.
pub emit_cache_version: Cow<'static, str>,
pub frozen_lockfile: Option<bool>, pub frozen_lockfile: Option<bool>,
pub lock_arg: Option<String>, pub lock_arg: Option<String>,
/// Whether to skip writing to the lockfile. /// Whether to skip writing to the lockfile.
pub lockfile_skip_write: bool, pub lockfile_skip_write: bool,
pub maybe_custom_deno_dir_root: Option<PathBuf>,
pub node_modules_dir: Option<NodeModulesDirMode>, pub node_modules_dir: Option<NodeModulesDirMode>,
pub no_lock: bool, pub no_lock: bool,
pub no_npm: bool, pub no_npm: bool,
@ -238,7 +201,7 @@ pub type WorkspaceFactoryRc<TSys> =
#[sys_traits::auto_impl] #[sys_traits::auto_impl]
pub trait WorkspaceFactorySys: pub trait WorkspaceFactorySys:
DenoDirPathProviderSys DenoDirSys
+ crate::lockfile::LockfileSys + crate::lockfile::LockfileSys
+ crate::npm::NpmResolverSys + crate::npm::NpmResolverSys
+ deno_cache_dir::GlobalHttpCacheSys + deno_cache_dir::GlobalHttpCacheSys
@ -248,7 +211,8 @@ pub trait WorkspaceFactorySys:
pub struct WorkspaceFactory<TSys: WorkspaceFactorySys> { pub struct WorkspaceFactory<TSys: WorkspaceFactorySys> {
sys: TSys, sys: TSys,
deno_dir_path: DenoDirPathProviderRc<TSys>, deno_dir_provider: Deferred<DenoDirProviderRc<TSys>>,
emit_cache: Deferred<EmitCacheRc<TSys>>,
global_http_cache: Deferred<GlobalHttpCacheRc<TSys>>, global_http_cache: Deferred<GlobalHttpCacheRc<TSys>>,
http_cache: Deferred<GlobalOrLocalHttpCache<TSys>>, http_cache: Deferred<GlobalOrLocalHttpCache<TSys>>,
jsr_url: Deferred<Url>, jsr_url: Deferred<Url>,
@ -263,27 +227,19 @@ pub struct WorkspaceFactory<TSys: WorkspaceFactorySys> {
Deferred<WorkspaceExternalImportMapLoaderRc<TSys>>, Deferred<WorkspaceExternalImportMapLoaderRc<TSys>>,
workspace_npm_link_packages: Deferred<WorkspaceNpmLinkPackagesRc>, workspace_npm_link_packages: Deferred<WorkspaceNpmLinkPackagesRc>,
initial_cwd: PathBuf, initial_cwd: PathBuf,
options: WorkspaceFactoryOptions<TSys>, options: WorkspaceFactoryOptions,
} }
impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> { impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
pub fn new( pub fn new(
sys: TSys, sys: TSys,
initial_cwd: PathBuf, initial_cwd: PathBuf,
mut options: WorkspaceFactoryOptions<TSys>, options: WorkspaceFactoryOptions,
) -> Self { ) -> Self {
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, sys,
deno_dir_provider: Default::default(),
emit_cache: Default::default(),
global_http_cache: Default::default(), global_http_cache: Default::default(),
http_cache: Default::default(), http_cache: Default::default(),
jsr_url: Default::default(), jsr_url: Default::default(),
@ -308,6 +264,27 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
self.workspace_directory = Deferred::from(workspace_directory); self.workspace_directory = Deferred::from(workspace_directory);
} }
pub fn deno_dir_provider(&self) -> &DenoDirProviderRc<TSys> {
self.deno_dir_provider.get_or_init(|| {
new_rc(DenoDirProvider::new(
self.sys.clone(),
DenoDirOptions {
maybe_custom_root: self.options.maybe_custom_deno_dir_root.clone(),
},
))
})
}
pub fn emit_cache(&self) -> Result<&EmitCacheRc<TSys>, anyhow::Error> {
self.emit_cache.get_or_try_init(|| {
Ok(new_rc(EmitCache::new(
&self.sys,
self.deno_dir()?.gen_cache.clone(),
self.options.emit_cache_version.clone(),
)))
})
}
pub fn jsr_url(&self) -> &Url { pub fn jsr_url(&self) -> &Url {
self.jsr_url.get_or_init(|| resolve_jsr_url(&self.sys)) self.jsr_url.get_or_init(|| resolve_jsr_url(&self.sys))
} }
@ -348,7 +325,8 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
let workspace = &self.workspace_directory()?.workspace; let workspace = &self.workspace_directory()?.workspace;
if let Some(pkg_json) = workspace.root_pkg_json() { if let Some(pkg_json) = workspace.root_pkg_json() {
if let Ok(deno_dir) = self.deno_dir_path() { if let Ok(deno_dir) = self.deno_dir() {
let deno_dir = &deno_dir.root;
// `deno_dir` can be symlink in macOS or on the CI // `deno_dir` can be symlink in macOS or on the CI
if let Ok(deno_dir) = if let Ok(deno_dir) =
canonicalize_path_maybe_not_exists(&self.sys, deno_dir) canonicalize_path_maybe_not_exists(&self.sys, deno_dir)
@ -431,15 +409,15 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
.map(|p| p.as_deref()) .map(|p| p.as_deref())
} }
pub fn deno_dir_path(&self) -> Result<&PathBuf, DenoDirResolutionError> { pub fn deno_dir(&self) -> Result<&DenoDir<TSys>, DenoDirResolutionError> {
self.deno_dir_path.get_or_create() self.deno_dir_provider().get_or_create()
} }
pub fn global_http_cache( pub fn global_http_cache(
&self, &self,
) -> Result<&GlobalHttpCacheRc<TSys>, DenoDirResolutionError> { ) -> Result<&GlobalHttpCacheRc<TSys>, DenoDirResolutionError> {
self.global_http_cache.get_or_try_init(|| { self.global_http_cache.get_or_try_init(|| {
let global_cache_dir = self.deno_dir_path()?.join("remote"); let global_cache_dir = self.deno_dir()?.remote_folder_path();
let global_http_cache = new_rc(deno_cache_dir::GlobalHttpCache::new( let global_http_cache = new_rc(deno_cache_dir::GlobalHttpCache::new(
self.sys.clone(), self.sys.clone(),
global_cache_dir, global_cache_dir,
@ -514,7 +492,7 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
&self, &self,
) -> Result<&NpmCacheDirRc, NpmCacheDirCreateError> { ) -> Result<&NpmCacheDirRc, NpmCacheDirCreateError> {
self.npm_cache_dir.get_or_try_init(|| { self.npm_cache_dir.get_or_try_init(|| {
let npm_cache_dir = self.deno_dir_path()?.join("npm"); let npm_cache_dir = self.deno_dir()?.npm_folder_path();
Ok(new_rc(NpmCacheDir::new( Ok(new_rc(NpmCacheDir::new(
&self.sys, &self.sys,
npm_cache_dir, npm_cache_dir,
@ -683,6 +661,8 @@ pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
#[cfg(feature = "graph")] #[cfg(feature = "graph")]
deno_resolver: deno_resolver:
async_once_cell::OnceCell<crate::graph::DefaultDenoResolverRc<TSys>>, async_once_cell::OnceCell<crate::graph::DefaultDenoResolverRc<TSys>>,
#[cfg(feature = "deno_ast")]
emitter: Deferred<crate::emit::EmitterRc<DenoInNpmPackageChecker, TSys>>,
#[cfg(feature = "graph")] #[cfg(feature = "graph")]
found_package_json_dep_flag: crate::graph::FoundPackageJsonDepFlagRc, found_package_json_dep_flag: crate::graph::FoundPackageJsonDepFlagRc,
in_npm_package_checker: Deferred<DenoInNpmPackageChecker>, in_npm_package_checker: Deferred<DenoInNpmPackageChecker>,
@ -704,6 +684,8 @@ pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
>, >,
npm_resolver: Deferred<NpmResolver<TSys>>, npm_resolver: Deferred<NpmResolver<TSys>>,
npm_resolution: NpmResolutionCellRc, npm_resolution: NpmResolutionCellRc,
#[cfg(feature = "deno_ast")]
parsed_source_cache: crate::cache::ParsedSourceCacheRc,
pkg_json_resolver: Deferred<PackageJsonResolverRc<TSys>>, pkg_json_resolver: Deferred<PackageJsonResolverRc<TSys>>,
raw_deno_resolver: async_once_cell::OnceCell<DefaultRawDenoResolverRc<TSys>>, raw_deno_resolver: async_once_cell::OnceCell<DefaultRawDenoResolverRc<TSys>>,
workspace_factory: WorkspaceFactoryRc<TSys>, workspace_factory: WorkspaceFactoryRc<TSys>,
@ -725,6 +707,8 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
raw_deno_resolver: Default::default(), raw_deno_resolver: Default::default(),
#[cfg(feature = "graph")] #[cfg(feature = "graph")]
deno_resolver: Default::default(), deno_resolver: Default::default(),
#[cfg(feature = "deno_ast")]
emitter: Default::default(),
#[cfg(feature = "graph")] #[cfg(feature = "graph")]
found_package_json_dep_flag: Default::default(), found_package_json_dep_flag: Default::default(),
in_npm_package_checker: Default::default(), in_npm_package_checker: Default::default(),
@ -732,6 +716,8 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
npm_req_resolver: Default::default(), npm_req_resolver: Default::default(),
npm_resolution: Default::default(), npm_resolution: Default::default(),
npm_resolver: Default::default(), npm_resolver: Default::default(),
#[cfg(feature = "deno_ast")]
parsed_source_cache: Default::default(),
pkg_json_resolver: Default::default(), pkg_json_resolver: Default::default(),
workspace_factory, workspace_factory,
workspace_resolver: Default::default(), workspace_resolver: Default::default(),
@ -798,6 +784,23 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
}) })
} }
#[cfg(feature = "deno_ast")]
pub fn emitter(
&self,
) -> Result<
&crate::emit::EmitterRc<DenoInNpmPackageChecker, TSys>,
anyhow::Error,
> {
self.emitter.get_or_try_init(|| {
Ok(new_rc(crate::emit::Emitter::new(
self.cjs_tracker()?.clone(),
self.workspace_factory.emit_cache()?.clone(),
self.parsed_source_cache().clone(),
self.compiler_options_resolver()?.clone(),
)))
})
}
#[cfg(feature = "graph")] #[cfg(feature = "graph")]
pub fn found_package_json_dep_flag( pub fn found_package_json_dep_flag(
&self, &self,
@ -936,6 +939,11 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
}) })
} }
#[cfg(feature = "deno_ast")]
pub fn parsed_source_cache(&self) -> &crate::cache::ParsedSourceCacheRc {
&self.parsed_source_cache
}
pub fn workspace_factory(&self) -> &WorkspaceFactoryRc<TSys> { pub fn workspace_factory(&self) -> &WorkspaceFactoryRc<TSys> {
&self.workspace_factory &self.workspace_factory
} }

View file

@ -41,10 +41,13 @@ use crate::workspace::MappedResolutionError;
use crate::workspace::WorkspaceResolvePkgJsonFolderError; use crate::workspace::WorkspaceResolvePkgJsonFolderError;
use crate::workspace::WorkspaceResolver; use crate::workspace::WorkspaceResolver;
pub mod cache;
pub mod cjs; pub mod cjs;
pub mod collections; pub mod collections;
pub mod deno_json; pub mod deno_json;
pub mod display; pub mod display;
#[cfg(feature = "deno_ast")]
pub mod emit;
pub mod factory; pub mod factory;
#[cfg(feature = "graph")] #[cfg(feature = "graph")]
pub mod file_fetcher; pub mod file_fetcher;
@ -54,6 +57,8 @@ pub mod import_map;
pub mod lockfile; pub mod lockfile;
pub mod npm; pub mod npm;
pub mod npmrc; pub mod npmrc;
#[cfg(all(feature = "deno_ast", feature = "sync"))]
mod rt;
mod sync; mod sync;
pub mod workspace; pub mod workspace;

24
libs/resolver/rt.rs Normal file
View file

@ -0,0 +1,24 @@
// Copyright 2018-2025 the Deno authors. MIT license.
#[cfg(not(target_arch = "wasm32"))]
use deno_unsync::JoinHandle;
#[cfg(target_arch = "wasm32")]
pub type JoinHandle<T> =
std::future::Ready<Result<T, std::convert::Infallible>>;
pub fn spawn_blocking<
F: (FnOnce() -> R) + Send + 'static,
R: Send + 'static,
>(
f: F,
) -> JoinHandle<R> {
#[cfg(target_arch = "wasm32")]
{
let result = f();
std::future::ready(Ok(result))
}
#[cfg(not(target_arch = "wasm32"))]
{
deno_unsync::spawn_blocking(f)
}
}

View file

@ -58,6 +58,19 @@ mod inner {
let mut inner = self.0.borrow_mut(); let mut inner = self.0.borrow_mut();
inner.insert(key, value) inner.insert(key, value)
} }
pub fn clear(&self) {
self.0.borrow_mut().clear();
}
pub fn remove(&self, key: &K) -> Option<(K, V)> {
self.0.borrow_mut().remove_entry(key)
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.borrow().len()
}
} }
// Wrapper struct that exposes a subset of `DashMap` API. // Wrapper struct that exposes a subset of `DashMap` API.