Skip to content

Commit

Permalink
feat: Add prefer_sliver_prefix rule (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
naipaka authored Jul 30, 2024
1 parent e5b056a commit 6c941e7
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/altive_lints/lib/altive_lints.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'src/lints/avoid_single_child.dart';
import 'src/lints/prefer_clock_now.dart';
import 'src/lints/prefer_dedicated_media_query_methods.dart';
import 'src/lints/prefer_space_between_elements.dart';
import 'src/lints/prefer_sliver_prefix.dart';

PluginBase createPlugin() => _AltivePlugin();

Expand All @@ -22,5 +23,6 @@ class _AltivePlugin extends PluginBase {
const PreferClockNow(),
const PreferDedicatedMediaQueryMethods(),
const PreferSpaceBetweenElements(),
const PreferSliverPrefix(),
];
}
76 changes: 76 additions & 0 deletions packages/altive_lints/lib/src/lints/prefer_sliver_prefix.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/listener.dart';
import 'package:collection/collection.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

/// A `prefer_sliver_prefix` rule that ensures widgets returning
/// a Sliver-type widget have a "Sliver" prefix in their class names.
///
/// This naming convention improves code readability and
/// consistency by clearly indicating the widget's functionality and
/// return type through its name.
///
/// ### Example
///
/// #### BAD:
///
/// ```dart
/// class MyCustomList extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
/// return SliverList(...); // LINT
/// }
/// }
/// ```
///
/// #### GOOD:
///
/// ```dart
/// class SliverMyCustomList extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
/// return SliverList(...);
/// }
/// }
/// ```
class PreferSliverPrefix extends DartLintRule {
const PreferSliverPrefix() : super(code: _code);

static const _code = LintCode(
name: 'prefer_sliver_prefix',
problemMessage: 'Widgets returning Sliver should have a "Sliver" prefix.',
correctionMessage: 'Consider adding "Sliver" prefix to the widget name.',
);

@override
void run(
CustomLintResolver resolver,
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addClassDeclaration((node) {
final className = node.name.lexeme;
final methodBody = node.members
.whereType<MethodDeclaration>()
.firstWhereOrNull((method) => method.name.lexeme == 'build')
?.body;

if (methodBody is BlockFunctionBody) {
final returnStatements =
methodBody.block.statements.whereType<ReturnStatement>();
final returnsSliverWidget = returnStatements.any(
(returnStatement) {
final returnType = returnStatement.expression?.staticType;
final typeName =
returnType?.getDisplayString(withNullability: false);
return typeName?.startsWith('Sliver') ?? false;
},
);

if (returnsSliverWidget && !className.startsWith('Sliver')) {
reporter.reportErrorForNode(_code, node);
}
}
});
}
}
16 changes: 16 additions & 0 deletions packages/altive_lints/lint_test/lints/prefer_sliver_prefix.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';

// expect_lint: prefer_sliver_prefix
class MyWidget extends StatelessWidget {
const MyWidget({super.key});

@override
Widget build(BuildContext context) {
return SliverList.builder(
itemCount: 10,
itemBuilder: (context, index) {
return const Placeholder();
},
);
}
}

0 comments on commit 6c941e7

Please sign in to comment.