package gendoc import ( "bytes" "encoding/json" "errors" html_template "html/template" text_template "text/template" "github.com/Masterminds/sprig" ) // RenderType is an "enum" for which type of renderer to use. type RenderType int8 // Available render types. const ( _ RenderType = iota RenderTypeDocBook RenderTypeHTML RenderTypeJSON RenderTypeMarkdown ) // NewRenderType creates a RenderType from the supplied string. If the type is not known, (0, error) is returned. It is // assumed (by the plugin) that invalid render type simply means that the path to a custom template was supplied. func NewRenderType(renderType string) (RenderType, error) { switch renderType { case "docbook": return RenderTypeDocBook, nil case "html": return RenderTypeHTML, nil case "json": return RenderTypeJSON, nil case "markdown": return RenderTypeMarkdown, nil } return 0, errors.New("Invalid render type") } func (rt RenderType) renderer() (Processor, error) { tmpl, err := rt.template() if err != nil { return nil, err } switch rt { case RenderTypeDocBook: return &textRenderer{string(tmpl)}, nil case RenderTypeHTML: return &htmlRenderer{string(tmpl)}, nil case RenderTypeJSON: return new(jsonRenderer), nil case RenderTypeMarkdown: return &htmlRenderer{string(tmpl)}, nil } return nil, errors.New("Unable to create a processor") } func (rt RenderType) template() ([]byte, error) { switch rt { case RenderTypeDocBook: return docbookTmpl, nil case RenderTypeHTML: return htmlTmpl, nil case RenderTypeJSON: return nil, nil case RenderTypeMarkdown: return markdownTmpl, nil } return nil, errors.New("Couldn't find template for render type") } var funcMap = map[string]interface{}{ "p": PFilter, "para": ParaFilter, "nobr": NoBrFilter, "anchor": AnchorFilter, } // Processor is an interface that is satisfied by all built-in processors (text, html, and json). type Processor interface { Apply(template *Template) ([]byte, error) } // RenderTemplate renders the template based on the render type. It supports overriding the default input templates by // supplying a non-empty string as the last parameter. // // Example: generating an HTML template (assuming you've got a Template object) // data, err := RenderTemplate(RenderTypeHTML, &template, "") // // Example: generating a custom template (assuming you've got a Template object) // data, err := RenderTemplate(RenderTypeHTML, &template, "{{range .Files}}{{.Name}}{{end}}") func RenderTemplate(kind RenderType, template *Template, inputTemplate string) ([]byte, error) { if inputTemplate != "" { processor := &textRenderer{inputTemplate} return processor.Apply(template) } processor, err := kind.renderer() if err != nil { return nil, err } return processor.Apply(template) } type textRenderer struct { inputTemplate string } func (mr *textRenderer) Apply(template *Template) ([]byte, error) { tmpl, err := text_template.New("Text Template").Funcs(funcMap).Funcs(sprig.TxtFuncMap()).Parse(mr.inputTemplate) if err != nil { return nil, err } var buf bytes.Buffer if err = tmpl.Execute(&buf, template); err != nil { return nil, err } return buf.Bytes(), nil } type htmlRenderer struct { inputTemplate string } func (mr *htmlRenderer) Apply(template *Template) ([]byte, error) { tmpl, err := html_template.New("Text Template").Funcs(funcMap).Funcs(sprig.HtmlFuncMap()).Parse(mr.inputTemplate) if err != nil { return nil, err } var buf bytes.Buffer if err = tmpl.Execute(&buf, template); err != nil { return nil, err } return buf.Bytes(), nil } type jsonRenderer struct{} func (r *jsonRenderer) Apply(template *Template) ([]byte, error) { return json.MarshalIndent(template, "", " ") }