From 203e64dd2574a02204365cd204fd97db69379607 Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Thu, 3 Aug 2023 17:53:18 +0200 Subject: [PATCH] :bookmark: release v7.0.1 (#465) # chopper ## 7.0.1 - Refactor ChopperClient constructor - Refactor ChopperClient.getService - Refactor CurlInterceptor # chopper_generator ## 7.0.1 - Add final class modifier to generated Chopper API implementation --- .github/workflows/dart.yml | 40 ++--------- chopper/CHANGELOG.md | 6 ++ chopper/example/definition.chopper.dart | 2 +- chopper/lib/src/base.dart | 71 ++++++++++--------- chopper/lib/src/interceptor.dart | 31 ++++---- chopper/lib/src/utils.dart | 4 +- chopper/pubspec.yaml | 2 +- chopper/test/base_test.dart | 54 ++++++++++++-- chopper/test/test_service.chopper.dart | 2 +- chopper_built_value/mono_pkg.yaml | 2 +- chopper_generator/CHANGELOG.md | 4 ++ chopper_generator/lib/src/generator.dart | 1 + chopper_generator/mono_pkg.yaml | 2 +- chopper_generator/pubspec.yaml | 2 +- .../test/test_service.chopper.dart | 2 +- example/lib/built_value_resource.chopper.dart | 2 +- example/lib/json_serializable.chopper.dart | 2 +- mono_repo.yaml | 2 +- tool/ci.sh | 2 +- 19 files changed, 127 insertions(+), 106 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index ee10d7f9..6a6322d9 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -1,4 +1,4 @@ -# Created with package:mono_repo v6.5.5 +# Created with package:mono_repo v6.5.7 name: Dart CI on: push: @@ -37,20 +37,20 @@ jobs: name: Checkout repository uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab - name: mono_repo self validate - run: dart pub global activate mono_repo 6.5.5 + run: dart pub global activate mono_repo 6.5.7 - name: mono_repo self validate run: dart pub global run mono_repo generate --validate job_002: - name: "analyze_and_format; PKG: chopper; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`" + name: "analyze_and_format; PKGS: chopper, chopper_built_value, chopper_generator; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:chopper;commands:format-analyze" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:chopper-chopper_built_value-chopper_generator;commands:format-analyze" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:chopper + os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:chopper-chopper_built_value-chopper_generator os:ubuntu-latest;pub-cache-hosted;sdk:stable os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -74,29 +74,6 @@ jobs: run: dart analyze --fatal-infos . if: "always() && steps.chopper_pub_upgrade.conclusion == 'success'" working-directory: chopper - needs: - - job_001 - job_003: - name: "analyzer_and_format; PKGS: chopper_built_value, chopper_generator; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`" - runs-on: ubuntu-latest - steps: - - name: Cache Pub hosted dependencies - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 - with: - path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:chopper_built_value-chopper_generator;commands:format-analyze" - restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:chopper_built_value-chopper_generator - os:ubuntu-latest;pub-cache-hosted;sdk:stable - os:ubuntu-latest;pub-cache-hosted - os:ubuntu-latest - - name: Setup Dart SDK - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f - with: - sdk: stable - - id: checkout - name: Checkout repository - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab - id: chopper_built_value_pub_upgrade name: chopper_built_value; dart pub upgrade run: dart pub upgrade @@ -125,8 +102,7 @@ jobs: working-directory: chopper_generator needs: - job_001 - - job_002 - job_004: + job_003: name: "unit_test; PKGS: chopper, chopper_built_value, chopper_generator; `dart pub global run coverage:test_with_coverage`" runs-on: ubuntu-latest steps: @@ -197,8 +173,7 @@ jobs: needs: - job_001 - job_002 - - job_003 - job_005: + job_004: name: "unit_test; PKGS: chopper, chopper_built_value; `dart test -p chrome`" runs-on: ubuntu-latest steps: @@ -240,4 +215,3 @@ jobs: needs: - job_001 - job_002 - - job_003 diff --git a/chopper/CHANGELOG.md b/chopper/CHANGELOG.md index b2846189..b226ff15 100644 --- a/chopper/CHANGELOG.md +++ b/chopper/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 7.0.1 + +- Refactor ChopperClient constructor +- Refactor ChopperClient.getService +- Refactor CurlInterceptor + ## 7.0.0 - Require Dart 3.0 or later diff --git a/chopper/example/definition.chopper.dart b/chopper/example/definition.chopper.dart index c7c86ef7..a7fdf51a 100644 --- a/chopper/example/definition.chopper.dart +++ b/chopper/example/definition.chopper.dart @@ -7,7 +7,7 @@ part of 'definition.dart'; // ************************************************************************** // ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps -class _$MyService extends MyService { +final class _$MyService extends MyService { _$MyService([ChopperClient? client]) { if (client == null) return; this.client = client; diff --git a/chopper/lib/src/base.dart b/chopper/lib/src/base.dart index 27ab57fc..e791c13b 100644 --- a/chopper/lib/src/base.dart +++ b/chopper/lib/src/base.dart @@ -10,8 +10,6 @@ import 'package:chopper/src/utils.dart'; import 'package:http/http.dart' as http; import 'package:meta/meta.dart'; -Type _typeOf() => T; - @visibleForTesting const List allowedInterceptorsType = [ RequestInterceptor, @@ -47,11 +45,13 @@ base class ChopperClient { /// (statusCode < 200 || statusCode >= 300\). final ErrorConverter? errorConverter; - final Map _services = {}; - final _requestInterceptors = []; - final _responseInterceptors = []; - final _requestController = StreamController.broadcast(); - final _responseController = StreamController.broadcast(); + late final Map _services; + late final List _requestInterceptors; + late final List _responseInterceptors; + final StreamController _requestController = + StreamController.broadcast(); + final StreamController _responseController = + StreamController.broadcast(); final bool _clientIsInternal; @@ -114,44 +114,46 @@ base class ChopperClient { ChopperClient({ Uri? baseUrl, http.Client? client, - Iterable interceptors = const [], + Iterable? interceptors, this.authenticator, this.converter, this.errorConverter, - Iterable services = const [], + Iterable? services, }) : assert( - baseUrl == null || !baseUrl.hasQuery, - 'baseUrl should not contain query parameters.' - 'Use a request interceptor to add default query parameters'), + baseUrl == null || !baseUrl.hasQuery, + 'baseUrl should not contain query parameters. ' + 'Use a request interceptor to add default query parameters', + ), baseUrl = baseUrl ?? Uri(), httpClient = client ?? http.Client(), - _clientIsInternal = client == null { - if (!interceptors.every(_isAnInterceptor)) { - throw ArgumentError( - 'Unsupported type for interceptors, it only support the following types:\n' - '${allowedInterceptorsType.join('\n - ')}', - ); - } - - _requestInterceptors.addAll(interceptors.where(_isRequestInterceptor)); - _responseInterceptors.addAll(interceptors.where(_isResponseInterceptor)); - - services.toSet().forEach((s) { - s.client = this; - _services[s.definitionType] = s; - }); + _clientIsInternal = client == null, + assert( + interceptors?.every(_isAnInterceptor) ?? true, + 'Unsupported type for interceptors, it only support the following types:\n' + ' - ${allowedInterceptorsType.join('\n - ')}', + ), + _requestInterceptors = [ + ...?interceptors?.where(_isRequestInterceptor), + ], + _responseInterceptors = [ + ...?interceptors?.where(_isResponseInterceptor), + ] { + _services = { + for (final ChopperService service in services?.toSet() ?? []) + service.definitionType: service..client = this + }; } - bool _isRequestInterceptor(value) => + static bool _isRequestInterceptor(value) => value is RequestInterceptor || value is RequestInterceptorFunc; - bool _isResponseInterceptor(value) => + static bool _isResponseInterceptor(value) => value is ResponseInterceptor || value is ResponseInterceptorFunc1 || value is ResponseInterceptorFunc2 || value is DynamicResponseInterceptorFunc; - bool _isAnInterceptor(value) => + static bool _isAnInterceptor(value) => _isResponseInterceptor(value) || _isRequestInterceptor(value); /// Retrieve any service included in the [ChopperClient] @@ -168,15 +170,14 @@ base class ChopperClient { /// final todoService = chopper.getService(); /// ``` ServiceType getService() { - final Type serviceType = _typeOf(); - if (serviceType == dynamic || serviceType == ChopperService) { + if (ServiceType == dynamic || ServiceType == ChopperService) { throw Exception( 'Service type should be provided, `dynamic` is not allowed.', ); } - final ChopperService? service = _services[serviceType]; + final ChopperService? service = _services[ServiceType]; if (service == null) { - throw Exception('Service of type \'$serviceType\' not found.'); + throw Exception("Service of type '$ServiceType' not found."); } return service as ServiceType; @@ -185,7 +186,7 @@ base class ChopperClient { Future _encodeRequest(Request request) async => converter?.convertRequest(request) ?? request; - Future> _decodeResponse( + static Future> _decodeResponse( Response response, Converter withConverter, ) async => diff --git a/chopper/lib/src/interceptor.dart b/chopper/lib/src/interceptor.dart index 185bfc97..1431fc23 100644 --- a/chopper/lib/src/interceptor.dart +++ b/chopper/lib/src/interceptor.dart @@ -137,32 +137,27 @@ class CurlInterceptor implements RequestInterceptor { @override Future onRequest(Request request) async { final http.BaseRequest baseRequest = await request.toBaseRequest(); - final String method = baseRequest.method; - final String url = baseRequest.url.toString(); - final Map headers = baseRequest.headers; - String curl = 'curl -v -X $method'; - headers.forEach((k, v) { - curl += ' -H \'$k: $v\''; - }); + final List curlParts = ['curl -v -X ${baseRequest.method}']; + for (final MapEntry header in baseRequest.headers.entries) { + curlParts.add("-H '${header.key}: ${header.value}'"); + } // this is fairly naive, but it should cover most cases if (baseRequest is http.Request) { - final body = baseRequest.body; + final String body = baseRequest.body; if (body.isNotEmpty) { - curl += ' -d \'$body\''; + curlParts.add("-d '$body'"); } } if (baseRequest is http.MultipartRequest) { - final fields = baseRequest.fields; - final files = baseRequest.files; - fields.forEach((k, v) { - curl += ' -f \'$k: $v\''; - }); - for (var file in files) { - curl += ' -f \'${file.field}: ${file.filename ?? ''}\''; + for (final MapEntry field in baseRequest.fields.entries) { + curlParts.add("-f '${field.key}: ${field.value}'"); + } + for (final http.MultipartFile file in baseRequest.files) { + curlParts.add("-f '${file.field}: ${file.filename ?? ''}'"); } } - curl += ' "$url"'; - chopperLogger.info(curl); + curlParts.add('"${baseRequest.url}"'); + chopperLogger.info(curlParts.join(' ')); return request; } diff --git a/chopper/lib/src/utils.dart b/chopper/lib/src/utils.dart index ce78291c..ea4995ff 100644 --- a/chopper/lib/src/utils.dart +++ b/chopper/lib/src/utils.dart @@ -156,6 +156,4 @@ final class _Pair with EquatableMixin { bool isTypeOf() => _Instance() is _Instance; -class _Instance { - // -} +final class _Instance {} diff --git a/chopper/pubspec.yaml b/chopper/pubspec.yaml index 5a6d5859..0e86235c 100644 --- a/chopper/pubspec.yaml +++ b/chopper/pubspec.yaml @@ -1,6 +1,6 @@ name: chopper description: Chopper is an http client generator using source_gen, inspired by Retrofit -version: 7.0.0 +version: 7.0.1 documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper diff --git a/chopper/test/base_test.dart b/chopper/test/base_test.dart index d6486c2e..3e6a6f01 100644 --- a/chopper/test/base_test.dart +++ b/chopper/test/base_test.dart @@ -28,6 +28,18 @@ void main() { ); group('Base', () { + test('getService', () async { + final httpClient = MockClient( + (_) async => http.Response('get response', 200), + ); + + final chopper = buildClient(httpClient); + final service = chopper.getService(); + + expect(service, isNotNull); + expect(service, isA()); + }); + test('get service errors', () async { final chopper = ChopperClient( baseUrl: baseUrl, @@ -38,7 +50,7 @@ void main() { } on Exception catch (e) { expect( e.toString(), - equals('Exception: Service of type \'HttpTestService\' not found.'), + equals("Exception: Service of type 'HttpTestService' not found."), ); } @@ -635,20 +647,50 @@ void main() { }); test('wrong type for interceptor', () { + expect( + () => ChopperClient(interceptors: [(bool foo) => 'bar']), + throwsA(isA()), + ); + try { ChopperClient( interceptors: [ (bool foo) => 'bar', ], ); - } on ArgumentError catch (e) { + } on AssertionError catch (error) { expect( - e.toString(), - 'Invalid argument(s): Unsupported type for interceptors, it only support the following types:\n' - '${allowedInterceptorsType.join('\n - ')}', + error.toString(), + contains( + 'Unsupported type for interceptors, it only support the following types:\n' + ' - ${allowedInterceptorsType.join('\n - ')}', + ), ); } - }); + }, testOn: 'vm'); + + test('wrong type for interceptor', () { + expect( + () => ChopperClient(interceptors: [(bool foo) => 'bar']), + throwsA(isA()), + ); + + try { + ChopperClient( + interceptors: [ + (bool foo) => 'bar', + ], + ); + } on AssertionError catch (error) { + expect( + error.toString(), + contains( + 'Unsupported type for interceptors, it only support the following types:\\n' + ' - ${allowedInterceptorsType.join('\\n - ')}', + ), + ); + } + }, testOn: 'browser'); test('Query Map 1', () async { final httpClient = MockClient((request) async { diff --git a/chopper/test/test_service.chopper.dart b/chopper/test/test_service.chopper.dart index 45e1d737..d0379988 100644 --- a/chopper/test/test_service.chopper.dart +++ b/chopper/test/test_service.chopper.dart @@ -7,7 +7,7 @@ part of 'test_service.dart'; // ************************************************************************** // ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps -class _$HttpTestService extends HttpTestService { +final class _$HttpTestService extends HttpTestService { _$HttpTestService([ChopperClient? client]) { if (client == null) return; this.client = client; diff --git a/chopper_built_value/mono_pkg.yaml b/chopper_built_value/mono_pkg.yaml index ae7b5f25..8cce50b9 100644 --- a/chopper_built_value/mono_pkg.yaml +++ b/chopper_built_value/mono_pkg.yaml @@ -2,7 +2,7 @@ sdk: - stable stages: -- analyzer_and_format: +- analyze_and_format: - group: - format - analyze: --fatal-infos . diff --git a/chopper_generator/CHANGELOG.md b/chopper_generator/CHANGELOG.md index d7b19300..7943acf4 100644 --- a/chopper_generator/CHANGELOG.md +++ b/chopper_generator/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 7.0.1 + +- Add final class modifier to generated Chopper API implementations + ## 7.0.0 - Require Dart 3.0 or later diff --git a/chopper_generator/lib/src/generator.dart b/chopper_generator/lib/src/generator.dart index f91820f7..70ee0790 100644 --- a/chopper_generator/lib/src/generator.dart +++ b/chopper_generator/lib/src/generator.dart @@ -68,6 +68,7 @@ final class ChopperGenerator final Class classBuilder = Class((builder) { builder + ..modifier = ClassModifier.final$ ..name = name ..extend = refer(friendlyName) ..fields.add(_buildDefinitionTypeMethod(friendlyName)) diff --git a/chopper_generator/mono_pkg.yaml b/chopper_generator/mono_pkg.yaml index c0087871..df365840 100644 --- a/chopper_generator/mono_pkg.yaml +++ b/chopper_generator/mono_pkg.yaml @@ -2,7 +2,7 @@ sdk: - stable stages: -- analyzer_and_format: +- analyze_and_format: - group: - format - analyze: --fatal-infos . diff --git a/chopper_generator/pubspec.yaml b/chopper_generator/pubspec.yaml index e342ecc7..ac8b3aa7 100644 --- a/chopper_generator/pubspec.yaml +++ b/chopper_generator/pubspec.yaml @@ -1,6 +1,6 @@ name: chopper_generator description: Chopper is an http client generator using source_gen, inspired by Retrofit -version: 7.0.0 +version: 7.0.1 documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper diff --git a/chopper_generator/test/test_service.chopper.dart b/chopper_generator/test/test_service.chopper.dart index 45e1d737..d0379988 100644 --- a/chopper_generator/test/test_service.chopper.dart +++ b/chopper_generator/test/test_service.chopper.dart @@ -7,7 +7,7 @@ part of 'test_service.dart'; // ************************************************************************** // ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps -class _$HttpTestService extends HttpTestService { +final class _$HttpTestService extends HttpTestService { _$HttpTestService([ChopperClient? client]) { if (client == null) return; this.client = client; diff --git a/example/lib/built_value_resource.chopper.dart b/example/lib/built_value_resource.chopper.dart index e30a468b..af0b742d 100644 --- a/example/lib/built_value_resource.chopper.dart +++ b/example/lib/built_value_resource.chopper.dart @@ -7,7 +7,7 @@ part of 'built_value_resource.dart'; // ************************************************************************** // ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps -class _$MyService extends MyService { +final class _$MyService extends MyService { _$MyService([ChopperClient? client]) { if (client == null) return; this.client = client; diff --git a/example/lib/json_serializable.chopper.dart b/example/lib/json_serializable.chopper.dart index 7a60b5ab..1aa9352e 100644 --- a/example/lib/json_serializable.chopper.dart +++ b/example/lib/json_serializable.chopper.dart @@ -7,7 +7,7 @@ part of 'json_serializable.dart'; // ************************************************************************** // ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps -class _$MyService extends MyService { +final class _$MyService extends MyService { _$MyService([ChopperClient? client]) { if (client == null) return; this.client = client; diff --git a/mono_repo.yaml b/mono_repo.yaml index 28e29828..1cdb37ac 100644 --- a/mono_repo.yaml +++ b/mono_repo.yaml @@ -12,7 +12,7 @@ github: - develop merge_stages: - - analyzer_and_format + - analyze_and_format - unit_test coverage_service: diff --git a/tool/ci.sh b/tool/ci.sh index 7449806d..9c1ac4c1 100755 --- a/tool/ci.sh +++ b/tool/ci.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Created with package:mono_repo v6.5.5 +# Created with package:mono_repo v6.5.7 # Support built in commands on windows out of the box. # When it is a flutter repo (check the pubspec.yaml for "sdk: flutter")