1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
package protokit
import (
"github.com/golang/protobuf/protoc-gen-go/descriptor"
"bytes"
"strconv"
"strings"
)
// A Comment describes the leading, trailing, and detached comments for a proto object. See `SourceCodeInfo_Location` in
// descriptor.proto for details on what those terms mean
type Comment struct {
Leading string
Trailing string
Detached []string
}
// String returns the leading and trailing comments joined by 2 line breaks (`\n\n`). If either are empty, the line
// breaks are removed.
func (c *Comment) String() string {
b := new(bytes.Buffer)
if c.GetLeading() != "" {
b.WriteString(c.GetLeading())
b.WriteString("\n\n")
}
b.WriteString(c.GetTrailing())
return strings.TrimSpace(b.String())
}
func newComment(loc *descriptor.SourceCodeInfo_Location) *Comment {
detached := make([]string, len(loc.GetLeadingDetachedComments()))
for i, c := range loc.GetLeadingDetachedComments() {
detached[i] = scrub(c)
}
return &Comment{
Leading: scrub(loc.GetLeadingComments()),
Trailing: scrub(loc.GetTrailingComments()),
Detached: detached,
}
}
// GetLeading returns the leading comments
func (c *Comment) GetLeading() string { return c.Leading }
// GetTrailing returns the leading comments
func (c *Comment) GetTrailing() string { return c.Trailing }
// GetDetached returns the detached leading comments
func (c *Comment) GetDetached() []string { return c.Detached }
// Comments is a map of source location paths to values.
type Comments map[string]*Comment
// ParseComments parses all comments within a proto file. The locations are encoded into the map by joining the paths
// with a "." character. E.g. `4.2.3.0`.
//
// Leading/trailing spaces are trimmed for each comment type (leading, trailing, detached)
func ParseComments(fd *descriptor.FileDescriptorProto) Comments {
comments := make(Comments)
for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
if loc.GetLeadingComments() == "" && loc.GetTrailingComments() == "" && len(loc.GetLeadingDetachedComments()) == 0 {
continue
}
path := loc.GetPath()
key := make([]string, len(path))
for idx, p := range path {
key[idx] = strconv.Itoa(int(p))
}
comments[strings.Join(key, ".")] = newComment(loc)
}
return comments
}
func (c Comments) Get(path string) *Comment {
if val, ok := c[path]; ok {
return val
}
// return an empty comment
return &Comment{Detached: make([]string, 0)}
}
func scrub(str string) string {
return strings.TrimSpace(strings.Replace(str, "\n ", "\n", -1))
}
|