@sun-asterisk/sunlint 1.3.40 → 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 (172) hide show
  1. package/core/rule-selection-service.js +11 -0
  2. package/package.json +1 -1
  3. package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
  4. package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
  5. package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
  6. package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
  7. package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
  8. package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
  9. package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
  10. package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
  11. package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
  12. package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
  13. package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
  14. package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
  15. package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
  16. package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
  17. package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
  18. package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
  19. package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
  20. package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
  21. package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
  22. package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
  23. package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
  24. package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
  25. package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
  26. package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
  27. package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
  28. package/skill-assets/sunlint-code-quality/rules/go/C006-verb-noun-functions.md +45 -0
  29. package/skill-assets/sunlint-code-quality/rules/go/C013-no-dead-code.md +48 -0
  30. package/skill-assets/sunlint-code-quality/rules/go/C014-dependency-injection.md +85 -0
  31. package/skill-assets/sunlint-code-quality/rules/go/C017-no-constructor-logic.md +67 -0
  32. package/skill-assets/sunlint-code-quality/rules/go/C018-generic-errors.md +63 -0
  33. package/skill-assets/sunlint-code-quality/rules/go/C019-error-log-level.md +50 -0
  34. package/skill-assets/sunlint-code-quality/rules/go/C020-no-unused-imports.md +45 -0
  35. package/skill-assets/sunlint-code-quality/rules/go/C022-no-unused-variables.md +34 -0
  36. package/skill-assets/sunlint-code-quality/rules/go/C023-no-duplicate-names.md +41 -0
  37. package/skill-assets/sunlint-code-quality/rules/go/C024-centralize-constants.md +55 -0
  38. package/skill-assets/sunlint-code-quality/rules/go/C029-catch-log-root-cause.md +56 -0
  39. package/skill-assets/sunlint-code-quality/rules/go/C030-custom-error-classes.md +69 -0
  40. package/skill-assets/sunlint-code-quality/rules/go/C033-separate-data-access.md +68 -0
  41. package/skill-assets/sunlint-code-quality/rules/go/C035-error-context-logging.md +48 -0
  42. package/skill-assets/sunlint-code-quality/rules/go/C041-no-hardcoded-secrets.md +45 -0
  43. package/skill-assets/sunlint-code-quality/rules/go/C042-boolean-naming.md +42 -0
  44. package/skill-assets/sunlint-code-quality/rules/go/C052-controller-parsing.md +62 -0
  45. package/skill-assets/sunlint-code-quality/rules/go/C060-superclass-logic.md +60 -0
  46. package/skill-assets/sunlint-code-quality/rules/go/C067-no-hardcoded-config.md +51 -0
  47. package/skill-assets/sunlint-code-quality/rules/go/S003-open-redirect.md +80 -0
  48. package/skill-assets/sunlint-code-quality/rules/go/S004-no-log-credentials.md +66 -0
  49. package/skill-assets/sunlint-code-quality/rules/go/S005-server-authorization.md +55 -0
  50. package/skill-assets/sunlint-code-quality/rules/go/S006-default-credentials.md +47 -0
  51. package/skill-assets/sunlint-code-quality/rules/go/S007-output-encoding.md +50 -0
  52. package/skill-assets/sunlint-code-quality/rules/go/S009-approved-crypto.md +63 -0
  53. package/skill-assets/sunlint-code-quality/rules/go/S010-csprng.md +53 -0
  54. package/skill-assets/sunlint-code-quality/rules/go/S011-encrypted-client-hello.md +34 -0
  55. package/skill-assets/sunlint-code-quality/rules/go/S012-secrets-management.md +49 -0
  56. package/skill-assets/sunlint-code-quality/rules/go/S013-tls-connections.md +61 -0
  57. package/skill-assets/sunlint-code-quality/rules/go/S016-no-sensitive-query-string.md +42 -0
  58. package/skill-assets/sunlint-code-quality/rules/go/S017-parameterized-queries.md +36 -0
  59. package/skill-assets/sunlint-code-quality/rules/go/S019-email-input-sanitization.md +44 -0
  60. package/skill-assets/sunlint-code-quality/rules/go/S020-eval-code-execution.md +47 -0
  61. package/skill-assets/sunlint-code-quality/rules/go/S022-context-escaping.md +49 -0
  62. package/skill-assets/sunlint-code-quality/rules/go/S023-dynamic-js-encoding.md +51 -0
  63. package/skill-assets/sunlint-code-quality/rules/go/S025-server-validation.md +57 -0
  64. package/skill-assets/sunlint-code-quality/rules/go/S026-tls-encryption.md +46 -0
  65. package/skill-assets/sunlint-code-quality/rules/go/S027-mtls-validation.md +52 -0
  66. package/skill-assets/sunlint-code-quality/rules/go/S028-upload-limits.md +58 -0
  67. package/skill-assets/sunlint-code-quality/rules/go/S029-csrf-protection.md +53 -0
  68. package/skill-assets/sunlint-code-quality/rules/go/S030-directory-browsing.md +53 -0
  69. package/skill-assets/sunlint-code-quality/rules/go/S031-secure-cookie-flag.md +48 -0
  70. package/skill-assets/sunlint-code-quality/rules/go/S032-httponly-cookie.md +42 -0
  71. package/skill-assets/sunlint-code-quality/rules/go/S033-samesite-cookie.md +49 -0
  72. package/skill-assets/sunlint-code-quality/rules/go/S034-host-prefix-cookie.md +44 -0
  73. package/skill-assets/sunlint-code-quality/rules/go/S035-app-hostnames.md +50 -0
  74. package/skill-assets/sunlint-code-quality/rules/go/S036-internal-file-paths.md +56 -0
  75. package/skill-assets/sunlint-code-quality/rules/go/S037-anti-cache-headers.md +43 -0
  76. package/skill-assets/sunlint-code-quality/rules/go/S039-tls-certificate-validation.md +41 -0
  77. package/skill-assets/sunlint-code-quality/rules/go/S041-logout-invalidation.md +46 -0
  78. package/skill-assets/sunlint-code-quality/rules/go/S042-long-lived-sessions.md +58 -0
  79. package/skill-assets/sunlint-code-quality/rules/go/S044-critical-changes-reauth.md +53 -0
  80. package/skill-assets/sunlint-code-quality/rules/go/S045-brute-force-protection.md +55 -0
  81. package/skill-assets/sunlint-code-quality/rules/go/S047-oauth-csrf-protection.md +51 -0
  82. package/skill-assets/sunlint-code-quality/rules/go/S048-oauth-redirect-validation.md +58 -0
  83. package/skill-assets/sunlint-code-quality/rules/go/S049-auth-code-expiry.md +52 -0
  84. package/skill-assets/sunlint-code-quality/rules/go/S050-token-entropy.md +53 -0
  85. package/skill-assets/sunlint-code-quality/rules/go/S051-password-length.md +49 -0
  86. package/skill-assets/sunlint-code-quality/rules/go/S052-otp-entropy.md +48 -0
  87. package/skill-assets/sunlint-code-quality/rules/go/S053-generic-error-messages.md +51 -0
  88. package/skill-assets/sunlint-code-quality/rules/go/S054-no-default-admin.md +43 -0
  89. package/skill-assets/sunlint-code-quality/rules/go/S055-content-type-validation.md +52 -0
  90. package/skill-assets/sunlint-code-quality/rules/go/S056-log-injection.md +40 -0
  91. package/skill-assets/sunlint-code-quality/rules/go/S057-synchronized-time.md +40 -0
  92. package/skill-assets/sunlint-code-quality/rules/go/S058-ssrf-protection.md +70 -0
  93. package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
  94. package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
  95. package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
  96. package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
  97. package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
  98. package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
  99. package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
  100. package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
  101. package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
  102. package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
  103. package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
  104. package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
  105. package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
  106. package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
  107. package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
  108. package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
  109. package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
  110. package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
  111. package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
  112. package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
  113. package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
  114. package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
  115. package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
  116. package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
  117. package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
  118. package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
  119. package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
  120. package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
  121. package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
  122. package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
  123. package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
  124. package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
  125. package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
  126. package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
  127. package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
  128. package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
  129. package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
  130. package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
  131. package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
  132. package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
  133. package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
  134. package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
  135. package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
  136. package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
  137. package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
  138. package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
  139. package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
  140. package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
  141. package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
  142. package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
  143. package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
  144. package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
  145. package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
  146. package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
  147. package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
  148. package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
  149. package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
  150. package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
  151. package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
  152. package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
  153. package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
  154. package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
  155. package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
  156. package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
  157. package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
  158. package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
  159. package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
  160. package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
  161. package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
  162. package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
  163. package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
  164. package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
  165. package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
  166. package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
  167. package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
  168. package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
  169. package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
  170. package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
  171. package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
  172. package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: Follow MVC architecture strictly
3
+ impact: CRITICAL
4
+ impactDescription: Maintain clear separation of concerns.
5
+ tags: rails, architecture, mvc, design
6
+ ---
7
+
8
+ ## Follow MVC architecture strictly
9
+
10
+ Maintain clear separation of concerns. Models should handle data and business logic, Views should only handle presentation, and Controllers should coordinate between them. Avoid business logic in views or controllers.
11
+
12
+ **Incorrect:**
13
+
14
+ ```erb
15
+ <%# View with business logic %>
16
+ <% if @user.orders.sum(&:price) > 1000 %>
17
+ <span class="premium">Premium</span>
18
+ <% end %>
19
+ ```
20
+
21
+ **Correct:**
22
+
23
+ ```ruby
24
+ # Model
25
+ class User < ApplicationRecord
26
+ def premium?
27
+ orders.sum(&:price) > 1000
28
+ end
29
+ end
30
+
31
+ # View
32
+ <% if @user.premium? %>
33
+ <span class="premium">Premium</span>
34
+ <% end %>
35
+ ```
36
+
37
+ **Tools:** Manual Review, Architectural Check
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Use concerns judiciously
3
+ impact: MEDIUM
4
+ impactDescription: Prevent concerns from becoming dumping grounds for unrelated code.
5
+ tags: rails, architecture, concerns, design
6
+ ---
7
+
8
+ ## Use concerns judiciously
9
+
10
+ Prevent concerns from becoming dumping grounds for unrelated code. Only use concerns for clearly reusable behavior across multiple models/controllers. Each concern should have a single, well-defined responsibility.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # A concern that handles too many unrelated things
16
+ module UserHelper
17
+ extend ActiveSupport::Concern
18
+ # logic for auth, analytics, and image processing mixed together
19
+ end
20
+ ```
21
+
22
+ **Correct:**
23
+
24
+ ```ruby
25
+ module Authenticatable
26
+ extend ActiveSupport::Concern
27
+ # focus on auth logic only
28
+ end
29
+ ```
30
+
31
+ **Tools:** Manual Review
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Document callbacks and use them sparingly
3
+ impact: MEDIUM
4
+ impactDescription: Prevent hidden side effects and improve code clarity.
5
+ tags: rails, architecture, callbacks, documentation
6
+ ---
7
+
8
+ ## Document callbacks and use them sparingly
9
+
10
+ Prevent hidden side effects and improve code clarity. Use callbacks (like `before_save`, `after_create`) only when necessary. Consider using service objects if a callback triggers complex business logic.
11
+
12
+ **Incorrect (Hidden side effects):**
13
+
14
+ ```ruby
15
+ class Order < ApplicationRecord
16
+ after_create :charge_credit_card # Dangerous side effect hidden in model lifecycle
17
+ end
18
+ ```
19
+
20
+ **Correct (Explicit action):**
21
+
22
+ ```ruby
23
+ class CheckoutService
24
+ def self.call(order)
25
+ order.save!
26
+ PaymentGateway.charge(order) # Explicit and easier to test
27
+ end
28
+ end
29
+ ```
30
+
31
+ **Tools:** Manual Review
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: Use decorators for view logic
3
+ impact: MEDIUM
4
+ impactDescription: Keep models and views clean by separating presentation logic.
5
+ tags: rails, architecture, decorator, presentation
6
+ ---
7
+
8
+ ## Use decorators for view logic
9
+
10
+ Keep models and views clean by separating presentation logic. Use decorators (e.g., using the Draper gem or simple delegate classes) to format model data for the view layer.
11
+
12
+ **Incorrect (Logic in model):**
13
+
14
+ ```ruby
15
+ class User < ApplicationRecord
16
+ def full_name_for_display
17
+ "#{first_name} #{last_name} (#{email})"
18
+ end
19
+ end
20
+ ```
21
+
22
+ **Correct (Logic in decorator):**
23
+
24
+ ```ruby
25
+ class UserDecorator < Draper::Decorator
26
+ delegate_all
27
+ def display_name
28
+ "#{object.first_name} #{object.last_name} (#{object.email})"
29
+ end
30
+ end
31
+ ```
32
+
33
+ **Tools:** Manual Review
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Write comprehensive tests
3
+ impact: CRITICAL
4
+ impactDescription: Ensure code quality and prevent regressions.
5
+ tags: ruby, quality, testing, stability
6
+ ---
7
+
8
+ ## Write comprehensive tests
9
+
10
+ Ensure code quality and prevent regressions. Write unit tests for models/services, integration tests for controllers, and system tests for critical paths. Aim for >80% coverage for business-critical code.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # No tests covering edge cases or failure modes
16
+ ```
17
+
18
+ **Correct:**
19
+
20
+ ```ruby
21
+ RSpec.describe User, type: :model do
22
+ it "is valid with proper attributes" do
23
+ # ...
24
+ end
25
+
26
+ it "is invalid without an email" do
27
+ # ...
28
+ end
29
+ end
30
+ ```
31
+
32
+ **Tools:** RSpec, Minitest, SimpleCov
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Use frozen_string_literal: true
3
+ impact: LOW
4
+ impactDescription: Improve memory efficiency and prepare for Ruby 4.0 string immutability.
5
+ tags: ruby, performance, memory, preparation
6
+ ---
7
+
8
+ ## Use frozen_string_literal: true
9
+
10
+ Improve memory efficiency and prepare for Ruby 4.0 string immutability. Add `# frozen_string_literal: true` magic comment at the top of every Ruby file.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ class MyClass
16
+ DEFAULT_STATUS = "pending" # New string object created every time
17
+ end
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ # frozen_string_literal: true
24
+ class MyClass
25
+ DEFAULT_STATUS = "pending" # String object is frozen and reused
26
+ end
27
+ ```
28
+
29
+ **Tools:** RuboCop (`Style/FrozenStringLiteralComment`)
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: Use 'it' as a default block parameter (Ruby 3.4+)
3
+ impact: LOW
4
+ impactDescription: Enhance code readability for concise block operations.
5
+ tags: ruby, readability, quality, syntax
6
+ ---
7
+
8
+ ## Use 'it' as a default block parameter (Ruby 3.4+)
9
+
10
+ Enhance code readability for concise block operations. In Ruby 3.4+, use the implicit `it` keyword instead of explicit single-use block parameters to make simple iterations cleaner.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ users.map { |user| user.name }
16
+ ```
17
+
18
+ **Correct:**
19
+
20
+ ```ruby
21
+ # Ruby 3.4+
22
+ users.map { it.name }
23
+ ```
24
+
25
+ **Tools:** RuboCop (`Style/ItAssignment`)
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Use modern hash-based enum syntax
3
+ impact: MEDIUM
4
+ impactDescription: Use the more readable and explicit enum configuration in ActiveRecord.
5
+ tags: rails, active-record, readability, clarity
6
+ ---
7
+
8
+ ## Use modern hash-based enum syntax
9
+
10
+ Use the more readable and explicit enum configuration in ActiveRecord. Prefer mapping values to database integers explicitly via a hash to prevent accidental shifts if elements are reordered.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ class Order < ApplicationRecord
16
+ enum status: [:pending, :active, :shipped] # Dangerous if order changes
17
+ end
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ class Order < ApplicationRecord
24
+ enum :status, { pending: 0, active: 1, shipped: 2 } # Explicit and safe
25
+ end
26
+ ```
27
+
28
+ **Tools:** RuboCop (`Rails/EnumSyntax`)
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Prefer Solid Adapters for Infrastructure (Rails 8+)
3
+ impact: MEDIUM
4
+ impactDescription: Simplify deployment and reduce external dependencies.
5
+ tags: rails, rails8, architecture, infrastructure
6
+ ---
7
+
8
+ ## Prefer Solid Adapters for Infrastructure (Rails 8+)
9
+
10
+ Simplify deployment and reduce external dependencies. For Rails 8 projects, prefer `Solid Queue`, `Solid Cache`, and `Solid Cable` over Redis-based solutions for standard workloads to keep the infrastructure "lean".
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # config/environments/production.rb
16
+ config.cache_store = :redis_cache_store
17
+ config.active_job.queue_adapter = :sidekiq
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ # Rails 8 lean stack
24
+ config.cache_store = :solid_cache_store
25
+ config.active_job.queue_adapter = :solid_queue
26
+ ```
27
+
28
+ **Tools:** Manual Review
29
+ ---
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: Use built-in Rails 8 Authentication for greenfield projects
3
+ impact: MEDIUM
4
+ impactDescription: Use the native, lightweight authentication system to reduce dependency on Devise.
5
+ tags: rails, rails8, authentication, security
6
+ ---
7
+
8
+ ## Use built-in Rails 8 Authentication for greenfield projects
9
+
10
+ Use the native, lightweight authentication system to reduce dependency on Devise. Use `bin/rails generate authentication` for new projects unless complex features mandate a library.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # Adding Devise by default without evaluating built-in needs
16
+ bundle add devise
17
+ ```
18
+
19
+ **Correct:**
20
+
21
+ ```bash
22
+ # Using Rails 8 built-in generator
23
+ bin/rails generate authentication
24
+ ```
25
+
26
+ **Tools:** Manual Review
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Use Async Query Loading for slow interactions
3
+ impact: MEDIUM
4
+ impactDescription: Improve web performance by loading database data concurrently with view rendering.
5
+ tags: rails, performance, active-record, async
6
+ ---
7
+
8
+ ## Use Async Query Loading for slow interactions
9
+
10
+ Improve web performance by loading database data concurrently with view rendering. Use `.load_async` on ActiveRecord relations when multiple independent queries can be executed in the background while the controller or view processes.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # Sequential execution (Sync)
16
+ @posts = Post.all.load
17
+ @users = User.all.load
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```ruby
23
+ # Parallel execution (Async)
24
+ @posts = Post.all.load_async
25
+ @users = User.all.load_async
26
+ ```
27
+
28
+ **Tools:** Manual Review
29
+ ---
@@ -0,0 +1,30 @@
1
+ ---
2
+ title: Minimize custom JavaScript with Hotwire/Turbo 2.0
3
+ impact: MEDIUM
4
+ impactDescription: Focus on the Rails "Majestic Monolith" approach for better maintainability.
5
+ tags: rails, hotwire, turbo, stimulus, architecture
6
+ ---
7
+
8
+ ## Minimize custom JavaScript with Hotwire/Turbo 2.0
9
+
10
+ Focus on the Rails "Majestic Monolith" approach for better maintainability. Prefer `Turbo Frames` and `Turbo Streams` for interaction. Use `Stimulus` for small client-side behaviors.
11
+
12
+ **Incorrect:**
13
+
14
+ ```javascript
15
+ // Complex React/Vue component for a simple list update
16
+ ```
17
+
18
+ **Correct:**
19
+
20
+ ```erb
21
+ <%# Rails Turbo Stream response %>
22
+ <turbo-stream action="append" target="messages">
23
+ <template>
24
+ <%= render @message %>
25
+ </template>
26
+ </turbo-stream>
27
+ ```
28
+
29
+ **Tools:** Manual Review
30
+ ---
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Use Propshaft as the default asset pipeline
3
+ impact: LOW
4
+ impactDescription: Use the modern, simplified asset pipeline instead of Sprockets.
5
+ tags: rails, assets, propshaft, performance
6
+ ---
7
+
8
+ ## Use Propshaft as the default asset pipeline
9
+
10
+ Use the modern, simplified asset pipeline instead of Sprockets. For new Rails 7+ projects, use `Propshaft` to handle asset digests and paths without the complexity of transpilation.
11
+
12
+ **Incorrect:**
13
+
14
+ ```ruby
15
+ # Gemfile
16
+ gem 'sprockets-rails'
17
+ ```
18
+
19
+ **Correct:**
20
+
21
+ ```ruby
22
+ # Gemfile
23
+ gem 'propshaft'
24
+ ```
25
+
26
+ **Tools:** Manual Review
27
+ ---
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Use Structured Logging for Observability
3
+ impact: MEDIUM
4
+ impactDescription: Improve log parsing and searching in production environments.
5
+ tags: ruby, rails, logs, observability, json
6
+ ---
7
+
8
+ ## Use Structured Logging for Observability
9
+
10
+ Improve log parsing and searching in production environments. Configure structured (JSON) logging in production to facilitate tracing and automated analysis.
11
+
12
+ **Incorrect:**
13
+
14
+ ```text
15
+ Processing by UsersController#show as HTML
16
+ Parameters: {"id"=>"1"}
17
+ Completed 200 OK in 10ms
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```json
23
+ {
24
+ "timestamp": "2025-02-05T12:00:00Z",
25
+ "level": "INFO",
26
+ "controller": "UsersController",
27
+ "action": "show",
28
+ "params": {"id": "1"},
29
+ "status": 200,
30
+ "duration_ms": 10
31
+ }
32
+ ```
33
+
34
+ **Tools:** Lograge gem
35
+ ---
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Use Prism as the default parser for tooling
3
+ impact: LOW
4
+ impactDescription: Leverage the faster, more accurate Ruby parser.
5
+ tags: ruby, tooling, prism, performance
6
+ ---
7
+
8
+ ## Use Prism as the default parser for tooling
9
+
10
+ Leverage the faster, more accurate Ruby parser. Configure tools like `RuboCop` or `SyntaxTree` to use `Prism` for parsing where supported in Ruby 3.4+.
11
+
12
+ **Incorrect:**
13
+
14
+ ```yaml
15
+ # .rubocop.yml
16
+ AllCops:
17
+ ParserEngine: parser # Default
18
+ ```
19
+
20
+ **Correct:**
21
+
22
+ ```yaml
23
+ # .rubocop.yml
24
+ AllCops:
25
+ ParserEngine: prism
26
+ ```
27
+
28
+ **Tools:** RuboCop (`ParserEngine: prism`)
29
+ ---
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Sử dụng observe property của Swift thay vì KVO cũ
3
+ impact: MEDIUM
4
+ impactDescription: Tránh sử dụng cơ chế KVO lỗi thời, giảm thiểu độ phức tạp và lỗi khi override observeValue.
5
+ tags: swift, ios, kvo, observation, code-quality
6
+ ---
7
+
8
+ ## Sử dụng observe property của Swift thay vì KVO cũ
9
+
10
+ Ưu tiên dùng block-based KVO API với `keypaths` khi dùng Swift 3.2 trở lên. Loại bỏ việc override `observeValue` truyền thống vốn phức tạp và dễ sai.
11
+
12
+ **Incorrect (KVO cũ):**
13
+
14
+ ```swift
15
+ class MyObserver: NSObject {
16
+ @objc var objectToObserve: MyObject
17
+
18
+ override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
19
+ if keyPath == "someProperty" {
20
+ // Xử lý thay đổi
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ **Correct (Block-based KVO):**
27
+
28
+ ```swift
29
+ class MyObserver {
30
+ var observation: NSKeyValueObservation?
31
+
32
+ init(object: MyObject) {
33
+ observation = object.observe(\.someProperty, options: [.new]) { object, change in
34
+ // Xử lý thay đổi qua block
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ **Tools:** SwiftLint (block_based_kvo)
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: Delegate Protocol phải là class-only
3
+ impact: HIGH
4
+ impactDescription: Cho phép dùng weak để tránh retain cycles (memory leak) giữa các đối tượng.
5
+ tags: swift, ios, delegate, memory-leak, AnyObject
6
+ ---
7
+
8
+ ## Delegate Protocol phải là class-only
9
+
10
+ `weak` chỉ hỗ trợ class types, do đó các delegate protocol phải được khai báo là `class`-based (`AnyObject`). Điều này giúp ngăn chặn retain cycles khi delegate trỏ ngược lại đối tượng sở hữu nó.
11
+
12
+ **Incorrect (không giới hạn class):**
13
+
14
+ ```swift
15
+ protocol MyDelegate {
16
+ func didUpdateData()
17
+ }
18
+
19
+ class MyView {
20
+ var delegate: MyDelegate? // Lỗi: Không thể dùng weak ở đây nếu protocol không là AnyObject
21
+ }
22
+ ```
23
+
24
+ **Correct (class-only protocol):**
25
+
26
+ ```swift
27
+ protocol MyDelegate: AnyObject {
28
+ func didUpdateData()
29
+ }
30
+
31
+ class MyView {
32
+ weak var delegate: MyDelegate? // Đúng: Có thể dùng weak để tránh memory leak
33
+ }
34
+ ```
35
+
36
+ **Tools:** SwiftLint (class_delegate_protocol)
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Không khởi tạo trực tiếp các protocol hệ thống
3
+ impact: MEDIUM
4
+ impactDescription: Tránh misuse các compiler protocol như ExpressibleByArrayLiteral, khuyến khích sử dụng literal syntax.
5
+ tags: swift, ios, compiler, literals, code-quality
6
+ ---
7
+
8
+ ## Không khởi tạo trực tiếp các protocol hệ thống
9
+
10
+ Các protocol của compiler (như `ExpressibleByArrayLiteral`) không nên được gọi `init` trực tiếp. Hãy sử dụng cú pháp gọn gàng (literals) để khởi tạo giá trị.
11
+
12
+ **Incorrect (Gọi init trực tiếp):**
13
+
14
+ ```swift
15
+ let array = Array(arrayLiteral: 1, 2, 3)
16
+ let dict = Dictionary(dictionaryLiteral: ("key", "value"))
17
+ let string = String(stringLiteral: "Hello")
18
+ ```
19
+
20
+ **Correct (Sử dụng literal syntax):**
21
+
22
+ ```swift
23
+ let array = [1, 2, 3]
24
+ let dict = ["key": "value"]
25
+ let string = "Hello"
26
+ ```
27
+
28
+ **Tools:** SwiftLint (compiler_protocol_init)
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Ưu tiên sử dụng .contains trong một số phép lọc
3
+ impact: LOW
4
+ impactDescription: Cải thiện hiệu năng và độ rõ ràng của code bằng cách dùng phương thức chuyên dụng thay vì lọc rồi đếm.
5
+ tags: swift, ios, performance, collections, readability
6
+ ---
7
+
8
+ ## Ưu tiên sử dụng .contains trong một số phép lọc
9
+
10
+ Thay vì `.filter { ... }.count > 0` hoặc `.first != nil`, hãy dùng `.contains`. `.contains` thường ngắn hơn, dễ hiểu hơn và hiệu quả hơn vì nó dừng ngay khi tìm thấy phần tử khớp.
11
+
12
+ **Incorrect (Lọc rồi đếm):**
13
+
14
+ ```swift
15
+ let numbers = [1, 2, 3, 4, 5]
16
+ let hasEven = numbers.filter { $0 % 2 == 0 }.count > 0
17
+ let hasFive = numbers.first { $0 == 5 } != nil
18
+ ```
19
+
20
+ **Correct (Sử dụng .contains):**
21
+
22
+ ```swift
23
+ let numbers = [1, 2, 3, 4, 5]
24
+ let hasEven = numbers.contains { $0 % 2 == 0 }
25
+ let hasFive = numbers.contains(5)
26
+ ```
27
+
28
+ **Tools:** SwiftLint (contains_over_*)
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Dùng enum cho type chỉ gồm static members
3
+ impact: LOW
4
+ impactDescription: Ngăn chặn việc khởi tạo các type không cần thiết khi chúng chỉ đóng vai trò là container cho hằng số hoặc tiện ích.
5
+ tags: swift, ios, architecture, enum, static-members
6
+ ---
7
+
8
+ ## Dùng enum cho type chỉ gồm static members
9
+
10
+ Nếu một type chỉ chứa static members (như hằng số, helper methods), nên dùng `enum` không có case để không cho phép khởi tạo. `enum` không thể được khởi tạo trực tiếp, giúp tránh việc lạm dụng hoặc tạo ra các instance vô nghĩa.
11
+
12
+ **Incorrect (Sử dụng struct/class):**
13
+
14
+ ```swift
15
+ struct Config {
16
+ static let apiKey = "SECRET"
17
+ static let baseUrl = "https://api.example.com"
18
+ }
19
+
20
+ let config = Config() // Vẫn có thể tạo instance
21
+ ```
22
+
23
+ **Correct (Sử dụng enum):**
24
+
25
+ ```swift
26
+ enum Config {
27
+ static let apiKey = "SECRET"
28
+ static let baseUrl = "https://api.example.com"
29
+ }
30
+
31
+ // let config = Config() // Lỗi: Enum không có case không thể khởi tạo
32
+ ```
33
+
34
+ **Tools:** SwiftLint (convenience_type)
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Luôn dispose observer của NotificationCenter
3
+ impact: HIGH
4
+ impactDescription: Tránh memory leak và các hành vi không mong muốn khi observer vẫn tồn tại dù đối tượng đã bị giải phóng.
5
+ tags: swift, ios, notification-center, memory-leak, observer
6
+ ---
7
+
8
+ ## Luôn dispose observer của NotificationCenter
9
+
10
+ Luôn lưu lại token khi `addObserver` với NotificationCenter bằng block-based API. Gọi `removeObserver()` khi observer không còn cần thiết hoặc trong `deinit` để giải phóng bộ nhớ.
11
+
12
+ **Incorrect (không lưu token hoặc không remove):**
13
+
14
+ ```swift
15
+ NotificationCenter.default.addObserver(forName: .myNotification, object: nil, queue: .main) { _ in
16
+ print("Notification received")
17
+ }
18
+ // Không có cách nào để remove observer này sau đó
19
+ ```
20
+
21
+ **Correct (lưu token và remove trong deinit):**
22
+
23
+ ```swift
24
+ class MyManager {
25
+ private var observer: NSObjectProtocol?
26
+
27
+ init() {
28
+ observer = NotificationCenter.default.addObserver(forName: .myNotification, object: nil, queue: .main) { _ in
29
+ print("Notification received")
30
+ }
31
+ }
32
+
33
+ deinit {
34
+ if let observer = observer {
35
+ NotificationCenter.default.removeObserver(observer)
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ **Tools:** SwiftLint (discarded_notification_center_observer)