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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +99 -0
- package/README.md +5 -5
- package/dist/analyzers/applicability.d.ts +19 -5
- package/dist/analyzers/applicability.d.ts.map +1 -1
- package/dist/analyzers/applicability.js +36 -24
- package/dist/analyzers/applicability.js.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.js +23 -2
- package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +52 -9
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js +228 -55
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts +19 -12
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js +78 -111
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +0 -6
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +85 -73
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
- package/dist/analyzers/documentationAnalyzer.js +5 -5
- package/dist/analyzers/documentationAnalyzer.js.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.js +1 -0
- package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
- package/dist/analyzers/provenance.d.ts +7 -9
- package/dist/analyzers/provenance.d.ts.map +1 -1
- package/dist/analyzers/provenance.js +88 -124
- package/dist/analyzers/provenance.js.map +1 -1
- package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/reactAnalyzer.js +120 -21
- package/dist/analyzers/reactAnalyzer.js.map +1 -1
- package/dist/analyzers/ruleRegistry.d.ts +35 -12
- package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
- package/dist/analyzers/ruleRegistry.js +66 -108
- package/dist/analyzers/ruleRegistry.js.map +1 -1
- package/dist/analyzers/ruleTiming.d.ts +2 -2
- package/dist/analyzers/ruleTiming.js +2 -2
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +60 -24
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js +5 -2
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +82 -71
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +2 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +23 -12
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +11 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +60 -22
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +5 -2
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -3
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js +258 -87
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js +7 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
- package/dist/analyzers/universal/schema/discovery.d.ts +29 -1
- package/dist/analyzers/universal/schema/discovery.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/discovery.js +76 -21
- package/dist/analyzers/universal/schema/discovery.js.map +1 -1
- package/dist/analyzers/universal/schema/jsonSchema.js +7 -11
- package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
- package/dist/auditRouter.d.ts +41 -0
- package/dist/auditRouter.d.ts.map +1 -0
- package/dist/auditRouter.js +185 -0
- package/dist/auditRouter.js.map +1 -0
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +93 -84
- package/dist/auditRunner.js.map +1 -1
- package/dist/cli.js +306 -95
- package/dist/cli.js.map +1 -1
- package/dist/codeIndexDB.d.ts.map +1 -1
- package/dist/codeIndexDB.js +41 -7
- package/dist/codeIndexDB.js.map +1 -1
- package/dist/componentScanner.d.ts.map +1 -1
- package/dist/componentScanner.js +2 -1
- package/dist/componentScanner.js.map +1 -1
- package/dist/config/configLoader.d.ts +9 -0
- package/dist/config/configLoader.d.ts.map +1 -1
- package/dist/config/configLoader.js +45 -2
- package/dist/config/configLoader.js.map +1 -1
- package/dist/config/defaults.d.ts +8 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +19 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/dataPaths.js +18 -1
- package/dist/dataPaths.js.map +1 -1
- package/dist/enforcement/gate.d.ts +14 -19
- package/dist/enforcement/gate.d.ts.map +1 -1
- package/dist/enforcement/gate.js +27 -45
- package/dist/enforcement/gate.js.map +1 -1
- package/dist/functionScanner.d.ts.map +1 -1
- package/dist/functionScanner.js +1 -17
- package/dist/functionScanner.js.map +1 -1
- package/dist/invariants/ruleEngine.d.ts +8 -0
- package/dist/invariants/ruleEngine.d.ts.map +1 -1
- package/dist/invariants/ruleEngine.js +35 -16
- package/dist/invariants/ruleEngine.js.map +1 -1
- package/dist/languages/LanguageOrchestrator.d.ts +9 -10
- package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.js +135 -101
- package/dist/languages/LanguageOrchestrator.js.map +1 -1
- package/dist/languages/RuntimeManager.d.ts +28 -1
- package/dist/languages/RuntimeManager.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.js +158 -47
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/languages/go/GoAdapter.d.ts +2 -0
- package/dist/languages/go/GoAdapter.d.ts.map +1 -1
- package/dist/languages/go/GoAdapter.js +15 -22
- package/dist/languages/go/GoAdapter.js.map +1 -1
- package/dist/languages/go/analyzer +0 -0
- package/dist/languages/go/analyzer-src/analyzer.go +510 -0
- package/dist/languages/go/analyzer-src/go.mod +3 -0
- package/dist/languages/go/analyzer-src/indexer.go +268 -0
- package/dist/languages/go/analyzer-src/parser.go +461 -0
- package/dist/languages/go/analyzer-src/solid.go +395 -0
- package/dist/languages/go/analyzer-src/testconventions.go +25 -0
- package/dist/languages/go/analyzer-src/types.go +148 -0
- package/dist/languages/go/go.mod +7 -0
- package/dist/languages/go/main.go +203 -0
- package/dist/languages/testConventions.d.ts +35 -0
- package/dist/languages/testConventions.d.ts.map +1 -0
- package/dist/languages/testConventions.js +51 -0
- package/dist/languages/testConventions.js.map +1 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +3 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +25 -18
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
- package/dist/mcp-tools/whitelistTools.d.ts +1 -1
- package/dist/mcp-tools-shared.d.ts +0 -3
- package/dist/mcp-tools-shared.d.ts.map +1 -1
- package/dist/mcp-tools-shared.js +8 -117
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/mcp.js +3 -1
- package/dist/mcp.js.map +1 -1
- package/dist/mcpAuditJobs.d.ts.map +1 -1
- package/dist/mcpAuditJobs.js +13 -0
- package/dist/mcpAuditJobs.js.map +1 -1
- package/dist/nextFile.d.ts +21 -0
- package/dist/nextFile.d.ts.map +1 -0
- package/dist/nextFile.js +51 -0
- package/dist/nextFile.js.map +1 -0
- package/dist/nextFileIncremental.d.ts +141 -0
- package/dist/nextFileIncremental.d.ts.map +1 -0
- package/dist/nextFileIncremental.js +314 -0
- package/dist/nextFileIncremental.js.map +1 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +43 -3
- package/dist/pipeline.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +17 -0
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +791 -40
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
- package/dist/reporting/jsonReportGenerator.js +11 -30
- package/dist/reporting/jsonReportGenerator.js.map +1 -1
- package/dist/styles/styleExtractor.js +2 -2
- package/dist/styles/styleExtractor.js.map +1 -1
- package/dist/styles/styleIndexer.d.ts +7 -0
- package/dist/styles/styleIndexer.d.ts.map +1 -1
- package/dist/styles/styleIndexer.js +51 -67
- package/dist/styles/styleIndexer.js.map +1 -1
- package/dist/styles/types.d.ts +3 -2
- package/dist/styles/types.d.ts.map +1 -1
- package/dist/types/crossLanguage.d.ts +1 -0
- package/dist/types/crossLanguage.d.ts.map +1 -1
- package/dist/types.d.ts +43 -34
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/fileDiscovery.d.ts +9 -0
- package/dist/utils/fileDiscovery.d.ts.map +1 -1
- package/dist/utils/fileDiscovery.js +18 -0
- package/dist/utils/fileDiscovery.js.map +1 -1
- package/package.json +16 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/README.md +11 -9
- package/plugin/hooks/hooks.json +4 -0
- package/plugin/scripts/hook-audit.sh +20 -30
- package/plugin/scripts/hook-common.sh +63 -0
- package/plugin/scripts/hook-self-audit.sh +99 -0
- package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +55 -9
- 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
|
+
}
|