lints (#1061)

* Enable and fix recommended lints

* Enable and fix two more lints
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa9918c..50a36c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+# 2.2.1-dev
+
 # 2.2.0
 
 * Fix analyzer dependency constraint (#1051).
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 14bcb12..1d03e8b 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,6 +1,8 @@
-include: package:pedantic/analysis_options.yaml
+include: package:lints/recommended.yaml
 linter:
   rules:
+    - avoid_dynamic_calls
+    - directives_ordering
     - prefer_equal_for_default_values
     - prefer_generic_function_type_aliases
     - slash_for_doc_comments
diff --git a/benchmark/benchmark.dart b/benchmark/benchmark.dart
index 6d02384..feab837 100644
--- a/benchmark/benchmark.dart
+++ b/benchmark/benchmark.dart
@@ -6,12 +6,11 @@
 
 import 'dart:io';
 
+import 'package:dart_style/dart_style.dart';
 import 'package:path/path.dart' as p;
 
-import 'package:dart_style/dart_style.dart';
-
-const NUM_TRIALS = 100;
-const FORMATS_PER_TRIAL = 30;
+const _numTrials = 100;
+const _formatsPerTrial = 30;
 
 /// Note, these files use ".txt" because while they can be *parsed* correctly,
 /// they don't resolve without error. That's OK because the formatter doesn't
@@ -24,17 +23,17 @@
 
   // Run the benchmark several times. This ensures the VM is warmed up and lets
   // us see how much variance there is.
-  for (var i = 0; i <= NUM_TRIALS; i++) {
+  for (var i = 0; i <= _numTrials; i++) {
     var start = DateTime.now();
 
     // For a single benchmark, format the source multiple times.
-    var result;
-    for (var j = 0; j < FORMATS_PER_TRIAL; j++) {
+    String? result;
+    for (var j = 0; j < _formatsPerTrial; j++) {
       result = formatSource();
     }
 
     var elapsed =
-        DateTime.now().difference(start).inMilliseconds / FORMATS_PER_TRIAL;
+        DateTime.now().difference(start).inMilliseconds / _formatsPerTrial;
 
     // Keep track of the best run so far.
     if (elapsed >= best) continue;
diff --git a/bin/format.dart b/bin/format.dart
index 2e30848..270025d 100644
--- a/bin/format.dart
+++ b/bin/format.dart
@@ -35,7 +35,7 @@
     return;
   }
 
-  if (argResults['verbose'] && !argResults['help']) {
+  if (argResults['verbose'] && !(argResults['help'] as bool)) {
     usageError(parser, 'Can only use --verbose with --help.');
   }
 
@@ -52,7 +52,7 @@
   }
 
   void checkForReporterCollision(String chosen, String other) {
-    if (!argResults[other]) return;
+    if (!(argResults[other] as bool)) return;
 
     usageError(parser, 'Cannot use --$chosen and --$other at the same time.');
   }
diff --git a/example/format.dart b/example/format.dart
index 77c79dc..01ec795 100644
--- a/example/format.dart
+++ b/example/format.dart
@@ -4,10 +4,9 @@
 import 'dart:io';
 import 'dart:mirrors';
 
-import 'package:path/path.dart' as p;
-
 import 'package:dart_style/dart_style.dart';
 import 'package:dart_style/src/debug.dart' as debug;
+import 'package:path/path.dart' as p;
 
 void main(List<String> args) {
   // Enable debugging so you can see some of the formatter's internal state.
@@ -33,7 +32,7 @@
   try {
     var formatter = DartFormatter(pageWidth: pageWidth);
 
-    var result;
+    String result;
     if (isCompilationUnit) {
       result = formatter.format(source);
     } else {
diff --git a/lib/dart_style.dart b/lib/dart_style.dart
index 4da21a8..bf5cc66 100644
--- a/lib/dart_style.dart
+++ b/lib/dart_style.dart
@@ -3,5 +3,5 @@
 // BSD-style license that can be found in the LICENSE file.
 export 'src/dart_formatter.dart';
 export 'src/exceptions.dart';
-export 'src/style_fix.dart';
 export 'src/source_code.dart';
+export 'src/style_fix.dart';
diff --git a/lib/src/argument_list_visitor.dart b/lib/src/argument_list_visitor.dart
index 429d5bc..9f4c6f2 100644
--- a/lib/src/argument_list_visitor.dart
+++ b/lib/src/argument_list_visitor.dart
@@ -64,8 +64,8 @@
       Token rightParenthesis,
       List<Expression> arguments) {
     // Look for a single contiguous range of block function arguments.
-    var functionsStart;
-    var functionsEnd;
+    int? functionsStart;
+    int? functionsEnd;
 
     for (var i = 0; i < arguments.length; i++) {
       var argument = arguments[i];
@@ -104,7 +104,7 @@
     //         another: argument);
     if (functionsStart != null &&
         arguments[0] is NamedExpression &&
-        (functionsStart > 0 || functionsEnd < arguments.length)) {
+        (functionsStart > 0 || functionsEnd! < arguments.length)) {
       functionsStart = null;
     }
 
@@ -125,7 +125,7 @@
         return false;
       }
 
-      for (var i = 0; i < functionsStart; i++) {
+      for (var i = 0; i < functionsStart!; i++) {
         var argument = arguments[i];
         if (argument is! NamedExpression) continue;
 
@@ -135,7 +135,7 @@
         }
       }
 
-      for (var i = functionsEnd; i < arguments.length; i++) {
+      for (var i = functionsEnd!; i < arguments.length; i++) {
         if (isArrow(arguments[i] as NamedExpression)) {
           functionsStart = null;
           break;
@@ -153,7 +153,7 @@
     // functions in the middle.
     var argumentsBefore = arguments.take(functionsStart).toList();
     var functions = arguments.sublist(functionsStart, functionsEnd);
-    var argumentsAfter = arguments.skip(functionsEnd).toList();
+    var argumentsAfter = arguments.skip(functionsEnd!).toList();
 
     return ArgumentListVisitor._(
         visitor,
diff --git a/lib/src/chunk_builder.dart b/lib/src/chunk_builder.dart
index 249250e..ab34beb 100644
--- a/lib/src/chunk_builder.dart
+++ b/lib/src/chunk_builder.dart
@@ -312,7 +312,7 @@
 
       // Make sure there is at least one newline after a line comment and allow
       // one or two after a block comment that has nothing after it.
-      var linesAfter;
+      int linesAfter;
       if (i < comments.length - 1) {
         linesAfter = comments[i + 1].linesBefore;
       } else {
@@ -432,6 +432,8 @@
           _pendingWhitespace = Whitespace.newline;
         }
         break;
+      default:
+        break;
     }
   }
 
@@ -670,8 +672,8 @@
     var result = writer.writeLines(_formatter.indent,
         isCompilationUnit: _source.isCompilationUnit);
 
-    var selectionStart;
-    var selectionLength;
+    int? selectionStart;
+    int? selectionLength;
     if (_source.selectionStart != null) {
       selectionStart = result.selectionStart;
       var selectionEnd = result.selectionEnd;
@@ -734,6 +736,8 @@
         // We should have pinned these down before getting here.
         assert(false);
         break;
+      default:
+        break;
     }
 
     _pendingWhitespace = Whitespace.none;
@@ -928,7 +932,7 @@
   void _hardenRules() {
     if (_hardSplitRules.isEmpty) return;
 
-    void walkConstraints(rule) {
+    void walkConstraints(Rule rule) {
       rule.harden();
 
       // Follow this rule's constraints, recursively.
diff --git a/lib/src/cli/format_command.dart b/lib/src/cli/format_command.dart
index 1badec6..ad8b126 100644
--- a/lib/src/cli/format_command.dart
+++ b/lib/src/cli/format_command.dart
@@ -78,7 +78,7 @@
     }
 
     // Can't use --verbose with anything but --help.
-    if (argResults['verbose'] && !argResults['help']) {
+    if (argResults['verbose'] && !(argResults['help'] as bool)) {
       usageException('Can only use --verbose with --help.');
     }
 
diff --git a/lib/src/cli/options.dart b/lib/src/cli/options.dart
index 94f999f..aea33ed 100644
--- a/lib/src/cli/options.dart
+++ b/lib/src/cli/options.dart
@@ -125,7 +125,7 @@
 }
 
 List<int>? parseSelection(ArgResults argResults, String optionName) {
-  var option = argResults[optionName];
+  var option = argResults[optionName] as String?;
   if (option == null) return null;
 
   // Can only preserve a selection when parsing from stdin.
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index 2510ace..3b39456 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -8,8 +8,9 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/error.dart';
+// ignore: implementation_imports
 import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/generated/parser.dart';
+// ignore: implementation_imports
 import 'package:analyzer/src/string_source.dart';
 import 'package:pub_semver/pub_semver.dart';
 
diff --git a/lib/src/debug.dart b/lib/src/debug.dart
index f796af3..cf0b7d8 100644
--- a/lib/src/debug.dart
+++ b/lib/src/debug.dart
@@ -222,7 +222,7 @@
 void dumpLines(List<Chunk> chunks, int firstLineIndent, SplitSet splits) {
   var buffer = StringBuffer();
 
-  void writeIndent(indent) => buffer.write(gray('| ' * (indent ~/ 2)));
+  void writeIndent(int indent) => buffer.write(gray('| ' * (indent ~/ 2)));
 
   void writeChunksUnsplit(List<Chunk> chunks) {
     for (var chunk in chunks) {
diff --git a/lib/src/fast_hash.dart b/lib/src/fast_hash.dart
index f1b2fe8..beea29d 100644
--- a/lib/src/fast_hash.dart
+++ b/lib/src/fast_hash.dart
@@ -9,7 +9,7 @@
 abstract class FastHash {
   static int _nextId = 0;
 
-  /// A semi-unique numeric indentifier for the object.
+  /// A semi-unique numeric identifier for the object.
   ///
   /// This is useful for debugging and also speeds up using the object in hash
   /// sets. Ids are *semi*-unique because they may wrap around in long running
@@ -18,5 +18,6 @@
   final int id = _nextId = (_nextId + 1) & 0x0fffffff;
 
   @override
+  // ignore: hash_and_equals
   int get hashCode => id;
 }
diff --git a/lib/src/io.dart b/lib/src/io.dart
index 66d56b8..1c6d5e9 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -105,7 +105,7 @@
 
     // If the path is in a subdirectory starting with ".", ignore it.
     var parts = p.split(p.relative(entry.path, from: directory.path));
-    var hiddenIndex;
+    int? hiddenIndex;
     for (var i = 0; i < parts.length; i++) {
       if (parts[i].startsWith('.')) {
         hiddenIndex = i;
diff --git a/lib/src/line_splitting/line_splitter.dart b/lib/src/line_splitting/line_splitter.dart
index 8ef5926..478c88c 100644
--- a/lib/src/line_splitting/line_splitter.dart
+++ b/lib/src/line_splitting/line_splitter.dart
@@ -120,17 +120,15 @@
 
   /// Creates a new splitter for [_writer] that tries to fit [chunks] into the
   /// page width.
-  LineSplitter(this.writer, List<Chunk> chunks, int blockIndentation,
-      int firstLineIndent,
+  LineSplitter(
+      this.writer, this.chunks, this.blockIndentation, int firstLineIndent,
       {bool flushLeft = false})
-      : chunks = chunks,
-        // Collect the set of rules that we need to select values for.
+      : // Collect the set of rules that we need to select values for.
         rules = chunks
             .map((chunk) => chunk.rule)
             .whereType<Rule>()
             .toSet()
             .toList(growable: false),
-        blockIndentation = blockIndentation,
         firstLineIndent = flushLeft ? 0 : firstLineIndent + blockIndentation {
     _queue.bindSplitter(this);
 
diff --git a/lib/src/line_splitting/rule_set.dart b/lib/src/line_splitting/rule_set.dart
index acffb83..739ffd4 100644
--- a/lib/src/line_splitting/rule_set.dart
+++ b/lib/src/line_splitting/rule_set.dart
@@ -68,7 +68,7 @@
 
     // Test this rule against the other rules being bound.
     for (var other in rule.constrainedRules) {
-      var otherValue;
+      int? otherValue;
       // Hardened rules are implicitly bound.
       if (other.isHardened) {
         otherValue = other.fullySplitValue;
diff --git a/lib/src/line_splitting/solve_state.dart b/lib/src/line_splitting/solve_state.dart
index a90a246..5dfd39e 100644
--- a/lib/src/line_splitting/solve_state.dart
+++ b/lib/src/line_splitting/solve_state.dart
@@ -347,7 +347,7 @@
     var splitSpans = <Span>{};
 
     // The nesting level of the chunk that ended the previous line.
-    var previousNesting;
+    NestingLevel? previousNesting;
 
     for (var i = 0; i < _splitter.chunks.length; i++) {
       var chunk = _splitter.chunks[i];
diff --git a/lib/src/line_splitting/solve_state_queue.dart b/lib/src/line_splitting/solve_state_queue.dart
index c8efdbb..f1622f6 100644
--- a/lib/src/line_splitting/solve_state_queue.dart
+++ b/lib/src/line_splitting/solve_state_queue.dart
@@ -203,8 +203,8 @@
       var rightChild = _queue[rightChildIndex]!;
 
       var comparison = _compare(leftChild, rightChild);
-      var minChildIndex;
-      var minChild;
+      int minChildIndex;
+      SolveState minChild;
 
       if (comparison < 0) {
         minChild = leftChild;
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 4a53ae6..99847d5 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -1,11 +1,13 @@
 // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+// ignore_for_file: avoid_dynamic_calls
+
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/source/line_info.dart';
 
 import 'argument_list_visitor.dart';
 import 'call_chain_visitor.dart';
@@ -809,10 +811,10 @@
   }
 
   @override
-  void visitComment(Comment node) => null;
+  void visitComment(Comment node) {}
 
   @override
-  void visitCommentReference(CommentReference node) => null;
+  void visitCommentReference(CommentReference node) {}
 
   @override
   void visitCompilationUnit(CompilationUnit node) {
@@ -1538,7 +1540,7 @@
 
     _metadataRules.add(MetadataRule());
 
-    var rule;
+    PositionalRule? rule;
     if (requiredParams.isNotEmpty) {
       rule = PositionalRule(null, 0, 0);
       _metadataRules.last.bindPositionalRule(rule);
@@ -3198,8 +3200,8 @@
     // probably broke the elements into lines deliberately, so preserve those.
     var preserveNewlines = _containsLineComments(elements, rightBracket);
 
-    var rule;
-    var lineRule;
+    Rule? rule;
+    late TypeArgumentRule lineRule;
     if (preserveNewlines) {
       // Newlines are significant, so we'll explicitly write those. Elements
       // on the same line all share an argument-list-like rule that allows
@@ -3499,8 +3501,8 @@
   /// This only looks for comments at the element boundary. Comments within an
   /// element are ignored.
   bool _containsLineComments(Iterable<AstNode> elements, Token rightBracket) {
-    bool hasLineCommentBefore(token) {
-      var comment = token.precedingComments;
+    bool hasLineCommentBefore(Token token) {
+      Token? comment = token.precedingComments;
       for (; comment != null; comment = comment.next) {
         if (comment.type == TokenType.SINGLE_LINE_COMMENT) return true;
       }
diff --git a/pubspec.lock b/pubspec.lock
index 62aa5bd..f3bd718 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -134,6 +134,13 @@
       url: "https://pub.dartlang.org"
     source: hosted
     version: "0.6.3"
+  lints:
+    dependency: "direct dev"
+    description:
+      name: lints
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.1"
   logging:
     dependency: transitive
     description:
@@ -184,7 +191,7 @@
     source: hosted
     version: "1.8.0"
   pedantic:
-    dependency: "direct dev"
+    dependency: transitive
     description:
       name: pedantic
       url: "https://pub.dartlang.org"
diff --git a/pubspec.yaml b/pubspec.yaml
index d858cac..033381c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: dart_style
 # Note: See tool/grind.dart for how to bump the version.
-version: 2.2.0
+version: 2.2.1-dev
 description: >-
   Opinionated, automatic Dart source code formatter.
   Provides an API and a CLI tool.
@@ -22,7 +22,7 @@
   # TODO(rnystrom): Disabled for now because node_preamble is not migrated yet
   # and publishing to npm hasn't been used in a while.
   #  node_preamble: ^1.0.0
-  pedantic: ^1.0.0
+  lints: ^1.0.0
   test: ^1.16.8
   test_descriptor: ^2.0.0
   test_process: ^2.0.0
diff --git a/test/command_line_test.dart b/test/command_line_test.dart
index 54d2034..0596e51 100644
--- a/test/command_line_test.dart
+++ b/test/command_line_test.dart
@@ -7,8 +7,8 @@
 import 'dart:convert';
 
 import 'package:path/path.dart' as p;
-import 'package:test_descriptor/test_descriptor.dart' as d;
 import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
 
 import 'utils.dart';
 
diff --git a/test/command_test.dart b/test/command_test.dart
index a6dece9..57d3ad8 100644
--- a/test/command_test.dart
+++ b/test/command_test.dart
@@ -5,8 +5,8 @@
 import 'dart:convert';
 
 import 'package:path/path.dart' as p;
-import 'package:test_descriptor/test_descriptor.dart' as d;
 import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
 
 import 'utils.dart';
 
diff --git a/test/fix_test.dart b/test/fix_test.dart
index 028930d..d65f99a 100644
--- a/test/fix_test.dart
+++ b/test/fix_test.dart
@@ -5,9 +5,8 @@
 @TestOn('vm')
 library dart_style.test.fix_test;
 
-import 'package:test/test.dart';
-
 import 'package:dart_style/dart_style.dart';
+import 'package:test/test.dart';
 
 import 'utils.dart';
 
diff --git a/test/formatter_test.dart b/test/formatter_test.dart
index e7f10f8..f9966ce 100644
--- a/test/formatter_test.dart
+++ b/test/formatter_test.dart
@@ -5,9 +5,8 @@
 @TestOn('vm')
 library dart_style.test.formatter_test;
 
-import 'package:test/test.dart';
-
 import 'package:dart_style/dart_style.dart';
+import 'package:test/test.dart';
 
 import 'utils.dart';
 
diff --git a/test/io_test.dart b/test/io_test.dart
index 00aae58..c4b1b8a 100644
--- a/test/io_test.dart
+++ b/test/io_test.dart
@@ -6,12 +6,11 @@
 
 import 'dart:io';
 
+import 'package:dart_style/src/cli/formatter_options.dart';
 import 'package:dart_style/src/io.dart';
 import 'package:path/path.dart' as p;
-import 'package:test_descriptor/test_descriptor.dart' as d;
 import 'package:test/test.dart';
-
-import 'package:dart_style/src/cli/formatter_options.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
 
 import 'utils.dart';
 
diff --git a/test/source_code_test.dart b/test/source_code_test.dart
index 3895e10..3b4b1e3 100644
--- a/test/source_code_test.dart
+++ b/test/source_code_test.dart
@@ -4,9 +4,8 @@
 
 library dart_style.test.source_code_test;
 
-import 'package:test/test.dart';
-
 import 'package:dart_style/dart_style.dart';
+import 'package:test/test.dart';
 
 void main() {
   var selection = SourceCode('123456;', selectionStart: 3, selectionLength: 2);
diff --git a/test/string_compare_test.dart b/test/string_compare_test.dart
index 3adaa71..7c6e5e6 100644
--- a/test/string_compare_test.dart
+++ b/test/string_compare_test.dart
@@ -5,9 +5,8 @@
 @TestOn('vm')
 library dart_style.test.string_compare_test;
 
-import 'package:test/test.dart';
-
 import 'package:dart_style/src/string_compare.dart';
+import 'package:test/test.dart';
 
 void main() {
   test('whitespace at end of string', () {
diff --git a/test/utils.dart b/test/utils.dart
index 926841f..593b4d9 100644
--- a/test/utils.dart
+++ b/test/utils.dart
@@ -7,13 +7,12 @@
 import 'dart:io';
 import 'dart:mirrors';
 
+import 'package:dart_style/dart_style.dart';
 import 'package:path/path.dart' as p;
 import 'package:test/test.dart';
 import 'package:test_descriptor/test_descriptor.dart' as d;
 import 'package:test_process/test_process.dart';
 
-import 'package:dart_style/dart_style.dart';
-
 const unformattedSource = 'void  main()  =>  print("hello") ;';
 const formattedSource = 'void main() => print("hello");\n';
 
@@ -183,7 +182,7 @@
     var lines = File(path).readAsLinesSync();
 
     // The first line may have a "|" to indicate the page width.
-    var pageWidth;
+    int? pageWidth;
     if (lines[0].endsWith('|')) {
       pageWidth = lines[0].indexOf('|');
       lines = lines.skip(1).toList();
diff --git a/tool/grind.dart b/tool/grind.dart
index cb8f8b6..95cc0f2 100644
--- a/tool/grind.dart
+++ b/tool/grind.dart
@@ -99,7 +99,7 @@
   // Read the version from the pubspec.
   var pubspecFile = getFile('pubspec.yaml');
   var pubspec = pubspecFile.readAsStringSync();
-  var version = Version.parse(yaml.loadYaml(pubspec)['version']);
+  var version = Version.parse((yaml.loadYaml(pubspec) as Map)['version']);
 
   // Require a "-dev" version since we don't otherwise know what to bump it to.
   if (!version.isPreRelease) throw 'Cannot publish non-dev version $version.';
diff --git a/tool/node_format_service.dart b/tool/node_format_service.dart
index a877003..7ce38d8 100644
--- a/tool/node_format_service.dart
+++ b/tool/node_format_service.dart
@@ -7,9 +7,8 @@
 
 import 'dart:math' as math;
 
-import 'package:js/js.dart';
-
 import 'package:dart_style/dart_style.dart';
+import 'package:js/js.dart';
 
 @JS()
 @anonymous
@@ -26,7 +25,7 @@
   formatCode = allowInterop((String source) {
     var formatter = DartFormatter();
 
-    var exception;
+    FormatterException exception;
     try {
       return FormatResult(code: DartFormatter().format(source));
     } on FormatterException catch (err) {