Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(check): compiler options from workspace members #27785

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
d52ccd2
feat(check): compiler options from workspace members
nayeemrmn Nov 22, 2024
88f7510
wildcard
nayeemrmn Nov 22, 2024
8f5465e
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Nov 22, 2024
9707974
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Nov 26, 2024
7a3a73c
fix file patterns
nayeemrmn Nov 26, 2024
27561dd
smart diagnostics concatenation
nayeemrmn Nov 26, 2024
b716050
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Nov 27, 2024
874260d
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Nov 27, 2024
6e3cedd
use deno_config temp branch
nayeemrmn Nov 27, 2024
3e9a63f
fix
nayeemrmn Nov 27, 2024
6b73819
fix fixture
nayeemrmn Nov 27, 2024
c521bfb
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Nov 29, 2024
14b3eb2
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Nov 30, 2024
6499ad6
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 4, 2024
de4e641
WorkspaceFileContainer
nayeemrmn Dec 5, 2024
b3bd581
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 5, 2024
871750a
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 6, 2024
f36d70d
move remote specifier handling to deno_config
nayeemrmn Dec 7, 2024
e33d51d
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 7, 2024
59511cb
cleanup
nayeemrmn Dec 7, 2024
7ceeb0b
fix --doc-only
nayeemrmn Dec 7, 2024
4d081d2
dedup discovered/specified config
nayeemrmn Dec 7, 2024
dab8352
use WorkspaceFileContainer in deno test
nayeemrmn Dec 9, 2024
655190e
fix ext flag
nayeemrmn Dec 9, 2024
c22b0e4
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 9, 2024
42eb554
fix fixture
nayeemrmn Dec 9, 2024
61aa023
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 10, 2024
0c44814
use WorkspaceFileContainer for test --watch
nayeemrmn Dec 10, 2024
78de1fb
use WorkspaceFileContainer for bench
nayeemrmn Dec 10, 2024
1af0cde
use single workspace dir for test -c and bench -c
nayeemrmn Dec 10, 2024
0c188eb
restore test --watch=... support
nayeemrmn Dec 10, 2024
b8b9eea
restore checking to test --watch
nayeemrmn Dec 10, 2024
37d45d0
use WorkspaceFileContainer for bench --watch
nayeemrmn Dec 10, 2024
83ee4c9
lint
nayeemrmn Dec 10, 2024
de37f41
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 10, 2024
f8be309
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 11, 2024
8f5d50c
private CliOptions::flags again
nayeemrmn Dec 11, 2024
0e2f9e7
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 11, 2024
f45d39b
move -c handling to CliOptions methods
nayeemrmn Dec 11, 2024
ff1f921
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 11, 2024
161468a
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 13, 2024
9a6263c
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 16, 2024
5d76fc9
remove need for outer factory
nayeemrmn Dec 16, 2024
5807b53
reduce dependency on outer CliOptions
nayeemrmn Dec 16, 2024
f5b258c
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 16, 2024
c7f2899
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 17, 2024
9f8d833
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 17, 2024
1c2fb5c
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 19, 2024
03cb973
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Dec 30, 2024
60de9fa
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 1, 2025
e91b0ef
fmt
nayeemrmn Jan 1, 2025
f61286b
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 6, 2025
01fb217
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 6, 2025
2eae9a9
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 6, 2025
b0cbae7
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 7, 2025
5a1bb6b
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 14, 2025
6128282
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 15, 2025
8719cb7
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 15, 2025
c8a0404
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 16, 2025
8d5fb5a
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 18, 2025
0ae3090
fix merge
nayeemrmn Jan 18, 2025
9d9a88f
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 20, 2025
766452f
single factory
nayeemrmn Jan 20, 2025
1e073ee
don't store specifier info
nayeemrmn Jan 20, 2025
1dd3614
remote CliFactoryWithWorkspaceFiles::initial_cwd()
nayeemrmn Jan 20, 2025
798f733
workspace_files
nayeemrmn Jan 20, 2025
36fcff8
coverage fixture
nayeemrmn Jan 20, 2025
971ec9b
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 20, 2025
1e9e24f
scoped jsx import source config
nayeemrmn Jan 20, 2025
c2a6fa1
Merge remote-tracking branch 'upstream/main' into check-workspace-mem…
nayeemrmn Jan 22, 2025
67c4da4
abstract CliOptions creation
nayeemrmn Jan 22, 2025
c885735
use closure for get_dirs_with_files
nayeemrmn Jan 22, 2025
85c8e4d
use closure for collect_specifiers
nayeemrmn Jan 22, 2025
532e3b3
CliFactor::with_watcher_communicator()
nayeemrmn Jan 22, 2025
bf82fe2
fixup! CliFactor::with_watcher_communicator()
nayeemrmn Jan 22, 2025
f8cb237
Merge branch 'main' into check-workspace-member-compiler-options
dsherret Jan 22, 2025
8ee8582
Update to mostly only change TypeChecker
dsherret Jan 22, 2025
a18bf43
Not sure why this test output was different?
dsherret Jan 22, 2025
7024cf8
clippy
dsherret Jan 22, 2025
209801a
improve finding members
dsherret Jan 23, 2025
58275aa
update to display diagnostics by folder
dsherret Jan 23, 2025
1b82b1c
Merge branch 'main' into check-workspace-member-compiler-options2
dsherret Jan 24, 2025
f830c67
Add TsConfigResolver
dsherret Jan 24, 2025
ebd5ca1
updates based on deno_config changes
dsherret Jan 24, 2025
857d993
only log once
dsherret Jan 24, 2025
b1013a9
conditionally inject @types/node
dsherret Jan 24, 2025
7339504
streaming errors and rework this to be more correct
dsherret Jan 25, 2025
64a9fe6
do not show check when there is nothing to check
dsherret Jan 25, 2025
40dd0a8
slightly better
dsherret Jan 25, 2025
bee6511
fix test
dsherret Jan 25, 2025
7255a9e
Merge branch 'main' into check-workspace-member-compiler-options2
dsherret Jan 27, 2025
4ab1c29
duplicates
dsherret Jan 27, 2025
9fcdfc7
Merge branch 'main' into check-workspace-member-compiler-options2
dsherret Jan 27, 2025
e16f70a
improve grouping files together for type checking
dsherret Jan 28, 2025
b1cda9d
Improve names
dsherret Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ deno_ast = { version = "=0.44.0", features = ["transpiling"] }
deno_core = { version = "0.333.0" }

deno_bench_util = { version = "0.181.0", path = "./bench_util" }
deno_config = { version = "=0.45.0", features = ["workspace"] }
deno_config = { version = "=0.46.0", features = ["workspace"] }
deno_lockfile = "=0.24.0"
deno_media_type = { version = "=0.2.5", features = ["module_specifier"] }
deno_npm = "=0.27.2"
Expand Down
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ deno_config = { workspace = true, features = ["sync", "workspace"] }
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "=0.164.0", features = ["rust", "comrak"] }
deno_error.workspace = true
deno_graph = { version = "=0.87.0" }
deno_graph = { version = "=0.87.2" }
deno_lib.workspace = true
deno_lint = { version = "0.70.0" }
deno_lockfile.workspace = true
Expand Down
276 changes: 268 additions & 8 deletions cli/args/deno_json.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
// Copyright 2018-2025 the Deno authors. MIT license.

use std::collections::HashSet;
use std::sync::Arc;

use deno_config::deno_json::TsConfigForEmit;
use deno_ast::SourceMapOption;
use deno_config::deno_json::CompilerOptionsParseError;
use deno_config::deno_json::TsConfig;
use deno_config::deno_json::TsConfigType;
use deno_config::deno_json::TsConfigWithIgnoredOptions;
use deno_config::deno_json::TsTypeLib;
use deno_config::workspace::Workspace;
use deno_config::workspace::WorkspaceDirectory;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::unsync::sync::AtomicFlag;
use deno_core::url::Url;
use deno_lib::util::hash::FastInsecureHasher;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
use once_cell::sync::OnceCell;

use crate::util::collections::FolderScopedMap;

pub fn import_map_deps(
import_map: &serde_json::Value,
Expand Down Expand Up @@ -102,17 +118,261 @@ fn value_to_dep_req(value: &str) -> Option<JsrDepPackageReq> {
}
}

pub fn check_warn_tsconfig(ts_config: &TsConfigForEmit) {
if let Some(ignored_options) = &ts_config.maybe_ignored_options {
log::warn!("{}", ignored_options);
fn check_warn_tsconfig(
ts_config: &TsConfigWithIgnoredOptions,
logged_warnings: &LoggedWarnings,
) {
for ignored_options in &ts_config.ignored_options {
if ignored_options
.maybe_specifier
.as_ref()
.map(|s| logged_warnings.folders.insert(s.clone()))
.unwrap_or(true)
{
log::warn!("{}", ignored_options);
}
}
let serde_json::Value::Object(obj) = &ts_config.ts_config.0 else {
return;
};
if obj.get("experimentalDecorators") == Some(&serde_json::Value::Bool(true)) {
if obj.get("experimentalDecorators") == Some(&serde_json::Value::Bool(true))
&& logged_warnings.experimental_decorators.raise()
{
log::warn!(
"{} experimentalDecorators compiler option is deprecated and may be removed at any time",
deno_runtime::colors::yellow("Warning"),
);
"{} experimentalDecorators compiler option is deprecated and may be removed at any time",
deno_runtime::colors::yellow("Warning"),
);
}
}

#[derive(Debug)]
pub struct TranspileAndEmitOptions {
pub transpile: deno_ast::TranspileOptions,
pub emit: deno_ast::EmitOptions,
// stored ahead of time so we don't have to recompute this a lot
pub pre_computed_hash: u64,
}

#[derive(Debug, Default)]
struct LoggedWarnings {
experimental_decorators: AtomicFlag,
folders: dashmap::DashSet<Url>,
}

#[derive(Default, Debug)]
struct MemoizedValues {
deno_window_check_tsconfig: OnceCell<Arc<TsConfig>>,
deno_worker_check_tsconfig: OnceCell<Arc<TsConfig>>,
emit_tsconfig: OnceCell<Arc<TsConfig>>,
transpile_options: OnceCell<Arc<TranspileAndEmitOptions>>,
}

#[derive(Debug)]
pub struct TsConfigFolderInfo {
pub dir: WorkspaceDirectory,
logged_warnings: Arc<LoggedWarnings>,
memoized: MemoizedValues,
}

impl TsConfigFolderInfo {
pub fn lib_tsconfig(
&self,
lib: TsTypeLib,
) -> Result<&Arc<TsConfig>, CompilerOptionsParseError> {
let cell = match lib {
TsTypeLib::DenoWindow => &self.memoized.deno_window_check_tsconfig,
TsTypeLib::DenoWorker => &self.memoized.deno_worker_check_tsconfig,
};

cell.get_or_try_init(|| {
let tsconfig_result = self
.dir
.to_resolved_ts_config(TsConfigType::Check { lib })?;
check_warn_tsconfig(&tsconfig_result, &self.logged_warnings);
Ok(Arc::new(tsconfig_result.ts_config))
})
}

pub fn emit_tsconfig(
&self,
) -> Result<&Arc<TsConfig>, CompilerOptionsParseError> {
self.memoized.emit_tsconfig.get_or_try_init(|| {
let tsconfig_result =
self.dir.to_resolved_ts_config(TsConfigType::Emit)?;
check_warn_tsconfig(&tsconfig_result, &self.logged_warnings);
Ok(Arc::new(tsconfig_result.ts_config))
})
}

pub fn transpile_options(
&self,
) -> Result<&Arc<TranspileAndEmitOptions>, CompilerOptionsParseError> {
self.memoized.transpile_options.get_or_try_init(|| {
let ts_config = self.emit_tsconfig()?;
ts_config_to_transpile_and_emit_options(ts_config.as_ref().clone())
.map(Arc::new)
.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()
}),
source,
})
})
}
}

#[derive(Debug)]
pub struct TsConfigResolver {
map: FolderScopedMap<TsConfigFolderInfo>,
}

impl TsConfigResolver {
pub fn from_workspace(workspace: &Arc<Workspace>) -> Self {
// separate the workspace into directories that have a tsconfig
let root_dir = workspace.resolve_member_dir(workspace.root_dir());
let logged_warnings = Arc::new(LoggedWarnings::default());
let mut map = FolderScopedMap::new(TsConfigFolderInfo {
dir: root_dir,
logged_warnings: logged_warnings.clone(),
memoized: Default::default(),
});
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(),
},
);
}
}
Self { map }
}

pub fn check_js_for_specifier(&self, specifier: &Url) -> bool {
self.folder_for_specifier(specifier).dir.check_js()
}

pub fn deno_lint_config(
&self,
specifier: &Url,
) -> Result<DenoLintConfig, AnyError> {
let transpile_options =
&self.transpile_and_emit_options(specifier)?.transpile;
// don't bother storing this in a cell because deno_lint requires an owned value
Ok(DenoLintConfig {
default_jsx_factory: (!transpile_options.jsx_automatic)
.then(|| transpile_options.jsx_factory.clone()),
default_jsx_fragment_factory: (!transpile_options.jsx_automatic)
.then(|| transpile_options.jsx_fragment_factory.clone()),
})
}

pub fn transpile_and_emit_options(
&self,
specifier: &Url,
) -> Result<&Arc<TranspileAndEmitOptions>, CompilerOptionsParseError> {
let value = self.map.get_for_specifier(specifier);
value.transpile_options()
}

pub fn folder_for_specifier(&self, specifier: &Url) -> &TsConfigFolderInfo {
self.folder_for_specifier_str(specifier.as_str())
}

pub fn folder_for_specifier_str(
&self,
specifier: &str,
) -> &TsConfigFolderInfo {
self.map.get_for_specifier_str(specifier)
}

pub fn folder_count(&self) -> usize {
self.map.count()
}
}

impl deno_graph::CheckJsResolver for TsConfigResolver {
fn resolve(&self, specifier: &deno_graph::ModuleSpecifier) -> bool {
self.check_js_for_specifier(specifier)
}
}

fn ts_config_to_transpile_and_emit_options(
config: deno_config::deno_json::TsConfig,
) -> Result<TranspileAndEmitOptions, serde_json::Error> {
let options: deno_config::deno_json::EmitConfigOptions =
serde_json::from_value(config.0)?;
let imports_not_used_as_values =
match options.imports_not_used_as_values.as_str() {
"preserve" => deno_ast::ImportsNotUsedAsValues::Preserve,
"error" => deno_ast::ImportsNotUsedAsValues::Error,
_ => deno_ast::ImportsNotUsedAsValues::Remove,
};
let (transform_jsx, jsx_automatic, jsx_development, precompile_jsx) =
match options.jsx.as_str() {
"react" => (true, false, false, false),
"react-jsx" => (true, true, false, false),
"react-jsxdev" => (true, true, true, false),
"precompile" => (false, false, false, true),
_ => (false, false, false, false),
};
let source_map = if options.inline_source_map {
SourceMapOption::Inline
} else if options.source_map {
SourceMapOption::Separate
} else {
SourceMapOption::None
};
let transpile = deno_ast::TranspileOptions {
use_ts_decorators: options.experimental_decorators,
use_decorators_proposal: !options.experimental_decorators,
emit_metadata: options.emit_decorator_metadata,
imports_not_used_as_values,
jsx_automatic,
jsx_development,
jsx_factory: options.jsx_factory,
jsx_fragment_factory: options.jsx_fragment_factory,
jsx_import_source: options.jsx_import_source,
precompile_jsx,
precompile_jsx_skip_elements: options.jsx_precompile_skip_elements,
precompile_jsx_dynamic_props: None,
transform_jsx,
var_decl_imports: false,
// todo(dsherret): support verbatim_module_syntax here properly
verbatim_module_syntax: false,
};
let emit = deno_ast::EmitOptions {
inline_sources: options.inline_sources,
remove_comments: false,
source_map,
source_map_base: None,
source_map_file: None,
};
let transpile_and_emit_options_hash = {
let mut hasher = FastInsecureHasher::new_without_deno_version();
hasher.write_hashable(&transpile);
hasher.write_hashable(&emit);
hasher.finish()
};
Ok(TranspileAndEmitOptions {
transpile,
emit,
pre_computed_hash: transpile_and_emit_options_hash,
})
}
Loading
Loading