Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions app/lib/frontend/templates/views/pkg/info_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:_pub_shared/format/encoding.dart';
import 'package:_pub_shared/search/tags.dart';
import 'package:pana/pana.dart';
import 'package:pub_dev/service/download_counts/download_counts.dart';
import 'package:pubspec_parse/pubspec_parse.dart' as pubspek;
Expand Down Expand Up @@ -105,7 +106,10 @@ d.Node packageInfoBoxNode({
),
if (license != null) _block('License', license),
if (dependencies != null) _block('Dependencies', dependencies),
_more(package.name!),
_more(
package.name!,
showImplementsLink: data.version.pubspec?.hasFlutterPlugin ?? false,
),
]);
}

Expand Down Expand Up @@ -160,14 +164,26 @@ d.Node _metadata({
]);
}

d.Node _more(String packageName) {
d.Node _more(String packageName, {required bool showImplementsLink}) {
return _block(
'More',
d.a(
href: urls.searchUrl(q: 'dependency:$packageName'),
rel: 'nofollow',
text: 'Packages that depend on $packageName',
),
d.fragment([
d.a(
href: urls.searchUrl(q: 'dependency:$packageName'),
rel: 'nofollow',
text: 'Packages that depend on $packageName',
),
if (showImplementsLink) ...[
d.br(),
d.br(),
d.a(
href: urls.searchUrl(
q: PackageVersionTags.implementsFederatedPlugin(packageName)),
rel: 'nofollow',
text: 'Packages that implement $packageName',
),
],
]),
);
}

Expand Down
58 changes: 34 additions & 24 deletions app/lib/package/model_properties.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Map<String, dynamic> _loadYaml(String yamlString) {
class Pubspec {
final pubspek.Pubspec _inner;
final String jsonString;
Map<String, dynamic>? _json;
String? _canonicalVersion;

Pubspec._(this._inner, this.jsonString);
Expand All @@ -44,10 +43,9 @@ class Pubspec {
factory Pubspec.fromJson(Map<String, dynamic> map) =>
Pubspec._(pubspek.Pubspec.fromJson(map, lenient: true), json.encode(map));

Map<String, dynamic> get asJson {
_load();
return _json!;
}
late final _json = _loadYaml(jsonString);

Map<String, dynamic> get asJson => _json;

String get name => _inner.name;

Expand Down Expand Up @@ -84,8 +82,7 @@ class Pubspec {
.toList();

Map<String, dynamic>? get executables {
_load();
final map = _json!['executables'];
final map = _json['executables'];
return map is Map<String, dynamic> ? map : null;
}

Expand All @@ -97,7 +94,6 @@ class Pubspec {
/// Returns null if the constraint is missing or does not follow the
/// `>=<version>` pattern.
MinSdkVersion? get minSdkVersion {
_load();
return MinSdkVersion.tryParse(_inner.environment['sdk']);
}

Expand All @@ -106,7 +102,6 @@ class Pubspec {
/// Returns null if the constraint is missing or does not follow the
/// `>=<version>` pattern.
late final _minFlutterSdkVersion = () {
_load();
return MinSdkVersion.tryParse(_inner.environment['flutter']);
}();

Expand Down Expand Up @@ -162,27 +157,32 @@ class Pubspec {
.intersect(VersionConstraint.parse('<2.12.0-0'))
.isEmpty;

/// Whether the pubspec file contains a flutter.plugin entry.
bool get hasFlutterPlugin {
_load();
final flutter = _json!['flutter'];
if (flutter == null || flutter is! Map) return false;
late final _flutterPluginMap = () {
final flutter = _json['flutter'];
if (flutter == null || flutter is! Map) {
return null;
}
final plugin = flutter['plugin'];
return plugin != null && plugin is Map;
}
if (plugin != null && plugin is Map<String, dynamic>) {
return plugin;
} else {
return null;
}
}();

/// Whether the pubspec file contains a flutter.plugin entry.
bool get hasFlutterPlugin => _flutterPluginMap != null;

/// Whether the package has a dependency on flutter.
bool get dependsOnFlutter {
_load();
final dependencies = _json!['dependencies'];
final dependencies = _json['dependencies'];
if (dependencies == null || dependencies is! Map) return false;
return dependencies.containsKey('flutter');
}

/// Whether the package has a dependency on flutter and it refers to the SDK.
bool get dependsOnFlutterSdk {
_load();
final dependencies = _json!['dependencies'];
final dependencies = _json['dependencies'];
if (dependencies == null || dependencies is! Map) return false;
final flutter = dependencies['flutter'];
if (flutter == null || flutter is! Map) return false;
Expand All @@ -195,14 +195,24 @@ class Pubspec {
bool get hasOptedIntoNullSafety =>
_sdkConstraintStatus.hasOptedIntoNullSafety;

void _load() {
_json ??= _loadYaml(jsonString);
}

late final List<Uri> funding = _inner.funding ?? const <Uri>[];

/// Whether the pubspec has any topic entry.
bool get hasTopic => canonicalizedTopics.isNotEmpty;

/// If package is implementing a federated Flutter plugin, this will be name
/// of the plugin package, `null` otherwise.
late final implementsFederatedPluginName = () {
if (_flutterPluginMap == null) {
return null;
}
final implements = _flutterPluginMap['implements'];
if (implements != null && implements is String) {
return implements;
} else {
return null;
}
}();
}

class MinSdkVersion {
Expand Down
5 changes: 5 additions & 0 deletions app/lib/package/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -658,13 +658,18 @@ class PackageVersion extends db.ExpandoModel<String> {

/// List of tags from the properties on the current [PackageVersion] entity.
Iterable<String> getTags() {
final pluginForName = pubspec!.implementsFederatedPluginName;
return <String>{
if (pubspec!.supportsOnlyLegacySdk) ...[
PackageVersionTags.isLegacy,
PackageTags.isUnlisted,
],
if (pubspec!.funding.isNotEmpty) PackageVersionTags.hasFundingLink,
if (pubspec!.hasTopic) PackageVersionTags.hasTopic,
if (pluginForName != null) ...[
PackageVersionTags.hasImplementsFederatedPlugin,
PackageVersionTags.implementsFederatedPlugin(pluginForName),
],
};
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/_pub_shared/lib/search/search_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final RegExp _allDependencyRegExp =
final _sortRegExp = RegExp('sort:([a-z]+)');
final _updatedRegExp = RegExp('updated:([0-9][0-9a-z]*)');
final _tagRegExp =
RegExp(r'([\+|\-]?[a-z0-9]+:[a-z0-9\-_\.]+)', caseSensitive: false);
RegExp(r'([\+|\-]?[a-z0-9\-]+:[a-z0-9\-_\.]+)', caseSensitive: false);

/// The tag prefixes that we can detect in the user-provided search query.
final _detectedTagPrefixes = <String>{
Expand Down
15 changes: 13 additions & 2 deletions pkg/_pub_shared/lib/search/tags.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const allowedTagPrefixes = [
'sdk:',
'show:',
'has:',
'topic:'
'topic:',
'implements-federated-plugin:',
];

/// Collection of package-related tags.
Expand Down Expand Up @@ -87,6 +88,14 @@ abstract class PackageVersionTags {
/// Package version may be used in WASM compilation.
static const String isWasmReady = 'is:wasm-ready';

/// Package version has an entry indicating it implements a federated plugin.
static const String hasImplementsFederatedPlugin =
'has:implements-federated-plugin';

/// The `implements-federated-plugin:<name>` tag.
static String implementsFederatedPlugin(String name) =>
'implements-federated-plugin:$name';

/// Version tags that provide a positive, forward-looking property
/// of a prerelease or preview version.
///
Expand Down Expand Up @@ -167,5 +176,7 @@ const _futureVersionTags = <String>{
/// Returns whether a [tag] is relevant to the package search,
/// if it is a value from a preview or prerelease version.
bool isFutureVersionTag(String tag) {
return _futureVersionTags.contains(tag) || tag.startsWith('runtime:');
return _futureVersionTags.contains(tag) ||
tag.startsWith('runtime:') ||
tag.startsWith('plugin-for:');
}
8 changes: 8 additions & 0 deletions pkg/_pub_shared/test/search/search_form_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ void main() {
query.parsedQuery.tagsPredicate.toQueryParameters(), ['is:legacy']);
});

test('complex tag', () {
final query =
SearchForm(query: 'implements-federated-plugin:url_launcher');
expect(query.parsedQuery.text, isNull);
expect(query.parsedQuery.tagsPredicate.toQueryParameters(),
['implements-federated-plugin:url_launcher']);
});

test('forbidden known tag', () {
final query = SearchForm(query: '-is:legacy');
expect(query.parsedQuery.text, isNull);
Expand Down