From 7f76ceee8d8ee4a0b2b11731ad5e989284637720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 14:59:51 +0100 Subject: [PATCH 01/13] :art: Migrate chopper/chopper away from pedantic to lints --- chopper/analysis_options.yaml | 33 +++++++++++- chopper/example/definition.dart | 1 + chopper/example/main.dart | 3 +- chopper/lib/chopper.dart | 2 +- chopper/lib/src/annotations.dart | 4 +- chopper/lib/src/authenticator.dart | 7 ++- chopper/lib/src/base.dart | 71 +++++++++++-------------- chopper/lib/src/interceptor.dart | 20 ++++--- chopper/lib/src/request.dart | 67 ++++++++++-------------- chopper/lib/src/utils.dart | 22 ++++---- chopper/pubspec.yaml | 5 +- chopper/test/base_test.dart | 40 +++++++------- chopper/test/client_test.dart | 5 +- chopper/test/converter_test.dart | 17 +++--- chopper/test/form_test.dart | 11 ++-- chopper/test/interceptors_test.dart | 22 +++++--- chopper/test/json_test.dart | 9 ++-- chopper/test/multipart_test.dart | 81 +++++++++++++++++------------ chopper/test/test_service.dart | 7 ++- 19 files changed, 249 insertions(+), 178 deletions(-) diff --git a/chopper/analysis_options.yaml b/chopper/analysis_options.yaml index d4fcc1ad..b080627c 100644 --- a/chopper/analysis_options.yaml +++ b/chopper/analysis_options.yaml @@ -1 +1,32 @@ -include: package:pedantic/analysis_options.yaml \ No newline at end of file +analyzer: + exclude: + - "**.g.dart" + - "**.chopper.dart" + - "**.mocks.dart" + - "example/**" + plugins: + - dart_code_metrics + +dart_code_metrics: + metrics: + cyclomatic-complexity: 20 + number-of-arguments: 4 + maximum-nesting-level: 5 + number-of-parameters: 7 + metrics-exclude: + - test/** + rules: + - newline-before-return + - no-boolean-literal-compare + - no-empty-block + - prefer-trailing-comma + - prefer-conditional-expressions + - no-equal-then-else + anti-patterns: + - long-method + - long-parameter-list + +linter: + rules: + avoid_print: true + prefer_single_quotes: true diff --git a/chopper/example/definition.dart b/chopper/example/definition.dart index 5103ca4d..ef8fcf9d 100644 --- a/chopper/example/definition.dart +++ b/chopper/example/definition.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:chopper/chopper.dart'; part 'definition.chopper.dart'; diff --git a/chopper/example/main.dart b/chopper/example/main.dart index d1831859..16f66abc 100644 --- a/chopper/example/main.dart +++ b/chopper/example/main.dart @@ -1,4 +1,5 @@ import 'package:chopper/chopper.dart'; + import 'definition.dart'; Future main() async { @@ -6,7 +7,7 @@ Future main() async { baseUrl: 'http://localhost:8000', services: [ // the generated service - MyService.create(ChopperClient()) + MyService.create(ChopperClient()), ], converter: JsonConverter(), ); diff --git a/chopper/lib/chopper.dart b/chopper/lib/chopper.dart index 9d1d9826..c004d675 100644 --- a/chopper/lib/chopper.dart +++ b/chopper/lib/chopper.dart @@ -6,8 +6,8 @@ library chopper; export 'src/annotations.dart'; export 'src/authenticator.dart'; export 'src/base.dart'; +export 'src/constants.dart'; export 'src/interceptor.dart'; export 'src/request.dart'; export 'src/response.dart'; export 'src/utils.dart' hide mapToQuery; -export 'src/constants.dart'; diff --git a/chopper/lib/src/annotations.dart b/chopper/lib/src/annotations.dart index 1bd3389d..8ebeda08 100644 --- a/chopper/lib/src/annotations.dart +++ b/chopper/lib/src/annotations.dart @@ -1,8 +1,10 @@ import 'dart:async'; + import 'package:meta/meta.dart'; + +import 'constants.dart'; import 'request.dart'; import 'response.dart'; -import 'constants.dart'; /// Defines a Chopper API. /// diff --git a/chopper/lib/src/authenticator.dart b/chopper/lib/src/authenticator.dart index db225a49..d69e6d76 100644 --- a/chopper/lib/src/authenticator.dart +++ b/chopper/lib/src/authenticator.dart @@ -5,6 +5,9 @@ import 'package:chopper/chopper.dart'; /// This method should return a [Request] that includes credentials to satisfy an authentication challenge received in /// [response]. It should return `null` if the challenge cannot be satisfied. abstract class Authenticator { - FutureOr authenticate(Request request, Response response, - [Request? originalRequest]); + FutureOr authenticate( + Request request, + Response response, [ + Request? originalRequest, + ]); } diff --git a/chopper/lib/src/base.dart b/chopper/lib/src/base.dart index b0f90848..fbf134ea 100644 --- a/chopper/lib/src/base.dart +++ b/chopper/lib/src/base.dart @@ -1,13 +1,14 @@ import 'dart:async'; -import 'package:meta/meta.dart'; + import 'package:http/http.dart' as http; -import 'constants.dart'; +import 'package:meta/meta.dart'; +import 'annotations.dart'; +import 'authenticator.dart'; +import 'constants.dart'; import 'interceptor.dart'; import 'request.dart'; import 'response.dart'; -import 'annotations.dart'; -import 'authenticator.dart'; import 'utils.dart'; Type _typeOf() => T; @@ -120,7 +121,7 @@ class ChopperClient { Iterable services = const [], }) : httpClient = client ?? http.Client(), _clientIsInternal = client == null { - if (interceptors.every(_isAnInterceptor) == false) { + if (!interceptors.every(_isAnInterceptor)) { throw ArgumentError( 'Unsupported type for interceptors, it only support the following types:\n' '${allowedInterceptorsType.join('\n - ')}', @@ -165,28 +166,25 @@ class ChopperClient { final serviceType = _typeOf(); if (serviceType == dynamic || serviceType == ChopperService) { throw Exception( - 'Service type should be provided, `dynamic` is not allowed.'); + 'Service type should be provided, `dynamic` is not allowed.', + ); } final service = _services[serviceType]; if (service == null) { throw Exception('Service of type \'$serviceType\' not found.'); } + return service as ServiceType; } - Future _encodeRequest(Request request) async { - return converter?.convertRequest(request) ?? request; - } + Future _encodeRequest(Request request) async => + converter?.convertRequest(request) ?? request; Future> _decodeResponse( Response response, Converter withConverter, - ) async { - final converted = - await withConverter.convertResponse(response); - - return converted; - } + ) async => + await withConverter.convertResponse(response); Future _interceptRequest(Request req) async { final body = req.body; @@ -203,6 +201,7 @@ class ChopperClient { 'Interceptors should not transform the body of the request' 'Use Request converter instead', ); + return req; } @@ -242,11 +241,7 @@ class ChopperClient { error = errorRes?.error ?? errorRes?.body; } - return Response( - response.base, - null, - error: error, - ); + return Response(response.base, null, error: error); } Future> _handleSuccessResponse( @@ -269,17 +264,12 @@ class ChopperClient { Future _handleRequestConverter( Request request, ConvertRequest? requestConverter, - ) async { - if (request.body != null || request.parts.isNotEmpty) { - if (requestConverter != null) { - request = await requestConverter(request); - } else { - request = (await _encodeRequest(request)); - } - } - - return request; - } + ) async => + request.body != null || request.parts.isNotEmpty + ? requestConverter != null + ? await requestConverter(request) + : await _encodeRequest(request) + : request; /// Sends a pre-build [Request], applying all provided [Interceptor]s and /// [Converter]s. @@ -324,27 +314,28 @@ class ChopperClient { return _processResponse(res); } else { res = await _handleErrorResponse(res); + return _processResponse(res); } } } - if (_responseIsSuccessful(res.statusCode)) { - res = await _handleSuccessResponse( - res, - responseConverter, - ); - } else { - res = await _handleErrorResponse(res); - } + res = _responseIsSuccessful(res.statusCode) + ? await _handleSuccessResponse( + res, + responseConverter, + ) + : await _handleErrorResponse(res); return _processResponse(res); } Future> _processResponse( - dynamic res) async { + dynamic res, + ) async { res = await _interceptResponse(res); _responseController.add(res); + return res; } diff --git a/chopper/lib/src/interceptor.dart b/chopper/lib/src/interceptor.dart index 5c89cbc3..2a5a9906 100644 --- a/chopper/lib/src/interceptor.dart +++ b/chopper/lib/src/interceptor.dart @@ -1,12 +1,13 @@ import 'dart:async'; import 'dart:convert'; -import 'package:meta/meta.dart'; + import 'package:http/http.dart' as http; +import 'package:meta/meta.dart'; +import 'constants.dart'; import 'request.dart'; import 'response.dart'; import 'utils.dart'; -import 'constants.dart'; /// An interface for implementing response interceptors. /// @@ -140,7 +141,7 @@ class CurlInterceptor implements RequestInterceptor { final method = baseRequest.method; final url = baseRequest.url.toString(); final headers = baseRequest.headers; - var curl = ''; + String curl = ''; curl += 'curl'; curl += ' -v'; curl += ' -X $method'; @@ -156,6 +157,7 @@ class CurlInterceptor implements RequestInterceptor { } curl += ' \"$url\"'; chopperLogger.info(curl); + return request; } } @@ -176,7 +178,7 @@ class HttpLoggingInterceptor chopperLogger.info('--> ${base.method} ${base.url}'); base.headers.forEach((k, v) => chopperLogger.info('$k: $v')); - var bytes = ''; + String bytes = ''; if (base is http.Request) { final body = base.body; if (body.isNotEmpty) { @@ -186,6 +188,7 @@ class HttpLoggingInterceptor } chopperLogger.info('--> END ${base.method}$bytes'); + return request; } @@ -196,7 +199,7 @@ class HttpLoggingInterceptor response.base.headers.forEach((k, v) => chopperLogger.info('$k: $v')); - var bytes; + String bytes = ''; if (response.base is http.Response) { final resp = response.base as http.Response; if (resp.body.isNotEmpty) { @@ -206,6 +209,7 @@ class HttpLoggingInterceptor } chopperLogger.info('--> END ${base.method}$bytes'); + return response; } } @@ -240,10 +244,11 @@ class JsonConverter implements Converter, ErrorConverter { } Request encodeJson(Request request) { - var contentType = request.headers[contentTypeKey]; + String? contentType = request.headers[contentTypeKey]; if (contentType != null && contentType.contains(jsonHeaders)) { return request.copyWith(body: json.encode(request.body)); } + return request; } @@ -284,6 +289,7 @@ class JsonConverter implements Converter, ErrorConverter { return json.decode(data); } catch (e) { chopperLogger.warning(e); + return data; } } @@ -314,7 +320,7 @@ class FormUrlEncodedConverter implements Converter, ErrorConverter { @override Request convertRequest(Request request) { - var req = applyHeader( + Request req = applyHeader( request, contentTypeKey, formEncodedHeaders, diff --git a/chopper/lib/src/request.dart b/chopper/lib/src/request.dart index 88a7ed05..144332a1 100644 --- a/chopper/lib/src/request.dart +++ b/chopper/lib/src/request.dart @@ -1,10 +1,11 @@ import 'dart:async'; import 'dart:convert'; -import 'package:meta/meta.dart'; import 'package:http/http.dart' as http; -import 'utils.dart'; +import 'package:meta/meta.dart'; + import 'constants.dart'; +import 'utils.dart'; /// This class represents an HTTP request that can be made with Chopper. @immutable @@ -54,7 +55,7 @@ class Request { Uri _buildUri() => buildUri(baseUrl, url, parameters); - Map _buildHeaders() => Map.from(headers); + Map _buildHeaders() => {...headers}; /// Converts this Chopper Request into a [http.BaseRequest]. /// @@ -65,32 +66,18 @@ class Request { /// - [http.MultipartRequest] if [multipart] is true /// - or a [http.Request] Future toBaseRequest() async { - final uri = _buildUri(); - final heads = _buildHeaders(); + final Uri uri = _buildUri(); + final Map heads = _buildHeaders(); if (body is Stream>) { - return toStreamedRequest( - body, - method, - uri, - heads, - ); + return toStreamedRequest(body, method, uri, heads); } if (multipart) { - return toMultipartRequest( - parts, - method, - uri, - heads, - ); + return toMultipartRequest(parts, method, uri, heads); } - return toHttpRequest( - body, - method, - uri, - heads, - ); + + return toHttpRequest(body, method, uri, heads); } } @@ -124,26 +111,23 @@ class PartValueFile extends PartValue { /// /// If [url] starts with 'http://' or 'https://', baseUrl is ignored. Uri buildUri(String baseUrl, String url, Map parameters) { - var uri; - if (url.startsWith('http://') || url.startsWith('https://')) { - // If the request's url is already a fully qualified URL, we can use it - // as-is and ignore the baseUrl. - uri = Uri.parse(url); - } else { - if (!baseUrl.endsWith('/') && !url.startsWith('/')) { - uri = Uri.parse('$baseUrl/$url'); - } else { - uri = Uri.parse('$baseUrl$url'); - } - } - - var query = mapToQuery(parameters); + // If the request's url is already a fully qualified URL, we can use it + // as-is and ignore the baseUrl. + Uri uri = url.startsWith('http://') || url.startsWith('https://') + ? Uri.parse(url) + : !baseUrl.endsWith('/') && !url.startsWith('/') + ? Uri.parse('$baseUrl/$url') + : Uri.parse('$baseUrl$url'); + + String query = mapToQuery(parameters); if (query.isNotEmpty) { if (uri.hasQuery) { query += '&${uri.query}'; } + return uri.replace(query: query); } + return uri; } @@ -168,6 +152,7 @@ Future toHttpRequest( throw ArgumentError.value('$body', 'body'); } } + return baseRequest; } @@ -210,6 +195,7 @@ Future toMultipartRequest( baseRequest.fields[part.name] = part.value.toString(); } } + return baseRequest; } @@ -223,8 +209,11 @@ Future toStreamedRequest( final req = http.StreamedRequest(method, uri); req.headers.addAll(headers); - bodyStream.listen(req.sink.add, - onDone: req.sink.close, onError: req.sink.addError); + bodyStream.listen( + req.sink.add, + onDone: req.sink.close, + onError: req.sink.addError, + ); return req; } diff --git a/chopper/lib/src/utils.dart b/chopper/lib/src/utils.dart index 21b0605f..ea1bdc6b 100644 --- a/chopper/lib/src/utils.dart +++ b/chopper/lib/src/utils.dart @@ -39,16 +39,16 @@ Request applyHeaders( Map headers, { bool override = true, }) { - final h = Map.from(request.headers); + final Map headersCopy = {...request.headers}; - for (var k in headers.keys) { - var val = headers[k]; - if (val == null) continue; - if (!override && h.containsKey(k)) continue; - h[k] = val; + for (String key in headers.keys) { + String? value = headers[key]; + if (value == null) continue; + if (!override && headersCopy.containsKey(key)) continue; + headersCopy[key] = value; } - return request.copyWith(headers: h); + return request.copyWith(headers: headersCopy); } final chopperLogger = Logger('Chopper'); @@ -62,12 +62,11 @@ Iterable<_Pair> _mapToQuery( Map map, { String? prefix, }) { - /// ignore: prefer_collection_literals - final pairs = Set<_Pair>(); + final Set<_Pair> pairs = {}; map.forEach((key, value) { if (value != null) { - var name = Uri.encodeQueryComponent(key); + String name = Uri.encodeQueryComponent(key); if (prefix != null) { name = '$prefix.$name'; @@ -77,11 +76,12 @@ Iterable<_Pair> _mapToQuery( pairs.addAll(_iterableToQuery(name, value)); } else if (value is Map) { pairs.addAll(_mapToQuery(value, prefix: name)); - } else if (value.toString().isNotEmpty == true) { + } else if (value.toString().isNotEmpty) { pairs.add(_Pair(name, _normalizeValue(value))); } } }); + return pairs; } diff --git a/chopper/pubspec.yaml b/chopper/pubspec.yaml index d2e41a97..5c811f5e 100644 --- a/chopper/pubspec.yaml +++ b/chopper/pubspec.yaml @@ -5,7 +5,7 @@ documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.14.0 <3.0.0" dependencies: http: ">=0.13.0 <1.0.0" @@ -18,6 +18,7 @@ dev_dependencies: build_test: ^2.0.0 coverage: ^1.0.2 http_parser: ^4.0.0 - pedantic: ^1.11.0 + dart_code_metrics: ^4.8.1 + lints: ^2.0.0 chopper_generator: path: ../chopper_generator diff --git a/chopper/test/base_test.dart b/chopper/test/base_test.dart index 24487c36..829ea2ef 100644 --- a/chopper/test/base_test.dart +++ b/chopper/test/base_test.dart @@ -2,16 +2,19 @@ import 'dart:async'; import 'dart:convert'; import 'package:chopper/chopper.dart'; -import 'package:test/test.dart'; -import 'package:http/testing.dart'; import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:test/test.dart'; + import 'test_service.dart'; const baseUrl = 'http://localhost:8000'; void main() { - final buildClient = ( - [http.Client? httpClient, ErrorConverter? errorConverter]) => + final buildClient = ([ + http.Client? httpClient, + ErrorConverter? errorConverter, + ]) => ChopperClient( baseUrl: baseUrl, services: [ @@ -39,8 +42,10 @@ void main() { try { chopper.getService(); } on Exception catch (e) { - expect(e.toString(), - 'Exception: Service type should be provided, `dynamic` is not allowed.'); + expect( + e.toString(), + 'Exception: Service type should be provided, `dynamic` is not allowed.', + ); } }); test('GET', () async { @@ -332,6 +337,7 @@ void main() { final client = MockClient((http.Request req) async { expect(req.headers.containsKey('foo'), isTrue); expect(req.headers['foo'], equals('bar')); + return http.Response('', 200); }); @@ -351,6 +357,7 @@ void main() { final client = MockClient((http.Request req) async { expect(req.headers.containsKey('test'), isTrue); expect(req.headers['test'], equals('42')); + return http.Response('', 200); }); @@ -375,6 +382,7 @@ void main() { req.url.toString(), equals('$baseUrl/test/get/1234'), ); + return http.Response('', 200); }); @@ -392,13 +400,10 @@ void main() { test('applyHeader', () { final req1 = applyHeader( - Request( - 'GET', - '/', - baseUrl, - ), - 'foo', - 'bar'); + Request('GET', '/', baseUrl), + 'foo', + 'bar', + ); expect(req1.headers, equals({'foo': 'bar'})); @@ -565,7 +570,8 @@ void main() { expect( request.url.toString(), equals( - '$baseUrl/test/query_map?test=true&foo=bar&list=1&list=2&inner.test=42'), + '$baseUrl/test/query_map?test=true&foo=bar&list=1&list=2&inner.test=42', + ), ); expect(request.method, equals('GET')); @@ -864,6 +870,7 @@ void main() { test('timeout', () async { final httpClient = MockClient((http.Request req) async { await Future.delayed(const Duration(minutes: 1)); + return http.Response('ok', 200); }); @@ -872,10 +879,7 @@ void main() { try { await service - .getTest( - '1234', - dynamicHeader: '', - ) + .getTest('1234', dynamicHeader: '') .timeout(const Duration(seconds: 3)); } catch (e) { expect(e is TimeoutException, isTrue); diff --git a/chopper/test/client_test.dart b/chopper/test/client_test.dart index 81c6d0c8..c1fad673 100644 --- a/chopper/test/client_test.dart +++ b/chopper/test/client_test.dart @@ -1,9 +1,9 @@ import 'dart:convert'; import 'package:chopper/chopper.dart'; -import 'package:test/test.dart'; -import 'package:http/testing.dart'; import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:test/test.dart'; const baseUrl = 'http://localhost:8000'; @@ -16,6 +16,7 @@ void main() { ], converter: JsonConverter(), ); + group('Client methods', () { test('GET', () async { final httpClient = MockClient((request) async { diff --git a/chopper/test/converter_test.dart b/chopper/test/converter_test.dart index 7bc98b58..6e7a5b75 100644 --- a/chopper/test/converter_test.dart +++ b/chopper/test/converter_test.dart @@ -1,9 +1,10 @@ import 'dart:convert' as dart_convert; import 'package:chopper/chopper.dart'; -import 'package:test/test.dart'; -import 'package:http/testing.dart'; import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:test/test.dart'; + import 'test_service.dart'; const baseUrl = 'http://localhost:8000'; @@ -111,16 +112,16 @@ class TestConverter implements Converter { Response convertResponse(Response res) { if (res.body is String) { return res.copyWith<_Converted>( - body: _Converted(res.body)) as Response; + body: _Converted(res.body), + ) as Response; } + return res as Response; } @override - Request convertRequest(Request req) { - if (req.body is _Converted) return req.copyWith(body: req.body.data); - return req; - } + Request convertRequest(Request req) => + req.body is _Converted ? req.copyWith(body: req.body.data) : req; } class TestErrorConverter implements ErrorConverter { @@ -128,8 +129,10 @@ class TestErrorConverter implements ErrorConverter { Response convertError(Response res) { if (res.body is String) { final error = dart_convert.jsonDecode(res.body); + return res.copyWith<_ConvertedError>(body: _ConvertedError(error)); } + return res; } } diff --git a/chopper/test/form_test.dart b/chopper/test/form_test.dart index 95045d0f..f28b17f7 100644 --- a/chopper/test/form_test.dart +++ b/chopper/test/form_test.dart @@ -1,8 +1,9 @@ -import 'package:test/test.dart'; import 'package:chopper/chopper.dart'; -import 'test_service.dart'; -import 'package:http/testing.dart'; import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:test/test.dart'; + +import 'test_service.dart'; void main() { group('Form', () { @@ -24,6 +25,7 @@ void main() { 'application/x-www-form-urlencoded; charset=utf-8', ); expect(req.body, 'foo=test&default=hello'); + return http.Response('ok', 200); }); @@ -46,6 +48,7 @@ void main() { 'application/x-www-form-urlencoded; charset=utf-8', ); expect(req.body, 'foo=test&factory=converter'); + return http.Response('ok', 200); }); @@ -68,6 +71,7 @@ void main() { 'application/x-www-form-urlencoded; charset=utf-8', ); expect(req.body, 'foo=test&factory=converter'); + return http.Response('ok', 200); }); @@ -91,6 +95,7 @@ void main() { 'application/x-www-form-urlencoded; charset=utf-8', ); expect(req.body, 'foo=test&bar=42'); + return http.Response('ok', 200); }); diff --git a/chopper/test/interceptors_test.dart b/chopper/test/interceptors_test.dart index a325faeb..d57dd8ab 100644 --- a/chopper/test/interceptors_test.dart +++ b/chopper/test/interceptors_test.dart @@ -1,9 +1,10 @@ import 'dart:async'; -import 'package:http/testing.dart'; +import 'package:chopper/chopper.dart'; import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; import 'package:test/test.dart'; -import 'package:chopper/chopper.dart'; + import 'test_service.dart'; void main() { @@ -14,6 +15,7 @@ void main() { request.url.toString(), equals('/test/get/1234/intercept'), ); + return http.Response('', 200); }, ); @@ -84,6 +86,7 @@ void main() { interceptors: [ (Response response) { intercepted = _Intercepted(response.body); + return response; }, ], @@ -108,6 +111,7 @@ void main() { interceptors: [ (Response response) { intercepted = _Intercepted(response.body); + return response; }, ], @@ -140,6 +144,7 @@ void main() { expect(isTypeOf(), isTrue); expect(isTypeOf>(), isTrue); intercepted = _Intercepted(response.body!); + return response; }, ], @@ -157,12 +162,13 @@ void main() { final client = MockClient((http.Request req) async { expect(req.headers.containsKey('foo'), isTrue); expect(req.headers['foo'], equals('bar')); + return http.Response('', 200); }); final chopper = ChopperClient( interceptors: [ - HeadersInterceptor({'foo': 'bar'}) + HeadersInterceptor({'foo': 'bar'}), ], services: [ HttpTestService.create(), @@ -223,9 +229,12 @@ void main() { final logger = HttpLoggingInterceptor(); final fakeResponse = Response( - http.Response('responseBodyBase', 200, - headers: {'foo': 'bar'}, - request: await fakeRequest.toBaseRequest()), + http.Response( + 'responseBodyBase', + 200, + headers: {'foo': 'bar'}, + request: await fakeRequest.toBaseRequest(), + ), 'responseBody', ); @@ -254,6 +263,7 @@ class ResponseIntercept implements ResponseInterceptor { @override FutureOr onResponse(Response response) { intercepted = _Intercepted(response.body); + return response; } } diff --git a/chopper/test/json_test.dart b/chopper/test/json_test.dart index c65053f0..3893f243 100644 --- a/chopper/test/json_test.dart +++ b/chopper/test/json_test.dart @@ -1,10 +1,11 @@ import 'dart:convert'; -import 'package:test/test.dart'; import 'package:chopper/chopper.dart'; -import 'test_service.dart'; -import 'package:http/testing.dart'; import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:test/test.dart'; + +import 'test_service.dart'; void main() { final sample = { @@ -30,6 +31,7 @@ void main() { expect(req.url.toString(), equals('/test/map')); expect(req.headers['content-type'], 'application/json; charset=utf-8'); expect(req.body, equals(json.encode(sample))); + return http.Response( json.encode(res), 200, @@ -56,6 +58,7 @@ void main() { expect(req.headers['content-type'], 'application/json; charset=utf-8'); expect(req.headers['customConverter'], 'true'); expect(req.body, equals(json.encode(sample))); + return http.Response( json.encode(res), 200, diff --git a/chopper/test/multipart_test.dart b/chopper/test/multipart_test.dart index ca42cd95..030c215d 100644 --- a/chopper/test/multipart_test.dart +++ b/chopper/test/multipart_test.dart @@ -1,8 +1,9 @@ import 'package:chopper/chopper.dart'; +import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; import 'package:http_parser/http_parser.dart'; import 'package:test/test.dart'; -import 'package:http/testing.dart'; -import 'package:http/http.dart' as http; + import 'test_service.dart'; void main() { @@ -26,6 +27,7 @@ void main() { '{bar: foo}\r\n', ), ); + return http.Response('ok', 200); }); @@ -46,14 +48,14 @@ void main() { contains('content-type: application/octet-stream'), ); expect( - req.body, - contains( - 'content-disposition: form-data; name="file"', - )); + req.body, + contains('content-disposition: form-data; name="file"'), + ); expect( req.body, contains('${String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}'), ); + return http.Response('ok', 200); }); @@ -79,14 +81,16 @@ void main() { isNot(contains('content-disposition: form-data; name="id"')), ); expect( - req.body, - contains( - 'content-disposition: form-data; name="file_field"; filename="file_name"', - )); + req.body, + contains( + 'content-disposition: form-data; name="file_field"; filename="file_name"', + ), + ); expect( req.body, contains('${String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}'), ); + return http.Response('ok', 200); }); @@ -109,22 +113,28 @@ void main() { final httpClient = MockClient((http.Request req) async { expect(req.headers['Content-Type'], contains('multipart/form-data;')); - expect(req.body, - contains('content-disposition: form-data; name="id"\r\n\r\n42\r\n')); + expect( + req.body, + contains( + 'content-disposition: form-data; name="id"\r\n\r\n42\r\n', + ), + ); expect( req.body, contains('content-type: application/octet-stream'), ); expect( - req.body, - contains( - 'content-disposition: form-data; name="file_field"; filename="file_name"', - )); + req.body, + contains( + 'content-disposition: form-data; name="file_field"; filename="file_name"', + ), + ); expect( req.body, contains('${String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}'), ); + return http.Response('ok', 200); }); @@ -166,6 +176,7 @@ void main() { 'World', ), ); + return http.Response('ok', 200); }); @@ -206,23 +217,29 @@ void main() { expect(req.fields['int'], equals('42')); }); - test('PartFile', () async { - final req = await toMultipartRequest( - [ - PartValueFile('foo', 'test/multipart_test.dart'), - PartValueFile>('int', [1, 2]), - ], - HttpMethod.Post, - Uri.parse('/foo'), - {}, - ); + test( + 'PartFile', + () async { + final req = await toMultipartRequest( + [ + PartValueFile('foo', 'test/multipart_test.dart'), + PartValueFile>('int', [1, 2]), + ], + HttpMethod.Post, + Uri.parse('/foo'), + {}, + ); - expect(req.files.firstWhere((f) => f.field == 'foo').filename, - equals('multipart_test.dart')); - final bytes = - await req.files.firstWhere((f) => f.field == 'int').finalize().first; - expect(bytes, equals([1, 2])); - }, testOn: 'vm'); + expect( + req.files.firstWhere((f) => f.field == 'foo').filename, + equals('multipart_test.dart'), + ); + final bytes = + await req.files.firstWhere((f) => f.field == 'int').finalize().first; + expect(bytes, equals([1, 2])); + }, + testOn: 'vm', + ); test('PartValue.replace', () { dynamic part = PartValue('foo', 'bar'); diff --git a/chopper/test/test_service.dart b/chopper/test/test_service.dart index fa137441..03abc239 100644 --- a/chopper/test/test_service.dart +++ b/chopper/test/test_service.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:convert'; -import 'package:chopper/chopper.dart'; +import 'package:chopper/chopper.dart'; import 'package:http/http.dart' show MultipartFile; part 'test_service.chopper.dart'; @@ -101,7 +101,9 @@ abstract class HttpTestService extends ChopperService { @Post(path: 'map/json') @FactoryConverter( - request: customConvertRequest, response: customConvertResponse) + request: customConvertRequest, + response: customConvertResponse, + ) Future forceJsonTest(@Body() Map map); @Post(path: 'multi') @@ -140,6 +142,7 @@ abstract class HttpTestService extends ChopperService { Request customConvertRequest(Request req) { final r = JsonConverter().convertRequest(req); + return applyHeader(r, 'customConverter', 'true'); } From 98b693d5ecfde628e75f417355aab9d4acfc4a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 15:32:42 +0100 Subject: [PATCH 02/13] :art: Migrate chopper/chopper_generator away from pedantic to lints --- chopper/pubspec.yaml | 2 +- chopper_generator/analysis_options.yaml | 34 +- chopper_generator/lib/chopper_generator.dart | 1 + chopper_generator/lib/src/generator.dart | 310 ++++++++++--------- chopper_generator/pubspec.yaml | 7 +- 5 files changed, 199 insertions(+), 155 deletions(-) diff --git a/chopper/pubspec.yaml b/chopper/pubspec.yaml index 5c811f5e..cff2ec03 100644 --- a/chopper/pubspec.yaml +++ b/chopper/pubspec.yaml @@ -5,7 +5,7 @@ documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper environment: - sdk: ">=2.14.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" dependencies: http: ">=0.13.0 <1.0.0" diff --git a/chopper_generator/analysis_options.yaml b/chopper_generator/analysis_options.yaml index d4fcc1ad..a0a63b5e 100644 --- a/chopper_generator/analysis_options.yaml +++ b/chopper_generator/analysis_options.yaml @@ -1 +1,33 @@ -include: package:pedantic/analysis_options.yaml \ No newline at end of file +analyzer: + exclude: + - "**.g.dart" + - "**.chopper.dart" + - "**.mocks.dart" + - "example/**" + plugins: + - dart_code_metrics + +dart_code_metrics: + metrics: + cyclomatic-complexity: 20 + number-of-arguments: 4 + maximum-nesting-level: 5 + number-of-parameters: 5 + source-lines-of-code: 200 + metrics-exclude: + - test/** + rules: + - newline-before-return + - no-boolean-literal-compare + - no-empty-block + - prefer-trailing-comma + - prefer-conditional-expressions + - no-equal-then-else + anti-patterns: + - long-method + - long-parameter-list + +linter: + rules: + avoid_print: true + prefer_single_quotes: true diff --git a/chopper_generator/lib/chopper_generator.dart b/chopper_generator/lib/chopper_generator.dart index 2facc8b0..74355389 100644 --- a/chopper_generator/lib/chopper_generator.dart +++ b/chopper_generator/lib/chopper_generator.dart @@ -1,6 +1,7 @@ library chopper_generator.dart; import 'package:build/build.dart'; + import 'src/generator.dart'; Builder chopperGeneratorFactory(BuilderOptions options) => diff --git a/chopper_generator/lib/src/generator.dart b/chopper_generator/lib/src/generator.dart index ab95ee80..1bc238c6 100644 --- a/chopper_generator/lib/src/generator.dart +++ b/chopper_generator/lib/src/generator.dart @@ -1,21 +1,20 @@ ///@nodoc import 'dart:async'; +import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; - import 'package:build/build.dart'; import 'package:built_collection/built_collection.dart'; -import 'package:dart_style/dart_style.dart'; - -import 'package:source_gen/source_gen.dart'; +import 'package:chopper/chopper.dart' as chopper; // TODO(lejard_h) Code builder not null safe yet // ignore: import_of_legacy_library_into_null_safe import 'package:code_builder/code_builder.dart'; -import 'package:chopper/chopper.dart' as chopper; +import 'package:dart_style/dart_style.dart'; import 'package:logging/logging.dart'; +import 'package:source_gen/source_gen.dart'; const _clientVar = 'client'; const _baseUrlVar = 'baseUrl'; @@ -69,11 +68,11 @@ class ChopperGenerator extends GeneratorForAnnotation { ); } - final friendlyName = element.name; - final name = '_\$$friendlyName'; - final baseUrl = annotation.peek(_baseUrlVar)?.stringValue ?? ''; + final String friendlyName = element.name; + final String name = '_\$$friendlyName'; + final String baseUrl = annotation.peek(_baseUrlVar)?.stringValue ?? ''; - final classBuilder = Class((builder) { + final Class classBuilder = Class((builder) { builder ..name = name ..extend = refer(friendlyName) @@ -82,9 +81,10 @@ class ChopperGenerator extends GeneratorForAnnotation { ..methods.addAll(_parseMethods(element, baseUrl)); }); - final ignore = + final String ignore = '// ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps'; final emitter = DartEmitter(); + return DartFormatter().format('$ignore\n${classBuilder.accept(emitter)}'); } @@ -101,38 +101,48 @@ class ChopperGenerator extends GeneratorForAnnotation { ); }); - Iterable _parseMethods(ClassElement element, String baseUrl) { - return element.methods.where((MethodElement method) { - final methodAnnotation = _getMethodAnnotation(method); - return methodAnnotation != null && - method.isAbstract && - method.returnType.isDartAsyncFuture; - }).map((MethodElement m) => _generateMethod(m, baseUrl)); - } + Iterable _parseMethods(ClassElement element, String baseUrl) => + element.methods + .where( + (MethodElement method) => + _getMethodAnnotation(method) != null && + method.isAbstract && + method.returnType.isDartAsyncFuture, + ) + .map((MethodElement m) => _generateMethod(m, baseUrl)); Method _generateMethod(MethodElement m, String baseUrl) { - final method = _getMethodAnnotation(m); - final multipart = _hasAnnotation(m, chopper.Multipart); - final factoryConverter = _getFactoryConverterAnnotation(m); - - final body = _getAnnotation(m, chopper.Body); - final paths = _getAnnotations(m, chopper.Path); - final queries = _getAnnotations(m, chopper.Query); - final queryMap = _getAnnotation(m, chopper.QueryMap); - final fields = _getAnnotations(m, chopper.Field); - final fieldMap = _getAnnotation(m, chopper.FieldMap); - final parts = _getAnnotations(m, chopper.Part); - final partMap = _getAnnotation(m, chopper.PartMap); - final fileFields = _getAnnotations(m, chopper.PartFile); - final fileFieldMap = _getAnnotation(m, chopper.PartFileMap); - - final headers = _generateHeaders(m, method!); - final url = _generateUrl(method, paths, baseUrl); - final responseType = _getResponseType(m.returnType); - final responseInnerType = + final ConstantReader? method = _getMethodAnnotation(m); + final bool multipart = _hasAnnotation(m, chopper.Multipart); + final ConstantReader? factoryConverter = _getFactoryConverterAnnotation(m); + + final Map body = _getAnnotation(m, chopper.Body); + final Map paths = + _getAnnotations(m, chopper.Path); + final Map queries = + _getAnnotations(m, chopper.Query); + final Map queryMap = + _getAnnotation(m, chopper.QueryMap); + final Map fields = + _getAnnotations(m, chopper.Field); + final Map fieldMap = + _getAnnotation(m, chopper.FieldMap); + final Map parts = + _getAnnotations(m, chopper.Part); + final Map partMap = + _getAnnotation(m, chopper.PartMap); + final Map fileFields = + _getAnnotations(m, chopper.PartFile); + final Map fileFieldMap = + _getAnnotation(m, chopper.PartFileMap); + + final Code? headers = _generateHeaders(m, method!); + final Expression url = _generateUrl(method, paths, baseUrl); + final DartType? responseType = _getResponseType(m.returnType); + final DartType? responseInnerType = _getResponseInnerType(m.returnType) ?? responseType; - return Method((b) { + return Method((MethodBuilder b) { b.annotations.add(refer('override')); b.name = m.displayName; @@ -164,7 +174,7 @@ class ChopperGenerator extends GeneratorForAnnotation { m.parameters.where((p) => p.isNamed).map(buildNamedParam), ); - final blocks = [ + final List blocks = [ url.assignFinal(_urlVar).statement, ]; @@ -173,12 +183,12 @@ class ChopperGenerator extends GeneratorForAnnotation { } // Build an iterable of all the parameters that are nullable - final optionalNullableParameters = [ + final Iterable optionalNullableParameters = [ ...m.parameters.where((p) => p.isOptionalPositional), ...m.parameters.where((p) => p.isNamed), ].where((el) => el.type.isNullable).map((el) => el.name); - final hasQueryMap = queryMap.isNotEmpty; + final bool hasQueryMap = queryMap.isNotEmpty; if (hasQueryMap) { if (queries.isNotEmpty) { blocks.add(refer('$_parametersVar.addAll').call( @@ -204,16 +214,16 @@ class ChopperGenerator extends GeneratorForAnnotation { } } - final hasQuery = hasQueryMap || queries.isNotEmpty; + final bool hasQuery = hasQueryMap || queries.isNotEmpty; if (headers != null) { blocks.add(headers); } - final methodOptionalBody = getMethodOptionalBody(method); - final methodName = getMethodName(method); - final methodUrl = getMethodPath(method); - var hasBody = body.isNotEmpty || fields.isNotEmpty; + final bool methodOptionalBody = getMethodOptionalBody(method); + final String methodName = getMethodName(method); + final String methodUrl = getMethodPath(method); + bool hasBody = body.isNotEmpty || fields.isNotEmpty; if (hasBody) { if (body.isNotEmpty) { blocks.add( @@ -226,7 +236,7 @@ class ChopperGenerator extends GeneratorForAnnotation { } } - final hasFieldMap = fieldMap.isNotEmpty; + final bool hasFieldMap = fieldMap.isNotEmpty; if (hasFieldMap) { if (hasBody) { blocks.add(refer('$_bodyVar.addAll').call( @@ -241,14 +251,14 @@ class ChopperGenerator extends GeneratorForAnnotation { hasBody = hasBody || hasFieldMap; - var hasParts = - multipart == true && (parts.isNotEmpty || fileFields.isNotEmpty); + bool hasParts = multipart && (parts.isNotEmpty || fileFields.isNotEmpty); if (hasParts) { blocks.add( - _generateList(parts, fileFields).assignFinal(_partsVar).statement); + _generateList(parts, fileFields).assignFinal(_partsVar).statement, + ); } - final hasPartMap = multipart == true && partMap.isNotEmpty; + final bool hasPartMap = multipart && partMap.isNotEmpty; if (hasPartMap) { if (hasParts) { blocks.add(refer('$_partsVar.addAll').call( @@ -261,7 +271,7 @@ class ChopperGenerator extends GeneratorForAnnotation { } } - final hasFileFilesMap = multipart == true && fileFieldMap.isNotEmpty; + final bool hasFileFilesMap = multipart && fileFieldMap.isNotEmpty; if (hasFileFilesMap) { if (hasParts || hasPartMap) { blocks.add(refer('$_partsVar.addAll').call( @@ -295,26 +305,28 @@ class ChopperGenerator extends GeneratorForAnnotation { hasParts: hasParts, ).assignFinal(_requestVar).statement); - final namedArguments = {}; + final Map namedArguments = {}; - final requestFactory = factoryConverter?.peek('request'); + final ConstantReader? requestFactory = factoryConverter?.peek('request'); if (requestFactory != null) { final func = requestFactory.objectValue.toFunctionValue(); namedArguments['requestConverter'] = refer(_factoryForFunction(func!)); } - final responseFactory = factoryConverter?.peek('response'); + final ConstantReader? responseFactory = + factoryConverter?.peek('response'); if (responseFactory != null) { final func = responseFactory.objectValue.toFunctionValue(); namedArguments['responseConverter'] = refer(_factoryForFunction(func!)); } - final typeArguments = []; + final List typeArguments = []; if (responseType != null) { typeArguments .add(refer(responseType.getDisplayString(withNullability: false))); typeArguments.add( - refer(responseInnerType!.getDisplayString(withNullability: false))); + refer(responseInnerType!.getDisplayString(withNullability: false)), + ); } blocks.add(refer('$_clientVar.send') @@ -326,39 +338,46 @@ class ChopperGenerator extends GeneratorForAnnotation { }); } - String _factoryForFunction(FunctionTypedElement function) { - if (function.enclosingElement is ClassElement) { - return '${function.enclosingElement!.name}.${function.name}'; - } - return function.name!; - } + String _factoryForFunction(FunctionTypedElement function) => + function.enclosingElement is ClassElement + ? '${function.enclosingElement!.name}.${function.name}' + : function.name!; Map _getAnnotation(MethodElement method, Type type) { var annotation; - var name = ''; - for (final p in method.parameters) { - dynamic a = _typeChecker(type).firstAnnotationOf(p); + String name = ''; + + for (final ParameterElement p in method.parameters) { + DartObject? a = _typeChecker(type).firstAnnotationOf(p); if (annotation != null && a != null) { throw Exception( - 'Too many $type annotation for \'${method.displayName}\''); + 'Too many $type annotation for \'${method.displayName}\'', + ); } else if (annotation == null && a != null) { annotation = a; name = p.displayName; } } + if (annotation == null) return {}; - return {name: ConstantReader(annotation)}; + + return { + name: ConstantReader(annotation), + }; } Map _getAnnotations( - MethodElement m, Type type) { - var annotation = {}; - for (final p in m.parameters) { - final a = _typeChecker(type).firstAnnotationOf(p); + MethodElement m, + Type type, + ) { + Map annotation = {}; + for (final ParameterElement p in m.parameters) { + final DartObject? a = _typeChecker(type).firstAnnotationOf(p); if (a != null) { annotation[p] = ConstantReader(a); } } + return annotation; } @@ -370,24 +389,22 @@ class ChopperGenerator extends GeneratorForAnnotation { .firstAnnotationOf(method, throwOnUnresolved: false); if (annotation != null) return ConstantReader(annotation); } + return null; } ConstantReader? _getFactoryConverterAnnotation(MethodElement method) { - final annotation = _typeChecker(chopper.FactoryConverter) + final DartObject? annotation = _typeChecker(chopper.FactoryConverter) .firstAnnotationOf(method, throwOnUnresolved: false); - if (annotation != null) return ConstantReader(annotation); - return null; - } - - bool _hasAnnotation(MethodElement method, Type type) { - final annotation = - _typeChecker(type).firstAnnotationOf(method, throwOnUnresolved: false); - return annotation != null; + return annotation != null ? ConstantReader(annotation) : null; } - final _methodsAnnotations = const [ + bool _hasAnnotation(MethodElement method, Type type) => + _typeChecker(type).firstAnnotationOf(method, throwOnUnresolved: false) != + null; + + final List _methodsAnnotations = const [ chopper.Get, chopper.Post, chopper.Delete, @@ -398,18 +415,15 @@ class ChopperGenerator extends GeneratorForAnnotation { chopper.Options, ]; - DartType? _genericOf(DartType? type) { - return type is InterfaceType && type.typeArguments.isNotEmpty - ? type.typeArguments.first - : null; - } + DartType? _genericOf(DartType? type) => + type is InterfaceType && type.typeArguments.isNotEmpty + ? type.typeArguments.first + : null; - DartType? _getResponseType(DartType type) { - return _genericOf(_genericOf(type)); - } + DartType? _getResponseType(DartType type) => _genericOf(_genericOf(type)); DartType? _getResponseInnerType(DartType type) { - final generic = _genericOf(type); + final DartType? generic = _genericOf(type); if (generic == null || _typeChecker(Map).isExactlyType(type) || @@ -428,9 +442,9 @@ class ChopperGenerator extends GeneratorForAnnotation { Map paths, String baseUrl, ) { - var path = getMethodPath(method); + String path = getMethodPath(method); paths.forEach((p, ConstantReader r) { - final name = r.peek('name')?.stringValue ?? p.displayName; + final String name = r.peek('name')?.stringValue ?? p.displayName; path = path.replaceFirst('{$name}', '\${${p.displayName}}'); }); @@ -459,13 +473,13 @@ class ChopperGenerator extends GeneratorForAnnotation { bool useQueries = false, bool useHeaders = false, }) { - final params = [ + final List params = [ literal(getMethodName(method)), refer(_urlVar), refer('$_clientVar.$_baseUrlVar'), ]; - final namedParams = {}; + final Map namedParams = {}; if (hasBody) { namedParams['body'] = refer(_bodyVar); @@ -488,9 +502,9 @@ class ChopperGenerator extends GeneratorForAnnotation { } Expression _generateMap(Map queries) { - final map = {}; + final Map map = {}; queries.forEach((p, ConstantReader r) { - final name = r.peek('name')?.stringValue ?? p.displayName; + final String name = r.peek('name')?.stringValue ?? p.displayName; map[literal(name)] = refer(p.displayName); }); @@ -501,21 +515,21 @@ class ChopperGenerator extends GeneratorForAnnotation { Map parts, Map fileFields, ) { - final list = []; + final List list = []; parts.forEach((p, ConstantReader r) { - final name = r.peek('name')?.stringValue ?? p.displayName; - final params = [ + final String name = r.peek('name')?.stringValue ?? p.displayName; + final List params = [ literal(name), refer(p.displayName), ]; list.add(refer( - 'PartValue<${p.type.getDisplayString(withNullability: p.type.isNullable)}>') - .newInstance(params)); + 'PartValue<${p.type.getDisplayString(withNullability: p.type.isNullable)}>', + ).newInstance(params)); }); fileFields.forEach((p, ConstantReader r) { - final name = r.peek('name')?.stringValue ?? p.displayName; - final params = [ + final String name = r.peek('name')?.stringValue ?? p.displayName; + final List params = [ literal(name), refer(p.displayName), ]; @@ -525,18 +539,20 @@ class ChopperGenerator extends GeneratorForAnnotation { .newInstance(params), ); }); + return literalList(list, refer('PartValue')); } Code? _generateHeaders(MethodElement methodElement, ConstantReader method) { - final codeBuffer = StringBuffer('')..writeln('{'); + final StringBuffer codeBuffer = StringBuffer('')..writeln('{'); // Search for @Header anotation in method parameters - final annotations = _getAnnotations(methodElement, chopper.Header); + final Map annotations = + _getAnnotations(methodElement, chopper.Header); annotations.forEach((parameter, ConstantReader annotation) { - final paramName = parameter.displayName; - final name = annotation.peek('name')?.stringValue ?? paramName; + final String paramName = parameter.displayName; + final String name = annotation.peek('name')?.stringValue ?? paramName; if (parameter.type.isNullable) { codeBuffer.writeln('if ($paramName != null) \'$name\': $paramName,'); @@ -545,10 +561,11 @@ class ChopperGenerator extends GeneratorForAnnotation { } }); - final headersReader = method.peek('headers'); + final ConstantReader? headersReader = method.peek('headers'); if (headersReader == null) return null; - final methodAnnotations = headersReader.mapValue; + final Map methodAnnotations = + headersReader.mapValue; methodAnnotations.forEach((headerName, headerValue) { if (headerName != null && headerValue != null) { @@ -559,12 +576,9 @@ class ChopperGenerator extends GeneratorForAnnotation { }); codeBuffer.writeln('};'); - final code = codeBuffer.toString(); - if (code == '{\n};\n') { - return null; - } + final String code = codeBuffer.toString(); - return Code('final $_headersVar = $code'); + return code == '{\n};\n' ? null : Code('final $_headersVar = $code'); } } @@ -587,45 +601,41 @@ extension DartTypeExtension on DartType { } // All positional required params must support nullability -Parameter buildRequiredPositionalParam(ParameterElement p) { - return Parameter( - (pb) => pb - ..name = p.name - ..type = Reference( - p.type.getDisplayString(withNullability: p.type.isNullable), - ), - ); -} +Parameter buildRequiredPositionalParam(ParameterElement p) => Parameter( + (ParameterBuilder pb) => pb + ..name = p.name + ..type = Reference( + p.type.getDisplayString(withNullability: p.type.isNullable), + ), + ); // All optional positional params must support nullability -Parameter buildOptionalPositionalParam(ParameterElement p) { - return Parameter((pb) { - pb - ..name = p.name - ..type = Reference( - p.type.getDisplayString(withNullability: p.type.isNullable), - ); +Parameter buildOptionalPositionalParam(ParameterElement p) => + Parameter((ParameterBuilder pb) { + pb + ..name = p.name + ..type = Reference( + p.type.getDisplayString(withNullability: p.type.isNullable), + ); - if (p.defaultValueCode != null) { - pb.defaultTo = Code(p.defaultValueCode!); - } - }); -} + if (p.defaultValueCode != null) { + pb.defaultTo = Code(p.defaultValueCode!); + } + }); // Named params can be optional or required, they also need to support // nullability -Parameter buildNamedParam(ParameterElement p) { - return Parameter((pb) { - pb - ..named = true - ..name = p.name - ..required = p.isRequiredNamed - ..type = Reference( - p.type.getDisplayString(withNullability: p.type.isNullable), - ); +Parameter buildNamedParam(ParameterElement p) => + Parameter((ParameterBuilder pb) { + pb + ..named = true + ..name = p.name + ..required = p.isRequiredNamed + ..type = Reference( + p.type.getDisplayString(withNullability: p.type.isNullable), + ); - if (p.defaultValueCode != null) { - pb.defaultTo = Code(p.defaultValueCode!); - } - }); -} + if (p.defaultValueCode != null) { + pb.defaultTo = Code(p.defaultValueCode!); + } + }); diff --git a/chopper_generator/pubspec.yaml b/chopper_generator/pubspec.yaml index 74edf66b..37dcb58f 100644 --- a/chopper_generator/pubspec.yaml +++ b/chopper_generator/pubspec.yaml @@ -5,7 +5,7 @@ documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" dependencies: analyzer: ^4.1.0 @@ -19,8 +19,9 @@ dependencies: source_gen: ^1.0.0 dev_dependencies: - pedantic: ^1.11.0 - test: ^1.15.4 + test: ^1.16.4 + dart_code_metrics: ^4.8.1 + lints: ^2.0.0 dependency_overrides: # Comment before publish From 2fdef60a0c24326868b860edc14c8cc6e469df20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 15:38:49 +0100 Subject: [PATCH 03/13] :art: Migrate chopper/chopper_generator away from pedantic to lints --- chopper_generator/lib/src/generator.dart | 23 ++++++++++------------- chopper_generator/pubspec.yaml | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/chopper_generator/lib/src/generator.dart b/chopper_generator/lib/src/generator.dart index 1bc238c6..f9b69fca 100644 --- a/chopper_generator/lib/src/generator.dart +++ b/chopper_generator/lib/src/generator.dart @@ -8,24 +8,21 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:build/build.dart'; import 'package:built_collection/built_collection.dart'; import 'package:chopper/chopper.dart' as chopper; - -// TODO(lejard_h) Code builder not null safe yet -// ignore: import_of_legacy_library_into_null_safe import 'package:code_builder/code_builder.dart'; import 'package:dart_style/dart_style.dart'; import 'package:logging/logging.dart'; import 'package:source_gen/source_gen.dart'; -const _clientVar = 'client'; -const _baseUrlVar = 'baseUrl'; -const _parametersVar = '\$params'; -const _headersVar = '\$headers'; -const _requestVar = '\$request'; -const _bodyVar = '\$body'; -const _partsVar = '\$parts'; -const _urlVar = '\$url'; +const String _clientVar = 'client'; +const String _baseUrlVar = 'baseUrl'; +const String _parametersVar = r'$params'; +const String _headersVar = r'$headers'; +const String _requestVar = r'$request'; +const String _bodyVar = r'$body'; +const String _partsVar = r'$parts'; +const String _urlVar = r'$url'; -final _logger = Logger('Chopper Generator'); +final Logger _logger = Logger('Chopper Generator'); class ChopperGenerator extends GeneratorForAnnotation { @override @@ -503,7 +500,7 @@ class ChopperGenerator extends GeneratorForAnnotation { Expression _generateMap(Map queries) { final Map map = {}; - queries.forEach((p, ConstantReader r) { + queries.forEach((ParameterElement p, ConstantReader r) { final String name = r.peek('name')?.stringValue ?? p.displayName; map[literal(name)] = refer(p.displayName); }); diff --git a/chopper_generator/pubspec.yaml b/chopper_generator/pubspec.yaml index 37dcb58f..fd3bfdcb 100644 --- a/chopper_generator/pubspec.yaml +++ b/chopper_generator/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: analyzer: ^4.1.0 build: ^2.0.0 built_collection: ^5.0.0 - chopper: ^4.0.0 + chopper: ^4.1.0 code_builder: ^4.0.0 dart_style: ^2.0.0 logging: ^1.0.0 From 9cd788caa4b1b15d7f51c9e57c8db6a288dc8628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 15:47:00 +0100 Subject: [PATCH 04/13] :art: Migrate chopper/chopper_built_value away from pedantic to lints --- chopper_built_value/analysis_options.yaml | 33 ++++++++++++++++++- .../lib/chopper_built_value.dart | 25 +++++++------- chopper_built_value/pubspec.yaml | 5 +-- chopper_built_value/test/converter_test.dart | 2 +- chopper_built_value/test/serializers.dart | 1 + 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/chopper_built_value/analysis_options.yaml b/chopper_built_value/analysis_options.yaml index d4fcc1ad..b080627c 100644 --- a/chopper_built_value/analysis_options.yaml +++ b/chopper_built_value/analysis_options.yaml @@ -1 +1,32 @@ -include: package:pedantic/analysis_options.yaml \ No newline at end of file +analyzer: + exclude: + - "**.g.dart" + - "**.chopper.dart" + - "**.mocks.dart" + - "example/**" + plugins: + - dart_code_metrics + +dart_code_metrics: + metrics: + cyclomatic-complexity: 20 + number-of-arguments: 4 + maximum-nesting-level: 5 + number-of-parameters: 7 + metrics-exclude: + - test/** + rules: + - newline-before-return + - no-boolean-literal-compare + - no-empty-block + - prefer-trailing-comma + - prefer-conditional-expressions + - no-equal-then-else + anti-patterns: + - long-method + - long-parameter-list + +linter: + rules: + avoid_print: true + prefer_single_quotes: true diff --git a/chopper_built_value/lib/chopper_built_value.dart b/chopper_built_value/lib/chopper_built_value.dart index 0468d0a0..e8ae0a82 100644 --- a/chopper_built_value/lib/chopper_built_value.dart +++ b/chopper_built_value/lib/chopper_built_value.dart @@ -1,7 +1,6 @@ -import 'package:chopper/chopper.dart'; - import 'package:built_collection/built_collection.dart'; import 'package:built_value/serializer.dart'; +import 'package:chopper/chopper.dart'; /// A custom [Converter] and [ErrorConverter] that handles conversion for classes /// having a serializer implementation made with the built_value package. @@ -33,7 +32,9 @@ class BuiltValueConverter implements Converter, ErrorConverter { } BuiltList _deserializeListOf(Iterable value) { - final deserialized = value.map((value) => _deserialize(value)); + final Iterable deserialized = + value.map((value) => _deserialize(value)); + return BuiltList(deserialized.toList(growable: false)); } @@ -42,25 +43,27 @@ class BuiltValueConverter implements Converter, ErrorConverter { if (entity is Iterable) { return _deserializeListOf(entity) as BodyType; } + return _deserialize(entity); } @override - Request convertRequest(Request request) { - request = request.copyWith(body: serializers.serialize(request.body)); - return jsonConverter.convertRequest(request); - } + Request convertRequest(Request request) => jsonConverter.convertRequest( + request.copyWith(body: serializers.serialize(request.body)), + ); @override Response convertResponse(Response response) { - final jsonResponse = jsonConverter.convertResponse(response); - final body = deserialize(jsonResponse.body); - return jsonResponse.copyWith(body: body); + final Response jsonResponse = jsonConverter.convertResponse(response); + + return jsonResponse.copyWith( + body: deserialize(jsonResponse.body), + ); } @override Response convertError(Response response) { - final jsonResponse = jsonConverter.convertResponse(response); + final Response jsonResponse = jsonConverter.convertResponse(response); var body; diff --git a/chopper_built_value/pubspec.yaml b/chopper_built_value/pubspec.yaml index 88ccd7fc..b96ad512 100644 --- a/chopper_built_value/pubspec.yaml +++ b/chopper_built_value/pubspec.yaml @@ -5,7 +5,7 @@ documentation: https://hadrien-lejard.gitbook.io/chopper/converters/built-value- repository: https://github.com/lejard-h/chopper environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" dependencies: built_value: ^8.0.0 @@ -18,7 +18,8 @@ dev_dependencies: build_runner: ^2.0.0 build_test: ^2.0.0 built_value_generator: ^8.0.6 - pedantic: ^1.10.0 + dart_code_metrics: ^4.8.1 + lints: ^2.0.0 dependency_overrides: # Comment before publish diff --git a/chopper_built_value/test/converter_test.dart b/chopper_built_value/test/converter_test.dart index f16b4171..a431ec85 100644 --- a/chopper_built_value/test/converter_test.dart +++ b/chopper_built_value/test/converter_test.dart @@ -2,8 +2,8 @@ import 'package:built_collection/built_collection.dart'; import 'package:built_value/standard_json_plugin.dart'; import 'package:chopper/chopper.dart'; import 'package:chopper_built_value/chopper_built_value.dart'; -import 'package:test/test.dart'; import 'package:http/http.dart' as http; +import 'package:test/test.dart'; import 'data.dart'; import 'serializers.dart'; diff --git a/chopper_built_value/test/serializers.dart b/chopper_built_value/test/serializers.dart index 370f4b37..7124a7c1 100644 --- a/chopper_built_value/test/serializers.dart +++ b/chopper_built_value/test/serializers.dart @@ -1,6 +1,7 @@ library serializers; import 'package:built_value/serializer.dart'; + import 'data.dart'; part 'serializers.g.dart'; From 9d1235c6c13a817354cfd51b619735ca3143d9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 15:58:49 +0100 Subject: [PATCH 05/13] :art: Migrate chopper/example away from pedantic to lints --- example/analysis_options.yaml | 30 ++++++++ example/bin/main_built_value.dart | 30 ++++---- example/bin/main_json_serializable.dart | 17 +++-- example/lib/built_value_resource.dart | 21 +++-- example/lib/built_value_resource.g.dart | 46 ++++++----- example/lib/built_value_serializers.dart | 1 + example/lib/built_value_serializers.g.dart | 2 +- example/lib/json_serializable.dart | 19 +++-- example/pubspec.lock | 89 +++++++++++++++++----- example/pubspec.yaml | 4 +- 10 files changed, 179 insertions(+), 80 deletions(-) create mode 100644 example/analysis_options.yaml diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 00000000..e76e22c1 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,30 @@ +analyzer: + exclude: + - "**.g.dart" + - "**.chopper.dart" + - "**.mocks.dart" + plugins: + - dart_code_metrics + +dart_code_metrics: + metrics: + cyclomatic-complexity: 20 + number-of-arguments: 4 + maximum-nesting-level: 5 + metrics-exclude: + - test/** + rules: + - newline-before-return + - no-boolean-literal-compare + - no-empty-block + - prefer-trailing-comma + - prefer-conditional-expressions + - no-equal-then-else + anti-patterns: + - long-method + - long-parameter-list + +linter: + rules: + avoid_print: false + prefer_single_quotes: true diff --git a/example/bin/main_built_value.dart b/example/bin/main_built_value.dart index 8ebaff5b..9fc4450a 100644 --- a/example/bin/main_built_value.dart +++ b/example/bin/main_built_value.dart @@ -1,14 +1,14 @@ import 'package:built_collection/built_collection.dart'; import 'package:built_value/serializer.dart'; +import 'package:built_value/standard_json_plugin.dart'; import 'package:chopper/chopper.dart'; import 'package:chopper_example/built_value_resource.dart'; import 'package:chopper_example/built_value_serializers.dart'; -import 'package:built_value/standard_json_plugin.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; final jsonSerializers = - (serializers.toBuilder()..addPlugin(new StandardJsonPlugin())).build(); + (serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build(); /// Simple client to have working example without remote server final client = MockClient((req) async { @@ -16,13 +16,14 @@ final client = MockClient((req) async { return http.Response('{"type":"Fatal","message":"fatal erorr"}', 500); if (req.url.path == '/resources/list') return http.Response('[{"id":"1","name":"Foo"}]', 200); + return http.Response('{"id":"1","name":"Foo"}', 200); }); main() async { - final chopper = new ChopperClient( + final chopper = ChopperClient( client: client, - baseUrl: "http://localhost:8000", + baseUrl: 'http://localhost:8000', converter: BuiltValueConverter(), errorConverter: BuiltValueConverter(), services: [ @@ -33,7 +34,7 @@ main() async { final myService = chopper.getService(); - final response1 = await myService.getResource("1"); + final response1 = await myService.getResource('1'); print('response 1: ${response1.body}'); // undecoded String final response2 = await myService.getTypedResource(); @@ -44,8 +45,8 @@ main() async { try { final builder = ResourceBuilder() - ..id = "3" - ..name = "Super Name"; + ..id = '3' + ..name = 'Super Name'; await myService.newResource(builder.build()); } on Response catch (error) { print(error.body); @@ -58,10 +59,8 @@ class BuiltValueConverter extends JsonConverter { if (serializer == null) { throw Exception('No serializer for type ${T}'); } - return jsonSerializers.deserializeWith( - serializer, - value, - ); + + return jsonSerializers.deserializeWith(serializer, value); } BuiltList _deserializeListOf(Iterable value) => BuiltList( @@ -75,10 +74,12 @@ class BuiltValueConverter extends JsonConverter { if (entity is T) return entity; try { - if (entity is List) return _deserializeListOf(entity); - return _deserialize(entity); + return entity is List + ? _deserializeListOf(entity) + : _deserialize(entity); } catch (e) { print(e); + return null; } } @@ -86,8 +87,9 @@ class BuiltValueConverter extends JsonConverter { @override Response convertResponse(Response response) { // use [JsonConverter] to decode json - final jsonRes = super.convertResponse(response); + final Response jsonRes = super.convertResponse(response); final body = _decode(jsonRes.body); + return jsonRes.copyWith(body: body); } diff --git a/example/bin/main_json_serializable.dart b/example/bin/main_json_serializable.dart index 0d09e8f8..543ade3e 100644 --- a/example/bin/main_json_serializable.dart +++ b/example/bin/main_json_serializable.dart @@ -1,7 +1,7 @@ -import "dart:async"; +import 'dart:async'; + import 'package:chopper/chopper.dart'; import 'package:chopper_example/json_serializable.dart'; - import 'package:http/http.dart' as http; import 'package:http/testing.dart'; @@ -11,6 +11,7 @@ final client = MockClient((req) async { return http.Response('{"type":"Fatal","message":"fatal erorr"}', 500); if (req.method == 'GET' && req.headers['test'] == 'list') return http.Response('[{"id":"1","name":"Foo"}]', 200); + return http.Response('{"id":"1","name":"Foo"}', 200); }); @@ -21,7 +22,7 @@ main() async { final chopper = ChopperClient( client: client, - baseUrl: "http://localhost:8000", + baseUrl: 'http://localhost:8000', // bind your object factories here converter: converter, errorConverter: converter, @@ -35,7 +36,7 @@ main() async { final myService = chopper.getService(); - final response1 = await myService.getResource("1"); + final response1 = await myService.getResource('1'); print('response 1: ${response1.body}'); // undecoded String final response2 = await myService.getResources(); @@ -44,11 +45,11 @@ main() async { final response3 = await myService.getTypedResource(); print('response 3: ${response3.body}'); // decoded Resource - final response4 = await myService.getMapResource("1"); + final response4 = await myService.getMapResource('1'); print('response 4: ${response4.body}'); // undecoded Resource try { - await myService.newResource(Resource("3", "Super Name")); + await myService.newResource(Resource('3', 'Super Name')); } on Response catch (error) { print(error.body); } @@ -56,8 +57,8 @@ main() async { Future authHeader(Request request) async => applyHeader( request, - "Authorization", - "42", + 'Authorization', + '42', ); typedef JsonFactory = T Function(Map json); diff --git a/example/lib/built_value_resource.dart b/example/lib/built_value_resource.dart index 6ea4e35b..d31e4533 100644 --- a/example/lib/built_value_resource.dart +++ b/example/lib/built_value_resource.dart @@ -7,44 +7,51 @@ import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; import 'package:chopper/chopper.dart'; -part 'built_value_resource.g.dart'; part 'built_value_resource.chopper.dart'; +part 'built_value_resource.g.dart'; + abstract class Resource implements Built { String get id; + String get name; static Serializer get serializer => _$resourceSerializer; factory Resource([updates(ResourceBuilder b)]) = _$Resource; + Resource._(); } abstract class ResourceError implements Built { String get type; + String get message; static Serializer get serializer => _$resourceErrorSerializer; factory ResourceError([updates(ResourceErrorBuilder b)]) = _$ResourceError; + ResourceError._(); } -@ChopperApi(baseUrl: "/resources") +@ChopperApi(baseUrl: '/resources') abstract class MyService extends ChopperService { static MyService create([ChopperClient? client]) => _$MyService(client); - @Get(path: "/{id}/") + @Get(path: '/{id}/') Future getResource(@Path() String id); - @Get(path: "/list") + @Get(path: '/list') Future>> getBuiltListResources(); - @Get(path: "/", headers: const {"foo": "bar"}) + @Get(path: '/', headers: const {'foo': 'bar'}) Future> getTypedResource(); @Post() - Future> newResource(@Body() Resource resource, - {@Header() String? name}); + Future> newResource( + @Body() Resource resource, { + @Header() String? name, + }); } diff --git a/example/lib/built_value_resource.g.dart b/example/lib/built_value_resource.g.dart index 8030092d..bc969e05 100644 --- a/example/lib/built_value_resource.g.dart +++ b/example/lib/built_value_resource.g.dart @@ -36,17 +36,17 @@ class _$ResourceSerializer implements StructuredSerializer { final iterator = serialized.iterator; while (iterator.moveNext()) { - final key = iterator.current as String; + final key = iterator.current! as String; iterator.moveNext(); final Object? value = iterator.current; switch (key) { case 'id': result.id = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; + specifiedType: const FullType(String))! as String; break; case 'name': result.name = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; + specifiedType: const FullType(String))! as String; break; } } @@ -83,17 +83,17 @@ class _$ResourceErrorSerializer implements StructuredSerializer { final iterator = serialized.iterator; while (iterator.moveNext()) { - final key = iterator.current as String; + final key = iterator.current! as String; iterator.moveNext(); final Object? value = iterator.current; switch (key) { case 'type': result.type = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; + specifiedType: const FullType(String))! as String; break; case 'message': result.message = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; + specifiedType: const FullType(String))! as String; break; } } @@ -109,11 +109,11 @@ class _$Resource extends Resource { final String name; factory _$Resource([void Function(ResourceBuilder)? updates]) => - (new ResourceBuilder()..update(updates)).build(); + (new ResourceBuilder()..update(updates))._build(); _$Resource._({required this.id, required this.name}) : super._() { - BuiltValueNullFieldError.checkNotNull(id, 'Resource', 'id'); - BuiltValueNullFieldError.checkNotNull(name, 'Resource', 'name'); + BuiltValueNullFieldError.checkNotNull(id, r'Resource', 'id'); + BuiltValueNullFieldError.checkNotNull(name, r'Resource', 'name'); } @override @@ -136,7 +136,7 @@ class _$Resource extends Resource { @override String toString() { - return (newBuiltValueToStringHelper('Resource') + return (newBuiltValueToStringHelper(r'Resource') ..add('id', id) ..add('name', name)) .toString(); @@ -178,12 +178,14 @@ class ResourceBuilder implements Builder { } @override - _$Resource build() { + Resource build() => _build(); + + _$Resource _build() { final _$result = _$v ?? new _$Resource._( - id: BuiltValueNullFieldError.checkNotNull(id, 'Resource', 'id'), + id: BuiltValueNullFieldError.checkNotNull(id, r'Resource', 'id'), name: BuiltValueNullFieldError.checkNotNull( - name, 'Resource', 'name')); + name, r'Resource', 'name')); replace(_$result); return _$result; } @@ -196,11 +198,11 @@ class _$ResourceError extends ResourceError { final String message; factory _$ResourceError([void Function(ResourceErrorBuilder)? updates]) => - (new ResourceErrorBuilder()..update(updates)).build(); + (new ResourceErrorBuilder()..update(updates))._build(); _$ResourceError._({required this.type, required this.message}) : super._() { - BuiltValueNullFieldError.checkNotNull(type, 'ResourceError', 'type'); - BuiltValueNullFieldError.checkNotNull(message, 'ResourceError', 'message'); + BuiltValueNullFieldError.checkNotNull(type, r'ResourceError', 'type'); + BuiltValueNullFieldError.checkNotNull(message, r'ResourceError', 'message'); } @override @@ -225,7 +227,7 @@ class _$ResourceError extends ResourceError { @override String toString() { - return (newBuiltValueToStringHelper('ResourceError') + return (newBuiltValueToStringHelper(r'ResourceError') ..add('type', type) ..add('message', message)) .toString(); @@ -268,16 +270,18 @@ class ResourceErrorBuilder } @override - _$ResourceError build() { + ResourceError build() => _build(); + + _$ResourceError _build() { final _$result = _$v ?? new _$ResourceError._( type: BuiltValueNullFieldError.checkNotNull( - type, 'ResourceError', 'type'), + type, r'ResourceError', 'type'), message: BuiltValueNullFieldError.checkNotNull( - message, 'ResourceError', 'message')); + message, r'ResourceError', 'message')); replace(_$result); return _$result; } } -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new +// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,deprecated_member_use_from_same_package,lines_longer_than_80_chars,no_leading_underscores_for_local_identifiers,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new,unnecessary_lambdas diff --git a/example/lib/built_value_serializers.dart b/example/lib/built_value_serializers.dart index cc8ef450..6ff6bd6b 100644 --- a/example/lib/built_value_serializers.dart +++ b/example/lib/built_value_serializers.dart @@ -1,6 +1,7 @@ library serializers; import 'package:built_value/serializer.dart'; + import 'built_value_resource.dart'; part 'built_value_serializers.g.dart'; diff --git a/example/lib/built_value_serializers.g.dart b/example/lib/built_value_serializers.g.dart index dbad2232..699b3f08 100644 --- a/example/lib/built_value_serializers.g.dart +++ b/example/lib/built_value_serializers.g.dart @@ -11,4 +11,4 @@ Serializers _$serializers = (new Serializers().toBuilder() ..add(ResourceError.serializer)) .build(); -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new +// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,deprecated_member_use_from_same_package,lines_longer_than_80_chars,no_leading_underscores_for_local_identifiers,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new,unnecessary_lambdas diff --git a/example/lib/json_serializable.dart b/example/lib/json_serializable.dart index 361f166a..53b6bd23 100644 --- a/example/lib/json_serializable.dart +++ b/example/lib/json_serializable.dart @@ -3,9 +3,10 @@ import 'dart:async'; import 'package:chopper/chopper.dart'; import 'package:json_annotation/json_annotation.dart'; -part 'json_serializable.g.dart'; part 'json_serializable.chopper.dart'; +part 'json_serializable.g.dart'; + @JsonSerializable() class Resource { final String id; @@ -33,23 +34,25 @@ class ResourceError { Map toJson() => _$ResourceErrorToJson(this); } -@ChopperApi(baseUrl: "/resources") +@ChopperApi(baseUrl: '/resources') abstract class MyService extends ChopperService { static MyService create([ChopperClient? client]) => _$MyService(client); - @Get(path: "/{id}/") + @Get(path: '/{id}/') Future getResource(@Path() String id); - @Get(path: "/all", headers: const {"test": "list"}) + @Get(path: '/all', headers: const {'test': 'list'}) Future>> getResources(); - @Get(path: "/") + @Get(path: '/') Future> getMapResource(@Query() String id); - @Get(path: "/", headers: const {"foo": "bar"}) + @Get(path: '/', headers: const {'foo': 'bar'}) Future> getTypedResource(); @Post() - Future> newResource(@Body() Resource resource, - {@Header() String? name}); + Future> newResource( + @Body() Resource resource, { + @Header() String? name, + }); } diff --git a/example/pubspec.lock b/example/pubspec.lock index fff2f649..7496a15c 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,14 +7,28 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "34.0.0" + version: "40.0.0" analyzer: dependency: "direct main" description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "4.1.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.0" + ansicolor: + dependency: transitive + description: + name: ansicolor + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" args: dependency: transitive description: @@ -35,7 +49,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.3.0" build_config: dependency: transitive description: @@ -49,21 +63,21 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.0.9" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" + version: "2.1.11" build_runner_core: dependency: transitive description: @@ -91,7 +105,7 @@ packages: name: built_value_generator url: "https://pub.dartlang.org" source: hosted - version: "8.1.4" + version: "8.4.0" charcode: dependency: transitive description: @@ -119,14 +133,7 @@ packages: path: "../chopper_generator" relative: true source: path - version: "4.0.2" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" + version: "4.0.3" code_builder: dependency: transitive description: @@ -155,13 +162,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.2" + dart_code_metrics: + dependency: "direct dev" + description: + name: dart_code_metrics + url: "https://pub.dartlang.org" + source: hosted + version: "4.16.0" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.2.3" file: dependency: transitive description: @@ -197,6 +218,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + html: + dependency: transitive + description: + name: html + url: "https://pub.dartlang.org" + source: hosted + version: "0.15.0" http: dependency: transitive description: @@ -245,7 +273,14 @@ packages: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.1.4" + version: "6.1.6" + lints: + dependency: "direct dev" + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" logging: dependency: transitive description: @@ -288,6 +323,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" pool: dependency: transitive description: @@ -336,14 +378,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.2" source_helper: dependency: transitive description: name: source_helper url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.2" source_span: dependency: transitive description: @@ -414,6 +456,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "5.3.1" yaml: dependency: transitive description: @@ -422,4 +471,4 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.16.0-100.0.dev <3.0.0" + dart: ">=2.17.0 <3.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9a88feed..dccc79da 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -5,7 +5,7 @@ documentation: https://hadrien-lejard.gitbook.io/chopper/ #author: Hadrien Lejard environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.17.0 <3.0.0' dependencies: chopper: @@ -18,6 +18,8 @@ dev_dependencies: chopper_generator: json_serializable: built_value_generator: + dart_code_metrics: ^4.8.1 + lints: ^2.0.0 dependency_overrides: chopper: From 6ff9447933fd1f235e638725c39cb8ae875fc44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 16:17:44 +0100 Subject: [PATCH 06/13] :bug: Fix chopper/chopper_generator pubspec.yaml --- chopper_generator/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chopper_generator/pubspec.yaml b/chopper_generator/pubspec.yaml index fd3bfdcb..37dcb58f 100644 --- a/chopper_generator/pubspec.yaml +++ b/chopper_generator/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: analyzer: ^4.1.0 build: ^2.0.0 built_collection: ^5.0.0 - chopper: ^4.1.0 + chopper: ^4.0.0 code_builder: ^4.0.0 dart_style: ^2.0.0 logging: ^1.0.0 From fc00eb61a93d0c836a3e6adc6a0052d2b09a42f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 23 Jul 2022 16:57:23 +0100 Subject: [PATCH 07/13] :arrow_up: Upgrade code_builder to ^4.1.0 --- chopper_generator/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chopper_generator/pubspec.yaml b/chopper_generator/pubspec.yaml index 37dcb58f..52de9861 100644 --- a/chopper_generator/pubspec.yaml +++ b/chopper_generator/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: build: ^2.0.0 built_collection: ^5.0.0 chopper: ^4.0.0 - code_builder: ^4.0.0 + code_builder: ^4.1.0 dart_style: ^2.0.0 logging: ^1.0.0 meta: ^1.3.0 From 1bce8b9d611e997843f643a3ba63613c2d036ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 24 Jul 2022 10:30:11 +0100 Subject: [PATCH 08/13] :art: Use super initializers in annotations --- chopper/lib/src/annotations.dart | 92 ++++++++++---------------------- 1 file changed, 29 insertions(+), 63 deletions(-) diff --git a/chopper/lib/src/annotations.dart b/chopper/lib/src/annotations.dart index 8ebeda08..dafed63b 100644 --- a/chopper/lib/src/annotations.dart +++ b/chopper/lib/src/annotations.dart @@ -173,15 +173,10 @@ class Method { @immutable class Get extends Method { const Get({ - bool optionalBody = true, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Get, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody = true, + super.path, + super.headers, + }) : super(HttpMethod.Get); } /// Defines a method as an HTTP POST request. @@ -190,30 +185,20 @@ class Get extends Method { @immutable class Post extends Method { const Post({ - bool optionalBody = false, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Post, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody, + super.path, + super.headers, + }) : super(HttpMethod.Post); } /// Defines a method as an HTTP DELETE request. @immutable class Delete extends Method { const Delete({ - bool optionalBody = true, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Delete, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody = true, + super.path, + super.headers, + }) : super(HttpMethod.Delete); } /// Defines a method as an HTTP PUT request. @@ -222,15 +207,10 @@ class Delete extends Method { @immutable class Put extends Method { const Put({ - bool optionalBody = false, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Put, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody, + super.path, + super.headers, + }) : super(HttpMethod.Put); } /// Defines a method as an HTTP PATCH request. @@ -238,44 +218,29 @@ class Put extends Method { @immutable class Patch extends Method { const Patch({ - bool optionalBody = false, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Patch, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody, + super.path, + super.headers, + }) : super(HttpMethod.Patch); } /// Defines a method as an HTTP HEAD request. @immutable class Head extends Method { const Head({ - bool optionalBody = true, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Head, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody = true, + super.path, + super.headers, + }) : super(HttpMethod.Head); } @immutable class Options extends Method { const Options({ - bool optionalBody = true, - String path = '', - Map headers = const {}, - }) : super( - HttpMethod.Options, - optionalBody: optionalBody, - path: path, - headers: headers, - ); + super.optionalBody = true, + super.path, + super.headers, + }) : super(HttpMethod.Options); } /// A function that should convert the body of a [Request] to the HTTP representation. @@ -379,6 +344,7 @@ class Multipart { @immutable class Part { final String? name; + const Part([this.name]); } From 024c9612a3ca33422bc972529986d18723c2b129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 24 Jul 2022 10:43:59 +0100 Subject: [PATCH 09/13] :art: More styling updates --- chopper/lib/src/base.dart | 6 +-- chopper/lib/src/constants.dart | 8 ++-- chopper/lib/src/interceptor.dart | 67 +++++++++++++------------------- chopper/lib/src/request.dart | 10 ++--- chopper/lib/src/response.dart | 2 +- chopper/lib/src/utils.dart | 2 +- 6 files changed, 42 insertions(+), 53 deletions(-) diff --git a/chopper/lib/src/base.dart b/chopper/lib/src/base.dart index fbf134ea..19c3ed63 100644 --- a/chopper/lib/src/base.dart +++ b/chopper/lib/src/base.dart @@ -14,7 +14,7 @@ import 'utils.dart'; Type _typeOf() => T; @visibleForTesting -final allowedInterceptorsType = [ +final List allowedInterceptorsType = [ RequestInterceptor, RequestInterceptorFunc, ResponseInterceptor, @@ -163,13 +163,13 @@ class ChopperClient { /// final todoService = chopper.getService(); /// ``` ServiceType getService() { - final serviceType = _typeOf(); + final Type serviceType = _typeOf(); if (serviceType == dynamic || serviceType == ChopperService) { throw Exception( 'Service type should be provided, `dynamic` is not allowed.', ); } - final service = _services[serviceType]; + final ChopperService? service = _services[serviceType]; if (service == null) { throw Exception('Service of type \'$serviceType\' not found.'); } diff --git a/chopper/lib/src/constants.dart b/chopper/lib/src/constants.dart index 21f388aa..c423157f 100644 --- a/chopper/lib/src/constants.dart +++ b/chopper/lib/src/constants.dart @@ -1,9 +1,9 @@ -const contentTypeKey = 'content-type'; -const jsonHeaders = 'application/json'; -const formEncodedHeaders = 'application/x-www-form-urlencoded'; +const String contentTypeKey = 'content-type'; +const String jsonHeaders = 'application/json'; +const String formEncodedHeaders = 'application/x-www-form-urlencoded'; // Represent the header for a json api response https://jsonapi.org/#mime-types -const jsonApiHeaders = 'application/vnd.api+json'; +const String jsonApiHeaders = 'application/vnd.api+json'; class HttpMethod { static const String Get = 'GET'; diff --git a/chopper/lib/src/interceptor.dart b/chopper/lib/src/interceptor.dart index 2a5a9906..a5d94471 100644 --- a/chopper/lib/src/interceptor.dart +++ b/chopper/lib/src/interceptor.dart @@ -137,10 +137,10 @@ typedef RequestInterceptorFunc = FutureOr Function(Request request); class CurlInterceptor implements RequestInterceptor { @override Future onRequest(Request request) async { - final baseRequest = await request.toBaseRequest(); - final method = baseRequest.method; - final url = baseRequest.url.toString(); - final headers = baseRequest.headers; + 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 += 'curl'; curl += ' -v'; @@ -232,30 +232,27 @@ class JsonConverter implements Converter, ErrorConverter { const JsonConverter(); @override - Request convertRequest(Request request) { - final req = applyHeader( - request, - contentTypeKey, - jsonHeaders, - override: false, - ); - - return encodeJson(req); - } + Request convertRequest(Request request) => encodeJson( + applyHeader( + request, + contentTypeKey, + jsonHeaders, + override: false, + ), + ); Request encodeJson(Request request) { - String? contentType = request.headers[contentTypeKey]; - if (contentType != null && contentType.contains(jsonHeaders)) { - return request.copyWith(body: json.encode(request.body)); - } + final String? contentType = request.headers[contentTypeKey]; - return request; + return (contentType?.contains(jsonHeaders) ?? false) + ? request.copyWith(body: json.encode(request.body)) + : request; } Response decodeJson(Response response) { - final supportedContentTypes = [jsonHeaders, jsonApiHeaders]; + final List supportedContentTypes = [jsonHeaders, jsonApiHeaders]; - final contentType = response.headers[contentTypeKey]; + final String? contentType = response.headers[contentTypeKey]; var body = response.body; if (supportedContentTypes.contains(contentType)) { @@ -280,9 +277,8 @@ class JsonConverter implements Converter, ErrorConverter { } @override - Response convertResponse(Response response) { - return decodeJson(response) as Response; - } + Response convertResponse(Response response) => + decodeJson(response) as Response; dynamic _tryDecodeJson(String data) { try { @@ -300,13 +296,11 @@ class JsonConverter implements Converter, ErrorConverter { static Response responseFactory( Response response, - ) { - return const JsonConverter().convertResponse(response); - } + ) => + const JsonConverter().convertResponse(response); - static Request requestFactory(Request request) { - return const JsonConverter().convertRequest(request); - } + static Request requestFactory(Request request) => + const JsonConverter().convertRequest(request); } /// A [Converter] implementation that converts only [Request]s having a [Map] as their body. @@ -320,7 +314,7 @@ class FormUrlEncodedConverter implements Converter, ErrorConverter { @override Request convertRequest(Request request) { - Request req = applyHeader( + final Request req = applyHeader( request, contentTypeKey, formEncodedHeaders, @@ -330,15 +324,10 @@ class FormUrlEncodedConverter implements Converter, ErrorConverter { if (req.body is Map) return req; if (req.body is Map) { - final body = {}; - - req.body.forEach((key, val) { - if (val != null) { - body[key.toString()] = val.toString(); - } + return req.copyWith(body: { + for (final MapEntry e in req.body.entries) + if (e.value != null) e.key.toString(): e.value.toString(), }); - - req = req.copyWith(body: body); } return req; diff --git a/chopper/lib/src/request.dart b/chopper/lib/src/request.dart index 144332a1..4a422d76 100644 --- a/chopper/lib/src/request.dart +++ b/chopper/lib/src/request.dart @@ -104,7 +104,7 @@ class PartValue { /// Represents a file part in a multipart request. @immutable class PartValueFile extends PartValue { - PartValueFile(String name, T value) : super(name, value); + const PartValueFile(super.name, super.value); } /// Builds a valid URI from [baseUrl], [url] and [parameters]. @@ -138,7 +138,7 @@ Future toHttpRequest( Uri uri, Map headers, ) async { - final baseRequest = http.Request(method, uri); + final http.Request baseRequest = http.Request(method, uri); baseRequest.headers.addAll(headers); if (body != null) { @@ -163,10 +163,10 @@ Future toMultipartRequest( Uri uri, Map headers, ) async { - final baseRequest = http.MultipartRequest(method, uri); + final http.MultipartRequest baseRequest = http.MultipartRequest(method, uri); baseRequest.headers.addAll(headers); - for (final part in parts) { + for (final PartValue part in parts) { if (part.value == null) continue; if (part.value is http.MultipartFile) { @@ -206,7 +206,7 @@ Future toStreamedRequest( Uri uri, Map headers, ) async { - final req = http.StreamedRequest(method, uri); + final http.StreamedRequest req = http.StreamedRequest(method, uri); req.headers.addAll(headers); bodyStream.listen( diff --git a/chopper/lib/src/response.dart b/chopper/lib/src/response.dart index e4d9a56f..1fc29fac 100644 --- a/chopper/lib/src/response.dart +++ b/chopper/lib/src/response.dart @@ -29,7 +29,7 @@ class Response { /// The body of the response if [isSuccessful] is false. final Object? error; - Response(this.base, this.body, {this.error}); + const Response(this.base, this.body, {this.error}); /// Makes a copy of this Response, replacing original values with the given ones. /// This method can also alter the type of the response body. diff --git a/chopper/lib/src/utils.dart b/chopper/lib/src/utils.dart index ea1bdc6b..e4d17f7d 100644 --- a/chopper/lib/src/utils.dart +++ b/chopper/lib/src/utils.dart @@ -97,7 +97,7 @@ class _Pair { final A first; final B second; - _Pair(this.first, this.second); + const _Pair(this.first, this.second); @override String toString() => '$first=$second'; From 6eb90cd4c22dd72ee6789a152ac67eeab20ae893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 24 Jul 2022 10:49:13 +0100 Subject: [PATCH 10/13] :art: Give BuiltValueConverter a const constructor --- .../lib/chopper_built_value.dart | 4 +- chopper_built_value/test/data.g.dart | 40 ++++++++++--------- chopper_built_value/test/serializers.g.dart | 2 +- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/chopper_built_value/lib/chopper_built_value.dart b/chopper_built_value/lib/chopper_built_value.dart index e8ae0a82..2e85afb1 100644 --- a/chopper_built_value/lib/chopper_built_value.dart +++ b/chopper_built_value/lib/chopper_built_value.dart @@ -6,7 +6,7 @@ import 'package:chopper/chopper.dart'; /// having a serializer implementation made with the built_value package. class BuiltValueConverter implements Converter, ErrorConverter { final Serializers serializers; - final JsonConverter jsonConverter = JsonConverter(); + final JsonConverter jsonConverter = const JsonConverter(); final Type? errorType; /// Builds a new BuiltValueConverter instance that uses built_value serializers defined @@ -15,7 +15,7 @@ class BuiltValueConverter implements Converter, ErrorConverter { /// If the error body cannot be converted with serializers and [errorType] is provided /// and it's not `null`, BuiltValueConverter will try to deserialize the error body into /// [errorType]. - BuiltValueConverter(this.serializers, {this.errorType}); + const BuiltValueConverter(this.serializers, {this.errorType}); T? _deserialize(dynamic value) { var serializer; diff --git a/chopper_built_value/test/data.g.dart b/chopper_built_value/test/data.g.dart index df30695c..d9413768 100644 --- a/chopper_built_value/test/data.g.dart +++ b/chopper_built_value/test/data.g.dart @@ -35,17 +35,17 @@ class _$DataModelSerializer implements StructuredSerializer { final iterator = serialized.iterator; while (iterator.moveNext()) { - final key = iterator.current as String; + final key = iterator.current! as String; iterator.moveNext(); final Object? value = iterator.current; switch (key) { case 'id': result.id = serializers.deserialize(value, - specifiedType: const FullType(int)) as int; + specifiedType: const FullType(int))! as int; break; case 'name': result.name = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; + specifiedType: const FullType(String))! as String; break; } } @@ -79,13 +79,13 @@ class _$ErrorModelSerializer implements StructuredSerializer { final iterator = serialized.iterator; while (iterator.moveNext()) { - final key = iterator.current as String; + final key = iterator.current! as String; iterator.moveNext(); final Object? value = iterator.current; switch (key) { case 'message': result.message = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; + specifiedType: const FullType(String))! as String; break; } } @@ -101,11 +101,11 @@ class _$DataModel extends DataModel { final String name; factory _$DataModel([void Function(DataModelBuilder)? updates]) => - (new DataModelBuilder()..update(updates)).build(); + (new DataModelBuilder()..update(updates))._build(); _$DataModel._({required this.id, required this.name}) : super._() { - BuiltValueNullFieldError.checkNotNull(id, 'DataModel', 'id'); - BuiltValueNullFieldError.checkNotNull(name, 'DataModel', 'name'); + BuiltValueNullFieldError.checkNotNull(id, r'DataModel', 'id'); + BuiltValueNullFieldError.checkNotNull(name, r'DataModel', 'name'); } @override @@ -128,7 +128,7 @@ class _$DataModel extends DataModel { @override String toString() { - return (newBuiltValueToStringHelper('DataModel') + return (newBuiltValueToStringHelper(r'DataModel') ..add('id', id) ..add('name', name)) .toString(); @@ -170,12 +170,14 @@ class DataModelBuilder implements Builder { } @override - _$DataModel build() { + DataModel build() => _build(); + + _$DataModel _build() { final _$result = _$v ?? new _$DataModel._( - id: BuiltValueNullFieldError.checkNotNull(id, 'DataModel', 'id'), + id: BuiltValueNullFieldError.checkNotNull(id, r'DataModel', 'id'), name: BuiltValueNullFieldError.checkNotNull( - name, 'DataModel', 'name')); + name, r'DataModel', 'name')); replace(_$result); return _$result; } @@ -186,10 +188,10 @@ class _$ErrorModel extends ErrorModel { final String message; factory _$ErrorModel([void Function(ErrorModelBuilder)? updates]) => - (new ErrorModelBuilder()..update(updates)).build(); + (new ErrorModelBuilder()..update(updates))._build(); _$ErrorModel._({required this.message}) : super._() { - BuiltValueNullFieldError.checkNotNull(message, 'ErrorModel', 'message'); + BuiltValueNullFieldError.checkNotNull(message, r'ErrorModel', 'message'); } @override @@ -212,7 +214,7 @@ class _$ErrorModel extends ErrorModel { @override String toString() { - return (newBuiltValueToStringHelper('ErrorModel')..add('message', message)) + return (newBuiltValueToStringHelper(r'ErrorModel')..add('message', message)) .toString(); } } @@ -247,14 +249,16 @@ class ErrorModelBuilder implements Builder { } @override - _$ErrorModel build() { + ErrorModel build() => _build(); + + _$ErrorModel _build() { final _$result = _$v ?? new _$ErrorModel._( message: BuiltValueNullFieldError.checkNotNull( - message, 'ErrorModel', 'message')); + message, r'ErrorModel', 'message')); replace(_$result); return _$result; } } -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new +// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,deprecated_member_use_from_same_package,lines_longer_than_80_chars,no_leading_underscores_for_local_identifiers,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new,unnecessary_lambdas diff --git a/chopper_built_value/test/serializers.g.dart b/chopper_built_value/test/serializers.g.dart index 6cb3a9e7..55d2a7d3 100644 --- a/chopper_built_value/test/serializers.g.dart +++ b/chopper_built_value/test/serializers.g.dart @@ -11,4 +11,4 @@ Serializers _$serializers = (new Serializers().toBuilder() ..add(ErrorModel.serializer)) .build(); -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new +// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,deprecated_member_use_from_same_package,lines_longer_than_80_chars,no_leading_underscores_for_local_identifiers,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new,unnecessary_lambdas From 17138e9d49d1ffa04395ab5899dbbfc67d396c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 24 Jul 2022 11:00:40 +0100 Subject: [PATCH 11/13] :art: More styling updates --- chopper_generator/lib/src/generator.dart | 50 ++++++++++++------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/chopper_generator/lib/src/generator.dart b/chopper_generator/lib/src/generator.dart index f9b69fca..13b3c606 100644 --- a/chopper_generator/lib/src/generator.dart +++ b/chopper_generator/lib/src/generator.dart @@ -32,7 +32,7 @@ class ChopperGenerator extends GeneratorForAnnotation { BuildStep buildStep, ) { if (element is! ClassElement) { - final friendlyName = element.displayName; + final String friendlyName = element.displayName; throw InvalidGenerationSourceError( 'Generator cannot target `$friendlyName`.', todo: 'Remove the [ChopperApi] annotation from `$friendlyName`.', @@ -58,7 +58,7 @@ class ChopperGenerator extends GeneratorForAnnotation { ClassElement element, ) { if (!element.allSupertypes.any(_extendsChopperService)) { - final friendlyName = element.displayName; + final String friendlyName = element.displayName; throw InvalidGenerationSourceError( 'Generator cannot target `$friendlyName`.', todo: '`$friendlyName` need to extends the [ChopperService] class.', @@ -80,23 +80,25 @@ class ChopperGenerator extends GeneratorForAnnotation { final String ignore = '// ignore_for_file: always_put_control_body_on_new_line, always_specify_types, prefer_const_declarations, unnecessary_brace_in_string_interps'; - final emitter = DartEmitter(); + final DartEmitter emitter = DartEmitter(); return DartFormatter().format('$ignore\n${classBuilder.accept(emitter)}'); } - Constructor _generateConstructor() => Constructor((constructorBuilder) { - constructorBuilder.optionalParameters.add( - Parameter((paramBuilder) { - paramBuilder.name = _clientVar; - paramBuilder.type = refer('${chopper.ChopperClient}?'); - }), - ); + Constructor _generateConstructor() => Constructor( + (ConstructorBuilder constructorBuilder) { + constructorBuilder.optionalParameters.add( + Parameter((paramBuilder) { + paramBuilder.name = _clientVar; + paramBuilder.type = refer('${chopper.ChopperClient}?'); + }), + ); - constructorBuilder.body = Code( - 'if ($_clientVar == null) return;\nthis.$_clientVar = $_clientVar;', - ); - }); + constructorBuilder.body = Code( + 'if ($_clientVar == null) return;\nthis.$_clientVar = $_clientVar;', + ); + }, + ); Iterable _parseMethods(ClassElement element, String baseUrl) => element.methods @@ -306,14 +308,16 @@ class ChopperGenerator extends GeneratorForAnnotation { final ConstantReader? requestFactory = factoryConverter?.peek('request'); if (requestFactory != null) { - final func = requestFactory.objectValue.toFunctionValue(); + final ExecutableElement? func = + requestFactory.objectValue.toFunctionValue(); namedArguments['requestConverter'] = refer(_factoryForFunction(func!)); } final ConstantReader? responseFactory = factoryConverter?.peek('response'); if (responseFactory != null) { - final func = responseFactory.objectValue.toFunctionValue(); + final ExecutableElement? func = + responseFactory.objectValue.toFunctionValue(); namedArguments['responseConverter'] = refer(_factoryForFunction(func!)); } @@ -341,7 +345,7 @@ class ChopperGenerator extends GeneratorForAnnotation { : function.name!; Map _getAnnotation(MethodElement method, Type type) { - var annotation; + DartObject? annotation; String name = ''; for (final ParameterElement p in method.parameters) { @@ -356,11 +360,7 @@ class ChopperGenerator extends GeneratorForAnnotation { } } - if (annotation == null) return {}; - - return { - name: ConstantReader(annotation), - }; + return annotation == null ? {} : {name: ConstantReader(annotation)}; } Map _getAnnotations( @@ -382,9 +382,11 @@ class ChopperGenerator extends GeneratorForAnnotation { ConstantReader? _getMethodAnnotation(MethodElement method) { for (final type in _methodsAnnotations) { - final annotation = _typeChecker(type) + final DartObject? annotation = _typeChecker(type) .firstAnnotationOf(method, throwOnUnresolved: false); - if (annotation != null) return ConstantReader(annotation); + if (annotation != null) { + return ConstantReader(annotation); + } } return null; From 581a0bee7993cc65b3fbf3b0169e95f41cf44e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 24 Jul 2022 11:16:34 +0100 Subject: [PATCH 12/13] :art: More styling updates --- chopper/lib/src/base.dart | 5 +++-- chopper/lib/src/interceptor.dart | 9 +++------ chopper/lib/src/request.dart | 12 ++++++------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/chopper/lib/src/base.dart b/chopper/lib/src/base.dart index 19c3ed63..3fa4e998 100644 --- a/chopper/lib/src/base.dart +++ b/chopper/lib/src/base.dart @@ -288,8 +288,9 @@ class ChopperClient { ConvertRequest? requestConverter, ConvertResponse? responseConverter, }) async { - var req = await _handleRequestConverter(request, requestConverter); - req = await _interceptRequest(req); + var req = await _interceptRequest( + await _handleRequestConverter(request, requestConverter), + ); _requestController.add(req); final streamRes = await httpClient.send(await req.toBaseRequest()); diff --git a/chopper/lib/src/interceptor.dart b/chopper/lib/src/interceptor.dart index a5d94471..f8b8f6f7 100644 --- a/chopper/lib/src/interceptor.dart +++ b/chopper/lib/src/interceptor.dart @@ -141,10 +141,7 @@ class CurlInterceptor implements RequestInterceptor { final String method = baseRequest.method; final String url = baseRequest.url.toString(); final Map headers = baseRequest.headers; - String curl = ''; - curl += 'curl'; - curl += ' -v'; - curl += ' -X $method'; + String curl = 'curl -v -X $method'; headers.forEach((k, v) { curl += ' -H \'$k: $v\''; }); @@ -174,7 +171,7 @@ class HttpLoggingInterceptor implements RequestInterceptor, ResponseInterceptor { @override FutureOr onRequest(Request request) async { - final base = await request.toBaseRequest(); + final http.BaseRequest base = await request.toBaseRequest(); chopperLogger.info('--> ${base.method} ${base.url}'); base.headers.forEach((k, v) => chopperLogger.info('$k: $v')); @@ -194,7 +191,7 @@ class HttpLoggingInterceptor @override FutureOr onResponse(Response response) { - final base = response.base.request; + final http.BaseRequest? base = response.base.request; chopperLogger.info('<-- ${response.statusCode} ${base!.url}'); response.base.headers.forEach((k, v) => chopperLogger.info('$k: $v')); diff --git a/chopper/lib/src/request.dart b/chopper/lib/src/request.dart index 4a422d76..8378e276 100644 --- a/chopper/lib/src/request.dart +++ b/chopper/lib/src/request.dart @@ -138,8 +138,8 @@ Future toHttpRequest( Uri uri, Map headers, ) async { - final http.Request baseRequest = http.Request(method, uri); - baseRequest.headers.addAll(headers); + final http.Request baseRequest = http.Request(method, uri) + ..headers.addAll(headers); if (body != null) { if (body is String) { @@ -163,8 +163,8 @@ Future toMultipartRequest( Uri uri, Map headers, ) async { - final http.MultipartRequest baseRequest = http.MultipartRequest(method, uri); - baseRequest.headers.addAll(headers); + final http.MultipartRequest baseRequest = http.MultipartRequest(method, uri) + ..headers.addAll(headers); for (final PartValue part in parts) { if (part.value == null) continue; @@ -206,8 +206,8 @@ Future toStreamedRequest( Uri uri, Map headers, ) async { - final http.StreamedRequest req = http.StreamedRequest(method, uri); - req.headers.addAll(headers); + final http.StreamedRequest req = http.StreamedRequest(method, uri) + ..headers.addAll(headers); bodyStream.listen( req.sink.add, From 4207cd7fc88a8e85a556b26dc2ce81c3501ce176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 24 Jul 2022 11:55:33 +0100 Subject: [PATCH 13/13] :rotating_light: Use package:lints/recommended.yaml --- chopper/analysis_options.yaml | 2 ++ chopper/lib/src/constants.dart | 2 ++ chopper/lib/src/interceptor.dart | 2 +- chopper/test/base_test.dart | 7 ++++--- chopper/test/client_test.dart | 2 +- chopper/test/converter_test.dart | 2 +- chopper/test/form_test.dart | 18 +++++++++--------- chopper/test/interceptors_test.dart | 8 ++++---- chopper/test/json_test.dart | 3 ++- chopper/test/multipart_test.dart | 6 +++--- chopper_built_value/analysis_options.yaml | 2 ++ .../lib/chopper_built_value.dart | 4 ++-- chopper_generator/analysis_options.yaml | 2 ++ example/analysis_options.yaml | 2 ++ example/bin/main_built_value.dart | 8 +++++--- example/bin/main_json_serializable.dart | 8 ++++++-- example/lib/built_value_resource.dart | 7 ++++--- example/lib/built_value_serializers.dart | 2 +- example/lib/json_serializable.dart | 4 ++-- example/pubspec.lock | 4 ++-- example/pubspec.yaml | 2 ++ 21 files changed, 59 insertions(+), 38 deletions(-) diff --git a/chopper/analysis_options.yaml b/chopper/analysis_options.yaml index b080627c..7f5a674f 100644 --- a/chopper/analysis_options.yaml +++ b/chopper/analysis_options.yaml @@ -1,3 +1,5 @@ +include: package:lints/recommended.yaml + analyzer: exclude: - "**.g.dart" diff --git a/chopper/lib/src/constants.dart b/chopper/lib/src/constants.dart index c423157f..e7e8faec 100644 --- a/chopper/lib/src/constants.dart +++ b/chopper/lib/src/constants.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names + const String contentTypeKey = 'content-type'; const String jsonHeaders = 'application/json'; const String formEncodedHeaders = 'application/x-www-form-urlencoded'; diff --git a/chopper/lib/src/interceptor.dart b/chopper/lib/src/interceptor.dart index f8b8f6f7..330b0997 100644 --- a/chopper/lib/src/interceptor.dart +++ b/chopper/lib/src/interceptor.dart @@ -152,7 +152,7 @@ class CurlInterceptor implements RequestInterceptor { curl += ' -d \'$body\''; } } - curl += ' \"$url\"'; + curl += ' "$url"'; chopperLogger.info(curl); return request; diff --git a/chopper/test/base_test.dart b/chopper/test/base_test.dart index 829ea2ef..99d81231 100644 --- a/chopper/test/base_test.dart +++ b/chopper/test/base_test.dart @@ -11,7 +11,7 @@ import 'test_service.dart'; const baseUrl = 'http://localhost:8000'; void main() { - final buildClient = ([ + ChopperClient buildClient([ http.Client? httpClient, ErrorConverter? errorConverter, ]) => @@ -24,6 +24,7 @@ void main() { client: httpClient, errorConverter: errorConverter, ); + group('Base', () { test('get service errors', () async { final chopper = ChopperClient( @@ -847,7 +848,7 @@ void main() { final chopper = buildClient(httpClient); final service = chopper.getService(); - final _ = await service.getAll(); + await service.getAll(); }); test('Slash in path gives a trailing slash', () async { @@ -864,7 +865,7 @@ void main() { final chopper = buildClient(httpClient); final service = chopper.getService(); - final _ = await service.getAllWithTrailingSlash(); + await service.getAllWithTrailingSlash(); }); test('timeout', () async { diff --git a/chopper/test/client_test.dart b/chopper/test/client_test.dart index c1fad673..babb172d 100644 --- a/chopper/test/client_test.dart +++ b/chopper/test/client_test.dart @@ -8,7 +8,7 @@ import 'package:test/test.dart'; const baseUrl = 'http://localhost:8000'; void main() { - final buildClient = ([http.Client? httpClient]) => ChopperClient( + ChopperClient buildClient([http.Client? httpClient]) => ChopperClient( baseUrl: baseUrl, client: httpClient, interceptors: [ diff --git a/chopper/test/converter_test.dart b/chopper/test/converter_test.dart index 6e7a5b75..95339d09 100644 --- a/chopper/test/converter_test.dart +++ b/chopper/test/converter_test.dart @@ -11,7 +11,7 @@ const baseUrl = 'http://localhost:8000'; void main() { group('Converter', () { - final buildClient = (http.BaseClient client) => ChopperClient( + ChopperClient buildClient(http.BaseClient client) => ChopperClient( baseUrl: baseUrl, client: client, converter: TestConverter(), diff --git a/chopper/test/form_test.dart b/chopper/test/form_test.dart index f28b17f7..ef5859d1 100644 --- a/chopper/test/form_test.dart +++ b/chopper/test/form_test.dart @@ -7,15 +7,15 @@ import 'test_service.dart'; void main() { group('Form', () { - final buildClient = - (http.Client httpClient, {bool isJson = false}) => ChopperClient( - services: [ - // the generated service - HttpTestService.create(), - ], - client: httpClient, - converter: isJson ? JsonConverter() : null, - ); + ChopperClient buildClient(http.Client httpClient, {bool isJson = false}) => + ChopperClient( + services: [ + // the generated service + HttpTestService.create(), + ], + client: httpClient, + converter: isJson ? JsonConverter() : null, + ); test('form-urlencoded default if no converter', () async { final httpClient = MockClient((http.Request req) async { diff --git a/chopper/test/interceptors_test.dart b/chopper/test/interceptors_test.dart index d57dd8ab..4650d89c 100644 --- a/chopper/test/interceptors_test.dart +++ b/chopper/test/interceptors_test.dart @@ -80,7 +80,7 @@ void main() { }); test('ResponseInterceptorFunc', () async { - var intercepted; + dynamic intercepted; final chopper = ChopperClient( interceptors: [ @@ -105,7 +105,7 @@ void main() { }); test('TypedResponseInterceptorFunc1', () async { - var intercepted; + dynamic intercepted; final chopper = ChopperClient( interceptors: [ @@ -134,7 +134,7 @@ void main() { return http.Response('["1","2"]', 200); }); - var intercepted; + dynamic intercepted; final chopper = ChopperClient( client: client, @@ -143,7 +143,7 @@ void main() { (Response response) { expect(isTypeOf(), isTrue); expect(isTypeOf>(), isTrue); - intercepted = _Intercepted(response.body!); + intercepted = _Intercepted(response.body as BodyType); return response; }, diff --git a/chopper/test/json_test.dart b/chopper/test/json_test.dart index 3893f243..6a8c637f 100644 --- a/chopper/test/json_test.dart +++ b/chopper/test/json_test.dart @@ -16,7 +16,8 @@ void main() { 'result': 'ok', }; group('JSON', () { - final buildClient = (bool json, http.Client httpClient) => ChopperClient( + ChopperClient buildClient(bool json, http.Client httpClient) => + ChopperClient( services: [ // the generated service HttpTestService.create(), diff --git a/chopper/test/multipart_test.dart b/chopper/test/multipart_test.dart index 030c215d..20d28044 100644 --- a/chopper/test/multipart_test.dart +++ b/chopper/test/multipart_test.dart @@ -53,7 +53,7 @@ void main() { ); expect( req.body, - contains('${String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}'), + contains(String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])), ); return http.Response('ok', 200); @@ -88,7 +88,7 @@ void main() { ); expect( req.body, - contains('${String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}'), + contains(String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])), ); return http.Response('ok', 200); @@ -132,7 +132,7 @@ void main() { ); expect( req.body, - contains('${String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}'), + contains(String.fromCharCodes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])), ); return http.Response('ok', 200); diff --git a/chopper_built_value/analysis_options.yaml b/chopper_built_value/analysis_options.yaml index b080627c..7f5a674f 100644 --- a/chopper_built_value/analysis_options.yaml +++ b/chopper_built_value/analysis_options.yaml @@ -1,3 +1,5 @@ +include: package:lints/recommended.yaml + analyzer: exclude: - "**.g.dart" diff --git a/chopper_built_value/lib/chopper_built_value.dart b/chopper_built_value/lib/chopper_built_value.dart index 2e85afb1..09d2c16c 100644 --- a/chopper_built_value/lib/chopper_built_value.dart +++ b/chopper_built_value/lib/chopper_built_value.dart @@ -18,7 +18,7 @@ class BuiltValueConverter implements Converter, ErrorConverter { const BuiltValueConverter(this.serializers, {this.errorType}); T? _deserialize(dynamic value) { - var serializer; + dynamic serializer; if (value is Map && value.containsKey('\$')) { serializer = serializers.serializerForWireName(value['\$']); } @@ -65,7 +65,7 @@ class BuiltValueConverter implements Converter, ErrorConverter { Response convertError(Response response) { final Response jsonResponse = jsonConverter.convertResponse(response); - var body; + dynamic body; try { // try to deserialize using wireName diff --git a/chopper_generator/analysis_options.yaml b/chopper_generator/analysis_options.yaml index a0a63b5e..57256269 100644 --- a/chopper_generator/analysis_options.yaml +++ b/chopper_generator/analysis_options.yaml @@ -1,3 +1,5 @@ +include: package:lints/recommended.yaml + analyzer: exclude: - "**.g.dart" diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index e76e22c1..7061686f 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -1,3 +1,5 @@ +include: package:lints/recommended.yaml + analyzer: exclude: - "**.g.dart" diff --git a/example/bin/main_built_value.dart b/example/bin/main_built_value.dart index 9fc4450a..a6f057ba 100644 --- a/example/bin/main_built_value.dart +++ b/example/bin/main_built_value.dart @@ -12,10 +12,12 @@ final jsonSerializers = /// Simple client to have working example without remote server final client = MockClient((req) async { - if (req.method == 'POST') + if (req.method == 'POST') { return http.Response('{"type":"Fatal","message":"fatal erorr"}', 500); - if (req.url.path == '/resources/list') + } + if (req.url.path == '/resources/list') { return http.Response('[{"id":"1","name":"Foo"}]', 200); + } return http.Response('{"id":"1","name":"Foo"}', 200); }); @@ -57,7 +59,7 @@ class BuiltValueConverter extends JsonConverter { T? _deserialize(dynamic value) { final serializer = jsonSerializers.serializerForType(T) as Serializer?; if (serializer == null) { - throw Exception('No serializer for type ${T}'); + throw Exception('No serializer for type $T'); } return jsonSerializers.deserializeWith(serializer, value); diff --git a/example/bin/main_json_serializable.dart b/example/bin/main_json_serializable.dart index 543ade3e..c6fd2767 100644 --- a/example/bin/main_json_serializable.dart +++ b/example/bin/main_json_serializable.dart @@ -7,10 +7,12 @@ import 'package:http/testing.dart'; /// Simple client to have working example without remote server final client = MockClient((req) async { - if (req.method == 'POST') + if (req.method == 'POST') { return http.Response('{"type":"Fatal","message":"fatal erorr"}', 500); - if (req.method == 'GET' && req.headers['test'] == 'list') + } + if (req.method == 'GET' && req.headers['test'] == 'list') { return http.Response('[{"id":"1","name":"Foo"}]', 200); + } return http.Response('{"id":"1","name":"Foo"}', 200); }); @@ -101,8 +103,10 @@ class JsonSerializableConverter extends JsonConverter { @override // all objects should implements toJson method + // ignore: unnecessary_overrides Request convertRequest(Request request) => super.convertRequest(request); + @override Response convertError(Response response) { // use [JsonConverter] to decode json final jsonRes = super.convertError(response); diff --git a/example/lib/built_value_resource.dart b/example/lib/built_value_resource.dart index d31e4533..ef8b50eb 100644 --- a/example/lib/built_value_resource.dart +++ b/example/lib/built_value_resource.dart @@ -18,7 +18,7 @@ abstract class Resource implements Built { static Serializer get serializer => _$resourceSerializer; - factory Resource([updates(ResourceBuilder b)]) = _$Resource; + factory Resource([Function(ResourceBuilder b) updates]) = _$Resource; Resource._(); } @@ -31,7 +31,8 @@ abstract class ResourceError static Serializer get serializer => _$resourceErrorSerializer; - factory ResourceError([updates(ResourceErrorBuilder b)]) = _$ResourceError; + factory ResourceError([Function(ResourceErrorBuilder b) updates]) = + _$ResourceError; ResourceError._(); } @@ -46,7 +47,7 @@ abstract class MyService extends ChopperService { @Get(path: '/list') Future>> getBuiltListResources(); - @Get(path: '/', headers: const {'foo': 'bar'}) + @Get(path: '/', headers: {'foo': 'bar'}) Future> getTypedResource(); @Post() diff --git a/example/lib/built_value_serializers.dart b/example/lib/built_value_serializers.dart index 6ff6bd6b..256983bf 100644 --- a/example/lib/built_value_serializers.dart +++ b/example/lib/built_value_serializers.dart @@ -7,7 +7,7 @@ import 'built_value_resource.dart'; part 'built_value_serializers.g.dart'; /// Collection of generated serializers for the built_value chat example. -@SerializersFor(const [ +@SerializersFor([ Resource, ResourceError, ]) diff --git a/example/lib/json_serializable.dart b/example/lib/json_serializable.dart index 53b6bd23..eb188891 100644 --- a/example/lib/json_serializable.dart +++ b/example/lib/json_serializable.dart @@ -41,13 +41,13 @@ abstract class MyService extends ChopperService { @Get(path: '/{id}/') Future getResource(@Path() String id); - @Get(path: '/all', headers: const {'test': 'list'}) + @Get(path: '/all', headers: {'test': 'list'}) Future>> getResources(); @Get(path: '/') Future> getMapResource(@Query() String id); - @Get(path: '/', headers: const {'foo': 'bar'}) + @Get(path: '/', headers: {'foo': 'bar'}) Future> getTypedResource(); @Post() diff --git a/example/pubspec.lock b/example/pubspec.lock index 7496a15c..572b2c64 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -86,7 +86,7 @@ packages: source: hosted version: "7.2.3" built_collection: - dependency: transitive + dependency: "direct main" description: name: built_collection url: "https://pub.dartlang.org" @@ -226,7 +226,7 @@ packages: source: hosted version: "0.15.0" http: - dependency: transitive + dependency: "direct main" description: name: http url: "https://pub.dartlang.org" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index dccc79da..9975770b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -12,6 +12,8 @@ dependencies: json_annotation: built_value: analyzer: + http: + built_collection: dev_dependencies: build_runner: