From 14c26f77e10c72358049857f7aec0c2b89229b7a Mon Sep 17 00:00:00 2001 From: Travis Cline Date: Mon, 11 Jul 2022 11:35:49 -0700 Subject: [PATCH] protoc-gen-apidocs: Separate hugo-specific output --- main.go | 32 +++++++- templates/hugo-markdown.tmpl | 146 +++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 templates/hugo-markdown.tmpl diff --git a/main.go b/main.go index bbad373..c2de346 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,8 @@ type GenOpts struct { } var formatFileSuffixes = map[string]string{ - "markdown": "md", + "markdown": "md", + "hugo-markdown": "md", } // generateFile generates a _ascii.pb.go file containing gRPC service definitions. @@ -66,6 +67,19 @@ func (o *GenOpts) generateFile(gen *protogen.Plugin, file *protogen.File) error return nil } +func (o *GenOpts) relPath(t1, t2 protoreflect.Descriptor) string { + path := "" + cpf := filepath.Base(fmt.Sprint(t1.ParentFile().Path())) + rpf := filepath.Base(fmt.Sprint(t2.ParentFile().Path())) + if cpf != rpf { + path, _ = filepath.Rel(cpf, rpf) + path = strings.TrimSuffix(path, filepath.Ext(path)) + path = strings.TrimPrefix(path, ".") + path = fmt.Sprintf("%s.%s", path, formatFileSuffixes[o.Format]) + } + return path +} + func longName(d protoreflect.Descriptor) string { p := d.Parent() if p != nil && p.Parent() != nil { @@ -125,6 +139,22 @@ func (o *GenOpts) templateFuncMap() template.FuncMap { return false }, "type_link": func(f *protogen.Field) string { + var t1, t2 protoreflect.Descriptor + t1 = f.Desc + if f.Message != nil { + t2 = f.Message.Desc + } + if f.Enum != nil { + t2 = f.Enum.Desc + } + if strings.HasPrefix(string(t2.FullName()), "google.") { + return string(t2.FullName()) + } + fn := o.relPath(t1, t2) + typ := anchor(fmt.Sprint(t2.FullName())) + return fmt.Sprintf(`%s#%s`, fn, typ) + }, + "type_link_hugo": func(f *protogen.Field) string { // exclude google types: if f.Message != nil { diff --git a/templates/hugo-markdown.tmpl b/templates/hugo-markdown.tmpl new file mode 100644 index 0000000..2c146ef --- /dev/null +++ b/templates/hugo-markdown.tmpl @@ -0,0 +1,146 @@ +{{/*************************************************************** +Markdown template for protoc-gen-apidocs + +This template is rendered once per incoming .proto file and +defines the resulting output documentation. + +This file is organized into blocks via the go template "define" +function and they are executed with the "template" function. +***************************************************************/}} + +{{/*************************************************************** +Main output block +***************************************************************/}} +{{define "output" -}} + +--- +title: {{ .Desc.Package }} +description: API Specification for the {{ .Desc.Package }} package. +--- + +

Top

+ + +{{range .Services}} +{{template "service" .}} +{{end}} + + +{{ range .Messages }} +{{template "message" .}} +{{end}} + + +{{range .Enums}} +{{template "enum" .}} +{{end}} + + +{{if .Extensions}} + + +### Extensions +| Extension | Type | Extension Point | Number | Description | +| --------- | ---- | ---- | ------ | ----------- | +{{range .Extensions -}} + | {{.Desc.Name}} | {{.Desc.FullName}} | {{ .Extendee | message_type }} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | +{{end}} +{{end}} + +{{end}} + + +{{/*************************************************************** +Service template +***************************************************************/}} +{{define "service"}} + + +### {{.Desc.Name}} + +{{.Comments.Leading | description}} +{{.Comments.Trailing | description}} + +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +{{range .Methods -}} + | {{.Desc.Name}} | [{{ .Input | message_type }}](#{{ .Input | full_message_type | anchor }}) | [{{ .Output | message_type }}](#{{ .Output | full_message_type | anchor }}){{if .Desc.IsStreamingServer}} stream{{end}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | +{{end}} +{{end}} + + + +{{/*************************************************************** +Message template +***************************************************************/}} +{{define "message"}} + + +### {{.Desc.Name}} + +{{.Comments.Leading | description}} +{{.Comments.Trailing | description}} + +{{if .Fields}} +| Field | Type | Description | +| ----- | ---- | ----------- | +{{range .Fields}}{{ if (not .Desc.ContainingOneof) }}{{template "field" .}}{{end}}{{end}} +{{- end -}} +{{range .Oneofs}}{{template "oneof" .}}{{end}} + +{{if .Extensions}} +| Extension | Type | Base | Number | Description | +| --------- | ---- | ---- | ------ | ----------- | +{{range .Extensions -}} + | {{.Desc.Name}} | {{.Desc | long_name}} | {{.Parent | message_type}} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | +{{end}} +{{end}} + +{{ range .Messages }} +{{template "message" .}} +{{end}} + +{{range .Enums}} +{{template "enum" .}} +{{end}} + +{{end}} + +{{/*************************************************************** +Field template +***************************************************************/}} +{{define "field" -}} + | {{.Desc.Name}}{{ if .Desc.IsList }}[]{{ end }} | +{{- if (or (is_primitive .) (is_google_type .)) -}} + {{ field_type . }} +{{- else -}} + [{{ .| field_type }}]({{ hugo_type_link . }}) +{{- end -}} +| {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr }} | +{{end}} + +{{/*************************************************************** +Oneof template +This is kind of gross since GFM doesn't support colspan. +***************************************************************/}} +{{define "oneof" -}} +|Union field `{{ .Desc.Name }}`. {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr }} `{{ .Desc.Name }}` can be only one of the following:| +{{range .Fields}}{{template "field" .}}{{end}} +{{end}} + +{{/*************************************************************** +Enum template +***************************************************************/}} +{{define "enum" }} + + +### {{.Desc | long_name}} +{{.Comments.Leading | description}} +{{.Comments.Trailing | description}} + +| Name | Number | Description | +| ---- | ------ | ----------- | +{{range .Values -}} + | {{.Desc.Name}} | {{.Desc.Number}} | {{ .Comments.Leading | description | nobr}} {{ .Comments.Trailing | description | nobr}} | +{{end}} +{{end}}