diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfb174e7..72065f316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgrade: don't migrate empty class rules to invalid `@utility` rules ([#20205](https://github.com/tailwindlabs/tailwindcss/pull/20205)) - Ensure transitions between `inset-shadow-none` and other inset shadows work correctly ([#20208](https://github.com/tailwindlabs/tailwindcss/pull/20208)) - Ensure explicitly referenced `@source` directories are scanned even when ignored by git ([#20214](https://github.com/tailwindlabs/tailwindcss/pull/20214)) +- Ensure `@source` globs ending in `**/*` preserve dynamic path segments to avoid scanning too many files ([#20217](https://github.com/tailwindlabs/tailwindcss/pull/20217)) ### Changed diff --git a/crates/oxide/src/scanner/sources.rs b/crates/oxide/src/scanner/sources.rs index e45eb9613..73bd7d6a7 100644 --- a/crates/oxide/src/scanner/sources.rs +++ b/crates/oxide/src/scanner/sources.rs @@ -512,8 +512,8 @@ impl From for SourceEntry { }; } - let auto = value.pattern.ends_with("**/*") - || PathBuf::from(&value.base).join(&value.pattern).is_dir(); + let auto = + value.pattern == "/**/*" || PathBuf::from(&value.base).join(&value.pattern).is_dir(); if !auto { return SourceEntry::Pattern { @@ -530,7 +530,7 @@ impl From for SourceEntry { std::path::MAIN_SEPARATOR )) || value .base - .ends_with(&format!("{}{}", std::path::MAIN_SEPARATOR, dir,)) + .ends_with(&format!("{}{}", std::path::MAIN_SEPARATOR, dir)) }); match inside_ignored_content_dir { diff --git a/crates/oxide/tests/scanner.rs b/crates/oxide/tests/scanner.rs index 86107d8b7..135b2bda5 100644 --- a/crates/oxide/tests/scanner.rs +++ b/crates/oxide/tests/scanner.rs @@ -659,6 +659,36 @@ mod scanner { assert_eq!(normalized_sources, vec!["**/*", "*.styl"]); } + #[test] + fn it_should_preserve_paths_for_sources_ending_in_a_deep_glob() { + let ScanResult { + candidates, + files, + globs, + normalized_sources, + } = scan_with_globs( + &[ + ( + "blog/2024/foo/bar/baz/index.html", + "content-['blog/2024/foo/bar/baz/index.html']", + ), + ( + "blog/2024/foo/bar/qux/index.html", + "content-['blog/2024/foo/bar/qux/index.html']", + ), + ], + vec!["@source './blog/*/foo/bar/baz/**/*'"], + ); + + assert_eq!( + candidates, + vec!["content-['blog/2024/foo/bar/baz/index.html']"] + ); + assert_eq!(files, vec!["blog/2024/foo/bar/baz/index.html"]); + assert_eq!(globs, vec!["blog/*/foo/bar/baz/**/*"]); + assert_eq!(normalized_sources, vec!["blog/*/foo/bar/baz/**/*"]); + } + #[test] fn it_should_scan_next_dynamic_folders() { let ScanResult {