Skip to content

Commit 20e3a59

Browse files
authored
Enable null safety (#472)
1 parent ca41835 commit 20e3a59

25 files changed

+168
-122
lines changed

.travis.yml

+24-12
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
11
language: dart
22

33
dart:
4-
- dev
5-
- 2.4.0
4+
- dev
65

7-
dart_task:
8-
- test: --platform vm,chrome
9-
- dartanalyzer: --fatal-infos --fatal-warnings .
10-
11-
matrix:
6+
jobs:
127
include:
13-
# Only validate formatting using the dev release
14-
- dart: dev
15-
dart_task: dartfmt
8+
- stage: analyze_and_format
9+
name: "Analyze"
10+
os: linux
11+
script: dartanalyzer --enable-experiment=non-nullable --fatal-warnings --fatal-infos .
12+
- stage: analyze_and_format
13+
name: "Format"
14+
os: linux
15+
script: dartfmt -n --set-exit-if-changed .
16+
- stage: test
17+
name: "Vm Tests"
18+
os: linux
19+
script: pub run --enable-experiment=non-nullable test -p vm
20+
- stage: test
21+
name: "Web Tests"
22+
os: linux
23+
script: pub run --enable-experiment=non-nullable test -p chrome
24+
25+
stages:
26+
- analyze_and_format
27+
- test
1628

1729
# Only building master means that we don't run two builds for each pull request.
1830
branches:
1931
only: [master]
2032

2133
cache:
22-
directories:
23-
- $HOME/.pub-cache
34+
directories:
35+
- $HOME/.pub-cache

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## 0.13.0-nullsafety-dev
2+
3+
Pre-release for the null safety migration of this package.
4+
5+
Note that 0.12.3 may not be the final stable null safety release version, we
6+
reserve the right to release it as a 0.13.0 breaking change.
7+
8+
This release will be pinned to only allow pre-release sdk versions starting from
9+
2.10.0-2.0.dev, which is the first version where this package will appear in the
10+
null safety allow list.
11+
12+
- Added `const` constructor to `ByteStream`.
13+
114
## 0.12.2
215

316
* Fix error handler callback type for response stream errors to avoid masking

analysis_options.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
include: package:pedantic/analysis_options.yaml
2+
23
analyzer:
34
strong-mode:
45
implicit-casts: false
6+
enable-experiment:
7+
- non-nullable
8+
59
linter:
610
rules:
711
- annotate_overrides

lib/http.dart

+11-11
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export 'src/streamed_response.dart';
3030
/// the same server, you should use a single [Client] for all of those requests.
3131
///
3232
/// For more fine-grained control over the request, use [Request] instead.
33-
Future<Response> head(url, {Map<String, String> headers}) =>
33+
Future<Response> head(Object url, {Map<String, String>? headers}) =>
3434
_withClient((client) => client.head(url, headers: headers));
3535

3636
/// Sends an HTTP GET request with the given headers to the given URL, which can
@@ -41,7 +41,7 @@ Future<Response> head(url, {Map<String, String> headers}) =>
4141
/// the same server, you should use a single [Client] for all of those requests.
4242
///
4343
/// For more fine-grained control over the request, use [Request] instead.
44-
Future<Response> get(url, {Map<String, String> headers}) =>
44+
Future<Response> get(Object url, {Map<String, String>? headers}) =>
4545
_withClient((client) => client.get(url, headers: headers));
4646

4747
/// Sends an HTTP POST request with the given headers and body to the given URL,
@@ -63,8 +63,8 @@ Future<Response> get(url, {Map<String, String> headers}) =>
6363
///
6464
/// For more fine-grained control over the request, use [Request] or
6565
/// [StreamedRequest] instead.
66-
Future<Response> post(url,
67-
{Map<String, String> headers, body, Encoding encoding}) =>
66+
Future<Response> post(Object url,
67+
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
6868
_withClient((client) =>
6969
client.post(url, headers: headers, body: body, encoding: encoding));
7070

@@ -87,8 +87,8 @@ Future<Response> post(url,
8787
///
8888
/// For more fine-grained control over the request, use [Request] or
8989
/// [StreamedRequest] instead.
90-
Future<Response> put(url,
91-
{Map<String, String> headers, body, Encoding encoding}) =>
90+
Future<Response> put(Object url,
91+
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
9292
_withClient((client) =>
9393
client.put(url, headers: headers, body: body, encoding: encoding));
9494

@@ -111,8 +111,8 @@ Future<Response> put(url,
111111
///
112112
/// For more fine-grained control over the request, use [Request] or
113113
/// [StreamedRequest] instead.
114-
Future<Response> patch(url,
115-
{Map<String, String> headers, body, Encoding encoding}) =>
114+
Future<Response> patch(Object url,
115+
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
116116
_withClient((client) =>
117117
client.patch(url, headers: headers, body: body, encoding: encoding));
118118

@@ -124,7 +124,7 @@ Future<Response> patch(url,
124124
/// the same server, you should use a single [Client] for all of those requests.
125125
///
126126
/// For more fine-grained control over the request, use [Request] instead.
127-
Future<Response> delete(url, {Map<String, String> headers}) =>
127+
Future<Response> delete(Object url, {Map<String, String>? headers}) =>
128128
_withClient((client) => client.delete(url, headers: headers));
129129

130130
/// Sends an HTTP GET request with the given headers to the given URL, which can
@@ -140,7 +140,7 @@ Future<Response> delete(url, {Map<String, String> headers}) =>
140140
///
141141
/// For more fine-grained control over the request and response, use [Request]
142142
/// instead.
143-
Future<String> read(url, {Map<String, String> headers}) =>
143+
Future<String> read(Object url, {Map<String, String>? headers}) =>
144144
_withClient((client) => client.read(url, headers: headers));
145145

146146
/// Sends an HTTP GET request with the given headers to the given URL, which can
@@ -156,7 +156,7 @@ Future<String> read(url, {Map<String, String> headers}) =>
156156
///
157157
/// For more fine-grained control over the request and response, use [Request]
158158
/// instead.
159-
Future<Uint8List> readBytes(url, {Map<String, String> headers}) =>
159+
Future<Uint8List> readBytes(Object url, {Map<String, String>? headers}) =>
160160
_withClient((client) => client.readBytes(url, headers: headers));
161161

162162
Future<T> _withClient<T>(Future<T> Function(Client) fn) async {

lib/src/base_client.dart

+15-13
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,42 @@ import 'streamed_response.dart';
1818
/// maybe [close], and then they get various convenience methods for free.
1919
abstract class BaseClient implements Client {
2020
@override
21-
Future<Response> head(url, {Map<String, String> headers}) =>
21+
Future<Response> head(Object url, {Map<String, String>? headers}) =>
2222
_sendUnstreamed('HEAD', url, headers);
2323

2424
@override
25-
Future<Response> get(url, {Map<String, String> headers}) =>
25+
Future<Response> get(Object url, {Map<String, String>? headers}) =>
2626
_sendUnstreamed('GET', url, headers);
2727

2828
@override
29-
Future<Response> post(url,
30-
{Map<String, String> headers, body, Encoding encoding}) =>
29+
Future<Response> post(Object url,
30+
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
3131
_sendUnstreamed('POST', url, headers, body, encoding);
3232

3333
@override
34-
Future<Response> put(url,
35-
{Map<String, String> headers, body, Encoding encoding}) =>
34+
Future<Response> put(Object url,
35+
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
3636
_sendUnstreamed('PUT', url, headers, body, encoding);
3737

3838
@override
39-
Future<Response> patch(url,
40-
{Map<String, String> headers, body, Encoding encoding}) =>
39+
Future<Response> patch(Object url,
40+
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
4141
_sendUnstreamed('PATCH', url, headers, body, encoding);
4242

4343
@override
44-
Future<Response> delete(url, {Map<String, String> headers}) =>
44+
Future<Response> delete(Object url, {Map<String, String>? headers}) =>
4545
_sendUnstreamed('DELETE', url, headers);
46+
4647
@override
47-
Future<String> read(url, {Map<String, String> headers}) async {
48+
Future<String> read(Object url, {Map<String, String>? headers}) async {
4849
final response = await get(url, headers: headers);
4950
_checkResponseSuccess(url, response);
5051
return response.body;
5152
}
5253

5354
@override
54-
Future<Uint8List> readBytes(url, {Map<String, String> headers}) async {
55+
Future<Uint8List> readBytes(Object url,
56+
{Map<String, String>? headers}) async {
5557
final response = await get(url, headers: headers);
5658
_checkResponseSuccess(url, response);
5759
return response.bodyBytes;
@@ -69,8 +71,8 @@ abstract class BaseClient implements Client {
6971

7072
/// Sends a non-streaming [Request] and returns a non-streaming [Response].
7173
Future<Response> _sendUnstreamed(
72-
String method, url, Map<String, String> headers,
73-
[body, Encoding encoding]) async {
74+
String method, url, Map<String, String>? headers,
75+
[body, Encoding? encoding]) async {
7476
var request = Request(method, _fromUriOrString(url));
7577

7678
if (headers != null) request.headers.addAll(headers);

lib/src/base_request.dart

+8-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import 'dart:collection';
66

7+
import 'package:meta/meta.dart';
8+
79
import 'byte_stream.dart';
810
import 'client.dart';
911
import 'streamed_response.dart';
@@ -29,10 +31,10 @@ abstract class BaseRequest {
2931
///
3032
/// This defaults to `null`, which indicates that the size of the request is
3133
/// not known in advance. May not be assigned a negative value.
32-
int get contentLength => _contentLength;
33-
int _contentLength;
34+
int? get contentLength => _contentLength;
35+
int? _contentLength;
3436

35-
set contentLength(int value) {
37+
set contentLength(int? value) {
3638
if (value != null && value < 0) {
3739
throw ArgumentError('Invalid content length $value.');
3840
}
@@ -93,16 +95,17 @@ abstract class BaseRequest {
9395
/// Freezes all mutable fields and returns a single-subscription [ByteStream]
9496
/// that emits the body of the request.
9597
///
96-
/// The base implementation of this returns null rather than a [ByteStream];
98+
/// The base implementation of this returns an empty [ByteStream];
9799
/// subclasses are responsible for creating the return value, which should be
98100
/// single-subscription to ensure that no data is dropped. They should also
99101
/// freeze any additional mutable fields they add that don't make sense to
100102
/// change after the request headers are sent.
103+
@mustCallSuper
101104
ByteStream finalize() {
102105
// TODO(nweiz): freeze headers
103106
if (finalized) throw StateError("Can't finalize a finalized Request.");
104107
_finalized = true;
105-
return null;
108+
return const ByteStream(Stream.empty());
106109
}
107110

108111
/// Sends this request.

lib/src/base_response.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import 'base_request.dart';
1010
/// they're returned by [BaseClient.send] or other HTTP client methods.
1111
abstract class BaseResponse {
1212
/// The (frozen) request that triggered this response.
13-
final BaseRequest request;
13+
final BaseRequest? request;
1414

1515
/// The HTTP status code for this response.
1616
final int statusCode;
1717

1818
/// The reason phrase associated with the status code.
19-
final String reasonPhrase;
19+
final String? reasonPhrase;
2020

2121
/// The size of the response body, in bytes.
2222
///
2323
/// If the size of the request is not known in advance, this is `null`.
24-
final int contentLength;
24+
final int? contentLength;
2525

2626
// TODO(nweiz): automatically parse cookies from headers
2727

@@ -42,7 +42,7 @@ abstract class BaseResponse {
4242
this.reasonPhrase}) {
4343
if (statusCode < 100) {
4444
throw ArgumentError('Invalid status code $statusCode.');
45-
} else if (contentLength != null && contentLength < 0) {
45+
} else if (contentLength != null && contentLength! < 0) {
4646
throw ArgumentError('Invalid content length $contentLength.');
4747
}
4848
}

lib/src/browser_client.dart

+7-4
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,17 @@ class BrowserClient extends BaseClient {
5252
request.headers.forEach(xhr.setRequestHeader);
5353

5454
var completer = Completer<StreamedResponse>();
55+
56+
// TODO(kevmoo): Waiting on https://github.com/dart-lang/linter/issues/2185
57+
// ignore: void_checks
5558
unawaited(xhr.onLoad.first.then((_) {
56-
// TODO(nweiz): Set the response type to "arraybuffer" when issue 18542
57-
// is fixed.
58-
var blob = xhr.response as Blob ?? Blob([]);
59+
var blob = xhr.response as Blob;
5960
var reader = FileReader();
6061

6162
reader.onLoad.first.then((_) {
6263
var body = reader.result as Uint8List;
6364
completer.complete(StreamedResponse(
64-
ByteStream.fromBytes(body), xhr.status,
65+
ByteStream.fromBytes(body), xhr.status!,
6566
contentLength: body.length,
6667
request: request,
6768
headers: xhr.responseHeaders,
@@ -76,6 +77,8 @@ class BrowserClient extends BaseClient {
7677
reader.readAsArrayBuffer(blob);
7778
}));
7879

80+
// TODO(kevmoo): Waiting on https://github.com/dart-lang/linter/issues/2185
81+
// ignore: void_checks
7982
unawaited(xhr.onError.first.then((_) {
8083
// Unfortunately, the underlying XMLHttpRequest API doesn't expose any
8184
// specific information about the error itself.

lib/src/byte_stream.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'dart:typed_data';
88

99
/// A stream of chunks of bytes representing a single piece of data.
1010
class ByteStream extends StreamView<List<int>> {
11-
ByteStream(Stream<List<int>> stream) : super(stream);
11+
const ByteStream(Stream<List<int>> stream) : super(stream);
1212

1313
/// Returns a single-subscription byte stream that will emit the given bytes
1414
/// in a single chunk.

0 commit comments

Comments
 (0)