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,293 @@
1
+ from datetime import datetime
2
+
3
+
4
+ class HtmlReporter:
5
+
6
+ def generate(
7
+ self,
8
+ file_violations,
9
+ function_violations,
10
+ architecture_violations,
11
+ circular_violations,
12
+ db_access_violations,
13
+ source_analysis,
14
+ score
15
+ ):
16
+
17
+ if score >= 90:
18
+ score_color = "#28a745"
19
+ status = "🟢 Excellent"
20
+ elif score >= 70:
21
+ score_color = "#ffc107"
22
+ status = "🟡 Good"
23
+ else:
24
+ score_color = "#dc3545"
25
+ status = "🔴 Needs Improvement"
26
+
27
+ total_files = len(source_analysis)
28
+
29
+ total_classes = sum(
30
+ len(item["classes"])
31
+ for item in source_analysis
32
+ )
33
+
34
+ total_functions = sum(
35
+ len(item["functions"])
36
+ for item in source_analysis
37
+ )
38
+
39
+ total_imports = sum(
40
+ len(item["imports"])
41
+ for item in source_analysis
42
+ )
43
+
44
+ html = f"""<!DOCTYPE html>
45
+
46
+ <html>
47
+
48
+ <head>
49
+
50
+ <meta charset="UTF-8">
51
+
52
+ <title>CodeGuardian Report</title>
53
+
54
+ <link rel="stylesheet" href="reports/style.css">
55
+
56
+ </head>
57
+
58
+ <body>
59
+
60
+ <div class="container">
61
+
62
+ <h1>CodeGuardian Report</h1>
63
+
64
+ <p>
65
+
66
+ <b>Generated:</b>
67
+
68
+ {datetime.now().strftime("%d %B %Y %H:%M")}
69
+
70
+ </p>
71
+
72
+ <div class="dashboard">
73
+
74
+ <div
75
+ class="score"
76
+ style="color:{score_color};">
77
+
78
+ Architecture Score
79
+
80
+ </div>
81
+
82
+ <div class="progress">
83
+
84
+ <div
85
+ class="progress-bar"
86
+ style="width:{score}%; background:{score_color};">
87
+
88
+ </div>
89
+
90
+ </div>
91
+
92
+ <h2>{score}/100</h2>
93
+
94
+ <p class="status">
95
+
96
+ {status}
97
+
98
+ </p>
99
+
100
+ <div class="grid">
101
+
102
+ <div class="card blue">
103
+ <h3>📄 Files</h3>
104
+ <p>{total_files}</p>
105
+ </div>
106
+
107
+ <div class="card green">
108
+ <h3>🏛 Classes</h3>
109
+ <p>{total_classes}</p>
110
+ </div>
111
+
112
+ <div class="card green">
113
+ <h3>⚙ Functions</h3>
114
+ <p>{total_functions}</p>
115
+ </div>
116
+
117
+ <div class="card blue">
118
+ <h3>📦 Imports</h3>
119
+ <p>{total_imports}</p>
120
+ </div>
121
+
122
+ <div class="card orange">
123
+ <h3>⚠ Oversized Files</h3>
124
+ <p>{len(file_violations)}</p>
125
+ </div>
126
+
127
+ <div class="card orange">
128
+ <h3>⚠ Oversized Functions</h3>
129
+ <p>{len(function_violations)}</p>
130
+ </div>
131
+
132
+ <div class="card red">
133
+ <h3>❌ Architecture Issues</h3>
134
+ <p>{len(architecture_violations)}</p>
135
+ </div>
136
+
137
+ <div class="card red">
138
+ <h3>🔁 Circular Dependencies</h3>
139
+ <p>{len(circular_violations)}</p>
140
+ </div>
141
+
142
+ </div>
143
+
144
+ </div>
145
+ """
146
+ def section(
147
+ title,
148
+ headers,
149
+ rows
150
+ ):
151
+
152
+ nonlocal html
153
+
154
+ html += f"<h2>{title}</h2>"
155
+
156
+ if not rows:
157
+
158
+ html += """
159
+ <p class="ok">
160
+ ✔ No issues found.
161
+ </p>
162
+ """
163
+ return
164
+
165
+ html += "<table>"
166
+
167
+ html += "<tr>"
168
+
169
+ for header in headers:
170
+
171
+ html += f"<th>{header}</th>"
172
+
173
+ html += "</tr>"
174
+
175
+ for row in rows:
176
+
177
+ html += "<tr>"
178
+
179
+ for cell in row:
180
+
181
+ html += f"<td>{cell}</td>"
182
+
183
+ html += "</tr>"
184
+
185
+ html += "</table>"
186
+ section(
187
+ "Oversized Files",
188
+ ["File", "Lines"],
189
+ [
190
+ [
191
+ violation.file_path,
192
+ violation.line_count
193
+ ]
194
+ for violation in file_violations
195
+ ]
196
+ )
197
+
198
+ section(
199
+ "Oversized Functions",
200
+ ["Function", "Lines"],
201
+ [
202
+ [
203
+ violation.function_name,
204
+ violation.line_count
205
+ ]
206
+ for violation in function_violations
207
+ ]
208
+ )
209
+
210
+ section(
211
+ "Architecture Violations",
212
+ ["File", "Rule Broken"],
213
+ [
214
+ [
215
+ violation.source_file,
216
+ f"{violation.source_layer} → {violation.target_layer}"
217
+ ]
218
+ for violation in architecture_violations
219
+ ]
220
+ )
221
+
222
+ section(
223
+ "Circular Dependencies",
224
+ ["Dependency Cycle"],
225
+ [
226
+ [
227
+ " → ".join(
228
+ violation.cycle
229
+ )
230
+ ]
231
+ for violation in circular_violations
232
+ ]
233
+ )
234
+
235
+ html += """
236
+ <h2>Source Code Analysis</h2>
237
+
238
+ <table>
239
+
240
+ <tr>
241
+
242
+ <th>File</th>
243
+
244
+ <th>Classes</th>
245
+
246
+ <th>Functions</th>
247
+
248
+ <th>Imports</th>
249
+
250
+ </tr>
251
+ """
252
+
253
+ for item in source_analysis:
254
+
255
+ html += f"""
256
+ <tr>
257
+
258
+ <td>{item["file"]}</td>
259
+
260
+ <td>{len(item["classes"])}</td>
261
+
262
+ <td>{len(item["functions"])}</td>
263
+
264
+ <td>{len(item["imports"])}</td>
265
+
266
+ </tr>
267
+ """
268
+
269
+ html += """
270
+ </table>
271
+
272
+ <div class="footer">
273
+
274
+ Generated by <b>CodeGuardian</b><br>
275
+
276
+ Version 1.0
277
+
278
+ </div>
279
+
280
+ </div>
281
+
282
+ </body>
283
+
284
+ </html>
285
+ """
286
+
287
+ with open(
288
+ "report.html",
289
+ "w",
290
+ encoding="utf-8"
291
+ ) as file:
292
+
293
+ file.write(html)
@@ -0,0 +1,69 @@
1
+ import json
2
+
3
+
4
+ class JsonReporter:
5
+
6
+ def generate(
7
+ self,
8
+ file_violations,
9
+ function_violations,
10
+ architecture_violations,
11
+ circular_violations,
12
+ db_access_violations,
13
+ source_analysis,
14
+ score
15
+ ):
16
+ report = {
17
+
18
+ "architecture_score": score,
19
+
20
+ "oversized_files": [
21
+
22
+ {
23
+ "file": v.file_path,
24
+ "lines": v.line_count
25
+ }
26
+
27
+ for v in file_violations
28
+ ],
29
+
30
+ "oversized_functions": [
31
+
32
+ {
33
+ "function": v.function_name,
34
+ "lines": v.line_count
35
+ }
36
+
37
+ for v in function_violations
38
+ ],
39
+
40
+ "architecture_violations": [
41
+
42
+ {
43
+ "source_file": v.source_file,
44
+ "rule": (
45
+ f"{v.source_layer}"
46
+ f" -> "
47
+ f"{v.target_layer}"
48
+ )
49
+ }
50
+
51
+ for v in architecture_violations
52
+ ],
53
+
54
+ "circular_dependencies": [
55
+
56
+ {
57
+ "cycle": c.cycle
58
+ }
59
+
60
+ for c in circular_violations
61
+ ],
62
+
63
+ "source_analysis": source_analysis
64
+ }
65
+
66
+ return json.dumps(
67
+ report,
68
+ indent=4
69
+ )
@@ -0,0 +1,130 @@
1
+ class MarkdownReporter:
2
+
3
+ def generate(
4
+ self,
5
+ file_violations,
6
+ function_violations,
7
+ architecture_violations,
8
+ circular_violations,
9
+ db_access_violations,
10
+ source_analysis,
11
+ score
12
+ ):
13
+
14
+ lines = []
15
+
16
+ lines.append("# CodeGuardian Report\n")
17
+
18
+ lines.append(f"## Architecture Score\n")
19
+ lines.append(f"**{score}/100**\n")
20
+
21
+ # --------------------------------------------------
22
+
23
+ lines.append("## Oversized Files\n")
24
+
25
+ if file_violations:
26
+
27
+ lines.append("| File | Lines |")
28
+ lines.append("|------|------:|")
29
+
30
+ for violation in file_violations:
31
+
32
+ lines.append(
33
+ f"| {violation.file_path} | {violation.line_count} |"
34
+ )
35
+
36
+ else:
37
+
38
+ lines.append("No oversized files found.")
39
+
40
+ lines.append("")
41
+
42
+ # --------------------------------------------------
43
+
44
+ lines.append("## Oversized Functions\n")
45
+
46
+ if function_violations:
47
+
48
+ lines.append("| Function | Lines |")
49
+ lines.append("|----------|------:|")
50
+
51
+ for violation in function_violations:
52
+
53
+ lines.append(
54
+ f"| {violation.function_name} | {violation.line_count} |"
55
+ )
56
+
57
+ else:
58
+
59
+ lines.append("No oversized functions found.")
60
+
61
+ lines.append("")
62
+
63
+ # --------------------------------------------------
64
+
65
+ lines.append("## Architecture Violations\n")
66
+
67
+ if architecture_violations:
68
+
69
+ lines.append("| File | Rule |")
70
+ lines.append("|------|------|")
71
+
72
+ for violation in architecture_violations:
73
+
74
+ lines.append(
75
+ f"| {violation.source_file} | "
76
+ f"{violation.source_layer} → "
77
+ f"{violation.target_layer} |"
78
+ )
79
+
80
+ else:
81
+
82
+ lines.append("No architecture violations found.")
83
+
84
+ lines.append("")
85
+
86
+ # --------------------------------------------------
87
+
88
+ lines.append("## Circular Dependencies\n")
89
+
90
+ if circular_violations:
91
+
92
+ for violation in circular_violations:
93
+
94
+ cycle = " → ".join(
95
+ violation.cycle
96
+ )
97
+
98
+ lines.append(f"- {cycle}")
99
+
100
+ else:
101
+
102
+ lines.append("No circular dependencies found.")
103
+
104
+ lines.append("")
105
+
106
+ # --------------------------------------------------
107
+
108
+ lines.append("## Source Code Analysis\n")
109
+
110
+ lines.append("| File | Classes | Functions | Imports |")
111
+ lines.append("|------|---------:|----------:|--------:|")
112
+
113
+ for item in source_analysis:
114
+
115
+ lines.append(
116
+ f"| {item['file']} | "
117
+ f"{len(item['classes'])} | "
118
+ f"{len(item['functions'])} | "
119
+ f"{len(item['imports'])} |"
120
+ )
121
+
122
+ with open(
123
+ "report.md",
124
+ "w",
125
+ encoding="utf-8"
126
+ ) as file:
127
+
128
+ file.write(
129
+ "\n".join(lines)
130
+ )
@@ -0,0 +1,15 @@
1
+ def get_severity(
2
+ value,
3
+ warning_threshold,
4
+ critical_threshold
5
+ ):
6
+
7
+ if value >= critical_threshold:
8
+
9
+ return "🔴 CRITICAL"
10
+
11
+ elif value >= warning_threshold:
12
+
13
+ return "🟡 WARNING"
14
+
15
+ return "🟢 OK"
@@ -0,0 +1,183 @@
1
+ import os
2
+
3
+ from rich.console import Console
4
+ from rich.table import Table
5
+
6
+
7
+ class StatisticsReporter:
8
+
9
+ def __init__(self):
10
+ self.console = Console()
11
+
12
+ def show_statistics(
13
+ self,
14
+ source_analysis,
15
+ file_violations,
16
+ function_violations,
17
+ architecture_violations,
18
+ circular_violations,
19
+ db_access_violations,
20
+ score
21
+ ):
22
+
23
+ total_files = len(source_analysis)
24
+
25
+ total_classes = sum(
26
+ len(item["classes"])
27
+ for item in source_analysis
28
+ )
29
+
30
+ total_functions = sum(
31
+ len(item["functions"])
32
+ for item in source_analysis
33
+ )
34
+
35
+ total_imports = sum(
36
+ len(item["imports"])
37
+ for item in source_analysis
38
+ )
39
+
40
+ py_files = 0
41
+ ts_files = 0
42
+ js_files = 0
43
+
44
+ total_lines = 0
45
+ largest_file = "-"
46
+ largest_line_count = 0
47
+
48
+ for item in source_analysis:
49
+
50
+ file_name = item["file"]
51
+
52
+ if file_name.endswith(".py"):
53
+ py_files += 1
54
+
55
+ elif file_name.endswith(".ts"):
56
+ ts_files += 1
57
+
58
+ elif file_name.endswith(".js"):
59
+ js_files += 1
60
+
61
+ try:
62
+
63
+ with open(
64
+ file_name,
65
+ "r",
66
+ encoding="utf-8"
67
+ ) as file:
68
+
69
+ line_count = len(
70
+ file.readlines()
71
+ )
72
+
73
+ total_lines += line_count
74
+
75
+ if line_count > largest_line_count:
76
+
77
+ largest_line_count = line_count
78
+ largest_file = file_name
79
+
80
+ except Exception:
81
+ continue
82
+
83
+ average_lines = (
84
+ total_lines // total_files
85
+ if total_files > 0
86
+ else 0
87
+ )
88
+
89
+ table = Table(
90
+ title="Project Statistics"
91
+ )
92
+
93
+ table.add_column(
94
+ "Metric",
95
+ style="cyan"
96
+ )
97
+
98
+ table.add_column(
99
+ "Value",
100
+ style="green"
101
+ )
102
+
103
+ table.add_row(
104
+ "Files Scanned",
105
+ str(total_files)
106
+ )
107
+
108
+ table.add_row(
109
+ "Classes Found",
110
+ str(total_classes)
111
+ )
112
+
113
+ table.add_row(
114
+ "Functions Found",
115
+ str(total_functions)
116
+ )
117
+
118
+ table.add_row(
119
+ "Imports Found",
120
+ str(total_imports)
121
+ )
122
+
123
+ table.add_row(
124
+ "Python Files",
125
+ str(py_files)
126
+ )
127
+
128
+ table.add_row(
129
+ "TypeScript Files",
130
+ str(ts_files)
131
+ )
132
+
133
+ table.add_row(
134
+ "JavaScript Files",
135
+ str(js_files)
136
+ )
137
+
138
+ table.add_row(
139
+ "Total Lines of Code",
140
+ str(total_lines)
141
+ )
142
+
143
+ table.add_row(
144
+ "Average File Size",
145
+ f"{average_lines} lines"
146
+ )
147
+
148
+ table.add_row(
149
+ "Largest File",
150
+ f"{largest_file} ({largest_line_count} lines)"
151
+ )
152
+
153
+ table.add_row(
154
+ "Oversized Files",
155
+ str(len(file_violations))
156
+ )
157
+
158
+ table.add_row(
159
+ "Oversized Functions",
160
+ str(len(function_violations))
161
+ )
162
+
163
+ table.add_row(
164
+ "Architecture Violations",
165
+ str(len(architecture_violations))
166
+ )
167
+
168
+ table.add_row(
169
+ "Circular Dependencies",
170
+ str(len(circular_violations))
171
+ )
172
+
173
+ table.add_row(
174
+ "Direct DB Access Issues",
175
+ str(len(db_access_violations))
176
+ )
177
+
178
+ table.add_row(
179
+ "Architecture Score",
180
+ f"{score}/100"
181
+ )
182
+
183
+ self.console.print(table)
File without changes
@@ -0,0 +1,5 @@
1
+ ALLOWED_DEPENDENCIES = {
2
+ "controllers": ["services"],
3
+ "services": ["repositories"],
4
+ "repositories": []
5
+ }