Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit e77069d

Browse files
authored
feat: add avoid-double-slash-imports rule (#1095)
1 parent 7a96369 commit e77069d

File tree

8 files changed

+193
-0
lines changed

8 files changed

+193
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
* fix: remove recursive traversal for [`ban-name`](https://dartcodemetrics.dev/docs/rules/common/ban-name) rule.
6+
* feat: add static code diagnostic [`avoid-double-slash-imports`](https://dartcodemetrics.dev/docs/rules/common/avoid-double-slash-imports).
67
* feat: add static code diagnostic [`prefer-using-list-view`](https://dartcodemetrics.dev/docs/rules/flutter/prefer-using-list-view).
78
* feat: add static code diagnostic [`avoid-unnecessary-conditionals`](https://dartcodemetrics.dev/docs/rules/common/avoid-unnecessary-conditionals).
89

lib/src/analyzers/lint_analyzer/rules/rules_factory.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'rules_list/avoid_banned_imports/avoid_banned_imports_rule.dart';
55
import 'rules_list/avoid_border_all/avoid_border_all_rule.dart';
66
import 'rules_list/avoid_cascade_after_if_null/avoid_cascade_after_if_null_rule.dart';
77
import 'rules_list/avoid_collection_methods_with_unrelated_types/avoid_collection_methods_with_unrelated_types_rule.dart';
8+
import 'rules_list/avoid_double_slash_imports/avoid_double_slash_imports_rule.dart';
89
import 'rules_list/avoid_duplicate_exports/avoid_duplicate_exports_rule.dart';
910
import 'rules_list/avoid_dynamic/avoid_dynamic_rule.dart';
1011
import 'rules_list/avoid_expanded_as_spacer/avoid_expanded_as_spacer_rule.dart';
@@ -78,6 +79,7 @@ final _implementedRules = <String, Rule Function(Map<String, Object>)>{
7879
AvoidCascadeAfterIfNullRule.ruleId: AvoidCascadeAfterIfNullRule.new,
7980
AvoidCollectionMethodsWithUnrelatedTypesRule.ruleId:
8081
AvoidCollectionMethodsWithUnrelatedTypesRule.new,
82+
AvoidDoubleSlashImportsRule.ruleId: AvoidDoubleSlashImportsRule.new,
8183
AvoidDuplicateExportsRule.ruleId: AvoidDuplicateExportsRule.new,
8284
AvoidDynamicRule.ruleId: AvoidDynamicRule.new,
8385
AvoidGlobalStateRule.ruleId: AvoidGlobalStateRule.new,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// ignore_for_file: public_member_api_docs
2+
3+
import 'package:analyzer/dart/ast/ast.dart';
4+
import 'package:analyzer/dart/ast/visitor.dart';
5+
6+
import '../../../../../utils/node_utils.dart';
7+
import '../../../lint_utils.dart';
8+
import '../../../models/internal_resolved_unit_result.dart';
9+
import '../../../models/issue.dart';
10+
import '../../../models/replacement.dart';
11+
import '../../../models/severity.dart';
12+
import '../../models/common_rule.dart';
13+
import '../../rule_utils.dart';
14+
15+
part 'visitor.dart';
16+
17+
class AvoidDoubleSlashImportsRule extends CommonRule {
18+
static const String ruleId = 'avoid-double-slash-imports';
19+
20+
static const _warning = 'Avoid double slash import/export directives.';
21+
static const _correctionMessage = 'Remove double slash.';
22+
23+
AvoidDoubleSlashImportsRule([Map<String, Object> config = const {}])
24+
: super(
25+
id: ruleId,
26+
severity: readSeverity(config, Severity.warning),
27+
excludes: readExcludes(config),
28+
includes: readIncludes(config),
29+
);
30+
31+
@override
32+
Iterable<Issue> check(InternalResolvedUnitResult source) {
33+
final visitor = _Visitor();
34+
35+
source.unit.visitChildren(visitor);
36+
37+
return visitor.nodes
38+
.map(
39+
(node) => createIssue(
40+
rule: this,
41+
location: nodeLocation(node: node, source: source),
42+
message: _warning,
43+
replacement: _createReplacement(node),
44+
),
45+
)
46+
.toList(growable: false);
47+
}
48+
49+
Replacement _createReplacement(UriBasedDirective directive) {
50+
final updatedDirective =
51+
directive.toString().replaceAll('//', '/').replaceAll(r'\\', r'\');
52+
53+
return Replacement(
54+
comment: _correctionMessage,
55+
replacement: updatedDirective,
56+
);
57+
}
58+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
part of 'avoid_double_slash_imports_rule.dart';
2+
3+
class _Visitor extends GeneralizingAstVisitor<void> {
4+
final _nodes = <UriBasedDirective>[];
5+
6+
Iterable<UriBasedDirective> get nodes => _nodes;
7+
8+
_Visitor();
9+
10+
@override
11+
void visitUriBasedDirective(UriBasedDirective node) {
12+
final uri = node.uri.stringValue;
13+
if (uri == null) {
14+
return;
15+
}
16+
17+
if (uri.contains('//') || (uri.contains(r'\\') && !uri.startsWith(r'\\'))) {
18+
_nodes.add(node);
19+
}
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import 'package:dart_code_metrics/src/analyzers/lint_analyzer/models/severity.dart';
2+
import 'package:dart_code_metrics/src/analyzers/lint_analyzer/rules/rules_list/avoid_double_slash_imports/avoid_double_slash_imports_rule.dart';
3+
import 'package:test/test.dart';
4+
5+
import '../../../../../helpers/rule_test_helper.dart';
6+
7+
const _examplePath = 'avoid_double_slash_imports/examples/example.dart';
8+
9+
void main() {
10+
group('AvoidDoubleSlashImportsRule', () {
11+
test('initialization', () async {
12+
final unit = await RuleTestHelper.resolveFromFile(_examplePath);
13+
final issues = AvoidDoubleSlashImportsRule().check(unit);
14+
15+
RuleTestHelper.verifyInitialization(
16+
issues: issues,
17+
ruleId: 'avoid-double-slash-imports',
18+
severity: Severity.warning,
19+
);
20+
});
21+
22+
test('reports about found issues', () async {
23+
final unit = await RuleTestHelper.resolveFromFile(_examplePath);
24+
final issues = AvoidDoubleSlashImportsRule().check(unit);
25+
26+
RuleTestHelper.verifyIssues(
27+
issues: issues,
28+
startLines: [1, 3, 5, 7],
29+
startColumns: [1, 1, 1, 1],
30+
locationTexts: [
31+
"import 'package:test//material.dart';",
32+
"import '../../..//rule_utils_test.dart';",
33+
"export 'package:mocktail//good_file.dart';",
34+
"part '..//empty.dart';",
35+
],
36+
messages: [
37+
'Avoid double slash import/export directives.',
38+
'Avoid double slash import/export directives.',
39+
'Avoid double slash import/export directives.',
40+
'Avoid double slash import/export directives.',
41+
],
42+
replacements: [
43+
"import 'package:test/material.dart';",
44+
"import '../../../rule_utils_test.dart';",
45+
"export 'package:mocktail/good_file.dart';",
46+
"part '../empty.dart';",
47+
],
48+
replacementComments: [
49+
'Remove double slash.',
50+
'Remove double slash.',
51+
'Remove double slash.',
52+
'Remove double slash.',
53+
],
54+
);
55+
});
56+
});
57+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import 'package:test//material.dart'; // LINT
2+
import 'package:mocktail/good_file.dart';
3+
import '../../..//rule_utils_test.dart'; // LINT
4+
5+
export 'package:mocktail//good_file.dart'; // LINT
6+
7+
part '..//empty.dart'; // LINT
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import RuleDetails from '@site/src/components/RuleDetails';
2+
3+
<RuleDetails version="5.2.0" severity="warning" hasFix />
4+
5+
Warns when an import/export directive contains a double slash.
6+
7+
Double slash in the URI is considered valid, but under some circumstances the programm won't run.
8+
9+
See:
10+
11+
- <https://github.com/dart-lang/sdk/issues/36337>
12+
13+
### Example {#example}
14+
15+
**❌ Bad:**
16+
17+
```dart
18+
import 'package:test//material.dart'; // LINT
19+
import 'package:mocktail/good_file.dart';
20+
import '../../..//rule_utils_test.dart'; // LINT
21+
22+
export 'package:mocktail//good_file.dart'; // LINT
23+
24+
part '..//empty.dart'; // LINT
25+
```
26+
27+
**✅ Good:**
28+
29+
```dart
30+
import 'package:test/material.dart';
31+
import 'package:mocktail/good_file.dart';
32+
import '../../../rule_utils_test.dart';
33+
34+
export 'package:mocktail/good_file.dart';
35+
36+
part '../empty.dart';
37+
```

website/docs/rules/index.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ Rules are grouped by category to help you understand their purpose. Each rule ha
5858
of integers using a string key.
5959
</RuleEntry>
6060

61+
<RuleEntry
62+
name="avoid-double-slash-imports"
63+
type="common"
64+
severity="warning"
65+
version="5.2.0"
66+
hasFix
67+
>
68+
Warns when an import/export directive contains a double slash.
69+
</RuleEntry>
70+
6171
<RuleEntry
6272
name="avoid-duplicate-exports"
6373
type="common"

0 commit comments

Comments
 (0)