diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000000..9c2def1070 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,5 @@ +plugins: + native_analyzer_plugin: + path: pkgs/native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/code_assets/analysis_options.yaml b/pkgs/code_assets/analysis_options.yaml index a366861354..7513262d98 100644 --- a/pkgs/code_assets/analysis_options.yaml +++ b/pkgs/code_assets/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -15,6 +13,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/code_assets/pubspec.yaml b/pkgs/code_assets/pubspec.yaml index c9bf929aef..d55a7455e4 100644 --- a/pkgs/code_assets/pubspec.yaml +++ b/pkgs/code_assets/pubspec.yaml @@ -24,11 +24,10 @@ dependencies: hooks: ^0.20.1 dev_dependencies: - custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 json_schema: ^5.2.0 # May only be used in tool/ and test/json_schema/. + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ - repo_lint_rules: - path: ../repo_lint_rules/ test: ^1.25.15 diff --git a/pkgs/data_assets/analysis_options.yaml b/pkgs/data_assets/analysis_options.yaml index c0462a3a77..a4dfae9f10 100644 --- a/pkgs/data_assets/analysis_options.yaml +++ b/pkgs/data_assets/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -14,6 +12,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/data_assets/pubspec.yaml b/pkgs/data_assets/pubspec.yaml index 3885fcc1e1..d3de30ed68 100644 --- a/pkgs/data_assets/pubspec.yaml +++ b/pkgs/data_assets/pubspec.yaml @@ -20,11 +20,8 @@ dependencies: hooks: ^0.20.1 dev_dependencies: - custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 json_schema: ^5.2.0 # May only be used in tool/ and test/json_schema/. native_test_helpers: path: ../native_test_helpers - repo_lint_rules: - path: ../repo_lint_rules/ test: ^1.25.15 diff --git a/pkgs/hooks/analysis_options.yaml b/pkgs/hooks/analysis_options.yaml index a366861354..7513262d98 100644 --- a/pkgs/hooks/analysis_options.yaml +++ b/pkgs/hooks/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -15,6 +13,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/hooks/lib/src/avoid_import_outside_src_rule_test.dart b/pkgs/hooks/lib/src/avoid_import_outside_src_rule_test.dart index d12846ae58..d88036af3c 100644 --- a/pkgs/hooks/lib/src/avoid_import_outside_src_rule_test.dart +++ b/pkgs/hooks/lib/src/avoid_import_outside_src_rule_test.dart @@ -2,7 +2,7 @@ // 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. -// expect_lint: avoid_import_outside_src +// ignore: native_analyzer_plugin/avoid_import_outside_src import '../hooks.dart'; /// A random use of a type. diff --git a/pkgs/hooks/pubspec.yaml b/pkgs/hooks/pubspec.yaml index 99040bef91..9afb82a069 100644 --- a/pkgs/hooks/pubspec.yaml +++ b/pkgs/hooks/pubspec.yaml @@ -30,7 +30,6 @@ dependencies: dev_dependencies: args: ^2.6.0 code_assets: ^0.19.7 # Used for running tests with real asset types. - custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 data_assets: any # Used for running tests with real asset types. file_testing: ^3.0.2 @@ -38,9 +37,9 @@ dev_dependencies: json_schema: ^5.2.0 # May only be used in tool/ and test/json_schema/. json_syntax_generator: path: ../json_syntax_generator/ + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ path: ^1.9.1 - repo_lint_rules: - path: ../repo_lint_rules/ test: ^1.25.15 diff --git a/pkgs/hooks_runner/analysis_options.yaml b/pkgs/hooks_runner/analysis_options.yaml index c0462a3a77..a4dfae9f10 100644 --- a/pkgs/hooks_runner/analysis_options.yaml +++ b/pkgs/hooks_runner/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -14,6 +12,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/hooks_runner/pubspec.yaml b/pkgs/hooks_runner/pubspec.yaml index fb0c116fc9..83dab331f4 100644 --- a/pkgs/hooks_runner/pubspec.yaml +++ b/pkgs/hooks_runner/pubspec.yaml @@ -26,14 +26,13 @@ dependencies: dev_dependencies: args: any - custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 data_assets: any # Used in tests. file_testing: ^3.0.2 + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ pub_formats: # Used in tests. path: ../pub_formats/ - repo_lint_rules: - path: ../repo_lint_rules/ test: ^1.25.15 diff --git a/pkgs/json_syntax_generator/analysis_options.yaml b/pkgs/json_syntax_generator/analysis_options.yaml index c0462a3a77..a4dfae9f10 100644 --- a/pkgs/json_syntax_generator/analysis_options.yaml +++ b/pkgs/json_syntax_generator/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -14,6 +12,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/json_syntax_generator/pubspec.yaml b/pkgs/json_syntax_generator/pubspec.yaml index 7a9a8effc2..1848983e3c 100644 --- a/pkgs/json_syntax_generator/pubspec.yaml +++ b/pkgs/json_syntax_generator/pubspec.yaml @@ -18,11 +18,10 @@ dependencies: json_schema: ^5.2.0 dev_dependencies: - custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ path: ^1.9.1 - repo_lint_rules: - path: ../repo_lint_rules/ test: ^1.25.15 diff --git a/pkgs/native_analyzer_plugin/lib/main.dart b/pkgs/native_analyzer_plugin/lib/main.dart new file mode 100644 index 0000000000..dfb8958d39 --- /dev/null +++ b/pkgs/native_analyzer_plugin/lib/main.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2025, 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. + +import 'package:analysis_server_plugin/plugin.dart'; +import 'package:analysis_server_plugin/registry.dart'; + +import 'src/rules/avoid_import_outside_src_rule.dart'; + +final plugin = NativeAnalyzerPlugin(); + +class NativeAnalyzerPlugin extends Plugin { + @override + void register(PluginRegistry registry) { + registry.registerLintRule(AvoidImportOutsideSrcRule()); + } +} diff --git a/pkgs/native_analyzer_plugin/lib/src/rules/avoid_import_outside_src_rule.dart b/pkgs/native_analyzer_plugin/lib/src/rules/avoid_import_outside_src_rule.dart new file mode 100644 index 0000000000..a720fa9753 --- /dev/null +++ b/pkgs/native_analyzer_plugin/lib/src/rules/avoid_import_outside_src_rule.dart @@ -0,0 +1,90 @@ +// Copyright (c) 2025, 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. + +import 'package:analyzer/analysis_rule/analysis_rule.dart'; +import 'package:analyzer/analysis_rule/rule_context.dart'; +import 'package:analyzer/analysis_rule/rule_visitor_registry.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:analyzer/error/error.dart'; + +class AvoidImportOutsideSrcRule extends AnalysisRule { + static const LintCode code = LintCode( + 'avoid_import_outside_src', + "Avoid importing files outside 'lib/src/' from files within 'lib/src/'.", + correctionMessage: + "Files outside 'lib/src/' likely only export definitions from inside 'lib/src/'. " + 'Import the file with the definition directly.', + ); + + AvoidImportOutsideSrcRule() + : super( + name: 'avoid_import_outside_src', + description: + "Avoid importing files outside 'lib/src/' from files within 'lib/src/'.", + ); + + @override + LintCode get diagnosticCode => code; + + @override + void registerNodeProcessors( + RuleVisitorRegistry registry, + RuleContext context, + ) { + var visitor = _Visitor(rule: this, context: context); + registry.addImportDirective(this, visitor); + } +} + +class _Visitor extends SimpleAstVisitor { + final RuleContext context; + final AnalysisRule rule; + + _Visitor({required this.rule, required this.context}); + + @override + void visitImportDirective(ImportDirective node) { + final importString = node.uri.stringValue; + final importedUri = node.libraryImport?.importedLibrary?.uri; + final importingFile = context.currentUnit?.file.toUri(); + + if (importedUri == null || importingFile == null || importString == null) { + return; + } + + if (importString.startsWith('package')) { + // Package imports are of no interest. Use prefer_relative_imports to + // prevent package imports of the same package. + return; + } + + if (importString.startsWith('dart')) { + return; + } + + if (_isInSrcDirectory(importingFile)) { + if (!_isInSrcDirectory(importedUri)) { + rule.reportAtNode(node); + } + } + } + + bool _isInSrcDirectory(Uri uri) { + if (uri.scheme == 'package') { + if (uri.path.contains('src/')) { + return true; + } + return false; + } else if (uri.scheme == 'file') { + if (uri.toFilePath(windows: false).contains('lib/src/')) { + return true; + } + if (uri.toFilePath(windows: false).contains('lib/')) { + return false; + } + } + return false; + } +} diff --git a/pkgs/native_analyzer_plugin/pubspec.yaml b/pkgs/native_analyzer_plugin/pubspec.yaml new file mode 100644 index 0000000000..607740f8f7 --- /dev/null +++ b/pkgs/native_analyzer_plugin/pubspec.yaml @@ -0,0 +1,18 @@ +name: native_analyzer_plugin +version: 0.1.0 +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.9.0 <4.0.0' + +dependencies: + analysis_server_plugin: ^0.2.2 + analyzer: ^8.0.0 + analyzer_plugin: ^0.13.6 + analyzer_testing: ^0.1.2 + +dev_dependencies: + test: any + test_reflective_loader: any diff --git a/pkgs/native_test_helpers/analysis_options.yaml b/pkgs/native_test_helpers/analysis_options.yaml index c0462a3a77..a4dfae9f10 100644 --- a/pkgs/native_test_helpers/analysis_options.yaml +++ b/pkgs/native_test_helpers/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -14,6 +12,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/native_toolchain_c/analysis_options.yaml b/pkgs/native_toolchain_c/analysis_options.yaml index c0462a3a77..a4dfae9f10 100644 --- a/pkgs/native_toolchain_c/analysis_options.yaml +++ b/pkgs/native_toolchain_c/analysis_options.yaml @@ -3,8 +3,6 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 linter: rules: @@ -14,6 +12,8 @@ linter: - prefer_final_in_for_each - prefer_final_locals -custom_lint: - rules: - - avoid_import_outside_src +plugins: + native_analyzer_plugin: + path: ../native_analyzer_plugin + diagnostics: + avoid_import_outside_src: true diff --git a/pkgs/native_toolchain_c/pubspec.yaml b/pkgs/native_toolchain_c/pubspec.yaml index 3e5c41518b..9cbcd5dcb0 100644 --- a/pkgs/native_toolchain_c/pubspec.yaml +++ b/pkgs/native_toolchain_c/pubspec.yaml @@ -26,10 +26,9 @@ dependencies: dev_dependencies: collection: ^1.19.1 - custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ - repo_lint_rules: - path: ../repo_lint_rules/ test: ^1.25.15 diff --git a/pkgs/objective_c/pubspec.yaml b/pkgs/objective_c/pubspec.yaml index 0bcf0da9b4..e83a67bf73 100644 --- a/pkgs/objective_c/pubspec.yaml +++ b/pkgs/objective_c/pubspec.yaml @@ -30,6 +30,8 @@ dev_dependencies: ffigen: ^20.0.0-dev.0 flutter_test: sdk: flutter + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ path: ^1.9.0 diff --git a/pkgs/pub_formats/pubspec.yaml b/pkgs/pub_formats/pubspec.yaml index f88342d3e0..b6d8f58043 100644 --- a/pkgs/pub_formats/pubspec.yaml +++ b/pkgs/pub_formats/pubspec.yaml @@ -20,6 +20,8 @@ dev_dependencies: json_schema: ^5.2.0 # May only be used in tool/ and test/json_schema/. json_syntax_generator: path: ../json_syntax_generator/ + native_analyzer_plugin: + path: ../native_analyzer_plugin/ native_test_helpers: path: ../native_test_helpers/ test: ^1.25.15 diff --git a/pkgs/repo_lint_rules/CHANGELOG.md b/pkgs/repo_lint_rules/CHANGELOG.md deleted file mode 100644 index 1b9970e51f..0000000000 --- a/pkgs/repo_lint_rules/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.1.0-wip - -- Initial version. diff --git a/pkgs/repo_lint_rules/analysis_options.yaml b/pkgs/repo_lint_rules/analysis_options.yaml deleted file mode 100644 index c0462a3a77..0000000000 --- a/pkgs/repo_lint_rules/analysis_options.yaml +++ /dev/null @@ -1,19 +0,0 @@ -include: package:dart_flutter_team_lints/analysis_options.yaml - -analyzer: - language: - strict-raw-types: true - plugins: - # - custom_lint # https://github.com/dart-lang/sdk/issues/60784 - -linter: - rules: - - avoid_positional_boolean_parameters - - prefer_const_declarations - - prefer_expression_function_bodies - - prefer_final_in_for_each - - prefer_final_locals - -custom_lint: - rules: - - avoid_import_outside_src diff --git a/pkgs/repo_lint_rules/lib/repo_lint_rules.dart b/pkgs/repo_lint_rules/lib/repo_lint_rules.dart deleted file mode 100644 index db9d8c2431..0000000000 --- a/pkgs/repo_lint_rules/lib/repo_lint_rules.dart +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2025, 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. - -import 'package:custom_lint_builder/custom_lint_builder.dart'; -import 'src/avoid_import_outside_src_rule.dart'; - -PluginBase createPlugin() => _MyLintRulesPlugin(); - -class _MyLintRulesPlugin extends PluginBase { - @override - List getLintRules(CustomLintConfigs configs) => [ - AvoidImportOutsideSrcRule(), - ]; -} diff --git a/pkgs/repo_lint_rules/lib/src/avoid_import_outside_src_rule.dart b/pkgs/repo_lint_rules/lib/src/avoid_import_outside_src_rule.dart deleted file mode 100644 index 6af5bd3aa4..0000000000 --- a/pkgs/repo_lint_rules/lib/src/avoid_import_outside_src_rule.dart +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2025, 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. - -import 'package:analyzer/error/listener.dart'; -import 'package:custom_lint_builder/custom_lint_builder.dart'; - -class AvoidImportOutsideSrcRule extends DartLintRule { - AvoidImportOutsideSrcRule() : super(code: _code); - - static const _code = LintCode( - name: 'avoid_import_outside_src', - problemMessage: - "Avoid importing files outside 'lib/src/' from files within 'lib/src/'.", - correctionMessage: - "Files outside 'lib/src/' likely only export definitions from inside 'lib/src/'. " - 'Import the file with the definition directly.', - ); - - @override - void run( - CustomLintResolver resolver, - ErrorReporter reporter, - CustomLintContext context, - ) { - context.registry.addImportDirective((node) { - final importedUri = node.uri.stringValue; - if (importedUri == null) { - return; - } - final importingFile = resolver.source.uri; - - if (importedUri.startsWith('package:')) { - // Package imports are of no interest. Use prefer_relative_imports to - // prevent package imports of the same package. - return; - } - if (importedUri.startsWith('dart:')) { - return; - } - final importedUriAbsolute = importingFile.resolve(importedUri); - if (_isInSrcDirectory(importingFile)) { - if (!_isInSrcDirectory(importedUriAbsolute)) { - reporter.atNode(node, code); - } - } - }); - } - - bool _isInSrcDirectory(Uri uri) { - if (uri.toFilePath(windows: false).contains('lib/src/')) { - return true; - } - if (uri.toFilePath(windows: false).contains('lib/')) { - return false; - } - return false; - } -} diff --git a/pkgs/repo_lint_rules/pubspec.yaml b/pkgs/repo_lint_rules/pubspec.yaml deleted file mode 100644 index f881794329..0000000000 --- a/pkgs/repo_lint_rules/pubspec.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: repo_lint_rules -description: Custom lints for this repository -version: 0.1.0-wip - -publish_to: none - -resolution: workspace - -environment: - sdk: '>=3.9.0 <4.0.0' - -dependencies: - analyzer: ^7.3.0 - custom_lint_builder: ^0.7.5 - dart_flutter_team_lints: ^3.5.2 - path: ^1.9.1 - -dev_dependencies: - custom_lint: ^0.7.5 diff --git a/pubspec.yaml b/pubspec.yaml index a650d63a83..d07924d473 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,10 +70,10 @@ workspace: - pkgs/hooks/example/link/app_with_asset_treeshaking - pkgs/hooks/example/link/package_with_assets - pkgs/json_syntax_generator + - pkgs/native_analyzer_plugin - pkgs/native_test_helpers - pkgs/native_toolchain_c - pkgs/pub_formats - - pkgs/repo_lint_rules # Hook user-defines are specified in the pub workspace. hooks: