code-auditor-mcp 3.4.18 → 3.5.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 (171) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +68 -0
  3. package/README.md +5 -5
  4. package/dist/analyzers/applicability.d.ts +13 -0
  5. package/dist/analyzers/applicability.d.ts.map +1 -1
  6. package/dist/analyzers/applicability.js +37 -0
  7. package/dist/analyzers/applicability.js.map +1 -1
  8. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
  9. package/dist/analyzers/cross-language/APIContractAnalyzer.js +23 -2
  10. package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
  11. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +52 -9
  12. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  13. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +228 -55
  14. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  15. package/dist/analyzers/cross-language/SchemaValidator.d.ts +19 -12
  16. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
  17. package/dist/analyzers/cross-language/SchemaValidator.js +78 -111
  18. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
  19. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +0 -6
  20. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
  21. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +85 -73
  22. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  23. package/dist/analyzers/documentationAnalyzer.js +5 -5
  24. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  25. package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
  26. package/dist/analyzers/invariantsAnalyzer.js +1 -0
  27. package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
  28. package/dist/analyzers/provenance.d.ts +7 -9
  29. package/dist/analyzers/provenance.d.ts.map +1 -1
  30. package/dist/analyzers/provenance.js +88 -124
  31. package/dist/analyzers/provenance.js.map +1 -1
  32. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  33. package/dist/analyzers/reactAnalyzer.js +120 -21
  34. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  35. package/dist/analyzers/ruleRegistry.d.ts +21 -0
  36. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  37. package/dist/analyzers/ruleRegistry.js +61 -12
  38. package/dist/analyzers/ruleRegistry.js.map +1 -1
  39. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  40. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +60 -24
  41. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  42. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  43. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +5 -2
  44. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  45. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  46. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +82 -71
  47. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  48. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +2 -1
  49. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  50. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +23 -12
  51. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  52. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +11 -1
  53. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  54. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +60 -22
  55. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  56. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -3
  57. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  58. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +258 -87
  59. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  60. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
  61. package/dist/analyzers/universal/schema/codeAnalysis.js +7 -1
  62. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  63. package/dist/analyzers/universal/schema/jsonSchema.js +7 -11
  64. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
  65. package/dist/auditRouter.d.ts +41 -0
  66. package/dist/auditRouter.d.ts.map +1 -0
  67. package/dist/auditRouter.js +185 -0
  68. package/dist/auditRouter.js.map +1 -0
  69. package/dist/auditRunner.d.ts.map +1 -1
  70. package/dist/auditRunner.js +93 -57
  71. package/dist/auditRunner.js.map +1 -1
  72. package/dist/cli.js +239 -18
  73. package/dist/cli.js.map +1 -1
  74. package/dist/codeIndexDB.d.ts.map +1 -1
  75. package/dist/codeIndexDB.js +35 -1
  76. package/dist/codeIndexDB.js.map +1 -1
  77. package/dist/componentScanner.d.ts.map +1 -1
  78. package/dist/componentScanner.js +2 -1
  79. package/dist/componentScanner.js.map +1 -1
  80. package/dist/config/configLoader.d.ts +9 -0
  81. package/dist/config/configLoader.d.ts.map +1 -1
  82. package/dist/config/configLoader.js +30 -2
  83. package/dist/config/configLoader.js.map +1 -1
  84. package/dist/config/defaults.d.ts.map +1 -1
  85. package/dist/config/defaults.js +9 -2
  86. package/dist/config/defaults.js.map +1 -1
  87. package/dist/functionScanner.d.ts.map +1 -1
  88. package/dist/functionScanner.js +1 -17
  89. package/dist/functionScanner.js.map +1 -1
  90. package/dist/invariants/ruleEngine.d.ts +8 -0
  91. package/dist/invariants/ruleEngine.d.ts.map +1 -1
  92. package/dist/invariants/ruleEngine.js +35 -16
  93. package/dist/invariants/ruleEngine.js.map +1 -1
  94. package/dist/languages/LanguageOrchestrator.d.ts +9 -10
  95. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  96. package/dist/languages/LanguageOrchestrator.js +135 -101
  97. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  98. package/dist/languages/RuntimeManager.d.ts +28 -1
  99. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  100. package/dist/languages/RuntimeManager.js +158 -47
  101. package/dist/languages/RuntimeManager.js.map +1 -1
  102. package/dist/languages/go/GoAdapter.d.ts +2 -0
  103. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  104. package/dist/languages/go/GoAdapter.js +15 -22
  105. package/dist/languages/go/GoAdapter.js.map +1 -1
  106. package/dist/languages/go/analyzer +0 -0
  107. package/dist/languages/go/analyzer-src/analyzer.go +510 -0
  108. package/dist/languages/go/analyzer-src/go.mod +3 -0
  109. package/dist/languages/go/analyzer-src/indexer.go +268 -0
  110. package/dist/languages/go/analyzer-src/parser.go +461 -0
  111. package/dist/languages/go/analyzer-src/solid.go +395 -0
  112. package/dist/languages/go/analyzer-src/testconventions.go +25 -0
  113. package/dist/languages/go/analyzer-src/types.go +148 -0
  114. package/dist/languages/go/go.mod +7 -0
  115. package/dist/languages/go/main.go +203 -0
  116. package/dist/languages/testConventions.d.ts +35 -0
  117. package/dist/languages/testConventions.d.ts.map +1 -0
  118. package/dist/languages/testConventions.js +51 -0
  119. package/dist/languages/testConventions.js.map +1 -0
  120. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +3 -0
  121. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  122. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +25 -18
  123. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  124. package/dist/mcp-tools/whitelistTools.d.ts +1 -1
  125. package/dist/mcp-tools-shared.d.ts +0 -3
  126. package/dist/mcp-tools-shared.d.ts.map +1 -1
  127. package/dist/mcp-tools-shared.js +8 -117
  128. package/dist/mcp-tools-shared.js.map +1 -1
  129. package/dist/mcp.js +3 -1
  130. package/dist/mcp.js.map +1 -1
  131. package/dist/mcpAuditJobs.d.ts.map +1 -1
  132. package/dist/mcpAuditJobs.js +13 -0
  133. package/dist/mcpAuditJobs.js.map +1 -1
  134. package/dist/nextFile.d.ts +21 -0
  135. package/dist/nextFile.d.ts.map +1 -0
  136. package/dist/nextFile.js +51 -0
  137. package/dist/nextFile.js.map +1 -0
  138. package/dist/nextFileIncremental.d.ts +141 -0
  139. package/dist/nextFileIncremental.d.ts.map +1 -0
  140. package/dist/nextFileIncremental.js +314 -0
  141. package/dist/nextFileIncremental.js.map +1 -0
  142. package/dist/pipeline.d.ts.map +1 -1
  143. package/dist/pipeline.js +22 -0
  144. package/dist/pipeline.js.map +1 -1
  145. package/dist/pipelineAdapters.d.ts +17 -0
  146. package/dist/pipelineAdapters.d.ts.map +1 -1
  147. package/dist/pipelineAdapters.js +791 -40
  148. package/dist/pipelineAdapters.js.map +1 -1
  149. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  150. package/dist/reporting/jsonReportGenerator.js +11 -30
  151. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  152. package/dist/styles/styleIndexer.d.ts +7 -0
  153. package/dist/styles/styleIndexer.d.ts.map +1 -1
  154. package/dist/styles/styleIndexer.js +44 -61
  155. package/dist/styles/styleIndexer.js.map +1 -1
  156. package/dist/types/crossLanguage.d.ts +1 -0
  157. package/dist/types/crossLanguage.d.ts.map +1 -1
  158. package/dist/types.d.ts +27 -4
  159. package/dist/types.d.ts.map +1 -1
  160. package/dist/types.js.map +1 -1
  161. package/dist/utils/fileDiscovery.d.ts +9 -0
  162. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  163. package/dist/utils/fileDiscovery.js +18 -0
  164. package/dist/utils/fileDiscovery.js.map +1 -1
  165. package/package.json +6 -4
  166. package/plugin/.claude-plugin/plugin.json +1 -1
  167. package/plugin/README.md +6 -6
  168. package/plugin/hooks/hooks.json +4 -0
  169. package/plugin/scripts/hook-self-audit.sh +107 -0
  170. package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +55 -9
  171. package/plugin/skills/code-auditor/SKILL.md +20 -21
@@ -0,0 +1,395 @@
1
+ package analyzer
2
+
3
+ import (
4
+ "go/ast"
5
+ "strings"
6
+ )
7
+
8
+ // SOLIDAnalyzer analyzes Go code for SOLID principle violations
9
+ type SOLIDAnalyzer struct {
10
+ parser *Parser
11
+ functions []Function
12
+ structs []Struct
13
+ interfaces []Interface
14
+ }
15
+
16
+ // NewSOLIDAnalyzer creates a new SOLID analyzer
17
+ func NewSOLIDAnalyzer(parser *Parser) *SOLIDAnalyzer {
18
+ return &SOLIDAnalyzer{
19
+ parser: parser,
20
+ functions: parser.ExtractFunctions(),
21
+ structs: parser.ExtractStructs(),
22
+ interfaces: parser.ExtractInterfaces(),
23
+ }
24
+ }
25
+
26
+ // Analyze performs SOLID principle analysis
27
+ func (s *SOLIDAnalyzer) Analyze() []Violation {
28
+ var violations []Violation
29
+
30
+ // Analyze Single Responsibility Principle
31
+ violations = append(violations, s.analyzeSRP()...)
32
+
33
+ // Analyze Open/Closed Principle
34
+ violations = append(violations, s.analyzeOCP()...)
35
+
36
+ // Analyze Liskov Substitution Principle
37
+ violations = append(violations, s.analyzeLSP()...)
38
+
39
+ // Analyze Interface Segregation Principle
40
+ violations = append(violations, s.analyzeISP()...)
41
+
42
+ // Analyze Dependency Inversion Principle
43
+ violations = append(violations, s.analyzeDIP()...)
44
+
45
+ return violations
46
+ }
47
+
48
+ // analyzeSRP analyzes Single Responsibility Principle violations
49
+ func (s *SOLIDAnalyzer) analyzeSRP() []Violation {
50
+ var violations []Violation
51
+
52
+ // Check functions for too many responsibilities
53
+ for _, function := range s.functions {
54
+ responsibilities := s.countFunctionResponsibilities(function)
55
+ if responsibilities > 3 {
56
+ violations = append(violations, Violation{
57
+ File: function.File,
58
+ Line: function.StartLine,
59
+ Severity: "warning",
60
+ Message: "Function has many parameters, returns, or high complexity",
61
+ Details: map[string]interface{}{
62
+ "function": function.Name,
63
+ "responsibilities": responsibilities,
64
+ "principle": "SRP",
65
+ },
66
+ Suggestion: "Consider breaking this function into smaller, more focused functions",
67
+ Analyzer: "solid",
68
+ Category: "single-responsibility",
69
+ })
70
+ }
71
+ }
72
+
73
+ // Check structs for too many responsibilities
74
+ for _, structInfo := range s.structs {
75
+ responsibilities := s.countStructResponsibilities(structInfo)
76
+ if responsibilities > 5 {
77
+ violations = append(violations, Violation{
78
+ File: structInfo.File,
79
+ Line: structInfo.StartLine,
80
+ Severity: "warning",
81
+ Message: "Struct has many fields",
82
+ Details: map[string]interface{}{
83
+ "struct": structInfo.Name,
84
+ "responsibilities": responsibilities,
85
+ "principle": "SRP",
86
+ "fieldCount": len(structInfo.Fields),
87
+ },
88
+ Suggestion: "Consider splitting this struct into smaller, more cohesive structs",
89
+ Analyzer: "solid",
90
+ Category: "single-responsibility",
91
+ })
92
+ }
93
+ }
94
+
95
+ return violations
96
+ }
97
+
98
+ // analyzeOCP analyzes Open/Closed Principle violations
99
+ func (s *SOLIDAnalyzer) analyzeOCP() []Violation {
100
+ var violations []Violation
101
+
102
+ // Check for large switch/case statements that could benefit from polymorphism
103
+ for filePath, file := range s.parser.files {
104
+ ast.Inspect(file, func(n ast.Node) bool {
105
+ switch node := n.(type) {
106
+ case *ast.SwitchStmt:
107
+ caseCount := s.countSwitchCases(node)
108
+ if caseCount > 5 {
109
+ pos := s.parser.fileSet.Position(node.Pos())
110
+ violations = append(violations, Violation{
111
+ File: filePath,
112
+ Line: pos.Line,
113
+ Severity: "suggestion",
114
+ Message: "Large switch statement detected - consider using polymorphism",
115
+ Details: map[string]interface{}{
116
+ "caseCount": caseCount,
117
+ "principle": "OCP",
118
+ },
119
+ Suggestion: "Consider using interfaces and polymorphism instead of large switch statements",
120
+ Analyzer: "solid",
121
+ Category: "open-closed",
122
+ })
123
+ }
124
+ case *ast.TypeSwitchStmt:
125
+ caseCount := s.countTypeSwitchCases(node)
126
+ if caseCount > 5 {
127
+ pos := s.parser.fileSet.Position(node.Pos())
128
+ violations = append(violations, Violation{
129
+ File: filePath,
130
+ Line: pos.Line,
131
+ Severity: "suggestion",
132
+ Message: "Large type switch detected - consider using interfaces",
133
+ Details: map[string]interface{}{
134
+ "caseCount": caseCount,
135
+ "principle": "OCP",
136
+ },
137
+ Suggestion: "Consider using interfaces with method dispatch instead of type switches",
138
+ Analyzer: "solid",
139
+ Category: "open-closed",
140
+ })
141
+ }
142
+ }
143
+ return true
144
+ })
145
+ }
146
+
147
+ return violations
148
+ }
149
+
150
+ // analyzeLSP analyzes Liskov Substitution Principle violations.
151
+ //
152
+ // A method that calls panic() breaks substitutability: a caller holding the
153
+ // interface (or embedding) has no way to recover from a panic the way it can
154
+ // from an error return. The honest, directly-observable signal is "the method
155
+ // body contains a panic() call" — we walk the AST for exactly that. We do not
156
+ // (yet) resolve whether the method overrides a parent, so the message claims
157
+ // only the panic, never the override.
158
+ func (s *SOLIDAnalyzer) analyzeLSP() []Violation {
159
+ var violations []Violation
160
+
161
+ for filePath, file := range s.parser.files {
162
+ ast.Inspect(file, func(n ast.Node) bool {
163
+ funcDecl, ok := n.(*ast.FuncDecl)
164
+ if !ok {
165
+ return true
166
+ }
167
+ // LSP governs methods only — a free function has no supertype to
168
+ // violate. Test functions are test entry points, not production API.
169
+ if funcDecl.Recv == nil || funcDecl.Body == nil || isTestFunction(funcDecl.Name.Name) {
170
+ return true
171
+ }
172
+ if !methodCallsPanic(funcDecl) {
173
+ return true
174
+ }
175
+ pos := s.parser.fileSet.Position(funcDecl.Pos())
176
+ violations = append(violations, Violation{
177
+ File: filePath,
178
+ Line: pos.Line,
179
+ Severity: "warning",
180
+ Message: "Method calls panic()",
181
+ Details: map[string]interface{}{
182
+ "function": funcDecl.Name.Name,
183
+ "principle": "LSP",
184
+ },
185
+ Suggestion: "Return an error instead of panicking so the method stays substitutable",
186
+ Analyzer: "solid",
187
+ Category: "liskov-substitution",
188
+ })
189
+ return true
190
+ })
191
+ }
192
+
193
+ return violations
194
+ }
195
+
196
+ // analyzeISP analyzes Interface Segregation Principle violations
197
+ func (s *SOLIDAnalyzer) analyzeISP() []Violation {
198
+ var violations []Violation
199
+
200
+ // Check for fat interfaces
201
+ for _, interfaceInfo := range s.interfaces {
202
+ if len(interfaceInfo.Methods) > 5 {
203
+ violations = append(violations, Violation{
204
+ File: interfaceInfo.File,
205
+ Line: interfaceInfo.StartLine,
206
+ Severity: "warning",
207
+ Message: "Interface has many methods",
208
+ Details: map[string]interface{}{
209
+ "interface": interfaceInfo.Name,
210
+ "methodCount": len(interfaceInfo.Methods),
211
+ "principle": "ISP",
212
+ },
213
+ Suggestion: "Consider splitting this interface into smaller, more focused interfaces",
214
+ Analyzer: "solid",
215
+ Category: "interface-segregation",
216
+ })
217
+ }
218
+ }
219
+
220
+ return violations
221
+ }
222
+
223
+ // analyzeDIP analyzes Dependency Inversion Principle violations
224
+ func (s *SOLIDAnalyzer) analyzeDIP() []Violation {
225
+ var violations []Violation
226
+
227
+ // Check for direct dependencies on concrete types instead of interfaces
228
+ for _, structInfo := range s.structs {
229
+ concreteDeps := s.countConcreteDependencies(structInfo)
230
+ if concreteDeps > 3 {
231
+ violations = append(violations, Violation{
232
+ File: structInfo.File,
233
+ Line: structInfo.StartLine,
234
+ Severity: "suggestion",
235
+ Message: "Struct has many concrete-typed fields",
236
+ Details: map[string]interface{}{
237
+ "struct": structInfo.Name,
238
+ "concreteDependencies": concreteDeps,
239
+ "principle": "DIP",
240
+ },
241
+ Suggestion: "Consider depending on interfaces instead of concrete types",
242
+ Analyzer: "solid",
243
+ Category: "dependency-inversion",
244
+ })
245
+ }
246
+ }
247
+
248
+ return violations
249
+ }
250
+
251
+ // Helper methods for analysis
252
+
253
+ func (s *SOLIDAnalyzer) countFunctionResponsibilities(function Function) int {
254
+ responsibilities := 1
255
+
256
+ // Count different types of operations
257
+ if function.Complexity > 10 {
258
+ responsibilities++
259
+ }
260
+
261
+ // Check for multiple return types (excluding error)
262
+ returns := strings.Split(function.ReturnType, ",")
263
+ if len(returns) > 2 {
264
+ responsibilities++
265
+ }
266
+
267
+ // Check parameter count
268
+ if len(function.Parameters) > 5 {
269
+ responsibilities++
270
+ }
271
+
272
+ return responsibilities
273
+ }
274
+
275
+ func (s *SOLIDAnalyzer) countStructResponsibilities(structInfo Struct) int {
276
+ responsibilities := 1
277
+
278
+ // Base on field count
279
+ fieldCount := len(structInfo.Fields)
280
+ if fieldCount > 10 {
281
+ responsibilities += 2
282
+ } else if fieldCount > 5 {
283
+ responsibilities++
284
+ }
285
+
286
+ // Check for mixed data types indicating different responsibilities
287
+ hasStrings := false
288
+ hasNumbers := false
289
+ hasCollections := false
290
+
291
+ for _, field := range structInfo.Fields {
292
+ switch {
293
+ case strings.Contains(field.Type, "string"):
294
+ hasStrings = true
295
+ case strings.Contains(field.Type, "int") || strings.Contains(field.Type, "float"):
296
+ hasNumbers = true
297
+ case strings.Contains(field.Type, "[]") || strings.Contains(field.Type, "map"):
298
+ hasCollections = true
299
+ }
300
+ }
301
+
302
+ mixedTypes := 0
303
+ if hasStrings {
304
+ mixedTypes++
305
+ }
306
+ if hasNumbers {
307
+ mixedTypes++
308
+ }
309
+ if hasCollections {
310
+ mixedTypes++
311
+ }
312
+
313
+ if mixedTypes > 2 {
314
+ responsibilities++
315
+ }
316
+
317
+ return responsibilities
318
+ }
319
+
320
+ func (s *SOLIDAnalyzer) countSwitchCases(switchStmt *ast.SwitchStmt) int {
321
+ caseCount := 0
322
+ if switchStmt.Body != nil {
323
+ for _, stmt := range switchStmt.Body.List {
324
+ if _, ok := stmt.(*ast.CaseClause); ok {
325
+ caseCount++
326
+ }
327
+ }
328
+ }
329
+ return caseCount
330
+ }
331
+
332
+ func (s *SOLIDAnalyzer) countTypeSwitchCases(typeSwitchStmt *ast.TypeSwitchStmt) int {
333
+ caseCount := 0
334
+ if typeSwitchStmt.Body != nil {
335
+ for _, stmt := range typeSwitchStmt.Body.List {
336
+ if _, ok := stmt.(*ast.CaseClause); ok {
337
+ caseCount++
338
+ }
339
+ }
340
+ }
341
+ return caseCount
342
+ }
343
+
344
+ func (s *SOLIDAnalyzer) countConcreteDependencies(structInfo Struct) int {
345
+ concreteDeps := 0
346
+
347
+ for _, field := range structInfo.Fields {
348
+ // Check if field type looks like a concrete type (not interface)
349
+ if !strings.Contains(field.Type, "interface") &&
350
+ !strings.HasPrefix(field.Type, "*") && // Pointers might be interfaces
351
+ !s.isBuiltinType(field.Type) {
352
+ concreteDeps++
353
+ }
354
+ }
355
+
356
+ return concreteDeps
357
+ }
358
+
359
+ func (s *SOLIDAnalyzer) isBuiltinType(typeName string) bool {
360
+ builtinTypes := []string{
361
+ "bool", "string", "int", "int8", "int16", "int32", "int64",
362
+ "uint", "uint8", "uint16", "uint32", "uint64", "uintptr",
363
+ "byte", "rune", "float32", "float64", "complex64", "complex128",
364
+ }
365
+
366
+ for _, builtin := range builtinTypes {
367
+ if typeName == builtin {
368
+ return true
369
+ }
370
+ }
371
+
372
+ return false
373
+ }
374
+
375
+ // methodCallsPanic reports whether a function body contains a direct panic()
376
+ // call. It matches the exact call shape — a call expression whose function is
377
+ // the identifier `panic` — so a helper that merely has "panic" in its name or
378
+ // a doc comment does not trip it (the near-miss the old name-substring check
379
+ // false-positived on).
380
+ func methodCallsPanic(funcDecl *ast.FuncDecl) bool {
381
+ callsPanic := false
382
+ ast.Inspect(funcDecl.Body, func(n ast.Node) bool {
383
+ call, ok := n.(*ast.CallExpr)
384
+ if !ok {
385
+ return true
386
+ }
387
+ ident, ok := call.Fun.(*ast.Ident)
388
+ if ok && ident.Name == "panic" {
389
+ callsPanic = true
390
+ return false
391
+ }
392
+ return true
393
+ })
394
+ return callsPanic
395
+ }
@@ -0,0 +1,25 @@
1
+ package analyzer
2
+
3
+ import "strings"
4
+
5
+ // Go test conventions — mirrors languages/testConventions.ts.
6
+ //
7
+ // `go test` compiles only `*_test.go` files; within them the `testing` package
8
+ // recognizes Test/Benchmark/Example/Fuzz-prefixed functions as entry points.
9
+ // Test code is not production API: it is exempt from analysis and indexing the
10
+ // same way the TypeScript pipeline exempts `.test.`/`.spec.` files. One
11
+ // per-language convention, not a hardcoded TS/JS list.
12
+
13
+ // isTestFile reports whether filePath is a Go test file (`*_test.go`).
14
+ func isTestFile(filePath string) bool {
15
+ return strings.HasSuffix(filePath, "_test.go")
16
+ }
17
+
18
+ // isTestFunction reports whether name is a Go test function
19
+ // (Test*/Benchmark*/Example*/Fuzz*).
20
+ func isTestFunction(name string) bool {
21
+ return strings.HasPrefix(name, "Test") ||
22
+ strings.HasPrefix(name, "Benchmark") ||
23
+ strings.HasPrefix(name, "Example") ||
24
+ strings.HasPrefix(name, "Fuzz")
25
+ }
@@ -0,0 +1,148 @@
1
+ package analyzer
2
+
3
+ // AnalysisOptions represents options for the analysis
4
+ type AnalysisOptions struct {
5
+ Analyzers []string `json:"analyzers"`
6
+ MinSeverity string `json:"minSeverity"`
7
+ Timeout int `json:"timeout"`
8
+ Language string `json:"language"`
9
+ Verbose bool `json:"verbose"`
10
+ }
11
+
12
+ // AnalysisResult represents the result of code analysis
13
+ type AnalysisResult struct {
14
+ Violations []Violation `json:"violations"`
15
+ IndexEntries []IndexEntry `json:"indexEntries"`
16
+ Metrics Metrics `json:"metrics"`
17
+ Errors []Error `json:"errors"`
18
+ }
19
+
20
+ // Violation represents a code quality violation
21
+ type Violation struct {
22
+ File string `json:"file"`
23
+ Line int `json:"line"`
24
+ Column int `json:"column"`
25
+ Severity string `json:"severity"`
26
+ Message string `json:"message"`
27
+ Details map[string]interface{} `json:"details,omitempty"`
28
+ Snippet string `json:"snippet,omitempty"`
29
+ Suggestion string `json:"suggestion,omitempty"`
30
+ Analyzer string `json:"analyzer"`
31
+ Category string `json:"category"`
32
+ }
33
+
34
+ // IndexEntry represents an entity in the code index
35
+ type IndexEntry struct {
36
+ ID string `json:"id"`
37
+ Name string `json:"name"`
38
+ Type string `json:"type"`
39
+ Language string `json:"language"`
40
+ File string `json:"file"`
41
+ Signature string `json:"signature"`
42
+ Parameters []Parameter `json:"parameters"`
43
+ Purpose string `json:"purpose"`
44
+ Context string `json:"context"`
45
+ StartLine int `json:"startLine"`
46
+ EndLine int `json:"endLine"`
47
+ Metadata map[string]interface{} `json:"metadata,omitempty"`
48
+ }
49
+
50
+ // Parameter represents a function parameter
51
+ type Parameter struct {
52
+ Name string `json:"name"`
53
+ Type string `json:"type"`
54
+ Optional bool `json:"optional"`
55
+ Language string `json:"language"`
56
+ }
57
+
58
+ // Metrics represents analysis metrics
59
+ type Metrics struct {
60
+ FilesAnalyzed int64 `json:"filesAnalyzed"`
61
+ ExecutionTime int64 `json:"executionTime"`
62
+ }
63
+
64
+ // Error represents an analysis error
65
+ type Error struct {
66
+ Message string `json:"message"`
67
+ Type string `json:"type"`
68
+ File string `json:"file,omitempty"`
69
+ Line int `json:"line,omitempty"`
70
+ }
71
+
72
+ // EntityInfo represents information about a Go entity
73
+ type EntityInfo struct {
74
+ Name string
75
+ Type string
76
+ File string
77
+ StartLine int
78
+ EndLine int
79
+ Signature string
80
+ Parameters []Parameter
81
+ ReturnType string
82
+ Purpose string
83
+ Context string
84
+ Receiver string // For methods
85
+ Package string
86
+ }
87
+
88
+ // Function represents a Go function
89
+ type Function struct {
90
+ EntityInfo
91
+ IsMethod bool
92
+ IsExported bool
93
+ Complexity int
94
+ Dependencies []string
95
+ }
96
+
97
+ // Struct represents a Go struct
98
+ type Struct struct {
99
+ EntityInfo
100
+ Fields []Field
101
+ Methods []string
102
+ IsExported bool
103
+ }
104
+
105
+ // Interface represents a Go interface
106
+ type Interface struct {
107
+ EntityInfo
108
+ Methods []Method
109
+ IsExported bool
110
+ }
111
+
112
+ // Field represents a struct field
113
+ type Field struct {
114
+ Name string
115
+ Type string
116
+ Tag string
117
+ IsExported bool
118
+ }
119
+
120
+ // Method represents an interface method
121
+ type Method struct {
122
+ Name string
123
+ Signature string
124
+ Parameters []Parameter
125
+ ReturnType string
126
+ }
127
+
128
+ // SOLIDViolation represents SOLID principle violations specific to Go
129
+ type SOLIDViolation struct {
130
+ Principle string // SRP, OCP, LSP, ISP, DIP
131
+ Entity string
132
+ Description string
133
+ Suggestion string
134
+ Severity string
135
+ Examples []string
136
+ }
137
+
138
+ // Package represents a Go package
139
+ type Package struct {
140
+ Name string
141
+ Path string
142
+ Files []string
143
+ Imports []string
144
+ Exports []string
145
+ Functions []Function
146
+ Structs []Struct
147
+ Interfaces []Interface
148
+ }
@@ -0,0 +1,7 @@
1
+ module code-auditor-go
2
+
3
+ go 1.19
4
+
5
+ replace code-auditor-go/analyzer => ./analyzer-src
6
+
7
+ require code-auditor-go/analyzer v0.0.0-00010101000000-000000000000