Files
mark/markdown/markdown.go

249 lines
9.8 KiB
Go
Raw Permalink Normal View History

2019-04-14 13:53:44 +03:00
package mark
import (
"bytes"
feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels chore: add test files fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline chore: remove test for droph1 and stripNewLines fix: add admonitions to StripNewLines and dropH1 tests feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline chore: remove test for droph1 and stripNewLines fix: add admonitions to StripNewLines and dropH1 tests feat: add mkdocsadmonition as opt-in renderer and parser fix: fix unit tests
2025-02-18 17:19:39 +01:00
"slices"
2019-04-14 13:53:44 +03:00
"github.com/kovetskiy/mark/v16/attachment"
cparser "github.com/kovetskiy/mark/v16/parser"
crenderer "github.com/kovetskiy/mark/v16/renderer"
"github.com/kovetskiy/mark/v16/stdlib"
ctransformer "github.com/kovetskiy/mark/v16/transformer"
"github.com/kovetskiy/mark/v16/types"
2026-03-28 09:55:58 +01:00
"github.com/rs/zerolog/log"
feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels chore: add test files fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline chore: remove test for droph1 and stripNewLines fix: add admonitions to StripNewLines and dropH1 tests feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline chore: remove test for droph1 and stripNewLines fix: add admonitions to StripNewLines and dropH1 tests feat: add mkdocsadmonition as opt-in renderer and parser fix: fix unit tests
2025-02-18 17:19:39 +01:00
mkDocsParser "github.com/stefanfritsch/goldmark-admonitions"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
)
// ConfluenceLegacyExtension is the original goldmark extension without GitHub Alerts support
// This extension is preserved for backward compatibility and testing purposes
type ConfluenceLegacyExtension struct {
html.Config
2025-05-29 01:21:02 +02:00
Stdlib *stdlib.Lib
Path string
MarkConfig types.MarkConfig
Attachments []attachment.Attachment
}
// NewConfluenceLegacyExtension creates a new instance of the legacy ConfluenceRenderer
func NewConfluenceLegacyExtension(stdlib *stdlib.Lib, path string, cfg types.MarkConfig) *ConfluenceLegacyExtension {
return &ConfluenceLegacyExtension{
2025-05-29 01:21:02 +02:00
Config: html.NewConfig(),
Stdlib: stdlib,
Path: path,
MarkConfig: cfg,
Attachments: []attachment.Attachment{},
2023-03-29 15:31:13 +02:00
}
}
func (c *ConfluenceLegacyExtension) Attach(a attachment.Attachment) {
2023-09-06 16:19:09 -07:00
c.Attachments = append(c.Attachments, a)
}
func (c *ConfluenceLegacyExtension) Extend(m goldmark.Markdown) {
2023-04-26 08:02:35 +02:00
2023-09-01 22:59:04 +02:00
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceTextLegacyRenderer(c.MarkConfig.StripNewlines), 100),
2023-09-01 22:59:04 +02:00
util.Prioritized(crenderer.NewConfluenceBlockQuoteRenderer(), 100),
util.Prioritized(crenderer.NewConfluenceCodeBlockRenderer(c.Stdlib, c.Path), 100),
2025-05-29 01:21:02 +02:00
util.Prioritized(crenderer.NewConfluenceFencedCodeBlockRenderer(c.Stdlib, c, c.MarkConfig), 100),
2023-09-01 22:59:04 +02:00
util.Prioritized(crenderer.NewConfluenceHTMLBlockRenderer(c.Stdlib), 100),
2025-05-29 01:21:02 +02:00
util.Prioritized(crenderer.NewConfluenceHeadingRenderer(c.MarkConfig.DropFirstH1), 100),
2026-02-18 09:15:51 +01:00
util.Prioritized(crenderer.NewConfluenceImageRenderer(c.Stdlib, c, c.Path, c.MarkConfig.ImageAlign), 100),
2024-07-25 22:24:36 +02:00
util.Prioritized(crenderer.NewConfluenceParagraphRenderer(), 100),
2023-09-01 22:59:04 +02:00
util.Prioritized(crenderer.NewConfluenceLinkRenderer(), 100),
util.Prioritized(crenderer.NewConfluenceTaskListRenderer(), 100),
2023-09-01 22:59:04 +02:00
))
2023-05-04 14:53:33 +02:00
feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels chore: add test files fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline chore: remove test for droph1 and stripNewLines fix: add admonitions to StripNewLines and dropH1 tests feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels fix: add tests for stripnewline and droph1 chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline feat: add Support for converting Material for MkDocs Admonitions to Confluence Info Panels chore: rename Admontion to MkDocsAdmonition, remove annoying comments fix: import parser instead of copying the file chore: rename mkDocs renderer function fix: fix bug and pipeline chore: remove test for droph1 and stripNewLines fix: add admonitions to StripNewLines and dropH1 tests feat: add mkdocsadmonition as opt-in renderer and parser fix: fix unit tests
2025-02-18 17:19:39 +01:00
if slices.Contains(c.MarkConfig.Features, "mkdocsadmonitions") {
m.Parser().AddOptions(
parser.WithBlockParsers(
util.Prioritized(mkDocsParser.NewAdmonitionParser(), 100),
),
)
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceMkDocsAdmonitionRenderer(), 100),
))
}
if slices.Contains(c.MarkConfig.Features, "mention") {
m.Parser().AddOptions(
parser.WithInlineParsers(
util.Prioritized(cparser.NewMentionParser(), 99),
),
)
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceMentionRenderer(c.Stdlib), 100),
))
}
2023-09-01 22:59:04 +02:00
m.Parser().AddOptions(parser.WithInlineParsers(
// Must be registered with a higher priority than goldmark's linkParser to make sure goldmark doesn't parse
// the <ac:*/> tags.
util.Prioritized(cparser.NewConfluenceTagParser(), 199),
))
2023-05-04 14:53:33 +02:00
}
// compileMarkdownWithExtension is a shared helper to eliminate code duplication
// between different compilation approaches
func compileMarkdownWithExtension(markdown []byte, ext goldmark.Extender, logMessage string) (string, error) {
log.Trace().Msgf(logMessage, string(markdown))
converter := goldmark.New(
goldmark.WithExtensions(
extension.Footnote,
extension.DefinitionList,
2023-10-23 21:03:57 +02:00
extension.NewTable(
extension.WithTableCellAlignMethod(extension.TableCellAlignStyle),
),
ext,
2025-05-29 01:21:02 +02:00
extension.GFM,
2019-04-14 13:53:44 +03:00
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithUnsafe(),
2023-10-23 21:03:57 +02:00
html.WithXHTML(),
))
ctx := parser.NewContext(parser.WithIDs(&cparser.ConfluenceIDs{Values: map[string]bool{}}))
var buf bytes.Buffer
err := converter.Convert(markdown, &buf, parser.WithContext(ctx))
if err != nil {
return "", err
}
2019-04-14 13:53:44 +03:00
html := buf.Bytes()
2026-03-28 09:55:58 +01:00
log.Trace().Msgf("rendered markdown to html:\n%s", string(html))
2019-04-20 10:24:30 +03:00
return string(html), nil
}
// CompileMarkdown compiles markdown to Confluence Storage Format with GitHub Alerts support
// This is the main function that now uses the enhanced GitHub Alerts transformer by default
// for superior processing of [!NOTE], [!TIP], [!WARNING], [!CAUTION], [!IMPORTANT] syntax.
// Note: This is a breaking change from previous versions which rendered these markers literally.
func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, cfg types.MarkConfig) (string, []attachment.Attachment, error) {
// Use the enhanced GitHub Alerts extension for better processing
ghAlertsExtension := NewConfluenceExtension(stdlib, path, cfg)
html, err := compileMarkdownWithExtension(markdown, ghAlertsExtension, "rendering markdown with GitHub Alerts support:\n%s")
return html, ghAlertsExtension.Attachments, err
}
// CompileMarkdownLegacy compiles markdown using the legacy approach without GitHub Alerts transformer
// This function is preserved for backward compatibility and testing purposes
func CompileMarkdownLegacy(markdown []byte, stdlib *stdlib.Lib, path string, cfg types.MarkConfig) (string, []attachment.Attachment, error) {
confluenceExtension := NewConfluenceLegacyExtension(stdlib, path, cfg)
html, err := compileMarkdownWithExtension(markdown, confluenceExtension, "rendering markdown with legacy renderer:\n%s")
return html, confluenceExtension.Attachments, err
}
// ConfluenceExtension is a goldmark extension for GitHub Alerts with Transformer approach
// This extension provides superior GitHub Alert processing by transforming [!NOTE], [!TIP], etc.
// into proper Confluence macros while maintaining full compatibility with existing functionality.
// This is now the primary/default extension.
type ConfluenceExtension struct {
html.Config
Stdlib *stdlib.Lib
Path string
MarkConfig types.MarkConfig
Attachments []attachment.Attachment
}
// NewConfluenceExtension creates a new instance of the GitHub Alerts extension
// This is the improved standalone version that doesn't depend on feature flags
func NewConfluenceExtension(stdlib *stdlib.Lib, path string, cfg types.MarkConfig) *ConfluenceExtension {
return &ConfluenceExtension{
Config: html.NewConfig(),
Stdlib: stdlib,
Path: path,
MarkConfig: cfg,
Attachments: []attachment.Attachment{},
}
}
func (c *ConfluenceExtension) Attach(a attachment.Attachment) {
c.Attachments = append(c.Attachments, a)
}
// Extend extends the Goldmark processor with GitHub Alerts transformer and renderers
// This method registers all necessary components for GitHub Alert processing:
// 1. Core renderers for standard markdown elements
// 2. GitHub Alerts specific renderers (blockquote and text) with higher priority
// 3. GitHub Alerts AST transformer for preprocessing
func (c *ConfluenceExtension) Extend(m goldmark.Markdown) {
// Register core renderers (excluding blockquote and text which we'll replace)
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceCodeBlockRenderer(c.Stdlib, c.Path), 100),
util.Prioritized(crenderer.NewConfluenceFencedCodeBlockRenderer(c.Stdlib, c, c.MarkConfig), 100),
util.Prioritized(crenderer.NewConfluenceHTMLBlockRenderer(c.Stdlib), 100),
util.Prioritized(crenderer.NewConfluenceHeadingRenderer(c.MarkConfig.DropFirstH1), 100),
util.Prioritized(crenderer.NewConfluenceImageRenderer(c.Stdlib, c, c.Path, c.MarkConfig.ImageAlign), 100),
util.Prioritized(crenderer.NewConfluenceParagraphRenderer(), 100),
util.Prioritized(crenderer.NewConfluenceLinkRenderer(), 100),
util.Prioritized(crenderer.NewConfluenceTaskListRenderer(), 100),
))
// Add GitHub Alerts specific renderers with higher priority to override defaults
// These renderers handle both GitHub Alerts and legacy blockquote syntax
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceGHAlertsBlockQuoteRenderer(), 200),
util.Prioritized(crenderer.NewConfluenceTextRenderer(c.MarkConfig.StripNewlines), 200),
))
// Add the GitHub Alerts AST transformer that preprocesses [!TYPE] syntax
m.Parser().AddOptions(parser.WithASTTransformers(
util.Prioritized(ctransformer.NewGHAlertsTransformer(), 100),
))
// Add mkdocsadmonitions support if requested
if slices.Contains(c.MarkConfig.Features, "mkdocsadmonitions") {
m.Parser().AddOptions(
parser.WithBlockParsers(
util.Prioritized(mkDocsParser.NewAdmonitionParser(), 100),
),
)
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceMkDocsAdmonitionRenderer(), 100),
))
}
// Add mention support if requested
if slices.Contains(c.MarkConfig.Features, "mention") {
m.Parser().AddOptions(
parser.WithInlineParsers(
util.Prioritized(cparser.NewMentionParser(), 99),
),
)
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(crenderer.NewConfluenceMentionRenderer(c.Stdlib), 100),
))
}
// Add confluence tag parser for <ac:*/> tags
m.Parser().AddOptions(parser.WithInlineParsers(
util.Prioritized(cparser.NewConfluenceTagParser(), 199),
))
}
// CompileMarkdownWithTransformer compiles markdown using the transformer approach for GitHub Alerts
// This function provides enhanced GitHub Alert processing while maintaining full compatibility
// with existing markdown functionality. It transforms [!NOTE], [!TIP], etc. into proper titles.
// This is an alias for CompileMarkdown for backward compatibility.
func CompileMarkdownWithTransformer(markdown []byte, stdlib *stdlib.Lib, path string, cfg types.MarkConfig) (string, []attachment.Attachment, error) {
return CompileMarkdown(markdown, stdlib, path, cfg)
}