Skip to content

Commit c898680

Browse files
authored
Merging separate Dart and Flutter SDK indexes into a single index. (#8776)
1 parent 6fc0f20 commit c898680

11 files changed

+84
-168
lines changed

app/bin/tools/sdk_search_benchmark.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:pub_dev/search/flutter_sdk_mem_index.dart';
5+
import 'package:pub_dev/search/sdk_mem_index.dart';
66

77
/// Loads a Dart SDK search snapshot and executes queries on it, benchmarking their total time to complete.
88
Future<void> main() async {
9-
final index = await createFlutterSdkMemIndex();
9+
final index = await createSdkMemIndex();
1010

1111
// NOTE: please add more queries to this list, especially if there is a performance bottleneck.
1212
final queries = [

app/lib/search/backend.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,9 @@ import '../task/backend.dart';
4242
import '../task/global_lock.dart';
4343
import '../task/models.dart';
4444

45-
import 'dart_sdk_mem_index.dart';
46-
import 'flutter_sdk_mem_index.dart';
4745
import 'models.dart';
4846
import 'result_combiner.dart';
47+
import 'sdk_mem_index.dart';
4948
import 'search_client.dart';
5049
import 'search_service.dart';
5150
import 'text_utils.dart';
@@ -623,8 +622,7 @@ class _CombinedSearchIndex implements SearchIndex {
623622
PackageSearchResult search(ServiceSearchQuery query) {
624623
final combiner = SearchResultCombiner(
625624
primaryIndex: _packageIndexHolder._index,
626-
dartSdkMemIndex: dartSdkMemIndex,
627-
flutterSdkMemIndex: flutterSdkMemIndex,
625+
sdkMemIndex: sdkMemIndex,
628626
);
629627
return combiner.search(query);
630628
}

app/lib/search/dart_sdk_mem_index.dart

Lines changed: 0 additions & 38 deletions
This file was deleted.

app/lib/search/flutter_sdk_mem_index.dart

Lines changed: 0 additions & 61 deletions
This file was deleted.

app/lib/search/result_combiner.dart

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ import 'search_service.dart';
1313
/// SDK index.
1414
class SearchResultCombiner {
1515
final InMemoryPackageIndex primaryIndex;
16-
final SdkMemIndex? dartSdkMemIndex;
17-
final SdkMemIndex? flutterSdkMemIndex;
16+
final SdkMemIndex? sdkMemIndex;
1817

1918
SearchResultCombiner({
2019
required this.primaryIndex,
21-
required this.dartSdkMemIndex,
22-
required this.flutterSdkMemIndex,
20+
required this.sdkMemIndex,
2321
});
2422

2523
PackageSearchResult search(ServiceSearchQuery query) {
@@ -30,11 +28,10 @@ class SearchResultCombiner {
3028

3129
final queryFlutterSdk = query.tagsPredicate.hasNoTagPrefix('sdk:') ||
3230
query.tagsPredicate.hasTag(SdkTag.sdkFlutter);
33-
final sdkLibraryHits = [
34-
...?dartSdkMemIndex?.search(query.query!, limit: 2),
35-
if (queryFlutterSdk)
36-
...?flutterSdkMemIndex?.search(query.query!, limit: 2),
37-
];
31+
final sdkLibraryHits = sdkMemIndex
32+
?.search(query.query!, limit: 2, skipFlutter: !queryFlutterSdk)
33+
.toList() ??
34+
<SdkLibraryHit>[];
3835
if (sdkLibraryHits.isNotEmpty) {
3936
// Do not display low SDK scores if the package hits are more relevant on the page.
4037
//

app/lib/search/sdk_mem_index.dart

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,29 @@
44

55
import 'dart:math';
66

7+
import 'package:gcloud/service_scope.dart' as ss;
8+
import 'package:logging/logging.dart';
79
import 'package:meta/meta.dart';
810
// ignore: implementation_imports
911
import 'package:pana/src/dartdoc/dartdoc_index.dart';
1012
import 'package:path/path.dart' as p;
11-
import 'package:pub_dev/search/flutter_sdk_mem_index.dart';
13+
import 'package:pub_dev/search/backend.dart';
1214

1315
import 'search_service.dart';
1416
import 'token_index.dart';
1517

1618
export 'package:pana/src/dartdoc/dartdoc_index.dart';
1719

20+
/// Sets the SDK in-memory index.
21+
void registerSdkMemIndex(SdkMemIndex? index) {
22+
if (index != null) {
23+
ss.register(#_sdkMemIndex, index);
24+
}
25+
}
26+
27+
/// The active SDK in-memory index.
28+
SdkMemIndex? get sdkMemIndex => ss.lookup(#_sdkMemIndex) as SdkMemIndex?;
29+
1830
/// Results from these libraries are ranked with lower score and
1931
/// will be displayed only if the query has the library name, or
2032
/// there are not other results that could match the query.
@@ -30,48 +42,54 @@ const _defaultApiPageDirWeights = {
3042
'material/Icons': 0.25,
3143
};
3244

45+
final _logger = Logger('search.dart_sdk_mem_index');
46+
final _dartUri = Uri.parse('https://api.dart.dev/stable/latest/');
47+
final _flutterUri = Uri.parse('https://api.flutter.dev/flutter/');
48+
49+
/// Tries to load Dart and Flutter SDK's dartdoc `index.json` and build
50+
/// a search index from it.
51+
///
52+
/// Returns `null` when the loading of `index.json` failed, or when there
53+
/// was an error parsing the file or building the index.
54+
Future<SdkMemIndex?> createSdkMemIndex() async {
55+
try {
56+
final dartSdkContent =
57+
await loadOrFetchSdkIndexJsonAsString(SdkMemIndex.dartSdkIndexJsonUri);
58+
final flutterSdkContent = await loadOrFetchSdkIndexJsonAsString(
59+
SdkMemIndex._flutterSdkIndexJsonUri);
60+
return SdkMemIndex(
61+
dartIndex: DartdocIndex.parseJsonText(dartSdkContent),
62+
flutterIndex: DartdocIndex.parseJsonText(flutterSdkContent),
63+
);
64+
} catch (e, st) {
65+
_logger.warning('Unable to load SDK index.', e, st);
66+
return null;
67+
}
68+
}
69+
3370
/// In-memory index for SDK library search queries.
3471
class SdkMemIndex {
3572
final _libraries = <String, _Library>{};
3673
final Map<String, double> _apiPageDirWeights;
3774

3875
SdkMemIndex({
39-
required String sdk,
40-
required Uri baseUri,
41-
required DartdocIndex index,
42-
Set<String>? allowedLibraries,
76+
required DartdocIndex dartIndex,
77+
required DartdocIndex flutterIndex,
4378
Map<String, double>? apiPageDirWeights,
4479
}) : _apiPageDirWeights = apiPageDirWeights ?? _defaultApiPageDirWeights {
45-
_addDartdocIndex(sdk, baseUri, index, allowedLibraries);
46-
}
47-
48-
static SdkMemIndex dart({required DartdocIndex index}) {
49-
return SdkMemIndex(
50-
sdk: 'dart',
51-
baseUri: Uri.parse('https://api.dart.dev/stable/latest/'),
52-
index: index,
53-
);
54-
}
55-
56-
factory SdkMemIndex.flutter({required DartdocIndex index}) {
57-
return SdkMemIndex(
58-
sdk: 'flutter',
59-
baseUri: Uri.parse('https://api.flutter.dev/flutter/'),
60-
index: index,
61-
allowedLibraries: flutterSdkAllowedLibraries,
62-
);
80+
_addDartdocIndex('dart', _dartUri, dartIndex);
81+
_addDartdocIndex('flutter', _flutterUri, flutterIndex);
6382
}
6483

6584
static final dartSdkIndexJsonUri =
6685
Uri.parse('https://api.dart.dev/stable/latest/index.json');
67-
static final flutterSdkIndexJsonUri =
86+
static final _flutterSdkIndexJsonUri =
6887
Uri.parse('https://api.flutter.dev/flutter/index.json');
6988

7089
void _addDartdocIndex(
7190
String sdk,
7291
Uri baseUri,
7392
DartdocIndex index,
74-
Set<String>? allowedLibraries,
7593
) {
7694
final textsPerLibrary = <String, Map<String, String>>{};
7795
final baseUris = <String, Uri>{};
@@ -81,11 +99,7 @@ class SdkMemIndex {
8199
final library = f.qualifiedName?.split('.').first;
82100
if (library == null) continue;
83101
if (f.href == null) continue;
84-
if (allowedLibraries != null &&
85-
allowedLibraries.isNotEmpty &&
86-
!allowedLibraries.contains(library)) {
87-
continue;
88-
}
102+
if (_libraries.containsKey(library)) continue;
89103
if (f.isLibrary) {
90104
baseUris[library] = baseUri.resolve(f.href!);
91105

@@ -116,13 +130,15 @@ class SdkMemIndex {
116130
List<SdkLibraryHit> search(
117131
String query, {
118132
int? limit,
133+
bool skipFlutter = false,
119134
}) {
120135
limit ??= 2;
121136
final words = query.split(' ').where((e) => e.isNotEmpty).toList();
122137
if (words.isEmpty) return <SdkLibraryHit>[];
123138

124139
final hits = <_Hit>[];
125140
for (final library in _libraries.values) {
141+
if (skipFlutter && library.isFlutter) continue;
126142
// We may reduce the rank of certain libraries, except when their name is
127143
// also part of the query. E.g. `dart:html` with `query=cursor` may be
128144
// scored lower than `query=html cursor`.
@@ -204,6 +220,7 @@ class _Library {
204220
required this.tokenIndex,
205221
});
206222

223+
late final isFlutter = sdk == 'flutter';
207224
late final weight = _libraryWeights[name] ?? 1.0;
208225
late final lastNamePart = name.split(':').last;
209226
}

app/lib/service/entrypoint/search_index.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import 'dart:isolate';
99
import 'package:gcloud/service_scope.dart';
1010
import 'package:logging/logging.dart';
1111
import 'package:pub_dev/search/backend.dart';
12-
import 'package:pub_dev/search/dart_sdk_mem_index.dart';
13-
import 'package:pub_dev/search/flutter_sdk_mem_index.dart';
12+
import 'package:pub_dev/search/sdk_mem_index.dart';
1413
import 'package:pub_dev/search/search_service.dart';
1514
import 'package:pub_dev/search/updater.dart';
1615
import 'package:pub_dev/service/entrypoint/_isolate.dart';
@@ -37,8 +36,7 @@ Future<void> main(List<String> args, var message) async {
3736
}
3837
await fork(() async {
3938
await servicesWrapperFn(() async {
40-
registerDartSdkMemIndex(await createDartSdkMemIndex());
41-
registerFlutterSdkMemIndex(await createFlutterSdkMemIndex());
39+
registerSdkMemIndex(await createSdkMemIndex());
4240
await indexUpdater.init();
4341

4442
final requestReceivePort = ReceivePort();

app/test/search/backend_test.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ void main() {
1515
testWithProfile('fetch SDK library description', fn: () async {
1616
final content = await loadOrFetchSdkIndexJsonAsString(
1717
SdkMemIndex.dartSdkIndexJsonUri);
18-
final index =
19-
SdkMemIndex.dart(index: DartdocIndex.parseJsonText(content));
18+
final index = SdkMemIndex(
19+
dartIndex: DartdocIndex.parseJsonText(content),
20+
flutterIndex: DartdocIndex([]),
21+
);
2022
expect(
2123
index.getLibraryDescription('dart:async'),
2224
'Support for asynchronous programming, with classes such as Future and Stream.',

app/test/search/dartdoc_index_parsing_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ void main() {
6666
expect(parserWithoutFirstEntry, originalWithoutFirstEntry);
6767

6868
// parsing into SDK index
69-
final sdkMemIndex = SdkMemIndex.flutter(index: index);
69+
final sdkMemIndex = SdkMemIndex(
70+
dartIndex: DartdocIndex([]),
71+
flutterIndex: index,
72+
);
7073
final rs = sdkMemIndex.search('StatelessWidget');
7174
expect(json.decode(json.encode(rs)), [
7275
{

app/test/search/result_combiner_test.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import 'package:pub_dev/search/mem_index.dart';
99
import 'package:pub_dev/search/result_combiner.dart';
1010
import 'package:pub_dev/search/sdk_mem_index.dart';
1111
import 'package:pub_dev/search/search_service.dart';
12-
import 'package:pub_dev/shared/versions.dart';
1312
import 'package:test/test.dart';
1413

1514
void main() {
@@ -30,10 +29,8 @@ void main() {
3029
);
3130
final combiner = SearchResultCombiner(
3231
primaryIndex: primaryIndex,
33-
dartSdkMemIndex: SdkMemIndex(
34-
sdk: 'dart',
35-
baseUri: Uri.parse('https://api.dart.dev/stable/$runtimeSdkVersion/'),
36-
index: DartdocIndex.fromJsonList([
32+
sdkMemIndex: SdkMemIndex(
33+
dartIndex: DartdocIndex.fromJsonList([
3734
{
3835
'name': 'dart:core',
3936
'qualifiedName': 'dart:core',
@@ -71,8 +68,8 @@ void main() {
7168
'enclosedBy': {'name': 'String', 'kind': 3}
7269
},
7370
]),
71+
flutterIndex: DartdocIndex([]),
7472
),
75-
flutterSdkMemIndex: null,
7673
);
7774

7875
test('non-text ranking', () async {

0 commit comments

Comments
 (0)