Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add package names endpoint #55

Merged
merged 15 commits into from
Jan 6, 2025
Merged
3 changes: 3 additions & 0 deletions lib/src/endpoints.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class Endpoint {
/// Retrieve all package names on pub.dev
String get packageNames => '$apiUrl/package-names';

/// Package names for name completion
String get packageNameCompletion => '$apiUrl/package-name-completion-data';

/// Url to add and remove likes
String likePackage(String name) => '$accountUrl/likes/$name';

Expand Down
22 changes: 22 additions & 0 deletions lib/src/models/search_results_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,28 @@ abstract class PaginatedResults<T> {
const PaginatedResults();
}

/// Package Names Model
@MappableClass()
class PackageNamesResults extends PaginatedResults<String> {
final List<String> packages;

@override
List<String> get results => packages;

final String? nextUrl;

@override
String? get next => nextUrl;

const PackageNamesResults({
required this.packages,
this.nextUrl,
});

static const fromMap = PackageNamesResultsMapper.fromMap;
static const fromJson = PackageNamesResultsMapper.fromJson;
}

/// Search Results Model
@MappableClass()
class SearchResults extends PaginatedResults<PackageResult>
Expand Down
122 changes: 122 additions & 0 deletions lib/src/models/search_results_model.mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,128 @@

part of 'search_results_model.dart';

class PackageNamesResultsMapper extends ClassMapperBase<PackageNamesResults> {
PackageNamesResultsMapper._();

static PackageNamesResultsMapper? _instance;
static PackageNamesResultsMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = PackageNamesResultsMapper._());
}
return _instance!;
}

@override
final String id = 'PackageNamesResults';

static List<String> _$packages(PackageNamesResults v) => v.packages;
static const Field<PackageNamesResults, List<String>> _f$packages =
Field('packages', _$packages);
static String? _$nextUrl(PackageNamesResults v) => v.nextUrl;
static const Field<PackageNamesResults, String> _f$nextUrl =
Field('nextUrl', _$nextUrl, opt: true);

@override
final MappableFields<PackageNamesResults> fields = const {
#packages: _f$packages,
#nextUrl: _f$nextUrl,
};

static PackageNamesResults _instantiate(DecodingData data) {
return PackageNamesResults(
packages: data.dec(_f$packages), nextUrl: data.dec(_f$nextUrl));
}

@override
final Function instantiate = _instantiate;

static PackageNamesResults fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<PackageNamesResults>(map);
}

static PackageNamesResults fromJson(String json) {
return ensureInitialized().decodeJson<PackageNamesResults>(json);
}
}

mixin PackageNamesResultsMappable {
String toJson() {
return PackageNamesResultsMapper.ensureInitialized()
.encodeJson<PackageNamesResults>(this as PackageNamesResults);
}

Map<String, dynamic> toMap() {
return PackageNamesResultsMapper.ensureInitialized()
.encodeMap<PackageNamesResults>(this as PackageNamesResults);
}

PackageNamesResultsCopyWith<PackageNamesResults, PackageNamesResults,
PackageNamesResults>
get copyWith => _PackageNamesResultsCopyWithImpl(
this as PackageNamesResults, $identity, $identity);
@override
String toString() {
return PackageNamesResultsMapper.ensureInitialized()
.stringifyValue(this as PackageNamesResults);
}

@override
bool operator ==(Object other) {
return PackageNamesResultsMapper.ensureInitialized()
.equalsValue(this as PackageNamesResults, other);
}

@override
int get hashCode {
return PackageNamesResultsMapper.ensureInitialized()
.hashValue(this as PackageNamesResults);
}
}

extension PackageNamesResultsValueCopy<$R, $Out>
on ObjectCopyWith<$R, PackageNamesResults, $Out> {
PackageNamesResultsCopyWith<$R, PackageNamesResults, $Out>
get $asPackageNamesResults =>
$base.as((v, t, t2) => _PackageNamesResultsCopyWithImpl(v, t, t2));
}

abstract class PackageNamesResultsCopyWith<$R, $In extends PackageNamesResults,
$Out> implements ClassCopyWith<$R, $In, $Out> {
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get packages;
$R call({List<String>? packages, String? nextUrl});
PackageNamesResultsCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}

class _PackageNamesResultsCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, PackageNamesResults, $Out>
implements PackageNamesResultsCopyWith<$R, PackageNamesResults, $Out> {
_PackageNamesResultsCopyWithImpl(super.value, super.then, super.then2);

@override
late final ClassMapperBase<PackageNamesResults> $mapper =
PackageNamesResultsMapper.ensureInitialized();
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get packages =>
ListCopyWith($value.packages, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(packages: v));
@override
$R call({List<String>? packages, Object? nextUrl = $none}) =>
$apply(FieldCopyWithData({
if (packages != null) #packages: packages,
if (nextUrl != $none) #nextUrl: nextUrl
}));
@override
PackageNamesResults $make(CopyWithData data) => PackageNamesResults(
packages: data.get(#packages, or: $value.packages),
nextUrl: data.get(#nextUrl, or: $value.nextUrl));

@override
PackageNamesResultsCopyWith<$R2, PackageNamesResults, $Out2>
$chain<$R2, $Out2>(Then<$Out2, $R2> t) =>
_PackageNamesResultsCopyWithImpl($value, $cast, t);
}

class SearchResultsMapper extends ClassMapperBase<SearchResults> {
SearchResultsMapper._();

Expand Down
17 changes: 14 additions & 3 deletions lib/src/pub_api_client_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,23 @@ class PubClient {
}

/// Returns a `List<String>` of all packages listed on pub.dev
Future<List<String>> packageNameCompletion() async {
leoafarias marked this conversation as resolved.
Show resolved Hide resolved
Future<List<String>> packageNames() async {
final data = await _fetch(endpoint.packageNames);
final packages = data['packages'] as List<dynamic>;
final results = PackageNamesResults.fromMap(data);
return recursivePaging(results, (url) async {
final data = await _fetch(endpoint.nextPage(url));
return PackageNamesResults.fromMap(data);
});
}

/// Package names for name completion
Future<List<String>> packageNameCompletion() async {
final data = await _fetch(endpoint.packageNameCompletion);
// This result is not paginated
final packages = data['packages'] as List;

/// Need to map to convert dynamic into String
return packages.map((item) => item as String).toList();
return packages.cast<String>();
}

/// Searches pub for [query] and can [page] results.
Expand Down
7 changes: 6 additions & 1 deletion test/pubdev_api_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,13 @@ void main() {
expect(documentation2.versions.length, greaterThan(0));
});

test('Get package names', () async {
test('Get package name completion', () async {
final packages = await _client.packageNameCompletion();
expect(packages.length, equals(20000));
});

test('Get package names', () async {
final packages = await _client.packageNames();
expect(packages.length, greaterThan(20000));
});

Expand Down
Loading