aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/pseudomuto/protokit/comments.go
blob: 5f0b9e6864bf3f70d82009bb19bf576d563dc49e (plain) (blame)
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))
}