package stdlib import ( "strings" "text/template" "github.com/kovetskiy/mark/confluence" "github.com/kovetskiy/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( "", "", 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( ``, /**/ `{{ if eq .Language "mermaid" }}true{{ else }}`, /**/ `{{ .Language }}{{ end }}`, /**/ `{{ .Collapse }}`, /**/ `{{ if .Theme }}{{ .Theme }}{{ end }}`, /**/ `{{ if .Linenumbers }}{{ .Linenumbers }}{{ end }}`, /**/ `{{ if .Firstline }}{{ .Firstline }}{{ end }}`, /**/ `{{ if .Title }}{{ .Title }}{{ end }}`, /**/ ``, ``, ), `ac:status`: text( ``, `{{ or .Color "Grey" }}`, `{{ or .Title .Color }}`, `{{ or .Subtle false }}`, ``, ), `ac:link:user`: text( `{{ with .Name | user }}`, /**/ ``, /**/ `{{ if .AccountID }}`, /****/ ``, /**/ `{{ else }}`, /****/ ``, /**/ `{{ end }}`, /**/ ``, `{{ else }}`, /**/ `{{ .Name }}`, `{{ end }}`, ), `ac:jira:ticket`: text( ``, `{{ .Ticket }}`, ``, ), /* Used for rendering Jira Filters */ `ac:jira:filter`: text( ``, `{{ or .Server "System JIRA" }}`, `{{ .JQL }}`, ``, ), /* https://confluence.atlassian.com/doc/jira-issues-macro-139380.html */ `ac:jiraissues`: text( ``, `{{ or .Anonymous false }}`, ``, `{{ 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" }}`, ``, `{{ or .Width "100%" }}`, ``, ), /* https://confluence.atlassian.com/conf59/info-tip-note-and-warning-macros-792499127.html */ `ac:box`: text( ``, `{{ or .Icon "false" }}`, `{{ if .Title }}{{ .Title }}{{ end }}`, `{{ .Body }}`, ``, ), /* https://confluence.atlassian.com/conf59/table-of-contents-macro-792499210.html */ `ac:toc`: text( ``, `{{ or .Printable "true" }}`, `{{ or .Style "disc" }}`, `{{ or .MaxLevel "7" }}`, `{{ or .Indent "" }}`, `{{ or .MinLevel "1" }}`, `{{ or .Exclude "" }}`, `{{ or .Type "list" }}`, `{{ or .Outline "clear" }}`, `{{ or .Include "" }}`, ``, ), /* https://confluence.atlassian.com/doc/children-display-macro-139501.html */ `ac:children`: text( ``, `{{ if .Reverse }}{{ or .Reverse }}{{ end }}`, `{{ if .Sort }}{{ .Sort }}{{ end }}`, `{{ if .Style }}{{ .Style }}{{ end }}`, `{{ if .Page }}`, /**/ ``, /**/ ``, /**/ ``, /**/ ``, /**/ ``, `{{ end }}`, `{{ if .Excerpt }}{{ .Excerpt }}{{ end }}`, `{{ if .First }}{{ .First }}{{ end }}`, `{{ if .Depth }}{{ .Depth }}{{ end }}`, `{{ if .All }}{{ .All }}{{ end }}`, ``, ), /* https://confluence.atlassian.com/doc/confluence-storage-format-790796544.html */ `ac:emoticon`: text( ``, ), `ac:image`: text( ``, `{{ if .Attachment }}{{ end }}`, `{{ if .Url }}{{ end }}`, ``, ), /* https://confluence.atlassian.com/doc/widget-connector-macro-171180449.html#WidgetConnectorMacro-YouTube */ `ac:youtube`: text( ``, `youtube`, `com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm`, `{{ or .Width "640px" }}`, `{{ or .Height "360px" }}`, ``, ``, ), /* https://support.atlassian.com/confluence-cloud/docs/insert-the-iframe-macro/ */ `ac:iframe`: text( ``, ``, `{{ if .Frameborder }}{{ .Frameborder }}{{ end }}`, `{{ if .Scrolling }}{{ .Scrolling }}{{ end }}`, `{{ if .Align }}{{ .Align }}{{ end }}`, `{{ or .Width "640px" }}`, `{{ or .Height "360px" }}`, ``, ), /* https://confluence.atlassian.com/doc/blog-posts-macro-139470.html */ `ac:blog-posts`: text( ``, `{{ if .Content }}{{ .Content }}{{ end }}`, `{{ if .Spaces }}{{ .Spaces }}{{ end }}`, `{{ if .Author }}{{ .Author }}{{ end }}`, `{{ if .Time }}{{ .Time }}{{ end }}`, `{{ if .Reverse }}{{ .Reverse }}{{ end }}`, `{{ if .Sort }}{{ .Sort }}{{ end }}`, `{{ if .Max }}{{ .Max }}{{ end }}`, `{{ if .Label }}{{ .Label }}{{ end }}`, ``, ), /* https://confluence.atlassian.com/conf59/include-page-macro-792499125.html */ `ac:include`: text( ``, ``, ``, ``, ``, ``, ``, ), /* https://confluence.atlassian.com/conf59/excerpt-include-macro-792499101.html */ /* https://support.atlassian.com/confluence-cloud/docs/insert-the-excerpt-include-macro/ */ `ac:excerpt-include`: text( ``, `{{ if .Name }}{{ .Name }}{{ end }}`, `{{ if .NoPanel }}{{ .NoPanel }}{{ else }}false{{ end }}`, `{{ .Page }}`, ``, ), /* https://confluence.atlassian.com/conf59/excerpt-macro-792499102.html */ /* https://support.atlassian.com/confluence-cloud/docs/insert-the-excerpt-macro/ */ `ac:excerpt`: text( ``, `{{ if .Name }}{{ .Name }}{{ end }}`, `{{ if .Hidden }}{{ .Hidden }}{{ else }}false{{ end }}`, `{{ if .OutputType }}{{ .OutputType }}{{ else }}BLOCK{{ end }}`, ``, `{{ .Excerpt }}`, ``, ``, ), /* https://confluence.atlassian.com/conf59/anchor-macro-792499068.html */ `ac:anchor`: text( ``, `{{ .Anchor }}`, ``, ), /* https://confluence.atlassian.com/conf59/expand-macro-792499106.html */ `ac:expand`: text( ``, `{{ .Title }}`, `{{ .Body }}`, ``, ), /* https://confluence.atlassian.com/conf59/user-profile-macro-792499223.html */ `ac:profile`: text( `{{ with .Name | user }}`, ``, ``, `{{ if .AccountID }}`, /**/ ``, `{{ else }}`, /**/ ``, `{{ end }}`, ``, ``, `{{ end }}`, ), /* https://confluence.atlassian.com/conf59/content-by-label-macro-792499087.html */ `ac:contentbylabel`: text( ``, `{{ .CQL }}`, ``, ), /* https://confluence.atlassian.com/conf59/page-properties-report-macro-792499165.html */ `ac:detailssummary`: text( ``, `{{ .Headings }}`, `{{ .FirstColumn }}`, `{{ .SortBy }}`, `{{ .CQL }}`, ``, ), /* https://confluence.atlassian.com/conf59/page-properties-macro-792499154.html */ `ac:details`: text( ``, `{{ .Body }}`, ``, ), /* https://confluence.atlassian.com/conf59/page-tree-macro-792499177.html */ `ac:pagetree`: text( ``, ``, ``, ``, ``, ``, `{{ or .Sort "" }}`, `{{ or .Excerpt "" }}`, `{{ or .Reverse "" }}`, `{{ or .SearchBox "" }}`, `{{ or .ExpandCollapseAll "" }}`, `{{ or .StartDepth "" }}`, ``, ), /* https://confluence.atlassian.com/conf59/page-tree-search-macro-792499178.html */ `ac:pagetreesearch`: text( ``, `{{ if .Root }}{{ .Root }}{{ end }}`, ``, ), /* https://confluence.atlassian.com/conf59/panel-macro-792499179.html */ `ac:panel`: text( ``, `{{ or .BGColor "" }}`, `{{ or .TitleBGColor "" }}`, `{{ or .Title "" }}`, `{{ or .BorderStyle "" }}`, `{{ or .BorderColor "" }}`, `{{ or .TitleColor "" }}`, `{{ .Body }}`, ``, ), /* https://confluence.atlassian.com/conf59/recently-updated-macro-792499187.html */ `ac:recently-updated`: text( ``, `{{ if .Spaces }}{{ end }}`, `{{ or .ShowProfilePic "" }}`, `{{ or .Types "page, comment, blogpost" }}`, `{{ or .Max "" }}`, `{{ or .Labels "" }}`, `{{ or .HideHeading "" }}`, `{{ or .Theme "" }}`, ``, ), /* https://confluence.atlassian.com/conf59/column-macro-792499085.html */ `ac:column`: text( ``, `{{ or .Width "" }}`, `{{ or .Body "" }}`, ``, ), /* https://confluence.atlassian.com/conf59/multimedia-macro-792499140.html */ `ac:multimedia`: text( ``, `{{ or .Width 500 }}`, ``, ``, ``, `{{ or .AutoPlay "false"}}`, ``, ), // 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 }