mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Ignore binary extensions, except in folder names (#17595)
We generate a glob to ignore binary extensions that looks something like
this:
```
*.{mp4,pages,exe,…}
```
However, if you have a folder that happens to end in `.pages` for
example, then this folder will be ignored in its entirety.
To solve this, we added a new flag to the `Gitignore` struct so we can
register a bunch of ignore rules that _only_ apply to paths and not
folders.
Fixes: #17569
## Test plan
- Added a unit test
---------
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
This commit is contained in:
parent
d801d8dc54
commit
bbd916aaa0
@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Ensure container query variant names can contain hyphens ([#17628](https://github.com/tailwindlabs/tailwindcss/pull/17628))
|
||||
- Ensure `shadow-inherit`, `inset-shadow-inherit`, `drop-shadow-inherit`, and `text-shadow-inherit` inherits the shadow color ([#17647](https://github.com/tailwindlabs/tailwindcss/pull/17647))
|
||||
- Ensure compatibility with array tuples used in `fontSize` JS theme keys ([#17630](https://github.com/tailwindlabs/tailwindcss/pull/17630))
|
||||
- Ensure folders with binary file extensions in its name are scanned for utilities ([#17595](https://github.com/tailwindlabs/tailwindcss/pull/17595))
|
||||
- Upgrade: Convert `fontSize` array tuple syntax to CSS theme variables ([#17630](https://github.com/tailwindlabs/tailwindcss/pull/17630))
|
||||
|
||||
## [4.1.3] - 2025-04-04
|
||||
|
||||
@ -85,6 +85,8 @@ pub struct Gitignore {
|
||||
num_ignores: u64,
|
||||
num_whitelists: u64,
|
||||
matches: Option<Arc<Pool<Vec<usize>>>>,
|
||||
// CHANGED: Add a flag to have Gitignore rules that apply only to files.
|
||||
only_on_files: bool,
|
||||
}
|
||||
|
||||
impl Gitignore {
|
||||
@ -140,6 +142,8 @@ impl Gitignore {
|
||||
num_ignores: 0,
|
||||
num_whitelists: 0,
|
||||
matches: None,
|
||||
// CHANGED: Add a flag to have Gitignore rules that apply only to files.
|
||||
only_on_files: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,6 +244,10 @@ impl Gitignore {
|
||||
if self.is_empty() {
|
||||
return Match::None;
|
||||
}
|
||||
// CHANGED: Rules marked as only_on_files can not match against directories.
|
||||
if self.only_on_files && is_dir {
|
||||
return Match::None;
|
||||
}
|
||||
let path = path.as_ref();
|
||||
let mut matches = self.matches.as_ref().unwrap().get();
|
||||
let candidate = Candidate::new(path);
|
||||
@ -295,6 +303,8 @@ pub struct GitignoreBuilder {
|
||||
root: PathBuf,
|
||||
globs: Vec<Glob>,
|
||||
case_insensitive: bool,
|
||||
// CHANGED: Add a flag to have Gitignore rules that apply only to files.
|
||||
only_on_files: bool,
|
||||
}
|
||||
|
||||
impl GitignoreBuilder {
|
||||
@ -311,6 +321,8 @@ impl GitignoreBuilder {
|
||||
root: strip_prefix("./", root).unwrap_or(root).to_path_buf(),
|
||||
globs: vec![],
|
||||
case_insensitive: false,
|
||||
// CHANGED: Add a flag to have Gitignore rules that apply only to files.
|
||||
only_on_files: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,6 +343,8 @@ impl GitignoreBuilder {
|
||||
num_ignores: nignore as u64,
|
||||
num_whitelists: nwhite as u64,
|
||||
matches: Some(Arc::new(Pool::new(|| vec![]))),
|
||||
// CHANGED: Add a flag to have Gitignore rules that apply only to files.
|
||||
only_on_files: self.only_on_files,
|
||||
})
|
||||
}
|
||||
|
||||
@ -514,6 +528,16 @@ impl GitignoreBuilder {
|
||||
self.case_insensitive = yes;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// CHANGED: Add a flag to have Gitignore rules that apply only to files.
|
||||
///
|
||||
/// If this is set, then the globs will only be matched against file paths.
|
||||
/// This will ensure that ignore rules like `*.pages` will _only_ ignore
|
||||
/// files ending in `.pages` and not folders ending in `.pages`.
|
||||
pub fn only_on_files(&mut self, yes: bool) -> &mut GitignoreBuilder {
|
||||
self.only_on_files = yes;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the file path of the current environment's global gitignore file.
|
||||
|
||||
@ -10,15 +10,21 @@ use std::sync;
|
||||
/// - Ignoring common binary file extensions like `.png` and `.jpg`
|
||||
/// - Ignoring common files like `yarn.lock` and `package-lock.json`
|
||||
///
|
||||
pub static RULES: sync::LazyLock<Gitignore> = sync::LazyLock::new(|| {
|
||||
pub static RULES: sync::LazyLock<Vec<Gitignore>> = sync::LazyLock::new(|| {
|
||||
let mut builder = GitignoreBuilder::new("");
|
||||
|
||||
builder.add_line(None, &IGNORED_CONTENT_DIRS_GLOB).unwrap();
|
||||
builder.add_line(None, &IGNORED_EXTENSIONS_GLOB).unwrap();
|
||||
builder.add_line(None, &BINARY_EXTENSIONS_GLOB).unwrap();
|
||||
builder.add_line(None, &IGNORED_FILES_GLOB).unwrap();
|
||||
|
||||
builder.build().unwrap()
|
||||
// Ensure these rules do not match on folder names
|
||||
let mut file_only_builder = GitignoreBuilder::new("");
|
||||
file_only_builder
|
||||
.only_on_files(true)
|
||||
.add_line(None, &BINARY_EXTENSIONS_GLOB)
|
||||
.unwrap();
|
||||
|
||||
vec![builder.build().unwrap(), file_only_builder.build().unwrap()]
|
||||
});
|
||||
|
||||
pub static IGNORED_CONTENT_DIRS: sync::LazyLock<Vec<&'static str>> = sync::LazyLock::new(|| {
|
||||
|
||||
@ -630,7 +630,9 @@ fn create_walker(sources: Sources) -> Option<WalkBuilder> {
|
||||
}
|
||||
|
||||
// Setup auto source detection rules
|
||||
builder.add_gitignore(auto_source_detection::RULES.clone());
|
||||
for ignore in auto_source_detection::RULES.iter() {
|
||||
builder.add_gitignore(ignore.clone());
|
||||
}
|
||||
|
||||
// Setup ignores based on `@source` definitions
|
||||
for (base, patterns) in ignores {
|
||||
|
||||
@ -311,6 +311,31 @@ mod scanner {
|
||||
assert_eq!(normalized_sources, vec!["**/*"]);
|
||||
}
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/17569
|
||||
#[test]
|
||||
fn it_should_not_ignore_folders_that_end_with_a_binary_extension() {
|
||||
let ScanResult {
|
||||
files,
|
||||
globs,
|
||||
normalized_sources,
|
||||
..
|
||||
} = scan(&[
|
||||
// Looks like `.pages` binary extension, but it's a folder
|
||||
("some.pages/index.html", "content-['some.pages/index.html']"),
|
||||
// Ignore a specific folder. This is to ensure that this still "wins" from the internal
|
||||
// solution of dealing with binary extensions for files only.
|
||||
(".gitignore", "other.pages"),
|
||||
(
|
||||
"other.pages/index.html",
|
||||
"content-['other.pages/index.html']",
|
||||
),
|
||||
]);
|
||||
|
||||
assert_eq!(files, vec!["some.pages/index.html"]);
|
||||
assert_eq!(globs, vec!["*", "some.pages/**/*.{aspx,astro,cjs,cts,eex,erb,gjs,gts,haml,handlebars,hbs,heex,html,jade,js,jsx,liquid,md,mdx,mjs,mts,mustache,njk,nunjucks,php,pug,py,razor,rb,rhtml,rs,slim,svelte,tpl,ts,tsx,twig,vue}"]);
|
||||
assert_eq!(normalized_sources, vec!["**/*"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_should_ignore_known_extensions() {
|
||||
let ScanResult {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user