use_class_suffix
Flags a class that derives from a type you name but does not carry the suffix you require. A quick fix appends it.
When a class extends Bloc but is called CounterManager, a reader has to follow the inheritance chain to learn its role. A consistent suffix puts the role in the name, and makes the codebase greppable by layer.
This rule is in no preset and reports nothing until you add entries:. Every example below shows the configuration that produces it.
many_lints: rules: use_class_suffix: entries: - type: Bloc package: bloc suffix: Blocrules: use_class_suffix: entries: - type: Bloc package: bloc suffix: Blocpackage: is optional. Omit it for a type you declare yourself — a local type has no package: URI to pin against. Add it when the name is ambiguous, so an unrelated Bloc from another dependency does not match.
A type matches whether it is reached by extends, implements, with, or an indirect ancestor. The configured base type is never reported against itself.
With entries: [{type: Bloc, package: bloc, suffix: Bloc}]:
import 'package:bloc/bloc.dart';
sealed class CounterEvent {}
class CounterManager extends Bloc<CounterEvent, int> { // LINT CounterManager() : super(0);}import 'package:bloc/bloc.dart';
sealed class CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0);}Examples
Section titled “Examples”A type from your own package
Section titled “A type from your own package”Omit package: — the type is declared in the code being analysed:
- type: Repository suffix: Repositoryabstract class Repository {}
// Don'tclass UserData implements Repository {} // LINT
// Doclass UserRepository implements Repository {}Repository itself is not reported: requiring the base type to be named RepositoryRepository is nonsense, and for a type owned by a dependency you could not act on it anyway.
Several conventions at once
Section titled “Several conventions at once”entries: - type: Bloc package: bloc suffix: Bloc - type: Cubit package: bloc suffix: Cubit - type: UseCase suffix: UseCaseabstract class UseCase {}
// Don'tclass PlaceOrder implements UseCase {} // LINT
// Doclass PlaceOrderUseCase implements UseCase {}When a class matches several entries, the first one wins and it is reported once.
Leaving private classes alone
Section titled “Leaving private classes alone”ignore_private: true skips classes whose name starts with _. A private class cannot be referenced outside its library, so the naming convention buys less there.
rules: use_class_suffix: ignore_private: true # rule-wide default entries: - type: Repository suffix: Repository - type: UseCase suffix: UseCase ignore_private: false # this one checks private classes tooabstract class Repository {}abstract class UseCase {}
// Not reported — private, and this entry ignores private classesclass _CachedUsers implements Repository {}
// Reported — this entry overrides the rule-wide defaultclass _PlaceOrder implements UseCase {} // LINTAn indirect ancestor still matches
Section titled “An indirect ancestor still matches”- type: Repository suffix: Repositoryabstract class Repository {}abstract class CachingRepository implements Repository {}
// Don't — reaches Repository through CachingRepositoryclass UserStore extends CachingRepository {} // LINT
// Doclass UserCachingRepository extends CachingRepository {}Quick fix
Section titled “Quick fix”The fix appends the required suffix, and repairs a near-miss rather than stacking onto it — CounterBlok becomes CounterBloc, not CounterBlokBloc. A same-named unnamed constructor is renamed along with the class, so the result still compiles.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
entries |
list of maps | [] |
The base types to track. With none, the rule reports nothing |
ignore_private |
bool | false |
Rule-wide default for skipping classes whose name starts with _ |
Each entry accepts:
| Key | Type | Required | Description |
|---|---|---|---|
type |
string | yes | Name of the base type, e.g. Bloc |
suffix |
string | yes | The suffix subtypes must end with |
package |
string | no | Package declaring type. Omit to match a type of that name from any library, including your own package |
ignore_private |
bool | no | Overrides the rule-wide ignore_private for this entry |
Known limitations
Section titled “Known limitations”Classes only. A mixin, enum or extension type is not checked, even when it implements a configured type. For those, reach for match_class_name_pattern.
A malformed entry is silent. An entry missing type or suffix is skipped, because a plugin cannot report problems against a YAML file. If an entry never fires, check both keys are present and non-empty.
Migration from use_bloc_suffix / use_cubit_suffix / use_notifier_suffix
Section titled “Migration from use_bloc_suffix / use_cubit_suffix / use_notifier_suffix”Those three rules were replaced by this one. To restore their exact behaviour:
many_lints: rules: use_class_suffix: entries: - type: Bloc package: bloc suffix: Bloc - type: Cubit package: bloc suffix: Cubit - type: Notifier package: riverpod suffix: Notifierrules: use_class_suffix: entries: - type: Bloc package: bloc suffix: Bloc - type: Cubit package: bloc suffix: Cubit - type: Notifier package: riverpod suffix: NotifierTurning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: use_class_suffix: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”match_class_name_pattern— Match class names against a regular expression.use_class_prefix— Require a name prefix for classes deriving from a configured type.prefer_correct_identifier_length— Keep identifier length within bounds.prefer_correct_type_name— Keep type names within a sensible length and correctly capitalised.