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:
David Sherret 2025-01-23 18:52:55 -05:00 committed by GitHub
parent b70aba6bae
commit 273ec9fbf2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 1902 additions and 1166 deletions

View file

@ -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,
})