mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
refactor: add TypeChecker
struct (#18709)
Adds a `TypeChecker` struct and pushes more shared functionality into it.
This commit is contained in:
parent
f6a28e3e62
commit
0a67a3965f
4 changed files with 185 additions and 206 deletions
|
@ -2,19 +2,17 @@
|
||||||
|
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::args::Lockfile;
|
use crate::args::Lockfile;
|
||||||
use crate::args::TsConfigType;
|
|
||||||
use crate::args::TsTypeLib;
|
use crate::args::TsTypeLib;
|
||||||
use crate::args::TypeCheckMode;
|
use crate::args::TypeCheckMode;
|
||||||
use crate::cache;
|
use crate::cache;
|
||||||
use crate::cache::DenoDir;
|
|
||||||
use crate::cache::ParsedSourceCache;
|
use crate::cache::ParsedSourceCache;
|
||||||
use crate::cache::TypeCheckCache;
|
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::errors::get_error_class_name;
|
use crate::errors::get_error_class_name;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
use crate::npm::NpmPackageResolver;
|
use crate::npm::NpmPackageResolver;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
use crate::tools::check;
|
use crate::tools::check;
|
||||||
|
use crate::tools::check::TypeChecker;
|
||||||
|
|
||||||
use deno_core::anyhow::bail;
|
use deno_core::anyhow::bail;
|
||||||
use deno_core::error::custom_error;
|
use deno_core::error::custom_error;
|
||||||
|
@ -170,10 +168,9 @@ pub struct ModuleGraphBuilder {
|
||||||
npm_resolver: Arc<NpmPackageResolver>,
|
npm_resolver: Arc<NpmPackageResolver>,
|
||||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||||
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
||||||
caches: Arc<cache::Caches>,
|
|
||||||
emit_cache: cache::EmitCache,
|
emit_cache: cache::EmitCache,
|
||||||
file_fetcher: Arc<FileFetcher>,
|
file_fetcher: Arc<FileFetcher>,
|
||||||
deno_dir: DenoDir,
|
type_checker: Arc<TypeChecker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleGraphBuilder {
|
impl ModuleGraphBuilder {
|
||||||
|
@ -184,10 +181,9 @@ impl ModuleGraphBuilder {
|
||||||
npm_resolver: Arc<NpmPackageResolver>,
|
npm_resolver: Arc<NpmPackageResolver>,
|
||||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||||
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
||||||
caches: Arc<cache::Caches>,
|
|
||||||
emit_cache: cache::EmitCache,
|
emit_cache: cache::EmitCache,
|
||||||
file_fetcher: Arc<FileFetcher>,
|
file_fetcher: Arc<FileFetcher>,
|
||||||
deno_dir: DenoDir,
|
type_checker: Arc<TypeChecker>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
options,
|
options,
|
||||||
|
@ -195,10 +191,9 @@ impl ModuleGraphBuilder {
|
||||||
npm_resolver,
|
npm_resolver,
|
||||||
parsed_source_cache,
|
parsed_source_cache,
|
||||||
lockfile,
|
lockfile,
|
||||||
caches,
|
|
||||||
emit_cache,
|
emit_cache,
|
||||||
file_fetcher,
|
file_fetcher,
|
||||||
deno_dir,
|
type_checker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,51 +265,24 @@ impl ModuleGraphBuilder {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
graph_valid_with_cli_options(&graph, &graph.roots, &self.options)?;
|
|
||||||
let graph = Arc::new(graph);
|
let graph = Arc::new(graph);
|
||||||
|
graph_valid_with_cli_options(&graph, &graph.roots, &self.options)?;
|
||||||
if let Some(lockfile) = &self.lockfile {
|
if let Some(lockfile) = &self.lockfile {
|
||||||
graph_lock_or_exit(&graph, &mut lockfile.lock());
|
graph_lock_or_exit(&graph, &mut lockfile.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.options.type_check_mode() != TypeCheckMode::None {
|
if self.options.type_check_mode() != TypeCheckMode::None {
|
||||||
// node built-in specifiers use the @types/node package to determine
|
self
|
||||||
// types, so inject that now after the lockfile has been written
|
.type_checker
|
||||||
if graph.has_node_specifier {
|
.check(
|
||||||
self
|
graph.clone(),
|
||||||
.npm_resolver
|
check::CheckOptions {
|
||||||
.inject_synthetic_types_node_package()
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ts_config_result =
|
|
||||||
self
|
|
||||||
.options
|
|
||||||
.resolve_ts_config_for_emit(TsConfigType::Check {
|
|
||||||
lib: self.options.ts_type_lib_window(),
|
lib: self.options.ts_type_lib_window(),
|
||||||
})?;
|
log_ignored_options: true,
|
||||||
if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
|
reload: self.options.reload_flag(),
|
||||||
log::warn!("{}", ignored_options);
|
},
|
||||||
}
|
)
|
||||||
let maybe_config_specifier = self.options.maybe_config_file_specifier();
|
.await?;
|
||||||
let cache =
|
|
||||||
TypeCheckCache::new(self.caches.type_checking_cache_db(&self.deno_dir));
|
|
||||||
let check_result = check::check(
|
|
||||||
graph.clone(),
|
|
||||||
&cache,
|
|
||||||
self.npm_resolver.clone(),
|
|
||||||
check::CheckOptions {
|
|
||||||
type_check_mode: self.options.type_check_mode(),
|
|
||||||
debug: self.options.log_level() == Some(log::Level::Debug),
|
|
||||||
maybe_config_specifier,
|
|
||||||
ts_config: ts_config_result.ts_config,
|
|
||||||
log_checks: true,
|
|
||||||
reload: self.options.reload_flag(),
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
log::debug!("{}", check_result.stats);
|
|
||||||
if !check_result.diagnostics.is_empty() {
|
|
||||||
return Err(check_result.diagnostics.into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(graph)
|
Ok(graph)
|
||||||
|
|
|
@ -2,13 +2,9 @@
|
||||||
|
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::args::DenoSubcommand;
|
use crate::args::DenoSubcommand;
|
||||||
use crate::args::TsConfigType;
|
|
||||||
use crate::args::TsTypeLib;
|
use crate::args::TsTypeLib;
|
||||||
use crate::args::TypeCheckMode;
|
use crate::args::TypeCheckMode;
|
||||||
use crate::cache::Caches;
|
|
||||||
use crate::cache::DenoDir;
|
|
||||||
use crate::cache::ParsedSourceCache;
|
use crate::cache::ParsedSourceCache;
|
||||||
use crate::cache::TypeCheckCache;
|
|
||||||
use crate::emit::Emitter;
|
use crate::emit::Emitter;
|
||||||
use crate::graph_util::graph_lock_or_exit;
|
use crate::graph_util::graph_lock_or_exit;
|
||||||
use crate::graph_util::graph_valid_with_cli_options;
|
use crate::graph_util::graph_valid_with_cli_options;
|
||||||
|
@ -24,6 +20,7 @@ use crate::proc_state::FileWatcherReporter;
|
||||||
use crate::proc_state::ProcState;
|
use crate::proc_state::ProcState;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
use crate::tools::check;
|
use crate::tools::check;
|
||||||
|
use crate::tools::check::TypeChecker;
|
||||||
use crate::util::progress_bar::ProgressBar;
|
use crate::util::progress_bar::ProgressBar;
|
||||||
use crate::util::text_encoding::code_without_source_map;
|
use crate::util::text_encoding::code_without_source_map;
|
||||||
use crate::util::text_encoding::source_map_from_code;
|
use crate::util::text_encoding::source_map_from_code;
|
||||||
|
@ -66,45 +63,39 @@ use std::sync::Arc;
|
||||||
|
|
||||||
pub struct ModuleLoadPreparer {
|
pub struct ModuleLoadPreparer {
|
||||||
options: Arc<CliOptions>,
|
options: Arc<CliOptions>,
|
||||||
caches: Arc<Caches>,
|
|
||||||
deno_dir: DenoDir,
|
|
||||||
graph_container: Arc<ModuleGraphContainer>,
|
graph_container: Arc<ModuleGraphContainer>,
|
||||||
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
||||||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||||
module_graph_builder: Arc<ModuleGraphBuilder>,
|
module_graph_builder: Arc<ModuleGraphBuilder>,
|
||||||
npm_resolver: Arc<NpmPackageResolver>,
|
|
||||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||||
progress_bar: ProgressBar,
|
progress_bar: ProgressBar,
|
||||||
resolver: Arc<CliGraphResolver>,
|
resolver: Arc<CliGraphResolver>,
|
||||||
|
type_checker: Arc<TypeChecker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleLoadPreparer {
|
impl ModuleLoadPreparer {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
options: Arc<CliOptions>,
|
options: Arc<CliOptions>,
|
||||||
caches: Arc<Caches>,
|
|
||||||
deno_dir: DenoDir,
|
|
||||||
graph_container: Arc<ModuleGraphContainer>,
|
graph_container: Arc<ModuleGraphContainer>,
|
||||||
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
||||||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||||
module_graph_builder: Arc<ModuleGraphBuilder>,
|
module_graph_builder: Arc<ModuleGraphBuilder>,
|
||||||
npm_resolver: Arc<NpmPackageResolver>,
|
|
||||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||||
progress_bar: ProgressBar,
|
progress_bar: ProgressBar,
|
||||||
resolver: Arc<CliGraphResolver>,
|
resolver: Arc<CliGraphResolver>,
|
||||||
|
type_checker: Arc<TypeChecker>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
options,
|
options,
|
||||||
caches,
|
|
||||||
deno_dir,
|
|
||||||
graph_container,
|
graph_container,
|
||||||
lockfile,
|
lockfile,
|
||||||
maybe_file_watcher_reporter,
|
maybe_file_watcher_reporter,
|
||||||
module_graph_builder,
|
module_graph_builder,
|
||||||
npm_resolver,
|
|
||||||
parsed_source_cache,
|
parsed_source_cache,
|
||||||
progress_bar,
|
progress_bar,
|
||||||
resolver,
|
resolver,
|
||||||
|
type_checker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,61 +157,40 @@ impl ModuleLoadPreparer {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// If there is a lockfile, validate the integrity of all the modules.
|
graph_valid_with_cli_options(graph, &roots, &self.options)?;
|
||||||
|
|
||||||
|
// If there is a lockfile...
|
||||||
if let Some(lockfile) = &self.lockfile {
|
if let Some(lockfile) = &self.lockfile {
|
||||||
graph_lock_or_exit(graph, &mut lockfile.lock());
|
let mut lockfile = lockfile.lock();
|
||||||
|
// validate the integrity of all the modules
|
||||||
|
graph_lock_or_exit(graph, &mut lockfile);
|
||||||
|
// update it with anything new
|
||||||
|
lockfile.write()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
graph_valid_with_cli_options(graph, &roots, &self.options)?;
|
|
||||||
// save the graph and get a reference to the new graph
|
// save the graph and get a reference to the new graph
|
||||||
let graph = graph_update_permit.commit();
|
let graph = graph_update_permit.commit();
|
||||||
|
|
||||||
if graph.has_node_specifier
|
|
||||||
&& self.options.type_check_mode() != TypeCheckMode::None
|
|
||||||
{
|
|
||||||
self
|
|
||||||
.npm_resolver
|
|
||||||
.inject_synthetic_types_node_package()
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(_pb_clear_guard);
|
drop(_pb_clear_guard);
|
||||||
|
|
||||||
// type check if necessary
|
// type check if necessary
|
||||||
if self.options.type_check_mode() != TypeCheckMode::None
|
if self.options.type_check_mode() != TypeCheckMode::None
|
||||||
&& !self.graph_container.is_type_checked(&roots, lib)
|
&& !self.graph_container.is_type_checked(&roots, lib)
|
||||||
{
|
{
|
||||||
// todo(dsherret): consolidate this with what's done in graph_util
|
|
||||||
log::debug!("Type checking.");
|
|
||||||
let maybe_config_specifier = self.options.maybe_config_file_specifier();
|
|
||||||
let graph = Arc::new(graph.segment(&roots));
|
let graph = Arc::new(graph.segment(&roots));
|
||||||
let options = check::CheckOptions {
|
self
|
||||||
type_check_mode: self.options.type_check_mode(),
|
.type_checker
|
||||||
debug: self.options.log_level() == Some(log::Level::Debug),
|
.check(
|
||||||
maybe_config_specifier,
|
graph,
|
||||||
ts_config: self
|
check::CheckOptions {
|
||||||
.options
|
lib,
|
||||||
.resolve_ts_config_for_emit(TsConfigType::Check { lib })?
|
log_ignored_options: false,
|
||||||
.ts_config,
|
reload: self.options.reload_flag()
|
||||||
log_checks: true,
|
&& !roots.iter().all(|r| reload_exclusions.contains(r)),
|
||||||
reload: self.options.reload_flag()
|
},
|
||||||
&& !roots.iter().all(|r| reload_exclusions.contains(r)),
|
)
|
||||||
};
|
.await?;
|
||||||
let check_cache =
|
|
||||||
TypeCheckCache::new(self.caches.type_checking_cache_db(&self.deno_dir));
|
|
||||||
let check_result =
|
|
||||||
check::check(graph, &check_cache, self.npm_resolver.clone(), options)?;
|
|
||||||
self.graph_container.set_type_checked(&roots, lib);
|
self.graph_container.set_type_checked(&roots, lib);
|
||||||
if !check_result.diagnostics.is_empty() {
|
|
||||||
return Err(anyhow!(check_result.diagnostics));
|
|
||||||
}
|
|
||||||
log::debug!("{}", check_result.stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
// any updates to the lockfile should be updated now
|
|
||||||
if let Some(ref lockfile) = self.lockfile {
|
|
||||||
let g = lockfile.lock();
|
|
||||||
g.write()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("Prepared module load.");
|
log::debug!("Prepared module load.");
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::npm::NpmPackageResolver;
|
||||||
use crate::npm::NpmResolution;
|
use crate::npm::NpmResolution;
|
||||||
use crate::npm::PackageJsonDepsInstaller;
|
use crate::npm::PackageJsonDepsInstaller;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
|
use crate::tools::check::TypeChecker;
|
||||||
use crate::util::progress_bar::ProgressBar;
|
use crate::util::progress_bar::ProgressBar;
|
||||||
use crate::util::progress_bar::ProgressBarStyle;
|
use crate::util::progress_bar::ProgressBarStyle;
|
||||||
|
|
||||||
|
@ -305,30 +306,33 @@ impl ProcState {
|
||||||
file_fetcher.clone(),
|
file_fetcher.clone(),
|
||||||
npm_resolver.clone(),
|
npm_resolver.clone(),
|
||||||
));
|
));
|
||||||
|
let type_checker = Arc::new(TypeChecker::new(
|
||||||
|
dir.clone(),
|
||||||
|
caches.clone(),
|
||||||
|
cli_options.clone(),
|
||||||
|
npm_resolver.clone(),
|
||||||
|
));
|
||||||
let module_graph_builder = Arc::new(ModuleGraphBuilder::new(
|
let module_graph_builder = Arc::new(ModuleGraphBuilder::new(
|
||||||
cli_options.clone(),
|
cli_options.clone(),
|
||||||
resolver.clone(),
|
resolver.clone(),
|
||||||
npm_resolver.clone(),
|
npm_resolver.clone(),
|
||||||
parsed_source_cache.clone(),
|
parsed_source_cache.clone(),
|
||||||
lockfile.clone(),
|
lockfile.clone(),
|
||||||
caches.clone(),
|
|
||||||
emit_cache.clone(),
|
emit_cache.clone(),
|
||||||
file_fetcher.clone(),
|
file_fetcher.clone(),
|
||||||
dir.clone(),
|
type_checker.clone(),
|
||||||
));
|
));
|
||||||
let graph_container: Arc<ModuleGraphContainer> = Default::default();
|
let graph_container: Arc<ModuleGraphContainer> = Default::default();
|
||||||
let module_load_preparer = Arc::new(ModuleLoadPreparer::new(
|
let module_load_preparer = Arc::new(ModuleLoadPreparer::new(
|
||||||
cli_options.clone(),
|
cli_options.clone(),
|
||||||
caches.clone(),
|
|
||||||
dir.clone(),
|
|
||||||
graph_container.clone(),
|
graph_container.clone(),
|
||||||
lockfile.clone(),
|
lockfile.clone(),
|
||||||
maybe_file_watcher_reporter.clone(),
|
maybe_file_watcher_reporter.clone(),
|
||||||
module_graph_builder.clone(),
|
module_graph_builder.clone(),
|
||||||
npm_resolver.clone(),
|
|
||||||
parsed_source_cache.clone(),
|
parsed_source_cache.clone(),
|
||||||
progress_bar.clone(),
|
progress_bar.clone(),
|
||||||
resolver.clone(),
|
resolver.clone(),
|
||||||
|
type_checker,
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(ProcState(Arc::new(Inner {
|
Ok(ProcState(Arc::new(Inner {
|
||||||
|
|
|
@ -12,136 +12,172 @@ use deno_runtime::colors;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::args::CliOptions;
|
||||||
use crate::args::TsConfig;
|
use crate::args::TsConfig;
|
||||||
|
use crate::args::TsConfigType;
|
||||||
|
use crate::args::TsTypeLib;
|
||||||
use crate::args::TypeCheckMode;
|
use crate::args::TypeCheckMode;
|
||||||
|
use crate::cache::Caches;
|
||||||
|
use crate::cache::DenoDir;
|
||||||
use crate::cache::FastInsecureHasher;
|
use crate::cache::FastInsecureHasher;
|
||||||
use crate::cache::TypeCheckCache;
|
use crate::cache::TypeCheckCache;
|
||||||
use crate::npm::NpmPackageResolver;
|
use crate::npm::NpmPackageResolver;
|
||||||
use crate::tsc;
|
use crate::tsc;
|
||||||
use crate::tsc::Diagnostics;
|
|
||||||
use crate::tsc::Stats;
|
|
||||||
use crate::version;
|
use crate::version;
|
||||||
|
|
||||||
/// 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
|
||||||
/// emit or not is determined by the `ts_config` settings.
|
/// emit or not is determined by the `ts_config` settings.
|
||||||
pub struct CheckOptions {
|
pub struct CheckOptions {
|
||||||
/// The check flag from the option which can effect the filtering of
|
/// Default type library to type check with.
|
||||||
/// diagnostics in the emit result.
|
pub lib: TsTypeLib,
|
||||||
pub type_check_mode: TypeCheckMode,
|
/// Whether to log about any ignored compiler options.
|
||||||
/// Set the debug flag on the TypeScript type checker.
|
pub log_ignored_options: bool,
|
||||||
pub debug: bool,
|
|
||||||
/// The module specifier to the configuration file, passed to tsc so that
|
|
||||||
/// configuration related diagnostics are properly formed.
|
|
||||||
pub maybe_config_specifier: Option<ModuleSpecifier>,
|
|
||||||
/// The derived tsconfig that should be used when checking.
|
|
||||||
pub ts_config: TsConfig,
|
|
||||||
/// If true, `Check <specifier>` will be written to stdout for each root.
|
|
||||||
pub log_checks: bool,
|
|
||||||
/// If true, valid `.tsbuildinfo` files will be ignored and type checking
|
/// If true, valid `.tsbuildinfo` files will be ignored and type checking
|
||||||
/// will always occur.
|
/// will always occur.
|
||||||
pub reload: bool,
|
pub reload: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a check of a module graph.
|
pub struct TypeChecker {
|
||||||
#[derive(Debug, Default)]
|
deno_dir: DenoDir,
|
||||||
pub struct CheckResult {
|
caches: Arc<Caches>,
|
||||||
pub diagnostics: Diagnostics,
|
cli_options: Arc<CliOptions>,
|
||||||
pub stats: Stats,
|
npm_resolver: Arc<NpmPackageResolver>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a set of roots and graph data, type check the module graph.
|
impl TypeChecker {
|
||||||
///
|
pub fn new(
|
||||||
/// It is expected that it is determined if a check and/or emit is validated
|
deno_dir: DenoDir,
|
||||||
/// before the function is called.
|
caches: Arc<Caches>,
|
||||||
pub fn check(
|
cli_options: Arc<CliOptions>,
|
||||||
graph: Arc<ModuleGraph>,
|
npm_resolver: Arc<NpmPackageResolver>,
|
||||||
cache: &TypeCheckCache,
|
) -> Self {
|
||||||
npm_resolver: Arc<NpmPackageResolver>,
|
Self {
|
||||||
options: CheckOptions,
|
deno_dir,
|
||||||
) -> Result<CheckResult, AnyError> {
|
caches,
|
||||||
let check_js = options.ts_config.get_check_js();
|
cli_options,
|
||||||
let check_hash = match get_check_hash(&graph, &options) {
|
npm_resolver,
|
||||||
CheckHashResult::NoFiles => return Ok(Default::default()),
|
}
|
||||||
CheckHashResult::Hash(hash) => hash,
|
|
||||||
};
|
|
||||||
|
|
||||||
// do not type check if we know this is type checked
|
|
||||||
if !options.reload && cache.has_check_hash(check_hash) {
|
|
||||||
return Ok(Default::default());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.log_checks {
|
/// Type check the module graph.
|
||||||
|
///
|
||||||
|
/// It is expected that it is determined if a check and/or emit is validated
|
||||||
|
/// before the function is called.
|
||||||
|
pub async fn check(
|
||||||
|
&self,
|
||||||
|
graph: Arc<ModuleGraph>,
|
||||||
|
options: CheckOptions,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
// node built-in specifiers use the @types/node package to determine
|
||||||
|
// types, so inject that now (the caller should do this after the lockfile
|
||||||
|
// has been written)
|
||||||
|
if graph.has_node_specifier {
|
||||||
|
self
|
||||||
|
.npm_resolver
|
||||||
|
.inject_synthetic_types_node_package()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if let Some(ignored_options) = ts_config_result.maybe_ignored_options {
|
||||||
|
log::warn!("{}", ignored_options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ts_config = ts_config_result.ts_config;
|
||||||
|
let type_check_mode = self.cli_options.type_check_mode();
|
||||||
|
let debug = self.cli_options.log_level() == Some(log::Level::Debug);
|
||||||
|
let cache =
|
||||||
|
TypeCheckCache::new(self.caches.type_checking_cache_db(&self.deno_dir));
|
||||||
|
let check_js = ts_config.get_check_js();
|
||||||
|
let check_hash = match get_check_hash(&graph, type_check_mode, &ts_config) {
|
||||||
|
CheckHashResult::NoFiles => return Ok(()),
|
||||||
|
CheckHashResult::Hash(hash) => hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
// do not type check if we know this is type checked
|
||||||
|
if !options.reload && cache.has_check_hash(check_hash) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
for root in &graph.roots {
|
for root in &graph.roots {
|
||||||
let root_str = root.as_str();
|
let root_str = root.as_str();
|
||||||
log::info!("{} {}", colors::green("Check"), root_str);
|
log::info!("{} {}", colors::green("Check"), root_str);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let root_names = get_tsc_roots(&graph, check_js);
|
let root_names = get_tsc_roots(&graph, check_js);
|
||||||
// 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 maybe_tsbuildinfo = if options.reload {
|
let maybe_tsbuildinfo = if options.reload {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
cache.get_tsbuildinfo(&graph.roots[0])
|
cache.get_tsbuildinfo(&graph.roots[0])
|
||||||
};
|
};
|
||||||
// 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
|
||||||
// that data here.
|
// that data here.
|
||||||
let hash_data = {
|
let hash_data = {
|
||||||
let mut hasher = FastInsecureHasher::new();
|
let mut hasher = FastInsecureHasher::new();
|
||||||
hasher.write(&options.ts_config.as_bytes());
|
hasher.write(&ts_config.as_bytes());
|
||||||
hasher.write_str(version::deno());
|
hasher.write_str(version::deno());
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = tsc::exec(tsc::Request {
|
let response = tsc::exec(tsc::Request {
|
||||||
config: options.ts_config,
|
config: ts_config,
|
||||||
debug: options.debug,
|
debug,
|
||||||
graph: graph.clone(),
|
graph: graph.clone(),
|
||||||
hash_data,
|
hash_data,
|
||||||
maybe_npm_resolver: Some(npm_resolver.clone()),
|
maybe_npm_resolver: Some(self.npm_resolver.clone()),
|
||||||
maybe_tsbuildinfo,
|
maybe_tsbuildinfo,
|
||||||
root_names,
|
root_names,
|
||||||
check_mode: options.type_check_mode,
|
check_mode: type_check_mode,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let diagnostics = if options.type_check_mode == TypeCheckMode::Local {
|
let diagnostics = if type_check_mode == TypeCheckMode::Local {
|
||||||
response.diagnostics.filter(|d| {
|
response.diagnostics.filter(|d| {
|
||||||
if let Some(file_name) = &d.file_name {
|
if let Some(file_name) = &d.file_name {
|
||||||
if !file_name.starts_with("http") {
|
if !file_name.starts_with("http") {
|
||||||
if ModuleSpecifier::parse(file_name)
|
if ModuleSpecifier::parse(file_name)
|
||||||
.map(|specifier| !npm_resolver.in_npm_package(&specifier))
|
.map(|specifier| !self.npm_resolver.in_npm_package(&specifier))
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
Some(d.clone())
|
Some(d.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
Some(d.clone())
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
Some(d.clone())
|
} else {
|
||||||
}
|
response.diagnostics
|
||||||
})
|
};
|
||||||
} else {
|
|
||||||
response.diagnostics
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(tsbuildinfo) = response.maybe_tsbuildinfo {
|
if let Some(tsbuildinfo) = response.maybe_tsbuildinfo {
|
||||||
cache.set_tsbuildinfo(&graph.roots[0], &tsbuildinfo);
|
cache.set_tsbuildinfo(&graph.roots[0], &tsbuildinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
cache.add_check_hash(check_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("{}", response.stats);
|
||||||
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
cache.add_check_hash(check_hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(CheckResult {
|
|
||||||
diagnostics,
|
|
||||||
stats: response.stats,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CheckHashResult {
|
enum CheckHashResult {
|
||||||
|
@ -153,17 +189,18 @@ enum CheckHashResult {
|
||||||
/// be used to tell
|
/// be used to tell
|
||||||
fn get_check_hash(
|
fn get_check_hash(
|
||||||
graph: &ModuleGraph,
|
graph: &ModuleGraph,
|
||||||
options: &CheckOptions,
|
type_check_mode: TypeCheckMode,
|
||||||
|
ts_config: &TsConfig,
|
||||||
) -> CheckHashResult {
|
) -> CheckHashResult {
|
||||||
let mut hasher = FastInsecureHasher::new();
|
let mut hasher = FastInsecureHasher::new();
|
||||||
hasher.write_u8(match options.type_check_mode {
|
hasher.write_u8(match type_check_mode {
|
||||||
TypeCheckMode::All => 0,
|
TypeCheckMode::All => 0,
|
||||||
TypeCheckMode::Local => 1,
|
TypeCheckMode::Local => 1,
|
||||||
TypeCheckMode::None => 2,
|
TypeCheckMode::None => 2,
|
||||||
});
|
});
|
||||||
hasher.write(&options.ts_config.as_bytes());
|
hasher.write(&ts_config.as_bytes());
|
||||||
|
|
||||||
let check_js = options.ts_config.get_check_js();
|
let check_js = ts_config.get_check_js();
|
||||||
let mut sorted_modules = graph.modules().collect::<Vec<_>>();
|
let mut sorted_modules = graph.modules().collect::<Vec<_>>();
|
||||||
sorted_modules.sort_by_key(|m| m.specifier().as_str()); // make it deterministic
|
sorted_modules.sort_by_key(|m| m.specifier().as_str()); // make it deterministic
|
||||||
let mut has_file = false;
|
let mut has_file = false;
|
||||||
|
|
Loading…
Reference in a new issue