@sun-asterisk/sunlint 1.0.6 → 1.1.3

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 (314) hide show
  1. package/.sunlint.json +35 -0
  2. package/CHANGELOG.md +135 -169
  3. package/CONTRIBUTING.md +235 -0
  4. package/PROJECT_STRUCTURE.md +60 -0
  5. package/README.md +77 -50
  6. package/cli.js +1 -0
  7. package/config/README.md +88 -0
  8. package/config/defaults/ai-rules-context.json +231 -0
  9. package/config/engines/engines.json +49 -0
  10. package/config/engines/eslint-rule-mapping.json +74 -0
  11. package/config/eslint-rule-mapping.json +126 -0
  12. package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +4 -0
  13. package/config/presets/beginner.json +1 -1
  14. package/config/presets/ci.json +3 -2
  15. package/config/presets/recommended.json +1 -1
  16. package/config/presets/strict.json +2 -2
  17. package/config/rule-analysis-strategies.js +74 -0
  18. package/config/{rules-registry.json → rules/rules-registry.json} +82 -0
  19. package/core/analysis-orchestrator.js +383 -591
  20. package/core/ast-modules/README.md +103 -0
  21. package/core/ast-modules/base-parser.js +90 -0
  22. package/core/ast-modules/index.js +97 -0
  23. package/core/ast-modules/package.json +37 -0
  24. package/core/ast-modules/parsers/eslint-js-parser.js +147 -0
  25. package/core/ast-modules/parsers/eslint-ts-parser.js +106 -0
  26. package/core/ast-modules/parsers/javascript-parser.js +187 -0
  27. package/core/ast-modules/parsers/typescript-parser.js +187 -0
  28. package/core/cli-action-handler.js +271 -255
  29. package/core/cli-program.js +18 -4
  30. package/core/config-manager.js +18 -11
  31. package/core/config-merger.js +52 -1
  32. package/core/config-validator.js +2 -2
  33. package/core/enhanced-rules-registry.js +331 -0
  34. package/core/file-targeting-service.js +93 -29
  35. package/core/interfaces/analysis-engine.interface.js +100 -0
  36. package/core/multi-rule-runner.js +0 -221
  37. package/core/output-service.js +1 -1
  38. package/core/rule-mapping-service.js +9 -1
  39. package/core/rule-selection-service.js +10 -2
  40. package/docs/CONFIGURATION.md +414 -0
  41. package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
  42. package/engines/eslint-engine.js +601 -0
  43. package/engines/heuristic-engine.js +860 -0
  44. package/engines/openai-engine.js +374 -0
  45. package/integrations/eslint/README.md +99 -0
  46. package/{eslint-integration → integrations/eslint/configs}/.eslintrc.js +1 -1
  47. package/integrations/eslint/configs/eslint.config.js +133 -0
  48. package/integrations/eslint/configs/eslint.config.simple.js +24 -0
  49. package/integrations/eslint/plugin/index.js +164 -0
  50. package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c006-function-name-verb-noun.js +11 -2
  51. package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
  52. package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
  53. package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c029-catch-block-logging.js +35 -0
  54. package/integrations/eslint/plugin/rules/common/c035-no-empty-catch.js +162 -0
  55. package/integrations/eslint/plugin/rules/common/c041-no-config-inline.js +122 -0
  56. package/integrations/eslint/plugin/rules/common/c072-one-assert-per-test.js +184 -0
  57. package/integrations/eslint/plugin/rules/common/c075-explicit-function-return-types.js +168 -0
  58. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +254 -0
  59. package/integrations/eslint/plugin/rules/security/s001-fail-securely.js +381 -0
  60. package/integrations/eslint/plugin/rules/security/s002-idor-check.js +945 -0
  61. package/integrations/eslint/plugin/rules/security/s007-no-plaintext-otp.js +74 -0
  62. package/integrations/eslint/plugin/rules/security/s013-verify-tls-connection.js +47 -0
  63. package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/typescript}/t003-ts-ignore-reason.js +3 -3
  64. package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/typescript}/t007-no-fn-in-constructor.js +1 -1
  65. package/integrations/eslint/plugin/rules/typescript/t019-no-this-assign.js +81 -0
  66. package/integrations/eslint/plugin/rules/typescript/t020-no-default-multi-export.js +127 -0
  67. package/integrations/eslint/plugin/rules/typescript/t021-limit-nested-generics.js +150 -0
  68. package/integrations/eslint/test-c041-rule.js +87 -0
  69. package/package.json +29 -19
  70. package/rules/README.md +252 -0
  71. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  72. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  73. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  74. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  75. package/rules/{C006_function_naming → common/C006_function_naming}/analyzer.js +13 -2
  76. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  77. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  78. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  79. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  80. package/rules/{C019_log_level_usage → common/C019_log_level_usage}/analyzer.js +5 -2
  81. package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/analyzer.js +49 -15
  82. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  83. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  84. package/rules/common/C043_no_console_or_print/analyzer.js +304 -0
  85. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +351 -0
  86. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  87. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  88. package/rules/docs/C002_no_duplicate_code.md +57 -0
  89. package/rules/index.js +149 -0
  90. package/rules/migration/converter.js +385 -0
  91. package/rules/migration/mapping.json +164 -0
  92. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  93. package/rules/security/S026_json_schema_validation/config.json +27 -0
  94. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +263 -0
  95. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  96. package/rules/security/S029_csrf_protection/analyzer.js +264 -0
  97. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  98. package/rules/utils/ast-utils.js +191 -0
  99. package/rules/utils/base-analyzer.js +98 -0
  100. package/rules/utils/pattern-matchers.js +239 -0
  101. package/rules/utils/rule-helpers.js +264 -0
  102. package/rules/utils/severity-constants.js +93 -0
  103. package/scripts/build-release.sh +117 -0
  104. package/scripts/ci-report.js +179 -0
  105. package/scripts/install.sh +196 -0
  106. package/scripts/manual-release.sh +338 -0
  107. package/scripts/merge-reports.js +424 -0
  108. package/scripts/pre-release-test.sh +175 -0
  109. package/scripts/prepare-release.sh +202 -0
  110. package/scripts/setup-github-registry.sh +42 -0
  111. package/scripts/test-scripts/README.md +22 -0
  112. package/scripts/test-scripts/test-c041-comparison.js +114 -0
  113. package/scripts/test-scripts/test-c041-eslint.js +67 -0
  114. package/scripts/test-scripts/test-eslint-rules.js +146 -0
  115. package/scripts/test-scripts/test-real-world.js +44 -0
  116. package/scripts/test-scripts/test-rules-on-real-projects.js +86 -0
  117. package/scripts/trigger-release.sh +285 -0
  118. package/scripts/validate-rule-structure.js +148 -0
  119. package/scripts/verify-install.sh +82 -0
  120. package/cli-legacy.js +0 -355
  121. package/config/sunlint-schema.json +0 -166
  122. package/config/typescript/custom-rules-new.js +0 -0
  123. package/config/typescript/custom-rules.js +0 -9
  124. package/config/typescript/package-lock.json +0 -1585
  125. package/config/typescript/package.json +0 -13
  126. package/config/typescript/security-rules/index.js +0 -90
  127. package/config/typescript/security-rules/s005-no-origin-auth.js +0 -95
  128. package/config/typescript/security-rules/s006-activation-recovery-secret-not-plaintext.js +0 -69
  129. package/config/typescript/security-rules/s008-crypto-agility.js +0 -62
  130. package/config/typescript/security-rules/s009-no-insecure-crypto.js +0 -103
  131. package/config/typescript/security-rules/s010-no-insecure-random-in-sensitive-context.js +0 -123
  132. package/config/typescript/security-rules/s011-no-insecure-uuid.js +0 -66
  133. package/config/typescript/security-rules/s012-hardcode-secret.js +0 -71
  134. package/config/typescript/security-rules/s014-insecure-tls-version.js +0 -50
  135. package/config/typescript/security-rules/s015-insecure-tls-certificate.js +0 -43
  136. package/config/typescript/security-rules/s016-sensitive-query-parameter.js +0 -59
  137. package/config/typescript/security-rules/s017-no-sql-injection.js +0 -193
  138. package/config/typescript/security-rules/s018-positive-input-validation.js +0 -56
  139. package/config/typescript/security-rules/s019-no-raw-user-input-in-email.js +0 -113
  140. package/config/typescript/security-rules/s020-no-eval-dynamic-execution.js +0 -89
  141. package/config/typescript/security-rules/s022-output-encoding.js +0 -78
  142. package/config/typescript/security-rules/s023-no-json-injection.js +0 -300
  143. package/config/typescript/security-rules/s025-server-side-input-validation.js +0 -217
  144. package/config/typescript/security-rules/s026-json-schema-validation.js +0 -68
  145. package/config/typescript/security-rules/s027-no-hardcoded-secrets.js +0 -80
  146. package/config/typescript/security-rules/s029-require-csrf-protection.js +0 -79
  147. package/config/typescript/security-rules/s030-no-directory-browsing.js +0 -78
  148. package/config/typescript/security-rules/s033-require-samesite-cookie.js +0 -80
  149. package/config/typescript/security-rules/s034-require-host-cookie-prefix.js +0 -77
  150. package/config/typescript/security-rules/s035-cookie-specific-path.js +0 -74
  151. package/config/typescript/security-rules/s036-no-unsafe-file-include.js +0 -68
  152. package/config/typescript/security-rules/s037-require-anti-cache-headers.js +0 -70
  153. package/config/typescript/security-rules/s038-no-version-disclosure.js +0 -74
  154. package/config/typescript/security-rules/s039-no-session-token-in-url.js +0 -63
  155. package/config/typescript/security-rules/s041-require-session-invalidate-on-logout.js +0 -211
  156. package/config/typescript/security-rules/s042-require-periodic-reauthentication.js +0 -294
  157. package/config/typescript/security-rules/s043-terminate-sessions-on-password-change.js +0 -254
  158. package/config/typescript/security-rules/s044-require-full-session-for-sensitive-operations.js +0 -292
  159. package/config/typescript/security-rules/s045-anti-automation-controls.js +0 -46
  160. package/config/typescript/security-rules/s046-secure-notification-on-auth-change.js +0 -44
  161. package/config/typescript/security-rules/s048-password-credential-recovery.js +0 -54
  162. package/config/typescript/security-rules/s050-session-token-weak-hash.js +0 -94
  163. package/config/typescript/security-rules/s052-secure-random-authentication-code.js +0 -66
  164. package/config/typescript/security-rules/s054-verification-default-account.js +0 -109
  165. package/config/typescript/security-rules/s057-utc-logging.js +0 -54
  166. package/config/typescript/security-rules/s058-no-ssrf.js +0 -73
  167. package/config/typescript/tsconfig.json +0 -29
  168. package/core/ai-analyzer.js +0 -169
  169. package/core/eslint-engine-service.js +0 -312
  170. package/core/eslint-instance-manager.js +0 -104
  171. package/core/eslint-integration-service.js +0 -363
  172. package/core/sunlint-engine-service.js +0 -23
  173. package/core/typescript-analyzer.js +0 -262
  174. package/core/typescript-engine.js +0 -313
  175. package/docs/ENHANCED_FILE_TARGETING.md +0 -0
  176. package/docs/FILE_TARGETING_COMPARISON.md +0 -0
  177. package/docs/RULE-RESPONSIBILITY-MATRIX.md +0 -204
  178. package/eslint-integration/cli.js +0 -35
  179. package/eslint-integration/eslint-plugin-custom/c013-no-dead-code.js +0 -43
  180. package/eslint-integration/eslint-plugin-custom/c017-limit-constructor-logic.js +0 -39
  181. package/eslint-integration/eslint-plugin-custom/c027-limit-function-nesting.js +0 -50
  182. package/eslint-integration/eslint-plugin-custom/c034-no-implicit-return.js +0 -34
  183. package/eslint-integration/eslint-plugin-custom/c035-no-empty-catch.js +0 -32
  184. package/eslint-integration/eslint-plugin-custom/c041-no-config-inline.js +0 -64
  185. package/eslint-integration/eslint-plugin-custom/c048-no-var-declaration.js +0 -31
  186. package/eslint-integration/eslint-plugin-custom/index.js +0 -155
  187. package/eslint-integration/eslint-plugin-custom/package.json.bak +0 -9
  188. package/eslint-integration/eslint-plugin-custom/t004-interface-public-only.js +0 -160
  189. package/eslint-integration/eslint-plugin-custom/t011-no-real-time-dependency.js +0 -175
  190. package/eslint-integration/eslint-plugin-custom/t026-limit-nested-generics.js +0 -377
  191. package/eslint-integration/sample.ts +0 -53
  192. package/eslint-integration/test-s003.js +0 -5
  193. package/examples/.github/workflows/code-quality.yml +0 -111
  194. package/examples/README.md +0 -69
  195. package/examples/basic-typescript-demo/.eslintrc.json +0 -18
  196. package/examples/basic-typescript-demo/.next/cache/eslint/.cache_1othrmo +0 -1
  197. package/examples/basic-typescript-demo/.sunlint.json +0 -29
  198. package/examples/basic-typescript-demo/eslint.config.mjs +0 -37
  199. package/examples/basic-typescript-demo/next-env.d.ts +0 -5
  200. package/examples/basic-typescript-demo/next.config.mjs +0 -4
  201. package/examples/basic-typescript-demo/package-lock.json +0 -5656
  202. package/examples/basic-typescript-demo/package.json +0 -34
  203. package/examples/basic-typescript-demo/src/app/layout.tsx +0 -18
  204. package/examples/basic-typescript-demo/src/app/page.tsx +0 -48
  205. package/examples/basic-typescript-demo/src/config.ts +0 -14
  206. package/examples/basic-typescript-demo/src/good-practices.ts +0 -58
  207. package/examples/basic-typescript-demo/src/types.generated.ts +0 -13
  208. package/examples/basic-typescript-demo/src/user.test.ts +0 -19
  209. package/examples/basic-typescript-demo/src/violations.ts +0 -61
  210. package/examples/basic-typescript-demo/tsconfig.json +0 -27
  211. package/examples/eslint-integration-demo/.eslintrc.js +0 -38
  212. package/examples/eslint-integration-demo/.sunlint.json +0 -42
  213. package/examples/eslint-integration-demo/next-env.d.ts +0 -5
  214. package/examples/eslint-integration-demo/next.config.js +0 -8
  215. package/examples/eslint-integration-demo/package-lock.json +0 -5740
  216. package/examples/eslint-integration-demo/package.json +0 -37
  217. package/examples/eslint-integration-demo/src/api.test.ts +0 -20
  218. package/examples/eslint-integration-demo/src/conflict-test.tsx +0 -44
  219. package/examples/eslint-integration-demo/src/naming-conflicts.ts +0 -50
  220. package/examples/eslint-integration-demo/tsconfig.json +0 -26
  221. package/examples/file-targeting-demo/global.d.ts +0 -11
  222. package/examples/file-targeting-demo/jest.config.js +0 -8
  223. package/examples/file-targeting-demo/sample.ts +0 -53
  224. package/examples/file-targeting-demo/src/server.js +0 -11
  225. package/examples/file-targeting-demo/src/server.test.js +0 -11
  226. package/examples/file-targeting-demo/src/types.d.ts +0 -4
  227. package/examples/file-targeting-demo/src/types.generated.ts +0 -10
  228. package/examples/file-targeting-demo/user-service.test.ts +0 -15
  229. package/examples/file-targeting-demo/user-service.ts +0 -13
  230. package/examples/file-targeting-demo/utils.js +0 -15
  231. package/examples/multi-language-project/.eslintrc.json +0 -38
  232. package/examples/multi-language-project/package.json +0 -37
  233. package/examples/multi-language-project/src/sample.ts +0 -39
  234. package/examples/rule-test-fixtures/README.md +0 -67
  235. package/examples/rule-test-fixtures/rules/C006_function_naming/clean/typescript-clean.ts +0 -64
  236. package/examples/rule-test-fixtures/rules/C006_function_naming/violations/dart-violations.dart +0 -56
  237. package/examples/rule-test-fixtures/rules/C006_function_naming/violations/typescript-violations.ts +0 -47
  238. package/examples/rule-test-fixtures/rules/C019_log_level_usage/clean/typescript-clean.ts +0 -93
  239. package/examples/rule-test-fixtures/rules/C019_log_level_usage/violations/dart-violations.dart +0 -75
  240. package/examples/rule-test-fixtures/rules/C019_log_level_usage/violations/typescript-violations.ts +0 -84
  241. package/examples/rule-test-fixtures/rules/C029_catch_block_logging/violations/typescript-violations.ts +0 -37
  242. /package/config/{default.json → defaults/default.json} +0 -0
  243. /package/{eslint-integration/eslint.config.js → config/integrations/eslint/base.config.js} +0 -0
  244. /package/{eslint-integration/eslint.config.simple.js → config/integrations/eslint/simple.config.js} +0 -0
  245. /package/{examples/rule-test-fixtures/rules/C029_catch_block_logging/clean/typescript-clean.ts → config/schemas/sunlint-schema.json} +0 -0
  246. /package/config/{typescript → testing}/test-s005-working.ts +0 -0
  247. /package/{examples/eslint-integration-demo/test-file-targeting.sh → engines/tree-sitter-parser.js} +0 -0
  248. /package/{examples/enhanced-config.json → engines/universal-ast-engine.js} +0 -0
  249. /package/{eslint-integration → integrations/eslint}/package.json +0 -0
  250. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin}/package.json +0 -0
  251. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c002-no-duplicate-code.js +0 -0
  252. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c003-no-vague-abbreviations.js +0 -0
  253. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c010-limit-block-nesting.js +0 -0
  254. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c014-abstract-dependency-preferred.js +0 -0
  255. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c018-no-generic-throw.js +0 -0
  256. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c023-no-duplicate-variable-name-in-scope.js +0 -0
  257. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c030-use-custom-error-classes.js +0 -0
  258. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c042-boolean-name-prefix.js +0 -0
  259. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c043-no-console-or-print.js +0 -0
  260. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c047-no-duplicate-retry-logic.js +0 -0
  261. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s003-no-unvalidated-redirect.js +0 -0
  262. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
  263. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
  264. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
  265. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
  266. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
  267. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
  268. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
  269. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
  270. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
  271. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
  272. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
  273. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
  274. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
  275. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
  276. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
  277. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
  278. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
  279. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
  280. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
  281. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
  282. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
  283. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
  284. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
  285. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
  286. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
  287. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
  288. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
  289. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
  290. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
  291. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
  292. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
  293. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
  294. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
  295. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
  296. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s047-secure-random-passwords.js +0 -0
  297. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
  298. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
  299. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
  300. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
  301. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s055-verification-rest-check-the-incoming-content-type.js +0 -0
  302. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
  303. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +0 -0
  304. /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/typescript}/t002-interface-prefix-i.js +0 -0
  305. /package/{eslint-integration/eslint-plugin-custom/t019-no-empty-type.js → integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js} +0 -0
  306. /package/{eslint-integration/eslint-plugin-custom/t025-no-nested-union-tuple.js → integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js} +0 -0
  307. /package/{eslint-integration → integrations/eslint}/tsconfig.json +0 -0
  308. /package/rules/{C006_function_naming → common/C006_function_naming}/config.json +0 -0
  309. /package/rules/{C019_log_level_usage → common/C019_log_level_usage}/config.json +0 -0
  310. /package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/config.json +0 -0
  311. /package/rules/{C031_validation_separation → common/C031_validation_separation}/analyzer.js +0 -0
  312. /package/rules/{C031_validation_separation/README.md → docs/C031_validation_separation.md} +0 -0
  313. /package/{examples/basic-typescript-demo/test-file-targeting.sh → rules/universal/C010/generic.js} +0 -0
  314. /package/{examples/basic-typescript-demo/test-config-priority.sh → rules/universal/C010/tree-sitter-analyzer.js} +0 -0
@@ -0,0 +1,164 @@
1
+ /**
2
+ * SunLint ESLint Plugin - Organized Rules Index
3
+ * 🔹 22 Common Rules | 🔒 49 Security Rules | 📘 13 TypeScript Rules
4
+ */
5
+
6
+ // 🔹 Common Rules (C-series) - General coding standards
7
+ const c002 = require("./rules/common/c002-no-duplicate-code.js");
8
+ const c003 = require("./rules/common/c003-no-vague-abbreviations.js");
9
+ const c006 = require("./rules/common/c006-function-name-verb-noun.js");
10
+ const c010 = require("./rules/common/c010-limit-block-nesting.js");
11
+ const c013 = require("./rules/common/c013-no-dead-code.js");
12
+ const c014 = require("./rules/common/c014-abstract-dependency-preferred.js");
13
+ const c017 = require("./rules/common/c017-limit-constructor-logic.js");
14
+ const c018 = require("./rules/common/c018-no-generic-throw.js");
15
+ const c023 = require("./rules/common/c023-no-duplicate-variable-name-in-scope.js");
16
+ const c041 = require("./rules/common/c041-no-config-inline.js");
17
+ const c029 = require("./rules/common/c029-catch-block-logging.js");
18
+ const c030 = require("./rules/common/c030-use-custom-error-classes.js");
19
+ const c035 = require("./rules/common/c035-no-empty-catch.js");
20
+ const c042 = require("./rules/common/c042-boolean-name-prefix.js");
21
+ const c043 = require("./rules/common/c043-no-console-or-print.js");
22
+ const c047 = require("./rules/common/c047-no-duplicate-retry-logic.js");
23
+ const c072 = require("./rules/common/c072-one-assert-per-test.js");
24
+ const c075 = require("./rules/common/c075-explicit-function-return-types.js");
25
+ const c076 = require("./rules/common/c076-single-behavior-per-test.js");
26
+
27
+ // 📘 TypeScript Rules (T-series)
28
+ const t002 = require("./rules/typescript/t002-interface-prefix-i.js");
29
+ const t003 = require("./rules/typescript/t003-ts-ignore-reason.js");
30
+ const t004 = require("./rules/typescript/t004-no-empty-type.js");
31
+ const t007 = require("./rules/typescript/t007-no-fn-in-constructor.js");
32
+ const t010 = require("./rules/typescript/t010-no-nested-union-tuple.js");
33
+ const t019 = require("./rules/typescript/t019-no-this-assign.js");
34
+ const t020 = require("./rules/typescript/t020-no-default-multi-export.js");
35
+ const t021 = require("./rules/typescript/t021-limit-nested-generics.js");
36
+
37
+ // 🔒 Security Rules (S-series)
38
+ const s001 = require("./rules/security/s001-fail-securely.js");
39
+ const s002 = require("./rules/security/s002-idor-check.js");
40
+ const s003 = require("./rules/security/s003-no-unvalidated-redirect.js");
41
+ const s005 = require("./rules/security/s005-no-origin-auth.js");
42
+ const s006 = require("./rules/security/s006-activation-recovery-secret-not-plaintext.js");
43
+ const s007 = require("./rules/security/s007-no-plaintext-otp.js");
44
+ const s008 = require("./rules/security/s008-crypto-agility.js");
45
+ const s009 = require("./rules/security/s009-no-insecure-crypto.js");
46
+ const s010 = require("./rules/security/s010-no-insecure-random-in-sensitive-context.js");
47
+ const s011 = require("./rules/security/s011-no-insecure-uuid.js");
48
+ const s012 = require("./rules/security/s012-hardcode-secret.js");
49
+ const s013 = require("./rules/security/s013-verify-tls-connection.js");
50
+ const s014 = require("./rules/security/s014-insecure-tls-version.js");
51
+ const s015 = require("./rules/security/s015-insecure-tls-certificate.js");
52
+ const s016 = require("./rules/security/s016-sensitive-query-parameter.js");
53
+ const s017 = require("./rules/security/s017-no-sql-injection.js");
54
+ const s018 = require("./rules/security/s018-positive-input-validation.js");
55
+ const s019 = require("./rules/security/s019-no-raw-user-input-in-email.js");
56
+ const s020 = require("./rules/security/s020-no-eval-dynamic-execution.js");
57
+ const s022 = require("./rules/security/s022-output-encoding.js");
58
+ const s023 = require("./rules/security/s023-no-json-injection.js");
59
+ const s025 = require("./rules/security/s025-server-side-input-validation.js");
60
+ const s026 = require("./rules/security/s026-json-schema-validation.js");
61
+ const s027 = require("./rules/security/s027-no-hardcoded-secrets.js");
62
+ const s029 = require("./rules/security/s029-require-csrf-protection.js");
63
+ const s030 = require("./rules/security/s030-no-directory-browsing.js");
64
+ const s033 = require("./rules/security/s033-require-samesite-cookie.js");
65
+ const s034 = require("./rules/security/s034-require-host-cookie-prefix.js");
66
+ const s035 = require("./rules/security/s035-cookie-specific-path.js");
67
+ const s036 = require("./rules/security/s036-no-unsafe-file-include.js");
68
+ const s037 = require("./rules/security/s037-require-anti-cache-headers.js");
69
+ const s038 = require("./rules/security/s038-no-version-disclosure.js");
70
+ const s039 = require("./rules/security/s039-no-session-token-in-url.js");
71
+ const s041 = require("./rules/security/s041-require-session-invalidate-on-logout.js");
72
+ const s042 = require("./rules/security/s042-require-periodic-reauthentication.js");
73
+ const s043 = require("./rules/security/s043-terminate-sessions-on-password-change.js");
74
+ const s044 = require("./rules/security/s044-require-full-session-for-sensitive-operations.js");
75
+ const s045 = require("./rules/security/s045-anti-automation-controls.js");
76
+ const s046 = require("./rules/security/s046-secure-notification-on-auth-change.js");
77
+ const s047 = require("./rules/security/s047-secure-random-passwords.js");
78
+ const s048 = require("./rules/security/s048-password-credential-recovery.js");
79
+ const s050 = require("./rules/security/s050-session-token-weak-hash.js");
80
+ const s052 = require("./rules/security/s052-secure-random-authentication-code.js");
81
+ const s054 = require("./rules/security/s054-verification-default-account.js");
82
+ const s055 = require("./rules/security/s055-verification-rest-check-the-incoming-content-type.js");
83
+ const s057 = require("./rules/security/s057-utc-logging.js");
84
+ const s058 = require("./rules/security/s058-no-ssrf.js");
85
+
86
+ module.exports = {
87
+ rules: {
88
+ "c002": c002,
89
+ "c003": c003,
90
+ "c006": c006,
91
+ "c010": c010,
92
+ "c013": c013,
93
+ "c014": c014,
94
+ "c017": c017,
95
+ "c018": c018,
96
+ "c030": c030,
97
+ "c035": c035,
98
+ "c023": c023,
99
+ "c029": c029,
100
+ "c041": c041,
101
+ "c042": c042,
102
+ "c043": c043,
103
+ "c047": c047,
104
+ "c072": c072,
105
+ "c075": c075,
106
+ "c076": c076,
107
+ "t002": t002,
108
+ "t003": t003,
109
+ "t004": t004,
110
+ "t007": t007,
111
+ "t010": t010,
112
+ "t019": t019,
113
+ "t020": t020,
114
+ "t021": t021,
115
+ // Security rules
116
+ "typescript_s001": s001,
117
+ "typescript_s002": s002,
118
+ "typescript_s003": s003,
119
+ "typescript_s005": s005,
120
+ "typescript_s006": s006,
121
+ "typescript_s007": s007,
122
+ "typescript_s008": s008,
123
+ "typescript_s009": s009,
124
+ "typescript_s010": s010,
125
+ "typescript_s011": s011,
126
+ "typescript_s012": s012,
127
+ "typescript_s013": s013,
128
+ "typescript_s014": s014,
129
+ "typescript_s015": s015,
130
+ "typescript_s016": s016,
131
+ "typescript_s017": s017,
132
+ "typescript_s018": s018,
133
+ "typescript_s019": s019,
134
+ "typescript_s020": s020,
135
+ "typescript_s022": s022,
136
+ "typescript_s023": s023,
137
+ "typescript_s025": s025,
138
+ "typescript_s026": s026,
139
+ "typescript_s027": s027,
140
+ "typescript_s029": s029,
141
+ "typescript_s030": s030,
142
+ "typescript_s033": s033,
143
+ "typescript_s034": s034,
144
+ "typescript_s035": s035,
145
+ "typescript_s036": s036,
146
+ "typescript_s037": s037,
147
+ "typescript_s038": s038,
148
+ "typescript_s039": s039,
149
+ "typescript_s041": s041,
150
+ "typescript_s042": s042,
151
+ "typescript_s043": s043,
152
+ "typescript_s044": s044,
153
+ "typescript_s045": s045,
154
+ "typescript_s046": s046,
155
+ "typescript_s047": s047,
156
+ "typescript_s048": s048,
157
+ "typescript_s050": s050,
158
+ "typescript_s052": s052,
159
+ "typescript_s054": s054,
160
+ "typescript_s055": s055,
161
+ "typescript_s057": s057,
162
+ "typescript_s058": s058
163
+ }
164
+ };
@@ -56,9 +56,18 @@ const c006Rule = {
56
56
  'show', 'hide', 'display', 'render', 'draw', 'paint',
57
57
  'connect', 'disconnect', 'link', 'unlink', 'attach', 'detach',
58
58
  'enable', 'disable', 'activate', 'deactivate', 'toggle',
59
- 'is', 'has', 'can', 'should', 'will', 'must', 'may',
59
+ 'is', 'has', 'can', 'should', 'will', 'must', 'may', 'does',
60
60
  'handle', 'manage', 'control', 'execute', 'run', 'invoke',
61
- 'reset', 'clear', 'clean', 'refresh', 'reload', 'restore'
61
+ 'reset', 'clear', 'clean', 'refresh', 'reload', 'restore',
62
+
63
+ // Based on user feedback - missing important verbs
64
+ 'count', 'reopen', 'request', 'use', 'go', 'retry', 'redirect',
65
+
66
+ // Event handler prefixes
67
+ 'on',
68
+
69
+ // Common patterns that should be allowed as verbs
70
+ 'process', // can be both noun and verb - when standalone should be allowed
62
71
  ]);
63
72
 
64
73
  const allowedPrefixes = new Set([
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Custom ESLint rule for: C013 – Do not leave dead code commented out
3
+ * Rule ID: custom/c013
4
+ * Purpose: Prevent commented-out code from being left in the codebase to maintain cleanliness
5
+ */
6
+
7
+ module.exports = {
8
+ meta: {
9
+ type: "suggestion",
10
+ docs: {
11
+ description: "Do not leave dead code commented out",
12
+ recommended: false
13
+ },
14
+ schema: [],
15
+ messages: {
16
+ deadCode: "Unreachable code detected after return statement. Remove dead code or restructure logic.",
17
+ commentedCode: "Do not leave dead code commented out. Remove it or use version control to track changes."
18
+ }
19
+ },
20
+ create(context) {
21
+ function isTerminatingStatement(stmt) {
22
+ return stmt.type === "ReturnStatement" ||
23
+ stmt.type === "ThrowStatement" ||
24
+ stmt.type === "ContinueStatement" ||
25
+ stmt.type === "BreakStatement";
26
+ }
27
+
28
+ function isExecutableStatement(stmt) {
29
+ // Exclude declarations and empty statements
30
+ return stmt.type !== "EmptyStatement" &&
31
+ stmt.type !== "FunctionDeclaration" &&
32
+ stmt.type !== "VariableDeclaration" &&
33
+ !stmt.type.includes("Declaration");
34
+ }
35
+
36
+ function checkBlockForUnreachableCode(node) {
37
+ let unreachable = false;
38
+ for (let i = 0; i < node.body.length; i++) {
39
+ const stmt = node.body[i];
40
+
41
+ if (unreachable && isExecutableStatement(stmt)) {
42
+ context.report({
43
+ node: stmt,
44
+ messageId: "deadCode"
45
+ });
46
+ }
47
+
48
+ if (isTerminatingStatement(stmt)) {
49
+ unreachable = true;
50
+ }
51
+ }
52
+ }
53
+
54
+ return {
55
+ // Handle unreachable code in all block statements
56
+ BlockStatement: checkBlockForUnreachableCode,
57
+
58
+ // Handle switch cases
59
+ SwitchCase(node) {
60
+ let unreachable = false;
61
+ for (let i = 0; i < node.consequent.length; i++) {
62
+ const stmt = node.consequent[i];
63
+
64
+ if (unreachable && isExecutableStatement(stmt)) {
65
+ context.report({
66
+ node: stmt,
67
+ messageId: "deadCode"
68
+ });
69
+ }
70
+
71
+ if (isTerminatingStatement(stmt)) {
72
+ unreachable = true;
73
+ }
74
+ }
75
+ }
76
+ };
77
+ }
78
+ };
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Custom ESLint rule for: C017 – Limit constructor logic
3
+ * Rule ID: custom/c017
4
+ * Purpose: Enforce minimal logic in constructors to maintain clean initialization
5
+ */
6
+
7
+ module.exports = {
8
+ meta: {
9
+ type: "suggestion",
10
+ docs: {
11
+ description: "Limit constructor logic",
12
+ recommended: false
13
+ },
14
+ schema: [],
15
+ messages: {
16
+ constructorLogic: "Constructor contains complex logic: {{description}}. Move to initialization methods",
17
+ tooManyStatements: "Constructor has too many statements ({{count}}). Consider simplifying or moving logic to initialization methods"
18
+ }
19
+ },
20
+ create(context) {
21
+ function isSimpleAssignment(node) {
22
+ // Simple property assignments like this.prop = value
23
+ if (node.type === "ExpressionStatement" &&
24
+ node.expression.type === "AssignmentExpression" &&
25
+ node.expression.left.type === "MemberExpression" &&
26
+ node.expression.left.object.type === "ThisExpression") {
27
+
28
+ // Check if right side is a simple value (not complex computation)
29
+ const right = node.expression.right;
30
+ return right.type === "Literal" ||
31
+ right.type === "Identifier" ||
32
+ (right.type === "MemberExpression" && right.property.name === "length") ||
33
+ (right.type === "CallExpression" && right.callee.type === "Identifier" &&
34
+ ['require', 'process'].includes(right.callee.name));
35
+ }
36
+ return false;
37
+ }
38
+
39
+ function isSimpleDeclaration(node) {
40
+ // Simple variable declarations
41
+ return node.type === "VariableDeclaration";
42
+ }
43
+
44
+ function isSuperCall(node) {
45
+ // super() calls
46
+ return node.type === "ExpressionStatement" &&
47
+ node.expression.type === "CallExpression" &&
48
+ node.expression.callee.type === "Super";
49
+ }
50
+
51
+ function isComplexLogic(node) {
52
+ // Complex patterns that shouldn't be in constructor
53
+ switch (node.type) {
54
+ case "IfStatement":
55
+ case "WhileStatement":
56
+ case "ForStatement":
57
+ case "SwitchStatement":
58
+ case "TryStatement":
59
+ return { type: "control_flow", description: "control flow statements" };
60
+
61
+ case "ExpressionStatement":
62
+ if (node.expression.type === "CallExpression") {
63
+ const callee = node.expression.callee;
64
+
65
+ // Method calls that aren't simple setters
66
+ if (callee.type === "MemberExpression") {
67
+ const methodName = callee.property.name;
68
+
69
+ // Allow simple MobX observable setup
70
+ if (methodName === "makeObservable" || methodName === "makeAutoObservable") {
71
+ return null;
72
+ }
73
+
74
+ // Flag complex method calls
75
+ if (!['push', 'set', 'add'].includes(methodName)) {
76
+ return { type: "method_call", description: "complex method calls" };
77
+ }
78
+ }
79
+
80
+ // Direct function calls (not method calls)
81
+ if (callee.type === "Identifier" &&
82
+ !['require', 'parseInt', 'parseFloat', 'Boolean', 'Number', 'String'].includes(callee.name)) {
83
+ return { type: "function_call", description: "function calls" };
84
+ }
85
+ }
86
+
87
+ // Complex assignments with computations
88
+ if (node.expression.type === "AssignmentExpression") {
89
+ const right = node.expression.right;
90
+ if (right.type === "BinaryExpression" ||
91
+ right.type === "ConditionalExpression" ||
92
+ (right.type === "CallExpression" &&
93
+ right.callee.type === "MemberExpression" &&
94
+ !['map', 'filter', 'toString', 'slice'].includes(right.callee.property.name))) {
95
+ return { type: "complex_assignment", description: "complex computations" };
96
+ }
97
+ }
98
+ break;
99
+ }
100
+
101
+ return null;
102
+ }
103
+
104
+ return {
105
+ MethodDefinition(node) {
106
+ if (node.kind === "constructor" && node.value && node.value.body) {
107
+ const statements = node.value.body.body;
108
+ let complexLogicCount = 0;
109
+
110
+ for (const stmt of statements) {
111
+ // Skip simple assignments, declarations, and super calls
112
+ if (isSimpleAssignment(stmt) ||
113
+ isSimpleDeclaration(stmt) ||
114
+ isSuperCall(stmt)) {
115
+ continue;
116
+ }
117
+
118
+ // Check for complex logic
119
+ const complexity = isComplexLogic(stmt);
120
+ if (complexity) {
121
+ context.report({
122
+ node: stmt,
123
+ messageId: "constructorLogic",
124
+ data: {
125
+ description: complexity.description
126
+ }
127
+ });
128
+ complexLogicCount++;
129
+ }
130
+ }
131
+
132
+ // Also flag constructors with too many statements overall
133
+ if (statements.length > 10) {
134
+ context.report({
135
+ node: node,
136
+ messageId: "tooManyStatements",
137
+ data: {
138
+ count: statements.length
139
+ }
140
+ });
141
+ }
142
+ }
143
+ }
144
+ };
145
+ }
146
+ };
@@ -42,6 +42,41 @@ module.exports = {
42
42
  return true;
43
43
  }
44
44
 
45
+ // Check for test assertions (Jest patterns)
46
+ if (stmt.type === "ExpressionStatement" &&
47
+ stmt.expression.type === "CallExpression" &&
48
+ stmt.expression.callee &&
49
+ stmt.expression.callee.name === "expect") {
50
+ return true;
51
+ }
52
+
53
+ // Check for Redux thunk error handling patterns
54
+ if (stmt.type === "VariableDeclaration" &&
55
+ stmt.declarations.some(decl =>
56
+ decl.init &&
57
+ decl.init.type === "CallExpression" &&
58
+ decl.init.callee &&
59
+ decl.init.callee.name === "handleAxiosError")) {
60
+ return true;
61
+ }
62
+
63
+ // Check for return rejectWithValue
64
+ if (stmt.type === "ReturnStatement" &&
65
+ stmt.argument &&
66
+ stmt.argument.type === "CallExpression" &&
67
+ stmt.argument.callee &&
68
+ stmt.argument.callee.name === "rejectWithValue") {
69
+ return true;
70
+ }
71
+
72
+ // Check for dispatch calls (Redux patterns)
73
+ if (stmt.type === "ExpressionStatement" &&
74
+ stmt.expression.type === "CallExpression" &&
75
+ stmt.expression.callee &&
76
+ stmt.expression.callee.name === "dispatch") {
77
+ return true;
78
+ }
79
+
45
80
  // Check for console.log, console.error, console.warn
46
81
  if (stmt.type === "ExpressionStatement" &&
47
82
  stmt.expression.type === "CallExpression" &&
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Custom ESLint rule for: C035 – No empty catch blocks (without error handling or logging)
3
+ * Rule ID: custom/c035
4
+ * Purpose: Prevent silently swallowing errors in catch blocks without logging or handling them
5
+ * Note: Primarily intended for backend code. Frontend may handle errors through UI.
6
+ */
7
+
8
+ module.exports = {
9
+ meta: {
10
+ type: "problem",
11
+ docs: {
12
+ description: "No empty catch blocks (without error handling or logging)",
13
+ recommended: true
14
+ },
15
+ schema: [
16
+ {
17
+ type: "object",
18
+ properties: {
19
+ allowFrontend: {
20
+ type: "boolean",
21
+ default: true
22
+ },
23
+ allowIgnoredParams: {
24
+ type: "boolean",
25
+ default: true
26
+ }
27
+ },
28
+ additionalProperties: false
29
+ }
30
+ ],
31
+ messages: {
32
+ emptyCatch: "Empty catch blocks are not allowed. Errors should be logged or handled explicitly.",
33
+ emptyCatchBackend: "Backend code must log errors in catch blocks. Consider using console.error(), logger, or proper error handling."
34
+ }
35
+ },
36
+ create(context) {
37
+ const options = context.options[0] || {};
38
+ const allowFrontend = options.allowFrontend !== false;
39
+ const allowIgnoredParams = options.allowIgnoredParams !== false;
40
+
41
+ function isBackendFile(filename) {
42
+ // Heuristics to determine if it's a backend file
43
+ const backendPatterns = [
44
+ /server/i, /backend/i, /api/i, /service/i,
45
+ /controller/i, /model/i, /dao/i, /repository/i,
46
+ /middleware/i, /route/i, /endpoint/i
47
+ ];
48
+
49
+ return backendPatterns.some(pattern => pattern.test(filename));
50
+ }
51
+
52
+ function isFrontendFile(filename) {
53
+ // Heuristics to determine if it's a frontend file
54
+ const frontendPatterns = [
55
+ /component/i, /page/i, /screen/i, /view/i,
56
+ /ui/i, /frontend/i, /client/i, /app/i,
57
+ /hook/i, /context/i, /store/i, /reducer/i
58
+ ];
59
+
60
+ return frontendPatterns.some(pattern => pattern.test(filename));
61
+ }
62
+
63
+ function isIntentionallyIgnored(param) {
64
+ if (!param || !param.name) return false;
65
+
66
+ const ignoredPatterns = [
67
+ 'ignored', '_', '__', 'unused', 'ignore',
68
+ '_error', '_err', '_e', 'ignored_error'
69
+ ];
70
+
71
+ const paramName = param.name.toLowerCase();
72
+ return ignoredPatterns.some(pattern =>
73
+ paramName === pattern || paramName.includes('ignored')
74
+ );
75
+ }
76
+
77
+ function hasFrontendErrorHandling(body) {
78
+ // Check for common frontend error handling patterns
79
+ const bodyText = context.getSourceCode().getText(body);
80
+ const frontendPatterns = [
81
+ /show.*error/i, /display.*error/i, /toast/i, /alert/i,
82
+ /notification/i, /modal/i, /snackbar/i, /message/i,
83
+ /set.*error/i, /error.*state/i, /ui.*error/i
84
+ ];
85
+
86
+ return frontendPatterns.some(pattern => pattern.test(bodyText));
87
+ }
88
+
89
+ return {
90
+ CatchClause(node) {
91
+ const filename = context.getFilename();
92
+ const body = node.body && node.body.body;
93
+ const param = node.param;
94
+
95
+ // Allow intentionally ignored parameters
96
+ if (allowIgnoredParams && isIntentionallyIgnored(param)) {
97
+ return;
98
+ }
99
+
100
+ // Check if catch block is empty
101
+ if (!Array.isArray(body) || body.length === 0) {
102
+ const isBackend = isBackendFile(filename);
103
+ const isFrontend = isFrontendFile(filename);
104
+
105
+ // For backend files, always report
106
+ if (isBackend) {
107
+ context.report({
108
+ node,
109
+ messageId: "emptyCatchBackend"
110
+ });
111
+ return;
112
+ }
113
+
114
+ // For frontend files, be more lenient if option is set
115
+ if (isFrontend && allowFrontend) {
116
+ return; // Allow empty catch in frontend
117
+ }
118
+
119
+ // Default behavior for unclassified files
120
+ context.report({
121
+ node,
122
+ messageId: "emptyCatch"
123
+ });
124
+ return;
125
+ }
126
+
127
+ // Check for proper error handling in non-empty blocks
128
+ const hasLogging = body.some(statement => {
129
+ const text = context.getSourceCode().getText(statement);
130
+ return /console\.(error|warn|log)|logger\.|log\(|throw\s/i.test(text);
131
+ });
132
+
133
+ const isBackend = isBackendFile(filename);
134
+ const isFrontend = isFrontendFile(filename);
135
+
136
+ // Backend should have logging or re-throwing
137
+ if (isBackend && !hasLogging) {
138
+ // Check if there's at least some error handling
139
+ const hasAnyHandling = body.some(statement => {
140
+ const text = context.getSourceCode().getText(statement);
141
+ return /error|err|exception|fail/i.test(text);
142
+ });
143
+
144
+ if (!hasAnyHandling) {
145
+ context.report({
146
+ node,
147
+ messageId: "emptyCatchBackend"
148
+ });
149
+ }
150
+ }
151
+
152
+ // Frontend can handle through UI
153
+ if (isFrontend && allowFrontend) {
154
+ const hasFrontendHandling = hasFrontendErrorHandling(node.body);
155
+ if (hasLogging || hasFrontendHandling) {
156
+ return; // OK for frontend
157
+ }
158
+ }
159
+ }
160
+ };
161
+ }
162
+ };