Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bloc_lint): move bloc_lint package from vmichalak repository to bloc monorepo #4278

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,7 @@ mason-lock.json
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
!/dev/ci/**/Gemfile.lock

# Custom_lint related.
custom_lint.log
3 changes: 3 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ analyzer:
strict-inference: true
strict-raw-types: true

plugins:
- custom_lint

errors:
close_sinks: ignore
missing_required_param: error
Expand Down
Empty file added packages/bloc_lint/.gitignore
Empty file.
11 changes: 11 additions & 0 deletions packages/bloc_lint/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## 0.1.0 - 2024-11-10

- Initial release
- New rules implemented:
- avoid_public_methods_on_bloc
- avoid_public_properties_on_bloc_and_cubit
- event_base_class_suffix
- prefer_multi_bloc_listener
- prefer_multi_bloc_provider
- prefer_multi_repository_provider
- state_base_class_suffix
21 changes: 21 additions & 0 deletions packages/bloc_lint/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Valentin Michalak

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
40 changes: 40 additions & 0 deletions packages/bloc_lint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Bloc Lint
===

Custom linter rules for Flutter projects using the [bloc library](https://bloclibrary.dev/). This package is based on
[dart_custom_lint](https://github.com/invertase/dart_custom_lint) package.

## Usage

Add the following to your `pubspec.yaml` file:

```yaml
dev_dependencies:
custom_lint: ^0.7.0
bloc_lint: ^0.1.0
```

Add the following to your `analysis_options.yaml` file:

```yaml
analyzer:
plugins:
- custom_lint
```

That's it! After running pub get (and possibly restarting their IDE), users should now see our custom lints in their
Dart files. You can also run `dart pub custom_lint` to run the linter in your CLI.

## Tests

The example folder contains a dart project to unit test the rules. (see custom_lint readme for more info)

## Implemented Rules

- [avoid_public_methods_on_bloc](doc/rules/avoid_public_methods_on_bloc.md)
- [avoid_public_properties_on_bloc_and_cubit](doc/rules/avoid_public_properties_on_bloc_and_cubit.md)
- [event_base_class_suffix](doc/rules/event_base_class_suffix.md)
- [prefer_multi_bloc_listener](doc/rules/prefer_multi_bloc_listener.md)
- [prefer_multi_bloc_provider](doc/rules/prefer_multi_bloc_provider.md)
- [prefer_multi_repository_provider](doc/rules/prefer_multi_repository_provider.md)
- [state_base_class_suffix](doc/rules/state_base_class_suffix.md)
27 changes: 27 additions & 0 deletions packages/bloc_lint/doc/rules/avoid_public_methods_on_bloc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
avoid_public_method_on_bloc
===
severity: WARNING

Avoid public methods on `Bloc` classes.

## Example:

❌ **BAD**:

```dart
class MyBloc extends Bloc<int, int> {
MyBloc(super.initialState);

void test() {}
}
```

✅ **GOOD**:

```dart
class MyBloc extends Bloc<int, int> {
MyBloc(super.initialState);

void _test() {}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
avoid_public_properties_on_bloc_and_cubit
===
severity: WARNING

Avoid public properties on `Bloc` and `Cubit`, prefer emit state or use private value.

## Example:

❌ **BAD**:

```dart
class MyCubit extends Cubit<int> {
MyCubit() : super(0);

int value = 1;
}
```

✅ **GOOD**:
```dart
class MyCubit extends Cubit<int> {
MyCubit() : super(0);

void init() {
emit(1);
}
}
```

or

```dart
class MyCubit extends Cubit<int> {
MyCubit() : super(0);

int _value = 1;
}
```
29 changes: 29 additions & 0 deletions packages/bloc_lint/doc/rules/event_base_class_suffix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
event_base_class_suffix
===
severity: WARNING

The base event class should always be suffixed by `Event`.

## Example:

❌ **BAD**:

```dart
@immutable
sealed class CounterData {}

final class CounterStarted extends CounterData {}
```

✅ **GOOD**:

```dart
@immutable
sealed class CounterEvent {}

final class CounterStarted extends CounterEvent {}
```

## Additional Resources

- [Bloc Library Documentation: Naming Conventions / Event Conventions](https://bloclibrary.dev/naming-conventions/#event-conventions)
38 changes: 38 additions & 0 deletions packages/bloc_lint/doc/rules/prefer_multi_bloc_listener.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
prefer-multi-bloc-listener
===
severity: WARNING

Warns when a `BlocListener` can be replaced by a `MultiBlocListener`.

## Example:

❌ **BAD**:

```dart
BlocListener<ACubit, AState>(
listener: (BuildContext context, state) {},
child: BlocListener<BCubit, BState>(
listener: (BuildContext context, state) {},
),
);
```

✅ **GOOD**:

```dart
MultiBlocListener(
listeners: [
BlocListener<ACubit, AState>(
listener: (BuildContext context, state) {},
),
BlocListener<BCubit, BState>(
listener: (BuildContext context, state) {},
),
],
child: Container(),
);
```

## Additional Resources

- [Bloc Library Documentation: Flutter Bloc Concepts / MultiBlocListener](https://bloclibrary.dev/flutter-bloc-concepts/#multibloclistener)
35 changes: 35 additions & 0 deletions packages/bloc_lint/doc/rules/prefer_multi_bloc_provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
prefer-multi-bloc-provider
===
severity: WARNING

Warns when a `BlocProvider` can be replaced by a `MultiBlocProvider`.

## Example:

❌ **BAD**:

```dart
BlocProvider<BlocA>(
create: (context) => BlocA(),
child: BlocProvider<BlocB>(
create: (context) => BlocB(),
child: Widget(),
),
);
```

✅ **GOOD**:

```dart
MultiBlocProvider(
providers: [
BlocProvider<BlocA>(create: (context) => BlocA()),
BlocProvider<BlocB>(create: (context) => BlocB()),
],
child: Widget(),
);
```

## Additional Resources

- [Bloc Library Documentation: Flutter Bloc Concepts / MultiBlocProvider](https://bloclibrary.dev/flutter-bloc-concepts/#multiblocprovider)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
prefer-multi-repository-provider
===
severity: WARNING

Warns when a `RepositoryProvider` can be replaced by a `MultiRepositoryProvider`.

## Example:

❌ **BAD**:

```dart
RepositoryProvider(
create: (_) => RepositoryA(),
child: RepositoryProvider(
create: (_) => RepositoryB(),
),
);
```

✅ **GOOD**:

```dart
MultiRepositoryProvider(
providers: [
RepositoryProvider(create: (_) => RepositoryA()),
RepositoryProvider(create: (_) => RepositoryB()),
],
child: Container(),
);
```

## Additional Resources

- [Bloc Library Documentation: Flutter Bloc Concepts / MultiRepositoryProvider](https://bloclibrary.dev/flutter-bloc-concepts/#multirepositoryprovider)
28 changes: 28 additions & 0 deletions packages/bloc_lint/doc/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)
3 changes: 3 additions & 0 deletions packages/bloc_lint/example/analysis_option.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
analyzer:
plugins:
- custom_lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:flutter_bloc/flutter_bloc.dart';

class AvoidPublicMethodOnBlocBloc extends Bloc<int, int> {
AvoidPublicMethodOnBlocBloc(super.initialState);

// expect_lint: avoid_public_methods_on_bloc
void publicMethod() {}

void _privateMethod() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:flutter_bloc/flutter_bloc.dart';

class TestPublicPropertiesCubit extends Cubit<int> {
TestPublicPropertiesCubit() : super(0);

// expect_lint: avoid_public_properties_on_bloc_and_cubit
int value = 0;
String _privateValue = 'abc';
}

class TestPublicPropertiesBloc extends Bloc<int, int> {
TestPublicPropertiesBloc() : super(0);

// expect_lint: avoid_public_properties_on_bloc_and_cubit
int value = 0;
String _privateValue = 'abc';
}
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 EventBaseClassSuffixLintRuleTestBloc extends Bloc<
// expect_lint: event_base_class_suffix
EventBaseClassSuffixLintRuleTestError,
EventBaseClassSuffixLintRuleTestState> {
EventBaseClassSuffixLintRuleTestBloc()
: super(EventBaseClassSuffixLintRuleTestInitial()) {
on<EventBaseClassSuffixLintRuleTestError>((event, emit) {
// TODO: implement event handler
});
}
}

@immutable
sealed class EventBaseClassSuffixLintRuleTestError {}

@immutable
sealed class EventBaseClassSuffixLintRuleTestState {}

final class EventBaseClassSuffixLintRuleTestInitial
extends EventBaseClassSuffixLintRuleTestState {}
Loading