pi-lens 2.2.9 → 3.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 (304) hide show
  1. package/CHANGELOG.md +198 -0
  2. package/README.md +709 -519
  3. package/clients/__tests__/file-time.test.js +216 -0
  4. package/clients/__tests__/file-time.test.ts +276 -0
  5. package/clients/__tests__/format-service.test.js +245 -0
  6. package/clients/__tests__/format-service.test.ts +339 -0
  7. package/clients/__tests__/formatters.test.js +271 -0
  8. package/clients/__tests__/formatters.test.ts +401 -0
  9. package/clients/amain-types.js +164 -0
  10. package/clients/amain-types.ts +165 -0
  11. package/clients/architect-client.js +56 -12
  12. package/clients/architect-client.ts +81 -16
  13. package/clients/ast-grep-client.js +2 -2
  14. package/clients/ast-grep-client.ts +14 -39
  15. package/clients/ast-grep-parser.ts +1 -1
  16. package/clients/ast-grep-rule-manager.js +8 -0
  17. package/clients/ast-grep-rule-manager.ts +10 -1
  18. package/clients/ast-grep-types.js +9 -0
  19. package/clients/ast-grep-types.ts +106 -0
  20. package/clients/auto-loop.js +10 -0
  21. package/clients/auto-loop.ts +14 -1
  22. package/clients/biome-client.js +81 -19
  23. package/clients/biome-client.ts +103 -22
  24. package/clients/bus/bus.js +191 -0
  25. package/clients/bus/bus.ts +251 -0
  26. package/clients/bus/events.js +214 -0
  27. package/clients/bus/events.ts +279 -0
  28. package/clients/bus/index.js +8 -0
  29. package/clients/bus/index.ts +9 -0
  30. package/clients/bus/integration.js +158 -0
  31. package/clients/bus/integration.ts +214 -0
  32. package/clients/complexity-client.js +13 -7
  33. package/clients/complexity-client.ts +13 -7
  34. package/clients/config-validator.js +465 -0
  35. package/clients/config-validator.ts +558 -0
  36. package/clients/dependency-checker.js +4 -10
  37. package/clients/dependency-checker.ts +4 -10
  38. package/clients/dispatch/__tests__/autofix-integration.test.js +245 -0
  39. package/clients/dispatch/__tests__/autofix-integration.test.ts +300 -0
  40. package/clients/dispatch/__tests__/runner-registration.test.js +236 -0
  41. package/clients/dispatch/__tests__/runner-registration.test.ts +282 -0
  42. package/clients/dispatch/bus-dispatcher.js +177 -0
  43. package/clients/dispatch/bus-dispatcher.ts +251 -0
  44. package/clients/dispatch/dispatcher.edge.test.js +82 -0
  45. package/clients/dispatch/dispatcher.edge.test.ts +100 -0
  46. package/clients/dispatch/dispatcher.format.test.js +46 -0
  47. package/clients/dispatch/dispatcher.format.test.ts +58 -0
  48. package/clients/dispatch/dispatcher.inline.test.js +74 -0
  49. package/clients/dispatch/dispatcher.inline.test.ts +93 -0
  50. package/clients/dispatch/dispatcher.js +19 -53
  51. package/clients/dispatch/dispatcher.ts +20 -67
  52. package/clients/dispatch/plan.js +9 -4
  53. package/clients/dispatch/plan.ts +9 -4
  54. package/clients/dispatch/runners/architect.js +21 -7
  55. package/clients/dispatch/runners/architect.test.js +138 -0
  56. package/clients/dispatch/runners/architect.test.ts +162 -0
  57. package/clients/dispatch/runners/architect.ts +22 -7
  58. package/clients/dispatch/runners/ast-grep-napi.js +462 -0
  59. package/clients/dispatch/runners/ast-grep-napi.test.js +111 -0
  60. package/clients/dispatch/runners/ast-grep-napi.test.ts +133 -0
  61. package/clients/dispatch/runners/ast-grep-napi.ts +506 -0
  62. package/clients/dispatch/runners/ast-grep.js +62 -19
  63. package/clients/dispatch/runners/ast-grep.ts +70 -18
  64. package/clients/dispatch/runners/biome.js +29 -53
  65. package/clients/dispatch/runners/biome.ts +29 -63
  66. package/clients/dispatch/runners/config-validation.js +67 -0
  67. package/clients/dispatch/runners/config-validation.ts +82 -0
  68. package/clients/dispatch/runners/go-vet.js +4 -28
  69. package/clients/dispatch/runners/go-vet.ts +4 -32
  70. package/clients/dispatch/runners/index.js +30 -10
  71. package/clients/dispatch/runners/index.ts +30 -10
  72. package/clients/dispatch/runners/oxlint.js +141 -0
  73. package/clients/dispatch/runners/oxlint.test.js +230 -0
  74. package/clients/dispatch/runners/oxlint.test.ts +303 -0
  75. package/clients/dispatch/runners/oxlint.ts +175 -0
  76. package/clients/dispatch/runners/pyright.js +40 -70
  77. package/clients/dispatch/runners/pyright.test.js +16 -2
  78. package/clients/dispatch/runners/pyright.test.ts +14 -2
  79. package/clients/dispatch/runners/pyright.ts +48 -91
  80. package/clients/dispatch/runners/python-slop.js +97 -0
  81. package/clients/dispatch/runners/python-slop.test.js +203 -0
  82. package/clients/dispatch/runners/python-slop.test.ts +298 -0
  83. package/clients/dispatch/runners/python-slop.ts +124 -0
  84. package/clients/dispatch/runners/ruff.js +18 -71
  85. package/clients/dispatch/runners/ruff.ts +19 -79
  86. package/clients/dispatch/runners/rust-clippy.js +28 -32
  87. package/clients/dispatch/runners/rust-clippy.ts +29 -31
  88. package/clients/dispatch/runners/scan_codebase.test.js +89 -0
  89. package/clients/dispatch/runners/scan_codebase.test.ts +105 -0
  90. package/clients/dispatch/runners/shellcheck.js +147 -0
  91. package/clients/dispatch/runners/shellcheck.test.js +98 -0
  92. package/clients/dispatch/runners/shellcheck.test.ts +129 -0
  93. package/clients/dispatch/runners/shellcheck.ts +188 -0
  94. package/clients/dispatch/runners/similarity.js +230 -0
  95. package/clients/dispatch/runners/similarity.ts +339 -0
  96. package/clients/dispatch/runners/spellcheck.js +106 -0
  97. package/clients/dispatch/runners/spellcheck.test.js +158 -0
  98. package/clients/dispatch/runners/spellcheck.test.ts +214 -0
  99. package/clients/dispatch/runners/spellcheck.ts +136 -0
  100. package/clients/dispatch/runners/tree-sitter.js +107 -0
  101. package/clients/dispatch/runners/tree-sitter.ts +135 -0
  102. package/clients/dispatch/runners/ts-lsp.js +104 -33
  103. package/clients/dispatch/runners/ts-lsp.ts +120 -38
  104. package/clients/dispatch/runners/ts-slop.js +113 -0
  105. package/clients/dispatch/runners/ts-slop.test.js +180 -0
  106. package/clients/dispatch/runners/ts-slop.test.ts +230 -0
  107. package/clients/dispatch/runners/ts-slop.ts +142 -0
  108. package/clients/dispatch/runners/utils/diagnostic-parsers.js +134 -0
  109. package/clients/dispatch/runners/utils/diagnostic-parsers.ts +186 -0
  110. package/clients/dispatch/runners/utils/runner-helpers.js +115 -0
  111. package/clients/dispatch/runners/utils/runner-helpers.ts +167 -0
  112. package/clients/dispatch/runners/utils.js +2 -4
  113. package/clients/dispatch/runners/utils.ts +2 -4
  114. package/clients/dispatch/types.ts +1 -1
  115. package/clients/dispatch/utils/format-utils.js +49 -0
  116. package/clients/dispatch/utils/format-utils.ts +60 -0
  117. package/clients/dogfood.test.js +201 -0
  118. package/clients/dogfood.test.ts +269 -0
  119. package/clients/file-time.js +152 -0
  120. package/clients/file-time.ts +208 -0
  121. package/clients/file-utils.js +40 -0
  122. package/clients/file-utils.ts +44 -0
  123. package/clients/fix-scanners.js +10 -20
  124. package/clients/fix-scanners.ts +10 -22
  125. package/clients/format-service.js +172 -0
  126. package/clients/format-service.ts +254 -0
  127. package/clients/formatters.js +435 -0
  128. package/clients/formatters.ts +508 -0
  129. package/clients/go-client.js +5 -14
  130. package/clients/go-client.ts +5 -13
  131. package/clients/installer/index.js +356 -0
  132. package/clients/installer/index.ts +426 -0
  133. package/clients/jscpd-client.js +11 -9
  134. package/clients/jscpd-client.ts +12 -8
  135. package/clients/knip-client.js +3 -7
  136. package/clients/knip-client.ts +3 -6
  137. package/clients/lsp/__tests__/client.test.js +325 -0
  138. package/clients/lsp/__tests__/client.test.ts +434 -0
  139. package/clients/lsp/__tests__/config.test.js +166 -0
  140. package/clients/lsp/__tests__/config.test.ts +209 -0
  141. package/clients/lsp/__tests__/error-recovery.test.js +213 -0
  142. package/clients/lsp/__tests__/error-recovery.test.ts +279 -0
  143. package/clients/lsp/__tests__/integration.test.js +127 -0
  144. package/clients/lsp/__tests__/integration.test.ts +160 -0
  145. package/clients/lsp/__tests__/launch.test.js +260 -0
  146. package/clients/lsp/__tests__/launch.test.ts +329 -0
  147. package/clients/lsp/__tests__/server.test.js +259 -0
  148. package/clients/lsp/__tests__/server.test.ts +332 -0
  149. package/clients/lsp/__tests__/service.test.js +417 -0
  150. package/clients/lsp/__tests__/service.test.ts +499 -0
  151. package/clients/lsp/client.js +235 -0
  152. package/clients/lsp/client.ts +328 -0
  153. package/clients/lsp/config.js +115 -0
  154. package/clients/lsp/config.ts +149 -0
  155. package/clients/lsp/index.js +222 -0
  156. package/clients/lsp/index.ts +280 -0
  157. package/clients/lsp/installer/index.js +391 -0
  158. package/clients/lsp/interactive-install.js +210 -0
  159. package/clients/lsp/interactive-install.ts +251 -0
  160. package/clients/lsp/language.js +170 -0
  161. package/clients/lsp/language.ts +216 -0
  162. package/clients/lsp/launch.js +174 -0
  163. package/clients/lsp/launch.ts +240 -0
  164. package/clients/lsp/lsp/launch.js +116 -0
  165. package/clients/lsp/lsp/server.js +532 -0
  166. package/clients/lsp/lsp-index.js +10 -0
  167. package/clients/lsp/lsp-index.ts +11 -0
  168. package/clients/lsp/path-utils.js +48 -0
  169. package/clients/lsp/path-utils.ts +52 -0
  170. package/clients/lsp/server.js +615 -0
  171. package/clients/lsp/server.ts +800 -0
  172. package/clients/lsp/test-py-spawn/requirements.txt +1 -0
  173. package/clients/lsp/test-py-spawn/test.py +3 -0
  174. package/clients/lsp/test-py-svc/requirements.txt +1 -0
  175. package/clients/lsp/test-py-svc/test.py +3 -0
  176. package/clients/lsp/test-python-project/requirements.txt +1 -0
  177. package/clients/lsp/test-python-project/test.py +5 -0
  178. package/clients/metrics-history.js +2 -2
  179. package/clients/metrics-history.ts +2 -2
  180. package/clients/production-readiness.js +522 -0
  181. package/clients/production-readiness.ts +556 -0
  182. package/clients/project-index.js +255 -0
  183. package/clients/project-index.ts +383 -0
  184. package/clients/project-metadata.js +531 -0
  185. package/clients/project-metadata.ts +624 -0
  186. package/clients/ruff-client.js +56 -16
  187. package/clients/ruff-client.ts +72 -15
  188. package/clients/runner-tracker.js +152 -0
  189. package/clients/runner-tracker.ts +213 -0
  190. package/clients/rust-client.js +4 -11
  191. package/clients/rust-client.ts +5 -11
  192. package/clients/safe-spawn.js +96 -0
  193. package/clients/safe-spawn.ts +128 -0
  194. package/clients/scan-architectural-debt.js +3 -6
  195. package/clients/scan-architectural-debt.ts +3 -6
  196. package/clients/scan-utils.js +5 -20
  197. package/clients/scan-utils.ts +5 -29
  198. package/clients/secrets-scanner.js +3 -17
  199. package/clients/secrets-scanner.ts +4 -20
  200. package/clients/services/__tests__/effect-integration.test.js +86 -0
  201. package/clients/services/__tests__/effect-integration.test.ts +111 -0
  202. package/clients/services/effect-integration.js +194 -0
  203. package/clients/services/effect-integration.ts +268 -0
  204. package/clients/services/index.js +7 -0
  205. package/clients/services/index.ts +8 -0
  206. package/clients/services/runner-service.js +105 -0
  207. package/clients/services/runner-service.ts +179 -0
  208. package/clients/sg-runner.js +87 -13
  209. package/clients/sg-runner.ts +97 -13
  210. package/clients/state-matrix.js +160 -0
  211. package/clients/state-matrix.ts +202 -0
  212. package/clients/subprocess-client.js +10 -9
  213. package/clients/subprocess-client.ts +10 -8
  214. package/clients/test-runner-client.js +3 -7
  215. package/clients/test-runner-client.ts +3 -6
  216. package/clients/tool-availability.js +4 -10
  217. package/clients/tool-availability.ts +4 -9
  218. package/clients/tree-sitter-client.js +564 -0
  219. package/clients/tree-sitter-client.ts +797 -0
  220. package/clients/tree-sitter-query-loader.js +355 -0
  221. package/clients/tree-sitter-query-loader.ts +425 -0
  222. package/clients/type-coverage-client.js +3 -7
  223. package/clients/type-coverage-client.ts +3 -6
  224. package/clients/typescript-client.codefix.test.js +157 -0
  225. package/clients/typescript-client.codefix.test.ts +186 -0
  226. package/clients/typescript-client.js +43 -0
  227. package/clients/typescript-client.ts +98 -0
  228. package/commands/booboo.js +799 -219
  229. package/commands/booboo.ts +1004 -225
  230. package/commands/clients/ast-grep-client.js +250 -0
  231. package/commands/clients/ast-grep-parser.js +86 -0
  232. package/commands/clients/ast-grep-rule-manager.js +91 -0
  233. package/commands/clients/ast-grep-types.js +9 -0
  234. package/commands/clients/biome-client.js +380 -0
  235. package/commands/clients/complexity-client.js +667 -0
  236. package/commands/clients/file-kinds.js +177 -0
  237. package/commands/clients/file-utils.js +40 -0
  238. package/commands/clients/jscpd-client.js +169 -0
  239. package/commands/clients/knip-client.js +211 -0
  240. package/commands/clients/ruff-client.js +297 -0
  241. package/commands/clients/safe-spawn.js +88 -0
  242. package/commands/clients/scan-utils.js +83 -0
  243. package/commands/clients/sg-runner.js +190 -0
  244. package/commands/clients/types.js +11 -0
  245. package/commands/clients/typescript-client.js +505 -0
  246. package/commands/fix-from-booboo.js +398 -0
  247. package/commands/fix-from-booboo.ts +485 -0
  248. package/commands/fix-simplified.js +618 -0
  249. package/commands/fix-simplified.ts +768 -0
  250. package/commands/rate.js +10 -14
  251. package/commands/rate.ts +9 -16
  252. package/default-architect.yaml +59 -15
  253. package/index.ts +342 -429
  254. package/package.json +16 -3
  255. package/rules/ast-grep-rules/rules/empty-catch.yml +38 -13
  256. package/rules/ast-grep-rules/rules/no-array-constructor.yml +1 -0
  257. package/rules/ast-grep-rules/rules/no-debugger.yml +2 -0
  258. package/rules/python-slop-rules/.sgconfig.yml +4 -0
  259. package/rules/python-slop-rules/rules/slop-rules.yml +647 -0
  260. package/rules/tree-sitter-queries/python/bare-except.yml +54 -0
  261. package/rules/tree-sitter-queries/python/eval-exec.yml +50 -0
  262. package/rules/tree-sitter-queries/python/is-vs-equals.yml +60 -0
  263. package/rules/tree-sitter-queries/python/mutable-default-arg.yml +57 -0
  264. package/rules/tree-sitter-queries/python/unreachable-except.yml +60 -0
  265. package/rules/tree-sitter-queries/python/wildcard-import.yml +46 -0
  266. package/rules/tree-sitter-queries/tsx/dangerously-set-inner-html.yml +63 -0
  267. package/rules/tree-sitter-queries/typescript/await-in-loop.yml +56 -0
  268. package/rules/tree-sitter-queries/typescript/console-statement.yml +47 -0
  269. package/rules/tree-sitter-queries/typescript/debugger.yml +47 -0
  270. package/rules/tree-sitter-queries/typescript/deep-nesting.yml +117 -0
  271. package/rules/tree-sitter-queries/typescript/deep-promise-chain.yml +73 -0
  272. package/rules/tree-sitter-queries/typescript/empty-catch.yml +64 -0
  273. package/rules/tree-sitter-queries/typescript/eval.yml +48 -0
  274. package/rules/tree-sitter-queries/typescript/hardcoded-secrets.yml +78 -0
  275. package/rules/tree-sitter-queries/typescript/long-parameter-list.yml +62 -0
  276. package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +49 -0
  277. package/rules/tree-sitter-queries/typescript/nested-ternary.yml +45 -0
  278. package/rules/ts-slop-rules/.sgconfig.yml +4 -0
  279. package/rules/ts-slop-rules/rules/in-correct-optional-input-type.yml +10 -0
  280. package/rules/ts-slop-rules/rules/jwt-no-verify.yml +13 -0
  281. package/rules/ts-slop-rules/rules/no-architecture-violation.yml +10 -0
  282. package/rules/ts-slop-rules/rules/no-case-declarations.yml +10 -0
  283. package/rules/ts-slop-rules/rules/no-dangerously-set-inner-html.yml +10 -0
  284. package/rules/ts-slop-rules/rules/no-debugger.yml +10 -0
  285. package/rules/ts-slop-rules/rules/no-dupe-args.yml +10 -0
  286. package/rules/ts-slop-rules/rules/no-dupe-class-members.yml +10 -0
  287. package/rules/ts-slop-rules/rules/no-dupe-keys.yml +10 -0
  288. package/rules/ts-slop-rules/rules/no-eval.yml +13 -0
  289. package/rules/ts-slop-rules/rules/no-hardcoded-secrets.yml +12 -0
  290. package/rules/ts-slop-rules/rules/no-implied-eval.yml +12 -0
  291. package/rules/ts-slop-rules/rules/no-inner-html.yml +13 -0
  292. package/rules/ts-slop-rules/rules/no-javascript-url.yml +10 -0
  293. package/rules/ts-slop-rules/rules/no-mutable-default.yml +10 -0
  294. package/rules/ts-slop-rules/rules/no-nested-links.yml +12 -0
  295. package/rules/ts-slop-rules/rules/no-new-symbol.yml +10 -0
  296. package/rules/ts-slop-rules/rules/no-new-wrappers.yml +13 -0
  297. package/rules/ts-slop-rules/rules/no-open-redirect.yml +16 -0
  298. package/rules/ts-slop-rules/rules/slop-rules.yml +455 -0
  299. package/rules/ts-slop-rules/rules/weak-rsa-key.yml +12 -0
  300. package/skills/ast-grep/SKILL.md +182 -0
  301. package/clients/dispatch/runners/secrets.js +0 -109
  302. package/commands/fix.js +0 -244
  303. package/commands/fix.ts +0 -373
  304. package/rules/ast-grep-rules/rules/no-lonely-if.yml +0 -13
@@ -0,0 +1,50 @@
1
+ # Eval/Exec Usage
2
+ # Detects eval() and exec() which are security risks
3
+ id: eval-exec
4
+ name: Eval/Exec Usage
5
+ severity: error
6
+ category: security
7
+ language: python
8
+
9
+ message: "{{FUNC}}() detected — security risk, code injection vulnerability"
10
+
11
+ description: |
12
+ eval() and exec() execute arbitrary Python code and are major
13
+ security vulnerabilities when used with untrusted input.
14
+
15
+ ✅ ALTERNATIVES:
16
+ - ast.literal_eval() for parsing literals
17
+ - json.loads() for JSON
18
+ - Proper parsing libraries for complex needs
19
+
20
+ query: |
21
+ (call
22
+ function: (identifier) @FUNC
23
+ (#match? @FUNC "^(eval|exec)$")
24
+ arguments: (argument_list) @ARGS)
25
+
26
+ metavars:
27
+ - FUNC
28
+ - ARGS
29
+
30
+ tags:
31
+ - security
32
+ - xss
33
+ - injection
34
+
35
+ examples:
36
+ bad: |
37
+ user_input = "os.system('rm -rf /')"
38
+ eval(user_input) # DANGEROUS!
39
+
40
+ good: |
41
+ import ast
42
+ import json
43
+
44
+ # For literals: use ast.literal_eval
45
+ data = ast.literal_eval("[1, 2, 3]")
46
+
47
+ # For JSON: use json.loads
48
+ data = json.loads(json_string)
49
+
50
+ has_fix: false
@@ -0,0 +1,60 @@
1
+ # Is vs Equals for Literals
2
+ # Detects 'is' used with string/int literals (should use '==')
3
+ id: is-vs-equals
4
+ name: Is vs Equals for Literals
5
+ severity: warning
6
+ category: reliability
7
+ language: python
8
+
9
+ message: "Using 'is' with literal — use '==' for value comparison"
10
+
11
+ description: |
12
+ 'is' checks identity (same object in memory), not equality.
13
+ For strings and small ints, Python may intern them, making
14
+ 'is' appear to work, but it's unreliable and wrong.
15
+
16
+ ✅ FIX: Use '==' for value comparison
17
+
18
+ ```python
19
+ if name == "admin": # GOOD - value comparison
20
+ if count == 0: # GOOD - value comparison
21
+ ```
22
+
23
+ query: |
24
+ (comparison_operator
25
+ (identifier)
26
+ ("is")
27
+ (string) @LITERAL)
28
+ (comparison_operator
29
+ (identifier)
30
+ ("is not")
31
+ (string) @LITERAL)
32
+ (comparison_operator
33
+ (identifier)
34
+ ("is")
35
+ (integer) @LITERAL)
36
+ (comparison_operator
37
+ (identifier)
38
+ ("is not")
39
+ (integer) @LITERAL)
40
+
41
+ metavars:
42
+ - LITERAL
43
+
44
+ tags:
45
+ - reliability
46
+ - common-mistake
47
+ - python-specific
48
+
49
+ examples:
50
+ bad: |
51
+ if name is "admin": # BAD - identity check
52
+ if count is 0: # BAD - may work by accident
53
+
54
+ good: |
55
+ if name == "admin": # GOOD
56
+ if count == 0: # GOOD
57
+ if obj is None: # OK - None is a singleton
58
+
59
+ has_fix: true
60
+ fix_action: replace_is_with_equals
@@ -0,0 +1,57 @@
1
+ # Mutable Default Argument
2
+ # Detects mutable defaults in function arguments (common Python pitfall)
3
+ id: mutable-default-arg
4
+ name: Mutable Default Argument
5
+ severity: error
6
+ category: reliability
7
+ language: python
8
+
9
+ message: "Mutable default argument — list/dict/set as default value"
10
+
11
+ description: |
12
+ Mutable default arguments are evaluated once at function definition time,
13
+ not each call. This causes unexpected shared state between calls.
14
+
15
+ ✅ FIX: Use None as default, create mutable inside function
16
+
17
+ ```python
18
+ def process(items=None): # GOOD
19
+ if items is None:
20
+ items = []
21
+ items.append(item)
22
+ ```
23
+
24
+ query: |
25
+ (function_definition
26
+ (parameters
27
+ (default_parameter
28
+ (identifier) @PARAM
29
+ [(list) (dictionary) (set)] @MUTABLE)))
30
+
31
+ metavars:
32
+ - PARAM
33
+ - MUTABLE
34
+
35
+ tags:
36
+ - reliability
37
+ - common-mistake
38
+ - python-specific
39
+
40
+ examples:
41
+ bad: |
42
+ def add_item(item, items=[]): # BAD - shared list!
43
+ items.append(item)
44
+ return items
45
+
46
+ print(add_item(1)) # [1]
47
+ print(add_item(2)) # [1, 2] - unexpected!
48
+
49
+ good: |
50
+ def add_item(item, items=None): # GOOD
51
+ if items is None:
52
+ items = []
53
+ items.append(item)
54
+ return items
55
+
56
+ has_fix: true
57
+ fix_action: convert_to_none_default
@@ -0,0 +1,60 @@
1
+ # Unreachable Except Clause
2
+ # Detects except clauses that can never be reached
3
+ id: unreachable-except
4
+ name: Unreachable Except Clause
5
+ severity: error
6
+ category: reliability
7
+ language: python
8
+
9
+ message: "Unreachable except clause — earlier except catches all"
10
+
11
+ description: |
12
+ When a bare 'except' or 'except Exception' comes before specific
13
+ exception handlers, those specific handlers are never reached.
14
+
15
+ ✅ FIX: Order from specific to general
16
+
17
+ ```python
18
+ try:
19
+ process()
20
+ except ValueError: # Specific first
21
+ handle_value_error()
22
+ except Exception: # General last
23
+ handle_general()
24
+ ```
25
+
26
+ query: |
27
+ (try_statement
28
+ (except_clause
29
+ "except") @GENERAL
30
+ (except_clause
31
+ "except"
32
+ (identifier) @SPECIFIC))
33
+
34
+ metavars:
35
+ - GENERAL
36
+ - SPECIFIC
37
+
38
+ tags:
39
+ - reliability
40
+ - dead-code
41
+ - exceptions
42
+
43
+ examples:
44
+ bad: |
45
+ try:
46
+ process()
47
+ except: # BAD - catches everything
48
+ handle_all()
49
+ except ValueError: # UNREACHABLE!
50
+ handle_value()
51
+
52
+ good: |
53
+ try:
54
+ process()
55
+ except ValueError: # GOOD - specific first
56
+ handle_value()
57
+ except Exception: # GOOD - general last
58
+ handle_general()
59
+
60
+ has_fix: false
@@ -0,0 +1,46 @@
1
+ # Wildcard Import
2
+ # Detects 'from module import *' which pollutes namespace
3
+ id: wildcard-import
4
+ name: Wildcard Import
5
+ severity: warning
6
+ category: readability
7
+ language: python
8
+
9
+ message: "Wildcard import — pollutes namespace, hard to track origin"
10
+
11
+ description: |
12
+ 'from module import *' makes it unclear where names come from
13
+ and can cause name collisions. Explicit is better than implicit.
14
+
15
+ ✅ FIX: Import specific names or use module prefix
16
+
17
+ ```python
18
+ from os import path, getenv # GOOD - explicit
19
+ import os # GOOD - namespace preserved
20
+ os.path.join(...) # Clear where this comes from
21
+ ```
22
+
23
+ query: |
24
+ (import_from_statement
25
+ module_name: (dotted_name) @MODULE
26
+ (wildcard_import) @WILDCARD)
27
+
28
+ metavars:
29
+ - MODULE
30
+ - WILDCARD
31
+
32
+ tags:
33
+ - readability
34
+ - best-practice
35
+ - imports
36
+
37
+ examples:
38
+ bad: |
39
+ from os import * # BAD - where does path come from?
40
+ from numpy import * # BAD - pollutes namespace
41
+
42
+ good: |
43
+ from os import path, getenv # GOOD - explicit
44
+ import numpy as np # GOOD - namespace preserved
45
+
46
+ has_fix: false
@@ -0,0 +1,63 @@
1
+ # Dangerously Set Inner HTML
2
+ # Detects dangerouslySetInnerHTML usage (XSS risk)
3
+ id: dangerously-set-inner-html
4
+ name: Dangerously Set Inner HTML
5
+ severity: error
6
+ category: security
7
+ language: tsx
8
+
9
+ message: "dangerouslySetInnerHTML — XSS risk, sanitize user input"
10
+
11
+ description: |
12
+ dangerouslySetInnerHTML allows arbitrary HTML injection.
13
+ This is a major XSS vulnerability if user input is used.
14
+
15
+ ✅ FIX: Sanitize HTML with a library like DOMPurify
16
+
17
+ ```tsx
18
+ import DOMPurify from 'dompurify';
19
+
20
+ <div dangerouslySetInnerHTML={{
21
+ __html: DOMPurify.sanitize(userInput)
22
+ }} />
23
+ ```
24
+
25
+ Or better, avoid using HTML altogether and use JSX.
26
+
27
+ query: |
28
+ (jsx_attribute
29
+ (property_identifier) @ATTR
30
+ (#match? @ATTR "dangerouslySetInnerHTML"))
31
+
32
+ metavars:
33
+ - ATTR
34
+
35
+ tags:
36
+ - security
37
+ - xss
38
+ - react
39
+ - jsx
40
+
41
+ examples:
42
+ bad: |
43
+ function Component({ userInput }) {
44
+ return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
45
+ }
46
+
47
+ good: |
48
+ import DOMPurify from 'dompurify';
49
+
50
+ function Component({ userInput }) {
51
+ return (
52
+ <div dangerouslySetInnerHTML={{
53
+ __html: DOMPurify.sanitize(userInput)
54
+ }} />
55
+ );
56
+ }
57
+
58
+ // Or better:
59
+ function Component({ content }) {
60
+ return <div>{content}</div>; // Just use JSX
61
+ }
62
+
63
+ has_fix: false
@@ -0,0 +1,56 @@
1
+ # Await in Loop
2
+ # Detects sequential await calls inside loops (performance anti-pattern)
3
+ id: await-in-loop
4
+ name: Await in Loop
5
+ severity: warning
6
+ category: performance
7
+ language: typescript
8
+
9
+ message: "Await in loop — sequential execution is slow, use Promise.all()"
10
+
11
+ description: |
12
+ Using await inside a loop forces sequential execution, making it O(n) time.
13
+ With Promise.all(), operations run in parallel, making it O(1) time.
14
+
15
+ ✅ FIX: Use Promise.all() for parallel execution
16
+
17
+ ⚠️ EXCEPTION: If order matters or you need to throttle requests, sequential
18
+ may be intentional. In that case, add a comment explaining why.
19
+
20
+ query: |
21
+ (for_in_statement
22
+ body: (statement_block
23
+ (expression_statement
24
+ (await_expression) @AWAIT)))
25
+ (for_statement
26
+ body: (statement_block
27
+ (expression_statement
28
+ (await_expression) @AWAIT)))
29
+ (while_statement
30
+ body: (statement_block
31
+ (expression_statement
32
+ (await_expression) @AWAIT)))
33
+
34
+ metavars:
35
+ - AWAIT
36
+
37
+ tags:
38
+ - performance
39
+ - async
40
+ - optimization
41
+
42
+ examples:
43
+ bad: |
44
+ // Slow: sequential execution
45
+ for (const id of ids) {
46
+ await fetchUser(id); // Wait, wait, wait...
47
+ }
48
+
49
+ good: |
50
+ // Fast: parallel execution
51
+ await Promise.all(
52
+ ids.map(id => fetchUser(id)) // All at once!
53
+ )
54
+
55
+ has_fix: true
56
+ fix_action: convert_to_promise_all
@@ -0,0 +1,47 @@
1
+ # Console Statement
2
+ # Detects console.log and friends (debug leftovers)
3
+ id: console-statement
4
+ name: Console Statement
5
+ severity: warning
6
+ category: debugging
7
+ language: typescript
8
+
9
+ message: "{{METHOD}} — remove debug statements before committing"
10
+
11
+ description: |
12
+ Console statements are for debugging and should not be in production code.
13
+
14
+ ✅ FIX: Remove or use a proper logging library.
15
+
16
+ query: |
17
+ (call_expression
18
+ function: (member_expression
19
+ object: (identifier) @OBJ (#eq? @OBJ "console")
20
+ property: (property_identifier) @METHOD)
21
+ arguments: (arguments) @ARGS)
22
+
23
+ # Post-filter: Exclude debug function names like "dbg"
24
+ post_filter: not_dbg_method
25
+
26
+ metavars:
27
+ - OBJ
28
+ - METHOD
29
+ - ARGS
30
+
31
+ tags:
32
+ - debugging
33
+ - code-quality
34
+
35
+ examples:
36
+ bad: |
37
+ console.log("debug info");
38
+ console.error("error");
39
+
40
+ good: |
41
+ // Use a logging library
42
+ import { logger } from './logger';
43
+ logger.info("info");
44
+ logger.error("error");
45
+
46
+ has_fix: true
47
+ fix_action: remove
@@ -0,0 +1,47 @@
1
+ # Debugger Statement
2
+ # Detects debugger statements left in code
3
+ id: debugger-statement
4
+ name: Debugger Statement
5
+ severity: warning
6
+ category: debugging
7
+ language: typescript
8
+
9
+ message: "Debugger statement — remove before committing"
10
+
11
+ description: |
12
+ Debugger statements pause execution and should never be committed to production.
13
+
14
+ ✅ FIX: Remove the debugger statement before committing.
15
+
16
+ If you need to debug, use:
17
+ - console.log() for quick checks
18
+ - IDE debugger for stepping through
19
+ - Add breakpoints in dev tools
20
+
21
+ query: |
22
+ (debugger_statement) @DEBUGGER
23
+
24
+ metavars:
25
+ - DEBUGGER
26
+
27
+ tags:
28
+ - debugging
29
+ - code-quality
30
+
31
+ examples:
32
+ bad: |
33
+ function process() {
34
+ const x = calculate();
35
+ debugger; // ← Remove this!
36
+ return x;
37
+ }
38
+
39
+ good: |
40
+ function process() {
41
+ const x = calculate();
42
+ console.log('Debug:', x); // Or just remove
43
+ return x;
44
+ }
45
+
46
+ has_fix: true
47
+ fix_action: remove
@@ -0,0 +1,117 @@
1
+ # Deep Nesting
2
+ # Detects functions with 3+ levels of control structure nesting (if/for/while/try)
3
+ id: deep-nesting
4
+ name: Deep Nesting
5
+ severity: warning
6
+ category: complexity
7
+ language: typescript
8
+
9
+ message: "Deep nesting (3+ levels) — consider early returns or extract functions"
10
+
11
+ description: |
12
+ Deeply nested code (if/for/while/try blocks 3+ levels deep) is hard to read and test.
13
+ Flatten by using early returns (guard clauses) or extracting nested logic.
14
+
15
+ query: |
16
+ [
17
+ ;; Pattern 1: if inside if inside if
18
+ (statement_block
19
+ (if_statement
20
+ consequence: (statement_block
21
+ (if_statement
22
+ consequence: (statement_block
23
+ (if_statement) @IF_NESTED)))))
24
+
25
+ ;; Pattern 2: for inside if inside if
26
+ (statement_block
27
+ (if_statement
28
+ consequence: (statement_block
29
+ (if_statement
30
+ consequence: (statement_block
31
+ (for_statement) @FOR_NESTED)))))
32
+
33
+ ;; Pattern 3: while inside if inside if
34
+ (statement_block
35
+ (if_statement
36
+ consequence: (statement_block
37
+ (if_statement
38
+ consequence: (statement_block
39
+ (while_statement) @WHILE_NESTED)))))
40
+
41
+ ;; Pattern 4: try inside if inside if
42
+ (statement_block
43
+ (if_statement
44
+ consequence: (statement_block
45
+ (if_statement
46
+ consequence: (statement_block
47
+ (try_statement) @TRY_NESTED)))))
48
+
49
+ ;; Pattern 5: if inside for inside if
50
+ (statement_block
51
+ (if_statement
52
+ consequence: (statement_block
53
+ (for_statement
54
+ body: (statement_block
55
+ (if_statement) @IF_IN_FOR)))))
56
+
57
+ ;; Pattern 6: if inside while inside if
58
+ (statement_block
59
+ (if_statement
60
+ consequence: (statement_block
61
+ (while_statement
62
+ body: (statement_block
63
+ (if_statement) @IF_IN_WHILE)))))
64
+
65
+ ;; Pattern 7: for inside for inside for
66
+ (statement_block
67
+ (for_statement
68
+ body: (statement_block
69
+ (for_statement
70
+ body: (statement_block
71
+ (for_statement) @FOR_NESTED)))))
72
+ ]
73
+
74
+ metavars:
75
+ - IF_NESTED
76
+ - FOR_NESTED
77
+ - WHILE_NESTED
78
+ - TRY_NESTED
79
+ - IF_IN_FOR
80
+ - IF_IN_WHILE
81
+
82
+ tags:
83
+ - complexity
84
+ - readability
85
+ - best-practice
86
+
87
+ examples:
88
+ bad: |
89
+ function process(user) {
90
+ if (user) {
91
+ if (user.active) {
92
+ if (user.permissions) { // 3 levels deep!
93
+ return doSomething();
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ function loop(items) {
100
+ for (const item of items) {
101
+ if (item.active) {
102
+ for (const sub of item.subs) { // 3 levels
103
+ process(sub);
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ good: |
110
+ function process(user) {
111
+ if (!user) return null;
112
+ if (!user.active) return null;
113
+ if (!user.permissions) return null;
114
+ return doSomething();
115
+ }
116
+
117
+ has_fix: false
@@ -0,0 +1,73 @@
1
+ # Deep Promise Chain
2
+ # Detects promise chains 4+ levels deep
3
+ id: deep-promise-chain
4
+ name: Deep Promise Chain (4+ levels)
5
+ severity: warning
6
+ category: complexity
7
+ language: typescript
8
+
9
+ message: "Promise chain {{M1}} → {{M2}} → {{M3}} → {{M4}} — consider async/await"
10
+
11
+ description: |
12
+ Deep promise chains (4+ levels) are hard to read and debug.
13
+ Async/await provides clearer control flow.
14
+
15
+ ✅ FIX: Convert to async/await
16
+
17
+ query: |
18
+ (call_expression
19
+ function: (member_expression
20
+ object: (call_expression
21
+ function: (member_expression
22
+ object: (call_expression
23
+ function: (member_expression
24
+ object: (call_expression
25
+ function: (member_expression
26
+ property: (property_identifier) @M1)
27
+ arguments: (arguments))
28
+ property: (property_identifier) @M2)
29
+ arguments: (arguments))
30
+ property: (property_identifier) @M3)
31
+ arguments: (arguments))
32
+ property: (property_identifier) @M4)
33
+ arguments: (arguments))
34
+ (#match? @M1 "^(then|catch|finally)$")
35
+ (#match? @M2 "^(then|catch|finally)$")
36
+ (#match? @M3 "^(then|catch|finally)$")
37
+ (#match? @M4 "^(then|catch|finally)$")
38
+
39
+ metavars:
40
+ - M1
41
+ - M2
42
+ - M3
43
+ - M4
44
+
45
+ tags:
46
+ - complexity
47
+ - async
48
+ - readability
49
+
50
+ examples:
51
+ bad: |
52
+ fetch('/api')
53
+ .then(r => r.json())
54
+ .catch(e => console.log(e))
55
+ .then(data => data.items)
56
+ .then(items => items[0])
57
+ .then(first => process(first));
58
+
59
+ good: |
60
+ async function fetchFirstItem() {
61
+ try {
62
+ const response = await fetch('/api');
63
+ const data = await response.json();
64
+ const items = data.items;
65
+ const first = items[0];
66
+ return process(first);
67
+ } catch (e) {
68
+ console.log(e);
69
+ }
70
+ }
71
+
72
+ has_fix: true
73
+ fix_action: convert_to_async_await