mirror of
https://github.com/denoland/deno.git
synced 2025-02-08 07:16:56 -05:00
single factory
This commit is contained in:
parent
9d9a88f7c3
commit
766452fca4
9 changed files with 445 additions and 539 deletions
|
@ -8,7 +8,7 @@ mod lockfile;
|
||||||
mod package_json;
|
mod package_json;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
@ -557,15 +557,6 @@ struct CliOptionOverrides {
|
||||||
import_map_specifier: Option<Option<ModuleSpecifier>>,
|
import_map_specifier: Option<Option<ModuleSpecifier>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overrides for the options below that when set will
|
|
||||||
/// use these values over the values derived from the
|
|
||||||
/// CLI flags or config file.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ScopeOptions {
|
|
||||||
pub scope: Option<Arc<ModuleSpecifier>>,
|
|
||||||
pub all_scopes: Arc<BTreeSet<Arc<ModuleSpecifier>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_external_import_map(
|
fn load_external_import_map(
|
||||||
deno_json: &ConfigFile,
|
deno_json: &ConfigFile,
|
||||||
) -> Result<Option<(PathBuf, serde_json::Value)>, AnyError> {
|
) -> Result<Option<(PathBuf, serde_json::Value)>, AnyError> {
|
||||||
|
@ -593,11 +584,10 @@ pub struct CliOptions {
|
||||||
npmrc: Arc<ResolvedNpmRc>,
|
npmrc: Arc<ResolvedNpmRc>,
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
||||||
sys: CliSys,
|
|
||||||
overrides: CliOptionOverrides,
|
overrides: CliOptionOverrides,
|
||||||
pub start_dir: Arc<WorkspaceDirectory>,
|
pub start_dir: Arc<WorkspaceDirectory>,
|
||||||
|
pub all_dirs: BTreeMap<Arc<Url>, Arc<WorkspaceDirectory>>,
|
||||||
pub deno_dir_provider: Arc<DenoDirProvider>,
|
pub deno_dir_provider: Arc<DenoDirProvider>,
|
||||||
pub scope_options: Option<Arc<ScopeOptions>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CliOptions {
|
impl CliOptions {
|
||||||
|
@ -611,7 +601,6 @@ impl CliOptions {
|
||||||
start_dir: Arc<WorkspaceDirectory>,
|
start_dir: Arc<WorkspaceDirectory>,
|
||||||
force_global_cache: bool,
|
force_global_cache: bool,
|
||||||
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
maybe_external_import_map: Option<(PathBuf, serde_json::Value)>,
|
||||||
scope_options: Option<Arc<ScopeOptions>>,
|
|
||||||
) -> Result<Self, AnyError> {
|
) -> Result<Self, AnyError> {
|
||||||
if let Some(insecure_allowlist) =
|
if let Some(insecure_allowlist) =
|
||||||
flags.unsafely_ignore_certificate_errors.as_ref()
|
flags.unsafely_ignore_certificate_errors.as_ref()
|
||||||
|
@ -643,6 +632,9 @@ impl CliOptions {
|
||||||
|
|
||||||
load_env_variables_from_env_file(flags.env_file.as_ref());
|
load_env_variables_from_env_file(flags.env_file.as_ref());
|
||||||
|
|
||||||
|
let all_dirs = [(start_dir.dir_url().clone(), start_dir.clone())]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
flags,
|
flags,
|
||||||
initial_cwd,
|
initial_cwd,
|
||||||
|
@ -653,9 +645,8 @@ impl CliOptions {
|
||||||
main_module_cell: std::sync::OnceLock::new(),
|
main_module_cell: std::sync::OnceLock::new(),
|
||||||
maybe_external_import_map,
|
maybe_external_import_map,
|
||||||
start_dir,
|
start_dir,
|
||||||
|
all_dirs,
|
||||||
deno_dir_provider,
|
deno_dir_provider,
|
||||||
sys: sys.clone(),
|
|
||||||
scope_options,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,39 +743,18 @@ impl CliOptions {
|
||||||
Arc::new(start_dir),
|
Arc::new(start_dir),
|
||||||
false,
|
false,
|
||||||
external_import_map,
|
external_import_map,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_new_start_dir_and_scope_options(
|
pub fn with_all_dirs(
|
||||||
&self,
|
self,
|
||||||
start_dir: Arc<WorkspaceDirectory>,
|
all_dirs: impl IntoIterator<Item = Arc<WorkspaceDirectory>>,
|
||||||
scope_options: Option<ScopeOptions>,
|
) -> Self {
|
||||||
) -> Result<Self, AnyError> {
|
let all_dirs = all_dirs
|
||||||
let (npmrc, _) = discover_npmrc_from_workspace(&start_dir.workspace)?;
|
.into_iter()
|
||||||
let external_import_map =
|
.map(|d| (d.dir_url().clone(), d))
|
||||||
if let Some(deno_json) = start_dir.workspace.root_deno_json() {
|
.collect();
|
||||||
load_external_import_map(deno_json)?
|
Self { all_dirs, ..self }
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let lockfile = CliLockfile::discover(
|
|
||||||
&self.sys,
|
|
||||||
&self.flags,
|
|
||||||
&start_dir.workspace,
|
|
||||||
external_import_map.as_ref().map(|(_, v)| v),
|
|
||||||
)?;
|
|
||||||
Self::new(
|
|
||||||
&self.sys,
|
|
||||||
self.flags.clone(),
|
|
||||||
self.initial_cwd().to_path_buf(),
|
|
||||||
lockfile.map(Arc::new),
|
|
||||||
npmrc,
|
|
||||||
start_dir,
|
|
||||||
false,
|
|
||||||
external_import_map,
|
|
||||||
scope_options.map(Arc::new),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is purposefully verbose to disourage its use. Do not use it
|
/// This method is purposefully verbose to disourage its use. Do not use it
|
||||||
|
|
287
cli/factory.rs
287
cli/factory.rs
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2025 the Deno authors. MIT license.
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -13,7 +12,6 @@ use deno_config::glob::FilePatterns;
|
||||||
use deno_config::workspace::PackageJsonDepResolution;
|
use deno_config::workspace::PackageJsonDepResolution;
|
||||||
use deno_config::workspace::WorkspaceDirectory;
|
use deno_config::workspace::WorkspaceDirectory;
|
||||||
use deno_config::workspace::WorkspaceResolver;
|
use deno_config::workspace::WorkspaceResolver;
|
||||||
use deno_core::anyhow::anyhow;
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::futures::FutureExt;
|
use deno_core::futures::FutureExt;
|
||||||
use deno_core::FeatureChecker;
|
use deno_core::FeatureChecker;
|
||||||
|
@ -42,7 +40,6 @@ use deno_runtime::deno_fs::RealFs;
|
||||||
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
|
||||||
use deno_runtime::deno_permissions::Permissions;
|
use deno_runtime::deno_permissions::Permissions;
|
||||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
|
||||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||||
use deno_runtime::deno_web::BlobStore;
|
use deno_runtime::deno_web::BlobStore;
|
||||||
|
@ -57,7 +54,6 @@ use crate::args::CliOptions;
|
||||||
use crate::args::DenoSubcommand;
|
use crate::args::DenoSubcommand;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::args::NpmInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::args::ScopeOptions;
|
|
||||||
use crate::args::TsConfigType;
|
use crate::args::TsConfigType;
|
||||||
use crate::cache::Caches;
|
use crate::cache::Caches;
|
||||||
use crate::cache::CodeCache;
|
use crate::cache::CodeCache;
|
||||||
|
@ -79,7 +75,6 @@ use crate::graph_util::ModuleGraphCreator;
|
||||||
use crate::http_util::HttpClientProvider;
|
use crate::http_util::HttpClientProvider;
|
||||||
use crate::module_loader::CliModuleLoaderFactory;
|
use crate::module_loader::CliModuleLoaderFactory;
|
||||||
use crate::module_loader::ModuleLoadPreparer;
|
use crate::module_loader::ModuleLoadPreparer;
|
||||||
use crate::module_loader::PrepareModuleLoadError;
|
|
||||||
use crate::node::CliCjsCodeAnalyzer;
|
use crate::node::CliCjsCodeAnalyzer;
|
||||||
use crate::node::CliNodeCodeTranslator;
|
use crate::node::CliNodeCodeTranslator;
|
||||||
use crate::node::CliNodeResolver;
|
use crate::node::CliNodeResolver;
|
||||||
|
@ -105,12 +100,10 @@ use crate::resolver::CliSloppyImportsResolver;
|
||||||
use crate::resolver::FoundPackageJsonDepFlag;
|
use crate::resolver::FoundPackageJsonDepFlag;
|
||||||
use crate::standalone::binary::DenoCompileBinaryWriter;
|
use crate::standalone::binary::DenoCompileBinaryWriter;
|
||||||
use crate::sys::CliSys;
|
use crate::sys::CliSys;
|
||||||
use crate::tools::check::CheckError;
|
|
||||||
use crate::tools::check::TypeChecker;
|
use crate::tools::check::TypeChecker;
|
||||||
use crate::tools::coverage::CoverageCollector;
|
use crate::tools::coverage::CoverageCollector;
|
||||||
use crate::tools::lint::LintRuleProvider;
|
use crate::tools::lint::LintRuleProvider;
|
||||||
use crate::tools::run::hmr::HmrRunner;
|
use crate::tools::run::hmr::HmrRunner;
|
||||||
use crate::tsc::Diagnostics;
|
|
||||||
use crate::tsc::TypeCheckingCjsTracker;
|
use crate::tsc::TypeCheckingCjsTracker;
|
||||||
use crate::util::file_watcher::WatcherCommunicator;
|
use crate::util::file_watcher::WatcherCommunicator;
|
||||||
use crate::util::fs::canonicalize_path;
|
use crate::util::fs::canonicalize_path;
|
||||||
|
@ -1247,15 +1240,96 @@ pub struct SpecifierInfo {
|
||||||
pub check_doc: bool,
|
pub check_doc: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WorkspaceDirFilesFactory {
|
pub struct CliFactoryWithWorkspaceFiles {
|
||||||
|
pub inner: CliFactory,
|
||||||
|
pub cli_options: Arc<CliOptions>,
|
||||||
specifiers: Vec<(ModuleSpecifier, SpecifierInfo)>,
|
specifiers: Vec<(ModuleSpecifier, SpecifierInfo)>,
|
||||||
doc_snippet_specifiers: Vec<ModuleSpecifier>,
|
doc_snippet_specifiers: Vec<ModuleSpecifier>,
|
||||||
cli_options: Arc<CliOptions>,
|
initial_cwd: PathBuf,
|
||||||
cli_factory: CliFactory,
|
|
||||||
permissions_options: Deferred<PermissionsOptions>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkspaceDirFilesFactory {
|
impl CliFactoryWithWorkspaceFiles {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub async fn from_workspace_dirs_with_files<T: Clone>(
|
||||||
|
mut workspace_dirs_with_files: Vec<(Arc<WorkspaceDirectory>, FilePatterns)>,
|
||||||
|
collect_specifiers: fn(
|
||||||
|
FilePatterns,
|
||||||
|
Arc<CliOptions>,
|
||||||
|
Arc<CliFileFetcher>,
|
||||||
|
T,
|
||||||
|
) -> std::pin::Pin<
|
||||||
|
Box<
|
||||||
|
dyn Future<
|
||||||
|
Output = Result<Vec<(ModuleSpecifier, SpecifierInfo)>, AnyError>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
args: T,
|
||||||
|
extract_doc_files: Option<fn(File) -> Result<Vec<File>, AnyError>>,
|
||||||
|
cli_options: CliOptions,
|
||||||
|
watcher_communicator: Option<&Arc<WatcherCommunicator>>,
|
||||||
|
) -> Result<Self, AnyError> {
|
||||||
|
let cli_options =
|
||||||
|
Arc::new(cli_options.with_all_dirs(
|
||||||
|
workspace_dirs_with_files.iter().map(|(d, _)| d.clone()),
|
||||||
|
));
|
||||||
|
let mut factory = CliFactory::from_cli_options(cli_options.clone());
|
||||||
|
factory.watcher_communicator = watcher_communicator.cloned();
|
||||||
|
let initial_cwd = cli_options.initial_cwd().to_path_buf();
|
||||||
|
if let Some(watcher_communicator) = watcher_communicator {
|
||||||
|
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||||
|
}
|
||||||
|
workspace_dirs_with_files.sort_by_cached_key(|(d, _)| d.dir_url().clone());
|
||||||
|
let mut specifiers = Vec::new();
|
||||||
|
let mut doc_snippet_specifiers = Vec::new();
|
||||||
|
for (_, files) in workspace_dirs_with_files {
|
||||||
|
if let Some(watcher_communicator) = watcher_communicator {
|
||||||
|
let _ = watcher_communicator.watch_paths(
|
||||||
|
files
|
||||||
|
.include
|
||||||
|
.iter()
|
||||||
|
.flat_map(|set| set.base_paths())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let file_fetcher = factory.file_fetcher()?;
|
||||||
|
let dir_specifiers = collect_specifiers(
|
||||||
|
files,
|
||||||
|
cli_options.clone(),
|
||||||
|
file_fetcher.clone(),
|
||||||
|
args.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
if let Some(extract_doc_files) = extract_doc_files {
|
||||||
|
let root_permissions = factory.root_permissions_container()?;
|
||||||
|
for (s, _) in dir_specifiers.iter().filter(|(_, i)| i.check_doc) {
|
||||||
|
let file = file_fetcher.fetch(s, root_permissions).await?;
|
||||||
|
let snippet_files = extract_doc_files(file)?;
|
||||||
|
for snippet_file in snippet_files {
|
||||||
|
doc_snippet_specifiers.push(snippet_file.url.clone());
|
||||||
|
file_fetcher.insert_memory_files(snippet_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
specifiers.extend(dir_specifiers);
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
inner: factory,
|
||||||
|
cli_options,
|
||||||
|
specifiers,
|
||||||
|
doc_snippet_specifiers,
|
||||||
|
initial_cwd,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initial_cwd(&self) -> &PathBuf {
|
||||||
|
&self.initial_cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn found_specifiers(&self) -> bool {
|
||||||
|
!self.specifiers.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn checked_specifiers(&self) -> impl Iterator<Item = &ModuleSpecifier> {
|
pub fn checked_specifiers(&self) -> impl Iterator<Item = &ModuleSpecifier> {
|
||||||
self
|
self
|
||||||
.specifiers
|
.specifiers
|
||||||
|
@ -1268,23 +1342,20 @@ impl WorkspaceDirFilesFactory {
|
||||||
&self,
|
&self,
|
||||||
canonicalized_dep_paths: &HashSet<PathBuf>,
|
canonicalized_dep_paths: &HashSet<PathBuf>,
|
||||||
) -> Result<Vec<&ModuleSpecifier>, AnyError> {
|
) -> Result<Vec<&ModuleSpecifier>, AnyError> {
|
||||||
let graph_kind = self
|
let graph_kind =
|
||||||
.cli_factory
|
self.inner.cli_options()?.type_check_mode().as_graph_kind();
|
||||||
.cli_options()?
|
let module_graph_creator = self.inner.module_graph_creator().await?;
|
||||||
.type_check_mode()
|
let specifiers = self.checked_specifiers().collect::<Vec<_>>();
|
||||||
.as_graph_kind();
|
|
||||||
let module_graph_creator = self.cli_factory.module_graph_creator().await?;
|
|
||||||
let specifiers = self.checked_specifiers().cloned().collect::<Vec<_>>();
|
|
||||||
let graph = module_graph_creator
|
let graph = module_graph_creator
|
||||||
.create_graph(
|
.create_graph(
|
||||||
graph_kind,
|
graph_kind,
|
||||||
specifiers.clone(),
|
specifiers.iter().map(|&s| s.clone()).collect(),
|
||||||
crate::graph_util::NpmCachingStrategy::Eager,
|
crate::graph_util::NpmCachingStrategy::Eager,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
module_graph_creator.graph_valid(&graph)?;
|
module_graph_creator.graph_valid(&graph)?;
|
||||||
let dependent_specifiers = self
|
let dependent_specifiers = specifiers
|
||||||
.checked_specifiers()
|
.into_iter()
|
||||||
.filter(|s| {
|
.filter(|s| {
|
||||||
let mut dependency_specifiers = graph.walk(
|
let mut dependency_specifiers = graph.walk(
|
||||||
std::iter::once(*s),
|
std::iter::once(*s),
|
||||||
|
@ -1313,172 +1384,16 @@ impl WorkspaceDirFilesFactory {
|
||||||
Ok(dependent_specifiers)
|
Ok(dependent_specifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn permissions_options(&self) -> &PermissionsOptions {
|
|
||||||
self
|
|
||||||
.permissions_options
|
|
||||||
.get_or_init(|| self.cli_options.permissions_options())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn permission_desc_parser(
|
|
||||||
&self,
|
|
||||||
) -> Result<&Arc<RuntimePermissionDescriptorParser<CliSys>>, AnyError> {
|
|
||||||
self.cli_factory.permission_desc_parser()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_cli_main_worker_factory(
|
|
||||||
&self,
|
|
||||||
) -> Result<CliMainWorkerFactory, AnyError> {
|
|
||||||
self.cli_factory.create_cli_main_worker_factory().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WorkspaceFilesFactory {
|
|
||||||
dirs: Vec<WorkspaceDirFilesFactory>,
|
|
||||||
initial_cwd: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WorkspaceFilesFactory {
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
pub async fn from_workspace_dirs_with_files<T: Clone>(
|
|
||||||
mut workspace_dirs_with_files: Vec<(Arc<WorkspaceDirectory>, FilePatterns)>,
|
|
||||||
collect_specifiers: fn(
|
|
||||||
FilePatterns,
|
|
||||||
Arc<CliOptions>,
|
|
||||||
Arc<CliFileFetcher>,
|
|
||||||
T,
|
|
||||||
) -> std::pin::Pin<
|
|
||||||
Box<
|
|
||||||
dyn Future<
|
|
||||||
Output = Result<Vec<(ModuleSpecifier, SpecifierInfo)>, AnyError>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
args: T,
|
|
||||||
extract_doc_files: Option<fn(File) -> Result<Vec<File>, AnyError>>,
|
|
||||||
cli_options: &CliOptions,
|
|
||||||
watcher_communicator: Option<&Arc<WatcherCommunicator>>,
|
|
||||||
) -> Result<Self, AnyError> {
|
|
||||||
let initial_cwd = cli_options.initial_cwd().to_path_buf();
|
|
||||||
if let Some(watcher_communicator) = watcher_communicator {
|
|
||||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
|
||||||
}
|
|
||||||
workspace_dirs_with_files.sort_by_cached_key(|(d, _)| d.dir_url().clone());
|
|
||||||
let all_scopes = Arc::new(
|
|
||||||
workspace_dirs_with_files
|
|
||||||
.iter()
|
|
||||||
.filter(|(d, _)| d.has_deno_or_pkg_json())
|
|
||||||
.map(|(d, _)| d.dir_url().clone())
|
|
||||||
.collect::<BTreeSet<_>>(),
|
|
||||||
);
|
|
||||||
let dir_count = workspace_dirs_with_files.len();
|
|
||||||
let mut dirs = Vec::with_capacity(dir_count);
|
|
||||||
for (workspace_dir, files) in workspace_dirs_with_files {
|
|
||||||
if let Some(watcher_communicator) = watcher_communicator {
|
|
||||||
let _ = watcher_communicator.watch_paths(
|
|
||||||
files
|
|
||||||
.include
|
|
||||||
.iter()
|
|
||||||
.flat_map(|set| set.base_paths())
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let scope_options = (dir_count > 1).then(|| ScopeOptions {
|
|
||||||
scope: workspace_dir
|
|
||||||
.has_deno_or_pkg_json()
|
|
||||||
.then(|| workspace_dir.dir_url().clone()),
|
|
||||||
all_scopes: all_scopes.clone(),
|
|
||||||
});
|
|
||||||
let cli_options = Arc::new(
|
|
||||||
cli_options
|
|
||||||
.with_new_start_dir_and_scope_options(workspace_dir, scope_options)?,
|
|
||||||
);
|
|
||||||
let mut factory = CliFactory::from_cli_options(cli_options.clone());
|
|
||||||
factory.watcher_communicator = watcher_communicator.cloned();
|
|
||||||
let file_fetcher = factory.file_fetcher()?;
|
|
||||||
let specifiers = collect_specifiers(
|
|
||||||
files,
|
|
||||||
cli_options.clone(),
|
|
||||||
file_fetcher.clone(),
|
|
||||||
args.clone(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let mut doc_snippet_specifiers = vec![];
|
|
||||||
if let Some(extract_doc_files) = extract_doc_files {
|
|
||||||
let root_permissions = factory.root_permissions_container()?;
|
|
||||||
for (s, _) in specifiers.iter().filter(|(_, i)| i.check_doc) {
|
|
||||||
let file = file_fetcher.fetch(s, root_permissions).await?;
|
|
||||||
let snippet_files = extract_doc_files(file)?;
|
|
||||||
for snippet_file in snippet_files {
|
|
||||||
doc_snippet_specifiers.push(snippet_file.url.clone());
|
|
||||||
file_fetcher.insert_memory_files(snippet_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dirs.push(WorkspaceDirFilesFactory {
|
|
||||||
specifiers,
|
|
||||||
doc_snippet_specifiers,
|
|
||||||
cli_options,
|
|
||||||
cli_factory: factory,
|
|
||||||
permissions_options: Default::default(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(Self { dirs, initial_cwd })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dirs(&self) -> &Vec<WorkspaceDirFilesFactory> {
|
|
||||||
&self.dirs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initial_cwd(&self) -> &PathBuf {
|
|
||||||
&self.initial_cwd
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn found_specifiers(&self) -> bool {
|
|
||||||
self.dirs.iter().any(|e| !e.specifiers.is_empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn check(&self) -> Result<(), AnyError> {
|
pub async fn check(&self) -> Result<(), AnyError> {
|
||||||
let mut diagnostics = vec![];
|
let main_graph_container =
|
||||||
let mut all_errors = vec![];
|
self.inner.main_module_graph_container().await?.clone();
|
||||||
for entry in &self.dirs {
|
let specifiers = self.checked_specifiers().cloned().collect::<Vec<_>>();
|
||||||
let main_graph_container = entry
|
if specifiers.is_empty() {
|
||||||
.cli_factory
|
return Ok(());
|
||||||
.main_module_graph_container()
|
|
||||||
.await?
|
|
||||||
.clone();
|
|
||||||
let specifiers_for_typecheck =
|
|
||||||
entry.checked_specifiers().cloned().collect::<Vec<_>>();
|
|
||||||
if specifiers_for_typecheck.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
let ext_flag = entry.cli_factory.cli_options()?.ext_flag().as_ref();
|
let ext_flag = self.cli_options.ext_flag().as_ref();
|
||||||
if let Err(err) = main_graph_container
|
main_graph_container
|
||||||
.check_specifiers(&specifiers_for_typecheck, ext_flag)
|
.check_specifiers(&specifiers, ext_flag)
|
||||||
.await
|
.await
|
||||||
{
|
|
||||||
match err {
|
|
||||||
PrepareModuleLoadError::Check(CheckError::Diagnostics(
|
|
||||||
Diagnostics(d),
|
|
||||||
)) => diagnostics.extend(d),
|
|
||||||
err => all_errors.push(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !diagnostics.is_empty() {
|
|
||||||
all_errors.push(PrepareModuleLoadError::Check(CheckError::Diagnostics(
|
|
||||||
Diagnostics(diagnostics),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
if !all_errors.is_empty() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"{}",
|
|
||||||
all_errors
|
|
||||||
.into_iter()
|
|
||||||
.map(|e| e.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n\n"),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ use deno_runtime::deno_permissions::PermissionsContainer;
|
||||||
|
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::module_loader::ModuleLoadPreparer;
|
use crate::module_loader::ModuleLoadPreparer;
|
||||||
use crate::module_loader::PrepareModuleLoadError;
|
|
||||||
use crate::util::fs::collect_specifiers;
|
use crate::util::fs::collect_specifiers;
|
||||||
use crate::util::path::is_script_ext;
|
use crate::util::path::is_script_ext;
|
||||||
|
|
||||||
|
@ -70,7 +69,7 @@ impl MainModuleGraphContainer {
|
||||||
&self,
|
&self,
|
||||||
specifiers: &[ModuleSpecifier],
|
specifiers: &[ModuleSpecifier],
|
||||||
ext_overwrite: Option<&String>,
|
ext_overwrite: Option<&String>,
|
||||||
) -> Result<(), PrepareModuleLoadError> {
|
) -> Result<(), AnyError> {
|
||||||
let mut graph_permit = self.acquire_update_permit().await;
|
let mut graph_permit = self.acquire_update_permit().await;
|
||||||
let graph = graph_permit.graph_mut();
|
let graph = graph_permit.graph_mut();
|
||||||
self
|
self
|
||||||
|
@ -100,7 +99,7 @@ impl MainModuleGraphContainer {
|
||||||
log::warn!("{} No matching files found.", colors::yellow("Warning"));
|
log::warn!("{} No matching files found.", colors::yellow("Warning"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.check_specifiers(&specifiers, None).await?)
|
self.check_specifiers(&specifiers, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_specifiers(
|
pub fn collect_specifiers(
|
||||||
|
|
|
@ -3666,7 +3666,6 @@ impl Inner {
|
||||||
workspace,
|
workspace,
|
||||||
force_global_cache,
|
force_global_cache,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let open_docs = self.documents.documents(DocumentsFilter::OpenDiagnosable);
|
let open_docs = self.documents.documents(DocumentsFilter::OpenDiagnosable);
|
||||||
|
|
|
@ -39,8 +39,8 @@ use crate::args::CliOptions;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::display::write_json_to_stdout;
|
use crate::display::write_json_to_stdout;
|
||||||
|
use crate::factory::CliFactoryWithWorkspaceFiles;
|
||||||
use crate::factory::SpecifierInfo;
|
use crate::factory::SpecifierInfo;
|
||||||
use crate::factory::WorkspaceFilesFactory;
|
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::sys::CliSys;
|
use crate::sys::CliSys;
|
||||||
use crate::tools::test::format_test_error;
|
use crate::tools::test::format_test_error;
|
||||||
|
@ -284,42 +284,32 @@ async fn bench_specifier_inner(
|
||||||
|
|
||||||
/// Test a collection of specifiers with test modes concurrently.
|
/// Test a collection of specifiers with test modes concurrently.
|
||||||
async fn bench_specifiers(
|
async fn bench_specifiers(
|
||||||
workspace_files_factory: &WorkspaceFilesFactory,
|
factory: &CliFactoryWithWorkspaceFiles,
|
||||||
changed_paths: Option<&HashSet<PathBuf>>,
|
changed_paths: Option<&HashSet<PathBuf>>,
|
||||||
options: BenchSpecifierOptions,
|
options: BenchSpecifierOptions,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let mut specifiers_with_services = vec![];
|
|
||||||
for factory in workspace_files_factory.dirs() {
|
|
||||||
let worker_factory =
|
|
||||||
Arc::new(factory.create_cli_main_worker_factory().await?);
|
|
||||||
let permission_desc_parser = factory.permission_desc_parser()?;
|
|
||||||
let permissions = Arc::new(Permissions::from_options(
|
|
||||||
permission_desc_parser.as_ref(),
|
|
||||||
factory.permissions_options(),
|
|
||||||
)?);
|
|
||||||
let specifiers = if let Some(changed_paths) = changed_paths {
|
let specifiers = if let Some(changed_paths) = changed_paths {
|
||||||
factory.dependent_checked_specifiers(changed_paths).await?
|
factory.dependent_checked_specifiers(changed_paths).await?
|
||||||
} else {
|
} else {
|
||||||
factory.checked_specifiers().collect()
|
factory.checked_specifiers().collect()
|
||||||
};
|
};
|
||||||
specifiers_with_services.extend(specifiers.into_iter().map(|s| {
|
let worker_factory =
|
||||||
(
|
Arc::new(factory.inner.create_cli_main_worker_factory().await?);
|
||||||
s.clone(),
|
let permission_desc_parser = factory.inner.permission_desc_parser()?;
|
||||||
worker_factory.clone(),
|
let permissions = Permissions::from_options(
|
||||||
permission_desc_parser.clone(),
|
permission_desc_parser.as_ref(),
|
||||||
permissions.clone(),
|
&factory.cli_options.permissions_options(),
|
||||||
)
|
)?;
|
||||||
}));
|
|
||||||
}
|
|
||||||
let (sender, mut receiver) = unbounded_channel::<BenchEvent>();
|
let (sender, mut receiver) = unbounded_channel::<BenchEvent>();
|
||||||
let log_level = options.log_level;
|
let log_level = options.log_level;
|
||||||
let option_for_handles = options.clone();
|
let option_for_handles = options.clone();
|
||||||
|
|
||||||
let join_handles = specifiers_with_services.into_iter().map(
|
let join_handles = specifiers.into_iter().cloned().map(move |specifier| {
|
||||||
move |(specifier, worker_factory, permissions_desc_parser, permissions)| {
|
let worker_factory = worker_factory.clone();
|
||||||
let permissions_container = PermissionsContainer::new(
|
let permissions_container = PermissionsContainer::new(
|
||||||
permissions_desc_parser.clone(),
|
permission_desc_parser.clone(),
|
||||||
permissions.as_ref().clone(),
|
permissions.clone(),
|
||||||
);
|
);
|
||||||
let sender = sender.clone();
|
let sender = sender.clone();
|
||||||
let options = option_for_handles.clone();
|
let options = option_for_handles.clone();
|
||||||
|
@ -333,8 +323,7 @@ async fn bench_specifiers(
|
||||||
);
|
);
|
||||||
create_and_run_current_thread(future)
|
create_and_run_current_thread(future)
|
||||||
})
|
})
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
let join_stream = stream::iter(join_handles)
|
let join_stream = stream::iter(join_handles)
|
||||||
.buffer_unordered(1)
|
.buffer_unordered(1)
|
||||||
|
@ -457,9 +446,8 @@ pub async fn run_benchmarks(
|
||||||
.resolve_bench_options_for_members(&bench_flags)?
|
.resolve_bench_options_for_members(&bench_flags)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(d, o)| (d, o.files))
|
.map(|(d, o)| (d, o.files))
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
let workspace_files_factory =
|
let factory = CliFactoryWithWorkspaceFiles::from_workspace_dirs_with_files(
|
||||||
WorkspaceFilesFactory::from_workspace_dirs_with_files(
|
|
||||||
workspace_dirs_with_files,
|
workspace_dirs_with_files,
|
||||||
|patterns, cli_options, _, _| {
|
|patterns, cli_options, _, _| {
|
||||||
async move {
|
async move {
|
||||||
|
@ -478,22 +466,22 @@ pub async fn run_benchmarks(
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
None,
|
None,
|
||||||
&cli_options,
|
cli_options,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if !workspace_files_factory.found_specifiers() {
|
if !factory.found_specifiers() {
|
||||||
return Err(anyhow!("No test modules found"));
|
return Err(anyhow!("No test modules found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace_files_factory.check().await?;
|
factory.check().await?;
|
||||||
|
|
||||||
if bench_flags.no_run {
|
if bench_flags.no_run {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_specifiers(
|
bench_specifiers(
|
||||||
&workspace_files_factory,
|
&factory,
|
||||||
None,
|
None,
|
||||||
BenchSpecifierOptions {
|
BenchSpecifierOptions {
|
||||||
filter: TestFilter::from_flag(&bench_flags.filter),
|
filter: TestFilter::from_flag(&bench_flags.filter),
|
||||||
|
@ -531,8 +519,8 @@ pub async fn run_benchmarks_with_watch(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(d, o)| (d, o.files))
|
.map(|(d, o)| (d, o.files))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let workspace_files_factory =
|
let factory =
|
||||||
WorkspaceFilesFactory::from_workspace_dirs_with_files(
|
CliFactoryWithWorkspaceFiles::from_workspace_dirs_with_files(
|
||||||
workspace_dirs_with_files,
|
workspace_dirs_with_files,
|
||||||
|patterns, cli_options, _, _| {
|
|patterns, cli_options, _, _| {
|
||||||
async move {
|
async move {
|
||||||
|
@ -551,19 +539,19 @@ pub async fn run_benchmarks_with_watch(
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
None,
|
None,
|
||||||
&cli_options,
|
cli_options,
|
||||||
Some(&watcher_communicator),
|
Some(&watcher_communicator),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
workspace_files_factory.check().await?;
|
factory.check().await?;
|
||||||
|
|
||||||
if bench_flags.no_run {
|
if bench_flags.no_run {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_specifiers(
|
bench_specifiers(
|
||||||
&workspace_files_factory,
|
&factory,
|
||||||
changed_paths.map(|p| p.into_iter().collect()).as_ref(),
|
changed_paths.map(|p| p.into_iter().collect()).as_ref(),
|
||||||
BenchSpecifierOptions {
|
BenchSpecifierOptions {
|
||||||
filter: TestFilter::from_flag(&bench_flags.filter),
|
filter: TestFilter::from_flag(&bench_flags.filter),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2025 the Deno authors. MIT license.
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -7,6 +8,7 @@ use std::sync::Arc;
|
||||||
use deno_ast::MediaType;
|
use deno_ast::MediaType;
|
||||||
use deno_ast::ModuleSpecifier;
|
use deno_ast::ModuleSpecifier;
|
||||||
use deno_config::deno_json;
|
use deno_config::deno_json;
|
||||||
|
use deno_config::workspace::WorkspaceDirectory;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::futures::FutureExt;
|
use deno_core::futures::FutureExt;
|
||||||
use deno_error::JsErrorBox;
|
use deno_error::JsErrorBox;
|
||||||
|
@ -15,6 +17,7 @@ use deno_graph::ModuleError;
|
||||||
use deno_graph::ModuleGraph;
|
use deno_graph::ModuleGraph;
|
||||||
use deno_graph::ModuleLoadError;
|
use deno_graph::ModuleLoadError;
|
||||||
use deno_lib::util::hash::FastInsecureHasher;
|
use deno_lib::util::hash::FastInsecureHasher;
|
||||||
|
use deno_path_util::url_from_directory_path;
|
||||||
use deno_semver::npm::NpmPackageNvReference;
|
use deno_semver::npm::NpmPackageNvReference;
|
||||||
use deno_terminal::colors;
|
use deno_terminal::colors;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
@ -32,8 +35,8 @@ use crate::args::TypeCheckMode;
|
||||||
use crate::cache::CacheDBHash;
|
use crate::cache::CacheDBHash;
|
||||||
use crate::cache::Caches;
|
use crate::cache::Caches;
|
||||||
use crate::cache::TypeCheckCache;
|
use crate::cache::TypeCheckCache;
|
||||||
|
use crate::factory::CliFactoryWithWorkspaceFiles;
|
||||||
use crate::factory::SpecifierInfo;
|
use crate::factory::SpecifierInfo;
|
||||||
use crate::factory::WorkspaceFilesFactory;
|
|
||||||
use crate::graph_util::maybe_additional_sloppy_imports_message;
|
use crate::graph_util::maybe_additional_sloppy_imports_message;
|
||||||
use crate::graph_util::BuildFastCheckGraphOptions;
|
use crate::graph_util::BuildFastCheckGraphOptions;
|
||||||
use crate::graph_util::ModuleGraphBuilder;
|
use crate::graph_util::ModuleGraphBuilder;
|
||||||
|
@ -59,8 +62,7 @@ pub async fn check(
|
||||||
ignore: Default::default(),
|
ignore: Default::default(),
|
||||||
include: check_flags.files,
|
include: check_flags.files,
|
||||||
})?;
|
})?;
|
||||||
let workspace_files_factory =
|
let factory = CliFactoryWithWorkspaceFiles::from_workspace_dirs_with_files(
|
||||||
WorkspaceFilesFactory::from_workspace_dirs_with_files(
|
|
||||||
workspace_dirs_with_files,
|
workspace_dirs_with_files,
|
||||||
|patterns, cli_options, _, (doc, doc_only)| {
|
|patterns, cli_options, _, (doc, doc_only)| {
|
||||||
async move {
|
async move {
|
||||||
|
@ -79,14 +81,14 @@ pub async fn check(
|
||||||
},
|
},
|
||||||
(check_flags.doc, check_flags.doc_only),
|
(check_flags.doc, check_flags.doc_only),
|
||||||
Some(extract_snippet_files),
|
Some(extract_snippet_files),
|
||||||
&cli_options,
|
cli_options,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if !workspace_files_factory.found_specifiers() {
|
if !factory.found_specifiers() {
|
||||||
log::warn!("{} No matching files found.", colors::yellow("Warning"));
|
log::warn!("{} No matching files found.", colors::yellow("Warning"));
|
||||||
}
|
}
|
||||||
workspace_files_factory.check().await
|
factory.check().await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options for performing a check of a module graph. Note that the decision to
|
/// Options for performing a check of a module graph. Note that the decision to
|
||||||
|
@ -229,17 +231,6 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("Type checking.");
|
log::debug!("Type checking.");
|
||||||
let ts_config_result = self
|
|
||||||
.cli_options
|
|
||||||
.resolve_ts_config_for_emit(TsConfigType::Check { lib: options.lib })?;
|
|
||||||
if options.log_ignored_options {
|
|
||||||
check_warn_tsconfig(&ts_config_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
let type_check_mode = options.type_check_mode;
|
|
||||||
let ts_config = ts_config_result.ts_config;
|
|
||||||
let cache = TypeCheckCache::new(self.caches.type_checking_cache_db());
|
|
||||||
let check_js = ts_config.get_check_js();
|
|
||||||
|
|
||||||
// add fast check to the graph before getting the roots
|
// add fast check to the graph before getting the roots
|
||||||
if options.build_fast_check_graph {
|
if options.build_fast_check_graph {
|
||||||
|
@ -251,20 +242,45 @@ impl TypeChecker {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let graph = Arc::new(graph);
|
||||||
|
|
||||||
|
let mut all_dirs = self.cli_options.all_dirs.clone();
|
||||||
|
let initial_cwd_url =
|
||||||
|
url_from_directory_path(self.cli_options.initial_cwd())
|
||||||
|
.map_err(JsErrorBox::from_err)?;
|
||||||
|
let initial_workspace_dir_url = all_dirs
|
||||||
|
.keys()
|
||||||
|
.rfind(|s| initial_cwd_url.as_str().starts_with(s.as_str()))
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
all_dirs.insert(
|
||||||
|
self.cli_options.start_dir.dir_url().clone(),
|
||||||
|
self.cli_options.start_dir.clone(),
|
||||||
|
);
|
||||||
|
self.cli_options.start_dir.dir_url().clone()
|
||||||
|
});
|
||||||
|
let is_scoped = all_dirs.len() > 1;
|
||||||
|
|
||||||
|
let mut diagnostics = Diagnostics::default();
|
||||||
|
|
||||||
|
for (dir_url, workspace_dir) in &all_dirs {
|
||||||
|
let is_initial_workspace_dir = *dir_url == initial_workspace_dir_url;
|
||||||
|
let ts_config_result = workspace_dir
|
||||||
|
.to_ts_config_for_emit(TsConfigType::Check { lib: options.lib })?;
|
||||||
|
if options.log_ignored_options {
|
||||||
|
check_warn_tsconfig(&ts_config_result);
|
||||||
|
}
|
||||||
|
let type_check_mode = options.type_check_mode;
|
||||||
|
let ts_config = ts_config_result.ts_config;
|
||||||
|
let cache = TypeCheckCache::new(self.caches.type_checking_cache_db());
|
||||||
|
let check_js = ts_config.get_check_js();
|
||||||
|
|
||||||
let is_visible_diagnostic = |d: &tsc::Diagnostic| {
|
let is_visible_diagnostic = |d: &tsc::Diagnostic| {
|
||||||
if self.is_remote_diagnostic(d) {
|
if self.is_remote_diagnostic(d) {
|
||||||
return type_check_mode == TypeCheckMode::All
|
return type_check_mode == TypeCheckMode::All
|
||||||
&& d.include_when_remote()
|
&& d.include_when_remote()
|
||||||
&& self
|
&& !is_scoped;
|
||||||
.cli_options
|
|
||||||
.scope_options
|
|
||||||
.as_ref()
|
|
||||||
.map(|o| o.scope.is_none())
|
|
||||||
.unwrap_or(true);
|
|
||||||
}
|
}
|
||||||
let Some(scope_options) = &self.cli_options.scope_options else {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
let Some(specifier) = d
|
let Some(specifier) = d
|
||||||
.file_name
|
.file_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -275,14 +291,16 @@ impl TypeChecker {
|
||||||
if specifier.scheme() != "file" {
|
if specifier.scheme() != "file" {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let scope = scope_options
|
let scope = all_dirs
|
||||||
.all_scopes
|
.keys()
|
||||||
.iter()
|
|
||||||
.rfind(|s| specifier.as_str().starts_with(s.as_str()));
|
.rfind(|s| specifier.as_str().starts_with(s.as_str()));
|
||||||
scope == scope_options.scope.as_ref()
|
scope
|
||||||
|
.map(|s| s == dir_url)
|
||||||
|
.unwrap_or(is_initial_workspace_dir)
|
||||||
};
|
};
|
||||||
let TscRoots {
|
let TscRoots {
|
||||||
roots: root_names,
|
roots: root_names,
|
||||||
|
display_roots,
|
||||||
missing_diagnostics,
|
missing_diagnostics,
|
||||||
maybe_check_hash,
|
maybe_check_hash,
|
||||||
} = get_tsc_roots(
|
} = get_tsc_roots(
|
||||||
|
@ -294,24 +312,31 @@ impl TypeChecker {
|
||||||
check_state_hash(&self.npm_resolver),
|
check_state_hash(&self.npm_resolver),
|
||||||
type_check_mode,
|
type_check_mode,
|
||||||
&ts_config,
|
&ts_config,
|
||||||
|
&all_dirs,
|
||||||
|
&initial_workspace_dir_url,
|
||||||
|
is_scoped.then_some(dir_url.as_ref()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let missing_diagnostics = missing_diagnostics.filter(is_visible_diagnostic);
|
let missing_diagnostics =
|
||||||
|
missing_diagnostics.filter(is_visible_diagnostic);
|
||||||
|
let has_missing_diagnostics = !missing_diagnostics.is_empty();
|
||||||
|
diagnostics.extend(missing_diagnostics);
|
||||||
|
|
||||||
if root_names.is_empty() && missing_diagnostics.is_empty() {
|
if root_names.is_empty() {
|
||||||
return Ok((graph.into(), Default::default()));
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !options.reload {
|
if !options.reload {
|
||||||
// do not type check if we know this is type checked
|
// do not type check if we know this is type checked
|
||||||
if let Some(check_hash) = maybe_check_hash {
|
if let Some(check_hash) = maybe_check_hash {
|
||||||
if cache.has_check_hash(check_hash) {
|
if cache.has_check_hash(check_hash) {
|
||||||
log::debug!("Already type checked.");
|
log::debug!("Already type checked.");
|
||||||
return Ok((graph.into(), Default::default()));
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for root in &graph.roots {
|
for root in &display_roots {
|
||||||
let root_str = root.as_str();
|
let root_str = root.as_str();
|
||||||
log::info!(
|
log::info!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
|
@ -323,10 +348,11 @@ impl TypeChecker {
|
||||||
// while there might be multiple roots, we can't "merge" the build info, so we
|
// while there might be multiple roots, we can't "merge" the build info, so we
|
||||||
// try to retrieve the build info for first root, which is the most common use
|
// try to retrieve the build info for first root, which is the most common use
|
||||||
// case.
|
// case.
|
||||||
|
let first_root = root_names[0].0.clone();
|
||||||
let maybe_tsbuildinfo = if options.reload {
|
let maybe_tsbuildinfo = if options.reload {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
cache.get_tsbuildinfo(&graph.roots[0])
|
cache.get_tsbuildinfo(&first_root)
|
||||||
};
|
};
|
||||||
// to make tsc build info work, we need to consistently hash modules, so that
|
// to make tsc build info work, we need to consistently hash modules, so that
|
||||||
// tsc can better determine if an emit is still valid or not, so we provide
|
// tsc can better determine if an emit is still valid or not, so we provide
|
||||||
|
@ -334,7 +360,6 @@ impl TypeChecker {
|
||||||
let tsconfig_hash_data = FastInsecureHasher::new_deno_versioned()
|
let tsconfig_hash_data = FastInsecureHasher::new_deno_versioned()
|
||||||
.write(&ts_config.as_bytes())
|
.write(&ts_config.as_bytes())
|
||||||
.finish();
|
.finish();
|
||||||
let graph = Arc::new(graph);
|
|
||||||
let response = tsc::exec(tsc::Request {
|
let response = tsc::exec(tsc::Request {
|
||||||
config: ts_config,
|
config: ts_config,
|
||||||
debug: self.cli_options.log_level() == Some(log::Level::Debug),
|
debug: self.cli_options.log_level() == Some(log::Level::Debug),
|
||||||
|
@ -353,22 +378,22 @@ impl TypeChecker {
|
||||||
let response_diagnostics =
|
let response_diagnostics =
|
||||||
response.diagnostics.filter(is_visible_diagnostic);
|
response.diagnostics.filter(is_visible_diagnostic);
|
||||||
|
|
||||||
let mut diagnostics = missing_diagnostics;
|
|
||||||
diagnostics.extend(response_diagnostics);
|
|
||||||
|
|
||||||
diagnostics.apply_fast_check_source_maps(&graph);
|
|
||||||
|
|
||||||
if let Some(tsbuildinfo) = response.maybe_tsbuildinfo {
|
if let Some(tsbuildinfo) = response.maybe_tsbuildinfo {
|
||||||
cache.set_tsbuildinfo(&graph.roots[0], &tsbuildinfo);
|
cache.set_tsbuildinfo(&first_root, &tsbuildinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
if !has_missing_diagnostics && response_diagnostics.is_empty() {
|
||||||
if let Some(check_hash) = maybe_check_hash {
|
if let Some(check_hash) = maybe_check_hash {
|
||||||
cache.add_check_hash(check_hash);
|
cache.add_check_hash(check_hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diagnostics.extend(response_diagnostics);
|
||||||
|
|
||||||
log::debug!("{}", response.stats);
|
log::debug!("{}", response.stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics.apply_fast_check_source_maps(&graph);
|
||||||
|
|
||||||
Ok((graph, diagnostics))
|
Ok((graph, diagnostics))
|
||||||
}
|
}
|
||||||
|
@ -390,6 +415,7 @@ impl TypeChecker {
|
||||||
|
|
||||||
struct TscRoots {
|
struct TscRoots {
|
||||||
roots: Vec<(ModuleSpecifier, MediaType)>,
|
roots: Vec<(ModuleSpecifier, MediaType)>,
|
||||||
|
display_roots: Vec<ModuleSpecifier>,
|
||||||
missing_diagnostics: tsc::Diagnostics,
|
missing_diagnostics: tsc::Diagnostics,
|
||||||
maybe_check_hash: Option<CacheDBHash>,
|
maybe_check_hash: Option<CacheDBHash>,
|
||||||
}
|
}
|
||||||
|
@ -410,6 +436,9 @@ fn get_tsc_roots(
|
||||||
npm_cache_state_hash: Option<u64>,
|
npm_cache_state_hash: Option<u64>,
|
||||||
type_check_mode: TypeCheckMode,
|
type_check_mode: TypeCheckMode,
|
||||||
ts_config: &TsConfig,
|
ts_config: &TsConfig,
|
||||||
|
all_dirs: &BTreeMap<Arc<ModuleSpecifier>, Arc<WorkspaceDirectory>>,
|
||||||
|
initial_workspace_dir_url: &ModuleSpecifier,
|
||||||
|
current_workspace_dir_url: Option<&ModuleSpecifier>,
|
||||||
) -> TscRoots {
|
) -> TscRoots {
|
||||||
fn maybe_get_check_entry(
|
fn maybe_get_check_entry(
|
||||||
module: &deno_graph::Module,
|
module: &deno_graph::Module,
|
||||||
|
@ -495,6 +524,7 @@ fn get_tsc_roots(
|
||||||
|
|
||||||
let mut result = TscRoots {
|
let mut result = TscRoots {
|
||||||
roots: Vec::with_capacity(graph.specifiers_count()),
|
roots: Vec::with_capacity(graph.specifiers_count()),
|
||||||
|
display_roots: Vec::with_capacity(graph.roots.len()),
|
||||||
missing_diagnostics: Default::default(),
|
missing_diagnostics: Default::default(),
|
||||||
maybe_check_hash: None,
|
maybe_check_hash: None,
|
||||||
};
|
};
|
||||||
|
@ -525,6 +555,16 @@ fn get_tsc_roots(
|
||||||
|
|
||||||
// put in the global types first so that they're resolved before anything else
|
// put in the global types first so that they're resolved before anything else
|
||||||
for (referrer, import) in graph.imports.iter() {
|
for (referrer, import) in graph.imports.iter() {
|
||||||
|
if let Some(current_workspace_dir_url) = current_workspace_dir_url {
|
||||||
|
let scope = all_dirs
|
||||||
|
.keys()
|
||||||
|
.rfind(|s| referrer.as_str().starts_with(s.as_str()))
|
||||||
|
.map(|s| s.as_ref())
|
||||||
|
.unwrap_or(initial_workspace_dir_url);
|
||||||
|
if scope != current_workspace_dir_url {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
for specifier in import
|
for specifier in import
|
||||||
.dependencies
|
.dependencies
|
||||||
.values()
|
.values()
|
||||||
|
@ -556,6 +596,17 @@ fn get_tsc_roots(
|
||||||
|
|
||||||
// then the roots
|
// then the roots
|
||||||
for root in &graph.roots {
|
for root in &graph.roots {
|
||||||
|
if let Some(current_workspace_dir_url) = current_workspace_dir_url {
|
||||||
|
let scope = all_dirs
|
||||||
|
.keys()
|
||||||
|
.rfind(|s| root.as_str().starts_with(s.as_str()))
|
||||||
|
.map(|s| s.as_ref())
|
||||||
|
.unwrap_or(initial_workspace_dir_url);
|
||||||
|
if scope != current_workspace_dir_url {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.display_roots.push(root.clone());
|
||||||
let specifier = graph.resolve(root);
|
let specifier = graph.resolve(root);
|
||||||
if seen.insert(specifier) {
|
if seen.insert(specifier) {
|
||||||
pending.push_back((specifier, false));
|
pending.push_back((specifier, false));
|
||||||
|
|
|
@ -73,8 +73,8 @@ use crate::args::TestFlags;
|
||||||
use crate::args::TestReporterConfig;
|
use crate::args::TestReporterConfig;
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::display;
|
use crate::display;
|
||||||
|
use crate::factory::CliFactoryWithWorkspaceFiles;
|
||||||
use crate::factory::SpecifierInfo;
|
use crate::factory::SpecifierInfo;
|
||||||
use crate::factory::WorkspaceFilesFactory;
|
|
||||||
use crate::file_fetcher::CliFileFetcher;
|
use crate::file_fetcher::CliFileFetcher;
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::sys::CliSys;
|
use crate::sys::CliSys;
|
||||||
|
@ -1180,38 +1180,27 @@ static HAS_TEST_RUN_SIGINT_HANDLER: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
/// Test a collection of specifiers with test modes concurrently.
|
/// Test a collection of specifiers with test modes concurrently.
|
||||||
async fn test_specifiers(
|
async fn test_specifiers(
|
||||||
workspace_files_factory: &WorkspaceFilesFactory,
|
factory: &CliFactoryWithWorkspaceFiles,
|
||||||
changed_paths: Option<&HashSet<PathBuf>>,
|
changed_paths: Option<&HashSet<PathBuf>>,
|
||||||
options: TestSpecifiersOptions,
|
options: TestSpecifiersOptions,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let mut specifiers_with_services = vec![];
|
let mut specifiers = if let Some(changed_paths) = changed_paths {
|
||||||
for factory in workspace_files_factory.dirs() {
|
|
||||||
let worker_factory =
|
|
||||||
Arc::new(factory.create_cli_main_worker_factory().await?);
|
|
||||||
let permission_desc_parser = factory.permission_desc_parser()?;
|
|
||||||
let permissions = Arc::new(Permissions::from_options(
|
|
||||||
permission_desc_parser.as_ref(),
|
|
||||||
factory.permissions_options(),
|
|
||||||
)?);
|
|
||||||
let specifiers = if let Some(changed_paths) = changed_paths {
|
|
||||||
factory.dependent_checked_specifiers(changed_paths).await?
|
factory.dependent_checked_specifiers(changed_paths).await?
|
||||||
} else {
|
} else {
|
||||||
factory.checked_specifiers().collect()
|
factory.checked_specifiers().collect()
|
||||||
};
|
};
|
||||||
specifiers_with_services.extend(specifiers.into_iter().map(|s| {
|
|
||||||
(
|
|
||||||
s.clone(),
|
|
||||||
worker_factory.clone(),
|
|
||||||
permission_desc_parser.clone(),
|
|
||||||
permissions.clone(),
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
if let Some(seed) = options.specifier.shuffle {
|
if let Some(seed) = options.specifier.shuffle {
|
||||||
let mut rng = SmallRng::seed_from_u64(seed);
|
let mut rng = SmallRng::seed_from_u64(seed);
|
||||||
specifiers_with_services.sort_by_cached_key(|(s, ..)| s.to_string());
|
specifiers.sort();
|
||||||
specifiers_with_services.shuffle(&mut rng);
|
specifiers.shuffle(&mut rng);
|
||||||
}
|
}
|
||||||
|
let worker_factory =
|
||||||
|
Arc::new(factory.inner.create_cli_main_worker_factory().await?);
|
||||||
|
let permission_desc_parser = factory.inner.permission_desc_parser()?;
|
||||||
|
let permissions = Permissions::from_options(
|
||||||
|
permission_desc_parser.as_ref(),
|
||||||
|
&factory.cli_options.permissions_options(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let (test_event_sender_factory, receiver) = create_test_event_channel();
|
let (test_event_sender_factory, receiver) = create_test_event_channel();
|
||||||
let concurrent_jobs = options.concurrent_jobs;
|
let concurrent_jobs = options.concurrent_jobs;
|
||||||
|
@ -1225,11 +1214,11 @@ async fn test_specifiers(
|
||||||
let reporter = get_test_reporter(&options);
|
let reporter = get_test_reporter(&options);
|
||||||
let fail_fast_tracker = FailFastTracker::new(options.fail_fast);
|
let fail_fast_tracker = FailFastTracker::new(options.fail_fast);
|
||||||
|
|
||||||
let join_handles = specifiers_with_services.into_iter().map(
|
let join_handles = specifiers.into_iter().cloned().map(move |specifier| {
|
||||||
move |(specifier, worker_factory, permission_desc_parser, permissions)| {
|
let worker_factory = worker_factory.clone();
|
||||||
let permissions_container = PermissionsContainer::new(
|
let permissions_container = PermissionsContainer::new(
|
||||||
permission_desc_parser,
|
permission_desc_parser.clone(),
|
||||||
permissions.as_ref().clone(),
|
permissions.clone(),
|
||||||
);
|
);
|
||||||
let worker_sender = test_event_sender_factory.worker();
|
let worker_sender = test_event_sender_factory.worker();
|
||||||
let fail_fast_tracker = fail_fast_tracker.clone();
|
let fail_fast_tracker = fail_fast_tracker.clone();
|
||||||
|
@ -1244,8 +1233,7 @@ async fn test_specifiers(
|
||||||
specifier_options,
|
specifier_options,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
let join_stream = stream::iter(join_handles)
|
let join_stream = stream::iter(join_handles)
|
||||||
.buffer_unordered(concurrent_jobs.get())
|
.buffer_unordered(concurrent_jobs.get())
|
||||||
|
@ -1516,9 +1504,8 @@ pub async fn run_tests(
|
||||||
.resolve_test_options_for_members(&test_flags)?
|
.resolve_test_options_for_members(&test_flags)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(d, o)| (d, o.files))
|
.map(|(d, o)| (d, o.files))
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
let workspace_files_factory =
|
let factory = CliFactoryWithWorkspaceFiles::from_workspace_dirs_with_files(
|
||||||
WorkspaceFilesFactory::from_workspace_dirs_with_files(
|
|
||||||
workspace_dirs_with_files,
|
workspace_dirs_with_files,
|
||||||
|patterns, cli_options, file_fetcher, doc| {
|
|patterns, cli_options, file_fetcher, doc| {
|
||||||
collect_specifiers_for_tests(patterns, cli_options, file_fetcher, doc)
|
collect_specifiers_for_tests(patterns, cli_options, file_fetcher, doc)
|
||||||
|
@ -1526,30 +1513,29 @@ pub async fn run_tests(
|
||||||
},
|
},
|
||||||
test_flags.doc,
|
test_flags.doc,
|
||||||
Some(extract_doc_tests),
|
Some(extract_doc_tests),
|
||||||
&cli_options,
|
cli_options,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if !test_flags.permit_no_files && !workspace_files_factory.found_specifiers()
|
if !test_flags.permit_no_files && !factory.found_specifiers() {
|
||||||
{
|
|
||||||
return Err(anyhow!("No test modules found"));
|
return Err(anyhow!("No test modules found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace_files_factory.check().await?;
|
factory.check().await?;
|
||||||
|
|
||||||
if test_flags.no_run {
|
if test_flags.no_run {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let initial_cwd = workspace_files_factory.initial_cwd();
|
let initial_cwd = factory.initial_cwd();
|
||||||
test_specifiers(
|
test_specifiers(
|
||||||
&workspace_files_factory,
|
&factory,
|
||||||
None,
|
None,
|
||||||
TestSpecifiersOptions {
|
TestSpecifiersOptions {
|
||||||
cwd: Url::from_directory_path(initial_cwd).map_err(|_| {
|
cwd: Url::from_directory_path(initial_cwd).map_err(|_| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Unable to construct URL from the path of cwd: {}",
|
"Unable to construct URL from the path of cwd: {}",
|
||||||
cli_options.initial_cwd().to_string_lossy(),
|
factory.cli_options.initial_cwd().to_string_lossy(),
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
concurrent_jobs: test_flags
|
concurrent_jobs: test_flags
|
||||||
|
@ -1612,8 +1598,8 @@ pub async fn run_tests_with_watch(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(d, o)| (d, o.files))
|
.map(|(d, o)| (d, o.files))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let workspace_files_factory =
|
let factory =
|
||||||
WorkspaceFilesFactory::from_workspace_dirs_with_files(
|
CliFactoryWithWorkspaceFiles::from_workspace_dirs_with_files(
|
||||||
workspace_dirs_with_files,
|
workspace_dirs_with_files,
|
||||||
|patterns, cli_options, file_fetcher, doc| {
|
|patterns, cli_options, file_fetcher, doc| {
|
||||||
collect_specifiers_for_tests(
|
collect_specifiers_for_tests(
|
||||||
|
@ -1626,26 +1612,26 @@ pub async fn run_tests_with_watch(
|
||||||
},
|
},
|
||||||
test_flags.doc,
|
test_flags.doc,
|
||||||
Some(extract_doc_tests),
|
Some(extract_doc_tests),
|
||||||
&cli_options,
|
cli_options,
|
||||||
Some(&watcher_communicator),
|
Some(&watcher_communicator),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
workspace_files_factory.check().await?;
|
factory.check().await?;
|
||||||
|
|
||||||
if test_flags.no_run {
|
if test_flags.no_run {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let initial_cwd = workspace_files_factory.initial_cwd();
|
let initial_cwd = factory.initial_cwd();
|
||||||
test_specifiers(
|
test_specifiers(
|
||||||
&workspace_files_factory,
|
&factory,
|
||||||
changed_paths.map(|p| p.into_iter().collect()).as_ref(),
|
changed_paths.map(|p| p.into_iter().collect()).as_ref(),
|
||||||
TestSpecifiersOptions {
|
TestSpecifiersOptions {
|
||||||
cwd: Url::from_directory_path(initial_cwd).map_err(|_| {
|
cwd: Url::from_directory_path(initial_cwd).map_err(|_| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Unable to construct URL from the path of cwd: {}",
|
"Unable to construct URL from the path of cwd: {}",
|
||||||
cli_options.initial_cwd().to_string_lossy(),
|
factory.cli_options.initial_cwd().to_string_lossy(),
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
concurrent_jobs: test_flags
|
concurrent_jobs: test_flags
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
Check file:///[WILDLINE]/non_existent.ts
|
|
||||||
error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/non_existent.ts'.
|
error: TS2307 [ERROR]: Cannot find module 'file:///[WILDLINE]/non_existent.ts'.
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
Download http://localhost:4545/missing_non_existent.ts
|
Download http://localhost:4545/missing_non_existent.ts
|
||||||
Check http://localhost:4545/missing_non_existent.ts
|
|
||||||
error: TS2307 [ERROR]: Cannot find module 'http://localhost:4545/missing_non_existent.ts'.
|
error: TS2307 [ERROR]: Cannot find module 'http://localhost:4545/missing_non_existent.ts'.
|
||||||
|
|
Loading…
Add table
Reference in a new issue