forked from pseudomuto/protoc-gen-doc
/
plugin.go
109 lines (91 loc) · 2.98 KB
/
plugin.go
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package gendoc
import (
"fmt"
"io/ioutil"
"path"
"regexp"
"strings"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/plugin"
"github.com/Kunde21/protoc-gen-doc/parser"
)
// PluginOptions encapsulates options for the plugin. The type of renderer, template file, and the name of the output
// file are included.
type PluginOptions struct {
Type RenderType
TemplateFile string
OutputFile string
ExcludePatterns []*regexp.Regexp
}
// ParseOptions parses plugin options from a CodeGeneratorRequest. It does this by splitting the `Parameter` field from
// the request object and parsing out the type of renderer to use and the name of the file to be generated.
//
// The parameter (`--doc_opt`) must be of the format <TYPE|TEMPLATE_FILE>,<OUTPUT_FILE>:<EXCLUDE_PATTERN>,<EXCLUDE_PATTERN>*.
// The file will be written to the directory specified with the `--doc_out` argument to protoc.
func ParseOptions(req *plugin_go.CodeGeneratorRequest) (*PluginOptions, error) {
options := &PluginOptions{
Type: RenderTypeHTML,
TemplateFile: "",
OutputFile: "index.html",
}
params := req.GetParameter()
if strings.Contains(params, ":") {
// Parse out exclude patterns if any
parts := strings.Split(params, ":")
for _, pattern := range strings.Split(parts[1], ",") {
r, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
options.ExcludePatterns = append(options.ExcludePatterns, r)
}
// The first part is parsed below
params = parts[0]
}
if params == "" {
return options, nil
}
if !strings.Contains(params, ",") {
return nil, fmt.Errorf("Invalid parameter: %s", params)
}
parts := strings.Split(params, ",")
if len(parts) != 2 {
return nil, fmt.Errorf("Invalid parameter: %s", params)
}
options.TemplateFile = parts[0]
options.OutputFile = path.Base(parts[1])
renderType, err := NewRenderType(options.TemplateFile)
if err == nil {
options.Type = renderType
options.TemplateFile = ""
}
return options, nil
}
// RunPlugin compiles the documentation and generates the CodeGeneratorResponse to send back to protoc. It does this
// by rendering a template based on the options parsed from the CodeGeneratorRequest.
func RunPlugin(request *plugin_go.CodeGeneratorRequest) (*plugin_go.CodeGeneratorResponse, error) {
options, err := ParseOptions(request)
if err != nil {
return nil, err
}
result := parser.ParseCodeRequest(request, options.ExcludePatterns)
template := NewTemplate(result)
customTemplate := ""
if options.TemplateFile != "" {
data, err := ioutil.ReadFile(options.TemplateFile)
if err != nil {
return nil, err
}
customTemplate = string(data)
}
output, err := RenderTemplate(options.Type, template, customTemplate)
if err != nil {
return nil, err
}
resp := new(plugin_go.CodeGeneratorResponse)
resp.File = append(resp.File, &plugin_go.CodeGeneratorResponse_File{
Name: proto.String(options.OutputFile),
Content: proto.String(string(output)),
})
return resp, nil
}