codeguardian-cli 1.0.0__py3-none-any.whl

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 (50) hide show
  1. CODEGUARDIAN/__init__.py +0 -0
  2. CODEGUARDIAN/analyzers/__init__.py +0 -0
  3. CODEGUARDIAN/analyzers/circular_dependency_analyzer.py +101 -0
  4. CODEGUARDIAN/analyzers/db_access_analyzer.py +55 -0
  5. CODEGUARDIAN/analyzers/dependency_analyzer.py +259 -0
  6. CODEGUARDIAN/analyzers/file_analyzer.py +96 -0
  7. CODEGUARDIAN/analyzers/function_analyzer.py +199 -0
  8. CODEGUARDIAN/analyzers/source_code_analyzer.py +169 -0
  9. CODEGUARDIAN/cli/__init__.py +0 -0
  10. CODEGUARDIAN/cli/commands.py +619 -0
  11. CODEGUARDIAN/config/__init__.py +0 -0
  12. CODEGUARDIAN/config/config_loader.py +76 -0
  13. CODEGUARDIAN/config/settings.py +2 -0
  14. CODEGUARDIAN/main.py +4 -0
  15. CODEGUARDIAN/reports/__init__.py +0 -0
  16. CODEGUARDIAN/reports/architecture_score.py +68 -0
  17. CODEGUARDIAN/reports/console_reporter.py +487 -0
  18. CODEGUARDIAN/reports/html_reporter.py +293 -0
  19. CODEGUARDIAN/reports/json_reporter.py +69 -0
  20. CODEGUARDIAN/reports/markdown_reporter.py +130 -0
  21. CODEGUARDIAN/reports/severity.py +15 -0
  22. CODEGUARDIAN/reports/statistics_reporter.py +183 -0
  23. CODEGUARDIAN/rules/__init__.py +0 -0
  24. CODEGUARDIAN/rules/architecture_rules.py +5 -0
  25. CODEGUARDIAN/rules/architecture_validator.py +69 -0
  26. CODEGUARDIAN/rules/controllers/user_controller.py +16 -0
  27. CODEGUARDIAN/src/__init__.py +0 -0
  28. CODEGUARDIAN/src/discovery/__init__.py +0 -0
  29. CODEGUARDIAN/src/discovery/finder.py +39 -0
  30. CODEGUARDIAN/src/extractor/__init__.py +0 -0
  31. CODEGUARDIAN/src/extractor/class_extractor.py +32 -0
  32. CODEGUARDIAN/src/extractor/function_extractor.py +17 -0
  33. CODEGUARDIAN/src/extractor/import_extractor.py +23 -0
  34. CODEGUARDIAN/src/extractor/python_class_extractor.py +13 -0
  35. CODEGUARDIAN/src/extractor/python_function_extractor.py +16 -0
  36. CODEGUARDIAN/src/extractor/python_imports_extractor.py +24 -0
  37. CODEGUARDIAN/src/main.py +65 -0
  38. CODEGUARDIAN/src/parser/__init__.py +0 -0
  39. CODEGUARDIAN/src/parser/ts_parser.py +14 -0
  40. CODEGUARDIAN/src/tree/Walker.py +10 -0
  41. CODEGUARDIAN/src/tree/__init__.py +0 -0
  42. CODEGUARDIAN/utils/__init__.py +0 -0
  43. CODEGUARDIAN/utils/ast_cache.py +47 -0
  44. CODEGUARDIAN/utils/file_cache.py +30 -0
  45. CODEGUARDIAN/utils/layer_utils.py +19 -0
  46. codeguardian_cli-1.0.0.dist-info/METADATA +43 -0
  47. codeguardian_cli-1.0.0.dist-info/RECORD +50 -0
  48. codeguardian_cli-1.0.0.dist-info/WHEEL +5 -0
  49. codeguardian_cli-1.0.0.dist-info/entry_points.txt +2 -0
  50. codeguardian_cli-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,68 @@
1
+ from CODEGUARDIAN.config.config_loader import (
2
+ ConfigLoader
3
+ )
4
+
5
+
6
+ class ArchitectureScoreCalculator:
7
+
8
+ def __init__(self):
9
+
10
+ config = ConfigLoader.load()
11
+
12
+ self.penalties = config.get(
13
+ "architecture_score",
14
+ {}
15
+ )
16
+
17
+ def calculate(
18
+ self,
19
+ file_violations,
20
+ function_violations,
21
+ architecture_violations,
22
+ circular_violations,
23
+ db_access_violations
24
+ ):
25
+
26
+ score = 100
27
+
28
+ score -= (
29
+ len(file_violations)
30
+ * self.penalties.get(
31
+ "file_penalty",
32
+ 10
33
+ )
34
+ )
35
+
36
+ score -= (
37
+ len(function_violations)
38
+ * self.penalties.get(
39
+ "function_penalty",
40
+ 5
41
+ )
42
+ )
43
+
44
+ score -= (
45
+ len(architecture_violations)
46
+ * self.penalties.get(
47
+ "architecture_penalty",
48
+ 20
49
+ )
50
+ )
51
+
52
+ score -= (
53
+ len(circular_violations)
54
+ * self.penalties.get(
55
+ "circular_dependency_penalty",
56
+ 30
57
+ )
58
+ )
59
+
60
+ score -= (
61
+ len(db_access_violations)
62
+ * self.penalties.get(
63
+ "db_access_penalty",
64
+ 15
65
+ )
66
+ )
67
+
68
+ return max(score, 0)
@@ -0,0 +1,487 @@
1
+ from rich.console import Console
2
+ from rich.table import Table
3
+
4
+ from CODEGUARDIAN.reports.severity import (
5
+ get_severity
6
+ )
7
+ from rich.panel import Panel
8
+ from rich.text import Text
9
+
10
+
11
+
12
+ class ConsoleReporter:
13
+
14
+ def __init__(self):
15
+
16
+ self.console = Console()
17
+
18
+ def show_dashboard(
19
+ self,
20
+ source_analysis,
21
+ file_violations,
22
+ function_violations,
23
+ architecture_violations,
24
+ circular_violations,
25
+ db_access_violations,
26
+ score
27
+ ):
28
+
29
+ total_files = len(source_analysis)
30
+
31
+ total_classes = sum(
32
+ len(item["classes"])
33
+ for item in source_analysis
34
+ )
35
+
36
+ total_functions = sum(
37
+ len(item["functions"])
38
+ for item in source_analysis
39
+ )
40
+
41
+ total_imports = sum(
42
+ len(item["imports"])
43
+ for item in source_analysis
44
+ )
45
+
46
+ if score >= 90:
47
+ score_style = "green"
48
+
49
+ elif score >= 70:
50
+ score_style = "yellow"
51
+
52
+ else:
53
+ score_style = "red"
54
+
55
+ dashboard = Text()
56
+
57
+ dashboard.append(
58
+ f"✔ Files Scanned : {total_files}\n",
59
+ style="cyan"
60
+ )
61
+
62
+ dashboard.append(
63
+ f"✔ Classes : {total_classes}\n",
64
+ style="green"
65
+ )
66
+
67
+ dashboard.append(
68
+ f"✔ Functions : {total_functions}\n",
69
+ style="green"
70
+ )
71
+
72
+ dashboard.append(
73
+ f"✔ Imports : {total_imports}\n\n",
74
+ style="green"
75
+ )
76
+
77
+ # Oversized Files
78
+ if len(file_violations) == 0:
79
+ dashboard.append(
80
+ f"✔ Oversized Files : 0\n",
81
+ style="green"
82
+ )
83
+ else:
84
+ dashboard.append(
85
+ f"⚠ Oversized Files : {len(file_violations)}\n",
86
+ style="yellow"
87
+ )
88
+
89
+ # Oversized Functions
90
+ if len(function_violations) == 0:
91
+ dashboard.append(
92
+ f"✔ Oversized Functions : 0\n",
93
+ style="green"
94
+ )
95
+ else:
96
+ dashboard.append(
97
+ f"⚠ Oversized Functions : {len(function_violations)}\n",
98
+ style="yellow"
99
+ )
100
+
101
+ # Architecture Violations
102
+ if len(architecture_violations) == 0:
103
+ dashboard.append(
104
+ f"✔ Architecture Violations : 0\n",
105
+ style="green"
106
+ )
107
+ else:
108
+ dashboard.append(
109
+ f"✖ Architecture Violations : {len(architecture_violations)}\n",
110
+ style="red"
111
+ )
112
+
113
+ # Circular Dependencies
114
+ if len(circular_violations) == 0:
115
+ dashboard.append(
116
+ f"✔ Circular Dependencies : 0\n",
117
+ style="green"
118
+ )
119
+ else:
120
+ dashboard.append(
121
+ f"✖ Circular Dependencies : {len(circular_violations)}\n",
122
+ style="red"
123
+ )
124
+
125
+ # Direct Database Access
126
+ if len(db_access_violations) == 0:
127
+ dashboard.append(
128
+ f"✔ Direct DB Access : 0\n\n",
129
+ style="green"
130
+ )
131
+ else:
132
+ dashboard.append(
133
+ f"✖ Direct DB Access : {len(db_access_violations)}\n\n",
134
+ style="red"
135
+ )
136
+
137
+ self.console.print(
138
+ Panel.fit(
139
+ dashboard,
140
+ title="Architecture Dashboard",
141
+ border_style="cyan"
142
+ )
143
+ )
144
+
145
+ def show_file_violations(
146
+ self,
147
+ violations
148
+ ):
149
+
150
+ table = Table(
151
+ title="Oversized Files"
152
+ )
153
+
154
+ table.add_column(
155
+ "File",
156
+ style="cyan"
157
+ )
158
+
159
+ table.add_column(
160
+ "Lines",
161
+ style="red"
162
+ )
163
+
164
+ table.add_column(
165
+ "Severity",
166
+ style="yellow"
167
+ )
168
+
169
+ for violation in violations:
170
+
171
+ severity = get_severity(
172
+ violation.line_count,
173
+ warning_threshold=300,
174
+ critical_threshold=500
175
+ )
176
+
177
+ table.add_row(
178
+ violation.file_path,
179
+ str(violation.line_count),
180
+ severity
181
+ )
182
+
183
+ self.console.print(table)
184
+
185
+
186
+ def show_function_violations(
187
+ self,
188
+ violations
189
+ ):
190
+
191
+ table = Table(
192
+ title="Oversized Functions"
193
+ )
194
+
195
+ table.add_column(
196
+ "Function",
197
+ style="cyan"
198
+ )
199
+
200
+ table.add_column(
201
+ "Lines",
202
+ style="red"
203
+ )
204
+
205
+ table.add_column(
206
+ "Severity",
207
+ style="yellow"
208
+ )
209
+
210
+ for violation in violations:
211
+
212
+ severity = get_severity(
213
+ violation.line_count,
214
+ warning_threshold=50,
215
+ critical_threshold=100
216
+ )
217
+
218
+ table.add_row(
219
+ violation.function_name,
220
+ str(violation.line_count),
221
+ severity
222
+ )
223
+
224
+ self.console.print(table)
225
+
226
+ def show_architecture_violations(
227
+ self,
228
+ violations
229
+ ):
230
+
231
+ table = Table(
232
+ title="Architecture Violations"
233
+ )
234
+
235
+ table.add_column(
236
+ "File",
237
+ style="cyan"
238
+ )
239
+
240
+ table.add_column(
241
+ "Rule Broken",
242
+ style="red"
243
+ )
244
+
245
+ table.add_column(
246
+ "Severity",
247
+ style="red"
248
+ )
249
+
250
+ for violation in violations:
251
+
252
+ table.add_row(
253
+ violation.source_file,
254
+ (
255
+ f"{violation.source_layer}"
256
+ f" → "
257
+ f"{violation.target_layer}"
258
+ ),
259
+ "🔴 CRITICAL"
260
+ )
261
+
262
+ self.console.print(table)
263
+
264
+ def show_circular_dependencies(
265
+ self,
266
+ violations
267
+ ):
268
+
269
+ table = Table(
270
+ title="Circular Dependencies"
271
+ )
272
+
273
+ table.add_column(
274
+ "Dependency Cycle",
275
+ style="red"
276
+ )
277
+
278
+ table.add_column(
279
+ "Severity",
280
+ style="red"
281
+ )
282
+
283
+ for violation in violations:
284
+
285
+ table.add_row(
286
+ " → ".join(
287
+ violation.cycle
288
+ ),
289
+ "🔴 CRITICAL"
290
+ )
291
+
292
+ self.console.print(table)
293
+
294
+
295
+ def show_db_access_violations(
296
+ self,
297
+ violations
298
+ ):
299
+
300
+ table = Table(
301
+ title="Direct Database Access"
302
+ )
303
+
304
+ table.add_column(
305
+ "Controller",
306
+ style="cyan"
307
+ )
308
+
309
+ table.add_column(
310
+ "Database",
311
+ style="red"
312
+ )
313
+
314
+ for violation in violations:
315
+
316
+ table.add_row(
317
+
318
+ violation.source_file,
319
+
320
+ violation.database_library
321
+
322
+ )
323
+
324
+ self.console.print(table)
325
+
326
+ def show_summary(
327
+ self,
328
+ total_files,
329
+ file_violations,
330
+ function_violations,
331
+ architecture_violations,
332
+ circular_violations,
333
+ db_access_violations,
334
+ score
335
+ ):
336
+
337
+ table = Table(
338
+ title="CodeGuardian Summary"
339
+ )
340
+
341
+ table.add_column(
342
+ "Metric",
343
+ style="cyan"
344
+ )
345
+
346
+ table.add_column(
347
+ "Value",
348
+ style="green"
349
+ )
350
+
351
+ table.add_row(
352
+ "Files Scanned",
353
+ str(total_files)
354
+ )
355
+
356
+ table.add_row(
357
+ "Oversized Files",
358
+ str(len(file_violations))
359
+ )
360
+
361
+ table.add_row(
362
+ "Oversized Functions",
363
+ str(len(function_violations))
364
+ )
365
+
366
+ table.add_row(
367
+ "Architecture Violations",
368
+ str(len(architecture_violations))
369
+ )
370
+
371
+ table.add_row(
372
+ "Circular Dependencies",
373
+ str(len(circular_violations))
374
+ )
375
+
376
+ table.add_row(
377
+ "Direct Database Access",
378
+ str(len(db_access_violations))
379
+ )
380
+
381
+ table.add_row(
382
+ "Architecture Score",
383
+ f"{score}/100"
384
+ )
385
+
386
+ self.console.print(table)
387
+
388
+ def show_source_analysis(
389
+ self,
390
+ source_analysis,
391
+ details=False
392
+ ):
393
+
394
+ table = Table(
395
+ title="Source Code Analysis"
396
+ )
397
+
398
+ table.add_column(
399
+ "File",
400
+ style="cyan"
401
+ )
402
+
403
+ table.add_column(
404
+ "Classes",
405
+ justify="center",
406
+ style="green"
407
+ )
408
+
409
+ table.add_column(
410
+ "Functions",
411
+ justify="center",
412
+ style="yellow"
413
+ )
414
+
415
+ table.add_column(
416
+ "Imports",
417
+ justify="center",
418
+ style="magenta"
419
+ )
420
+
421
+ for item in source_analysis:
422
+
423
+ table.add_row(
424
+ item["file"],
425
+ str(len(item["classes"])),
426
+ str(len(item["functions"])),
427
+ str(len(item["imports"]))
428
+ )
429
+
430
+ self.console.print(table)
431
+
432
+ if not details:
433
+ return
434
+
435
+ self.console.rule(
436
+ "[bold blue]Source Code Details[/bold blue]"
437
+ )
438
+
439
+ for item in source_analysis:
440
+
441
+ # Skip completely empty files
442
+ if (
443
+ not item["classes"]
444
+ and not item["functions"]
445
+ and not item["imports"]
446
+ ):
447
+ continue
448
+
449
+ self.console.print()
450
+
451
+ self.console.print(
452
+ f"[bold cyan]{item['file']}[/bold cyan]"
453
+ )
454
+
455
+ classes = (
456
+ ", ".join(item["classes"])
457
+ if item["classes"]
458
+ else "-"
459
+ )
460
+
461
+ functions = (
462
+ ", ".join(item["functions"])
463
+ if item["functions"]
464
+ else "-"
465
+ )
466
+
467
+ imports = (
468
+ ", ".join(item["imports"])
469
+ if item["imports"]
470
+ else "-"
471
+ )
472
+
473
+ self.console.print(
474
+ f"[green]Classes:[/green] {classes}"
475
+ )
476
+
477
+ self.console.print(
478
+ f"[yellow]Functions:[/yellow] {functions}"
479
+ )
480
+
481
+ self.console.print(
482
+ f"[magenta]Imports:[/magenta] {imports}"
483
+ )
484
+
485
+ self.console.print(
486
+ "-" * 70
487
+ )