Enable and fix a number of lints, disallow implicit casts (#148)

diff --git a/analysis_options.yaml b/analysis_options.yaml
index cc05835..09635ee 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,8 +1,77 @@
 include: package:pedantic/analysis_options.yaml
+
+analyzer:
+  strong-mode:
+    implicit-casts: false
+
 linter:
   rules:
-  - prefer_equal_for_default_values
-  - prefer_generic_function_type_aliases
-  - slash_for_doc_comments
-  - unnecessary_const
-  - unnecessary_new
+  - avoid_bool_literals_in_conditional_expressions
+  - avoid_catching_errors
+  - avoid_classes_with_only_static_members
+  - avoid_function_literals_in_foreach_calls
+  - avoid_private_typedef_functions
+  - avoid_redundant_argument_values
+  - avoid_renaming_method_parameters
+  - avoid_returning_null
+  - avoid_returning_null_for_future
+  - avoid_returning_null_for_void
+  - avoid_returning_this
+  - avoid_single_cascade_in_expression_statements
+  - avoid_unused_constructor_parameters
+  - avoid_void_async
+  - await_only_futures
+  - camel_case_types
+  - cancel_subscriptions
+  - comment_references
+  - constant_identifier_names
+  - control_flow_in_finally
+  - directives_ordering
+  - empty_statements
+  - file_names
+  - hash_and_equals
+  - implementation_imports
+  - invariant_booleans
+  - iterable_contains_unrelated_type
+  - join_return_with_assignment
+  - lines_longer_than_80_chars
+  - list_remove_unrelated_type
+  - literal_only_boolean_expressions
+  - missing_whitespace_between_adjacent_strings
+  - no_adjacent_strings_in_list
+  - no_runtimeType_toString
+  - non_constant_identifier_names
+  - only_throw_errors
+  - overridden_fields
+  - package_api_docs
+  - package_names
+  - package_prefixed_library_names
+  - prefer_asserts_in_initializer_lists
+  - prefer_const_constructors
+  - prefer_const_declarations
+  - prefer_expression_function_bodies
+  - prefer_final_locals
+  - prefer_function_declarations_over_variables
+  - prefer_initializing_formals
+  - prefer_inlined_adds
+  - prefer_interpolation_to_compose_strings
+  - prefer_is_not_operator
+  - prefer_null_aware_operators
+  - prefer_relative_imports
+  - prefer_typing_uninitialized_variables
+  - prefer_void_to_null
+  - provide_deprecation_message
+  - sort_pub_dependencies
+  - test_types_in_equals
+  - throw_in_finally
+  - unnecessary_await_in_return
+  - unnecessary_brace_in_string_interps
+  - unnecessary_getters_setters
+  - unnecessary_lambdas
+  - unnecessary_null_aware_assignments
+  - unnecessary_overrides
+  - unnecessary_parenthesis
+  - unnecessary_statements
+  - unnecessary_string_interpolations
+  - use_string_buffers
+  - void_checks
diff --git a/example/example.dart b/example/example.dart
index af7bd4d..e3a1505 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -5,8 +5,8 @@
 import 'package:web_socket_channel/io.dart';
 import 'package:web_socket_channel/status.dart' as status;
 
-void main() async {
-  final channel = await IOWebSocketChannel.connect('ws://localhost:1234');
+void main() {
+  final channel = IOWebSocketChannel.connect('ws://localhost:1234');
 
   channel.stream.listen((message) {
     channel.sink.add('received!');
diff --git a/lib/html.dart b/lib/html.dart
index 2819b63..7afaf94 100644
--- a/lib/html.dart
+++ b/lib/html.dart
@@ -70,7 +70,7 @@
       : this(WebSocket(url.toString(), protocols)
           ..binaryType = (binaryType ?? BinaryType.list).value);
 
-  /// Creates a channel wrapping [webSocket].
+  /// Creates a channel wrapping [_webSocket].
   HtmlWebSocketChannel(this._webSocket) {
     _sink = _HtmlWebSocketSink(this);
 
@@ -109,8 +109,7 @@
 
   /// Pipes user events to [_webSocket].
   void _listen() {
-    _controller.local.stream.listen((message) => _webSocket.send(message),
-        onDone: () {
+    _controller.local.stream.listen(_webSocket.send, onDone: () {
       // On Chrome and possibly other browsers, `null` can't be passed as the
       // default here. The actual arity of the function call must be correct or
       // it will fail.
diff --git a/lib/io.dart b/lib/io.dart
index e6023d6..0ec108f 100644
--- a/lib/io.dart
+++ b/lib/io.dart
@@ -23,8 +23,10 @@
 
   @override
   String get protocol => _webSocket?.protocol;
+
   @override
   int get closeCode => _webSocket?.closeCode;
+
   @override
   String get closeReason => _webSocket?.closeReason;
 
@@ -51,23 +53,28 @@
   ///
   /// If there's an error connecting, the channel's stream emits a
   /// [WebSocketChannelException] wrapping that error and then closes.
-  factory IOWebSocketChannel.connect(url,
-      {Iterable<String> protocols,
-      Map<String, dynamic> headers,
-      Duration pingInterval}) {
-    var channel;
-    var sinkCompleter = WebSocketSinkCompleter();
-    var stream = StreamCompleter.fromFuture(WebSocket.connect(url.toString(),
-            headers: headers, protocols: protocols)
-        .then((webSocket) {
-      webSocket.pingInterval = pingInterval;
-      channel._webSocket = webSocket;
-      sinkCompleter.setDestinationSink(_IOWebSocketSink(webSocket));
-      return webSocket;
-    }).catchError((error) => throw WebSocketChannelException.from(error)));
+  factory IOWebSocketChannel.connect(
+    Object url, {
+    Iterable<String> protocols,
+    Map<String, dynamic> headers,
+    Duration pingInterval,
+  }) {
+    IOWebSocketChannel channel;
+    final sinkCompleter = WebSocketSinkCompleter();
+    final stream = StreamCompleter.fromFuture(
+      WebSocket.connect(url.toString(), headers: headers, protocols: protocols)
+          .then((webSocket) {
+        webSocket.pingInterval = pingInterval;
+        channel._webSocket = webSocket;
+        sinkCompleter.setDestinationSink(_IOWebSocketSink(webSocket));
+        return webSocket;
+      }).catchError(
+        (Object error) => throw WebSocketChannelException.from(error),
+      ),
+    );
 
-    channel = IOWebSocketChannel._withoutSocket(stream, sinkCompleter.sink);
-    return channel;
+    return channel =
+        IOWebSocketChannel._withoutSocket(stream, sinkCompleter.sink);
   }
 
   /// Creates a channel wrapping [socket].
@@ -79,7 +86,7 @@
 
   /// Creates a channel without a socket.
   ///
-  /// This is used with [connect] to synchronously provide a channel that later
+  /// This is used with `connect` to synchronously provide a channel that later
   /// has a socket added.
   IOWebSocketChannel._withoutSocket(Stream stream, this.sink)
       : _webSocket = null,
diff --git a/lib/src/_connect_api.dart b/lib/src/_connect_api.dart
index b9fe0b4..c816181 100644
--- a/lib/src/_connect_api.dart
+++ b/lib/src/_connect_api.dart
@@ -9,7 +9,7 @@
 /// Connects to [uri] using and returns a channel that can be used to
 /// communicate over the resulting socket.
 ///
-/// The optional [protocols] parameter is the same as [WebSocket.connect].
+/// The optional [protocols] parameter is the same as `WebSocket.connect`.
 WebSocketChannel connect(Uri uri, {Iterable<String> protocols}) {
   throw UnsupportedError('No implementation of the connect api provided');
 }
diff --git a/lib/src/_connect_html.dart b/lib/src/_connect_html.dart
index 895b7b2..5839c41 100644
--- a/lib/src/_connect_html.dart
+++ b/lib/src/_connect_html.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:web_socket_channel/html.dart';
+import '../html.dart';
 
 import '../web_socket_channel.dart';
 
@@ -11,6 +11,6 @@
 /// Connects to [uri] using and returns a channel that can be used to
 /// communicate over the resulting socket.
 ///
-/// The optional [protocols] parameter is the same as [WebSocket.connect].
+/// The optional [protocols] parameter is the same as `WebSocket.connect`.
 WebSocketChannel connect(Uri uri, {Iterable<String> protocols}) =>
     HtmlWebSocketChannel.connect(uri, protocols: protocols);
diff --git a/lib/src/_connect_io.dart b/lib/src/_connect_io.dart
index 60f02c4..5e6bcd8 100644
--- a/lib/src/_connect_io.dart
+++ b/lib/src/_connect_io.dart
@@ -2,14 +2,14 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import '../web_socket_channel.dart';
 import '../io.dart';
+import '../web_socket_channel.dart';
 
 /// Creates a new WebSocket connection.
 ///
 /// Connects to [uri] using and returns a channel that can be used to
 /// communicate over the resulting socket.
 ///
-/// The optional [protocols] parameter is the same as [WebSocket.connect].
+/// The optional [protocols] parameter is the same as `WebSocket.connect`.
 WebSocketChannel connect(Uri uri, {Iterable<String> protocols}) =>
     IOWebSocketChannel.connect(uri, protocols: protocols);
diff --git a/lib/src/channel.dart b/lib/src/channel.dart
index c2c13e2..75522a8 100644
--- a/lib/src/channel.dart
+++ b/lib/src/channel.dart
@@ -9,11 +9,11 @@
 import 'package:crypto/crypto.dart';
 import 'package:stream_channel/stream_channel.dart';
 
-import 'copy/web_socket_impl.dart';
-
 import '_connect_api.dart'
     if (dart.library.io) '_connect_io.dart'
     if (dart.library.html) '_connect_html.dart' as platform;
+import 'copy/web_socket_impl.dart';
+import 'exception.dart';
 
 /// A [StreamChannel] that communicates over a WebSocket.
 ///
@@ -68,12 +68,12 @@
   /// `Sec-WebSocket-Accept` header.
   ///
   /// [initial handshake]: https://tools.ietf.org/html/rfc6455#section-4.2.2
-  static String signKey(String key) {
-    // We use [codeUnits] here rather than UTF-8-decoding the string because
-    // [key] is expected to be base64 encoded, and so will be pure ASCII.
-    return convert.base64
-        .encode(sha1.convert((key + webSocketGUID).codeUnits).bytes);
-  }
+  static String signKey(String key)
+      // We use [codeUnits] here rather than UTF-8-decoding the string because
+      // [key] is expected to be base64 encoded, and so will be pure ASCII.
+      =>
+      convert.base64
+          .encode(sha1.convert((key + webSocketGUID).codeUnits).bytes);
 
   /// Creates a new WebSocket handling messaging across an existing [channel].
   ///
@@ -106,7 +106,7 @@
   /// Connects to [uri] using and returns a channel that can be used to
   /// communicate over the resulting socket.
   ///
-  /// The optional [protocols] parameter is the same as [WebSocket.connect].
+  /// The optional [protocols] parameter is the same as `WebSocket.connect`.
   factory WebSocketChannel.connect(Uri uri, {Iterable<String> protocols}) =>
       platform.connect(uri, protocols: protocols);
 }
diff --git a/lib/src/copy/io_sink.dart b/lib/src/copy/io_sink.dart
index 8da7f12..0ee0508 100644
--- a/lib/src/copy/io_sink.dart
+++ b/lib/src/copy/io_sink.dart
@@ -51,7 +51,7 @@
     if (_hasError) return done;
 
     _isBound = true;
-    var future = _controllerCompleter == null
+    final future = _controllerCompleter == null
         ? _target.addStream(stream)
         : _controllerCompleter.future.then((_) => _target.addStream(stream));
     _controllerInstance?.close();
@@ -71,7 +71,7 @@
     // Adding an empty stream-controller will return a future that will complete
     // when all data is done.
     _isBound = true;
-    var future = _controllerCompleter.future;
+    final future = _controllerCompleter.future;
     _controllerInstance.close();
     return future.whenComplete(() {
       _isBound = false;
@@ -134,7 +134,7 @@
           // No new stream, .close was called. Close _target.
           _closeTarget();
         }
-      }, onError: (error, stackTrace) {
+      }, onError: (error, StackTrace stackTrace) {
         if (_isBound) {
           // A new stream takes over - forward errors to that stream.
           _controllerCompleter.completeError(error, stackTrace);
diff --git a/lib/src/copy/web_socket.dart b/lib/src/copy/web_socket.dart
index 1928a34..0bfb498 100644
--- a/lib/src/copy/web_socket.dart
+++ b/lib/src/copy/web_socket.dart
@@ -11,6 +11,8 @@
 // This is up-to-date as of sdk revision
 // 365f7b5a8b6ef900a5ee23913b7203569b81b175.
 
+// ignore_for_file: constant_identifier_names
+
 /// Web socket status codes used when closing a web socket connection.
 abstract class WebSocketStatus {
   static const int NORMAL_CLOSURE = 1000;
diff --git a/lib/src/copy/web_socket_impl.dart b/lib/src/copy/web_socket_impl.dart
index 4476805..14cc542 100644
--- a/lib/src/copy/web_socket_impl.dart
+++ b/lib/src/copy/web_socket_impl.dart
@@ -12,7 +12,7 @@
 // This is up-to-date as of sdk revision
 // 365f7b5a8b6ef900a5ee23913b7203569b81b175.
 
-// ignore_for_file: unused_field
+// ignore_for_file: unused_field, constant_identifier_names
 
 import 'dart:async';
 import 'dart:convert';
@@ -99,15 +99,14 @@
 
   @override
   Stream<dynamic /*List<int>|_WebSocketPing|_WebSocketPong*/ > bind(
-      Stream<List<int>> stream) {
-    return Stream.eventTransformed(stream, (EventSink eventSink) {
-      if (_eventSink != null) {
-        throw StateError('WebSocket transformer already used.');
-      }
-      _eventSink = eventSink;
-      return this;
-    });
-  }
+          Stream<List<int>> stream) =>
+      Stream.eventTransformed(stream, (EventSink eventSink) {
+        if (_eventSink != null) {
+          throw StateError('WebSocket transformer already used.');
+        }
+        _eventSink = eventSink;
+        return this;
+      });
 
   @override
   void addError(Object error, [StackTrace stackTrace]) {
@@ -122,9 +121,9 @@
   /// Process data received from the underlying communication channel.
   @override
   void add(List<int> bytes) {
-    var buffer = bytes is Uint8List ? bytes : Uint8List.fromList(bytes);
+    final buffer = bytes is Uint8List ? bytes : Uint8List.fromList(bytes);
     var index = 0;
-    var lastIndex = buffer.length;
+    final lastIndex = buffer.length;
     if (_state == CLOSED) {
       throw WebSocketChannelException('Data on closed connection');
     }
@@ -132,7 +131,7 @@
       throw WebSocketChannelException('Data on failed connection');
     }
     while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
-      var byte = buffer[index];
+      final byte = buffer[index];
       if (_state <= LEN_REST) {
         if (_state == START) {
           _fin = (byte & FIN) != 0;
@@ -142,7 +141,7 @@
             throw WebSocketChannelException('Protocol error');
           }
 
-          _opcode = (byte & OPCODE);
+          _opcode = byte & OPCODE;
 
           if (_opcode <= _WebSocketOpcode.BINARY) {
             if (_opcode == _WebSocketOpcode.CONTINUATION) {
@@ -200,7 +199,7 @@
         } else {
           assert(_state == PAYLOAD);
           // The payload is not handled one byte at a time but in blocks.
-          var payloadLength = min(lastIndex - index, _remainingPayloadBytes);
+          final payloadLength = min(lastIndex - index, _remainingPayloadBytes);
           _remainingPayloadBytes -= payloadLength;
           // Unmask payload if masked.
           if (_masked) {
@@ -248,8 +247,8 @@
         for (var i = 3; i >= 0; i--) {
           mask = (mask << 8) | _maskingBytes[(_unmaskingIndex + i) & 3];
         }
-        var blockMask = Int32x4(mask, mask, mask, mask);
-        var blockBuffer = Int32x4List.view(buffer.buffer, index, blockCount);
+        final blockMask = Int32x4(mask, mask, mask, mask);
+        final blockBuffer = Int32x4List.view(buffer.buffer, index, blockCount);
         for (var i = 0; i < blockBuffer.length; i++) {
           blockBuffer[i] ^= blockMask;
         }
@@ -313,7 +312,7 @@
 
   void _messageFrameEnd() {
     if (_fin) {
-      var bytes = _payload.takeBytes();
+      final bytes = _payload.takeBytes();
 
       switch (_currentMessageType) {
         case _WebSocketMessageType.TEXT:
@@ -332,7 +331,7 @@
     switch (_opcode) {
       case _WebSocketOpcode.CLOSE:
         closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
-        var payload = _payload.takeBytes();
+        final payload = _payload.takeBytes();
         if (payload.isNotEmpty) {
           if (payload.length == 1) {
             throw WebSocketChannelException('Protocol error');
@@ -360,11 +359,10 @@
     _prepareForNextFrame();
   }
 
-  bool _isControlFrame() {
-    return _opcode == _WebSocketOpcode.CLOSE ||
-        _opcode == _WebSocketOpcode.PING ||
-        _opcode == _WebSocketOpcode.PONG;
-  }
+  bool _isControlFrame() =>
+      _opcode == _WebSocketOpcode.CLOSE ||
+      _opcode == _WebSocketOpcode.PING ||
+      _opcode == _WebSocketOpcode.PONG;
 
   void _prepareForNextFrame() {
     if (_state != CLOSED && _state != FAILURE) _state = START;
@@ -380,11 +378,13 @@
 
 class _WebSocketPing {
   final List<int> payload;
+
   _WebSocketPing([this.payload]);
 }
 
 class _WebSocketPong {
   final List<int> payload;
+
   _WebSocketPong([this.payload]);
 }
 
@@ -397,16 +397,15 @@
   _WebSocketOutgoingTransformer(this.webSocket);
 
   @override
-  Stream<List<int>> bind(Stream stream) {
-    return Stream<List<int>>.eventTransformed(stream,
-        (EventSink<List<int>> eventSink) {
-      if (_eventSink != null) {
-        throw StateError('WebSocket transformer already used');
-      }
-      _eventSink = eventSink;
-      return this;
-    });
-  }
+  Stream<List<int>> bind(Stream stream) =>
+      Stream<List<int>>.eventTransformed(stream,
+          (EventSink<List<int>> eventSink) {
+        if (_eventSink != null) {
+          throw StateError('WebSocket transformer already used');
+        }
+        _eventSink = eventSink;
+        return this;
+      });
 
   @override
   void add(message) {
@@ -443,8 +442,8 @@
 
   @override
   void close() {
-    var code = webSocket._outCloseCode;
-    var reason = webSocket._outCloseReason;
+    final code = webSocket._outCloseCode;
+    final reason = webSocket._outCloseReason;
     List<int> data;
     if (code != null) {
       data = <int>[];
@@ -463,8 +462,8 @@
             opcode,
             data,
             webSocket._serverSide,
-            // Logic around _deflateHelper was removed here, since ther ewill never
-            // be a deflate helper for a cross-platform WebSocket client.
+            // Logic around _deflateHelper was removed here, since there will
+            // never be a deflate helper for a cross-platform WebSocket client.
             false)
         .forEach((e) {
       _eventSink.add(e);
@@ -473,20 +472,20 @@
 
   static Iterable<List<int>> createFrame(
       int opcode, List<int> data, bool serverSide, bool compressed) {
-    var mask = !serverSide; // Masking not implemented for server.
-    var dataLength = data == null ? 0 : data.length;
+    final mask = !serverSide; // Masking not implemented for server.
+    final dataLength = data == null ? 0 : data.length;
     // Determine the header size.
-    var headerSize = (mask) ? 6 : 2;
+    var headerSize = mask ? 6 : 2;
     if (dataLength > 65535) {
       headerSize += 8;
     } else if (dataLength > 125) {
       headerSize += 2;
     }
-    var header = Uint8List(headerSize);
+    final header = Uint8List(headerSize);
     var index = 0;
 
     // Set FIN and opcode.
-    var hoc = _WebSocketProtocolTransformer.FIN |
+    final hoc = _WebSocketProtocolTransformer.FIN |
         (compressed ? _WebSocketProtocolTransformer.RSV1 : 0) |
         (opcode & _WebSocketProtocolTransformer.OPCODE);
 
@@ -506,7 +505,7 @@
     }
     if (mask) {
       header[1] |= 1 << 7;
-      var maskBytes = [
+      final maskBytes = [
         _random.nextInt(256),
         _random.nextInt(256),
         _random.nextInt(256),
@@ -535,15 +534,15 @@
           }
         }
         const BLOCK_SIZE = 16;
-        var blockCount = list.length ~/ BLOCK_SIZE;
+        final blockCount = list.length ~/ BLOCK_SIZE;
         if (blockCount > 0) {
           // Create mask block.
           var mask = 0;
           for (var i = 3; i >= 0; i--) {
             mask = (mask << 8) | maskBytes[i];
           }
-          var blockMask = Int32x4(mask, mask, mask, mask);
-          var blockBuffer = Int32x4List.view(list.buffer, 0, blockCount);
+          final blockMask = Int32x4(mask, mask, mask, mask);
+          final blockBuffer = Int32x4List.view(list.buffer, 0, blockCount);
           for (var i = 0; i < blockBuffer.length; i++) {
             blockBuffer[i] ^= blockMask;
           }
@@ -600,7 +599,7 @@
 
   void _cancel() {
     if (_subscription != null) {
-      var subscription = _subscription;
+      final subscription = _subscription;
       _subscription = null;
       subscription.cancel();
     }
@@ -613,7 +612,7 @@
         onPause: _onPause,
         onResume: _onResume,
         onCancel: _onListen);
-    var stream =
+    final stream =
         _WebSocketOutgoingTransformer(webSocket).bind(_controller.stream);
     sink.addStream(stream).then((_) {
       _done();
@@ -664,9 +663,8 @@
   @override
   Future close() {
     _ensureController();
-    Future closeSocket() {
-      return sink.close().catchError((_) {}).then((_) => webSocket);
-    }
+    Future closeSocket() =>
+        sink.close().catchError((_) {}).then((_) => webSocket);
 
     _controller.close();
     return _closeCompleter.future.then((_) => closeSocket());
@@ -717,7 +715,7 @@
     _sink = StreamSinkImpl(_consumer);
     _readyState = WebSocket.OPEN;
 
-    var transformer = _WebSocketProtocolTransformer(_serverSide);
+    final transformer = _WebSocketProtocolTransformer(_serverSide);
     _subscription = transformer.bind(stream).listen((data) {
       if (data is _WebSocketPing) {
         if (!_writeClosed) _consumer.add(_WebSocketPong(data.payload));
@@ -770,10 +768,9 @@
 
   @override
   StreamSubscription listen(void Function(dynamic) onData,
-      {Function onError, void Function() onDone, bool cancelOnError}) {
-    return _controller.stream.listen(onData,
-        onError: onError, onDone: onDone, cancelOnError: cancelOnError);
-  }
+          {Function onError, void Function() onDone, bool cancelOnError}) =>
+      _controller.stream.listen(onData,
+          onError: onError, onDone: onDone, cancelOnError: cancelOnError);
 
   Duration get pingInterval => _pingInterval;
 
@@ -797,7 +794,9 @@
   int get readyState => _readyState;
 
   String get extensions => null;
+
   int get closeCode => _closeCode;
+
   String get closeReason => _closeReason;
 
   @override
@@ -812,6 +811,7 @@
 
   @override
   Future addStream(Stream stream) => _sink.addStream(stream);
+
   @override
   Future get done => _sink.done;
 
@@ -861,16 +861,15 @@
   // deleted for web_socket_channel. The methods were unused in WebSocket code
   // and produced warnings.
 
-  static bool _isReservedStatusCode(int code) {
-    return code != null &&
-        (code < WebSocketStatus.NORMAL_CLOSURE ||
-            code == WebSocketStatus.RESERVED_1004 ||
-            code == WebSocketStatus.NO_STATUS_RECEIVED ||
-            code == WebSocketStatus.ABNORMAL_CLOSURE ||
-            (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
-                code < WebSocketStatus.RESERVED_1015) ||
-            (code >= WebSocketStatus.RESERVED_1015 && code < 3000));
-  }
+  static bool _isReservedStatusCode(int code) =>
+      code != null &&
+      (code < WebSocketStatus.NORMAL_CLOSURE ||
+          code == WebSocketStatus.RESERVED_1004 ||
+          code == WebSocketStatus.NO_STATUS_RECEIVED ||
+          code == WebSocketStatus.ABNORMAL_CLOSURE ||
+          (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
+              code < WebSocketStatus.RESERVED_1015) ||
+          (code >= WebSocketStatus.RESERVED_1015 && code < 3000));
 }
 
 // The following code is from sdk/lib/io/service_object.dart.
@@ -880,12 +879,13 @@
 // TODO(ajohnsen): Use other way of getting a uniq id.
 abstract class _ServiceObject {
   int __serviceId = 0;
+
   int get _serviceId {
     if (__serviceId == 0) __serviceId = _nextServiceId++;
     return __serviceId;
   }
 
-  // The _toJSON, _servicePath, _serviceTypePath, _serviceTypeName, and
-  // _serviceType methods have been deleted for http_parser. The methods were
-  // unused in WebSocket code and produced warnings.
+// The _toJSON, _servicePath, _serviceTypePath, _serviceTypeName, and
+// _serviceType methods have been deleted for http_parser. The methods were
+// unused in WebSocket code and produced warnings.
 }
diff --git a/lib/src/exception.dart b/lib/src/exception.dart
index d166e6a..ece5cfa 100644
--- a/lib/src/exception.dart
+++ b/lib/src/exception.dart
@@ -9,13 +9,11 @@
   final String message;
 
   /// The exception that caused this one, if available.
-  final inner;
+  final Object inner;
 
   WebSocketChannelException([this.message]) : inner = null;
 
-  WebSocketChannelException.from(inner)
-      : message = inner.toString(),
-        inner = inner;
+  WebSocketChannelException.from(this.inner) : message = inner.toString();
 
   @override
   String toString() => message == null
diff --git a/lib/src/sink_completer.dart b/lib/src/sink_completer.dart
index c6204d6..4d6a2d3 100644
--- a/lib/src/sink_completer.dart
+++ b/lib/src/sink_completer.dart
@@ -8,8 +8,8 @@
 
 /// A [WebSocketSink] where the destination is provided later.
 ///
-/// This is like a [StreamSinkCompleter], except that it properly forwards
-/// paramters to [WebSocketSink.close].
+/// This is like a `StreamSinkCompleter`, except that it properly forwards
+/// parameters to [WebSocketSink.close].
 class WebSocketSinkCompleter {
   /// The sink for this completer.
   ///
@@ -21,7 +21,7 @@
   final WebSocketSink sink = _CompleterSink();
 
   /// Returns [sink] typed as a [_CompleterSink].
-  _CompleterSink get _sink => sink;
+  _CompleterSink get _sink => sink as _CompleterSink;
 
   /// Sets a sink as the destination for events from the
   /// [WebSocketSinkCompleter]'s [sink].
diff --git a/test/html_test.dart b/test/html_test.dart
index 4271a6b..aa87c36 100644
--- a/test/html_test.dart
+++ b/test/html_test.dart
@@ -17,7 +17,7 @@
 void main() {
   int port;
   setUpAll(() async {
-    var channel = spawnHybridCode(r'''
+    final channel = spawnHybridCode(r'''
       // @dart=2.7
       import 'dart:io';
 
@@ -34,7 +34,7 @@
       }
     ''', stayAlive: true);
 
-    port = await channel.stream.first;
+    port = await channel.stream.first as int;
   });
 
   WebSocketChannel channel;
@@ -43,15 +43,18 @@
   });
 
   test('communicates using an existing WebSocket', () async {
-    var webSocket = WebSocket('ws://localhost:$port');
+    final webSocket = WebSocket('ws://localhost:$port');
     channel = HtmlWebSocketChannel(webSocket);
 
-    var queue = StreamQueue(channel.stream);
+    final queue = StreamQueue(channel.stream);
     channel.sink.add('foo');
     expect(await queue.next, equals('foo'));
 
     channel.sink.add(Uint8List.fromList([1, 2, 3, 4, 5]));
-    expect(await _decodeBlob(await queue.next), equals([1, 2, 3, 4, 5]));
+    expect(
+      await _decodeBlob(await queue.next as Blob),
+      equals([1, 2, 3, 4, 5]),
+    );
 
     webSocket.binaryType = 'arraybuffer';
     channel.sink.add(Uint8List.fromList([1, 2, 3, 4, 5]));
@@ -59,12 +62,12 @@
   });
 
   test('communicates using an existing open WebSocket', () async {
-    var webSocket = WebSocket('ws://localhost:$port');
+    final webSocket = WebSocket('ws://localhost:$port');
     await webSocket.onOpen.first;
 
     channel = HtmlWebSocketChannel(webSocket);
 
-    var queue = StreamQueue(channel.stream);
+    final queue = StreamQueue(channel.stream);
     channel.sink.add('foo');
     expect(await queue.next, equals('foo'));
   });
@@ -72,7 +75,7 @@
   test('.connect defaults to binary lists', () async {
     channel = HtmlWebSocketChannel.connect('ws://localhost:$port');
 
-    var queue = StreamQueue(channel.stream);
+    final queue = StreamQueue(channel.stream);
     channel.sink.add('foo');
     expect(await queue.next, equals('foo'));
 
@@ -84,7 +87,7 @@
       () async {
     channel = WebSocketChannel.connect(Uri.parse('ws://localhost:$port'));
 
-    var queue = StreamQueue(channel.stream);
+    final queue = StreamQueue(channel.stream);
     channel.sink.add('foo');
     expect(await queue.next, equals('foo'));
 
@@ -96,18 +99,19 @@
     channel = HtmlWebSocketChannel.connect('ws://localhost:$port',
         binaryType: BinaryType.blob);
 
-    var queue = StreamQueue(channel.stream);
+    final queue = StreamQueue(channel.stream);
     channel.sink.add('foo');
     expect(await queue.next, equals('foo'));
 
     channel.sink.add(Uint8List.fromList([1, 2, 3, 4, 5]));
-    expect(await _decodeBlob(await queue.next), equals([1, 2, 3, 4, 5]));
+    expect(
+        await _decodeBlob(await queue.next as Blob), equals([1, 2, 3, 4, 5]));
   });
 
   test('.connect wraps a connection error in WebSocketChannelException',
       () async {
     // Spawn a server that will immediately reject the connection.
-    var serverChannel = spawnHybridCode(r'''
+    final serverChannel = spawnHybridCode(r'''
       import 'dart:io';
 
       import 'package:stream_channel/stream_channel.dart';
@@ -123,15 +127,14 @@
 
     // TODO(nweiz): Make this channel use a port number that's guaranteed to be
     // invalid.
-    var channel = HtmlWebSocketChannel.connect(
+    final channel = HtmlWebSocketChannel.connect(
         'ws://localhost:${await serverChannel.stream.first}');
-    expect(channel.stream.toList(),
-        throwsA(TypeMatcher<WebSocketChannelException>()));
+    expect(channel.stream.toList(), throwsA(isA<WebSocketChannelException>()));
   });
 }
 
 Future<List<int>> _decodeBlob(Blob blob) async {
-  var reader = FileReader();
+  final reader = FileReader();
   reader.readAsArrayBuffer(blob);
   await reader.onLoad.first;
   return reader.result as Uint8List;
diff --git a/test/io_test.dart b/test/io_test.dart
index 7d87c3f..bb4a017 100644
--- a/test/io_test.dart
+++ b/test/io_test.dart
@@ -3,24 +3,22 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @TestOn('vm')
-
 import 'dart:io';
 
 import 'package:test/test.dart';
-
 import 'package:web_socket_channel/io.dart';
 import 'package:web_socket_channel/web_socket_channel.dart';
 
 void main() {
-  var server;
+  HttpServer server;
   tearDown(() async {
     if (server != null) await server.close();
   });
 
   test('communicates using existing WebSockets', () async {
     server = await HttpServer.bind('localhost', 0);
-    server.transform(WebSocketTransformer()).listen((webSocket) {
-      var channel = IOWebSocketChannel(webSocket);
+    server.transform(WebSocketTransformer()).listen((WebSocket webSocket) {
+      final channel = IOWebSocketChannel(webSocket);
       channel.sink.add('hello!');
       channel.stream.listen((request) {
         expect(request, equals('ping'));
@@ -29,8 +27,8 @@
       });
     });
 
-    var webSocket = await WebSocket.connect('ws://localhost:${server.port}');
-    var channel = IOWebSocketChannel(webSocket);
+    final webSocket = await WebSocket.connect('ws://localhost:${server.port}');
+    final channel = IOWebSocketChannel(webSocket);
 
     var n = 0;
     channel.stream.listen((message) {
@@ -51,15 +49,15 @@
 
   test('.connect communicates immediately', () async {
     server = await HttpServer.bind('localhost', 0);
-    server.transform(WebSocketTransformer()).listen((webSocket) {
-      var channel = IOWebSocketChannel(webSocket);
+    server.transform(WebSocketTransformer()).listen((WebSocket webSocket) {
+      final channel = IOWebSocketChannel(webSocket);
       channel.stream.listen((request) {
         expect(request, equals('ping'));
         channel.sink.add('pong');
       });
     });
 
-    var channel = IOWebSocketChannel.connect('ws://localhost:${server.port}');
+    final channel = IOWebSocketChannel.connect('ws://localhost:${server.port}');
     channel.sink.add('ping');
 
     channel.stream.listen(
@@ -73,15 +71,15 @@
   test('.connect communicates immediately using platform independent api',
       () async {
     server = await HttpServer.bind('localhost', 0);
-    server.transform(WebSocketTransformer()).listen((webSocket) {
-      var channel = IOWebSocketChannel(webSocket);
+    server.transform(WebSocketTransformer()).listen((WebSocket webSocket) {
+      final channel = IOWebSocketChannel(webSocket);
       channel.stream.listen((request) {
         expect(request, equals('ping'));
         channel.sink.add('pong');
       });
     });
 
-    var channel =
+    final channel =
         WebSocketChannel.connect(Uri.parse('ws://localhost:${server.port}'));
     channel.sink.add('ping');
 
@@ -95,16 +93,16 @@
 
   test('.connect with an immediate call to close', () async {
     server = await HttpServer.bind('localhost', 0);
-    server.transform(WebSocketTransformer()).listen((webSocket) {
+    server.transform(WebSocketTransformer()).listen((WebSocket webSocket) {
       expect(() async {
-        var channel = IOWebSocketChannel(webSocket);
+        final channel = IOWebSocketChannel(webSocket);
         await channel.stream.drain();
         expect(channel.closeCode, equals(5678));
         expect(channel.closeReason, equals('raisin'));
       }(), completes);
     });
 
-    var channel = IOWebSocketChannel.connect('ws://localhost:${server.port}');
+    final channel = IOWebSocketChannel.connect('ws://localhost:${server.port}');
     await channel.sink.close(5678, 'raisin');
   });
 
@@ -116,41 +114,48 @@
       request.response.close();
     });
 
-    var channel = IOWebSocketChannel.connect('ws://localhost:${server.port}');
-    expect(channel.stream.drain(),
-        throwsA(TypeMatcher<WebSocketChannelException>()));
+    final channel = IOWebSocketChannel.connect('ws://localhost:${server.port}');
+    expect(channel.stream.drain(), throwsA(isA<WebSocketChannelException>()));
   });
 
   test('.protocols fail', () async {
-    var passedProtocol = 'passed-protocol';
-    var failedProtocol = 'failed-protocol';
-    var selector = (List<String> receivedProtocols) => passedProtocol;
+    const passedProtocol = 'passed-protocol';
+    const failedProtocol = 'failed-protocol';
+    String selector(List<String> receivedProtocols) => passedProtocol;
 
     server = await HttpServer.bind('localhost', 0);
-    server.listen((request) {
-      expect(WebSocketTransformer.upgrade(request, protocolSelector: selector),
-          throwsException);
+    server.listen((HttpRequest request) {
+      expect(
+        WebSocketTransformer.upgrade(request, protocolSelector: selector),
+        throwsException,
+      );
     });
 
-    var channel = IOWebSocketChannel.connect('ws://localhost:${server.port}',
-        protocols: [failedProtocol]);
-    expect(channel.stream.drain(),
-        throwsA(TypeMatcher<WebSocketChannelException>()));
+    final channel = IOWebSocketChannel.connect(
+      'ws://localhost:${server.port}',
+      protocols: [failedProtocol],
+    );
+    expect(
+      channel.stream.drain(),
+      throwsA(isA<WebSocketChannelException>()),
+    );
   });
 
   test('.protocols pass', () async {
-    var passedProtocol = 'passed-protocol';
-    var selector = (List<String> receivedProtocols) => passedProtocol;
+    const passedProtocol = 'passed-protocol';
+    String selector(List<String> receivedProtocols) => passedProtocol;
 
     server = await HttpServer.bind('localhost', 0);
-    server.listen((request) async {
-      var webSocket = await WebSocketTransformer.upgrade(request,
-          protocolSelector: selector);
+    server.listen((HttpRequest request) async {
+      final webSocket = await WebSocketTransformer.upgrade(
+        request,
+        protocolSelector: selector,
+      );
       expect(webSocket.protocol, passedProtocol);
       await webSocket.close();
     });
 
-    var channel = IOWebSocketChannel.connect('ws://localhost:${server.port}',
+    final channel = IOWebSocketChannel.connect('ws://localhost:${server.port}',
         protocols: [passedProtocol]);
     await channel.stream.drain();
     expect(channel.protocol, passedProtocol);
diff --git a/test/web_socket_test.dart b/test/web_socket_test.dart
index be22850..f9873e0 100644
--- a/test/web_socket_test.dart
+++ b/test/web_socket_test.dart
@@ -14,7 +14,7 @@
 void main() {
   group('using WebSocketChannel', () {
     test('a client can communicate with a WebSocket server', () async {
-      var server = await HttpServer.bind('localhost', 0);
+      final server = await HttpServer.bind('localhost', 0);
       server.transform(WebSocketTransformer()).listen((webSocket) {
         webSocket.add('hello!');
         webSocket.listen((request) {
@@ -24,8 +24,8 @@
         });
       });
 
-      var client = HttpClient();
-      var request = await client.openUrl(
+      final client = HttpClient();
+      final request = await client.openUrl(
           'GET', Uri.parse('http://localhost:${server.port}'));
       request.headers
         ..set('Connection', 'Upgrade')
@@ -33,10 +33,10 @@
         ..set('Sec-WebSocket-Key', 'x3JJHMbDL1EzLkh9GBhXDw==')
         ..set('Sec-WebSocket-Version', '13');
 
-      var response = await request.close();
-      var socket = await response.detachSocket();
-      var innerChannel = StreamChannel<List<int>>(socket, socket);
-      var webSocket = WebSocketChannel(innerChannel, serverSide: false);
+      final response = await request.close();
+      final socket = await response.detachSocket();
+      final innerChannel = StreamChannel<List<int>>(socket, socket);
+      final webSocket = WebSocketChannel(innerChannel, serverSide: false);
 
       var n = 0;
       await webSocket.stream.listen((message) {
@@ -55,9 +55,9 @@
     });
 
     test('a server can communicate with a WebSocket client', () async {
-      var server = await HttpServer.bind('localhost', 0);
+      final server = await HttpServer.bind('localhost', 0);
       server.listen((request) async {
-        var response = request.response;
+        final response = request.response;
         response.statusCode = 101;
         response.headers
           ..set('Connection', 'Upgrade')
@@ -68,18 +68,19 @@
                   request.headers.value('Sec-WebSocket-Key')));
         response.contentLength = 0;
 
-        var socket = await response.detachSocket();
-        var innerChannel = StreamChannel<List<int>>(socket, socket);
-        var webSocket = WebSocketChannel(innerChannel);
+        final socket = await response.detachSocket();
+        final innerChannel = StreamChannel<List<int>>(socket, socket);
+        final webSocket = WebSocketChannel(innerChannel);
         webSocket.sink.add('hello!');
 
-        var message = await webSocket.stream.first;
+        final message = await webSocket.stream.first;
         expect(message, equals('ping'));
         webSocket.sink.add('pong');
         await webSocket.sink.close();
       });
 
-      var webSocket = await WebSocket.connect('ws://localhost:${server.port}');
+      final webSocket =
+          await WebSocket.connect('ws://localhost:${server.port}');
       var n = 0;
       await webSocket.listen((message) {
         if (n == 0) {