discoverFlutterPlugins function

Future<List<PluginCandidate>> discoverFlutterPlugins(
  1. PubDevClient client, {
  2. int resultsPerQuery = 100,
  3. int concurrency = 4,
})

Discovers Flutter plugin candidates from pub.dev search, reds first (SPEC §3.1.1, 2026-09-27): discoveryQueries, sorted by downloads, resultsPerQuery results each (rounded up to pages of 10 — pub.dev caps a single query at 100 results). Merges and dedupes both queries, then folds federated platform packages into their app-facing plugin so a plugin's downloads/status aren't split across rows.

Implementation

Future<List<PluginCandidate>> discoverFlutterPlugins(
  PubDevClient client, {
  int resultsPerQuery = 100,
  int concurrency = 4,
}) async {
  final pagesPerQuery = (resultsPerQuery / _resultsPerPage).ceil();
  final order = <String>[];
  final sourcesByName = <String, Set<String>>{};
  for (final discoveryQuery in discoveryQueries) {
    final names = await _fetchQueryNames(
      client,
      discoveryQuery.query,
      pagesPerQuery,
      concurrency,
    );
    for (final name in names) {
      final labels = sourcesByName.putIfAbsent(name, () => <String>{});
      final isNew = labels.isEmpty;
      labels.add(discoveryQuery.label);
      if (isNew) order.add(name);
    }
  }

  final survivors = await _foldFederatedPackages(client, order, concurrency);

  return mapWithConcurrency(survivors, concurrency, (name) async {
    final tags = await _safeTags(client, name);
    final sources = sourcesByName[name]!.toList()..sort();
    return PluginCandidate(name: name, tags: tags, sources: sources);
  });
}