@sun-asterisk/sunlint 1.3.41 → 1.3.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rules/security/S024_xpath_xxe_protection/typescript/regex-based-analyzer.js +4 -4
- package/rules/security/S024_xpath_xxe_protection/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S025_server_side_validation/typescript/regex-based-analyzer.js +5 -5
- package/rules/security/S025_server_side_validation/typescript/symbol-based-analyzer.js +6 -6
- package/rules/security/S032_httponly_session_cookies/typescript/regex-based-analyzer.js +8 -8
- package/rules/security/S033_samesite_session_cookies/typescript/regex-based-analyzer.js +12 -12
- package/rules/security/S033_samesite_session_cookies/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S034_host_prefix_session_cookies/typescript/regex-based-analyzer.js +1 -1
- package/rules/security/S041_session_token_invalidation/typescript/regex-based-analyzer.js +4 -4
- package/rules/security/S041_session_token_invalidation/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S044_re_authentication_required/typescript/regex-based-analyzer.js +1 -1
- package/rules/security/S044_re_authentication_required/typescript/symbol-based-analyzer.js +1 -1
- package/rules/security/S045_brute_force_protection/typescript/analyzer.js +1 -1
- package/rules/security/S045_brute_force_protection/typescript/symbol-based-analyzer.js +1 -1
- package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prefer Extracting Large Callbacks from Build
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability and testability by extracting large callback functions
|
|
5
|
+
tags: readability, maintainability, testability, callback
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Prefer Extracting Large Callbacks from Build
|
|
9
|
+
|
|
10
|
+
Callback functions (onTap, onPressed, onChanged, etc.) in widget builders should not exceed 5 lines. Large inline callbacks make the build method harder to read and maintain. Extract callbacks that exceed this limit to separate methods or functions.
|
|
11
|
+
|
|
12
|
+
**Incorrect (large inline callback):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
@override
|
|
16
|
+
Widget build(BuildContext context) {
|
|
17
|
+
return ElevatedButton(
|
|
18
|
+
onPressed: () {
|
|
19
|
+
final data = _formKey.currentState?.value;
|
|
20
|
+
if (data != null && data.isNotEmpty) {
|
|
21
|
+
_logger.info('Submitting data: $data');
|
|
22
|
+
_repository.save(data).then((_) {
|
|
23
|
+
Navigator.pop(context);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
child: Text('Submit'),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Correct (extracted callback method):**
|
|
33
|
+
|
|
34
|
+
```dart
|
|
35
|
+
void _handleSubmit() {
|
|
36
|
+
final data = _formKey.currentState?.value;
|
|
37
|
+
if (data != null && data.isNotEmpty) {
|
|
38
|
+
_logger.info('Submitting data: $data');
|
|
39
|
+
_repository.save(data).then((_) {
|
|
40
|
+
Navigator.pop(context);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@override
|
|
46
|
+
Widget build(BuildContext context) {
|
|
47
|
+
return ElevatedButton(
|
|
48
|
+
onPressed: _handleSubmit,
|
|
49
|
+
child: Text('Submit'),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Tools:** Custom analyzer (D006)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prefer Init First, Dispose Last
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Ensure proper lifecycle method ordering in StatefulWidget
|
|
5
|
+
tags: lifecycle, maintenance, flutter, statefulwidget
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Prefer Init First, Dispose Last
|
|
9
|
+
|
|
10
|
+
In StatefulWidget lifecycle methods, `super.initState()` should be called first before any initialization code, and `super.dispose()` should be called last after all cleanup code. This ensures that the framework's internal state management is properly initialized before your code runs and is the last to clean up.
|
|
11
|
+
|
|
12
|
+
**Incorrect (wrong order):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
@override
|
|
16
|
+
void initState() {
|
|
17
|
+
_controller = TextEditingController();
|
|
18
|
+
super.initState(); // Called after custom logic
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
void dispose() {
|
|
23
|
+
super.dispose(); // Called before cleanup
|
|
24
|
+
_controller.dispose();
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (framework-friendly order):**
|
|
29
|
+
|
|
30
|
+
```dart
|
|
31
|
+
@override
|
|
32
|
+
void initState() {
|
|
33
|
+
super.initState(); // Always first
|
|
34
|
+
_controller = TextEditingController();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@override
|
|
38
|
+
void dispose() {
|
|
39
|
+
_controller.dispose();
|
|
40
|
+
super.dispose(); // Always last
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Tools:** Custom analyzer (D007)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Long Functions
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Improve code readability and maintainability by limiting function length
|
|
5
|
+
tags: readability, maintainability, clean-code, dev-efficiency
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Long Functions
|
|
9
|
+
|
|
10
|
+
Functions should not exceed 60 lines of effective code (excluding comments and opening/closing braces). Long functions are harder to understand, test, and maintain. They often indicate that the function is doing too much and should be broken down into smaller, more focused functions.
|
|
11
|
+
|
|
12
|
+
**Incorrect (too long):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
void processOrder(Order order) {
|
|
16
|
+
// Line 1
|
|
17
|
+
// ... 60+ more lines of logic ...
|
|
18
|
+
// Line 70
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (modular functions):**
|
|
23
|
+
|
|
24
|
+
```dart
|
|
25
|
+
void processOrder(Order order) {
|
|
26
|
+
validateOrder(order);
|
|
27
|
+
calculateTotal(order);
|
|
28
|
+
saveToDatabase(order);
|
|
29
|
+
sendNotification(order);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void validateOrder(Order order) { ... }
|
|
33
|
+
void calculateTotal(Order order) { ... }
|
|
34
|
+
// Each function is focused and short
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Tools:** Custom analyzer (D008)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Limit Function Parameters
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Improve code readability by limiting the number of function parameters
|
|
5
|
+
tags: readability, maintainability, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Limit Function Parameters
|
|
9
|
+
|
|
10
|
+
Functions, methods, and constructors should not have more than 5 parameters. Too many parameters make code harder to read, understand, and maintain. When a function needs many parameters, consider grouping related parameters into a data class or using a configuration object.
|
|
11
|
+
|
|
12
|
+
**Incorrect (too many positional parameters):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
void createUser(String firstName, String lastName, int age, String email, String phone, String address, String city) {
|
|
16
|
+
// ...
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (using data object or named parameters):**
|
|
21
|
+
|
|
22
|
+
```dart
|
|
23
|
+
// Option 1: Data class
|
|
24
|
+
void createUser(UserDetail details) {
|
|
25
|
+
// ...
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Option 2: Grouped named parameters
|
|
29
|
+
void createUser({
|
|
30
|
+
required String name,
|
|
31
|
+
required ContactInfo contact,
|
|
32
|
+
required Address address,
|
|
33
|
+
}) {
|
|
34
|
+
// ...
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Tools:** Custom analyzer (D009)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Limit Cyclomatic Complexity
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Improve code readability and maintainability by limiting cyclomatic complexity
|
|
5
|
+
tags: complexity, maintainability, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Limit Cyclomatic Complexity
|
|
9
|
+
|
|
10
|
+
Functions, methods, and constructors should not have cyclomatic complexity exceeding 10. High cyclomatic complexity indicates that the code has too many independent paths, making it harder to understand, test, and maintain. Use early returns or extract complex logic into sub-functions.
|
|
11
|
+
|
|
12
|
+
**Incorrect (high complexity):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
String getStatusDescription(int status, bool isUrgent, bool isAdmin) {
|
|
16
|
+
if (status == 1) {
|
|
17
|
+
if (isUrgent) return "Urgent Pending";
|
|
18
|
+
return "Pending";
|
|
19
|
+
} else if (status == 2) {
|
|
20
|
+
if (isAdmin) return "Admin Approved";
|
|
21
|
+
return "Approved";
|
|
22
|
+
} else if (status == 3) {
|
|
23
|
+
return "Rejected";
|
|
24
|
+
} else {
|
|
25
|
+
return "Unknown";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Correct (reduced complexity with Map or early returns):**
|
|
31
|
+
|
|
32
|
+
```dart
|
|
33
|
+
static const statusMap = {
|
|
34
|
+
1: "Pending",
|
|
35
|
+
2: "Approved",
|
|
36
|
+
3: "Rejected",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
String getStatusDescription(int status, bool isUrgent, bool isAdmin) {
|
|
40
|
+
if (status == 1 && isUrgent) return "Urgent Pending";
|
|
41
|
+
if (status == 2 && isAdmin) return "Admin Approved";
|
|
42
|
+
return statusMap[status] ?? "Unknown";
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Tools:** Custom analyzer (D010)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prefer Named Parameters
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability and prevent parameter confusion
|
|
5
|
+
tags: readability, safety, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Prefer Named Parameters
|
|
9
|
+
|
|
10
|
+
Functions, methods, and constructors with more than 3 parameters that have 2 or more adjacent parameters of the same type should use named parameters. This improves code clarity by making it explicit which value corresponds to which parameter, reducing the risk of accidentally swapping arguments of the same type.
|
|
11
|
+
|
|
12
|
+
**Incorrect (confusing positional parameters):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
// At call site, hard to tell which is width and which is height
|
|
16
|
+
final rect = Rectangle(100.0, 50.0, 10.0, "red");
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (clear named parameters):**
|
|
20
|
+
|
|
21
|
+
```dart
|
|
22
|
+
// Much clearer at call site
|
|
23
|
+
final rect = Rectangle(
|
|
24
|
+
width: 100.0,
|
|
25
|
+
height: 50.0,
|
|
26
|
+
padding: 10.0,
|
|
27
|
+
color: "red",
|
|
28
|
+
);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Tools:** Custom analyzer (D011)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prefer Named Boolean Parameters
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability by avoiding unclear boolean parameters
|
|
5
|
+
tags: readability, clean-code, boolean
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Prefer Named Boolean Parameters
|
|
9
|
+
|
|
10
|
+
Boolean parameters in functions make code harder to understand at call sites (the "Boolean Trap"). When a function has boolean parameters, use named parameters to make the intent explicit. Better yet, create separate functions (e.g., `enableUser()` instead of `setUser(true)`).
|
|
11
|
+
|
|
12
|
+
**Incorrect (unclear boolean meaning):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
updateStatus(user, true); // What does true mean? Is it active? deleted? admin?
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (explicit naming):**
|
|
19
|
+
|
|
20
|
+
```dart
|
|
21
|
+
// Option 1: Named parameter
|
|
22
|
+
updateStatus(user, isActive: true);
|
|
23
|
+
|
|
24
|
+
// Option 2: Semantic function
|
|
25
|
+
activateUser(user);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Tools:** Custom analyzer (D012)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prefer a Single Public Class Per File
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code organization and maintainability
|
|
5
|
+
tags: organization, maintainability, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Prefer a Single Public Class Per File
|
|
9
|
+
|
|
10
|
+
Each Dart file should contain only one public class. Multiple public classes in a single file make code harder to navigate, test, and maintain. Private implementation classes (starting with `_`) are allowed in the same file.
|
|
11
|
+
|
|
12
|
+
**Incorrect (multiple public classes):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
// user_models.dart
|
|
16
|
+
class User { ... }
|
|
17
|
+
class UserProfile { ... }
|
|
18
|
+
class UserSettings { ... }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (split into separate files):**
|
|
22
|
+
|
|
23
|
+
```dart
|
|
24
|
+
// user.dart
|
|
25
|
+
class User { ... }
|
|
26
|
+
|
|
27
|
+
// user_profile.dart
|
|
28
|
+
class UserProfile { ... }
|
|
29
|
+
|
|
30
|
+
// user_settings.dart
|
|
31
|
+
class UserSettings { ... }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Tools:** Custom analyzer (D013)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Unsafe Collection Access
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevent runtime errors from accessing empty collections
|
|
5
|
+
tags: safety, stability, collections, crash-prevention
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Unsafe Collection Access
|
|
9
|
+
|
|
10
|
+
Using `.first`, `.last`, or `.single` on collections without checking if they're empty causes runtime `StateError` exceptions. Always check `isEmpty`, `isNotEmpty`, or use safe alternatives from `collection` package or built-in `firstOrNull`.
|
|
11
|
+
|
|
12
|
+
**Incorrect (potential crash):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
final firstUser = users.first; // Throws StateError if users is empty
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (safe access):**
|
|
19
|
+
|
|
20
|
+
```dart
|
|
21
|
+
// Option 1: check length
|
|
22
|
+
if (users.isNotEmpty) {
|
|
23
|
+
final firstUser = users.first;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Option 2: use null-safe getter (Dart 3.0+)
|
|
27
|
+
final firstUser = users.firstOrNull;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Tools:** Custom analyzer (D014)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Ensure copyWith includes all constructor parameters
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Maintain data integrity and completeness in immutable objects
|
|
5
|
+
tags: safety, immutability, data-integrity, boilerplate
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Ensure copyWith includes all constructor parameters
|
|
9
|
+
|
|
10
|
+
When a class implements a `copyWith` method for creating modified copies, it should include all constructor parameters. Missing parameters in `copyWith` can lead to unintended data loss or inability to update certain fields. This is especially important for data classes, models, and immutable state objects.
|
|
11
|
+
|
|
12
|
+
**Incorrect (incomplete copyWith):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
class User {
|
|
16
|
+
final String id;
|
|
17
|
+
final String name;
|
|
18
|
+
final int age;
|
|
19
|
+
|
|
20
|
+
User({required this.id, required this.name, required this.age});
|
|
21
|
+
|
|
22
|
+
User copyWith({String? name}) {
|
|
23
|
+
return User(
|
|
24
|
+
id: this.id,
|
|
25
|
+
name: name ?? this.name,
|
|
26
|
+
age: this.age, // age cannot be updated via copyWith
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Correct (complete copyWith):**
|
|
33
|
+
|
|
34
|
+
```dart
|
|
35
|
+
class User {
|
|
36
|
+
final String id;
|
|
37
|
+
final String name;
|
|
38
|
+
final int age;
|
|
39
|
+
|
|
40
|
+
User({required this.id, required this.name, required this.age});
|
|
41
|
+
|
|
42
|
+
User copyWith({String? name, int? age}) {
|
|
43
|
+
return User(
|
|
44
|
+
id: this.id,
|
|
45
|
+
name: name ?? this.name,
|
|
46
|
+
age: age ?? this.age,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Tools:** Custom analyzer (D015)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Project should have tests
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Ensure code quality and prevent regressions through automated testing
|
|
5
|
+
tags: testing, quality, reliability
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Project should have tests
|
|
9
|
+
|
|
10
|
+
Every Dart/Flutter project should have a `test` directory containing test files (files ending with `_test.dart`). Tests are essential for maintaining code quality, catching bugs early, and enabling safe refactoring.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no tests):**
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
my_project/
|
|
16
|
+
lib/
|
|
17
|
+
pubspec.yaml
|
|
18
|
+
# MISSING test/ directory
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (testing infrastructure included):**
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
my_project/
|
|
25
|
+
lib/
|
|
26
|
+
test/
|
|
27
|
+
unit_test.dart
|
|
28
|
+
widget_test.dart
|
|
29
|
+
pubspec.yaml
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Tools:** Custom analyzer (D016)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pubspec dependencies should be reviewed regularly
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Ensure dependencies are kept up-to-date for security and stability
|
|
5
|
+
tags: maintenance, security, dependencies
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Pubspec dependencies should be reviewed regularly
|
|
9
|
+
|
|
10
|
+
Dependencies in `pubspec.yaml` should be reviewed and updated regularly (at least every 4 months). Outdated dependencies may contain security vulnerabilities or miss critical performance improvements.
|
|
11
|
+
|
|
12
|
+
**Incorrect (old lock file):**
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
# pubspec.lock last modified: 6 months ago
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (regularly updated):**
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
# run 'flutter pub upgrade' and review dependencies regularly
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Tools:** Custom analyzer (D017)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remove Commented-Out Code
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Keep codebase clean by removing commented-out code
|
|
5
|
+
tags: cleanliness, readability, maintenance
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Remove Commented-Out Code
|
|
9
|
+
|
|
10
|
+
Commented-out code should be removed instead of being left in the source files. Dead code comments create clutter and confusion. If you need to reference old code, rely on version control (Git).
|
|
11
|
+
|
|
12
|
+
**Incorrect (abandoned code):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
void calculate() {
|
|
16
|
+
final result = 10 + 5;
|
|
17
|
+
// print("Debug result: $result");
|
|
18
|
+
// if (result > 10) {
|
|
19
|
+
// doSomething();
|
|
20
|
+
// }
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (clean file):**
|
|
26
|
+
|
|
27
|
+
```dart
|
|
28
|
+
void calculate() {
|
|
29
|
+
final result = 10 + 5;
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Tools:** Custom analyzer (D018)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Single Child in Multi-Child Widget
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Use appropriate widget types for the number of children
|
|
5
|
+
tags: performance, efficiency, best-practices
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Single Child in Multi-Child Widget
|
|
9
|
+
|
|
10
|
+
Multi-child widgets like `Column`, `Row`, `Stack`, `ListView`, or `GridView` are inefficient when used with only a single child. Use single-child optimized widgets like `SizedBox`, `Padding`, `Center`, or `Container` instead.
|
|
11
|
+
|
|
12
|
+
**Incorrect (inefficient Column):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
Column(
|
|
16
|
+
children: [
|
|
17
|
+
Text("Only one child here"),
|
|
18
|
+
],
|
|
19
|
+
)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (efficient wrapper):**
|
|
23
|
+
|
|
24
|
+
```dart
|
|
25
|
+
Padding(
|
|
26
|
+
padding: const EdgeInsets.all(8.0),
|
|
27
|
+
child: Text("Only one child here"),
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Tools:** Custom analyzer (D019)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Limit If/Else Branches
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Reduce complexity by limiting the number of if/else branches
|
|
5
|
+
tags: readability, complexity, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Limit If/Else Branches
|
|
9
|
+
|
|
10
|
+
Complex if/else chains with more than 3 branches reduce code readability and increase cyclomatic complexity. When facing multiple branches, consider using `switch` statements, lookup tables (Maps), or the Strategy pattern.
|
|
11
|
+
|
|
12
|
+
**Incorrect (long if/else chain):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
if (type == 'A') {
|
|
16
|
+
doA();
|
|
17
|
+
} else if (type == 'B') {
|
|
18
|
+
doB();
|
|
19
|
+
} else if (type == 'C') {
|
|
20
|
+
doC();
|
|
21
|
+
} else if (type == 'D') {
|
|
22
|
+
doD();
|
|
23
|
+
} else {
|
|
24
|
+
doDefault();
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (using switch or Map):**
|
|
29
|
+
|
|
30
|
+
```dart
|
|
31
|
+
// Option 1: Switch (better readability)
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'A': doA(); break;
|
|
34
|
+
case 'B': doB(); break;
|
|
35
|
+
case 'C': doC(); break;
|
|
36
|
+
case 'D': doD(); break;
|
|
37
|
+
default: doDefault();
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Tools:** Custom analyzer (D020)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Negated Boolean Checks
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability by avoiding inverted or negated boolean conditions
|
|
5
|
+
tags: readability, logic, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Negated Boolean Checks
|
|
9
|
+
|
|
10
|
+
Negated boolean checks (using `!`) make code harder to read and understand. Replace negative conditions with positive ones wherever possible, and avoid double negations like `!!`.
|
|
11
|
+
|
|
12
|
+
**Incorrect (fragmented logic):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
if (!isNotAuthorized) { ... }
|
|
16
|
+
if (!(a == b)) { ... }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (clear logic):**
|
|
20
|
+
|
|
21
|
+
```dart
|
|
22
|
+
if (isAuthorized) { ... }
|
|
23
|
+
if (a != b) { ... }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Tools:** Custom analyzer (D021)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use setState Correctly
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Ensure setState is used correctly in StatefulWidget to avoid performance issues and bugs
|
|
5
|
+
tags: performance, best-practices, lifecycle, state-management
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use setState Correctly
|
|
9
|
+
|
|
10
|
+
Common `setState` anti-patterns include: calling `setState` inside `build()`, nesting `setState` calls, making multiple `setState` calls in the same method, or using async callbacks inside `setState`. These lead to performance issues, unnecessary rebuilds, or hard-to-track UI bugs.
|
|
11
|
+
|
|
12
|
+
**Incorrect (async inside setState):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
setState(() async {
|
|
16
|
+
await fetchData(); // WRONG: setState should be synchronous
|
|
17
|
+
_data = "new data";
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (sync update after async):**
|
|
22
|
+
|
|
23
|
+
```dart
|
|
24
|
+
// Fetch data first
|
|
25
|
+
final newData = await fetchData();
|
|
26
|
+
|
|
27
|
+
// Update state synchronously
|
|
28
|
+
if (mounted) {
|
|
29
|
+
setState(() {
|
|
30
|
+
_data = newData;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tools:** Custom analyzer (D022)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Unnecessary Method Overrides
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Remove methods that only call super with the same parameters as they add no value
|
|
5
|
+
tags: readability, clean-code, refactoring
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Unnecessary Method Overrides
|
|
9
|
+
|
|
10
|
+
Methods that override a parent method but only call `super.methodName()` with the same parameters are unnecessary and should be removed. These empty overrides add no functionality and create unnecessary code clutter. Common examples include lifecycle methods like `initState()`, `dispose()`, or `didUpdateWidget()` that only call their super implementation.
|
|
11
|
+
|
|
12
|
+
**Incorrect (super call only):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
@override
|
|
16
|
+
void initState() {
|
|
17
|
+
super.initState();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
void dispose() {
|
|
22
|
+
super.dispose();
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Correct (remove if no logic):**
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
// Just remove the method override entirely if it only calls super
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Tools:** Custom analyzer (D023)
|