diff --git a/Cargo.lock b/Cargo.lock index 34606205c5..be77c69978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2698,6 +2698,7 @@ dependencies = [ "http 1.1.0", "import_map", "indexmap 2.9.0", + "jsonc-parser", "log", "node_resolver", "once_cell", diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 7a1a61abe3..cb77d2f8c9 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -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; -pub type CliTsConfigResolver = - deno_resolver::deno_json::TsConfigResolver; pub fn jsr_url() -> &'static Url { static JSR_URL: Lazy = Lazy::new(|| resolve_jsr_url(&CliSys::default())); diff --git a/cli/emit.rs b/cli/emit.rs index acd25ad384..8e07705f36 100644 --- a/cli/emit.rs +++ b/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, emit_cache: Arc, parsed_source_cache: Arc, - tsconfig_resolver: Arc, + compiler_options_resolver: Arc, } impl Emitter { @@ -41,13 +41,13 @@ impl Emitter { cjs_tracker: Arc, emit_cache: Arc, parsed_source_cache: Arc, - tsconfig_resolver: Arc, + compiler_options_resolver: Arc, ) -> Self { Self { cjs_tracker, emit_cache, parsed_source_cache, - tsconfig_resolver, + compiler_options_resolver, } } @@ -96,8 +96,9 @@ impl Emitter { source: &str, ) -> Result, 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, ) -> Result { 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, ) -> Result { 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, ) -> 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; diff --git a/cli/factory.rs b/cli/factory.rs index c1afd9e4f8..dbb7c0d9fb 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -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, AnyError> { - Ok(self.workspace_factory()?.tsconfig_resolver()?) + ) -> Result<&Arc, AnyError> { + self.resolver_factory()?.compiler_options_resolver() } pub async fn type_checker(&self) -> Result<&Arc, 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, AnyError> { + Ok(self.workspace_factory()?.workspace_directory_provider()?) + } + fn workspace_external_import_map_loader( &self, ) -> Result<&Arc>, AnyError> { diff --git a/cli/graph_util.rs b/cli/graph_util.rs index 52dae56efd..12b2afc6bb 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -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, root_permissions_container: PermissionsContainer, sys: CliSys, - tsconfig_resolver: Arc, + compiler_options_resolver: Arc, } impl ModuleGraphBuilder { @@ -711,7 +712,7 @@ impl ModuleGraphBuilder { resolver: Arc, root_permissions_container: PermissionsContainer, sys: CliSys, - tsconfig_resolver: Arc, + compiler_options_resolver: Arc, ) -> 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 graph_resolver = self - .resolver - .as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config); + 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(), + &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 graph_resolver = self - .resolver - .as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config); + 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(), + &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!( diff --git a/cli/tools/bundle/mod.rs b/cli/tools/bundle/mod.rs index 82f0dfca6a..90429a36a3 100644 --- a/cli/tools/bundle/mod.rs +++ b/cli/tools/bundle/mod.rs @@ -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; diff --git a/cli/tools/compile.rs b/cli/tools/compile.rs index a80c1c5ab3..1bf28aea2f 100644 --- a/cli/tools/compile.rs +++ b/cli/tools/compile.rs @@ -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(); diff --git a/cli/tools/jupyter/mod.rs b/cli/tools/jupyter/mod.rs index aeeb6e9099..7e768a6bee 100644 --- a/cli/tools/jupyter/mod.rs +++ b/cli/tools/jupyter/mod.rs @@ -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, diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs index 218401d364..12a7fea7a6 100644 --- a/cli/tools/lint/mod.rs +++ b/cli/tools/lint/mod.rs @@ -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, lint_rule_provider: LintRuleProvider, module_graph_creator: Arc, - tsconfig_resolver: Arc, + compiler_options_resolver: Arc, workspace_dir: Arc, reporter_lock: Arc>>, workspace_module_graph: Option, @@ -258,7 +258,7 @@ impl WorkspaceLinter { caches: Arc, lint_rule_provider: LintRuleProvider, module_graph_creator: Arc, - tsconfig_resolver: Arc, + compiler_options_resolver: Arc, workspace_dir: Arc, 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 { 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 { - 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) diff --git a/cli/tools/pm/deps.rs b/cli/tools/pm/deps.rs index f3e60d6ace..ae79efd60e 100644 --- a/cli/tools/pm/deps.rs +++ b/cli/tools/pm/deps.rs @@ -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, diff --git a/cli/tools/publish/mod.rs b/cli/tools/publish/mod.rs index fc7f3a9507..c6a14b7d30 100644 --- a/cli/tools/publish/mod.rs +++ b/cli/tools/publish/mod.rs @@ -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()), diff --git a/cli/tools/publish/module_content.rs b/cli/tools/publish/module_content.rs index 3dacb5832f..aec588fd4a 100644 --- a/cli/tools/publish/module_content.rs +++ b/cli/tools/publish/module_content.rs @@ -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 { specifier_unfurler: SpecifierUnfurler, parsed_source_cache: Arc, sys: TSys, - tsconfig_resolver: Arc>, + compiler_options_resolver: Arc, } impl ModuleContentProvider { @@ -45,13 +45,13 @@ impl ModuleContentProvider { parsed_source_cache: Arc, specifier_unfurler: SpecifierUnfurler, sys: TSys, - tsconfig_resolver: Arc>, + compiler_options_resolver: Arc, ) -> Self { Self { specifier_unfurler, parsed_source_cache, sys, - tsconfig_resolver, + compiler_options_resolver, } } @@ -227,13 +227,10 @@ impl ModuleContentProvider { text_info: &SourceTextInfo, diagnostic_reporter: &mut dyn FnMut(SpecifierUnfurlerDiagnostic), ) -> Result, 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 ModuleContentProvider { 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 ModuleContentProvider { ) }); 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, ) } } diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs index 6b28ffaf5d..d224a5098e 100644 --- a/cli/tools/repl/mod.rs +++ b/cli/tools/repl/mod.rs @@ -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, diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index 3136cd4b8d..5b0e268ddb 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -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>, resolver: Arc, - 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 { diff --git a/cli/type_checker.rs b/cli/type_checker.rs index 1d733eaffb..dbfaacb443 100644 --- a/cli/type_checker.rs +++ b/cli/type_checker.rs @@ -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, npm_resolver: CliNpmResolver, sys: CliSys, - tsconfig_resolver: Arc, + workspace_directory_provider: Arc, + compiler_options_resolver: Arc, code_cache: Option>, } @@ -120,7 +122,8 @@ impl TypeChecker { node_resolver: Arc, npm_resolver: CliNpmResolver, sys: CliSys, - tsconfig_resolver: Arc, + workspace_directory_provider: Arc, + compiler_options_resolver: Arc, code_cache: Option>, ) -> 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, CheckGroupInfo>, CheckError> { - let mut imports_for_specifier: HashMap, Rc>> = - HashMap::with_capacity(self.tsconfig_resolver.folder_count()); - let mut roots_by_config: IndexMap<_, CheckGroupInfo> = - IndexMap::with_capacity(self.tsconfig_resolver.folder_count()); + ) -> Result>, 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( - graph, - &folder.dir, - )); - vacant_entry.insert(value.clone()); - value - } - }; - let compiler_options = folder.lib_compiler_options(lib)?; - let key = CheckGroupKey { - 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 { + 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, + 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, // 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()), + } + }); + group.roots.push(root.clone()); } - Ok(roots_by_config) + 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 { - fn resolve_graph_imports_for_referrer<'a>( - graph: &'a ModuleGraph, - referrer: &'a Url, - ) -> Option + '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::>(); specifiers.sort(); specifiers } -/// Key to use to group roots together by config. -#[derive(Debug, Hash, PartialEq, Eq)] -struct CheckGroupKey<'a> { - compiler_options: &'a Arc, - imports: Rc>, -} - -struct CheckGroupInfo { +#[derive(Debug)] +struct CheckGroup<'a> { roots: Vec, + imports: Rc>, referrer: Url, + compiler_options: &'a Arc, } pub struct DiagnosticsByFolderIterator<'a>( @@ -390,9 +367,10 @@ struct DiagnosticsByFolderRealIterator<'a> { cjs_tracker: &'a Arc, node_resolver: &'a Arc, npm_resolver: &'a CliNpmResolver, - tsconfig_resolver: &'a CliTsConfigResolver, + compiler_options_resolver: &'a CompilerOptionsResolver, type_check_cache: TypeCheckCache, - grouped_roots: IndexMap, CheckGroupInfo>, + groups: Vec>, + current_group_index: usize, log_level: Option, npm_check_state_hash: Option, seen_diagnotics: HashSet, @@ -404,8 +382,9 @@ impl Iterator for DiagnosticsByFolderRealIterator<'_> { type Item = Result; fn next(&mut self) -> Option { - 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 { 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 = 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, 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, 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)) diff --git a/libs/config/deno_json/mod.rs b/libs/config/deno_json/mod.rs index 5bf939ffce..c77ee20ed7 100644 --- a/libs/config/deno_json/mod.rs +++ b/libs/config/deno_json/mod.rs @@ -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(&self, serializer: S) -> Result - 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, } -/// 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; diff --git a/libs/config/workspace/mod.rs b/libs/config/workspace/mod.rs index 3bc5ccf335..a825bc151d 100644 --- a/libs/config/workspace/mod.rs +++ b/libs/config/workspace/mod.rs @@ -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, +} + +/// 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 { - 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 { + 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(), diff --git a/libs/resolver/Cargo.toml b/libs/resolver/Cargo.toml index b370bdb433..c79e1e6783 100644 --- a/libs/resolver/Cargo.toml +++ b/libs/resolver/Cargo.toml @@ -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 diff --git a/libs/resolver/collections.rs b/libs/resolver/collections.rs index 5a515d67d2..0052e4d059 100644 --- a/libs/resolver/collections.rs +++ b/libs/resolver/collections.rs @@ -13,7 +13,7 @@ type UrlRc = crate::sync::MaybeArc; /// The root directory is considered "unscoped" so values that /// fall outside the other directories land here (ex. remote modules). pub struct FolderScopedMap { - unscoped: TValue, + pub unscoped: TValue, scoped: BTreeMap, } @@ -64,9 +64,41 @@ impl FolderScopedMap { .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, &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( + &self, + mut f: impl FnMut(&TValue) -> Result, + ) -> Result, E> { + Ok(FolderScopedMap { + unscoped: f(&self.unscoped)?, + scoped: self + .scoped + .iter() + .map(|(s, v)| Ok((s.clone(), f(v)?))) + .collect::>()?, + }) + } } diff --git a/libs/resolver/deno_json.rs b/libs/resolver/deno_json.rs index 1a318ac41a..0affecb15f 100644 --- a/libs/resolver/deno_json.rs +++ b/libs/resolver/deno_json.rs @@ -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 = - crate::sync::MaybeArc>; - #[allow(clippy::disallowed_types)] type CompilerOptionsRc = crate::sync::MaybeArc; #[allow(clippy::disallowed_types)] -type LoggedWarningsRc = crate::sync::MaybeArc; -#[cfg(feature = "deno_ast")] -#[allow(clippy::disallowed_types)] -pub type TranspileAndEmitOptionsRc = - crate::sync::MaybeArc; +pub type CompilerOptionsTypesRc = + crate::sync::MaybeArc)>>; #[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; + #[derive(Debug, Default)] struct LoggedWarnings { experimental_decorators: AtomicFlag, folders: crate::sync::MaybeDashSet, } +#[allow(clippy::disallowed_types)] +type LoggedWarningsRc = crate::sync::MaybeArc; + #[derive(Default, Debug)] struct MemoizedValues { deno_window_check_compiler_options: OnceCell, @@ -54,55 +82,87 @@ struct MemoizedValues { emit_compiler_options: OnceCell, #[cfg(feature = "deno_ast")] transpile_options: OnceCell, + compiler_options_types: OnceCell, + jsx_import_source_config: OnceCell>, + check_js: OnceCell, } #[derive(Debug)] -pub struct TsConfigFolderInfo { - pub dir: WorkspaceDirectory, - logged_warnings: LoggedWarningsRc, +pub struct CompilerOptionsData { + pub sources: Vec, + source_kind: CompilerOptionsSourceKind, memoized: MemoizedValues, - sys: TSys, + logged_warnings: LoggedWarningsRc, } -impl TsConfigFolderInfo { - pub fn lib_compiler_options( +impl CompilerOptionsData { + fn new( + sources: Vec, + 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 TsConfigFolderInfo { &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, 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) -> 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)>, + include: Option, + exclude: Option, + dir_path: PathBuf, +} + +impl TsConfigFileFilter { + fn includes_path(&self, path: impl AsRef) -> 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; + +#[derive(Debug)] +pub struct TsConfigData { + pub compiler_options: CompilerOptionsData, + filter: TsConfigFileFilterRc, + references: Vec, +} + +impl TsConfigData { + pub fn files(&self) -> Option<(&Url, &Vec)> { + 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 = NodeResolver< + DenoInNpmPackageChecker, + DenoIsBuiltInNodeModuleChecker, + NpmResolver, + TSys, +>; + +#[derive(Debug)] +struct TsConfigCollector<'a, TSys: FsRead, NSys: NpmResolverSys> { + roots: BTreeSet, + collected: IndexMap>, + read_cache: HashMap, Rc>>, + currently_reading: IndexSet, + sys: &'a TSys, + node_resolver: &'a TsConfigNodeResolver, + logged_warnings: &'a LoggedWarningsRc, +} + +impl<'a, TSys: FsRead, NSys: NpmResolverSys> TsConfigCollector<'a, TSys, NSys> { + fn new( + sys: &'a TSys, + node_resolver: &'a TsConfigNodeResolver, + 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 { + 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) { + 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, + ) -> Result, Rc> { + 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, + ) -> Result { + 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::>(); + 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::>(), + ) + .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::>(), + ) + .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 { - map: FolderScopedMap>, +pub struct CompilerOptionsResolver { + workspace_configs: FolderScopedMap, + ts_configs: Vec, } -impl TsConfigResolver { - 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( + sys: &TSys, + workspace_directory_provider: &WorkspaceDirectoryProvider, + node_resolver: &TsConfigNodeResolver, + ) -> 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 } - } -} - -impl TsConfigResolver { - pub fn check_js_for_specifier(&self, specifier: &Url) -> bool { - self.folder_for_specifier(specifier).dir.check_js() + Self { + workspace_configs, + ts_configs: ts_config_collector.collect(), + } } - #[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 { - self.folder_for_specifier_str(specifier.as_str()) + pub fn all(&self) -> impl Iterator { + 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 { - 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 { + &self.ts_configs } } #[cfg(feature = "graph")] -impl deno_graph::CheckJsResolver - for TsConfigResolver -{ - 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; + +/// 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>, + ts_configs: Vec<(Option, TsConfigFileFilterRc)>, +} + +impl JsxImportSourceConfigResolver { + pub fn from_compiler_options_resolver( + compiler_options_resolver: &CompilerOptionsResolver, + ) -> Result { + 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::>()?, + }) + } + + 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; + #[cfg(feature = "deno_ast")] fn compiler_options_to_transpile_and_emit_options( config: deno_config::deno_json::CompilerOptions, diff --git a/libs/resolver/factory.rs b/libs/resolver/factory.rs index edb4f0d2a6..b65dbe797c 100644 --- a/libs/resolver/factory.rs +++ b/libs/resolver/factory.rs @@ -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 = once_cell::sync::OnceCell; #[cfg(not(feature = "sync"))] type Deferred = once_cell::unsync::OnceCell; +#[allow(clippy::disallowed_types)] +type UrlRc = crate::sync::MaybeArc; #[allow(clippy::disallowed_types)] pub type WorkspaceDirectoryRc = crate::sync::MaybeArc; #[allow(clippy::disallowed_types)] @@ -254,8 +257,8 @@ pub struct WorkspaceFactory { npm_cache_dir: Deferred, npmrc: Deferred<(ResolvedNpmRcRc, Option)>, node_modules_dir_mode: Deferred, - tsconfig_resolver: Deferred>, workspace_directory: Deferred, + workspace_directory_provider: Deferred, workspace_external_import_map_loader: Deferred>, workspace_npm_link_packages: Deferred, @@ -289,8 +292,8 @@ impl WorkspaceFactory { 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 WorkspaceFactory { }) } - pub fn tsconfig_resolver( - &self, - ) -> Result<&TsConfigResolverRc, 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 WorkspaceFactory { }) } + 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, WorkspaceDiscoverError> @@ -677,6 +679,7 @@ pub struct ResolverFactory { options: ResolverFactoryOptions, sys: NodeResolutionSys, cjs_tracker: Deferred>, + compiler_options_resolver: Deferred, #[cfg(feature = "graph")] deno_resolver: async_once_cell::OnceCell>, @@ -718,6 +721,7 @@ impl ResolverFactory { 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 ResolverFactory { }) } + 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 ResolverFactory { ) } } + +#[derive(Debug)] +pub struct WorkspaceDirectoryProvider { + pub workspace: WorkspaceRc, + dirs: FolderScopedMap>, +} + +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, &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; diff --git a/libs/resolver/graph.rs b/libs/resolver/graph.rs index 4fd8f5b49f..357a8d41cc 100644 --- a/libs/resolver/graph.rs +++ b/libs/resolver/graph.rs @@ -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, - 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 { 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 { 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) } diff --git a/libs/resolver/workspace.rs b/libs/resolver/workspace.rs index 33367d45df..17a36a08f2 100644 --- a/libs/resolver/workspace.rs +++ b/libs/resolver/workspace.rs @@ -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, - by_scope: BTreeMap>, -} - -impl ScopedJsxImportSourceConfig { - pub fn from_workspace_dir( - start_dir: &WorkspaceDirectory, - ) -> Result { - 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; diff --git a/tests/specs/check/tsconfig_default_libs/__test__.jsonc b/tests/specs/check/tsconfig_default_libs/__test__.jsonc new file mode 100644 index 0000000000..97cd3de543 --- /dev/null +++ b/tests/specs/check/tsconfig_default_libs/__test__.jsonc @@ -0,0 +1,4 @@ +{ + "args": "check --quiet", + "output": "" +} diff --git a/tests/specs/check/tsconfig_default_libs/deno.json b/tests/specs/check/tsconfig_default_libs/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_default_libs/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_default_libs/main.ts b/tests/specs/check/tsconfig_default_libs/main.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_default_libs/main.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_default_libs/tsconfig.json b/tests/specs/check/tsconfig_default_libs/tsconfig.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_default_libs/tsconfig.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_exclude/__test__.jsonc b/tests/specs/check/tsconfig_exclude/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_exclude/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_exclude/deno.json b/tests/specs/check/tsconfig_exclude/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_exclude/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_exclude/main.deno.ts b/tests/specs/check/tsconfig_exclude/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_exclude/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_exclude/main.dom.ts b/tests/specs/check/tsconfig_exclude/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_exclude/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_exclude/main.out b/tests/specs/check/tsconfig_exclude/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_exclude/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_exclude/tsconfig.json b/tests/specs/check/tsconfig_exclude/tsconfig.json new file mode 100644 index 0000000000..4f334da999 --- /dev/null +++ b/tests/specs/check/tsconfig_exclude/tsconfig.json @@ -0,0 +1,6 @@ +{ + "exclude": ["*.deno.ts"], + "compilerOptions": { + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_extends/__test__.jsonc b/tests/specs/check/tsconfig_extends/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_extends/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_extends/deno.json b/tests/specs/check/tsconfig_extends/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_extends/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_extends/main.deno.ts b/tests/specs/check/tsconfig_extends/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_extends/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_extends/main.dom.ts b/tests/specs/check/tsconfig_extends/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_extends/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_extends/main.out b/tests/specs/check/tsconfig_extends/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_extends/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_extends/tsconfig.dom.json b/tests/specs/check/tsconfig_extends/tsconfig.dom.json new file mode 100644 index 0000000000..a610598bb2 --- /dev/null +++ b/tests/specs/check/tsconfig_extends/tsconfig.dom.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_extends/tsconfig.json b/tests/specs/check/tsconfig_extends/tsconfig.json new file mode 100644 index 0000000000..c1ad9a8964 --- /dev/null +++ b/tests/specs/check/tsconfig_extends/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.dom.json", + "files": ["main.dom.ts"] +} diff --git a/tests/specs/check/tsconfig_extends_array/__test__.jsonc b/tests/specs/check/tsconfig_extends_array/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_extends_array/deno.json b/tests/specs/check/tsconfig_extends_array/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_extends_array/main.deno.ts b/tests/specs/check/tsconfig_extends_array/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_extends_array/main.dom.ts b/tests/specs/check/tsconfig_extends_array/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_extends_array/main.out b/tests/specs/check/tsconfig_extends_array/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_extends_array/tsconfig.dom.json b/tests/specs/check/tsconfig_extends_array/tsconfig.dom.json new file mode 100644 index 0000000000..a610598bb2 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/tsconfig.dom.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_extends_array/tsconfig.dom_files.json b/tests/specs/check/tsconfig_extends_array/tsconfig.dom_files.json new file mode 100644 index 0000000000..43f016bb61 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/tsconfig.dom_files.json @@ -0,0 +1,6 @@ +{ + "files": ["main.dom.ts"], + "compilerOptions": { + "lib": [] + } +} diff --git a/tests/specs/check/tsconfig_extends_array/tsconfig.json b/tests/specs/check/tsconfig_extends_array/tsconfig.json new file mode 100644 index 0000000000..3730372d81 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_array/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": ["./tsconfig.dom_files.json", "./tsconfig.dom.json"] +} diff --git a/tests/specs/check/tsconfig_extends_node_resolution/__test__.jsonc b/tests/specs/check/tsconfig_extends_node_resolution/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_extends_node_resolution/deno.json b/tests/specs/check/tsconfig_extends_node_resolution/deno.json new file mode 100644 index 0000000000..fde86a1efb --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/deno.json @@ -0,0 +1,3 @@ +{ + "nodeModulesDir": "manual" +} diff --git a/tests/specs/check/tsconfig_extends_node_resolution/main.deno.ts b/tests/specs/check/tsconfig_extends_node_resolution/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_extends_node_resolution/main.dom.ts b/tests/specs/check/tsconfig_extends_node_resolution/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_extends_node_resolution/main.out b/tests/specs/check/tsconfig_extends_node_resolution/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/package.json b/tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/package.json new file mode 100644 index 0000000000..68d5ad7458 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/package.json @@ -0,0 +1,7 @@ +{ + "exports": { + "./tsconfig.dom": { + "require": "./tsconfig.dom.json" + } + } +} diff --git a/tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/tsconfig.dom.json b/tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/tsconfig.dom.json new file mode 100644 index 0000000000..a610598bb2 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/node_modules/foo/tsconfig.dom.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_extends_node_resolution/tsconfig.json b/tests/specs/check/tsconfig_extends_node_resolution/tsconfig.json new file mode 100644 index 0000000000..6b665ebc42 --- /dev/null +++ b/tests/specs/check/tsconfig_extends_node_resolution/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "foo/tsconfig.dom", + "files": ["main.dom.ts"] +} diff --git a/tests/specs/check/tsconfig_files/__test__.jsonc b/tests/specs/check/tsconfig_files/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_files/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_files/deno.json b/tests/specs/check/tsconfig_files/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_files/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_files/main.deno.ts b/tests/specs/check/tsconfig_files/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_files/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_files/main.dom.ts b/tests/specs/check/tsconfig_files/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_files/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_files/main.out b/tests/specs/check/tsconfig_files/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_files/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_files/tsconfig.json b/tests/specs/check/tsconfig_files/tsconfig.json new file mode 100644 index 0000000000..8a21d5529f --- /dev/null +++ b/tests/specs/check/tsconfig_files/tsconfig.json @@ -0,0 +1,6 @@ +{ + "files": ["main.dom.ts"], + "compilerOptions": { + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_files_for_globals/__test__.jsonc b/tests/specs/check/tsconfig_files_for_globals/__test__.jsonc new file mode 100644 index 0000000000..4342487f5a --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check main.deno.ts main.dom.ts --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_files_for_globals/deno.json b/tests/specs/check/tsconfig_files_for_globals/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_files_for_globals/globals.d.ts b/tests/specs/check/tsconfig_files_for_globals/globals.d.ts new file mode 100644 index 0000000000..50def2c522 --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/globals.d.ts @@ -0,0 +1,3 @@ +/// +/// +/// diff --git a/tests/specs/check/tsconfig_files_for_globals/main.deno.ts b/tests/specs/check/tsconfig_files_for_globals/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_files_for_globals/main.dom.ts b/tests/specs/check/tsconfig_files_for_globals/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_files_for_globals/main.out b/tests/specs/check/tsconfig_files_for_globals/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_files_for_globals/tsconfig.json b/tests/specs/check/tsconfig_files_for_globals/tsconfig.json new file mode 100644 index 0000000000..38ed9e2147 --- /dev/null +++ b/tests/specs/check/tsconfig_files_for_globals/tsconfig.json @@ -0,0 +1,3 @@ +{ + "files": ["main.dom.ts", "globals.d.ts"] +} diff --git a/tests/specs/check/tsconfig_include/__test__.jsonc b/tests/specs/check/tsconfig_include/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_include/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_include/deno.json b/tests/specs/check/tsconfig_include/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_include/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_include/main.deno.ts b/tests/specs/check/tsconfig_include/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_include/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_include/main.dom.ts b/tests/specs/check/tsconfig_include/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_include/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_include/main.out b/tests/specs/check/tsconfig_include/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_include/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_include/tsconfig.json b/tests/specs/check/tsconfig_include/tsconfig.json new file mode 100644 index 0000000000..19c149d786 --- /dev/null +++ b/tests/specs/check/tsconfig_include/tsconfig.json @@ -0,0 +1,6 @@ +{ + "include": ["*.dom.ts"], + "compilerOptions": { + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_references/__test__.jsonc b/tests/specs/check/tsconfig_references/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_references/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_references/deno.json b/tests/specs/check/tsconfig_references/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_references/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_references/main.deno.ts b/tests/specs/check/tsconfig_references/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_references/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_references/main.dom.ts b/tests/specs/check/tsconfig_references/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_references/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_references/main.out b/tests/specs/check/tsconfig_references/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_references/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_references/tsconfig.dom.json b/tests/specs/check/tsconfig_references/tsconfig.dom.json new file mode 100644 index 0000000000..0bc1cfd0e6 --- /dev/null +++ b/tests/specs/check/tsconfig_references/tsconfig.dom.json @@ -0,0 +1,7 @@ +{ + "files": ["main.dom.ts"], + "compilerOptions": { + "composite": true, + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/check/tsconfig_references/tsconfig.json b/tests/specs/check/tsconfig_references/tsconfig.json new file mode 100644 index 0000000000..1b3f26cd34 --- /dev/null +++ b/tests/specs/check/tsconfig_references/tsconfig.json @@ -0,0 +1,6 @@ +{ + "files": [], + "references": [ + { "path": "tsconfig.dom.json" } + ] +} diff --git a/tests/specs/check/tsconfig_references_dir/__test__.jsonc b/tests/specs/check/tsconfig_references_dir/__test__.jsonc new file mode 100644 index 0000000000..61e11a01ad --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/__test__.jsonc @@ -0,0 +1,5 @@ +{ + "args": "check --quiet", + "output": "main.out", + "exitCode": 1 +} diff --git a/tests/specs/check/tsconfig_references_dir/deno.json b/tests/specs/check/tsconfig_references_dir/deno.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/deno.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/check/tsconfig_references_dir/main.deno.ts b/tests/specs/check/tsconfig_references_dir/main.deno.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/main.deno.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_references_dir/main.dom.ts b/tests/specs/check/tsconfig_references_dir/main.dom.ts new file mode 100644 index 0000000000..d69c644b33 --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/main.dom.ts @@ -0,0 +1,2 @@ +Deno.readTextFileSync("hello.txt"); +document.body.innerHTML = "
Hello
"; diff --git a/tests/specs/check/tsconfig_references_dir/main.out b/tests/specs/check/tsconfig_references_dir/main.out new file mode 100644 index 0000000000..b71eeff2fc --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/main.out @@ -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 = "
Hello
"; +~~~~~~~~ + 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): /// +Deno.readTextFileSync("hello.txt"); +~~~~ + at file:///[WILDLINE]main.dom.ts:1:1 + +error: Type checking failed. diff --git a/tests/specs/check/tsconfig_references_dir/tsconfig.json b/tests/specs/check/tsconfig_references_dir/tsconfig.json new file mode 100644 index 0000000000..c19e27124f --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/tsconfig.json @@ -0,0 +1,6 @@ +{ + "files": [], + "references": [ + { "path": "tsconfig_dom" } + ] +} diff --git a/tests/specs/check/tsconfig_references_dir/tsconfig_dom/tsconfig.json b/tests/specs/check/tsconfig_references_dir/tsconfig_dom/tsconfig.json new file mode 100644 index 0000000000..0c8abb5ca0 --- /dev/null +++ b/tests/specs/check/tsconfig_references_dir/tsconfig_dom/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": ["../main.dom.ts"], + "compilerOptions": { + "composite": true, + "lib": ["esnext", "dom"] + } +} diff --git a/tests/specs/npm/file_specifier/compile.out b/tests/specs/npm/file_specifier/compile.out index 05a8e39a6b..bc84a8aac2 100644 --- a/tests/specs/npm/file_specifier/compile.out +++ b/tests/specs/npm/file_specifier/compile.out @@ -1,3 +1,4 @@ +Check [WILDLINE]/index.mjs Compile [WILDLINE]/index.mjs to [WILDLINE] Embedded Files diff --git a/tests/specs/run/config/__test__.jsonc b/tests/specs/run/config/__test__.jsonc index 59d3ae5fcc..e36f8d5840 100644 --- a/tests/specs/run/config/__test__.jsonc +++ b/tests/specs/run/config/__test__.jsonc @@ -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" } diff --git a/tests/specs/run/config/config/tsconfig.json b/tests/specs/run/config/config/config.json similarity index 100% rename from tests/specs/run/config/config/tsconfig.json rename to tests/specs/run/config/config/config.json diff --git a/tests/specs/run/config/config/main.out b/tests/specs/run/config/config/main.out index 2773148073..2bd4e02df5 100644 --- a/tests/specs/run/config/config/main.out +++ b/tests/specs/run/config/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 diff --git a/tests/specs/run/config_types/__test__.jsonc b/tests/specs/run/config_types/__test__.jsonc index d803915c73..e4e5779f9c 100644 --- a/tests/specs/run/config_types/__test__.jsonc +++ b/tests/specs/run/config_types/__test__.jsonc @@ -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" } diff --git a/tests/specs/run/config_types_remote/__test__.jsonc b/tests/specs/run/config_types_remote/__test__.jsonc index 87457ace21..ce297b196e 100644 --- a/tests/specs/run/config_types_remote/__test__.jsonc +++ b/tests/specs/run/config_types_remote/__test__.jsonc @@ -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" }