@@ -74,28 +74,41 @@ class OutdatedCommand extends PubCommand {
7474
7575 var resolvablePubspec = _stripVersionConstraints (upgradePubspec);
7676
77- SolveResult upgradableSolveResult ;
78- SolveResult resolvableSolveResult ;
77+ List < PackageId > upgradablePackages ;
78+ List < PackageId > resolvablePackages ;
7979
8080 await log.warningsOnlyUnlessTerminal (
8181 () => log.spinner (
8282 'Resolving' ,
8383 () async {
84- upgradableSolveResult = await resolveVersions (
84+ upgradablePackages = ( await resolveVersions (
8585 SolveType .UPGRADE ,
8686 cache,
8787 Package .inMemory (upgradePubspec),
88- );
88+ ))
89+ .packages;
8990
90- resolvableSolveResult = await resolveVersions (
91+ resolvablePackages = ( await resolveVersions (
9192 SolveType .UPGRADE ,
9293 cache,
9394 Package .inMemory (resolvablePubspec),
94- );
95+ ))
96+ .packages;
9597 },
9698 ),
9799 );
98100
101+ final currentPackages = entrypoint.lockFile.packages.values;
102+
103+ /// The set of all dependencies (direct and transitive) that are in the
104+ /// closure of the non-dev dependencies from the root in at least one of
105+ /// the current, upgradable and resolvable resolutions.
106+ final nonDevDependencies = < String > {
107+ ...await nonDevDependencyClosure (entrypoint.root, currentPackages),
108+ ...await nonDevDependencyClosure (entrypoint.root, upgradablePackages),
109+ ...await nonDevDependencyClosure (entrypoint.root, resolvablePackages)
110+ };
111+
99112 Future <_PackageDetails > analyzeDependency (PackageRef packageRef) async {
100113 final name = packageRef.name;
101114 final current = (entrypoint.lockFile? .packages ?? {})[name]? .version;
@@ -104,10 +117,10 @@ class OutdatedCommand extends PubCommand {
104117 .map ((id) => id.version)
105118 .toList ()
106119 ..sort (argResults['pre-releases' ] ? null : Version .prioritize);
107- final upgradable = upgradableSolveResult.packages
120+ final upgradable = upgradablePackages
108121 .firstWhere ((id) => id.name == name, orElse: () => null )
109122 ? .version;
110- final resolvable = resolvableSolveResult.packages
123+ final resolvable = resolvablePackages
111124 .firstWhere ((id) => id.name == name, orElse: () => null )
112125 ? .version;
113126 final latest = available.last;
@@ -118,7 +131,7 @@ class OutdatedCommand extends PubCommand {
118131 await _describeVersion (name, source, description, upgradable),
119132 await _describeVersion (name, source, description, resolvable),
120133 await _describeVersion (name, source, description, latest),
121- _kind (name, entrypoint));
134+ _kind (name, entrypoint, nonDevDependencies ));
122135 }
123136
124137 final rows = < _PackageDetails > [];
@@ -135,9 +148,9 @@ class OutdatedCommand extends PubCommand {
135148 ...immediateDependencies.map ((d) => d.name)
136149 };
137150 for (final id in [
138- if (includeDevDependencies) ...entrypoint.lockFile.packages.values ,
139- ...upgradableSolveResult.packages ,
140- ...resolvableSolveResult.packages
151+ ...currentPackages ,
152+ ...upgradablePackages ,
153+ ...resolvablePackages
141154 ]) {
142155 final name = id.name;
143156 if (! visited.add (name)) continue ;
@@ -181,6 +194,24 @@ class OutdatedCommand extends PubCommand {
181194 .source (source)
182195 .describe (PackageId (name, source, version, description));
183196 }
197+
198+ /// Computes the closure of the graph of dependencies (not including
199+ /// dev_dependencies from [root] , given the package versions in [resolution] .
200+ Future <Set <String >> nonDevDependencyClosure (
201+ Package root, Iterable <PackageId > resolution) async {
202+ final mapping =
203+ Map <String , PackageId >.fromIterable (resolution, key: (id) => id.name);
204+ final visited = < String > {root.name};
205+ final toVisit = [...root.dependencies.keys];
206+ while (toVisit.isNotEmpty) {
207+ final name = toVisit.removeLast ();
208+ if (! visited.add (name)) continue ;
209+ final id = mapping[name];
210+ toVisit.addAll (
211+ (await cache.source (id.source).describe (id)).dependencies.keys);
212+ }
213+ return visited;
214+ }
184215}
185216
186217Pubspec _stripDevDependencies (Pubspec original) {
@@ -241,6 +272,8 @@ Future<void> _outputHuman(List<_PackageDetails> rows,
241272 final devRows = rows.where ((row) => row.kind == _DependencyKind .dev);
242273 final transitiveRows =
243274 rows.where ((row) => row.kind == _DependencyKind .transitive);
275+ final devTransitiveRows =
276+ rows.where ((row) => row.kind == _DependencyKind .devTransitive);
244277
245278 final formattedRows = < List <_FormattedString >> [
246279 ['Dependencies' , 'Current' , 'Upgradable' , 'Resolvable' , 'Latest' ]
@@ -261,6 +294,13 @@ Future<void> _outputHuman(List<_PackageDetails> rows,
261294 : _format ('\n transitive dependencies' , log.bold)
262295 ],
263296 ...await Future .wait (transitiveRows.map (marker)),
297+ if (includeDevDependencies)
298+ [
299+ devTransitiveRows.isEmpty
300+ ? _raw ('\n transitive dev_dependencies: all up-to-date' )
301+ : _format ('\n transitive dev_dependencies' , log.bold)
302+ ],
303+ ...await Future .wait (devTransitiveRows.map (marker)),
264304 ];
265305
266306 final columnWidths = < int , int > {};
@@ -400,13 +440,18 @@ class _PackageDetails implements Comparable<_PackageDetails> {
400440 }
401441}
402442
403- _DependencyKind _kind (String name, Entrypoint entrypoint) {
443+ _DependencyKind _kind (
444+ String name, Entrypoint entrypoint, Set <String > nonDevTransitive) {
404445 if (entrypoint.root.dependencies.containsKey (name)) {
405446 return _DependencyKind .direct;
406447 } else if (entrypoint.root.devDependencies.containsKey (name)) {
407448 return _DependencyKind .dev;
408449 } else {
409- return _DependencyKind .transitive;
450+ if (nonDevTransitive.contains (name)) {
451+ return _DependencyKind .transitive;
452+ } else {
453+ return _DependencyKind .devTransitive;
454+ }
410455 }
411456}
412457
@@ -417,8 +462,11 @@ enum _DependencyKind {
417462 /// Direct dev dependencies.
418463 dev,
419464
420- /// Transitive dependencies.
421- transitive
465+ /// Transitive dependencies of direct dependencies.
466+ transitive,
467+
468+ /// Transitive dependencies needed only by dev_dependencies.
469+ devTransitive,
422470}
423471
424472_FormattedString _format (String value, Function (String ) format, {prefix = '' }) {
0 commit comments