codeslick-cli 1.0.0

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 (455) hide show
  1. package/README.md +458 -0
  2. package/__tests__/cli-reporter.test.ts +86 -0
  3. package/__tests__/config-loader.test.ts +247 -0
  4. package/__tests__/local-scanner.test.ts +245 -0
  5. package/bin/codeslick.cjs +153 -0
  6. package/dist/packages/cli/src/commands/auth.d.ts +36 -0
  7. package/dist/packages/cli/src/commands/auth.d.ts.map +1 -0
  8. package/dist/packages/cli/src/commands/auth.js +226 -0
  9. package/dist/packages/cli/src/commands/auth.js.map +1 -0
  10. package/dist/packages/cli/src/commands/config.d.ts +37 -0
  11. package/dist/packages/cli/src/commands/config.d.ts.map +1 -0
  12. package/dist/packages/cli/src/commands/config.js +196 -0
  13. package/dist/packages/cli/src/commands/config.js.map +1 -0
  14. package/dist/packages/cli/src/commands/init.d.ts +32 -0
  15. package/dist/packages/cli/src/commands/init.d.ts.map +1 -0
  16. package/dist/packages/cli/src/commands/init.js +171 -0
  17. package/dist/packages/cli/src/commands/init.js.map +1 -0
  18. package/dist/packages/cli/src/commands/scan.d.ts +40 -0
  19. package/dist/packages/cli/src/commands/scan.d.ts.map +1 -0
  20. package/dist/packages/cli/src/commands/scan.js +204 -0
  21. package/dist/packages/cli/src/commands/scan.js.map +1 -0
  22. package/dist/packages/cli/src/config/config-loader.d.ts +67 -0
  23. package/dist/packages/cli/src/config/config-loader.d.ts.map +1 -0
  24. package/dist/packages/cli/src/config/config-loader.js +146 -0
  25. package/dist/packages/cli/src/config/config-loader.js.map +1 -0
  26. package/dist/packages/cli/src/reporters/cli-reporter.d.ts +69 -0
  27. package/dist/packages/cli/src/reporters/cli-reporter.d.ts.map +1 -0
  28. package/dist/packages/cli/src/reporters/cli-reporter.js +244 -0
  29. package/dist/packages/cli/src/reporters/cli-reporter.js.map +1 -0
  30. package/dist/packages/cli/src/scanner/local-scanner.d.ts +92 -0
  31. package/dist/packages/cli/src/scanner/local-scanner.d.ts.map +1 -0
  32. package/dist/packages/cli/src/scanner/local-scanner.js +221 -0
  33. package/dist/packages/cli/src/scanner/local-scanner.js.map +1 -0
  34. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.d.ts +88 -0
  35. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.d.ts.map +1 -0
  36. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.js +371 -0
  37. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.js.map +1 -0
  38. package/dist/src/lib/analyzers/helpers/jsx-helpers.d.ts +63 -0
  39. package/dist/src/lib/analyzers/helpers/jsx-helpers.d.ts.map +1 -0
  40. package/dist/src/lib/analyzers/helpers/jsx-helpers.js +95 -0
  41. package/dist/src/lib/analyzers/helpers/jsx-helpers.js.map +1 -0
  42. package/dist/src/lib/analyzers/helpers/variable-tracker.d.ts +59 -0
  43. package/dist/src/lib/analyzers/helpers/variable-tracker.d.ts.map +1 -0
  44. package/dist/src/lib/analyzers/helpers/variable-tracker.js +231 -0
  45. package/dist/src/lib/analyzers/helpers/variable-tracker.js.map +1 -0
  46. package/dist/src/lib/analyzers/java/security-checks/access-control.d.ts +20 -0
  47. package/dist/src/lib/analyzers/java/security-checks/access-control.d.ts.map +1 -0
  48. package/dist/src/lib/analyzers/java/security-checks/access-control.js +129 -0
  49. package/dist/src/lib/analyzers/java/security-checks/access-control.js.map +1 -0
  50. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.d.ts +25 -0
  51. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.d.ts.map +1 -0
  52. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.js +221 -0
  53. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.js.map +1 -0
  54. package/dist/src/lib/analyzers/java/security-checks/code-quality.d.ts +18 -0
  55. package/dist/src/lib/analyzers/java/security-checks/code-quality.d.ts.map +1 -0
  56. package/dist/src/lib/analyzers/java/security-checks/code-quality.js +84 -0
  57. package/dist/src/lib/analyzers/java/security-checks/code-quality.js.map +1 -0
  58. package/dist/src/lib/analyzers/java/security-checks/crypto-validation.d.ts +18 -0
  59. package/dist/src/lib/analyzers/java/security-checks/crypto-validation.d.ts.map +1 -0
  60. package/dist/src/lib/analyzers/java/security-checks/crypto-validation.js +161 -0
  61. package/dist/src/lib/analyzers/java/security-checks/crypto-validation.js.map +1 -0
  62. package/dist/src/lib/analyzers/java/security-checks/deserialization-xxe.d.ts +20 -0
  63. package/dist/src/lib/analyzers/java/security-checks/deserialization-xxe.d.ts.map +1 -0
  64. package/dist/src/lib/analyzers/java/security-checks/deserialization-xxe.js +163 -0
  65. package/dist/src/lib/analyzers/java/security-checks/deserialization-xxe.js.map +1 -0
  66. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.d.ts +24 -0
  67. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.d.ts.map +1 -0
  68. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.js +178 -0
  69. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.js.map +1 -0
  70. package/dist/src/lib/analyzers/java/security-checks/exception-handling.d.ts +25 -0
  71. package/dist/src/lib/analyzers/java/security-checks/exception-handling.d.ts.map +1 -0
  72. package/dist/src/lib/analyzers/java/security-checks/exception-handling.js +179 -0
  73. package/dist/src/lib/analyzers/java/security-checks/exception-handling.js.map +1 -0
  74. package/dist/src/lib/analyzers/java/security-checks/file-operations.d.ts +17 -0
  75. package/dist/src/lib/analyzers/java/security-checks/file-operations.d.ts.map +1 -0
  76. package/dist/src/lib/analyzers/java/security-checks/file-operations.js +67 -0
  77. package/dist/src/lib/analyzers/java/security-checks/file-operations.js.map +1 -0
  78. package/dist/src/lib/analyzers/java/security-checks/framework-security.d.ts +25 -0
  79. package/dist/src/lib/analyzers/java/security-checks/framework-security.d.ts.map +1 -0
  80. package/dist/src/lib/analyzers/java/security-checks/framework-security.js +396 -0
  81. package/dist/src/lib/analyzers/java/security-checks/framework-security.js.map +1 -0
  82. package/dist/src/lib/analyzers/java/security-checks/hardcoded-credentials.d.ts +20 -0
  83. package/dist/src/lib/analyzers/java/security-checks/hardcoded-credentials.d.ts.map +1 -0
  84. package/dist/src/lib/analyzers/java/security-checks/hardcoded-credentials.js +123 -0
  85. package/dist/src/lib/analyzers/java/security-checks/hardcoded-credentials.js.map +1 -0
  86. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.d.ts +23 -0
  87. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.d.ts.map +1 -0
  88. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.js +201 -0
  89. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.js.map +1 -0
  90. package/dist/src/lib/analyzers/java/security-checks/insecure-design.d.ts +20 -0
  91. package/dist/src/lib/analyzers/java/security-checks/insecure-design.d.ts.map +1 -0
  92. package/dist/src/lib/analyzers/java/security-checks/insecure-design.js +121 -0
  93. package/dist/src/lib/analyzers/java/security-checks/insecure-design.js.map +1 -0
  94. package/dist/src/lib/analyzers/java/security-checks/logging-failures.d.ts +20 -0
  95. package/dist/src/lib/analyzers/java/security-checks/logging-failures.d.ts.map +1 -0
  96. package/dist/src/lib/analyzers/java/security-checks/logging-failures.js +89 -0
  97. package/dist/src/lib/analyzers/java/security-checks/logging-failures.js.map +1 -0
  98. package/dist/src/lib/analyzers/java/security-checks/security-misconfiguration.d.ts +26 -0
  99. package/dist/src/lib/analyzers/java/security-checks/security-misconfiguration.d.ts.map +1 -0
  100. package/dist/src/lib/analyzers/java/security-checks/security-misconfiguration.js +309 -0
  101. package/dist/src/lib/analyzers/java/security-checks/security-misconfiguration.js.map +1 -0
  102. package/dist/src/lib/analyzers/java/security-checks/unsafe-patterns.d.ts +18 -0
  103. package/dist/src/lib/analyzers/java/security-checks/unsafe-patterns.d.ts.map +1 -0
  104. package/dist/src/lib/analyzers/java/security-checks/unsafe-patterns.js +114 -0
  105. package/dist/src/lib/analyzers/java/security-checks/unsafe-patterns.js.map +1 -0
  106. package/dist/src/lib/analyzers/java/utils/createVulnerability.d.ts +58 -0
  107. package/dist/src/lib/analyzers/java/utils/createVulnerability.d.ts.map +1 -0
  108. package/dist/src/lib/analyzers/java/utils/createVulnerability.js +71 -0
  109. package/dist/src/lib/analyzers/java/utils/createVulnerability.js.map +1 -0
  110. package/dist/src/lib/analyzers/java-analyzer.d.ts +209 -0
  111. package/dist/src/lib/analyzers/java-analyzer.d.ts.map +1 -0
  112. package/dist/src/lib/analyzers/java-analyzer.js +1720 -0
  113. package/dist/src/lib/analyzers/java-analyzer.js.map +1 -0
  114. package/dist/src/lib/analyzers/javascript/quality-checks/ai-hallucinations.d.ts +27 -0
  115. package/dist/src/lib/analyzers/javascript/quality-checks/ai-hallucinations.d.ts.map +1 -0
  116. package/dist/src/lib/analyzers/javascript/quality-checks/ai-hallucinations.js +123 -0
  117. package/dist/src/lib/analyzers/javascript/quality-checks/ai-hallucinations.js.map +1 -0
  118. package/dist/src/lib/analyzers/javascript/quality-checks/async-patterns.d.ts +44 -0
  119. package/dist/src/lib/analyzers/javascript/quality-checks/async-patterns.d.ts.map +1 -0
  120. package/dist/src/lib/analyzers/javascript/quality-checks/async-patterns.js +224 -0
  121. package/dist/src/lib/analyzers/javascript/quality-checks/async-patterns.js.map +1 -0
  122. package/dist/src/lib/analyzers/javascript/quality-checks/code-patterns.d.ts +50 -0
  123. package/dist/src/lib/analyzers/javascript/quality-checks/code-patterns.d.ts.map +1 -0
  124. package/dist/src/lib/analyzers/javascript/quality-checks/code-patterns.js +284 -0
  125. package/dist/src/lib/analyzers/javascript/quality-checks/code-patterns.js.map +1 -0
  126. package/dist/src/lib/analyzers/javascript/quality-checks/comparison-issues.d.ts +27 -0
  127. package/dist/src/lib/analyzers/javascript/quality-checks/comparison-issues.d.ts.map +1 -0
  128. package/dist/src/lib/analyzers/javascript/quality-checks/comparison-issues.js +86 -0
  129. package/dist/src/lib/analyzers/javascript/quality-checks/comparison-issues.js.map +1 -0
  130. package/dist/src/lib/analyzers/javascript/quality-checks/reference-errors.d.ts +32 -0
  131. package/dist/src/lib/analyzers/javascript/quality-checks/reference-errors.d.ts.map +1 -0
  132. package/dist/src/lib/analyzers/javascript/quality-checks/reference-errors.js +44 -0
  133. package/dist/src/lib/analyzers/javascript/quality-checks/reference-errors.js.map +1 -0
  134. package/dist/src/lib/analyzers/javascript/security-checks/access-control.d.ts +22 -0
  135. package/dist/src/lib/analyzers/javascript/security-checks/access-control.d.ts.map +1 -0
  136. package/dist/src/lib/analyzers/javascript/security-checks/access-control.js +168 -0
  137. package/dist/src/lib/analyzers/javascript/security-checks/access-control.js.map +1 -0
  138. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.d.ts +25 -0
  139. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.d.ts.map +1 -0
  140. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.js +232 -0
  141. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.js.map +1 -0
  142. package/dist/src/lib/analyzers/javascript/security-checks/authentication-failures.d.ts +27 -0
  143. package/dist/src/lib/analyzers/javascript/security-checks/authentication-failures.d.ts.map +1 -0
  144. package/dist/src/lib/analyzers/javascript/security-checks/authentication-failures.js +222 -0
  145. package/dist/src/lib/analyzers/javascript/security-checks/authentication-failures.js.map +1 -0
  146. package/dist/src/lib/analyzers/javascript/security-checks/credential-crypto.d.ts +28 -0
  147. package/dist/src/lib/analyzers/javascript/security-checks/credential-crypto.d.ts.map +1 -0
  148. package/dist/src/lib/analyzers/javascript/security-checks/credential-crypto.js +176 -0
  149. package/dist/src/lib/analyzers/javascript/security-checks/credential-crypto.js.map +1 -0
  150. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.d.ts +23 -0
  151. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.d.ts.map +1 -0
  152. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.js +113 -0
  153. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.js.map +1 -0
  154. package/dist/src/lib/analyzers/javascript/security-checks/exception-handling.d.ts +28 -0
  155. package/dist/src/lib/analyzers/javascript/security-checks/exception-handling.d.ts.map +1 -0
  156. package/dist/src/lib/analyzers/javascript/security-checks/exception-handling.js +227 -0
  157. package/dist/src/lib/analyzers/javascript/security-checks/exception-handling.js.map +1 -0
  158. package/dist/src/lib/analyzers/javascript/security-checks/injection-attacks.d.ts +32 -0
  159. package/dist/src/lib/analyzers/javascript/security-checks/injection-attacks.d.ts.map +1 -0
  160. package/dist/src/lib/analyzers/javascript/security-checks/injection-attacks.js +260 -0
  161. package/dist/src/lib/analyzers/javascript/security-checks/injection-attacks.js.map +1 -0
  162. package/dist/src/lib/analyzers/javascript/security-checks/insecure-design.d.ts +26 -0
  163. package/dist/src/lib/analyzers/javascript/security-checks/insecure-design.d.ts.map +1 -0
  164. package/dist/src/lib/analyzers/javascript/security-checks/insecure-design.js +164 -0
  165. package/dist/src/lib/analyzers/javascript/security-checks/insecure-design.js.map +1 -0
  166. package/dist/src/lib/analyzers/javascript/security-checks/security-misconfiguration.d.ts +26 -0
  167. package/dist/src/lib/analyzers/javascript/security-checks/security-misconfiguration.d.ts.map +1 -0
  168. package/dist/src/lib/analyzers/javascript/security-checks/security-misconfiguration.js +775 -0
  169. package/dist/src/lib/analyzers/javascript/security-checks/security-misconfiguration.js.map +1 -0
  170. package/dist/src/lib/analyzers/javascript/security-checks/software-integrity.d.ts +25 -0
  171. package/dist/src/lib/analyzers/javascript/security-checks/software-integrity.d.ts.map +1 -0
  172. package/dist/src/lib/analyzers/javascript/security-checks/software-integrity.js +168 -0
  173. package/dist/src/lib/analyzers/javascript/security-checks/software-integrity.js.map +1 -0
  174. package/dist/src/lib/analyzers/javascript/security-checks/storage-security.d.ts +27 -0
  175. package/dist/src/lib/analyzers/javascript/security-checks/storage-security.d.ts.map +1 -0
  176. package/dist/src/lib/analyzers/javascript/security-checks/storage-security.js +108 -0
  177. package/dist/src/lib/analyzers/javascript/security-checks/storage-security.js.map +1 -0
  178. package/dist/src/lib/analyzers/javascript/security-checks/xss-dom-security.d.ts +28 -0
  179. package/dist/src/lib/analyzers/javascript/security-checks/xss-dom-security.d.ts.map +1 -0
  180. package/dist/src/lib/analyzers/javascript/security-checks/xss-dom-security.js +143 -0
  181. package/dist/src/lib/analyzers/javascript/security-checks/xss-dom-security.js.map +1 -0
  182. package/dist/src/lib/analyzers/javascript/syntax/syntax-helpers.d.ts +53 -0
  183. package/dist/src/lib/analyzers/javascript/syntax/syntax-helpers.d.ts.map +1 -0
  184. package/dist/src/lib/analyzers/javascript/syntax/syntax-helpers.js +144 -0
  185. package/dist/src/lib/analyzers/javascript/syntax/syntax-helpers.js.map +1 -0
  186. package/dist/src/lib/analyzers/javascript/syntax/typescript-syntax.d.ts +72 -0
  187. package/dist/src/lib/analyzers/javascript/syntax/typescript-syntax.d.ts.map +1 -0
  188. package/dist/src/lib/analyzers/javascript/syntax/typescript-syntax.js +314 -0
  189. package/dist/src/lib/analyzers/javascript/syntax/typescript-syntax.js.map +1 -0
  190. package/dist/src/lib/analyzers/javascript/utils/createVulnerability.d.ts +58 -0
  191. package/dist/src/lib/analyzers/javascript/utils/createVulnerability.d.ts.map +1 -0
  192. package/dist/src/lib/analyzers/javascript/utils/createVulnerability.js +71 -0
  193. package/dist/src/lib/analyzers/javascript/utils/createVulnerability.js.map +1 -0
  194. package/dist/src/lib/analyzers/javascript/utils/metrics-calculator.d.ts +36 -0
  195. package/dist/src/lib/analyzers/javascript/utils/metrics-calculator.d.ts.map +1 -0
  196. package/dist/src/lib/analyzers/javascript/utils/metrics-calculator.js +70 -0
  197. package/dist/src/lib/analyzers/javascript/utils/metrics-calculator.js.map +1 -0
  198. package/dist/src/lib/analyzers/javascript/utils/performance-analyzer.d.ts +29 -0
  199. package/dist/src/lib/analyzers/javascript/utils/performance-analyzer.d.ts.map +1 -0
  200. package/dist/src/lib/analyzers/javascript/utils/performance-analyzer.js +55 -0
  201. package/dist/src/lib/analyzers/javascript/utils/performance-analyzer.js.map +1 -0
  202. package/dist/src/lib/analyzers/javascript-analyzer.d.ts +95 -0
  203. package/dist/src/lib/analyzers/javascript-analyzer.d.ts.map +1 -0
  204. package/dist/src/lib/analyzers/javascript-analyzer.js +2141 -0
  205. package/dist/src/lib/analyzers/javascript-analyzer.js.map +1 -0
  206. package/dist/src/lib/analyzers/python/security-checks/access-control.d.ts +21 -0
  207. package/dist/src/lib/analyzers/python/security-checks/access-control.d.ts.map +1 -0
  208. package/dist/src/lib/analyzers/python/security-checks/access-control.js +305 -0
  209. package/dist/src/lib/analyzers/python/security-checks/access-control.js.map +1 -0
  210. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.d.ts +25 -0
  211. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.d.ts.map +1 -0
  212. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.js +242 -0
  213. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.js.map +1 -0
  214. package/dist/src/lib/analyzers/python/security-checks/authentication-flaws.d.ts +24 -0
  215. package/dist/src/lib/analyzers/python/security-checks/authentication-flaws.d.ts.map +1 -0
  216. package/dist/src/lib/analyzers/python/security-checks/authentication-flaws.js +207 -0
  217. package/dist/src/lib/analyzers/python/security-checks/authentication-flaws.js.map +1 -0
  218. package/dist/src/lib/analyzers/python/security-checks/code-quality.d.ts +27 -0
  219. package/dist/src/lib/analyzers/python/security-checks/code-quality.d.ts.map +1 -0
  220. package/dist/src/lib/analyzers/python/security-checks/code-quality.js +206 -0
  221. package/dist/src/lib/analyzers/python/security-checks/code-quality.js.map +1 -0
  222. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.d.ts +24 -0
  223. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.d.ts.map +1 -0
  224. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.js +113 -0
  225. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.js.map +1 -0
  226. package/dist/src/lib/analyzers/python/security-checks/crypto-failures.d.ts +20 -0
  227. package/dist/src/lib/analyzers/python/security-checks/crypto-failures.d.ts.map +1 -0
  228. package/dist/src/lib/analyzers/python/security-checks/crypto-failures.js +129 -0
  229. package/dist/src/lib/analyzers/python/security-checks/crypto-failures.js.map +1 -0
  230. package/dist/src/lib/analyzers/python/security-checks/data-integrity.d.ts +19 -0
  231. package/dist/src/lib/analyzers/python/security-checks/data-integrity.d.ts.map +1 -0
  232. package/dist/src/lib/analyzers/python/security-checks/data-integrity.js +90 -0
  233. package/dist/src/lib/analyzers/python/security-checks/data-integrity.js.map +1 -0
  234. package/dist/src/lib/analyzers/python/security-checks/deserialization.d.ts +20 -0
  235. package/dist/src/lib/analyzers/python/security-checks/deserialization.d.ts.map +1 -0
  236. package/dist/src/lib/analyzers/python/security-checks/deserialization.js +68 -0
  237. package/dist/src/lib/analyzers/python/security-checks/deserialization.js.map +1 -0
  238. package/dist/src/lib/analyzers/python/security-checks/django-security.d.ts +25 -0
  239. package/dist/src/lib/analyzers/python/security-checks/django-security.d.ts.map +1 -0
  240. package/dist/src/lib/analyzers/python/security-checks/django-security.js +180 -0
  241. package/dist/src/lib/analyzers/python/security-checks/django-security.js.map +1 -0
  242. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.d.ts +23 -0
  243. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.d.ts.map +1 -0
  244. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.js +127 -0
  245. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.js.map +1 -0
  246. package/dist/src/lib/analyzers/python/security-checks/exception-handling.d.ts +23 -0
  247. package/dist/src/lib/analyzers/python/security-checks/exception-handling.d.ts.map +1 -0
  248. package/dist/src/lib/analyzers/python/security-checks/exception-handling.js +120 -0
  249. package/dist/src/lib/analyzers/python/security-checks/exception-handling.js.map +1 -0
  250. package/dist/src/lib/analyzers/python/security-checks/flask-security.d.ts +24 -0
  251. package/dist/src/lib/analyzers/python/security-checks/flask-security.d.ts.map +1 -0
  252. package/dist/src/lib/analyzers/python/security-checks/flask-security.js +143 -0
  253. package/dist/src/lib/analyzers/python/security-checks/flask-security.js.map +1 -0
  254. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.d.ts +28 -0
  255. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.d.ts.map +1 -0
  256. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.js +174 -0
  257. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.js.map +1 -0
  258. package/dist/src/lib/analyzers/python/security-checks/insecure-design.d.ts +20 -0
  259. package/dist/src/lib/analyzers/python/security-checks/insecure-design.d.ts.map +1 -0
  260. package/dist/src/lib/analyzers/python/security-checks/insecure-design.js +160 -0
  261. package/dist/src/lib/analyzers/python/security-checks/insecure-design.js.map +1 -0
  262. package/dist/src/lib/analyzers/python/security-checks/logging-failures.d.ts +20 -0
  263. package/dist/src/lib/analyzers/python/security-checks/logging-failures.d.ts.map +1 -0
  264. package/dist/src/lib/analyzers/python/security-checks/logging-failures.js +121 -0
  265. package/dist/src/lib/analyzers/python/security-checks/logging-failures.js.map +1 -0
  266. package/dist/src/lib/analyzers/python/security-checks/nosql-injection.d.ts +26 -0
  267. package/dist/src/lib/analyzers/python/security-checks/nosql-injection.d.ts.map +1 -0
  268. package/dist/src/lib/analyzers/python/security-checks/nosql-injection.js +248 -0
  269. package/dist/src/lib/analyzers/python/security-checks/nosql-injection.js.map +1 -0
  270. package/dist/src/lib/analyzers/python/security-checks/security-misconfiguration.d.ts +26 -0
  271. package/dist/src/lib/analyzers/python/security-checks/security-misconfiguration.d.ts.map +1 -0
  272. package/dist/src/lib/analyzers/python/security-checks/security-misconfiguration.js +375 -0
  273. package/dist/src/lib/analyzers/python/security-checks/security-misconfiguration.js.map +1 -0
  274. package/dist/src/lib/analyzers/python/security-checks/ssrf-detection.d.ts +26 -0
  275. package/dist/src/lib/analyzers/python/security-checks/ssrf-detection.d.ts.map +1 -0
  276. package/dist/src/lib/analyzers/python/security-checks/ssrf-detection.js +160 -0
  277. package/dist/src/lib/analyzers/python/security-checks/ssrf-detection.js.map +1 -0
  278. package/dist/src/lib/analyzers/python/security-checks/web-security.d.ts +23 -0
  279. package/dist/src/lib/analyzers/python/security-checks/web-security.d.ts.map +1 -0
  280. package/dist/src/lib/analyzers/python/security-checks/web-security.js +117 -0
  281. package/dist/src/lib/analyzers/python/security-checks/web-security.js.map +1 -0
  282. package/dist/src/lib/analyzers/python/utils/createVulnerability.d.ts +58 -0
  283. package/dist/src/lib/analyzers/python/utils/createVulnerability.d.ts.map +1 -0
  284. package/dist/src/lib/analyzers/python/utils/createVulnerability.js +71 -0
  285. package/dist/src/lib/analyzers/python/utils/createVulnerability.js.map +1 -0
  286. package/dist/src/lib/analyzers/python-analyzer.d.ts +111 -0
  287. package/dist/src/lib/analyzers/python-analyzer.d.ts.map +1 -0
  288. package/dist/src/lib/analyzers/python-analyzer.js +1600 -0
  289. package/dist/src/lib/analyzers/python-analyzer.js.map +1 -0
  290. package/dist/src/lib/analyzers/secrets/patterns/api-keys/ai-providers.d.ts +14 -0
  291. package/dist/src/lib/analyzers/secrets/patterns/api-keys/ai-providers.d.ts.map +1 -0
  292. package/dist/src/lib/analyzers/secrets/patterns/api-keys/ai-providers.js +47 -0
  293. package/dist/src/lib/analyzers/secrets/patterns/api-keys/ai-providers.js.map +1 -0
  294. package/dist/src/lib/analyzers/secrets/patterns/api-keys/aws.d.ts +13 -0
  295. package/dist/src/lib/analyzers/secrets/patterns/api-keys/aws.d.ts.map +1 -0
  296. package/dist/src/lib/analyzers/secrets/patterns/api-keys/aws.js +36 -0
  297. package/dist/src/lib/analyzers/secrets/patterns/api-keys/aws.js.map +1 -0
  298. package/dist/src/lib/analyzers/secrets/patterns/api-keys/cloud-providers.d.ts +15 -0
  299. package/dist/src/lib/analyzers/secrets/patterns/api-keys/cloud-providers.d.ts.map +1 -0
  300. package/dist/src/lib/analyzers/secrets/patterns/api-keys/cloud-providers.js +68 -0
  301. package/dist/src/lib/analyzers/secrets/patterns/api-keys/cloud-providers.js.map +1 -0
  302. package/dist/src/lib/analyzers/secrets/patterns/api-keys/communication.d.ts +15 -0
  303. package/dist/src/lib/analyzers/secrets/patterns/api-keys/communication.d.ts.map +1 -0
  304. package/dist/src/lib/analyzers/secrets/patterns/api-keys/communication.js +68 -0
  305. package/dist/src/lib/analyzers/secrets/patterns/api-keys/communication.js.map +1 -0
  306. package/dist/src/lib/analyzers/secrets/patterns/api-keys/generic.d.ts +12 -0
  307. package/dist/src/lib/analyzers/secrets/patterns/api-keys/generic.d.ts.map +1 -0
  308. package/dist/src/lib/analyzers/secrets/patterns/api-keys/generic.js +45 -0
  309. package/dist/src/lib/analyzers/secrets/patterns/api-keys/generic.js.map +1 -0
  310. package/dist/src/lib/analyzers/secrets/patterns/api-keys/github.d.ts +14 -0
  311. package/dist/src/lib/analyzers/secrets/patterns/api-keys/github.d.ts.map +1 -0
  312. package/dist/src/lib/analyzers/secrets/patterns/api-keys/github.js +47 -0
  313. package/dist/src/lib/analyzers/secrets/patterns/api-keys/github.js.map +1 -0
  314. package/dist/src/lib/analyzers/secrets/patterns/api-keys/stripe.d.ts +13 -0
  315. package/dist/src/lib/analyzers/secrets/patterns/api-keys/stripe.d.ts.map +1 -0
  316. package/dist/src/lib/analyzers/secrets/patterns/api-keys/stripe.js +36 -0
  317. package/dist/src/lib/analyzers/secrets/patterns/api-keys/stripe.js.map +1 -0
  318. package/dist/src/lib/analyzers/secrets/patterns/api-keys.d.ts +15 -0
  319. package/dist/src/lib/analyzers/secrets/patterns/api-keys.d.ts.map +1 -0
  320. package/dist/src/lib/analyzers/secrets/patterns/api-keys.js +32 -0
  321. package/dist/src/lib/analyzers/secrets/patterns/api-keys.js.map +1 -0
  322. package/dist/src/lib/analyzers/secrets/patterns/credentials.d.ts +15 -0
  323. package/dist/src/lib/analyzers/secrets/patterns/credentials.d.ts.map +1 -0
  324. package/dist/src/lib/analyzers/secrets/patterns/credentials.js +68 -0
  325. package/dist/src/lib/analyzers/secrets/patterns/credentials.js.map +1 -0
  326. package/dist/src/lib/analyzers/secrets/patterns/private-keys.d.ts +16 -0
  327. package/dist/src/lib/analyzers/secrets/patterns/private-keys.d.ts.map +1 -0
  328. package/dist/src/lib/analyzers/secrets/patterns/private-keys.js +79 -0
  329. package/dist/src/lib/analyzers/secrets/patterns/private-keys.js.map +1 -0
  330. package/dist/src/lib/analyzers/secrets/patterns/tokens.d.ts +15 -0
  331. package/dist/src/lib/analyzers/secrets/patterns/tokens.d.ts.map +1 -0
  332. package/dist/src/lib/analyzers/secrets/patterns/tokens.js +58 -0
  333. package/dist/src/lib/analyzers/secrets/patterns/tokens.js.map +1 -0
  334. package/dist/src/lib/analyzers/secrets/secrets-analyzer.d.ts +88 -0
  335. package/dist/src/lib/analyzers/secrets/secrets-analyzer.d.ts.map +1 -0
  336. package/dist/src/lib/analyzers/secrets/secrets-analyzer.js +162 -0
  337. package/dist/src/lib/analyzers/secrets/secrets-analyzer.js.map +1 -0
  338. package/dist/src/lib/analyzers/secrets/validators/context-checker.d.ts +56 -0
  339. package/dist/src/lib/analyzers/secrets/validators/context-checker.d.ts.map +1 -0
  340. package/dist/src/lib/analyzers/secrets/validators/context-checker.js +199 -0
  341. package/dist/src/lib/analyzers/secrets/validators/context-checker.js.map +1 -0
  342. package/dist/src/lib/analyzers/secrets/validators/entropy-checker.d.ts +56 -0
  343. package/dist/src/lib/analyzers/secrets/validators/entropy-checker.d.ts.map +1 -0
  344. package/dist/src/lib/analyzers/secrets/validators/entropy-checker.js +102 -0
  345. package/dist/src/lib/analyzers/secrets/validators/entropy-checker.js.map +1 -0
  346. package/dist/src/lib/analyzers/security-checks/es6-security.d.ts +38 -0
  347. package/dist/src/lib/analyzers/security-checks/es6-security.d.ts.map +1 -0
  348. package/dist/src/lib/analyzers/security-checks/es6-security.js +125 -0
  349. package/dist/src/lib/analyzers/security-checks/es6-security.js.map +1 -0
  350. package/dist/src/lib/analyzers/security-checks/python-async-security.d.ts +46 -0
  351. package/dist/src/lib/analyzers/security-checks/python-async-security.d.ts.map +1 -0
  352. package/dist/src/lib/analyzers/security-checks/python-async-security.js +92 -0
  353. package/dist/src/lib/analyzers/security-checks/python-async-security.js.map +1 -0
  354. package/dist/src/lib/analyzers/security-checks/react-security.d.ts +49 -0
  355. package/dist/src/lib/analyzers/security-checks/react-security.d.ts.map +1 -0
  356. package/dist/src/lib/analyzers/security-checks/react-security.js +125 -0
  357. package/dist/src/lib/analyzers/security-checks/react-security.js.map +1 -0
  358. package/dist/src/lib/analyzers/types.d.ts +92 -0
  359. package/dist/src/lib/analyzers/types.d.ts.map +1 -0
  360. package/dist/src/lib/analyzers/types.js +3 -0
  361. package/dist/src/lib/analyzers/types.js.map +1 -0
  362. package/dist/src/lib/analyzers/typescript/security-checks/access-control.d.ts +19 -0
  363. package/dist/src/lib/analyzers/typescript/security-checks/access-control.d.ts.map +1 -0
  364. package/dist/src/lib/analyzers/typescript/security-checks/access-control.js +210 -0
  365. package/dist/src/lib/analyzers/typescript/security-checks/access-control.js.map +1 -0
  366. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.d.ts +25 -0
  367. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.d.ts.map +1 -0
  368. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.js +242 -0
  369. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.js.map +1 -0
  370. package/dist/src/lib/analyzers/typescript/security-checks/authentication.d.ts +28 -0
  371. package/dist/src/lib/analyzers/typescript/security-checks/authentication.d.ts.map +1 -0
  372. package/dist/src/lib/analyzers/typescript/security-checks/authentication.js +357 -0
  373. package/dist/src/lib/analyzers/typescript/security-checks/authentication.js.map +1 -0
  374. package/dist/src/lib/analyzers/typescript/security-checks/code-injection.d.ts +26 -0
  375. package/dist/src/lib/analyzers/typescript/security-checks/code-injection.d.ts.map +1 -0
  376. package/dist/src/lib/analyzers/typescript/security-checks/code-injection.js +380 -0
  377. package/dist/src/lib/analyzers/typescript/security-checks/code-injection.js.map +1 -0
  378. package/dist/src/lib/analyzers/typescript/security-checks/code-quality.d.ts +23 -0
  379. package/dist/src/lib/analyzers/typescript/security-checks/code-quality.d.ts.map +1 -0
  380. package/dist/src/lib/analyzers/typescript/security-checks/code-quality.js +109 -0
  381. package/dist/src/lib/analyzers/typescript/security-checks/code-quality.js.map +1 -0
  382. package/dist/src/lib/analyzers/typescript/security-checks/credentials-crypto.d.ts +21 -0
  383. package/dist/src/lib/analyzers/typescript/security-checks/credentials-crypto.d.ts.map +1 -0
  384. package/dist/src/lib/analyzers/typescript/security-checks/credentials-crypto.js +153 -0
  385. package/dist/src/lib/analyzers/typescript/security-checks/credentials-crypto.js.map +1 -0
  386. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.d.ts +23 -0
  387. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.d.ts.map +1 -0
  388. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.js +146 -0
  389. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.js.map +1 -0
  390. package/dist/src/lib/analyzers/typescript/security-checks/exception-handling.d.ts +23 -0
  391. package/dist/src/lib/analyzers/typescript/security-checks/exception-handling.d.ts.map +1 -0
  392. package/dist/src/lib/analyzers/typescript/security-checks/exception-handling.js +187 -0
  393. package/dist/src/lib/analyzers/typescript/security-checks/exception-handling.js.map +1 -0
  394. package/dist/src/lib/analyzers/typescript/security-checks/information-disclosure.d.ts +19 -0
  395. package/dist/src/lib/analyzers/typescript/security-checks/information-disclosure.d.ts.map +1 -0
  396. package/dist/src/lib/analyzers/typescript/security-checks/information-disclosure.js +97 -0
  397. package/dist/src/lib/analyzers/typescript/security-checks/information-disclosure.js.map +1 -0
  398. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.d.ts +29 -0
  399. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.d.ts.map +1 -0
  400. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.js +319 -0
  401. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.js.map +1 -0
  402. package/dist/src/lib/analyzers/typescript/security-checks/logging-failures.d.ts +21 -0
  403. package/dist/src/lib/analyzers/typescript/security-checks/logging-failures.d.ts.map +1 -0
  404. package/dist/src/lib/analyzers/typescript/security-checks/logging-failures.js +121 -0
  405. package/dist/src/lib/analyzers/typescript/security-checks/logging-failures.js.map +1 -0
  406. package/dist/src/lib/analyzers/typescript/security-checks/security-misconfiguration.d.ts +27 -0
  407. package/dist/src/lib/analyzers/typescript/security-checks/security-misconfiguration.d.ts.map +1 -0
  408. package/dist/src/lib/analyzers/typescript/security-checks/security-misconfiguration.js +213 -0
  409. package/dist/src/lib/analyzers/typescript/security-checks/security-misconfiguration.js.map +1 -0
  410. package/dist/src/lib/analyzers/typescript/security-checks/type-security.d.ts +19 -0
  411. package/dist/src/lib/analyzers/typescript/security-checks/type-security.d.ts.map +1 -0
  412. package/dist/src/lib/analyzers/typescript/security-checks/type-security.js +59 -0
  413. package/dist/src/lib/analyzers/typescript/security-checks/type-security.js.map +1 -0
  414. package/dist/src/lib/analyzers/typescript/type-checker.d.ts +17 -0
  415. package/dist/src/lib/analyzers/typescript/type-checker.d.ts.map +1 -0
  416. package/dist/src/lib/analyzers/typescript/type-checker.js +515 -0
  417. package/dist/src/lib/analyzers/typescript/type-checker.js.map +1 -0
  418. package/dist/src/lib/analyzers/typescript/utils/createVulnerability.d.ts +58 -0
  419. package/dist/src/lib/analyzers/typescript/utils/createVulnerability.d.ts.map +1 -0
  420. package/dist/src/lib/analyzers/typescript/utils/createVulnerability.js +71 -0
  421. package/dist/src/lib/analyzers/typescript/utils/createVulnerability.js.map +1 -0
  422. package/dist/src/lib/analyzers/typescript-analyzer.d.ts +116 -0
  423. package/dist/src/lib/analyzers/typescript-analyzer.d.ts.map +1 -0
  424. package/dist/src/lib/analyzers/typescript-analyzer.js +1660 -0
  425. package/dist/src/lib/analyzers/typescript-analyzer.js.map +1 -0
  426. package/dist/src/lib/security/compliance-mapping.d.ts +29 -0
  427. package/dist/src/lib/security/compliance-mapping.d.ts.map +1 -0
  428. package/dist/src/lib/security/compliance-mapping.js +1342 -0
  429. package/dist/src/lib/security/compliance-mapping.js.map +1 -0
  430. package/dist/src/lib/security/severity-scoring.d.ts +47 -0
  431. package/dist/src/lib/security/severity-scoring.d.ts.map +1 -0
  432. package/dist/src/lib/security/severity-scoring.js +965 -0
  433. package/dist/src/lib/security/severity-scoring.js.map +1 -0
  434. package/dist/src/lib/standards/references.d.ts +16 -0
  435. package/dist/src/lib/standards/references.d.ts.map +1 -0
  436. package/dist/src/lib/standards/references.js +1161 -0
  437. package/dist/src/lib/standards/references.js.map +1 -0
  438. package/dist/src/lib/types/index.d.ts +167 -0
  439. package/dist/src/lib/types/index.d.ts.map +1 -0
  440. package/dist/src/lib/types/index.js +3 -0
  441. package/dist/src/lib/types/index.js.map +1 -0
  442. package/dist/src/lib/utils/code-cleaner.d.ts +59 -0
  443. package/dist/src/lib/utils/code-cleaner.d.ts.map +1 -0
  444. package/dist/src/lib/utils/code-cleaner.js +283 -0
  445. package/dist/src/lib/utils/code-cleaner.js.map +1 -0
  446. package/package.json +51 -0
  447. package/src/commands/auth.ts +308 -0
  448. package/src/commands/config.ts +226 -0
  449. package/src/commands/init.ts +202 -0
  450. package/src/commands/scan.ts +238 -0
  451. package/src/config/config-loader.ts +175 -0
  452. package/src/reporters/cli-reporter.ts +282 -0
  453. package/src/scanner/local-scanner.ts +250 -0
  454. package/tsconfig.json +24 -0
  455. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,1600 @@
1
+ "use strict";
2
+ /**
3
+ * ⚠️ SHARED MODULE: Python Security Analyzer
4
+ *
5
+ * CRITICAL: This module is used by BOTH WebTool and GitHub App
6
+ *
7
+ * WebTool uses this for:
8
+ * - /api/analyze endpoint - Interactive single-file analysis (<3s target)
9
+ * - Real-time vulnerability detection for individual developers
10
+ *
11
+ * GitHub App uses this for:
12
+ * - /api/github/webhook - Batch PR analysis (10-30s OK)
13
+ * - Automated security checks for professional teams
14
+ *
15
+ * ⚠️ BEFORE MODIFYING THIS FILE:
16
+ * 1. Run all 96 analyzer tests: npm test analyzers
17
+ * 2. Test WebTool: Paste Python code at /analyze → Verify results
18
+ * 3. Test GitHub: Open PR with Python → Verify webhook comment
19
+ * 4. Verify performance: Analysis must complete in <2s per file
20
+ * 5. Check detection rate: All 19 Python checks must still detect
21
+ *
22
+ * CRITICAL OUTPUT FORMAT (DO NOT CHANGE):
23
+ * - result.security.vulnerabilities - Used by both systems
24
+ * - Each vulnerability has: line, message, severity, cvssScore, owasp, cwe
25
+ * - Changing this structure breaks BOTH WebTool and GitHub UI parsing
26
+ *
27
+ * See: docs/technical/WEBTOOL_GITHUB_SEPARATION.md
28
+ *
29
+ * Last modified: 2025-11-18
30
+ * Last verified (both systems): 2025-11-18
31
+ */
32
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ var desc = Object.getOwnPropertyDescriptor(m, k);
35
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
36
+ desc = { enumerable: true, get: function() { return m[k]; } };
37
+ }
38
+ Object.defineProperty(o, k2, desc);
39
+ }) : (function(o, m, k, k2) {
40
+ if (k2 === undefined) k2 = k;
41
+ o[k2] = m[k];
42
+ }));
43
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
44
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
45
+ }) : function(o, v) {
46
+ o["default"] = v;
47
+ });
48
+ var __importStar = (this && this.__importStar) || (function () {
49
+ var ownKeys = function(o) {
50
+ ownKeys = Object.getOwnPropertyNames || function (o) {
51
+ var ar = [];
52
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
53
+ return ar;
54
+ };
55
+ return ownKeys(o);
56
+ };
57
+ return function (mod) {
58
+ if (mod && mod.__esModule) return mod;
59
+ var result = {};
60
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
61
+ __setModuleDefault(result, mod);
62
+ return result;
63
+ };
64
+ })();
65
+ Object.defineProperty(exports, "__esModule", { value: true });
66
+ exports.PythonAnalyzer = void 0;
67
+ const references_1 = require("../standards/references");
68
+ const severity_scoring_1 = require("../security/severity-scoring");
69
+ const compliance_mapping_1 = require("../security/compliance-mapping");
70
+ const code_cleaner_1 = require("../utils/code-cleaner");
71
+ const PythonAsyncSecurity = __importStar(require("./security-checks/python-async-security"));
72
+ const injection_attacks_1 = require("./python/security-checks/injection-attacks");
73
+ const credentials_crypto_1 = require("./python/security-checks/credentials-crypto");
74
+ const deserialization_1 = require("./python/security-checks/deserialization");
75
+ const web_security_1 = require("./python/security-checks/web-security");
76
+ const code_quality_1 = require("./python/security-checks/code-quality");
77
+ const django_security_1 = require("./python/security-checks/django-security");
78
+ const flask_security_1 = require("./python/security-checks/flask-security");
79
+ const security_misconfiguration_1 = require("./python/security-checks/security-misconfiguration");
80
+ const exception_handling_1 = require("./python/security-checks/exception-handling");
81
+ const enhanced_supply_chain_1 = require("./python/security-checks/enhanced-supply-chain");
82
+ const access_control_1 = require("./python/security-checks/access-control");
83
+ const crypto_failures_1 = require("./python/security-checks/crypto-failures");
84
+ const insecure_design_1 = require("./python/security-checks/insecure-design");
85
+ const logging_failures_1 = require("./python/security-checks/logging-failures");
86
+ const data_integrity_1 = require("./python/security-checks/data-integrity");
87
+ const nosql_injection_1 = require("./python/security-checks/nosql-injection");
88
+ const ssrf_detection_1 = require("./python/security-checks/ssrf-detection");
89
+ const authentication_flaws_1 = require("./python/security-checks/authentication-flaws");
90
+ const secrets_analyzer_1 = require("./secrets/secrets-analyzer");
91
+ const ai_generated_code_1 = require("./python/security-checks/ai-generated-code");
92
+ class PythonAnalyzer {
93
+ constructor() {
94
+ this.language = 'python';
95
+ }
96
+ async analyze(input) {
97
+ const result = {
98
+ syntax: { valid: true, errors: [], lineErrors: [] },
99
+ quality: { score: 100, issues: [] },
100
+ performance: { score: 100, suggestions: [] },
101
+ security: { vulnerabilities: [] },
102
+ metrics: { complexity: 1, maintainability: 100, lines: 0, functions: 0 }
103
+ };
104
+ try {
105
+ this.analyzeSyntax(input.code, result);
106
+ this.analyzeQuality(input.code, result);
107
+ this.analyzePerformance(input.code, result);
108
+ this.analyzeSecurity(input.code, result);
109
+ this.calculateMetrics(input.code, result);
110
+ // AI-Generated Code Detection (Phase 1.5, Week 5-7)
111
+ const lines = input.code.split('\n');
112
+ result.security.vulnerabilities.push(...(0, ai_generated_code_1.checkAIGeneratedCode)(lines, input.filename));
113
+ }
114
+ catch (error) {
115
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
116
+ result.syntax.valid = false;
117
+ result.syntax.errors.push(`Python analysis error: ${errorMessage}`);
118
+ }
119
+ return result;
120
+ }
121
+ async validateSyntax(code) {
122
+ // Basic Python syntax checks
123
+ const lines = code.split('\n');
124
+ for (let i = 0; i < lines.length; i++) {
125
+ const line = lines[i].trim();
126
+ if (!line || line.startsWith('#'))
127
+ continue;
128
+ // Verificar estruturas que devem terminar com :
129
+ if (line.match(/^(if|for|while|def|class|try|except|finally|with|elif)\s/) && !line.endsWith(':')) {
130
+ return false;
131
+ }
132
+ // Verificar comentários JavaScript em código Python
133
+ if (line.includes('//')) {
134
+ return false;
135
+ }
136
+ }
137
+ return true;
138
+ }
139
+ getLanguageInfo() {
140
+ return {
141
+ name: 'Python',
142
+ extensions: ['.py', '.pyw', '.pyc', '.pyo', '.pyd'],
143
+ description: 'Language for data science, web, and automation'
144
+ };
145
+ }
146
+ analyzeSyntax(code, result) {
147
+ const errors = [];
148
+ const lineErrors = [];
149
+ const processedLines = new Set(); // Track lines that already have errors
150
+ const lines = code.split('\n');
151
+ let inMultilineString = false; // Track if we're inside a triple-quoted string
152
+ // First pass: Priority syntax errors (critical issues first)
153
+ lines.forEach((line, index) => {
154
+ const lineNumber = index + 1;
155
+ const trimmed = line.trim();
156
+ // CRITICAL: Track Python triple-quote strings (""" ... """ or ''' ... ''')
157
+ const hasTripleQuote = trimmed.includes('"""') || trimmed.includes("'''");
158
+ if (hasTripleQuote) {
159
+ if (!inMultilineString) {
160
+ // Start of multi-line string
161
+ inMultilineString = true;
162
+ // Check if it closes on the same line (single-line docstring)
163
+ const tripleQuoteCount = (trimmed.match(/"""/g) || []).length + (trimmed.match(/'''/g) || []).length;
164
+ if (tripleQuoteCount >= 2) {
165
+ // Opens and closes on same line, reset flag
166
+ inMultilineString = false;
167
+ }
168
+ return; // Skip this line
169
+ }
170
+ else {
171
+ // End of multi-line string
172
+ inMultilineString = false;
173
+ return; // Skip this line
174
+ }
175
+ }
176
+ // Skip lines inside multi-line strings, empty lines, and comments
177
+ if (inMultilineString || !trimmed || trimmed.startsWith('#'))
178
+ return;
179
+ // Priority 1: Check for unclosed strings (general detection)
180
+ // CRITICAL FIX: Remove comments to prevent false positives
181
+ // Example: message = "Hello World # Missing closing quote
182
+ const lineWithoutComments = code_cleaner_1.CodeCleaner.removeLineComments(line, 'python');
183
+ // Detect unclosed strings: count unescaped quotes
184
+ const checkUnclosedString = (text, quoteChar) => {
185
+ let count = 0;
186
+ let escaped = false;
187
+ for (let i = 0; i < text.length; i++) {
188
+ if (escaped) {
189
+ escaped = false;
190
+ continue;
191
+ }
192
+ if (text[i] === '\\') {
193
+ escaped = true;
194
+ continue;
195
+ }
196
+ if (text[i] === quoteChar) {
197
+ count++;
198
+ }
199
+ }
200
+ // Odd count means unclosed string
201
+ return count % 2 !== 0;
202
+ };
203
+ // Check for unclosed double quotes
204
+ if (checkUnclosedString(lineWithoutComments, '"')) {
205
+ lineErrors.push({
206
+ line: lineNumber,
207
+ error: 'Unclosed string - missing closing double quote (")',
208
+ suggestion: 'Add " to close the string',
209
+ severity: 'error'
210
+ });
211
+ // Don't return - continue checking for other errors
212
+ }
213
+ // Check for unclosed single quotes
214
+ if (checkUnclosedString(lineWithoutComments, "'")) {
215
+ lineErrors.push({
216
+ line: lineNumber,
217
+ error: "Unclosed string - missing closing single quote (')",
218
+ suggestion: "Add ' to close the string",
219
+ severity: 'error'
220
+ });
221
+ // Don't return - continue checking for other errors
222
+ }
223
+ // Priority 2: Check for unclosed f-strings (improved pattern)
224
+ const fStringMatches = lineWithoutComments.match(/f["'][^"']*\{[^}]*$/);
225
+ if (fStringMatches) {
226
+ lineErrors.push({
227
+ line: lineNumber,
228
+ error: 'f-string with unclosed brace',
229
+ suggestion: 'Add } to close the expression in the f-string',
230
+ severity: 'error'
231
+ });
232
+ // Don't return - continue checking for other errors
233
+ }
234
+ // Priority 3: Check for format string argument mismatch (improved logic)
235
+ // Use cleaned line to avoid false positives from comments
236
+ const formatMatch = lineWithoutComments.match(/\"([^\"]*)\"\s*\.format\s*\(([^)]*)\)/);
237
+ if (formatMatch) {
238
+ const formatStr = formatMatch[1];
239
+ const argsStr = formatMatch[2];
240
+ // Count placeholders in the format string
241
+ const placeholders = (formatStr.match(/\{\}/g) || []).length;
242
+ // Count arguments more accurately
243
+ let argsCount = 0;
244
+ if (argsStr.trim()) {
245
+ // Split by comma, but be careful with nested structures
246
+ const args = argsStr.split(',').map(arg => arg.trim()).filter(arg => arg.length > 0);
247
+ argsCount = args.length;
248
+ }
249
+ if (argsCount > placeholders) {
250
+ lineErrors.push({
251
+ line: lineNumber,
252
+ error: 'Extra arguments in .format()',
253
+ suggestion: `Has ${argsCount} arguments but only ${placeholders} placeholder(s) {}`,
254
+ severity: 'error'
255
+ });
256
+ // Continue checking for other errors
257
+ }
258
+ }
259
+ // Priority 4: JavaScript-style comments in Python
260
+ // CRITICAL FIX: Check in original line (before comment removal) BUT avoid strings
261
+ // We want to detect: const x = 5; // JavaScript comment
262
+ // But not detect: url = "https://example.com"
263
+ if (line.includes('//') && !line.match(/["'].*\/\/.*["']/)) {
264
+ lineErrors.push({
265
+ line: lineNumber,
266
+ error: 'Python uses # for comments, not //',
267
+ suggestion: 'Change // to # at the beginning of the comment',
268
+ severity: 'error'
269
+ });
270
+ // Continue checking
271
+ }
272
+ // Priority 5: Missing colons in control structures
273
+ // CRITICAL FIX: Check lineWithoutComments (not trimmed) to avoid false positives from comments
274
+ // Example: def foo(): # comment <- This should NOT trigger error!
275
+ if ((trimmed.startsWith('if ') ||
276
+ trimmed.startsWith('for ') ||
277
+ trimmed.startsWith('while ') ||
278
+ trimmed.startsWith('def ') ||
279
+ trimmed.startsWith('class ') ||
280
+ trimmed.startsWith('try') ||
281
+ trimmed.startsWith('except') ||
282
+ trimmed.startsWith('finally') ||
283
+ trimmed.startsWith('with ') ||
284
+ trimmed.startsWith('elif ')) &&
285
+ !lineWithoutComments.trimEnd().endsWith(':')) {
286
+ lineErrors.push({
287
+ line: lineNumber,
288
+ error: 'Missing colon at the end of statement',
289
+ suggestion: `Add : at the end: ${lineWithoutComments.trimEnd()}:`,
290
+ severity: 'error'
291
+ });
292
+ // Continue checking
293
+ }
294
+ // Priority 6: Assignment in conditional (if x = 10: instead of if x == 10:)
295
+ // CRITICAL: Detect single = in if/while/elif but allow := (walrus operator)
296
+ // Use cleaned line to avoid false positives from comments
297
+ if ((trimmed.startsWith('if ') || trimmed.startsWith('elif ') || trimmed.startsWith('while ')) &&
298
+ lineWithoutComments.match(/\s+\w+\s*=\s*[^=]/) &&
299
+ !lineWithoutComments.includes(':=')) {
300
+ lineErrors.push({
301
+ line: lineNumber,
302
+ error: 'Assignment (=) in conditional statement - should use comparison (==)',
303
+ suggestion: 'Change = to == for comparison, or use := for assignment (walrus operator)',
304
+ severity: 'error'
305
+ });
306
+ // Continue checking
307
+ }
308
+ // Priority 6: Python 3 print syntax
309
+ // Use cleaned line to avoid false positives from comments
310
+ if (lineWithoutComments.match(/\bprint\s+[^(]/)) {
311
+ lineErrors.push({
312
+ line: lineNumber,
313
+ error: 'print in Python 3 requires parentheses',
314
+ suggestion: 'Use print("message") instead of print "message"',
315
+ severity: 'error'
316
+ });
317
+ // Continue checking
318
+ }
319
+ // Priority 7: Invalid escape sequences in strings
320
+ // Python only recognizes specific escape sequences: \n, \t, \r, \\, \', \", etc.
321
+ // Common error: "C:\new\folder" has invalid \n and \f (should be raw string or escaped)
322
+ // Use cleaned line to avoid false positives from comments
323
+ // Check for invalid escape sequences in double-quoted strings
324
+ const doubleQuotedMatches = lineWithoutComments.matchAll(/"([^"]*)"/g);
325
+ for (const match of doubleQuotedMatches) {
326
+ const stringContent = match[1];
327
+ // Check for invalid escape sequences (backslash followed by character that's not a valid escape)
328
+ // Valid escapes: \n, \t, \r, \\, \', \", \a, \b, \f, \v, \0, \x, \u, \N, and octal
329
+ const invalidEscapes = stringContent.match(/\\([^ntr\\'\"abfv0xuN0-7])/g);
330
+ if (invalidEscapes) {
331
+ lineErrors.push({
332
+ line: lineNumber,
333
+ error: `Invalid escape sequence(s): ${invalidEscapes.join(', ')}`,
334
+ suggestion: 'Use raw string (r"...") for paths or escape the backslash (\\\\)',
335
+ severity: 'error'
336
+ });
337
+ break; // Only report once per line
338
+ }
339
+ }
340
+ // Check for invalid escape sequences in single-quoted strings
341
+ const singleQuotedMatches = lineWithoutComments.matchAll(/'([^']*)'/g);
342
+ for (const match of singleQuotedMatches) {
343
+ const stringContent = match[1];
344
+ const invalidEscapes = stringContent.match(/\\([^ntr\\'\"abfv0xuN0-7])/g);
345
+ if (invalidEscapes) {
346
+ lineErrors.push({
347
+ line: lineNumber,
348
+ error: `Invalid escape sequence(s): ${invalidEscapes.join(', ')}`,
349
+ suggestion: 'Use raw string (r"...") for paths or escape the backslash (\\\\)',
350
+ severity: 'error'
351
+ });
352
+ break; // Only report once per line
353
+ }
354
+ }
355
+ // Priority 8: Malformed f-strings (missing opening quote)
356
+ // Pattern: print(f{...} or similar where f is followed by { without quotes
357
+ // Use cleaned line to avoid false positives from comments
358
+ if (lineWithoutComments.match(/\bf\s*\{[^}]*\}/)) {
359
+ lineErrors.push({
360
+ line: lineNumber,
361
+ error: 'Malformed f-string - missing quotes',
362
+ suggestion: 'f-strings must start with quotes: f"{...}" or f\'{...}\'',
363
+ severity: 'error'
364
+ });
365
+ // Continue checking
366
+ }
367
+ // Priority 9: Missing parentheses on method calls
368
+ // Pattern: .date > or .date < or .date = (should be .date())
369
+ // Use cleaned line to avoid false positives from comments
370
+ if (lineWithoutComments.match(/\.\w+\s*[><=!]/)) {
371
+ const match = lineWithoutComments.match(/\.(\w+)\s*([><=!])/);
372
+ if (match) {
373
+ const methodName = match[1];
374
+ // Common Python methods that require parentheses
375
+ const methodsRequiringParens = ['date', 'time', 'now', 'today', 'strip', 'lower', 'upper', 'count', 'copy'];
376
+ if (methodsRequiringParens.includes(methodName)) {
377
+ lineErrors.push({
378
+ line: lineNumber,
379
+ error: `Method .${methodName} requires parentheses`,
380
+ suggestion: `Add parentheses: .${methodName}()`,
381
+ severity: 'error'
382
+ });
383
+ }
384
+ }
385
+ // Continue checking
386
+ }
387
+ // Priority 10: Trailing comma in assignments (not in lists/tuples)
388
+ // Pattern: self.var = value, at end of line
389
+ // Use cleaned line to avoid false positives from comments
390
+ if (lineWithoutComments.match(/=\s*[^,\[\{]+,\s*$/) && !lineWithoutComments.includes('[') && !lineWithoutComments.includes('{')) {
391
+ lineErrors.push({
392
+ line: lineNumber,
393
+ error: 'Extra comma at the end of assignment',
394
+ suggestion: 'Remove the trailing comma (or were you trying to create a tuple?)',
395
+ severity: 'error'
396
+ });
397
+ // Continue checking
398
+ }
399
+ // Priority 11: Incomplete ternary operator (missing value after else)
400
+ // Pattern: var = "value" if condition else (missing value)
401
+ // Use cleaned line to avoid false positives from comments
402
+ if (lineWithoutComments.match(/=.*\bif\b.*\belse\s*$/)) {
403
+ lineErrors.push({
404
+ line: lineNumber,
405
+ error: 'Incomplete ternary operator - missing value after "else"',
406
+ suggestion: 'Complete: variable = value_if_true if condition else value_if_false',
407
+ severity: 'error'
408
+ });
409
+ // Continue checking
410
+ }
411
+ // Priority 12: AI Hallucination - .push() instead of .append()
412
+ // JavaScript method being used in Python
413
+ // Use cleaned line to avoid false positives from comments
414
+ if (lineWithoutComments.match(/\.\s*push\s*\(/)) {
415
+ lineErrors.push({
416
+ line: lineNumber,
417
+ error: 'Method .push() does not exist in Python - use .append()',
418
+ suggestion: 'In Python, lists use .append() instead of .push()',
419
+ severity: 'error'
420
+ });
421
+ // Continue checking
422
+ }
423
+ // Priority 13: Empty parentheses in class definition (not inheriting)
424
+ // Pattern: class ClassName(): (should be class ClassName:)
425
+ // Use cleaned line to avoid false positives from comments
426
+ if (lineWithoutComments.match(/^\s*class\s+\w+\s*\(\s*\)\s*:/)) {
427
+ lineErrors.push({
428
+ line: lineNumber,
429
+ error: 'Unnecessary empty parentheses in class definition',
430
+ suggestion: 'Remove empty parentheses: class ClassName: (or add base class if inheriting)',
431
+ severity: 'warning'
432
+ });
433
+ // Continue checking
434
+ }
435
+ // Priority 14: Check for missing commas in dictionaries
436
+ // Pattern: key: value followed by a new key (without comma)
437
+ // Example: 'age': int(record.get('age', 0))
438
+ // 'active': ... <- missing comma before 'active'
439
+ if (trimmed.match(/['"].*['"]\s*:\s*/) && !trimmed.includes('#')) {
440
+ // This line starts a dict key
441
+ const nextLineIndex = index + 1;
442
+ if (nextLineIndex < lines.length) {
443
+ const nextLine = lines[nextLineIndex].trim();
444
+ // Check if next line also has a dict key and current line doesn't end with comma or opening brace
445
+ if (nextLine.match(/^['"].*['"]\s*:/) &&
446
+ !trimmed.endsWith(',') &&
447
+ !trimmed.endsWith('{') &&
448
+ !nextLine.startsWith('}')) {
449
+ lineErrors.push({
450
+ line: lineNumber,
451
+ error: 'Missing comma in dictionary',
452
+ suggestion: 'Add comma at the end of this line before the next key',
453
+ severity: 'error'
454
+ });
455
+ // Continue checking
456
+ }
457
+ }
458
+ }
459
+ // Priority 15: Check for trailing commas before comments
460
+ // Example: float(record['amount'], # comment
461
+ // CRITICAL FIX: Exclude list/tuple items (trailing commas are valid in Python)
462
+ // Valid: "item", # comment (in a list)
463
+ // Invalid: float(x, # missing closing paren
464
+ if (trimmed.match(/,\s*#/)) {
465
+ const beforeComment = trimmed.split('#')[0].trim();
466
+ // Check if this is a valid list/tuple/dict item with trailing comma
467
+ const isListItem = beforeComment.match(/^["'][^"']*["']\s*,\s*$/) || // String with trailing comma
468
+ beforeComment.match(/^[^=()]+,\s*$/); // Expression with trailing comma
469
+ // Check if line has unmatched opening bracket (likely a function call issue)
470
+ const hasOpenParen = trimmed.includes('(') && !trimmed.includes(')');
471
+ // Only flag if it's likely a function call with missing argument, not a list item
472
+ if (beforeComment.endsWith(',') && hasOpenParen && !isListItem) {
473
+ lineErrors.push({
474
+ line: lineNumber,
475
+ error: 'Extra comma before comment',
476
+ suggestion: 'Remove the extra comma or add another argument',
477
+ severity: 'error'
478
+ });
479
+ // Continue checking
480
+ }
481
+ }
482
+ });
483
+ // NEW: Check for missing imports (scan whole code)
484
+ this.checkMissingImports(code, lineErrors);
485
+ // NEW: Check for unclosed function/method calls across multiple lines
486
+ this.checkUnbalancedParentheses(code, lineErrors);
487
+ // Advanced detections (similar to JavaScript analyzer)
488
+ this.detectAIHallucinations(code, lineErrors);
489
+ this.detectIndentationErrors(code, lineErrors);
490
+ this.detectTypeErrors(code, lineErrors);
491
+ this.detectNameErrors(code, lineErrors);
492
+ this.detectAttributeErrors(code, lineErrors);
493
+ this.detectIndexErrors(code, lineErrors);
494
+ this.detectKeyErrors(code, lineErrors);
495
+ this.detectMutableDefaults(code, lineErrors);
496
+ this.detectLoopModification(code, lineErrors);
497
+ this.detectScopeIssues(code, lineErrors);
498
+ // Second pass: Bracket/parentheses checking (only if no critical errors found)
499
+ if (lineErrors.filter(e => e.severity === 'error').length === 0) {
500
+ this.checkBracketBalance(code, errors, lineErrors);
501
+ }
502
+ // Third pass: Indentation warnings (ALWAYS run - helps identify root cause of syntax errors)
503
+ lines.forEach((line, index) => {
504
+ const lineNumber = index + 1;
505
+ const trimmed = line.trim();
506
+ // Only check indentation for non-empty, non-comment lines that are indented
507
+ if (trimmed && !trimmed.startsWith('#') && line.startsWith(' ') && lineNumber > 1) {
508
+ const indentation = line.search(/\S/);
509
+ // Skip indentation check for definition lines
510
+ const isDefinitionLine = trimmed.startsWith('def ') || trimmed.startsWith('class ') ||
511
+ trimmed.startsWith('if ') || trimmed.startsWith('for ') ||
512
+ trimmed.startsWith('while ') || trimmed.startsWith('try:') ||
513
+ trimmed.startsWith('except') || trimmed.startsWith('finally');
514
+ if (!isDefinitionLine && indentation % 4 !== 0) {
515
+ lineErrors.push({
516
+ line: lineNumber,
517
+ error: `Incorrect indentation (${indentation} spaces)`,
518
+ suggestion: 'Use multiples of 4 spaces for indentation in Python',
519
+ severity: 'warning'
520
+ });
521
+ }
522
+ }
523
+ });
524
+ result.syntax.errors = errors;
525
+ result.syntax.lineErrors = lineErrors;
526
+ result.syntax.valid = errors.length === 0 && lineErrors.filter(e => e.severity === 'error').length === 0;
527
+ if (!result.syntax.valid || lineErrors.length > 0) {
528
+ result.quality.score -= lineErrors.length * 15;
529
+ }
530
+ }
531
+ checkBracketBalance(code, errors, lineErrors) {
532
+ let parenBalance = 0;
533
+ let braceBalance = 0;
534
+ let bracketBalance = 0;
535
+ let inLineComment = false;
536
+ let inString = false;
537
+ let inMultilineString = false;
538
+ let stringChar = '';
539
+ let currentLine = 1;
540
+ // Track opening positions for better error reporting
541
+ const openBraces = [];
542
+ for (let i = 0; i < code.length; i++) {
543
+ const char = code[i];
544
+ const nextChar = code[i + 1];
545
+ const nextNextChar = code[i + 2];
546
+ // Track line numbers
547
+ if (char === '\n') {
548
+ currentLine++;
549
+ inLineComment = false; // End line comment
550
+ }
551
+ // Handle line comments
552
+ if (!inString && !inMultilineString && char === '#') {
553
+ inLineComment = true;
554
+ continue;
555
+ }
556
+ // Skip if in comment
557
+ if (inLineComment)
558
+ continue;
559
+ // Handle multiline strings (triple quotes)
560
+ if (!inString && (char === '"' || char === "'")) {
561
+ if (nextChar === char && nextNextChar === char) {
562
+ if (!inMultilineString) {
563
+ inMultilineString = true;
564
+ stringChar = char;
565
+ }
566
+ else if (char === stringChar) {
567
+ inMultilineString = false;
568
+ stringChar = '';
569
+ }
570
+ i += 2; // Skip next two chars
571
+ continue;
572
+ }
573
+ }
574
+ // Handle single line strings
575
+ if (!inMultilineString && (char === '"' || char === "'")) {
576
+ if (!inString) {
577
+ inString = true;
578
+ stringChar = char;
579
+ }
580
+ else if (char === stringChar && code[i - 1] !== '\\') {
581
+ inString = false;
582
+ stringChar = '';
583
+ }
584
+ continue;
585
+ }
586
+ // Only count brackets outside comments and strings
587
+ if (!inLineComment && !inString && !inMultilineString) {
588
+ if (char === '(') {
589
+ parenBalance++;
590
+ openBraces.push({ line: currentLine, char: '(' });
591
+ }
592
+ else if (char === ')') {
593
+ parenBalance--;
594
+ // Find matching opening parenthesis
595
+ for (let j = openBraces.length - 1; j >= 0; j--) {
596
+ if (openBraces[j].char === '(') {
597
+ openBraces.splice(j, 1);
598
+ break;
599
+ }
600
+ }
601
+ }
602
+ else if (char === '{') {
603
+ braceBalance++;
604
+ openBraces.push({ line: currentLine, char: '{' });
605
+ }
606
+ else if (char === '}') {
607
+ braceBalance--;
608
+ // Find matching opening brace
609
+ for (let j = openBraces.length - 1; j >= 0; j--) {
610
+ if (openBraces[j].char === '{') {
611
+ openBraces.splice(j, 1);
612
+ break;
613
+ }
614
+ }
615
+ }
616
+ else if (char === '[') {
617
+ bracketBalance++;
618
+ openBraces.push({ line: currentLine, char: '[' });
619
+ }
620
+ else if (char === ']') {
621
+ bracketBalance--;
622
+ // Find matching opening bracket
623
+ for (let j = openBraces.length - 1; j >= 0; j--) {
624
+ if (openBraces[j].char === '[') {
625
+ openBraces.splice(j, 1);
626
+ break;
627
+ }
628
+ }
629
+ }
630
+ }
631
+ }
632
+ // Create line-specific errors for unmatched brackets
633
+ openBraces.forEach(brace => {
634
+ const closingChar = brace.char === '{' ? '}' : brace.char === '(' ? ')' : ']';
635
+ const typeName = brace.char === '{' ? 'brace' : brace.char === '(' ? 'parenthesis' : 'bracket';
636
+ lineErrors.push({
637
+ line: brace.line,
638
+ error: `${typeName.charAt(0).toUpperCase() + typeName.slice(1)} "${brace.char}" was not closed`,
639
+ suggestion: `Add "${closingChar}" to close the ${typeName} opened on line ${brace.line}`,
640
+ severity: 'error'
641
+ });
642
+ });
643
+ // DON'T add general balance errors - the code above already adds specific line errors
644
+ // with proper line numbers, enabling Auto-Fix functionality
645
+ }
646
+ analyzeQuality(code, result) {
647
+ const issues = [];
648
+ // Check for snake_case variable names
649
+ const camelCaseVars = code.match(/\b[a-z]+[A-Z][a-zA-Z]*\s*=/g);
650
+ if (camelCaseVars) {
651
+ issues.push({
652
+ type: 'warning',
653
+ message: 'Use snake_case for variable names in Python',
654
+ severity: 'medium'
655
+ });
656
+ result.quality.score -= 5;
657
+ }
658
+ // Check for unused imports
659
+ const imports = code.match(/import\s+(\w+)/g);
660
+ if (imports) {
661
+ imports.forEach(imp => {
662
+ const moduleName = imp.split(' ')[1];
663
+ if (!code.includes(moduleName + '.') && !code.includes(moduleName + '(')) {
664
+ issues.push({
665
+ type: 'warning',
666
+ message: `Import '${moduleName}' is unused`,
667
+ severity: 'low'
668
+ });
669
+ result.quality.score -= 3;
670
+ }
671
+ });
672
+ }
673
+ // Check for lines that are too long (PEP 8)
674
+ const lines = code.split('\n');
675
+ lines.forEach((line, index) => {
676
+ if (line.length > 79) {
677
+ issues.push({
678
+ type: 'info',
679
+ message: `Line ${index + 1} exceeds 79 characters (PEP 8)`,
680
+ line: index + 1,
681
+ severity: 'low'
682
+ });
683
+ result.quality.score -= 1;
684
+ }
685
+ });
686
+ // Check for multiple statements on one line
687
+ const multipleStatements = code.match(/;[^#\n]*\w/g);
688
+ if (multipleStatements) {
689
+ issues.push({
690
+ type: 'warning',
691
+ message: 'Avoid multiple statements on one line (PEP 8)',
692
+ severity: 'medium'
693
+ });
694
+ result.quality.score -= 5;
695
+ }
696
+ result.quality.issues = issues;
697
+ result.quality.score = Math.max(0, result.quality.score);
698
+ }
699
+ analyzePerformance(code, result) {
700
+ const suggestions = [];
701
+ // Check for loops with range(len())
702
+ if (code.includes('range(len(')) {
703
+ suggestions.push('Use enumerate() instead of range(len())');
704
+ result.performance.score -= 8;
705
+ }
706
+ // Check for string concatenation in loops
707
+ if (code.match(/for.*:[\s\S]*?\+\s*=.*str/)) {
708
+ suggestions.push('Use join() instead of concatenation in loops');
709
+ result.performance.score -= 12;
710
+ }
711
+ // Check for append usage in loops to create lists
712
+ if (code.match(/for.*:[\s\S]*?\.append\(/)) {
713
+ suggestions.push('Consider using list comprehension for better performance');
714
+ result.performance.score -= 5;
715
+ }
716
+ // Check for global usage
717
+ if (code.includes('global ')) {
718
+ suggestions.push('Avoid excessive use of global variables');
719
+ result.performance.score -= 8;
720
+ }
721
+ result.performance.suggestions = suggestions;
722
+ result.performance.score = Math.max(0, result.performance.score);
723
+ }
724
+ createSecurityVulnerability(vulnerabilityType, message, suggestion, lineNumber, attackDescription, exploitExample, realWorldImpact, remediationBefore, remediationAfter, remediationExplanation) {
725
+ const scoring = (0, severity_scoring_1.calculateSeverityScore)(vulnerabilityType);
726
+ const compliance = (0, compliance_mapping_1.getComplianceMapping)(vulnerabilityType);
727
+ return {
728
+ severity: scoring.severity,
729
+ message,
730
+ suggestion,
731
+ line: lineNumber,
732
+ cvssScore: scoring.cvssScore,
733
+ exploitLikelihood: scoring.exploitLikelihood,
734
+ impact: scoring.impact,
735
+ owasp: compliance.owasp,
736
+ cwe: compliance.cwe,
737
+ pciDss: compliance.pciDss,
738
+ attackVector: {
739
+ description: attackDescription,
740
+ exploitExample,
741
+ realWorldImpact
742
+ },
743
+ remediation: {
744
+ before: remediationBefore,
745
+ after: remediationAfter,
746
+ explanation: remediationExplanation
747
+ }
748
+ };
749
+ }
750
+ analyzeSecurity(code, result) {
751
+ const vulnerabilities = [];
752
+ const lines = code.split('\n');
753
+ // PHASE 6 ENHANCEMENT (2025-11-21): Data flow analysis for SQL injection
754
+ // Track variables assigned with unsafe SQL string formatting
755
+ const unsafeSqlVariables = new Map(); // variable name -> line number
756
+ // PHASE 6 FIX (2025-11-22): Data flow analysis for Markup() XSS
757
+ // Track variables assigned from user input (request.args, request.form, etc.)
758
+ const userInputVariables = new Map(); // variable name -> line number
759
+ // Async/await context tracking
760
+ let inAsyncContext = false;
761
+ let asyncFunctionIndent = 0;
762
+ // =============================================================================
763
+ // ASYNC/AWAIT CHECKS (Using Modular Security Checks)
764
+ // =============================================================================
765
+ // Helper functions extracted to: ./security-checks/python-async-security.ts
766
+ // This improves maintainability and follows the same pattern as JavaScript analyzer
767
+ // First pass: Identify unsafe SQL query construction and user input variables
768
+ lines.forEach((line, index) => {
769
+ const lineNumber = index + 1;
770
+ const trimmed = line.trim();
771
+ // Skip comments and empty lines
772
+ if (!trimmed || trimmed.startsWith('#'))
773
+ return;
774
+ // Track user input variables: variable = request.args.get(...) or similar
775
+ // Patterns:
776
+ // - request.args.get('key'), request.form.get('field')
777
+ // - request.json(), request.get_json()
778
+ // - request.args['key'], request.form['field']
779
+ const userInputMatch = trimmed.match(/^(\w+)\s*=\s*request\.(args|form|data|json|values|params|get_json|cookies)(?:\.get\([^)]*\)|\[[^\]]+\]|\(\))?/);
780
+ if (userInputMatch) {
781
+ const variableName = userInputMatch[1];
782
+ userInputVariables.set(variableName, lineNumber);
783
+ }
784
+ // Detect SQL string formatting: variable = "SQL..." with formatting
785
+ // Patterns: %, .format(), f-strings, string concatenation with +
786
+ const hasSqlKeywords = /\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|UNION)\b/i.test(trimmed);
787
+ const hasStringFormatting = trimmed.includes('%') || // % formatting
788
+ trimmed.includes('.format(') || // .format() method
789
+ /f["']/.test(trimmed) || // f-strings
790
+ /["'][^"']*\+/.test(trimmed); // string concatenation with +
791
+ // Check for variable assignment: variable_name = "SQL query"
792
+ const assignmentMatch = trimmed.match(/^(\w+)\s*=\s*["'f]/);
793
+ if (assignmentMatch && hasSqlKeywords && hasStringFormatting) {
794
+ const variableName = assignmentMatch[1];
795
+ unsafeSqlVariables.set(variableName, lineNumber);
796
+ }
797
+ });
798
+ // =============================================================================
799
+ // MODULAR SECURITY CHECKS (Refactored 2025-12-01)
800
+ // =============================================================================
801
+ // Checks #1-31: Extracted to dedicated modules for better maintainability
802
+ // 2,547 lines → 8 focused modules (~200-300 lines each)
803
+ // Injection Attacks (Checks #1-6): eval, exec, compile, SQL injection, command injection
804
+ vulnerabilities.push(...(0, injection_attacks_1.checkInjectionAttacks)(lines, unsafeSqlVariables));
805
+ // Credentials & Crypto (Checks #7-8): Hardcoded credentials, weak crypto, random module
806
+ vulnerabilities.push(...(0, credentials_crypto_1.checkCredentialsAndCrypto)(lines));
807
+ // Deserialization (Checks #9-10): pickle.load(), yaml.load() without SafeLoader
808
+ vulnerabilities.push(...(0, deserialization_1.checkDeserialization)(lines));
809
+ // Web Security (Checks #11-12): Path traversal, XSS
810
+ vulnerabilities.push(...(0, web_security_1.checkWebSecurity)(lines, userInputVariables));
811
+ // Code Quality (Checks #13-21): assert, input(), ReDoS, tempfile.mktemp, imports
812
+ vulnerabilities.push(...(0, code_quality_1.checkCodeQuality)(lines));
813
+ // Django Framework (Checks #22-27): CSRF, DEBUG, mark_safe, ORM, login_required, SECRET_KEY
814
+ vulnerabilities.push(...(0, django_security_1.checkDjangoSecurity)(lines, unsafeSqlVariables));
815
+ // Flask Framework (Checks #28-31): Debug mode, CSRF, SSTI, Markup, SECRET_KEY
816
+ vulnerabilities.push(...(0, flask_security_1.checkFlaskSecurity)(lines, userInputVariables));
817
+ // OWASP A02:2025 - Security Misconfiguration (NEW - Phase 7B)
818
+ // Security Misconfiguration (Checks #32-39): Django/Flask debug, AWS credentials, database config
819
+ vulnerabilities.push(...(0, security_misconfiguration_1.checkSecurityMisconfiguration)(lines));
820
+ // OWASP A10:2025 - Mishandling of Exceptional Conditions (NEW - Phase 7B)
821
+ // Exception Handling (Checks #40-44): Bare except, exposed details, silent suppression, resource cleanup
822
+ vulnerabilities.push(...(0, exception_handling_1.checkExceptionHandling)(lines));
823
+ // OWASP A03:2025 - Software Supply Chain Failures (Enhanced - Phase 7B)
824
+ // Enhanced Supply Chain (Checks #45-49): Dynamic imports, runtime installation, typosquatting, untrusted sources
825
+ vulnerabilities.push(...(0, enhanced_supply_chain_1.checkEnhancedSupplyChain)(lines));
826
+ // OWASP A01:2025 - Broken Access Control (NEW - Phase 7B Day 3)
827
+ // Access Control (Checks #50-51): Missing authentication decorators, IDOR
828
+ vulnerabilities.push(...(0, access_control_1.checkAccessControl)(lines));
829
+ // OWASP A04:2025 - Cryptographic Failures (NEW - Phase 7B Day 3)
830
+ // Crypto Failures (Checks #52-53): Weak algorithms (MD5/SHA1/DES), insecure random
831
+ vulnerabilities.push(...(0, crypto_failures_1.checkCryptoFailures)(lines));
832
+ // OWASP A06:2025 - Insecure Design (NEW - Phase 7B Day 4)
833
+ // Insecure Design (Checks #54-55): Missing rate limiting, mass assignment
834
+ vulnerabilities.push(...(0, insecure_design_1.checkInsecureDesign)(lines));
835
+ // OWASP A09:2025 - Logging Failures (NEW - Phase 7B Day 4)
836
+ // Logging Failures (Checks #56-57): Missing security logging, sensitive data logging
837
+ vulnerabilities.push(...(0, logging_failures_1.checkLoggingFailures)(lines));
838
+ // OWASP A08:2025 - Software and Data Integrity Failures (NEW - Phase 7B Day 5)
839
+ // Data Integrity (Check #58): Insecure deserialization (pickle)
840
+ vulnerabilities.push(...(0, data_integrity_1.checkDataIntegrity)(lines));
841
+ // OWASP A03:2021 - Injection (NoSQL) - Phase 0 Priority 0 (CRITICAL)
842
+ // NoSQL Injection (Checks #35-39): MongoDB, Cassandra, Redis, $where JavaScript injection
843
+ vulnerabilities.push(...(0, nosql_injection_1.checkNoSQLInjection)(lines, userInputVariables));
844
+ // OWASP A10:2021 - Server-Side Request Forgery - Phase 0 Priority 0 (CRITICAL)
845
+ // SSRF (Checks #40-44): requests, urllib, httplib, URL validation, internal IPs
846
+ vulnerabilities.push(...(0, ssrf_detection_1.checkSSRF)(lines, userInputVariables));
847
+ // OWASP A07:2021 - Identification and Authentication Failures - Phase 0 Priority 0 (CRITICAL)
848
+ // Authentication Logic Flaws (Checks #45-48): Plaintext passwords, weak tokens, master password backdoors, fail-open authorization
849
+ vulnerabilities.push(...(0, authentication_flaws_1.checkAuthenticationFlaws)(lines));
850
+ // =============================================================================
851
+ // ASYNC/AWAIT CHECKS (Modular - Using PythonAsyncSecurity helpers)
852
+ // =============================================================================
853
+ lines.forEach((line, index) => {
854
+ const lineNumber = index + 1;
855
+ const trimmed = line.trim();
856
+ // Skip comments and empty lines
857
+ if (!trimmed || trimmed.startsWith('#')) {
858
+ return;
859
+ }
860
+ // =============================================================================
861
+ // NOTE: Legacy inline checks #1-31 were REMOVED on Dec 7, 2025
862
+ // All security checks are now handled by modular functions (lines 848-878)
863
+ // This eliminated 1107 lines of duplicate code
864
+ // =============================================================================
865
+ // =============================================================================
866
+ // ASYNC/AWAIT CHECKS (Using Modular Helpers)
867
+ // =============================================================================
868
+ // Track async function context
869
+ if (PythonAsyncSecurity.isAsyncFunctionStart(line)) {
870
+ inAsyncContext = true;
871
+ // CRITICAL FIX: Track indent of FUNCTION BODY (not the def line)
872
+ // Function body is typically +4 spaces from def line
873
+ asyncFunctionIndent = (line.length - line.trimStart().length) + 4;
874
+ }
875
+ // Check for async/await issues
876
+ const missingAwaitVuln = PythonAsyncSecurity.detectMissingAwait(line, lineNumber, inAsyncContext, this.createSecurityVulnerability.bind(this));
877
+ if (missingAwaitVuln) {
878
+ vulnerabilities.push(missingAwaitVuln);
879
+ }
880
+ const asyncioRunVuln = PythonAsyncSecurity.detectAsyncioRunMisuse(line, lineNumber, inAsyncContext, this.createSecurityVulnerability.bind(this));
881
+ if (asyncioRunVuln) {
882
+ vulnerabilities.push(asyncioRunVuln);
883
+ }
884
+ // End async context when dedenting back to module level
885
+ if (inAsyncContext && PythonAsyncSecurity.isAsyncFunctionEnd(line, asyncFunctionIndent)) {
886
+ inAsyncContext = false;
887
+ }
888
+ // =============================================================================
889
+ // END ASYNC/AWAIT CHECKS
890
+ // =============================================================================
891
+ });
892
+ // Secrets Detection (Phase 1.5, Week 1)
893
+ const secretsAnalyzer = (0, secrets_analyzer_1.createSecretsAnalyzer)();
894
+ vulnerabilities.push(...secretsAnalyzer.analyzeCode(code, 'unknown.py', 'python'));
895
+ // =============================================================================
896
+ // DEDUPLICATION: Remove duplicate vulnerabilities on same line
897
+ // =============================================================================
898
+ // Fix for Beta Testing Issue: Line 48 reported twice (hardcoded credentials)
899
+ // Multiple checks can flag the same line (e.g., credentials-crypto.ts + security-misconfiguration.ts)
900
+ // Solution: Keep only the vulnerability with highest CVSS score per line
901
+ result.security.vulnerabilities = this.deduplicateVulnerabilities(vulnerabilities);
902
+ }
903
+ /**
904
+ * Deduplicate vulnerabilities by line number
905
+ * When multiple checks flag the same line, keep only the one with highest CVSS score
906
+ *
907
+ * Common duplicates:
908
+ * - Hardcoded credentials detected by both credentials-crypto.ts and security-misconfiguration.ts
909
+ * - Flask debug mode detected by both flask-security.ts and security-misconfiguration.ts
910
+ * - Random module detected by credentials-crypto.ts, crypto-failures.ts, and authentication-flaws.ts
911
+ * - Pickle detected by deserialization.ts and data-integrity.ts
912
+ * - MD5 detected by crypto-failures.ts and credentials-crypto.ts
913
+ */
914
+ deduplicateVulnerabilities(vulnerabilities) {
915
+ // Define groups of related vulnerability types that should be deduplicated
916
+ // When multiple vulnerabilities from the same group appear on the same line, keep only the highest CVSS
917
+ const similarityGroups = [
918
+ // Weak random/crypto randomness (all detect random.random(), random.randint(), etc.)
919
+ ['weak-random', 'insecure-random', 'insecure-random-number-generator', 'weak-token-generation'],
920
+ // Pickle deserialization (both detect pickle.load/loads)
921
+ ['unsafe-pickle', 'insecure-pickle', 'pickle-deserialization', 'insecure-deserialization'],
922
+ // Weak hashing (MD5, SHA1)
923
+ ['weak-crypto', 'weak-crypto-algorithm', 'weak-hash-md5', 'weak-hash-sha1', 'md5-sha1-password-hashing', 'weak-cryptographic-hash'],
924
+ // Hardcoded credentials
925
+ ['hardcoded-credentials', 'flask-weak-secret-key', 'django-weak-secret-key'],
926
+ // Debug mode
927
+ ['flask-debug-mode', 'django-debug-mode'],
928
+ ];
929
+ const lineMap = new Map();
930
+ // Group vulnerabilities by line number
931
+ vulnerabilities.forEach(vuln => {
932
+ if (!vuln.line)
933
+ return;
934
+ const existing = lineMap.get(vuln.line) || [];
935
+ existing.push(vuln);
936
+ lineMap.set(vuln.line, existing);
937
+ });
938
+ const deduplicated = [];
939
+ // For each line, check if there are duplicates
940
+ lineMap.forEach((vulns, line) => {
941
+ if (vulns.length === 1) {
942
+ // No duplicates, keep as-is
943
+ deduplicated.push(vulns[0]);
944
+ return;
945
+ }
946
+ // Multiple vulnerabilities on same line - group by similarity
947
+ const processed = new Set();
948
+ vulns.forEach(vuln => {
949
+ if (processed.has(vuln))
950
+ return;
951
+ const category = vuln.category || vuln.message || 'unknown';
952
+ // Find which similarity group this vulnerability belongs to
953
+ const similarityGroup = similarityGroups.find(group => group.some(cat => category.toLowerCase().includes(cat.toLowerCase())));
954
+ if (similarityGroup) {
955
+ // Find all vulnerabilities in this line that belong to the same similarity group
956
+ const relatedVulns = vulns.filter(v => {
957
+ const vCat = v.category || v.message || 'unknown';
958
+ return similarityGroup.some(cat => vCat.toLowerCase().includes(cat.toLowerCase()));
959
+ });
960
+ if (relatedVulns.length > 1) {
961
+ // Multiple related vulnerabilities - keep only the highest CVSS
962
+ const highest = relatedVulns.reduce((prev, current) => (current.cvssScore || 0) > (prev.cvssScore || 0) ? current : prev);
963
+ deduplicated.push(highest);
964
+ relatedVulns.forEach(v => processed.add(v));
965
+ }
966
+ else {
967
+ // Only one vulnerability in this group
968
+ deduplicated.push(vuln);
969
+ processed.add(vuln);
970
+ }
971
+ }
972
+ else {
973
+ // Not in any similarity group - keep as unique vulnerability
974
+ deduplicated.push(vuln);
975
+ processed.add(vuln);
976
+ }
977
+ });
978
+ return; // Skip the old message-based deduplication logic below
979
+ // OLD LOGIC (now skipped by return above):
980
+ // Group by similarity
981
+ const credentialVulns = vulns.filter(v => v.message?.toLowerCase().includes('credential') ||
982
+ v.message?.toLowerCase().includes('password') ||
983
+ v.message?.toLowerCase().includes('secret') ||
984
+ v.message?.toLowerCase().includes('api') && v.message?.toLowerCase().includes('key'));
985
+ const debugVulns = vulns.filter(v => v.message?.toLowerCase().includes('debug') ||
986
+ v.message?.toLowerCase().includes('flask') && v.message?.toLowerCase().includes('debug'));
987
+ // Deduplicate credential-related vulnerabilities (keep highest CVSS)
988
+ if (credentialVulns.length > 1) {
989
+ const highest = credentialVulns.reduce((prev, current) => (current.cvssScore || 0) > (prev.cvssScore || 0) ? current : prev);
990
+ deduplicated.push(highest);
991
+ // Add any non-credential vulnerabilities from this line
992
+ vulns.forEach(v => {
993
+ if (!credentialVulns.includes(v)) {
994
+ deduplicated.push(v);
995
+ }
996
+ });
997
+ }
998
+ // Deduplicate debug-related vulnerabilities (keep highest CVSS)
999
+ else if (debugVulns.length > 1) {
1000
+ const highest = debugVulns.reduce((prev, current) => (current.cvssScore || 0) > (prev.cvssScore || 0) ? current : prev);
1001
+ deduplicated.push(highest);
1002
+ // Add any non-debug vulnerabilities from this line
1003
+ vulns.forEach(v => {
1004
+ if (!debugVulns.includes(v)) {
1005
+ deduplicated.push(v);
1006
+ }
1007
+ });
1008
+ }
1009
+ // No similar duplicates, keep all
1010
+ else {
1011
+ deduplicated.push(...vulns);
1012
+ }
1013
+ });
1014
+ return deduplicated;
1015
+ }
1016
+ calculateMetrics(code, result) {
1017
+ const lines = code.split('\n');
1018
+ result.metrics.lines = lines.length;
1019
+ const functions = (code.match(/def\s+\w+/g) || []).length;
1020
+ result.metrics.functions = functions;
1021
+ // Calcular complexidade ciclomática - Python
1022
+ let complexity = 1;
1023
+ const pythonKeywords = ['if', 'elif', 'for', 'while', 'except', 'and', 'or'];
1024
+ pythonKeywords.forEach(keyword => {
1025
+ const matches = code.match(new RegExp(`\\b${keyword}\\b`, 'g'));
1026
+ if (matches)
1027
+ complexity += matches.length;
1028
+ });
1029
+ result.metrics.complexity = complexity;
1030
+ result.metrics.maintainability = Math.max(0, 100 - complexity * 3);
1031
+ }
1032
+ /**
1033
+ * Check for missing imports - detects usage of common modules without imports
1034
+ */
1035
+ checkMissingImports(code, lineErrors) {
1036
+ const lines = code.split('\n');
1037
+ const imports = new Set();
1038
+ const usages = new Map();
1039
+ // Common Python modules/functions that require imports
1040
+ const requiresImport = {
1041
+ 'defaultdict': 'from collections import defaultdict',
1042
+ 'Counter': 'from collections import Counter',
1043
+ 'OrderedDict': 'from collections import OrderedDict',
1044
+ 'datetime': 'from datetime import datetime',
1045
+ 'timedelta': 'from datetime import timedelta',
1046
+ 'json': 'import json',
1047
+ 'os': 'import os',
1048
+ 're': 'import re',
1049
+ 'sys': 'import sys',
1050
+ 'math': 'import math',
1051
+ 'random': 'import random',
1052
+ 'pandas': 'import pandas as pd',
1053
+ 'numpy': 'import numpy as np'
1054
+ };
1055
+ // First pass: collect all imports
1056
+ lines.forEach((line) => {
1057
+ const trimmed = line.trim();
1058
+ if (trimmed.startsWith('import ') || trimmed.startsWith('from ')) {
1059
+ // Extract module names from imports
1060
+ Object.keys(requiresImport).forEach(moduleName => {
1061
+ if (trimmed.includes(moduleName)) {
1062
+ imports.add(moduleName);
1063
+ }
1064
+ });
1065
+ }
1066
+ });
1067
+ // Second pass: find usages
1068
+ lines.forEach((line, index) => {
1069
+ const trimmed = line.trim();
1070
+ if (trimmed.startsWith('#') || trimmed.startsWith('import ') || trimmed.startsWith('from ')) {
1071
+ return;
1072
+ }
1073
+ Object.keys(requiresImport).forEach(moduleName => {
1074
+ // Check for usage (function call, class instantiation, or attribute access)
1075
+ const usagePattern = new RegExp(`\\b${moduleName}\\s*[\\(\\.]`);
1076
+ if (usagePattern.test(line) && !imports.has(moduleName)) {
1077
+ if (!usages.has(moduleName)) {
1078
+ usages.set(moduleName, []);
1079
+ }
1080
+ usages.get(moduleName)?.push(index + 1);
1081
+ }
1082
+ });
1083
+ });
1084
+ // Report missing imports
1085
+ usages.forEach((lineNumbers, moduleName) => {
1086
+ if (!imports.has(moduleName)) {
1087
+ lineErrors.push({
1088
+ line: lineNumbers[0],
1089
+ error: `'${moduleName}' used without import`,
1090
+ suggestion: `Add: ${requiresImport[moduleName]}`,
1091
+ severity: 'error'
1092
+ });
1093
+ }
1094
+ });
1095
+ }
1096
+ /**
1097
+ * Check for unbalanced parentheses in function/method calls
1098
+ */
1099
+ checkUnbalancedParentheses(code, lineErrors) {
1100
+ const lines = code.split('\n');
1101
+ let parenBalance = 0;
1102
+ const unclosedLines = [];
1103
+ let inString = false;
1104
+ let stringChar = '';
1105
+ lines.forEach((line, index) => {
1106
+ const lineNumber = index + 1;
1107
+ const trimmed = line.trim();
1108
+ // Skip comments and empty lines
1109
+ if (!trimmed || trimmed.startsWith('#'))
1110
+ return;
1111
+ let lineOpenCount = 0;
1112
+ let lineCloseCount = 0;
1113
+ // Simple string detection (not perfect but catches most cases)
1114
+ for (let i = 0; i < line.length; i++) {
1115
+ const char = line[i];
1116
+ // Toggle string state
1117
+ if ((char === '"' || char === "'") && (i === 0 || line[i - 1] !== '\\')) {
1118
+ if (!inString) {
1119
+ inString = true;
1120
+ stringChar = char;
1121
+ }
1122
+ else if (char === stringChar) {
1123
+ inString = false;
1124
+ stringChar = '';
1125
+ }
1126
+ }
1127
+ // Count parentheses outside of strings
1128
+ if (!inString) {
1129
+ if (char === '(') {
1130
+ lineOpenCount++;
1131
+ parenBalance++;
1132
+ }
1133
+ else if (char === ')') {
1134
+ lineCloseCount++;
1135
+ parenBalance--;
1136
+ }
1137
+ }
1138
+ }
1139
+ // Track lines that open parentheses without closing them
1140
+ if (lineOpenCount > lineCloseCount) {
1141
+ unclosedLines.push(lineNumber);
1142
+ }
1143
+ });
1144
+ // Report unclosed parentheses
1145
+ if (parenBalance > 0 && unclosedLines.length > 0) {
1146
+ // Report the last line that opened parentheses
1147
+ const lastUnclosedLine = unclosedLines[unclosedLines.length - 1];
1148
+ lineErrors.push({
1149
+ line: lastUnclosedLine,
1150
+ error: `Unclosed parenthesis (${parenBalance} open parenthesis/parentheses)`,
1151
+ suggestion: 'Add ) to close the open parenthesis/parentheses',
1152
+ severity: 'error'
1153
+ });
1154
+ }
1155
+ else if (parenBalance < 0) {
1156
+ lineErrors.push({
1157
+ line: lines.length,
1158
+ error: `Extra closing parenthesis (${Math.abs(parenBalance)} too many)`,
1159
+ suggestion: 'Remove extra ) or add opening (',
1160
+ severity: 'error'
1161
+ });
1162
+ }
1163
+ }
1164
+ /**
1165
+ * Detect AI Hallucinations - Common method name errors
1166
+ * Similar to JavaScript analyzer but for Python-specific methods
1167
+ */
1168
+ detectAIHallucinations(code, lineErrors) {
1169
+ const lines = code.split('\n');
1170
+ // Python AI hallucination patterns
1171
+ const hallucinationMap = new Map([
1172
+ // String method hallucinations
1173
+ ['toUpper', { description: 'Non-existent method in Python', correct: '.upper()' }],
1174
+ ['toLower', { description: 'Non-existent method in Python', correct: '.lower()' }],
1175
+ ['toUpperCase', { description: 'Non-existent method (JavaScript influence)', correct: '.upper()' }],
1176
+ ['toLowerCase', { description: 'Non-existent method (JavaScript influence)', correct: '.lower()' }],
1177
+ ['substring', { description: 'Non-existent method (use slicing)', correct: '[start:end]' }],
1178
+ ['charAt', { description: 'Non-existent method (use indexing)', correct: '[index]' }],
1179
+ ['indexOf', { description: 'Non-existent method', correct: '.find() or .index()' }],
1180
+ // List method hallucinations
1181
+ ['push', { description: 'Non-existent method (JavaScript influence)', correct: '.append()' }],
1182
+ ['pop_front', { description: 'Non-existent method', correct: '.pop(0)' }],
1183
+ ['add', { description: 'Use .append() for lists', correct: '.append()' }],
1184
+ ['remove_at', { description: 'Non-existent method', correct: '.pop(index) or del list[index]' }],
1185
+ ['size', { description: 'Non-existent method', correct: 'len()' }],
1186
+ ['length', { description: 'Non-existent property', correct: 'len()' }],
1187
+ // Dict method hallucinations
1188
+ ['hasKey', { description: 'Non-existent method', correct: 'key in dict' }],
1189
+ ['contains', { description: 'Non-existent method', correct: 'in operator' }],
1190
+ ['containsKey', { description: 'Non-existent method', correct: 'key in dict' }],
1191
+ ]);
1192
+ lines.forEach((line, index) => {
1193
+ const lineNumber = index + 1;
1194
+ if (line.trim().startsWith('#'))
1195
+ return;
1196
+ // CRITICAL FIX: Remove comments before pattern matching to prevent false positives
1197
+ // Example: list.append(x) # ERROR: Don't use .push() here
1198
+ // ^^^^^ This would trigger false positive!
1199
+ const lineWithoutComments = code_cleaner_1.CodeCleaner.removeLineComments(line, 'python');
1200
+ // Detect method hallucinations with pattern: .method(
1201
+ const methodMatches = lineWithoutComments.matchAll(/\.(\w+)\s*\(/g);
1202
+ for (const match of methodMatches) {
1203
+ const method = match[1];
1204
+ const details = hallucinationMap.get(method);
1205
+ if (details) {
1206
+ let references = references_1.pythonStandards['ai-hallucination'] || [];
1207
+ // Add specific references based on method type
1208
+ if (method.includes('Upper') || method.includes('Lower')) {
1209
+ references = [
1210
+ {
1211
+ title: 'Python String Methods',
1212
+ url: 'https://docs.python.org/3/library/stdtypes.html#string-methods',
1213
+ description: 'String case conversion: use .upper() and .lower()'
1214
+ },
1215
+ {
1216
+ title: 'Python str.upper()',
1217
+ url: 'https://docs.python.org/3/library/stdtypes.html#str.upper',
1218
+ description: 'Convert string to uppercase'
1219
+ }
1220
+ ];
1221
+ }
1222
+ else if (method === 'push' || method === 'add') {
1223
+ references = [
1224
+ {
1225
+ title: 'Python List Methods',
1226
+ url: 'https://docs.python.org/3/tutorial/datastructures.html#more-on-lists',
1227
+ description: 'Use .append() to add elements to a list'
1228
+ },
1229
+ {
1230
+ title: 'Python list.append()',
1231
+ url: 'https://docs.python.org/3/tutorial/datastructures.html',
1232
+ description: 'Add an item to the end of the list'
1233
+ }
1234
+ ];
1235
+ }
1236
+ lineErrors.push({
1237
+ line: lineNumber,
1238
+ error: ` AI Hallucination: ${details.description}`,
1239
+ suggestion: `Replace with: ${details.correct}`,
1240
+ severity: 'error',
1241
+ references
1242
+ });
1243
+ }
1244
+ }
1245
+ });
1246
+ }
1247
+ /**
1248
+ * Detect indentation errors (IndentationError, TabError)
1249
+ */
1250
+ detectIndentationErrors(code, lineErrors) {
1251
+ const lines = code.split('\n');
1252
+ let hasTabs = false;
1253
+ let hasSpaces = false;
1254
+ lines.forEach((line, index) => {
1255
+ const lineNumber = index + 1;
1256
+ if (!line.trim() || line.trim().startsWith('#'))
1257
+ return;
1258
+ // Check for tab/space mixing
1259
+ if (line.startsWith('\t'))
1260
+ hasTabs = true;
1261
+ if (line.startsWith(' '))
1262
+ hasSpaces = true;
1263
+ // Detect TabError - mixing tabs and spaces
1264
+ if (hasTabs && hasSpaces) {
1265
+ lineErrors.push({
1266
+ line: lineNumber,
1267
+ error: 'TabError: Inconsistent use of tabs and spaces',
1268
+ suggestion: 'Use only spaces (4 spaces per indentation level - PEP 8)',
1269
+ severity: 'error',
1270
+ references: references_1.pythonStandards['indentation'] || []
1271
+ });
1272
+ }
1273
+ });
1274
+ }
1275
+ /**
1276
+ * Detect TypeError patterns
1277
+ */
1278
+ detectTypeErrors(code, lineErrors) {
1279
+ const lines = code.split('\n');
1280
+ lines.forEach((line, index) => {
1281
+ const lineNumber = index + 1;
1282
+ if (line.trim().startsWith('#'))
1283
+ return;
1284
+ // Detect string concatenation with non-strings
1285
+ if (line.match(/["'].*["']\s*\+\s*\d+/) || line.match(/\d+\s*\+\s*["'].*["']/)) {
1286
+ lineErrors.push({
1287
+ line: lineNumber,
1288
+ error: 'Potential TypeError: String concatenation with number',
1289
+ suggestion: 'Use str() to convert number to string or use f-string: f"{number}"',
1290
+ severity: 'warning',
1291
+ references: references_1.pythonStandards['type-errors'] || []
1292
+ });
1293
+ }
1294
+ // Detect calling non-callable objects
1295
+ if (line.match(/\b(str|int|list|dict)\s*=\s*/) && line.match(/\(\)/)) {
1296
+ lineErrors.push({
1297
+ line: lineNumber,
1298
+ error: 'Potential TypeError: Attempting to call non-callable object',
1299
+ suggestion: 'Don\'t override built-in types (str, int, list, dict)',
1300
+ severity: 'error',
1301
+ references: references_1.pythonStandards['type-errors'] || []
1302
+ });
1303
+ }
1304
+ });
1305
+ }
1306
+ /**
1307
+ * Detect NameError - undefined variables
1308
+ */
1309
+ detectNameErrors(code, lineErrors) {
1310
+ const lines = code.split('\n');
1311
+ const definedVars = new Set();
1312
+ const imports = new Set();
1313
+ const conditionalVars = new Map();
1314
+ // Helper to get indentation level
1315
+ const getIndent = (line) => {
1316
+ const match = line.match(/^(\s*)/);
1317
+ return match ? match[1].length : 0;
1318
+ };
1319
+ // Track function-level base indentation
1320
+ let functionBaseIndent = 0;
1321
+ let inFunction = false;
1322
+ lines.forEach((line, index) => {
1323
+ const lineNumber = index + 1;
1324
+ const trimmed = line.trim();
1325
+ if (trimmed.startsWith('#'))
1326
+ return;
1327
+ const indent = getIndent(line);
1328
+ // Track function definitions
1329
+ const funcMatch = trimmed.match(/^def\s+(\w+)/);
1330
+ if (funcMatch) {
1331
+ definedVars.add(funcMatch[1]);
1332
+ functionBaseIndent = indent;
1333
+ inFunction = true;
1334
+ return;
1335
+ }
1336
+ // Track imports
1337
+ if (trimmed.startsWith('import ') || trimmed.startsWith('from ')) {
1338
+ const importMatch = trimmed.match(/(?:import|from)\s+(\w+)/);
1339
+ if (importMatch)
1340
+ imports.add(importMatch[1]);
1341
+ return;
1342
+ }
1343
+ // Track variable assignments
1344
+ const assignMatch = trimmed.match(/^(\w+)\s*=/);
1345
+ if (assignMatch && inFunction) {
1346
+ const varName = assignMatch[1];
1347
+ // Check if this assignment is inside a conditional block (higher indentation than function base)
1348
+ if (indent > functionBaseIndent + 4) {
1349
+ // Variable assigned inside conditional block (if/for/while/try)
1350
+ conditionalVars.set(varName, { line: lineNumber, indent });
1351
+ }
1352
+ else {
1353
+ // Variable assigned at function level (safe)
1354
+ definedVars.add(varName);
1355
+ conditionalVars.delete(varName); // Remove from conditional tracking
1356
+ }
1357
+ }
1358
+ // Check for variable usage (return statements, expressions)
1359
+ if (trimmed.startsWith('return ') && inFunction) {
1360
+ // Match variable name in return statement (handle various patterns)
1361
+ const returnMatch = trimmed.match(/^return\s+(\w+)/);
1362
+ if (returnMatch) {
1363
+ const varName = returnMatch[1];
1364
+ // Check if variable is only defined conditionally
1365
+ if (conditionalVars.has(varName) && !definedVars.has(varName) && !imports.has(varName)) {
1366
+ const defInfo = conditionalVars.get(varName);
1367
+ // Flag if return is at lower indentation than where var was defined (outside the conditional block)
1368
+ // Example: var defined at indent 8 (inside if), return at indent 4 (outside if)
1369
+ if (indent < defInfo.indent) {
1370
+ lineErrors.push({
1371
+ line: lineNumber,
1372
+ error: `NameError: '${varName}' might not be defined`,
1373
+ suggestion: `Variable '${varName}' was assigned inside a conditional block (line ${defInfo.line}) but used outside it. Initialize '${varName}' before the block or ensure it's always defined.`,
1374
+ severity: 'error',
1375
+ references: references_1.pythonStandards['name-errors'] || []
1376
+ });
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+ // Check for common undefined variable patterns
1382
+ const commonUndefined = ['undefined', 'NULL', 'nil', 'null'];
1383
+ commonUndefined.forEach(undef => {
1384
+ if (line.includes(undef) && !line.includes('#') && !line.includes('"') && !line.includes("'")) {
1385
+ lineErrors.push({
1386
+ line: lineNumber,
1387
+ error: `NameError: '${undef}' does not exist in Python`,
1388
+ suggestion: undef === 'undefined' || undef === 'null' ? 'Use None in Python' : 'Use None',
1389
+ severity: 'error',
1390
+ references: references_1.pythonStandards['name-errors'] || []
1391
+ });
1392
+ }
1393
+ });
1394
+ });
1395
+ }
1396
+ /**
1397
+ * Detect AttributeError - accessing non-existent attributes
1398
+ */
1399
+ detectAttributeErrors(code, lineErrors) {
1400
+ const lines = code.split('\n');
1401
+ lines.forEach((line, index) => {
1402
+ const lineNumber = index + 1;
1403
+ if (line.trim().startsWith('#'))
1404
+ return;
1405
+ // Detect common attribute errors with string methods
1406
+ const stringAttrErrors = [
1407
+ { pattern: /\.toUpperCase\(\)/, correct: '.upper()', wrong: 'toUpperCase' },
1408
+ { pattern: /\.toLowerCase\(\)/, correct: '.lower()', wrong: 'toLowerCase' },
1409
+ { pattern: /\.trim\(\)/, correct: '.strip()', wrong: 'trim' },
1410
+ { pattern: /\.substring\(/, correct: '[start:end]', wrong: 'substring' },
1411
+ ];
1412
+ stringAttrErrors.forEach(({ pattern, correct, wrong }) => {
1413
+ if (pattern.test(line)) {
1414
+ lineErrors.push({
1415
+ line: lineNumber,
1416
+ error: `AttributeError: Strings don't have method '${wrong}'`,
1417
+ suggestion: `Use ${correct}`,
1418
+ severity: 'error',
1419
+ references: references_1.pythonStandards['attribute-errors'] || []
1420
+ });
1421
+ }
1422
+ });
1423
+ // Detect common list attribute errors
1424
+ if (line.match(/\.push\(/)) {
1425
+ lineErrors.push({
1426
+ line: lineNumber,
1427
+ error: 'AttributeError: Lists don\'t have method push',
1428
+ suggestion: 'Use .append() to add elements',
1429
+ severity: 'error',
1430
+ references: references_1.pythonStandards['attribute-errors'] || []
1431
+ });
1432
+ }
1433
+ });
1434
+ }
1435
+ /**
1436
+ * Detect IndexError - list index out of range
1437
+ */
1438
+ detectIndexErrors(code, lineErrors) {
1439
+ const lines = code.split('\n');
1440
+ lines.forEach((line, index) => {
1441
+ const lineNumber = index + 1;
1442
+ if (line.trim().startsWith('#'))
1443
+ return;
1444
+ // Detect potential IndexError: accessing list[len(list)]
1445
+ if (line.match(/\[\s*len\([^)]+\)\s*\]/)) {
1446
+ lineErrors.push({
1447
+ line: lineNumber,
1448
+ error: 'Potential IndexError: index len(list) is out of range',
1449
+ suggestion: 'Use len(list)-1 for the last element or list[-1]',
1450
+ severity: 'warning',
1451
+ references: references_1.pythonStandards['index-errors'] || []
1452
+ });
1453
+ }
1454
+ // Detect hardcoded index access without length check
1455
+ const indexMatch = line.match(/(\w+)\[(\d+)\]/);
1456
+ if (indexMatch) {
1457
+ const [, varName, indexStr] = indexMatch;
1458
+ const indexNum = parseInt(indexStr);
1459
+ if (indexNum > 10) { // Flag suspiciously high indices
1460
+ lineErrors.push({
1461
+ line: lineNumber,
1462
+ error: `Potential IndexError: index ${indexNum} may be out of range`,
1463
+ suggestion: `Check if the index is within bounds before accessing ${varName}[${indexNum}]`,
1464
+ severity: 'info',
1465
+ references: references_1.pythonStandards['index-errors'] || []
1466
+ });
1467
+ }
1468
+ }
1469
+ });
1470
+ }
1471
+ /**
1472
+ * Detect KeyError - dictionary key access without checking
1473
+ */
1474
+ detectKeyErrors(code, lineErrors) {
1475
+ const lines = code.split('\n');
1476
+ lines.forEach((line, index) => {
1477
+ const lineNumber = index + 1;
1478
+ if (line.trim().startsWith('#'))
1479
+ return;
1480
+ // Detect dict[key] access pattern (potentially unsafe)
1481
+ const dictAccessMatch = line.match(/(\w+)\[['"](\w+)['"]\]/);
1482
+ if (dictAccessMatch && !line.includes('.get(')) {
1483
+ const [, dictName, key] = dictAccessMatch;
1484
+ // Check if there's a prior 'if key in dict' check
1485
+ const checkExists = lines.slice(Math.max(0, index - 3), index).some(prevLine => prevLine.includes(`${key}`) && prevLine.includes('in') && prevLine.includes(dictName));
1486
+ if (!checkExists) {
1487
+ lineErrors.push({
1488
+ line: lineNumber,
1489
+ error: `Potential KeyError: key '${key}' may not exist in ${dictName}`,
1490
+ suggestion: `Use ${dictName}.get('${key}', default) or check with 'if '${key}' in ${dictName}'`,
1491
+ severity: 'warning',
1492
+ references: references_1.pythonStandards['key-errors'] || []
1493
+ });
1494
+ }
1495
+ }
1496
+ });
1497
+ }
1498
+ /**
1499
+ * Detect mutable default arguments
1500
+ */
1501
+ detectMutableDefaults(code, lineErrors) {
1502
+ const lines = code.split('\n');
1503
+ lines.forEach((line, index) => {
1504
+ const lineNumber = index + 1;
1505
+ if (!line.trim().startsWith('def '))
1506
+ return;
1507
+ // Detect mutable default arguments: def func(arg=[]) or def func(arg={})
1508
+ if (line.match(/def\s+\w+\s*\([^)]*=\s*[\[{]/)) {
1509
+ lineErrors.push({
1510
+ line: lineNumber,
1511
+ error: 'Mutable default argument detected (list or dictionary)',
1512
+ suggestion: 'Use None as default and initialize inside function: if arg is None: arg = []',
1513
+ severity: 'warning',
1514
+ references: references_1.pythonStandards['mutable-defaults'] || []
1515
+ });
1516
+ }
1517
+ });
1518
+ }
1519
+ /**
1520
+ * Detect loop modification - modifying list/dict while iterating
1521
+ */
1522
+ detectLoopModification(code, lineErrors) {
1523
+ const lines = code.split('\n');
1524
+ lines.forEach((line, index) => {
1525
+ const lineNumber = index + 1;
1526
+ const trimmed = line.trim();
1527
+ // Check if we're in a for loop
1528
+ const forMatch = trimmed.match(/for\s+\w+\s+in\s+(\w+)/);
1529
+ if (forMatch) {
1530
+ const iterVar = forMatch[1];
1531
+ // Check next few lines for modifications to the iterated variable
1532
+ const nextLines = lines.slice(index + 1, Math.min(index + 5, lines.length));
1533
+ nextLines.forEach((nextLine) => {
1534
+ // Detect append, remove, pop, del on the same variable
1535
+ if (nextLine.includes(`${iterVar}.append`) ||
1536
+ nextLine.includes(`${iterVar}.remove`) ||
1537
+ nextLine.includes(`${iterVar}.pop`) ||
1538
+ nextLine.includes(`del ${iterVar}`)) {
1539
+ lineErrors.push({
1540
+ line: lineNumber,
1541
+ error: `Modification of '${iterVar}' during iteration`,
1542
+ suggestion: `Create a copy of the list before iterating: for item in ${iterVar}.copy():`,
1543
+ severity: 'error',
1544
+ references: references_1.pythonStandards['loop-modification'] || []
1545
+ });
1546
+ }
1547
+ });
1548
+ }
1549
+ });
1550
+ }
1551
+ /**
1552
+ * Detect scope issues - global/nonlocal misuse
1553
+ */
1554
+ detectScopeIssues(code, lineErrors) {
1555
+ const lines = code.split('\n');
1556
+ const globalVars = new Set();
1557
+ lines.forEach((line, index) => {
1558
+ const lineNumber = index + 1;
1559
+ const trimmed = line.trim();
1560
+ if (trimmed.startsWith('#'))
1561
+ return;
1562
+ // Track global declarations
1563
+ const globalMatch = trimmed.match(/global\s+(\w+)/);
1564
+ if (globalMatch) {
1565
+ const varName = globalMatch[1];
1566
+ // Warn about excessive global usage
1567
+ if (globalVars.has(varName)) {
1568
+ lineErrors.push({
1569
+ line: lineNumber,
1570
+ error: `Excessive use of 'global ${varName}'`,
1571
+ suggestion: 'Consider using classes or passing variables as parameters',
1572
+ severity: 'warning',
1573
+ references: references_1.pythonStandards['scope-issues'] || []
1574
+ });
1575
+ }
1576
+ globalVars.add(varName);
1577
+ }
1578
+ // Detect assignment to variable that might need global/nonlocal
1579
+ const funcMatch = lines.slice(Math.max(0, index - 10), index).some(l => l.trim().startsWith('def '));
1580
+ if (funcMatch) {
1581
+ const assignMatch = trimmed.match(/^(\w+)\s*=/);
1582
+ if (assignMatch && globalVars.has(assignMatch[1])) {
1583
+ // Check if global declaration exists
1584
+ const hasGlobal = lines.slice(Math.max(0, index - 5), index).some(l => l.includes(`global ${assignMatch[1]}`));
1585
+ if (!hasGlobal) {
1586
+ lineErrors.push({
1587
+ line: lineNumber,
1588
+ error: `Possible scope error: assignment to '${assignMatch[1]}' without 'global'`,
1589
+ suggestion: `Add 'global ${assignMatch[1]}' or use function parameter`,
1590
+ severity: 'info',
1591
+ references: references_1.pythonStandards['scope-issues'] || []
1592
+ });
1593
+ }
1594
+ }
1595
+ }
1596
+ });
1597
+ }
1598
+ }
1599
+ exports.PythonAnalyzer = PythonAnalyzer;
1600
+ //# sourceMappingURL=python-analyzer.js.map