Remove pedantic and cleanup a few lints (#3224)

* Remove pedantic and cleanup a few lints

* Do not use super as an object

* Rename SolveType constants

* Retain prefer_single_quotes

* Rename to camelCase in log.dart
diff --git a/analysis_options.yaml b/analysis_options.yaml
index f469a93..f07a060 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,4 +1,4 @@
-include: package:pedantic/analysis_options.yaml
+include: package:lints/recommended.yaml
 
 analyzer:
   errors:
@@ -12,52 +12,26 @@
 linter:
   rules:
     - avoid_catching_errors
-    - avoid_function_literals_in_foreach_calls
     - avoid_private_typedef_functions
     - avoid_redundant_argument_values
-    - avoid_renaming_method_parameters
     - avoid_returning_null_for_future
-    - avoid_returning_null_for_void
     - avoid_unused_constructor_parameters
     - avoid_void_async
-    - await_only_futures
-    - camel_case_types
     - cancel_subscriptions
-    - control_flow_in_finally
     - directives_ordering
-    - empty_statements
-    - file_names
-    - implementation_imports
-    - iterable_contains_unrelated_type
-    - list_remove_unrelated_type
     - missing_whitespace_between_adjacent_strings
     - no_adjacent_strings_in_list
     - no_runtimeType_toString
-    - non_constant_identifier_names
     - only_throw_errors
-    - overridden_fields
     - package_api_docs
-    - package_names
-    - package_prefixed_library_names
     - prefer_asserts_in_initializer_lists
     - prefer_const_declarations
-    - prefer_function_declarations_over_variables
-    - prefer_initializing_formals
-    - prefer_inlined_adds
-    - prefer_is_not_operator
-    - prefer_null_aware_operators
     - prefer_relative_imports
-    - prefer_typing_uninitialized_variables
-    - prefer_void_to_null
+    - prefer_single_quotes
     - sort_pub_dependencies
     - test_types_in_equals
     - throw_in_finally
-    - unnecessary_brace_in_string_interps
-    - unnecessary_getters_setters
     - unnecessary_lambdas
     - unnecessary_null_aware_assignments
-    - unnecessary_overrides
     - unnecessary_parenthesis
     - unnecessary_statements
-    - unnecessary_string_interpolations
-    - void_checks
diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart
index 09cc426..f268381 100644
--- a/lib/src/command/add.dart
+++ b/lib/src/command/add.dart
@@ -111,7 +111,7 @@
       /// that a resolution exists before we update pubspec.yaml.
       // TODO(sigurdm): We should really use a spinner here.
       solveResult = await resolveVersions(
-          SolveType.UPGRADE, cache, Package.inMemory(updatedPubSpec));
+          SolveType.upgrade, cache, Package.inMemory(updatedPubSpec));
     } on GitException {
       dataError('Unable to resolve package "${package.name}" with the given '
           'git parameters.');
@@ -149,7 +149,7 @@
       // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output
       await Entrypoint.global(newRoot, entrypoint.lockFile, cache,
               solveResult: solveResult)
-          .acquireDependencies(SolveType.GET,
+          .acquireDependencies(SolveType.get,
               dryRun: true,
               precompile: argResults['precompile'],
               analytics: analytics);
@@ -164,14 +164,14 @@
       /// pubspec file.
       final updatedEntrypoint = Entrypoint(directory, cache);
       await updatedEntrypoint.acquireDependencies(
-        SolveType.GET,
+        SolveType.get,
         precompile: argResults['precompile'],
         analytics: analytics,
       );
 
       if (argResults['example'] && entrypoint.example != null) {
         await entrypoint.example!.acquireDependencies(
-          SolveType.GET,
+          SolveType.get,
           precompile: argResults['precompile'],
           onlyReportSuccessOrFailure: true,
           analytics: analytics,
diff --git a/lib/src/command/downgrade.dart b/lib/src/command/downgrade.dart
index 5dd9d41..274ab48 100644
--- a/lib/src/command/downgrade.dart
+++ b/lib/src/command/downgrade.dart
@@ -53,7 +53,7 @@
     var dryRun = argResults['dry-run'];
 
     await entrypoint.acquireDependencies(
-      SolveType.DOWNGRADE,
+      SolveType.downgrade,
       unlock: argResults.rest,
       dryRun: dryRun,
       analytics: analytics,
@@ -61,7 +61,7 @@
     var example = entrypoint.example;
     if (argResults['example'] && example != null) {
       await example.acquireDependencies(
-        SolveType.GET,
+        SolveType.get,
         unlock: argResults.rest,
         dryRun: dryRun,
         onlyReportSuccessOrFailure: true,
diff --git a/lib/src/command/get.dart b/lib/src/command/get.dart
index 9255e1e..302bb93 100644
--- a/lib/src/command/get.dart
+++ b/lib/src/command/get.dart
@@ -50,7 +50,7 @@
           'The --packages-dir flag is no longer used and does nothing.'));
     }
     await entrypoint.acquireDependencies(
-      SolveType.GET,
+      SolveType.get,
       dryRun: argResults['dry-run'],
       precompile: argResults['precompile'],
       analytics: analytics,
@@ -58,7 +58,7 @@
 
     var example = entrypoint.example;
     if (argResults['example'] && example != null) {
-      await example.acquireDependencies(SolveType.GET,
+      await example.acquireDependencies(SolveType.get,
           dryRun: argResults['dry-run'],
           precompile: argResults['precompile'],
           onlyReportSuccessOrFailure: true,
diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart
index cedbadf..609b7ae 100644
--- a/lib/src/command/outdated.dart
+++ b/lib/src/command/outdated.dart
@@ -392,7 +392,7 @@
 /// resolution was found.
 Future<List<PackageId>?> _tryResolve(Pubspec pubspec, SystemCache cache) async {
   final solveResult = await tryResolveVersions(
-    SolveType.UPGRADE,
+    SolveType.upgrade,
     cache,
     Package.inMemory(pubspec),
   );
@@ -833,6 +833,9 @@
           _overridden == other._overridden &&
           _id.source == other._id.source &&
           _pubspec.version == other._pubspec.version;
+
+  @override
+  int get hashCode => Object.hash(_pubspec.version, _id.source, _overridden);
 }
 
 class _PackageDetails implements Comparable<_PackageDetails> {
diff --git a/lib/src/command/remove.dart b/lib/src/command/remove.dart
index c7c674a..af91d8c 100644
--- a/lib/src/command/remove.dart
+++ b/lib/src/command/remove.dart
@@ -66,7 +66,7 @@
       final newRoot = Package.inMemory(newPubspec);
 
       await Entrypoint.global(newRoot, entrypoint.lockFile, cache)
-          .acquireDependencies(SolveType.GET,
+          .acquireDependencies(SolveType.get,
               precompile: argResults['precompile'],
               dryRun: true,
               analytics: null);
@@ -78,7 +78,7 @@
       /// pubspec file.
       final updatedEntrypoint = Entrypoint(directory, cache);
       await updatedEntrypoint.acquireDependencies(
-        SolveType.GET,
+        SolveType.get,
         precompile: argResults['precompile'],
         analytics: analytics,
       );
@@ -86,7 +86,7 @@
       var example = entrypoint.example;
       if (argResults['example'] && example != null) {
         await example.acquireDependencies(
-          SolveType.GET,
+          SolveType.get,
           precompile: argResults['precompile'],
           onlyReportSuccessOrFailure: true,
           analytics: analytics,
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart
index 8e44abf..34e061d 100644
--- a/lib/src/command/upgrade.dart
+++ b/lib/src/command/upgrade.dart
@@ -121,7 +121,7 @@
 
   Future<void> _runUpgrade(Entrypoint e, {bool onlySummary = false}) async {
     await e.acquireDependencies(
-      SolveType.UPGRADE,
+      SolveType.upgrade,
       unlock: argResults.rest,
       dryRun: _dryRun,
       precompile: _precompile,
@@ -179,7 +179,7 @@
     final resolvedPackages = <String, PackageId>{};
     final solveResult = await log.spinner('Resolving dependencies', () async {
       return await resolveVersions(
-        SolveType.UPGRADE,
+        SolveType.upgrade,
         cache,
         Package.inMemory(resolvablePubspec),
       );
@@ -229,7 +229,7 @@
         cache,
         solveResult: solveResult,
       ).acquireDependencies(
-        SolveType.UPGRADE,
+        SolveType.upgrade,
         dryRun: true,
         precompile: _precompile,
         analytics: null, // No analytics for dry-run
@@ -241,7 +241,7 @@
       //       we can show the changes when not in --dry-run mode. For now we only show
       //       the changes made to pubspec.yaml in dry-run mode.
       await Entrypoint(directory, cache).acquireDependencies(
-        SolveType.UPGRADE,
+        SolveType.upgrade,
         precompile: _precompile,
         analytics: analytics,
       );
@@ -276,7 +276,7 @@
     final resolvedPackages = <String, PackageId>{};
     final solveResult = await log.spinner('Resolving dependencies', () async {
       return await resolveVersions(
-        SolveType.UPGRADE,
+        SolveType.upgrade,
         cache,
         Package.inMemory(nullsafetyPubspec),
       );
@@ -323,7 +323,7 @@
         cache,
         solveResult: solveResult,
       ).acquireDependencies(
-        SolveType.UPGRADE,
+        SolveType.upgrade,
         dryRun: true,
         precompile: _precompile,
         analytics: null,
@@ -335,7 +335,7 @@
       //       we can show the changes in --dry-run mode. For now we only show
       //       the changes made to pubspec.yaml in dry-run mode.
       await Entrypoint(directory, cache).acquireDependencies(
-        SolveType.UPGRADE,
+        SolveType.upgrade,
         precompile: _precompile,
         analytics: analytics,
       );
diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart
index 4ed33f6..02faaf9 100644
--- a/lib/src/command_runner.dart
+++ b/lib/src/command_runner.dart
@@ -58,21 +58,21 @@
   Verbosity get verbosity {
     switch (argResults['verbosity']) {
       case 'error':
-        return log.Verbosity.ERROR;
+        return log.Verbosity.error;
       case 'warning':
-        return log.Verbosity.WARNING;
+        return log.Verbosity.warning;
       case 'normal':
-        return log.Verbosity.NORMAL;
+        return log.Verbosity.normal;
       case 'io':
-        return log.Verbosity.IO;
+        return log.Verbosity.io;
       case 'solver':
-        return log.Verbosity.SOLVER;
+        return log.Verbosity.solver;
       case 'all':
-        return log.Verbosity.ALL;
+        return log.Verbosity.all;
       default:
         // No specific verbosity given, so check for the shortcut.
-        if (argResults['verbose']) return log.Verbosity.ALL;
-        return log.Verbosity.NORMAL;
+        if (argResults['verbose']) return log.Verbosity.all;
+        return log.Verbosity.normal;
     }
   }
 
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
index 2112acc..5d8ea8b 100644
--- a/lib/src/executable.dart
+++ b/lib/src/executable.dart
@@ -306,7 +306,7 @@
     try {
       await warningsOnlyUnlessTerminal(
         () => entrypoint.acquireDependencies(
-          SolveType.GET,
+          SolveType.get,
           analytics: analytics,
         ),
       );
diff --git a/lib/src/exit_codes.dart b/lib/src/exit_codes.dart
index e072ef2..c6acaf7 100644
--- a/lib/src/exit_codes.dart
+++ b/lib/src/exit_codes.dart
@@ -2,6 +2,8 @@
 // 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: constant_identifier_names
+
 /// Exit code constants.
 ///
 /// From [the BSD sysexits manpage][manpage]. Not every constant here is used,
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart
index 578eca1..a868b4b 100644
--- a/lib/src/global_packages.dart
+++ b/lib/src/global_packages.dart
@@ -149,7 +149,7 @@
     var entrypoint = Entrypoint(path, cache);
 
     // Get the package's dependencies.
-    await entrypoint.acquireDependencies(SolveType.GET, analytics: analytics);
+    await entrypoint.acquireDependencies(SolveType.get, analytics: analytics);
     var name = entrypoint.root.name;
 
     try {
@@ -201,7 +201,7 @@
     SolveResult result;
     try {
       result = await log.progress('Resolving dependencies',
-          () => resolveVersions(SolveType.GET, cache, root));
+          () => resolveVersions(SolveType.get, cache, root));
     } on SolveFailure catch (error) {
       for (var incompatibility
           in error.incompatibility.externalIncompatibilities) {
@@ -221,7 +221,7 @@
 To recompile executables, first run `$topLevelProgram pub global deactivate ${dep.name}`.
 ''');
     } else {
-      await result.showReport(SolveType.GET, cache);
+      await result.showReport(SolveType.get, cache);
     }
 
     // Make sure all of the dependencies are locally installed.
diff --git a/lib/src/http.dart b/lib/src/http.dart
index fb6e9aa..724962b 100644
--- a/lib/src/http.dart
+++ b/lib/src/http.dart
@@ -10,7 +10,6 @@
 
 import 'package:http/http.dart' as http;
 import 'package:http/retry.dart';
-import 'package:pedantic/pedantic.dart';
 import 'package:pool/pool.dart';
 import 'package:stack_trace/stack_trace.dart';
 
diff --git a/lib/src/io.dart b/lib/src/io.dart
index d6af9c2..231aba5 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -14,7 +14,6 @@
 import 'package:http_multi_server/http_multi_server.dart';
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as path;
-import 'package:pedantic/pedantic.dart';
 import 'package:pool/pool.dart';
 import 'package:stack_trace/stack_trace.dart';
 
diff --git a/lib/src/log.dart b/lib/src/log.dart
index ff7fe29..930e0fb 100644
--- a/lib/src/log.dart
+++ b/lib/src/log.dart
@@ -24,7 +24,7 @@
 final json = _JsonLogger();
 
 /// The current logging verbosity.
-Verbosity verbosity = Verbosity.NORMAL;
+Verbosity verbosity = Verbosity.normal;
 
 /// In cases where there's a ton of log spew, make sure we don't eat infinite
 /// memory.
@@ -32,7 +32,7 @@
 /// This can occur when the backtracking solver stumbles into a pathological
 /// dependency graph. It generally will find a solution, but it may log
 /// thousands and thousands of entries to get there.
-const _MAX_TRANSCRIPT = 10000;
+const _maxTranscript = 10000;
 
 /// The list of recorded log messages. Will only be recorded if
 /// [recordTranscript()] is called.
@@ -58,34 +58,34 @@
 /// An enum type for defining the different logging levels a given message can
 /// be associated with.
 ///
-/// By default, [ERROR] and [WARNING] messages are printed to sterr. [MESSAGE]
+/// By default, [error] and [warning] messages are printed to sterr. [message]
 /// messages are printed to stdout, and others are ignored.
 class Level {
   /// An error occurred and an operation could not be completed.
   ///
   /// Usually shown to the user on stderr.
-  static const ERROR = Level._('ERR ');
+  static const error = Level._('ERR ');
 
   /// Something unexpected happened, but the program was able to continue,
   /// though possibly in a degraded fashion.
-  static const WARNING = Level._('WARN');
+  static const warning = Level._('WARN');
 
   /// A message intended specifically to be shown to the user.
-  static const MESSAGE = Level._('MSG ');
+  static const message = Level._('MSG ');
 
   /// Some interaction with the external world occurred, such as a network
   /// operation, process spawning, or file IO.
-  static const IO = Level._('IO  ');
+  static const io = Level._('IO  ');
 
   /// Incremental output during pub's version constraint solver.
-  static const SOLVER = Level._('SLVR');
+  static const solver = Level._('SLVR');
 
   /// Fine-grained and verbose additional information.
   ///
   /// Used to provide program state context for other logs (such as what pub
   /// was doing when an IO operation occurred) or just more detail for an
   /// operation.
-  static const FINE = Level._('FINE');
+  static const fine = Level._('FINE');
 
   const Level._(this.name);
 
@@ -99,73 +99,73 @@
 /// displayed.
 class Verbosity {
   /// Silence all logging.
-  static const NONE = Verbosity._('none', {
-    Level.ERROR: null,
-    Level.WARNING: null,
-    Level.MESSAGE: null,
-    Level.IO: null,
-    Level.SOLVER: null,
-    Level.FINE: null
+  static const none = Verbosity._('none', {
+    Level.error: null,
+    Level.warning: null,
+    Level.message: null,
+    Level.io: null,
+    Level.solver: null,
+    Level.fine: null
   });
 
   /// Shows only errors.
-  static const ERROR = Verbosity._('error', {
-    Level.ERROR: _logToStderr,
-    Level.WARNING: null,
-    Level.MESSAGE: null,
-    Level.IO: null,
-    Level.SOLVER: null,
-    Level.FINE: null
+  static const error = Verbosity._('error', {
+    Level.error: _logToStderr,
+    Level.warning: null,
+    Level.message: null,
+    Level.io: null,
+    Level.solver: null,
+    Level.fine: null
   });
 
   /// Shows only errors and warnings.
-  static const WARNING = Verbosity._('warning', {
-    Level.ERROR: _logToStderr,
-    Level.WARNING: _logToStderr,
-    Level.MESSAGE: null,
-    Level.IO: null,
-    Level.SOLVER: null,
-    Level.FINE: null
+  static const warning = Verbosity._('warning', {
+    Level.error: _logToStderr,
+    Level.warning: _logToStderr,
+    Level.message: null,
+    Level.io: null,
+    Level.solver: null,
+    Level.fine: null
   });
 
   /// The default verbosity which shows errors, warnings, and messages.
-  static const NORMAL = Verbosity._('normal', {
-    Level.ERROR: _logToStderr,
-    Level.WARNING: _logToStderr,
-    Level.MESSAGE: _logToStdout,
-    Level.IO: null,
-    Level.SOLVER: null,
-    Level.FINE: null
+  static const normal = Verbosity._('normal', {
+    Level.error: _logToStderr,
+    Level.warning: _logToStderr,
+    Level.message: _logToStdout,
+    Level.io: null,
+    Level.solver: null,
+    Level.fine: null
   });
 
   /// Shows errors, warnings, messages, and IO event logs.
-  static const IO = Verbosity._('io', {
-    Level.ERROR: _logToStderrWithLabel,
-    Level.WARNING: _logToStderrWithLabel,
-    Level.MESSAGE: _logToStdoutWithLabel,
-    Level.IO: _logToStderrWithLabel,
-    Level.SOLVER: null,
-    Level.FINE: null
+  static const io = Verbosity._('io', {
+    Level.error: _logToStderrWithLabel,
+    Level.warning: _logToStderrWithLabel,
+    Level.message: _logToStdoutWithLabel,
+    Level.io: _logToStderrWithLabel,
+    Level.solver: null,
+    Level.fine: null
   });
 
   /// Shows errors, warnings, messages, and version solver logs.
-  static const SOLVER = Verbosity._('solver', {
-    Level.ERROR: _logToStderr,
-    Level.WARNING: _logToStderr,
-    Level.MESSAGE: _logToStdout,
-    Level.IO: null,
-    Level.SOLVER: _logToStdout,
-    Level.FINE: null
+  static const solver = Verbosity._('solver', {
+    Level.error: _logToStderr,
+    Level.warning: _logToStderr,
+    Level.message: _logToStdout,
+    Level.io: null,
+    Level.solver: _logToStdout,
+    Level.fine: null
   });
 
   /// Shows all logs.
-  static const ALL = Verbosity._('all', {
-    Level.ERROR: _logToStderrWithLabel,
-    Level.WARNING: _logToStderrWithLabel,
-    Level.MESSAGE: _logToStdoutWithLabel,
-    Level.IO: _logToStderrWithLabel,
-    Level.SOLVER: _logToStderrWithLabel,
-    Level.FINE: _logToStderrWithLabel
+  static const all = Verbosity._('all', {
+    Level.error: _logToStderrWithLabel,
+    Level.warning: _logToStderrWithLabel,
+    Level.message: _logToStdoutWithLabel,
+    Level.io: _logToStderrWithLabel,
+    Level.solver: _logToStderrWithLabel,
+    Level.fine: _logToStderrWithLabel
   });
 
   const Verbosity._(this.name, this._loggers);
@@ -188,7 +188,7 @@
   _Entry(this.level, this.lines);
 }
 
-/// Logs [message] at [Level.ERROR].
+/// Logs [message] at [Level.error].
 ///
 /// If [error] is passed, it's appended to [message]. If [trace] is passed, it's
 /// printed at log level fine.
@@ -198,24 +198,24 @@
     message = message.isEmpty ? '$error' : '$message: $error';
     if (error is Error && trace == null) trace = error.stackTrace;
   }
-  write(Level.ERROR, message);
-  if (trace != null) write(Level.FINE, Chain.forTrace(trace));
+  write(Level.error, message);
+  if (trace != null) write(Level.fine, Chain.forTrace(trace));
 }
 
-/// Logs [message] at [Level.WARNING].
-void warning(message) => write(Level.WARNING, message);
+/// Logs [message] at [Level.warning].
+void warning(message) => write(Level.warning, message);
 
-/// Logs [message] at [Level.MESSAGE].
-void message(message) => write(Level.MESSAGE, message);
+/// Logs [message] at [Level.message].
+void message(message) => write(Level.message, message);
 
-/// Logs [message] at [Level.IO].
-void io(message) => write(Level.IO, message);
+/// Logs [message] at [Level.io].
+void io(message) => write(Level.io, message);
 
-/// Logs [message] at [Level.SOLVER].
-void solver(message) => write(Level.SOLVER, message);
+/// Logs [message] at [Level.solver].
+void solver(message) => write(Level.solver, message);
 
-/// Logs [message] at [Level.FINE].
-void fine(message) => write(Level.FINE, message);
+/// Logs [message] at [Level.fine].
+void fine(message) => write(Level.fine, message);
 
 /// Logs [message] at [level].
 void write(Level level, message) {
@@ -236,7 +236,7 @@
   if (_transcript != null) _transcript!.add(entry);
 }
 
-/// Logs the spawning of an [executable] process with [arguments] at [IO]
+/// Logs the spawning of an [executable] process with [arguments] at [io]
 /// level.
 void process(
     String executable, List<String> arguments, String workingDirectory) {
@@ -315,7 +315,7 @@
 
 /// Enables recording of log entries.
 void recordTranscript() {
-  _transcript = Transcript<_Entry>(_MAX_TRANSCRIPT);
+  _transcript = Transcript<_Entry>(_maxTranscript);
 }
 
 /// If [recordTranscript()] was called, then prints the previously recorded log
@@ -339,8 +339,8 @@
 /// This is useful to not pollute stdout when the output is piped somewhere.
 Future<T> warningsOnlyUnlessTerminal<T>(FutureOr<T> Function() callback) async {
   final oldVerbosity = verbosity;
-  if (verbosity == Verbosity.NORMAL && !stdout.hasTerminal) {
-    verbosity = Verbosity.WARNING;
+  if (verbosity == Verbosity.normal && !stdout.hasTerminal) {
+    verbosity = Verbosity.warning;
   }
   final result = await callback();
   verbosity = oldVerbosity;
@@ -353,7 +353,7 @@
 /// If anything else is logged during this (including another call to
 /// [progress]) that cancels the progress animation, although the total time
 /// will still be printed once it finishes. If [fine] is passed, the progress
-/// information will only be visible at [Level.FINE].
+/// information will only be visible at [Level.fine].
 Future<T> progress<T>(String message, Future<T> Function() callback) {
   _stopProgress();
 
diff --git a/lib/src/null_safety_analysis.dart b/lib/src/null_safety_analysis.dart
index 2ad034d..5b882a8 100644
--- a/lib/src/null_safety_analysis.dart
+++ b/lib/src/null_safety_analysis.dart
@@ -109,7 +109,7 @@
     SolveResult result;
     try {
       result = await resolveVersions(
-        SolveType.GET,
+        SolveType.get,
         _systemCache,
         fakeRoot,
       );
diff --git a/lib/src/package_name.dart b/lib/src/package_name.dart
index 50f4bcc..d83f466 100644
--- a/lib/src/package_name.dart
+++ b/lib/src/package_name.dart
@@ -57,6 +57,10 @@
   }
 
   @override
+  bool operator ==(Object other) =>
+      throw UnimplementedError('Subclass should implement ==');
+
+  @override
   int get hashCode {
     var thisSource = source;
     if (thisSource == null) return name.hashCode;
@@ -104,6 +108,9 @@
 
   @override
   bool operator ==(other) => other is PackageRef && samePackage(other);
+
+  @override
+  int get hashCode => super.hashCode ^ 'PackageRef'.hashCode;
 }
 
 /// A reference to a specific version of a package.
diff --git a/lib/src/progress.dart b/lib/src/progress.dart
index 06ad9e9..b9c6931 100644
--- a/lib/src/progress.dart
+++ b/lib/src/progress.dart
@@ -34,7 +34,7 @@
   Progress(this._message, {bool fine = false}) {
     _stopwatch.start();
 
-    var level = fine ? log.Level.FINE : log.Level.MESSAGE;
+    var level = fine ? log.Level.fine : log.Level.message;
 
     // The animation is only shown when it would be meaningful to a human.
     // That means we're writing a visible message to a TTY at normal log levels
@@ -43,7 +43,7 @@
         !log.verbosity.isLevelVisible(level) ||
         log.json.enabled ||
         fine ||
-        log.verbosity.isLevelVisible(log.Level.FINE)) {
+        log.verbosity.isLevelVisible(log.Level.fine)) {
       // Not animating, so just log the start and wait until the task is
       // completed.
       log.write(level, '$_message...');
diff --git a/lib/src/pub_embeddable_command.dart b/lib/src/pub_embeddable_command.dart
index c1fa863..a46e3f5 100644
--- a/lib/src/pub_embeddable_command.dart
+++ b/lib/src/pub_embeddable_command.dart
@@ -105,7 +105,7 @@
 
   @override
   Verbosity get verbosity =>
-      argResults['verbose'] ? Verbosity.ALL : Verbosity.NORMAL;
+      argResults['verbose'] ? Verbosity.all : Verbosity.normal;
 
   @override
   bool get trace => argResults['verbose'];
diff --git a/lib/src/rate_limited_scheduler.dart b/lib/src/rate_limited_scheduler.dart
index 2d301d3..85d73cd 100644
--- a/lib/src/rate_limited_scheduler.dart
+++ b/lib/src/rate_limited_scheduler.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 import 'dart:collection';
 
-import 'package:pedantic/pedantic.dart';
 import 'package:pool/pool.dart';
 
 /// Handles rate-limited scheduling of tasks.
diff --git a/lib/src/solver/report.dart b/lib/src/solver/report.dart
index 251c290..3b72cd8 100644
--- a/lib/src/solver/report.dart
+++ b/lib/src/solver/report.dart
@@ -89,7 +89,7 @@
       }
     } else {
       if (numChanged == 0) {
-        if (_type == SolveType.GET) {
+        if (_type == SolveType.get) {
           log.message('Got dependencies$suffix!');
         } else {
           log.message('No dependencies changed$suffix.');
@@ -245,7 +245,7 @@
     String? message;
     // See if there are any newer versions of the package that we were
     // unable to upgrade to.
-    if (newId != null && _type != SolveType.DOWNGRADE) {
+    if (newId != null && _type != SolveType.downgrade) {
       var versions = _result.availableVersions[newId.name]!;
 
       var newerStable = false;
@@ -292,7 +292,7 @@
       }
     }
 
-    if (_type == SolveType.GET &&
+    if (_type == SolveType.get &&
         !(alwaysShow || changed || addedOrRemoved || message != null)) {
       return;
     }
diff --git a/lib/src/solver/result.dart b/lib/src/solver/result.dart
index 692b05f..b8ff0e5 100644
--- a/lib/src/solver/result.dart
+++ b/lib/src/solver/result.dart
@@ -122,7 +122,7 @@
     final report =
         SolveReport(type, _sources, _root, _previousLockFile, this, cache);
     report.summarize(dryRun: dryRun);
-    if (type == SolveType.UPGRADE) {
+    if (type == SolveType.upgrade) {
       await report.reportDiscontinued();
       report.reportOutdated();
     }
diff --git a/lib/src/solver/type.dart b/lib/src/solver/type.dart
index c899e31..28a3230 100644
--- a/lib/src/solver/type.dart
+++ b/lib/src/solver/type.dart
@@ -6,15 +6,15 @@
 class SolveType {
   /// As few changes to the lockfile as possible to be consistent with the
   /// pubspec.
-  static const GET = SolveType._('get');
+  static const get = SolveType._('get');
 
   /// Upgrade all packages or specific packages to the highest versions
   /// possible, regardless of the lockfile.
-  static const UPGRADE = SolveType._('upgrade');
+  static const upgrade = SolveType._('upgrade');
 
   /// Downgrade all packages or specific packages to the lowest versions
   /// possible, regardless of the lockfile.
-  static const DOWNGRADE = SolveType._('downgrade');
+  static const downgrade = SolveType._('downgrade');
 
   final String _name;
 
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart
index 120244a..d4e3a75 100644
--- a/lib/src/solver/version_solver.dart
+++ b/lib/src/solver/version_solver.dart
@@ -485,7 +485,7 @@
           _root.dependencyType(package.name),
           overridden,
           _getAllowedRetracted(ref.name),
-          downgrade: _type == SolveType.DOWNGRADE);
+          downgrade: _type == SolveType.downgrade);
     });
   }
 
@@ -493,7 +493,7 @@
   ///
   /// Returns `null` if it isn't in the lockfile (or has been unlocked).
   PackageId? _getLocked(String? package) {
-    if (_type == SolveType.GET) {
+    if (_type == SolveType.get) {
       if (_unlock.contains(package)) {
         return null;
       }
@@ -503,7 +503,7 @@
     // When downgrading, we don't want to force the latest versions of
     // non-hosted packages, since they don't support multiple versions and thus
     // can't be downgraded.
-    if (_type == SolveType.DOWNGRADE) {
+    if (_type == SolveType.downgrade) {
       var locked = _lockFile.packages[package];
       if (locked != null && !locked.source!.hasMultipleVersions) return locked;
     }
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart
index def4a98..0b6fbaa 100644
--- a/lib/src/source/hosted.dart
+++ b/lib/src/source/hosted.dart
@@ -10,7 +10,6 @@
     show maxBy, IterableNullableExtension;
 import 'package:http/http.dart' as http;
 import 'package:path/path.dart' as p;
-import 'package:pedantic/pedantic.dart';
 import 'package:pub_semver/pub_semver.dart';
 import 'package:stack_trace/stack_trace.dart';
 
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 39439e9..2a5768e 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -375,7 +375,7 @@
 
   // If we're using verbose logging, be more verbose but more accurate when
   // reporting timing information.
-  var msString = log.verbosity.isLevelVisible(log.Level.FINE)
+  var msString = log.verbosity.isLevelVisible(log.Level.fine)
       ? _padLeft(ms.toString(), 3, '0')
       : (ms ~/ 100).toString();
 
diff --git a/lib/src/validator.dart b/lib/src/validator.dart
index 29392fa..1b07560 100644
--- a/lib/src/validator.dart
+++ b/lib/src/validator.dart
@@ -101,7 +101,7 @@
         'Make sure your SDK constraint excludes old versions:\n'
         '\n'
         'environment:\n'
-        '  sdk: \"$newSdkConstraint\"');
+        '  sdk: "$newSdkConstraint"');
   }
 
   /// Returns whether [version1] and [version2] are pre-releases of the same version.
diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart
index 063ad7e..ff25e53 100644
--- a/lib/src/validator/sdk_constraint.dart
+++ b/lib/src/validator/sdk_constraint.dart
@@ -50,7 +50,7 @@
             'Expand it manually instead:\n'
             '\n'
             'environment:\n'
-            '  sdk: \"$dartConstraintWithoutCaret\"');
+            '  sdk: "$dartConstraintWithoutCaret"');
       }
 
       if (dartConstraint.max == null) {
diff --git a/lib/src/validator/size.dart b/lib/src/validator/size.dart
index 8f258a9..e989518 100644
--- a/lib/src/validator/size.dart
+++ b/lib/src/validator/size.dart
@@ -10,7 +10,7 @@
 import '../validator.dart';
 
 /// The maximum size of the package to upload (100 MB).
-const _MAX_SIZE = 100 * 1024 * 1024;
+const _maxSize = 100 * 1024 * 1024;
 
 /// A validator that validates that a package isn't too big.
 class SizeValidator extends Validator {
@@ -21,7 +21,7 @@
   @override
   Future validate() {
     return packageSize.then((size) {
-      if (size <= _MAX_SIZE) return;
+      if (size <= _maxSize) return;
       var sizeInMb = (size / math.pow(2, 20)).toStringAsPrecision(4);
       // Current implementation of Package.listFiles skips hidden files
       var ignoreExists = fileExists(entrypoint.root.path('.gitignore'));
diff --git a/pubspec.yaml b/pubspec.yaml
index 8c76708..a7d9bb4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -18,7 +18,6 @@
   meta: ^1.3.0
   oauth2: ^2.0.0
   path: ^1.8.0
-  pedantic: ^1.11.0
   pool: ^1.5.0
   pub_semver: ^2.1.0
   shelf: ^1.1.1
@@ -29,6 +28,7 @@
   yaml_edit: ^2.0.0
 
 dev_dependencies:
+  lints: ^1.0.1
   shelf_test_handler: ^2.0.0
   test: ^1.17.3
   test_descriptor: ^2.0.0
diff --git a/test/cache/repair/handles_orphaned_binstub_test.dart b/test/cache/repair/handles_orphaned_binstub_test.dart
index 9c4e74a..0754496 100644
--- a/test/cache/repair/handles_orphaned_binstub_test.dart
+++ b/test/cache/repair/handles_orphaned_binstub_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _ORPHANED_BINSTUB = '''
+const _orphanedBinstub = '''
 #!/usr/bin/env sh
 # This file was created by pub v0.1.2-3.
 # Package: foo
@@ -20,7 +20,7 @@
 void main() {
   test('handles an orphaned binstub script', () async {
     await d.dir(cachePath, [
-      d.dir('bin', [d.file(binStubName('script'), _ORPHANED_BINSTUB)])
+      d.dir('bin', [d.file(binStubName('script'), _orphanedBinstub)])
     ]).create();
 
     await runPub(
diff --git a/test/cache/repair/updates_binstubs_test.dart b/test/cache/repair/updates_binstubs_test.dart
index 1cd848b..c311697 100644
--- a/test/cache/repair/updates_binstubs_test.dart
+++ b/test/cache/repair/updates_binstubs_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _OUTDATED_BINSTUB = '''
+const _outdatedBinstub = '''
 #!/usr/bin/env sh
 # This file was created by pub v0.1.2-3.
 # Package: foo
@@ -31,7 +31,7 @@
     await runPub(args: ['global', 'activate', 'foo']);
 
     await d.dir(cachePath, [
-      d.dir('bin', [d.file(binStubName('foo-script'), _OUTDATED_BINSTUB)])
+      d.dir('bin', [d.file(binStubName('foo-script'), _outdatedBinstub)])
     ]).create();
 
     // Repair them.
diff --git a/test/embedding/embedding_test.dart b/test/embedding/embedding_test.dart
index 20e127e..faef3b0 100644
--- a/test/embedding/embedding_test.dart
+++ b/test/embedding/embedding_test.dart
@@ -12,7 +12,7 @@
 import '../golden_file.dart';
 import '../test_pub.dart';
 
-const _command_runner = 'tool/test-bin/pub_command_runner.dart';
+const _commandRunner = 'tool/test-bin/pub_command_runner.dart';
 
 late String snapshot;
 
@@ -36,7 +36,7 @@
   await process.shouldExit(exitCode);
 
   buffer.writeln([
-    '\$ $_command_runner ${args.join(' ')}',
+    '\$ $_commandRunner ${args.join(' ')}',
     ...await process.stdout.rest.toList(),
   ].join('\n'));
   final stdErr = await process.stderr.rest.toList();
@@ -73,7 +73,7 @@
     final tempDir = Directory.systemTemp.createTempSync();
     snapshot = path.join(tempDir.path, 'command_runner.dart.snapshot');
     final r = Process.runSync(
-        Platform.resolvedExecutable, ['--snapshot=$snapshot', _command_runner]);
+        Platform.resolvedExecutable, ['--snapshot=$snapshot', _commandRunner]);
     expect(r.exitCode, 0, reason: r.stderr);
   });
 
diff --git a/test/embedding/get_executable_for_command_test.dart b/test/embedding/get_executable_for_command_test.dart
index 611f5ef..a74da6a 100644
--- a/test/embedding/get_executable_for_command_test.dart
+++ b/test/embedding/get_executable_for_command_test.dart
@@ -25,7 +25,7 @@
 }) async {
   final _cachePath = getPubTestEnvironment()['PUB_CACHE'];
   final oldVerbosity = log.verbosity;
-  log.verbosity = log.Verbosity.NONE;
+  log.verbosity = log.Verbosity.none;
   if (executable == null) {
     expect(
       () => getExecutableForCommand(
diff --git a/test/global/activate/outdated_binstub_test.dart b/test/global/activate/outdated_binstub_test.dart
index 5a5a0e6..64a379a 100644
--- a/test/global/activate/outdated_binstub_test.dart
+++ b/test/global/activate/outdated_binstub_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const _OUTDATED_BINSTUB = '''
+const _outdatedBinstub = '''
 #!/usr/bin/env sh
 # This file was created by pub v0.1.2-3.
 # Package: foo
@@ -31,7 +31,7 @@
     await runPub(args: ['global', 'activate', 'foo']);
 
     await d.dir(cachePath, [
-      d.dir('bin', [d.file(binStubName('foo-script'), _OUTDATED_BINSTUB)])
+      d.dir('bin', [d.file(binStubName('foo-script'), _outdatedBinstub)])
     ]).create();
 
     await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/runs_script_in_unchecked_mode_test.dart b/test/global/run/runs_script_in_unchecked_mode_test.dart
index d684c27..866847b 100644
--- a/test/global/run/runs_script_in_unchecked_mode_test.dart
+++ b/test/global/run/runs_script_in_unchecked_mode_test.dart
@@ -7,7 +7,7 @@
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
-const SCRIPT = '''
+const _script = '''
 main() {
   assert(false);
   print("no checks");
@@ -18,7 +18,7 @@
   test('runs a script in unchecked mode by default', () async {
     await servePackages((builder) {
       builder.serve('foo', '1.0.0', contents: [
-        d.dir('bin', [d.file('script.dart', SCRIPT)])
+        d.dir('bin', [d.file('script.dart', _script)])
       ]);
     });
 
diff --git a/test/rate_limited_scheduler_test.dart b/test/rate_limited_scheduler_test.dart
index e94bbc7..8562b07 100644
--- a/test/rate_limited_scheduler_test.dart
+++ b/test/rate_limited_scheduler_test.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 
-import 'package:pedantic/pedantic.dart';
 import 'package:pub/src/rate_limited_scheduler.dart';
 import 'package:test/test.dart';
 
diff --git a/test/run/allows_dart_extension_test.dart b/test/run/allows_dart_extension_test.dart
index 27640fc..962270f 100644
--- a/test/run/allows_dart_extension_test.dart
+++ b/test/run/allows_dart_extension_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const SCRIPT = """
+const _script = """
 import 'dart:io';
 
 main() {
@@ -21,7 +21,7 @@
   test('allows a ".dart" extension on the argument', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', SCRIPT)])
+      d.dir('bin', [d.file('script.dart', _script)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/forwards_signal_posix_test.dart b/test/run/forwards_signal_posix_test.dart
index 1a32be8..5205145 100644
--- a/test/run/forwards_signal_posix_test.dart
+++ b/test/run/forwards_signal_posix_test.dart
@@ -23,7 +23,7 @@
   ProcessSignal.sigwinch,
 ];
 
-const SCRIPT = """
+const _script = """
 import 'dart:io';
 
 main() {
@@ -41,7 +41,7 @@
   test('forwards signals to the inner script', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', SCRIPT)])
+      d.dir('bin', [d.file('script.dart', _script)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/includes_parent_directories_of_entrypoint_test.dart b/test/run/includes_parent_directories_of_entrypoint_test.dart
index d351ac4..6bc4e27 100644
--- a/test/run/includes_parent_directories_of_entrypoint_test.dart
+++ b/test/run/includes_parent_directories_of_entrypoint_test.dart
@@ -8,7 +8,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const SCRIPT = r"""
+const _script = r"""
 import '../../a.dart';
 import '../b.dart';
 main() {
@@ -26,7 +26,7 @@
         d.file('a.dart', "var a = 'a';"),
         d.dir('a', [
           d.file('b.dart', "var b = 'b';"),
-          d.dir('b', [d.file('app.dart', SCRIPT)])
+          d.dir('b', [d.file('app.dart', _script)])
         ])
       ])
     ]).create();
diff --git a/test/run/passes_along_arguments_test.dart b/test/run/passes_along_arguments_test.dart
index 66a7d53..624d9f2 100644
--- a/test/run/passes_along_arguments_test.dart
+++ b/test/run/passes_along_arguments_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const SCRIPT = '''
+const _script = '''
 main(List<String> args) {
   print(args.join(" "));
 }
@@ -17,7 +17,7 @@
   test('passes arguments to the spawned script', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('args.dart', SCRIPT)])
+      d.dir('bin', [d.file('args.dart', _script)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/precompile_test.dart b/test/run/precompile_test.dart
index ef8787d..5506a0b 100644
--- a/test/run/precompile_test.dart
+++ b/test/run/precompile_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const SCRIPT = r'''
+const _script = r'''
 import 'dart:io';
 
 main(List<String> args) {
@@ -59,7 +59,7 @@
 
     await servePackages((server) => server
       ..serve('test', '1.0.0', contents: [
-        d.dir('bin', [d.file('test.dart', SCRIPT)])
+        d.dir('bin', [d.file('test.dart', _script)])
       ]));
 
     await pubGet(
@@ -82,7 +82,7 @@
 
     await servePackages((server) => server
       ..serve('test', '1.0.0', contents: [
-        d.dir('bin', [d.file('test.dart', SCRIPT)])
+        d.dir('bin', [d.file('test.dart', _script)])
       ]));
 
     await pubGet(
@@ -106,7 +106,7 @@
 
     await servePackages((server) => server
       ..serve('test', '1.0.0', contents: [
-        d.dir('bin', [d.file('test.dart', SCRIPT)])
+        d.dir('bin', [d.file('test.dart', _script)])
       ]));
 
     await pubGet(
diff --git a/test/run/runs_app_in_entrypoint_test.dart b/test/run/runs_app_in_entrypoint_test.dart
index 27a7381..6cb932a 100644
--- a/test/run/runs_app_in_entrypoint_test.dart
+++ b/test/run/runs_app_in_entrypoint_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const SCRIPT = """
+const _script = """
 import 'dart:io';
 
 main() {
@@ -21,7 +21,7 @@
   test('runs a Dart application in the entrypoint package', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', SCRIPT)])
+      d.dir('bin', [d.file('script.dart', _script)])
     ]).create();
 
     await pubGet();
diff --git a/test/run/runs_the_script_in_unchecked_mode_test.dart b/test/run/runs_the_script_in_unchecked_mode_test.dart
index 2652706..026a748 100644
--- a/test/run/runs_the_script_in_unchecked_mode_test.dart
+++ b/test/run/runs_the_script_in_unchecked_mode_test.dart
@@ -7,7 +7,7 @@
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
-const SCRIPT = '''
+const _script = '''
 main() {
   assert(false);
   print("no checks");
@@ -18,7 +18,7 @@
   test('runs the script without assertions by default', () async {
     await d.dir(appPath, [
       d.appPubspec(),
-      d.dir('bin', [d.file('script.dart', SCRIPT)])
+      d.dir('bin', [d.file('script.dart', _script)])
     ]).create();
 
     await pubGet();
diff --git a/test/test_pub.dart b/test/test_pub.dart
index 3983f8b..5897d69 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -506,8 +506,8 @@
 
   StreamSplitter<Pair<log.Level, String>> createLogSplitter() {
     return StreamSplitter(StreamGroup.merge([
-      _outputToLog(super.stdoutStream(), log.Level.MESSAGE),
-      _outputToLog(super.stderrStream(), log.Level.ERROR)
+      _outputToLog(super.stdoutStream(), log.Level.message),
+      _outputToLog(super.stderrStream(), log.Level.error)
     ]));
   }
 
@@ -544,12 +544,12 @@
 
   final _logLineRegExp = RegExp(r'^([A-Z ]{4})[:|] (.*)$');
   final Map<String, log.Level> _logLevels = [
-    log.Level.ERROR,
-    log.Level.WARNING,
-    log.Level.MESSAGE,
-    log.Level.IO,
-    log.Level.SOLVER,
-    log.Level.FINE
+    log.Level.error,
+    log.Level.warning,
+    log.Level.message,
+    log.Level.io,
+    log.Level.solver,
+    log.Level.fine
   ].fold({}, (levels, level) {
     levels[level.name] = level;
     return levels;
@@ -571,7 +571,7 @@
   @override
   Stream<String> stdoutStream() {
     return _logSplitter.split().expand((entry) {
-      if (entry.first != log.Level.MESSAGE) return [];
+      if (entry.first != log.Level.message) return [];
       return [entry.last];
     });
   }
@@ -579,7 +579,7 @@
   @override
   Stream<String> stderrStream() {
     return _logSplitter.split().expand((entry) {
-      if (entry.first != log.Level.ERROR && entry.first != log.Level.WARNING) {
+      if (entry.first != log.Level.error && entry.first != log.Level.warning) {
         return [];
       }
       return [entry.last];
@@ -589,9 +589,9 @@
   /// A stream of log messages that are silent by default.
   Stream<String> silentStream() {
     return _logSplitter.split().expand((entry) {
-      if (entry.first == log.Level.MESSAGE) return [];
-      if (entry.first == log.Level.ERROR) return [];
-      if (entry.first == log.Level.WARNING) return [];
+      if (entry.first == log.Level.message) return [];
+      if (entry.first == log.Level.error) return [];
+      if (entry.first == log.Level.warning) return [];
       return [entry.last];
     });
   }