package stdlib import ( "strings" "text/template" "github.com/kovetskiy/mark/pkg/confluence" "github.com/kovetskiy/mark/pkg/mark/macro" "github.com/reconquest/pkg/log" "github.com/reconquest/karma-go" ) type Lib struct { Macros []macro.Macro Templates *template.Template } func New(api *confluence.API) (*Lib, error) { var ( lib Lib err error ) lib.Templates, err = templates(api) if err != nil { return nil, err } lib.Macros, err = macros(lib.Templates) if err != nil { return nil, err } return &lib, nil } func macros(templates *template.Template) ([]macro.Macro, error) { text := func(line ...string) []byte { return []byte(strings.Join(line, "\n")) } macros, _, err := macro.ExtractMacros( "", []byte(text( ``, // TODO(seletskiy): more macros here )), templates, ) if err != nil { return nil, err } return macros, nil } func templates(api *confluence.API) (*template.Template, error) { text := func(line ...string) string { return strings.Join(line, ``) } templates := template.New(`stdlib`).Funcs( template.FuncMap{ "user": func(name string) *confluence.User { user, err := api.GetUserByName(name) if err != nil { log.Error(err) } return user }, // The only way to escape CDATA end marker ']]>' is to split it // into two CDATA sections. "cdata": func(data string) string { return strings.ReplaceAll( data, "]]>", "]]>", ) }, "convertAttachment": func(data string) string { return strings.ReplaceAll( data, "/", "_", ) }, }, ) var err error for name, body := range map[string]string{ // This template is used to select whole article layout `ac:layout`: text( `{{ if eq .Layout "article" }}`, /**/ ``, /**/ ``, /**/ `{{ .Body }}`, /**/ `{{ .Sidebar }}`, /**/ ``, /**/ ``, `{{ else }}`, /**/ `{{ .Body }}`, `{{ end }}`, ), // This template is used for rendering code in ``` `ac:code`: text( `{{printf "\n"}}`, /**/ `{{ if eq .Language "mermaid" }}true{{printf "\n"}}{{ else }}`, /**/ `{{ .Language }}{{printf "\n"}}{{ end }}`, /**/ `{{ .Collapse }}{{printf "\n"}}`, /**/ `{{ if .Theme }}{{ .Theme }}{{printf "\n"}}{{ end }}`, /**/ `{{ if .Linenumbers }}{{ .Linenumbers }}{{printf "\n"}}{{ end }}`, /**/ `{{ if .Firstline }}{{ .Firstline }}{{printf "\n"}}{{ end }}`, /**/ `{{ if .Title }}{{ .Title }}{{printf "\n"}}{{ end }}`, /**/ `{{printf "\n"}}`, `{{printf "\n"}}`, ), `ac:status`: text( ``, `{{ or .Color "Grey" }}`, `{{ or .Title .Color }}`, `{{ or .Subtle false }}`, ``, ), `ac:link:user`: text( `{{ with .Name | user }}`, /**/ ``, /**/ ``, /**/ ``, `{{ else }}`, /**/ `{{ .Name }}`, `{{ end }}`, ), `ac:jira:ticket`: text( ``, `{{ .Ticket }}`, ``, ), /* https://confluence.atlassian.com/doc/jira-issues-macro-139380.html */ `ac:jiraissues`: text( ``, `{{ or .Anonymous false }}`, `{{ or .BaseURL .URL }}`, `{{ or .Columns "type;key;summary;assignee;reporter;priority;status;resolution;created;updated;due" }}`, `{{ or .Count false }}`, `{{ or .Cache "on" }}`, `{{ or .Height 480 }}`, `{{ or .RenderMode "static" }}`, `{{ or .Title "Jira Issues" }}`, `{{ .URL }}`, `{{ or .Width "100%" }}`, ``, ), /* https://confluence.atlassian.com/conf59/info-tip-note-and-warning-macros-792499127.html */ `ac:box`: text( `{{printf "\n"}}`, `{{ or .Icon "false" }}{{printf "\n"}}`, `{{ if .Title }}{{ .Title }}{{printf "\n"}}{{ end }}`, `{{ .Body }}{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/conf59/table-of-contents-macro-792499210.html */ `ac:toc`: text( `{{printf "\n"}}`, `{{ or .Printable "true" }}{{printf "\n"}}`, `{{ or .Style "disc" }}{{printf "\n"}}`, `{{ or .MaxLevel "7" }}{{printf "\n"}}`, `{{ or .Indent "" }}{{printf "\n"}}`, `{{ or .MinLevel "1" }}{{printf "\n"}}`, `{{ or .Exclude "" }}{{printf "\n"}}`, `{{ or .Type "list" }}{{printf "\n"}}`, `{{ or .Outline "clear" }}{{printf "\n"}}`, `{{ or .Include "" }}{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/doc/children-display-macro-139501.html */ `ac:children`: text( `{{printf "\n"}}`, `{{ if .Reverse}}{{ or .Reverse }}{{printf "\n"}}{{end}}`, `{{ if .Sort}}{{ .Sort }}{{printf "\n"}}{{end}}`, `{{ if .Style}}{{ .Style }}{{printf "\n"}}{{end}}`, `{{ if .Page}}`, /**/ ``, /**/ ``, /**/ ``, /**/ ``, /**/ ``, `{{printf "\n"}}{{end}}`, `{{ if .Excerpt}}{{ .Excerpt }}{{printf "\n"}}{{end}}`, `{{ if .First}}{{ .First }}{{printf "\n"}}{{end}}`, `{{ if .Depth}}{{ .Depth }}{{printf "\n"}}{{end}}`, `{{ if .All}}{{ .All }}{{printf "\n"}}{{end}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/doc/confluence-storage-format-790796544.html */ `ac:emoticon`: text( ``, ), `ac:image`: text( ``, ), /* https://confluence.atlassian.com/doc/widget-connector-macro-171180449.html#WidgetConnectorMacro-YouTube */ `ac:youtube`: text( `{{printf "\n"}}`, `youtube{{printf "\n"}}`, `com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm{{printf "\n"}}`, `{{ or .Width "640px" }}{{printf "\n"}}`, `{{ or .Height "360px" }}{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://support.atlassian.com/confluence-cloud/docs/insert-the-iframe-macro/ */ `ac:iframe`: text( `{{printf "\n"}}`, `{{printf "\n"}}`, `{{ if .Frameborder}}{{ .Frameborder }}{{printf "\n"}}{{end}}`, `{{ if .Scrolling}}{{ .Scrolling }}{{printf "\n"}}{{end}}`, `{{ if .Align}}{{ .Align }}{{printf "\n"}}{{end}}`, `{{ or .Width "640px" }}{{printf "\n"}}`, `{{ or .Height "360px" }}{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/doc/blog-posts-macro-139470.html */ `ac:blog-posts`: text( `{{printf "\n"}}`, `{{ if .Content }}{{ .Content }}{{printf "\n"}}{{end}}`, `{{ if .Spaces }}{{ .Spaces }}{{printf "\n"}}{{end}}`, `{{ if .Author }}{{ .Author }}{{printf "\n"}}{{end}}`, `{{ if .Time }}{{ .Time }}{{printf "\n"}}{{end}}`, `{{ if .Reverse }}{{ .Reverse }}{{printf "\n"}}{{end}}`, `{{ if .Sort }}{{ .Sort }}{{printf "\n"}}{{end}}`, `{{ if .Max }}{{ .Max }}{{printf "\n"}}{{end}}`, `{{ if .Label }}{{ .Label }}{{printf "\n"}}{{end}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/conf59/include-page-macro-792499125.html */ `ac:include`: text( `{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/conf59/excerpt-include-macro-792499101.html */ `ac:excerpt-include`: text( `{{printf "\n"}}`, `{{ if .NoPanel }}{{ .NoPanel }}{{ else }}false{{ end }}{{printf "\n"}}`, `{{ .Page }}{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/conf59/excerpt-macro-792499102.html */ `ac:excerpt`: text( `{{printf "\n"}}`, `{{ if .Hidden }}{{ .Hidden }}{{ else }}false{{ end }}{{printf "\n"}}`, `{{ if .OutputType }}{{ .OutputType }}{{ else }}BLOCK{{ end }}{{printf "\n"}}`, `{{printf "\n"}}`, `{{ .Excerpt }}{{printf "\n"}}`, `{{printf "\n"}}`, `{{printf "\n"}}`, ), /* https://confluence.atlassian.com/conf59/anchor-macro-792499068.html */ `ac:anchor`: text( `{{printf "\n"}}`, `{{ .Anchor }}{{printf "\n"}}`, `{{printf "\n"}}`, ), // TODO(seletskiy): more templates here } { templates, err = templates.New(name).Parse(body) if err != nil { return nil, karma. Describe("template", body). Format( err, "unable to parse template", ) } } return templates, nil }