update package:dart_flutter_team_lints to use the beta package:lints (#179)

* update package:dart_flutter_team_lints to use the beta package:lints

* update pubspecs

* regenerate mono_repo files

* update package:lints dep

* Update pkgs/dart_flutter_team_lints/tool/dedup.dart

Co-authored-by: Nate Bosch <nbosch@google.com>

* review feedback

---------

Co-authored-by: Nate Bosch <nbosch@google.com>
diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml
index aec4e7f..fdbe387 100644
--- a/.github/workflows/dart.yml
+++ b/.github/workflows/dart.yml
@@ -1,4 +1,4 @@
-# Created with package:mono_repo v6.5.7
+# Created with package:mono_repo v6.6.0
 name: Dart CI
 on:
   push:
@@ -35,28 +35,27 @@
         name: Checkout repository
         uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
       - name: mono_repo self validate
-        run: dart pub global activate mono_repo 6.5.7
-      # TODO: disabled to validate a pre-release version of setup-dart
-      # - name: mono_repo self validate
-        # run: dart pub global run mono_repo generate --validate
+        run: dart pub global activate mono_repo 6.6.0
+      - name: mono_repo self validate
+        run: dart pub global run mono_repo generate --validate
   job_002:
-    name: "analyze_and_format; Dart 2.19.0; PKGS: pkgs/corpus, pkgs/repo_manage; `dart analyze --fatal-infos .`"
+    name: "analyze_and_format; Dart 3.0.0; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/firehose, pkgs/repo_manage; `dart analyze --fatal-infos .`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
         uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
         with:
           path: "~/.pub-cache/hosted"
-          key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus-pkgs/repo_manage;commands:analyze"
+          key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/firehose-pkgs/repo_manage;commands:analyze"
           restore-keys: |
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus-pkgs/repo_manage
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/corpus-pkgs/dart_flutter_team_lints-pkgs/firehose-pkgs/repo_manage
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
         uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1
         with:
-          sdk: "2.19.0"
+          sdk: "3.0.0"
       - id: checkout
         name: Checkout repository
         uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
@@ -69,38 +68,6 @@
         run: dart analyze --fatal-infos .
         if: "always() && steps.pkgs_corpus_pub_upgrade.conclusion == 'success'"
         working-directory: pkgs/corpus
-      - id: pkgs_repo_manage_pub_upgrade
-        name: pkgs/repo_manage; dart pub upgrade
-        run: dart pub upgrade
-        if: "always() && steps.checkout.conclusion == 'success'"
-        working-directory: pkgs/repo_manage
-      - name: "pkgs/repo_manage; dart analyze --fatal-infos ."
-        run: dart analyze --fatal-infos .
-        if: "always() && steps.pkgs_repo_manage_pub_upgrade.conclusion == 'success'"
-        working-directory: pkgs/repo_manage
-    needs:
-      - job_001
-  job_003:
-    name: "analyze_and_format; Dart 3.0.0; PKGS: pkgs/dart_flutter_team_lints, pkgs/firehose; `dart analyze --fatal-infos .`"
-    runs-on: ubuntu-latest
-    steps:
-      - name: Cache Pub hosted dependencies
-        uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
-        with:
-          path: "~/.pub-cache/hosted"
-          key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/dart_flutter_team_lints-pkgs/firehose;commands:analyze"
-          restore-keys: |
-            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/dart_flutter_team_lints-pkgs/firehose
-            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0
-            os:ubuntu-latest;pub-cache-hosted
-            os:ubuntu-latest
-      - name: Setup Dart SDK
-        uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1
-        with:
-          sdk: "3.0.0"
-      - id: checkout
-        name: Checkout repository
-        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
       - id: pkgs_dart_flutter_team_lints_pub_upgrade
         name: pkgs/dart_flutter_team_lints; dart pub upgrade
         run: dart pub upgrade
@@ -119,9 +86,18 @@
         run: dart analyze --fatal-infos .
         if: "always() && steps.pkgs_firehose_pub_upgrade.conclusion == 'success'"
         working-directory: pkgs/firehose
+      - id: pkgs_repo_manage_pub_upgrade
+        name: pkgs/repo_manage; dart pub upgrade
+        run: dart pub upgrade
+        if: "always() && steps.checkout.conclusion == 'success'"
+        working-directory: pkgs/repo_manage
+      - name: "pkgs/repo_manage; dart analyze --fatal-infos ."
+        run: dart analyze --fatal-infos .
+        if: "always() && steps.pkgs_repo_manage_pub_upgrade.conclusion == 'success'"
+        working-directory: pkgs/repo_manage
     needs:
       - job_001
-  job_004:
+  job_003:
     name: "analyze_and_format; Dart dev; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/firehose, pkgs/repo_manage; `dart analyze --fatal-infos .`"
     runs-on: ubuntu-latest
     steps:
@@ -180,7 +156,7 @@
         working-directory: pkgs/repo_manage
     needs:
       - job_001
-  job_005:
+  job_004:
     name: "analyze_and_format; Dart dev; PKGS: pkgs/corpus, pkgs/dart_flutter_team_lints, pkgs/firehose, pkgs/repo_manage; `dart format --output=none --set-exit-if-changed .`"
     runs-on: ubuntu-latest
     steps:
@@ -239,24 +215,24 @@
         working-directory: pkgs/repo_manage
     needs:
       - job_001
-  job_006:
-    name: "unit_test; Dart 2.19.0; PKG: pkgs/corpus; `dart test`"
+  job_005:
+    name: "unit_test; Dart 3.0.0; PKG: pkgs/corpus; `dart test`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
         uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
         with:
           path: "~/.pub-cache/hosted"
-          key: "os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus;commands:test_1"
+          key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/corpus;commands:test_1"
           restore-keys: |
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0;packages:pkgs/corpus
-            os:ubuntu-latest;pub-cache-hosted;sdk:2.19.0
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0;packages:pkgs/corpus
+            os:ubuntu-latest;pub-cache-hosted;sdk:3.0.0
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
       - name: Setup Dart SDK
         uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1
         with:
-          sdk: "2.19.0"
+          sdk: "3.0.0"
       - id: checkout
         name: Checkout repository
         uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
@@ -274,8 +250,7 @@
       - job_002
       - job_003
       - job_004
-      - job_005
-  job_007:
+  job_006:
     name: "unit_test; Dart 3.0.0; PKG: pkgs/dart_flutter_team_lints; `dart test`"
     runs-on: ubuntu-latest
     steps:
@@ -310,8 +285,7 @@
       - job_002
       - job_003
       - job_004
-      - job_005
-  job_008:
+  job_007:
     name: "unit_test; Dart 3.0.0; PKG: pkgs/firehose; `dart test`"
     runs-on: ubuntu-latest
     steps:
@@ -346,8 +320,7 @@
       - job_002
       - job_003
       - job_004
-      - job_005
-  job_009:
+  job_008:
     name: "unit_test; Dart dev; PKG: pkgs/corpus; `dart test`"
     runs-on: ubuntu-latest
     steps:
@@ -382,8 +355,7 @@
       - job_002
       - job_003
       - job_004
-      - job_005
-  job_010:
+  job_009:
     name: "unit_test; Dart dev; PKG: pkgs/dart_flutter_team_lints; `dart test`"
     runs-on: ubuntu-latest
     steps:
@@ -418,8 +390,7 @@
       - job_002
       - job_003
       - job_004
-      - job_005
-  job_011:
+  job_010:
     name: "unit_test; Dart dev; PKG: pkgs/firehose; `dart test`"
     runs-on: ubuntu-latest
     steps:
@@ -454,8 +425,7 @@
       - job_002
       - job_003
       - job_004
-      - job_005
-  job_012:
+  job_011:
     name: "analyze_format; Dart dev; PKG: pkgs/blast_repo; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`"
     runs-on: ubuntu-latest
     steps:
@@ -500,8 +470,7 @@
       - job_008
       - job_009
       - job_010
-      - job_011
-  job_013:
+  job_012:
     name: "test; Dart dev; PKG: pkgs/blast_repo; `dart test --test-randomize-ordering-seed=random`"
     runs-on: ubuntu-latest
     steps:
@@ -543,4 +512,3 @@
       - job_009
       - job_010
       - job_011
-      - job_012
diff --git a/pkgs/blast_repo/pubspec.yaml b/pkgs/blast_repo/pubspec.yaml
index 1e434bb..ede638c 100644
--- a/pkgs/blast_repo/pubspec.yaml
+++ b/pkgs/blast_repo/pubspec.yaml
@@ -1,5 +1,6 @@
 name: blast_repo
 description: A tool to bulk validate and fix GitHub repos.
+
 publish_to: none
 
 environment:
@@ -19,7 +20,7 @@
   yaml_edit: ^2.1.0
 
 dev_dependencies:
-  dart_flutter_team_lints: ^1.0.0
+  dart_flutter_team_lints: ^2.0.0
   test: ^1.22.0
   test_descriptor: ^2.0.0
 
diff --git a/pkgs/corpus/pubspec.yaml b/pkgs/corpus/pubspec.yaml
index 19c5b6f..a9c3392 100644
--- a/pkgs/corpus/pubspec.yaml
+++ b/pkgs/corpus/pubspec.yaml
@@ -1,9 +1,10 @@
 name: corpus
 description: A tool to calculate the API usage for a package.
+
 publish_to: none
 
 environment:
-  sdk: '>=2.19.0 <3.0.0'
+  sdk: ^3.0.0
 
 dependencies:
   analyzer: ^5.0.0
@@ -17,6 +18,6 @@
 
 dev_dependencies:
   checks: ^0.2.0
-  dart_flutter_team_lints: ^1.0.0
+  dart_flutter_team_lints: ^2.0.0
   test: ^1.22.0
   test_descriptor: ^2.0.0
diff --git a/pkgs/dart_flutter_team_lints/CHANGELOG.md b/pkgs/dart_flutter_team_lints/CHANGELOG.md
index 9a01b78..85f438d 100644
--- a/pkgs/dart_flutter_team_lints/CHANGELOG.md
+++ b/pkgs/dart_flutter_team_lints/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 2.1.0
+
+- Updated to the preview `3.0.0-beta` version of package:lints/recommended.yaml.
+- Removed lints duplicated from package:lints/core.yaml and
+  package:lints/recommended.yaml.
+
 ## 2.0.0
 
 - Enable `strict-inference`.
diff --git a/pkgs/dart_flutter_team_lints/lib/analysis_options.yaml b/pkgs/dart_flutter_team_lints/lib/analysis_options.yaml
index 4fca56b..75dfb96 100644
--- a/pkgs/dart_flutter_team_lints/lib/analysis_options.yaml
+++ b/pkgs/dart_flutter_team_lints/lib/analysis_options.yaml
@@ -23,51 +23,31 @@
 linter:
   rules:
     # consistency
-    - avoid_empty_else
-    - avoid_shadowing_type_parameters
-    - avoid_types_as_parameter_names
-    - camel_case_extensions
     - combinators_ordering
-    - curly_braces_in_flow_control_structures
     - directives_ordering
-    - empty_catches
-    - file_names
     - library_annotations
     - lines_longer_than_80_chars
     - omit_local_variable_types
     - prefer_asserts_in_initializer_lists
     - prefer_const_constructors
-    - prefer_generic_function_type_aliases
-    - prefer_is_empty
     - prefer_relative_imports
     - prefer_single_quotes
-    - prefer_typing_uninitialized_variables
     - sort_pub_dependencies
     - unnecessary_lambdas
     - unnecessary_library_directive
-    - unnecessary_overrides
     - unnecessary_parenthesis
     - unnecessary_statements
     - use_is_even_rather_than_modulo
-    - use_string_in_part_of_directives
-    - use_super_parameters
 
     # correctness
     - always_declare_return_types
     - avoid_catching_errors
     - avoid_dynamic_calls
-    - await_only_futures
-    - collection_methods_unrelated_type
     - comment_references
     - conditional_uri_does_not_exist
-    - dangling_library_doc_comments
-    - hash_and_equals
-    - implicit_call_tearoffs
-    - no_duplicate_case_values
     - only_throw_errors
     - test_types_in_equals
     - throw_in_finally
     - type_annotate_public_apis
     - unawaited_futures
     - unreachable_from_main
-    - unrelated_type_equality_checks
diff --git a/pkgs/dart_flutter_team_lints/pubspec.yaml b/pkgs/dart_flutter_team_lints/pubspec.yaml
index 886263e..f432ddb 100644
--- a/pkgs/dart_flutter_team_lints/pubspec.yaml
+++ b/pkgs/dart_flutter_team_lints/pubspec.yaml
@@ -1,15 +1,16 @@
 name: dart_flutter_team_lints
 description: An analysis rule set used by the Dart and Flutter teams.
-version: 2.0.0
+version: 2.1.0
 repository: https://github.com/dart-lang/ecosystem/tree/main/pkgs/dart_flutter_team_lints
 
 environment:
   sdk: ^3.0.0
 
 dependencies:
-  lints: ^2.0.0
+  lints: ^3.0.0-0
 
 dev_dependencies:
   checks: ^0.2.0
+  path: ^1.8.0
   test: ^1.0.0
   yaml: ^3.0.0
diff --git a/pkgs/dart_flutter_team_lints/tool/dedup.dart b/pkgs/dart_flutter_team_lints/tool/dedup.dart
new file mode 100644
index 0000000..d39139d
--- /dev/null
+++ b/pkgs/dart_flutter_team_lints/tool/dedup.dart
@@ -0,0 +1,146 @@
+// Copyright (c) 2023, 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.
+
+/// A tool to deduplicate lints from analysis_options.yaml files.
+library;
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:yaml/yaml.dart';
+
+void main(List<String> args) {
+  if (args.length != 1) {
+    print('usage: dart tool/dedups.dart <analysis-options-file>');
+  }
+
+  final file = File(args.first);
+  print('De-duplicating lints for ${file.path}:');
+
+  final yaml = loadYaml(file.readAsStringSync()) as YamlMap;
+
+  final include = yaml['include'] as String?;
+  if (include == null) {
+    print('No duplicates found (file does not contain an include section).');
+    return;
+  }
+
+  if (!include.startsWith('package:')) {
+    print('include type not supported: $include');
+    return;
+  }
+
+  final packageConfig = _findPackageConfig(file.parent)!;
+
+  final includes = Lints.readFrom(include, packageConfig);
+  void printLints(Lints lints) {
+    print('  ${lints.include}, read ${lints.lints.length} lints');
+    if (lints.parent != null) printLints(lints.parent!);
+  }
+
+  print('');
+  printLints(includes);
+
+  // Look for duplicates in the linter rules.
+  var count = 0;
+  final lints = (yaml['linter'] as YamlMap?)?['rules'] as YamlList?;
+  if (lints != null) {
+    print('');
+    print('${lints.length} local lints');
+
+    for (final lint in lints.cast<String>()) {
+      final definingFile = includes.containingInclude(lint);
+      if (definingFile != null) {
+        if (count == 0) print('');
+
+        count++;
+        print('  duplicate: $lint [${definingFile.include}]');
+      }
+    }
+  }
+
+  print('');
+
+  if (count == 0) {
+    print('No duplicates found.');
+  } else {
+    print('$count duplicates.');
+  }
+
+  // TODO: Also handle the analyzer/language section.
+}
+
+Map<String, Directory>? _findPackageConfig(Directory dir) {
+  if (dir.parent == dir) {
+    return null;
+  }
+
+  final configFile =
+      File(path.join(dir.path, '.dart_tool', 'package_config.json'));
+  if (configFile.existsSync()) {
+    return _parseConfigFile(configFile);
+  } else {
+    return _findPackageConfig(dir.parent);
+  }
+}
+
+Map<String, Directory>? _parseConfigFile(File configFile) {
+  final json =
+      jsonDecode(configFile.readAsStringSync()) as Map<String, dynamic>;
+  final packages = (json['packages'] as List).cast<Map<String, dynamic>>();
+  return Map.fromIterable(
+    packages,
+    key: (p) => (p as Map)['name'] as String,
+    value: (p) {
+      final rootUri = (p as Map)['rootUri'] as String;
+      final filePath = Uri.parse(rootUri).toFilePath();
+      if (path.isRelative(filePath)) {
+        return Directory(
+          path.normalize(path.join(configFile.parent.path, filePath)),
+        );
+      } else {
+        return Directory(filePath);
+      }
+    },
+  );
+}
+
+class Lints {
+  static Lints readFrom(String include, Map<String, Directory> packages) {
+    // "package:lints/recommended.yaml"
+    final uri = Uri.parse(include);
+    final package = uri.pathSegments[0];
+    final filePath = uri.pathSegments[1];
+
+    final dir = packages[package]!;
+    final configFile = File(path.join(dir.path, 'lib', filePath));
+
+    final yaml = loadYaml(configFile.readAsStringSync()) as YamlMap;
+    final localInclude = yaml['include'] as String?;
+    final lints = (yaml['linter'] as YamlMap?)?['rules'] as YamlList;
+
+    return Lints._(
+      parent:
+          localInclude == null ? null : Lints.readFrom(localInclude, packages),
+      include: include,
+      lints: lints.cast<String>().toList(),
+    );
+  }
+
+  final Lints? parent;
+  final String include;
+  final List<String> lints;
+
+  Lints._({
+    this.parent,
+    required this.include,
+    required this.lints,
+  });
+
+  Lints? containingInclude(String lint) {
+    if (lints.contains(lint)) return this;
+    return parent?.containingInclude(lint);
+  }
+}
diff --git a/pkgs/repo_manage/pubspec.yaml b/pkgs/repo_manage/pubspec.yaml
index 2dae2d9..56717e5 100644
--- a/pkgs/repo_manage/pubspec.yaml
+++ b/pkgs/repo_manage/pubspec.yaml
@@ -4,7 +4,7 @@
 publish_to: none
 
 environment:
-  sdk: ^2.19.0
+  sdk: ^3.0.0
 
 dependencies:
   args: ^2.4.0
@@ -14,4 +14,4 @@
   path: ^1.8.0
 
 dev_dependencies:
-  dart_flutter_team_lints: ^1.0.0
+  dart_flutter_team_lints: ^2.0.0
diff --git a/tool/ci.sh b/tool/ci.sh
index 2f3ec2f..9b4f6ff 100755
--- a/tool/ci.sh
+++ b/tool/ci.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Created with package:mono_repo v6.5.7
+# Created with package:mono_repo v6.6.0
 
 # Support built in commands on windows out of the box.
 # When it is a flutter repo (check the pubspec.yaml for "sdk: flutter")