mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00:00
feat(check): tsconfig "references", "extends", "files", "include" and "exclude" (#29843)
- Each workspace directory is probed for a `tsconfig.json`. - These and any that are included by their `references` are put into a list ordered by priority. - A tsconfig has lower priority than its `references`. - An earlier listed entry in `references` has higher priority than a later one. - A probed tsconfig in an inner directory has higher priority than an outer one. Their `references` would be interspersed between them. - Each tsconfig has a filter based on its `files`, `include` and `exclude` fields. If it doesn't have `files` or `include`, it will match any path in its containing directory not exempted by `exclude`. - For type-checking, each root path will be allocated compiler options based on the first tsconfig it whose filter it matches from this list. - Only if it doesn't match any tsconfig, it will fall back to using the nearest `deno.json`. If it's a workspace member and the root `deno.json` has `compilerOptions`, these will be merged using the same logic from `extends`. Inheritance between configs strictly occurs via `extends` in a `tsconfig.json`, and between workspace member and root `deno.json`s' `compilerOptions`. There is no implicit inheritance between `tsconfig.json` and `deno.json`. The default compiler options currently applied against tsconfigs are Deno's normal defaults, with the exception of `lib`. The default value for `lib` is `["deno.window", "deno.unstable", "dom"]` for files in the scope of a tsconfig with `lib` unspecified. This behaviour is depended on by, for example, the template project created by `create-vite -> svelte`. I expect we'll add more such exceptions over time with other fields.
This commit is contained in:
parent
9913311860
commit
7a9ab843bd
95 changed files with 1512 additions and 514 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2698,6 +2698,7 @@ dependencies = [
|
|||
"http 1.1.0",
|
||||
"import_map",
|
||||
"indexmap 2.9.0",
|
||||
"jsonc-parser",
|
||||
"log",
|
||||
"node_resolver",
|
||||
"once_cell",
|
||||
|
|
|
@ -24,8 +24,8 @@ pub use deno_config::deno_json::LintRulesConfig;
|
|||
use deno_config::deno_json::NodeModulesDirMode;
|
||||
pub use deno_config::deno_json::ProseWrap;
|
||||
use deno_config::deno_json::TestConfig;
|
||||
pub use deno_config::deno_json::TsTypeLib;
|
||||
pub use deno_config::glob::FilePatterns;
|
||||
pub use deno_config::workspace::TsTypeLib;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_config::workspace::WorkspaceDirLintConfig;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
|
@ -59,8 +59,6 @@ use thiserror::Error;
|
|||
use crate::sys::CliSys;
|
||||
|
||||
pub type CliLockfile = deno_resolver::lockfile::LockfileLock<CliSys>;
|
||||
pub type CliTsConfigResolver =
|
||||
deno_resolver::deno_json::TsConfigResolver<CliSys>;
|
||||
|
||||
pub fn jsr_url() -> &'static Url {
|
||||
static JSR_URL: Lazy<Url> = Lazy::new(|| resolve_jsr_url(&CliSys::default()));
|
||||
|
|
33
cli/emit.rs
33
cli/emit.rs
|
@ -21,9 +21,9 @@ use deno_graph::MediaType;
|
|||
use deno_graph::Module;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use deno_resolver::deno_json::TranspileAndEmitOptions;
|
||||
|
||||
use crate::args::CliTsConfigResolver;
|
||||
use crate::cache::EmitCache;
|
||||
use crate::cache::ParsedSourceCache;
|
||||
use crate::resolver::CliCjsTracker;
|
||||
|
@ -33,7 +33,7 @@ pub struct Emitter {
|
|||
cjs_tracker: Arc<CliCjsTracker>,
|
||||
emit_cache: Arc<EmitCache>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
}
|
||||
|
||||
impl Emitter {
|
||||
|
@ -41,13 +41,13 @@ impl Emitter {
|
|||
cjs_tracker: Arc<CliCjsTracker>,
|
||||
emit_cache: Arc<EmitCache>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_tracker,
|
||||
emit_cache,
|
||||
parsed_source_cache,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,8 +96,9 @@ impl Emitter {
|
|||
source: &str,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let transpile_and_emit_options = self
|
||||
.tsconfig_resolver
|
||||
.transpile_and_emit_options(specifier)?;
|
||||
.compiler_options_resolver
|
||||
.for_specifier(specifier)
|
||||
.transpile_options()?;
|
||||
let source_hash =
|
||||
self.get_source_hash(module_kind, transpile_and_emit_options, source);
|
||||
Ok(self.emit_cache.get_emit_code(specifier, source_hash))
|
||||
|
@ -111,8 +112,9 @@ impl Emitter {
|
|||
source: &Arc<str>,
|
||||
) -> Result<String, EmitParsedSourceHelperError> {
|
||||
let transpile_and_emit_options = self
|
||||
.tsconfig_resolver
|
||||
.transpile_and_emit_options(specifier)?;
|
||||
.compiler_options_resolver
|
||||
.for_specifier(specifier)
|
||||
.transpile_options()?;
|
||||
// Note: keep this in sync with the sync version below
|
||||
let helper = EmitParsedSourceHelper(self);
|
||||
match helper.pre_emit_parsed_source(
|
||||
|
@ -162,8 +164,9 @@ impl Emitter {
|
|||
source: &Arc<str>,
|
||||
) -> Result<String, EmitParsedSourceHelperError> {
|
||||
let transpile_and_emit_options = self
|
||||
.tsconfig_resolver
|
||||
.transpile_and_emit_options(specifier)?;
|
||||
.compiler_options_resolver
|
||||
.for_specifier(specifier)
|
||||
.transpile_options()?;
|
||||
// Note: keep this in sync with the async version above
|
||||
let helper = EmitParsedSourceHelper(self);
|
||||
match helper.pre_emit_parsed_source(
|
||||
|
@ -202,8 +205,9 @@ impl Emitter {
|
|||
source: &Arc<str>,
|
||||
) -> Result<(String, String), AnyError> {
|
||||
let transpile_and_emit_options = self
|
||||
.tsconfig_resolver
|
||||
.transpile_and_emit_options(specifier)?;
|
||||
.compiler_options_resolver
|
||||
.for_specifier(specifier)
|
||||
.transpile_options()?;
|
||||
let mut emit_options = transpile_and_emit_options.emit.clone();
|
||||
emit_options.inline_sources = false;
|
||||
emit_options.source_map = SourceMapOption::Separate;
|
||||
|
@ -247,8 +251,9 @@ impl Emitter {
|
|||
// the option to not use them (though you should test this out because
|
||||
// this statement is probably wrong)
|
||||
let transpile_and_emit_options = self
|
||||
.tsconfig_resolver
|
||||
.transpile_and_emit_options(specifier)
|
||||
.compiler_options_resolver
|
||||
.for_specifier(specifier)
|
||||
.transpile_options()
|
||||
.map_err(JsErrorBox::from_err)?;
|
||||
let mut options = transpile_and_emit_options.emit.clone();
|
||||
options.source_map = SourceMapOption::None;
|
||||
|
|
|
@ -32,11 +32,13 @@ use deno_npm_installer::lifecycle_scripts::NullLifecycleScriptsExecutor;
|
|||
use deno_npm_installer::process_state::NpmProcessStateKind;
|
||||
use deno_npm_installer::NpmInstallerFactoryOptions;
|
||||
use deno_resolver::cjs::IsCjsResolutionMode;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use deno_resolver::factory::ConfigDiscoveryOption;
|
||||
use deno_resolver::factory::DenoDirPathProviderOptions;
|
||||
use deno_resolver::factory::NpmProcessStateOptions;
|
||||
use deno_resolver::factory::ResolverFactoryOptions;
|
||||
use deno_resolver::factory::SpecifiedImportMapProvider;
|
||||
use deno_resolver::factory::WorkspaceDirectoryProvider;
|
||||
use deno_resolver::import_map::WorkspaceExternalImportMapLoader;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::workspace::WorkspaceResolver;
|
||||
|
@ -61,7 +63,6 @@ use crate::args::BundleFlags;
|
|||
use crate::args::BundlePlatform;
|
||||
use crate::args::CliLockfile;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::CliTsConfigResolver;
|
||||
use crate::args::ConfigFlag;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::Flags;
|
||||
|
@ -693,7 +694,7 @@ impl CliFactory {
|
|||
self.cjs_tracker()?.clone(),
|
||||
self.emit_cache()?.clone(),
|
||||
self.parsed_source_cache().clone(),
|
||||
self.tsconfig_resolver()?.clone(),
|
||||
self.compiler_options_resolver()?.clone(),
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
@ -780,10 +781,10 @@ impl CliFactory {
|
|||
Ok(self.resolver_factory()?.pkg_json_resolver())
|
||||
}
|
||||
|
||||
pub fn tsconfig_resolver(
|
||||
pub fn compiler_options_resolver(
|
||||
&self,
|
||||
) -> Result<&Arc<CliTsConfigResolver>, AnyError> {
|
||||
Ok(self.workspace_factory()?.tsconfig_resolver()?)
|
||||
) -> Result<&Arc<CompilerOptionsResolver>, AnyError> {
|
||||
self.resolver_factory()?.compiler_options_resolver()
|
||||
}
|
||||
|
||||
pub async fn type_checker(&self) -> Result<&Arc<TypeChecker>, AnyError> {
|
||||
|
@ -804,7 +805,8 @@ impl CliFactory {
|
|||
self.node_resolver().await?.clone(),
|
||||
self.npm_resolver().await?.clone(),
|
||||
self.sys(),
|
||||
self.tsconfig_resolver()?.clone(),
|
||||
self.workspace_directory_provider()?.clone(),
|
||||
self.compiler_options_resolver()?.clone(),
|
||||
if cli_options.code_cache_enabled() {
|
||||
Some(self.code_cache()?.clone())
|
||||
} else {
|
||||
|
@ -843,7 +845,7 @@ impl CliFactory {
|
|||
self.resolver().await?.clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
self.sys(),
|
||||
self.tsconfig_resolver()?.clone(),
|
||||
self.compiler_options_resolver()?.clone(),
|
||||
)))
|
||||
}
|
||||
.boxed_local(),
|
||||
|
@ -985,6 +987,12 @@ impl CliFactory {
|
|||
})
|
||||
}
|
||||
|
||||
fn workspace_directory_provider(
|
||||
&self,
|
||||
) -> Result<&Arc<WorkspaceDirectoryProvider>, AnyError> {
|
||||
Ok(self.workspace_factory()?.workspace_directory_provider()?)
|
||||
}
|
||||
|
||||
fn workspace_external_import_map_loader(
|
||||
&self,
|
||||
) -> Result<&Arc<WorkspaceExternalImportMapLoader<CliSys>>, AnyError> {
|
||||
|
|
|
@ -34,20 +34,21 @@ use deno_graph::WorkspaceFastCheckOption;
|
|||
use deno_npm_installer::graph::NpmCachingStrategy;
|
||||
use deno_npm_installer::PackageCaching;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use deno_resolver::deno_json::JsxImportSourceConfigResolver;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::workspace::sloppy_imports_resolve;
|
||||
use deno_resolver::workspace::ScopedJsxImportSourceConfig;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrDepPackageReq;
|
||||
use deno_semver::SmallStackString;
|
||||
use indexmap::IndexMap;
|
||||
use sys_traits::FsMetadata;
|
||||
|
||||
use crate::args::config_to_deno_graph_workspace_member;
|
||||
use crate::args::jsr_url;
|
||||
use crate::args::CliLockfile;
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::CliTsConfigResolver;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::cache;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
|
@ -689,7 +690,7 @@ pub struct ModuleGraphBuilder {
|
|||
resolver: Arc<CliResolver>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
sys: CliSys,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
}
|
||||
|
||||
impl ModuleGraphBuilder {
|
||||
|
@ -711,7 +712,7 @@ impl ModuleGraphBuilder {
|
|||
resolver: Arc<CliResolver>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
sys: CliSys,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
) -> Self {
|
||||
Self {
|
||||
caches,
|
||||
|
@ -730,7 +731,7 @@ impl ModuleGraphBuilder {
|
|||
resolver,
|
||||
root_permissions_container,
|
||||
sys,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,12 +761,14 @@ impl ModuleGraphBuilder {
|
|||
MutLoaderRef::Owned(self.create_graph_loader_with_root_permissions())
|
||||
}
|
||||
};
|
||||
let scoped_jsx_config = ScopedJsxImportSourceConfig::from_workspace_dir(
|
||||
&self.cli_options.start_dir,
|
||||
let jsx_import_source_config_resolver =
|
||||
JsxImportSourceConfigResolver::from_compiler_options_resolver(
|
||||
&self.compiler_options_resolver,
|
||||
)?;
|
||||
let graph_resolver = self
|
||||
.resolver
|
||||
.as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config);
|
||||
let graph_resolver = self.resolver.as_graph_resolver(
|
||||
self.cjs_tracker.as_ref(),
|
||||
&jsx_import_source_config_resolver,
|
||||
);
|
||||
let maybe_file_watcher_reporter = self
|
||||
.maybe_file_watcher_reporter
|
||||
.as_ref()
|
||||
|
@ -854,19 +857,39 @@ impl ModuleGraphBuilder {
|
|||
return Err(BuildGraphWithNpmResolutionError::UnsupportedNpmSpecifierEntrypointResolutionWay);
|
||||
}
|
||||
let imports = if graph.graph_kind().include_types() {
|
||||
// Resolve all the imports from every deno.json. We'll separate
|
||||
// Resolve all the imports from every config file. We'll separate
|
||||
// them later based on the folder we're type checking.
|
||||
let mut imports = Vec::new();
|
||||
for deno_json in self.cli_options.workspace().deno_jsons() {
|
||||
let maybe_imports = deno_json.to_compiler_option_types()?;
|
||||
imports.extend(maybe_imports.into_iter().map(
|
||||
|(referrer, imports)| deno_graph::ReferrerImports {
|
||||
referrer,
|
||||
imports,
|
||||
},
|
||||
));
|
||||
let mut imports_by_referrer = IndexMap::<_, Vec<_>>::with_capacity(
|
||||
self.compiler_options_resolver.size(),
|
||||
);
|
||||
for (referrer, files) in self
|
||||
.compiler_options_resolver
|
||||
.ts_configs()
|
||||
.iter()
|
||||
.filter_map(|t| t.files())
|
||||
{
|
||||
imports_by_referrer
|
||||
.entry(referrer)
|
||||
.or_default()
|
||||
.extend(files.iter().map(|f| f.relative_specifier.clone()));
|
||||
}
|
||||
imports
|
||||
for (referrer, types) in self
|
||||
.compiler_options_resolver
|
||||
.all()
|
||||
.flat_map(|d| d.compiler_options_types().as_ref())
|
||||
{
|
||||
imports_by_referrer
|
||||
.entry(referrer)
|
||||
.or_default()
|
||||
.extend(types.clone());
|
||||
}
|
||||
imports_by_referrer
|
||||
.into_iter()
|
||||
.map(|(referrer, imports)| deno_graph::ReferrerImports {
|
||||
referrer: referrer.clone(),
|
||||
imports,
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
@ -938,12 +961,14 @@ impl ModuleGraphBuilder {
|
|||
None
|
||||
};
|
||||
let parser = self.parsed_source_cache.as_capturing_parser();
|
||||
let scoped_jsx_config = ScopedJsxImportSourceConfig::from_workspace_dir(
|
||||
&self.cli_options.start_dir,
|
||||
let jsx_import_source_config_resolver =
|
||||
JsxImportSourceConfigResolver::from_compiler_options_resolver(
|
||||
&self.compiler_options_resolver,
|
||||
)?;
|
||||
let graph_resolver = self
|
||||
.resolver
|
||||
.as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config);
|
||||
let graph_resolver = self.resolver.as_graph_resolver(
|
||||
self.cjs_tracker.as_ref(),
|
||||
&jsx_import_source_config_resolver,
|
||||
);
|
||||
|
||||
graph.build_fast_check_type_graph(
|
||||
deno_graph::BuildFastCheckTypeGraphOptions {
|
||||
|
@ -1012,7 +1037,9 @@ impl ModuleGraphBuilder {
|
|||
} else {
|
||||
GraphKind::CodeOnly
|
||||
},
|
||||
check_js: CheckJsOption::Custom(self.tsconfig_resolver.as_ref()),
|
||||
check_js: CheckJsOption::Custom(
|
||||
self.compiler_options_resolver.as_ref(),
|
||||
),
|
||||
exit_integrity_errors: true,
|
||||
allow_unknown_media_types,
|
||||
ignore_graph_errors: matches!(
|
||||
|
|
|
@ -16,7 +16,7 @@ use std::time::Duration;
|
|||
use deno_ast::EmitOptions;
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_config::deno_json::TsTypeLib;
|
||||
use deno_config::workspace::TsTypeLib;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::FutureExt as _;
|
||||
use deno_core::resolve_url_or_path;
|
||||
|
|
|
@ -163,7 +163,7 @@ pub async fn compile_eszip(
|
|||
let cli_options = factory.cli_options()?;
|
||||
let module_graph_creator = factory.module_graph_creator().await?;
|
||||
let parsed_source_cache = factory.parsed_source_cache();
|
||||
let tsconfig_resolver = factory.tsconfig_resolver()?;
|
||||
let compiler_options_resolver = factory.compiler_options_resolver()?;
|
||||
let bin_name_resolver = factory.bin_name_resolver()?;
|
||||
let entrypoint = cli_options.resolve_main_module()?;
|
||||
let mut output_path = resolve_compile_executable_output_path(
|
||||
|
@ -203,8 +203,9 @@ pub async fn compile_eszip(
|
|||
graph
|
||||
};
|
||||
|
||||
let transpile_and_emit_options = tsconfig_resolver
|
||||
.transpile_and_emit_options(cli_options.workspace().root_dir())?;
|
||||
let transpile_and_emit_options = compiler_options_resolver
|
||||
.for_specifier(cli_options.workspace().root_dir())
|
||||
.transpile_options()?;
|
||||
let transpile_options = transpile_and_emit_options.transpile.clone();
|
||||
let emit_options = transpile_and_emit_options.emit.clone();
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ pub async fn kernel(
|
|||
let permissions =
|
||||
PermissionsContainer::allow_all(factory.permission_desc_parser()?.clone());
|
||||
let npm_installer = factory.npm_installer_if_managed().await?.cloned();
|
||||
let tsconfig_resolver = factory.tsconfig_resolver()?;
|
||||
let compiler_options_resolver = factory.compiler_options_resolver()?;
|
||||
let resolver = factory.resolver().await?.clone();
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let (stdio_tx, stdio_rx) = mpsc::unbounded_channel();
|
||||
|
@ -124,7 +124,7 @@ pub async fn kernel(
|
|||
cli_options,
|
||||
npm_installer,
|
||||
resolver,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
worker,
|
||||
main_module,
|
||||
test_event_receiver,
|
||||
|
|
|
@ -29,12 +29,12 @@ use deno_core::unsync::future::SharedLocal;
|
|||
use deno_graph::ModuleGraph;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_lint::diagnostic::LintDiagnostic;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use log::debug;
|
||||
use reporters::create_reporter;
|
||||
use reporters::LintReporter;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::CliTsConfigResolver;
|
||||
use crate::args::Flags;
|
||||
use crate::args::LintFlags;
|
||||
use crate::args::LintOptions;
|
||||
|
@ -90,7 +90,7 @@ pub async fn lint(
|
|||
let cli_options = factory.cli_options()?;
|
||||
let lint_rule_provider = factory.lint_rule_provider().await?;
|
||||
let is_stdin = lint_flags.is_stdin();
|
||||
let tsconfig_resolver = factory.tsconfig_resolver()?;
|
||||
let compiler_options_resolver = factory.compiler_options_resolver()?;
|
||||
let workspace_lint_options =
|
||||
cli_options.resolve_workspace_lint_options(&lint_flags)?;
|
||||
let success = if is_stdin {
|
||||
|
@ -99,14 +99,14 @@ pub async fn lint(
|
|||
lint_rule_provider,
|
||||
workspace_lint_options,
|
||||
lint_flags,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
)?
|
||||
} else {
|
||||
let mut linter = WorkspaceLinter::new(
|
||||
factory.caches()?.clone(),
|
||||
lint_rule_provider,
|
||||
factory.module_graph_creator().await?.clone(),
|
||||
tsconfig_resolver.clone(),
|
||||
compiler_options_resolver.clone(),
|
||||
cli_options.start_dir.clone(),
|
||||
&workspace_lint_options,
|
||||
);
|
||||
|
@ -165,7 +165,7 @@ async fn lint_with_watch_inner(
|
|||
factory.caches()?.clone(),
|
||||
factory.lint_rule_provider().await?,
|
||||
factory.module_graph_creator().await?.clone(),
|
||||
factory.tsconfig_resolver()?.clone(),
|
||||
factory.compiler_options_resolver()?.clone(),
|
||||
cli_options.start_dir.clone(),
|
||||
&cli_options.resolve_workspace_lint_options(&lint_flags)?,
|
||||
);
|
||||
|
@ -245,7 +245,7 @@ struct WorkspaceLinter {
|
|||
caches: Arc<Caches>,
|
||||
lint_rule_provider: LintRuleProvider,
|
||||
module_graph_creator: Arc<ModuleGraphCreator>,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
workspace_dir: Arc<WorkspaceDirectory>,
|
||||
reporter_lock: Arc<Mutex<Box<dyn LintReporter + Send>>>,
|
||||
workspace_module_graph: Option<WorkspaceModuleGraphFuture>,
|
||||
|
@ -258,7 +258,7 @@ impl WorkspaceLinter {
|
|||
caches: Arc<Caches>,
|
||||
lint_rule_provider: LintRuleProvider,
|
||||
module_graph_creator: Arc<ModuleGraphCreator>,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
workspace_dir: Arc<WorkspaceDirectory>,
|
||||
workspace_options: &WorkspaceLintOptions,
|
||||
) -> Self {
|
||||
|
@ -268,7 +268,7 @@ impl WorkspaceLinter {
|
|||
caches,
|
||||
lint_rule_provider,
|
||||
module_graph_creator,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
workspace_dir,
|
||||
reporter_lock,
|
||||
workspace_module_graph: None,
|
||||
|
@ -341,7 +341,7 @@ impl WorkspaceLinter {
|
|||
configured_rules: lint_rules,
|
||||
fix: lint_options.fix,
|
||||
deno_lint_config: resolve_lint_config(
|
||||
&self.tsconfig_resolver,
|
||||
&self.compiler_options_resolver,
|
||||
member_dir.dir_url(),
|
||||
)?,
|
||||
maybe_plugin_runner: plugin_runner,
|
||||
|
@ -577,7 +577,7 @@ fn lint_stdin(
|
|||
lint_rule_provider: LintRuleProvider,
|
||||
workspace_lint_options: WorkspaceLintOptions,
|
||||
lint_flags: LintFlags,
|
||||
tsconfig_resolver: &CliTsConfigResolver,
|
||||
compiler_options_resolver: &CompilerOptionsResolver,
|
||||
) -> Result<bool, AnyError> {
|
||||
let start_dir = &cli_options.start_dir;
|
||||
let reporter_lock = Arc::new(Mutex::new(create_reporter(
|
||||
|
@ -586,7 +586,7 @@ fn lint_stdin(
|
|||
let lint_config = start_dir
|
||||
.to_lint_config(FilePatterns::new_with_base(start_dir.dir_path()))?;
|
||||
let deno_lint_config =
|
||||
resolve_lint_config(tsconfig_resolver, start_dir.dir_url())?;
|
||||
resolve_lint_config(compiler_options_resolver, start_dir.dir_url())?;
|
||||
let lint_options = LintOptions::resolve(lint_config, &lint_flags)?;
|
||||
let configured_rules = lint_rule_provider.resolve_lint_rules_err_empty(
|
||||
lint_options.rules,
|
||||
|
@ -654,11 +654,12 @@ fn handle_lint_result(
|
|||
}
|
||||
|
||||
fn resolve_lint_config(
|
||||
tsconfig_resolver: &CliTsConfigResolver,
|
||||
compiler_options_resolver: &CompilerOptionsResolver,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<deno_lint::linter::LintConfig, AnyError> {
|
||||
let transpile_options = &tsconfig_resolver
|
||||
.transpile_and_emit_options(specifier)?
|
||||
let transpile_options = &compiler_options_resolver
|
||||
.for_specifier(specifier)
|
||||
.transpile_options()?
|
||||
.transpile;
|
||||
Ok(deno_lint::linter::LintConfig {
|
||||
default_jsx_factory: (!transpile_options.jsx_automatic)
|
||||
|
|
|
@ -640,7 +640,7 @@ impl DepManager {
|
|||
&roots,
|
||||
crate::module_loader::PrepareModuleLoadOptions {
|
||||
is_dynamic: false,
|
||||
lib: deno_config::deno_json::TsTypeLib::DenoWindow,
|
||||
lib: deno_config::workspace::TsTypeLib::DenoWindow,
|
||||
permissions: self.permissions_container.clone(),
|
||||
ext_overwrite: None,
|
||||
allow_unknown_media_types: true,
|
||||
|
|
|
@ -121,7 +121,7 @@ pub async fn publish(
|
|||
cli_factory.parsed_source_cache().clone(),
|
||||
specifier_unfurler,
|
||||
cli_factory.sys(),
|
||||
cli_factory.tsconfig_resolver()?.clone(),
|
||||
cli_factory.compiler_options_resolver()?.clone(),
|
||||
));
|
||||
let publish_preparer = PublishPreparer::new(
|
||||
GraphDiagnosticsCollector::new(cli_factory.parsed_source_cache().clone()),
|
||||
|
|
|
@ -11,7 +11,7 @@ use deno_core::anyhow::Context;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_resolver::deno_json::TsConfigResolver;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use deno_resolver::workspace::ResolutionKind;
|
||||
use lazy_regex::Lazy;
|
||||
use sys_traits::FsMetadata;
|
||||
|
@ -37,7 +37,7 @@ pub struct ModuleContentProvider<TSys: FsMetadata + FsRead = CliSys> {
|
|||
specifier_unfurler: SpecifierUnfurler<TSys>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
sys: TSys,
|
||||
tsconfig_resolver: Arc<TsConfigResolver<TSys>>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
}
|
||||
|
||||
impl<TSys: FsMetadata + FsRead> ModuleContentProvider<TSys> {
|
||||
|
@ -45,13 +45,13 @@ impl<TSys: FsMetadata + FsRead> ModuleContentProvider<TSys> {
|
|||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
specifier_unfurler: SpecifierUnfurler<TSys>,
|
||||
sys: TSys,
|
||||
tsconfig_resolver: Arc<TsConfigResolver<TSys>>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
) -> Self {
|
||||
Self {
|
||||
specifier_unfurler,
|
||||
parsed_source_cache,
|
||||
sys,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,13 +227,10 @@ impl<TSys: FsMetadata + FsRead> ModuleContentProvider<TSys> {
|
|||
text_info: &SourceTextInfo,
|
||||
diagnostic_reporter: &mut dyn FnMut(SpecifierUnfurlerDiagnostic),
|
||||
) -> Result<JsxFolderOptions<'a>, AnyError> {
|
||||
let tsconfig_folder_info =
|
||||
self.tsconfig_resolver.folder_for_specifier(specifier);
|
||||
let jsx_config = tsconfig_folder_info
|
||||
.dir
|
||||
.to_maybe_jsx_import_source_config()?;
|
||||
let transpile_options =
|
||||
&tsconfig_folder_info.transpile_options()?.transpile;
|
||||
let compiler_options =
|
||||
self.compiler_options_resolver.for_specifier(specifier);
|
||||
let jsx_config = compiler_options.jsx_import_source_config()?;
|
||||
let transpile_options = &compiler_options.transpile_options()?.transpile;
|
||||
let jsx_runtime = if transpile_options.jsx_automatic {
|
||||
"automatic"
|
||||
} else {
|
||||
|
@ -254,7 +251,6 @@ impl<TSys: FsMetadata + FsRead> ModuleContentProvider<TSys> {
|
|||
maybe_import_source.unwrap_or_else(|| import_source.to_string())
|
||||
};
|
||||
let jsx_import_source = jsx_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.import_source.as_ref())
|
||||
.map(|jsx_import_source| {
|
||||
unfurl_import_source(
|
||||
|
@ -264,7 +260,6 @@ impl<TSys: FsMetadata + FsRead> ModuleContentProvider<TSys> {
|
|||
)
|
||||
});
|
||||
let jsx_import_source_types = jsx_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.import_source_types.as_ref())
|
||||
.map(|jsx_import_source_types| {
|
||||
unfurl_import_source(
|
||||
|
@ -289,13 +284,24 @@ mod test {
|
|||
|
||||
use deno_config::workspace::WorkspaceDiscoverStart;
|
||||
use deno_path_util::url_from_file_path;
|
||||
use deno_resolver::factory::WorkspaceDirectoryProvider;
|
||||
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
|
||||
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::npm::NpmResolverCreateOptions;
|
||||
use deno_resolver::workspace::WorkspaceResolver;
|
||||
use node_resolver::cache::NodeResolutionSys;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolver;
|
||||
use node_resolver::NodeResolverOptions;
|
||||
use node_resolver::PackageJsonResolver;
|
||||
use pretty_assertions::assert_eq;
|
||||
use sys_traits::impls::InMemorySys;
|
||||
use sys_traits::FsCreateDirAll;
|
||||
use sys_traits::FsWrite;
|
||||
|
||||
use super::*;
|
||||
use crate::npm::CliNpmResolver;
|
||||
|
||||
#[test]
|
||||
fn test_module_content_jsx() {
|
||||
|
@ -409,15 +415,32 @@ mod test {
|
|||
.unwrap(),
|
||||
);
|
||||
let specifier_unfurler = SpecifierUnfurler::new(resolver, false);
|
||||
let tsconfig_resolver = Arc::new(TsConfigResolver::from_workspace(
|
||||
let package_json_resolver =
|
||||
Arc::new(PackageJsonResolver::new(sys.clone(), None));
|
||||
let node_resolver = NodeResolver::new(
|
||||
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Byonm),
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver::new(NpmResolverCreateOptions::Byonm(
|
||||
ByonmNpmResolverCreateOptions {
|
||||
root_node_modules_dir: None,
|
||||
sys: NodeResolutionSys::new(sys.clone(), None),
|
||||
pkg_json_resolver: package_json_resolver.clone(),
|
||||
},
|
||||
)),
|
||||
package_json_resolver,
|
||||
NodeResolutionSys::new(sys.clone(), None),
|
||||
NodeResolverOptions::default(),
|
||||
);
|
||||
let compiler_options_resolver = Arc::new(CompilerOptionsResolver::new(
|
||||
&sys,
|
||||
&workspace_dir.workspace,
|
||||
&WorkspaceDirectoryProvider::from_initial_dir(&Arc::new(workspace_dir)),
|
||||
&node_resolver,
|
||||
));
|
||||
ModuleContentProvider::new(
|
||||
Arc::new(ParsedSourceCache::default()),
|
||||
specifier_unfurler,
|
||||
sys,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ pub async fn run(
|
|||
let npm_installer = factory.npm_installer_if_managed().await?.cloned();
|
||||
let resolver = factory.resolver().await?.clone();
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let tsconfig_resolver = factory.tsconfig_resolver()?;
|
||||
let compiler_options_resolver = factory.compiler_options_resolver()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let history_file_path = factory
|
||||
.deno_dir()
|
||||
|
@ -200,7 +200,7 @@ pub async fn run(
|
|||
cli_options,
|
||||
npm_installer,
|
||||
resolver,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
worker,
|
||||
main_module.clone(),
|
||||
test_event_receiver,
|
||||
|
|
|
@ -33,6 +33,7 @@ use deno_graph::analysis::SpecifierWithRange;
|
|||
use deno_graph::Position;
|
||||
use deno_graph::PositionRange;
|
||||
use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
|
@ -43,7 +44,6 @@ use regex::Regex;
|
|||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::CliTsConfigResolver;
|
||||
use crate::cdp;
|
||||
use crate::cdp::RemoteObjectId;
|
||||
use crate::colors;
|
||||
|
@ -194,7 +194,7 @@ impl ReplSession {
|
|||
cli_options: &CliOptions,
|
||||
npm_installer: Option<Arc<CliNpmInstaller>>,
|
||||
resolver: Arc<CliResolver>,
|
||||
tsconfig_resolver: &CliTsConfigResolver,
|
||||
compiler_options_resolver: &CompilerOptionsResolver,
|
||||
mut worker: MainWorker,
|
||||
main_module: ModuleSpecifier,
|
||||
test_event_receiver: TestEventReceiver,
|
||||
|
@ -250,8 +250,9 @@ impl ReplSession {
|
|||
cli_options.initial_cwd().to_string_lossy(),
|
||||
)
|
||||
})?;
|
||||
let experimental_decorators = tsconfig_resolver
|
||||
.transpile_and_emit_options(&cwd_url)?
|
||||
let experimental_decorators = compiler_options_resolver
|
||||
.for_specifier(&cwd_url)
|
||||
.transpile_options()?
|
||||
.transpile
|
||||
.use_ts_decorators;
|
||||
let mut repl_session = ReplSession {
|
||||
|
|
|
@ -10,12 +10,14 @@ use deno_ast::MediaType;
|
|||
use deno_ast::ModuleSpecifier;
|
||||
use deno_config::deno_json;
|
||||
use deno_config::deno_json::CompilerOptionTypesDeserializeError;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_core::url::Url;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_graph::Module;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_lib::util::hash::FastInsecureHasher;
|
||||
use deno_resolver::deno_json::CompilerOptionsData;
|
||||
use deno_resolver::deno_json::CompilerOptionsResolver;
|
||||
use deno_resolver::factory::WorkspaceDirectoryProvider;
|
||||
use deno_semver::npm::NpmPackageNvReference;
|
||||
use deno_terminal::colors;
|
||||
use indexmap::IndexMap;
|
||||
|
@ -23,7 +25,6 @@ use once_cell::sync::Lazy;
|
|||
use regex::Regex;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::args::CliTsConfigResolver;
|
||||
use crate::args::CompilerOptions;
|
||||
use crate::args::DenoSubcommand;
|
||||
use crate::args::TsTypeLib;
|
||||
|
@ -106,7 +107,8 @@ pub struct TypeChecker {
|
|||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_resolver: CliNpmResolver,
|
||||
sys: CliSys,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
workspace_directory_provider: Arc<WorkspaceDirectoryProvider>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
code_cache: Option<Arc<crate::cache::CodeCache>>,
|
||||
}
|
||||
|
||||
|
@ -120,7 +122,8 @@ impl TypeChecker {
|
|||
node_resolver: Arc<CliNodeResolver>,
|
||||
npm_resolver: CliNpmResolver,
|
||||
sys: CliSys,
|
||||
tsconfig_resolver: Arc<CliTsConfigResolver>,
|
||||
workspace_directory_provider: Arc<WorkspaceDirectoryProvider>,
|
||||
compiler_options_resolver: Arc<CompilerOptionsResolver>,
|
||||
code_cache: Option<Arc<crate::cache::CodeCache>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -131,7 +134,8 @@ impl TypeChecker {
|
|||
node_resolver,
|
||||
npm_resolver,
|
||||
sys,
|
||||
tsconfig_resolver,
|
||||
workspace_directory_provider,
|
||||
compiler_options_resolver,
|
||||
code_cache,
|
||||
}
|
||||
}
|
||||
|
@ -235,13 +239,14 @@ impl TypeChecker {
|
|||
cjs_tracker: &self.cjs_tracker,
|
||||
node_resolver: &self.node_resolver,
|
||||
npm_resolver: &self.npm_resolver,
|
||||
tsconfig_resolver: &self.tsconfig_resolver,
|
||||
compiler_options_resolver: &self.compiler_options_resolver,
|
||||
log_level: self.cli_options.log_level(),
|
||||
npm_check_state_hash: check_state_hash(&self.npm_resolver),
|
||||
type_check_cache: TypeCheckCache::new(
|
||||
self.caches.type_checking_cache_db(),
|
||||
),
|
||||
grouped_roots,
|
||||
groups: grouped_roots,
|
||||
current_group_index: 0,
|
||||
options,
|
||||
seen_diagnotics: Default::default(),
|
||||
code_cache: self.code_cache.clone(),
|
||||
|
@ -256,102 +261,74 @@ impl TypeChecker {
|
|||
&'a self,
|
||||
graph: &ModuleGraph,
|
||||
lib: TsTypeLib,
|
||||
) -> Result<IndexMap<CheckGroupKey<'a>, CheckGroupInfo>, CheckError> {
|
||||
let mut imports_for_specifier: HashMap<Arc<Url>, Rc<Vec<Url>>> =
|
||||
HashMap::with_capacity(self.tsconfig_resolver.folder_count());
|
||||
let mut roots_by_config: IndexMap<_, CheckGroupInfo> =
|
||||
IndexMap::with_capacity(self.tsconfig_resolver.folder_count());
|
||||
) -> Result<Vec<CheckGroup<'a>>, CheckError> {
|
||||
let group_count = self.compiler_options_resolver.size();
|
||||
let mut imports_for_specifier = HashMap::with_capacity(group_count);
|
||||
let mut groups_by_key = IndexMap::with_capacity(group_count);
|
||||
for root in &graph.roots {
|
||||
let folder = self.tsconfig_resolver.folder_for_specifier(root);
|
||||
let imports =
|
||||
match imports_for_specifier.entry(folder.dir.dir_url().clone()) {
|
||||
std::collections::hash_map::Entry::Occupied(entry) => {
|
||||
entry.get().clone()
|
||||
}
|
||||
std::collections::hash_map::Entry::Vacant(vacant_entry) => {
|
||||
let value = Rc::new(resolve_graph_imports_for_workspace_dir(
|
||||
let compiler_options_data =
|
||||
self.compiler_options_resolver.for_specifier(root);
|
||||
let compiler_options =
|
||||
compiler_options_data.compiler_options_for_lib(lib)?;
|
||||
let imports = imports_for_specifier
|
||||
.entry(compiler_options_data.sources.last().map(|s| &s.specifier))
|
||||
.or_insert_with(|| {
|
||||
Rc::new(resolve_graph_imports_for_compiler_options_data(
|
||||
graph,
|
||||
&folder.dir,
|
||||
));
|
||||
vacant_entry.insert(value.clone());
|
||||
value
|
||||
}
|
||||
};
|
||||
let compiler_options = folder.lib_compiler_options(lib)?;
|
||||
let key = CheckGroupKey {
|
||||
compiler_options_data,
|
||||
))
|
||||
})
|
||||
.clone();
|
||||
let group_key = (compiler_options, imports.clone());
|
||||
let group = groups_by_key.entry(group_key).or_insert_with(|| {
|
||||
let dir = self.workspace_directory_provider.for_specifier(root);
|
||||
CheckGroup {
|
||||
roots: Default::default(),
|
||||
compiler_options,
|
||||
imports,
|
||||
};
|
||||
let entry = roots_by_config.entry(key);
|
||||
let entry = match entry {
|
||||
indexmap::map::Entry::Occupied(entry) => entry.into_mut(),
|
||||
indexmap::map::Entry::Vacant(entry) => entry.insert(CheckGroupInfo {
|
||||
roots: Default::default(),
|
||||
// this is slightly hacky. It's used as the referrer for resolving
|
||||
// npm imports in the key
|
||||
referrer: folder
|
||||
.dir
|
||||
referrer: self
|
||||
.workspace_directory_provider
|
||||
.for_specifier(root)
|
||||
.maybe_deno_json()
|
||||
.map(|d| d.specifier.clone())
|
||||
.unwrap_or_else(|| folder.dir.dir_url().as_ref().clone()),
|
||||
}),
|
||||
};
|
||||
entry.roots.push(root.clone());
|
||||
.unwrap_or_else(|| dir.dir_url().as_ref().clone()),
|
||||
}
|
||||
Ok(roots_by_config)
|
||||
});
|
||||
group.roots.push(root.clone());
|
||||
}
|
||||
Ok(groups_by_key.into_values().collect())
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_graph_imports_for_workspace_dir(
|
||||
/// This function assumes that 'graph imports' strictly refer to tsconfig
|
||||
/// `files` and `compilerOptions.types` which they currently do. In fact, if
|
||||
/// they were more general than that, we don't really have sufficient context to
|
||||
/// group them for type-checking.
|
||||
fn resolve_graph_imports_for_compiler_options_data(
|
||||
graph: &ModuleGraph,
|
||||
dir: &WorkspaceDirectory,
|
||||
compiler_options: &CompilerOptionsData,
|
||||
) -> Vec<Url> {
|
||||
fn resolve_graph_imports_for_referrer<'a>(
|
||||
graph: &'a ModuleGraph,
|
||||
referrer: &'a Url,
|
||||
) -> Option<impl Iterator<Item = Url> + 'a> {
|
||||
let imports = graph.imports.get(referrer)?;
|
||||
Some(
|
||||
imports
|
||||
.dependencies
|
||||
.values()
|
||||
.filter_map(|dep| dep.get_type().or_else(|| dep.get_code()))
|
||||
.map(|url| graph.resolve(url))
|
||||
.cloned(),
|
||||
)
|
||||
}
|
||||
|
||||
let root_deno_json = dir.workspace.root_deno_json();
|
||||
let member_deno_json = dir.maybe_deno_json().filter(|c| {
|
||||
Some(&c.specifier) != root_deno_json.as_ref().map(|c| &c.specifier)
|
||||
});
|
||||
let mut specifiers = root_deno_json
|
||||
.map(|c| resolve_graph_imports_for_referrer(graph, &c.specifier))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.chain(
|
||||
member_deno_json
|
||||
.map(|c| resolve_graph_imports_for_referrer(graph, &c.specifier))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flatten(),
|
||||
)
|
||||
let mut specifiers = compiler_options
|
||||
.sources
|
||||
.iter()
|
||||
.map(|s| &s.specifier)
|
||||
.filter_map(|s| graph.imports.get(s))
|
||||
.flat_map(|i| i.dependencies.values())
|
||||
.filter_map(|d| Some(graph.resolve(d.get_type().or_else(|| d.get_code())?)))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
specifiers.sort();
|
||||
specifiers
|
||||
}
|
||||
|
||||
/// Key to use to group roots together by config.
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
struct CheckGroupKey<'a> {
|
||||
compiler_options: &'a Arc<CompilerOptions>,
|
||||
imports: Rc<Vec<Url>>,
|
||||
}
|
||||
|
||||
struct CheckGroupInfo {
|
||||
#[derive(Debug)]
|
||||
struct CheckGroup<'a> {
|
||||
roots: Vec<Url>,
|
||||
imports: Rc<Vec<Url>>,
|
||||
referrer: Url,
|
||||
compiler_options: &'a Arc<CompilerOptions>,
|
||||
}
|
||||
|
||||
pub struct DiagnosticsByFolderIterator<'a>(
|
||||
|
@ -390,9 +367,10 @@ struct DiagnosticsByFolderRealIterator<'a> {
|
|||
cjs_tracker: &'a Arc<TypeCheckingCjsTracker>,
|
||||
node_resolver: &'a Arc<CliNodeResolver>,
|
||||
npm_resolver: &'a CliNpmResolver,
|
||||
tsconfig_resolver: &'a CliTsConfigResolver,
|
||||
compiler_options_resolver: &'a CompilerOptionsResolver,
|
||||
type_check_cache: TypeCheckCache,
|
||||
grouped_roots: IndexMap<CheckGroupKey<'a>, CheckGroupInfo>,
|
||||
groups: Vec<CheckGroup<'a>>,
|
||||
current_group_index: usize,
|
||||
log_level: Option<log::Level>,
|
||||
npm_check_state_hash: Option<u64>,
|
||||
seen_diagnotics: HashSet<String>,
|
||||
|
@ -404,8 +382,9 @@ impl Iterator for DiagnosticsByFolderRealIterator<'_> {
|
|||
type Item = Result<Diagnostics, CheckError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let (group_key, group_info) = self.grouped_roots.shift_remove_index(0)?;
|
||||
let mut result = self.check_diagnostics_in_folder(&group_key, group_info);
|
||||
let check_group = self.groups.get(self.current_group_index)?;
|
||||
self.current_group_index += 1;
|
||||
let mut result = self.check_diagnostics_in_folder(check_group);
|
||||
if let Ok(diagnostics) = &mut result {
|
||||
diagnostics.retain(|d| {
|
||||
if let (Some(file_name), Some(start)) = (&d.file_name, &d.start) {
|
||||
|
@ -446,13 +425,12 @@ pub fn ambient_modules_to_regex_string(ambient_modules: &[String]) -> String {
|
|||
regex_string
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
||||
impl DiagnosticsByFolderRealIterator<'_> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::result_large_err)]
|
||||
fn check_diagnostics_in_folder(
|
||||
&self,
|
||||
group_key: &'a CheckGroupKey<'a>,
|
||||
group_info: CheckGroupInfo,
|
||||
check_group: &CheckGroup,
|
||||
) -> Result<Diagnostics, CheckError> {
|
||||
fn log_provided_roots(provided_roots: &[Url]) {
|
||||
for root in provided_roots {
|
||||
|
@ -465,23 +443,21 @@ impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
|||
}
|
||||
|
||||
// walk the graph
|
||||
let compiler_options = group_key.compiler_options;
|
||||
let mut graph_walker = GraphWalker::new(
|
||||
&self.graph,
|
||||
self.sys,
|
||||
self.node_resolver,
|
||||
self.npm_resolver,
|
||||
self.tsconfig_resolver,
|
||||
self.compiler_options_resolver,
|
||||
self.npm_check_state_hash,
|
||||
compiler_options.as_ref(),
|
||||
check_group.compiler_options,
|
||||
self.options.type_check_mode,
|
||||
);
|
||||
let mut provided_roots = group_info.roots;
|
||||
for import in group_key.imports.iter() {
|
||||
graph_walker.add_config_import(import, &group_info.referrer);
|
||||
for import in check_group.imports.iter() {
|
||||
graph_walker.add_config_import(import, &check_group.referrer);
|
||||
}
|
||||
|
||||
for root in &provided_roots {
|
||||
for root in &check_group.roots {
|
||||
graph_walker.add_root(root);
|
||||
}
|
||||
|
||||
|
@ -498,7 +474,7 @@ impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
|||
|
||||
if root_names.is_empty() {
|
||||
if missing_diagnostics.has_diagnostic() {
|
||||
log_provided_roots(&provided_roots);
|
||||
log_provided_roots(&check_group.roots);
|
||||
}
|
||||
return Ok(missing_diagnostics);
|
||||
}
|
||||
|
@ -507,18 +483,21 @@ impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
|||
// do not type check if we know this is type checked
|
||||
if let Some(check_hash) = maybe_check_hash {
|
||||
if self.type_check_cache.has_check_hash(check_hash) {
|
||||
log::debug!("Already type checked {}", group_info.referrer);
|
||||
log::debug!("Already type checked {}", &check_group.referrer);
|
||||
return Ok(Default::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// log out the roots that we're checking
|
||||
log_provided_roots(&provided_roots);
|
||||
log_provided_roots(&check_group.roots);
|
||||
|
||||
// the first root will always either be the specifier that the user provided
|
||||
// or the first specifier in a directory
|
||||
let first_root = provided_roots.remove(0);
|
||||
let first_root = check_group
|
||||
.roots
|
||||
.first()
|
||||
.expect("must be at least one root");
|
||||
|
||||
// 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
|
||||
|
@ -526,13 +505,13 @@ impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
|||
let maybe_tsbuildinfo = if self.options.reload {
|
||||
None
|
||||
} else {
|
||||
self.type_check_cache.get_tsbuildinfo(&first_root)
|
||||
self.type_check_cache.get_tsbuildinfo(first_root)
|
||||
};
|
||||
// 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
|
||||
// that data here.
|
||||
let compiler_options_hash_data = FastInsecureHasher::new_deno_versioned()
|
||||
.write_hashable(compiler_options)
|
||||
.write_hashable(check_group.compiler_options)
|
||||
.finish();
|
||||
let code_cache = self.code_cache.as_ref().map(|c| {
|
||||
let c: Arc<dyn deno_runtime::code_cache::CodeCache> = c.clone();
|
||||
|
@ -540,7 +519,7 @@ impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
|||
});
|
||||
let response = tsc::exec(
|
||||
tsc::Request {
|
||||
config: compiler_options.clone(),
|
||||
config: check_group.compiler_options.clone(),
|
||||
debug: self.log_level == Some(log::Level::Debug),
|
||||
graph: self.graph.clone(),
|
||||
hash_data: compiler_options_hash_data,
|
||||
|
@ -586,7 +565,7 @@ impl<'a> DiagnosticsByFolderRealIterator<'a> {
|
|||
if let Some(tsbuildinfo) = response.maybe_tsbuildinfo {
|
||||
self
|
||||
.type_check_cache
|
||||
.set_tsbuildinfo(&first_root, &tsbuildinfo);
|
||||
.set_tsbuildinfo(first_root, &tsbuildinfo);
|
||||
}
|
||||
|
||||
if !diagnostics.has_diagnostic() {
|
||||
|
@ -641,7 +620,7 @@ struct GraphWalker<'a> {
|
|||
sys: &'a CliSys,
|
||||
node_resolver: &'a CliNodeResolver,
|
||||
npm_resolver: &'a CliNpmResolver,
|
||||
tsconfig_resolver: &'a CliTsConfigResolver,
|
||||
compiler_options_resolver: &'a CompilerOptionsResolver,
|
||||
maybe_hasher: Option<FastInsecureHasher>,
|
||||
seen: HashSet<&'a Url>,
|
||||
pending: VecDeque<(&'a Url, bool)>,
|
||||
|
@ -657,7 +636,7 @@ impl<'a> GraphWalker<'a> {
|
|||
sys: &'a CliSys,
|
||||
node_resolver: &'a CliNodeResolver,
|
||||
npm_resolver: &'a CliNpmResolver,
|
||||
tsconfig_resolver: &'a CliTsConfigResolver,
|
||||
compiler_options_resolver: &'a CompilerOptionsResolver,
|
||||
npm_cache_state_hash: Option<u64>,
|
||||
compiler_options: &CompilerOptions,
|
||||
type_check_mode: TypeCheckMode,
|
||||
|
@ -679,7 +658,7 @@ impl<'a> GraphWalker<'a> {
|
|||
sys,
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
tsconfig_resolver,
|
||||
compiler_options_resolver,
|
||||
maybe_hasher,
|
||||
seen: HashSet::with_capacity(
|
||||
graph.imports.len() + graph.specifiers_count(),
|
||||
|
@ -784,7 +763,14 @@ impl<'a> GraphWalker<'a> {
|
|||
Module::Wasm(module) => {
|
||||
maybe_module_dependencies = Some(&module.dependencies);
|
||||
}
|
||||
Module::Json(_) | Module::Npm(_) | Module::External(_) => {}
|
||||
Module::Json(_) | Module::Npm(_) => {}
|
||||
Module::External(module) => {
|
||||
// NPM files for `"nodeModulesDir": "manual"`.
|
||||
let media_type = MediaType::from_specifier(&module.specifier);
|
||||
if media_type.is_declaration() {
|
||||
self.roots.push((module.specifier.clone(), media_type));
|
||||
}
|
||||
}
|
||||
Module::Node(_) => {
|
||||
if !self.has_seen_node_builtin {
|
||||
self.has_seen_node_builtin = true;
|
||||
|
@ -851,8 +837,9 @@ impl<'a> GraphWalker<'a> {
|
|||
| MediaType::Cjs
|
||||
| MediaType::Jsx => {
|
||||
if self
|
||||
.tsconfig_resolver
|
||||
.check_js_for_specifier(&module.specifier)
|
||||
.compiler_options_resolver
|
||||
.for_specifier(&module.specifier)
|
||||
.check_js()
|
||||
|| has_ts_check(module.media_type, &module.source.text)
|
||||
{
|
||||
Some((module.specifier.clone(), module.media_type))
|
||||
|
|
|
@ -19,12 +19,10 @@ use serde::de::Visitor;
|
|||
use serde::Deserialize;
|
||||
use serde::Deserializer;
|
||||
use serde::Serialize;
|
||||
use serde::Serializer;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
use sys_traits::FsRead;
|
||||
use thiserror::Error;
|
||||
use ts::parse_compiler_options;
|
||||
use url::Url;
|
||||
|
||||
use crate::glob::FilePatterns;
|
||||
|
@ -34,6 +32,7 @@ use crate::UrlToFilePathError;
|
|||
|
||||
mod ts;
|
||||
|
||||
pub use ts::parse_compiler_options;
|
||||
pub use ts::CompilerOptions;
|
||||
pub use ts::EmitConfigOptions;
|
||||
pub use ts::IgnoredCompilerOptions;
|
||||
|
@ -1887,123 +1886,12 @@ impl ConfigFile {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents the "default" type library that should be used when type
|
||||
/// checking the code in the module graph. Note that a user provided config
|
||||
/// of `"lib"` would override this value.
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub enum TsTypeLib {
|
||||
DenoWindow,
|
||||
DenoWorker,
|
||||
}
|
||||
|
||||
impl Default for TsTypeLib {
|
||||
fn default() -> Self {
|
||||
Self::DenoWindow
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TsTypeLib {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let value = match self {
|
||||
Self::DenoWindow => {
|
||||
vec!["deno.window".to_string(), "deno.unstable".to_string()]
|
||||
}
|
||||
Self::DenoWorker => {
|
||||
vec!["deno.worker".to_string(), "deno.unstable".to_string()]
|
||||
}
|
||||
};
|
||||
Serialize::serialize(&value, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// An enum that represents the base tsc configuration to return.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum CompilerOptionsType {
|
||||
/// Return a configuration for bundling, using swc to emit the bundle. This is
|
||||
/// independent of type checking.
|
||||
Bundle,
|
||||
/// Return a configuration to use tsc to type check. This
|
||||
/// is independent of either bundling or emitting via swc.
|
||||
Check { lib: TsTypeLib },
|
||||
/// Return a configuration to use swc to emit single module files.
|
||||
Emit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CompilerOptionsWithIgnoredOptions {
|
||||
pub compiler_options: CompilerOptions,
|
||||
pub ignored_options: Vec<IgnoredCompilerOptions>,
|
||||
}
|
||||
|
||||
/// For a given configuration type get the starting point CompilerOptions
|
||||
/// used that can then be merged with user specified options.
|
||||
pub fn get_base_compiler_options_for_emit(
|
||||
config_type: CompilerOptionsType,
|
||||
) -> CompilerOptions {
|
||||
match config_type {
|
||||
CompilerOptionsType::Bundle => CompilerOptions::new(json!({
|
||||
"allowImportingTsExtensions": true,
|
||||
"checkJs": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": true,
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"inlineSourceMap": false,
|
||||
"inlineSources": false,
|
||||
"sourceMap": false,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "React.createElement",
|
||||
"jsxFragmentFactory": "React.Fragment",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
})),
|
||||
CompilerOptionsType::Check { lib } => CompilerOptions::new(json!({
|
||||
"allowJs": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"checkJs": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"incremental": true,
|
||||
"jsx": "react",
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"isolatedModules": true,
|
||||
"lib": lib,
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"noImplicitOverride": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": false,
|
||||
"strict": true,
|
||||
"target": "esnext",
|
||||
"tsBuildInfoFile": "internal:///.tsbuildinfo",
|
||||
"useDefineForClassFields": true,
|
||||
})),
|
||||
CompilerOptionsType::Emit => CompilerOptions::new(json!({
|
||||
"allowImportingTsExtensions": true,
|
||||
"checkJs": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"sourceMap": false,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "React.createElement",
|
||||
"jsxFragmentFactory": "React.Fragment",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"resolveJsonModule": true,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
|
|
@ -28,6 +28,7 @@ use discovery::ConfigFolder;
|
|||
use discovery::DenoOrPkgJson;
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use serde_json::json;
|
||||
use sys_traits::FsMetadata;
|
||||
use sys_traits::FsRead;
|
||||
use sys_traits::FsReadDir;
|
||||
|
@ -35,12 +36,10 @@ use thiserror::Error;
|
|||
use url::Url;
|
||||
|
||||
use crate::deno_json;
|
||||
use crate::deno_json::get_base_compiler_options_for_emit;
|
||||
use crate::deno_json::BenchConfig;
|
||||
use crate::deno_json::CompilerOptionTypesDeserializeError;
|
||||
use crate::deno_json::CompilerOptions;
|
||||
use crate::deno_json::CompilerOptionsParseError;
|
||||
use crate::deno_json::CompilerOptionsType;
|
||||
use crate::deno_json::CompilerOptionsWithIgnoredOptions;
|
||||
use crate::deno_json::ConfigFile;
|
||||
use crate::deno_json::ConfigFileError;
|
||||
|
@ -1120,6 +1119,118 @@ pub struct WorkspaceDirLintConfig {
|
|||
pub files: FilePatterns,
|
||||
}
|
||||
|
||||
/// Represents the "default" type library that should be used when type
|
||||
/// checking the code in the module graph. Note that a user provided config
|
||||
/// of `"lib"` would override this value.
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub enum TsTypeLib {
|
||||
DenoWindow,
|
||||
DenoWorker,
|
||||
}
|
||||
|
||||
impl Default for TsTypeLib {
|
||||
fn default() -> Self {
|
||||
Self::DenoWindow
|
||||
}
|
||||
}
|
||||
|
||||
/// An enum that represents the base tsc configuration to return.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum CompilerOptionsType {
|
||||
/// Return a configuration for bundling, using swc to emit the bundle. This is
|
||||
/// independent of type checking.
|
||||
Bundle,
|
||||
/// Return a configuration to use tsc to type check. This
|
||||
/// is independent of either bundling or emitting via swc.
|
||||
Check { lib: TsTypeLib },
|
||||
/// Return a configuration to use swc to emit single module files.
|
||||
Emit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum CompilerOptionsSourceKind {
|
||||
DenoJson,
|
||||
TsConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompilerOptionsSource {
|
||||
pub specifier: Url,
|
||||
pub compiler_options: Option<CompilerOptions>,
|
||||
}
|
||||
|
||||
/// For a given configuration type get the starting point CompilerOptions
|
||||
/// used that can then be merged with user specified options.
|
||||
pub fn get_base_compiler_options_for_emit(
|
||||
config_type: CompilerOptionsType,
|
||||
source_kind: CompilerOptionsSourceKind,
|
||||
) -> CompilerOptions {
|
||||
match config_type {
|
||||
CompilerOptionsType::Bundle => CompilerOptions::new(json!({
|
||||
"allowImportingTsExtensions": true,
|
||||
"checkJs": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": true,
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"inlineSourceMap": false,
|
||||
"inlineSources": false,
|
||||
"sourceMap": false,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "React.createElement",
|
||||
"jsxFragmentFactory": "React.Fragment",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
})),
|
||||
CompilerOptionsType::Check { lib } => CompilerOptions::new(json!({
|
||||
"allowJs": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"checkJs": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"incremental": true,
|
||||
"jsx": "react",
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"isolatedModules": true,
|
||||
"lib": match (lib, source_kind) {
|
||||
(TsTypeLib::DenoWindow, CompilerOptionsSourceKind::DenoJson) => vec!["deno.window", "deno.unstable"],
|
||||
(TsTypeLib::DenoWindow, CompilerOptionsSourceKind::TsConfig) => vec!["deno.window", "deno.unstable", "dom"],
|
||||
(TsTypeLib::DenoWorker, CompilerOptionsSourceKind::DenoJson) => vec!["deno.worker", "deno.unstable"],
|
||||
(TsTypeLib::DenoWorker, CompilerOptionsSourceKind::TsConfig) => vec!["deno.worker", "deno.unstable", "dom"],
|
||||
},
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"noImplicitOverride": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": false,
|
||||
"strict": true,
|
||||
"target": "esnext",
|
||||
"tsBuildInfoFile": "internal:///.tsbuildinfo",
|
||||
"useDefineForClassFields": true,
|
||||
})),
|
||||
CompilerOptionsType::Emit => CompilerOptions::new(json!({
|
||||
"allowImportingTsExtensions": true,
|
||||
"checkJs": false,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"sourceMap": false,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "React.createElement",
|
||||
"jsxFragmentFactory": "React.Fragment",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"resolveJsonModule": true,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WorkspaceDirectory {
|
||||
pub workspace: WorkspaceRc,
|
||||
|
@ -1422,8 +1533,10 @@ impl WorkspaceDirectory {
|
|||
sys: &TSys,
|
||||
config_type: CompilerOptionsType,
|
||||
) -> Result<CompilerOptionsWithIgnoredOptions, CompilerOptionsParseError> {
|
||||
let mut base_compiler_options =
|
||||
get_base_compiler_options_for_emit(config_type);
|
||||
let mut base_compiler_options = get_base_compiler_options_for_emit(
|
||||
config_type,
|
||||
CompilerOptionsSourceKind::DenoJson,
|
||||
);
|
||||
let CompilerOptionsWithIgnoredOptions {
|
||||
compiler_options,
|
||||
ignored_options,
|
||||
|
@ -1449,6 +1562,38 @@ impl WorkspaceDirectory {
|
|||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Gets a list of raw compiler options that the user provided, in a vec of
|
||||
/// size 0-2 based on `[maybe_root, maybe_member].flatten()`.
|
||||
pub fn to_configured_compiler_options_sources(
|
||||
&self,
|
||||
) -> Vec<CompilerOptionsSource> {
|
||||
let Some(deno_json) = self.deno_json.as_ref() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let root = deno_json.root.as_ref().map(|d| CompilerOptionsSource {
|
||||
specifier: d.specifier.clone(),
|
||||
compiler_options: d
|
||||
.json
|
||||
.compiler_options
|
||||
.as_ref()
|
||||
.filter(|v| !v.is_null())
|
||||
.cloned()
|
||||
.map(CompilerOptions),
|
||||
});
|
||||
let member = CompilerOptionsSource {
|
||||
specifier: deno_json.member.specifier.clone(),
|
||||
compiler_options: deno_json
|
||||
.member
|
||||
.json
|
||||
.compiler_options
|
||||
.as_ref()
|
||||
.filter(|v| !v.is_null())
|
||||
.cloned()
|
||||
.map(CompilerOptions),
|
||||
};
|
||||
root.into_iter().chain([member]).collect()
|
||||
}
|
||||
|
||||
/// Gets the combined compiler options that the user provided, without any of
|
||||
/// Deno's defaults. Use `to_resolved_compiler_options()` to get the resolved
|
||||
/// config instead.
|
||||
|
@ -3019,7 +3164,7 @@ pub mod test {
|
|||
.to_resolved_compiler_options(
|
||||
&sys,
|
||||
CompilerOptionsType::Check {
|
||||
lib: deno_json::TsTypeLib::DenoWindow
|
||||
lib: TsTypeLib::DenoWindow
|
||||
}
|
||||
)
|
||||
.unwrap(),
|
||||
|
|
|
@ -44,6 +44,7 @@ futures.workspace = true
|
|||
http = { workspace = true, optional = true }
|
||||
import_map.workspace = true
|
||||
indexmap.workspace = true
|
||||
jsonc-parser.workspace = true
|
||||
log.workspace = true
|
||||
node_resolver.workspace = true
|
||||
once_cell.workspace = true
|
||||
|
|
|
@ -13,7 +13,7 @@ type UrlRc = crate::sync::MaybeArc<Url>;
|
|||
/// The root directory is considered "unscoped" so values that
|
||||
/// fall outside the other directories land here (ex. remote modules).
|
||||
pub struct FolderScopedMap<TValue> {
|
||||
unscoped: TValue,
|
||||
pub unscoped: TValue,
|
||||
scoped: BTreeMap<UrlRc, TValue>,
|
||||
}
|
||||
|
||||
|
@ -64,9 +64,41 @@ impl<TValue> FolderScopedMap<TValue> {
|
|||
.unwrap_or(&self.unscoped)
|
||||
}
|
||||
|
||||
pub fn entry_for_specifier(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
) -> (Option<&UrlRc>, &TValue) {
|
||||
self
|
||||
.scoped
|
||||
.iter()
|
||||
.rfind(|(s, _)| specifier.as_str().starts_with(s.as_str()))
|
||||
.map(|(s, v)| (Some(s), v))
|
||||
.unwrap_or((None, &self.unscoped))
|
||||
}
|
||||
|
||||
pub fn entries(&self) -> impl Iterator<Item = (Option<&UrlRc>, &TValue)> {
|
||||
[(None, &self.unscoped)]
|
||||
.into_iter()
|
||||
.chain(self.scoped.iter().map(|(s, v)| (Some(s), v)))
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, dir_url: UrlRc, value: TValue) {
|
||||
debug_assert!(dir_url.path().ends_with("/")); // must be a dir url
|
||||
debug_assert_eq!(dir_url.scheme(), "file");
|
||||
self.scoped.insert(dir_url, value);
|
||||
}
|
||||
|
||||
pub fn try_map<B, E>(
|
||||
&self,
|
||||
mut f: impl FnMut(&TValue) -> Result<B, E>,
|
||||
) -> Result<FolderScopedMap<B>, E> {
|
||||
Ok(FolderScopedMap {
|
||||
unscoped: f(&self.unscoped)?,
|
||||
scoped: self
|
||||
.scoped
|
||||
.iter()
|
||||
.map(|(s, v)| Ok((s.clone(), f(v)?)))
|
||||
.collect::<Result<_, _>>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,37 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_config::deno_json::parse_compiler_options;
|
||||
use deno_config::deno_json::CompilerOptions;
|
||||
use deno_config::deno_json::CompilerOptionsParseError;
|
||||
use deno_config::deno_json::CompilerOptionsType;
|
||||
use deno_config::deno_json::CompilerOptionsWithIgnoredOptions;
|
||||
use deno_config::deno_json::TsTypeLib;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_config::glob::PathOrPatternSet;
|
||||
use deno_config::workspace::get_base_compiler_options_for_emit;
|
||||
use deno_config::workspace::CompilerOptionsSource;
|
||||
use deno_config::workspace::CompilerOptionsSourceKind;
|
||||
use deno_config::workspace::CompilerOptionsType;
|
||||
use deno_config::workspace::JsxImportSourceConfig;
|
||||
use deno_config::workspace::JsxImportSourceSpecifierConfig;
|
||||
use deno_config::workspace::ToMaybeJsxImportSourceConfigError;
|
||||
use deno_config::workspace::TsTypeLib;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_path_util::url_from_file_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_terminal::colors;
|
||||
use deno_unsync::sync::AtomicFlag;
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::NodeResolver;
|
||||
use node_resolver::ResolutionMode;
|
||||
#[cfg(feature = "sync")]
|
||||
use once_cell::sync::OnceCell;
|
||||
#[cfg(not(feature = "sync"))]
|
||||
|
@ -16,21 +40,17 @@ use sys_traits::FsRead;
|
|||
use url::Url;
|
||||
|
||||
use crate::collections::FolderScopedMap;
|
||||
use crate::factory::WorkspaceRc;
|
||||
use crate::factory::WorkspaceDirectoryProvider;
|
||||
use crate::npm::DenoInNpmPackageChecker;
|
||||
use crate::npm::NpmResolver;
|
||||
use crate::npm::NpmResolverSys;
|
||||
use crate::sync::new_rc;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type TsConfigResolverRc<TSys> =
|
||||
crate::sync::MaybeArc<TsConfigResolver<TSys>>;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type CompilerOptionsRc = crate::sync::MaybeArc<CompilerOptions>;
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type LoggedWarningsRc = crate::sync::MaybeArc<LoggedWarnings>;
|
||||
#[cfg(feature = "deno_ast")]
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type TranspileAndEmitOptionsRc =
|
||||
crate::sync::MaybeArc<TranspileAndEmitOptions>;
|
||||
pub type CompilerOptionsTypesRc =
|
||||
crate::sync::MaybeArc<Vec<(Url, Vec<String>)>>;
|
||||
|
||||
#[cfg(feature = "deno_ast")]
|
||||
#[derive(Debug)]
|
||||
|
@ -41,12 +61,20 @@ pub struct TranspileAndEmitOptions {
|
|||
pub pre_computed_hash: u64,
|
||||
}
|
||||
|
||||
#[cfg(feature = "deno_ast")]
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type TranspileAndEmitOptionsRc =
|
||||
crate::sync::MaybeArc<TranspileAndEmitOptions>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct LoggedWarnings {
|
||||
experimental_decorators: AtomicFlag,
|
||||
folders: crate::sync::MaybeDashSet<Url>,
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type LoggedWarningsRc = crate::sync::MaybeArc<LoggedWarnings>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct MemoizedValues {
|
||||
deno_window_check_compiler_options: OnceCell<CompilerOptionsRc>,
|
||||
|
@ -54,55 +82,87 @@ struct MemoizedValues {
|
|||
emit_compiler_options: OnceCell<CompilerOptionsRc>,
|
||||
#[cfg(feature = "deno_ast")]
|
||||
transpile_options: OnceCell<TranspileAndEmitOptionsRc>,
|
||||
compiler_options_types: OnceCell<CompilerOptionsTypesRc>,
|
||||
jsx_import_source_config: OnceCell<Option<JsxImportSourceConfigRc>>,
|
||||
check_js: OnceCell<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TsConfigFolderInfo<TSys: FsRead> {
|
||||
pub dir: WorkspaceDirectory,
|
||||
logged_warnings: LoggedWarningsRc,
|
||||
pub struct CompilerOptionsData {
|
||||
pub sources: Vec<CompilerOptionsSource>,
|
||||
source_kind: CompilerOptionsSourceKind,
|
||||
memoized: MemoizedValues,
|
||||
sys: TSys,
|
||||
logged_warnings: LoggedWarningsRc,
|
||||
}
|
||||
|
||||
impl<TSys: FsRead> TsConfigFolderInfo<TSys> {
|
||||
pub fn lib_compiler_options(
|
||||
impl CompilerOptionsData {
|
||||
fn new(
|
||||
sources: Vec<CompilerOptionsSource>,
|
||||
source_kind: CompilerOptionsSourceKind,
|
||||
logged_warnings: LoggedWarningsRc,
|
||||
) -> Self {
|
||||
Self {
|
||||
sources,
|
||||
source_kind,
|
||||
memoized: Default::default(),
|
||||
logged_warnings,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compiler_options_for_lib(
|
||||
&self,
|
||||
lib: TsTypeLib,
|
||||
) -> Result<&CompilerOptionsRc, CompilerOptionsParseError> {
|
||||
let cell = match lib {
|
||||
TsTypeLib::DenoWindow => {
|
||||
&self.memoized.deno_window_check_compiler_options
|
||||
}
|
||||
TsTypeLib::DenoWorker => {
|
||||
&self.memoized.deno_worker_check_compiler_options
|
||||
}
|
||||
};
|
||||
|
||||
cell.get_or_try_init(|| {
|
||||
let compiler_options_result = self.dir.to_resolved_compiler_options(
|
||||
&self.sys,
|
||||
CompilerOptionsType::Check { lib },
|
||||
)?;
|
||||
check_warn_compiler_options(
|
||||
&compiler_options_result,
|
||||
&self.logged_warnings,
|
||||
);
|
||||
Ok(new_rc(compiler_options_result.compiler_options))
|
||||
})
|
||||
self.compiler_options_inner(CompilerOptionsType::Check { lib })
|
||||
}
|
||||
|
||||
pub fn emit_compiler_options(
|
||||
pub fn compiler_options_for_emit(
|
||||
&self,
|
||||
) -> Result<&CompilerOptionsRc, CompilerOptionsParseError> {
|
||||
self.memoized.emit_compiler_options.get_or_try_init(|| {
|
||||
let compiler_options_result = self
|
||||
.dir
|
||||
.to_resolved_compiler_options(&self.sys, CompilerOptionsType::Emit)?;
|
||||
check_warn_compiler_options(
|
||||
&compiler_options_result,
|
||||
&self.logged_warnings,
|
||||
);
|
||||
Ok(new_rc(compiler_options_result.compiler_options))
|
||||
self.compiler_options_inner(CompilerOptionsType::Emit)
|
||||
}
|
||||
|
||||
fn compiler_options_inner(
|
||||
&self,
|
||||
typ: CompilerOptionsType,
|
||||
) -> Result<&CompilerOptionsRc, CompilerOptionsParseError> {
|
||||
let cell = match typ {
|
||||
CompilerOptionsType::Bundle => unreachable!(),
|
||||
CompilerOptionsType::Check {
|
||||
lib: TsTypeLib::DenoWindow,
|
||||
} => &self.memoized.deno_window_check_compiler_options,
|
||||
CompilerOptionsType::Check {
|
||||
lib: TsTypeLib::DenoWorker,
|
||||
} => &self.memoized.deno_worker_check_compiler_options,
|
||||
CompilerOptionsType::Emit => &self.memoized.emit_compiler_options,
|
||||
};
|
||||
cell.get_or_try_init(|| {
|
||||
let mut result = CompilerOptionsWithIgnoredOptions {
|
||||
compiler_options: get_base_compiler_options_for_emit(
|
||||
typ,
|
||||
self.source_kind,
|
||||
),
|
||||
ignored_options: Vec::new(),
|
||||
};
|
||||
for source in &self.sources {
|
||||
let Some(compiler_options) = source.compiler_options.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
let object = serde_json::from_value(compiler_options.0.clone())
|
||||
.map_err(|err| CompilerOptionsParseError {
|
||||
specifier: source.specifier.clone(),
|
||||
source: err,
|
||||
})?;
|
||||
let parsed = parse_compiler_options(object, Some(&source.specifier));
|
||||
result.compiler_options.merge_object_mut(parsed.options);
|
||||
if let Some(ignored) = parsed.maybe_ignored {
|
||||
result.ignored_options.push(ignored);
|
||||
}
|
||||
}
|
||||
if self.source_kind != CompilerOptionsSourceKind::TsConfig {
|
||||
check_warn_compiler_options(&result, &self.logged_warnings);
|
||||
}
|
||||
Ok(new_rc(result.compiler_options))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -111,109 +171,601 @@ impl<TSys: FsRead> TsConfigFolderInfo<TSys> {
|
|||
&self,
|
||||
) -> Result<&TranspileAndEmitOptionsRc, CompilerOptionsParseError> {
|
||||
self.memoized.transpile_options.get_or_try_init(|| {
|
||||
let compiler_options = self.emit_compiler_options()?;
|
||||
let compiler_options = self.compiler_options_for_emit()?;
|
||||
compiler_options_to_transpile_and_emit_options(
|
||||
compiler_options.as_ref().clone(),
|
||||
)
|
||||
.map(new_rc)
|
||||
.map_err(|source| CompilerOptionsParseError {
|
||||
specifier: self
|
||||
.dir
|
||||
.maybe_deno_json()
|
||||
.map(|d| d.specifier.clone())
|
||||
.unwrap_or_else(|| {
|
||||
// will never happen because each dir should have a
|
||||
// deno.json if we got here
|
||||
debug_assert!(false);
|
||||
self.dir.dir_url().as_ref().clone()
|
||||
}),
|
||||
specifier: self.sources.last().map(|s| s.specifier.clone()).expect(
|
||||
"Compiler options parse errors must come from a user source.",
|
||||
),
|
||||
source,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compiler_options_types(&self) -> &CompilerOptionsTypesRc {
|
||||
self.memoized.compiler_options_types.get_or_init(|| {
|
||||
let types = self
|
||||
.sources
|
||||
.iter()
|
||||
.filter_map(|s| {
|
||||
let types = s
|
||||
.compiler_options
|
||||
.as_ref()?
|
||||
.0
|
||||
.as_object()?
|
||||
.get("types")?
|
||||
.as_array()?
|
||||
.iter()
|
||||
.filter_map(|v| Some(v.as_str()?.to_string()))
|
||||
.collect();
|
||||
Some((s.specifier.clone(), types))
|
||||
})
|
||||
.collect();
|
||||
new_rc(types)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn jsx_import_source_config(
|
||||
&self,
|
||||
) -> Result<Option<&JsxImportSourceConfigRc>, ToMaybeJsxImportSourceConfigError>
|
||||
{
|
||||
self.memoized.jsx_import_source_config.get_or_try_init(|| {
|
||||
let jsx = self.sources.iter().rev().find_map(|s| Some((s.compiler_options.as_ref()?.0.as_object()?.get("jsx")?.as_str()?, &s.specifier)));
|
||||
let is_jsx_automatic = matches!(
|
||||
jsx,
|
||||
Some(("react-jsx" | "preserve" | "react-jsxdev" | "precompile", _)),
|
||||
);
|
||||
let import_source = self.sources.iter().rev().find_map(|s| {
|
||||
Some(JsxImportSourceSpecifierConfig {
|
||||
specifier: s.compiler_options.as_ref()?.0.as_object()?.get("jsxImportSource")?.as_str()?.to_string(),
|
||||
base: s.specifier.clone()
|
||||
})
|
||||
}).or_else(|| {
|
||||
if !is_jsx_automatic {
|
||||
return None;
|
||||
}
|
||||
Some(JsxImportSourceSpecifierConfig {
|
||||
base: self.sources.last()?.specifier.clone(),
|
||||
specifier: "react".to_string()
|
||||
})
|
||||
});
|
||||
let import_source_types = self.sources.iter().rev().find_map(|s| {
|
||||
Some(JsxImportSourceSpecifierConfig {
|
||||
specifier: s.compiler_options.as_ref()?.0.as_object()?.get("jsxImportSourceTypes")?.as_str()?.to_string(),
|
||||
base: s.specifier.clone()
|
||||
})
|
||||
}).or_else(|| import_source.clone());
|
||||
let module = match jsx {
|
||||
Some(("react-jsx" | "preserve", _)) => "jsx-runtime".to_string(),
|
||||
Some(("react-jsxdev", _)) => "jsx-dev-runtime".to_string(),
|
||||
Some(("react", _)) | None => {
|
||||
if let Some(import_source) = &import_source {
|
||||
return Err(
|
||||
ToMaybeJsxImportSourceConfigError::InvalidJsxImportSourceValue(
|
||||
import_source.base.clone(),
|
||||
),
|
||||
);
|
||||
}
|
||||
if let Some(import_source_types) = &import_source_types {
|
||||
return Err(
|
||||
ToMaybeJsxImportSourceConfigError::InvalidJsxImportSourceTypesValue(
|
||||
import_source_types.base.clone(),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
Some(("precompile", _)) => "jsx-runtime".to_string(),
|
||||
Some((setting, setting_source)) => {
|
||||
return Err(
|
||||
ToMaybeJsxImportSourceConfigError::InvalidJsxCompilerOption {
|
||||
value: setting.to_string(),
|
||||
specifier: setting_source.clone(),
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
Ok(Some(new_rc(JsxImportSourceConfig {
|
||||
module,
|
||||
import_source,
|
||||
import_source_types,
|
||||
})))
|
||||
}).map(|c| c.as_ref())
|
||||
}
|
||||
|
||||
pub fn check_js(&self) -> bool {
|
||||
*self.memoized.check_js.get_or_init(|| {
|
||||
self
|
||||
.sources
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|s| {
|
||||
s.compiler_options
|
||||
.as_ref()?
|
||||
.0
|
||||
.as_object()?
|
||||
.get("checkJs")?
|
||||
.as_bool()
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A resolved element of the `files` array in a tsconfig.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TsConfigFile {
|
||||
pub relative_specifier: String,
|
||||
pub absolute_path: PathBuf,
|
||||
}
|
||||
|
||||
impl TsConfigFile {
|
||||
fn from_raw(raw: &str, dir_path: impl AsRef<Path>) -> Self {
|
||||
let relative_specifier = if raw.starts_with("./")
|
||||
|| raw.starts_with("../")
|
||||
|| raw.starts_with('/')
|
||||
{
|
||||
raw.to_string()
|
||||
} else {
|
||||
format!("./{raw}")
|
||||
};
|
||||
let path = Path::new(raw);
|
||||
let absolute_path = if path.is_absolute() {
|
||||
normalize_path(path)
|
||||
} else {
|
||||
normalize_path(dir_path.as_ref().join(path))
|
||||
};
|
||||
Self {
|
||||
relative_specifier,
|
||||
absolute_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TsConfigFileFilter {
|
||||
// Note that `files`, `include` and `exclude` are overwritten, not merged,
|
||||
// when using `extends`. So we only need to store one referrer for `files`.
|
||||
// See: https://www.typescriptlang.org/tsconfig/#extends.
|
||||
files: Option<(Url, Vec<TsConfigFile>)>,
|
||||
include: Option<PathOrPatternSet>,
|
||||
exclude: Option<PathOrPatternSet>,
|
||||
dir_path: PathBuf,
|
||||
}
|
||||
|
||||
impl TsConfigFileFilter {
|
||||
fn includes_path(&self, path: impl AsRef<Path>) -> bool {
|
||||
let path = path.as_ref();
|
||||
if let Some((_, files)) = &self.files {
|
||||
if files.iter().any(|f| f.absolute_path == path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if let Some(exclude) = &self.exclude {
|
||||
if exclude.matches_path(path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(include) = &self.include {
|
||||
if include.matches_path(path) {
|
||||
return true;
|
||||
}
|
||||
} else if path.starts_with(&self.dir_path) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type TsConfigFileFilterRc = crate::sync::MaybeArc<TsConfigFileFilter>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TsConfigData {
|
||||
pub compiler_options: CompilerOptionsData,
|
||||
filter: TsConfigFileFilterRc,
|
||||
references: Vec<String>,
|
||||
}
|
||||
|
||||
impl TsConfigData {
|
||||
pub fn files(&self) -> Option<(&Url, &Vec<TsConfigFile>)> {
|
||||
let (referrer, files) = self.filter.files.as_ref()?;
|
||||
Some((referrer, files))
|
||||
}
|
||||
|
||||
fn specifier(&self) -> &Url {
|
||||
&self
|
||||
.compiler_options
|
||||
.sources
|
||||
.last()
|
||||
.expect("Tsconfigs should always have at least one source.")
|
||||
.specifier
|
||||
}
|
||||
}
|
||||
|
||||
fn is_maybe_directory_error(err: &std::io::Error) -> bool {
|
||||
let kind = err.kind();
|
||||
kind == ErrorKind::IsADirectory
|
||||
// This happens on Windows for some reason.
|
||||
|| cfg!(windows) && kind == ErrorKind::PermissionDenied
|
||||
}
|
||||
|
||||
type TsConfigNodeResolver<TSys> = NodeResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
NpmResolver<TSys>,
|
||||
TSys,
|
||||
>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TsConfigCollector<'a, TSys: FsRead, NSys: NpmResolverSys> {
|
||||
roots: BTreeSet<PathBuf>,
|
||||
collected: IndexMap<Url, Rc<TsConfigData>>,
|
||||
read_cache: HashMap<PathBuf, Result<Rc<TsConfigData>, Rc<std::io::Error>>>,
|
||||
currently_reading: IndexSet<PathBuf>,
|
||||
sys: &'a TSys,
|
||||
node_resolver: &'a TsConfigNodeResolver<NSys>,
|
||||
logged_warnings: &'a LoggedWarningsRc,
|
||||
}
|
||||
|
||||
impl<'a, TSys: FsRead, NSys: NpmResolverSys> TsConfigCollector<'a, TSys, NSys> {
|
||||
fn new(
|
||||
sys: &'a TSys,
|
||||
node_resolver: &'a TsConfigNodeResolver<NSys>,
|
||||
logged_warnings: &'a LoggedWarningsRc,
|
||||
) -> Self {
|
||||
Self {
|
||||
roots: Default::default(),
|
||||
collected: Default::default(),
|
||||
read_cache: Default::default(),
|
||||
currently_reading: Default::default(),
|
||||
sys,
|
||||
node_resolver,
|
||||
logged_warnings,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_root(&mut self, path: PathBuf) {
|
||||
self.roots.insert(path);
|
||||
}
|
||||
|
||||
fn collect(mut self) -> Vec<TsConfigData> {
|
||||
for root in std::mem::take(&mut self.roots) {
|
||||
let Ok(ts_config) = self.read_ts_config_with_cache(root) else {
|
||||
continue;
|
||||
};
|
||||
self.visit_reference(ts_config);
|
||||
}
|
||||
let Self { collected, .. } = { self };
|
||||
collected
|
||||
.into_values()
|
||||
.map(|t| {
|
||||
Rc::try_unwrap(t).expect(
|
||||
"No other references should be held since the read cache is dropped.",
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn visit_reference(&mut self, ts_config: Rc<TsConfigData>) {
|
||||
let specifier = ts_config.specifier();
|
||||
if self.collected.contains_key(specifier) {
|
||||
return;
|
||||
}
|
||||
let Some(dir_path) = url_to_file_path(specifier)
|
||||
.ok()
|
||||
.and_then(|p| Some(p.parent()?.to_path_buf()))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
for reference in &ts_config.references {
|
||||
let reference_path = Path::new(reference);
|
||||
let reference_path = if reference_path.is_absolute() {
|
||||
Cow::Borrowed(reference_path)
|
||||
} else {
|
||||
Cow::Owned(dir_path.join(reference_path))
|
||||
};
|
||||
match self.read_ts_config_with_cache(&reference_path) {
|
||||
Ok(ts_config) => self.visit_reference(ts_config),
|
||||
Err(err) if is_maybe_directory_error(&err) => {
|
||||
if let Ok(ts_config) =
|
||||
self.read_ts_config_with_cache(reference_path.join("tsconfig.json"))
|
||||
{
|
||||
self.visit_reference(ts_config)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.collected.insert(specifier.clone(), ts_config);
|
||||
}
|
||||
|
||||
fn read_ts_config_with_cache(
|
||||
&mut self,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<Rc<TsConfigData>, Rc<std::io::Error>> {
|
||||
let path = normalize_path(path.as_ref());
|
||||
self.read_cache.get(&path).cloned().unwrap_or_else(|| {
|
||||
if !self.currently_reading.insert(path.clone()) {
|
||||
return Err(Rc::new(std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Cycle detected while following `extends`.",
|
||||
)));
|
||||
}
|
||||
let result = self.read_ts_config(&path).map(Rc::new).map_err(Rc::new);
|
||||
self.currently_reading.pop();
|
||||
self.read_cache.insert(path, result.clone());
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
fn read_ts_config(
|
||||
&mut self,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<TsConfigData, std::io::Error> {
|
||||
let path = path.as_ref();
|
||||
let warn = |err: &dyn std::fmt::Display| {
|
||||
log::warn!("Failed reading {}: {}", path.display(), err);
|
||||
};
|
||||
let specifier = url_from_file_path(path)
|
||||
.inspect_err(|e| warn(e))
|
||||
.map_err(|err| std::io::Error::new(ErrorKind::InvalidInput, err))?;
|
||||
let text = self.sys.fs_read_to_string(path).inspect_err(|e| {
|
||||
if e.kind() != ErrorKind::NotFound && !is_maybe_directory_error(e) {
|
||||
warn(e)
|
||||
}
|
||||
})?;
|
||||
let value = jsonc_parser::parse_to_serde_value(&text, &Default::default())
|
||||
.inspect_err(|e| warn(e))
|
||||
.ok()
|
||||
.flatten();
|
||||
let object = value.as_ref().and_then(|v| v.as_object());
|
||||
let extends_targets = object
|
||||
.and_then(|o| o.get("extends"))
|
||||
.into_iter()
|
||||
.flat_map(|v| {
|
||||
if let Some(s) = v.as_str() {
|
||||
vec![s]
|
||||
} else if let Some(a) = v.as_array() {
|
||||
a.iter().filter_map(|v| v.as_str()).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
})
|
||||
.filter_map(|s| {
|
||||
let node_resolution = self
|
||||
.node_resolver
|
||||
.resolve(
|
||||
s,
|
||||
&specifier,
|
||||
ResolutionMode::Require,
|
||||
NodeResolutionKind::Execution,
|
||||
)
|
||||
.ok()?;
|
||||
let url = node_resolution.into_url().ok()?;
|
||||
let path = url_to_file_path(&url).ok()?;
|
||||
self.read_ts_config_with_cache(&path).ok()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let sources = extends_targets
|
||||
.iter()
|
||||
.flat_map(|t| &t.compiler_options.sources)
|
||||
.cloned()
|
||||
.chain([CompilerOptionsSource {
|
||||
specifier: specifier.clone(),
|
||||
compiler_options: object
|
||||
.and_then(|o| o.get("compilerOptions"))
|
||||
.filter(|v| !v.is_null())
|
||||
.cloned()
|
||||
.map(CompilerOptions),
|
||||
}])
|
||||
.collect();
|
||||
let dir_path = path.parent().expect("file path should have a parent");
|
||||
let files = object
|
||||
.and_then(|o| {
|
||||
let files = o
|
||||
.get("files")?
|
||||
.as_array()?
|
||||
.iter()
|
||||
.filter_map(|v| Some(TsConfigFile::from_raw(v.as_str()?, dir_path)))
|
||||
.collect();
|
||||
Some((specifier, files))
|
||||
})
|
||||
.or_else(|| {
|
||||
extends_targets
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|t| t.filter.files.clone())
|
||||
});
|
||||
let include = object
|
||||
.and_then(|o| {
|
||||
PathOrPatternSet::from_include_relative_path_or_patterns(
|
||||
dir_path,
|
||||
&o.get("include")?
|
||||
.as_array()?
|
||||
.iter()
|
||||
.filter_map(|v| Some(v.as_str()?.to_string()))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.or_else(|| {
|
||||
extends_targets
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|t| t.filter.include.clone())
|
||||
})
|
||||
.or_else(|| files.is_some().then(Default::default));
|
||||
let exclude = object
|
||||
.and_then(|o| {
|
||||
PathOrPatternSet::from_exclude_relative_path_or_patterns(
|
||||
dir_path,
|
||||
&o.get("exclude")?
|
||||
.as_array()?
|
||||
.iter()
|
||||
.filter_map(|v| Some(v.as_str()?.to_string()))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.or_else(|| {
|
||||
extends_targets
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|t| t.filter.exclude.clone())
|
||||
});
|
||||
let references = object
|
||||
.and_then(|o| o.get("references")?.as_array())
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|v| Some(v.as_object()?.get("path")?.as_str()?.to_string()))
|
||||
.collect();
|
||||
Ok(TsConfigData {
|
||||
compiler_options: CompilerOptionsData::new(
|
||||
sources,
|
||||
CompilerOptionsSourceKind::TsConfig,
|
||||
self.logged_warnings.clone(),
|
||||
),
|
||||
filter: new_rc(TsConfigFileFilter {
|
||||
files,
|
||||
include,
|
||||
exclude,
|
||||
dir_path: dir_path.to_path_buf(),
|
||||
}),
|
||||
references,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TsConfigResolver<TSys: FsRead> {
|
||||
map: FolderScopedMap<TsConfigFolderInfo<TSys>>,
|
||||
pub struct CompilerOptionsResolver {
|
||||
workspace_configs: FolderScopedMap<CompilerOptionsData>,
|
||||
ts_configs: Vec<TsConfigData>,
|
||||
}
|
||||
|
||||
impl<TSys: FsRead + Clone> TsConfigResolver<TSys> {
|
||||
pub fn from_workspace(sys: &TSys, workspace: &WorkspaceRc) -> Self {
|
||||
// separate the workspace into directories that have compiler options
|
||||
let root_dir = workspace.resolve_member_dir(workspace.root_dir());
|
||||
impl CompilerOptionsResolver {
|
||||
pub fn new<TSys: FsRead, NSys: NpmResolverSys>(
|
||||
sys: &TSys,
|
||||
workspace_directory_provider: &WorkspaceDirectoryProvider,
|
||||
node_resolver: &TsConfigNodeResolver<NSys>,
|
||||
) -> Self {
|
||||
let logged_warnings = new_rc(LoggedWarnings::default());
|
||||
let mut map = FolderScopedMap::new(TsConfigFolderInfo {
|
||||
dir: root_dir,
|
||||
logged_warnings: logged_warnings.clone(),
|
||||
memoized: Default::default(),
|
||||
sys: sys.clone(),
|
||||
});
|
||||
for (url, folder) in workspace.config_folders() {
|
||||
let folder_has_compiler_options = folder
|
||||
.deno_json
|
||||
.as_ref()
|
||||
.map(|d| d.json.compiler_options.is_some())
|
||||
.unwrap_or(false);
|
||||
if url != workspace.root_dir() && folder_has_compiler_options {
|
||||
let dir = workspace.resolve_member_dir(url);
|
||||
map.insert(
|
||||
url.clone(),
|
||||
TsConfigFolderInfo {
|
||||
dir,
|
||||
logged_warnings: logged_warnings.clone(),
|
||||
memoized: Default::default(),
|
||||
sys: sys.clone(),
|
||||
},
|
||||
let root_dir = workspace_directory_provider.root();
|
||||
let mut workspace_configs = FolderScopedMap::new(CompilerOptionsData::new(
|
||||
root_dir.to_configured_compiler_options_sources(),
|
||||
CompilerOptionsSourceKind::DenoJson,
|
||||
logged_warnings.clone(),
|
||||
));
|
||||
let mut ts_config_collector =
|
||||
TsConfigCollector::new(sys, node_resolver, &logged_warnings);
|
||||
for (dir_url, dir) in workspace_directory_provider.entries() {
|
||||
ts_config_collector.add_root(dir.dir_path().join("tsconfig.json"));
|
||||
if let Some(dir_url) = dir_url {
|
||||
workspace_configs.insert(
|
||||
dir_url.clone(),
|
||||
CompilerOptionsData::new(
|
||||
dir.to_configured_compiler_options_sources(),
|
||||
CompilerOptionsSourceKind::DenoJson,
|
||||
logged_warnings.clone(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Self { map }
|
||||
Self {
|
||||
workspace_configs,
|
||||
ts_configs: ts_config_collector.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSys: FsRead> TsConfigResolver<TSys> {
|
||||
pub fn check_js_for_specifier(&self, specifier: &Url) -> bool {
|
||||
self.folder_for_specifier(specifier).dir.check_js()
|
||||
}
|
||||
|
||||
#[cfg(feature = "deno_ast")]
|
||||
pub fn transpile_and_emit_options(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
) -> Result<&TranspileAndEmitOptionsRc, CompilerOptionsParseError> {
|
||||
let value = self.map.get_for_specifier(specifier);
|
||||
value.transpile_options()
|
||||
pub fn for_specifier(&self, specifier: &Url) -> &CompilerOptionsData {
|
||||
if let Ok(path) = url_to_file_path(specifier) {
|
||||
for ts_config in &self.ts_configs {
|
||||
if ts_config.filter.includes_path(&path) {
|
||||
return &ts_config.compiler_options;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.workspace_configs.get_for_specifier(specifier)
|
||||
}
|
||||
|
||||
pub fn folder_for_specifier(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
) -> &TsConfigFolderInfo<TSys> {
|
||||
self.folder_for_specifier_str(specifier.as_str())
|
||||
pub fn all(&self) -> impl Iterator<Item = &CompilerOptionsData> {
|
||||
self
|
||||
.workspace_configs
|
||||
.entries()
|
||||
.map(|(_, r)| r)
|
||||
.chain(self.ts_configs.iter().map(|t| &t.compiler_options))
|
||||
}
|
||||
|
||||
pub fn folder_for_specifier_str(
|
||||
&self,
|
||||
specifier: &str,
|
||||
) -> &TsConfigFolderInfo<TSys> {
|
||||
self.map.get_for_specifier_str(specifier)
|
||||
pub fn size(&self) -> usize {
|
||||
self.workspace_configs.count() + self.ts_configs.len()
|
||||
}
|
||||
|
||||
pub fn folder_count(&self) -> usize {
|
||||
self.map.count()
|
||||
pub fn ts_configs(&self) -> &Vec<TsConfigData> {
|
||||
&self.ts_configs
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
impl<TSys: FsRead + std::fmt::Debug> deno_graph::CheckJsResolver
|
||||
for TsConfigResolver<TSys>
|
||||
{
|
||||
fn resolve(&self, specifier: &deno_graph::ModuleSpecifier) -> bool {
|
||||
self.check_js_for_specifier(specifier)
|
||||
impl deno_graph::CheckJsResolver for CompilerOptionsResolver {
|
||||
fn resolve(&self, specifier: &Url) -> bool {
|
||||
self.for_specifier(specifier).check_js()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type CompilerOptionsResolverRc =
|
||||
crate::sync::MaybeArc<CompilerOptionsResolver>;
|
||||
|
||||
/// JSX config stored in `CompilerOptionsResolver`, but fallibly resolved
|
||||
/// ahead of time as needed for the graph resolver.
|
||||
#[derive(Debug)]
|
||||
pub struct JsxImportSourceConfigResolver {
|
||||
workspace_configs: FolderScopedMap<Option<JsxImportSourceConfigRc>>,
|
||||
ts_configs: Vec<(Option<JsxImportSourceConfigRc>, TsConfigFileFilterRc)>,
|
||||
}
|
||||
|
||||
impl JsxImportSourceConfigResolver {
|
||||
pub fn from_compiler_options_resolver(
|
||||
compiler_options_resolver: &CompilerOptionsResolver,
|
||||
) -> Result<Self, ToMaybeJsxImportSourceConfigError> {
|
||||
Ok(Self {
|
||||
workspace_configs: compiler_options_resolver
|
||||
.workspace_configs
|
||||
.try_map(|d| Ok(d.jsx_import_source_config()?.cloned()))?,
|
||||
ts_configs: compiler_options_resolver
|
||||
.ts_configs
|
||||
.iter()
|
||||
.map(|t| {
|
||||
Ok((
|
||||
t.compiler_options.jsx_import_source_config()?.cloned(),
|
||||
t.filter.clone(),
|
||||
))
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_specifier(
|
||||
&self,
|
||||
specifier: &Url,
|
||||
) -> Option<&JsxImportSourceConfigRc> {
|
||||
if let Ok(path) = url_to_file_path(specifier) {
|
||||
for (config, filter) in &self.ts_configs {
|
||||
if filter.includes_path(&path) {
|
||||
return config.as_ref();
|
||||
}
|
||||
}
|
||||
}
|
||||
self.workspace_configs.get_for_specifier(specifier).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type JsxImportSourceConfigRc = crate::sync::MaybeArc<JsxImportSourceConfig>;
|
||||
|
||||
#[cfg(feature = "deno_ast")]
|
||||
fn compiler_options_to_transpile_and_emit_options(
|
||||
config: deno_config::deno_json::CompilerOptions,
|
||||
|
|
|
@ -41,8 +41,9 @@ use url::Url;
|
|||
use crate::cjs::CjsTracker;
|
||||
use crate::cjs::CjsTrackerRc;
|
||||
use crate::cjs::IsCjsResolutionMode;
|
||||
use crate::deno_json::TsConfigResolver;
|
||||
use crate::deno_json::TsConfigResolverRc;
|
||||
use crate::collections::FolderScopedMap;
|
||||
use crate::deno_json::CompilerOptionsResolver;
|
||||
use crate::deno_json::CompilerOptionsResolverRc;
|
||||
use crate::import_map::WorkspaceExternalImportMapLoader;
|
||||
use crate::import_map::WorkspaceExternalImportMapLoaderRc;
|
||||
use crate::lockfile::LockfileLock;
|
||||
|
@ -83,6 +84,8 @@ type Deferred<T> = once_cell::sync::OnceCell<T>;
|
|||
#[cfg(not(feature = "sync"))]
|
||||
type Deferred<T> = once_cell::unsync::OnceCell<T>;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
type UrlRc = crate::sync::MaybeArc<Url>;
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type WorkspaceDirectoryRc = crate::sync::MaybeArc<WorkspaceDirectory>;
|
||||
#[allow(clippy::disallowed_types)]
|
||||
|
@ -254,8 +257,8 @@ pub struct WorkspaceFactory<TSys: WorkspaceFactorySys> {
|
|||
npm_cache_dir: Deferred<NpmCacheDirRc>,
|
||||
npmrc: Deferred<(ResolvedNpmRcRc, Option<PathBuf>)>,
|
||||
node_modules_dir_mode: Deferred<NodeModulesDirMode>,
|
||||
tsconfig_resolver: Deferred<TsConfigResolverRc<TSys>>,
|
||||
workspace_directory: Deferred<WorkspaceDirectoryRc>,
|
||||
workspace_directory_provider: Deferred<WorkspaceDirectoryProviderRc>,
|
||||
workspace_external_import_map_loader:
|
||||
Deferred<WorkspaceExternalImportMapLoaderRc<TSys>>,
|
||||
workspace_npm_link_packages: Deferred<WorkspaceNpmLinkPackagesRc>,
|
||||
|
@ -289,8 +292,8 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
|
|||
npm_cache_dir: Default::default(),
|
||||
npmrc: Default::default(),
|
||||
node_modules_dir_mode: Default::default(),
|
||||
tsconfig_resolver: Default::default(),
|
||||
workspace_directory: Default::default(),
|
||||
workspace_directory_provider: Default::default(),
|
||||
workspace_external_import_map_loader: Default::default(),
|
||||
workspace_npm_link_packages: Default::default(),
|
||||
initial_cwd,
|
||||
|
@ -536,17 +539,6 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn tsconfig_resolver(
|
||||
&self,
|
||||
) -> Result<&TsConfigResolverRc<TSys>, WorkspaceDiscoverError> {
|
||||
self.tsconfig_resolver.get_or_try_init(|| {
|
||||
Ok(new_rc(TsConfigResolver::from_workspace(
|
||||
self.sys(),
|
||||
&self.workspace_directory()?.workspace,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sys(&self) -> &TSys {
|
||||
&self.sys
|
||||
}
|
||||
|
@ -615,6 +607,16 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn workspace_directory_provider(
|
||||
&self,
|
||||
) -> Result<&WorkspaceDirectoryProviderRc, WorkspaceDiscoverError> {
|
||||
self.workspace_directory_provider.get_or_try_init(|| {
|
||||
Ok(new_rc(WorkspaceDirectoryProvider::from_initial_dir(
|
||||
self.workspace_directory()?,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn workspace_external_import_map_loader(
|
||||
&self,
|
||||
) -> Result<&WorkspaceExternalImportMapLoaderRc<TSys>, WorkspaceDiscoverError>
|
||||
|
@ -677,6 +679,7 @@ pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
|
|||
options: ResolverFactoryOptions,
|
||||
sys: NodeResolutionSys<TSys>,
|
||||
cjs_tracker: Deferred<CjsTrackerRc<DenoInNpmPackageChecker, TSys>>,
|
||||
compiler_options_resolver: Deferred<CompilerOptionsResolverRc>,
|
||||
#[cfg(feature = "graph")]
|
||||
deno_resolver:
|
||||
async_once_cell::OnceCell<crate::graph::DefaultDenoResolverRc<TSys>>,
|
||||
|
@ -718,6 +721,7 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
|
|||
options.node_resolution_cache.clone(),
|
||||
),
|
||||
cjs_tracker: Default::default(),
|
||||
compiler_options_resolver: Default::default(),
|
||||
raw_deno_resolver: Default::default(),
|
||||
#[cfg(feature = "graph")]
|
||||
deno_resolver: Default::default(),
|
||||
|
@ -781,6 +785,18 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn compiler_options_resolver(
|
||||
&self,
|
||||
) -> Result<&CompilerOptionsResolverRc, anyhow::Error> {
|
||||
self.compiler_options_resolver.get_or_try_init(|| {
|
||||
Ok(new_rc(CompilerOptionsResolver::new(
|
||||
&self.sys,
|
||||
self.workspace_factory.workspace_directory_provider()?,
|
||||
self.node_resolver()?,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
pub fn found_package_json_dep_flag(
|
||||
&self,
|
||||
|
@ -1012,3 +1028,64 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WorkspaceDirectoryProvider {
|
||||
pub workspace: WorkspaceRc,
|
||||
dirs: FolderScopedMap<Deferred<WorkspaceDirectoryRc>>,
|
||||
}
|
||||
|
||||
impl WorkspaceDirectoryProvider {
|
||||
pub fn from_initial_dir(dir: &WorkspaceDirectoryRc) -> Self {
|
||||
let workspace = dir.workspace.clone();
|
||||
let mut dirs = FolderScopedMap::new(Deferred::default());
|
||||
for dir_url in workspace.config_folders().keys() {
|
||||
if dir_url == workspace.root_dir() {
|
||||
continue;
|
||||
} else if dir_url == dir.dir_url() {
|
||||
dirs.insert(dir_url.clone(), Deferred::from(dir.clone()));
|
||||
} else {
|
||||
dirs.insert(dir_url.clone(), Deferred::default());
|
||||
}
|
||||
}
|
||||
Self { workspace, dirs }
|
||||
}
|
||||
|
||||
pub fn for_specifier(&self, specifier: &Url) -> &WorkspaceDirectoryRc {
|
||||
let (dir_url, dir) = self.dirs.entry_for_specifier(specifier);
|
||||
dir.get_or_init(|| {
|
||||
new_rc(
|
||||
self
|
||||
.workspace
|
||||
.resolve_member_dir(dir_url.unwrap_or(self.workspace.root_dir())),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn root(&self) -> &WorkspaceDirectoryRc {
|
||||
self.dirs.unscoped.get_or_init(|| {
|
||||
new_rc(self.workspace.resolve_member_dir(self.workspace.root_dir()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn entries(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (Option<&UrlRc>, &WorkspaceDirectoryRc)> {
|
||||
self.dirs.entries().map(|(s, d)| {
|
||||
(
|
||||
s,
|
||||
d.get_or_init(|| {
|
||||
new_rc(
|
||||
self
|
||||
.workspace
|
||||
.resolve_member_dir(s.unwrap_or(self.workspace.root_dir())),
|
||||
)
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type WorkspaceDirectoryProviderRc =
|
||||
crate::sync::MaybeArc<WorkspaceDirectoryProvider>;
|
||||
|
|
|
@ -18,9 +18,9 @@ use node_resolver::UrlOrPath;
|
|||
use url::Url;
|
||||
|
||||
use crate::cjs::CjsTracker;
|
||||
use crate::deno_json::JsxImportSourceConfigResolver;
|
||||
use crate::npm;
|
||||
use crate::workspace::MappedResolutionDiagnostic;
|
||||
use crate::workspace::ScopedJsxImportSourceConfig;
|
||||
use crate::DenoResolveError;
|
||||
use crate::DenoResolverSys;
|
||||
use crate::RawDenoResolverRc;
|
||||
|
@ -405,7 +405,7 @@ impl<
|
|||
pub fn as_graph_resolver<'a>(
|
||||
&'a self,
|
||||
cjs_tracker: &'a CjsTracker<TInNpmPackageChecker, TSys>,
|
||||
scoped_jsx_import_source_config: &'a ScopedJsxImportSourceConfig,
|
||||
jsx_import_source_config_resolver: &'a JsxImportSourceConfigResolver,
|
||||
) -> DenoGraphResolverAdapter<
|
||||
'a,
|
||||
TInNpmPackageChecker,
|
||||
|
@ -416,7 +416,7 @@ impl<
|
|||
DenoGraphResolverAdapter {
|
||||
cjs_tracker,
|
||||
resolver: self,
|
||||
scoped_jsx_import_source_config,
|
||||
jsx_import_source_config_resolver,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,7 +435,7 @@ pub struct DenoGraphResolverAdapter<
|
|||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>,
|
||||
scoped_jsx_import_source_config: &'a ScopedJsxImportSourceConfig,
|
||||
jsx_import_source_config_resolver: &'a JsxImportSourceConfigResolver,
|
||||
}
|
||||
|
||||
impl<
|
||||
|
@ -473,22 +473,22 @@ impl<
|
|||
{
|
||||
fn default_jsx_import_source(&self, referrer: &Url) -> Option<String> {
|
||||
self
|
||||
.scoped_jsx_import_source_config
|
||||
.resolve_by_referrer(referrer)
|
||||
.jsx_import_source_config_resolver
|
||||
.for_specifier(referrer)
|
||||
.and_then(|c| c.import_source.as_ref().map(|s| s.specifier.clone()))
|
||||
}
|
||||
|
||||
fn default_jsx_import_source_types(&self, referrer: &Url) -> Option<String> {
|
||||
self
|
||||
.scoped_jsx_import_source_config
|
||||
.resolve_by_referrer(referrer)
|
||||
.jsx_import_source_config_resolver
|
||||
.for_specifier(referrer)
|
||||
.and_then(|c| c.import_source_types.as_ref().map(|s| s.specifier.clone()))
|
||||
}
|
||||
|
||||
fn jsx_import_source_module(&self, referrer: &Url) -> &str {
|
||||
self
|
||||
.scoped_jsx_import_source_config
|
||||
.resolve_by_referrer(referrer)
|
||||
.jsx_import_source_config_resolver
|
||||
.for_specifier(referrer)
|
||||
.map(|c| c.module.as_str())
|
||||
.unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
|
||||
}
|
||||
|
|
|
@ -11,11 +11,8 @@ use std::path::PathBuf;
|
|||
|
||||
use deno_config::deno_json::ConfigFile;
|
||||
use deno_config::deno_json::ConfigFileError;
|
||||
use deno_config::workspace::JsxImportSourceConfig;
|
||||
use deno_config::workspace::ResolverWorkspaceJsrPackage;
|
||||
use deno_config::workspace::ToMaybeJsxImportSourceConfigError;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_error::JsError;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_npm::registry::NpmPackageVersionInfo;
|
||||
|
@ -1643,41 +1640,6 @@ impl BaseUrl<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScopedJsxImportSourceConfig {
|
||||
unscoped: Option<JsxImportSourceConfig>,
|
||||
by_scope: BTreeMap<UrlRc, Option<JsxImportSourceConfig>>,
|
||||
}
|
||||
|
||||
impl ScopedJsxImportSourceConfig {
|
||||
pub fn from_workspace_dir(
|
||||
start_dir: &WorkspaceDirectory,
|
||||
) -> Result<Self, ToMaybeJsxImportSourceConfigError> {
|
||||
let unscoped = start_dir.to_maybe_jsx_import_source_config()?;
|
||||
let mut by_scope = BTreeMap::default();
|
||||
for (dir_url, _) in start_dir.workspace.config_folders() {
|
||||
let dir = start_dir.workspace.resolve_member_dir(dir_url);
|
||||
let jsx_import_source_config_unscoped =
|
||||
dir.to_maybe_jsx_import_source_config()?;
|
||||
by_scope.insert(dir_url.clone(), jsx_import_source_config_unscoped);
|
||||
}
|
||||
Ok(Self { unscoped, by_scope })
|
||||
}
|
||||
|
||||
/// Resolves the `JsxImportSourceConfig` to use for the provided referrer.
|
||||
pub fn resolve_by_referrer(
|
||||
&self,
|
||||
referrer: &Url,
|
||||
) -> Option<&JsxImportSourceConfig> {
|
||||
self
|
||||
.by_scope
|
||||
.iter()
|
||||
.rfind(|(s, _)| referrer.as_str().starts_with(s.as_str()))
|
||||
.map(|(_, c)| c.as_ref())
|
||||
.unwrap_or(self.unscoped.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)] // ok, because definition
|
||||
pub type WorkspaceNpmLinkPackagesRc =
|
||||
crate::sync::MaybeArc<WorkspaceNpmLinkPackages>;
|
||||
|
|
4
tests/specs/check/tsconfig_default_libs/__test__.jsonc
Normal file
4
tests/specs/check/tsconfig_default_libs/__test__.jsonc
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": ""
|
||||
}
|
1
tests/specs/check/tsconfig_default_libs/deno.json
Normal file
1
tests/specs/check/tsconfig_default_libs/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_default_libs/main.ts
Normal file
2
tests/specs/check/tsconfig_default_libs/main.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
1
tests/specs/check/tsconfig_default_libs/tsconfig.json
Normal file
1
tests/specs/check/tsconfig_default_libs/tsconfig.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
5
tests/specs/check/tsconfig_exclude/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_exclude/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_exclude/deno.json
Normal file
1
tests/specs/check/tsconfig_exclude/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_exclude/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_exclude/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_exclude/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_exclude/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_exclude/main.out
Normal file
11
tests/specs/check/tsconfig_exclude/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
6
tests/specs/check/tsconfig_exclude/tsconfig.json
Normal file
6
tests/specs/check/tsconfig_exclude/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"exclude": ["*.deno.ts"],
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
5
tests/specs/check/tsconfig_extends/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_extends/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_extends/deno.json
Normal file
1
tests/specs/check/tsconfig_extends/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_extends/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_extends/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_extends/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_extends/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_extends/main.out
Normal file
11
tests/specs/check/tsconfig_extends/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
5
tests/specs/check/tsconfig_extends/tsconfig.dom.json
Normal file
5
tests/specs/check/tsconfig_extends/tsconfig.dom.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
4
tests/specs/check/tsconfig_extends/tsconfig.json
Normal file
4
tests/specs/check/tsconfig_extends/tsconfig.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "./tsconfig.dom.json",
|
||||
"files": ["main.dom.ts"]
|
||||
}
|
5
tests/specs/check/tsconfig_extends_array/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_extends_array/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_extends_array/deno.json
Normal file
1
tests/specs/check/tsconfig_extends_array/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_extends_array/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_extends_array/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_extends_array/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_extends_array/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_extends_array/main.out
Normal file
11
tests/specs/check/tsconfig_extends_array/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"files": ["main.dom.ts"],
|
||||
"compilerOptions": {
|
||||
"lib": []
|
||||
}
|
||||
}
|
3
tests/specs/check/tsconfig_extends_array/tsconfig.json
Normal file
3
tests/specs/check/tsconfig_extends_array/tsconfig.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": ["./tsconfig.dom_files.json", "./tsconfig.dom.json"]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"nodeModulesDir": "manual"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_extends_node_resolution/main.out
Normal file
11
tests/specs/check/tsconfig_extends_node_resolution/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
7
tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/package.json
generated
vendored
Normal file
7
tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/package.json
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"exports": {
|
||||
"./tsconfig.dom": {
|
||||
"require": "./tsconfig.dom.json"
|
||||
}
|
||||
}
|
||||
}
|
5
tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/tsconfig.dom.json
generated
vendored
Normal file
5
tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/tsconfig.dom.json
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "foo/tsconfig.dom",
|
||||
"files": ["main.dom.ts"]
|
||||
}
|
5
tests/specs/check/tsconfig_files/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_files/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_files/deno.json
Normal file
1
tests/specs/check/tsconfig_files/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_files/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_files/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_files/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_files/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_files/main.out
Normal file
11
tests/specs/check/tsconfig_files/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
6
tests/specs/check/tsconfig_files/tsconfig.json
Normal file
6
tests/specs/check/tsconfig_files/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"files": ["main.dom.ts"],
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check main.deno.ts main.dom.ts --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_files_for_globals/deno.json
Normal file
1
tests/specs/check/tsconfig_files_for_globals/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
3
tests/specs/check/tsconfig_files_for_globals/globals.d.ts
vendored
Normal file
3
tests/specs/check/tsconfig_files_for_globals/globals.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="dom" />
|
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_files_for_globals/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_files_for_globals/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_files_for_globals/main.out
Normal file
11
tests/specs/check/tsconfig_files_for_globals/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"files": ["main.dom.ts", "globals.d.ts"]
|
||||
}
|
5
tests/specs/check/tsconfig_include/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_include/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_include/deno.json
Normal file
1
tests/specs/check/tsconfig_include/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_include/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_include/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_include/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_include/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_include/main.out
Normal file
11
tests/specs/check/tsconfig_include/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
6
tests/specs/check/tsconfig_include/tsconfig.json
Normal file
6
tests/specs/check/tsconfig_include/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"include": ["*.dom.ts"],
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
5
tests/specs/check/tsconfig_references/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_references/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_references/deno.json
Normal file
1
tests/specs/check/tsconfig_references/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_references/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_references/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_references/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_references/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_references/main.out
Normal file
11
tests/specs/check/tsconfig_references/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
7
tests/specs/check/tsconfig_references/tsconfig.dom.json
Normal file
7
tests/specs/check/tsconfig_references/tsconfig.dom.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": ["main.dom.ts"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
6
tests/specs/check/tsconfig_references/tsconfig.json
Normal file
6
tests/specs/check/tsconfig_references/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "tsconfig.dom.json" }
|
||||
]
|
||||
}
|
5
tests/specs/check/tsconfig_references_dir/__test__.jsonc
Normal file
5
tests/specs/check/tsconfig_references_dir/__test__.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"args": "check --quiet",
|
||||
"output": "main.out",
|
||||
"exitCode": 1
|
||||
}
|
1
tests/specs/check/tsconfig_references_dir/deno.json
Normal file
1
tests/specs/check/tsconfig_references_dir/deno.json
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
2
tests/specs/check/tsconfig_references_dir/main.deno.ts
Normal file
2
tests/specs/check/tsconfig_references_dir/main.deno.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
2
tests/specs/check/tsconfig_references_dir/main.dom.ts
Normal file
2
tests/specs/check/tsconfig_references_dir/main.dom.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.readTextFileSync("hello.txt");
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
11
tests/specs/check/tsconfig_references_dir/main.out
Normal file
11
tests/specs/check/tsconfig_references_dir/main.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
|
||||
document.body.innerHTML = "<div>Hello</div>";
|
||||
~~~~~~~~
|
||||
at file:///[WILDLINE]main.deno.ts:2:1
|
||||
|
||||
TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to the top of your entrypoint (main file): /// <reference lib="deno.ns" />
|
||||
Deno.readTextFileSync("hello.txt");
|
||||
~~~~
|
||||
at file:///[WILDLINE]main.dom.ts:1:1
|
||||
|
||||
error: Type checking failed.
|
6
tests/specs/check/tsconfig_references_dir/tsconfig.json
Normal file
6
tests/specs/check/tsconfig_references_dir/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "tsconfig_dom" }
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": ["../main.dom.ts"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
Check [WILDLINE]/index.mjs
|
||||
Compile [WILDLINE]/index.mjs to [WILDLINE]
|
||||
|
||||
Embedded Files
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "run --reload --config config/tsconfig.json --check config/main.ts",
|
||||
"args": "run --reload --config config/config.json --check config/main.ts",
|
||||
"output": "config/main.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[WILDCARD]Unsupported compiler options in "[WILDCARD]tsconfig.json".
|
||||
[WILDCARD]Unsupported compiler options in "[WILDCARD]config.json".
|
||||
The following options were ignored:
|
||||
module, target
|
||||
Check [WILDCARD]/main.ts
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "run --reload --quiet --check=all --config config_types/tsconfig.json config_types/main.ts",
|
||||
"args": "run --reload --quiet --check --config config_types/tsconfig.json config_types/main.ts",
|
||||
"output": "config_types/main.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "run --allow-import --reload --quiet --check=all --config config_types/remote.tsconfig.json config_types/main.ts",
|
||||
"args": "run --allow-import --reload --quiet --check --config config_types/remote.tsconfig.json config_types/main.ts",
|
||||
"output": "config_types/main.out"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue