| Index: lib/src/rules/implementation_imports.dart
|
| diff --git a/lib/src/rules/implementation_imports.dart b/lib/src/rules/implementation_imports.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0d40df088fb9463cd09cdfa69766e1d83fd0b7ea
|
| --- /dev/null
|
| +++ b/lib/src/rules/implementation_imports.dart
|
| @@ -0,0 +1,95 @@
|
| +// Copyright (c) 2015, 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.
|
| +
|
| +library linter.src.rules.implementation_imports;
|
| +
|
| +import 'package:analyzer/src/generated/ast.dart'
|
| + show AstVisitor, ImportDirective, SimpleAstVisitor;
|
| +import 'package:linter/src/linter.dart';
|
| +
|
| +const desc = "Don't import implementation files from another package.";
|
| +
|
| +const details = '''
|
| +**DON'T** import implementation files from another package.
|
| +
|
| +From the the [pub package layout doc]
|
| +(https://www.dartlang.org/tools/pub/package-layout.html#implementation-files):
|
| +
|
| +The libraries inside `lib` are publicly visible: other packages are free to
|
| +import them. But much of a package's code is internal implementation libraries
|
| +that should only be imported and used by the package itself. Those go inside a
|
| +subdirectory of `lib` called `src`. You can create subdirectories in there if
|
| +it helps you organize things.
|
| +
|
| +You are free to import libraries that live in `lib/src` from within other Dart
|
| +code in the same package (like other libraries in `lib`, scripts in `bin`,
|
| +and tests) but you should never import from another package's `lib/src`
|
| +directory. Those files are not part of the package’s public API, and they
|
| +might change in ways that could break your code.
|
| +
|
| +**Bad:**
|
| +
|
| +```
|
| +// In 'road_runner'
|
| +import 'package:acme/lib/src/internals.dart;
|
| +```
|
| +''';
|
| +
|
| +bool isImplementation(Uri uri) {
|
| + List<String> segments = uri?.pathSegments ?? const [];
|
| + if (segments.length > 2) {
|
| + if (segments[1] == 'src') {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool isPackage(Uri uri) => uri?.scheme == 'package';
|
| +
|
| +bool samePackage(Uri uri1, Uri uri2) {
|
| + var segments1 = uri1.pathSegments;
|
| + var segments2 = uri2.pathSegments;
|
| + if (segments1.length < 1 || segments2.length < 1) {
|
| + return false;
|
| + }
|
| + return segments1[0] == segments2[0];
|
| +}
|
| +
|
| +class ImplementationImports extends LintRule {
|
| + ImplementationImports()
|
| + : super(
|
| + name: 'implementation_imports',
|
| + description: desc,
|
| + details: details,
|
| + group: Group.style);
|
| +
|
| + @override
|
| + AstVisitor getVisitor() => new Visitor(this);
|
| +}
|
| +
|
| +class Visitor extends SimpleAstVisitor {
|
| + final LintRule rule;
|
| + Visitor(this.rule);
|
| +
|
| + @override
|
| + visitImportDirective(ImportDirective node) {
|
| + Uri importUri = node?.source?.uri;
|
| + Uri sourceUri = node?.element?.source?.uri;
|
| +
|
| + // Test for 'package:*/src/'.
|
| + if (!isImplementation(importUri)) {
|
| + return;
|
| + }
|
| +
|
| + // If the source URI is not a `package` URI bail out.
|
| + if (!isPackage(sourceUri)) {
|
| + return;
|
| + }
|
| +
|
| + if (!samePackage(importUri, sourceUri)) {
|
| + rule.reportLint(node.uri);
|
| + }
|
| + }
|
| +}
|
|
|