github.com/anthonyme00/gomarkdoc@v1.0.0/lang/symbol.go (about) 1 package lang 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/doc" 7 "strings" 8 ) 9 10 type ( 11 // Symbol provides identity information for a symbol in a package. 12 Symbol struct { 13 // Receiver holds the receiver for a method or field. 14 Receiver string 15 // Name holds the name of the symbol itself. 16 Name string 17 // Kind identifies the category of the symbol. 18 Kind SymbolKind 19 // Parent holds the linkable parent symbol which contains this one. 20 Parent *Symbol 21 } 22 23 // SymbolKind identifies the type of symbol. 24 SymbolKind int 25 ) 26 27 // The list of valid symbol kinds. 28 const ( 29 TypeSymbolKind SymbolKind = iota + 1 30 FuncSymbolKind 31 ConstSymbolKind 32 VarSymbolKind 33 MethodSymbolKind 34 FieldSymbolKind 35 ) 36 37 // PackageSymbols gets the list of symbols for a doc package. 38 func PackageSymbols(pkg *doc.Package) map[string]Symbol { 39 sym := make(map[string]Symbol) 40 for _, c := range pkg.Consts { 41 parent := Symbol{ 42 Name: c.Names[0], 43 Kind: ConstSymbolKind, 44 } 45 46 for _, n := range c.Names { 47 sym[symbolName("", n)] = Symbol{ 48 Name: n, 49 Kind: ConstSymbolKind, 50 Parent: &parent, 51 } 52 } 53 } 54 55 for _, v := range pkg.Vars { 56 parent := Symbol{ 57 Name: v.Names[0], 58 Kind: VarSymbolKind, 59 } 60 61 for _, n := range v.Names { 62 sym[symbolName("", n)] = Symbol{ 63 Name: n, 64 Kind: VarSymbolKind, 65 Parent: &parent, 66 } 67 } 68 } 69 70 for _, v := range pkg.Funcs { 71 sym[symbolName("", v.Name)] = Symbol{ 72 Name: v.Name, 73 Kind: FuncSymbolKind, 74 } 75 } 76 77 for _, t := range pkg.Types { 78 typeSymbols(sym, t) 79 } 80 81 return sym 82 } 83 84 func typeSymbols(sym map[string]Symbol, t *doc.Type) { 85 typeSym := Symbol{ 86 Name: t.Name, 87 Kind: TypeSymbolKind, 88 } 89 90 sym[t.Name] = typeSym 91 92 for _, f := range t.Methods { 93 sym[symbolName(t.Name, f.Name)] = Symbol{ 94 Receiver: t.Name, 95 Name: f.Name, 96 Kind: MethodSymbolKind, 97 } 98 } 99 100 for _, s := range t.Decl.Specs { 101 typ, ok := s.(*ast.TypeSpec).Type.(*ast.StructType) 102 if !ok { 103 continue 104 } 105 106 for _, f := range typ.Fields.List { 107 for _, n := range f.Names { 108 sym[symbolName(t.Name, n.String())] = Symbol{ 109 Receiver: t.Name, 110 Name: n.String(), 111 Kind: FieldSymbolKind, 112 Parent: &typeSym, 113 } 114 } 115 } 116 } 117 118 for _, f := range t.Funcs { 119 sym[symbolName("", f.Name)] = Symbol{ 120 Name: f.Name, 121 Kind: FuncSymbolKind, 122 } 123 } 124 125 for _, c := range t.Consts { 126 parent := Symbol{ 127 Name: c.Names[0], 128 Kind: ConstSymbolKind, 129 } 130 131 for _, n := range c.Names { 132 sym[symbolName("", n)] = Symbol{ 133 Name: n, 134 Kind: ConstSymbolKind, 135 Parent: &parent, 136 } 137 } 138 } 139 140 for _, v := range t.Vars { 141 parent := Symbol{ 142 Name: v.Names[0], 143 Kind: VarSymbolKind, 144 } 145 146 for _, n := range v.Names { 147 sym[symbolName("", n)] = Symbol{ 148 Name: n, 149 Kind: VarSymbolKind, 150 Parent: &parent, 151 } 152 } 153 } 154 155 } 156 157 // Anchor produces anchor text for the symbol. 158 func (s Symbol) Anchor() string { 159 if s.Parent != nil { 160 return s.Parent.Anchor() 161 } 162 163 switch s.Kind { 164 case MethodSymbolKind, FieldSymbolKind: 165 return fmt.Sprintf("%s.%s", strings.TrimLeft(s.Receiver, "*"), s.Name) 166 default: 167 return s.Name 168 } 169 } 170 171 // symbolName returns the string representation of the symbol. 172 func symbolName(receiver string, name string) string { 173 receiver = strings.TrimLeft(receiver, "*") 174 name = strings.TrimLeft(name, "*") 175 176 if receiver == "" { 177 return name 178 } 179 180 return fmt.Sprintf("%s.%s", receiver, name) 181 }