Skip to content

Commit

Permalink
Add package names endpoint (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexios80 authored Jan 6, 2025
1 parent ce55f76 commit 1d808b4
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 4 deletions.
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 {
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

0 comments on commit 1d808b4

Please sign in to comment.