Enforce package:pedantic lints (#41)

diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..bff1a74
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,5 @@
+# Defines a default set of lint rules enforced for
+# projects at Google. For details and rationale,
+# see https://github.com/dart-lang/pedantic#enabled-lints.
+include: package:pedantic/analysis_options.yaml
+
diff --git a/lib/error_code.dart b/lib/error_code.dart
index eb2d9be..4bb0808 100644
--- a/lib/error_code.dart
+++ b/lib/error_code.dart
@@ -40,15 +40,15 @@
 String name(int errorCode) {
   switch (errorCode) {
     case PARSE_ERROR:
-      return "parse error";
+      return 'parse error';
     case INVALID_REQUEST:
-      return "invalid request";
+      return 'invalid request';
     case METHOD_NOT_FOUND:
-      return "method not found";
+      return 'method not found';
     case INVALID_PARAMS:
-      return "invalid parameters";
+      return 'invalid parameters';
     case INTERNAL_ERROR:
-      return "internal error";
+      return 'internal error';
     default:
       return null;
   }
diff --git a/lib/src/channel_manager.dart b/lib/src/channel_manager.dart
index 162c9ef..5be11dd 100644
--- a/lib/src/channel_manager.dart
+++ b/lib/src/channel_manager.dart
@@ -25,7 +25,7 @@
   ///
   /// This is the same future that's returned by [listen].
   Future get done => _doneCompleter.future;
-  final _doneCompleter = new Completer.sync();
+  final _doneCompleter = Completer.sync();
 
   /// Whether the underlying communication channel is closed.
   bool get isClosed => _doneCompleter.isCompleted;
@@ -45,9 +45,9 @@
   ///
   /// The returned Future will complete when the input stream is closed. If the
   /// input stream emits an error, that will be piped to the returned Future.
-  Future listen(void handleInput(input)) {
+  Future listen(void Function(dynamic) handleInput) {
     if (_listenCalled) {
-      throw new StateError("Can only call $_name.listen() once.");
+      throw StateError('Can only call $_name.listen() once.');
     }
     _listenCalled = true;
 
diff --git a/lib/src/client.dart b/lib/src/client.dart
index ff5c803..1e421ed 100644
--- a/lib/src/client.dart
+++ b/lib/src/client.dart
@@ -28,7 +28,7 @@
   List _batch;
 
   /// The map of request ids to pending requests.
-  final _pendingRequests = new Map<int, _Request>();
+  final _pendingRequests = <int, _Request>{};
 
   /// Returns a [Future] that completes when the underlying connection is
   /// closed.
@@ -61,11 +61,11 @@
   /// Note that the client won't begin listening to [responses] until
   /// [Client.listen] is called.
   Client.withoutJson(StreamChannel channel)
-      : _manager = new ChannelManager("Client", channel) {
+      : _manager = ChannelManager('Client', channel) {
     _manager.done.whenComplete(() {
       for (var request in _pendingRequests.values) {
         request.completer.completeError(
-            new StateError(
+            StateError(
                 'The client closed with pending request "${request.method}".'),
             StackTrace.current);
       }
@@ -106,8 +106,8 @@
     var id = _id++;
     _send(method, parameters, id);
 
-    var completer = new Completer.sync();
-    _pendingRequests[id] = new _Request(method, completer, new Chain.current());
+    var completer = Completer.sync();
+    _pendingRequests[id] = _Request(method, completer, Chain.current());
     return completer.future;
   }
 
@@ -133,14 +133,14 @@
   void _send(String method, parameters, [int id]) {
     if (parameters is Iterable) parameters = parameters.toList();
     if (parameters is! Map && parameters is! List && parameters != null) {
-      throw new ArgumentError('Only maps and lists may be used as JSON-RPC '
+      throw ArgumentError('Only maps and lists may be used as JSON-RPC '
           'parameters, was "$parameters".');
     }
-    if (isClosed) throw new StateError("The client is closed.");
+    if (isClosed) throw StateError('The client is closed.');
 
-    var message = <String, dynamic>{"jsonrpc": "2.0", "method": method};
-    if (id != null) message["id"] = id;
-    if (parameters != null) message["params"] = parameters;
+    var message = <String, dynamic>{'jsonrpc': '2.0', 'method': method};
+    if (id != null) message['id'] = id;
+    if (parameters != null) message['params'] = parameters;
 
     if (_batch != null) {
       _batch.add(message);
@@ -161,7 +161,7 @@
   /// If this is called in the context of another [withBatch] call, it just
   /// invokes [callback] without creating another batch. This means that
   /// responses are batched until the first batch ends.
-  withBatch(callback()) {
+  void withBatch(Function() callback) {
     if (_batch != null) return callback();
 
     _batch = [];
@@ -184,14 +184,13 @@
   /// resolved.
   void _handleSingleResponse(response) {
     if (!_isResponseValid(response)) return;
-    var request = _pendingRequests.remove(response["id"]);
-    if (response.containsKey("result")) {
-      request.completer.complete(response["result"]);
+    var request = _pendingRequests.remove(response['id']);
+    if (response.containsKey('result')) {
+      request.completer.complete(response['result']);
     } else {
       request.completer.completeError(
-          new RpcException(
-              response["error"]["code"], response["error"]["message"],
-              data: response["error"]["data"]),
+          RpcException(response['error']['code'], response['error']['message'],
+              data: response['error']['data']),
           request.chain);
     }
   }
@@ -199,15 +198,15 @@
   /// Determines whether the server's response is valid per the spec.
   bool _isResponseValid(response) {
     if (response is! Map) return false;
-    if (response["jsonrpc"] != "2.0") return false;
-    if (!_pendingRequests.containsKey(response["id"])) return false;
-    if (response.containsKey("result")) return true;
+    if (response['jsonrpc'] != '2.0') return false;
+    if (!_pendingRequests.containsKey(response['id'])) return false;
+    if (response.containsKey('result')) return true;
 
-    if (!response.containsKey("error")) return false;
-    var error = response["error"];
+    if (!response.containsKey('error')) return false;
+    var error = response['error'];
     if (error is! Map) return false;
-    if (error["code"] is! int) return false;
-    if (error["message"] is! String) return false;
+    if (error['code'] is! int) return false;
+    if (error['message'] is! String) return false;
     return true;
   }
 }
diff --git a/lib/src/exception.dart b/lib/src/exception.dart
index b359155..64c97d0 100644
--- a/lib/src/exception.dart
+++ b/lib/src/exception.dart
@@ -43,10 +43,10 @@
 
   /// Converts this exception into a JSON-serializable object that's a valid
   /// JSON-RPC 2.0 error response.
-  serialize(request) {
+  Map<String, dynamic> serialize(request) {
     var modifiedData;
     if (data is Map && !data.containsKey('request')) {
-      modifiedData = new Map.from(data);
+      modifiedData = Map.from(data);
       modifiedData['request'] = request;
     } else if (data == null) {
       modifiedData = {'request': request};
@@ -63,10 +63,11 @@
     };
   }
 
+  @override
   String toString() {
-    var prefix = "JSON-RPC error $code";
+    var prefix = 'JSON-RPC error $code';
     var errorName = error_code.name(code);
-    if (errorName != null) prefix += " ($errorName)";
-    return "$prefix: $message";
+    if (errorName != null) prefix += ' ($errorName)';
+    return '$prefix: $message';
   }
 }
diff --git a/lib/src/parameters.dart b/lib/src/parameters.dart
index 8b39d46..665765b 100644
--- a/lib/src/parameters.dart
+++ b/lib/src/parameters.dart
@@ -26,7 +26,7 @@
   ///
   /// If this is accessed for a [Parameter] that was not passed, the request
   /// will be automatically rejected. To avoid this, use [Parameter.valueOr].
-  get value => _value;
+  dynamic get value => _value;
   final _value;
 
   Parameters(this.method, this._value);
@@ -48,19 +48,19 @@
     if (key is int) {
       _assertPositional();
       if (key < value.length) {
-        return new Parameter._(method, value[key], this, key);
+        return Parameter._(method, value[key], this, key);
       } else {
-        return new _MissingParameter(method, this, key);
+        return _MissingParameter(method, this, key);
       }
     } else if (key is String) {
       _assertNamed();
       if (value.containsKey(key)) {
-        return new Parameter._(method, value[key], this, key);
+        return Parameter._(method, value[key], this, key);
       } else {
-        return new _MissingParameter(method, this, key);
+        return _MissingParameter(method, this, key);
       }
     } else {
-      throw new ArgumentError('Parameters[] only takes an int or a string, was '
+      throw ArgumentError('Parameters[] only takes an int or a string, was '
           '"$key".');
     }
   }
@@ -80,14 +80,14 @@
   /// Asserts that [value] is a positional argument list.
   void _assertPositional() {
     if (value is List) return;
-    throw new RpcException.invalidParams('Parameters for method "$method" '
+    throw RpcException.invalidParams('Parameters for method "$method" '
         'must be passed by position.');
   }
 
   /// Asserts that [value] is a named argument map.
   void _assertNamed() {
     if (value is Map) return;
-    throw new RpcException.invalidParams('Parameters for method "$method" '
+    throw RpcException.invalidParams('Parameters for method "$method" '
         'must be passed by name.');
   }
 }
@@ -131,20 +131,20 @@
       return _key is int ? (_key + 1).toString() : jsonEncode(_key);
     }
 
-    quoteKey(key) {
-      if (key.contains(new RegExp(r'[^a-zA-Z0-9_-]'))) return jsonEncode(key);
+    String quoteKey(key) {
+      if (key.contains(RegExp(r'[^a-zA-Z0-9_-]'))) return jsonEncode(key);
       return key;
     }
 
-    computePath(params) {
+    String computePath(params) {
       if (params._parent is! Parameter) {
-        return params._key is int ? "[${params._key}]" : quoteKey(params._key);
+        return params._key is int ? '[${params._key}]' : quoteKey(params._key);
       }
 
       var path = computePath(params._parent);
       return params._key is int
-          ? "$path[${params._key}]"
-          : "$path.${quoteKey(params._key)}";
+          ? '$path[${params._key}]'
+          : '$path.${quoteKey(params._key)}';
     }
 
     return computePath(this);
@@ -157,7 +157,7 @@
       : super(method, value);
 
   /// Returns [value], or [defaultValue] if this parameter wasn't passed.
-  valueOr(defaultValue) => value;
+  dynamic valueOr(defaultValue) => value;
 
   /// Asserts that [value] exists and is a number and returns it.
   ///
@@ -215,6 +215,7 @@
   ///
   /// [asListOr] may be used to provide a default value instead of rejecting the
   /// request if [value] doesn't exist.
+  @override
   List get asList => _getTyped('an Array', (value) => value is List);
 
   /// Asserts that [value] is a [List] and returns it.
@@ -226,6 +227,7 @@
   ///
   /// [asMapOr] may be used to provide a default value instead of rejecting the
   /// request if [value] doesn't exist.
+  @override
   Map get asMap => _getTyped('an Object', (value) => value is Map);
 
   /// Asserts that [value] is a [Map] and returns it.
@@ -264,13 +266,13 @@
   ///
   /// [type] is used for the error message. It should begin with an indefinite
   /// article.
-  _getTyped(String type, bool test(value)) {
+  dynamic _getTyped(String type, bool Function(dynamic) test) {
     if (test(value)) return value;
-    throw new RpcException.invalidParams('Parameter $_path for method '
+    throw RpcException.invalidParams('Parameter $_path for method '
         '"$method" must be $type, but was ${jsonEncode(value)}.');
   }
 
-  _getParsed(String description, parse(String value)) {
+  dynamic _getParsed(String description, Function(String) parse) {
     var string = asString;
     try {
       return parse(string);
@@ -285,17 +287,19 @@
         message = '\n$message';
       }
 
-      throw new RpcException.invalidParams('Parameter $_path for method '
+      throw RpcException.invalidParams('Parameter $_path for method '
           '"$method" must be a valid $description, but was '
           '${jsonEncode(string)}.$message');
     }
   }
 
+  @override
   void _assertPositional() {
     // Throw the standard exception for a mis-typed list.
     asList;
   }
 
+  @override
   void _assertNamed() {
     // Throw the standard exception for a mis-typed map.
     asMap;
@@ -304,31 +308,42 @@
 
 /// A subclass of [Parameter] representing a missing parameter.
 class _MissingParameter extends Parameter {
-  get value {
-    throw new RpcException.invalidParams('Request for method "$method" is '
+  @override
+  dynamic get value {
+    throw RpcException.invalidParams('Request for method "$method" is '
         'missing required parameter $_path.');
   }
 
+  @override
   bool get exists => false;
 
   _MissingParameter(String method, Parameters parent, key)
       : super._(method, null, parent, key);
 
-  valueOr(defaultValue) => defaultValue;
+  @override
+  dynamic valueOr(defaultValue) => defaultValue;
 
+  @override
   num asNumOr(num defaultValue) => defaultValue;
 
+  @override
   int asIntOr(int defaultValue) => defaultValue;
 
+  @override
   bool asBoolOr(bool defaultValue) => defaultValue;
 
+  @override
   String asStringOr(String defaultValue) => defaultValue;
 
+  @override
   List asListOr(List defaultValue) => defaultValue;
 
+  @override
   Map asMapOr(Map defaultValue) => defaultValue;
 
+  @override
   DateTime asDateTimeOr(DateTime defaultValue) => defaultValue;
 
+  @override
   Uri asUriOr(Uri defaultValue) => defaultValue;
 }
diff --git a/lib/src/peer.dart b/lib/src/peer.dart
index 7176763..cd51a7c 100644
--- a/lib/src/peer.dart
+++ b/lib/src/peer.dart
@@ -30,13 +30,15 @@
 
   /// A stream controller that forwards incoming messages to [_server] if
   /// they're requests.
-  final _serverIncomingForwarder = new StreamController(sync: true);
+  final _serverIncomingForwarder = StreamController(sync: true);
 
   /// A stream controller that forwards incoming messages to [_client] if
   /// they're responses.
-  final _clientIncomingForwarder = new StreamController(sync: true);
+  final _clientIncomingForwarder = StreamController(sync: true);
 
+  @override
   Future get done => _manager.done;
+  @override
   bool get isClosed => _manager.isClosed;
 
   @override
@@ -65,34 +67,40 @@
   /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
   /// If this is not provided, unhandled exceptions will be swallowed.
   Peer.withoutJson(StreamChannel channel, {ErrorCallback onUnhandledError})
-      : _manager = new ChannelManager("Peer", channel) {
-    _server = new Server.withoutJson(
-        new StreamChannel(_serverIncomingForwarder.stream, channel.sink),
+      : _manager = ChannelManager('Peer', channel) {
+    _server = Server.withoutJson(
+        StreamChannel(_serverIncomingForwarder.stream, channel.sink),
         onUnhandledError: onUnhandledError);
-    _client = new Client.withoutJson(
-        new StreamChannel(_clientIncomingForwarder.stream, channel.sink));
+    _client = Client.withoutJson(
+        StreamChannel(_clientIncomingForwarder.stream, channel.sink));
   }
 
   // Client methods.
 
+  @override
   Future sendRequest(String method, [parameters]) =>
       _client.sendRequest(method, parameters);
 
+  @override
   void sendNotification(String method, [parameters]) =>
       _client.sendNotification(method, parameters);
 
-  withBatch(callback()) => _client.withBatch(callback);
+  @override
+  void withBatch(Function() callback) => _client.withBatch(callback);
 
   // Server methods.
 
+  @override
   void registerMethod(String name, Function callback) =>
       _server.registerMethod(name, callback);
 
-  void registerFallback(callback(Parameters parameters)) =>
+  @override
+  void registerFallback(Function(Parameters parameters) callback) =>
       _server.registerFallback(callback);
 
   // Shared methods.
 
+  @override
   Future listen() {
     _client.listen();
     _server.listen();
@@ -120,6 +128,7 @@
     });
   }
 
+  @override
   Future close() =>
       Future.wait([_client.close(), _server.close(), _manager.close()]);
 }
diff --git a/lib/src/server.dart b/lib/src/server.dart
index 5c3b132..30da924 100644
--- a/lib/src/server.dart
+++ b/lib/src/server.dart
@@ -32,13 +32,13 @@
   final ChannelManager _manager;
 
   /// The methods registered for this server.
-  final _methods = new Map<String, Function>();
+  final _methods = <String, Function>{};
 
   /// The fallback methods for this server.
   ///
   /// These are tried in order until one of them doesn't throw a
   /// [RpcException.methodNotFound] exception.
-  final _fallbacks = new Queue<Function>();
+  final _fallbacks = Queue<Function>();
 
   /// Returns a [Future] that completes when the underlying connection is
   /// closed.
@@ -85,7 +85,7 @@
   /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
   /// If this is not provided, unhandled exceptions will be swallowed.
   Server.withoutJson(StreamChannel channel, {this.onUnhandledError})
-      : _manager = new ChannelManager("Server", channel);
+      : _manager = ChannelManager('Server', channel);
 
   /// Starts listening to the underlying stream.
   ///
@@ -112,7 +112,7 @@
   /// reported to the client as JSON-RPC 2.0 errors.
   void registerMethod(String name, Function callback) {
     if (_methods.containsKey(name)) {
-      throw new ArgumentError('There\'s already a method named "$name".');
+      throw ArgumentError('There\'s already a method named "$name".');
     }
 
     _methods[name] = callback;
@@ -129,7 +129,7 @@
   /// completes to a JSON-serializable object. Any errors in [callback] will be
   /// reported to the client as JSON-RPC 2.0 errors. [callback] may send custom
   /// errors by throwing an [RpcException].
-  void registerFallback(callback(Parameters parameters)) {
+  void registerFallback(Function(Parameters parameters) callback) {
     _fallbacks.add(callback);
   }
 
@@ -144,7 +144,7 @@
     var response;
     if (request is List) {
       if (request.isEmpty) {
-        response = new RpcException(error_code.INVALID_REQUEST,
+        response = RpcException(error_code.INVALID_REQUEST,
                 'A batch must contain at least one request.')
             .serialize(request);
       } else {
@@ -168,17 +168,17 @@
 
       var name = request['method'];
       var method = _methods[name];
-      if (method == null) method = _tryFallbacks;
+      method ??= _tryFallbacks;
 
       Object result;
       if (method is ZeroArgumentFunction) {
         if (request.containsKey('params')) {
-          throw new RpcException.invalidParams('No parameters are allowed for '
+          throw RpcException.invalidParams('No parameters are allowed for '
               'method "$name".');
         }
         result = await method();
       } else {
-        result = await method(new Parameters(name, request['params']));
+        result = await method(Parameters(name, request['params']));
       }
 
       // A request without an id is a notification, which should not be sent a
@@ -199,8 +199,8 @@
         onUnhandledError?.call(error, stackTrace);
         return null;
       }
-      final chain = new Chain.forTrace(stackTrace);
-      return new RpcException(error_code.SERVER_ERROR, getErrorMessage(error),
+      final chain = Chain.forTrace(stackTrace);
+      return RpcException(error_code.SERVER_ERROR, getErrorMessage(error),
           data: {
             'full': '$error',
             'stack': '$chain',
@@ -211,28 +211,28 @@
   /// Validates that [request] matches the JSON-RPC spec.
   void _validateRequest(request) {
     if (request is! Map) {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Request must be '
           'an Array or an Object.');
     }
 
     if (!request.containsKey('jsonrpc')) {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Request must '
           'contain a "jsonrpc" key.');
     }
 
     if (request['jsonrpc'] != '2.0') {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Invalid JSON-RPC '
           'version ${jsonEncode(request['jsonrpc'])}, expected "2.0".');
     }
 
     if (!request.containsKey('method')) {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Request must '
           'contain a "method" key.');
@@ -240,7 +240,7 @@
 
     var method = request['method'];
     if (request['method'] is! String) {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Request method must '
           'be a string, but was ${jsonEncode(method)}.');
@@ -248,7 +248,7 @@
 
     var params = request['params'];
     if (request.containsKey('params') && params is! List && params is! Map) {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Request params must '
           'be an Array or an Object, but was ${jsonEncode(params)}.');
@@ -256,7 +256,7 @@
 
     var id = request['id'];
     if (id != null && id is! String && id is! num) {
-      throw new RpcException(
+      throw RpcException(
           error_code.INVALID_REQUEST,
           'Request id must be a '
           'string, number, or null, but was ${jsonEncode(id)}.');
@@ -267,16 +267,16 @@
   Future _tryFallbacks(Parameters params) {
     var iterator = _fallbacks.toList().iterator;
 
-    _tryNext() async {
+    Future _tryNext() async {
       if (!iterator.moveNext()) {
-        throw new RpcException.methodNotFound(params.method);
+        throw RpcException.methodNotFound(params.method);
       }
 
       try {
         return iterator.current(params);
       } on RpcException catch (error) {
-        if (error is! RpcException) throw error;
-        if (error.code != error_code.METHOD_NOT_FOUND) throw error;
+        if (error is! RpcException) rethrow;
+        if (error.code != error_code.METHOD_NOT_FOUND) rethrow;
         return _tryNext();
       }
     }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 1e2d6b1..f1989a7 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -9,7 +9,7 @@
 import '../error_code.dart' as error_code;
 import 'exception.dart';
 
-typedef ZeroArgumentFunction();
+typedef ZeroArgumentFunction = Function();
 
 /// Returns a sentence fragment listing the elements of [iter].
 ///
@@ -17,7 +17,7 @@
 /// commas and/or "and" where appropriate.
 String toSentence(Iterable iter) {
   if (iter.length == 1) return iter.first.toString();
-  return iter.take(iter.length - 1).join(", ") + " and ${iter.last}";
+  return iter.take(iter.length - 1).join(', ') + ' and ${iter.last}';
 }
 
 /// Returns [name] if [number] is 1, or the plural of [name] otherwise.
@@ -32,7 +32,7 @@
 
 /// A regular expression to match the exception prefix that some exceptions'
 /// [Object.toString] values contain.
-final _exceptionPrefix = new RegExp(r'^([A-Z][a-zA-Z]*)?(Exception|Error): ');
+final _exceptionPrefix = RegExp(r'^([A-Z][a-zA-Z]*)?(Exception|Error): ');
 
 /// Get a string description of an exception.
 ///
@@ -46,7 +46,7 @@
 ///
 /// This is synchronicity-agnostic relative to [body]. If [body] returns a
 /// [Future], this wil run asynchronously; otherwise it will run synchronously.
-tryFinally(body(), whenComplete()) {
+void tryFinally(Function() body, Function() whenComplete) {
   var result;
   try {
     result = body();
@@ -64,27 +64,27 @@
 }
 
 /// A transformer that silently drops [FormatException]s.
-final ignoreFormatExceptions =
-    new StreamTransformer<Object, Object>.fromHandlers(
-        handleError: (error, stackTrace, sink) {
+final ignoreFormatExceptions = StreamTransformer<Object, Object>.fromHandlers(
+    handleError: (error, stackTrace, sink) {
   if (error is FormatException) return;
   sink.addError(error, stackTrace);
 });
 
 /// A transformer that sends error responses on [FormatException]s.
 final StreamChannelTransformer respondToFormatExceptions =
-    new _RespondToFormatExceptionsTransformer();
+    _RespondToFormatExceptionsTransformer();
 
 /// The implementation of [respondToFormatExceptions].
 class _RespondToFormatExceptionsTransformer
     implements StreamChannelTransformer {
+  @override
   StreamChannel bind(StreamChannel channel) {
     var transformed;
     transformed = channel.changeStream((stream) {
       return stream.handleError((error) {
         if (error is! FormatException) throw error;
 
-        var exception = new RpcException(
+        var exception = RpcException(
             error_code.PARSE_ERROR, 'Invalid JSON: ${error.message}');
         transformed.sink.add(exception.serialize(error.source));
       });
@@ -95,21 +95,26 @@
 
 /// Returns a [StreamSink] that wraps [sink] and maps each event added using
 /// [callback].
-StreamSink mapStreamSink(StreamSink sink, callback(event)) =>
-    new _MappedStreamSink(sink, callback);
+StreamSink mapStreamSink(StreamSink sink, Function(dynamic) callback) =>
+    _MappedStreamSink(sink, callback);
 
 /// A [StreamSink] wrapper that maps each event added to the sink.
 class _MappedStreamSink implements StreamSink {
   final StreamSink _inner;
   final Function _callback;
 
+  @override
   Future get done => _inner.done;
 
   _MappedStreamSink(this._inner, this._callback);
 
+  @override
   void add(event) => _inner.add(_callback(event));
+  @override
   void addError(error, [StackTrace stackTrace]) =>
       _inner.addError(error, stackTrace);
+  @override
   Future addStream(Stream stream) => _inner.addStream(stream.map(_callback));
+  @override
   Future close() => _inner.close();
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 40c0293..5e8e29c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -13,4 +13,5 @@
   stream_channel: ">=1.1.0 <3.0.0"
 
 dev_dependencies:
+  pedantic: ^1.8.0
   test: ^1.0.0
diff --git a/test/client/client_test.dart b/test/client/client_test.dart
index 358247d..c1edbe4 100644
--- a/test/client/client_test.dart
+++ b/test/client/client_test.dart
@@ -12,9 +12,9 @@
 
 void main() {
   var controller;
-  setUp(() => controller = new ClientController());
+  setUp(() => controller = ClientController());
 
-  test("sends a message and returns the response", () {
+  test('sends a message and returns the response', () {
     controller.expectRequest((request) {
       expect(
           request,
@@ -27,11 +27,11 @@
       return {'jsonrpc': '2.0', 'result': 'bar', 'id': request['id']};
     });
 
-    expect(controller.client.sendRequest("foo", {'param': 'value'}),
+    expect(controller.client.sendRequest('foo', {'param': 'value'}),
         completion(equals('bar')));
   });
 
-  test("sends a notification and expects no response", () {
+  test('sends a notification and expects no response', () {
     controller.expectRequest((request) {
       expect(
           request,
@@ -42,10 +42,10 @@
           }));
     });
 
-    controller.client.sendNotification("foo", {'param': 'value'});
+    controller.client.sendNotification('foo', {'param': 'value'});
   });
 
-  test("sends a notification with positional parameters", () {
+  test('sends a notification with positional parameters', () {
     controller.expectRequest((request) {
       expect(
           request,
@@ -56,20 +56,20 @@
           }));
     });
 
-    controller.client.sendNotification("foo", ['value1', 'value2']);
+    controller.client.sendNotification('foo', ['value1', 'value2']);
   });
 
-  test("sends a notification with no parameters", () {
+  test('sends a notification with no parameters', () {
     controller.expectRequest((request) {
       expect(request, equals({'jsonrpc': '2.0', 'method': 'foo'}));
     });
 
-    controller.client.sendNotification("foo");
+    controller.client.sendNotification('foo');
   });
 
-  test("sends a synchronous batch of requests", () {
+  test('sends a synchronous batch of requests', () {
     controller.expectRequest((request) {
-      expect(request, new TypeMatcher<List>());
+      expect(request, TypeMatcher<List>());
       expect(request, hasLength(3));
       expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'}));
       expect(
@@ -91,17 +91,17 @@
     });
 
     controller.client.withBatch(() {
-      controller.client.sendNotification("foo");
-      expect(controller.client.sendRequest("bar", {'param': 'value'}),
-          completion(equals("bar response")));
-      expect(controller.client.sendRequest("baz"),
-          completion(equals("baz response")));
+      controller.client.sendNotification('foo');
+      expect(controller.client.sendRequest('bar', {'param': 'value'}),
+          completion(equals('bar response')));
+      expect(controller.client.sendRequest('baz'),
+          completion(equals('baz response')));
     });
   });
 
-  test("sends an asynchronous batch of requests", () {
+  test('sends an asynchronous batch of requests', () {
     controller.expectRequest((request) {
-      expect(request, new TypeMatcher<List>());
+      expect(request, TypeMatcher<List>());
       expect(request, hasLength(3));
       expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'}));
       expect(
@@ -123,21 +123,21 @@
     });
 
     controller.client.withBatch(() {
-      return new Future.value().then((_) {
-        controller.client.sendNotification("foo");
-        return new Future.value();
+      return Future.value().then((_) {
+        controller.client.sendNotification('foo');
+        return Future.value();
       }).then((_) {
-        expect(controller.client.sendRequest("bar", {'param': 'value'}),
-            completion(equals("bar response")));
-        return new Future.value();
+        expect(controller.client.sendRequest('bar', {'param': 'value'}),
+            completion(equals('bar response')));
+        return Future.value();
       }).then((_) {
-        expect(controller.client.sendRequest("baz"),
-            completion(equals("baz response")));
+        expect(controller.client.sendRequest('baz'),
+            completion(equals('baz response')));
       });
     });
   });
 
-  test("reports an error from the server", () {
+  test('reports an error from the server', () {
     controller.expectRequest((request) {
       expect(
           request,
@@ -155,9 +155,9 @@
       };
     });
 
-    expect(controller.client.sendRequest("foo", {'param': 'value'}),
+    expect(controller.client.sendRequest('foo', {'param': 'value'}),
         throwsA(predicate((exception) {
-      expect(exception, new TypeMatcher<json_rpc.RpcException>());
+      expect(exception, TypeMatcher<json_rpc.RpcException>());
       expect(exception.code, equals(error_code.SERVER_ERROR));
       expect(exception.message, equals('you are bad at requests'));
       expect(exception.data, equals('some junk'));
@@ -165,17 +165,17 @@
     })));
   });
 
-  test("requests throw StateErrors if the client is closed", () {
+  test('requests throw StateErrors if the client is closed', () {
     controller.client.close();
-    expect(() => controller.client.sendRequest("foo"), throwsStateError);
-    expect(() => controller.client.sendNotification("foo"), throwsStateError);
+    expect(() => controller.client.sendRequest('foo'), throwsStateError);
+    expect(() => controller.client.sendNotification('foo'), throwsStateError);
   });
 
-  test("ignores bogus responses", () {
+  test('ignores bogus responses', () {
     // Make a request so we have something to respond to.
     controller.expectRequest((request) {
-      controller.sendJsonResponse("{invalid");
-      controller.sendResponse("not a map");
+      controller.sendJsonResponse('{invalid');
+      controller.sendResponse('not a map');
       controller.sendResponse(
           {'jsonrpc': 'wrong version', 'result': 'wrong', 'id': request['id']});
       controller.sendResponse({'jsonrpc': '2.0', 'result': 'wrong'});
@@ -197,6 +197,6 @@
           (_) => {'jsonrpc': '2.0', 'result': 'right', 'id': request['id']});
     });
 
-    expect(controller.client.sendRequest("foo"), completion(equals('right')));
+    expect(controller.client.sendRequest('foo'), completion(equals('right')));
   });
 }
diff --git a/test/client/stream_test.dart b/test/client/stream_test.dart
index 94a0604..4080064 100644
--- a/test/client/stream_test.dart
+++ b/test/client/stream_test.dart
@@ -14,13 +14,13 @@
   var requestController;
   var client;
   setUp(() {
-    responseController = new StreamController();
-    requestController = new StreamController();
-    client = new json_rpc.Client.withoutJson(
-        new StreamChannel(responseController.stream, requestController.sink));
+    responseController = StreamController();
+    requestController = StreamController();
+    client = json_rpc.Client.withoutJson(
+        StreamChannel(responseController.stream, requestController.sink));
   });
 
-  test(".withoutJson supports decoded stream and sink", () {
+  test('.withoutJson supports decoded stream and sink', () {
     client.listen();
 
     expect(requestController.stream.first.then((request) {
@@ -36,7 +36,7 @@
     client.sendRequest('foo');
   });
 
-  test(".listen returns when the controller is closed", () {
+  test('.listen returns when the controller is closed', () {
     var hasListenCompeted = false;
     expect(client.listen().then((_) => hasListenCompeted = true), completes);
 
@@ -48,17 +48,17 @@
     });
   });
 
-  test(".listen returns a stream error", () {
+  test('.listen returns a stream error', () {
     expect(client.listen(), throwsA('oh no'));
     responseController.addError('oh no');
   });
 
-  test(".listen can't be called twice", () {
+  test('.listen can\'t be called twice', () {
     client.listen();
     expect(() => client.listen(), throwsStateError);
   });
 
-  test(".close cancels the stream subscription and closes the sink", () {
+  test('.close cancels the stream subscription and closes the sink', () {
     // Work around sdk#19095.
     requestController.stream.listen(null);
 
@@ -72,22 +72,22 @@
     expect(requestController.isClosed, isTrue);
   });
 
-  group("a stream error", () {
-    test("is reported through .done", () {
-      expect(client.listen(), throwsA("oh no!"));
-      expect(client.done, throwsA("oh no!"));
-      responseController.addError("oh no!");
+  group('a stream error', () {
+    test('is reported through .done', () {
+      expect(client.listen(), throwsA('oh no!'));
+      expect(client.done, throwsA('oh no!'));
+      responseController.addError('oh no!');
     });
 
-    test("cause a pending request to throw a StateError", () {
-      expect(client.listen(), throwsA("oh no!"));
+    test('cause a pending request to throw a StateError', () {
+      expect(client.listen(), throwsA('oh no!'));
       expect(client.sendRequest('foo'), throwsStateError);
-      responseController.addError("oh no!");
+      responseController.addError('oh no!');
     });
 
-    test("causes future requests to throw StateErrors", () async {
-      expect(client.listen(), throwsA("oh no!"));
-      responseController.addError("oh no!");
+    test('causes future requests to throw StateErrors', () async {
+      expect(client.listen(), throwsA('oh no!'));
+      responseController.addError('oh no!');
       await pumpEventQueue();
 
       expect(() => client.sendRequest('foo'), throwsStateError);
diff --git a/test/client/utils.dart b/test/client/utils.dart
index 8a0a9a3..1684b37 100644
--- a/test/client/utils.dart
+++ b/test/client/utils.dart
@@ -13,18 +13,18 @@
 /// A controller used to test a [json_rpc.Client].
 class ClientController {
   /// The controller for the client's response stream.
-  final _responseController = new StreamController<String>();
+  final _responseController = StreamController<String>();
 
   /// The controller for the client's request sink.
-  final _requestController = new StreamController<String>();
+  final _requestController = StreamController<String>();
 
   /// The client.
   json_rpc.Client get client => _client;
   json_rpc.Client _client;
 
   ClientController() {
-    _client = new json_rpc.Client(
-        new StreamChannel(_responseController.stream, _requestController.sink));
+    _client = json_rpc.Client(
+        StreamChannel(_responseController.stream, _requestController.sink));
     _client.listen();
   }
 
@@ -34,7 +34,7 @@
   /// returns a String, that's sent as the response directly. If it returns
   /// null, no response is sent. Otherwise, the return value is encoded and sent
   /// as the response.
-  void expectRequest(callback(request)) {
+  void expectRequest(Function(dynamic) callback) {
     expect(
         _requestController.stream.first.then((request) {
           return callback(jsonDecode(request));
diff --git a/test/peer_test.dart b/test/peer_test.dart
index 491526f..33184b0 100644
--- a/test/peer_test.dart
+++ b/test/peer_test.dart
@@ -16,62 +16,62 @@
   var outgoing;
   var peer;
   setUp(() {
-    var incomingController = new StreamController();
+    var incomingController = StreamController();
     incoming = incomingController.sink;
-    var outgoingController = new StreamController();
+    var outgoingController = StreamController();
     outgoing = outgoingController.stream;
-    peer = new json_rpc.Peer.withoutJson(
-        new StreamChannel(incomingController.stream, outgoingController));
+    peer = json_rpc.Peer.withoutJson(
+        StreamChannel(incomingController.stream, outgoingController));
   });
 
-  group("like a client,", () {
-    test("can send a message and receive a response", () {
+  group('like a client,', () {
+    test('can send a message and receive a response', () {
       expect(outgoing.first.then((request) {
         expect(
             request,
             equals({
-              "jsonrpc": "2.0",
-              "method": "foo",
-              "params": {"bar": "baz"},
-              "id": 0
+              'jsonrpc': '2.0',
+              'method': 'foo',
+              'params': {'bar': 'baz'},
+              'id': 0
             }));
-        incoming.add({"jsonrpc": "2.0", "result": "qux", "id": 0});
+        incoming.add({'jsonrpc': '2.0', 'result': 'qux', 'id': 0});
       }), completes);
 
       peer.listen();
       expect(
-          peer.sendRequest("foo", {"bar": "baz"}), completion(equals("qux")));
+          peer.sendRequest('foo', {'bar': 'baz'}), completion(equals('qux')));
     });
 
-    test("can send a batch of messages and receive a batch of responses", () {
+    test('can send a batch of messages and receive a batch of responses', () {
       expect(outgoing.first.then((request) {
         expect(
             request,
             equals([
               {
-                "jsonrpc": "2.0",
-                "method": "foo",
-                "params": {"bar": "baz"},
-                "id": 0
+                'jsonrpc': '2.0',
+                'method': 'foo',
+                'params': {'bar': 'baz'},
+                'id': 0
               },
               {
-                "jsonrpc": "2.0",
-                "method": "a",
-                "params": {"b": "c"},
-                "id": 1
+                'jsonrpc': '2.0',
+                'method': 'a',
+                'params': {'b': 'c'},
+                'id': 1
               },
               {
-                "jsonrpc": "2.0",
-                "method": "w",
-                "params": {"x": "y"},
-                "id": 2
+                'jsonrpc': '2.0',
+                'method': 'w',
+                'params': {'x': 'y'},
+                'id': 2
               }
             ]));
 
         incoming.add([
-          {"jsonrpc": "2.0", "result": "qux", "id": 0},
-          {"jsonrpc": "2.0", "result": "d", "id": 1},
-          {"jsonrpc": "2.0", "result": "z", "id": 2}
+          {'jsonrpc': '2.0', 'result': 'qux', 'id': 0},
+          {'jsonrpc': '2.0', 'result': 'd', 'id': 1},
+          {'jsonrpc': '2.0', 'result': 'z', 'id': 2}
         ]);
       }), completes);
 
@@ -79,119 +79,119 @@
 
       peer.withBatch(() {
         expect(
-            peer.sendRequest("foo", {"bar": "baz"}), completion(equals("qux")));
-        expect(peer.sendRequest("a", {"b": "c"}), completion(equals("d")));
-        expect(peer.sendRequest("w", {"x": "y"}), completion(equals("z")));
+            peer.sendRequest('foo', {'bar': 'baz'}), completion(equals('qux')));
+        expect(peer.sendRequest('a', {'b': 'c'}), completion(equals('d')));
+        expect(peer.sendRequest('w', {'x': 'y'}), completion(equals('z')));
       });
     });
   });
 
-  group("like a server,", () {
-    test("can receive a call and return a response", () {
+  group('like a server,', () {
+    test('can receive a call and return a response', () {
       expect(outgoing.first,
-          completion(equals({"jsonrpc": "2.0", "result": "qux", "id": 0})));
+          completion(equals({'jsonrpc': '2.0', 'result': 'qux', 'id': 0})));
 
-      peer.registerMethod("foo", (_) => "qux");
+      peer.registerMethod('foo', (_) => 'qux');
       peer.listen();
 
       incoming.add({
-        "jsonrpc": "2.0",
-        "method": "foo",
-        "params": {"bar": "baz"},
-        "id": 0
+        'jsonrpc': '2.0',
+        'method': 'foo',
+        'params': {'bar': 'baz'},
+        'id': 0
       });
     });
 
-    test("can receive a batch of calls and return a batch of responses", () {
+    test('can receive a batch of calls and return a batch of responses', () {
       expect(
           outgoing.first,
           completion(equals([
-            {"jsonrpc": "2.0", "result": "qux", "id": 0},
-            {"jsonrpc": "2.0", "result": "d", "id": 1},
-            {"jsonrpc": "2.0", "result": "z", "id": 2}
+            {'jsonrpc': '2.0', 'result': 'qux', 'id': 0},
+            {'jsonrpc': '2.0', 'result': 'd', 'id': 1},
+            {'jsonrpc': '2.0', 'result': 'z', 'id': 2}
           ])));
 
-      peer.registerMethod("foo", (_) => "qux");
-      peer.registerMethod("a", (_) => "d");
-      peer.registerMethod("w", (_) => "z");
+      peer.registerMethod('foo', (_) => 'qux');
+      peer.registerMethod('a', (_) => 'd');
+      peer.registerMethod('w', (_) => 'z');
       peer.listen();
 
       incoming.add([
         {
-          "jsonrpc": "2.0",
-          "method": "foo",
-          "params": {"bar": "baz"},
-          "id": 0
+          'jsonrpc': '2.0',
+          'method': 'foo',
+          'params': {'bar': 'baz'},
+          'id': 0
         },
         {
-          "jsonrpc": "2.0",
-          "method": "a",
-          "params": {"b": "c"},
-          "id": 1
+          'jsonrpc': '2.0',
+          'method': 'a',
+          'params': {'b': 'c'},
+          'id': 1
         },
         {
-          "jsonrpc": "2.0",
-          "method": "w",
-          "params": {"x": "y"},
-          "id": 2
+          'jsonrpc': '2.0',
+          'method': 'w',
+          'params': {'x': 'y'},
+          'id': 2
         }
       ]);
     });
 
-    test("returns a response for malformed JSON", () {
-      var incomingController = new StreamController<String>();
-      var outgoingController = new StreamController<String>();
-      var jsonPeer = new json_rpc.Peer(
-          new StreamChannel(incomingController.stream, outgoingController));
+    test('returns a response for malformed JSON', () {
+      var incomingController = StreamController<String>();
+      var outgoingController = StreamController<String>();
+      var jsonPeer = json_rpc.Peer(
+          StreamChannel(incomingController.stream, outgoingController));
 
       expect(
           outgoingController.stream.first.then(jsonDecode),
           completion({
-            "jsonrpc": "2.0",
-            "error": {
+            'jsonrpc': '2.0',
+            'error': {
               'code': error_code.PARSE_ERROR,
-              "message": startsWith("Invalid JSON: "),
+              'message': startsWith('Invalid JSON: '),
               // TODO(nweiz): Always expect the source when sdk#25655 is fixed.
-              "data": {
+              'data': {
                 'request': anyOf([isNull, '{invalid'])
               }
             },
-            "id": null
+            'id': null
           }));
 
       jsonPeer.listen();
 
-      incomingController.add("{invalid");
+      incomingController.add('{invalid');
     });
 
-    test("returns a response for incorrectly-structured JSON", () {
+    test('returns a response for incorrectly-structured JSON', () {
       expect(
           outgoing.first,
           completion({
-            "jsonrpc": "2.0",
-            "error": {
+            'jsonrpc': '2.0',
+            'error': {
               'code': error_code.INVALID_REQUEST,
-              "message": 'Request must contain a "jsonrpc" key.',
-              "data": {
+              'message': 'Request must contain a "jsonrpc" key.',
+              'data': {
                 'request': {'completely': 'wrong'}
               }
             },
-            "id": null
+            'id': null
           }));
 
       peer.listen();
 
-      incoming.add({"completely": "wrong"});
+      incoming.add({'completely': 'wrong'});
     });
   });
 
-  test("can notify on unhandled errors for if the method throws", () async {
-    Exception exception = Exception('test exception');
-    var incomingController = new StreamController();
-    var outgoingController = new StreamController();
-    final Completer<Exception> completer = Completer<Exception>();
-    peer = new json_rpc.Peer.withoutJson(
-      new StreamChannel(incomingController.stream, outgoingController),
+  test('can notify on unhandled errors for if the method throws', () async {
+    var exception = Exception('test exception');
+    var incomingController = StreamController();
+    var outgoingController = StreamController();
+    final completer = Completer<Exception>();
+    peer = json_rpc.Peer.withoutJson(
+      StreamChannel(incomingController.stream, outgoingController),
       onUnhandledError: (error, stack) {
         completer.complete(error);
       },
@@ -201,7 +201,7 @@
       ..listen();
 
     incomingController.add({'jsonrpc': '2.0', 'method': 'foo'});
-    Exception receivedException = await completer.future;
+    var receivedException = await completer.future;
     expect(receivedException, equals(exception));
   });
 }
diff --git a/test/server/batch_test.dart b/test/server/batch_test.dart
index 3257256..c9411b3 100644
--- a/test/server/batch_test.dart
+++ b/test/server/batch_test.dart
@@ -10,7 +10,7 @@
 void main() {
   var controller;
   setUp(() {
-    controller = new ServerController();
+    controller = ServerController();
     controller.server
       ..registerMethod('foo', () => 'foo')
       ..registerMethod('id', (params) => params.value)
diff --git a/test/server/invalid_request_test.dart b/test/server/invalid_request_test.dart
index e62558f..4dbca0c 100644
--- a/test/server/invalid_request_test.dart
+++ b/test/server/invalid_request_test.dart
@@ -9,19 +9,19 @@
 
 void main() {
   var controller;
-  setUp(() => controller = new ServerController());
+  setUp(() => controller = ServerController());
 
-  test("a non-Array/Object request is invalid", () {
+  test('a non-Array/Object request is invalid', () {
     expectErrorResponse(controller, 'foo', error_code.INVALID_REQUEST,
         'Request must be an Array or an Object.');
   });
 
-  test("requests must have a jsonrpc key", () {
+  test('requests must have a jsonrpc key', () {
     expectErrorResponse(controller, {'method': 'foo', 'id': 1234},
         error_code.INVALID_REQUEST, 'Request must contain a "jsonrpc" key.');
   });
 
-  test("the jsonrpc version must be 2.0", () {
+  test('the jsonrpc version must be 2.0', () {
     expectErrorResponse(
         controller,
         {'jsonrpc': '1.0', 'method': 'foo', 'id': 1234},
@@ -29,12 +29,12 @@
         'Invalid JSON-RPC version "1.0", expected "2.0".');
   });
 
-  test("requests must have a method key", () {
+  test('requests must have a method key', () {
     expectErrorResponse(controller, {'jsonrpc': '2.0', 'id': 1234},
         error_code.INVALID_REQUEST, 'Request must contain a "method" key.');
   });
 
-  test("request method must be a string", () {
+  test('request method must be a string', () {
     expectErrorResponse(
         controller,
         {'jsonrpc': '2.0', 'method': 1234, 'id': 1234},
@@ -42,7 +42,7 @@
         'Request method must be a string, but was 1234.');
   });
 
-  test("request params must be an Array or Object", () {
+  test('request params must be an Array or Object', () {
     expectErrorResponse(
         controller,
         {'jsonrpc': '2.0', 'method': 'foo', 'params': 1234, 'id': 1234},
@@ -50,7 +50,7 @@
         'Request params must be an Array or an Object, but was 1234.');
   });
 
-  test("request id may not be an Array or Object", () {
+  test('request id may not be an Array or Object', () {
     expect(
         controller.handleRequest({
           'jsonrpc': '2.0',
diff --git a/test/server/parameters_test.dart b/test/server/parameters_test.dart
index c970bef..8b8d07f 100644
--- a/test/server/parameters_test.dart
+++ b/test/server/parameters_test.dart
@@ -8,231 +8,231 @@
 import 'utils.dart';
 
 void main() {
-  group("with named parameters", () {
+  group('with named parameters', () {
     var parameters;
     setUp(() {
-      parameters = new json_rpc.Parameters("foo", {
-        "num": 1.5,
-        "int": 1,
-        "bool": true,
-        "string": "zap",
-        "list": [1, 2, 3],
-        "date-time": "1990-01-01 00:00:00.000",
-        "uri": "http://dartlang.org",
-        "invalid-uri": "http://[::1",
-        "map": {"num": 4.2, "bool": false}
+      parameters = json_rpc.Parameters('foo', {
+        'num': 1.5,
+        'int': 1,
+        'bool': true,
+        'string': 'zap',
+        'list': [1, 2, 3],
+        'date-time': '1990-01-01 00:00:00.000',
+        'uri': 'http://dartlang.org',
+        'invalid-uri': 'http://[::1',
+        'map': {'num': 4.2, 'bool': false}
       });
     });
 
-    test("value returns the wrapped value", () {
+    test('value returns the wrapped value', () {
       expect(
           parameters.value,
           equals({
-            "num": 1.5,
-            "int": 1,
-            "bool": true,
-            "string": "zap",
-            "list": [1, 2, 3],
-            "date-time": "1990-01-01 00:00:00.000",
-            "uri": "http://dartlang.org",
-            "invalid-uri": "http://[::1",
-            "map": {"num": 4.2, "bool": false}
+            'num': 1.5,
+            'int': 1,
+            'bool': true,
+            'string': 'zap',
+            'list': [1, 2, 3],
+            'date-time': '1990-01-01 00:00:00.000',
+            'uri': 'http://dartlang.org',
+            'invalid-uri': 'http://[::1',
+            'map': {'num': 4.2, 'bool': false}
           }));
     });
 
-    test("[int] throws a parameter error", () {
+    test('[int] throws a parameter error', () {
       expect(
           () => parameters[0],
           throwsInvalidParams('Parameters for method "foo" must be passed by '
               'position.'));
     });
 
-    test("[].value returns existing parameters", () {
+    test('[].value returns existing parameters', () {
       expect(parameters['num'].value, equals(1.5));
     });
 
-    test("[].valueOr returns existing parameters", () {
+    test('[].valueOr returns existing parameters', () {
       expect(parameters['num'].valueOr(7), equals(1.5));
     });
 
-    test("[].value fails for absent parameters", () {
+    test('[].value fails for absent parameters', () {
       expect(
           () => parameters['fblthp'].value,
           throwsInvalidParams('Request for method "foo" is missing required '
               'parameter "fblthp".'));
     });
 
-    test("[].valueOr succeeds for absent parameters", () {
+    test('[].valueOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].valueOr(7), equals(7));
     });
 
-    test("[].exists returns true for existing parameters", () {
+    test('[].exists returns true for existing parameters', () {
       expect(parameters['num'].exists, isTrue);
     });
 
-    test("[].exists returns false for missing parameters", () {
+    test('[].exists returns false for missing parameters', () {
       expect(parameters['fblthp'].exists, isFalse);
     });
 
-    test("[].asNum returns numeric parameters", () {
+    test('[].asNum returns numeric parameters', () {
       expect(parameters['num'].asNum, equals(1.5));
       expect(parameters['int'].asNum, equals(1));
     });
 
-    test("[].asNumOr returns numeric parameters", () {
+    test('[].asNumOr returns numeric parameters', () {
       expect(parameters['num'].asNumOr(7), equals(1.5));
     });
 
-    test("[].asNum fails for non-numeric parameters", () {
+    test('[].asNum fails for non-numeric parameters', () {
       expect(
           () => parameters['bool'].asNum,
           throwsInvalidParams('Parameter "bool" for method "foo" must be a '
               'number, but was true.'));
     });
 
-    test("[].asNumOr fails for non-numeric parameters", () {
+    test('[].asNumOr fails for non-numeric parameters', () {
       expect(
           () => parameters['bool'].asNumOr(7),
           throwsInvalidParams('Parameter "bool" for method "foo" must be a '
               'number, but was true.'));
     });
 
-    test("[].asNum fails for absent parameters", () {
+    test('[].asNum fails for absent parameters', () {
       expect(
           () => parameters['fblthp'].asNum,
           throwsInvalidParams('Request for method "foo" is missing required '
               'parameter "fblthp".'));
     });
 
-    test("[].asNumOr succeeds for absent parameters", () {
+    test('[].asNumOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].asNumOr(7), equals(7));
     });
 
-    test("[].asInt returns integer parameters", () {
+    test('[].asInt returns integer parameters', () {
       expect(parameters['int'].asInt, equals(1));
     });
 
-    test("[].asIntOr returns integer parameters", () {
+    test('[].asIntOr returns integer parameters', () {
       expect(parameters['int'].asIntOr(7), equals(1));
     });
 
-    test("[].asInt fails for non-integer parameters", () {
+    test('[].asInt fails for non-integer parameters', () {
       expect(
           () => parameters['bool'].asInt,
           throwsInvalidParams('Parameter "bool" for method "foo" must be an '
               'integer, but was true.'));
     });
 
-    test("[].asIntOr succeeds for absent parameters", () {
+    test('[].asIntOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].asIntOr(7), equals(7));
     });
 
-    test("[].asBool returns boolean parameters", () {
+    test('[].asBool returns boolean parameters', () {
       expect(parameters['bool'].asBool, isTrue);
     });
 
-    test("[].asBoolOr returns boolean parameters", () {
+    test('[].asBoolOr returns boolean parameters', () {
       expect(parameters['bool'].asBoolOr(false), isTrue);
     });
 
-    test("[].asBoolOr fails for non-boolean parameters", () {
+    test('[].asBoolOr fails for non-boolean parameters', () {
       expect(
           () => parameters['int'].asBool,
           throwsInvalidParams('Parameter "int" for method "foo" must be a '
               'boolean, but was 1.'));
     });
 
-    test("[].asBoolOr succeeds for absent parameters", () {
+    test('[].asBoolOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].asBoolOr(false), isFalse);
     });
 
-    test("[].asString returns string parameters", () {
-      expect(parameters['string'].asString, equals("zap"));
+    test('[].asString returns string parameters', () {
+      expect(parameters['string'].asString, equals('zap'));
     });
 
-    test("[].asStringOr returns string parameters", () {
-      expect(parameters['string'].asStringOr("bap"), equals("zap"));
+    test('[].asStringOr returns string parameters', () {
+      expect(parameters['string'].asStringOr('bap'), equals('zap'));
     });
 
-    test("[].asString fails for non-string parameters", () {
+    test('[].asString fails for non-string parameters', () {
       expect(
           () => parameters['int'].asString,
           throwsInvalidParams('Parameter "int" for method "foo" must be a '
               'string, but was 1.'));
     });
 
-    test("[].asStringOr succeeds for absent parameters", () {
-      expect(parameters['fblthp'].asStringOr("bap"), equals("bap"));
+    test('[].asStringOr succeeds for absent parameters', () {
+      expect(parameters['fblthp'].asStringOr('bap'), equals('bap'));
     });
 
-    test("[].asList returns list parameters", () {
+    test('[].asList returns list parameters', () {
       expect(parameters['list'].asList, equals([1, 2, 3]));
     });
 
-    test("[].asListOr returns list parameters", () {
+    test('[].asListOr returns list parameters', () {
       expect(parameters['list'].asListOr([5, 6, 7]), equals([1, 2, 3]));
     });
 
-    test("[].asList fails for non-list parameters", () {
+    test('[].asList fails for non-list parameters', () {
       expect(
           () => parameters['int'].asList,
           throwsInvalidParams('Parameter "int" for method "foo" must be an '
               'Array, but was 1.'));
     });
 
-    test("[].asListOr succeeds for absent parameters", () {
+    test('[].asListOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].asListOr([5, 6, 7]), equals([5, 6, 7]));
     });
 
-    test("[].asMap returns map parameters", () {
-      expect(parameters['map'].asMap, equals({"num": 4.2, "bool": false}));
+    test('[].asMap returns map parameters', () {
+      expect(parameters['map'].asMap, equals({'num': 4.2, 'bool': false}));
     });
 
-    test("[].asMapOr returns map parameters", () {
+    test('[].asMapOr returns map parameters', () {
       expect(
-          parameters['map'].asMapOr({}), equals({"num": 4.2, "bool": false}));
+          parameters['map'].asMapOr({}), equals({'num': 4.2, 'bool': false}));
     });
 
-    test("[].asMap fails for non-map parameters", () {
+    test('[].asMap fails for non-map parameters', () {
       expect(
           () => parameters['int'].asMap,
           throwsInvalidParams('Parameter "int" for method "foo" must be an '
               'Object, but was 1.'));
     });
 
-    test("[].asMapOr succeeds for absent parameters", () {
+    test('[].asMapOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].asMapOr({}), equals({}));
     });
 
-    test("[].asDateTime returns date/time parameters", () {
-      expect(parameters['date-time'].asDateTime, equals(new DateTime(1990)));
+    test('[].asDateTime returns date/time parameters', () {
+      expect(parameters['date-time'].asDateTime, equals(DateTime(1990)));
     });
 
-    test("[].asDateTimeOr returns date/time parameters", () {
-      expect(parameters['date-time'].asDateTimeOr(new DateTime(2014)),
-          equals(new DateTime(1990)));
+    test('[].asDateTimeOr returns date/time parameters', () {
+      expect(parameters['date-time'].asDateTimeOr(DateTime(2014)),
+          equals(DateTime(1990)));
     });
 
-    test("[].asDateTime fails for non-date/time parameters", () {
+    test('[].asDateTime fails for non-date/time parameters', () {
       expect(
           () => parameters['int'].asDateTime,
           throwsInvalidParams('Parameter "int" for method "foo" must be a '
               'string, but was 1.'));
     });
 
-    test("[].asDateTimeOr succeeds for absent parameters", () {
-      expect(parameters['fblthp'].asDateTimeOr(new DateTime(2014)),
-          equals(new DateTime(2014)));
+    test('[].asDateTimeOr succeeds for absent parameters', () {
+      expect(parameters['fblthp'].asDateTimeOr(DateTime(2014)),
+          equals(DateTime(2014)));
     });
 
-    test("[].asDateTime fails for non-date/time parameters", () {
+    test('[].asDateTime fails for non-date/time parameters', () {
       expect(
           () => parameters['int'].asDateTime,
           throwsInvalidParams('Parameter "int" for method "foo" must be a '
               'string, but was 1.'));
     });
 
-    test("[].asDateTime fails for invalid date/times", () {
+    test('[].asDateTime fails for invalid date/times', () {
       expect(
           () => parameters['string'].asDateTime,
           throwsInvalidParams('Parameter "string" for method "foo" must be a '
@@ -240,35 +240,35 @@
               'Invalid date format'));
     });
 
-    test("[].asUri returns URI parameters", () {
+    test('[].asUri returns URI parameters', () {
       expect(parameters['uri'].asUri, equals(Uri.parse('http://dartlang.org')));
     });
 
-    test("[].asUriOr returns URI parameters", () {
+    test('[].asUriOr returns URI parameters', () {
       expect(parameters['uri'].asUriOr(Uri.parse('http://google.com')),
           equals(Uri.parse('http://dartlang.org')));
     });
 
-    test("[].asUri fails for non-URI parameters", () {
+    test('[].asUri fails for non-URI parameters', () {
       expect(
           () => parameters['int'].asUri,
           throwsInvalidParams('Parameter "int" for method "foo" must be a '
               'string, but was 1.'));
     });
 
-    test("[].asUriOr succeeds for absent parameters", () {
+    test('[].asUriOr succeeds for absent parameters', () {
       expect(parameters['fblthp'].asUriOr(Uri.parse('http://google.com')),
           equals(Uri.parse('http://google.com')));
     });
 
-    test("[].asUri fails for non-URI parameters", () {
+    test('[].asUri fails for non-URI parameters', () {
       expect(
           () => parameters['int'].asUri,
           throwsInvalidParams('Parameter "int" for method "foo" must be a '
               'string, but was 1.'));
     });
 
-    test("[].asUri fails for invalid URIs", () {
+    test('[].asUri fails for invalid URIs', () {
       expect(
           () => parameters['invalid-uri'].asUri,
           throwsInvalidParams('Parameter "invalid-uri" for method "foo" must '
@@ -276,34 +276,34 @@
               'Missing end `]` to match `[` in host'));
     });
 
-    group("with a nested parameter map", () {
+    group('with a nested parameter map', () {
       var nested;
       setUp(() => nested = parameters['map']);
 
-      test("[int] fails with a type error", () {
+      test('[int] fails with a type error', () {
         expect(
             () => nested[0],
             throwsInvalidParams('Parameter "map" for method "foo" must be an '
                 'Array, but was {"num":4.2,"bool":false}.'));
       });
 
-      test("[].value returns existing parameters", () {
+      test('[].value returns existing parameters', () {
         expect(nested['num'].value, equals(4.2));
         expect(nested['bool'].value, isFalse);
       });
 
-      test("[].value fails for absent parameters", () {
+      test('[].value fails for absent parameters', () {
         expect(
             () => nested['fblthp'].value,
             throwsInvalidParams('Request for method "foo" is missing required '
                 'parameter map.fblthp.'));
       });
 
-      test("typed getters return correctly-typed parameters", () {
+      test('typed getters return correctly-typed parameters', () {
         expect(nested['num'].asNum, equals(4.2));
       });
 
-      test("typed getters fail for incorrectly-typed parameters", () {
+      test('typed getters fail for incorrectly-typed parameters', () {
         expect(
             () => nested['bool'].asNum,
             throwsInvalidParams('Parameter map.bool for method "foo" must be '
@@ -311,34 +311,34 @@
       });
     });
 
-    group("with a nested parameter list", () {
+    group('with a nested parameter list', () {
       var nested;
       setUp(() => nested = parameters['list']);
 
-      test("[string] fails with a type error", () {
+      test('[string] fails with a type error', () {
         expect(
             () => nested['foo'],
             throwsInvalidParams('Parameter "list" for method "foo" must be an '
                 'Object, but was [1,2,3].'));
       });
 
-      test("[].value returns existing parameters", () {
+      test('[].value returns existing parameters', () {
         expect(nested[0].value, equals(1));
         expect(nested[1].value, equals(2));
       });
 
-      test("[].value fails for absent parameters", () {
+      test('[].value fails for absent parameters', () {
         expect(
             () => nested[5].value,
             throwsInvalidParams('Request for method "foo" is missing required '
                 'parameter list[5].'));
       });
 
-      test("typed getters return correctly-typed parameters", () {
+      test('typed getters return correctly-typed parameters', () {
         expect(nested[0].asInt, equals(1));
       });
 
-      test("typed getters fail for incorrectly-typed parameters", () {
+      test('typed getters fail for incorrectly-typed parameters', () {
         expect(
             () => nested[0].asBool,
             throwsInvalidParams('Parameter list[0] for method "foo" must be '
@@ -347,43 +347,43 @@
     });
   });
 
-  group("with positional parameters", () {
+  group('with positional parameters', () {
     var parameters;
-    setUp(() => parameters = new json_rpc.Parameters("foo", [1, 2, 3, 4, 5]));
+    setUp(() => parameters = json_rpc.Parameters('foo', [1, 2, 3, 4, 5]));
 
-    test("value returns the wrapped value", () {
+    test('value returns the wrapped value', () {
       expect(parameters.value, equals([1, 2, 3, 4, 5]));
     });
 
-    test("[string] throws a parameter error", () {
+    test('[string] throws a parameter error', () {
       expect(
           () => parameters['foo'],
           throwsInvalidParams('Parameters for method "foo" must be passed by '
               'name.'));
     });
 
-    test("[].value returns existing parameters", () {
+    test('[].value returns existing parameters', () {
       expect(parameters[2].value, equals(3));
     });
 
-    test("[].value fails for out-of-range parameters", () {
+    test('[].value fails for out-of-range parameters', () {
       expect(
           () => parameters[10].value,
           throwsInvalidParams('Request for method "foo" is missing required '
               'parameter 11.'));
     });
 
-    test("[].exists returns true for existing parameters", () {
+    test('[].exists returns true for existing parameters', () {
       expect(parameters[0].exists, isTrue);
     });
 
-    test("[].exists returns false for missing parameters", () {
+    test('[].exists returns false for missing parameters', () {
       expect(parameters[10].exists, isFalse);
     });
   });
 
-  test("with a complex parameter path", () {
-    var parameters = new json_rpc.Parameters("foo", {
+  test('with a complex parameter path', () {
+    var parameters = json_rpc.Parameters('foo', {
       'bar baz': [
         0,
         1,
diff --git a/test/server/server_test.dart b/test/server/server_test.dart
index b9ba504..14ae1e4 100644
--- a/test/server/server_test.dart
+++ b/test/server/server_test.dart
@@ -12,9 +12,9 @@
 
 void main() {
   var controller;
-  setUp(() => controller = new ServerController());
+  setUp(() => controller = ServerController());
 
-  test("calls a registered method with the given name", () {
+  test('calls a registered method with the given name', () {
     controller.server.registerMethod('foo', (params) {
       return {'params': params.value};
     });
@@ -35,7 +35,7 @@
         })));
   });
 
-  test("calls a method that takes no parameters", () {
+  test('calls a method that takes no parameters', () {
     controller.server.registerMethod('foo', () => 'foo');
 
     expect(
@@ -44,7 +44,7 @@
         completion(equals({'jsonrpc': '2.0', 'result': 'foo', 'id': 1234})));
   });
 
-  test("a method that takes no parameters rejects parameters", () {
+  test('a method that takes no parameters rejects parameters', () {
     controller.server.registerMethod('foo', () => 'foo');
 
     expectErrorResponse(
@@ -54,9 +54,9 @@
         'No parameters are allowed for method "foo".');
   });
 
-  test("an unexpected error in a method is captured", () {
+  test('an unexpected error in a method is captured', () {
     controller.server
-        .registerMethod('foo', () => throw new FormatException('bad format'));
+        .registerMethod('foo', () => throw FormatException('bad format'));
 
     expect(
         controller
@@ -70,13 +70,13 @@
             'data': {
               'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234},
               'full': 'FormatException: bad format',
-              'stack': new TypeMatcher<String>()
+              'stack': TypeMatcher<String>()
             }
           }
         }));
   });
 
-  test("doesn't return a result for a notification", () {
+  test('doesn\'t return a result for a notification', () {
     controller.server.registerMethod('foo', (args) => 'result');
 
     expect(
@@ -85,9 +85,9 @@
         doesNotComplete);
   });
 
-  test("includes the error data in the response", () {
+  test('includes the error data in the response', () {
     controller.server.registerMethod('foo', (params) {
-      throw new json_rpc.RpcException(5, 'Error message.', data: 'data value');
+      throw json_rpc.RpcException(5, 'Error message.', data: 'data value');
     });
 
     expectErrorResponse(
@@ -98,13 +98,13 @@
         data: 'data value');
   });
 
-  test("a JSON parse error is rejected", () {
+  test('a JSON parse error is rejected', () {
     return controller.handleJsonRequest('invalid json {').then((result) {
       expect(jsonDecode(result), {
         'jsonrpc': '2.0',
         'error': {
           'code': error_code.PARSE_ERROR,
-          'message': startsWith("Invalid JSON: "),
+          'message': startsWith('Invalid JSON: '),
           // TODO(nweiz): Always expect the source when sdk#25655 is fixed.
           'data': {
             'request': anyOf([isNull, 'invalid json {'])
@@ -115,8 +115,8 @@
     });
   });
 
-  group("fallbacks", () {
-    test("calls a fallback if no method matches", () {
+  group('fallbacks', () {
+    test('calls a fallback if no method matches', () {
       controller.server
         ..registerMethod('foo', () => 'foo')
         ..registerMethod('bar', () => 'foo')
@@ -138,10 +138,10 @@
           })));
     });
 
-    test("calls the first matching fallback", () {
+    test('calls the first matching fallback', () {
       controller.server
         ..registerFallback((params) =>
-            throw new json_rpc.RpcException.methodNotFound(params.method))
+            throw json_rpc.RpcException.methodNotFound(params.method))
         ..registerFallback((params) => 'fallback 2')
         ..registerFallback((params) => 'fallback 3');
 
@@ -152,9 +152,9 @@
               equals({'jsonrpc': '2.0', 'result': 'fallback 2', 'id': 1234})));
     });
 
-    test("an unexpected error in a fallback is captured", () {
+    test('an unexpected error in a fallback is captured', () {
       controller.server
-          .registerFallback((_) => throw new FormatException('bad format'));
+          .registerFallback((_) => throw FormatException('bad format'));
 
       expect(
           controller
@@ -168,14 +168,14 @@
               'data': {
                 'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234},
                 'full': 'FormatException: bad format',
-                'stack': new TypeMatcher<String>()
+                'stack': TypeMatcher<String>()
               }
             }
           }));
     });
   });
 
-  test("disallows multiple methods with the same name", () {
+  test('disallows multiple methods with the same name', () {
     controller.server.registerMethod('foo', () => null);
     expect(() => controller.server.registerMethod('foo', () => null),
         throwsArgumentError);
diff --git a/test/server/stream_test.dart b/test/server/stream_test.dart
index 19629e7..7105cd6 100644
--- a/test/server/stream_test.dart
+++ b/test/server/stream_test.dart
@@ -14,13 +14,13 @@
   var responseController;
   var server;
   setUp(() {
-    requestController = new StreamController();
-    responseController = new StreamController();
-    server = new json_rpc.Server.withoutJson(
-        new StreamChannel(requestController.stream, responseController.sink));
+    requestController = StreamController();
+    responseController = StreamController();
+    server = json_rpc.Server.withoutJson(
+        StreamChannel(requestController.stream, responseController.sink));
   });
 
-  test(".withoutJson supports decoded stream and sink", () {
+  test('.withoutJson supports decoded stream and sink', () {
     server.listen();
 
     server.registerMethod('foo', (params) {
@@ -45,7 +45,7 @@
         })));
   });
 
-  test(".listen returns when the controller is closed", () {
+  test('.listen returns when the controller is closed', () {
     var hasListenCompeted = false;
     expect(server.listen().then((_) => hasListenCompeted = true), completes);
 
@@ -57,18 +57,18 @@
     });
   });
 
-  test(".listen returns a stream error", () {
+  test('.listen returns a stream error', () {
     expect(server.listen(), throwsA('oh no'));
     requestController.addError('oh no');
   });
 
-  test(".listen can't be called twice", () {
+  test('.listen can\'t be called twice', () {
     server.listen();
 
     expect(() => server.listen(), throwsStateError);
   });
 
-  test(".close cancels the stream subscription and closes the sink", () {
+  test('.close cancels the stream subscription and closes the sink', () {
     // Work around sdk#19095.
     responseController.stream.listen(null);
 
diff --git a/test/server/utils.dart b/test/server/utils.dart
index ef089ad..bf1db6f 100644
--- a/test/server/utils.dart
+++ b/test/server/utils.dart
@@ -14,18 +14,18 @@
 /// A controller used to test a [json_rpc.Server].
 class ServerController {
   /// The controller for the server's request stream.
-  final _requestController = new StreamController<String>();
+  final _requestController = StreamController<String>();
 
   /// The controller for the server's response sink.
-  final _responseController = new StreamController<String>();
+  final _responseController = StreamController<String>();
 
   /// The server.
   json_rpc.Server get server => _server;
   json_rpc.Server _server;
 
   ServerController({json_rpc.ErrorCallback onUnhandledError}) {
-    _server = new json_rpc.Server(
-        new StreamChannel(_requestController.stream, _responseController.sink),
+    _server = json_rpc.Server(
+        StreamChannel(_requestController.stream, _responseController.sink),
         onUnhandledError: onUnhandledError);
     _server.listen();
   }
@@ -50,7 +50,7 @@
     {data}) {
   var id;
   if (request is Map) id = request['id'];
-  if (data == null) data = {'request': request};
+  data ??= {'request': request};
 
   expect(
       controller.handleRequest(request),
@@ -65,7 +65,7 @@
 /// `invalid_params` error code.
 Matcher throwsInvalidParams(String message) {
   return throwsA(predicate((error) {
-    expect(error, new TypeMatcher<json_rpc.RpcException>());
+    expect(error, TypeMatcher<json_rpc.RpcException>());
     expect(error.code, equals(error_code.INVALID_PARAMS));
     expect(error.message, equals(message));
     return true;