@@ -1534,6 +1534,10 @@ impl Workspace {
15341534 for folder_url in matched_folder_urls {
15351535 let entry = results. entry ( ( * folder_url) . clone ( ) ) ;
15361536 let folder_path = url_to_file_path ( folder_url) . unwrap ( ) ;
1537+ let scoped_include = pattern
1538+ . include
1539+ . as_ref ( )
1540+ . map ( |i| scope_include_to_folder ( i, & folder_path) ) ;
15371541 match entry {
15381542 indexmap:: map:: Entry :: Occupied ( entry) => {
15391543 let entry = entry. into_mut ( ) ;
@@ -1545,7 +1549,7 @@ impl Workspace {
15451549 }
15461550 match & mut entry. include {
15471551 Some ( set) => {
1548- if let Some ( includes) = & pattern . include {
1552+ if let Some ( includes) = & scoped_include {
15491553 for include in includes. inner ( ) {
15501554 if !set. inner ( ) . contains ( include) {
15511555 set. push ( include. clone ( ) )
@@ -1554,7 +1558,7 @@ impl Workspace {
15541558 }
15551559 }
15561560 None => {
1557- entry. include . clone_from ( & pattern . include ) ;
1561+ entry. include = scoped_include ;
15581562 }
15591563 }
15601564 }
@@ -1565,7 +1569,7 @@ impl Workspace {
15651569 } else {
15661570 folder_path. clone ( )
15671571 } ,
1568- include : pattern . include . clone ( ) ,
1572+ include : scoped_include ,
15691573 exclude : pattern. exclude . clone ( ) ,
15701574 } ) ;
15711575 }
@@ -2796,6 +2800,30 @@ fn combine_patterns(
27962800 }
27972801}
27982802
2803+ /// Restrict a CLI-supplied include set to a single workspace folder.
2804+ ///
2805+ /// `split_by_base` uses each include path as the walk root, so an include path
2806+ /// that's a proper parent of the member's folder (e.g. `Path(cwd)` for member
2807+ /// `cwd/member-a`) would cause every member to traverse the entire workspace.
2808+ /// Clamp such paths down to the member's folder so each member only walks its
2809+ /// own subtree.
2810+ fn scope_include_to_folder (
2811+ include : & PathOrPatternSet ,
2812+ folder_path : & Path ,
2813+ ) -> PathOrPatternSet {
2814+ let scoped = include
2815+ . inner ( )
2816+ . iter ( )
2817+ . map ( |p| match p {
2818+ PathOrPattern :: Path ( path) if folder_path. starts_with ( path) => {
2819+ PathOrPattern :: Path ( folder_path. to_path_buf ( ) )
2820+ }
2821+ _ => p. clone ( ) ,
2822+ } )
2823+ . collect :: < Vec < _ > > ( ) ;
2824+ PathOrPatternSet :: new ( scoped)
2825+ }
2826+
27992827fn combine_files_config_with_cli_args (
28002828 files_config : & mut FilePatterns ,
28012829 cli_arg_patterns : FilePatterns ,
@@ -6032,6 +6060,72 @@ pub mod test {
60326060 } ) ;
60336061 }
60346062
6063+ // Regression test for https://github.com/denoland/deno/issues/30915 — running
6064+ // `deno fmt .` (or `deno lint .`) from the workspace root must not cause each
6065+ // member to walk the whole workspace.
6066+ #[ test]
6067+ fn test_resolve_config_for_members_cli_include_workspace_root ( ) {
6068+ let sys = InMemorySys :: default ( ) ;
6069+ sys. fs_insert_json (
6070+ root_dir ( ) . join ( "deno.json" ) ,
6071+ json ! ( {
6072+ "workspace" : [ "./member-a" , "./member-b" ] ,
6073+ } ) ,
6074+ ) ;
6075+ sys. fs_insert_json ( root_dir ( ) . join ( "member-a/deno.json" ) , json ! ( { } ) ) ;
6076+ sys. fs_insert_json ( root_dir ( ) . join ( "member-b/deno.json" ) , json ! ( { } ) ) ;
6077+ let workspace_dir = workspace_at_start_dir ( & sys, & root_dir ( ) ) ;
6078+ // Simulate CLI args from `deno fmt .` — base + include both pointing at the
6079+ // workspace root.
6080+ let cli_args = FilePatterns {
6081+ base : root_dir ( ) ,
6082+ include : Some ( PathOrPatternSet :: new ( vec ! [ PathOrPattern :: Path (
6083+ root_dir( ) ,
6084+ ) ] ) ) ,
6085+ exclude : Default :: default ( ) ,
6086+ } ;
6087+ let config_for_members = workspace_dir
6088+ . workspace
6089+ . resolve_fmt_config_for_members ( & cli_args)
6090+ . unwrap ( ) ;
6091+ let file_patterns = config_for_members
6092+ . into_iter ( )
6093+ . map ( |( _ctx, config) | config. files )
6094+ . collect :: < Vec < _ > > ( ) ;
6095+ assert_eq ! (
6096+ file_patterns,
6097+ vec![
6098+ // Root walks from the workspace root, but excludes the member dirs.
6099+ FilePatterns {
6100+ base: root_dir( ) ,
6101+ include: Some ( PathOrPatternSet :: new( vec![ PathOrPattern :: Path (
6102+ root_dir( )
6103+ ) ] ) ) ,
6104+ exclude: PathOrPatternSet :: new( vec![
6105+ PathOrPattern :: Path ( root_dir( ) . join( "member-a" ) ) ,
6106+ PathOrPattern :: Path ( root_dir( ) . join( "member-b" ) ) ,
6107+ ] ) ,
6108+ } ,
6109+ // Each member's include is clamped to the member's own directory so
6110+ // that file collection walks only that subtree.
6111+ FilePatterns {
6112+ base: root_dir( ) . join( "member-a" ) ,
6113+ include: Some ( PathOrPatternSet :: new( vec![ PathOrPattern :: Path (
6114+ root_dir( ) . join( "member-a" )
6115+ ) ] ) ) ,
6116+ exclude: Default :: default ( ) ,
6117+ } ,
6118+ FilePatterns {
6119+ base: root_dir( ) . join( "member-b" ) ,
6120+ include: Some ( PathOrPatternSet :: new( vec![ PathOrPattern :: Path (
6121+ root_dir( ) . join( "member-b" )
6122+ ) ] ) ) ,
6123+ exclude: Default :: default ( ) ,
6124+ } ,
6125+ ]
6126+ ) ;
6127+ }
6128+
60356129 #[ test]
60366130 fn test_resolve_config_for_members_excluded_member ( ) {
60376131 let sys = InMemorySys :: default ( ) ;
0 commit comments