From 37fdece72f7a5bdb24bbd56aa20a43ee4d142001 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 18 Jun 2025 10:57:36 +0200 Subject: [PATCH] [ty] Anchor all exclude patterns (#18685) Co-authored-by: Andrew Gallant --- crates/ty/docs/configuration.md | 50 +++++----- crates/ty/src/args.rs | 11 +-- crates/ty/tests/cli/file_selection.rs | 4 +- crates/ty_project/src/glob.rs | 4 +- crates/ty_project/src/glob/exclude.rs | 25 ++--- crates/ty_project/src/glob/include.rs | 4 +- crates/ty_project/src/glob/portable.rs | 36 +++---- crates/ty_project/src/metadata/options.rs | 115 +++++++++++----------- crates/ty_project/src/metadata/value.rs | 75 +++----------- ty.schema.json | 4 +- 10 files changed, 134 insertions(+), 194 deletions(-) diff --git a/crates/ty/docs/configuration.md b/crates/ty/docs/configuration.md index 1ff58a5437..e37fc42924 100644 --- a/crates/ty/docs/configuration.md +++ b/crates/ty/docs/configuration.md @@ -270,7 +270,7 @@ A list of file and directory patterns to exclude from type checking. Patterns follow a syntax similar to `.gitignore`: - `./src/` matches only a directory - `./src` matches both files and directories -- `src` matches files or directories named `src` anywhere in the tree (e.g. `./src` or `./tests/src`) +- `src` matches files or directories named `src` - `*` matches any (possibly empty) sequence of characters (except `/`). - `**` matches zero or more path components. This sequence **must** form a single path component, so both `**a` and `b**` are invalid and will result in an error. @@ -280,28 +280,32 @@ Patterns follow a syntax similar to `.gitignore`: so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid. - `!pattern` negates a pattern (undoes the exclusion of files that would otherwise be excluded) -By default, the following directories are excluded: +All paths are anchored relative to the project root (`src` only +matches `/src` and not `/test/src`). +To exclude any directory or file named `src`, use `**/src` instead. -- `.bzr` -- `.direnv` -- `.eggs` -- `.git` -- `.git-rewrite` -- `.hg` -- `.mypy_cache` -- `.nox` -- `.pants.d` -- `.pytype` -- `.ruff_cache` -- `.svn` -- `.tox` -- `.venv` -- `__pypackages__` -- `_build` -- `buck-out` -- `dist` -- `node_modules` -- `venv` +By default, ty excludes commonly ignored directories: + +- `**/.bzr/` +- `**/.direnv/` +- `**/.eggs/` +- `**/.git/` +- `**/.git-rewrite/` +- `**/.hg/` +- `**/.mypy_cache/` +- `**/.nox/` +- `**/.pants.d/` +- `**/.pytype/` +- `**/.ruff_cache/` +- `**/.svn/` +- `**/.tox/` +- `**/.venv/` +- `**/__pypackages__/` +- `**/_build/` +- `**/buck-out/` +- `**/dist/` +- `**/node_modules/` +- `**/venv/` You can override any default exclude by using a negated pattern. For example, to re-include `dist` use `exclude = ["!dist"]` @@ -342,7 +346,7 @@ are type checked. - `[abc]` matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid. -Unlike `exclude`, all paths are anchored relative to the project root (`src` only +All paths are anchored relative to the project root (`src` only matches `/src` and not `/test/src`). `exclude` takes precedence over `include`. diff --git a/crates/ty/src/args.rs b/crates/ty/src/args.rs index 2dc77377dd..0d48bba54a 100644 --- a/crates/ty/src/args.rs +++ b/crates/ty/src/args.rs @@ -5,9 +5,7 @@ use clap::{ArgAction, ArgMatches, Error, Parser}; use ruff_db::system::SystemPathBuf; use ty_project::combine::Combine; use ty_project::metadata::options::{EnvironmentOptions, Options, SrcOptions, TerminalOptions}; -use ty_project::metadata::value::{ - RangedValue, RelativeExcludePattern, RelativePathBuf, ValueSource, -}; +use ty_project::metadata::value::{RangedValue, RelativeGlobPattern, RelativePathBuf, ValueSource}; use ty_python_semantic::lint; #[derive(Debug, Parser)] @@ -205,12 +203,7 @@ impl CheckCommand { src: Some(SrcOptions { respect_ignore_files, exclude: self.exclude.map(|excludes| { - RangedValue::cli( - excludes - .iter() - .map(|exclude| RelativeExcludePattern::cli(exclude)) - .collect(), - ) + RangedValue::cli(excludes.iter().map(RelativeGlobPattern::cli).collect()) }), ..SrcOptions::default() }), diff --git a/crates/ty/tests/cli/file_selection.rs b/crates/ty/tests/cli/file_selection.rs index 7c47e53bf5..4f84e2e7d5 100644 --- a/crates/ty/tests/cli/file_selection.rs +++ b/crates/ty/tests/cli/file_selection.rs @@ -283,7 +283,7 @@ fn exclude_precedence_over_include() -> anyhow::Result<()> { r#" [src] include = ["src"] - exclude = ["test_*.py"] + exclude = ["**/test_*.py"] "#, )?; @@ -404,7 +404,7 @@ fn remove_default_exclude() -> anyhow::Result<()> { "ty.toml", r#" [src] - exclude = ["!dist"] + exclude = ["!**/dist/"] "#, )?; diff --git a/crates/ty_project/src/glob.rs b/crates/ty_project/src/glob.rs index f681dee13b..e98a1e881c 100644 --- a/crates/ty_project/src/glob.rs +++ b/crates/ty_project/src/glob.rs @@ -2,7 +2,9 @@ use ruff_db::system::SystemPath; pub(crate) use exclude::{ExcludeFilter, ExcludeFilterBuilder}; pub(crate) use include::{IncludeFilter, IncludeFilterBuilder}; -pub(crate) use portable::{AbsolutePortableGlobPattern, PortableGlobError, PortableGlobPattern}; +pub(crate) use portable::{ + AbsolutePortableGlobPattern, PortableGlobError, PortableGlobKind, PortableGlobPattern, +}; mod exclude; mod include; diff --git a/crates/ty_project/src/glob/exclude.rs b/crates/ty_project/src/glob/exclude.rs index 9a0b1a4093..4f236db196 100644 --- a/crates/ty_project/src/glob/exclude.rs +++ b/crates/ty_project/src/glob/exclude.rs @@ -100,16 +100,16 @@ impl ExcludeFilterBuilder { /// Matcher for gitignore like globs. /// /// This code is our own vendored copy of the ignore's crate `Gitignore` type. -/// The main difference to `ignore`'s version is that it makes use -/// of the fact that all our globs are absolute. This simplifies the implementation a fair bit. -/// Making globs absolute is also because the globs can come from both the CLI and configuration files, -/// where the paths are anchored relative to the current working directory or the project root respectively. /// -/// Vendoring our own copy has the added benefit that we don't need to deal with ignore's `Error` type. -/// Instead, we can exclusively use [`globset::Error`]. +/// The differences with the ignore's crate version are: /// -/// This implementation also removes supported for comments, because the patterns aren't read -/// from a `.gitignore` file. This removes the need to escape `#` for file names starting with `#`, +/// * All globs are anchored. `src` matches `./src` only and not `**/src` to be consistent with `include`. +/// * It makes use of the fact that all our globs are absolute. This simplifies the implementation a fair bit. +/// Making globs absolute is also motivated by the fact that the globs can come from both the CLI and configuration files, +/// where the paths are anchored relative to the current working directory or the project root respectively. +/// * It uses [`globset::Error`] over the ignore's crate `Error` type. +/// * Removes supported for commented lines, because the patterns aren't read +/// from a `.gitignore` file. This removes the need to escape `#` for file names starting with `#`, /// /// You can find the original source on [GitHub](https://github.com/BurntSushi/ripgrep/blob/cbc598f245f3c157a872b69102653e2e349b6d92/crates/ignore/src/gitignore.rs#L81). /// @@ -267,15 +267,6 @@ impl GitignoreBuilder { let mut actual = pattern.to_string(); - // If there is a literal slash, then this is a glob that must match the - // entire path name. Otherwise, we should let it match anywhere, so use - // a **/ prefix. - if !pattern.chars().any(|c| c == '/') { - // ... but only if we don't already have a **/ prefix. - if !pattern.starts_with("**/") { - actual = format!("**/{actual}"); - } - } // If the glob ends with `/**`, then we should only match everything // inside a directory, but not the directory itself. Standard globs // will match the directory. So we add `/*` to force the issue. diff --git a/crates/ty_project/src/glob/include.rs b/crates/ty_project/src/glob/include.rs index dc9e10dd48..c3c61f26f2 100644 --- a/crates/ty_project/src/glob/include.rs +++ b/crates/ty_project/src/glob/include.rs @@ -241,8 +241,8 @@ impl IncludeFilterBuilder { mod tests { use std::path::{MAIN_SEPARATOR, MAIN_SEPARATOR_STR}; - use crate::glob::PortableGlobPattern; use crate::glob::include::{IncludeFilter, IncludeFilterBuilder}; + use crate::glob::{PortableGlobKind, PortableGlobPattern}; use ruff_db::system::{MemoryFileSystem, walk_directory::WalkState}; fn create_filter(patterns: impl IntoIterator) -> IncludeFilter { @@ -250,7 +250,7 @@ mod tests { for pattern in patterns { builder .add( - &PortableGlobPattern::parse(pattern, false) + &PortableGlobPattern::parse(pattern, PortableGlobKind::Include) .unwrap() .into_absolute(""), ) diff --git a/crates/ty_project/src/glob/portable.rs b/crates/ty_project/src/glob/portable.rs index 7b147c4a61..dd21666cc4 100644 --- a/crates/ty_project/src/glob/portable.rs +++ b/crates/ty_project/src/glob/portable.rs @@ -32,15 +32,15 @@ use thiserror::Error; #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub(crate) struct PortableGlobPattern<'a> { pattern: &'a str, - is_exclude: bool, + kind: PortableGlobKind, } impl<'a> PortableGlobPattern<'a> { /// Parses a portable glob pattern. Returns an error if the pattern isn't valid. - pub(crate) fn parse(glob: &'a str, is_exclude: bool) -> Result { + pub(crate) fn parse(glob: &'a str, kind: PortableGlobKind) -> Result { let mut chars = glob.chars().enumerate().peekable(); - if is_exclude { + if matches!(kind, PortableGlobKind::Exclude) { chars.next_if(|(_, c)| *c == '!'); } @@ -124,7 +124,7 @@ impl<'a> PortableGlobPattern<'a> { } Ok(PortableGlobPattern { pattern: glob, - is_exclude, + kind, }) } @@ -138,21 +138,12 @@ impl<'a> PortableGlobPattern<'a> { let mut pattern = self.pattern; let mut negated = false; - if self.is_exclude { + if matches!(self.kind, PortableGlobKind::Exclude) { // If the pattern starts with `!`, we need to remove it and then anchor the rest. if let Some(after) = self.pattern.strip_prefix('!') { pattern = after; negated = true; } - - // Patterns that don't contain any `/`, e.g. `.venv` are unanchored patterns - // that match anywhere. - if !self.chars().any(|c| c == '/') { - return AbsolutePortableGlobPattern { - absolute: self.to_string(), - relative: self.pattern.to_string(), - }; - } } if pattern.starts_with('/') { @@ -242,6 +233,15 @@ impl AbsolutePortableGlobPattern { } } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub(crate) enum PortableGlobKind { + /// An include pattern. Doesn't allow negated patterns. + Include, + + /// An exclude pattern. Allows for negated patterns. + Exclude, +} + #[derive(Debug, Error)] pub(crate) enum PortableGlobError { /// Shows the failing glob in the error message. @@ -284,7 +284,7 @@ impl std::fmt::Display for InvalidChar { #[cfg(test)] mod tests { - use crate::glob::PortableGlobPattern; + use crate::glob::{PortableGlobKind, PortableGlobPattern}; use insta::assert_snapshot; use ruff_db::system::SystemPath; @@ -292,7 +292,7 @@ mod tests { fn test_error() { #[track_caller] fn parse_err(glob: &str) -> String { - let error = PortableGlobPattern::parse(glob, true).unwrap_err(); + let error = PortableGlobPattern::parse(glob, PortableGlobKind::Exclude).unwrap_err(); error.to_string() } @@ -376,13 +376,13 @@ mod tests { r"**/\@test", ]; for case in cases.iter().chain(cases_uv.iter()) { - PortableGlobPattern::parse(case, true).unwrap(); + PortableGlobPattern::parse(case, PortableGlobKind::Exclude).unwrap(); } } #[track_caller] fn assert_absolute_path(pattern: &str, relative_to: impl AsRef, expected: &str) { - let pattern = PortableGlobPattern::parse(pattern, true).unwrap(); + let pattern = PortableGlobPattern::parse(pattern, PortableGlobKind::Exclude).unwrap(); let pattern = pattern.into_absolute(relative_to); assert_eq!(pattern.absolute(), expected); } diff --git a/crates/ty_project/src/metadata/options.rs b/crates/ty_project/src/metadata/options.rs index b81c8c43dc..7af7bf6591 100644 --- a/crates/ty_project/src/metadata/options.rs +++ b/crates/ty_project/src/metadata/options.rs @@ -1,10 +1,9 @@ use crate::Db; use crate::combine::Combine; -use crate::glob::{ExcludeFilter, IncludeExcludeFilter, IncludeFilter}; +use crate::glob::{ExcludeFilter, IncludeExcludeFilter, IncludeFilter, PortableGlobKind}; use crate::metadata::settings::{OverrideSettings, SrcSettings}; use crate::metadata::value::{ - RangedValue, RelativeExcludePattern, RelativeIncludePattern, RelativePathBuf, ValueSource, - ValueSourceGuard, + RangedValue, RelativeGlobPattern, RelativePathBuf, ValueSource, ValueSourceGuard, }; use ordermap::OrderMap; @@ -475,7 +474,7 @@ pub struct SrcOptions { /// - `[abc]` matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, /// so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid. /// - /// Unlike `exclude`, all paths are anchored relative to the project root (`src` only + /// All paths are anchored relative to the project root (`src` only /// matches `/src` and not `/test/src`). /// /// `exclude` takes precedence over `include`. @@ -490,14 +489,14 @@ pub struct SrcOptions { ] "# )] - pub include: Option>>, + pub include: Option>>, /// A list of file and directory patterns to exclude from type checking. /// /// Patterns follow a syntax similar to `.gitignore`: /// - `./src/` matches only a directory /// - `./src` matches both files and directories - /// - `src` matches files or directories named `src` anywhere in the tree (e.g. `./src` or `./tests/src`) + /// - `src` matches files or directories named `src` /// - `*` matches any (possibly empty) sequence of characters (except `/`). /// - `**` matches zero or more path components. /// This sequence **must** form a single path component, so both `**a` and `b**` are invalid and will result in an error. @@ -507,28 +506,32 @@ pub struct SrcOptions { /// so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid. /// - `!pattern` negates a pattern (undoes the exclusion of files that would otherwise be excluded) /// - /// By default, the following directories are excluded: + /// All paths are anchored relative to the project root (`src` only + /// matches `/src` and not `/test/src`). + /// To exclude any directory or file named `src`, use `**/src` instead. /// - /// - `.bzr` - /// - `.direnv` - /// - `.eggs` - /// - `.git` - /// - `.git-rewrite` - /// - `.hg` - /// - `.mypy_cache` - /// - `.nox` - /// - `.pants.d` - /// - `.pytype` - /// - `.ruff_cache` - /// - `.svn` - /// - `.tox` - /// - `.venv` - /// - `__pypackages__` - /// - `_build` - /// - `buck-out` - /// - `dist` - /// - `node_modules` - /// - `venv` + /// By default, ty excludes commonly ignored directories: + /// + /// - `**/.bzr/` + /// - `**/.direnv/` + /// - `**/.eggs/` + /// - `**/.git/` + /// - `**/.git-rewrite/` + /// - `**/.hg/` + /// - `**/.mypy_cache/` + /// - `**/.nox/` + /// - `**/.pants.d/` + /// - `**/.pytype/` + /// - `**/.ruff_cache/` + /// - `**/.svn/` + /// - `**/.tox/` + /// - `**/.venv/` + /// - `**/__pypackages__/` + /// - `**/_build/` + /// - `**/buck-out/` + /// - `**/dist/` + /// - `**/node_modules/` + /// - `**/venv/` /// /// You can override any default exclude by using a negated pattern. For example, /// to re-include `dist` use `exclude = ["!dist"]` @@ -545,7 +548,7 @@ pub struct SrcOptions { "# )] #[serde(skip_serializing_if = "Option::is_none")] - pub exclude: Option>>, + pub exclude: Option>>, } impl SrcOptions { @@ -672,33 +675,33 @@ impl Rules { /// Default exclude patterns for src options. const DEFAULT_SRC_EXCLUDES: &[&str] = &[ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".git-rewrite", - ".hg", - ".mypy_cache", - ".nox", - ".pants.d", - ".pytype", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - "__pypackages__", - "_build", - "buck-out", - "dist", - "node_modules", - "venv", + "**/.bzr/", + "**/.direnv/", + "**/.eggs/", + "**/.git/", + "**/.git-rewrite/", + "**/.hg/", + "**/.mypy_cache/", + "**/.nox/", + "**/.pants.d/", + "**/.pytype/", + "**/.ruff_cache/", + "**/.svn/", + "**/.tox/", + "**/.venv/", + "**/__pypackages__/", + "**/_build/", + "**/buck-out/", + "**/dist/", + "**/node_modules/", + "**/venv/", ]; /// Helper function to build an include filter from patterns with proper error handling. fn build_include_filter( db: &dyn Db, project_root: &SystemPath, - include_patterns: Option<&RangedValue>>, + include_patterns: Option<&RangedValue>>, context: GlobFilterContext, diagnostics: &mut Vec, ) -> Result> { @@ -735,7 +738,7 @@ fn build_include_filter( } for pattern in include_patterns { - pattern.absolute(project_root, system) + pattern.absolute(project_root, system, PortableGlobKind::Include) .and_then(|include| Ok(includes.add(&include)?)) .map_err(|err| { let diagnostic = OptionDiagnostic::new( @@ -773,7 +776,7 @@ fn build_include_filter( } else { includes .add( - &PortableGlobPattern::parse("**", false) + &PortableGlobPattern::parse("**", PortableGlobKind::Include) .unwrap() .into_absolute(""), ) @@ -797,7 +800,7 @@ fn build_include_filter( fn build_exclude_filter( db: &dyn Db, project_root: &SystemPath, - exclude_patterns: Option<&RangedValue>>, + exclude_patterns: Option<&RangedValue>>, default_patterns: &[&str], context: GlobFilterContext, ) -> Result> { @@ -807,7 +810,7 @@ fn build_exclude_filter( let mut excludes = ExcludeFilterBuilder::new(); for pattern in default_patterns { - PortableGlobPattern::parse(pattern, true) + PortableGlobPattern::parse(pattern, PortableGlobKind::Exclude) .and_then(|exclude| Ok(excludes.add(&exclude.into_absolute(""))?)) .unwrap_or_else(|err| { panic!("Expected default exclude to be valid glob but adding it failed with: {err}") @@ -817,7 +820,7 @@ fn build_exclude_filter( // Add user-specified excludes if let Some(exclude_patterns) = exclude_patterns { for exclude in exclude_patterns { - exclude.absolute(project_root, system) + exclude.absolute(project_root, system, PortableGlobKind::Exclude) .and_then(|pattern| Ok(excludes.add(&pattern)?)) .map_err(|err| { let diagnostic = OptionDiagnostic::new( @@ -1001,7 +1004,7 @@ pub struct OverrideOptions { ] "# )] - pub include: Option>>, + pub include: Option>>, /// A list of file and directory patterns to exclude from this override. /// @@ -1023,7 +1026,7 @@ pub struct OverrideOptions { ] "# )] - pub exclude: Option>>, + pub exclude: Option>>, /// Rule overrides for files matching the include/exclude patterns. /// diff --git a/crates/ty_project/src/metadata/value.rs b/crates/ty_project/src/metadata/value.rs index 5d38185e13..1ad5b58e87 100644 --- a/crates/ty_project/src/metadata/value.rs +++ b/crates/ty_project/src/metadata/value.rs @@ -1,6 +1,8 @@ use crate::Db; use crate::combine::Combine; -use crate::glob::{AbsolutePortableGlobPattern, PortableGlobError, PortableGlobPattern}; +use crate::glob::{ + AbsolutePortableGlobPattern, PortableGlobError, PortableGlobKind, PortableGlobPattern, +}; use ruff_db::system::{System, SystemPath, SystemPathBuf}; use ruff_macros::Combine; use ruff_text_size::{TextRange, TextSize}; @@ -372,14 +374,14 @@ impl RelativePathBuf { )] #[serde(transparent)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -pub struct RelativeIncludePattern(RangedValue); +pub struct RelativeGlobPattern(RangedValue); -impl RelativeIncludePattern { - pub fn new(pattern: &str, source: ValueSource) -> Self { - Self(RangedValue::new(pattern.to_string(), source)) +impl RelativeGlobPattern { + pub fn new(pattern: impl AsRef, source: ValueSource) -> Self { + Self(RangedValue::new(pattern.as_ref().to_string(), source)) } - pub fn cli(pattern: &str) -> Self { + pub fn cli(pattern: impl AsRef) -> Self { Self::new(pattern, ValueSource::Cli) } @@ -396,74 +398,19 @@ impl RelativeIncludePattern { &self, project_root: &SystemPath, system: &dyn System, + kind: PortableGlobKind, ) -> Result { let relative_to = match &self.0.source { ValueSource::File(_) => project_root, ValueSource::Cli => system.current_directory(), }; - let pattern = PortableGlobPattern::parse(&self.0, false)?; + let pattern = PortableGlobPattern::parse(&self.0, kind)?; Ok(pattern.into_absolute(relative_to)) } } -impl std::fmt::Display for RelativeIncludePattern { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[derive( - Debug, - Clone, - serde::Serialize, - serde::Deserialize, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Combine, -)] -#[serde(transparent)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -pub struct RelativeExcludePattern(RangedValue); - -impl RelativeExcludePattern { - pub fn new(pattern: &str, source: ValueSource) -> Self { - Self(RangedValue::new(pattern.to_string(), source)) - } - - pub fn cli(pattern: &str) -> Self { - Self::new(pattern, ValueSource::Cli) - } - - pub(crate) fn source(&self) -> &ValueSource { - self.0.source() - } - - pub(crate) fn range(&self) -> Option { - self.0.range() - } - - /// Resolves the absolute pattern for `self` based on its origin. - pub(crate) fn absolute( - &self, - project_root: &SystemPath, - system: &dyn System, - ) -> Result { - let relative_to = match &self.0.source { - ValueSource::File(_) => project_root, - ValueSource::Cli => system.current_directory(), - }; - - let pattern = PortableGlobPattern::parse(&self.0, true)?; - - Ok(pattern.into_absolute(relative_to)) - } -} - -impl std::fmt::Display for RelativeExcludePattern { +impl std::fmt::Display for RelativeGlobPattern { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } diff --git a/ty.schema.json b/ty.schema.json index 7485084b38..e6b871ecdd 100644 --- a/ty.schema.json +++ b/ty.schema.json @@ -920,7 +920,7 @@ "type": "object", "properties": { "exclude": { - "description": "A list of file and directory patterns to exclude from type checking.\n\nPatterns follow a syntax similar to `.gitignore`: - `./src/` matches only a directory - `./src` matches both files and directories - `src` matches files or directories named `src` anywhere in the tree (e.g. `./src` or `./tests/src`) - `*` matches any (possibly empty) sequence of characters (except `/`). - `**` matches zero or more path components. This sequence **must** form a single path component, so both `**a` and `b**` are invalid and will result in an error. A sequence of more than two consecutive `*` characters is also invalid. - `?` matches any single character except `/` - `[abc]` matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid. - `!pattern` negates a pattern (undoes the exclusion of files that would otherwise be excluded)\n\nBy default, the following directories are excluded:\n\n- `.bzr` - `.direnv` - `.eggs` - `.git` - `.git-rewrite` - `.hg` - `.mypy_cache` - `.nox` - `.pants.d` - `.pytype` - `.ruff_cache` - `.svn` - `.tox` - `.venv` - `__pypackages__` - `_build` - `buck-out` - `dist` - `node_modules` - `venv`\n\nYou can override any default exclude by using a negated pattern. For example, to re-include `dist` use `exclude = [\"!dist\"]`", + "description": "A list of file and directory patterns to exclude from type checking.\n\nPatterns follow a syntax similar to `.gitignore`: - `./src/` matches only a directory - `./src` matches both files and directories - `src` matches files or directories named `src` - `*` matches any (possibly empty) sequence of characters (except `/`). - `**` matches zero or more path components. This sequence **must** form a single path component, so both `**a` and `b**` are invalid and will result in an error. A sequence of more than two consecutive `*` characters is also invalid. - `?` matches any single character except `/` - `[abc]` matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid. - `!pattern` negates a pattern (undoes the exclusion of files that would otherwise be excluded)\n\nAll paths are anchored relative to the project root (`src` only matches `/src` and not `/test/src`). To exclude any directory or file named `src`, use `**/src` instead.\n\nBy default, ty excludes commonly ignored directories:\n\n- `**/.bzr/` - `**/.direnv/` - `**/.eggs/` - `**/.git/` - `**/.git-rewrite/` - `**/.hg/` - `**/.mypy_cache/` - `**/.nox/` - `**/.pants.d/` - `**/.pytype/` - `**/.ruff_cache/` - `**/.svn/` - `**/.tox/` - `**/.venv/` - `**/__pypackages__/` - `**/_build/` - `**/buck-out/` - `**/dist/` - `**/node_modules/` - `**/venv/`\n\nYou can override any default exclude by using a negated pattern. For example, to re-include `dist` use `exclude = [\"!dist\"]`", "type": [ "array", "null" @@ -930,7 +930,7 @@ } }, "include": { - "description": "A list of files and directories to check. The `include` option follows a similar syntax to `.gitignore` but reversed: Including a file or directory will make it so that it (and its contents) are type checked.\n\n- `./src/` matches only a directory - `./src` matches both files and directories - `src` matches a file or directory named `src` - `*` matches any (possibly empty) sequence of characters (except `/`). - `**` matches zero or more path components. This sequence **must** form a single path component, so both `**a` and `b**` are invalid and will result in an error. A sequence of more than two consecutive `*` characters is also invalid. - `?` matches any single character except `/` - `[abc]` matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid.\n\nUnlike `exclude`, all paths are anchored relative to the project root (`src` only matches `/src` and not `/test/src`).\n\n`exclude` takes precedence over `include`.", + "description": "A list of files and directories to check. The `include` option follows a similar syntax to `.gitignore` but reversed: Including a file or directory will make it so that it (and its contents) are type checked.\n\n- `./src/` matches only a directory - `./src` matches both files and directories - `src` matches a file or directory named `src` - `*` matches any (possibly empty) sequence of characters (except `/`). - `**` matches zero or more path components. This sequence **must** form a single path component, so both `**a` and `b**` are invalid and will result in an error. A sequence of more than two consecutive `*` characters is also invalid. - `?` matches any single character except `/` - `[abc]` matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character between `0` and `9` inclusive. An unclosed bracket is invalid.\n\nAll paths are anchored relative to the project root (`src` only matches `/src` and not `/test/src`).\n\n`exclude` takes precedence over `include`.", "type": [ "array", "null"