@sun-asterisk/sunlint 1.3.41 → 1.3.42

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.
Files changed (106) hide show
  1. package/package.json +1 -1
  2. package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
  3. package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
  4. package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
  5. package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
  6. package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
  7. package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
  8. package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
  9. package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
  10. package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
  11. package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
  12. package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
  13. package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
  14. package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
  15. package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
  16. package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
  17. package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
  18. package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
  19. package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
  20. package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
  21. package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
  22. package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
  23. package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
  24. package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
  25. package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
  26. package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
  27. package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
  28. package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
  29. package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
  30. package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
  31. package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
  32. package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
  33. package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
  34. package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
  35. package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
  36. package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
  37. package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
  38. package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
  39. package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
  40. package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
  41. package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
  42. package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
  43. package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
  44. package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
  45. package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
  46. package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
  47. package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
  48. package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
  49. package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
  50. package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
  51. package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
  52. package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
  53. package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
  54. package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
  55. package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
  56. package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
  57. package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
  58. package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
  59. package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
  60. package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
  61. package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
  62. package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
  63. package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
  64. package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
  65. package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
  66. package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
  67. package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
  68. package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
  69. package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
  70. package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
  71. package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
  72. package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
  73. package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
  74. package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
  75. package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
  76. package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
  77. package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
  78. package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
  79. package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
  80. package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
  81. package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
  82. package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
  83. package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
  84. package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
  85. package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
  86. package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
  87. package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
  88. package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
  89. package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
  90. package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
  91. package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
  92. package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
  93. package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
  94. package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
  95. package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
  96. package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
  97. package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
  98. package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
  99. package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
  100. package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
  101. package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
  102. package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
  103. package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
  104. package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
  105. package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
  106. package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.3.41",
3
+ "version": "1.3.42",
4
4
  "description": "☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: Recommended Lint Rules Should Be Enabled
3
+ impact: MEDIUM
4
+ impactDescription: Ensure code quality through standard lint configurations
5
+ tags: lint, quality, static-analysis
6
+ ---
7
+
8
+ ## Recommended Lint Rules Should Be Enabled
9
+
10
+ The `analysis_options.yaml` file should include recommended lint packages (flutter_lints, very_good_analysis, or lints) and critical lint rules should not be disabled. This ensures consistent code quality standards across the project.
11
+
12
+ **Incorrect (minimal components):**
13
+
14
+ ```yaml
15
+ analyzer:
16
+ exclude:
17
+ - build/**
18
+ ```
19
+
20
+ **Correct (recommended setup):**
21
+
22
+ ```yaml
23
+ include: package:flutter_lints/flutter.yaml
24
+
25
+ analyzer:
26
+ exclude:
27
+ - "**/*.g.dart"
28
+ - "**/*.freezed.dart"
29
+
30
+ linter:
31
+ rules:
32
+ - avoid_print
33
+ - prefer_const_constructors
34
+ ```
35
+
36
+ **Tools:** Custom analyzer (D001)
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Always Dispose Resources and Remove Listeners
3
+ impact: HIGH
4
+ impactDescription: Prevent memory leaks by ensuring proper resource disposal
5
+ tags: memory-leak, resources, disposal, lifecycle, performance
6
+ ---
7
+
8
+ ## Always Dispose Resources and Remove Listeners
9
+
10
+ All disposable resources (Controllers, StreamSubscriptions, FocusNodes, Listeners) must be properly disposed in the `dispose()` method. This includes TextEditingController, AnimationController, ScrollController, StreamSubscription, FocusNode, and other resources that implement Disposable. Failing to dispose these resources leads to memory leaks.
11
+
12
+ **Incorrect (not disposed):**
13
+
14
+ ```dart
15
+ class _MyWidgetState extends State<MyWidget> {
16
+ final _controller = TextEditingController();
17
+
18
+ @override
19
+ Widget build(BuildContext context) {
20
+ return TextField(controller: _controller);
21
+ }
22
+ }
23
+ ```
24
+
25
+ **Correct (properly disposed):**
26
+
27
+ ```dart
28
+ class _MyWidgetState extends State<MyWidget> {
29
+ final _controller = TextEditingController();
30
+
31
+ @override
32
+ void dispose() {
33
+ _controller.dispose();
34
+ super.dispose();
35
+ }
36
+
37
+ @override
38
+ Widget build(BuildContext context) {
39
+ return TextField(controller: _controller);
40
+ }
41
+ }
42
+ ```
43
+
44
+ **Tools:** Custom analyzer (D002)
@@ -0,0 +1,53 @@
1
+ ---
2
+ title: Prefer Widgets Over Methods Returning Widgets
3
+ impact: LOW
4
+ impactDescription: Improve performance and maintainability by extracting widget-returning methods into widget classes
5
+ tags: performance, maintainability, widgets, extraction
6
+ ---
7
+
8
+ ## Prefer Widgets Over Methods Returning Widgets
9
+
10
+ Methods that return widgets should be extracted into separate StatelessWidget or StatefulWidget classes. This improves performance as Flutter can optimize widget rebuilds, makes code more reusable, and follows Flutter best practices. Only the build() method and lifecycle methods are exempt from this rule.
11
+
12
+ **Incorrect (method returning widget):**
13
+
14
+ ```dart
15
+ Widget _buildHeader() {
16
+ return Text("Title", style: TextStyle(fontSize: 24));
17
+ }
18
+
19
+ @override
20
+ Widget build(BuildContext context) {
21
+ return Column(
22
+ children: [
23
+ _buildHeader(),
24
+ Text("Content"),
25
+ ],
26
+ );
27
+ }
28
+ ```
29
+
30
+ **Correct (extracted widget class):**
31
+
32
+ ```dart
33
+ class HeaderWidget extends StatelessWidget {
34
+ const HeaderWidget({super.key});
35
+
36
+ @override
37
+ Widget build(BuildContext context) {
38
+ return Text("Title", style: TextStyle(fontSize: 24));
39
+ }
40
+ }
41
+
42
+ @override
43
+ Widget build(BuildContext context) {
44
+ return Column(
45
+ children: [
46
+ const HeaderWidget(),
47
+ Text("Content"),
48
+ ],
49
+ );
50
+ }
51
+ ```
52
+
53
+ **Tools:** Custom analyzer (D003)
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Avoid shrinkWrap in ListView
3
+ impact: LOW
4
+ impactDescription: Prevent performance issues caused by shrinkWrap in scrollable widgets
5
+ tags: performance, scroll, listview, lazy-loading
6
+ ---
7
+
8
+ ## Avoid shrinkWrap in ListView
9
+
10
+ Using `shrinkWrap: true` in ListView or GridView disables lazy loading and forces all items to render at once, causing severe performance degradation. Instead, use Expanded or Flexible widgets to constrain the ListView size, or use SliverList within a CustomScrollView for better performance. The shrinkWrap parameter should only be used in rare cases where the list is guaranteed to be small.
11
+
12
+ **Incorrect (using shrinkWrap):**
13
+
14
+ ```dart
15
+ ListView(
16
+ shrinkWrap: true,
17
+ children: [ ... ],
18
+ )
19
+ ```
20
+
21
+ **Correct (using Expanded):**
22
+
23
+ ```dart
24
+ Expanded(
25
+ child: ListView(
26
+ children: [ ... ],
27
+ ),
28
+ )
29
+ ```
30
+
31
+ **Tools:** Custom analyzer (D004)
@@ -0,0 +1,62 @@
1
+ ---
2
+ title: Limit Widget Nesting Depth to 6
3
+ impact: LOW
4
+ impactDescription: Maintain code readability and prevent performance issues caused by deeply nested widgets
5
+ tags: readability, maintainability, performance, nesting
6
+ ---
7
+
8
+ ## Limit Widget Nesting Depth to 6
9
+
10
+ Widget nesting should not exceed 6 levels in the build method. Deeply nested widgets make code harder to understand, maintain, and can impact performance. When nesting exceeds this limit, extract nested widgets into separate StatelessWidget or StatefulWidget classes.
11
+
12
+ **Incorrect (deeply nested):**
13
+
14
+ ```dart
15
+ @override
16
+ Widget build(BuildContext context) {
17
+ return Scaffold(
18
+ body: Center(
19
+ child: Container(
20
+ padding: const EdgeInsets.all(16),
21
+ child: Column(
22
+ children: [
23
+ Padding(
24
+ padding: const EdgeInsets.only(bottom: 8),
25
+ child: Row(
26
+ children: [
27
+ Expanded(
28
+ child: Card(
29
+ child: Padding(
30
+ padding: const EdgeInsets.all(12),
31
+ child: Text("Too deep!"), // Level 11
32
+ ),
33
+ ),
34
+ ),
35
+ ],
36
+ ),
37
+ ),
38
+ ],
39
+ ),
40
+ ),
41
+ ),
42
+ );
43
+ }
44
+ ```
45
+
46
+ **Correct (extracted widget):**
47
+
48
+ ```dart
49
+ @override
50
+ Widget build(BuildContext context) {
51
+ return Scaffold(
52
+ body: Center(
53
+ child: Container(
54
+ padding: const EdgeInsets.all(16),
55
+ child: const MyCustomHeader(), // Extracted at level 4
56
+ ),
57
+ ),
58
+ );
59
+ }
60
+ ```
61
+
62
+ **Tools:** Custom analyzer (D005)
@@ -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)