From b9b75a79fcd266f2355215adef4911c3d1bab371 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Tue, 28 Nov 2023 18:10:25 -0500 Subject: [PATCH] fix(core): fix handling of globs with {,.snap} (#20461) --- packages/nx/src/native/glob.rs | 10 ++++- packages/nx/src/native/glob/glob_parser.rs | 46 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/nx/src/native/glob.rs b/packages/nx/src/native/glob.rs index 03138d12d98c2..a2cd876aa4317 100644 --- a/packages/nx/src/native/glob.rs +++ b/packages/nx/src/native/glob.rs @@ -92,7 +92,8 @@ pub(crate) fn build_glob_set + Debug>(globs: &[S]) -> anyhow::Resu .iter() .flat_map(|s| potential_glob_split(s.as_ref())) .map(|glob| { - if glob.contains('!') || glob.contains('|') || glob.contains('(') { + if glob.contains('!') || glob.contains('|') || glob.contains('(') || glob.contains("{,") + { convert_glob(glob) } else { Ok(vec![glob.to_string()]) @@ -226,6 +227,13 @@ mod test { assert!(!glob_set.is_match("dist/file.js")); assert!(!glob_set.is_match("dist/cache/")); assert!(!glob_set.is_match("dist/main/")); + + let glob_set = build_glob_set(&["**/*.spec.ts{,.snap}"]).unwrap(); + // matches + assert!(glob_set.is_match("src/file.spec.ts")); + assert!(glob_set.is_match("src/file.spec.ts.snap")); + // no matches + assert!(!glob_set.is_match("src/file.ts")); } #[test] diff --git a/packages/nx/src/native/glob/glob_parser.rs b/packages/nx/src/native/glob/glob_parser.rs index 33b284057bcf3..8ecb167c7eac9 100644 --- a/packages/nx/src/native/glob/glob_parser.rs +++ b/packages/nx/src/native/glob/glob_parser.rs @@ -36,6 +36,13 @@ fn one_or_more_group(input: &str) -> IResult<&str, GlobGroup, VerboseError<&str> )(input) } +fn brace_group_with_empty_item(input: &str) -> IResult<&str, GlobGroup, VerboseError<&str>> { + context( + "brace_group_with_empty_item", + map(preceded(tag("{,"), brace_group), GlobGroup::ZeroOrOne), + )(input) +} + fn exact_one_group(input: &str) -> IResult<&str, GlobGroup, VerboseError<&str>> { context( "exact_one_group", @@ -71,6 +78,7 @@ fn non_special_character(input: &str) -> IResult<&str, GlobGroup, VerboseError<& "non_special_character", map( alt(( + take_until("{,"), take_while(|c| c != '?' && c != '+' && c != '@' && c != '!' && c != '('), is_not("*("), )), @@ -86,6 +94,13 @@ fn group(input: &str) -> IResult<&str, Cow, VerboseError<&str>> { )(input) } +fn brace_group(input: &str) -> IResult<&str, Cow, VerboseError<&str>> { + context( + "brace_group", + map_parser(terminated(take_until("}"), tag("}")), separated_group_items), + )(input) +} + fn separated_group_items(input: &str) -> IResult<&str, Cow, VerboseError<&str>> { map( separated_list0( @@ -117,6 +132,7 @@ fn parse_segment(input: &str) -> IResult<&str, Vec, VerboseError<&str negated_file_group, negated_wildcard, negated_group, + brace_group_with_empty_item, non_special_character, )), ), @@ -296,4 +312,34 @@ mod test { ) ); } + #[test] + fn should_parse_globs_with_braces() { + let result = parse_glob("**/*.spec.ts{,.snap}").unwrap(); + + assert_eq!( + result, + ( + false, + vec![ + vec![GlobGroup::NonSpecial("**".into())], + vec![ + GlobGroup::NonSpecial("*.spec.ts".into()), + GlobGroup::ZeroOrOne(".snap".into()) + ] + ] + ) + ); + let result = parse_glob("**/*.spec.ts{.snapshot,.snap}").unwrap(); + + assert_eq!( + result, + ( + false, + vec![ + vec![GlobGroup::NonSpecial("**".into())], + vec![GlobGroup::NonSpecial("*.spec.ts{.snapshot,.snap}".into()),] + ] + ) + ); + } }