github.com/rmarku/gomarkdoc@v0.0.0-20230517164305-78688ebe4325/lang/func.go (about) 1 package lang 2 3 import ( 4 "fmt" 5 "go/doc" 6 "go/token" 7 "strings" 8 ) 9 10 // Func holds documentation information for a single func declaration within a 11 // package or type. 12 type Func struct { 13 cfg *Config 14 doc *doc.Func 15 examples []*doc.Example 16 } 17 18 // NewFunc creates a new Func from the corresponding documentation construct 19 // from the standard library, the related token.FileSet for the package and 20 // the list of examples for the package. 21 func NewFunc(cfg *Config, doc *doc.Func, examples []*doc.Example) *Func { 22 return &Func{cfg, doc, examples} 23 } 24 25 // Level provides the default level at which headers for the func should be 26 // rendered in the final documentation. 27 func (fn *Func) Level() int { 28 return fn.cfg.Level 29 } 30 31 // Name provides the name of the function. 32 func (fn *Func) Name() string { 33 return fn.doc.Name 34 } 35 36 // Title provides the formatted name of the func. It is primarily designed for 37 // generating headers. 38 func (fn *Func) Title() string { 39 if fn.doc.Recv != "" { 40 return fmt.Sprintf("func (%s) %s", fn.doc.Recv, fn.doc.Name) 41 } 42 43 return fmt.Sprintf("func %s", fn.doc.Name) 44 } 45 46 // Receiver provides the type of the receiver for the function, or empty string 47 // if there is no receiver type. 48 func (fn *Func) Receiver() string { 49 return fn.doc.Recv 50 } 51 52 // Location returns a representation of the node's location in a file within a 53 // repository. 54 func (fn *Func) Location() Location { 55 return NewLocation(fn.cfg, fn.doc.Decl) 56 } 57 58 // Summary provides the one-sentence summary of the function's documentation 59 // comment 60 func (fn *Func) Summary() string { 61 return extractSummary(fn.doc.Doc) 62 } 63 64 // Doc provides the structured contents of the documentation comment for the 65 // function. 66 func (fn *Func) Doc() *Doc { 67 return NewDoc(fn.cfg.Inc(1), fn.doc.Doc) 68 } 69 70 // Signature provides the raw text representation of the code for the 71 // function's signature. 72 func (fn *Func) Signature() (string, error) { 73 // We use a custom FileSet so that we don't inherit multiline formatting 74 return printNode(fn.doc.Decl, token.NewFileSet()) 75 } 76 77 // Examples provides the list of examples from the list given on initialization 78 // that pertain to the function. 79 func (fn *Func) Examples() (examples []*Example) { 80 var fullName string 81 if fn.doc.Recv != "" { 82 fullName = fmt.Sprintf("%s_%s", fn.rawRecv(), fn.doc.Name) 83 } else { 84 fullName = fn.doc.Name 85 } 86 underscorePrefix := fmt.Sprintf("%s_", fullName) 87 88 for _, example := range fn.examples { 89 var name string 90 switch { 91 case example.Name == fullName: 92 name = "" 93 case strings.HasPrefix(example.Name, underscorePrefix): 94 name = example.Name[len(underscorePrefix):] 95 default: 96 // TODO: better filtering 97 continue 98 } 99 100 examples = append(examples, NewExample(fn.cfg.Inc(1), name, example)) 101 } 102 103 return 104 } 105 106 // Anchor produces anchor text for the func. 107 func (fn *Func) Anchor() string { 108 if fn.doc.Recv != "" { 109 return Symbol{ 110 Kind: MethodSymbolKind, 111 Receiver: fn.doc.Recv, 112 Name: fn.doc.Name, 113 }.Anchor() 114 } 115 116 return Symbol{ 117 Kind: FuncSymbolKind, 118 Name: fn.doc.Name, 119 }.Anchor() 120 } 121 122 func (fn *Func) rawRecv() string { 123 // remove type parameters 124 recv := strings.Split(fn.doc.Recv, "[")[0] 125 126 if strings.HasPrefix(recv, "*") { 127 return recv[1:] 128 } 129 130 return recv 131 }