Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

feat(lint): implement state_base_class_suffix rule #14

Merged
merged 1 commit into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ The example folder contains a dart project to unit test the rules. (see custom_l
- [avoid_public_properties_on_bloc_and_cubit](docs/rules/avoid_public_properties_on_bloc_and_cubit.md)
- [prefer_multi_bloc_listener](docs/rules/prefer_multi_bloc_listener.md)
- [prefer_multi_bloc_provider](docs/rules/prefer_multi_bloc_provider.md)
- [prefer_multi_repository_provider](docs/rules/prefer_multi_repository_provider.md)
- [prefer_multi_repository_provider](docs/rules/prefer_multi_repository_provider.md)
- [state_base_class_suffix](docs/rules/state_base_class_suffix.md)
28 changes: 28 additions & 0 deletions docs/rules/state_base_class_suffix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
state_base_class_suffix
===
severity: WARNING

The base state class should always be suffixed by `State`.

## Example:

❌ **BAD**:

```dart
@immutable
sealed class HomepageData {}

final class HomepageInitial extends HomepageData {}
```

✅ **GOOD**:

```dart
sealed class HomepageState {}

final class HomepageInitial extends HomepageState {}
```

## Additional Resources

- [Bloc Library Documentation: Naming Conventions / State Conventions](https://bloclibrary.dev/naming-conventions/#state-conventions)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

class StateBaseClassSuffixLintRuleTestBloc extends Bloc<
StateBaseClassSuffixLintRuleTestEvent,
// expect_lint: state_base_class_suffix
StateBaseClassSuffixLintRuleTestError> {
StateBaseClassSuffixLintRuleTestBloc()
: super(StateBaseClassSuffixLintRuleTestInitial()) {
on<StateBaseClassSuffixLintRuleTestEvent>((event, emit) {
// TODO: implement event handler
});
}
}

@immutable
sealed class StateBaseClassSuffixLintRuleTestEvent {}

@immutable
sealed class StateBaseClassSuffixLintRuleTestError {}

final class StateBaseClassSuffixLintRuleTestInitial
extends StateBaseClassSuffixLintRuleTestError {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

class StateBaseClassSuffixLintRuleTestCubit // expect_lint: state_base_class_suffix
extends Cubit<StateBaseClassSuffixLintRuleTest> {
StateBaseClassSuffixLintRuleTestCubit()
: super(StateBaseClassSuffixLintRuleTestInitial());
}

@immutable
sealed class StateBaseClassSuffixLintRuleTest {}

final class StateBaseClassSuffixLintRuleTestInitial
extends StateBaseClassSuffixLintRuleTest {}
2 changes: 2 additions & 0 deletions lib/bloc_lint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:bloc_lint/lint_rules/avoid_public_properties_on_bloc_and_cubit_l
import 'package:bloc_lint/lint_rules/prefer_multi_bloc_listener_lint_rule.dart';
import 'package:bloc_lint/lint_rules/prefer_multi_bloc_provider_lint_rule.dart';
import 'package:bloc_lint/lint_rules/prefer_multi_repository_provider_lint_rule.dart';
import 'package:bloc_lint/lint_rules/state_base_class_suffix.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

PluginBase createPlugin() => _BlocLintPlugin();
Expand All @@ -15,5 +16,6 @@ class _BlocLintPlugin extends PluginBase {
const PreferMultiBlocListenerLintRule(),
const PreferMultiBlocProviderLintRule(),
const PreferMultiRepositoryProviderLintRule(),
const StateBaseClassSuffix(),
];
}
58 changes: 58 additions & 0 deletions lib/lint_rules/state_base_class_suffix.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:bloc_lint/bloc_lint_constants.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

class StateBaseClassSuffix extends DartLintRule {
const StateBaseClassSuffix()
: super(
code: const LintCode(
name: 'state_base_class_suffix',
problemMessage:
'''The base state class should always be suffixed by 'State'.''',
errorSeverity: ErrorSeverity.WARNING,
),
);

static const _ignoredType = [
'int',
'double',
'num',
'String',
'bool',
'List',
'Set',
'Map',
];

@override
void run(
CustomLintResolver resolver,
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addExtendsClause((node) {
final superClass = node.superclass;
TypeAnnotation? stateNode;

if (superClass.element?.name == BlocLintConstants.cubitClass) {
stateNode = superClass.typeArguments?.arguments[0];
} else if (superClass.element?.name == BlocLintConstants.blocClass) {
stateNode = superClass.typeArguments?.arguments[1];
}
if (stateNode == null) {
return;
}
final stateType = stateNode.type as InterfaceType?;
if (stateType == null || _ignoredType.contains(stateType.element.name)) {
return;
}

if (stateType.element.name.endsWith('State') == false) {
reporter.atNode(stateNode, code);
}
});
}
}
67 changes: 0 additions & 67 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.12.0"
bloc:
dependency: transitive
description:
name: bloc
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
url: "https://pub.dev"
source: hosted
version: "8.1.4"
boolean_selector:
dependency: transitive
description:
Expand All @@ -62,14 +54,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
Expand Down Expand Up @@ -182,19 +166,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_bloc:
dependency: "direct dev"
description:
name: flutter_bloc
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
url: "https://pub.dev"
source: hosted
version: "8.1.6"
freezed_annotation:
dependency: transitive
description:
Expand Down Expand Up @@ -291,14 +262,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
Expand All @@ -315,14 +278,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
node_preamble:
dependency: transitive
description:
Expand Down Expand Up @@ -355,14 +310,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
provider:
dependency: transitive
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
pub_semver:
dependency: transitive
description:
Expand Down Expand Up @@ -419,11 +366,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_map_stack_trace:
dependency: transitive
description:
Expand Down Expand Up @@ -536,14 +478,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.5.1"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
very_good_analysis:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -610,4 +544,3 @@ packages:
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=1.16.0"