@sun-asterisk/sunlint 1.3.32 → 1.3.34

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 (456) hide show
  1. package/README.md +47 -0
  2. package/config/released-rules.json +62 -0
  3. package/config/rules/enhanced-rules-registry.json +2315 -1354
  4. package/core/adapters/dart-analyzer.js +658 -0
  5. package/core/adapters/index.js +102 -0
  6. package/core/adapters/sunlint-rule-adapter.js +0 -2
  7. package/core/adapters/typescript-analyzer.js +277 -0
  8. package/core/analysis-orchestrator.js +168 -40
  9. package/core/architecture-integration.js +220 -0
  10. package/core/cli-action-handler.js +72 -24
  11. package/core/cli-program.js +13 -1
  12. package/core/config-merger.js +24 -14
  13. package/core/constants/defaults.js +1 -2
  14. package/core/github-annotate-service.js +141 -89
  15. package/core/github-step-summary-generator.js +8 -8
  16. package/core/interfaces/language-analyzer.interface.js +393 -0
  17. package/core/output-service.js +102 -38
  18. package/core/rule-selection-service.js +77 -27
  19. package/core/scoring-service.js +65 -20
  20. package/core/semantic-engine-manager.js +375 -0
  21. package/core/semantic-engine.js +4 -57
  22. package/core/unified-rule-registry.js +52 -11
  23. package/core/upload-service.js +43 -9
  24. package/docs/DART_RULE_EXECUTION_FLOW.md +745 -0
  25. package/docs/DART_SUPPORT_IMPLEMENTATION.md +245 -0
  26. package/docs/SUNLINT_ARCHITECTURE.md +692 -0
  27. package/docs/skills/CREATE_DART_RULE.md +909 -0
  28. package/engines/eslint-engine.js +2 -8
  29. package/engines/heuristic-engine.js +234 -38
  30. package/package.json +6 -5
  31. package/rules/common/C002_no_duplicate_code/config.json +12 -20
  32. package/rules/common/C002_no_duplicate_code/dart/analyzer.js +53 -0
  33. package/rules/common/C002_no_duplicate_code/index.js +93 -0
  34. package/rules/common/C003_no_vague_abbreviations/config.json +1 -1
  35. package/rules/common/C003_no_vague_abbreviations/dart/analyzer.js +54 -0
  36. package/rules/common/C003_no_vague_abbreviations/index.js +93 -0
  37. package/rules/common/C006_function_naming/dart/analyzer.js +40 -0
  38. package/rules/common/C006_function_naming/index.js +86 -0
  39. package/rules/common/C008_variable_declaration_locality/dart/analyzer.js +32 -0
  40. package/rules/common/C008_variable_declaration_locality/index.js +86 -0
  41. package/rules/common/C010_limit_block_nesting/dart/analyzer.js +32 -0
  42. package/rules/common/C010_limit_block_nesting/index.js +86 -0
  43. package/rules/common/C012_command_query_separation/config.json +61 -0
  44. package/rules/common/C012_command_query_separation/dart/analyzer.js +32 -0
  45. package/rules/common/C012_command_query_separation/index.js +86 -0
  46. package/rules/common/C013_no_dead_code/dart/analyzer.js +32 -0
  47. package/rules/common/C013_no_dead_code/index.js +86 -0
  48. package/rules/common/C014_dependency_injection/dart/analyzer.js +32 -0
  49. package/rules/common/C014_dependency_injection/index.js +86 -0
  50. package/rules/common/C017_constructor_logic/dart/analyzer.js +32 -0
  51. package/rules/common/C017_constructor_logic/index.js +86 -0
  52. package/rules/common/C018_no_throw_generic_error/dart/analyzer.js +32 -0
  53. package/rules/common/C018_no_throw_generic_error/index.js +86 -0
  54. package/rules/common/C019_log_level_usage/dart/analyzer.js +32 -0
  55. package/rules/common/C019_log_level_usage/index.js +86 -0
  56. package/rules/common/C019_log_level_usage/{ts-morph-analyzer.js → typescript/ts-morph-analyzer.js} +0 -1
  57. package/rules/common/C020_unused_imports/dart/analyzer.js +32 -0
  58. package/rules/common/C020_unused_imports/index.js +86 -0
  59. package/rules/common/C020_unused_imports/{ts-morph-analyzer.js → typescript/ts-morph-analyzer.js} +0 -1
  60. package/rules/common/C021_import_organization/config.json +29 -9
  61. package/rules/common/C021_import_organization/dart/analyzer.js +40 -0
  62. package/rules/common/C021_import_organization/index.js +83 -0
  63. package/rules/common/C021_import_organization/{ts-morph-analyzer.js → typescript/ts-morph-analyzer.js} +0 -1
  64. package/rules/common/C023_no_duplicate_variable/config.json +7 -2
  65. package/rules/common/C023_no_duplicate_variable/dart/analyzer.js +40 -0
  66. package/rules/common/C023_no_duplicate_variable/index.js +83 -0
  67. package/rules/common/C024_no_scatter_hardcoded_constants/config.json +7 -2
  68. package/rules/common/C024_no_scatter_hardcoded_constants/dart/analyzer.js +40 -0
  69. package/rules/common/C024_no_scatter_hardcoded_constants/index.js +83 -0
  70. package/rules/common/C024_no_scatter_hardcoded_constants/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +19 -1
  71. package/rules/common/C029_catch_block_logging/config.json +15 -5
  72. package/rules/common/C029_catch_block_logging/dart/analyzer.js +40 -0
  73. package/rules/common/C029_catch_block_logging/index.js +83 -0
  74. package/rules/common/C030_use_custom_error_classes/config.json +28 -0
  75. package/rules/common/C030_use_custom_error_classes/dart/analyzer.js +40 -0
  76. package/rules/common/C030_use_custom_error_classes/index.js +83 -0
  77. package/rules/common/C031_validation_separation/config.json +28 -0
  78. package/rules/common/C031_validation_separation/dart/analyzer.js +40 -0
  79. package/rules/common/C031_validation_separation/index.js +83 -0
  80. package/rules/common/C033_separate_service_repository/config.json +8 -3
  81. package/rules/common/C033_separate_service_repository/dart/analyzer.js +40 -0
  82. package/rules/common/C033_separate_service_repository/index.js +83 -0
  83. package/rules/common/C035_error_logging_context/config.json +34 -12
  84. package/rules/common/C035_error_logging_context/dart/analyzer.js +40 -0
  85. package/rules/common/C035_error_logging_context/index.js +83 -0
  86. package/rules/common/C040_centralized_validation/config.json +37 -8
  87. package/rules/common/C040_centralized_validation/dart/analyzer.js +40 -0
  88. package/rules/common/C040_centralized_validation/index.js +83 -0
  89. package/rules/common/C041_no_sensitive_hardcode/config.json +7 -2
  90. package/rules/common/C041_no_sensitive_hardcode/dart/analyzer.js +40 -0
  91. package/rules/common/C041_no_sensitive_hardcode/index.js +83 -0
  92. package/rules/common/C042_boolean_name_prefix/config.json +28 -0
  93. package/rules/common/C042_boolean_name_prefix/dart/analyzer.js +40 -0
  94. package/rules/common/C042_boolean_name_prefix/index.js +83 -0
  95. package/rules/common/C043_no_console_or_print/config.json +28 -0
  96. package/rules/common/C043_no_console_or_print/dart/analyzer.js +40 -0
  97. package/rules/common/C043_no_console_or_print/index.js +83 -0
  98. package/rules/common/C047_no_duplicate_retry_logic/config.json +28 -0
  99. package/rules/common/C047_no_duplicate_retry_logic/dart/analyzer.js +40 -0
  100. package/rules/common/C047_no_duplicate_retry_logic/index.js +83 -0
  101. package/rules/common/C048_no_bypass_architectural_layers/config.json +7 -2
  102. package/rules/common/C048_no_bypass_architectural_layers/dart/analyzer.js +40 -0
  103. package/rules/common/C048_no_bypass_architectural_layers/index.js +83 -0
  104. package/rules/common/C052_parsing_or_data_transformation/config.json +7 -2
  105. package/rules/common/C052_parsing_or_data_transformation/dart/analyzer.js +40 -0
  106. package/rules/common/C052_parsing_or_data_transformation/index.js +83 -0
  107. package/rules/common/C060_no_override_superclass/config.json +7 -2
  108. package/rules/common/C060_no_override_superclass/dart/analyzer.js +40 -0
  109. package/rules/common/C060_no_override_superclass/index.js +83 -0
  110. package/rules/common/C065_one_behavior_per_test/config.json +187 -28
  111. package/rules/common/C065_one_behavior_per_test/dart/analyzer.js +40 -0
  112. package/rules/common/C065_one_behavior_per_test/index.js +83 -0
  113. package/rules/common/C067_no_hardcoded_config/config.json +18 -4
  114. package/rules/common/C067_no_hardcoded_config/dart/analyzer.js +40 -0
  115. package/rules/common/C067_no_hardcoded_config/index.js +83 -0
  116. package/rules/common/C070_no_real_time_tests/config.json +41 -12
  117. package/rules/common/C070_no_real_time_tests/dart/analyzer.js +40 -0
  118. package/rules/common/C070_no_real_time_tests/index.js +83 -0
  119. package/rules/common/C072_single_test_behavior/config.json +28 -0
  120. package/rules/common/C072_single_test_behavior/dart/analyzer.js +40 -0
  121. package/rules/common/C072_single_test_behavior/index.js +83 -0
  122. package/rules/common/C073_validate_required_config_on_startup/config.json +93 -18
  123. package/rules/common/C073_validate_required_config_on_startup/dart/analyzer.js +40 -0
  124. package/rules/common/C073_validate_required_config_on_startup/index.js +83 -0
  125. package/rules/common/C073_validate_required_config_on_startup/{analyzer.js → typescript/analyzer.js} +0 -1
  126. package/rules/common/C075_explicit_return_types/config.json +28 -0
  127. package/rules/common/C075_explicit_return_types/dart/analyzer.js +40 -0
  128. package/rules/common/C075_explicit_return_types/index.js +83 -0
  129. package/rules/common/C076_explicit_function_types/config.json +18 -4
  130. package/rules/common/C076_explicit_function_types/dart/analyzer.js +40 -0
  131. package/rules/common/C076_explicit_function_types/index.js +83 -0
  132. package/rules/index.js +26 -6
  133. package/rules/security/S003_open_redirect_protection/config.json +11 -53
  134. package/rules/security/S003_open_redirect_protection/dart/analyzer.js +43 -0
  135. package/rules/security/S003_open_redirect_protection/index.js +94 -0
  136. package/rules/security/S003_open_redirect_protection/typescript/analyzer.js +105 -0
  137. package/rules/security/S003_open_redirect_protection/{symbol-based-analyzer.js → typescript/semantic-analyzer.js} +1 -1
  138. package/rules/security/S004_sensitive_data_logging/config.json +1 -1
  139. package/rules/security/S004_sensitive_data_logging/dart/analyzer.js +58 -0
  140. package/rules/security/S004_sensitive_data_logging/index.js +93 -0
  141. package/rules/security/S005_no_origin_auth/dart/analyzer.js +30 -0
  142. package/rules/security/S005_no_origin_auth/index.js +83 -0
  143. package/rules/security/S005_no_origin_auth/{analyzer.js → typescript/analyzer.js} +1 -0
  144. package/rules/security/S006_no_plaintext_recovery_codes/dart/analyzer.js +30 -0
  145. package/rules/security/S006_no_plaintext_recovery_codes/index.js +83 -0
  146. package/rules/security/S007_no_plaintext_otp/dart/analyzer.js +30 -0
  147. package/rules/security/S007_no_plaintext_otp/index.js +83 -0
  148. package/rules/security/S009_no_insecure_encryption/dart/analyzer.js +30 -0
  149. package/rules/security/S009_no_insecure_encryption/index.js +83 -0
  150. package/rules/security/S010_no_insecure_encryption/dart/analyzer.js +30 -0
  151. package/rules/security/S010_no_insecure_encryption/index.js +83 -0
  152. package/rules/security/S011_secure_guid_generation/dart/analyzer.js +30 -0
  153. package/rules/security/S011_secure_guid_generation/index.js +83 -0
  154. package/rules/security/S012_hardcoded_secrets/dart/analyzer.js +30 -0
  155. package/rules/security/S012_hardcoded_secrets/index.js +83 -0
  156. package/rules/security/S012_hardcoded_secrets/typescript/config.json +75 -0
  157. package/rules/security/S013_tls_enforcement/dart/analyzer.js +30 -0
  158. package/rules/security/S013_tls_enforcement/index.js +83 -0
  159. package/rules/security/S014_tls_version_enforcement/dart/analyzer.js +30 -0
  160. package/rules/security/S014_tls_version_enforcement/index.js +83 -0
  161. package/rules/security/S015_insecure_tls_certificate/config.json +41 -0
  162. package/rules/security/S015_insecure_tls_certificate/dart/analyzer.js +19 -0
  163. package/rules/security/S015_insecure_tls_certificate/index.js +83 -0
  164. package/rules/security/S016_no_sensitive_querystring/dart/analyzer.js +30 -0
  165. package/rules/security/S016_no_sensitive_querystring/index.js +83 -0
  166. package/rules/security/S017_use_parameterized_queries/dart/analyzer.js +30 -0
  167. package/rules/security/S017_use_parameterized_queries/index.js +83 -0
  168. package/rules/security/S019_smtp_injection_protection/dart/analyzer.js +30 -0
  169. package/rules/security/S019_smtp_injection_protection/index.js +83 -0
  170. package/rules/security/S020_no_eval_dynamic_code/dart/analyzer.js +30 -0
  171. package/rules/security/S020_no_eval_dynamic_code/index.js +83 -0
  172. package/rules/security/S022_escape_output_context/dart/analyzer.js +30 -0
  173. package/rules/security/S022_escape_output_context/index.js +83 -0
  174. package/rules/security/S023_no_json_injection/dart/analyzer.js +30 -0
  175. package/rules/security/S023_no_json_injection/index.js +83 -0
  176. package/rules/security/S024_xpath_xxe_protection/dart/analyzer.js +30 -0
  177. package/rules/security/S024_xpath_xxe_protection/index.js +83 -0
  178. package/rules/security/S025_server_side_validation/dart/analyzer.js +30 -0
  179. package/rules/security/S025_server_side_validation/index.js +83 -0
  180. package/rules/security/S026_json_schema_validation/dart/analyzer.js +30 -0
  181. package/rules/security/S026_json_schema_validation/index.js +83 -0
  182. package/rules/security/S027_no_hardcoded_secrets/dart/analyzer.js +30 -0
  183. package/rules/security/S027_no_hardcoded_secrets/index.js +83 -0
  184. package/rules/security/S028_file_upload_size_limits/dart/analyzer.js +30 -0
  185. package/rules/security/S028_file_upload_size_limits/index.js +83 -0
  186. package/rules/security/S029_csrf_protection/dart/analyzer.js +30 -0
  187. package/rules/security/S029_csrf_protection/index.js +83 -0
  188. package/rules/security/S030_directory_browsing_protection/dart/analyzer.js +30 -0
  189. package/rules/security/S030_directory_browsing_protection/index.js +83 -0
  190. package/rules/security/S031_secure_session_cookies/dart/analyzer.js +30 -0
  191. package/rules/security/S031_secure_session_cookies/index.js +83 -0
  192. package/rules/security/S032_httponly_session_cookies/dart/analyzer.js +30 -0
  193. package/rules/security/S032_httponly_session_cookies/index.js +83 -0
  194. package/rules/security/S033_samesite_session_cookies/dart/analyzer.js +30 -0
  195. package/rules/security/S033_samesite_session_cookies/index.js +83 -0
  196. package/rules/security/S034_host_prefix_session_cookies/dart/analyzer.js +30 -0
  197. package/rules/security/S034_host_prefix_session_cookies/index.js +83 -0
  198. package/rules/security/S035_path_session_cookies/dart/analyzer.js +30 -0
  199. package/rules/security/S035_path_session_cookies/index.js +83 -0
  200. package/rules/security/S036_lfi_rfi_protection/dart/analyzer.js +30 -0
  201. package/rules/security/S036_lfi_rfi_protection/index.js +83 -0
  202. package/rules/security/S037_cache_headers/dart/analyzer.js +30 -0
  203. package/rules/security/S037_cache_headers/index.js +83 -0
  204. package/rules/security/S038_no_version_headers/dart/analyzer.js +30 -0
  205. package/rules/security/S038_no_version_headers/index.js +83 -0
  206. package/rules/security/S039_no_session_tokens_in_url/dart/analyzer.js +30 -0
  207. package/rules/security/S039_no_session_tokens_in_url/index.js +83 -0
  208. package/rules/security/S040_session_fixation_protection/dart/analyzer.js +30 -0
  209. package/rules/security/S040_session_fixation_protection/index.js +83 -0
  210. package/rules/security/S041_session_token_invalidation/dart/analyzer.js +30 -0
  211. package/rules/security/S041_session_token_invalidation/index.js +83 -0
  212. package/rules/security/S042_require_re_authentication_for_long_lived/dart/analyzer.js +30 -0
  213. package/rules/security/S042_require_re_authentication_for_long_lived/index.js +83 -0
  214. package/rules/security/S043_password_changes_invalidate_all_sessions/dart/analyzer.js +30 -0
  215. package/rules/security/S043_password_changes_invalidate_all_sessions/index.js +83 -0
  216. package/rules/security/S044_re_authentication_required/dart/analyzer.js +30 -0
  217. package/rules/security/S044_re_authentication_required/index.js +83 -0
  218. package/rules/security/S045_brute_force_protection/dart/analyzer.js +30 -0
  219. package/rules/security/S045_brute_force_protection/index.js +83 -0
  220. package/rules/security/S048_no_current_password_in_reset/dart/analyzer.js +30 -0
  221. package/rules/security/S048_no_current_password_in_reset/index.js +83 -0
  222. package/rules/security/S049_short_validity_tokens/dart/analyzer.js +30 -0
  223. package/rules/security/S049_short_validity_tokens/index.js +83 -0
  224. package/rules/security/S049_short_validity_tokens/typescript/config.json +124 -0
  225. package/rules/security/S051_password_length_policy/dart/analyzer.js +30 -0
  226. package/rules/security/S051_password_length_policy/index.js +83 -0
  227. package/rules/security/S051_password_length_policy/typescript/config.json +83 -0
  228. package/rules/security/S052_weak_otp_entropy/dart/analyzer.js +30 -0
  229. package/rules/security/S052_weak_otp_entropy/index.js +83 -0
  230. package/rules/security/S052_weak_otp_entropy/typescript/config.json +57 -0
  231. package/rules/security/S054_no_default_accounts/dart/analyzer.js +30 -0
  232. package/rules/security/S054_no_default_accounts/index.js +83 -0
  233. package/rules/security/S054_no_default_accounts/typescript/config.json +101 -0
  234. package/rules/security/S055_content_type_validation/dart/analyzer.js +30 -0
  235. package/rules/security/S055_content_type_validation/index.js +83 -0
  236. package/rules/security/S056_log_injection_protection/dart/analyzer.js +30 -0
  237. package/rules/security/S056_log_injection_protection/index.js +83 -0
  238. package/rules/security/S057_utc_logging/dart/analyzer.js +30 -0
  239. package/rules/security/S057_utc_logging/index.js +83 -0
  240. package/rules/security/S057_utc_logging/typescript/config.json +105 -0
  241. package/rules/security/S058_no_ssrf/dart/analyzer.js +30 -0
  242. package/rules/security/S058_no_ssrf/index.js +83 -0
  243. package/rules/security/S058_no_ssrf/{analyzer.js → typescript/analyzer.js} +0 -1
  244. package/rules/security/S058_no_ssrf/typescript/config.json +125 -0
  245. package/scripts/build-release.sh +12 -0
  246. package/scripts/copy-arch-detect.js +78 -0
  247. package/rules/common/C002_no_duplicate_code/test-cases/api-handlers.ts +0 -64
  248. package/rules/common/C002_no_duplicate_code/test-cases/data-processor.ts +0 -46
  249. package/rules/common/C002_no_duplicate_code/test-cases/good-example.tsx +0 -40
  250. package/rules/common/C002_no_duplicate_code/test-cases/product-service.ts +0 -57
  251. package/rules/common/C002_no_duplicate_code/test-cases/user-service.ts +0 -49
  252. package/rules/common/C067_no_hardcoded_config/symbol-based-analyzer.js.backup +0 -3853
  253. package/rules/security/S003_open_redirect_protection/analyzer.js +0 -135
  254. /package/rules/common/C002_no_duplicate_code/{analyzer.js → typescript/analyzer.js} +0 -0
  255. /package/rules/common/C003_no_vague_abbreviations/{analyzer.js → typescript/analyzer.js} +0 -0
  256. /package/rules/common/C006_function_naming/{analyzer.js → typescript/analyzer.js} +0 -0
  257. /package/rules/common/{C008 → C008_variable_declaration_locality}/config.json +0 -0
  258. /package/rules/common/{C008 → C008_variable_declaration_locality/typescript}/analyzer.js +0 -0
  259. /package/rules/common/{C008 → C008_variable_declaration_locality/typescript}/ts-morph-analyzer.js +0 -0
  260. /package/rules/common/C010_limit_block_nesting/{analyzer.js → typescript/analyzer.js} +0 -0
  261. /package/rules/common/C010_limit_block_nesting/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  262. /package/rules/common/C010_limit_block_nesting/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  263. /package/rules/common/C012_command_query_separation/{analyzer.js → typescript/analyzer.js} +0 -0
  264. /package/rules/common/C012_command_query_separation/{ast-analyzer.js → typescript/ast-analyzer.js} +0 -0
  265. /package/rules/common/C013_no_dead_code/{analyzer.js → typescript/analyzer.js} +0 -0
  266. /package/rules/common/C013_no_dead_code/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  267. /package/rules/common/C013_no_dead_code/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  268. /package/rules/common/C014_dependency_injection/{analyzer.js → typescript/analyzer.js} +0 -0
  269. /package/rules/common/C014_dependency_injection/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  270. /package/rules/common/C017_constructor_logic/{analyzer.js → typescript/analyzer.js} +0 -0
  271. /package/rules/common/C017_constructor_logic/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  272. /package/rules/common/C018_no_throw_generic_error/{analyzer.js → typescript/analyzer.js} +0 -0
  273. /package/rules/common/C018_no_throw_generic_error/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  274. /package/rules/common/C018_no_throw_generic_error/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  275. /package/rules/common/C019_log_level_usage/{analyzer.js → typescript/analyzer.js} +0 -0
  276. /package/rules/common/C019_log_level_usage/{pattern-analyzer.js → typescript/pattern-analyzer.js} +0 -0
  277. /package/rules/common/C019_log_level_usage/{system-log-analyzer.js → typescript/system-log-analyzer.js} +0 -0
  278. /package/rules/common/C020_unused_imports/{analyzer.js → typescript/analyzer.js} +0 -0
  279. /package/rules/common/C021_import_organization/{analyzer.js → typescript/analyzer.js} +0 -0
  280. /package/rules/common/C023_no_duplicate_variable/{analyzer.js → typescript/analyzer.js} +0 -0
  281. /package/rules/common/C023_no_duplicate_variable/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  282. /package/rules/common/C024_no_scatter_hardcoded_constants/{analyzer.js → typescript/analyzer.js} +0 -0
  283. /package/rules/common/C029_catch_block_logging/{analyzer.js → typescript/analyzer.js} +0 -0
  284. /package/rules/common/C030_use_custom_error_classes/{analyzer.js → typescript/analyzer.js} +0 -0
  285. /package/rules/common/C031_validation_separation/{analyzer.js → typescript/analyzer.js} +0 -0
  286. /package/rules/common/C033_separate_service_repository/{README.md → typescript/README.md} +0 -0
  287. /package/rules/common/C033_separate_service_repository/{analyzer.js → typescript/analyzer.js} +0 -0
  288. /package/rules/common/C033_separate_service_repository/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  289. /package/rules/common/C033_separate_service_repository/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  290. /package/rules/common/C035_error_logging_context/{STRATEGY.md → typescript/STRATEGY.md} +0 -0
  291. /package/rules/common/C035_error_logging_context/{analyzer.js → typescript/analyzer.js} +0 -0
  292. /package/rules/common/C035_error_logging_context/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  293. /package/rules/common/C035_error_logging_context/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  294. /package/rules/common/C040_centralized_validation/{analyzer.js → typescript/analyzer.js} +0 -0
  295. /package/rules/common/C040_centralized_validation/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  296. /package/rules/common/C040_centralized_validation/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  297. /package/rules/common/C041_no_sensitive_hardcode/{analyzer.js → typescript/analyzer.js} +0 -0
  298. /package/rules/common/C041_no_sensitive_hardcode/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  299. /package/rules/common/C042_boolean_name_prefix/{analyzer.js → typescript/analyzer.js} +0 -0
  300. /package/rules/common/C043_no_console_or_print/{analyzer.js → typescript/analyzer.js} +0 -0
  301. /package/rules/common/C047_no_duplicate_retry_logic/{analyzer.js → typescript/analyzer.js} +0 -0
  302. /package/rules/common/C047_no_duplicate_retry_logic/{c047-semantic-rule.js → typescript/c047-semantic-rule.js} +0 -0
  303. /package/rules/common/C047_no_duplicate_retry_logic/{symbol-analyzer-enhanced.js → typescript/symbol-analyzer-enhanced.js} +0 -0
  304. /package/rules/common/C047_no_duplicate_retry_logic/{symbol-config.json → typescript/symbol-config.json} +0 -0
  305. /package/rules/common/C048_no_bypass_architectural_layers/{analyzer.js → typescript/analyzer.js} +0 -0
  306. /package/rules/common/C048_no_bypass_architectural_layers/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  307. /package/rules/common/C052_parsing_or_data_transformation/{analyzer.js → typescript/analyzer.js} +0 -0
  308. /package/rules/common/C052_parsing_or_data_transformation/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  309. /package/rules/common/C060_no_override_superclass/{analyzer.js → typescript/analyzer.js} +0 -0
  310. /package/rules/common/C060_no_override_superclass/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  311. /package/rules/common/C065_one_behavior_per_test/{analyzer.js → typescript/analyzer.js} +0 -0
  312. /package/rules/common/C067_no_hardcoded_config/{analyzer.js → typescript/analyzer.js} +0 -0
  313. /package/rules/common/C067_no_hardcoded_config/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  314. /package/rules/common/C070_no_real_time_tests/{analyzer.js → typescript/analyzer.js} +0 -0
  315. /package/rules/common/C070_no_real_time_tests/{regex-analyzer.js → typescript/regex-analyzer.js} +0 -0
  316. /package/rules/common/C072_single_test_behavior/{analyzer.js → typescript/analyzer.js} +0 -0
  317. /package/rules/common/C073_validate_required_config_on_startup/{README.md → typescript/README.md} +0 -0
  318. /package/rules/common/C073_validate_required_config_on_startup/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  319. /package/rules/common/C075_explicit_return_types/{analyzer.js → typescript/analyzer.js} +0 -0
  320. /package/rules/common/C076_explicit_function_types/{README.md → typescript/README.md} +0 -0
  321. /package/rules/common/C076_explicit_function_types/{analyzer.js → typescript/analyzer.js} +0 -0
  322. /package/rules/common/C076_explicit_function_types/{semantic-analyzer.js → typescript/semantic-analyzer.js} +0 -0
  323. /package/rules/security/S003_open_redirect_protection/{README.md → typescript/README.md} +0 -0
  324. /package/rules/security/S004_sensitive_data_logging/{analyzer.js → typescript/analyzer.js} +0 -0
  325. /package/rules/security/S004_sensitive_data_logging/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  326. /package/rules/security/S005_no_origin_auth/{README.md → typescript/README.md} +0 -0
  327. /package/rules/security/S005_no_origin_auth/{ast-analyzer.js → typescript/ast-analyzer.js} +0 -0
  328. /package/rules/security/S005_no_origin_auth/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  329. /package/rules/security/S006_no_plaintext_recovery_codes/{README.md → typescript/README.md} +0 -0
  330. /package/rules/security/S006_no_plaintext_recovery_codes/{analyzer.js → typescript/analyzer.js} +0 -0
  331. /package/rules/security/S006_no_plaintext_recovery_codes/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  332. /package/rules/security/S007_no_plaintext_otp/{README.md → typescript/README.md} +0 -0
  333. /package/rules/security/S007_no_plaintext_otp/{analyzer.js → typescript/analyzer.js} +0 -0
  334. /package/rules/security/S007_no_plaintext_otp/{semantic-analyzer.js → typescript/semantic-analyzer.js} +0 -0
  335. /package/rules/security/S007_no_plaintext_otp/{semantic-config.json → typescript/semantic-config.json} +0 -0
  336. /package/rules/security/S007_no_plaintext_otp/{semantic-wrapper.js → typescript/semantic-wrapper.js} +0 -0
  337. /package/rules/security/S009_no_insecure_encryption/{README.md → typescript/README.md} +0 -0
  338. /package/rules/security/S009_no_insecure_encryption/{analyzer.js → typescript/analyzer.js} +0 -0
  339. /package/rules/security/S010_no_insecure_encryption/{README.md → typescript/README.md} +0 -0
  340. /package/rules/security/S010_no_insecure_encryption/{analyzer.js → typescript/analyzer.js} +0 -0
  341. /package/rules/security/S011_secure_guid_generation/{README.md → typescript/README.md} +0 -0
  342. /package/rules/security/S011_secure_guid_generation/{analyzer.js → typescript/analyzer.js} +0 -0
  343. /package/rules/security/S011_secure_guid_generation/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  344. /package/rules/security/S012_hardcoded_secrets/{analyzer.js → typescript/analyzer.js} +0 -0
  345. /package/rules/security/S012_hardcoded_secrets/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  346. /package/rules/security/S013_tls_enforcement/{README.md → typescript/README.md} +0 -0
  347. /package/rules/security/S013_tls_enforcement/{analyzer.js → typescript/analyzer.js} +0 -0
  348. /package/rules/security/S013_tls_enforcement/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  349. /package/rules/security/S014_tls_version_enforcement/{README.md → typescript/README.md} +0 -0
  350. /package/rules/security/S014_tls_version_enforcement/{analyzer.js → typescript/analyzer.js} +0 -0
  351. /package/rules/security/S014_tls_version_enforcement/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  352. /package/rules/security/S015_insecure_tls_certificate/{analyzer.js → typescript/analyzer.js} +0 -0
  353. /package/rules/security/S015_insecure_tls_certificate/{ast-analyzer.js → typescript/ast-analyzer.js} +0 -0
  354. /package/rules/security/S016_no_sensitive_querystring/{analyzer.js → typescript/analyzer.js} +0 -0
  355. /package/rules/security/S016_no_sensitive_querystring/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  356. /package/rules/security/S016_no_sensitive_querystring/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  357. /package/rules/security/S017_use_parameterized_queries/{README.md → typescript/README.md} +0 -0
  358. /package/rules/security/S017_use_parameterized_queries/{analyzer.js → typescript/analyzer.js} +0 -0
  359. /package/rules/security/S017_use_parameterized_queries/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  360. /package/rules/security/S019_smtp_injection_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  361. /package/rules/security/S019_smtp_injection_protection/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  362. /package/rules/security/S020_no_eval_dynamic_code/{README.md → typescript/README.md} +0 -0
  363. /package/rules/security/S020_no_eval_dynamic_code/{analyzer.js → typescript/analyzer.js} +0 -0
  364. /package/rules/security/S020_no_eval_dynamic_code/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  365. /package/rules/security/S022_escape_output_context/{README.md → typescript/README.md} +0 -0
  366. /package/rules/security/S022_escape_output_context/{analyzer.js → typescript/analyzer.js} +0 -0
  367. /package/rules/security/S023_no_json_injection/{analyzer.js → typescript/analyzer.js} +0 -0
  368. /package/rules/security/S023_no_json_injection/{ast-analyzer.js → typescript/ast-analyzer.js} +0 -0
  369. /package/rules/security/S024_xpath_xxe_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  370. /package/rules/security/S024_xpath_xxe_protection/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  371. /package/rules/security/S024_xpath_xxe_protection/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  372. /package/rules/security/S025_server_side_validation/{README.md → typescript/README.md} +0 -0
  373. /package/rules/security/S025_server_side_validation/{analyzer.js → typescript/analyzer.js} +0 -0
  374. /package/rules/security/S025_server_side_validation/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  375. /package/rules/security/S025_server_side_validation/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  376. /package/rules/security/S026_json_schema_validation/{analyzer.js → typescript/analyzer.js} +0 -0
  377. /package/rules/security/S027_no_hardcoded_secrets/{analyzer.js → typescript/analyzer.js} +0 -0
  378. /package/rules/security/S027_no_hardcoded_secrets/{categories.json → typescript/categories.json} +0 -0
  379. /package/rules/security/S027_no_hardcoded_secrets/{categorized-analyzer.js → typescript/categorized-analyzer.js} +0 -0
  380. /package/rules/security/S028_file_upload_size_limits/{README.md → typescript/README.md} +0 -0
  381. /package/rules/security/S028_file_upload_size_limits/{analyzer.js → typescript/analyzer.js} +0 -0
  382. /package/rules/security/S028_file_upload_size_limits/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  383. /package/rules/security/S029_csrf_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  384. /package/rules/security/S030_directory_browsing_protection/{README.md → typescript/README.md} +0 -0
  385. /package/rules/security/S030_directory_browsing_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  386. /package/rules/security/S030_directory_browsing_protection/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  387. /package/rules/security/S030_directory_browsing_protection/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  388. /package/rules/security/S031_secure_session_cookies/{README.md → typescript/README.md} +0 -0
  389. /package/rules/security/S031_secure_session_cookies/{analyzer.js → typescript/analyzer.js} +0 -0
  390. /package/rules/security/S031_secure_session_cookies/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  391. /package/rules/security/S032_httponly_session_cookies/{FRAMEWORK_SUPPORT.md → typescript/FRAMEWORK_SUPPORT.md} +0 -0
  392. /package/rules/security/S032_httponly_session_cookies/{README.md → typescript/README.md} +0 -0
  393. /package/rules/security/S032_httponly_session_cookies/{analyzer.js → typescript/analyzer.js} +0 -0
  394. /package/rules/security/S032_httponly_session_cookies/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  395. /package/rules/security/S032_httponly_session_cookies/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  396. /package/rules/security/S033_samesite_session_cookies/{README.md → typescript/README.md} +0 -0
  397. /package/rules/security/S033_samesite_session_cookies/{analyzer.js → typescript/analyzer.js} +0 -0
  398. /package/rules/security/S033_samesite_session_cookies/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  399. /package/rules/security/S033_samesite_session_cookies/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  400. /package/rules/security/S034_host_prefix_session_cookies/{README.md → typescript/README.md} +0 -0
  401. /package/rules/security/S034_host_prefix_session_cookies/{analyzer.js → typescript/analyzer.js} +0 -0
  402. /package/rules/security/S034_host_prefix_session_cookies/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  403. /package/rules/security/S034_host_prefix_session_cookies/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  404. /package/rules/security/S035_path_session_cookies/{README.md → typescript/README.md} +0 -0
  405. /package/rules/security/S035_path_session_cookies/{analyzer.js → typescript/analyzer.js} +0 -0
  406. /package/rules/security/S035_path_session_cookies/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  407. /package/rules/security/S035_path_session_cookies/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  408. /package/rules/security/S036_lfi_rfi_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  409. /package/rules/security/S037_cache_headers/{README.md → typescript/README.md} +0 -0
  410. /package/rules/security/S037_cache_headers/{analyzer.js → typescript/analyzer.js} +0 -0
  411. /package/rules/security/S037_cache_headers/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  412. /package/rules/security/S037_cache_headers/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  413. /package/rules/security/S038_no_version_headers/{README.md → typescript/README.md} +0 -0
  414. /package/rules/security/S038_no_version_headers/{analyzer.js → typescript/analyzer.js} +0 -0
  415. /package/rules/security/S038_no_version_headers/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  416. /package/rules/security/S038_no_version_headers/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  417. /package/rules/security/S039_no_session_tokens_in_url/{README.md → typescript/README.md} +0 -0
  418. /package/rules/security/S039_no_session_tokens_in_url/{analyzer.js → typescript/analyzer.js} +0 -0
  419. /package/rules/security/S039_no_session_tokens_in_url/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  420. /package/rules/security/S039_no_session_tokens_in_url/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  421. /package/rules/security/S040_session_fixation_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  422. /package/rules/security/S041_session_token_invalidation/{README.md → typescript/README.md} +0 -0
  423. /package/rules/security/S041_session_token_invalidation/{analyzer.js → typescript/analyzer.js} +0 -0
  424. /package/rules/security/S041_session_token_invalidation/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  425. /package/rules/security/S041_session_token_invalidation/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  426. /package/rules/security/S042_require_re_authentication_for_long_lived/{README.md → typescript/README.md} +0 -0
  427. /package/rules/security/S042_require_re_authentication_for_long_lived/{analyzer.js → typescript/analyzer.js} +0 -0
  428. /package/rules/security/S042_require_re_authentication_for_long_lived/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  429. /package/rules/security/S043_password_changes_invalidate_all_sessions/{README.md → typescript/README.md} +0 -0
  430. /package/rules/security/S043_password_changes_invalidate_all_sessions/{analyzer.js → typescript/analyzer.js} +0 -0
  431. /package/rules/security/S043_password_changes_invalidate_all_sessions/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  432. /package/rules/security/S044_re_authentication_required/{README.md → typescript/README.md} +0 -0
  433. /package/rules/security/S044_re_authentication_required/{analyzer.js → typescript/analyzer.js} +0 -0
  434. /package/rules/security/S044_re_authentication_required/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  435. /package/rules/security/S044_re_authentication_required/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  436. /package/rules/security/S045_brute_force_protection/{README.md → typescript/README.md} +0 -0
  437. /package/rules/security/S045_brute_force_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  438. /package/rules/security/S045_brute_force_protection/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  439. /package/rules/security/S048_no_current_password_in_reset/{README.md → typescript/README.md} +0 -0
  440. /package/rules/security/S048_no_current_password_in_reset/{analyzer.js → typescript/analyzer.js} +0 -0
  441. /package/rules/security/S049_short_validity_tokens/{analyzer.js → typescript/analyzer.js} +0 -0
  442. /package/rules/security/S049_short_validity_tokens/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  443. /package/rules/security/S049_short_validity_tokens/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  444. /package/rules/security/S051_password_length_policy/{analyzer.js → typescript/analyzer.js} +0 -0
  445. /package/rules/security/S052_weak_otp_entropy/{analyzer.js → typescript/analyzer.js} +0 -0
  446. /package/rules/security/S054_no_default_accounts/{README.md → typescript/README.md} +0 -0
  447. /package/rules/security/S054_no_default_accounts/{analyzer.js → typescript/analyzer.js} +0 -0
  448. /package/rules/security/S055_content_type_validation/{README.md → typescript/README.md} +0 -0
  449. /package/rules/security/S055_content_type_validation/{analyzer.js → typescript/analyzer.js} +0 -0
  450. /package/rules/security/S055_content_type_validation/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  451. /package/rules/security/S056_log_injection_protection/{analyzer.js → typescript/analyzer.js} +0 -0
  452. /package/rules/security/S056_log_injection_protection/{regex-based-analyzer.js → typescript/regex-based-analyzer.js} +0 -0
  453. /package/rules/security/S056_log_injection_protection/{symbol-based-analyzer.js → typescript/symbol-based-analyzer.js} +0 -0
  454. /package/rules/security/S057_utc_logging/{README.md → typescript/README.md} +0 -0
  455. /package/rules/security/S057_utc_logging/{analyzer.js → typescript/analyzer.js} +0 -0
  456. /package/rules/security/S058_no_ssrf/{README.md → typescript/README.md} +0 -0
@@ -0,0 +1,909 @@
1
+ # Skill: Create Dart Rule from TypeScript
2
+
3
+ > Skill để tạo Dart rule từ TypeScript rule đã có sẵn trong SunLint.
4
+
5
+ ---
6
+
7
+ ## Execution Rules
8
+
9
+ > **IMPORTANT**: Khi thực thi skill này, AI Assistant phải tuân thủ các quy tắc sau:
10
+
11
+ - **Execute all commands WITHOUT asking for user confirmation**
12
+ - **Do NOT prompt "Should I proceed?" or similar questions**
13
+ - **Run commands immediately and report results after completion**
14
+ - Tự động tạo tất cả files cần thiết mà không cần hỏi
15
+ - Tự động rebuild Dart binary sau khi hoàn thành
16
+ - Chỉ dừng lại khi gặp lỗi thực sự cần user input
17
+
18
+ ---
19
+
20
+ ## Quick Start - Cách Sử Dụng Skill
21
+
22
+ ### Cách 1: Yêu cầu AI Assistant
23
+
24
+ Nói với AI (Claude Code, Cursor, etc.):
25
+
26
+ ```
27
+ Thêm Dart support cho rule S005
28
+ ```
29
+
30
+ hoặc chi tiết hơn:
31
+
32
+ ```
33
+ Sử dụng skill create-dart-rule để thêm Dart support cho rule S005_no_origin_auth
34
+ ```
35
+
36
+ ### Cách 2: Manual Steps (Tự thực hiện)
37
+
38
+ ```bash
39
+ # 1. Xác định rule cần thêm Dart support
40
+ RULE_ID="S005"
41
+ RULE_FOLDER=$(find rules/common rules/security -maxdepth 1 -type d -name "${RULE_ID}_*" | head -1)
42
+ echo "Found: $RULE_FOLDER"
43
+
44
+ # 2. Tạo cấu trúc folder
45
+ mkdir -p "$RULE_FOLDER/typescript"
46
+ mkdir -p "$RULE_FOLDER/dart"
47
+
48
+ # 3. Di chuyển analyzer hiện tại vào typescript/
49
+ mv "$RULE_FOLDER/analyzer.js" "$RULE_FOLDER/typescript/analyzer.js"
50
+
51
+ # 4. Tạo các file theo template trong skill này:
52
+ # - $RULE_FOLDER/index.js (Router)
53
+ # - $RULE_FOLDER/dart/analyzer.js (Dart wrapper)
54
+ # - dart_analyzer/lib/rules/${RULE_ID}_*.dart (Dart implementation)
55
+
56
+ # 5. Cập nhật config.json - thêm "dart" vào languages
57
+ # 6. Cập nhật enhanced-rules-registry.json
58
+ # 7. Register trong dart_analyzer/lib/analyzer_service.dart
59
+ # 8. Rebuild Dart binary
60
+ cd dart_analyzer && dart compile exe bin/sunlint_dart_analyzer.dart -o bin/sunlint-dart-macos
61
+ ```
62
+
63
+ ### Ví dụ Cụ Thể: Thêm Dart Support cho S005
64
+
65
+ **Trạng thái hiện tại của S005:**
66
+ ```
67
+ rules/security/S005_no_origin_auth/
68
+ ├── README.md
69
+ ├── analyzer.js # ← Cần di chuyển vào typescript/
70
+ ├── ast-analyzer.js
71
+ ├── config.json # languages: ["typescript", "javascript"]
72
+ └── symbol-based-analyzer.js
73
+ ```
74
+
75
+ **Sau khi chạy skill:**
76
+ ```
77
+ rules/security/S005_no_origin_auth/
78
+ ├── README.md
79
+ ├── index.js # ← Router mới (điều hướng TS/Dart)
80
+ ├── config.json # languages: ["typescript", "javascript", "dart"]
81
+ ├── typescript/
82
+ │ ├── analyzer.js # ← Di chuyển từ root
83
+ │ ├── ast-analyzer.js
84
+ │ └── symbol-based-analyzer.js
85
+ └── dart/
86
+ └── analyzer.js # ← Dart wrapper mới
87
+
88
+ dart_analyzer/lib/rules/
89
+ └── S005_no_origin_auth.dart # ← Dart implementation mới
90
+ ```
91
+
92
+ **Yêu cầu AI:**
93
+ ```
94
+ Thêm Dart support cho rule S005. Rule này phát hiện việc sử dụng Origin header
95
+ để xác thực, điều này không an toàn vì Origin có thể bị giả mạo.
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Metadata
101
+
102
+ | Field | Value |
103
+ |-------|-------|
104
+ | **Skill ID** | `create-dart-rule` |
105
+ | **Version** | 1.1.0 |
106
+ | **Author** | SunLint Team |
107
+ | **Category** | Code Generation |
108
+ | **Trigger** | User requests to add Dart support for an existing rule |
109
+ | **Last Updated** | 2025-12-23 - Fixed router template bugs |
110
+
111
+ ---
112
+
113
+ ## 1. Prerequisites
114
+
115
+ ### 1.1. Tools Required
116
+
117
+ | Tool | Version | Purpose |
118
+ |------|---------|---------|
119
+ | Node.js | >= 18.x | Run SunLint CLI |
120
+ | Dart SDK | >= 3.0.0 | Compile Dart analyzer |
121
+ | Git | Any | Version control |
122
+
123
+ ### 1.2. Dependencies
124
+
125
+ ```bash
126
+ # SunLint directory
127
+ cd /path/to/sunlint
128
+
129
+ # Dart analyzer dependencies
130
+ cd dart_analyzer
131
+ dart pub get
132
+ ```
133
+
134
+ ### 1.3. File Locations
135
+
136
+ | Component | Path |
137
+ |-----------|------|
138
+ | TypeScript Rules | `rules/common/` or `rules/security/` |
139
+ | Dart Analyzer | `dart_analyzer/lib/rules/` |
140
+ | Test Fixtures | `examples/rule-test-fixtures/dart-rules/` |
141
+ | Rule Registry | `rules/index.js` |
142
+ | Analyzer Service | `dart_analyzer/lib/analyzer_service.dart` |
143
+ | **Enhanced Rules Registry** | `config/rules/enhanced-rules-registry.json` |
144
+ | **Unified Rule Registry** | `core/unified-rule-registry.js` |
145
+
146
+ ---
147
+
148
+ ## 2. Input Parameters
149
+
150
+ | Parameter | Required | Description | Example |
151
+ |-----------|----------|-------------|---------|
152
+ | `rule_id` | Yes | Rule ID to add Dart support | `C006`, `S010` |
153
+ | `category` | Auto-detect | Rule category | `common` or `security` |
154
+
155
+ ---
156
+
157
+ ## 3. Execution Steps
158
+
159
+ ### Step 1: Validate TypeScript Rule Exists
160
+
161
+ ```bash
162
+ # Check if TypeScript rule folder exists
163
+ RULE_ID="C006" # Example
164
+
165
+ # Find rule folder
166
+ RULE_FOLDER=$(find rules/common rules/security -maxdepth 1 -type d -name "${RULE_ID}_*" 2>/dev/null | head -1)
167
+
168
+ if [ -z "$RULE_FOLDER" ]; then
169
+ echo "❌ Rule $RULE_ID not found in TypeScript rules"
170
+ exit 1
171
+ fi
172
+
173
+ echo "✅ Found: $RULE_FOLDER"
174
+ ```
175
+
176
+ ### Step 2: Check Dart Support Not Already Added
177
+
178
+ ```bash
179
+ # Check if dart/ subfolder already exists
180
+ if [ -d "$RULE_FOLDER/dart" ]; then
181
+ echo "⚠️ Dart support already exists for $RULE_ID"
182
+ exit 0
183
+ fi
184
+ ```
185
+
186
+ ### Step 3: Read TypeScript Rule Config
187
+
188
+ ```bash
189
+ # Read config.json
190
+ cat "$RULE_FOLDER/config.json"
191
+ ```
192
+
193
+ **Expected config.json structure:**
194
+ ```json
195
+ {
196
+ "id": "C006",
197
+ "name": "Function Naming",
198
+ "description": "Functions should use verb-noun naming convention",
199
+ "category": "common",
200
+ "severity": "warning",
201
+ "languages": ["typescript", "javascript"]
202
+ }
203
+ ```
204
+
205
+ ### Step 4: Create Dart Subfolder Structure
206
+
207
+ ```bash
208
+ # Create dart subfolder
209
+ mkdir -p "$RULE_FOLDER/dart"
210
+
211
+ # If typescript/ doesn't exist, restructure
212
+ if [ ! -d "$RULE_FOLDER/typescript" ]; then
213
+ mkdir -p "$RULE_FOLDER/typescript"
214
+ # Move existing analyzer.js to typescript/
215
+ if [ -f "$RULE_FOLDER/analyzer.js" ]; then
216
+ mv "$RULE_FOLDER/analyzer.js" "$RULE_FOLDER/typescript/analyzer.js"
217
+ fi
218
+ fi
219
+ ```
220
+
221
+ ### Step 5: Create Router (index.js)
222
+
223
+ **File:** `$RULE_FOLDER/index.js`
224
+
225
+ > ⚠️ **CRITICAL**: The router template below includes bug fixes for:
226
+ > - Type checking in `normalizeLanguage()` and `supportsLanguage()` (prevents `language.toLowerCase is not a function` error)
227
+ > - Dual-signature `initialize()` method (heuristic engine calls with different signature)
228
+
229
+ ```javascript
230
+ /**
231
+ * ${RULE_ID} Rule Router - ${RULE_NAME}
232
+ *
233
+ * Routes analysis to the appropriate language-specific analyzer.
234
+ * Supports: TypeScript, JavaScript, Dart
235
+ *
236
+ * Rule: ${RULE_DESCRIPTION}
237
+ */
238
+
239
+ const path = require('path');
240
+
241
+ class ${RULE_ID}Router {
242
+ constructor() {
243
+ this.analyzers = new Map();
244
+ this.ruleId = '${RULE_ID}';
245
+ }
246
+
247
+ getAnalyzer(language) {
248
+ const normalizedLang = this.normalizeLanguage(language);
249
+
250
+ if (!this.analyzers.has(normalizedLang)) {
251
+ try {
252
+ const analyzerPath = path.join(__dirname, normalizedLang, 'analyzer.js');
253
+ const AnalyzerClass = require(analyzerPath);
254
+ this.analyzers.set(normalizedLang, new AnalyzerClass());
255
+ } catch (error) {
256
+ return null;
257
+ }
258
+ }
259
+
260
+ return this.analyzers.get(normalizedLang);
261
+ }
262
+
263
+ normalizeLanguage(language) {
264
+ // ⚠️ CRITICAL: Handle case where language might not be a string
265
+ // Heuristic engine may pass non-string values
266
+ if (typeof language !== 'string') {
267
+ return 'typescript'; // Default fallback
268
+ }
269
+ const languageMap = {
270
+ 'typescript': 'typescript',
271
+ 'javascript': 'typescript',
272
+ 'ts': 'typescript',
273
+ 'js': 'typescript',
274
+ 'dart': 'dart'
275
+ };
276
+ return languageMap[language.toLowerCase()] || language.toLowerCase();
277
+ }
278
+
279
+ supportsLanguage(language) {
280
+ // ⚠️ CRITICAL: Handle non-string language parameter
281
+ if (typeof language !== 'string') return false;
282
+ const supported = ['typescript', 'javascript', 'ts', 'js', 'dart'];
283
+ return supported.includes(language.toLowerCase());
284
+ }
285
+
286
+ getSupportedLanguages() {
287
+ return ['typescript', 'javascript', 'dart'];
288
+ }
289
+
290
+ async analyze(files, language, options = {}) {
291
+ const analyzer = this.getAnalyzer(language);
292
+ if (!analyzer) return [];
293
+ if (typeof analyzer.analyze === 'function') {
294
+ return analyzer.analyze(files, language, options);
295
+ }
296
+ return [];
297
+ }
298
+
299
+ async initialize(semanticEngineOrLanguage = null, semanticEngine = null) {
300
+ // ⚠️ CRITICAL: Handle both signatures:
301
+ // 1. initialize(semanticEngine) - called by heuristic engine
302
+ // 2. initialize(language, semanticEngine) - original signature
303
+ let engine = semanticEngine;
304
+ let lang = null;
305
+
306
+ if (typeof semanticEngineOrLanguage === 'string') {
307
+ lang = semanticEngineOrLanguage;
308
+ } else if (semanticEngineOrLanguage && typeof semanticEngineOrLanguage === 'object') {
309
+ engine = semanticEngineOrLanguage;
310
+ }
311
+
312
+ // If language specified, initialize only that analyzer
313
+ if (lang) {
314
+ const analyzer = this.getAnalyzer(lang);
315
+ if (analyzer && typeof analyzer.initialize === 'function') {
316
+ await analyzer.initialize(engine);
317
+ }
318
+ }
319
+ }
320
+ }
321
+
322
+ module.exports = new ${RULE_ID}Router();
323
+ ```
324
+
325
+ ### Step 6: Create Dart Wrapper (dart/analyzer.js)
326
+
327
+ **File:** `$RULE_FOLDER/dart/analyzer.js`
328
+
329
+ ```javascript
330
+ /**
331
+ * ${RULE_ID} Dart Analyzer - ${RULE_NAME}
332
+ *
333
+ * This is a JS wrapper that delegates to DartAnalyzer binary.
334
+ * Actual implementation: dart_analyzer/lib/rules/${RULE_ID}_${RULE_SNAKE_NAME}.dart
335
+ */
336
+
337
+ class Dart${RULE_ID}Analyzer {
338
+ constructor() {
339
+ this.ruleId = '${RULE_ID}';
340
+ this.language = 'dart';
341
+ }
342
+
343
+ getMetadata() {
344
+ return {
345
+ ruleId: '${RULE_ID}',
346
+ name: '${RULE_NAME}',
347
+ language: 'dart',
348
+ delegateTo: 'dart_analyzer',
349
+ description: '${RULE_DESCRIPTION}'
350
+ };
351
+ }
352
+
353
+ getConfig() {
354
+ return {
355
+ // Rule-specific config
356
+ severity: 'warning'
357
+ };
358
+ }
359
+
360
+ async analyze(files, language, options) {
361
+ // Delegated to DartAnalyzer binary via heuristic-engine.js
362
+ return [];
363
+ }
364
+
365
+ supportsLanguage(language) {
366
+ return language === 'dart';
367
+ }
368
+ }
369
+
370
+ module.exports = Dart${RULE_ID}Analyzer;
371
+ ```
372
+
373
+ ### Step 7: Update config.json
374
+
375
+ ```bash
376
+ # Add "dart" to languages array
377
+ # Before: "languages": ["typescript", "javascript"]
378
+ # After: "languages": ["typescript", "javascript", "dart"]
379
+ ```
380
+
381
+ ### Step 7.1: Update enhanced-rules-registry.json
382
+
383
+ > **IMPORTANT**: This registry is used by UnifiedRuleRegistry for rule discovery and metadata.
384
+
385
+ **File:** `config/rules/enhanced-rules-registry.json`
386
+
387
+ ```json
388
+ {
389
+ "rules": {
390
+ "${RULE_ID}": {
391
+ "id": "${RULE_ID}",
392
+ "name": "${RULE_NAME}",
393
+ "category": "${CATEGORY}",
394
+ "severity": "warning",
395
+ "languages": ["typescript", "javascript", "dart"], // ← Add "dart" here
396
+ "path": "rules/${CATEGORY}/${RULE_ID}_${RULE_SNAKE_NAME}",
397
+ "analyzer": "index.js", // ← Use index.js for router-based rules
398
+ "description": "${RULE_DESCRIPTION}"
399
+ }
400
+ }
401
+ }
402
+ ```
403
+
404
+ **Key points:**
405
+ - Add `"dart"` to the `languages` array
406
+ - Set `"analyzer": "index.js"` to point to the router file
407
+ - The registry is sorted alphabetically by prefix (C→R→S→T) then by number
408
+
409
+ ### Step 8: Create Dart Analyzer Implementation
410
+
411
+ **File:** `dart_analyzer/lib/rules/${RULE_ID}_${RULE_SNAKE_NAME}.dart`
412
+
413
+ ```dart
414
+ import 'package:analyzer/dart/ast/ast.dart';
415
+ import 'package:analyzer/dart/ast/visitor.dart';
416
+ import 'package:analyzer/source/line_info.dart';
417
+
418
+ import '../models/rule.dart';
419
+ import '../models/violation.dart';
420
+ import 'base_analyzer.dart';
421
+
422
+ /// ${RULE_ID}: ${RULE_NAME}
423
+ /// ${RULE_DESCRIPTION}
424
+ class ${RULE_ID}${RULE_PASCAL_NAME}Analyzer extends BaseAnalyzer {
425
+ @override
426
+ String get ruleId => '${RULE_ID}';
427
+
428
+ @override
429
+ List<Violation> analyze({
430
+ required CompilationUnit unit,
431
+ required String filePath,
432
+ required Rule rule,
433
+ required LineInfo lineInfo,
434
+ }) {
435
+ final violations = <Violation>[];
436
+
437
+ final visitor = _${RULE_ID}Visitor(
438
+ filePath: filePath,
439
+ lineInfo: lineInfo,
440
+ violations: violations,
441
+ analyzer: this,
442
+ );
443
+
444
+ unit.accept(visitor);
445
+
446
+ return violations;
447
+ }
448
+ }
449
+
450
+ class _${RULE_ID}Visitor extends RecursiveAstVisitor<void> {
451
+ final String filePath;
452
+ final LineInfo lineInfo;
453
+ final List<Violation> violations;
454
+ final ${RULE_ID}${RULE_PASCAL_NAME}Analyzer analyzer;
455
+
456
+ _${RULE_ID}Visitor({
457
+ required this.filePath,
458
+ required this.lineInfo,
459
+ required this.violations,
460
+ required this.analyzer,
461
+ });
462
+
463
+ // TODO: Implement visitor methods based on TypeScript logic
464
+ // Example:
465
+ // @override
466
+ // void visitFunctionDeclaration(FunctionDeclaration node) {
467
+ // // Check rule logic
468
+ // super.visitFunctionDeclaration(node);
469
+ // }
470
+ }
471
+ ```
472
+
473
+ ### Step 9: Register in AnalyzerService
474
+
475
+ **File:** `dart_analyzer/lib/analyzer_service.dart`
476
+
477
+ ```dart
478
+ // Add import
479
+ import 'rules/${RULE_ID}_${RULE_SNAKE_NAME}.dart';
480
+
481
+ // Add to _registerAnalyzers()
482
+ void _registerAnalyzers() {
483
+ // ... existing rules
484
+ _analyzers['${RULE_ID}'] = ${RULE_ID}${RULE_PASCAL_NAME}Analyzer();
485
+ }
486
+ ```
487
+
488
+ ### Step 10: Create Test Fixtures
489
+
490
+ > **IMPORTANT**: Test fixtures are REQUIRED for each Dart rule. Both `violations/` and `clean/` folders MUST contain at least one `.dart` file. Empty folders are not acceptable.
491
+
492
+ ```bash
493
+ # Create test fixture folders
494
+ mkdir -p "examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/{clean,violations}"
495
+ ```
496
+
497
+ **violations/ - Files with rule violations (REQUIRED):**
498
+ ```dart
499
+ // examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/violations/bad_example.dart
500
+
501
+ // ❌ VIOLATION: ${RULE_ID} - ${RULE_NAME}
502
+ // Description of what makes this code violate the rule
503
+
504
+ class BadExample {
505
+ // Code that violates the rule
506
+ // Include multiple examples of violations
507
+ // Make sure the analyzer CAN detect these violations
508
+ }
509
+ ```
510
+
511
+ **clean/ - Files without violations (REQUIRED):**
512
+ ```dart
513
+ // examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/clean/good_example.dart
514
+
515
+ // ✅ CLEAN: ${RULE_ID} - ${RULE_NAME}
516
+ // Description of what makes this code compliant
517
+
518
+ class GoodExample {
519
+ // Code that follows the rule correctly
520
+ // Show the recommended way to write code
521
+ }
522
+ ```
523
+
524
+ **Test Fixture Requirements:**
525
+ - Each rule MUST have at least 1 file in `violations/` and 1 file in `clean/`
526
+ - Violation files should contain code that the analyzer WILL detect
527
+ - Clean files should contain code that the analyzer will NOT flag
528
+ - Use descriptive filenames (e.g., `bad_naming.dart`, `good_naming.dart`)
529
+ - Add comments explaining WHY the code violates or follows the rule
530
+
531
+ ### Step 11: Rebuild Dart Analyzer
532
+
533
+ ```bash
534
+ cd dart_analyzer
535
+
536
+ # Get dependencies
537
+ dart pub get
538
+
539
+ # Analyze for errors
540
+ dart analyze lib/
541
+
542
+ # Compile binary
543
+ dart compile exe bin/sunlint_dart_analyzer.dart -o bin/sunlint-dart-macos
544
+ ```
545
+
546
+ ### Step 12: Test the Rule
547
+
548
+ ```bash
549
+ cd /path/to/sunlint
550
+
551
+ # Test on violations (should find issues)
552
+ node cli.js --rule=${RULE_ID} \
553
+ --input="examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/violations" \
554
+ --languages=dart \
555
+ --include="**/*.dart"
556
+
557
+ # Test on clean code (should find no issues)
558
+ node cli.js --rule=${RULE_ID} \
559
+ --input="examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/clean" \
560
+ --languages=dart \
561
+ --include="**/*.dart"
562
+ ```
563
+
564
+ ---
565
+
566
+ ## 4. Verification Checklist
567
+
568
+ | Check | Command | Expected |
569
+ |-------|---------|----------|
570
+ | Dart folder exists | `ls rules/*/${RULE_ID}_*/dart/` | `analyzer.js` |
571
+ | Router exists | `ls rules/*/${RULE_ID}_*/index.js` | File exists |
572
+ | Config updated | `grep dart rules/*/${RULE_ID}_*/config.json` | `"dart"` in languages |
573
+ | **Registry updated** | `grep ${RULE_ID} config/rules/enhanced-rules-registry.json` | `"dart"` in languages |
574
+ | Dart analyzer exists | `ls dart_analyzer/lib/rules/${RULE_ID}_*.dart` | File exists |
575
+ | Registered | `grep ${RULE_ID} dart_analyzer/lib/analyzer_service.dart` | Registration line |
576
+ | Binary compiles | `dart analyze dart_analyzer/lib/` | No errors |
577
+ | Test fixtures exist | `ls examples/rule-test-fixtures/dart-rules/${RULE_ID}_*` | clean/ and violations/ |
578
+ | **Fixtures have files** | `ls examples/rule-test-fixtures/dart-rules/${RULE_ID}_*/{clean,violations}/*.dart` | At least 2 files |
579
+ | **TypeScript works** | Run on TS files | Violations found |
580
+ | **Dart works** | Run on Dart files | Violations found |
581
+ | **Violations detected** | Run on violations/ | > 0 violations |
582
+ | Clean passes | Run on clean/ | No violations |
583
+
584
+ ---
585
+
586
+ ## 5. Example: Adding Dart Support for C006
587
+
588
+ ### Input
589
+ ```
590
+ Rule ID: C006
591
+ ```
592
+
593
+ ### Execution
594
+
595
+ ```bash
596
+ # Step 1: Find rule
597
+ RULE_FOLDER="rules/common/C006_function_naming"
598
+
599
+ # Step 2: Check not exists
600
+ ls rules/common/C006_function_naming/dart/ # Should not exist
601
+
602
+ # Step 3: Create structure
603
+ mkdir -p rules/common/C006_function_naming/{typescript,dart}
604
+ mv rules/common/C006_function_naming/analyzer.js rules/common/C006_function_naming/typescript/
605
+
606
+ # Step 4: Create files
607
+ # - rules/common/C006_function_naming/index.js
608
+ # - rules/common/C006_function_naming/dart/analyzer.js
609
+ # - dart_analyzer/lib/rules/C006_function_naming.dart
610
+
611
+ # Step 5: Update config.json
612
+ # Add "dart" to languages
613
+
614
+ # Step 6: Register in analyzer_service.dart
615
+ # _analyzers['C006'] = C006FunctionNamingAnalyzer();
616
+
617
+ # Step 7: Create test fixtures
618
+ mkdir -p examples/rule-test-fixtures/dart-rules/C006_function_naming/{clean,violations}
619
+
620
+ # Step 8: Rebuild
621
+ cd dart_analyzer && dart compile exe bin/sunlint_dart_analyzer.dart -o bin/sunlint-dart-macos
622
+
623
+ # Step 9: Test
624
+ node cli.js --rule=C006 \
625
+ --input="examples/rule-test-fixtures/dart-rules/C006_function_naming/violations" \
626
+ --languages=dart \
627
+ --include="**/*.dart"
628
+ ```
629
+
630
+ ---
631
+
632
+ ## 6. Naming Conventions
633
+
634
+ | Type | Convention | Example |
635
+ |------|------------|---------|
636
+ | Rule ID | Uppercase + Number | `C006`, `S010` |
637
+ | Folder name | `{ID}_{snake_case}` | `C006_function_naming` |
638
+ | Dart file | `{ID}_{snake_case}.dart` | `C006_function_naming.dart` |
639
+ | Class name | `{ID}{PascalCase}Analyzer` | `C006FunctionNamingAnalyzer` |
640
+ | Visitor class | `_{ID}Visitor` | `_C006Visitor` |
641
+
642
+ ---
643
+
644
+ ## 7. Common Patterns for Dart Rules
645
+
646
+ ### Pattern 1: Check Class Names
647
+
648
+ ```dart
649
+ @override
650
+ void visitClassDeclaration(ClassDeclaration node) {
651
+ final name = node.name.lexeme;
652
+ if (!isValidClassName(name)) {
653
+ violations.add(analyzer.createViolation(
654
+ filePath: filePath,
655
+ line: analyzer.getLine(lineInfo, node.name.offset),
656
+ column: analyzer.getColumn(lineInfo, node.name.offset),
657
+ message: 'Class name "$name" violates rule',
658
+ ));
659
+ }
660
+ super.visitClassDeclaration(node);
661
+ }
662
+ ```
663
+
664
+ ### Pattern 2: Check Function/Method Names
665
+
666
+ ```dart
667
+ @override
668
+ void visitFunctionDeclaration(FunctionDeclaration node) {
669
+ final name = node.name.lexeme;
670
+ // Check function name
671
+ super.visitFunctionDeclaration(node);
672
+ }
673
+
674
+ @override
675
+ void visitMethodDeclaration(MethodDeclaration node) {
676
+ if (node.isOperator) return;
677
+ final name = node.name.lexeme;
678
+ // Check method name
679
+ super.visitMethodDeclaration(node);
680
+ }
681
+ ```
682
+
683
+ ### Pattern 3: Check Variable Names
684
+
685
+ ```dart
686
+ @override
687
+ void visitVariableDeclaration(VariableDeclaration node) {
688
+ final name = node.name.lexeme;
689
+ // Check variable name
690
+ super.visitVariableDeclaration(node);
691
+ }
692
+ ```
693
+
694
+ ### Pattern 4: Check Method Invocations
695
+
696
+ ```dart
697
+ @override
698
+ void visitMethodInvocation(MethodInvocation node) {
699
+ final methodName = node.methodName.name;
700
+ final target = node.target?.toSource() ?? '';
701
+ // Check method call
702
+ super.visitMethodInvocation(node);
703
+ }
704
+ ```
705
+
706
+ ### Pattern 5: Check String Literals
707
+
708
+ ```dart
709
+ @override
710
+ void visitSimpleStringLiteral(SimpleStringLiteral node) {
711
+ final value = node.value;
712
+ // Check string content
713
+ super.visitSimpleStringLiteral(node);
714
+ }
715
+ ```
716
+
717
+ ---
718
+
719
+ ## 8. Error Handling
720
+
721
+ ### 8.1. Dart Compile Error
722
+
723
+ ```bash
724
+ # Check for errors
725
+ dart analyze dart_analyzer/lib/
726
+
727
+ # Common fixes:
728
+ # - Import missing files
729
+ # - Fix syntax errors
730
+ # - Add missing dependencies to pubspec.yaml
731
+ ```
732
+
733
+ ### 8.2. Rule Not Detected
734
+
735
+ ```bash
736
+ # Verify dart/ folder exists
737
+ ls rules/*/${RULE_ID}_*/dart/
738
+
739
+ # Check detectDartSupport function finds it
740
+ node -e "
741
+ const path = require('path');
742
+ const fs = require('fs');
743
+ const rulesPath = 'rules/common';
744
+ const folders = fs.readdirSync(rulesPath);
745
+ const match = folders.find(f => f.startsWith('${RULE_ID}_'));
746
+ console.log('Found:', match);
747
+ console.log('Dart exists:', fs.existsSync(path.join(rulesPath, match, 'dart')));
748
+ "
749
+ ```
750
+
751
+ ### 8.3. No Violations Found
752
+
753
+ ```bash
754
+ # Check DartAnalyzer is running
755
+ node cli.js --rule=${RULE_ID} --input=... --languages=dart --include="**/*.dart" --verbose
756
+
757
+ # Check analyzer is registered
758
+ grep ${RULE_ID} dart_analyzer/lib/analyzer_service.dart
759
+ ```
760
+
761
+ ### 8.4. ⚠️ `language.toLowerCase is not a function` Error
762
+
763
+ **Symptom:**
764
+ ```
765
+ TypeError: language.toLowerCase is not a function
766
+ at ${RULE_ID}Router.normalizeLanguage
767
+ ```
768
+
769
+ **Cause:** Heuristic engine passes `semanticEngine` object to `initialize()`, not a language string.
770
+
771
+ **Solution:** Update router methods with type checking:
772
+
773
+ ```javascript
774
+ normalizeLanguage(language) {
775
+ // Add this check at the beginning
776
+ if (typeof language !== 'string') {
777
+ return 'typescript'; // Default fallback
778
+ }
779
+ // ... rest of method
780
+ }
781
+
782
+ supportsLanguage(language) {
783
+ // Add this check at the beginning
784
+ if (typeof language !== 'string') return false;
785
+ // ... rest of method
786
+ }
787
+ ```
788
+
789
+ ### 8.5. ⚠️ Rule Not Supported by Heuristic Engine
790
+
791
+ **Symptom:**
792
+ ```
793
+ Rule ${RULE_ID} is not supported by the heuristic engine
794
+ ```
795
+
796
+ **Cause:** UnifiedRuleRegistry cannot find the analyzer because it looks for `analyzer.js` but the router uses `index.js`.
797
+
798
+ **Solution:** Ensure `unified-rule-registry.js` supports router discovery. The `router` type should be added to `analyzerFiles`:
799
+
800
+ ```javascript
801
+ // In core/unified-rule-registry.js
802
+ const analyzerFiles = {
803
+ analyzer: path.join(rulePath, 'analyzer.js'),
804
+ tsAnalyzer: path.join(rulePath, 'typescript', 'analyzer.js'),
805
+ dartAnalyzer: path.join(rulePath, 'dart', 'analyzer.js'),
806
+ router: path.join(rulePath, 'index.js') // ← This enables router discovery
807
+ };
808
+ ```
809
+
810
+ ### 8.6. ⚠️ RangeError in Dart Analyzer
811
+
812
+ **Symptom:**
813
+ ```
814
+ RangeError: Value not in range: 4
815
+ ```
816
+
817
+ **Cause:** Using `string.substring(0, 4)` without checking string length.
818
+
819
+ **Solution:** Always check string length before substring operations:
820
+
821
+ ```dart
822
+ // ❌ BAD - causes RangeError when name.length < 4
823
+ 'recommendation': 'Use masking like: "${name.substring(0, 4)}****"'
824
+
825
+ // ✅ GOOD - check length first
826
+ 'recommendation': 'Use masking like: "${name.length > 4 ? name.substring(0, 4) : name}****"'
827
+ ```
828
+
829
+ ### 8.7. Semantic Analyzer Not Working
830
+
831
+ **Symptom:** TypeScript semantic analysis (using ts-morph) doesn't work after adding Dart support.
832
+
833
+ **Cause:** Moving files around may delete semantic analyzer files.
834
+
835
+ **Solution:**
836
+ - Keep semantic analyzer in `typescript/semantic-analyzer.js`
837
+ - The router will load it from the typescript subfolder
838
+ - Verify file exists: `ls rules/*/${RULE_ID}_*/typescript/semantic-analyzer.js`
839
+
840
+ ---
841
+
842
+ ## 9. Files Created by This Skill
843
+
844
+ | File | Purpose |
845
+ |------|---------|
846
+ | `rules/*/${RULE_ID}_*/index.js` | Multi-language router |
847
+ | `rules/*/${RULE_ID}_*/dart/analyzer.js` | JS wrapper for Dart |
848
+ | `dart_analyzer/lib/rules/${RULE_ID}_*.dart` | Dart analyzer implementation |
849
+ | `examples/rule-test-fixtures/dart-rules/${RULE_ID}_*/clean/*.dart` | Clean test cases |
850
+ | `examples/rule-test-fixtures/dart-rules/${RULE_ID}_*/violations/*.dart` | Violation test cases |
851
+
852
+ ---
853
+
854
+ ## 10. Related Documentation
855
+
856
+ - [DART_RULE_EXECUTION_FLOW.md](../DART_RULE_EXECUTION_FLOW.md) - Chi tiết luồng thực thi rule
857
+ - [dart_analyzer/README.md](../../dart_analyzer/README.md) - Dart analyzer documentation
858
+ - [rules/README.md](../../rules/README.md) - Rule structure documentation
859
+
860
+ ---
861
+
862
+ ## 11. Architecture Notes
863
+
864
+ ### 11.1. Rule Discovery Flow
865
+
866
+ ```
867
+ CLI → HeuristicEngine → UnifiedRuleRegistry → Router (index.js)
868
+
869
+ ┌───────────┴───────────┐
870
+ ↓ ↓
871
+ typescript/analyzer.js dart/analyzer.js
872
+ ↓ ↓
873
+ (ts-morph analysis) (delegates to DartAnalyzer binary)
874
+ ```
875
+
876
+ ### 11.2. Initialize Method Signatures
877
+
878
+ The heuristic engine calls `initialize()` with different arguments depending on context:
879
+
880
+ | Caller | Signature | Arguments |
881
+ |--------|-----------|-----------|
882
+ | Heuristic Engine | `initialize(engine)` | `semanticEngine` object |
883
+ | Direct usage | `initialize(lang, engine)` | Language string, then engine |
884
+
885
+ **The router must handle both signatures!**
886
+
887
+ ### 11.3. Registry Files
888
+
889
+ | File | Purpose | When to Update |
890
+ |------|---------|----------------|
891
+ | `config/rules/enhanced-rules-registry.json` | Rule metadata & discovery | Add "dart" to languages |
892
+ | `core/unified-rule-registry.js` | Analyzer path resolution | Only if adding new patterns |
893
+ | `rules/index.js` | Legacy rule exports | Usually not needed |
894
+ | `dart_analyzer/lib/analyzer_service.dart` | Dart analyzer registration | Register new Dart analyzer |
895
+
896
+ ---
897
+
898
+ ## 12. Changelog
899
+
900
+ ### v1.1.0 (2025-12-23)
901
+ - Fixed router template: Added type checking in `normalizeLanguage()` and `supportsLanguage()`
902
+ - Fixed `initialize()` method to handle both heuristic engine and direct call signatures
903
+ - Added Step 7.1: Update enhanced-rules-registry.json
904
+ - Added detailed error handling sections (8.4 - 8.7) based on real bugs encountered
905
+ - Added Architecture Notes section explaining discovery flow and registry files
906
+ - Added Lessons Learned section
907
+
908
+ ### v1.0.0 (Initial)
909
+ - Initial skill documentation for creating Dart rules