pyramid_lint 0.4.0 pyramid_lint: ^0.4.0 copied to clipboard
pyramid_lint introduces a set of additional lints and fixes to enforce a consistent coding style, prevent common mistakes and enhance code readability.
Pyramid Lint #
pyramid_lint introduces a set of additional lints and fixes to enforce a consistent coding style, prevent common mistakes and enhance code readability using custom_lint.
Table of contents #
- Table of contents
- Installation
- Configuration
- Dart lints
- Flutter lints
- avoid_single_child_in_flex
- correct_order_for_super_dispose
- correct_order_for_super_init_state
- prefer_border_from_border_side
- prefer_border_radius_all
- prefer_dedicated_media_query_method
- prefer_spacer
- prefer_text_rich
- proper_controller_dispose
- proper_edge_insets_constructor
- proper_usage_of_expanded_and_flexible
- Dart assists
- Flutter assists
Installation #
Run the following command to add custom_lint
and pyramid_lint
to your project's dev dependencies:
dart pub add --dev custom_lint pyramid_lint
Enable custom_lint
in your analysis_options.yaml
file:
analyzer:
plugins:
- custom_lint
Configuration #
By default, all lints are enabled.
To disable a specific lint, add the following to your analysis_options.yaml
file:
custom_lint:
rules:
- specific_lint_rule: false # disable specific_lint_rule
To disable all lints and only enable the one you want, edit your analysis_options.yaml
file as below:
custom_lint:
enable_all_lint_rules: false # disable all lints
rules:
- specific_lint_rule # enable specific_lint_rule
Some lints have additional configuration options. To configure a lint, follow the example below:
custom_lint:
rules:
- configurable_lint_rule:
option1: value1
option2: value2
Dart lints #
avoid_duplicate_import #
Duplicate imports are unnecessary.
Bad
import 'dart:math' as math show max;
import 'dart:math';
final a = math.max(1, 10);
final b = min(1, 10);
Good
import 'dart:math' as math show max, min;
final a = math.max(1, 10);
final b = math.min(1, 10);
avoid_empty_block #
Empty block usually indicates a missing implementation.
Bad
void doSomething() {
}
Good
void doSomething() {
actuallyDoSomething();
}
void doSomething() {}
// TODO: implement doSomething
}
avoid_inverted_boolean_expression #
Inverted boolean expression decreases code readability.
Bad
if (!(number == 0)) {}
if (!(number > 0)) {}
final anotherNumber = !(number == 0) ? 1 : 2;
Good
if (number != 0) {}
if (number <= 0) {}
final anotherNumber = number != 0 ? 2 : 1;
Fix
max_lines_for_file #
A file should not exceed a certain number of lines.
Options:
max_lines
(default: 200)
max_lines_for_function #
A function should not exceed a certain number of lines.
Options:
max_lines
(default: 100)
prefer_declaring_const_constructor #
Constructors of classes with only final fields should be declared as const constructors when possible.
Bad
class Point {
final double x;
final double y;
Point(this.x, this.y);
Point.origin()
: x = 0,
y = 0;
}
Good
class Point {
final double x;
final double y;
const Point(this.x, this.y);
const Point.origin()
: x = 0,
y = 0;
}
Fix
prefer_declaring_parameter_name #
Not declaring parameter name decreases code readability and the IDEs code completion will not be able to suggest the parameter name.
Bad
typedef ItemBuilder = Widget Function(BuildContext, int);
Good
typedef ItemBuilder = Widget Function(BuildContext context, int index);
prefer_immediate_return #
Declaring a variable to return it on the next line is unnecessary.
Bad
int add(int a, int b) {
final result = a + b;
return result;
}
Good
int add(int a, int b) {
return a + b;
}
Fix
prefer_iterable_first #
Using iterable.first increases code readability.
Bad
const numbers = [1, 2, 3];
int firstNumber;
firstNumber = numbers[0];
firstNumber = numbers.elementAt(0);
Good
const numbers = [1, 2, 3];
int firstNumber;
firstNumber = numbers.first;
Fix
prefer_iterable_last #
Using iterable.last increases code readability.
Bad
const numbers = [1, 2, 3];
int lastNumber;
lastNumber = numbers[numbers.length - 1];
lastNumber = numbers.elementAt(numbers.length - 1);
Fix
Good
const numbers = [1, 2, 3];
int lastNumber;
lastNumber = numbers.last;
Flutter lints #
avoid_single_child_in_flex #
Using Column or Row with only one child is inefficient.
Bad
Row(
children: [
Container(),
],
)
Good
Align(
child: Container(),
)
// or
Center(
child: Container(),
)
Fix
correct_order_for_super_dispose #
super.dispose() should be called at the end of the dispose method.
Bad
@override
void dispose() {
super.dispose();
_dispose();
}
Good
@override
void dispose() {
_dispose();
super.dispose();
}
Fix
correct_order_for_super_init_state #
super.initState() should be called at the start of the initState method.
Bad
@override
void initState() {
_init();
super.initState();
}
Good
@override
void initState() {
super.initState();
_init();
}
Fix
prefer_border_from_border_side #
Border.all is not a const constructor and it uses const constructor Border.fromBorderSide internally.
Bad
DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
width: 1,
style: BorderStyle.solid,
),
),
)
Good
const DecoratedBox(
decoration: BoxDecoration(
border: Border.fromBorderSide(
BorderSide(
width: 1,
style: BorderStyle.solid,
),
),
),
)
Fix
prefer_border_radius_all #
BorderRadius.all is not a const constructor and it uses const constructor BorderRadius.circular internally.
Bad
DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
)
Good
const DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
)
Fix
prefer_dedicated_media_query_method #
Using MediaQuery.of(context) to access below properties will cause unnecessary rebuilds.
- accessibleNavigation
- alwaysUse24HourFormat
- boldText
- devicePixelRatio
- disableAnimations
- displayFeatures
- gestureSettings
- highContrast
- invertColors
- navigationMode
- orientation
- padding
- platformBrightness
- size
- systemGestureInsets
- textScaleFactor
- viewInsets
- viewPadding
Bad
final size = MediaQuery.of(context).size;
final orientation = MediaQuery.maybeOf(context)?.orientation;
Good
final size = MediaQuery.of(context).size;
final orientation = MediaQuery.maybeOrientationOf(context);
Fix
prefer_spacer #
Using Expanded with an empty Container or SizedBox is inefficient.
Bad
Column(
children: [
Expanded(
flex: 2,
child: SizedBox(),
),
],
)
Good
Column(
children: [
Spacer(flex: 2),
],
)
Fix
prefer_text_rich #
RichText does not inherit TextStyle from DefaultTextStyle.
Bad
RichText(
text: const TextSpan(
text: 'Pyramid',
children: [
TextSpan(text: 'Lint'),
],
),
)
Good
const Text.rich(
TextSpan(
text: 'Pyramid',
children: [
TextSpan(text: 'Lint'),
],
),
)
Fix
proper_controller_dispose #
Controllers should be disposed in dispose method.
- AnimationController
- PageController
- ScrollController
- SearchController
- TabController
- TextEditingController
- UndoHistoryController
Bad
class _MyWidgetState extends State<MyWidget> {
final _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Container();
}
}
Good
class _MyWidgetState extends State<MyWidget> {
final _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Container();
}
@override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
}
proper_edge_insets_constructor #
EdgeInsets.all(0) should be replaced with EdgeInsets.zero.
Bad
padding = const EdgeInsets.fromLTRB(0, 0, 0, 0);
padding = const EdgeInsets.fromLTRB(8, 8, 8, 8);
padding = const EdgeInsets.fromLTRB(8, 0, 8, 0);
padding = const EdgeInsets.fromLTRB(8, 4, 8, 4);
padding = const EdgeInsets.fromLTRB(8, 4, 8, 0);
padding = const EdgeInsets.only(left: 0, top: 0, right: 0, bottom: 0);
padding = const EdgeInsets.only(left: 8, top: 8, right: 8, bottom: 8);
padding = const EdgeInsets.only(left: 8, top: 0, right: 8, bottom: 0);
padding = const EdgeInsets.only(left: 8, top: 4, right: 8, bottom: 4);
padding = const EdgeInsets.only(left: 2, top: 4, right: 6, bottom: 8);
padding = const EdgeInsets.symmetric(horizontal: 0, vertical: 0);
padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 8);
padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 0);
Good
padding = EdgeInsets.zero;
padding = const EdgeInsets.all(8);
padding = const EdgeInsets.symmetric(horizontal: 8);
padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 4);
padding = const EdgeInsets.only(left: 8, top: 4, right: 8);
padding = EdgeInsets.zero;
padding = const EdgeInsets.all(8);
padding = const EdgeInsets.symmetric(horizontal: 8);
padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 4);
padding = const EdgeInsets.fromLTRB(2, 4, 6, 8);
padding = EdgeInsets.zero;
padding = const EdgeInsets.all(8);
padding = const EdgeInsets.symmetric(horizontal: 8);
Fix
proper_usage_of_expanded_and_flexible #
Expanded and Flexible should be placed inside a Row, Column, or Flex.
Bad
Center(
child: Expanded(
child: Container(),
),
)
Good
Row(
children: [
Expanded(
child: Container(),
),
],
)
Dart assists #
invert_boolean_expression #
Invert a boolean expression.
swap_then_else_expression #
Swap the then and else expression of a if-else expression or conditional expression.
Flutter assists #
use_edge_insets_zero #
Replace
- EdgeInsets.all(0)
- EdgeInsets.fromLTRB(0, 0, 0, 0)
- EdgeInsets.only(left: 0, top: 0, right: 0, bottom: 0)
- EdgeInsets.symmetric(horizontal: 0, vertical: 0)
with EdgeInsets.zero.
wrap_with_expanded #
Wrap the selected widget with an Expanded.
wrap_with_stack #
Wrap the selected widget with a Stack.