nilts
nilts provides lint rules, quick fixes, and assists for Dart and Flutter projects to help you enforce best practices and avoid errors.
Contents
Usage
Note: nilts no longer supports custom_lint.
If you're using custom_lint, please use nilts versions below v1.0 and refer to README_CUSTOM_LINT.md.
If you're using Dart SDK version 3.10 or later, add nilts to the top-level plugins section of your analysis_options.yaml file:
plugins:
nilts: ^1.0.0
Configuration
All lint rules in nilts are disabled by default.
This is because rules defined in warnings cannot currently be disabled individually. By using diagnostics, you can enable only the rules you need.
To enable rules, use the map format with version: and diagnostics::
plugins:
nilts:
version: ^1.0.0
diagnostics:
defined_async_callback_type: true
For a complete example of enabling all rules, see analysis_options.yaml.
See also:
Lint rules and quick fixes
See below to learn what each lint rule does. Some rules support quick fixes in your IDE.
Overview
| Rule name | Overview | Target SDK | Rule type | Maturity level | Severity | Quick fix |
|---|---|---|---|---|---|---|
| defined_async_callback_type | Checks Future<void> Function() definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| defined_async_value_getter_type | Checks Future<T> Function() definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| defined_async_value_setter_type | Checks Future<void> Function(T value) definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| defined_value_changed_type | Checks void Function(T value) definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| defined_value_getter_type | Checks T Function() definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| defined_value_setter_type | Checks void Function(T value) definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| defined_void_callback_type | Checks void Function() definitions. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| fixed_text_scale_rich_text | Checks usage of textScaler or textScaleFactor in RichText constructor. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| flaky_tests_with_set_up_all | Checks setUpAll usages. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| low_readability_numeric_literals | Checks numeric literals with 5 or more digits. | >= Dart 3.6.0 | Practice | Stable | Info | ✅️ |
| no_support_multi_text_direction | Checks if supports TextDirection changes. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| no_support_web_platform_check | Checks if Platform.isXxx usages. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| open_type_hierarchy | Checks if class modifiers exist (final, sealed, etc.) | Any versions nilts supports | Practice | Stable | Info | ✅️ |
| shrink_wrapped_scroll_view | Checks the content of the scroll view is shrink wrapped. | Any versions nilts supports | Practice | Stable | Info | ✅️ |
| unnecessary_rebuilds_from_media_query | Checks MediaQuery.xxxOf(context) or MediaQuery.maybeXxxOf(context) usages. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| unsafe_null_assertion | Checks usage of the ! operator for forced type casting. |
Any versions nilts supports | Practice | Stable | Info | ✅️ |
| unstable_enum_name | Checks usage of enum name property. | Any versions nilts supports | Practice | Stable | Info | ❌ |
| unstable_enum_values | Checks usage of enum values property. | Any versions nilts supports | Practice | Stable | Info | ❌ |
Details
defined_async_callback_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing Future<void> Function() with AsyncCallback, which is defined in the Flutter SDK.
BAD:
final Future<void> Function() callback;
GOOD:
final AsyncCallback callback;
See also:
defined_async_value_getter_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing Future<T> Function() with AsyncValueGetter, which is defined in the Flutter SDK.
BAD:
final Future<int> Function() callback;
GOOD:
final AsyncValueGetter<int> callback;
See also:
defined_async_value_setter_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing Future<void> Function(T value) with AsyncValueSetter, which is defined in the Flutter SDK.
BAD:
final Future<void> Function(int value) callback;
GOOD:
final AsyncValueSetter<int> callback;
See also:
defined_value_changed_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing void Function(T value) with ValueChanged, which is defined in the Flutter SDK.
If the value has been set, use ValueSetter instead.
BAD:
final void Function(int value) callback;
GOOD:
final ValueChanged<int> callback;
See also:
defined_value_getter_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing T Function() with ValueGetter, which is defined in the Flutter SDK.
BAD:
final int Function() callback;
GOOD:
final ValueGetter<int> callback;
See also:
defined_value_setter_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing void Function(T value) with ValueSetter, which is defined in the Flutter SDK.
If the value has changed, use ValueChanged instead.
BAD:
final void Function(int value) callback;
GOOD:
final ValueSetter<int> callback;
See also:
defined_void_callback_type
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider replacing void Function() with VoidCallback, which is defined in the Flutter SDK.
BAD:
final void Function() callback;
GOOD:
final VoidCallback callback;
See also:
fixed_text_scale_rich_text
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider using Text.rich or adding the textScaler or textScaleFactor (deprecated in Flutter 3.16.0 and above) argument to the RichText constructor to make the text size responsive to user settings.
BAD:
RichText(
text: TextSpan(
text: 'Hello, world!',
),
)
GOOD:
Text.rich(
TextSpan(
text: 'Hello, world!',
),
)
GOOD:
RichText(
text: TextSpan(
text: 'Hello, world!',
),
textScaler: MediaQuery.textScalerOf(context),
)
GOOD (deprecated on Flutter 3.16.0 and above):
RichText(
text: TextSpan(
text: 'Hello, world!',
),
textScaleFactor: MediaQuery.textScaleFactorOf(context),
)
See also:
flaky_tests_with_set_up_all
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider using the setUp function or performing initialization at the top level or within the test group body.
setUpAll may cause flaky tests when tests run concurrently.
BAD:
setUpAll(() {
// ...
});
GOOD:
setUp(() {
// ...
});
void main() {
// do initialization on top level
// ...
group('...', () {
// or do initialization on body of test group
// ...
});
}
See also:
low_readability_numeric_literals
- Target SDK : >= Dart 3.6.0
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider using digit separators for numeric literals with 5 or more digits to improve readability.
BAD:
const int value = 123456;
GOOD:
const int value = 123_456;
See also:
no_support_multi_text_direction
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider using TextDirection aware configurations if your application supports different TextDirection languages.
BAD:
Align(
alignment: Alignment.bottomLeft,
)
BAD:
Padding(
padding: EdgeInsets.only(left: 16, right: 4),
)
BAD:
Positioned(left: 12, child: SizedBox())
GOOD:
Align(
alignment: AlignmentDirectional.bottomStart,
)
GOOD:
Padding(
padding: EdgeInsetsDirectional.only(start: 16, end: 4),
)
GOOD:
Positioned.directional(
start: 12,
textDirection: TextDirection.ltr,
child: SizedBox(),
)
PositionedDirectional(
start: 12,
child: SizedBox(),
)
See also:
no_support_web_platform_check
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Prefer using defaultTargetPlatform instead of Platform API if you want to know which platform your application is running on.
This is because
PlatformAPI throws a runtime exception on web application.- By combining
kIsWebanddefaultTargetPlatform, you can accurately determine which platform your web application is running on.
BAD:
bool get isIOS => !kIsWeb && Platform.isIOS;
GOOD:
bool get isIOS => !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS;
See also:
open_type_hierarchy
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider adding a class modifier (final, sealed, etc.) to explicitly define the inheritance policy of your class.
BAD:
class MyClass {}
GOOD:
final class MyClass {}
shrink_wrapped_scroll_view
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Consider removing the shrinkWrap argument and updating the widget to avoid shrink wrapping.
Shrink wrapping the content of a scroll view is significantly more expensive than expanding to the maximum allowed size because the content can expand and contract during scrolling, which means the size of the scroll view needs to be recomputed whenever the scroll position changes.
You can avoid shrink wrapping with the following 3 steps if your scroll view is nested:
- Replace the parent scroll view with
CustomScrollView. - Replace the child scroll view with
SliverListVieworSliverGridView. - Set
SliverChildBuilderDelegatetodelegateargument of theSliverListVieworSliverGridView.
BAD:
ListView(shrinkWrap: true)
GOOD:
ListView(shrinkWrap: false)
See also:
unnecessary_rebuilds_from_media_query
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Prefer using MediaQuery.xxxOf or MediaQuery.maybeXxxOf instead of MediaQuery.of or MediaQuery.maybeOf to avoid unnecessary rebuilds.
BAD:
final size = MediaQuery.of(context).size;
GOOD:
final size = MediaQuery.sizeOf(context);
Note that using MediaQuery.of or MediaQuery.maybeOf makes sense in the following cases:
- Wrapping a widget with
MediaQueryto overrideMediaQueryData - Observing all changes to
MediaQueryData
See also:
unsafe_null_assertion
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ✅
Prefer using the if-null operator, null-aware operator, or pattern matching instead of force type casting with the ! operator.
BAD:
final value = someValue!;
GOOD:
final value = someValue ?? /* default value */;
GOOD:
final value = someValue?.someMethod();
See also:
unstable_enum_name
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ❌
Consider using a more stable way to handle enum values.
The name property is a string representation of the enum value,
which can be changed without breaking the code.
BAD:
void printColorValue(Color color) {
print(color.name); // 'red', 'green', 'blue'
}
GOOD:
enum Color {
red,
green,
blue,
;
String get id => switch (this) {
red => 'red',
green => 'green',
blue => 'blue',
};
}
void printColorValue(Color color) {
print(color.id);
}
See also:
unstable_enum_values
- Target SDK : Any versions nilts supports
- Rule type : Practice
- Maturity level : Stable
- Severity : Info
- Quick fix : ❌
Consider using a more stable way to handle enum values.
The values property returns a mutable List, which can be modified
and may cause unexpected behavior.
BAD:
enum Color { red, green, blue }
void printColors() {
for (final color in Color.values) {
print(color);
}
}
GOOD:
enum Color { red, green, blue }
void printColors() {
final colors = [Color.red, Color.green, Color.blue];
for (final color in colors) {
print(color);
}
}
See also:
Assists
Coming soon... 🚀
Feature requests
If you have any feature requests, please create an issue from this template.
Bug reports
If you find any bugs, please create an issue from this template.
Contributing
Contributions are welcome! Please read the CONTRIBUTING guide before submitting your PR.