Use package lints (#70)

* use package lints
* fix lint warnings
* update the changelog
* dart format
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 20d83d7..120bee4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # webkit_inspection_protocol.dart
 
+## 1.0.1-dev
+- Use `package:lints` for analysis.
+- Populate the pubspec `repository` field.
+
 ## 1.0.0
 - Migrate to null safety.
 
diff --git a/analysis_options.yaml b/analysis_options.yaml
index ab3a9b3..2de85d5 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,16 +1,5 @@
+include: package:lints/recommended.yaml
+
 analyzer:
   errors:
     deprecated_member_use_from_same_package: ignore
-
-linter:
-  rules:
-    - always_declare_return_types
-    - avoid_init_to_null
-    - directives_ordering
-    - slash_for_doc_comments
-    - prefer_const_constructors
-    - prefer_const_constructors_in_immutables
-    - prefer_const_declarations
-    - prefer_const_literals_to_create_immutables
-    - prefer_final_fields
-    - type_annotate_public_apis
diff --git a/example/multiplex.dart b/example/multiplex.dart
index 6ed123d..8fc6e97 100644
--- a/example/multiplex.dart
+++ b/example/multiplex.dart
@@ -14,7 +14,7 @@
 import 'multiplex_impl.dart' show Server;
 
 void main(List<String> argv) async {
-  var args = (new ArgParser()
+  var args = (ArgParser()
         ..addFlag('verbose', abbr: 'v', defaultsTo: false, negatable: false)
         ..addFlag('model_dom', defaultsTo: false, negatable: true)
         ..addOption('chrome_host', defaultsTo: 'localhost')
@@ -34,8 +34,8 @@
     stderr.writeln('${rec.level.name}: ${rec.time}: ${rec.message}');
   });
 
-  var cr = new ChromeConnection(
+  var cr = ChromeConnection(
       args['chrome_host'] as String, int.parse(args['chrome_port'] as String));
-  new Server(int.parse(args['listen_port'] as String), cr,
+  Server(int.parse(args['listen_port'] as String), cr,
       modelDom: args['model_dom'] as bool);
 }
diff --git a/example/multiplex_impl.dart b/example/multiplex_impl.dart
index 704942a..0f64d23 100644
--- a/example/multiplex_impl.dart
+++ b/example/multiplex_impl.dart
@@ -19,7 +19,7 @@
     show ChromeConnection, ChromeTab, WipConnection;
 
 class Server {
-  static final _log = new Logger('Server');
+  static final _log = Logger('Server');
 
   Future<HttpServer>? _server;
   final ChromeConnection chrome;
@@ -35,7 +35,7 @@
 
   shelf.Handler get _handler => const shelf.Pipeline()
       .addMiddleware(shelf.logRequests(logger: _shelfLogger))
-      .addHandler(new shelf.Cascade()
+      .addHandler(shelf.Cascade()
           .add(_webSocket)
           .add(_mainPage)
           .add(_json)
@@ -55,14 +55,13 @@
     if (path.isEmpty) {
       var resp = await _mainPageHtml();
       _log.info('mainPage: $resp');
-      return new shelf.Response.ok(resp,
-          headers: {'Content-Type': 'text/html'});
+      return shelf.Response.ok(resp, headers: {'Content-Type': 'text/html'});
     }
-    return new shelf.Response.notFound(null);
+    return shelf.Response.notFound(null);
   }
 
   Future<String> _mainPageHtml() async {
-    var html = new StringBuffer(r'''<!DOCTYPE html>
+    var html = StringBuffer(r'''<!DOCTYPE html>
 <html>
 <head>
 <title>Chrome Windows</title>
@@ -103,10 +102,10 @@
     if (path.length == 1 && path[0] == 'json') {
       var resp = jsonEncode(await chrome.getTabs(), toEncodable: _jsonEncode);
       _log.info('json: $resp');
-      return new shelf.Response.ok(resp,
+      return shelf.Response.ok(resp,
           headers: {'Content-Type': 'application/json'});
     }
-    return new shelf.Response.notFound(null);
+    return shelf.Response.notFound(null);
   }
 
   Future<shelf.Response> _forward(shelf.Request request) async {
@@ -114,18 +113,18 @@
     var dtResp = await chrome.getUrl(request.url.path);
 
     if (dtResp.statusCode == 200) {
-      return new shelf.Response.ok(dtResp,
+      return shelf.Response.ok(dtResp,
           headers: {'Content-Type': dtResp.headers.contentType.toString()});
     }
     _log.warning(
         'Forwarded ${request.url} returned statusCode: ${dtResp.statusCode}');
-    return new shelf.Response.notFound(null);
+    return shelf.Response.notFound(null);
   }
 
   Future<shelf.Response> _webSocket(shelf.Request request) async {
     var path = request.url.pathSegments;
     if (path.length != 3 || path[0] != 'devtools' || path[1] != 'page') {
-      return new shelf.Response.notFound(null);
+      return shelf.Response.notFound(null);
     }
     _log.info('connecting to websocket: ${request.url}');
 
@@ -136,11 +135,11 @@
       });
       WipDomModel? dom;
       if (modelDom) {
-        dom = await _modelDoms.putIfAbsent(path[2], () {
-          return new WipDomModel(debugger.dom);
+        dom = _modelDoms.putIfAbsent(path[2], () {
+          return WipDomModel(debugger.dom);
         });
       }
-      var forwarder = new WipForwarder(debugger, webSocket.stream.cast(),
+      var forwarder = WipForwarder(debugger, webSocket.stream.cast(),
           sink: webSocket.sink, domModel: dom);
       debugger.onClose.listen((_) {
         _connections.remove(path[2]);
diff --git a/lib/dom_model.dart b/lib/dom_model.dart
index b05714f..9bb5f05 100644
--- a/lib/dom_model.dart
+++ b/lib/dom_model.dart
@@ -26,34 +26,42 @@
 /// Implementation of WipDom that maintains and updates a model of the DOM
 /// based on incoming events.
 class WipDomModel implements WipDom {
-  static final _log = new Logger('WipDomModel');
+  static final _log = Logger('WipDomModel');
 
   final WipDom _dom;
 
   final Map<int, _Node> _nodeCache = {};
   Future<_Node>? _root;
 
+  @override
   late final Stream<AttributeModifiedEvent> onAttributeModified =
       StreamTransformer.fromHandlers(handleData: _onAttributeModified)
           .bind(_dom.onAttributeModified);
+  @override
   late final Stream<AttributeRemovedEvent> onAttributeRemoved =
       StreamTransformer.fromHandlers(handleData: _onAttributeRemoved)
           .bind(_dom.onAttributeRemoved);
+  @override
   late final Stream<CharacterDataModifiedEvent> onCharacterDataModified =
       StreamTransformer.fromHandlers(handleData: _onCharacterDataModified)
           .bind(_dom.onCharacterDataModified);
+  @override
   late final Stream<ChildNodeCountUpdatedEvent> onChildNodeCountUpdated =
       StreamTransformer.fromHandlers(handleData: _onChildNodeCountUpdated)
           .bind(_dom.onChildNodeCountUpdated);
+  @override
   late final Stream<ChildNodeInsertedEvent> onChildNodeInserted =
       StreamTransformer.fromHandlers(handleData: _onChildNodeInserted)
           .bind(_dom.onChildNodeInserted);
+  @override
   late final Stream<ChildNodeRemovedEvent> onChildNodeRemoved =
       StreamTransformer.fromHandlers(handleData: _onChildNodeRemoved)
           .bind(_dom.onChildNodeRemoved);
+  @override
   late final Stream<DocumentUpdatedEvent> onDocumentUpdated =
       StreamTransformer.fromHandlers(handleData: _onDocumentUpdated)
           .bind(_dom.onDocumentUpdated);
+  @override
   late final Stream<SetChildNodesEvent> onSetChildNodes =
       StreamTransformer.fromHandlers(handleData: _onSetChildNodes)
           .bind(_dom.onSetChildNodes);
@@ -141,7 +149,7 @@
   Future<Map<String, String>> getAttributes(int nodeId) async {
     Map<String, String> attributes = await _dom.getAttributes(nodeId);
     var node = _getOrCreateNode(nodeId);
-    node._attributes = new Map.from(attributes);
+    node._attributes = Map.from(attributes);
     return attributes;
   }
 
@@ -150,14 +158,12 @@
   /// multiple times on the same page.
   @override
   Future<Node> getDocument() {
-    if (_root == null) {
-      _root = _dom.getDocument().then((n) => _getOrCreateNodeFromNode(n));
-    }
+    _root ??= _dom.getDocument().then((n) => _getOrCreateNodeFromNode(n));
     return _root!;
   }
 
   _Node _getOrCreateNode(int nodeId) =>
-      _nodeCache.putIfAbsent(nodeId, () => new _Node(nodeId));
+      _nodeCache.putIfAbsent(nodeId, () => _Node(nodeId));
 
   _Node _getOrCreateNodeFromNode(Node src) {
     try {
@@ -191,6 +197,7 @@
     }
   }
 
+  @override
   dynamic noSuchMethod(Invocation invocation) =>
       reflect(_dom).delegate(invocation);
 }
@@ -200,7 +207,7 @@
 
   @override
   Map<String, String>? get attributes =>
-      _attributes != null ? new UnmodifiableMapView(_attributes!) : null;
+      _attributes != null ? UnmodifiableMapView(_attributes!) : null;
 
   int? _childNodeCount;
 
@@ -211,7 +218,7 @@
 
   @override
   List<Node>? get children =>
-      _children != null ? new UnmodifiableListView(_children!) : null;
+      _children != null ? UnmodifiableListView(_children!) : null;
 
   _Node? _contentDocument;
 
@@ -278,7 +285,7 @@
 
   _Node(this.nodeId);
 
-  Map toJson() => _toJsonInternal(new Set());
+  Map toJson() => _toJsonInternal({});
 
   Map _toJsonInternal(Set visited) {
     var map = {
@@ -297,9 +304,9 @@
       }
       if (_children != null && _children!.isNotEmpty) {
         var newChildren = [];
-        _children!.forEach((child) {
+        for (var child in _children!) {
           newChildren.add(child._toJsonInternal(visited));
-        });
+        }
         map['children'] = newChildren;
       }
       if (_contentDocument != null) {
diff --git a/lib/forwarder.dart b/lib/forwarder.dart
index bd29583..c53c36f 100644
--- a/lib/forwarder.dart
+++ b/lib/forwarder.dart
@@ -16,7 +16,7 @@
 /// Forwards a [Stream] to a [WipConnection] and events
 /// from a [WipConnection] to a [StreamSink].
 class WipForwarder {
-  static final _log = new Logger('ChromeForwarder');
+  static final _log = Logger('ChromeForwarder');
 
   final Stream<String> _in;
   final StreamSink _out;
@@ -29,15 +29,12 @@
 
   final List<StreamSubscription> _subscriptions = <StreamSubscription>[];
 
-  final StreamController<Null> _closedController =
-      new StreamController.broadcast();
+  final StreamController<void> _closedController = StreamController.broadcast();
 
   factory WipForwarder(WipConnection debugger, Stream<String> stream,
       {StreamSink? sink, WipDom? domModel}) {
-    if (sink == null) {
-      sink = stream as StreamSink;
-    }
-    return new WipForwarder._(debugger, stream, sink, domModel);
+    sink ??= stream as StreamSink;
+    return WipForwarder._(debugger, stream, sink, domModel);
   }
 
   WipForwarder._(this._debugger, this._in, this._out, this.domModel) {
@@ -125,21 +122,27 @@
   void pause() {
     assert(_subscriptions.isNotEmpty);
     _log.info('Pausing forwarding');
-    _subscriptions.forEach((s) => s.pause());
+    for (var s in _subscriptions) {
+      s.pause();
+    }
     _subscriptions.clear();
   }
 
   void resume() {
     assert(_subscriptions.isNotEmpty);
     _log.info('Resuming forwarding');
-    _subscriptions.forEach((s) => s.resume());
+    for (var s in _subscriptions) {
+      s.resume();
+    }
     _subscriptions.clear();
   }
 
   Future stop() {
     assert(_subscriptions.isNotEmpty);
     _log.info('Stopping forwarding');
-    _subscriptions.forEach((s) => s.cancel());
+    for (var s in _subscriptions) {
+      s.cancel();
+    }
     _subscriptions.clear();
     _closedController.add(null);
     return Future.wait([_closedController.close(), _out.close()]);
diff --git a/lib/src/console.dart b/lib/src/console.dart
index 689736a..4864a9f 100644
--- a/lib/src/console.dart
+++ b/lib/src/console.dart
@@ -17,11 +17,11 @@
 
   Stream<ConsoleMessageEvent> get onMessage => eventStream(
       'Console.messageAdded',
-      (WipEvent event) => new ConsoleMessageEvent(event.json));
+      (WipEvent event) => ConsoleMessageEvent(event.json));
 
   Stream<ConsoleClearedEvent> get onCleared => eventStream(
       'Console.messagesCleared',
-      (WipEvent event) => new ConsoleClearedEvent(event.json));
+      (WipEvent event) => ConsoleClearedEvent(event.json));
 }
 
 class ConsoleMessageEvent extends WipEvent {
@@ -38,12 +38,13 @@
   Iterable<WipConsoleCallFrame> getStackTrace() {
     if (_message.containsKey('stackTrace')) {
       return (params!['stackTrace'] as List).map((frame) =>
-          new WipConsoleCallFrame.fromMap(frame as Map<String, dynamic>));
+          WipConsoleCallFrame.fromMap(frame as Map<String, dynamic>));
     } else {
       return [];
     }
   }
 
+  @override
   String toString() => text;
 }
 
diff --git a/lib/src/debugger.dart b/lib/src/debugger.dart
index 577cb40..73bf2ca 100644
--- a/lib/src/debugger.dart
+++ b/lib/src/debugger.dart
@@ -66,10 +66,10 @@
         await sendCommand('Debugger.setBreakpoint', params: params);
 
     if (response.result!.containsKey('exceptionDetails')) {
-      throw new ExceptionDetails(
+      throw ExceptionDetails(
           response.result!['exceptionDetails'] as Map<String, dynamic>);
     } else {
-      return new SetBreakpointResponse(response.json);
+      return SetBreakpointResponse(response.json);
     }
   }
 
@@ -102,11 +102,10 @@
         await sendCommand('Debugger.evaluateOnCallFrame', params: params);
 
     if (response.result!.containsKey('exceptionDetails')) {
-      throw new ExceptionDetails(
+      throw ExceptionDetails(
           response.result!['exceptionDetails'] as Map<String, dynamic>);
     } else {
-      return new RemoteObject(
-          response.result!['result'] as Map<String, dynamic>);
+      return RemoteObject(response.result!['result'] as Map<String, dynamic>);
     }
   }
 
@@ -137,7 +136,7 @@
         await sendCommand('Debugger.getPossibleBreakpoints', params: params);
 
     if (response.result!.containsKey('exceptionDetails')) {
-      throw new ExceptionDetails(
+      throw ExceptionDetails(
           response.result!['exceptionDetails'] as Map<String, dynamic>);
     } else {
       List locations = response.result!['locations'];
@@ -155,21 +154,21 @@
     });
   }
 
-  Stream<DebuggerPausedEvent> get onPaused => eventStream('Debugger.paused',
-      (WipEvent event) => new DebuggerPausedEvent(event.json));
+  Stream<DebuggerPausedEvent> get onPaused => eventStream(
+      'Debugger.paused', (WipEvent event) => DebuggerPausedEvent(event.json));
 
   Stream<GlobalObjectClearedEvent> get onGlobalObjectCleared => eventStream(
       'Debugger.globalObjectCleared',
-      (WipEvent event) => new GlobalObjectClearedEvent(event.json));
+      (WipEvent event) => GlobalObjectClearedEvent(event.json));
 
-  Stream<DebuggerResumedEvent> get onResumed => eventStream('Debugger.resumed',
-      (WipEvent event) => new DebuggerResumedEvent(event.json));
+  Stream<DebuggerResumedEvent> get onResumed => eventStream(
+      'Debugger.resumed', (WipEvent event) => DebuggerResumedEvent(event.json));
 
   Stream<ScriptParsedEvent> get onScriptParsed => eventStream(
       'Debugger.scriptParsed',
-      (WipEvent event) => new ScriptParsedEvent(event.json));
+      (WipEvent event) => ScriptParsedEvent(event.json));
 
-  Map<String, WipScript> get scripts => new UnmodifiableMapView(_scripts);
+  Map<String, WipScript> get scripts => UnmodifiableMapView(_scripts);
 }
 
 String _pauseStateToString(PauseState state) {
@@ -181,7 +180,7 @@
     case PauseState.uncaught:
       return 'uncaught';
     default:
-      throw new ArgumentError('unknown state: $state');
+      throw ArgumentError('unknown state: $state');
   }
 }
 
@@ -190,8 +189,9 @@
 class ScriptParsedEvent extends WipEvent {
   ScriptParsedEvent(Map<String, dynamic> json) : super(json);
 
-  WipScript get script => new WipScript(params!);
+  WipScript get script => WipScript(params!);
 
+  @override
   String toString() => script.toString();
 }
 
@@ -210,7 +210,7 @@
 
   /// Call stack the virtual machine stopped on.
   List<WipCallFrame> getCallFrames() => (params!['callFrames'] as List)
-      .map((frame) => new WipCallFrame(frame as Map<String, dynamic>))
+      .map((frame) => WipCallFrame(frame as Map<String, dynamic>))
       .toList();
 
   /// Pause reason.
@@ -233,7 +233,8 @@
       ? null
       : StackTrace(params!['asyncStackTrace']);
 
-  String toString() => 'paused: ${reason}';
+  @override
+  String toString() => 'paused: $reason';
 }
 
 /// A debugger call frame.
@@ -254,29 +255,30 @@
 
   /// Location in the source code.
   WipLocation get location =>
-      new WipLocation(json['location'] as Map<String, dynamic>);
+      WipLocation(json['location'] as Map<String, dynamic>);
 
   /// JavaScript script name or url.
   String get url => json['url'] as String;
 
   /// Scope chain for this call frame.
   Iterable<WipScope> getScopeChain() => (json['scopeChain'] as List)
-      .map((scope) => new WipScope(scope as Map<String, dynamic>));
+      .map((scope) => WipScope(scope as Map<String, dynamic>));
 
   /// `this` object for this call frame.
   RemoteObject get thisObject =>
-      new RemoteObject(json['this'] as Map<String, dynamic>);
+      RemoteObject(json['this'] as Map<String, dynamic>);
 
   /// The value being returned, if the function is at return point.
   ///
   /// (optional)
   RemoteObject? get returnValue {
     return json.containsKey('returnValue')
-        ? new RemoteObject(json['returnValue'] as Map<String, dynamic>)
+        ? RemoteObject(json['returnValue'] as Map<String, dynamic>)
         : null;
   }
 
-  String toString() => '[${functionName}]';
+  @override
+  String toString() => '[$functionName]';
 }
 
 class WipLocation {
@@ -303,7 +305,8 @@
     return json;
   }
 
-  String toString() => '[${scriptId}:${lineNumber}:${columnNumber}]';
+  @override
+  String toString() => '[$scriptId:$lineNumber:$columnNumber]';
 }
 
 class WipScript {
@@ -327,7 +330,8 @@
 
   String? get sourceMapURL => json['sourceMapURL'] as String?;
 
-  String toString() => '[script ${scriptId}: ${url}]';
+  @override
+  String toString() => '[script $scriptId: $url]';
 }
 
 class WipScope {
@@ -345,7 +349,7 @@
   /// the actual object; for the rest of the scopes, it is artificial transient
   /// object enumerating scope variables as its properties.
   RemoteObject get object =>
-      new RemoteObject(json['object'] as Map<String, dynamic>);
+      RemoteObject(json['object'] as Map<String, dynamic>);
 }
 
 class WipBreakLocation extends WipLocation {
diff --git a/lib/src/dom.dart b/lib/src/dom.dart
index be0d978..bc56adb 100644
--- a/lib/src/dom.dart
+++ b/lib/src/dom.dart
@@ -18,7 +18,7 @@
   }
 
   Future<Node> getDocument() async =>
-      new Node((await sendCommand('DOM.getDocument')).result!['root']
+      Node((await sendCommand('DOM.getDocument')).result!['root']
           as Map<String, dynamic>);
 
   Future<String> getOuterHtml(int nodeId) async =>
@@ -125,7 +125,7 @@
     }
 
     var resp = await sendCommand('DOM.resolveNode', params: params);
-    return new RemoteObject(resp.result!['object'] as Map<String, dynamic>);
+    return RemoteObject(resp.result!['object'] as Map<String, dynamic>);
   }
 
   Future<void> setAttributeValue(int nodeId, String name, String value) =>
@@ -156,35 +156,34 @@
 
   Stream<AttributeModifiedEvent> get onAttributeModified => eventStream(
       'DOM.attributeModified',
-      (WipEvent event) => new AttributeModifiedEvent(event.json));
+      (WipEvent event) => AttributeModifiedEvent(event.json));
 
   Stream<AttributeRemovedEvent> get onAttributeRemoved => eventStream(
       'DOM.attributeRemoved',
-      (WipEvent event) => new AttributeRemovedEvent(event.json));
+      (WipEvent event) => AttributeRemovedEvent(event.json));
 
   Stream<CharacterDataModifiedEvent> get onCharacterDataModified => eventStream(
       'DOM.characterDataModified',
-      (WipEvent event) => new CharacterDataModifiedEvent(event.json));
+      (WipEvent event) => CharacterDataModifiedEvent(event.json));
 
   Stream<ChildNodeCountUpdatedEvent> get onChildNodeCountUpdated => eventStream(
       'DOM.childNodeCountUpdated',
-      (WipEvent event) => new ChildNodeCountUpdatedEvent(event.json));
+      (WipEvent event) => ChildNodeCountUpdatedEvent(event.json));
 
   Stream<ChildNodeInsertedEvent> get onChildNodeInserted => eventStream(
       'DOM.childNodeInserted',
-      (WipEvent event) => new ChildNodeInsertedEvent(event.json));
+      (WipEvent event) => ChildNodeInsertedEvent(event.json));
 
   Stream<ChildNodeRemovedEvent> get onChildNodeRemoved => eventStream(
       'DOM.childNodeRemoved',
-      (WipEvent event) => new ChildNodeRemovedEvent(event.json));
+      (WipEvent event) => ChildNodeRemovedEvent(event.json));
 
   Stream<DocumentUpdatedEvent> get onDocumentUpdated => eventStream(
       'DOM.documentUpdated',
-      (WipEvent event) => new DocumentUpdatedEvent(event.json));
+      (WipEvent event) => DocumentUpdatedEvent(event.json));
 
   Stream<SetChildNodesEvent> get onSetChildNodes => eventStream(
-      'DOM.setChildNodes',
-      (WipEvent event) => new SetChildNodesEvent(event.json));
+      'DOM.setChildNodes', (WipEvent event) => SetChildNodesEvent(event.json));
 }
 
 class AttributeModifiedEvent extends WipEvent {
@@ -250,10 +249,11 @@
 
   Iterable<Node> get nodes sync* {
     for (Map node in params!['nodes']) {
-      yield new Node(node as Map<String, dynamic>);
+      yield Node(node as Map<String, dynamic>);
     }
   }
 
+  @override
   String toString() => 'SetChildNodes $nodeId: $nodes';
 }
 
@@ -273,12 +273,12 @@
 
   late final List<Node>? children = _map.containsKey('children')
       ? UnmodifiableListView((_map['children'] as List)
-          .map((c) => new Node(c as Map<String, dynamic>)))
+          .map((c) => Node(c as Map<String, dynamic>)))
       : null;
 
   Node? get contentDocument {
     if (_map.containsKey('contentDocument')) {
-      return new Node(_map['contentDocument'] as Map<String, dynamic>);
+      return Node(_map['contentDocument'] as Map<String, dynamic>);
     }
     return null;
   }
@@ -307,6 +307,7 @@
 
   String? get xmlVersion => _map['xmlVersion'] as String?;
 
+  @override
   String toString() => '$nodeName: $nodeId $attributes';
 }
 
@@ -332,5 +333,5 @@
   for (int i = 0; i < attrList.length; i += 2) {
     attributes[attrList[i]] = attrList[i + 1];
   }
-  return new UnmodifiableMapView(attributes);
+  return UnmodifiableMapView(attributes);
 }
diff --git a/lib/src/log.dart b/lib/src/log.dart
index 97ec139..9839472 100644
--- a/lib/src/log.dart
+++ b/lib/src/log.dart
@@ -12,8 +12,8 @@
 
   Future<WipResponse> disable() => sendCommand('Log.disable');
 
-  Stream<LogEntry> get onEntryAdded => eventStream(
-      'Log.entryAdded', (WipEvent event) => new LogEntry(event.json));
+  Stream<LogEntry> get onEntryAdded =>
+      eventStream('Log.entryAdded', (WipEvent event) => LogEntry(event.json));
 }
 
 class LogEntry extends WipEvent {
@@ -39,5 +39,6 @@
   /// Timestamp when this entry was added.
   num get timestamp => _entry['timestamp'] as num;
 
+  @override
   String toString() => text;
 }
diff --git a/lib/src/runtime.dart b/lib/src/runtime.dart
index 8a66086..4089fae 100644
--- a/lib/src/runtime.dart
+++ b/lib/src/runtime.dart
@@ -49,11 +49,10 @@
         await sendCommand('Runtime.evaluate', params: params);
 
     if (response.result!.containsKey('exceptionDetails')) {
-      throw new ExceptionDetails(
+      throw ExceptionDetails(
           response.result!['exceptionDetails'] as Map<String, dynamic>);
     } else {
-      return new RemoteObject(
-          response.result!['result'] as Map<String, dynamic>);
+      return RemoteObject(response.result!['result'] as Map<String, dynamic>);
     }
   }
 
@@ -96,11 +95,10 @@
         await sendCommand('Runtime.callFunctionOn', params: params);
 
     if (response.result!.containsKey('exceptionDetails')) {
-      throw new ExceptionDetails(
+      throw ExceptionDetails(
           response.result!['exceptionDetails'] as Map<String, dynamic>);
     } else {
-      return new RemoteObject(
-          response.result!['result'] as Map<String, dynamic>);
+      return RemoteObject(response.result!['result'] as Map<String, dynamic>);
     }
   }
 
@@ -140,7 +138,7 @@
         await sendCommand('Runtime.getProperties', params: params);
 
     if (response.result!.containsKey('exceptionDetails')) {
-      throw new ExceptionDetails(
+      throw ExceptionDetails(
           response.result!['exceptionDetails'] as Map<String, dynamic>);
     } else {
       List locations = response.result!['result'];
@@ -150,18 +148,18 @@
 
   Stream<ConsoleAPIEvent> get onConsoleAPICalled => eventStream(
       'Runtime.consoleAPICalled',
-      (WipEvent event) => new ConsoleAPIEvent(event.json));
+      (WipEvent event) => ConsoleAPIEvent(event.json));
 
   Stream<ExceptionThrownEvent> get onExceptionThrown => eventStream(
       'Runtime.exceptionThrown',
-      (WipEvent event) => new ExceptionThrownEvent(event.json));
+      (WipEvent event) => ExceptionThrownEvent(event.json));
 
   /// Issued when new execution context is created.
   Stream<ExecutionContextDescription> get onExecutionContextCreated =>
       eventStream(
           'Runtime.executionContextCreated',
           (WipEvent event) =>
-              new ExecutionContextDescription(event.params!['context']));
+              ExecutionContextDescription(event.params!['context']));
 
   /// Issued when execution context is destroyed.
   Stream<String> get onExecutionContextDestroyed => eventStream(
@@ -187,7 +185,7 @@
 
   /// Call arguments.
   List<RemoteObject> get args => (params!['args'] as List)
-      .map((m) => new RemoteObject(m as Map<String, dynamic>))
+      .map((m) => RemoteObject(m as Map<String, dynamic>))
       .toList();
 }
 
@@ -215,7 +213,7 @@
   int get timestamp => params!['timestamp'] as int;
 
   ExceptionDetails get exceptionDetails =>
-      new ExceptionDetails(params!['exceptionDetails'] as Map<String, dynamic>);
+      ExceptionDetails(params!['exceptionDetails'] as Map<String, dynamic>);
 }
 
 class ExceptionDetails implements Exception {
@@ -249,14 +247,15 @@
   @optional
   StackTrace? get stackTrace => json['stackTrace'] == null
       ? null
-      : new StackTrace(json['stackTrace'] as Map<String, dynamic>);
+      : StackTrace(json['stackTrace'] as Map<String, dynamic>);
 
   /// Exception object if available.
   @optional
   RemoteObject? get exception => json['exception'] == null
       ? null
-      : new RemoteObject(json['exception'] as Map<String, dynamic>);
+      : RemoteObject(json['exception'] as Map<String, dynamic>);
 
+  @override
   String toString() => '$text, $url, $scriptId, $lineNumber, $exception';
 }
 
@@ -267,7 +266,7 @@
   StackTrace(this.json);
 
   List<CallFrame> get callFrames => (json['callFrames'] as List)
-      .map((m) => new CallFrame(m as Map<String, dynamic>))
+      .map((m) => CallFrame(m as Map<String, dynamic>))
       .toList();
 
   /// String label of this stack trace. For async traces this may be a name of
@@ -295,6 +294,7 @@
     }).toList();
   }
 
+  @override
   String toString() => callFrames.map((f) => '  $f').join('\n');
 }
 
@@ -321,6 +321,7 @@
   /// JavaScript script column number (0-based).
   int get columnNumber => json['columnNumber'] as int;
 
+  @override
   String toString() => '$functionName() ($url $lineNumber:$columnNumber)';
 }
 
diff --git a/lib/webkit_inspection_protocol.dart b/lib/webkit_inspection_protocol.dart
index a8f6b13..25b7e8a 100644
--- a/lib/webkit_inspection_protocol.dart
+++ b/lib/webkit_inspection_protocol.dart
@@ -29,24 +29,24 @@
 /// This assumes the browser has been started with the `--remote-debugging-port`
 /// flag. The data is read from the `http://{host}:{port}/json` url.
 class ChromeConnection {
-  final HttpClient _client = new HttpClient();
+  final HttpClient _client = HttpClient();
 
   final Uri url;
 
   ChromeConnection(String host, [int port = 9222])
-      : url = Uri.parse('http://${host}:${port}/');
+      : url = Uri.parse('http://$host:$port/');
 
   // TODO(DrMarcII): consider changing this to return Stream<ChromeTab>.
   Future<List<ChromeTab>> getTabs() async {
     var response = await getUrl('/json');
     var respBody = await utf8.decodeStream(response.cast<List<int>>());
-    return new List<ChromeTab>.from(
-        (jsonDecode(respBody) as List).map((m) => new ChromeTab(m as Map)));
+    return List<ChromeTab>.from(
+        (jsonDecode(respBody) as List).map((m) => ChromeTab(m as Map)));
   }
 
-  Future<ChromeTab?> getTab(bool accept(ChromeTab tab),
+  Future<ChromeTab?> getTab(bool Function(ChromeTab tab) accept,
       {Duration? retryFor}) async {
-    var start = new DateTime.now();
+    var start = DateTime.now();
     var end = start;
     if (retryFor != null) {
       end = start.add(retryFor);
@@ -59,15 +59,15 @@
             return tab;
           }
         }
-        if (end.isBefore(new DateTime.now())) {
+        if (end.isBefore(DateTime.now())) {
           return null;
         }
       } catch (e) {
-        if (end.isBefore(new DateTime.now())) {
+        if (end.isBefore(DateTime.now())) {
           rethrow;
         }
       }
-      await new Future.delayed(const Duration(milliseconds: 25));
+      await Future.delayed(const Duration(milliseconds: 25));
     }
   }
 
@@ -112,6 +112,7 @@
   Future<WipConnection> connect() =>
       WipConnection.connect(webSocketDebuggerUrl);
 
+  @override
   String toString() => url;
 }
 
@@ -146,12 +147,12 @@
 
   final Map _completers = <int, Completer<WipResponse>>{};
 
-  final _closeController = new StreamController<WipConnection>.broadcast();
-  final _notificationController = new StreamController<WipEvent>.broadcast();
+  final _closeController = StreamController<WipConnection>.broadcast();
+  final _notificationController = StreamController<WipEvent>.broadcast();
 
   static Future<WipConnection> connect(String url) {
     return WebSocket.connect(url).then((socket) {
-      return new WipConnection._(url, socket);
+      return WipConnection._(url, socket);
     });
   }
 
@@ -174,11 +175,12 @@
 
   Future close() => _ws.close();
 
+  @override
   String toString() => url;
 
   Future<WipResponse> sendCommand(String method,
       [Map<String, dynamic>? params]) {
-    var completer = new Completer<WipResponse>();
+    var completer = Completer<WipResponse>();
     var json = {'id': _nextId++, 'method': method};
     if (params != null) {
       json['params'] = params;
@@ -191,16 +193,16 @@
   }
 
   void _handleNotification(Map<String, dynamic> json) {
-    _notificationController.add(new WipEvent(json));
+    _notificationController.add(WipEvent(json));
   }
 
   void _handleResponse(Map<String, dynamic> event) {
     var completer = _completers.remove(event['id']);
 
     if (event.containsKey('error')) {
-      completer.completeError(new WipError(event));
+      completer.completeError(WipError(event));
     } else {
-      completer.complete(new WipResponse(event));
+      completer.complete(WipResponse(event));
     }
   }
 
@@ -227,6 +229,7 @@
       : method = json['method'] as String,
         params = json['params'] as Map<String, dynamic>?;
 
+  @override
   String toString() => 'WipEvent: $method($params)';
 }
 
@@ -244,6 +247,7 @@
 
   String? get message => error == null ? null : error!['message'];
 
+  @override
   String toString() => 'WipError $code $message';
 }
 
@@ -257,10 +261,11 @@
       : id = json['id'] as int,
         result = json['result'] as Map<String, dynamic>?;
 
+  @override
   String toString() => 'WipResponse $id: $result';
 }
 
-typedef T WipEventTransformer<T>(WipEvent event);
+typedef WipEventTransformer<T> = T Function(WipEvent event);
 
 /// @optional
 const String optional = 'optional';
@@ -275,13 +280,13 @@
     sink.add(this);
   }).bind(connection.onClose);
 
-  WipDomain(WipConnection connection) : this.connection = connection;
+  WipDomain(this.connection);
 
   Stream<T> eventStream<T>(String method, WipEventTransformer<T> transformer) {
     return _eventStreams
         .putIfAbsent(
           method,
-          () => new StreamTransformer.fromHandlers(
+          () => StreamTransformer.fromHandlers(
             handleData: (WipEvent event, EventSink<T> sink) {
               if (event.method == method) {
                 sink.add(transformer(event));
@@ -300,7 +305,7 @@
   }
 }
 
-const _Experimental experimental = const _Experimental();
+const _Experimental experimental = _Experimental();
 
 class _Experimental {
   const _Experimental();
diff --git a/pubspec.yaml b/pubspec.yaml
index 7da6c45..16c4126 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,23 +1,21 @@
 name: webkit_inspection_protocol
-version: 1.0.0
-description: A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol).
-homepage: https://github.com/google/webkit_inspection_protocol.dart
+version: 1.0.1-dev
+description: >
+  A client for the Chrome DevTools Protocol (previously called the Webkit
+  Inspection Protocol).
+repository: https://github.com/google/webkit_inspection_protocol.dart
 
 environment:
-  sdk: '>=2.12.0-0 <3.0.0'
+  sdk: '>=2.12.0 <3.0.0'
 
 dependencies:
   logging: ^1.0.0
 
 dev_dependencies:
   args: ^2.0.0
-  shelf: ^1.0.0
+  lints: ^1.0.0
   shelf_static: ^1.0.0
   shelf_web_socket: ^1.0.0
+  shelf: ^1.0.0
   test: ^1.16.0
   webdriver: ^3.0.0
-
-dependency_overrides:
-  test: ^1.16.0
-  shelf_static: ^1.0.0
-  shelf_web_socket: ^1.0.0
diff --git a/test/console_test.dart b/test/console_test.dart
index e1441bf..94eaf1a 100644
--- a/test/console_test.dart
+++ b/test/console_test.dart
@@ -19,7 +19,7 @@
 
     Future checkMessages(int expectedCount) async {
       // make sure all messages have been delivered
-      await new Future.delayed(const Duration(seconds: 1));
+      await Future.delayed(const Duration(seconds: 1));
       expect(events, hasLength(expectedCount));
       for (int i = 0; i < expectedCount; i++) {
         if (i == 0) {
@@ -39,10 +39,12 @@
     });
 
     tearDown(() async {
-      await console!.disable();
+      await console?.disable();
       console = null;
       await closeConnection();
-      subs.forEach((s) => s.cancel());
+      for (var s in subs) {
+        s.cancel();
+      }
       subs.clear();
     });
 
diff --git a/test/debugger_test.dart b/test/debugger_test.dart
index 9315cfc..b9e691c 100644
--- a/test/debugger_test.dart
+++ b/test/debugger_test.dart
@@ -21,11 +21,13 @@
     });
 
     tearDown(() async {
-      await debugger!.disable();
+      await debugger?.disable();
       debugger = null;
 
       await closeConnection();
-      subs.forEach((s) => s.cancel());
+      for (var s in subs) {
+        s.cancel();
+      }
       subs.clear();
     });
 
diff --git a/test/dom_model_test.dart b/test/dom_model_test.dart
index 6b9f8d7..5ac2b53 100644
--- a/test/dom_model_test.dart
+++ b/test/dom_model_test.dart
@@ -15,7 +15,7 @@
     WipDom? dom;
 
     setUp(() async {
-      dom = new WipDomModel((await navigateToPage('dom_model_test.html')).dom);
+      dom = WipDomModel((await navigateToPage('dom_model_test.html')).dom);
     });
 
     tearDown(() async {
diff --git a/test/runtime_test.dart b/test/runtime_test.dart
index c318203..33d61cf 100644
--- a/test/runtime_test.dart
+++ b/test/runtime_test.dart
@@ -21,11 +21,13 @@
     });
 
     tearDown(() async {
-      await runtime!.disable();
+      await runtime?.disable();
       runtime = null;
 
       await closeConnection();
-      subs.forEach((s) => s.cancel());
+      for (var s in subs) {
+        s.cancel();
+      }
       subs.clear();
     });
 
diff --git a/test/test_setup.dart b/test/test_setup.dart
index 5a600b4..03cc9f8 100644
--- a/test/test_setup.dart
+++ b/test/test_setup.dart
@@ -15,17 +15,15 @@
 /// Returns a (cached) debugger connection to the first regular tab of
 /// the browser with remote debugger running at 'localhost:9222',
 Future<WipConnection> get wipConnection {
-  if (_wipConnection == null) {
-    _wipConnection = () async {
-      var debugPort = await _startWebDriver(await _startChromeDriver());
-      var chrome = new ChromeConnection('localhost', debugPort);
-      var tab = (await chrome
-          .getTab((tab) => !tab.isBackgroundPage && !tab.isChromeExtension))!;
-      var connection = await tab.connect();
-      connection.onClose.listen((_) => _wipConnection = null);
-      return connection;
-    }();
-  }
+  _wipConnection ??= () async {
+    var debugPort = await _startWebDriver(await _startChromeDriver());
+    var chrome = ChromeConnection('localhost', debugPort);
+    var tab = (await chrome
+        .getTab((tab) => !tab.isBackgroundPage && !tab.isChromeExtension))!;
+    var connection = await tab.connect();
+    connection.onClose.listen((_) => _wipConnection = null);
+    return connection;
+  }();
   return _wipConnection!;
 }
 
@@ -93,24 +91,22 @@
   return port;
 }
 
-var _testServerUri;
+Future<Uri>? _testServerUri;
 
 /// Ensures that an HTTP server serving files from 'test/data' has been
 /// started and navigates to to [page] using [wipConnection].
 /// Return [wipConnection].
 Future<WipConnection> navigateToPage(String page) async {
-  if (_testServerUri == null) {
-    _testServerUri = () async {
-      var receivePort = new ReceivePort();
-      await Isolate.spawn(_startHttpServer, receivePort.sendPort);
-      var port = await receivePort.first;
-      return new Uri.http('localhost:$port', '');
-    }();
-  }
+  _testServerUri ??= () async {
+    var receivePort = ReceivePort();
+    await Isolate.spawn(_startHttpServer, receivePort.sendPort);
+    var port = await receivePort.first;
+    return Uri.http('localhost:$port', '');
+  }();
   await (await wipConnection)
       .page
-      .navigate((await _testServerUri).resolve(page).toString());
-  await new Future.delayed(const Duration(seconds: 1));
+      .navigate((await _testServerUri)!.resolve(page).toString());
+  await Future.delayed(const Duration(seconds: 1));
   return wipConnection;
 }