@sun-asterisk/sunlint 1.0.7 → 1.1.4

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 (219) hide show
  1. package/.sunlint.json +35 -0
  2. package/CHANGELOG.md +30 -3
  3. package/CONTRIBUTING.md +235 -0
  4. package/PROJECT_STRUCTURE.md +60 -0
  5. package/README.md +146 -58
  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/integrations/eslint/base.config.js +125 -0
  13. package/config/integrations/eslint/simple.config.js +24 -0
  14. package/config/presets/strict.json +0 -1
  15. package/config/rule-analysis-strategies.js +74 -0
  16. package/config/{rules-registry.json → rules/rules-registry.json} +30 -7
  17. package/core/analysis-orchestrator.js +383 -591
  18. package/core/ast-modules/README.md +103 -0
  19. package/core/ast-modules/base-parser.js +90 -0
  20. package/core/ast-modules/index.js +97 -0
  21. package/core/ast-modules/package.json +37 -0
  22. package/core/ast-modules/parsers/eslint-js-parser.js +153 -0
  23. package/core/ast-modules/parsers/eslint-ts-parser.js +98 -0
  24. package/core/ast-modules/parsers/javascript-parser.js +187 -0
  25. package/core/ast-modules/parsers/typescript-parser.js +187 -0
  26. package/core/cli-action-handler.js +271 -255
  27. package/core/cli-program.js +18 -4
  28. package/core/config-manager.js +9 -3
  29. package/core/config-merger.js +40 -1
  30. package/core/config-validator.js +2 -2
  31. package/core/dependency-checker.js +125 -0
  32. package/core/enhanced-rules-registry.js +331 -0
  33. package/core/file-targeting-service.js +92 -23
  34. package/core/interfaces/analysis-engine.interface.js +100 -0
  35. package/core/multi-rule-runner.js +0 -221
  36. package/core/output-service.js +1 -1
  37. package/core/rule-mapping-service.js +1 -1
  38. package/core/rule-selection-service.js +10 -2
  39. package/core/smart-installer.js +164 -0
  40. package/docs/AI.md +163 -0
  41. package/docs/ARCHITECTURE.md +78 -0
  42. package/docs/CI-CD-GUIDE.md +315 -0
  43. package/docs/COMMAND-EXAMPLES.md +256 -0
  44. package/docs/CONFIGURATION.md +414 -0
  45. package/docs/DEBUG.md +86 -0
  46. package/docs/DEPENDENCIES.md +90 -0
  47. package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
  48. package/docs/DISTRIBUTION.md +153 -0
  49. package/docs/ESLINT-INTEGRATION-STRATEGY.md +392 -0
  50. package/docs/ESLINT_INTEGRATION.md +238 -0
  51. package/docs/FOLDER_STRUCTURE.md +59 -0
  52. package/docs/FUTURE_PACKAGES.md +83 -0
  53. package/docs/HEURISTIC_VS_AI.md +113 -0
  54. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +112 -0
  55. package/docs/PRODUCTION_SIZE_IMPACT.md +183 -0
  56. package/docs/README.md +32 -0
  57. package/docs/RELEASE_GUIDE.md +230 -0
  58. package/engines/eslint-engine.js +610 -0
  59. package/engines/heuristic-engine.js +864 -0
  60. package/engines/openai-engine.js +374 -0
  61. package/engines/tree-sitter-parser.js +0 -0
  62. package/engines/universal-ast-engine.js +0 -0
  63. package/integrations/eslint/README.md +99 -0
  64. package/integrations/eslint/configs/.eslintrc.js +98 -0
  65. package/integrations/eslint/configs/eslint.config.js +133 -0
  66. package/integrations/eslint/configs/eslint.config.simple.js +24 -0
  67. package/integrations/eslint/package.json +23 -0
  68. package/integrations/eslint/plugin/index.js +164 -0
  69. package/integrations/eslint/plugin/package.json +13 -0
  70. package/integrations/eslint/plugin/rules/common/c002-no-duplicate-code.js +204 -0
  71. package/integrations/eslint/plugin/rules/common/c003-no-vague-abbreviations.js +246 -0
  72. package/integrations/eslint/plugin/rules/common/c006-function-name-verb-noun.js +216 -0
  73. package/integrations/eslint/plugin/rules/common/c010-limit-block-nesting.js +90 -0
  74. package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
  75. package/integrations/eslint/plugin/rules/common/c014-abstract-dependency-preferred.js +38 -0
  76. package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
  77. package/integrations/eslint/plugin/rules/common/c018-no-generic-throw.js +335 -0
  78. package/integrations/eslint/plugin/rules/common/c023-no-duplicate-variable-name-in-scope.js +142 -0
  79. package/integrations/eslint/plugin/rules/common/c029-catch-block-logging.js +115 -0
  80. package/integrations/eslint/plugin/rules/common/c030-use-custom-error-classes.js +294 -0
  81. package/integrations/eslint/plugin/rules/common/c035-no-empty-catch.js +162 -0
  82. package/integrations/eslint/plugin/rules/common/c041-no-config-inline.js +122 -0
  83. package/integrations/eslint/plugin/rules/common/c042-boolean-name-prefix.js +406 -0
  84. package/integrations/eslint/plugin/rules/common/c043-no-console-or-print.js +300 -0
  85. package/integrations/eslint/plugin/rules/common/c047-no-duplicate-retry-logic.js +239 -0
  86. package/integrations/eslint/plugin/rules/common/c072-one-assert-per-test.js +184 -0
  87. package/integrations/eslint/plugin/rules/common/c075-explicit-function-return-types.js +168 -0
  88. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +254 -0
  89. package/integrations/eslint/plugin/rules/security/s001-fail-securely.js +381 -0
  90. package/integrations/eslint/plugin/rules/security/s002-idor-check.js +945 -0
  91. package/integrations/eslint/plugin/rules/security/s003-no-unvalidated-redirect.js +86 -0
  92. package/integrations/eslint/plugin/rules/security/s007-no-plaintext-otp.js +74 -0
  93. package/integrations/eslint/plugin/rules/security/s013-verify-tls-connection.js +47 -0
  94. package/integrations/eslint/plugin/rules/security/s047-secure-random-passwords.js +108 -0
  95. package/integrations/eslint/plugin/rules/security/s055-verification-rest-check-the-incoming-content-type.js +143 -0
  96. package/integrations/eslint/plugin/rules/typescript/t002-interface-prefix-i.js +42 -0
  97. package/integrations/eslint/plugin/rules/typescript/t003-ts-ignore-reason.js +48 -0
  98. package/integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js +95 -0
  99. package/integrations/eslint/plugin/rules/typescript/t007-no-fn-in-constructor.js +52 -0
  100. package/integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js +48 -0
  101. package/integrations/eslint/plugin/rules/typescript/t019-no-this-assign.js +81 -0
  102. package/integrations/eslint/plugin/rules/typescript/t020-no-default-multi-export.js +127 -0
  103. package/integrations/eslint/plugin/rules/typescript/t021-limit-nested-generics.js +150 -0
  104. package/integrations/eslint/tsconfig.json +27 -0
  105. package/package.json +61 -21
  106. package/rules/README.md +252 -0
  107. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  108. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  109. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  110. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  111. package/rules/{C006_function_naming → common/C006_function_naming}/analyzer.js +13 -2
  112. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  113. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  114. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  115. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  116. package/rules/{C019_log_level_usage → common/C019_log_level_usage}/analyzer.js +5 -2
  117. package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/analyzer.js +49 -15
  118. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  119. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  120. package/rules/common/C043_no_console_or_print/analyzer.js +304 -0
  121. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +351 -0
  122. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  123. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  124. package/rules/docs/C002_no_duplicate_code.md +57 -0
  125. package/rules/index.js +149 -0
  126. package/rules/migration/converter.js +385 -0
  127. package/rules/migration/mapping.json +164 -0
  128. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  129. package/rules/security/S026_json_schema_validation/config.json +27 -0
  130. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +263 -0
  131. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  132. package/rules/security/S029_csrf_protection/analyzer.js +264 -0
  133. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  134. package/rules/universal/C010/generic.js +0 -0
  135. package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
  136. package/rules/utils/ast-utils.js +191 -0
  137. package/rules/utils/base-analyzer.js +98 -0
  138. package/rules/utils/pattern-matchers.js +239 -0
  139. package/rules/utils/rule-helpers.js +264 -0
  140. package/rules/utils/severity-constants.js +93 -0
  141. package/scripts/build-release.sh +117 -0
  142. package/scripts/ci-report.js +179 -0
  143. package/scripts/install.sh +196 -0
  144. package/scripts/manual-release.sh +338 -0
  145. package/scripts/merge-reports.js +424 -0
  146. package/scripts/pre-release-test.sh +175 -0
  147. package/scripts/prepare-release.sh +202 -0
  148. package/scripts/setup-github-registry.sh +42 -0
  149. package/scripts/test-scripts/README.md +22 -0
  150. package/scripts/test-scripts/test-c041-comparison.js +114 -0
  151. package/scripts/test-scripts/test-c041-eslint.js +67 -0
  152. package/scripts/test-scripts/test-eslint-rules.js +146 -0
  153. package/scripts/test-scripts/test-real-world.js +44 -0
  154. package/scripts/test-scripts/test-rules-on-real-projects.js +86 -0
  155. package/scripts/trigger-release.sh +285 -0
  156. package/scripts/validate-rule-structure.js +148 -0
  157. package/scripts/verify-install.sh +82 -0
  158. package/config/sunlint-schema.json +0 -159
  159. package/config/typescript/custom-rules.js +0 -9
  160. package/config/typescript/package-lock.json +0 -1585
  161. package/config/typescript/package.json +0 -13
  162. package/config/typescript/security-rules/index.js +0 -90
  163. package/config/typescript/tsconfig.json +0 -29
  164. package/core/ai-analyzer.js +0 -169
  165. package/core/eslint-engine-service.js +0 -312
  166. package/core/eslint-instance-manager.js +0 -104
  167. package/core/eslint-integration-service.js +0 -363
  168. package/core/sunlint-engine-service.js +0 -23
  169. package/core/typescript-analyzer.js +0 -262
  170. package/core/typescript-engine.js +0 -313
  171. /package/config/{default.json → defaults/default.json} +0 -0
  172. /package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +0 -0
  173. /package/config/{typescript/custom-rules-new.js → schemas/sunlint-schema.json} +0 -0
  174. /package/config/{typescript → testing}/test-s005-working.ts +0 -0
  175. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
  176. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
  177. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
  178. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
  179. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
  180. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
  181. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
  182. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
  183. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
  184. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
  185. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
  186. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
  187. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
  188. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
  189. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
  190. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
  191. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
  192. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
  193. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
  194. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
  195. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
  196. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
  197. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
  198. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
  199. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
  200. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
  201. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
  202. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
  203. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
  204. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
  205. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
  206. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
  207. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
  208. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
  209. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
  210. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
  211. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
  212. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
  213. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
  214. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +0 -0
  215. /package/rules/{C006_function_naming → common/C006_function_naming}/config.json +0 -0
  216. /package/rules/{C019_log_level_usage → common/C019_log_level_usage}/config.json +0 -0
  217. /package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/config.json +0 -0
  218. /package/rules/{C031_validation_separation → common/C031_validation_separation}/analyzer.js +0 -0
  219. /package/rules/{C031_validation_separation/README.md → docs/C031_validation_separation.md} +0 -0
@@ -1,13 +0,0 @@
1
- {
2
- "name": "sunlint-eslint-typescript",
3
- "version": "1.0.0",
4
- "description": "ESLint integration for SunLint TypeScript analysis",
5
- "dependencies": {
6
- "eslint": "^9.16.0",
7
- "@typescript-eslint/parser": "^8.15.0",
8
- "@typescript-eslint/eslint-plugin": "^8.15.0"
9
- },
10
- "devDependencies": {
11
- "typescript": "^5.7.2"
12
- }
13
- }
@@ -1,90 +0,0 @@
1
- /**
2
- * Custom ESLint plugin: custom rules index
3
- * Export toàn bộ rule tự định nghĩa dùng cho plugin "custom"
4
- */
5
-
6
- const s005 = require("./s005-no-origin-auth.js");
7
- const s006 = require("./s006-activation-recovery-secret-not-plaintext.js");
8
- const s008 = require("./s008-crypto-agility.js");
9
- const s009 = require("./s009-no-insecure-crypto.js");
10
- const s010 = require("./s010-no-insecure-random-in-sensitive-context.js");
11
- const s011 = require("./s011-no-insecure-uuid.js");
12
- const s012 = require("./s012-hardcode-secret.js");
13
- const s014 = require("./s014-insecure-tls-version.js");
14
- const s015 = require("./s015-insecure-tls-certificate.js");
15
- const s016 = require("./s016-sensitive-query-parameter.js");
16
- const s017 = require("./s017-no-sql-injection.js");
17
- const s018 = require("./s018-positive-input-validation.js");
18
- const s019 = require("./s019-no-raw-user-input-in-email.js");
19
- const s020 = require("./s020-no-eval-dynamic-execution.js");
20
- const s022 = require("./s022-output-encoding.js");
21
- const s023 = require("./s023-no-json-injection.js");
22
- const s025 = require("./s025-server-side-input-validation.js");
23
- const s026 = require("./s026-json-schema-validation.js");
24
- const s027 = require("./s027-no-hardcoded-secrets.js");
25
- const s029 = require("./s029-require-csrf-protection.js");
26
- const s030 = require("./s030-no-directory-browsing.js");
27
- const s033 = require("./s033-require-samesite-cookie.js");
28
- const s034 = require("./s034-require-host-cookie-prefix.js");
29
- const s035 = require("./s035-cookie-specific-path.js");
30
- const s036 = require("./s036-no-unsafe-file-include.js");
31
- const s037 = require("./s037-require-anti-cache-headers.js");
32
- const s038 = require("./s038-no-version-disclosure.js");
33
- const s039 = require("./s039-no-session-token-in-url.js");
34
- const s041 = require("./s041-require-session-invalidate-on-logout.js");
35
- const s042 = require("./s042-require-periodic-reauthentication.js");
36
- const s043 = require("./s043-terminate-sessions-on-password-change.js");
37
- const s044 = require("./s044-require-full-session-for-sensitive-operations.js");
38
- const s045 = require("./s045-anti-automation-controls.js");
39
- const s046 = require("./s046-secure-notification-on-auth-change.js");
40
- const s048 = require("./s048-password-credential-recovery.js");
41
- const s050 = require("./s050-session-token-weak-hash.js");
42
- const s052 = require("./s052-secure-random-authentication-code.js");
43
- const s054 = require("./s054-verification-default-account.js");
44
- const s057 = require("./s057-utc-logging.js");
45
- const s058 = require("./s058-no-ssrf.js");
46
-
47
- module.exports = {
48
- rules: {
49
- typescript_s005: s005,
50
- typescript_s006: s006,
51
- typescript_s008: s008,
52
- typescript_s009: s009,
53
- typescript_s010: s010,
54
- typescript_s011: s011,
55
- typescript_s012: s012,
56
- typescript_s014: s014,
57
- typescript_s015: s015,
58
- typescript_s016: s016,
59
- typescript_s017: s017,
60
- typescript_s018: s018,
61
- typescript_s019: s019,
62
- typescript_s020: s020,
63
- typescript_s022: s022,
64
- typescript_s023: s023,
65
- typescript_s025: s025,
66
- typescript_s026: s026,
67
- typescript_s027: s027,
68
- typescript_s029: s029,
69
- typescript_s030: s030,
70
- typescript_s033: s033,
71
- typescript_s034: s034,
72
- typescript_s035: s035,
73
- typescript_s036: s036,
74
- typescript_s037: s037,
75
- typescript_s038: s038,
76
- typescript_s039: s039,
77
- typescript_s041: s041,
78
- typescript_s042: s042,
79
- typescript_s043: s043,
80
- typescript_s044: s044,
81
- typescript_s045: s045,
82
- typescript_s046: s046,
83
- typescript_s048: s048,
84
- typescript_s050: s050,
85
- typescript_s052: s052,
86
- typescript_s054: s054,
87
- typescript_s057: s057,
88
- typescript_s058: s058,
89
- },
90
- };
@@ -1,29 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "commonjs",
5
- "lib": ["ES2020"],
6
- "allowJs": true,
7
- "outDir": "./dist",
8
- "rootDir": "./",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "sourceMap": true,
16
- "resolveJsonModule": true,
17
- "moduleResolution": "node"
18
- },
19
- "include": [
20
- "**/*.ts",
21
- "**/*.tsx",
22
- "**/*.js",
23
- "**/*.jsx"
24
- ],
25
- "exclude": [
26
- "node_modules",
27
- "dist"
28
- ]
29
- }
@@ -1,169 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- class AIAnalyzer {
5
- constructor(config = {}) {
6
- this.config = config;
7
- this.apiKey = process.env.OPENAI_API_KEY || config.apiKey;
8
- this.model = config.model || 'gpt-4o-mini';
9
- this.provider = config.provider || 'openai';
10
- }
11
-
12
- async analyzeWithAI(filePath, content, ruleConfig) {
13
- if (!this.apiKey) {
14
- console.warn('⚠️ AI API key not found, falling back to pattern analysis');
15
- return null;
16
- }
17
-
18
- try {
19
- const prompt = this.buildPrompt(content, ruleConfig);
20
- const response = await this.callAI(prompt);
21
- return this.parseAIResponse(response, filePath);
22
- } catch (error) {
23
- console.error('AI Analysis failed:', error.message);
24
- return null;
25
- }
26
- }
27
-
28
- buildPrompt(content, ruleConfig) {
29
- return `You are a code quality expert analyzing code ONLY for logging best practices.
30
-
31
- RULE: ${ruleConfig.ruleId} - ${ruleConfig.name}
32
- DESCRIPTION: ${ruleConfig.description}
33
-
34
- IMPORTANT: You are ONLY checking for LOG LEVEL VIOLATIONS. Do NOT analyze function naming, variable naming, or other code quality issues.
35
-
36
- ANALYZE THIS CODE FOR LOG LEVEL VIOLATIONS ONLY:
37
- \`\`\`
38
- ${content}
39
- \`\`\`
40
-
41
- SPECIFIC CRITERIA FOR LOG LEVELS ONLY:
42
- 1. Don't use console.error() or logger.error() for non-critical issues (should use console.warn() or console.log())
43
- 2. Avoid generic error messages without context
44
- 3. Error logs should be reserved for actual errors/exceptions that need immediate attention
45
- 4. Info/debug logs should use appropriate levels
46
- 5. Validation errors should typically use warn level, not error level
47
-
48
- FOCUS ONLY ON:
49
- - console.error() usage
50
- - logger.error() usage
51
- - this.logger.error() usage
52
- - Other error-level logging calls
53
-
54
- DO NOT CHECK:
55
- - Function names
56
- - Variable names
57
- - Code structure
58
- - Other code quality issues
59
-
60
- RESPOND WITH JSON FORMAT:
61
- {
62
- "violations": [
63
- {
64
- "line": <line_number>,
65
- "column": <column_number>,
66
- "message": "<specific_logging_violation_description>",
67
- "severity": "warning|error|info",
68
- "code": "<code_snippet>",
69
- "suggestion": "<how_to_fix_logging>"
70
- }
71
- ],
72
- "summary": "<overall_logging_assessment>"
73
- }
74
-
75
- Be precise about line numbers and provide actionable suggestions for LOG LEVEL issues only.`;
76
- }
77
-
78
- async callAI(prompt) {
79
- if (this.provider === 'openai') {
80
- return await this.callOpenAI(prompt);
81
- } else if (this.provider === 'copilot') {
82
- return await this.callCopilot(prompt);
83
- }
84
- throw new Error(`Unsupported AI provider: ${this.provider}`);
85
- }
86
-
87
- async callOpenAI(prompt) {
88
- const fetch = (await import('node-fetch')).default;
89
-
90
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
91
- method: 'POST',
92
- headers: {
93
- 'Content-Type': 'application/json',
94
- 'Authorization': `Bearer ${this.apiKey}`
95
- },
96
- body: JSON.stringify({
97
- model: this.model,
98
- messages: [
99
- {
100
- role: 'system',
101
- content: 'You are an expert code analyzer specializing in logging best practices. Provide precise, actionable feedback.'
102
- },
103
- {
104
- role: 'user',
105
- content: prompt
106
- }
107
- ],
108
- temperature: 0.1,
109
- max_tokens: 2000
110
- })
111
- });
112
-
113
- if (!response.ok) {
114
- throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
115
- }
116
-
117
- const data = await response.json();
118
- return data.choices[0].message.content;
119
- }
120
-
121
- async callCopilot(prompt) {
122
- // TODO: Implement GitHub Copilot API integration
123
- // This would require GitHub Copilot API access
124
- throw new Error('GitHub Copilot API integration not yet implemented');
125
- }
126
-
127
- parseAIResponse(aiResponse, filePath) {
128
- try {
129
- // Extract JSON from AI response
130
- const jsonMatch = aiResponse.match(/\{[\s\S]*\}/);
131
- if (!jsonMatch) {
132
- throw new Error('No JSON found in AI response');
133
- }
134
-
135
- const parsed = JSON.parse(jsonMatch[0]);
136
-
137
- return parsed.violations.map(violation => ({
138
- line: violation.line,
139
- column: violation.column || 1,
140
- message: violation.message,
141
- severity: violation.severity || 'warning',
142
- ruleId: 'C019',
143
- code: violation.code,
144
- suggestion: violation.suggestion,
145
- file: filePath,
146
- source: 'ai'
147
- }));
148
- } catch (error) {
149
- console.error('Failed to parse AI response:', error.message);
150
- return [];
151
- }
152
- }
153
-
154
- async testConnection() {
155
- if (!this.apiKey) {
156
- return { success: false, error: 'API key not configured' };
157
- }
158
-
159
- try {
160
- const testPrompt = 'Respond with: {"status": "ok"}';
161
- await this.callAI(testPrompt);
162
- return { success: true, provider: this.provider, model: this.model };
163
- } catch (error) {
164
- return { success: false, error: error.message };
165
- }
166
- }
167
- }
168
-
169
- module.exports = AIAnalyzer;
@@ -1,312 +0,0 @@
1
- /**
2
- * ESLint Engine Service
3
- * Handles ESLint integration for TypeScript analysis
4
- * Following Rule C005: Single responsibility - only handle ESLint execution
5
- * Following Rule C014: Dependency injection for configuration
6
- */
7
-
8
- const { execSync } = require('child_process');
9
- const path = require('path');
10
- const fs = require('fs');
11
- const chalk = require('chalk');
12
-
13
- class ESLintEngineService {
14
- constructor() {
15
- this.eslintConfigPath = path.join(__dirname, '../config/typescript/eslint.config.js');
16
- this.eslintPackagePath = path.join(__dirname, '../config/typescript');
17
- }
18
-
19
- /**
20
- * Query: Check if ESLint is available
21
- */
22
- isAvailable() {
23
- try {
24
- // Check if config exists
25
- if (!fs.existsSync(this.eslintConfigPath)) {
26
- return false;
27
- }
28
-
29
- // Check if ESLint is available
30
- execSync('npx eslint --version', {
31
- stdio: 'ignore',
32
- cwd: this.eslintPackagePath
33
- });
34
- return true;
35
- } catch (error) {
36
- return false;
37
- }
38
- }
39
-
40
- /**
41
- * Command: Ensure ESLint dependencies are installed
42
- */
43
- async ensureDependencies() {
44
- try {
45
- console.log(chalk.blue('🔧 Ensuring ESLint dependencies...'));
46
-
47
- const packageJsonPath = path.join(this.eslintPackagePath, 'package.json');
48
- if (fs.existsSync(packageJsonPath)) {
49
- execSync('npm install', {
50
- cwd: this.eslintPackagePath,
51
- stdio: 'inherit'
52
- });
53
- }
54
-
55
- console.log(chalk.green('✅ ESLint dependencies ready'));
56
- } catch (error) {
57
- throw new Error(`Failed to ensure ESLint dependencies: ${error.message}`);
58
- }
59
- }
60
-
61
- /**
62
- * Command: Run ESLint analysis
63
- */
64
- async runAnalysis(rulesToRun, options) {
65
- try {
66
- // Map SunLint rules to ESLint rules
67
- const eslintRules = this.mapSunLintRulesToESLint(rulesToRun);
68
-
69
- // Build ESLint command
70
- const command = this.buildESLintCommand(eslintRules, options);
71
-
72
- if (options.debug) {
73
- console.log(chalk.yellow('ESLint command:'), command);
74
- }
75
-
76
- // Execute ESLint
77
- const output = execSync(command, {
78
- cwd: this.eslintPackagePath,
79
- encoding: 'utf-8'
80
- });
81
-
82
- // Parse results
83
- return this.parseESLintOutput(output, options);
84
-
85
- } catch (error) {
86
- // ESLint might exit with non-zero code when violations are found
87
- if (error.stdout) {
88
- return this.parseESLintOutput(error.stdout, options);
89
- }
90
- throw new Error(`ESLint execution failed: ${error.message}`);
91
- }
92
- }
93
-
94
- /**
95
- * Query: Map SunLint rule IDs to ESLint rule IDs
96
- */
97
- mapSunLintRulesToESLint(rules) {
98
- const ruleMapping = {
99
- // Quality rules (C-rules)
100
- 'C002': 'custom/c002',
101
- 'C003': 'custom/c003',
102
- 'C006': 'custom/c006',
103
- 'C010': 'custom/c010',
104
- 'C013': 'custom/c013',
105
- 'C014': 'custom/c014',
106
- 'C017': 'custom/c017',
107
- 'C018': 'custom/c018',
108
- 'C023': 'custom/c023',
109
- 'C027': 'custom/c027',
110
- 'C029': 'custom/c029',
111
- 'C030': 'custom/c030',
112
- 'C034': 'custom/c034',
113
- 'C035': 'custom/c035',
114
- 'C041': 'custom/c041',
115
- 'C042': 'custom/c042',
116
- 'C043': 'custom/c043',
117
- 'C047': 'custom/c047',
118
- 'C048': 'custom/c048',
119
-
120
- // Security rules (S-rules)
121
- 'S005': 'custom/typescript_s005',
122
- 'S006': 'custom/typescript_s006',
123
- 'S008': 'custom/typescript_s008',
124
- 'S009': 'custom/typescript_s009',
125
- 'S010': 'custom/typescript_s010',
126
- 'S011': 'custom/typescript_s011',
127
- 'S012': 'custom/typescript_s012',
128
- 'S014': 'custom/typescript_s014',
129
- 'S015': 'custom/typescript_s015',
130
- 'S016': 'custom/typescript_s016',
131
- 'S017': 'custom/typescript_s017',
132
- 'S018': 'custom/typescript_s018',
133
- 'S019': 'custom/typescript_s019',
134
- 'S020': 'custom/typescript_s020',
135
- 'S022': 'custom/typescript_s022',
136
- 'S023': 'custom/typescript_s023',
137
- 'S025': 'custom/typescript_s025',
138
- 'S026': 'custom/typescript_s026',
139
- 'S027': 'custom/typescript_s027',
140
- 'S029': 'custom/typescript_s029',
141
- 'S030': 'custom/typescript_s030',
142
- 'S033': 'custom/typescript_s033',
143
- 'S034': 'custom/typescript_s034',
144
- 'S035': 'custom/typescript_s035',
145
- 'S036': 'custom/typescript_s036',
146
- 'S037': 'custom/typescript_s037',
147
- 'S038': 'custom/typescript_s038',
148
- 'S039': 'custom/typescript_s039',
149
- 'S041': 'custom/typescript_s041',
150
- 'S042': 'custom/typescript_s042',
151
- 'S043': 'custom/typescript_s043',
152
- 'S044': 'custom/typescript_s044',
153
- 'S045': 'custom/typescript_s045',
154
- 'S046': 'custom/typescript_s046',
155
- 'S048': 'custom/typescript_s048',
156
- 'S050': 'custom/typescript_s050',
157
- 'S052': 'custom/typescript_s052',
158
- 'S054': 'custom/typescript_s054',
159
- 'S057': 'custom/typescript_s057',
160
- 'S058': 'custom/typescript_s058'
161
- };
162
-
163
- return rules
164
- .filter(rule => ruleMapping[rule.id])
165
- .map(rule => ruleMapping[rule.id]);
166
- }
167
-
168
- /**
169
- * Command: Build ESLint command
170
- */
171
- buildESLintCommand(eslintRules, options) {
172
- const parts = [
173
- 'npx eslint',
174
- `--config ${this.eslintConfigPath}`,
175
- '--format json',
176
- `"${options.input}"`
177
- ];
178
-
179
- // Add specific rules if provided
180
- if (eslintRules.length > 0) {
181
- const rulesFlag = eslintRules.map(rule => `${rule}:error`).join(' ');
182
- parts.push(`--rule "${rulesFlag}"`);
183
- }
184
-
185
- // Add file extensions
186
- parts.push('--ext .ts,.tsx,.js,.jsx');
187
-
188
- return parts.join(' ');
189
- }
190
-
191
- /**
192
- * Query: Parse ESLint JSON output to SunLint format
193
- */
194
- parseESLintOutput(output, options) {
195
- try {
196
- const eslintResults = JSON.parse(output);
197
-
198
- const results = {
199
- results: [],
200
- filesAnalyzed: eslintResults.length,
201
- engine: 'eslint'
202
- };
203
-
204
- eslintResults.forEach(file => {
205
- if (file.messages.length > 0) {
206
- const violations = file.messages.map(msg => ({
207
- ruleId: this.mapESLintRuleToSunLint(msg.ruleId),
208
- severity: this.mapESLintSeverity(msg.severity),
209
- message: msg.message,
210
- line: msg.line,
211
- column: msg.column,
212
- file: file.filePath
213
- }));
214
-
215
- results.results.push({
216
- file: file.filePath,
217
- violations: violations
218
- });
219
- }
220
- });
221
-
222
- return results;
223
- } catch (error) {
224
- throw new Error(`Failed to parse ESLint output: ${error.message}`);
225
- }
226
- }
227
-
228
- /**
229
- * Query: Map ESLint rule ID back to SunLint rule ID
230
- */
231
- mapESLintRuleToSunLint(eslintRuleId) {
232
- const reverseMapping = {
233
- // Quality rules (C-rules)
234
- 'custom/c002': 'C002',
235
- 'custom/c003': 'C003',
236
- 'custom/c006': 'C006',
237
- 'custom/c010': 'C010',
238
- 'custom/c013': 'C013',
239
- 'custom/c014': 'C014',
240
- 'custom/c017': 'C017',
241
- 'custom/c018': 'C018',
242
- 'custom/c023': 'C023',
243
- 'custom/c027': 'C027',
244
- 'custom/c029': 'C029',
245
- 'custom/c030': 'C030',
246
- 'custom/c034': 'C034',
247
- 'custom/c035': 'C035',
248
- 'custom/c041': 'C041',
249
- 'custom/c042': 'C042',
250
- 'custom/c043': 'C043',
251
- 'custom/c047': 'C047',
252
- 'custom/c048': 'C048',
253
-
254
- // Security rules (S-rules)
255
- 'custom/typescript_s005': 'S005',
256
- 'custom/typescript_s006': 'S006',
257
- 'custom/typescript_s008': 'S008',
258
- 'custom/typescript_s009': 'S009',
259
- 'custom/typescript_s010': 'S010',
260
- 'custom/typescript_s011': 'S011',
261
- 'custom/typescript_s012': 'S012',
262
- 'custom/typescript_s014': 'S014',
263
- 'custom/typescript_s015': 'S015',
264
- 'custom/typescript_s016': 'S016',
265
- 'custom/typescript_s017': 'S017',
266
- 'custom/typescript_s018': 'S018',
267
- 'custom/typescript_s019': 'S019',
268
- 'custom/typescript_s020': 'S020',
269
- 'custom/typescript_s022': 'S022',
270
- 'custom/typescript_s023': 'S023',
271
- 'custom/typescript_s025': 'S025',
272
- 'custom/typescript_s026': 'S026',
273
- 'custom/typescript_s027': 'S027',
274
- 'custom/typescript_s029': 'S029',
275
- 'custom/typescript_s030': 'S030',
276
- 'custom/typescript_s033': 'S033',
277
- 'custom/typescript_s034': 'S034',
278
- 'custom/typescript_s035': 'S035',
279
- 'custom/typescript_s036': 'S036',
280
- 'custom/typescript_s037': 'S037',
281
- 'custom/typescript_s038': 'S038',
282
- 'custom/typescript_s039': 'S039',
283
- 'custom/typescript_s041': 'S041',
284
- 'custom/typescript_s042': 'S042',
285
- 'custom/typescript_s043': 'S043',
286
- 'custom/typescript_s044': 'S044',
287
- 'custom/typescript_s045': 'S045',
288
- 'custom/typescript_s046': 'S046',
289
- 'custom/typescript_s048': 'S048',
290
- 'custom/typescript_s050': 'S050',
291
- 'custom/typescript_s052': 'S052',
292
- 'custom/typescript_s054': 'S054',
293
- 'custom/typescript_s057': 'S057',
294
- 'custom/typescript_s058': 'S058'
295
- };
296
-
297
- return reverseMapping[eslintRuleId] || eslintRuleId;
298
- }
299
-
300
- /**
301
- * Query: Map ESLint severity to SunLint severity
302
- */
303
- mapESLintSeverity(eslintSeverity) {
304
- switch (eslintSeverity) {
305
- case 1: return 'warning';
306
- case 2: return 'error';
307
- default: return 'info';
308
- }
309
- }
310
- }
311
-
312
- module.exports = ESLintEngineService;