Skip to content

use_class_suffix

v1.0.0WarningFixConfigurableClass Naming

Flags classes that derive from a type you configure but don’t carry the name suffix you require. The type can be anything — a class from a dependency, or one declared in your own package.

This rule reports nothing until you configure it. It enforces your naming convention, not a built-in one.

When a class extends Bloc but is named CounterManager, or implements Repository but is named UserData, other developers have to check the inheritance chain to understand its role. A consistent suffix makes the architectural role obvious at a glance, and makes the codebase greppable by layer.

Because both the base type and the suffix are configuration, this works for ...Bloc, ...Cubit, ...Notifier, ...Repository, ...UseCase, ...Store — whatever vocabulary your project actually uses.

A type matches whether it is reached by extends, implements, with, or an indirect ancestor. The configured base type is never reported against itself.

import 'package:bloc/bloc.dart';
sealed class CounterEvent {}
// With an entry requiring the 'Bloc' suffix for subtypes of Bloc:
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);
}

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.

This rule is in no preset, so it is off unless you enable it by name:

many_lints.yaml
rules:
use_class_suffix: true

To turn it off again:

many_lints.yaml
rules:
use_class_suffix: false

To keep the rule on but skip certain paths, use per-rule exclude.

analysis_options.yaml
many_lints:
rules:
use_class_suffix:
ignore_private: true # rule-wide default, optional
entries:
- type: Bloc
package: bloc # optional; omit to match any package
suffix: Bloc
- type: Repository # a type from your own package
suffix: Repository
- type: UseCase
suffix: UseCase
ignore_private: false # per-entry override
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

Omit package for types you declare yourself — a local type has no package: URI to pin against. Add it when a name is ambiguous, so an unrelated Bloc from another dependency doesn’t match.

When a class matches several entries, the first one wins and it is reported once. An entry missing type or suffix is skipped; because a plugin cannot report problems against a YAML file, a malformed entry degrades quietly rather than failing analysis.

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:

analysis_options.yaml
many_lints:
rules:
use_class_suffix:
entries:
- type: Bloc
package: bloc
suffix: Bloc
- type: Cubit
package: bloc
suffix: Cubit
- type: Notifier
package: riverpod
suffix: Notifier