deno/libs/resolver/collections.rs
Nayeem Rahman 7a9ab843bd
feat(check): tsconfig "references", "extends", "files", "include" and "exclude" (#29843)
- Each workspace directory is probed for a `tsconfig.json`.
- These and any that are included by their `references` are put into a
list ordered by priority.
  - A tsconfig has lower priority than its `references`.
- An earlier listed entry in `references` has higher priority than a
later one.
- A probed tsconfig in an inner directory has higher priority than an
outer one. Their `references` would be interspersed between them.
- Each tsconfig has a filter based on its `files`, `include` and
`exclude` fields. If it doesn't have `files` or `include`, it will match
any path in its containing directory not exempted by `exclude`.
- For type-checking, each root path will be allocated compiler options
based on the first tsconfig it whose filter it matches from this list.
- Only if it doesn't match any tsconfig, it will fall back to using the
nearest `deno.json`. If it's a workspace member and the root `deno.json`
has `compilerOptions`, these will be merged using the same logic from
`extends`.

Inheritance between configs strictly occurs via `extends` in a
`tsconfig.json`, and between workspace member and root `deno.json`s'
`compilerOptions`. There is no implicit inheritance between
`tsconfig.json` and `deno.json`.

The default compiler options currently applied against tsconfigs are
Deno's normal defaults, with the exception of `lib`. The default value
for `lib` is `["deno.window", "deno.unstable", "dom"]` for files in the
scope of a tsconfig with `lib` unspecified. This behaviour is depended
on by, for example, the template project created by `create-vite ->
svelte`. I expect we'll add more such exceptions over time with other
fields.
2025-06-26 21:17:07 +00:00

104 lines
2.5 KiB
Rust

// Copyright 2018-2025 the Deno authors. MIT license.
use std::collections::BTreeMap;
use url::Url;
#[allow(clippy::disallowed_types)]
type UrlRc = crate::sync::MaybeArc<Url>;
/// A map that stores values scoped to a specific directory
/// on the file system.
///
/// The root directory is considered "unscoped" so values that
/// fall outside the other directories land here (ex. remote modules).
pub struct FolderScopedMap<TValue> {
pub unscoped: TValue,
scoped: BTreeMap<UrlRc, TValue>,
}
impl<TValue> std::fmt::Debug for FolderScopedMap<TValue>
where
TValue: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FolderScopedMap")
.field("unscoped", &self.unscoped)
.field("scoped", &self.scoped)
.finish()
}
}
impl<TValue> Default for FolderScopedMap<TValue>
where
TValue: Default,
{
fn default() -> Self {
Self::new(Default::default())
}
}
impl<TValue> FolderScopedMap<TValue> {
pub fn new(unscoped: TValue) -> Self {
Self {
unscoped,
scoped: Default::default(),
}
}
pub fn count(&self) -> usize {
// +1 for unscoped
self.scoped.len() + 1
}
pub fn get_for_specifier(&self, specifier: &Url) -> &TValue {
self.get_for_specifier_str(specifier.as_str())
}
pub fn get_for_specifier_str(&self, specifier: &str) -> &TValue {
self
.scoped
.iter()
.rfind(|(s, _)| specifier.starts_with(s.as_str()))
.map(|(_, v)| v)
.unwrap_or(&self.unscoped)
}
pub fn entry_for_specifier(
&self,
specifier: &Url,
) -> (Option<&UrlRc>, &TValue) {
self
.scoped
.iter()
.rfind(|(s, _)| specifier.as_str().starts_with(s.as_str()))
.map(|(s, v)| (Some(s), v))
.unwrap_or((None, &self.unscoped))
}
pub fn entries(&self) -> impl Iterator<Item = (Option<&UrlRc>, &TValue)> {
[(None, &self.unscoped)]
.into_iter()
.chain(self.scoped.iter().map(|(s, v)| (Some(s), v)))
}
pub fn insert(&mut self, dir_url: UrlRc, value: TValue) {
debug_assert!(dir_url.path().ends_with("/")); // must be a dir url
debug_assert_eq!(dir_url.scheme(), "file");
self.scoped.insert(dir_url, value);
}
pub fn try_map<B, E>(
&self,
mut f: impl FnMut(&TValue) -> Result<B, E>,
) -> Result<FolderScopedMap<B>, E> {
Ok(FolderScopedMap {
unscoped: f(&self.unscoped)?,
scoped: self
.scoped
.iter()
.map(|(s, v)| Ok((s.clone(), f(v)?)))
.collect::<Result<_, _>>()?,
})
}
}