mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 06:11:21 +00:00
[ty] Anchor all exclude patterns (#18685)
Co-authored-by: Andrew Gallant <andrew@astral.sh>
This commit is contained in:
parent
8184dae287
commit
37fdece72f
10 changed files with 134 additions and 194 deletions
50
crates/ty/docs/configuration.md
generated
50
crates/ty/docs/configuration.md
generated
|
@ -270,7 +270,7 @@ A list of file and directory patterns to exclude from type checking.
|
||||||
Patterns follow a syntax similar to `.gitignore`:
|
Patterns follow a syntax similar to `.gitignore`:
|
||||||
- `./src/` matches only a directory
|
- `./src/` matches only a directory
|
||||||
- `./src` matches both files and directories
|
- `./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 any (possibly empty) sequence of characters (except `/`).
|
||||||
- `**` matches zero or more path components.
|
- `**` 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.
|
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.
|
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)
|
- `!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 `<project_root>/src` and not `<project_root>/test/src`).
|
||||||
|
To exclude any directory or file named `src`, use `**/src` instead.
|
||||||
|
|
||||||
- `.bzr`
|
By default, ty excludes commonly ignored directories:
|
||||||
- `.direnv`
|
|
||||||
- `.eggs`
|
- `**/.bzr/`
|
||||||
- `.git`
|
- `**/.direnv/`
|
||||||
- `.git-rewrite`
|
- `**/.eggs/`
|
||||||
- `.hg`
|
- `**/.git/`
|
||||||
- `.mypy_cache`
|
- `**/.git-rewrite/`
|
||||||
- `.nox`
|
- `**/.hg/`
|
||||||
- `.pants.d`
|
- `**/.mypy_cache/`
|
||||||
- `.pytype`
|
- `**/.nox/`
|
||||||
- `.ruff_cache`
|
- `**/.pants.d/`
|
||||||
- `.svn`
|
- `**/.pytype/`
|
||||||
- `.tox`
|
- `**/.ruff_cache/`
|
||||||
- `.venv`
|
- `**/.svn/`
|
||||||
- `__pypackages__`
|
- `**/.tox/`
|
||||||
- `_build`
|
- `**/.venv/`
|
||||||
- `buck-out`
|
- `**/__pypackages__/`
|
||||||
- `dist`
|
- `**/_build/`
|
||||||
- `node_modules`
|
- `**/buck-out/`
|
||||||
- `venv`
|
- `**/dist/`
|
||||||
|
- `**/node_modules/`
|
||||||
|
- `**/venv/`
|
||||||
|
|
||||||
You can override any default exclude by using a negated pattern. For example,
|
You can override any default exclude by using a negated pattern. For example,
|
||||||
to re-include `dist` use `exclude = ["!dist"]`
|
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,
|
- `[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.
|
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 `<project_root>/src` and not `<project_root>/test/src`).
|
matches `<project_root>/src` and not `<project_root>/test/src`).
|
||||||
|
|
||||||
`exclude` takes precedence over `include`.
|
`exclude` takes precedence over `include`.
|
||||||
|
|
|
@ -5,9 +5,7 @@ use clap::{ArgAction, ArgMatches, Error, Parser};
|
||||||
use ruff_db::system::SystemPathBuf;
|
use ruff_db::system::SystemPathBuf;
|
||||||
use ty_project::combine::Combine;
|
use ty_project::combine::Combine;
|
||||||
use ty_project::metadata::options::{EnvironmentOptions, Options, SrcOptions, TerminalOptions};
|
use ty_project::metadata::options::{EnvironmentOptions, Options, SrcOptions, TerminalOptions};
|
||||||
use ty_project::metadata::value::{
|
use ty_project::metadata::value::{RangedValue, RelativeGlobPattern, RelativePathBuf, ValueSource};
|
||||||
RangedValue, RelativeExcludePattern, RelativePathBuf, ValueSource,
|
|
||||||
};
|
|
||||||
use ty_python_semantic::lint;
|
use ty_python_semantic::lint;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
@ -205,12 +203,7 @@ impl CheckCommand {
|
||||||
src: Some(SrcOptions {
|
src: Some(SrcOptions {
|
||||||
respect_ignore_files,
|
respect_ignore_files,
|
||||||
exclude: self.exclude.map(|excludes| {
|
exclude: self.exclude.map(|excludes| {
|
||||||
RangedValue::cli(
|
RangedValue::cli(excludes.iter().map(RelativeGlobPattern::cli).collect())
|
||||||
excludes
|
|
||||||
.iter()
|
|
||||||
.map(|exclude| RelativeExcludePattern::cli(exclude))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
..SrcOptions::default()
|
..SrcOptions::default()
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -283,7 +283,7 @@ fn exclude_precedence_over_include() -> anyhow::Result<()> {
|
||||||
r#"
|
r#"
|
||||||
[src]
|
[src]
|
||||||
include = ["src"]
|
include = ["src"]
|
||||||
exclude = ["test_*.py"]
|
exclude = ["**/test_*.py"]
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ fn remove_default_exclude() -> anyhow::Result<()> {
|
||||||
"ty.toml",
|
"ty.toml",
|
||||||
r#"
|
r#"
|
||||||
[src]
|
[src]
|
||||||
exclude = ["!dist"]
|
exclude = ["!**/dist/"]
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,9 @@ use ruff_db::system::SystemPath;
|
||||||
|
|
||||||
pub(crate) use exclude::{ExcludeFilter, ExcludeFilterBuilder};
|
pub(crate) use exclude::{ExcludeFilter, ExcludeFilterBuilder};
|
||||||
pub(crate) use include::{IncludeFilter, IncludeFilterBuilder};
|
pub(crate) use include::{IncludeFilter, IncludeFilterBuilder};
|
||||||
pub(crate) use portable::{AbsolutePortableGlobPattern, PortableGlobError, PortableGlobPattern};
|
pub(crate) use portable::{
|
||||||
|
AbsolutePortableGlobPattern, PortableGlobError, PortableGlobKind, PortableGlobPattern,
|
||||||
|
};
|
||||||
|
|
||||||
mod exclude;
|
mod exclude;
|
||||||
mod include;
|
mod include;
|
||||||
|
|
|
@ -100,15 +100,15 @@ impl ExcludeFilterBuilder {
|
||||||
/// Matcher for gitignore like globs.
|
/// Matcher for gitignore like globs.
|
||||||
///
|
///
|
||||||
/// This code is our own vendored copy of the ignore's crate `Gitignore` type.
|
/// 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.
|
/// The differences with the ignore's crate version are:
|
||||||
/// Making globs absolute is also because the globs can come from both the CLI and configuration files,
|
///
|
||||||
|
/// * 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.
|
/// 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.
|
||||||
/// Vendoring our own copy has the added benefit that we don't need to deal with ignore's `Error` type.
|
/// * Removes supported for commented lines, because the patterns aren't read
|
||||||
/// Instead, we can exclusively use [`globset::Error`].
|
|
||||||
///
|
|
||||||
/// 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 `#`,
|
/// 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).
|
/// 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();
|
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
|
// If the glob ends with `/**`, then we should only match everything
|
||||||
// inside a directory, but not the directory itself. Standard globs
|
// inside a directory, but not the directory itself. Standard globs
|
||||||
// will match the directory. So we add `/*` to force the issue.
|
// will match the directory. So we add `/*` to force the issue.
|
||||||
|
|
|
@ -241,8 +241,8 @@ impl IncludeFilterBuilder {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::{MAIN_SEPARATOR, MAIN_SEPARATOR_STR};
|
use std::path::{MAIN_SEPARATOR, MAIN_SEPARATOR_STR};
|
||||||
|
|
||||||
use crate::glob::PortableGlobPattern;
|
|
||||||
use crate::glob::include::{IncludeFilter, IncludeFilterBuilder};
|
use crate::glob::include::{IncludeFilter, IncludeFilterBuilder};
|
||||||
|
use crate::glob::{PortableGlobKind, PortableGlobPattern};
|
||||||
use ruff_db::system::{MemoryFileSystem, walk_directory::WalkState};
|
use ruff_db::system::{MemoryFileSystem, walk_directory::WalkState};
|
||||||
|
|
||||||
fn create_filter(patterns: impl IntoIterator<Item = &'static str>) -> IncludeFilter {
|
fn create_filter(patterns: impl IntoIterator<Item = &'static str>) -> IncludeFilter {
|
||||||
|
@ -250,7 +250,7 @@ mod tests {
|
||||||
for pattern in patterns {
|
for pattern in patterns {
|
||||||
builder
|
builder
|
||||||
.add(
|
.add(
|
||||||
&PortableGlobPattern::parse(pattern, false)
|
&PortableGlobPattern::parse(pattern, PortableGlobKind::Include)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_absolute(""),
|
.into_absolute(""),
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,15 +32,15 @@ use thiserror::Error;
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub(crate) struct PortableGlobPattern<'a> {
|
pub(crate) struct PortableGlobPattern<'a> {
|
||||||
pattern: &'a str,
|
pattern: &'a str,
|
||||||
is_exclude: bool,
|
kind: PortableGlobKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PortableGlobPattern<'a> {
|
impl<'a> PortableGlobPattern<'a> {
|
||||||
/// Parses a portable glob pattern. Returns an error if the pattern isn't valid.
|
/// 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<Self, PortableGlobError> {
|
pub(crate) fn parse(glob: &'a str, kind: PortableGlobKind) -> Result<Self, PortableGlobError> {
|
||||||
let mut chars = glob.chars().enumerate().peekable();
|
let mut chars = glob.chars().enumerate().peekable();
|
||||||
|
|
||||||
if is_exclude {
|
if matches!(kind, PortableGlobKind::Exclude) {
|
||||||
chars.next_if(|(_, c)| *c == '!');
|
chars.next_if(|(_, c)| *c == '!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ impl<'a> PortableGlobPattern<'a> {
|
||||||
}
|
}
|
||||||
Ok(PortableGlobPattern {
|
Ok(PortableGlobPattern {
|
||||||
pattern: glob,
|
pattern: glob,
|
||||||
is_exclude,
|
kind,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,21 +138,12 @@ impl<'a> PortableGlobPattern<'a> {
|
||||||
let mut pattern = self.pattern;
|
let mut pattern = self.pattern;
|
||||||
let mut negated = false;
|
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 the pattern starts with `!`, we need to remove it and then anchor the rest.
|
||||||
if let Some(after) = self.pattern.strip_prefix('!') {
|
if let Some(after) = self.pattern.strip_prefix('!') {
|
||||||
pattern = after;
|
pattern = after;
|
||||||
negated = true;
|
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('/') {
|
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)]
|
#[derive(Debug, Error)]
|
||||||
pub(crate) enum PortableGlobError {
|
pub(crate) enum PortableGlobError {
|
||||||
/// Shows the failing glob in the error message.
|
/// Shows the failing glob in the error message.
|
||||||
|
@ -284,7 +284,7 @@ impl std::fmt::Display for InvalidChar {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::glob::PortableGlobPattern;
|
use crate::glob::{PortableGlobKind, PortableGlobPattern};
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
use ruff_db::system::SystemPath;
|
use ruff_db::system::SystemPath;
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ mod tests {
|
||||||
fn test_error() {
|
fn test_error() {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn parse_err(glob: &str) -> String {
|
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()
|
error.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,13 +376,13 @@ mod tests {
|
||||||
r"**/\@test",
|
r"**/\@test",
|
||||||
];
|
];
|
||||||
for case in cases.iter().chain(cases_uv.iter()) {
|
for case in cases.iter().chain(cases_uv.iter()) {
|
||||||
PortableGlobPattern::parse(case, true).unwrap();
|
PortableGlobPattern::parse(case, PortableGlobKind::Exclude).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_absolute_path(pattern: &str, relative_to: impl AsRef<SystemPath>, expected: &str) {
|
fn assert_absolute_path(pattern: &str, relative_to: impl AsRef<SystemPath>, expected: &str) {
|
||||||
let pattern = PortableGlobPattern::parse(pattern, true).unwrap();
|
let pattern = PortableGlobPattern::parse(pattern, PortableGlobKind::Exclude).unwrap();
|
||||||
let pattern = pattern.into_absolute(relative_to);
|
let pattern = pattern.into_absolute(relative_to);
|
||||||
assert_eq!(pattern.absolute(), expected);
|
assert_eq!(pattern.absolute(), expected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
use crate::combine::Combine;
|
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::settings::{OverrideSettings, SrcSettings};
|
||||||
use crate::metadata::value::{
|
use crate::metadata::value::{
|
||||||
RangedValue, RelativeExcludePattern, RelativeIncludePattern, RelativePathBuf, ValueSource,
|
RangedValue, RelativeGlobPattern, RelativePathBuf, ValueSource, ValueSourceGuard,
|
||||||
ValueSourceGuard,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ordermap::OrderMap;
|
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,
|
/// - `[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.
|
/// 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 `<project_root>/src` and not `<project_root>/test/src`).
|
/// matches `<project_root>/src` and not `<project_root>/test/src`).
|
||||||
///
|
///
|
||||||
/// `exclude` takes precedence over `include`.
|
/// `exclude` takes precedence over `include`.
|
||||||
|
@ -490,14 +489,14 @@ pub struct SrcOptions {
|
||||||
]
|
]
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
pub include: Option<RangedValue<Vec<RelativeIncludePattern>>>,
|
pub include: Option<RangedValue<Vec<RelativeGlobPattern>>>,
|
||||||
|
|
||||||
/// A list of file and directory patterns to exclude from type checking.
|
/// A list of file and directory patterns to exclude from type checking.
|
||||||
///
|
///
|
||||||
/// Patterns follow a syntax similar to `.gitignore`:
|
/// Patterns follow a syntax similar to `.gitignore`:
|
||||||
/// - `./src/` matches only a directory
|
/// - `./src/` matches only a directory
|
||||||
/// - `./src` matches both files and directories
|
/// - `./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 any (possibly empty) sequence of characters (except `/`).
|
||||||
/// - `**` matches zero or more path components.
|
/// - `**` 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.
|
/// 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.
|
/// 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)
|
/// - `!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 `<project_root>/src` and not `<project_root>/test/src`).
|
||||||
|
/// To exclude any directory or file named `src`, use `**/src` instead.
|
||||||
///
|
///
|
||||||
/// - `.bzr`
|
/// By default, ty excludes commonly ignored directories:
|
||||||
/// - `.direnv`
|
///
|
||||||
/// - `.eggs`
|
/// - `**/.bzr/`
|
||||||
/// - `.git`
|
/// - `**/.direnv/`
|
||||||
/// - `.git-rewrite`
|
/// - `**/.eggs/`
|
||||||
/// - `.hg`
|
/// - `**/.git/`
|
||||||
/// - `.mypy_cache`
|
/// - `**/.git-rewrite/`
|
||||||
/// - `.nox`
|
/// - `**/.hg/`
|
||||||
/// - `.pants.d`
|
/// - `**/.mypy_cache/`
|
||||||
/// - `.pytype`
|
/// - `**/.nox/`
|
||||||
/// - `.ruff_cache`
|
/// - `**/.pants.d/`
|
||||||
/// - `.svn`
|
/// - `**/.pytype/`
|
||||||
/// - `.tox`
|
/// - `**/.ruff_cache/`
|
||||||
/// - `.venv`
|
/// - `**/.svn/`
|
||||||
/// - `__pypackages__`
|
/// - `**/.tox/`
|
||||||
/// - `_build`
|
/// - `**/.venv/`
|
||||||
/// - `buck-out`
|
/// - `**/__pypackages__/`
|
||||||
/// - `dist`
|
/// - `**/_build/`
|
||||||
/// - `node_modules`
|
/// - `**/buck-out/`
|
||||||
/// - `venv`
|
/// - `**/dist/`
|
||||||
|
/// - `**/node_modules/`
|
||||||
|
/// - `**/venv/`
|
||||||
///
|
///
|
||||||
/// You can override any default exclude by using a negated pattern. For example,
|
/// You can override any default exclude by using a negated pattern. For example,
|
||||||
/// to re-include `dist` use `exclude = ["!dist"]`
|
/// to re-include `dist` use `exclude = ["!dist"]`
|
||||||
|
@ -545,7 +548,7 @@ pub struct SrcOptions {
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub exclude: Option<RangedValue<Vec<RelativeExcludePattern>>>,
|
pub exclude: Option<RangedValue<Vec<RelativeGlobPattern>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SrcOptions {
|
impl SrcOptions {
|
||||||
|
@ -672,33 +675,33 @@ impl Rules {
|
||||||
|
|
||||||
/// Default exclude patterns for src options.
|
/// Default exclude patterns for src options.
|
||||||
const DEFAULT_SRC_EXCLUDES: &[&str] = &[
|
const DEFAULT_SRC_EXCLUDES: &[&str] = &[
|
||||||
".bzr",
|
"**/.bzr/",
|
||||||
".direnv",
|
"**/.direnv/",
|
||||||
".eggs",
|
"**/.eggs/",
|
||||||
".git",
|
"**/.git/",
|
||||||
".git-rewrite",
|
"**/.git-rewrite/",
|
||||||
".hg",
|
"**/.hg/",
|
||||||
".mypy_cache",
|
"**/.mypy_cache/",
|
||||||
".nox",
|
"**/.nox/",
|
||||||
".pants.d",
|
"**/.pants.d/",
|
||||||
".pytype",
|
"**/.pytype/",
|
||||||
".ruff_cache",
|
"**/.ruff_cache/",
|
||||||
".svn",
|
"**/.svn/",
|
||||||
".tox",
|
"**/.tox/",
|
||||||
".venv",
|
"**/.venv/",
|
||||||
"__pypackages__",
|
"**/__pypackages__/",
|
||||||
"_build",
|
"**/_build/",
|
||||||
"buck-out",
|
"**/buck-out/",
|
||||||
"dist",
|
"**/dist/",
|
||||||
"node_modules",
|
"**/node_modules/",
|
||||||
"venv",
|
"**/venv/",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Helper function to build an include filter from patterns with proper error handling.
|
/// Helper function to build an include filter from patterns with proper error handling.
|
||||||
fn build_include_filter(
|
fn build_include_filter(
|
||||||
db: &dyn Db,
|
db: &dyn Db,
|
||||||
project_root: &SystemPath,
|
project_root: &SystemPath,
|
||||||
include_patterns: Option<&RangedValue<Vec<RelativeIncludePattern>>>,
|
include_patterns: Option<&RangedValue<Vec<RelativeGlobPattern>>>,
|
||||||
context: GlobFilterContext,
|
context: GlobFilterContext,
|
||||||
diagnostics: &mut Vec<OptionDiagnostic>,
|
diagnostics: &mut Vec<OptionDiagnostic>,
|
||||||
) -> Result<IncludeFilter, Box<OptionDiagnostic>> {
|
) -> Result<IncludeFilter, Box<OptionDiagnostic>> {
|
||||||
|
@ -735,7 +738,7 @@ fn build_include_filter(
|
||||||
}
|
}
|
||||||
|
|
||||||
for pattern in include_patterns {
|
for pattern in include_patterns {
|
||||||
pattern.absolute(project_root, system)
|
pattern.absolute(project_root, system, PortableGlobKind::Include)
|
||||||
.and_then(|include| Ok(includes.add(&include)?))
|
.and_then(|include| Ok(includes.add(&include)?))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
let diagnostic = OptionDiagnostic::new(
|
let diagnostic = OptionDiagnostic::new(
|
||||||
|
@ -773,7 +776,7 @@ fn build_include_filter(
|
||||||
} else {
|
} else {
|
||||||
includes
|
includes
|
||||||
.add(
|
.add(
|
||||||
&PortableGlobPattern::parse("**", false)
|
&PortableGlobPattern::parse("**", PortableGlobKind::Include)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_absolute(""),
|
.into_absolute(""),
|
||||||
)
|
)
|
||||||
|
@ -797,7 +800,7 @@ fn build_include_filter(
|
||||||
fn build_exclude_filter(
|
fn build_exclude_filter(
|
||||||
db: &dyn Db,
|
db: &dyn Db,
|
||||||
project_root: &SystemPath,
|
project_root: &SystemPath,
|
||||||
exclude_patterns: Option<&RangedValue<Vec<RelativeExcludePattern>>>,
|
exclude_patterns: Option<&RangedValue<Vec<RelativeGlobPattern>>>,
|
||||||
default_patterns: &[&str],
|
default_patterns: &[&str],
|
||||||
context: GlobFilterContext,
|
context: GlobFilterContext,
|
||||||
) -> Result<ExcludeFilter, Box<OptionDiagnostic>> {
|
) -> Result<ExcludeFilter, Box<OptionDiagnostic>> {
|
||||||
|
@ -807,7 +810,7 @@ fn build_exclude_filter(
|
||||||
let mut excludes = ExcludeFilterBuilder::new();
|
let mut excludes = ExcludeFilterBuilder::new();
|
||||||
|
|
||||||
for pattern in default_patterns {
|
for pattern in default_patterns {
|
||||||
PortableGlobPattern::parse(pattern, true)
|
PortableGlobPattern::parse(pattern, PortableGlobKind::Exclude)
|
||||||
.and_then(|exclude| Ok(excludes.add(&exclude.into_absolute(""))?))
|
.and_then(|exclude| Ok(excludes.add(&exclude.into_absolute(""))?))
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
panic!("Expected default exclude to be valid glob but adding it failed with: {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
|
// Add user-specified excludes
|
||||||
if let Some(exclude_patterns) = exclude_patterns {
|
if let Some(exclude_patterns) = exclude_patterns {
|
||||||
for exclude in 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)?))
|
.and_then(|pattern| Ok(excludes.add(&pattern)?))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
let diagnostic = OptionDiagnostic::new(
|
let diagnostic = OptionDiagnostic::new(
|
||||||
|
@ -1001,7 +1004,7 @@ pub struct OverrideOptions {
|
||||||
]
|
]
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
pub include: Option<RangedValue<Vec<RelativeIncludePattern>>>,
|
pub include: Option<RangedValue<Vec<RelativeGlobPattern>>>,
|
||||||
|
|
||||||
/// A list of file and directory patterns to exclude from this override.
|
/// A list of file and directory patterns to exclude from this override.
|
||||||
///
|
///
|
||||||
|
@ -1023,7 +1026,7 @@ pub struct OverrideOptions {
|
||||||
]
|
]
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
pub exclude: Option<RangedValue<Vec<RelativeExcludePattern>>>,
|
pub exclude: Option<RangedValue<Vec<RelativeGlobPattern>>>,
|
||||||
|
|
||||||
/// Rule overrides for files matching the include/exclude patterns.
|
/// Rule overrides for files matching the include/exclude patterns.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
use crate::combine::Combine;
|
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_db::system::{System, SystemPath, SystemPathBuf};
|
||||||
use ruff_macros::Combine;
|
use ruff_macros::Combine;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
@ -372,14 +374,14 @@ impl RelativePathBuf {
|
||||||
)]
|
)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
pub struct RelativeIncludePattern(RangedValue<String>);
|
pub struct RelativeGlobPattern(RangedValue<String>);
|
||||||
|
|
||||||
impl RelativeIncludePattern {
|
impl RelativeGlobPattern {
|
||||||
pub fn new(pattern: &str, source: ValueSource) -> Self {
|
pub fn new(pattern: impl AsRef<str>, source: ValueSource) -> Self {
|
||||||
Self(RangedValue::new(pattern.to_string(), source))
|
Self(RangedValue::new(pattern.as_ref().to_string(), source))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cli(pattern: &str) -> Self {
|
pub fn cli(pattern: impl AsRef<str>) -> Self {
|
||||||
Self::new(pattern, ValueSource::Cli)
|
Self::new(pattern, ValueSource::Cli)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,74 +398,19 @@ impl RelativeIncludePattern {
|
||||||
&self,
|
&self,
|
||||||
project_root: &SystemPath,
|
project_root: &SystemPath,
|
||||||
system: &dyn System,
|
system: &dyn System,
|
||||||
|
kind: PortableGlobKind,
|
||||||
) -> Result<AbsolutePortableGlobPattern, PortableGlobError> {
|
) -> Result<AbsolutePortableGlobPattern, PortableGlobError> {
|
||||||
let relative_to = match &self.0.source {
|
let relative_to = match &self.0.source {
|
||||||
ValueSource::File(_) => project_root,
|
ValueSource::File(_) => project_root,
|
||||||
ValueSource::Cli => system.current_directory(),
|
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))
|
Ok(pattern.into_absolute(relative_to))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for RelativeIncludePattern {
|
impl std::fmt::Display for RelativeGlobPattern {
|
||||||
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<String>);
|
|
||||||
|
|
||||||
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<TextRange> {
|
|
||||||
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<AbsolutePortableGlobPattern, PortableGlobError> {
|
|
||||||
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 {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
|
|
4
ty.schema.json
generated
4
ty.schema.json
generated
|
@ -920,7 +920,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"exclude": {
|
"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 `<project_root>/src` and not `<project_root>/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": [
|
"type": [
|
||||||
"array",
|
"array",
|
||||||
"null"
|
"null"
|
||||||
|
@ -930,7 +930,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": {
|
"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 `<project_root>/src` and not `<project_root>/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 `<project_root>/src` and not `<project_root>/test/src`).\n\n`exclude` takes precedence over `include`.",
|
||||||
"type": [
|
"type": [
|
||||||
"array",
|
"array",
|
||||||
"null"
|
"null"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue