@@ -12,6 +12,7 @@ import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
12
12
import 'package:analyzer/src/context/packages.dart' ;
13
13
import 'package:analyzer/src/dart/analysis/analysis_options.dart' ;
14
14
import 'package:analyzer/src/dart/analysis/context_root.dart' ;
15
+ import 'package:analyzer/src/lint/pub.dart' ;
15
16
import 'package:analyzer/src/task/options.dart' ;
16
17
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
17
18
import 'package:analyzer/src/util/yaml.dart' ;
@@ -111,8 +112,69 @@ class ContextLocatorImpl {
111
112
}
112
113
}
113
114
115
+ var workspaceResolutionRootMap = < String , List <Folder >> {};
116
+ var nonWorkspaceResolutionFolders = < Folder > [];
117
+ _sortIncludedFoldersIntoWorkspaceResolutions (
118
+ includedFolders,
119
+ defaultOptionsFile,
120
+ defaultPackagesFile,
121
+ nonWorkspaceResolutionFolders,
122
+ workspaceResolutionRootMap,
123
+ );
124
+
114
125
var roots = < ContextRootImpl > [];
115
- for (Folder folder in includedFolders) {
126
+ for (var workspaceResolution in workspaceResolutionRootMap.entries) {
127
+ var workspaceRootFolder = resourceProvider.getFolder (
128
+ workspaceResolution.key,
129
+ );
130
+ var location = _contextRootLocation (
131
+ workspaceRootFolder,
132
+ defaultOptionsFile: defaultOptionsFile,
133
+ defaultPackagesFile: defaultPackagesFile,
134
+ defaultRootFolder: () => workspaceRootFolder,
135
+ );
136
+
137
+ ContextRootImpl root = _createContextRoot (
138
+ roots,
139
+ rootFolder: workspaceRootFolder,
140
+ workspace: location.workspace,
141
+ optionsFile: location.optionsFile,
142
+ packagesFile: location.packagesFile,
143
+ );
144
+
145
+ var rootEnabledLegacyPlugins = _getEnabledLegacyPlugins (
146
+ location.workspace,
147
+ location.optionsFile,
148
+ );
149
+
150
+ Set <String > visited = {};
151
+ bool usedRoot = false ;
152
+
153
+ for (var folder in workspaceResolution.value) {
154
+ if (! root.isAnalyzed (folder.path)) {
155
+ root.included.add (folder);
156
+ }
157
+
158
+ usedRoot | = _createContextRoots (
159
+ roots,
160
+ visited,
161
+ folder,
162
+ excludedFolders,
163
+ root,
164
+ rootEnabledLegacyPlugins,
165
+ root.excludedGlobs,
166
+ defaultOptionsFile,
167
+ defaultPackagesFile,
168
+ );
169
+ }
170
+ if (! usedRoot) {
171
+ // If all included folders under this workspace resolution ended up
172
+ // creating new contexts remove the (not used) root.
173
+ roots.remove (root);
174
+ }
175
+ }
176
+
177
+ for (Folder folder in nonWorkspaceResolutionFolders) {
116
178
var location = _contextRootLocation (
117
179
folder,
118
180
defaultOptionsFile: defaultOptionsFile,
@@ -315,7 +377,10 @@ class ContextLocatorImpl {
315
377
/// For each directory within the given [folder] that is neither in the list
316
378
/// of [excludedFolders] nor excluded by the [excludedGlobs] , recursively
317
379
/// search for nested context roots.
318
- void _createContextRoots (
380
+ ///
381
+ /// Returns true if the folder was contained in the root and did not create a
382
+ /// new root, false if it did create a new root.
383
+ bool _createContextRoots (
319
384
List <ContextRoot > roots,
320
385
Set <String > visited,
321
386
Folder folder,
@@ -353,6 +418,8 @@ class ContextLocatorImpl {
353
418
localEnabledPlugins,
354
419
);
355
420
421
+ bool usedThisRoot = true ;
422
+
356
423
// Create a context root for the given [folder] if a packages or build file
357
424
// is locally specified, or the set of enabled legacy plugins changed.
358
425
if (pluginsDiffer || localPackagesFile != null || buildGnFile != null ) {
@@ -391,6 +458,7 @@ class ContextLocatorImpl {
391
458
containingRootEnabledLegacyPlugins = localEnabledPlugins;
392
459
excludedGlobs = _getExcludedGlobs (root.optionsFile, workspace);
393
460
root.excludedGlobs = excludedGlobs;
461
+ usedThisRoot = false ;
394
462
}
395
463
396
464
if (localOptionsFile != null ) {
@@ -414,6 +482,8 @@ class ContextLocatorImpl {
414
482
optionsFile,
415
483
packagesFile,
416
484
);
485
+
486
+ return usedThisRoot;
417
487
}
418
488
419
489
/// For each directory within the given [folder] that is neither in the list
@@ -647,6 +717,47 @@ class ContextLocatorImpl {
647
717
return null ;
648
718
}
649
719
720
+ /// Load the `workspace` paths from the pubspec file in the given [root] .
721
+ ///
722
+ /// From https://dart.dev/tools/pub/workspaces a root folder pubspec file will
723
+ /// look like this:
724
+ ///
725
+ /// ```
726
+ /// name: _
727
+ /// publish_to: none
728
+ /// environment:
729
+ /// sdk: ^3.6.0
730
+ /// workspace:
731
+ /// - packages/helper
732
+ /// - packages/client_package
733
+ /// - packages/server_package
734
+ /// ```
735
+ ///
736
+ /// This loads the paths from the `workspace` entry and return them as
737
+ /// Folders if they exist as folders in the filesystem.
738
+ Set <Folder > _loadWorkspaceDetailsFromPubspec (String root) {
739
+ var result = < Folder > {};
740
+ var rootFolder = resourceProvider.getFolder (root);
741
+ var rootPubspecFile = rootFolder.getChildAssumingFile (
742
+ file_paths.pubspecYaml,
743
+ );
744
+ if (rootPubspecFile.exists) {
745
+ var rootPubspec = Pubspec .parse (rootPubspecFile.readAsStringSync ());
746
+ var workspace = rootPubspec.workspace;
747
+ if (workspace != null ) {
748
+ for (var entry in workspace) {
749
+ if (entry.text case var relativePath? ) {
750
+ var child = rootFolder.getChild (relativePath);
751
+ if (child.exists && child is Folder ) {
752
+ result.add (child);
753
+ }
754
+ }
755
+ }
756
+ }
757
+ }
758
+ return result;
759
+ }
760
+
650
761
/// Add to the given lists of [folders] and [files] all of the resources in
651
762
/// the given list of [paths] that exist and are not contained within one of
652
763
/// the folders.
@@ -667,6 +778,65 @@ class ContextLocatorImpl {
667
778
}
668
779
}
669
780
781
+ /// Sorts [includedFolders] into either pub workspace resolution or not.
782
+ ///
783
+ /// For each [Folder] in [includedFolders] sort into either
784
+ /// [nonWorkspaceResolutionFolders] or [workspaceResolutionRootMap] depending
785
+ /// on `pubspec.yaml` specifications.
786
+ ///
787
+ /// Folders with `pubspec.yaml` files with a `resolution: workspace` setting
788
+ /// that matches a root-folders `pubspec.yaml` files `workspace` list is
789
+ /// sorted into the [workspaceResolutionRootMap] map. Other folders end up in
790
+ /// [nonWorkspaceResolutionFolders] .
791
+ void _sortIncludedFoldersIntoWorkspaceResolutions (
792
+ List <Folder > includedFolders,
793
+ File ? defaultOptionsFile,
794
+ File ? defaultPackagesFile,
795
+ List <Folder > nonWorkspaceResolutionFolders,
796
+ Map <String , List <Folder >> workspaceResolutionRootMap,
797
+ ) {
798
+ var rootWorkspaceSpecification = < String , Set <Folder >> {};
799
+ for (Folder folder in includedFolders) {
800
+ var location = _contextRootLocation (
801
+ folder,
802
+ defaultOptionsFile: defaultOptionsFile,
803
+ defaultPackagesFile: defaultPackagesFile,
804
+ defaultRootFolder: () => folder,
805
+ );
806
+
807
+ var addedToWorkspace = false ;
808
+
809
+ if (folder.path == location.workspace.root) {
810
+ // If opening the root don't try to do anything special.
811
+ var known = rootWorkspaceSpecification[location.workspace.root] ?? = {};
812
+ known.clear ();
813
+ nonWorkspaceResolutionFolders.addAll (
814
+ workspaceResolutionRootMap[location.workspace.root] ?? [],
815
+ );
816
+ } else {
817
+ var pubspecFile = folder.getChildAssumingFile (file_paths.pubspecYaml);
818
+ if (pubspecFile.exists) {
819
+ var pubspec = Pubspec .parse (pubspecFile.readAsStringSync ());
820
+ var resolution = pubspec.resolution;
821
+ if (resolution != null && resolution.value.text == 'workspace' ) {
822
+ var known =
823
+ rootWorkspaceSpecification[location.workspace.root] ?? =
824
+ _loadWorkspaceDetailsFromPubspec (location.workspace.root);
825
+ if (known.contains (folder)) {
826
+ (workspaceResolutionRootMap[location.workspace.root] ?? = []).add (
827
+ folder,
828
+ );
829
+ addedToWorkspace = true ;
830
+ }
831
+ }
832
+ }
833
+ }
834
+ if (! addedToWorkspace) {
835
+ nonWorkspaceResolutionFolders.add (folder);
836
+ }
837
+ }
838
+ }
839
+
670
840
/// Return a list of paths that contains all of the unique elements from the
671
841
/// given list of [paths] , sorted such that shorter paths are first.
672
842
List <String > _uniqueSortedPaths (List <String > paths) {
0 commit comments