code-auditor-mcp 3.4.18 → 3.6.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 (193) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +99 -0
  3. package/README.md +5 -5
  4. package/dist/analyzers/applicability.d.ts +19 -5
  5. package/dist/analyzers/applicability.d.ts.map +1 -1
  6. package/dist/analyzers/applicability.js +36 -24
  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 +35 -12
  36. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  37. package/dist/analyzers/ruleRegistry.js +66 -108
  38. package/dist/analyzers/ruleRegistry.js.map +1 -1
  39. package/dist/analyzers/ruleTiming.d.ts +2 -2
  40. package/dist/analyzers/ruleTiming.js +2 -2
  41. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  42. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +60 -24
  43. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  44. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  45. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +5 -2
  46. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  47. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  48. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +82 -71
  49. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  50. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +2 -1
  51. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  52. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +23 -12
  53. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  54. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +11 -1
  55. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  56. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +60 -22
  57. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  58. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  59. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +5 -2
  60. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  61. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -3
  62. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  63. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +258 -87
  64. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  65. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
  66. package/dist/analyzers/universal/schema/codeAnalysis.js +7 -1
  67. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  68. package/dist/analyzers/universal/schema/discovery.d.ts +29 -1
  69. package/dist/analyzers/universal/schema/discovery.d.ts.map +1 -1
  70. package/dist/analyzers/universal/schema/discovery.js +76 -21
  71. package/dist/analyzers/universal/schema/discovery.js.map +1 -1
  72. package/dist/analyzers/universal/schema/jsonSchema.js +7 -11
  73. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
  74. package/dist/auditRouter.d.ts +41 -0
  75. package/dist/auditRouter.d.ts.map +1 -0
  76. package/dist/auditRouter.js +185 -0
  77. package/dist/auditRouter.js.map +1 -0
  78. package/dist/auditRunner.d.ts.map +1 -1
  79. package/dist/auditRunner.js +93 -84
  80. package/dist/auditRunner.js.map +1 -1
  81. package/dist/cli.js +306 -95
  82. package/dist/cli.js.map +1 -1
  83. package/dist/codeIndexDB.d.ts.map +1 -1
  84. package/dist/codeIndexDB.js +41 -7
  85. package/dist/codeIndexDB.js.map +1 -1
  86. package/dist/componentScanner.d.ts.map +1 -1
  87. package/dist/componentScanner.js +2 -1
  88. package/dist/componentScanner.js.map +1 -1
  89. package/dist/config/configLoader.d.ts +9 -0
  90. package/dist/config/configLoader.d.ts.map +1 -1
  91. package/dist/config/configLoader.js +45 -2
  92. package/dist/config/configLoader.js.map +1 -1
  93. package/dist/config/defaults.d.ts +8 -1
  94. package/dist/config/defaults.d.ts.map +1 -1
  95. package/dist/config/defaults.js +19 -3
  96. package/dist/config/defaults.js.map +1 -1
  97. package/dist/dataPaths.js +18 -1
  98. package/dist/dataPaths.js.map +1 -1
  99. package/dist/enforcement/gate.d.ts +14 -19
  100. package/dist/enforcement/gate.d.ts.map +1 -1
  101. package/dist/enforcement/gate.js +27 -45
  102. package/dist/enforcement/gate.js.map +1 -1
  103. package/dist/functionScanner.d.ts.map +1 -1
  104. package/dist/functionScanner.js +1 -17
  105. package/dist/functionScanner.js.map +1 -1
  106. package/dist/invariants/ruleEngine.d.ts +8 -0
  107. package/dist/invariants/ruleEngine.d.ts.map +1 -1
  108. package/dist/invariants/ruleEngine.js +35 -16
  109. package/dist/invariants/ruleEngine.js.map +1 -1
  110. package/dist/languages/LanguageOrchestrator.d.ts +9 -10
  111. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  112. package/dist/languages/LanguageOrchestrator.js +135 -101
  113. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  114. package/dist/languages/RuntimeManager.d.ts +28 -1
  115. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  116. package/dist/languages/RuntimeManager.js +158 -47
  117. package/dist/languages/RuntimeManager.js.map +1 -1
  118. package/dist/languages/go/GoAdapter.d.ts +2 -0
  119. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  120. package/dist/languages/go/GoAdapter.js +15 -22
  121. package/dist/languages/go/GoAdapter.js.map +1 -1
  122. package/dist/languages/go/analyzer +0 -0
  123. package/dist/languages/go/analyzer-src/analyzer.go +510 -0
  124. package/dist/languages/go/analyzer-src/go.mod +3 -0
  125. package/dist/languages/go/analyzer-src/indexer.go +268 -0
  126. package/dist/languages/go/analyzer-src/parser.go +461 -0
  127. package/dist/languages/go/analyzer-src/solid.go +395 -0
  128. package/dist/languages/go/analyzer-src/testconventions.go +25 -0
  129. package/dist/languages/go/analyzer-src/types.go +148 -0
  130. package/dist/languages/go/go.mod +7 -0
  131. package/dist/languages/go/main.go +203 -0
  132. package/dist/languages/testConventions.d.ts +35 -0
  133. package/dist/languages/testConventions.d.ts.map +1 -0
  134. package/dist/languages/testConventions.js +51 -0
  135. package/dist/languages/testConventions.js.map +1 -0
  136. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +3 -0
  137. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  138. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +25 -18
  139. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  140. package/dist/mcp-tools/whitelistTools.d.ts +1 -1
  141. package/dist/mcp-tools-shared.d.ts +0 -3
  142. package/dist/mcp-tools-shared.d.ts.map +1 -1
  143. package/dist/mcp-tools-shared.js +8 -117
  144. package/dist/mcp-tools-shared.js.map +1 -1
  145. package/dist/mcp.js +3 -1
  146. package/dist/mcp.js.map +1 -1
  147. package/dist/mcpAuditJobs.d.ts.map +1 -1
  148. package/dist/mcpAuditJobs.js +13 -0
  149. package/dist/mcpAuditJobs.js.map +1 -1
  150. package/dist/nextFile.d.ts +21 -0
  151. package/dist/nextFile.d.ts.map +1 -0
  152. package/dist/nextFile.js +51 -0
  153. package/dist/nextFile.js.map +1 -0
  154. package/dist/nextFileIncremental.d.ts +141 -0
  155. package/dist/nextFileIncremental.d.ts.map +1 -0
  156. package/dist/nextFileIncremental.js +314 -0
  157. package/dist/nextFileIncremental.js.map +1 -0
  158. package/dist/pipeline.d.ts.map +1 -1
  159. package/dist/pipeline.js +43 -3
  160. package/dist/pipeline.js.map +1 -1
  161. package/dist/pipelineAdapters.d.ts +17 -0
  162. package/dist/pipelineAdapters.d.ts.map +1 -1
  163. package/dist/pipelineAdapters.js +791 -40
  164. package/dist/pipelineAdapters.js.map +1 -1
  165. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  166. package/dist/reporting/jsonReportGenerator.js +11 -30
  167. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  168. package/dist/styles/styleExtractor.js +2 -2
  169. package/dist/styles/styleExtractor.js.map +1 -1
  170. package/dist/styles/styleIndexer.d.ts +7 -0
  171. package/dist/styles/styleIndexer.d.ts.map +1 -1
  172. package/dist/styles/styleIndexer.js +51 -67
  173. package/dist/styles/styleIndexer.js.map +1 -1
  174. package/dist/styles/types.d.ts +3 -2
  175. package/dist/styles/types.d.ts.map +1 -1
  176. package/dist/types/crossLanguage.d.ts +1 -0
  177. package/dist/types/crossLanguage.d.ts.map +1 -1
  178. package/dist/types.d.ts +43 -34
  179. package/dist/types.d.ts.map +1 -1
  180. package/dist/types.js.map +1 -1
  181. package/dist/utils/fileDiscovery.d.ts +9 -0
  182. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  183. package/dist/utils/fileDiscovery.js +18 -0
  184. package/dist/utils/fileDiscovery.js.map +1 -1
  185. package/package.json +16 -6
  186. package/plugin/.claude-plugin/plugin.json +1 -1
  187. package/plugin/README.md +11 -9
  188. package/plugin/hooks/hooks.json +4 -0
  189. package/plugin/scripts/hook-audit.sh +20 -30
  190. package/plugin/scripts/hook-common.sh +63 -0
  191. package/plugin/scripts/hook-self-audit.sh +99 -0
  192. package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +55 -9
  193. package/plugin/skills/code-auditor/SKILL.md +22 -23
@@ -0,0 +1,461 @@
1
+ package analyzer
2
+
3
+ import (
4
+ "fmt"
5
+ "go/ast"
6
+ "go/parser"
7
+ "go/token"
8
+ "strings"
9
+ )
10
+
11
+ // Parser handles Go AST parsing and entity extraction
12
+ type Parser struct {
13
+ fileSet *token.FileSet
14
+ files map[string]*ast.File
15
+ options AnalysisOptions
16
+ }
17
+
18
+ // NewParser creates a new Go parser
19
+ func NewParser(options AnalysisOptions) *Parser {
20
+ return &Parser{
21
+ fileSet: token.NewFileSet(),
22
+ files: make(map[string]*ast.File),
23
+ options: options,
24
+ }
25
+ }
26
+
27
+ // ParseFiles parses the given Go files
28
+ func (p *Parser) ParseFiles(filePaths []string) error {
29
+ for _, filePath := range filePaths {
30
+ if !strings.HasSuffix(filePath, ".go") {
31
+ continue
32
+ }
33
+
34
+ file, err := parser.ParseFile(p.fileSet, filePath, nil, parser.ParseComments)
35
+ if err != nil {
36
+ return fmt.Errorf("failed to parse %s: %w", filePath, err)
37
+ }
38
+
39
+ p.files[filePath] = file
40
+ }
41
+
42
+ return nil
43
+ }
44
+
45
+ // ParseContent parses Go source code from a string
46
+ func (p *Parser) ParseContent(filePath, content string) error {
47
+ if !strings.HasSuffix(filePath, ".go") {
48
+ return fmt.Errorf("not a Go file: %s", filePath)
49
+ }
50
+
51
+ file, err := parser.ParseFile(p.fileSet, filePath, content, parser.ParseComments)
52
+ if err != nil {
53
+ return fmt.Errorf("failed to parse content for %s: %w", filePath, err)
54
+ }
55
+
56
+ p.files[filePath] = file
57
+ return nil
58
+ }
59
+
60
+ // ExtractFunctions extracts all functions from parsed files
61
+ func (p *Parser) ExtractFunctions() []Function {
62
+ var functions []Function
63
+
64
+ for filePath, file := range p.files {
65
+ ast.Inspect(file, func(n ast.Node) bool {
66
+ switch node := n.(type) {
67
+ case *ast.FuncDecl:
68
+ // Skip test functions (Test*/Benchmark*/Example*/Fuzz*): they are
69
+ // `go test` entry points, not production API. Mirrors the Go
70
+ // test-function convention in languages/testConventions.ts.
71
+ if isTestFunction(node.Name.Name) {
72
+ return true
73
+ }
74
+ function := p.extractFunction(node, filePath, file)
75
+ functions = append(functions, function)
76
+ }
77
+ return true
78
+ })
79
+ }
80
+
81
+ return functions
82
+ }
83
+
84
+ // ExtractStructs extracts all structs from parsed files
85
+ func (p *Parser) ExtractStructs() []Struct {
86
+ var structs []Struct
87
+
88
+ for filePath, file := range p.files {
89
+ ast.Inspect(file, func(n ast.Node) bool {
90
+ switch node := n.(type) {
91
+ case *ast.GenDecl:
92
+ if node.Tok == token.TYPE {
93
+ for _, spec := range node.Specs {
94
+ if typeSpec, ok := spec.(*ast.TypeSpec); ok {
95
+ if structType, ok := typeSpec.Type.(*ast.StructType); ok {
96
+ structInfo := p.extractStruct(typeSpec, structType, filePath, file)
97
+ structs = append(structs, structInfo)
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ return true
104
+ })
105
+ }
106
+
107
+ return structs
108
+ }
109
+
110
+ // ExtractInterfaces extracts all interfaces from parsed files
111
+ func (p *Parser) ExtractInterfaces() []Interface {
112
+ var interfaces []Interface
113
+
114
+ for filePath, file := range p.files {
115
+ ast.Inspect(file, func(n ast.Node) bool {
116
+ switch node := n.(type) {
117
+ case *ast.GenDecl:
118
+ if node.Tok == token.TYPE {
119
+ for _, spec := range node.Specs {
120
+ if typeSpec, ok := spec.(*ast.TypeSpec); ok {
121
+ if interfaceType, ok := typeSpec.Type.(*ast.InterfaceType); ok {
122
+ interfaceInfo := p.extractInterface(typeSpec, interfaceType, filePath, file)
123
+ interfaces = append(interfaces, interfaceInfo)
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ return true
130
+ })
131
+ }
132
+
133
+ return interfaces
134
+ }
135
+
136
+ // extractFunction extracts function information from AST
137
+ func (p *Parser) extractFunction(funcDecl *ast.FuncDecl, filePath string, file *ast.File) Function {
138
+ pos := p.fileSet.Position(funcDecl.Pos())
139
+ end := p.fileSet.Position(funcDecl.End())
140
+
141
+ function := Function{
142
+ EntityInfo: EntityInfo{
143
+ Name: funcDecl.Name.Name,
144
+ Type: "function",
145
+ File: filePath,
146
+ StartLine: pos.Line,
147
+ EndLine: end.Line,
148
+ Package: file.Name.Name,
149
+ },
150
+ IsMethod: funcDecl.Recv != nil,
151
+ IsExported: ast.IsExported(funcDecl.Name.Name),
152
+ }
153
+
154
+ // Extract receiver for methods
155
+ if funcDecl.Recv != nil && len(funcDecl.Recv.List) > 0 {
156
+ if field := funcDecl.Recv.List[0]; field.Type != nil {
157
+ function.Receiver = p.typeToString(field.Type)
158
+ }
159
+ }
160
+
161
+ // Extract parameters
162
+ if funcDecl.Type.Params != nil {
163
+ for _, param := range funcDecl.Type.Params.List {
164
+ paramType := p.typeToString(param.Type)
165
+ if len(param.Names) > 0 {
166
+ for _, name := range param.Names {
167
+ function.Parameters = append(function.Parameters, Parameter{
168
+ Name: name.Name,
169
+ Type: paramType,
170
+ Language: "go",
171
+ })
172
+ }
173
+ } else {
174
+ // Anonymous parameter
175
+ function.Parameters = append(function.Parameters, Parameter{
176
+ Name: "",
177
+ Type: paramType,
178
+ Language: "go",
179
+ })
180
+ }
181
+ }
182
+ }
183
+
184
+ // Extract return type
185
+ if funcDecl.Type.Results != nil {
186
+ var returnTypes []string
187
+ for _, result := range funcDecl.Type.Results.List {
188
+ returnTypes = append(returnTypes, p.typeToString(result.Type))
189
+ }
190
+ function.ReturnType = strings.Join(returnTypes, ", ")
191
+ }
192
+
193
+ // Build signature
194
+ function.Signature = p.buildFunctionSignature(function)
195
+
196
+ // Extract purpose from comments
197
+ if funcDecl.Doc != nil {
198
+ function.Purpose = p.extractPurposeFromComments(funcDecl.Doc.Text())
199
+ }
200
+
201
+ // Calculate complexity (basic implementation)
202
+ function.Complexity = p.calculateComplexity(funcDecl)
203
+
204
+ return function
205
+ }
206
+
207
+ // extractStruct extracts struct information from AST
208
+ func (p *Parser) extractStruct(typeSpec *ast.TypeSpec, structType *ast.StructType, filePath string, file *ast.File) Struct {
209
+ pos := p.fileSet.Position(typeSpec.Pos())
210
+ end := p.fileSet.Position(typeSpec.End())
211
+
212
+ structInfo := Struct{
213
+ EntityInfo: EntityInfo{
214
+ Name: typeSpec.Name.Name,
215
+ Type: "struct",
216
+ File: filePath,
217
+ StartLine: pos.Line,
218
+ EndLine: end.Line,
219
+ Package: file.Name.Name,
220
+ },
221
+ IsExported: ast.IsExported(typeSpec.Name.Name),
222
+ }
223
+
224
+ // Extract fields
225
+ if structType.Fields != nil {
226
+ for _, field := range structType.Fields.List {
227
+ fieldType := p.typeToString(field.Type)
228
+ tag := ""
229
+ if field.Tag != nil {
230
+ tag = field.Tag.Value
231
+ }
232
+
233
+ if len(field.Names) > 0 {
234
+ for _, name := range field.Names {
235
+ structInfo.Fields = append(structInfo.Fields, Field{
236
+ Name: name.Name,
237
+ Type: fieldType,
238
+ Tag: tag,
239
+ IsExported: ast.IsExported(name.Name),
240
+ })
241
+ }
242
+ } else {
243
+ // Embedded field
244
+ structInfo.Fields = append(structInfo.Fields, Field{
245
+ Name: fieldType, // Use type as name for embedded fields
246
+ Type: fieldType,
247
+ Tag: tag,
248
+ IsExported: true, // Embedded fields are typically exported
249
+ })
250
+ }
251
+ }
252
+ }
253
+
254
+ // Build signature
255
+ structInfo.Signature = fmt.Sprintf("type %s struct", structInfo.Name)
256
+
257
+ return structInfo
258
+ }
259
+
260
+ // extractInterface extracts interface information from AST
261
+ func (p *Parser) extractInterface(typeSpec *ast.TypeSpec, interfaceType *ast.InterfaceType, filePath string, file *ast.File) Interface {
262
+ pos := p.fileSet.Position(typeSpec.Pos())
263
+ end := p.fileSet.Position(typeSpec.End())
264
+
265
+ interfaceInfo := Interface{
266
+ EntityInfo: EntityInfo{
267
+ Name: typeSpec.Name.Name,
268
+ Type: "interface",
269
+ File: filePath,
270
+ StartLine: pos.Line,
271
+ EndLine: end.Line,
272
+ Package: file.Name.Name,
273
+ },
274
+ IsExported: ast.IsExported(typeSpec.Name.Name),
275
+ }
276
+
277
+ // Extract methods
278
+ if interfaceType.Methods != nil {
279
+ for _, method := range interfaceType.Methods.List {
280
+ if len(method.Names) > 0 {
281
+ // Named method
282
+ for _, name := range method.Names {
283
+ if funcType, ok := method.Type.(*ast.FuncType); ok {
284
+ methodInfo := Method{
285
+ Name: name.Name,
286
+ Signature: p.buildMethodSignature(name.Name, funcType),
287
+ }
288
+
289
+ // Extract parameters
290
+ if funcType.Params != nil {
291
+ for _, param := range funcType.Params.List {
292
+ paramType := p.typeToString(param.Type)
293
+ if len(param.Names) > 0 {
294
+ for _, paramName := range param.Names {
295
+ methodInfo.Parameters = append(methodInfo.Parameters, Parameter{
296
+ Name: paramName.Name,
297
+ Type: paramType,
298
+ Language: "go",
299
+ })
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ // Extract return type
306
+ if funcType.Results != nil {
307
+ var returnTypes []string
308
+ for _, result := range funcType.Results.List {
309
+ returnTypes = append(returnTypes, p.typeToString(result.Type))
310
+ }
311
+ methodInfo.ReturnType = strings.Join(returnTypes, ", ")
312
+ }
313
+
314
+ interfaceInfo.Methods = append(interfaceInfo.Methods, methodInfo)
315
+ }
316
+ }
317
+ }
318
+ }
319
+ }
320
+
321
+ // Build signature
322
+ interfaceInfo.Signature = fmt.Sprintf("type %s interface", interfaceInfo.Name)
323
+
324
+ return interfaceInfo
325
+ }
326
+
327
+ // typeToString converts an AST type to string representation
328
+ func (p *Parser) typeToString(expr ast.Expr) string {
329
+ switch t := expr.(type) {
330
+ case *ast.Ident:
331
+ return t.Name
332
+ case *ast.SelectorExpr:
333
+ return p.typeToString(t.X) + "." + t.Sel.Name
334
+ case *ast.StarExpr:
335
+ return "*" + p.typeToString(t.X)
336
+ case *ast.ArrayType:
337
+ if t.Len == nil {
338
+ return "[]" + p.typeToString(t.Elt)
339
+ }
340
+ return "[...]" + p.typeToString(t.Elt)
341
+ case *ast.MapType:
342
+ return "map[" + p.typeToString(t.Key) + "]" + p.typeToString(t.Value)
343
+ case *ast.ChanType:
344
+ dir := ""
345
+ switch t.Dir {
346
+ case ast.SEND:
347
+ dir = "chan<- "
348
+ case ast.RECV:
349
+ dir = "<-chan "
350
+ default:
351
+ dir = "chan "
352
+ }
353
+ return dir + p.typeToString(t.Value)
354
+ case *ast.FuncType:
355
+ return "func" // Simplified for now
356
+ case *ast.InterfaceType:
357
+ return "interface{}"
358
+ case *ast.StructType:
359
+ return "struct{}"
360
+ default:
361
+ return "unknown"
362
+ }
363
+ }
364
+
365
+ // buildFunctionSignature builds a function signature string
366
+ func (p *Parser) buildFunctionSignature(function Function) string {
367
+ var parts []string
368
+
369
+ // Add receiver for methods
370
+ if function.IsMethod && function.Receiver != "" {
371
+ parts = append(parts, fmt.Sprintf("func (%s)", function.Receiver))
372
+ } else {
373
+ parts = append(parts, "func")
374
+ }
375
+
376
+ // Add function name
377
+ parts = append(parts, function.Name)
378
+
379
+ // Add parameters
380
+ var paramStrs []string
381
+ for _, param := range function.Parameters {
382
+ if param.Name != "" {
383
+ paramStrs = append(paramStrs, fmt.Sprintf("%s %s", param.Name, param.Type))
384
+ } else {
385
+ paramStrs = append(paramStrs, param.Type)
386
+ }
387
+ }
388
+ parts = append(parts, fmt.Sprintf("(%s)", strings.Join(paramStrs, ", ")))
389
+
390
+ // Add return type
391
+ if function.ReturnType != "" {
392
+ parts = append(parts, function.ReturnType)
393
+ }
394
+
395
+ return strings.Join(parts, " ")
396
+ }
397
+
398
+ // buildMethodSignature builds a method signature string for interfaces
399
+ func (p *Parser) buildMethodSignature(name string, funcType *ast.FuncType) string {
400
+ var parts []string
401
+ parts = append(parts, name)
402
+
403
+ // Add parameters
404
+ var paramStrs []string
405
+ if funcType.Params != nil {
406
+ for _, param := range funcType.Params.List {
407
+ paramType := p.typeToString(param.Type)
408
+ if len(param.Names) > 0 {
409
+ for _, paramName := range param.Names {
410
+ paramStrs = append(paramStrs, fmt.Sprintf("%s %s", paramName.Name, paramType))
411
+ }
412
+ } else {
413
+ paramStrs = append(paramStrs, paramType)
414
+ }
415
+ }
416
+ }
417
+ parts = append(parts, fmt.Sprintf("(%s)", strings.Join(paramStrs, ", ")))
418
+
419
+ // Add return type
420
+ if funcType.Results != nil {
421
+ var returnTypes []string
422
+ for _, result := range funcType.Results.List {
423
+ returnTypes = append(returnTypes, p.typeToString(result.Type))
424
+ }
425
+ if len(returnTypes) > 0 {
426
+ parts = append(parts, strings.Join(returnTypes, ", "))
427
+ }
428
+ }
429
+
430
+ return strings.Join(parts, " ")
431
+ }
432
+
433
+ // extractPurposeFromComments extracts purpose from Go doc comments
434
+ func (p *Parser) extractPurposeFromComments(docText string) string {
435
+ lines := strings.Split(strings.TrimSpace(docText), "\n")
436
+ if len(lines) > 0 {
437
+ // Take the first line as purpose, removing comment markers
438
+ purpose := strings.TrimSpace(lines[0])
439
+ purpose = strings.TrimPrefix(purpose, "//")
440
+ purpose = strings.TrimSpace(purpose)
441
+ return purpose
442
+ }
443
+ return ""
444
+ }
445
+
446
+ // calculateComplexity calculates basic cyclomatic complexity
447
+ func (p *Parser) calculateComplexity(funcDecl *ast.FuncDecl) int {
448
+ complexity := 1 // Base complexity
449
+
450
+ ast.Inspect(funcDecl, func(n ast.Node) bool {
451
+ switch n.(type) {
452
+ case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.TypeSwitchStmt:
453
+ complexity++
454
+ case *ast.CaseClause:
455
+ complexity++
456
+ }
457
+ return true
458
+ })
459
+
460
+ return complexity
461
+ }