parser
packageAPI reference for the parser
package.
Imports
(9)EntityExtractor
EntityExtractor defines an interface for extracting information from AST declarations.
type EntityExtractor interface
Methods
FunctionExtractor
FunctionExtractor extracts details from function declarations.
type FunctionExtractor struct
Methods
Extract implements the EntityExtractor interface for functions.
Parameters
Returns
func (FunctionExtractor) Extract(node ast.Node, fset *token.FileSet, pkgPath string, fileContent []byte) ([]EntityInfo, error)
{
decl, ok := node.(*ast.FuncDecl)
if !ok {
return nil, nil
}
doc := decl.Doc.Text()
descData := extractDescriptionData(doc)
pos := fset.Position(decl.Pos())
end := fset.Position(decl.End())
signature := "func " + decl.Name.Name + strings.TrimPrefix(formatExpr(decl.Type), "func")
entity := EntityInfo{
Name: decl.Name.Name,
Description: descData.Description,
DescriptionRaw: descData.DescriptionRaw,
DeprecationNote: descData.DeprecationNote,
DeprecationNoteRaw: descData.DeprecationNoteRaw,
Parameters: extractParameters(decl.Type.Params),
Returns: extractParameters(decl.Type.Results),
Body: extractBody(decl.Body, fset, fileContent),
Example: descData.Example,
Notes: descData.Notes,
Type: "function",
Signature: signature,
File: pos.Filename,
LineStart: pos.Line,
LineEnd: end.Line,
Package: pkgPath,
PackagePath: pkgPath,
}
return []EntityInfo{entity}, nil
}
MethodExtractor
MethodExtractor extracts details from method declarations.
type MethodExtractor struct
Methods
Extract implements the EntityExtractor interface for methods.
Parameters
Returns
func (MethodExtractor) Extract(node ast.Node, fset *token.FileSet, pkgPath string, fileContent []byte) ([]EntityInfo, error)
{
decl, ok := node.(*ast.FuncDecl)
if !ok {
return nil, nil
}
doc := decl.Doc.Text()
descData := extractDescriptionData(doc)
pos := fset.Position(decl.Pos())
end := fset.Position(decl.End())
recv := ""
if decl.Recv != nil && len(decl.Recv.List) > 0 {
recv = "(" + formatExpr(decl.Recv.List[0].Type) + ") "
}
signature := "func " + recv + decl.Name.Name + strings.TrimPrefix(formatExpr(decl.Type), "func")
entity := EntityInfo{
Name: decl.Name.Name,
Description: descData.Description,
DescriptionRaw: descData.DescriptionRaw,
DeprecationNote: descData.DeprecationNote,
DeprecationNoteRaw: descData.DeprecationNoteRaw,
Parameters: extractParameters(decl.Type.Params),
Returns: extractParameters(decl.Type.Results),
Body: extractBody(decl.Body, fset, fileContent),
Example: descData.Example,
Notes: descData.Notes,
Type: "method",
Signature: signature,
File: pos.Filename,
LineStart: pos.Line,
LineEnd: end.Line,
Package: pkgPath,
PackagePath: pkgPath,
}
return []EntityInfo{entity}, nil
}
StructExtractor
StructExtractor extracts details from struct declarations.
type StructExtractor struct
Methods
Extract implements the EntityExtractor interface for structs.
Parameters
Returns
func (StructExtractor) Extract(node ast.Node, fset *token.FileSet, pkgPath string, fileContent []byte) ([]EntityInfo, error)
{
decl, ok := node.(*ast.GenDecl)
if !ok {
return nil, nil
}
var entities []EntityInfo
for _, spec := range decl.Specs {
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
structType, ok := typeSpec.Type.(*ast.StructType)
if !ok {
continue
}
doc := decl.Doc.Text()
if typeSpec.Doc != nil {
doc = typeSpec.Doc.Text()
}
descData := extractDescriptionData(doc)
pos := fset.Position(typeSpec.Pos())
end := fset.Position(typeSpec.End())
signature := "type " + typeSpec.Name.Name + " struct"
entity := EntityInfo{
Name: typeSpec.Name.Name,
Description: descData.Description,
DescriptionRaw: descData.DescriptionRaw,
DeprecationNote: descData.DeprecationNote,
DeprecationNoteRaw: descData.DeprecationNoteRaw,
Fields: extractFields(structType),
Example: descData.Example,
Notes: descData.Notes,
Type: "struct",
Signature: signature,
File: pos.Filename,
LineStart: pos.Line,
LineEnd: end.Line,
Package: pkgPath,
PackagePath: pkgPath,
}
entities = append(entities, entity)
}
return entities, nil
}
InterfaceExtractor
InterfaceExtractor extracts details from interface declarations.
type InterfaceExtractor struct
Methods
Extract implements the EntityExtractor interface for interfaces.
Parameters
Returns
func (InterfaceExtractor) Extract(node ast.Node, fset *token.FileSet, pkgPath string, fileContent []byte) ([]EntityInfo, error)
{
decl, ok := node.(*ast.GenDecl)
if !ok {
return nil, nil
}
var entities []EntityInfo
for _, spec := range decl.Specs {
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
continue
}
doc := decl.Doc.Text()
if typeSpec.Doc != nil {
doc = typeSpec.Doc.Text()
}
descData := extractDescriptionData(doc)
pos := fset.Position(typeSpec.Pos())
end := fset.Position(typeSpec.End())
signature := "type " + typeSpec.Name.Name + " interface"
entity := EntityInfo{
Name: typeSpec.Name.Name,
Description: descData.Description,
DescriptionRaw: descData.DescriptionRaw,
DeprecationNote: descData.DeprecationNote,
DeprecationNoteRaw: descData.DeprecationNoteRaw,
Methods: extractMethods(interfaceType),
Example: descData.Example,
Notes: descData.Notes,
Type: "interface",
Signature: signature,
File: pos.Filename,
LineStart: pos.Line,
LineEnd: end.Line,
Package: pkgPath,
PackagePath: pkgPath,
}
entities = append(entities, entity)
}
return entities, nil
}
TypeExtractor
TypeExtractor extracts details from general type declarations.
type TypeExtractor struct
Methods
Extract implements the EntityExtractor interface for types.
Parameters
Returns
func (TypeExtractor) Extract(node ast.Node, fset *token.FileSet, pkgPath string, fileContent []byte) ([]EntityInfo, error)
{
decl, ok := node.(*ast.GenDecl)
if !ok {
return nil, nil
}
var entities []EntityInfo
for _, spec := range decl.Specs {
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
if _, ok := typeSpec.Type.(*ast.StructType); ok {
continue
}
if _, ok := typeSpec.Type.(*ast.InterfaceType); ok {
continue
}
doc := decl.Doc.Text()
if typeSpec.Doc != nil {
doc = typeSpec.Doc.Text()
}
descData := extractDescriptionData(doc)
pos := fset.Position(typeSpec.Pos())
end := fset.Position(typeSpec.End())
signature := "type " + typeSpec.Name.Name + " " + formatExpr(typeSpec.Type)
entity := EntityInfo{
Name: typeSpec.Name.Name,
Description: descData.Description,
DescriptionRaw: descData.DescriptionRaw,
DeprecationNote: descData.DeprecationNote,
DeprecationNoteRaw: descData.DeprecationNoteRaw,
Example: descData.Example,
Notes: descData.Notes,
Type: "type",
Signature: signature,
File: pos.Filename,
LineStart: pos.Line,
LineEnd: end.Line,
Package: pkgPath,
PackagePath: pkgPath,
}
entities = append(entities, entity)
}
return entities, nil
}
GetPackages
GetPackages identifies and returns absolute paths to all Go package directories in the project.
Parameters
Returns
func GetPackages(projectRoot string) ([]string, error)
{
absRoot, err := filepath.Abs(projectRoot)
if err != nil {
return nil, err
}
cfg := &packages.Config{
Mode: packages.NeedFiles,
Dir: absRoot,
}
pkgs, err := packages.Load(cfg, "./...")
if err != nil {
return nil, err
}
var packageDirs []string
for _, pkg := range pkgs {
if len(pkg.GoFiles) > 0 {
dir := filepath.Dir(pkg.GoFiles[0])
// We intentionally skip the root directory to focus on subpackages
if dir == absRoot {
continue
}
packageDirs = append(packageDirs, dir)
}
}
return packageDirs, nil
}
ParseEntitiesInPackage
ParseEntitiesInPackage parses all Go entities (functions, structs, etc.) within a specified package directory.
It returns a list of entities, associated imports, and any encountered error.
Parameters
Returns
func ParseEntitiesInPackage(projectRoot string, pkgPath string, relPath string) ([]EntityInfo, []ImportInfo, error)
{
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, pkgPath, nil, parser.ParseComments)
if err != nil {
return nil, nil, err
}
var entities []EntityInfo
var imports []ImportInfo
var methodsByType = make(map[string][]EntityInfo)
var interfaces = make(map[string]EntityInfo)
var entityIndex = make(map[string]EntityInfo)
extractors := map[string]EntityExtractor{
"function": FunctionExtractor{},
"method": MethodExtractor{},
"struct": StructExtractor{},
"interface": InterfaceExtractor{},
"type": TypeExtractor{},
}
for pkgName, pkg := range pkgs {
for filename, file := range pkg.Files {
content, err := os.ReadFile(filename)
if err != nil {
return nil, nil, err
}
// Process file imports
for _, imp := range file.Imports {
path := strings.Trim(imp.Path.Value, "\"")
name := ""
if imp.Name != nil {
name = imp.Name.Name
}
importURL := strings.ReplaceAll(path, "/", "-")
doc := ""
comment := ""
if imp.Doc != nil {
doc = imp.Doc.Text()
}
if imp.Comment != nil {
comment = imp.Comment.Text()
}
imports = append(imports, ImportInfo{
Path: path,
Alias: name,
URL: importURL,
Doc: doc,
Comment: comment,
Package: pkgName,
File: filename,
})
}
// Process declarations
for _, decl := range file.Decls {
switch d := decl.(type) {
case *ast.FuncDecl:
if d.Recv != nil {
exs, err := extractors["method"].Extract(d, fset, pkgName, content)
if err == nil && len(exs) > 0 {
receiverType := formatExpr(d.Recv.List[0].Type)
methodsByType[receiverType] = append(methodsByType[receiverType], exs[0])
}
} else {
exs, err := extractors["function"].Extract(d, fset, pkgName, content)
if err == nil && len(exs) > 0 {
entities = append(entities, exs[0])
entityIndex[pkgName+"."+exs[0].Name] = exs[0]
}
}
case *ast.GenDecl:
if d.Tok == token.TYPE {
structs, _ := extractors["struct"].Extract(d, fset, pkgName, content)
for _, s := range structs {
entities = append(entities, s)
entityIndex[pkgName+"."+s.Name] = s
}
ifaces, _ := extractors["interface"].Extract(d, fset, pkgName, content)
for _, i := range ifaces {
entities = append(entities, i)
interfaces[i.Name] = i
entityIndex[pkgName+"."+i.Name] = i
}
types, _ := extractors["type"].Extract(d, fset, pkgName, content)
for _, t := range types {
entities = append(entities, t)
entityIndex[pkgName+"."+t.Name] = t
}
}
}
}
}
}
// Link methods and calculate relationships between entities
for i, entity := range entities {
entity.References = findReferences(entity, entityIndex)
if entity.Type == "struct" {
receiverName := entity.Name
if methods, ok := methodsByType[receiverName]; ok {
entity.Methods = append(entity.Methods, methods...)
}
if methods, ok := methodsByType["*"+receiverName]; ok {
entity.Methods = append(entity.Methods, methods...)
}
for j, method := range entity.Methods {
entity.Methods[j].References = findReferences(method, entityIndex)
}
entity.Implements = findImplementedInterfaces(entity, interfaces)
}
entities[i] = entity
}
return entities, imports, nil
}
findImplementedInterfaces
findImplementedInterfaces identifies which interfaces are implemented by a given struct.
Parameters
Returns
func findImplementedInterfaces(entity EntityInfo, interfaces map[string]EntityInfo) []ImplementationInfo
{
var implemented []ImplementationInfo
for ifaceName, ifaceInfo := range interfaces {
if implementsInterface(entity, ifaceInfo) {
implemented = append(implemented, ImplementationInfo{
InterfaceName: ifaceName,
Package: ifaceInfo.Package,
})
}
}
return implemented
}
Uses
implementsInterface
implementsInterface checks if a struct implements all methods of a given interface.
Parameters
Returns
func implementsInterface(entity EntityInfo, iface EntityInfo) bool
{
methodSet := make(map[string]EntityInfo)
for _, method := range entity.Methods {
methodSet[method.Name] = method
}
for _, ifaceMethod := range iface.Methods {
if method, ok := methodSet[ifaceMethod.Name]; !ok {
return false
} else {
if !methodsMatch(ifaceMethod, method) {
return false
}
}
}
return true
}
methodsMatch
methodsMatch verifies if the signatures of two methods match.
Parameters
Returns
func methodsMatch(ifaceMethod, structMethod EntityInfo) bool
{
if len(ifaceMethod.Parameters) != len(structMethod.Parameters) ||
len(ifaceMethod.Returns) != len(structMethod.Returns) {
return false
}
for i, param := range ifaceMethod.Parameters {
if param != structMethod.Parameters[i] {
return false
}
}
for i, ret := range ifaceMethod.Returns {
if ret != structMethod.Returns[i] {
return false
}
}
return true
}
ExampleDeprecationNote
ExampleDeprecationNote is an example of a deprecated function
func ExampleDeprecationNote()
{}
extractMethods
extractMethods collects method information from an interface.
Parameters
Returns
func extractMethods(interfaceType *ast.InterfaceType) []EntityInfo
{
var methods []EntityInfo
for _, field := range interfaceType.Methods.List {
if funcType, ok := field.Type.(*ast.FuncType); ok {
methodInfo := EntityInfo{
Name: field.Names[0].Name,
Parameters: extractParameters(funcType.Params),
Returns: extractParameters(funcType.Results),
}
methods = append(methods, methodInfo)
}
}
return methods
}
extractFields
extractFields collects field information from a struct.
Parameters
Returns
func extractFields(structType *ast.StructType) []FieldInfo
{
var fields []FieldInfo
for _, field := range structType.Fields.List {
typeStr := formatExpr(field.Type)
for _, name := range field.Names {
fieldInfo := FieldInfo{
Name: name.Name,
Type: typeStr,
Tag: extractTag(field),
}
fields = append(fields, fieldInfo)
}
}
return fields
}
extractTag
extractTag returns the backtick-wrapped tag string of a struct field.
Parameters
Returns
func extractTag(field *ast.Field) string
{
if field.Tag != nil {
return strings.Trim(field.Tag.Value, "`")
}
return ""
}
DescriptionData
DescriptionData holds both formatted (HTML) and raw documentation components.
type DescriptionData struct
Fields
| Name | Type | Description |
|---|---|---|
| Description | string | |
| Example | string | |
| Notes | string | |
| DeprecationNote | string | |
| Returns | string | |
| DescriptionRaw | string | |
| DeprecationNoteRaw | string |
extractDescriptionData
extractDescriptionData parses a Go documentation comment and extracts metadata sections.
Parameters
Returns
func extractDescriptionData(doc string) DescriptionData
{
lines := strings.Split(doc, "\n")
var descLines []string
var exampleLines []string
var notesLines []string
var deprecationNoteLines []string
var returnsLines []string
var description string
var example string
var notes string
var deprecationNote string
var returns string
isExample := false
isNotes := false
isDeprecationNote := false
isReturns := false
for _, line := range lines {
trimmedLine := strings.TrimSpace(line)
if strings.HasPrefix(trimmedLine, "Example:") {
isExample = true
isNotes = false
isDeprecationNote = false
isReturns = false
continue
}
if strings.HasPrefix(trimmedLine, "Notes:") {
isNotes = true
isExample = false
isDeprecationNote = false
isReturns = false
continue
}
if strings.HasPrefix(trimmedLine, "Deprecated:") {
isDeprecationNote = true
isExample = false
isNotes = false
isReturns = false
continue
}
if strings.HasPrefix(trimmedLine, "Returns:") {
isReturns = true
isExample = false
isNotes = false
isDeprecationNote = false
continue
}
if isExample {
exampleLines = append(exampleLines, line)
} else if isNotes {
notesLines = append(notesLines, trimmedLine)
} else if isDeprecationNote {
deprecationNoteLines = append(deprecationNoteLines, trimmedLine)
} else if isReturns {
returnsLines = append(returnsLines, trimmedLine)
} else {
descLines = append(descLines, trimmedLine)
}
}
descriptionRaw := strings.Join(descLines, "\n")
description = markdownToHTML(descriptionRaw)
example = strings.Join(exampleLines, "\n")
example = formatExample(example)
notesRaw := strings.Join(notesLines, "\n")
notes = markdownToHTML(notesRaw)
deprecationNoteRaw := strings.Join(deprecationNoteLines, "\n")
deprecationNote = markdownToHTML(deprecationNoteRaw)
returnsRaw := strings.Join(returnsLines, "\n")
returns = markdownToHTML(returnsRaw)
return DescriptionData{
Description: description,
Example: example,
Notes: notes,
DeprecationNote: deprecationNote,
Returns: returns,
DescriptionRaw: descriptionRaw,
DeprecationNoteRaw: deprecationNoteRaw,
}
}
markdownToHTML
markdownToHTML converts markdown text to HTML using the blackfriday engine.
Parameters
Returns
func markdownToHTML(md string) string
{
renderer := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
Flags: blackfriday.CommonHTMLFlags,
})
extensions := blackfriday.CommonExtensions | blackfriday.AutoHeadingIDs | blackfriday.HardLineBreak | blackfriday.Autolink
output := blackfriday.Run([]byte(md), blackfriday.WithRenderer(renderer), blackfriday.WithExtensions(extensions))
return string(output)
}
formatExample
formatExample cleans up indentation in code examples while preserving relative structure.
Parameters
Returns
func formatExample(example string) string
{
lines := strings.Split(example, "\n")
for len(lines) > 0 && strings.TrimSpace(lines[0]) == "" {
lines = lines[1:]
}
for len(lines) > 0 && strings.TrimSpace(lines[len(lines)-1]) == "" {
lines = lines[:len(lines)-1]
}
if len(lines) == 0 {
return ""
}
minIndent := -1
for _, line := range lines {
if strings.TrimSpace(line) == "" {
continue
}
indent := len(line) - len(strings.TrimLeft(line, " \t"))
if minIndent == -1 || indent < minIndent {
minIndent = indent
}
}
if minIndent <= 0 {
return strings.Join(lines, "\n")
}
dedentedLines := make([]string, len(lines))
for i, line := range lines {
if len(line) >= minIndent {
dedentedLines[i] = line[minIndent:]
} else {
dedentedLines[i] = strings.TrimLeft(line, " \t")
}
}
return strings.Join(dedentedLines, "\n")
}
extractParameters
extractParameters returns a slice of formatted parameter strings.
Parameters
Returns
func extractParameters(fieldList *ast.FieldList) []string
{
var params []string
if fieldList != nil {
for _, param := range fieldList.List {
typeStr := formatExpr(param.Type)
for _, name := range param.Names {
params = append(params, name.Name+" "+typeStr)
}
if len(param.Names) == 0 {
params = append(params, typeStr)
}
}
}
return params
}
formatExpr
formatExpr converts an AST expression إلى its Go source representation.
Parameters
Returns
func formatExpr(expr ast.Expr) string
{
var out strings.Builder
if err := format.Node(&out, token.NewFileSet(), expr); err != nil {
return ""
}
return out.String()
}
extractBody
extractBody retrieves the source code block of a function or method.
Parameters
Returns
func extractBody(node ast.Node, fset *token.FileSet, fileContent []byte) string
{
if node == nil {
return ""
}
// Try to slice directly from the original file content for accuracy
if len(fileContent) > 0 {
start := fset.Position(node.Pos()).Offset
end := fset.Position(node.End()).Offset
if start >= 0 && end <= len(fileContent) && start < end {
return string(fileContent[start:end])
}
}
var buf strings.Builder
if err := format.Node(&buf, fset, node); err != nil {
return ""
}
return buf.String()
}
findReferences
findReferences scans an entity for references to other known types within the same package.
Parameters
Returns
func findReferences(entity EntityInfo, entityIndex map[string]EntityInfo) []ReferenceInfo
{
var references []ReferenceInfo
for _, param := range entity.Parameters {
parts := strings.Fields(param)
if len(parts) == 0 {
continue
}
paramType := parts[len(parts)-1]
if refEntity, found := entityIndex[entity.Package+"."+paramType]; found {
references = append(references, ReferenceInfo{
Name: paramType,
Package: refEntity.Package,
PackageURL: refEntity.PackageURL,
PackagePath: refEntity.PackagePath,
})
}
}
for _, ret := range entity.Returns {
parts := strings.Fields(ret)
if len(parts) == 0 {
continue
}
retType := parts[len(parts)-1]
if refEntity, found := entityIndex[entity.Package+"."+retType]; found {
references = append(references, ReferenceInfo{
Name: retType,
Package: refEntity.Package,
PackageURL: refEntity.PackageURL,
PackagePath: refEntity.PackagePath,
})
}
}
for _, field := range entity.Fields {
if refEntity, found := entityIndex[entity.Package+"."+field.Type]; found {
references = append(references, ReferenceInfo{
Name: field.Type,
Package: refEntity.Package,
PackageURL: refEntity.PackageURL,
PackagePath: refEntity.PackagePath,
})
}
}
return references
}
Uses
EntityInfo
EntityInfo represents a Go entity such as a function, struct, interface, or type alias.
type EntityInfo struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | |
| Description | string | |
| Example | string | |
| Notes | string | |
| DeprecationNote | string | |
| Parameters | []string | |
| Returns | []string | |
| Body | string | |
| Type | string | |
| Fields | []FieldInfo | |
| Methods | []EntityInfo | |
| Implements | []ImplementationInfo | |
| Package | string | |
| PackageURL | string | |
| PackagePath | string | |
| References | []ReferenceInfo | |
| DescriptionRaw | string | |
| DeprecationNoteRaw | string | |
| Signature | string | |
| File | string | |
| LineStart | int | |
| LineEnd | int |
ReferenceInfo
ReferenceInfo contains details about a type referenced by an entity.
type ReferenceInfo struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | |
| Package | string | |
| PackageURL | string | |
| PackagePath | string |
FieldInfo
FieldInfo represents a single field within a struct.
type FieldInfo struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | |
| Type | string | |
| Tag | string |
ImplementationInfo
ImplementationInfo identifies an interface implemented by a struct.
type ImplementationInfo struct
Fields
| Name | Type | Description |
|---|---|---|
| InterfaceName | string | |
| Package | string |
ImportInfo
ImportInfo captures details about a package import.
type ImportInfo struct
Fields
| Name | Type | Description |
|---|---|---|
| URL | string | |
| Path | string | |
| Alias | string | |
| Doc | string | |
| Comment | string | |
| Package | string | |
| File | string |