| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | /// A function used to determine whether results should be collected for the | 
 | /// file with the given [path]. | 
 | typedef ShouldCollectPredicate = bool Function(String path); | 
 |  | 
 | /// An object used to collect partial results (of type [E]) where the partial | 
 | /// results are contributed by plugins. | 
 | class ResultCollector<E> { | 
 |   /// The id used as a plugin id for contributions from the server. | 
 |   final String serverId; | 
 |  | 
 |   /// A function used to determine whether results should be collected for the | 
 |   /// file whose path is passed in as an argument. | 
 |   final ShouldCollectPredicate? _shouldCollect; | 
 |  | 
 |   /// A multi-keyed map, where the first key is the (normalized and absolute) | 
 |   /// path to the file associated with the results, and the second is the id of | 
 |   /// the plugin that provided the partial results. The value is the partial | 
 |   /// results contributed by the plugin for the file. | 
 |   final Map<String, Map<String, E>> resultMap = <String, Map<String, E>>{}; | 
 |  | 
 |   /// Initialize a newly created result manager. | 
 |   ResultCollector(this.serverId, {ShouldCollectPredicate? predicate}) | 
 |     : _shouldCollect = predicate; | 
 |  | 
 |   /// Clear any results that have been contributed for the file with the given | 
 |   /// [filePath], but continue to collect results for the file. This is used | 
 |   /// when the results for the specified file are known to be invalid, typically | 
 |   /// because the content of the file has been modified. | 
 |   void clearResultsForFile(String filePath) { | 
 |     resultMap[filePath]?.clear(); | 
 |   } | 
 |  | 
 |   /// Clear any results that have been contributed by the plugin with the given | 
 |   /// [pluginId]. | 
 |   void clearResultsFromPlugin(String pluginId) { | 
 |     for (var partialResults in resultMap.values) { | 
 |       partialResults.remove(pluginId); | 
 |     } | 
 |   } | 
 |  | 
 |   /// Return an iterator producing the partial results that have been | 
 |   /// contributed for the given [filePath]. | 
 |   List<E> getResults(String filePath) { | 
 |     var partialResultMap = resultMap[filePath]; | 
 |     if (partialResultMap == null) { | 
 |       return <E>[]; | 
 |     } | 
 |     var values = partialResultMap.values.toList(); | 
 |     // | 
 |     // Ensure that the server's contributions are always first in the list. | 
 |     // | 
 |     var serverContributions = partialResultMap[serverId]; | 
 |     if (serverContributions != null && values.remove(serverContributions)) { | 
 |       values.insert(0, serverContributions); | 
 |     } | 
 |     return values; | 
 |   } | 
 |  | 
 |   /// Return `true` if this collector is collecting results associated with the | 
 |   /// given [filePath]. | 
 |   bool isCollectingFor(String filePath) { | 
 |     var predicate = _shouldCollect; | 
 |     if (predicate != null) { | 
 |       return predicate(filePath); | 
 |     } | 
 |     return resultMap.containsKey(filePath); | 
 |   } | 
 |  | 
 |   /// Record the [partialResults] as having been contributed for the given | 
 |   /// [filePath] by the plugin with the given [pluginId]. | 
 |   void putResults(String filePath, String pluginId, E partialResults) { | 
 |     var fileResults = resultMap[filePath]; | 
 |     if (fileResults == null) { | 
 |       var predicate = _shouldCollect; | 
 |       if (predicate != null && predicate(filePath)) { | 
 |         resultMap[filePath] = <String, E>{pluginId: partialResults}; | 
 |       } | 
 |     } else { | 
 |       fileResults[pluginId] = partialResults; | 
 |     } | 
 |   } | 
 |  | 
 |   /// Start collecting results contributed for the file with the given | 
 |   /// [filePath]. Unless the collector is told to collect results for a file, | 
 |   /// any results that are contributed for that file are discarded. | 
 |   void startCollectingFor(String filePath) { | 
 |     resultMap.putIfAbsent(filePath, () => <String, E>{}); | 
 |   } | 
 |  | 
 |   /// Stop collecting results contributed for the file with the given | 
 |   /// [filePath]. Until the collector is told to start collecting results for | 
 |   /// the file, any results that are contributed for the file are discarded. | 
 |   void stopCollectingFor(String filePath) { | 
 |     resultMap.remove(filePath); | 
 |   } | 
 | } |