@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
@@ -47,48 +47,59 @@ class FileTargetingService {
47
47
  */
48
48
  applyFiltering(files, config, cliOptions) {
49
49
  let filteredFiles = [...files];
50
+ const debug = cliOptions?.debug || false;
51
+
52
+ if (debug) console.log(`🔍 [DEBUG] applyFiltering: start with ${filteredFiles.length} files`);
53
+ if (debug) console.log(`🔍 [DEBUG] config.include:`, config.include);
54
+ if (debug) console.log(`🔍 [DEBUG] cliOptions.include:`, cliOptions.include);
50
55
 
51
56
  // 1. Apply config include patterns first (medium priority)
52
57
  if (config.include && config.include.length > 0) {
53
- filteredFiles = this.applyIncludePatterns(filteredFiles, config.include);
58
+ filteredFiles = this.applyIncludePatterns(filteredFiles, config.include, debug);
59
+ if (debug) console.log(`🔍 [DEBUG] After config include: ${filteredFiles.length} files`);
54
60
  }
55
61
 
56
62
  // 2. Apply CLI include overrides (highest priority - completely overrides config)
57
63
  if (cliOptions.include) {
58
64
  // CLI include completely replaces config include - start fresh from all files
59
- filteredFiles = this.applyIncludePatterns([...files], cliOptions.include);
65
+ filteredFiles = this.applyIncludePatterns([...files], cliOptions.include, debug);
60
66
  }
61
67
 
62
68
  // 3. Apply config exclude patterns
63
69
  if (config.exclude && config.exclude.length > 0) {
64
- filteredFiles = this.applyExcludePatterns(filteredFiles, config.exclude);
70
+ if (debug) console.log(`🔍 [DEBUG] About to apply config exclude patterns: ${config.exclude}`);
71
+ if (debug) console.log(`🔍 [DEBUG] Files before config exclude: ${filteredFiles.length}`);
72
+ filteredFiles = this.applyExcludePatterns(filteredFiles, config.exclude, debug);
73
+ if (debug) console.log(`🔍 [DEBUG] Files after config exclude: ${filteredFiles.length}`);
65
74
  }
66
75
 
67
76
  // 4. Apply CLI exclude overrides (highest priority)
68
77
  if (cliOptions.exclude) {
69
- filteredFiles = this.applyExcludePatterns(filteredFiles, cliOptions.exclude);
78
+ if (debug) console.log(`🔍 [DEBUG] About to apply CLI exclude patterns: ${cliOptions.exclude}`);
79
+ if (debug) console.log(`🔍 [DEBUG] Files before CLI exclude: ${filteredFiles.length}`);
80
+ filteredFiles = this.applyExcludePatterns(filteredFiles, cliOptions.exclude, debug);
81
+ if (debug) console.log(`🔍 [DEBUG] Files after CLI exclude: ${filteredFiles.length}`);
70
82
  }
71
83
 
72
84
  // 5. Apply language-specific filtering
73
85
  if (cliOptions.languages || config.languages) {
74
- filteredFiles = this.applyLanguageFiltering(filteredFiles, config, cliOptions);
75
- }
76
-
77
- // 6. Apply legacy ignorePatterns (backward compatibility)
78
- if (config.ignorePatterns && config.ignorePatterns.length > 0) {
79
- filteredFiles = this.applyExcludePatterns(filteredFiles, config.ignorePatterns);
86
+ filteredFiles = this.applyLanguageFiltering(filteredFiles, config, cliOptions, debug);
87
+ if (debug) console.log(`🔍 [DEBUG] After language filtering: ${filteredFiles.length} files`);
80
88
  }
81
89
 
82
- // 7. Apply only-source filtering (exclude tests, configs, etc.)
90
+ // 6. Apply only-source filtering (exclude tests, configs, etc.)
83
91
  if (cliOptions.onlySource) {
84
92
  filteredFiles = this.applyOnlySourceFiltering(filteredFiles);
93
+ if (debug) console.log(`🔍 [DEBUG] After onlySource filtering: ${filteredFiles.length} files`);
85
94
  } else {
86
95
  // 8. Handle test files normally
87
96
  if (config.testPatterns) {
88
97
  filteredFiles = this.handleTestFiles(filteredFiles, config.testPatterns, cliOptions, config);
98
+ if (debug) console.log(`🔍 [DEBUG] After test files handling: ${filteredFiles.length} files`);
89
99
  }
90
100
  }
91
101
 
102
+ if (debug) console.log(`🔍 [DEBUG] Final filtered files: ${filteredFiles.length}`);
92
103
  return filteredFiles;
93
104
  }
94
105
 
@@ -96,7 +107,11 @@ class FileTargetingService {
96
107
  * Apply language-specific filtering
97
108
  * Rule C005: Single responsibility - language filtering only
98
109
  */
99
- applyLanguageFiltering(files, config, cliOptions) {
110
+ applyLanguageFiltering(files, config, cliOptions, debug = false) {
111
+ if (debug) console.log(`🔍 [DEBUG] === applyLanguageFiltering ENTRY ===`);
112
+ if (debug) console.log(`🔍 [DEBUG] Input files.length: ${files.length}`);
113
+ if (debug) console.log(`🔍 [DEBUG] Sample input files:`, files.slice(0, 3));
114
+
100
115
  // Determine target languages from CLI or config
101
116
  let targetLanguages;
102
117
  if (cliOptions.languages) {
@@ -107,78 +122,118 @@ class FileTargetingService {
107
122
  targetLanguages = Object.keys(config.languages || {});
108
123
  }
109
124
 
125
+ if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: cliOptions.languages = ${cliOptions.languages}`);
126
+ if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: config.languages =`, config.languages);
127
+ if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: targetLanguages =`, targetLanguages);
128
+
110
129
  if (targetLanguages.length === 0) {
130
+ if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: No language filtering, returning all files`);
111
131
  return files; // No language filtering
112
132
  }
113
133
 
114
134
  let languageFiles = [];
115
135
 
116
136
  for (const language of targetLanguages) {
137
+ if (debug) console.log(`🔍 [DEBUG] Processing language: ${language}`);
117
138
  if (Array.isArray(config.languages)) {
118
139
  // New array format - use isLanguageFile method
119
140
  const langFiles = files.filter(file => this.isLanguageFile(file, language));
120
141
  languageFiles.push(...langFiles);
142
+ if (debug) console.log(`🔍 [DEBUG] Array format - found ${langFiles.length} files for ${language}`);
121
143
  } else {
122
144
  // Legacy object format - use include/exclude patterns
123
145
  const langConfig = config.languages[language];
124
- if (!langConfig) continue;
146
+ if (!langConfig) {
147
+ if (debug) console.log(`🔍 [DEBUG] No config for language: ${language}`);
148
+ continue;
149
+ }
125
150
 
126
151
  let langFiles = [...files];
152
+ if (debug) console.log(`🔍 [DEBUG] Starting with ${langFiles.length} files for ${language}`);
127
153
 
128
154
  // Apply language-specific include patterns
129
155
  if (langConfig.include && langConfig.include.length > 0) {
130
- langFiles = this.applyIncludePatterns(langFiles, langConfig.include);
156
+ langFiles = this.applyIncludePatterns(langFiles, langConfig.include, debug);
157
+ if (debug) console.log(`🔍 [DEBUG] After include patterns ${langConfig.include}: ${langFiles.length} files`);
131
158
  }
132
159
 
133
160
  // Apply language-specific exclude patterns
134
161
  if (langConfig.exclude && langConfig.exclude.length > 0) {
135
- langFiles = this.applyExcludePatterns(langFiles, langConfig.exclude);
162
+ langFiles = this.applyExcludePatterns(langFiles, langConfig.exclude, debug);
163
+ if (debug) console.log(`🔍 [DEBUG] After exclude patterns ${langConfig.exclude}: ${langFiles.length} files`);
136
164
  }
137
165
 
138
166
  languageFiles.push(...langFiles);
167
+ if (debug) console.log(`🔍 [DEBUG] Added ${langFiles.length} files for ${language}, total: ${languageFiles.length}`);
139
168
  }
140
169
  }
141
170
 
142
171
  // Remove duplicates
143
- return [...new Set(languageFiles)];
172
+ const finalFiles = [...new Set(languageFiles)];
173
+ if (debug) console.log(`🔍 [DEBUG] Final language files after dedup: ${finalFiles.length}`);
174
+ return finalFiles;
144
175
  }
145
176
 
146
177
  /**
147
178
  * Apply include patterns using minimatch
148
179
  * Rule C006: applyIncludePatterns - verb-noun naming
149
180
  */
150
- applyIncludePatterns(files, patterns) {
181
+ applyIncludePatterns(files, patterns, debug = false) {
151
182
  if (!patterns) return files;
152
183
 
153
184
  // Normalize patterns to array
154
185
  const patternArray = Array.isArray(patterns) ? patterns : [patterns];
155
186
  if (patternArray.length === 0) return files;
156
187
 
157
- return files.filter(file => {
188
+ if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - input files:`, files.length);
189
+ if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - patterns:`, patternArray);
190
+ if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - sample input files:`, files.slice(0, 3));
191
+
192
+ const result = files.filter(file => {
158
193
  return patternArray.some(pattern => {
159
194
  const normalizedFile = this.normalizePath(file);
160
- return minimatch(normalizedFile, pattern, { dot: true });
195
+ const match = minimatch(normalizedFile, pattern, { dot: true });
196
+ if (debug && file.includes('.ts') && !file.includes('.test.')) {
197
+ console.log(`🔍 [DEBUG] Testing: '${file}' -> '${normalizedFile}' vs '${pattern}' = ${match}`);
198
+ }
199
+ return match;
161
200
  });
162
201
  });
202
+
203
+ if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - result:`, result.length);
204
+ return result;
163
205
  }
164
206
 
165
207
  /**
166
208
  * Apply exclude patterns using minimatch
167
209
  * Rule C006: applyExcludePatterns - verb-noun naming
168
210
  */
169
- applyExcludePatterns(files, patterns) {
211
+ applyExcludePatterns(files, patterns, debug = false) {
170
212
  if (!patterns) return files;
171
213
 
172
214
  // Normalize patterns to array
173
215
  const patternArray = Array.isArray(patterns) ? patterns : [patterns];
174
216
  if (patternArray.length === 0) return files;
175
217
 
176
- return files.filter(file => {
177
- return !patternArray.some(pattern => {
218
+ // Filter out negation patterns (starting with !) - these should not be in exclude patterns
219
+ const excludePatterns = patternArray.filter(pattern => !pattern.startsWith('!'));
220
+
221
+ if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - input files: ${files.length}`);
222
+ if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - original patterns:`, patternArray);
223
+ if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - filtered patterns:`, excludePatterns);
224
+
225
+ if (excludePatterns.length === 0) return files;
226
+
227
+ const result = files.filter(file => {
228
+ return !excludePatterns.some(pattern => {
178
229
  const normalizedFile = this.normalizePath(file);
179
- return minimatch(normalizedFile, pattern, { dot: true });
230
+ const match = minimatch(normalizedFile, pattern, { dot: true });
231
+ return match;
180
232
  });
181
233
  });
234
+
235
+ if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - result: ${result.length}`);
236
+ return result;
182
237
  }
183
238
 
184
239
  /**
@@ -213,13 +268,22 @@ class FileTargetingService {
213
268
  */
214
269
  async collectFiles(inputPath) {
215
270
  const files = [];
216
- const stats = fs.statSync(inputPath);
271
+
272
+ try {
273
+ const stats = fs.statSync(inputPath);
217
274
 
218
- if (stats.isFile()) {
219
- files.push(path.resolve(inputPath));
220
- } else if (stats.isDirectory()) {
221
- const dirFiles = await this.collectFilesFromDirectory(inputPath);
222
- files.push(...dirFiles);
275
+ if (stats.isFile()) {
276
+ files.push(path.resolve(inputPath));
277
+ } else if (stats.isDirectory()) {
278
+ const dirFiles = await this.collectFilesFromDirectory(inputPath);
279
+ files.push(...dirFiles);
280
+ }
281
+ } catch (error) {
282
+ if (error.code === 'ENOENT') {
283
+ console.warn(`⚠️ Path not found: ${inputPath}`);
284
+ return files; // Return empty array instead of throwing
285
+ }
286
+ throw error; // Re-throw other errors
223
287
  }
224
288
 
225
289
  return files;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Analysis Engine Interface
3
+ * Following Rule C014: Dependency Injection interface
4
+ * Following Rule C015: Use domain language - clear interface naming
5
+ */
6
+
7
+ class AnalysisEngineInterface {
8
+ /**
9
+ * Constructor for Analysis Engine
10
+ * @param {string} id - Engine ID (e.g., 'eslint', 'heuristic', 'openai')
11
+ * @param {string} version - Engine version
12
+ * @param {string[]} supportedLanguages - Array of supported languages
13
+ */
14
+ constructor(id, version, supportedLanguages = []) {
15
+ this.id = id;
16
+ this.version = version;
17
+ this.supportedLanguages = supportedLanguages;
18
+ this.initialized = false;
19
+ }
20
+
21
+ /**
22
+ * Initialize the analysis engine
23
+ * Following Rule C006: Verb-noun naming
24
+ * @param {Object} config - Engine-specific configuration
25
+ * @returns {Promise<void>}
26
+ */
27
+ async initialize(config) {
28
+ throw new Error(`Method initialize() must be implemented by ${this.constructor.name}`);
29
+ }
30
+
31
+ /**
32
+ * Analyze files with given rules
33
+ * Following Rule C006: Verb-noun naming
34
+ * @param {string[]} files - Array of file paths to analyze
35
+ * @param {Object[]} rules - Array of rule objects to apply
36
+ * @param {Object} options - Analysis options
37
+ * @returns {Promise<Object>} Analysis results
38
+ */
39
+ async analyze(files, rules, options) {
40
+ throw new Error(`Method analyze() must be implemented by ${this.constructor.name}`);
41
+ }
42
+
43
+ /**
44
+ * Get supported rules for this engine
45
+ * Following Rule C006: Verb-noun naming
46
+ * @returns {string[]} Array of supported rule IDs
47
+ */
48
+ getSupportedRules() {
49
+ throw new Error(`Method getSupportedRules() must be implemented by ${this.constructor.name}`);
50
+ }
51
+
52
+ /**
53
+ * Check if a specific rule is supported
54
+ * Following Rule C006: Verb-noun naming
55
+ * @param {string} ruleId - Rule ID to check
56
+ * @returns {boolean} True if rule is supported
57
+ */
58
+ isRuleSupported(ruleId) {
59
+ return this.getSupportedRules().includes(ruleId);
60
+ }
61
+
62
+ /**
63
+ * Check if a language is supported
64
+ * Following Rule C006: Verb-noun naming
65
+ * @param {string} language - Language to check
66
+ * @returns {boolean} True if language is supported
67
+ */
68
+ isLanguageSupported(language) {
69
+ return this.supportedLanguages.includes(language) ||
70
+ this.supportedLanguages.includes('all') ||
71
+ this.supportedLanguages.length === 0;
72
+ }
73
+
74
+ /**
75
+ * Get engine metadata
76
+ * Following Rule C006: Verb-noun naming
77
+ * @returns {Object} Engine metadata
78
+ */
79
+ getEngineInfo() {
80
+ return {
81
+ name: this.name,
82
+ version: this.version,
83
+ supportedLanguages: this.supportedLanguages,
84
+ supportedRules: this.getSupportedRules(),
85
+ initialized: this.initialized
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Cleanup engine resources
91
+ * Following Rule C006: Verb-noun naming
92
+ * @returns {Promise<void>}
93
+ */
94
+ async cleanup() {
95
+ // Default implementation - engines can override if needed
96
+ this.initialized = false;
97
+ }
98
+ }
99
+
100
+ module.exports = AnalysisEngineInterface;
@@ -1,221 +0,0 @@
1
- const path = require('path');
2
- const fs = require('fs');
3
- const glob = require('glob');
4
- const chalk = require('chalk');
5
- const FileTargetingService = require('./file-targeting-service');
6
-
7
- class MultiRuleRunner {
8
- constructor(config, options) {
9
- this.config = config;
10
- this.options = options;
11
- this.ruleCache = new Map();
12
- this.fileTargetingService = new FileTargetingService();
13
- }
14
-
15
- async runRules(rules, inputPath, options) {
16
- console.log(chalk.blue(`🔄 Analyzing ${rules.length} rules...`));
17
-
18
- // Get files to analyze
19
- const files = await this.getFilesToAnalyze(inputPath, options);
20
-
21
- console.log(chalk.gray(`📁 Found ${files ? files.length : 'undefined'} files to analyze`));
22
-
23
- if (!files || files.length === 0) {
24
- console.log(chalk.yellow('⚠️ No files found to analyze'));
25
- return [];
26
- }
27
-
28
- // Group files by language
29
- const filesByLanguage = this.groupFilesByLanguage(files);
30
-
31
- // Run rules in parallel (with concurrency limit)
32
- const maxConcurrent = parseInt(options.maxConcurrent) || 5;
33
- const timeout = parseInt(options.timeout) || 30000;
34
-
35
- const results = [];
36
-
37
- // Process rules in batches
38
- for (let i = 0; i < rules.length; i += maxConcurrent) {
39
- const batch = rules.slice(i, i + maxConcurrent);
40
-
41
- const batchPromises = batch.map(async (rule) => {
42
- try {
43
- return await this.runSingleRule(rule, filesByLanguage, options, timeout);
44
- } catch (error) {
45
- console.error(chalk.red(`❌ Rule ${rule.id} failed:`), error.message);
46
- return {
47
- ruleId: rule.id,
48
- ruleName: rule.name,
49
- violations: [],
50
- error: error.message,
51
- status: 'failed'
52
- };
53
- }
54
- });
55
-
56
- const batchResults = await Promise.all(batchPromises);
57
- results.push(...batchResults);
58
-
59
- if (options.verbose) {
60
- console.log(chalk.gray(`✅ Completed batch ${Math.floor(i/maxConcurrent) + 1}/${Math.ceil(rules.length/maxConcurrent)}`));
61
- }
62
- }
63
-
64
- return this.consolidateResults(results, files.length);
65
- }
66
-
67
- async runSingleRule(rule, filesByLanguage, options, timeout) {
68
- if (options.verbose) {
69
- console.log(chalk.gray(`🔍 Running rule ${rule.id}: ${rule.name}`));
70
- }
71
-
72
- const startTime = Date.now();
73
-
74
- // Load rule analyzer
75
- const analyzer = await this.loadRuleAnalyzer(rule);
76
-
77
- if (!analyzer) {
78
- return {
79
- ruleId: rule.id,
80
- ruleName: rule.name,
81
- violations: [],
82
- error: 'Analyzer not found',
83
- status: 'skipped'
84
- };
85
- }
86
-
87
- const violations = [];
88
-
89
- // Run analyzer for each supported language
90
- for (const language of rule.languages) {
91
- const languageFiles = filesByLanguage[language] || [];
92
-
93
- if (languageFiles.length === 0) {
94
- continue;
95
- }
96
-
97
- try {
98
- // Run with timeout
99
- const languageViolations = await Promise.race([
100
- analyzer.analyze(languageFiles, language, this.config),
101
- new Promise((_, reject) =>
102
- setTimeout(() => reject(new Error('Timeout')), timeout)
103
- )
104
- ]);
105
-
106
- violations.push(...languageViolations);
107
- } catch (error) {
108
- console.error(chalk.yellow(`⚠️ Rule ${rule.id} failed for ${language}:`), error.message);
109
- }
110
- }
111
-
112
- const duration = Date.now() - startTime;
113
-
114
- return {
115
- ruleId: rule.id,
116
- ruleName: rule.name,
117
- category: rule.category,
118
- severity: rule.severity,
119
- violations,
120
- filesAnalyzed: Object.values(filesByLanguage).flat().length,
121
- duration,
122
- status: 'completed'
123
- };
124
- }
125
-
126
- async loadRuleAnalyzer(rule) {
127
- // Check cache first
128
- if (this.ruleCache.has(rule.id)) {
129
- return this.ruleCache.get(rule.id);
130
- }
131
-
132
- try {
133
- const analyzerPath = path.resolve(__dirname, '..', rule.analyzer);
134
-
135
- if (!fs.existsSync(analyzerPath)) {
136
- console.error(chalk.yellow(`⚠️ Analyzer not found for rule ${rule.id}: ${analyzerPath}`));
137
- return null;
138
- }
139
-
140
- const analyzer = require(analyzerPath);
141
- this.ruleCache.set(rule.id, analyzer);
142
- return analyzer;
143
- } catch (error) {
144
- console.error(chalk.red(`❌ Failed to load analyzer for rule ${rule.id}:`), error.message);
145
- return null;
146
- }
147
- }
148
-
149
- async getFilesToAnalyze(inputPath, options) {
150
- // Use centralized file targeting service - convert single path to array
151
- const inputPaths = Array.isArray(inputPath) ? inputPath : [inputPath];
152
- const result = await this.fileTargetingService.getTargetFiles(inputPaths, this.config, options);
153
- return result.files; // Extract files array from result object
154
- }
155
-
156
- groupFilesByLanguage(files) {
157
- const rulesRegistry = require('../config/rules-registry.json');
158
- const languageConfig = rulesRegistry.languages;
159
-
160
- const filesByLanguage = {};
161
-
162
- files.forEach(file => {
163
- const ext = path.extname(file);
164
-
165
- for (const [language, config] of Object.entries(languageConfig)) {
166
- if (config.extensions.includes(ext)) {
167
- if (!filesByLanguage[language]) {
168
- filesByLanguage[language] = [];
169
- }
170
- filesByLanguage[language].push(file);
171
- break; // File belongs to first matching language
172
- }
173
- }
174
- });
175
-
176
- return filesByLanguage;
177
- }
178
-
179
- consolidateResults(results, totalFiles) {
180
- const consolidatedResults = {
181
- filesAnalyzed: totalFiles,
182
- rulesRun: results.length,
183
- totalViolations: 0,
184
- violationsBySeverity: { error: 0, warning: 0, info: 0 },
185
- violationsByRule: {},
186
- violationsByFile: {},
187
- results: []
188
- };
189
-
190
- results.forEach(result => {
191
- consolidatedResults.results.push(result);
192
-
193
- if (result.violations) {
194
- consolidatedResults.totalViolations += result.violations.length;
195
-
196
- // Count by severity
197
- result.violations.forEach(violation => {
198
- const severity = violation.severity || result.severity || 'warning';
199
- consolidatedResults.violationsBySeverity[severity] =
200
- (consolidatedResults.violationsBySeverity[severity] || 0) + 1;
201
- });
202
-
203
- // Count by rule
204
- consolidatedResults.violationsByRule[result.ruleId] = result.violations.length;
205
-
206
- // Count by file
207
- result.violations.forEach(violation => {
208
- const file = violation.file || violation.filePath;
209
- if (file) {
210
- consolidatedResults.violationsByFile[file] =
211
- (consolidatedResults.violationsByFile[file] || 0) + 1;
212
- }
213
- });
214
- }
215
- });
216
-
217
- return consolidatedResults;
218
- }
219
- }
220
-
221
- module.exports = MultiRuleRunner;
@@ -35,7 +35,7 @@ class OutputService {
35
35
 
36
36
  generateReport(results, metadata, options = {}) {
37
37
  const allViolations = [];
38
- let totalFiles = results.filesAnalyzed || results.totalFiles || results.fileCount || 0;
38
+ let totalFiles = results.filesAnalyzed || results.summary?.totalFiles || results.totalFiles || results.fileCount || 0;
39
39
 
40
40
  // Collect all violations - handle both file-based and rule-based results
41
41
  if (results.results) {
@@ -16,7 +16,7 @@ class RuleMappingService {
16
16
  */
17
17
  createEslintToSunlintMapping() {
18
18
  return {
19
- // Custom rules mapping (using actual rule IDs from eslint-plugin-custom)
19
+ // Custom rules mapping (using actual rule IDs from integrations/eslint/plugin/rules)
20
20
  'custom/c002': 'C002',
21
21
  'custom/c003': 'C003',
22
22
  'custom/c006': 'C006',
@@ -50,14 +50,18 @@ class RuleMappingService {
50
50
  'custom/no-console-error': 'C019',
51
51
 
52
52
  // Security rules mapping
53
+ 'custom/typescript_s001': 'S001',
54
+ 'custom/typescript_s002': 'S002',
53
55
  'custom/typescript_s003': 'S003',
54
56
  'custom/typescript_s005': 'S005',
55
57
  'custom/typescript_s006': 'S006',
58
+ 'custom/typescript_s007': 'S007',
56
59
  'custom/typescript_s008': 'S008',
57
60
  'custom/typescript_s009': 'S009',
58
61
  'custom/typescript_s010': 'S010',
59
62
  'custom/typescript_s011': 'S011',
60
63
  'custom/typescript_s012': 'S012',
64
+ 'custom/typescript_s013': 'S013',
61
65
  'custom/typescript_s014': 'S014',
62
66
  'custom/typescript_s015': 'S015',
63
67
  'custom/typescript_s016': 'S016',
@@ -173,13 +177,17 @@ class RuleMappingService {
173
177
  mapping['C076'] = ['custom/c076']; // One assert per test
174
178
 
175
179
  // Security rules mapping
180
+ mapping['S001'] = ['custom/typescript_s001']; // Fail securely
181
+ mapping['S002'] = ['custom/typescript_s002']; // IDOR check
176
182
  mapping['S005'] = ['custom/typescript_s005']; // No Origin header auth
177
183
  mapping['S006'] = ['custom/typescript_s006']; // Activation recovery secret
184
+ mapping['S007'] = ['custom/typescript_s007']; // No plaintext OTP
178
185
  mapping['S008'] = ['custom/typescript_s008']; // Crypto agility
179
186
  mapping['S009'] = ['custom/typescript_s009']; // No insecure crypto
180
187
  mapping['S010'] = ['custom/typescript_s010']; // No insecure random
181
188
  mapping['S011'] = ['custom/typescript_s011']; // No insecure UUID
182
189
  mapping['S012'] = ['custom/typescript_s012']; // No hardcoded secrets
190
+ mapping['S013'] = ['custom/typescript_s013']; // Verify TLS connection
183
191
  mapping['S014'] = ['custom/typescript_s014']; // Insecure TLS version
184
192
  mapping['S015'] = ['custom/typescript_s015']; // Insecure TLS certificate
185
193
  mapping['S016'] = ['custom/typescript_s016']; // Sensitive query parameter
@@ -15,7 +15,7 @@ class RuleSelectionService {
15
15
  async selectRules(config, options) {
16
16
  // Load rules registry
17
17
  try {
18
- this.rulesRegistry = require('../config/rules-registry.json');
18
+ this.rulesRegistry = require('../config/rules/rules-registry.json');
19
19
  } catch (error) {
20
20
  console.log(chalk.yellow('⚠️ Rules registry not found, using minimal rule set'));
21
21
  this.rulesRegistry = this.getMinimalRuleSet();
@@ -40,6 +40,14 @@ class RuleSelectionService {
40
40
  if (options.verbose) {
41
41
  console.log(chalk.blue(`📋 Found ${selectedRules.length} total rules (${registryRules.length} registry + ${eslintSupportedRules.length} ESLint)`));
42
42
  }
43
+ } else if (options.quality) {
44
+ // Handle --quality shortcut
45
+ const categoryRules = this.getRulesByCategory('quality');
46
+ selectedRules = categoryRules;
47
+ } else if (options.security) {
48
+ // Handle --security shortcut
49
+ const categoryRules = this.getRulesByCategory('security');
50
+ selectedRules = categoryRules;
43
51
  } else if (options.category) {
44
52
  const categoryRules = this.getRulesByCategory(options.category);
45
53
  selectedRules = categoryRules;
@@ -96,7 +104,7 @@ class RuleSelectionService {
96
104
  'C043', 'C047', 'C048', 'C076', 'T002', 'T003', 'T004', 'T007', 'T011',
97
105
  'T019', 'T025', 'T026'
98
106
  ],
99
- 'security': ['S003', 'S005', 'S006', 'S008', 'S009', 'S010', 'S011', 'S012', 'S014', 'S015', 'S016', 'S017', 'S018', 'S019', 'S020', 'S022', 'S023', 'S025', 'S026', 'S027', 'S029', 'S030', 'S033', 'S034', 'S035', 'S036', 'S037', 'S038', 'S039', 'S041', 'S042', 'S043', 'S044', 'S045', 'S046', 'S047', 'S048', 'S050', 'S052', 'S054', 'S055', 'S057', 'S058'],
107
+ 'security': ['S001', 'S002', 'S003', 'S005', 'S006', 'S007', 'S008', 'S009', 'S010', 'S011', 'S012', 'S013', 'S014', 'S015', 'S016', 'S017', 'S018', 'S019', 'S020', 'S022', 'S023', 'S025', 'S026', 'S027', 'S029', 'S030', 'S033', 'S034', 'S035', 'S036', 'S037', 'S038', 'S039', 'S041', 'S042', 'S043', 'S044', 'S045', 'S046', 'S047', 'S048', 'S050', 'S052', 'S054', 'S055', 'S057', 'S058'],
100
108
  'naming': ['C006'],
101
109
  'logging': ['C019', 'S057'],
102
110
  'validation': ['C031', 'S018', 'S025', 'S026']